[cdo] 01/01: upstream 1.7.1

Alastair McKinstry mckinstry at moszumanska.debian.org
Thu Jun 9 07:45:33 UTC 2016


This is an automated email from the git hooks/post-receive script.

mckinstry pushed a commit to tag upstream/1.7.1
in repository cdo.

commit f305ea549d0b9f6ba132dfc5ad3a19e83a7527e4
Author: Alastair McKinstry <mckinstry at debian.org>
Date:   Wed Apr 27 10:05:16 2016 +0100

    upstream 1.7.1
---
 ChangeLog                                      |    99 +-
 Makefile.am                                    |     2 +-
 Makefile.in                                    |     4 +-
 NEWS                                           |    20 +
 OPERATORS                                      |    91 +-
 cdo.spec                                       |     2 +-
 config/default                                 |    54 +-
 configure                                      |   112 +-
 configure.ac                                   |    22 +-
 contrib/Makefile.in                            |     2 +
 contrib/cdoCompletion.bash                     |   800 +-
 contrib/cdoCompletion.tcsh                     |   800 +-
 contrib/cdoCompletion.zsh                      |   800 +-
 doc/cdo.pdf                                    |   Bin 1414096 -> 2652027 bytes
 doc/cdo_eca.pdf                                |   Bin 213128 -> 213128 bytes
 doc/cdo_magics.pdf                             |   Bin 0 -> 829844 bytes
 doc/cdo_refcard.pdf                            |   Bin 91167 -> 91624 bytes
 libcdi/ChangeLog                               |    37 +
 libcdi/app/cdi.c                               |    18 +-
 libcdi/app/createtable.c                       |     1 -
 libcdi/app/printinfo.h                         |    16 +-
 libcdi/configure                               |   249 +-
 libcdi/configure.ac                            |    25 +-
 libcdi/doc/cdi_cman.pdf                        |   Bin 332635 -> 333778 bytes
 libcdi/doc/cdi_fman.pdf                        |   Bin 360969 -> 362370 bytes
 libcdi/interfaces/cdi.hpp                      |     2 +-
 libcdi/src/Makefile.am                         |    17 +-
 libcdi/src/Makefile.in                         |    85 +-
 libcdi/src/basetime.c                          |     1 -
 libcdi/src/binary.c                            |    22 +-
 libcdi/src/calendar.h                          |     9 +-
 libcdi/src/cdf_read.c                          |   720 +
 libcdi/src/cdf_write.c                         |  1272 +
 libcdi/src/cdi.h                               |    36 +-
 libcdi/src/cdi.inc                             |    38 +-
 libcdi/src/cdiFortran.c                        |    11 +
 libcdi/src/cdi_error.c                         |     2 +-
 libcdi/src/cdi_int.c                           |    13 +-
 libcdi/src/cdi_int.h                           |    51 +-
 libcdi/src/cdi_util.c                          |    48 +
 libcdi/src/cdi_uuid.h                          |    42 +
 libcdi/src/cdilib.c                            | 35864 ++++++++++++-----------
 libcdi/src/cdipio.inc                          |     2 +-
 libcdi/src/cgribex.h                           |    15 +-
 libcdi/src/cgribexlib.c                        |  2918 +-
 libcdi/src/config.h.in                         |     3 +-
 libcdi/src/create_uuid.h                       |    23 -
 libcdi/src/dmemory.h                           |     8 +
 libcdi/src/error.c                             |     8 +-
 libcdi/src/error.h                             |    10 +-
 libcdi/src/gaussgrid.h                         |    10 +-
 libcdi/src/grb_read.c                          |   239 +
 libcdi/src/grb_write.c                         |   257 +
 libcdi/src/gribapi_utilities.c                 |    62 +-
 libcdi/src/gribapi_utilities.h                 |     3 +-
 libcdi/src/grid.c                              |  2075 +-
 libcdi/src/grid.h                              |    72 +-
 libcdi/src/ieglib.c                            |    14 +-
 libcdi/src/institution.c                       |     2 +-
 libcdi/src/iterator.c                          |   161 +-
 libcdi/src/iterator_fallback.c                 |   133 +-
 libcdi/src/iterator_fallback.h                 |     5 +-
 libcdi/src/iterator_grib.c                     |    87 +-
 libcdi/src/iterator_grib.h                     |     5 +-
 libcdi/src/mo_cdi.f90                          |   205 +-
 libcdi/src/namespace.h                         |     2 +-
 libcdi/src/pio_client.c                        |    10 +
 libcdi/src/pio_mpi_fw_at_reblock.c             |     3 +-
 libcdi/src/pio_server.c                        |    40 +-
 libcdi/src/pio_util.c                          |    44 -
 libcdi/src/pio_util.h                          |    11 +-
 libcdi/src/stream.c                            |   728 +-
 libcdi/src/stream_cdf.c                        |  3958 +--
 libcdi/src/stream_cdf.h                        |    12 +-
 libcdi/src/stream_cgribex.c                    |   107 +-
 libcdi/src/stream_cgribex.h                    |     6 +-
 libcdi/src/stream_ext.c                        |    56 +-
 libcdi/src/stream_fcommon.c                    |     5 +-
 libcdi/src/stream_grb.c                        |   635 +-
 libcdi/src/stream_grb.h                        |    20 +-
 libcdi/src/stream_gribapi.c                    |   233 +-
 libcdi/src/stream_gribapi.h                    |     6 +-
 libcdi/src/stream_ieg.c                        |   133 +-
 libcdi/src/stream_read.c                       |   357 +
 libcdi/src/stream_record.c                     |   143 +-
 libcdi/src/stream_srv.c                        |   130 +-
 libcdi/src/stream_write.c                      |   431 +
 libcdi/src/subtype.c                           |   134 +-
 libcdi/src/table.c                             |     4 +-
 libcdi/src/table.h                             |   355 +-
 libcdi/src/taxis.c                             |   113 +-
 libcdi/src/timebase.h                          |     8 +
 libcdi/src/util.c                              |    16 +-
 libcdi/src/varscan.c                           |    57 +-
 libcdi/src/varscan.h                           |     6 +-
 libcdi/src/vlist.c                             |    66 +-
 libcdi/src/vlist.h                             |    14 +-
 libcdi/src/vlist_var.c                         |    17 +-
 libcdi/src/zaxis.c                             |    36 +-
 libcdi/tables/gen_tableheaderfile.in           |    22 +-
 libcdi/tests/cksum_read.c                      |     4 +
 libcdi/tests/cksum_write.c                     |     6 +-
 libcdi/tests/deco2d_model.c                    |    38 +-
 libcdi/tests/pio_write.c                       |    18 +-
 libcdi/tests/pio_write.h                       |     2 +-
 libcdi/tests/simple_model.c                    |    42 +-
 libcdi/tests/test_resource_copy.c              |     7 +-
 m4/acx_options.m4                              |     6 +-
 src/Adisit.c                                   |    16 +-
 src/Afterburner.c                              |    87 +-
 src/Arith.c                                    |    13 +-
 src/Arithc.c                                   |     9 +-
 src/Arithdays.c                                |     9 +-
 src/Arithlat.c                                 |     2 +-
 src/CDIread.c                                  |    26 +-
 src/CDItest.c                                  |     2 +-
 src/CDIwrite.c                                 |    20 +-
 src/CMOR.c                                     |   692 +-
 src/Cat.c                                      |    47 +-
 src/CdoMagicsMapper.c                          |   166 +-
 src/CdoMagicsMapper.h                          |     4 -
 src/Change.c                                   |     2 +-
 src/Change_e5slm.c                             |     2 +-
 src/Cloudlayer.c                               |     2 +-
 src/Collgrid.c                                 |    52 +-
 src/Command.c                                  |     2 +-
 src/Comp.c                                     |     2 +-
 src/Compc.c                                    |     2 +-
 src/Complextorect.c                            |     4 +-
 src/Cond.c                                     |     2 +-
 src/Cond2.c                                    |     2 +-
 src/Condc.c                                    |     2 +-
 src/Consecstat.c                               |    14 +-
 src/Copy.c                                     |    56 +-
 src/Deltime.c                                  |     4 +-
 src/Derivepar.c                                |     2 +-
 src/Detrend.c                                  |    10 +-
 src/Diff.c                                     |     2 +-
 src/Distgrid.c                                 |     2 +-
 src/Duplicate.c                                |     4 +-
 src/EOFs.c                                     |     2 +-
 src/Echam5ini.c                                |    12 +-
 src/Enlarge.c                                  |     2 +-
 src/Enlargegrid.c                              |     2 +-
 src/Ensstat.c                                  |     2 +-
 src/Ensstat3.c                                 |     2 +-
 src/Ensval.c                                   |     2 +-
 src/Eof3d.c                                    |     2 +-
 src/Eofcoeff.c                                 |     9 +-
 src/Eofcoeff3d.c                               |    12 +-
 src/Exprf.c                                    |   604 +-
 src/FC.c                                       |     2 +-
 src/Filedes.c                                  |    47 +-
 src/Fillmiss.c                                 |     6 +-
 src/Filter.c                                   |     2 +-
 src/Fldrms.c                                   |    11 +-
 src/Fldstat.c                                  |    13 +-
 src/Fldstat2.c                                 |     6 +-
 src/Fourier.c                                  |     4 +-
 src/Gengrid.c                                  |     2 +-
 src/Gradsdes.c                                 |    15 +-
 src/Gridboxstat.c                              |    12 +-
 src/Gridcell.c                                 |    74 +-
 src/Gridsearch.c                               |     2 +-
 src/Harmonic.c                                 |     2 +-
 src/Hi.c                                       |    14 +-
 src/Histogram.c                                |     2 +-
 src/Importamsr.c                               |     2 +-
 src/Importbinary.c                             |     2 +-
 src/Importcmsaf.c                              |     2 +-
 src/Importobs.c                                |     2 +-
 src/Info.c                                     |     2 +-
 src/Input.c                                    |     2 +-
 src/Intgrid.c                                  |     2 +-
 src/Intgridtraj.c                              |     2 +-
 src/Intlevel.c                                 |     2 +-
 src/Intlevel3d.c                               |     2 +-
 src/Intntime.c                                 |     2 +-
 src/Inttime.c                                  |     2 +-
 src/Intyear.c                                  |     2 +-
 src/Invert.c                                   |    68 +-
 src/Invertlev.c                                |     2 +-
 src/Isosurface.c                               |     2 +-
 src/Kvl.c                                      |     2 +-
 src/Log.c                                      |     2 +-
 src/Maggraph.c                                 |   386 +-
 src/Magplot.c                                  |   910 +-
 src/Magvector.c                                |   323 +-
 src/Makefile.am                                |    12 +-
 src/Makefile.in                                |   311 +-
 src/Maskbox.c                                  |     2 +-
 src/Mastrfu.c                                  |     2 +-
 src/Math.c                                     |     4 +-
 src/Merge.c                                    |     2 +-
 src/Mergegrid.c                                |     2 +-
 src/Mergetime.c                                |    17 +-
 src/Merstat.c                                  |    13 +-
 src/Monarith.c                                 |    20 +-
 src/Mrotuv.c                                   |     2 +-
 src/Mrotuvb.c                                  |     2 +-
 src/Ninfo.c                                    |     2 +-
 src/Nmltest.c                                  |     2 +-
 src/Output.c                                   |     2 +-
 src/Outputgmt.c                                |   902 +-
 src/Pack.c                                     |     2 +-
 src/{Vardup.c => Pardup.c}                     |     8 +-
 src/Pinfo.c                                    |     2 +-
 src/Pressure.c                                 |     2 +-
 src/Regres.c                                   |    18 +-
 src/Remap.c                                    |     4 +-
 src/Remapeta.c                                 |     9 +-
 src/Replace.c                                  |     2 +-
 src/Replacevalues.c                            |     2 +-
 src/Rhopot.c                                   |    16 +-
 src/Rotuv.c                                    |     2 +-
 src/Runstat.c                                  |     8 +-
 src/Seascount.c                                |     6 +-
 src/Seasstat.c                                 |    17 +-
 src/Selbox.c                                   |     2 +-
 src/Select.c                                   |   470 +-
 src/Seloperator.c                              |     2 +-
 src/Selrec.c                                   |     6 +-
 src/Seltime.c                                  |   124 +-
 src/Selvar.c                                   |    35 +-
 src/Set.c                                      |     2 +-
 src/Setbox.c                                   |     2 +-
 src/Setgatt.c                                  |     2 +-
 src/Setgrid.c                                  |     2 +-
 src/Sethalo.c                                  |     2 +-
 src/Setmiss.c                                  |     2 +-
 src/Setpartab.c                                |    66 +-
 src/Setrcaname.c                               |     2 +-
 src/Settime.c                                  |    16 +-
 src/Setzaxis.c                                 |     2 +-
 src/Showinfo.c                                 |     2 +-
 src/Sinfo.c                                    |     9 +-
 src/Smooth9.c                                  |     2 +-
 src/Sort.c                                     |     2 +-
 src/Sorttimestamp.c                            |     2 +-
 src/Specinfo.c                                 |     2 +-
 src/Spectral.c                                 |     2 +-
 src/Spectrum.c                                 |     2 +-
 src/Split.c                                    |     2 +-
 src/Splitrec.c                                 |     2 +-
 src/Splitsel.c                                 |     9 +-
 src/Splittime.c                                |     2 +-
 src/Splityear.c                                |     2 +-
 src/StringUtilities.c                          |    85 +-
 src/StringUtilities.h                          |     7 +-
 src/Subtrend.c                                 |     4 +-
 src/Tee.c                                      |     2 +-
 src/Templates.c                                |    51 +-
 src/Test.c                                     |     2 +-
 src/Tests.c                                    |     2 +-
 src/Timcount.c                                 |     6 +-
 src/Timedt.c                                   |   121 +
 src/Timselstat.c                               |    15 +-
 src/Timsort.c                                  |     2 +-
 src/Timstat.c                                  |   349 +-
 src/Timstat2.c                                 |    32 +-
 src/Timstat3.c                                 |    45 +-
 src/Tinfo.c                                    |     3 +-
 src/Tocomplex.c                                |     4 +-
 src/Transpose.c                                |     2 +-
 src/Trend.c                                    |    18 +-
 src/Trms.c                                     |    10 +-
 src/Tstepcount.c                               |     2 +-
 src/Vargen.c                                   |     4 +-
 src/Varrms.c                                   |     2 +-
 src/Verifygrid.c                               |  1188 +
 src/Vertcum.c                                  |     4 +-
 src/Vertintap.c                                |     2 +-
 src/Vertintml.c                                |     2 +-
 src/Vertstat.c                                 |    19 +-
 src/Vertwind.c                                 |     2 +-
 src/Wct.c                                      |    13 +-
 src/Wind.c                                     |     4 +-
 src/Writegrid.c                                |     2 +-
 src/Writerandom.c                              |     4 +-
 src/XTimstat.c                                 |   440 +-
 src/YAR.c                                      |     2 +-
 src/Ydayarith.c                                |   131 +-
 src/Ydaypctl.c                                 |    65 +-
 src/Ydaystat.c                                 |    65 +-
 src/Ydrunpctl.c                                |    17 +-
 src/Ydrunstat.c                                |     9 +-
 src/Yearmonstat.c                              |    10 +-
 src/Yhourarith.c                               |    18 +-
 src/Yhourstat.c                                |    18 +-
 src/Ymonarith.c                                |    20 +-
 src/Ymonpctl.c                                 |    59 +-
 src/Ymonstat.c                                 |    18 +-
 src/Yseaspctl.c                                |     9 +-
 src/Yseasstat.c                                |    17 +-
 src/Zonstat.c                                  |    12 +-
 src/after_sptrans.c                            |     6 +
 {libcdi/src => src}/calendar.h                 |     9 +-
 src/cdi_uuid.h                                 |    42 +
 src/cdo.c                                      |   197 +-
 src/cdo.h                                      |     2 +-
 src/cdo_getopt.c                               |     2 +-
 src/cdo_getopt.h                               |     2 +-
 src/cdo_history.c                              |    11 +-
 src/cdo_int.h                                  |    26 +-
 src/cdo_pthread.c                              |     2 +-
 src/cdo_vlist.c                                |    54 +-
 src/commandline.c                              |     2 +-
 src/compare.h                                  |     2 +-
 src/config.h.in                                |    15 +
 src/dmemory.h                                  |    17 +-
 src/ecacore.c                                  |    27 +-
 src/error.h                                    |    49 +
 src/exception.c                                |    41 +-
 src/expr.c                                     |  1739 +-
 src/expr.h                                     |   183 +-
 src/expr_fun.c                                 |    76 +
 src/{cdo.h => expr_fun.h}                      |    12 +-
 src/expr_lex.c                                 |   385 +-
 src/expr_yacc.c                                |   527 +-
 src/expr_yacc.h                                |    42 +-
 src/features.c                                 |     3 +
 src/field.c                                    |   260 +-
 src/field.h                                    |    90 +-
 src/field2.c                                   |   881 +-
 src/fieldc.c                                   |    10 +-
 src/fieldmem.c                                 |    32 +-
 src/fieldmer.c                                 |     8 +-
 src/fieldzon.c                                 |     8 +-
 src/grid.c                                     |   193 +-
 src/grid.h                                     |     4 -
 src/grid_area.c                                |    62 +-
 src/grid_search.c                              |    45 +-
 src/grid_search.h                              |     2 +-
 src/griddes.c                                  |    10 +-
 src/griddes_nc.c                               |    50 +-
 src/gridreference.c                            |     2 +-
 src/institution.c                              |     2 +-
 src/juldate.c                                  |     7 +-
 src/kdtreelib/kdtree.h                         |   119 +-
 src/kdtreelib/kdtree_cartesian.c               |    72 +-
 src/kdtreelib/kdtree_common.c                  |    65 +-
 src/kdtreelib/kdtree_spherical.c               |    70 +-
 src/kvlist.c                                   |     2 +-
 src/kvlist.h                                   |     2 +-
 src/list.c                                     |     2 +-
 src/list.h                                     |     2 +-
 src/magics_template_parser.c                   |    84 +-
 src/magics_template_parser.h                   |    13 +-
 src/modules.c                                  |   776 +-
 src/modules.h                                  |     3 +-
 src/namelist.c                                 |     2 +-
 src/namelist.h                                 |     2 +-
 src/operator_help.h                            |   541 +-
 src/pipe.c                                     |     2 +-
 src/pipe.h                                     |     2 +-
 src/printinfo.h                                |    24 +-
 src/process.c                                  |     7 +-
 src/process.h                                  |     2 +-
 src/pstream.c                                  |    73 +-
 src/pstream.h                                  |     6 +-
 src/pstream_int.h                              |     2 +-
 src/pstream_write.h                            |     2 +-
 src/readline.c                                 |     2 +-
 src/remap.h                                    |     3 +
 src/remap_conserv.c                            |   623 +-
 src/remap_conserv_scrip.c                      |    22 +-
 src/remap_distwgt.c                            |     6 +-
 src/remap_scrip_io.c                           |   160 +-
 src/remaplib.c                                 |    25 +
 src/results_template_parser.c                  |    64 +-
 src/results_template_parser.h                  |     9 +-
 src/table.c                                    |     2 +-
 src/template_parser.c                          |   203 +-
 src/template_parser.h                          |    18 +-
 src/timebase.h                                 |    18 +
 src/timer.c                                    |     2 +-
 src/util.c                                     |    42 +-
 src/util.h                                     |     5 +-
 src/zaxis.c                                    |     2 +-
 test/{Copy_netcdf.test.in => Collgrid.test.in} |    24 +-
 test/Copy_netcdf.test.in                       |     6 +-
 test/Expr.test.in                              |    64 +
 test/Makefile.am                               |     5 +-
 test/Makefile.in                               |    21 +-
 test/data/Makefile.am                          |     7 +-
 test/data/Makefile.in                          |     9 +-
 test/data/aexpr1_ref                           |   Bin 0 -> 16800 bytes
 test/data/aexpr2_ref                           |   Bin 0 -> 16800 bytes
 test/data/datac.nc                             |   Bin 0 -> 7012 bytes
 test/data/datag.nc                             |   Bin 0 -> 704 bytes
 test/data/datar.nc                             |   Bin 0 -> 1156 bytes
 test/data/datau.nc                             |   Bin 0 -> 6884 bytes
 test/data/expr1_ref                            |   Bin 0 -> 6720 bytes
 test/data/expr2_ref                            |   Bin 0 -> 6720 bytes
 test/data/grib_testfile01_sinfo_ref            |     2 +-
 test/data/grib_testfile02_sinfo_ref            |     2 +-
 test/data/netcdf_testfile01_sinfon_ref         |     4 +-
 test/data/netcdf_testfile02_sinfon_ref         |     4 +-
 test/data/thread1_ref                          |   Bin 0 -> 312 bytes
 test/threads.test.in                           |    55 +
 400 files changed, 38438 insertions(+), 34667 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 5f3e60d..239359e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,100 @@
+2016-02-25  Uwe Schulzweida
+
+	* using CDI library version 1.7.1
+	* Version 1.7.1 released
+
+2016-02-26  Uwe Schulzweida
+
+	* cat: skip time constant fields for nfile>1 (bug fix) [report: Ralf M�ller]
+	* copy: skip time constant fields for nfile>1 (bug fix)
+	* mergetime: skip time constant fields for nfile>1 (bug fix)
+	* select: skip time constant fields for nfile>1 (bug fix)
+	* select: search key timestep doesn't work with nfiles>1 (bug fix)
+
+2016-02-22  Uwe Schulzweida
+
+	* settaxis: set default increment to 1hour
+
+2016-02-08  Uwe Schulzweida
+
+	* expr: added support for function clon(), clat() and clev()
+
+2016-02-04  Uwe Schulzweida
+
+	* selmon: renamed to selmonth
+	* selseas: renamed to selseason
+
+2016-02-03  Uwe Schulzweida
+
+	* select: added search key season to select seasons
+	* selseas: added support for season ANN
+
+2016-01-13  Uwe Schulzweida
+
+	* Expr: added support for temporary variables (starting with underscore)
+
+2016-01-11  Uwe Schulzweida
+
+	* grfill: removed unused plot parameter: resolution
+
+2016-01-08  Uwe Schulzweida
+
+	* ydaypctl: check of verification date failed (bug fix)
+
+2016-01-07  Uwe Schulzweida
+
+	* setpartab: added support to combine setpartab operators (bug fix) [report: Karl-Hermann Wieners]
+
+2016-01-06  Uwe Schulzweida
+
+	* genbil: generate weight file also for num_links=0
+
+2016-01-05  Uwe Schulzweida
+
+	* Select: added search key steptype
+
+2016-01-04  Uwe Schulzweida
+
+	* select/delete: added full support for time constant fields (bug fix) [report: Ralf M�ller]
+	* delete: don't abort if variables are available (bug fix) [report: Renate Brokopf]
+
+2015-12-28  Uwe Schulzweida
+
+	* Exprf: init nmiss (bug fix)
+
+2015-12-15  Uwe Schulzweida
+
+	* after: added optional parameter to read VCT from file
+
+2015-12-14  Uwe Schulzweida
+
+	* grfill: changed contour_shade_technique from cell_shading to grid_shading
+
+2015-12-10  Uwe Schulzweida
+
+	* Select: added search key gridnum and gridname
+	* Select: added search key zaxisnum and zaxisname
+
+2015-11-26  Uwe Schulzweida
+
+	* Timstat: added frequency attribute for day, mon and year
+
+2015-11-25  Uwe Schulzweida
+
+	* selname: select also ps for variables on hybrid sigma pressure levels
+
+2015-11-18  Modali Kameswarrao
+
+	* Magplot: added support for projections and regions
+
+2015-11-16  Uwe Schulzweida
+
+	* seldate: stop reading if data date is greater than end date
+
+2015-11-16  Uwe Schulzweida
+
+	* timcor: set data range -1 to 1
+
 2015-10-28  Uwe Schulzweida
 
 	* using CDI library version 1.7.0
@@ -526,7 +623,7 @@
 
 2014-06-19  Uwe Schulzweida
 
-	* Filter: disable zero-padding
+	* Filter (operator: highpass,lowpass,bandpass): disable zero-padding
 	* Detrend: added test
 	* added option --use_fftw: used in module filter
 
diff --git a/Makefile.am b/Makefile.am
index d55fc98..df6b08d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
 # Process this file with automake to produce Makefile.in
 SUBDIRS = libcdi src contrib test/data test
 #
-EXTRA_DIST=config/default OPERATORS doc/cdo.pdf doc/cdo_eca.pdf doc/cdo_refcard.pdf cdo.spec README
+EXTRA_DIST=config/default OPERATORS doc/cdo.pdf doc/cdo_eca.pdf doc/cdo_magics.pdf doc/cdo_refcard.pdf cdo.spec README
 #
 ACLOCAL_AMFLAGS = -I m4
 #
diff --git a/Makefile.in b/Makefile.in
index d637110..a0347df 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -239,6 +239,7 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 ENABLE_CDI_LIB = @ENABLE_CDI_LIB@
 ENABLE_CGRIBEX = @ENABLE_CGRIBEX@
+ENABLE_CXX = @ENABLE_CXX@
 ENABLE_DATA = @ENABLE_DATA@
 ENABLE_EXTRA = @ENABLE_EXTRA@
 ENABLE_GRIB = @ENABLE_GRIB@
@@ -249,6 +250,7 @@ ENABLE_NC4 = @ENABLE_NC4@
 ENABLE_NC4HDF5 = @ENABLE_NC4HDF5@
 ENABLE_NETCDF = @ENABLE_NETCDF@
 ENABLE_SERVICE = @ENABLE_SERVICE@
+ENABLE_THREADS = @ENABLE_THREADS@
 EXEEXT = @EXEEXT@
 FCFLAGS = @FCFLAGS@
 FGREP = @FGREP@
@@ -379,7 +381,7 @@ top_srcdir = @top_srcdir@
 # Process this file with automake to produce Makefile.in
 SUBDIRS = libcdi src contrib test/data test
 #
-EXTRA_DIST = config/default OPERATORS doc/cdo.pdf doc/cdo_eca.pdf doc/cdo_refcard.pdf cdo.spec README
+EXTRA_DIST = config/default OPERATORS doc/cdo.pdf doc/cdo_eca.pdf doc/cdo_magics.pdf doc/cdo_refcard.pdf cdo.spec README
 #
 ACLOCAL_AMFLAGS = -I m4
 #
diff --git a/NEWS b/NEWS
index d864dda..3bd9eb9 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,26 @@
 CDO NEWS
 --------
 
+Version 1.7.1 (25 February 2016):
+
+   New features:
+     * select: added search key steptype, gridnum, gridname, zaxisnum, zaxisname
+     * expr, exprf, aexpr, aexprf: added support for function clon(x), clat(x), clev(x),
+       remove(x), ngp(x), nlev(x), size(x), missval(x), sellevel(x,k), sellevidx(x,k),
+       fldmin(x), fldmax(x), fldsum(x), fldmean(x), fldavg(x), fldstd(x), fldstd1(x), fldvar(x), fldvar1(x),
+       vertmin(x), vertmax(x), vertsum(x), vertmean(x), vertavg(x), vertstd(x), vertstd1(x), vertvar(x), vertvar1(x)
+   New operators:
+     * contour: Contour plot
+     * shaded: Shaded contour plot
+     * grfill: Shaded gridfill plot
+     * gmtxyz: Output GMT xyz format to create contour plots with the GMT module pscontour.
+     * gmtcells: Output GMT multiple segment format to create shaded gridfill plots with psxy.
+   Fixed bugs:
+     * cdo -t table_file does not read variable name from table file [Bug #6312]
+     * One day shift backwards when converting to relative time axis with -r [Bug #6496]
+     * ydaypctl: check of verification date failed (bug fix)
+     * cat, copy, mergetime, select: remove time constant input fields for nfile>1 [Bug #6552]
+
 Version 1.7.0 (28 October 2015):
 
    New features:
diff --git a/OPERATORS b/OPERATORS
index e6a283e..11a5dd5 100644
--- a/OPERATORS
+++ b/OPERATORS
@@ -84,9 +84,9 @@ Operator catalog:
    Seltime       seltime         Select times
    Seltime       selhour         Select hours
    Seltime       selday          Select days
-   Seltime       selmon          Select months
+   Seltime       selmonth        Select months
    Seltime       selyear         Select years
-   Seltime       selseas         Select seasons
+   Seltime       selseason       Select seasons
    Seltime       seldate         Select dates
    Seltime       selsmon         Select single month
    Selbox        sellonlatbox    Select a longitude/latitude box
@@ -186,6 +186,7 @@ Operator catalog:
    Math          tan             Tangent
    Math          asin            Arc sine
    Math          acos            Arc cosine
+   Math          atan            Arc tangent
    Math          reci            Reciprocal value
    Arithc        addc            Add a constant
    Arithc        subc            Subtract a constant
@@ -233,9 +234,9 @@ Operator catalog:
    Ensstat       ensmean         Ensemble mean
    Ensstat       ensavg          Ensemble average
    Ensstat       ensstd          Ensemble standard deviation
-   Ensstat       ensstd1         Ensemble standard deviation
+   Ensstat       ensstd1         Ensemble standard deviation (n-1)
    Ensstat       ensvar          Ensemble variance
-   Ensstat       ensvar1         Ensemble variance
+   Ensstat       ensvar1         Ensemble variance (n-1)
    Ensstat       enspctl         Ensemble percentiles
    Ensstat2      ensrkhistspace  Ranked Histogram averaged over time
    Ensstat2      ensrkhisttime   Ranked Histogram averaged over space
@@ -248,9 +249,9 @@ Operator catalog:
    Fldstat       fldmean         Field mean
    Fldstat       fldavg          Field average
    Fldstat       fldstd          Field standard deviation
-   Fldstat       fldstd1         Field standard deviation
+   Fldstat       fldstd1         Field standard deviation (n-1)
    Fldstat       fldvar          Field variance
-   Fldstat       fldvar1         Field variance
+   Fldstat       fldvar1         Field variance (n-1)
    Fldstat       fldpctl         Field percentiles
    Zonstat       zonmin          Zonal minimum
    Zonstat       zonmax          Zonal maximum
@@ -258,9 +259,9 @@ Operator catalog:
    Zonstat       zonmean         Zonal mean
    Zonstat       zonavg          Zonal average
    Zonstat       zonstd          Zonal standard deviation
-   Zonstat       zonstd1         Zonal standard deviation
+   Zonstat       zonstd1         Zonal standard deviation (n-1)
    Zonstat       zonvar          Zonal variance
-   Zonstat       zonvar1         Zonal variance
+   Zonstat       zonvar1         Zonal variance (n-1)
    Zonstat       zonpctl         Zonal percentiles
    Merstat       mermin          Meridional minimum
    Merstat       mermax          Meridional maximum
@@ -268,9 +269,9 @@ Operator catalog:
    Merstat       mermean         Meridional mean
    Merstat       meravg          Meridional average
    Merstat       merstd          Meridional standard deviation
-   Merstat       merstd1         Meridional standard deviation
+   Merstat       merstd1         Meridional standard deviation (n-1)
    Merstat       mervar          Meridional variance
-   Merstat       mervar1         Meridional variance
+   Merstat       mervar1         Meridional variance (n-1)
    Merstat       merpctl         Meridional percentiles
    Gridboxstat   gridboxmin      Gridbox minimum
    Gridboxstat   gridboxmax      Gridbox maximum
@@ -278,27 +279,27 @@ Operator catalog:
    Gridboxstat   gridboxmean     Gridbox mean
    Gridboxstat   gridboxavg      Gridbox average
    Gridboxstat   gridboxstd      Gridbox standard deviation
-   Gridboxstat   gridboxstd1     Gridbox standard deviation
+   Gridboxstat   gridboxstd1     Gridbox standard deviation (n-1)
    Gridboxstat   gridboxvar      Gridbox variance
-   Gridboxstat   gridboxvar1     Gridbox variance
+   Gridboxstat   gridboxvar1     Gridbox variance (n-1)
    Vertstat      vertmin         Vertical minimum
    Vertstat      vertmax         Vertical maximum
    Vertstat      vertsum         Vertical sum
    Vertstat      vertmean        Vertical mean
    Vertstat      vertavg         Vertical average
    Vertstat      vertstd         Vertical standard deviation
-   Vertstat      vertstd1        Vertical standard deviation
+   Vertstat      vertstd1        Vertical standard deviation (n-1)
    Vertstat      vertvar         Vertical variance
-   Vertstat      vertvar1        Vertical variance
+   Vertstat      vertvar1        Vertical variance (n-1)
    Timselstat    timselmin       Time range minimum
    Timselstat    timselmax       Time range maximum
    Timselstat    timselsum       Time range sum
    Timselstat    timselmean      Time range mean
    Timselstat    timselavg       Time range average
    Timselstat    timselstd       Time range standard deviation
-   Timselstat    timselstd1      Time range standard deviation
+   Timselstat    timselstd1      Time range standard deviation (n-1)
    Timselstat    timselvar       Time range variance
-   Timselstat    timselvar1      Time range variance
+   Timselstat    timselvar1      Time range variance (n-1)
    Timselpctl    timselpctl      Time range percentiles
    Runstat       runmin          Running minimum
    Runstat       runmax          Running maximum
@@ -306,9 +307,9 @@ Operator catalog:
    Runstat       runmean         Running mean
    Runstat       runavg          Running average
    Runstat       runstd          Running standard deviation
-   Runstat       runstd1         Running standard deviation
+   Runstat       runstd1         Running standard deviation (n-1)
    Runstat       runvar          Running variance
-   Runstat       runvar1         Running variance
+   Runstat       runvar1         Running variance (n-1)
    Runpctl       runpctl         Running percentiles
    Timstat       timmin          Time minimum
    Timstat       timmax          Time maximum
@@ -316,9 +317,9 @@ Operator catalog:
    Timstat       timmean         Time mean
    Timstat       timavg          Time average
    Timstat       timstd          Time standard deviation
-   Timstat       timstd1         Time standard deviation
+   Timstat       timstd1         Time standard deviation (n-1)
    Timstat       timvar          Time variance
-   Timstat       timvar1         Time variance
+   Timstat       timvar1         Time variance (n-1)
    Timpctl       timpctl         Time percentiles
    Hourstat      hourmin         Hourly minimum
    Hourstat      hourmax         Hourly maximum
@@ -326,9 +327,9 @@ Operator catalog:
    Hourstat      hourmean        Hourly mean
    Hourstat      houravg         Hourly average
    Hourstat      hourstd         Hourly standard deviation
-   Hourstat      hourstd1        Hourly standard deviation
+   Hourstat      hourstd1        Hourly standard deviation (n-1)
    Hourstat      hourvar         Hourly variance
-   Hourstat      hourvar1        Hourly variance
+   Hourstat      hourvar1        Hourly variance (n-1)
    Hourpctl      hourpctl        Hourly percentiles
    Daystat       daymin          Daily minimum
    Daystat       daymax          Daily maximum
@@ -336,9 +337,9 @@ Operator catalog:
    Daystat       daymean         Daily mean
    Daystat       dayavg          Daily average
    Daystat       daystd          Daily standard deviation
-   Daystat       daystd1         Daily standard deviation
+   Daystat       daystd1         Daily standard deviation (n-1)
    Daystat       dayvar          Daily variance
-   Daystat       dayvar1         Daily variance
+   Daystat       dayvar1         Daily variance (n-1)
    Daypctl       daypctl         Daily percentiles
    Monstat       monmin          Monthly minimum
    Monstat       monmax          Monthly maximum
@@ -346,9 +347,9 @@ Operator catalog:
    Monstat       monmean         Monthly mean
    Monstat       monavg          Monthly average
    Monstat       monstd          Monthly standard deviation
-   Monstat       monstd1         Monthly standard deviation
+   Monstat       monstd1         Monthly standard deviation (n-1)
    Monstat       monvar          Monthly variance
-   Monstat       monvar1         Monthly variance
+   Monstat       monvar1         Monthly variance (n-1)
    Monpctl       monpctl         Monthly percentiles
    Yearmonstat   yearmonmean     Yearly mean from monthly data
    Yearstat      yearmin         Yearly minimum
@@ -357,9 +358,9 @@ Operator catalog:
    Yearstat      yearmean        Yearly mean
    Yearstat      yearavg         Yearly average
    Yearstat      yearstd         Yearly standard deviation
-   Yearstat      yearstd1        Yearly standard deviation
+   Yearstat      yearstd1        Yearly standard deviation (n-1)
    Yearstat      yearvar         Yearly variance
-   Yearstat      yearvar1        Yearly variance
+   Yearstat      yearvar1        Yearly variance (n-1)
    Yearpctl      yearpctl        Yearly percentiles
    Seasstat      seasmin         Seasonal minimum
    Seasstat      seasmax         Seasonal maximum
@@ -367,9 +368,9 @@ Operator catalog:
    Seasstat      seasmean        Seasonal mean
    Seasstat      seasavg         Seasonal average
    Seasstat      seasstd         Seasonal standard deviation
-   Seasstat      seasstd1        Seasonal standard deviation
+   Seasstat      seasstd1        Seasonal standard deviation (n-1)
    Seasstat      seasvar         Seasonal variance
-   Seasstat      seasvar1        Seasonal variance
+   Seasstat      seasvar1        Seasonal variance (n-1)
    Seaspctl      seaspctl        Seasonal percentiles
    Yhourstat     yhourmin        Multi-year hourly minimum
    Yhourstat     yhourmax        Multi-year hourly maximum
@@ -377,18 +378,18 @@ Operator catalog:
    Yhourstat     yhourmean       Multi-year hourly mean
    Yhourstat     yhouravg        Multi-year hourly average
    Yhourstat     yhourstd        Multi-year hourly standard deviation
-   Yhourstat     yhourstd1       Multi-year hourly standard deviation
+   Yhourstat     yhourstd1       Multi-year hourly standard deviation (n-1)
    Yhourstat     yhourvar        Multi-year hourly variance
-   Yhourstat     yhourvar1       Multi-year hourly variance
+   Yhourstat     yhourvar1       Multi-year hourly variance (n-1)
    Ydaystat      ydaymin         Multi-year daily minimum
    Ydaystat      ydaymax         Multi-year daily maximum
    Ydaystat      ydaysum         Multi-year daily sum
    Ydaystat      ydaymean        Multi-year daily mean
    Ydaystat      ydayavg         Multi-year daily average
    Ydaystat      ydaystd         Multi-year daily standard deviation
-   Ydaystat      ydaystd1        Multi-year daily standard deviation
+   Ydaystat      ydaystd1        Multi-year daily standard deviation (n-1)
    Ydaystat      ydayvar         Multi-year daily variance
-   Ydaystat      ydayvar1        Multi-year daily variance
+   Ydaystat      ydayvar1        Multi-year daily variance (n-1)
    Ydaypctl      ydaypctl        Multi-year daily percentiles
    Ymonstat      ymonmin         Multi-year monthly minimum
    Ymonstat      ymonmax         Multi-year monthly maximum
@@ -396,9 +397,9 @@ Operator catalog:
    Ymonstat      ymonmean        Multi-year monthly mean
    Ymonstat      ymonavg         Multi-year monthly average
    Ymonstat      ymonstd         Multi-year monthly standard deviation
-   Ymonstat      ymonstd1        Multi-year monthly standard deviation
+   Ymonstat      ymonstd1        Multi-year monthly standard deviation (n-1)
    Ymonstat      ymonvar         Multi-year monthly variance
-   Ymonstat      ymonvar1        Multi-year monthly variance
+   Ymonstat      ymonvar1        Multi-year monthly variance (n-1)
    Ymonpctl      ymonpctl        Multi-year monthly percentiles
    Yseasstat     yseasmin        Multi-year seasonal minimum
    Yseasstat     yseasmax        Multi-year seasonal maximum
@@ -406,9 +407,9 @@ Operator catalog:
    Yseasstat     yseasmean       Multi-year seasonal mean
    Yseasstat     yseasavg        Multi-year seasonal average
    Yseasstat     yseasstd        Multi-year seasonal standard deviation
-   Yseasstat     yseasstd1       Multi-year seasonal standard deviation
+   Yseasstat     yseasstd1       Multi-year seasonal standard deviation (n-1)
    Yseasstat     yseasvar        Multi-year seasonal variance
-   Yseasstat     yseasvar1       Multi-year seasonal variance
+   Yseasstat     yseasvar1       Multi-year seasonal variance (n-1)
    Yseaspctl     yseaspctl       Multi-year seasonal percentiles
    Ydrunstat     ydrunmin        Multi-year daily running minimum
    Ydrunstat     ydrunmax        Multi-year daily running maximum
@@ -416,9 +417,9 @@ Operator catalog:
    Ydrunstat     ydrunmean       Multi-year daily running mean
    Ydrunstat     ydrunavg        Multi-year daily running average
    Ydrunstat     ydrunstd        Multi-year daily running standard deviation
-   Ydrunstat     ydrunstd1       Multi-year daily running standard deviation
+   Ydrunstat     ydrunstd1       Multi-year daily running standard deviation (n-1)
    Ydrunstat     ydrunvar        Multi-year daily running variance
-   Ydrunstat     ydrunvar1       Multi-year daily running variance
+   Ydrunstat     ydrunvar1       Multi-year daily running variance (n-1)
    Ydrunpctl     ydrunpctl       Multi-year daily running percentiles
 -------------------------------------------------------------
    Correlation and co.
@@ -500,6 +501,8 @@ Operator catalog:
    Output        outputsrv       SERVICE ASCII output
    Output        outputext       EXTRA ASCII output
    Outputtab     outputtab       Table output
+   Outputgmt     gmtxyz          GMT xyz format
+   Outputgmt     gmtcells        GMT multiple segment format
 -------------------------------------------------------------
    Miscellaneous
 -------------------------------------------------------------
@@ -538,6 +541,14 @@ Operator catalog:
    Strgal        strgal          Strong gale days index per time period
    Hurr          hurr            Hurricane days index per time period
 -------------------------------------------------------------
+   Magics
+-------------------------------------------------------------
+   Magplot       contour         Contour plot
+   Magplot       shaded          Shaded contour plot
+   Magplot       grfill          Shaded gridfill plot
+   Magvector     vector          Vector arrows plot
+   Maggraph      graph           Line graph plot
+-------------------------------------------------------------
    Climate indices
 -------------------------------------------------------------
    EcaCdd        eca_cdd         Consecutive dry days index per time period
diff --git a/cdo.spec b/cdo.spec
index 44e87cc..6f6566e 100644
--- a/cdo.spec
+++ b/cdo.spec
@@ -4,7 +4,7 @@
 
 Name:           cdo
 #BuildRequires:  
-Version:        1.7.0
+Version:        1.7.1
 Release:        1
 Summary:        Climate Data Operators
 License:        GNU GENERAL PUBLIC LICENSE Version 2, June 1991
diff --git a/config/default b/config/default
index 7216c98..d2b1912 100755
--- a/config/default
+++ b/config/default
@@ -36,29 +36,31 @@ case "${HOSTNAME}" in
                  --with-hdf5=$HOME/local/hdf5-1.8.15-threadsafe \
                  --with-udunits2=/opt/local \
                  --with-curl=/opt/local \
+                 --with-libxml2=/usr \
+                 --with-magics=$HOME/local/Magics-2.25.3 \
                  --with-proj=/opt/local \
                  --with-szlib=$HOME/local"
 
-        if  test "$COMP" = icc ; then
-	  ${CONFPATH}configure  \
+        if  test "$COMP" = icpc ; then
+	  ${CONFPATH}configure --enable-cxx \
                     $CDOLIBS \
-	            CC=icc CFLAGS="-g -Wall -Wwrite-strings -O2 -qopt-report=5 -march=native" CXX=icpc
-        elif  test "$COMP" = icpc ; then
+	            CC=icc CXX=icpc CFLAGS="-g -Wall -O2 -qopt-report=5 -march=native"
+        elif  test "$COMP" = icc ; then
 	  ${CONFPATH}configure  \
                     $CDOLIBS \
-	            CC=icpc CFLAGS="-g -std=c++11 -Wall -O2 -qopt-report=5 -march=native"
+	            CC=icc CFLAGS="-g -Wall -Wwrite-strings -O2 -qopt-report=5 -march=native"
         elif  test "$COMP" = clang++ ; then
-	  ${CONFPATH}configure  \
+	  ${CONFPATH}configure --enable-cxx \
                     $CDOLIBS \
-	            CC=clang++ CFLAGS="-g -Wall -O3"
+	            CC=clang CXX=clang++ CFLAGS="-g -Wall -O3"
         elif  test "$COMP" = clang ; then
 	  ${CONFPATH}configure  \
                     $CDOLIBS \
 	            CC=clang CFLAGS="-g -Wall -Wwrite-strings -O3"
         elif  test "$COMP" = g++ ; then
-	  ${CONFPATH}configure  \
+	  ${CONFPATH}configure --enable-cxx \
                     $CDOLIBS \
-	            CC=g++ CFLAGS="-g -std=c++14 -Wall -W -Wfloat-equal -pedantic -O3 -march=native"
+	            CC=gcc CXX=g++ CFLAGS="-g -Wall -W -Wfloat-equal -pedantic -O3 -march=native"
         else
 	  ${CONFPATH}configure --prefix=$HOME/local \
                     --enable-maintainer-mode \
@@ -75,39 +77,41 @@ case "${HOSTNAME}" in
 #                 --with-szlib=$HOME/local \
 #                 --with-proj=/opt/local \
 #                 --with-cmor=/Users/m214003/work/CMOR \
+#                 --with-magics=$HOME/local/magics-2.25.3 \
 #                 --with-curl=/opt/local"
         CDOLIBS="--enable-nearpt3 \
                  --with-fftw3 \
                  --with-grib_api=$HOME/local/gribapi-1.13.0 \
                  --with-netcdf=$HOME/local \
                  --with-hdf5=$HOME/local \
+                 --with-libxml2=/opt/local \
                  --with-proj=/opt/local"
 
-        if  test "$COMP" = icc ; then
-	  ${CONFPATH}configure --prefix=$HOME/local \
+        if  test "$COMP" = icpc ; then
+	  ${CONFPATH}configure --enable-cxx --prefix=$HOME/local \
                     $CDOLIBS \
-	            CC=icc CFLAGS="-g -Wall -Wwrite-strings -O2 -qopt-report=5 -march=native" CXX=icpc
+	            CC=icc CXX=icpc CFLAGS="-g -Wall -O2 -qopt-report=5 -march=native" CXX=icpc
         elif  test "$COMP" = icpc ; then
-	  ${CONFPATH}configure  \
+	  ${CONFPATH}configure \
                     $CDOLIBS \
-	            CC=icpc CFLAGS="-g -std=c++11 -Wall -O2 -qopt-report=5 -march=native"
+	            CC=icc CFLAGS="-g -Wall -Wwrite-strings -O2 -qopt-report=5 -march=native"
         elif  test "$COMP" = clang++ ; then
-	  ${CONFPATH}configure  \
+	  ${CONFPATH}configure --enable-cxx \
                     $CDOLIBS \
-	            CC=clang++ CFLAGS="-g -Wall -O3"
+	            CC=clang CXX=clang++ CFLAGS="-g -Wall -O3"
         elif  test "$COMP" = clang ; then
 	  ${CONFPATH}configure  \
                     $CDOLIBS \
 	            CC=clang CFLAGS="-g -Wall -Wwrite-strings -Ofast -march=native"
         elif  test "$COMP" = g++ ; then
-	  ${CONFPATH}configure  \
+	  ${CONFPATH}configure --enable-cxx \
                     $CDOLIBS \
-	            CC=g++ CFLAGS="-g -std=c++14 -Wall -W -Wfloat-equal -pedantic -O3"
+	            CC=gcc CXX=g++ CFLAGS="-g -Wall -W -Wfloat-equal -pedantic -O3"
         else
 	  ${CONFPATH}configure --prefix=$HOME/local \
                     --enable-maintainer-mode \
                     $CDOLIBS \
-	            CC=gcc CFLAGS="-g -std=c11 -pipe -Wall -Wwrite-strings -W -Wfloat-equal -pedantic -O3 -march=native -fstack-protector -Wa,-q"
+	            CC=gcc CFLAGS="-g -std=c11 -pipe -Wall -Wpointer-arith -Wwrite-strings -W -Wfloat-equal -pedantic -O3 -march=native -fstack-protector -funsigned-char -Wa,-q"
 #                    --with-libxml2=/usr \
 #                    --with-magics=/Users/m214003/local/Magics-2.18.14nio \
         fi
@@ -144,7 +148,12 @@ case "${HOSTNAME}" in
                  --with-udunits2=/sw/squeeze-x64/udunits-2.1.19 \
                  --with-proj=/sw/squeeze-x64/proj-4.7.0"
 
-        if  test "$COMP" = icc ; then
+        if  test "$COMP" = icpc ; then
+          ${CONFPATH}configure --enable-cxx --prefix=$HOME/local --exec_prefix=$HOME/local/thunder \
+                    --with-fftw3 \
+                    $CDOLIBS \
+	            CC=icc CXX=icpc CFLAGS="-g -Wall -O2 -qopt-report=5 -march=native"
+        elif  test "$COMP" = icc ; then
           ${CONFPATH}configure --prefix=$HOME/local --exec_prefix=$HOME/local/thunder \
                     --with-fftw3 \
                     $CDOLIBS \
@@ -153,6 +162,10 @@ case "${HOSTNAME}" in
           ${CONFPATH}configure --prefix=$HOME/local --exec_prefix=$HOME/local/thunder \
                     $CDOLIBS \
 	            CC=pgcc CFLAGS="-g -fast"
+        elif  test "$COMP" = g++ ; then
+	  ${CONFPATH}configure --enable-cxx \
+                    $CDOLIBS \
+	            CC=gcc CXX=g++ CFLAGS="-g -Wall -O3"
 	else
           ${CONFPATH}configure --prefix=$HOME/local --exec_prefix=$HOME/local/thunder \
                     --with-fftw3 \
@@ -168,6 +181,7 @@ case "${HOSTNAME}" in
                  --with-szlib=/sw/rhel6-x64/sys/szip-2.1-gcc48 \
                  --with-udunits2=/sw/rhel6-x64/util/udunits-2.2.17-gcc48 \
                  --with-proj=/sw/rhel6-x64/graphics/proj4-4.9.1-gcc48"
+#                 --with-cmor=/sw/rhel6-x64/cmor-2.9.2-shared-gcc48 \
 
         if  test "$COMP" = icc ; then
           ${CONFPATH}configure --prefix=$HOME/local \
diff --git a/configure b/configure
index cc5ef9b..116e78f 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for cdo 1.7.0.
+# Generated by GNU Autoconf 2.68 for cdo 1.7.1.
 #
 # Report bugs to <http://mpimet.mpg.de/cdo>.
 #
@@ -570,8 +570,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='cdo'
 PACKAGE_TARNAME='cdo'
-PACKAGE_VERSION='1.7.0'
-PACKAGE_STRING='cdo 1.7.0'
+PACKAGE_VERSION='1.7.1'
+PACKAGE_STRING='cdo 1.7.1'
 PACKAGE_BUGREPORT='http://mpimet.mpg.de/cdo'
 PACKAGE_URL=''
 
@@ -621,6 +621,7 @@ AM_CPPFLAGS
 CLIBS
 CLDFLAGS
 FCFLAGS
+ENABLE_CXX
 BUILD_AVX2_TESTS_FALSE
 BUILD_AVX2_TESTS_TRUE
 BUILD_AVX_TESTS_FALSE
@@ -671,6 +672,7 @@ ZLIB_LIBS
 ZLIB_INCLUDE
 THREADS_LIBS
 THREADS_INCLUDE
+ENABLE_THREADS
 PTHREAD_CFLAGS
 PTHREAD_LIBS
 PTHREAD_CC
@@ -839,6 +841,7 @@ with_magics
 with_libxml2
 enable_cdi_lib
 enable_all_static
+enable_cxx
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1395,7 +1398,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures cdo 1.7.0 to adapt to many kinds of systems.
+\`configure' configures cdo 1.7.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1465,7 +1468,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of cdo 1.7.0:";;
+     short | recursive ) echo "Configuration of cdo 1.7.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1499,6 +1502,7 @@ Optional Features:
                           [default=no]
   --enable-all-static     build a completely statically linked CDO binary
                           [default=no]
+  --enable-cxx            Use CXX as default compiler [default=no]
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1616,7 +1620,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-cdo configure 1.7.0
+cdo configure 1.7.1
 generated by GNU Autoconf 2.68
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2209,7 +2213,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by cdo $as_me 1.7.0, which was
+It was created by cdo $as_me 1.7.1, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
@@ -3158,7 +3162,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='cdo'
- VERSION='1.7.0'
+ VERSION='1.7.1'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -17521,6 +17525,18 @@ fi
 
 done
 
+for ac_header in execinfo.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
+if test "x$ac_cv_header_execinfo_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_EXECINFO_H 1
+_ACEOF
+
+fi
+
+done
+
 #  ----------------------------------------------------------------------
 # Checks for the availability of functions
 for ac_func in mallinfo
@@ -17534,6 +17550,17 @@ _ACEOF
 fi
 done
 
+for ac_func in backtrace
+do :
+  ac_fn_c_check_func "$LINENO" "backtrace" "ac_cv_func_backtrace"
+if test "x$ac_cv_func_backtrace" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_BACKTRACE 1
+_ACEOF
+
+fi
+done
+
 #  ----------------------------------------------------------------------
 # Checks for the availability of ANSI-C99 functions
 for ac_func in getrlimit
@@ -17688,6 +17715,39 @@ _ACEOF
 fi
 done
 
+for ac_func in feenableexcept
+do :
+  ac_fn_c_check_func "$LINENO" "feenableexcept" "ac_cv_func_feenableexcept"
+if test "x$ac_cv_func_feenableexcept" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_FEENABLEEXCEPT 1
+_ACEOF
+
+fi
+done
+
+#
+ac_fn_c_check_member "$LINENO" "fenv_t" "__control" "ac_cv_member_fenv_t___control" "#include <fenv.h>
+"
+if test "x$ac_cv_member_fenv_t___control" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FENV_T___CONTROL 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "fenv_t" "__mxcsr" "ac_cv_member_fenv_t___mxcsr" "#include <fenv.h>
+"
+if test "x$ac_cv_member_fenv_t___mxcsr" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FENV_T___MXCSR 1
+_ACEOF
+
+
+fi
+
 #  ----------------------------------------------------------------------
 #  Enable NEARPT3 support
 # AC_MSG_CHECKING([for nearpt3 support])
@@ -17728,6 +17788,7 @@ CFLAGS="$CFLAGS ${OPENMP_CFLAGS}"
 
 #  ----------------------------------------------------------------------
 #  Checks for multithreaded compiling + linking
+ENABLE_THREADS=no
 
 # Check whether --with-threads was given.
 if test "${with_threads+set}" = set; then :
@@ -18175,6 +18236,7 @@ if test x"$ax_pthread_ok" = xyes; then
 
 $as_echo "#define HAVE_LIBPTHREAD 1" >>confdefs.h
 
+                           ENABLE_THREADS=yes
         :
 else
         ax_pthread_ok=no
@@ -18252,6 +18314,7 @@ _ACEOF
 
 fi
 
+             ENABLE_THREADS=yes
              THREADS_LIBS=" -L$THREADS_ROOT/lib -lpthread"
              THREADS_INCLUDE=" -I$THREADS_ROOT/include" ;; #(
   *) :
@@ -18259,6 +18322,7 @@ fi
 esac
 
 
+
 #  ----------------------------------------------------------------------
 #  Link application to ZLIB library, needed for netcdf
 ZLIB_INCLUDE=''
@@ -21167,11 +21231,29 @@ else
 fi
 
 
+# Check whether --enable-cxx was given.
+if test "${enable_cxx+set}" = set; then :
+  enableval=$enable_cxx; if test "x$enable_cxx" != 'xno'; then :
+  CC=$CXX
+                      CXXFLAGS=$CFLAGS
+                      enable_cxx=yes
+else
+  enable_cxx=no
+fi
+else
+  enable_cxx=no
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_cxx" >&5
+$as_echo "$enable_cxx" >&6; }
+ENABLE_CXX=$enable_cxx
+
 #  ----------------------------------------------------------------------
 
 
 
 
+
 #AC_SUBST([INCLUDES])
 
 
@@ -21236,9 +21318,9 @@ ac_config_files="$ac_config_files test/Select.test test/Spectral.test test/Timst
 
 ac_config_files="$ac_config_files test/Ymonstat.test test/Fldstat.test test/Fldpctl.test test/Ensstat.test test/Enspctl.test"
 
-ac_config_files="$ac_config_files test/Afterburner.test test/Detrend.test test/Arith.test test/Gradsdes.test"
+ac_config_files="$ac_config_files test/Afterburner.test test/Detrend.test test/Arith.test test/Expr.test"
 
-ac_config_files="$ac_config_files test/wildcard.test"
+ac_config_files="$ac_config_files test/Gradsdes.test test/Collgrid.test test/threads.test test/wildcard.test"
 
 ac_config_files="$ac_config_files Makefile src/Makefile contrib/Makefile test/Makefile test/data/Makefile cdo.spec cdo.settings"
 
@@ -21816,7 +21898,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by cdo $as_me 1.7.0, which was
+This file was extended by cdo $as_me 1.7.1, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -21882,7 +21964,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-cdo config.status 1.7.0
+cdo config.status 1.7.1
 configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
@@ -22409,7 +22491,10 @@ do
     "test/Afterburner.test") CONFIG_FILES="$CONFIG_FILES test/Afterburner.test" ;;
     "test/Detrend.test") CONFIG_FILES="$CONFIG_FILES test/Detrend.test" ;;
     "test/Arith.test") CONFIG_FILES="$CONFIG_FILES test/Arith.test" ;;
+    "test/Expr.test") CONFIG_FILES="$CONFIG_FILES test/Expr.test" ;;
     "test/Gradsdes.test") CONFIG_FILES="$CONFIG_FILES test/Gradsdes.test" ;;
+    "test/Collgrid.test") CONFIG_FILES="$CONFIG_FILES test/Collgrid.test" ;;
+    "test/threads.test") CONFIG_FILES="$CONFIG_FILES test/threads.test" ;;
     "test/wildcard.test") CONFIG_FILES="$CONFIG_FILES test/wildcard.test" ;;
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
     "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
@@ -23923,7 +24008,10 @@ _LT_EOF
     "test/Afterburner.test":F) chmod a+x "$ac_file" ;;
     "test/Detrend.test":F) chmod a+x "$ac_file" ;;
     "test/Arith.test":F) chmod a+x "$ac_file" ;;
+    "test/Expr.test":F) chmod a+x "$ac_file" ;;
     "test/Gradsdes.test":F) chmod a+x "$ac_file" ;;
+    "test/Collgrid.test":F) chmod a+x "$ac_file" ;;
+    "test/threads.test":F) chmod a+x "$ac_file" ;;
     "test/wildcard.test":F) chmod a+x "$ac_file" ;;
 
   esac
diff --git a/configure.ac b/configure.ac
index 8d8b8d9..518d115 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@
 #  autoconf 2.68
 #  libtool  2.4.2
 
-AC_INIT([cdo], [1.7.0], [http://mpimet.mpg.de/cdo])
+AC_INIT([cdo], [1.7.1], [http://mpimet.mpg.de/cdo])
 
 AC_DEFINE_UNQUOTED(CDO, ["$PACKAGE_VERSION"], [CDO version])
 
@@ -67,9 +67,11 @@ AC_CHECK_HEADERS(malloc.h)
 AC_CHECK_HEADERS(glob.h)
 AC_CHECK_HEADERS(fnmatch.h)
 AC_CHECK_HEADERS(wordexp.h)
+AC_CHECK_HEADERS(execinfo.h)
 #  ----------------------------------------------------------------------
 # Checks for the availability of functions
 AC_CHECK_FUNCS(mallinfo)
+AC_CHECK_FUNCS(backtrace)
 #  ----------------------------------------------------------------------
 # Checks for the availability of ANSI-C99 functions
 AC_CHECK_FUNCS(getrlimit)
@@ -115,6 +117,9 @@ AC_CHECK_LIB([m],[floor])
 AC_CHECK_DECLS([isnan],,,[AC_INCLUDES_DEFAULT
 @%:@include <math.h>])
 AC_CHECK_FUNCS(sqrtl)
+AC_CHECK_FUNCS(feenableexcept)
+#
+AC_CHECK_MEMBERS([fenv_t.__control, fenv_t.__mxcsr],,,[[#include <fenv.h>]])
 #  ----------------------------------------------------------------------
 #  Enable NEARPT3 support
 # AC_MSG_CHECKING([for nearpt3 support])
@@ -215,7 +220,18 @@ AC_MSG_RESULT([no])
 
 AM_CONDITIONAL(BUILD_AVX2_TESTS, test x$ac_have_as_avx2 = xyes)
 
+AC_ARG_ENABLE([cxx],
+              [AS_HELP_STRING([--enable-cxx],[Use CXX as default compiler [default=no]])],
+              [AS_IF([test "x$enable_cxx" != 'xno'],
+                     [CC=$CXX
+                      CXXFLAGS=$CFLAGS
+                      enable_cxx=yes],
+              [enable_cxx=no])],
+              [enable_cxx=no])
+AC_MSG_RESULT([$enable_cxx])
+AC_SUBST([ENABLE_CXX],[$enable_cxx])
 #  ----------------------------------------------------------------------
+AC_SUBST([CXXFLAGS])
 AC_SUBST([CPPFLAGS])
 AC_SUBST([FCFLAGS])
 AC_SUBST([CLDFLAGS])
@@ -235,8 +251,8 @@ AC_CONFIG_FILES([test/File.test test/Read_grib.test test/Read_netcdf.test test/C
 AC_CONFIG_FILES([test/Cat.test test/Gridarea.test test/Genweights.test test/Remap.test],[chmod a+x "$ac_file"])
 AC_CONFIG_FILES([test/Select.test test/Spectral.test test/Timstat.test test/Vertint.test],[chmod a+x "$ac_file"])
 AC_CONFIG_FILES([test/Ymonstat.test test/Fldstat.test test/Fldpctl.test test/Ensstat.test test/Enspctl.test],[chmod a+x "$ac_file"])
-AC_CONFIG_FILES([test/Afterburner.test test/Detrend.test test/Arith.test test/Gradsdes.test],[chmod a+x "$ac_file"])
-AC_CONFIG_FILES([test/wildcard.test],[chmod a+x "$ac_file"])
+AC_CONFIG_FILES([test/Afterburner.test test/Detrend.test test/Arith.test test/Expr.test],[chmod a+x "$ac_file"])
+AC_CONFIG_FILES([test/Gradsdes.test test/Collgrid.test test/threads.test test/wildcard.test],[chmod a+x "$ac_file"])
 AC_CONFIG_FILES([Makefile src/Makefile contrib/Makefile test/Makefile test/data/Makefile cdo.spec cdo.settings])
 AC_OUTPUT
 
diff --git a/contrib/Makefile.in b/contrib/Makefile.in
index bbc9966..e3ff687 100644
--- a/contrib/Makefile.in
+++ b/contrib/Makefile.in
@@ -150,6 +150,7 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 ENABLE_CDI_LIB = @ENABLE_CDI_LIB@
 ENABLE_CGRIBEX = @ENABLE_CGRIBEX@
+ENABLE_CXX = @ENABLE_CXX@
 ENABLE_DATA = @ENABLE_DATA@
 ENABLE_EXTRA = @ENABLE_EXTRA@
 ENABLE_GRIB = @ENABLE_GRIB@
@@ -160,6 +161,7 @@ ENABLE_NC4 = @ENABLE_NC4@
 ENABLE_NC4HDF5 = @ENABLE_NC4HDF5@
 ENABLE_NETCDF = @ENABLE_NETCDF@
 ENABLE_SERVICE = @ENABLE_SERVICE@
+ENABLE_THREADS = @ENABLE_THREADS@
 EXEEXT = @EXEEXT@
 FCFLAGS = @FCFLAGS@
 FGREP = @FGREP@
diff --git a/contrib/cdoCompletion.bash b/contrib/cdoCompletion.bash
index 948aa02..517486b 100644
--- a/contrib/cdoCompletion.bash
+++ b/contrib/cdoCompletion.bash
@@ -4,6 +4,8 @@ complete -W "
 -- \
 -- \
 -- \
+-- \
+-- \
 -L \
 -M \
 -O \
@@ -25,795 +27,13 @@ complete -W "
 -t \
 -v \
 -z \
-abs -abs \
-acos -acos \
-add -add \
-addc -addc \
-adipot -adipot \
-adisit -adisit \
-aexpr -aexpr \
-aexprf -aexprf \
-after -after \
-afterburner -afterburner \
-anomaly -anomaly \
-ap2pl -ap2pl \
-ap2pl_lp -ap2pl_lp \
-ap2plx -ap2plx \
-ap2plx_lp -ap2plx_lp \
-asin -asin \
-atan -atan \
-atan2 -atan2 \
-bandpass -bandpass \
-beta -beta \
-boxavg -boxavg \
-cat -cat \
-cdiread -cdiread \
-cdiwrite -cdiwrite \
-change_e5lsm -change_e5lsm \
-change_e5mask -change_e5mask \
-change_e5slm -change_e5slm \
-chcode -chcode \
-chisquare -chisquare \
-chlevel -chlevel \
-chlevelc -chlevelc \
-chlevelv -chlevelv \
-chltype -chltype \
-chname -chname \
-chparam -chparam \
-chtabnum -chtabnum \
-chunit -chunit \
-chvar -chvar \
-cloudlayer -cloudlayer \
-cmd -cmd \
-cmor -cmor \
-collgrid -collgrid \
-com -com \
-command -command \
-complextorect -complextorect \
-consecsum -consecsum \
-consects -consects \
-const -const \
-conv_cmor_table -conv_cmor_table \
-copy -copy \
-cos -cos \
-coshill -coshill \
-covar0 -covar0 \
-covar0r -covar0r \
-dayavg -dayavg \
-daycount -daycount \
-daylogs -daylogs \
-daymax -daymax \
-daymean -daymean \
-daymin -daymin \
-daypctl -daypctl \
-daystd -daystd \
-daystd1 -daystd1 \
-daysum -daysum \
-dayvar -dayvar \
-dayvar1 -dayvar1 \
-del29feb -del29feb \
-delcode -delcode \
-delday -delday \
-delete -delete \
-delname -delname \
-delparam -delparam \
-deltap -deltap \
-deltap_fl -deltap_fl \
-delvar -delvar \
-detrend -detrend \
-diff -diff \
-diffc -diffc \
-diffn -diffn \
-diffp -diffp \
-diffv -diffv \
-distgrid -distgrid \
-div -div \
-divc -divc \
-divcoslat -divcoslat \
-divdpm -divdpm \
-divdpy -divdpy \
-dumplogo -dumplogo \
-dumplogs -dumplogs \
-dumpmap -dumpmap \
-duplicate -duplicate \
-dv2ps -dv2ps \
-dv2uv -dv2uv \
-dv2uvl -dv2uvl \
-eca_cdd -eca_cdd \
-eca_cfd -eca_cfd \
-eca_csu -eca_csu \
-eca_cwd -eca_cwd \
-eca_cwdi -eca_cwdi \
-eca_cwfi -eca_cwfi \
-eca_etr -eca_etr \
-eca_fd -eca_fd \
-eca_gsl -eca_gsl \
-eca_hd -eca_hd \
-eca_hwdi -eca_hwdi \
-eca_hwfi -eca_hwfi \
-eca_id -eca_id \
-eca_pd -eca_pd \
-eca_r10mm -eca_r10mm \
-eca_r1mm -eca_r1mm \
-eca_r20mm -eca_r20mm \
-eca_r75p -eca_r75p \
-eca_r75ptot -eca_r75ptot \
-eca_r90p -eca_r90p \
-eca_r90ptot -eca_r90ptot \
-eca_r95p -eca_r95p \
-eca_r95ptot -eca_r95ptot \
-eca_r99p -eca_r99p \
-eca_r99ptot -eca_r99ptot \
-eca_rr1 -eca_rr1 \
-eca_rx1day -eca_rx1day \
-eca_rx5day -eca_rx5day \
-eca_sdii -eca_sdii \
-eca_su -eca_su \
-eca_tg10p -eca_tg10p \
-eca_tg90p -eca_tg90p \
-eca_tn10p -eca_tn10p \
-eca_tn90p -eca_tn90p \
-eca_tr -eca_tr \
-eca_tx10p -eca_tx10p \
-eca_tx90p -eca_tx90p \
-enlarge -enlarge \
-enlargegrid -enlargegrid \
-ensavg -ensavg \
-ensbrs -ensbrs \
-enscrps -enscrps \
-ensmax -ensmax \
-ensmean -ensmean \
-ensmin -ensmin \
-enspctl -enspctl \
-ensrkhist_space -ensrkhist_space \
-ensrkhist_time -ensrkhist_time \
-ensrkhistspace -ensrkhistspace \
-ensrkhisttime -ensrkhisttime \
-ensroc -ensroc \
-ensstd -ensstd \
-ensstd1 -ensstd1 \
-enssum -enssum \
-ensvar -ensvar \
-ensvar1 -ensvar1 \
-eof -eof \
-eof3d -eof3d \
-eof3dspatial -eof3dspatial \
-eof3dtime -eof3dtime \
-eofcoeff -eofcoeff \
-eofcoeff3d -eofcoeff3d \
-eofspatial -eofspatial \
-eoftime -eoftime \
-eq -eq \
-eqc -eqc \
-exp -exp \
-export_e5ml -export_e5ml \
-export_e5res -export_e5res \
-expr -expr \
-exprf -exprf \
-fc2gp -fc2gp \
-fc2sp -fc2sp \
-fdns -fdns \
-filedes -filedes \
-fillmiss -fillmiss \
-fillmiss2 -fillmiss2 \
-fisher -fisher \
-fldavg -fldavg \
-fldcor -fldcor \
-fldcovar -fldcovar \
-fldmax -fldmax \
-fldmean -fldmean \
-fldmin -fldmin \
-fldpctl -fldpctl \
-fldrms -fldrms \
-fldstd -fldstd \
-fldstd1 -fldstd1 \
-fldsum -fldsum \
-fldvar -fldvar \
-fldvar1 -fldvar1 \
+--operators ---operators \
+Use -Use \
+a -a \
+all -all \
 for -for \
-fourier -fourier \
-fpressure -fpressure \
-gather -gather \
-ge -ge \
-gec -gec \
-genbic -genbic \
-genbil -genbil \
-gencon -gencon \
-gencon2 -gencon2 \
-gendis -gendis \
-gengrid -gengrid \
-genlaf -genlaf \
-genlevelbounds -genlevelbounds \
-gennn -gennn \
-genycon -genycon \
-geopotheight -geopotheight \
-ggstat -ggstat \
-ggstats -ggstats \
-gheight -gheight \
-globavg -globavg \
-gp2fc -gp2fc \
-gp2sp -gp2sp \
-gp2spl -gp2spl \
-gradsdes -gradsdes \
-gridarea -gridarea \
-gridboxavg -gridboxavg \
-gridboxmax -gridboxmax \
-gridboxmean -gridboxmean \
-gridboxmin -gridboxmin \
-gridboxstd -gridboxstd \
-gridboxstd1 -gridboxstd1 \
-gridboxsum -gridboxsum \
-gridboxvar -gridboxvar \
-gridboxvar1 -gridboxvar1 \
-griddes -griddes \
-griddes2 -griddes2 \
-griddx -griddx \
-griddy -griddy \
-gridmask -gridmask \
-gridverify -gridverify \
-gridweights -gridweights \
-gt -gt \
-gtc -gtc \
-harmonic -harmonic \
-highpass -highpass \
-histcount -histcount \
-histfreq -histfreq \
-histmean -histmean \
-histsum -histsum \
-houravg -houravg \
-hourcount -hourcount \
-hourmax -hourmax \
-hourmean -hourmean \
-hourmin -hourmin \
-hourpctl -hourpctl \
-hourstd -hourstd \
-hourstd1 -hourstd1 \
-hoursum -hoursum \
-hourvar -hourvar \
-hourvar1 -hourvar1 \
-hpressure -hpressure \
-hurr -hurr \
-ifnotthen -ifnotthen \
-ifnotthenc -ifnotthenc \
-ifthen -ifthen \
-ifthenc -ifthenc \
-ifthenelse -ifthenelse \
-import_amsr -import_amsr \
-import_binary -import_binary \
-import_cmsaf -import_cmsaf \
-import_e5ml -import_e5ml \
-import_e5res -import_e5res \
-import_grads -import_grads \
-import_obs -import_obs \
-imtocomplex -imtocomplex \
-info -info \
-infoc -infoc \
-infon -infon \
-infop -infop \
-infos -infos \
-infov -infov \
-input -input \
-inputext -inputext \
-inputsrv -inputsrv \
-int -int \
-interpolate -interpolate \
-intgrid -intgrid \
-intgridbil -intgridbil \
-intgridcon -intgridcon \
-intgridtraj -intgridtraj \
-intlevel -intlevel \
-intlevel3d -intlevel3d \
-intlevelx -intlevelx \
-intlevelx3d -intlevelx3d \
-intntime -intntime \
-intpoint -intpoint \
-inttime -inttime \
-intyear -intyear \
-invertlat -invertlat \
-invertlatdata -invertlatdata \
-invertlatdes -invertlatdes \
-invertlev -invertlev \
-invertlon -invertlon \
-invertlondata -invertlondata \
-invertlondes -invertlondes \
-isosurface -isosurface \
-le -le \
-lec -lec \
-lmavg -lmavg \
-lmean -lmean \
-lmmean -lmmean \
-lmstd -lmstd \
-ln -ln \
-log -log \
-log10 -log10 \
-lowpass -lowpass \
-lsmean -lsmean \
-lt -lt \
-ltc -ltc \
-map -map \
-mask -mask \
-maskindexbox -maskindexbox \
-masklonlatbox -masklonlatbox \
-maskregion -maskregion \
-mastrfu -mastrfu \
-max -max \
-meandiff2test -meandiff2test \
-meravg -meravg \
-merge -merge \
-mergegrid -mergegrid \
-mergetime -mergetime \
-mermax -mermax \
-mermean -mermean \
-mermin -mermin \
-merpctl -merpctl \
-merstd -merstd \
-merstd1 -merstd1 \
-mersum -mersum \
-mervar -mervar \
-mervar1 -mervar1 \
-min -min \
-ml2hl -ml2hl \
-ml2hl_lp -ml2hl_lp \
-ml2hlx -ml2hlx \
-ml2hlx_lp -ml2hlx_lp \
-ml2pl -ml2pl \
-ml2pl_lp -ml2pl_lp \
-ml2plx -ml2plx \
-ml2plx_lp -ml2plx_lp \
-mod -mod \
-monadd -monadd \
-monavg -monavg \
-moncount -moncount \
-mondiv -mondiv \
-monlogs -monlogs \
-monmax -monmax \
-monmean -monmean \
-monmin -monmin \
-monmul -monmul \
-monpctl -monpctl \
-monstd -monstd \
-monstd1 -monstd1 \
-monsub -monsub \
-monsum -monsum \
-monvar -monvar \
-monvar1 -monvar1 \
-mrotuv -mrotuv \
-mrotuvb -mrotuvb \
-mul -mul \
-mulc -mulc \
-mulcoslat -mulcoslat \
-muldoy -muldoy \
-muldpm -muldpm \
-muldpy -muldpy \
-ncode -ncode \
-ncode -ncode \
-ncopy -ncopy \
-ndate -ndate \
-ne -ne \
-nec -nec \
-nint -nint \
-nlevel -nlevel \
-nmltest -nmltest \
-nmon -nmon \
-normal -normal \
-npar -npar \
-ntime -ntime \
-nvar -nvar \
-nyear -nyear \
-output -output \
-outputarr -outputarr \
-outputbounds -outputbounds \
-outputboundscpt -outputboundscpt \
-outputcenter -outputcenter \
-outputcenter2 -outputcenter2 \
-outputcentercpt -outputcentercpt \
-outputext -outputext \
-outputf -outputf \
-outputfld -outputfld \
-outputint -outputint \
-outputkey -outputkey \
-outputsrv -outputsrv \
-outputtab -outputtab \
-outputtri -outputtri \
-outputts -outputts \
-outputvector -outputvector \
-outputvrml -outputvrml \
-outputxyz -outputxyz \
-pack -pack \
-pardes -pardes \
-pardup -pardup \
-parmul -parmul \
-partab -partab \
-partab2 -partab2 \
-pinfo -pinfo \
-pinfov -pinfov \
-pow -pow \
-pressure_fl -pressure_fl \
-pressure_hl -pressure_hl \
-random -random \
-read_cmor_table -read_cmor_table \
-read_e5ml -read_e5ml \
-reci -reci \
-regres -regres \
-remap -remap \
-remapbic -remapbic \
-remapbil -remapbil \
-remapcon -remapcon \
-remapcon1 -remapcon1 \
-remapcon2 -remapcon2 \
-remapdis -remapdis \
-remapdis1 -remapdis1 \
-remapeta -remapeta \
-remapeta_s -remapeta_s \
-remapeta_z -remapeta_z \
-remaplaf -remaplaf \
-remapnn -remapnn \
-remapsum -remapsum \
-remapycon -remapycon \
-replace -replace \
-retocomplex -retocomplex \
-rhopot -rhopot \
-rotuvb -rotuvb \
-runavg -runavg \
-runmax -runmax \
-runmean -runmean \
-runmin -runmin \
-runpctl -runpctl \
-runstd -runstd \
-runstd1 -runstd1 \
-runsum -runsum \
-runvar -runvar \
-runvar1 -runvar1 \
-scalllogo -scalllogo \
-scatter -scatter \
-sealevelpressure -sealevelpressure \
-seasavg -seasavg \
-seascount -seascount \
-seasmax -seasmax \
-seasmean -seasmean \
-seasmin -seasmin \
-seaspctl -seaspctl \
-seasstd -seasstd \
-seasstd1 -seasstd1 \
-seassum -seassum \
-seasvar -seasvar \
-seasvar1 -seasvar1 \
-seinfo -seinfo \
-seinfoc -seinfoc \
-seinfon -seinfon \
-seinfop -seinfop \
-selall -selall \
-selcode -selcode \
-seldate -seldate \
-selday -selday \
-select -select \
-selgrid -selgrid \
-selgridname -selgridname \
-selhour -selhour \
-selindexbox -selindexbox \
-sellevel -sellevel \
-sellevidx -sellevidx \
-sellonlatbox -sellonlatbox \
-selltype -selltype \
-selmon -selmon \
-selname -selname \
-seloperator -seloperator \
-selparam -selparam \
-selrec -selrec \
-selseas -selseas \
-selsmon -selsmon \
-selstdname -selstdname \
-seltabnum -seltabnum \
-seltime -seltime \
-seltimestep -seltimestep \
-selvar -selvar \
-selyear -selyear \
-selzaxis -selzaxis \
-selzaxisname -selzaxisname \
-setcalendar -setcalendar \
-setcindexbox -setcindexbox \
-setclonlatbox -setclonlatbox \
-setcode -setcode \
-setctomiss -setctomiss \
-setdate -setdate \
-setday -setday \
-setgatt -setgatt \
-setgatts -setgatts \
-setgrid -setgrid \
-setgridarea -setgridarea \
-setgridmask -setgridmask \
-setgridnumber -setgridnumber \
-setgridtype -setgridtype \
-setgriduri -setgriduri \
-sethalo -sethalo \
-setlevel -setlevel \
-setltype -setltype \
-setmisstoc -setmisstoc \
-setmisstodis -setmisstodis \
-setmisstonn -setmisstonn \
-setmissval -setmissval \
-setmon -setmon \
-setname -setname \
-setparam -setparam \
-setpartab -setpartab \
-setpartabc -setpartabc \
-setpartabn -setpartabn \
-setpartabp -setpartabp \
-setpartabv -setpartabv \
-setrcaname -setrcaname \
-setreftime -setreftime \
-setrtoc -setrtoc \
-setrtoc2 -setrtoc2 \
-setrtomiss -setrtomiss \
-settabnum -settabnum \
-settaxis -settaxis \
-settime -settime \
-settunits -settunits \
-setunit -setunit \
-setvals -setvals \
-setvar -setvar \
-setvrange -setvrange \
-setyear -setyear \
-setzaxis -setzaxis \
-shifttime -shifttime \
-showcode -showcode \
-showdate -showdate \
-showformat -showformat \
-showlevel -showlevel \
-showltype -showltype \
-showmon -showmon \
-showname -showname \
-showparam -showparam \
-showstdname -showstdname \
-showtime -showtime \
-showtimestamp -showtimestamp \
-showunit -showunit \
-showvar -showvar \
-showyear -showyear \
-sin -sin \
-sincos -sincos \
-sinfo -sinfo \
-sinfoc -sinfoc \
-sinfon -sinfon \
-sinfop -sinfop \
-sinfov -sinfov \
-smemlogo -smemlogo \
-smooth9 -smooth9 \
-snamelogo -snamelogo \
-sort -sort \
-sortcode -sortcode \
-sortlevel -sortlevel \
-sortname -sortname \
-sortparam -sortparam \
-sorttaxis -sorttaxis \
-sorttimestamp -sorttimestamp \
-sortvar -sortvar \
-sp2fc -sp2fc \
-sp2gp -sp2gp \
-sp2gpl -sp2gpl \
-sp2sp -sp2sp \
-spartab -spartab \
-spcut -spcut \
-specinfo -specinfo \
-spectrum -spectrum \
-sperclogo -sperclogo \
-splitcode -splitcode \
-splitday -splitday \
-splitgrid -splitgrid \
-splithour -splithour \
-splitlevel -splitlevel \
-splitmon -splitmon \
-splitname -splitname \
-splitparam -splitparam \
-splitrec -splitrec \
-splitseas -splitseas \
-splitsel -splitsel \
-splittabnum -splittabnum \
-splitvar -splitvar \
-splityear -splityear \
-splityearmon -splityearmon \
-splitzaxis -splitzaxis \
-sqr -sqr \
-sqrt -sqrt \
-ssopar -ssopar \
-stdatm -stdatm \
-stimelogo -stimelogo \
-strbre -strbre \
-strgal -strgal \
-strwin -strwin \
-studentt -studentt \
-sub -sub \
-subc -subc \
-subtrend -subtrend \
-szip -szip \
-tan -tan \
-tee -tee \
-temp -temp \
-template1 -template1 \
-template2 -template2 \
-test -test \
-test2 -test2 \
-testcellsearch -testcellsearch \
-testdata -testdata \
-testpointsearch -testpointsearch \
-thinout -thinout \
-timavg -timavg \
-timcor -timcor \
-timcount -timcount \
-timcovar -timcovar \
-timmax -timmax \
-timmean -timmean \
-timmin -timmin \
-timpctl -timpctl \
-timselavg -timselavg \
-timselmax -timselmax \
-timselmean -timselmean \
-timselmin -timselmin \
-timselpctl -timselpctl \
-timselstd -timselstd \
-timselstd1 -timselstd1 \
-timselsum -timselsum \
-timselvar -timselvar \
-timselvar1 -timselvar1 \
-timsort -timsort \
-timstd -timstd \
-timstd1 -timstd1 \
-timsum -timsum \
-timvar -timvar \
-timvar1 -timvar1 \
-tinfo -tinfo \
-topo -topo \
-tpnhalo -tpnhalo \
-transxy -transxy \
-trend -trend \
-trms -trms \
-tstepcount -tstepcount \
-unsetgridmask -unsetgridmask \
-uv2dv -uv2dv \
-uv2dvl -uv2dvl \
-vardes -vardes \
-vardup -vardup \
-varmul -varmul \
-varquot2test -varquot2test \
-varrms -varrms \
-vct -vct \
-vct2 -vct2 \
-vertavg -vertavg \
-vertcum -vertcum \
-vertcumhl -vertcumhl \
-vertint -vertint \
-vertmax -vertmax \
-vertmean -vertmean \
-vertmin -vertmin \
-vertstd -vertstd \
-vertstd1 -vertstd1 \
-vertsum -vertsum \
-vertvar -vertvar \
-vertvar1 -vertvar1 \
-vertwind -vertwind \
-vlist -vlist \
-wct -wct \
-write_e5ml -write_e5ml \
-writegrid -writegrid \
-writerandom -writerandom \
-xmonavg -xmonavg \
-xmonmax -xmonmax \
-xmonmean -xmonmean \
-xmonmin -xmonmin \
-xmonstd -xmonstd \
-xmonstd1 -xmonstd1 \
-xmonsum -xmonsum \
-xmonvar -xmonvar \
-xmonvar1 -xmonvar1 \
-xtimavg -xtimavg \
-xtimmax -xtimmax \
-xtimmean -xtimmean \
-xtimmin -xtimmin \
-xtimstd -xtimstd \
-xtimstd1 -xtimstd1 \
-xtimsum -xtimsum \
-xtimvar -xtimvar \
-xtimvar1 -xtimvar1 \
-xyearavg -xyearavg \
-xyearmax -xyearmax \
-xyearmean -xyearmean \
-xyearmin -xyearmin \
-xyearstd -xyearstd \
-xyearstd1 -xyearstd1 \
-xyearsum -xyearsum \
-xyearvar -xyearvar \
-xyearvar1 -xyearvar1 \
-yarbil -yarbil \
-yarcon -yarcon \
-yarnn -yarnn \
-ydayadd -ydayadd \
-ydayavg -ydayavg \
-ydaydiv -ydaydiv \
-ydaymax -ydaymax \
-ydaymean -ydaymean \
-ydaymin -ydaymin \
-ydaymul -ydaymul \
-ydaypctl -ydaypctl \
-ydaystd -ydaystd \
-ydaystd1 -ydaystd1 \
-ydaysub -ydaysub \
-ydaysum -ydaysum \
-ydayvar -ydayvar \
-ydayvar1 -ydayvar1 \
-ydrunavg -ydrunavg \
-ydrunmax -ydrunmax \
-ydrunmean -ydrunmean \
-ydrunmin -ydrunmin \
-ydrunpctl -ydrunpctl \
-ydrunstd -ydrunstd \
-ydrunstd1 -ydrunstd1 \
-ydrunsum -ydrunsum \
-ydrunvar -ydrunvar \
-ydrunvar1 -ydrunvar1 \
-yearavg -yearavg \
-yearcount -yearcount \
-yearmax -yearmax \
-yearmean -yearmean \
-yearmin -yearmin \
-yearmonavg -yearmonavg \
-yearmonmean -yearmonmean \
-yearpctl -yearpctl \
-yearstd -yearstd \
-yearstd1 -yearstd1 \
-yearsum -yearsum \
-yearvar -yearvar \
-yearvar1 -yearvar1 \
-yhouradd -yhouradd \
-yhouravg -yhouravg \
-yhourdiv -yhourdiv \
-yhourmax -yhourmax \
-yhourmean -yhourmean \
-yhourmin -yhourmin \
-yhourmul -yhourmul \
-yhourstd -yhourstd \
-yhourstd1 -yhourstd1 \
-yhoursub -yhoursub \
-yhoursum -yhoursum \
-yhourvar -yhourvar \
-yhourvar1 -yhourvar1 \
-ymonadd -ymonadd \
-ymonavg -ymonavg \
-ymondiv -ymondiv \
-ymonmax -ymonmax \
-ymonmean -ymonmean \
-ymonmin -ymonmin \
-ymonmul -ymonmul \
-ymonpctl -ymonpctl \
-ymonstd -ymonstd \
-ymonstd1 -ymonstd1 \
-ymonsub -ymonsub \
-ymonsum -ymonsum \
-ymonvar -ymonvar \
-ymonvar1 -ymonvar1 \
-yseasadd -yseasadd \
-yseasavg -yseasavg \
-yseasdiv -yseasdiv \
-yseasmax -yseasmax \
-yseasmean -yseasmean \
-yseasmin -yseasmin \
-yseasmul -yseasmul \
-yseaspctl -yseaspctl \
-yseasstd -yseasstd \
-yseasstd1 -yseasstd1 \
-yseassub -yseassub \
-yseassum -yseassum \
-yseasvar -yseasvar \
-yseasvar1 -yseasvar1 \
-zaxisdes -zaxisdes \
-zonavg -zonavg \
-zonmax -zonmax \
-zonmean -zonmean \
-zonmin -zonmin \
-zonpctl -zonpctl \
-zonrange -zonrange \
-zonstd -zonstd \
-zonstd1 -zonstd1 \
-zonsum -zonsum \
-zonvar -zonvar \
-zonvar1 -zonvar1 \
+list -list \
+of -of \
+operators. -operators. \
+option -option \
 " -f cdo
diff --git a/contrib/cdoCompletion.tcsh b/contrib/cdoCompletion.tcsh
index 839531f..ab97758 100644
--- a/contrib/cdoCompletion.tcsh
+++ b/contrib/cdoCompletion.tcsh
@@ -4,6 +4,8 @@ set cdoCmpl = (\
 - \
 - \
 - \
+- \
+- \
 L \
 M \
 O \
@@ -25,795 +27,13 @@ s \
 t \
 v \
 z \
-abs \
-acos \
-add \
-addc \
-adipot \
-adisit \
-aexpr \
-aexprf \
-after \
-afterburner \
-anomaly \
-ap2pl \
-ap2pl_lp \
-ap2plx \
-ap2plx_lp \
-asin \
-atan \
-atan2 \
-bandpass \
-beta \
-boxavg \
-cat \
-cdiread \
-cdiwrite \
-change_e5lsm \
-change_e5mask \
-change_e5slm \
-chcode \
-chisquare \
-chlevel \
-chlevelc \
-chlevelv \
-chltype \
-chname \
-chparam \
-chtabnum \
-chunit \
-chvar \
-cloudlayer \
-cmd \
-cmor \
-collgrid \
-com \
-command \
-complextorect \
-consecsum \
-consects \
-const \
-conv_cmor_table \
-copy \
-cos \
-coshill \
-covar0 \
-covar0r \
-dayavg \
-daycount \
-daylogs \
-daymax \
-daymean \
-daymin \
-daypctl \
-daystd \
-daystd1 \
-daysum \
-dayvar \
-dayvar1 \
-del29feb \
-delcode \
-delday \
-delete \
-delname \
-delparam \
-deltap \
-deltap_fl \
-delvar \
-detrend \
-diff \
-diffc \
-diffn \
-diffp \
-diffv \
-distgrid \
-div \
-divc \
-divcoslat \
-divdpm \
-divdpy \
-dumplogo \
-dumplogs \
-dumpmap \
-duplicate \
-dv2ps \
-dv2uv \
-dv2uvl \
-eca_cdd \
-eca_cfd \
-eca_csu \
-eca_cwd \
-eca_cwdi \
-eca_cwfi \
-eca_etr \
-eca_fd \
-eca_gsl \
-eca_hd \
-eca_hwdi \
-eca_hwfi \
-eca_id \
-eca_pd \
-eca_r10mm \
-eca_r1mm \
-eca_r20mm \
-eca_r75p \
-eca_r75ptot \
-eca_r90p \
-eca_r90ptot \
-eca_r95p \
-eca_r95ptot \
-eca_r99p \
-eca_r99ptot \
-eca_rr1 \
-eca_rx1day \
-eca_rx5day \
-eca_sdii \
-eca_su \
-eca_tg10p \
-eca_tg90p \
-eca_tn10p \
-eca_tn90p \
-eca_tr \
-eca_tx10p \
-eca_tx90p \
-enlarge \
-enlargegrid \
-ensavg \
-ensbrs \
-enscrps \
-ensmax \
-ensmean \
-ensmin \
-enspctl \
-ensrkhist_space \
-ensrkhist_time \
-ensrkhistspace \
-ensrkhisttime \
-ensroc \
-ensstd \
-ensstd1 \
-enssum \
-ensvar \
-ensvar1 \
-eof \
-eof3d \
-eof3dspatial \
-eof3dtime \
-eofcoeff \
-eofcoeff3d \
-eofspatial \
-eoftime \
-eq \
-eqc \
-exp \
-export_e5ml \
-export_e5res \
-expr \
-exprf \
-fc2gp \
-fc2sp \
-fdns \
-filedes \
-fillmiss \
-fillmiss2 \
-fisher \
-fldavg \
-fldcor \
-fldcovar \
-fldmax \
-fldmean \
-fldmin \
-fldpctl \
-fldrms \
-fldstd \
-fldstd1 \
-fldsum \
-fldvar \
-fldvar1 \
+--operators \
+Use \
+a \
+all \
 for \
-fourier \
-fpressure \
-gather \
-ge \
-gec \
-genbic \
-genbil \
-gencon \
-gencon2 \
-gendis \
-gengrid \
-genlaf \
-genlevelbounds \
-gennn \
-genycon \
-geopotheight \
-ggstat \
-ggstats \
-gheight \
-globavg \
-gp2fc \
-gp2sp \
-gp2spl \
-gradsdes \
-gridarea \
-gridboxavg \
-gridboxmax \
-gridboxmean \
-gridboxmin \
-gridboxstd \
-gridboxstd1 \
-gridboxsum \
-gridboxvar \
-gridboxvar1 \
-griddes \
-griddes2 \
-griddx \
-griddy \
-gridmask \
-gridverify \
-gridweights \
-gt \
-gtc \
-harmonic \
-highpass \
-histcount \
-histfreq \
-histmean \
-histsum \
-houravg \
-hourcount \
-hourmax \
-hourmean \
-hourmin \
-hourpctl \
-hourstd \
-hourstd1 \
-hoursum \
-hourvar \
-hourvar1 \
-hpressure \
-hurr \
-ifnotthen \
-ifnotthenc \
-ifthen \
-ifthenc \
-ifthenelse \
-import_amsr \
-import_binary \
-import_cmsaf \
-import_e5ml \
-import_e5res \
-import_grads \
-import_obs \
-imtocomplex \
-info \
-infoc \
-infon \
-infop \
-infos \
-infov \
-input \
-inputext \
-inputsrv \
-int \
-interpolate \
-intgrid \
-intgridbil \
-intgridcon \
-intgridtraj \
-intlevel \
-intlevel3d \
-intlevelx \
-intlevelx3d \
-intntime \
-intpoint \
-inttime \
-intyear \
-invertlat \
-invertlatdata \
-invertlatdes \
-invertlev \
-invertlon \
-invertlondata \
-invertlondes \
-isosurface \
-le \
-lec \
-lmavg \
-lmean \
-lmmean \
-lmstd \
-ln \
-log \
-log10 \
-lowpass \
-lsmean \
-lt \
-ltc \
-map \
-mask \
-maskindexbox \
-masklonlatbox \
-maskregion \
-mastrfu \
-max \
-meandiff2test \
-meravg \
-merge \
-mergegrid \
-mergetime \
-mermax \
-mermean \
-mermin \
-merpctl \
-merstd \
-merstd1 \
-mersum \
-mervar \
-mervar1 \
-min \
-ml2hl \
-ml2hl_lp \
-ml2hlx \
-ml2hlx_lp \
-ml2pl \
-ml2pl_lp \
-ml2plx \
-ml2plx_lp \
-mod \
-monadd \
-monavg \
-moncount \
-mondiv \
-monlogs \
-monmax \
-monmean \
-monmin \
-monmul \
-monpctl \
-monstd \
-monstd1 \
-monsub \
-monsum \
-monvar \
-monvar1 \
-mrotuv \
-mrotuvb \
-mul \
-mulc \
-mulcoslat \
-muldoy \
-muldpm \
-muldpy \
-ncode \
-ncode \
-ncopy \
-ndate \
-ne \
-nec \
-nint \
-nlevel \
-nmltest \
-nmon \
-normal \
-npar \
-ntime \
-nvar \
-nyear \
-output \
-outputarr \
-outputbounds \
-outputboundscpt \
-outputcenter \
-outputcenter2 \
-outputcentercpt \
-outputext \
-outputf \
-outputfld \
-outputint \
-outputkey \
-outputsrv \
-outputtab \
-outputtri \
-outputts \
-outputvector \
-outputvrml \
-outputxyz \
-pack \
-pardes \
-pardup \
-parmul \
-partab \
-partab2 \
-pinfo \
-pinfov \
-pow \
-pressure_fl \
-pressure_hl \
-random \
-read_cmor_table \
-read_e5ml \
-reci \
-regres \
-remap \
-remapbic \
-remapbil \
-remapcon \
-remapcon1 \
-remapcon2 \
-remapdis \
-remapdis1 \
-remapeta \
-remapeta_s \
-remapeta_z \
-remaplaf \
-remapnn \
-remapsum \
-remapycon \
-replace \
-retocomplex \
-rhopot \
-rotuvb \
-runavg \
-runmax \
-runmean \
-runmin \
-runpctl \
-runstd \
-runstd1 \
-runsum \
-runvar \
-runvar1 \
-scalllogo \
-scatter \
-sealevelpressure \
-seasavg \
-seascount \
-seasmax \
-seasmean \
-seasmin \
-seaspctl \
-seasstd \
-seasstd1 \
-seassum \
-seasvar \
-seasvar1 \
-seinfo \
-seinfoc \
-seinfon \
-seinfop \
-selall \
-selcode \
-seldate \
-selday \
-select \
-selgrid \
-selgridname \
-selhour \
-selindexbox \
-sellevel \
-sellevidx \
-sellonlatbox \
-selltype \
-selmon \
-selname \
-seloperator \
-selparam \
-selrec \
-selseas \
-selsmon \
-selstdname \
-seltabnum \
-seltime \
-seltimestep \
-selvar \
-selyear \
-selzaxis \
-selzaxisname \
-setcalendar \
-setcindexbox \
-setclonlatbox \
-setcode \
-setctomiss \
-setdate \
-setday \
-setgatt \
-setgatts \
-setgrid \
-setgridarea \
-setgridmask \
-setgridnumber \
-setgridtype \
-setgriduri \
-sethalo \
-setlevel \
-setltype \
-setmisstoc \
-setmisstodis \
-setmisstonn \
-setmissval \
-setmon \
-setname \
-setparam \
-setpartab \
-setpartabc \
-setpartabn \
-setpartabp \
-setpartabv \
-setrcaname \
-setreftime \
-setrtoc \
-setrtoc2 \
-setrtomiss \
-settabnum \
-settaxis \
-settime \
-settunits \
-setunit \
-setvals \
-setvar \
-setvrange \
-setyear \
-setzaxis \
-shifttime \
-showcode \
-showdate \
-showformat \
-showlevel \
-showltype \
-showmon \
-showname \
-showparam \
-showstdname \
-showtime \
-showtimestamp \
-showunit \
-showvar \
-showyear \
-sin \
-sincos \
-sinfo \
-sinfoc \
-sinfon \
-sinfop \
-sinfov \
-smemlogo \
-smooth9 \
-snamelogo \
-sort \
-sortcode \
-sortlevel \
-sortname \
-sortparam \
-sorttaxis \
-sorttimestamp \
-sortvar \
-sp2fc \
-sp2gp \
-sp2gpl \
-sp2sp \
-spartab \
-spcut \
-specinfo \
-spectrum \
-sperclogo \
-splitcode \
-splitday \
-splitgrid \
-splithour \
-splitlevel \
-splitmon \
-splitname \
-splitparam \
-splitrec \
-splitseas \
-splitsel \
-splittabnum \
-splitvar \
-splityear \
-splityearmon \
-splitzaxis \
-sqr \
-sqrt \
-ssopar \
-stdatm \
-stimelogo \
-strbre \
-strgal \
-strwin \
-studentt \
-sub \
-subc \
-subtrend \
-szip \
-tan \
-tee \
-temp \
-template1 \
-template2 \
-test \
-test2 \
-testcellsearch \
-testdata \
-testpointsearch \
-thinout \
-timavg \
-timcor \
-timcount \
-timcovar \
-timmax \
-timmean \
-timmin \
-timpctl \
-timselavg \
-timselmax \
-timselmean \
-timselmin \
-timselpctl \
-timselstd \
-timselstd1 \
-timselsum \
-timselvar \
-timselvar1 \
-timsort \
-timstd \
-timstd1 \
-timsum \
-timvar \
-timvar1 \
-tinfo \
-topo \
-tpnhalo \
-transxy \
-trend \
-trms \
-tstepcount \
-unsetgridmask \
-uv2dv \
-uv2dvl \
-vardes \
-vardup \
-varmul \
-varquot2test \
-varrms \
-vct \
-vct2 \
-vertavg \
-vertcum \
-vertcumhl \
-vertint \
-vertmax \
-vertmean \
-vertmin \
-vertstd \
-vertstd1 \
-vertsum \
-vertvar \
-vertvar1 \
-vertwind \
-vlist \
-wct \
-write_e5ml \
-writegrid \
-writerandom \
-xmonavg \
-xmonmax \
-xmonmean \
-xmonmin \
-xmonstd \
-xmonstd1 \
-xmonsum \
-xmonvar \
-xmonvar1 \
-xtimavg \
-xtimmax \
-xtimmean \
-xtimmin \
-xtimstd \
-xtimstd1 \
-xtimsum \
-xtimvar \
-xtimvar1 \
-xyearavg \
-xyearmax \
-xyearmean \
-xyearmin \
-xyearstd \
-xyearstd1 \
-xyearsum \
-xyearvar \
-xyearvar1 \
-yarbil \
-yarcon \
-yarnn \
-ydayadd \
-ydayavg \
-ydaydiv \
-ydaymax \
-ydaymean \
-ydaymin \
-ydaymul \
-ydaypctl \
-ydaystd \
-ydaystd1 \
-ydaysub \
-ydaysum \
-ydayvar \
-ydayvar1 \
-ydrunavg \
-ydrunmax \
-ydrunmean \
-ydrunmin \
-ydrunpctl \
-ydrunstd \
-ydrunstd1 \
-ydrunsum \
-ydrunvar \
-ydrunvar1 \
-yearavg \
-yearcount \
-yearmax \
-yearmean \
-yearmin \
-yearmonavg \
-yearmonmean \
-yearpctl \
-yearstd \
-yearstd1 \
-yearsum \
-yearvar \
-yearvar1 \
-yhouradd \
-yhouravg \
-yhourdiv \
-yhourmax \
-yhourmean \
-yhourmin \
-yhourmul \
-yhourstd \
-yhourstd1 \
-yhoursub \
-yhoursum \
-yhourvar \
-yhourvar1 \
-ymonadd \
-ymonavg \
-ymondiv \
-ymonmax \
-ymonmean \
-ymonmin \
-ymonmul \
-ymonpctl \
-ymonstd \
-ymonstd1 \
-ymonsub \
-ymonsum \
-ymonvar \
-ymonvar1 \
-yseasadd \
-yseasavg \
-yseasdiv \
-yseasmax \
-yseasmean \
-yseasmin \
-yseasmul \
-yseaspctl \
-yseasstd \
-yseasstd1 \
-yseassub \
-yseassum \
-yseasvar \
-yseasvar1 \
-zaxisdes \
-zonavg \
-zonmax \
-zonmean \
-zonmin \
-zonpctl \
-zonrange \
-zonstd \
-zonstd1 \
-zonsum \
-zonvar \
-zonvar1 \
+list \
+of \
+operators. \
+option \
 ); complete cdo 'c/-/$cdoCmpl/' 'n/*/f/'
diff --git a/contrib/cdoCompletion.zsh b/contrib/cdoCompletion.zsh
index 7dc2836..af132a8 100644
--- a/contrib/cdoCompletion.zsh
+++ b/contrib/cdoCompletion.zsh
@@ -4,6 +4,8 @@ compctl -k "(
 -- \
 -- \
 -- \
+-- \
+-- \
 -L \
 -M \
 -O \
@@ -25,795 +27,13 @@ compctl -k "(
 -t \
 -v \
 -z \
-abs -abs \
-acos -acos \
-add -add \
-addc -addc \
-adipot -adipot \
-adisit -adisit \
-aexpr -aexpr \
-aexprf -aexprf \
-after -after \
-afterburner -afterburner \
-anomaly -anomaly \
-ap2pl -ap2pl \
-ap2pl_lp -ap2pl_lp \
-ap2plx -ap2plx \
-ap2plx_lp -ap2plx_lp \
-asin -asin \
-atan -atan \
-atan2 -atan2 \
-bandpass -bandpass \
-beta -beta \
-boxavg -boxavg \
-cat -cat \
-cdiread -cdiread \
-cdiwrite -cdiwrite \
-change_e5lsm -change_e5lsm \
-change_e5mask -change_e5mask \
-change_e5slm -change_e5slm \
-chcode -chcode \
-chisquare -chisquare \
-chlevel -chlevel \
-chlevelc -chlevelc \
-chlevelv -chlevelv \
-chltype -chltype \
-chname -chname \
-chparam -chparam \
-chtabnum -chtabnum \
-chunit -chunit \
-chvar -chvar \
-cloudlayer -cloudlayer \
-cmd -cmd \
-cmor -cmor \
-collgrid -collgrid \
-com -com \
-command -command \
-complextorect -complextorect \
-consecsum -consecsum \
-consects -consects \
-const -const \
-conv_cmor_table -conv_cmor_table \
-copy -copy \
-cos -cos \
-coshill -coshill \
-covar0 -covar0 \
-covar0r -covar0r \
-dayavg -dayavg \
-daycount -daycount \
-daylogs -daylogs \
-daymax -daymax \
-daymean -daymean \
-daymin -daymin \
-daypctl -daypctl \
-daystd -daystd \
-daystd1 -daystd1 \
-daysum -daysum \
-dayvar -dayvar \
-dayvar1 -dayvar1 \
-del29feb -del29feb \
-delcode -delcode \
-delday -delday \
-delete -delete \
-delname -delname \
-delparam -delparam \
-deltap -deltap \
-deltap_fl -deltap_fl \
-delvar -delvar \
-detrend -detrend \
-diff -diff \
-diffc -diffc \
-diffn -diffn \
-diffp -diffp \
-diffv -diffv \
-distgrid -distgrid \
-div -div \
-divc -divc \
-divcoslat -divcoslat \
-divdpm -divdpm \
-divdpy -divdpy \
-dumplogo -dumplogo \
-dumplogs -dumplogs \
-dumpmap -dumpmap \
-duplicate -duplicate \
-dv2ps -dv2ps \
-dv2uv -dv2uv \
-dv2uvl -dv2uvl \
-eca_cdd -eca_cdd \
-eca_cfd -eca_cfd \
-eca_csu -eca_csu \
-eca_cwd -eca_cwd \
-eca_cwdi -eca_cwdi \
-eca_cwfi -eca_cwfi \
-eca_etr -eca_etr \
-eca_fd -eca_fd \
-eca_gsl -eca_gsl \
-eca_hd -eca_hd \
-eca_hwdi -eca_hwdi \
-eca_hwfi -eca_hwfi \
-eca_id -eca_id \
-eca_pd -eca_pd \
-eca_r10mm -eca_r10mm \
-eca_r1mm -eca_r1mm \
-eca_r20mm -eca_r20mm \
-eca_r75p -eca_r75p \
-eca_r75ptot -eca_r75ptot \
-eca_r90p -eca_r90p \
-eca_r90ptot -eca_r90ptot \
-eca_r95p -eca_r95p \
-eca_r95ptot -eca_r95ptot \
-eca_r99p -eca_r99p \
-eca_r99ptot -eca_r99ptot \
-eca_rr1 -eca_rr1 \
-eca_rx1day -eca_rx1day \
-eca_rx5day -eca_rx5day \
-eca_sdii -eca_sdii \
-eca_su -eca_su \
-eca_tg10p -eca_tg10p \
-eca_tg90p -eca_tg90p \
-eca_tn10p -eca_tn10p \
-eca_tn90p -eca_tn90p \
-eca_tr -eca_tr \
-eca_tx10p -eca_tx10p \
-eca_tx90p -eca_tx90p \
-enlarge -enlarge \
-enlargegrid -enlargegrid \
-ensavg -ensavg \
-ensbrs -ensbrs \
-enscrps -enscrps \
-ensmax -ensmax \
-ensmean -ensmean \
-ensmin -ensmin \
-enspctl -enspctl \
-ensrkhist_space -ensrkhist_space \
-ensrkhist_time -ensrkhist_time \
-ensrkhistspace -ensrkhistspace \
-ensrkhisttime -ensrkhisttime \
-ensroc -ensroc \
-ensstd -ensstd \
-ensstd1 -ensstd1 \
-enssum -enssum \
-ensvar -ensvar \
-ensvar1 -ensvar1 \
-eof -eof \
-eof3d -eof3d \
-eof3dspatial -eof3dspatial \
-eof3dtime -eof3dtime \
-eofcoeff -eofcoeff \
-eofcoeff3d -eofcoeff3d \
-eofspatial -eofspatial \
-eoftime -eoftime \
-eq -eq \
-eqc -eqc \
-exp -exp \
-export_e5ml -export_e5ml \
-export_e5res -export_e5res \
-expr -expr \
-exprf -exprf \
-fc2gp -fc2gp \
-fc2sp -fc2sp \
-fdns -fdns \
-filedes -filedes \
-fillmiss -fillmiss \
-fillmiss2 -fillmiss2 \
-fisher -fisher \
-fldavg -fldavg \
-fldcor -fldcor \
-fldcovar -fldcovar \
-fldmax -fldmax \
-fldmean -fldmean \
-fldmin -fldmin \
-fldpctl -fldpctl \
-fldrms -fldrms \
-fldstd -fldstd \
-fldstd1 -fldstd1 \
-fldsum -fldsum \
-fldvar -fldvar \
-fldvar1 -fldvar1 \
+--operators ---operators \
+Use -Use \
+a -a \
+all -all \
 for -for \
-fourier -fourier \
-fpressure -fpressure \
-gather -gather \
-ge -ge \
-gec -gec \
-genbic -genbic \
-genbil -genbil \
-gencon -gencon \
-gencon2 -gencon2 \
-gendis -gendis \
-gengrid -gengrid \
-genlaf -genlaf \
-genlevelbounds -genlevelbounds \
-gennn -gennn \
-genycon -genycon \
-geopotheight -geopotheight \
-ggstat -ggstat \
-ggstats -ggstats \
-gheight -gheight \
-globavg -globavg \
-gp2fc -gp2fc \
-gp2sp -gp2sp \
-gp2spl -gp2spl \
-gradsdes -gradsdes \
-gridarea -gridarea \
-gridboxavg -gridboxavg \
-gridboxmax -gridboxmax \
-gridboxmean -gridboxmean \
-gridboxmin -gridboxmin \
-gridboxstd -gridboxstd \
-gridboxstd1 -gridboxstd1 \
-gridboxsum -gridboxsum \
-gridboxvar -gridboxvar \
-gridboxvar1 -gridboxvar1 \
-griddes -griddes \
-griddes2 -griddes2 \
-griddx -griddx \
-griddy -griddy \
-gridmask -gridmask \
-gridverify -gridverify \
-gridweights -gridweights \
-gt -gt \
-gtc -gtc \
-harmonic -harmonic \
-highpass -highpass \
-histcount -histcount \
-histfreq -histfreq \
-histmean -histmean \
-histsum -histsum \
-houravg -houravg \
-hourcount -hourcount \
-hourmax -hourmax \
-hourmean -hourmean \
-hourmin -hourmin \
-hourpctl -hourpctl \
-hourstd -hourstd \
-hourstd1 -hourstd1 \
-hoursum -hoursum \
-hourvar -hourvar \
-hourvar1 -hourvar1 \
-hpressure -hpressure \
-hurr -hurr \
-ifnotthen -ifnotthen \
-ifnotthenc -ifnotthenc \
-ifthen -ifthen \
-ifthenc -ifthenc \
-ifthenelse -ifthenelse \
-import_amsr -import_amsr \
-import_binary -import_binary \
-import_cmsaf -import_cmsaf \
-import_e5ml -import_e5ml \
-import_e5res -import_e5res \
-import_grads -import_grads \
-import_obs -import_obs \
-imtocomplex -imtocomplex \
-info -info \
-infoc -infoc \
-infon -infon \
-infop -infop \
-infos -infos \
-infov -infov \
-input -input \
-inputext -inputext \
-inputsrv -inputsrv \
-int -int \
-interpolate -interpolate \
-intgrid -intgrid \
-intgridbil -intgridbil \
-intgridcon -intgridcon \
-intgridtraj -intgridtraj \
-intlevel -intlevel \
-intlevel3d -intlevel3d \
-intlevelx -intlevelx \
-intlevelx3d -intlevelx3d \
-intntime -intntime \
-intpoint -intpoint \
-inttime -inttime \
-intyear -intyear \
-invertlat -invertlat \
-invertlatdata -invertlatdata \
-invertlatdes -invertlatdes \
-invertlev -invertlev \
-invertlon -invertlon \
-invertlondata -invertlondata \
-invertlondes -invertlondes \
-isosurface -isosurface \
-le -le \
-lec -lec \
-lmavg -lmavg \
-lmean -lmean \
-lmmean -lmmean \
-lmstd -lmstd \
-ln -ln \
-log -log \
-log10 -log10 \
-lowpass -lowpass \
-lsmean -lsmean \
-lt -lt \
-ltc -ltc \
-map -map \
-mask -mask \
-maskindexbox -maskindexbox \
-masklonlatbox -masklonlatbox \
-maskregion -maskregion \
-mastrfu -mastrfu \
-max -max \
-meandiff2test -meandiff2test \
-meravg -meravg \
-merge -merge \
-mergegrid -mergegrid \
-mergetime -mergetime \
-mermax -mermax \
-mermean -mermean \
-mermin -mermin \
-merpctl -merpctl \
-merstd -merstd \
-merstd1 -merstd1 \
-mersum -mersum \
-mervar -mervar \
-mervar1 -mervar1 \
-min -min \
-ml2hl -ml2hl \
-ml2hl_lp -ml2hl_lp \
-ml2hlx -ml2hlx \
-ml2hlx_lp -ml2hlx_lp \
-ml2pl -ml2pl \
-ml2pl_lp -ml2pl_lp \
-ml2plx -ml2plx \
-ml2plx_lp -ml2plx_lp \
-mod -mod \
-monadd -monadd \
-monavg -monavg \
-moncount -moncount \
-mondiv -mondiv \
-monlogs -monlogs \
-monmax -monmax \
-monmean -monmean \
-monmin -monmin \
-monmul -monmul \
-monpctl -monpctl \
-monstd -monstd \
-monstd1 -monstd1 \
-monsub -monsub \
-monsum -monsum \
-monvar -monvar \
-monvar1 -monvar1 \
-mrotuv -mrotuv \
-mrotuvb -mrotuvb \
-mul -mul \
-mulc -mulc \
-mulcoslat -mulcoslat \
-muldoy -muldoy \
-muldpm -muldpm \
-muldpy -muldpy \
-ncode -ncode \
-ncode -ncode \
-ncopy -ncopy \
-ndate -ndate \
-ne -ne \
-nec -nec \
-nint -nint \
-nlevel -nlevel \
-nmltest -nmltest \
-nmon -nmon \
-normal -normal \
-npar -npar \
-ntime -ntime \
-nvar -nvar \
-nyear -nyear \
-output -output \
-outputarr -outputarr \
-outputbounds -outputbounds \
-outputboundscpt -outputboundscpt \
-outputcenter -outputcenter \
-outputcenter2 -outputcenter2 \
-outputcentercpt -outputcentercpt \
-outputext -outputext \
-outputf -outputf \
-outputfld -outputfld \
-outputint -outputint \
-outputkey -outputkey \
-outputsrv -outputsrv \
-outputtab -outputtab \
-outputtri -outputtri \
-outputts -outputts \
-outputvector -outputvector \
-outputvrml -outputvrml \
-outputxyz -outputxyz \
-pack -pack \
-pardes -pardes \
-pardup -pardup \
-parmul -parmul \
-partab -partab \
-partab2 -partab2 \
-pinfo -pinfo \
-pinfov -pinfov \
-pow -pow \
-pressure_fl -pressure_fl \
-pressure_hl -pressure_hl \
-random -random \
-read_cmor_table -read_cmor_table \
-read_e5ml -read_e5ml \
-reci -reci \
-regres -regres \
-remap -remap \
-remapbic -remapbic \
-remapbil -remapbil \
-remapcon -remapcon \
-remapcon1 -remapcon1 \
-remapcon2 -remapcon2 \
-remapdis -remapdis \
-remapdis1 -remapdis1 \
-remapeta -remapeta \
-remapeta_s -remapeta_s \
-remapeta_z -remapeta_z \
-remaplaf -remaplaf \
-remapnn -remapnn \
-remapsum -remapsum \
-remapycon -remapycon \
-replace -replace \
-retocomplex -retocomplex \
-rhopot -rhopot \
-rotuvb -rotuvb \
-runavg -runavg \
-runmax -runmax \
-runmean -runmean \
-runmin -runmin \
-runpctl -runpctl \
-runstd -runstd \
-runstd1 -runstd1 \
-runsum -runsum \
-runvar -runvar \
-runvar1 -runvar1 \
-scalllogo -scalllogo \
-scatter -scatter \
-sealevelpressure -sealevelpressure \
-seasavg -seasavg \
-seascount -seascount \
-seasmax -seasmax \
-seasmean -seasmean \
-seasmin -seasmin \
-seaspctl -seaspctl \
-seasstd -seasstd \
-seasstd1 -seasstd1 \
-seassum -seassum \
-seasvar -seasvar \
-seasvar1 -seasvar1 \
-seinfo -seinfo \
-seinfoc -seinfoc \
-seinfon -seinfon \
-seinfop -seinfop \
-selall -selall \
-selcode -selcode \
-seldate -seldate \
-selday -selday \
-select -select \
-selgrid -selgrid \
-selgridname -selgridname \
-selhour -selhour \
-selindexbox -selindexbox \
-sellevel -sellevel \
-sellevidx -sellevidx \
-sellonlatbox -sellonlatbox \
-selltype -selltype \
-selmon -selmon \
-selname -selname \
-seloperator -seloperator \
-selparam -selparam \
-selrec -selrec \
-selseas -selseas \
-selsmon -selsmon \
-selstdname -selstdname \
-seltabnum -seltabnum \
-seltime -seltime \
-seltimestep -seltimestep \
-selvar -selvar \
-selyear -selyear \
-selzaxis -selzaxis \
-selzaxisname -selzaxisname \
-setcalendar -setcalendar \
-setcindexbox -setcindexbox \
-setclonlatbox -setclonlatbox \
-setcode -setcode \
-setctomiss -setctomiss \
-setdate -setdate \
-setday -setday \
-setgatt -setgatt \
-setgatts -setgatts \
-setgrid -setgrid \
-setgridarea -setgridarea \
-setgridmask -setgridmask \
-setgridnumber -setgridnumber \
-setgridtype -setgridtype \
-setgriduri -setgriduri \
-sethalo -sethalo \
-setlevel -setlevel \
-setltype -setltype \
-setmisstoc -setmisstoc \
-setmisstodis -setmisstodis \
-setmisstonn -setmisstonn \
-setmissval -setmissval \
-setmon -setmon \
-setname -setname \
-setparam -setparam \
-setpartab -setpartab \
-setpartabc -setpartabc \
-setpartabn -setpartabn \
-setpartabp -setpartabp \
-setpartabv -setpartabv \
-setrcaname -setrcaname \
-setreftime -setreftime \
-setrtoc -setrtoc \
-setrtoc2 -setrtoc2 \
-setrtomiss -setrtomiss \
-settabnum -settabnum \
-settaxis -settaxis \
-settime -settime \
-settunits -settunits \
-setunit -setunit \
-setvals -setvals \
-setvar -setvar \
-setvrange -setvrange \
-setyear -setyear \
-setzaxis -setzaxis \
-shifttime -shifttime \
-showcode -showcode \
-showdate -showdate \
-showformat -showformat \
-showlevel -showlevel \
-showltype -showltype \
-showmon -showmon \
-showname -showname \
-showparam -showparam \
-showstdname -showstdname \
-showtime -showtime \
-showtimestamp -showtimestamp \
-showunit -showunit \
-showvar -showvar \
-showyear -showyear \
-sin -sin \
-sincos -sincos \
-sinfo -sinfo \
-sinfoc -sinfoc \
-sinfon -sinfon \
-sinfop -sinfop \
-sinfov -sinfov \
-smemlogo -smemlogo \
-smooth9 -smooth9 \
-snamelogo -snamelogo \
-sort -sort \
-sortcode -sortcode \
-sortlevel -sortlevel \
-sortname -sortname \
-sortparam -sortparam \
-sorttaxis -sorttaxis \
-sorttimestamp -sorttimestamp \
-sortvar -sortvar \
-sp2fc -sp2fc \
-sp2gp -sp2gp \
-sp2gpl -sp2gpl \
-sp2sp -sp2sp \
-spartab -spartab \
-spcut -spcut \
-specinfo -specinfo \
-spectrum -spectrum \
-sperclogo -sperclogo \
-splitcode -splitcode \
-splitday -splitday \
-splitgrid -splitgrid \
-splithour -splithour \
-splitlevel -splitlevel \
-splitmon -splitmon \
-splitname -splitname \
-splitparam -splitparam \
-splitrec -splitrec \
-splitseas -splitseas \
-splitsel -splitsel \
-splittabnum -splittabnum \
-splitvar -splitvar \
-splityear -splityear \
-splityearmon -splityearmon \
-splitzaxis -splitzaxis \
-sqr -sqr \
-sqrt -sqrt \
-ssopar -ssopar \
-stdatm -stdatm \
-stimelogo -stimelogo \
-strbre -strbre \
-strgal -strgal \
-strwin -strwin \
-studentt -studentt \
-sub -sub \
-subc -subc \
-subtrend -subtrend \
-szip -szip \
-tan -tan \
-tee -tee \
-temp -temp \
-template1 -template1 \
-template2 -template2 \
-test -test \
-test2 -test2 \
-testcellsearch -testcellsearch \
-testdata -testdata \
-testpointsearch -testpointsearch \
-thinout -thinout \
-timavg -timavg \
-timcor -timcor \
-timcount -timcount \
-timcovar -timcovar \
-timmax -timmax \
-timmean -timmean \
-timmin -timmin \
-timpctl -timpctl \
-timselavg -timselavg \
-timselmax -timselmax \
-timselmean -timselmean \
-timselmin -timselmin \
-timselpctl -timselpctl \
-timselstd -timselstd \
-timselstd1 -timselstd1 \
-timselsum -timselsum \
-timselvar -timselvar \
-timselvar1 -timselvar1 \
-timsort -timsort \
-timstd -timstd \
-timstd1 -timstd1 \
-timsum -timsum \
-timvar -timvar \
-timvar1 -timvar1 \
-tinfo -tinfo \
-topo -topo \
-tpnhalo -tpnhalo \
-transxy -transxy \
-trend -trend \
-trms -trms \
-tstepcount -tstepcount \
-unsetgridmask -unsetgridmask \
-uv2dv -uv2dv \
-uv2dvl -uv2dvl \
-vardes -vardes \
-vardup -vardup \
-varmul -varmul \
-varquot2test -varquot2test \
-varrms -varrms \
-vct -vct \
-vct2 -vct2 \
-vertavg -vertavg \
-vertcum -vertcum \
-vertcumhl -vertcumhl \
-vertint -vertint \
-vertmax -vertmax \
-vertmean -vertmean \
-vertmin -vertmin \
-vertstd -vertstd \
-vertstd1 -vertstd1 \
-vertsum -vertsum \
-vertvar -vertvar \
-vertvar1 -vertvar1 \
-vertwind -vertwind \
-vlist -vlist \
-wct -wct \
-write_e5ml -write_e5ml \
-writegrid -writegrid \
-writerandom -writerandom \
-xmonavg -xmonavg \
-xmonmax -xmonmax \
-xmonmean -xmonmean \
-xmonmin -xmonmin \
-xmonstd -xmonstd \
-xmonstd1 -xmonstd1 \
-xmonsum -xmonsum \
-xmonvar -xmonvar \
-xmonvar1 -xmonvar1 \
-xtimavg -xtimavg \
-xtimmax -xtimmax \
-xtimmean -xtimmean \
-xtimmin -xtimmin \
-xtimstd -xtimstd \
-xtimstd1 -xtimstd1 \
-xtimsum -xtimsum \
-xtimvar -xtimvar \
-xtimvar1 -xtimvar1 \
-xyearavg -xyearavg \
-xyearmax -xyearmax \
-xyearmean -xyearmean \
-xyearmin -xyearmin \
-xyearstd -xyearstd \
-xyearstd1 -xyearstd1 \
-xyearsum -xyearsum \
-xyearvar -xyearvar \
-xyearvar1 -xyearvar1 \
-yarbil -yarbil \
-yarcon -yarcon \
-yarnn -yarnn \
-ydayadd -ydayadd \
-ydayavg -ydayavg \
-ydaydiv -ydaydiv \
-ydaymax -ydaymax \
-ydaymean -ydaymean \
-ydaymin -ydaymin \
-ydaymul -ydaymul \
-ydaypctl -ydaypctl \
-ydaystd -ydaystd \
-ydaystd1 -ydaystd1 \
-ydaysub -ydaysub \
-ydaysum -ydaysum \
-ydayvar -ydayvar \
-ydayvar1 -ydayvar1 \
-ydrunavg -ydrunavg \
-ydrunmax -ydrunmax \
-ydrunmean -ydrunmean \
-ydrunmin -ydrunmin \
-ydrunpctl -ydrunpctl \
-ydrunstd -ydrunstd \
-ydrunstd1 -ydrunstd1 \
-ydrunsum -ydrunsum \
-ydrunvar -ydrunvar \
-ydrunvar1 -ydrunvar1 \
-yearavg -yearavg \
-yearcount -yearcount \
-yearmax -yearmax \
-yearmean -yearmean \
-yearmin -yearmin \
-yearmonavg -yearmonavg \
-yearmonmean -yearmonmean \
-yearpctl -yearpctl \
-yearstd -yearstd \
-yearstd1 -yearstd1 \
-yearsum -yearsum \
-yearvar -yearvar \
-yearvar1 -yearvar1 \
-yhouradd -yhouradd \
-yhouravg -yhouravg \
-yhourdiv -yhourdiv \
-yhourmax -yhourmax \
-yhourmean -yhourmean \
-yhourmin -yhourmin \
-yhourmul -yhourmul \
-yhourstd -yhourstd \
-yhourstd1 -yhourstd1 \
-yhoursub -yhoursub \
-yhoursum -yhoursum \
-yhourvar -yhourvar \
-yhourvar1 -yhourvar1 \
-ymonadd -ymonadd \
-ymonavg -ymonavg \
-ymondiv -ymondiv \
-ymonmax -ymonmax \
-ymonmean -ymonmean \
-ymonmin -ymonmin \
-ymonmul -ymonmul \
-ymonpctl -ymonpctl \
-ymonstd -ymonstd \
-ymonstd1 -ymonstd1 \
-ymonsub -ymonsub \
-ymonsum -ymonsum \
-ymonvar -ymonvar \
-ymonvar1 -ymonvar1 \
-yseasadd -yseasadd \
-yseasavg -yseasavg \
-yseasdiv -yseasdiv \
-yseasmax -yseasmax \
-yseasmean -yseasmean \
-yseasmin -yseasmin \
-yseasmul -yseasmul \
-yseaspctl -yseaspctl \
-yseasstd -yseasstd \
-yseasstd1 -yseasstd1 \
-yseassub -yseassub \
-yseassum -yseassum \
-yseasvar -yseasvar \
-yseasvar1 -yseasvar1 \
-zaxisdes -zaxisdes \
-zonavg -zonavg \
-zonmax -zonmax \
-zonmean -zonmean \
-zonmin -zonmin \
-zonpctl -zonpctl \
-zonrange -zonrange \
-zonstd -zonstd \
-zonstd1 -zonstd1 \
-zonsum -zonsum \
-zonvar -zonvar \
-zonvar1 -zonvar1 \
+list -list \
+of -of \
+operators. -operators. \
+option -option \
 )" -f cdo
diff --git a/doc/cdo.pdf b/doc/cdo.pdf
index 8310717..f8d2ff9 100644
Binary files a/doc/cdo.pdf and b/doc/cdo.pdf differ
diff --git a/doc/cdo_eca.pdf b/doc/cdo_eca.pdf
index 99ff09e..d4cc2d5 100644
Binary files a/doc/cdo_eca.pdf and b/doc/cdo_eca.pdf differ
diff --git a/doc/cdo_magics.pdf b/doc/cdo_magics.pdf
new file mode 100644
index 0000000..0a19605
Binary files /dev/null and b/doc/cdo_magics.pdf differ
diff --git a/doc/cdo_refcard.pdf b/doc/cdo_refcard.pdf
index acd98c9..2115cf3 100644
Binary files a/doc/cdo_refcard.pdf and b/doc/cdo_refcard.pdf differ
diff --git a/libcdi/ChangeLog b/libcdi/ChangeLog
index 01c8edf..bbc83d6 100644
--- a/libcdi/ChangeLog
+++ b/libcdi/ChangeLog
@@ -1,3 +1,40 @@
+2016-02-19  Uwe Schulzweida
+
+	* Version 1.7.1 released
+        * using CGRIBEX library version 1.7.4
+
+2016-02-05  Uwe Schulzweida
+
+	* timeval2vtime: set vtime=rtime if timevalue=0 [Bug: #6496]
+
+2015-12-23  Uwe Schulzweida
+
+	* ZAXIS_HEIGHT: added support for units cm, dm and km
+
+2015-12-19  Uwe Schulzweida
+
+	* gribapiDecode internal problem when processing 1x1 GRIB2 data with JPEG compression [Bug #6402]
+
+2015-12-10  Uwe Schulzweida
+
+	* gridGenYvals: bug fix [Bug #6373]
+
+2015-11-25  Uwe Schulzweida
+
+	* cdfDefXaxis/cdfDefXaxis: generate bounds for CDI_cmor_mode
+
+2015-11-23  Nathanael Huebbe
+
+	* replaced the vlist locked flag by two other flags
+
+2015-11-17  Uwe Schulzweida
+
+       * cdfCopyRecord: use MEMTYPE_FLOAT for DATATYPE_FLT32 
+
+2015-11-04  Uwe Schulzweida
+
+	* tableRead: name is not interpreted correctly (bug introduced in 1.7.0 #3933)
+
 2015-10-27  Uwe Schulzweida
 
 	* Version 1.7.0 released
diff --git a/libcdi/app/cdi.c b/libcdi/app/cdi.c
index eeee339..8b32c5a 100644
--- a/libcdi/app/cdi.c
+++ b/libcdi/app/cdi.c
@@ -12,6 +12,8 @@
 #include <math.h>
 
 #include <cdi.h>
+#include <cdi_uuid.h>
+
 int      vlistInqVarMissvalUsed(int vlistID, int varID);
 #ifndef DBL_IS_NAN
 #if  defined  (HAVE_DECL_ISNAN)
@@ -44,7 +46,13 @@ static const uint32_t HOST_ENDIANNESS_temp[1] = { UINT32_C(0x00030201) };
 
 #include "printinfo.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 void cdiDefTableID(int tableID);
+#if defined (__cplusplus)
+}
+#endif
 
 int getopt(int argc, char *const argv[], const char *optstring);
 
@@ -61,6 +69,8 @@ static int DefaultByteorder = CDI_UNDEFID;
 static int comptype  = COMPRESS_NONE;  // Compression type
 static int complevel = 0;              // Compression level
 
+enum datamode {SP_MODE, DP_MODE};
+static int datamode = DP_MODE;
 
 static
 void version(void)
@@ -749,7 +759,7 @@ int main(int argc, char *argv[])
   if (Progname == 0) Progname = argv[0];
   else               Progname++;
 
-  while ( (c = getopt(argc, argv, "b:f:t:w:z:cdhlMmqRrsvVZ")) != EOF )
+  while ( (c = getopt(argc, argv, "b:f:t:w:z:cdhlMmqRrsvVxZ")) != EOF )
     {
       switch (c)
 	{
@@ -798,6 +808,9 @@ int main(int argc, char *argv[])
 	case 'w':
 	  wTable = optarg;
 	  break;
+	case 'x':
+	  datamode = SP_MODE;
+	  break;
 	case 'z':
 	  defineCompress(optarg);
 	  break;
@@ -925,8 +938,7 @@ int main(int argc, char *argv[])
 	nts = cdiInqTimeSize(streamID1);
       */
       if (Debug)
-	printf("nts = %d\n"
-               "streamID1 = %d, streamID2 = %d\n",
+	printf("nts = %d streamID1 = %d, streamID2 = %d\n",
                nts, streamID1, streamID2);
 
       if ( Shortinfo )
diff --git a/libcdi/app/createtable.c b/libcdi/app/createtable.c
index 3a32019..29377bf 100644
--- a/libcdi/app/createtable.c
+++ b/libcdi/app/createtable.c
@@ -64,7 +64,6 @@ int main(int argc, char *argv[])
 	  usage();
 	  fprintf(stderr, "illegal option %s\n", cstring);
 	  return EXIT_FAILURE;
-	  break;
         }
     }
 
diff --git a/libcdi/app/printinfo.h b/libcdi/app/printinfo.h
index c68c2ec..fe64df6 100644
--- a/libcdi/app/printinfo.h
+++ b/libcdi/app/printinfo.h
@@ -3,18 +3,6 @@
 #define DATE_FORMAT "%5.4d-%2.2d-%2.2d"
 #define TIME_FORMAT "%2.2d:%2.2d:%2.2d"
 
-void uuid2str(const unsigned char uuid[CDI_UUID_SIZE], char *uuidstr);
-
-static inline
-int cdiUUIDIsNull(const unsigned char uuid[CDI_UUID_SIZE])
-{
-  int isNull = 1;
-  for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
-    isNull &= (uuid[i] == 0);
-  return isNull;
-}
-
-
 void datetime2str(int date, int time, char *datetimestr, int maxlen)
 {
   int year, month, day;
@@ -385,7 +373,7 @@ void printGridInfo(int vlistID)
       if ( !cdiUUIDIsNull(uuidOfHGrid) )
         {
           char uuidOfHGridStr[37];
-          uuid2str(uuidOfHGrid, uuidOfHGridStr);
+          cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
           if ( uuidOfHGridStr[0] != 0  && strlen(uuidOfHGridStr) == 36 )
             {
 	      fprintf(stdout, "%33s : %s\n", "uuid", uuidOfHGridStr);
@@ -502,7 +490,7 @@ void printZaxisInfo(int vlistID)
           if ( !cdiUUIDIsNull(uuidOfVGrid) )
             {
               char uuidOfVGridStr[37];
-              uuid2str(uuidOfVGrid, uuidOfVGridStr);
+              cdiUUID2Str(uuidOfVGrid, uuidOfVGridStr);
               if ( uuidOfVGridStr[0] != 0  && strlen(uuidOfVGridStr) == 36 )
                 {
                   fprintf(stdout, "%33s : ", "uuid");
diff --git a/libcdi/configure b/libcdi/configure
index b56dc78..ff3c62a 100755
--- a/libcdi/configure
+++ b/libcdi/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for cdi 1.7.0.
+# Generated by GNU Autoconf 2.68 for cdi 1.7.1.
 #
 # Report bugs to <http://mpimet.mpg.de/cdi>.
 #
@@ -570,8 +570,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='cdi'
 PACKAGE_TARNAME='cdi'
-PACKAGE_VERSION='1.7.0'
-PACKAGE_STRING='cdi 1.7.0'
+PACKAGE_VERSION='1.7.1'
+PACKAGE_STRING='cdi 1.7.1'
 PACKAGE_BUGREPORT='http://mpimet.mpg.de/cdi'
 PACKAGE_URL=''
 
@@ -1473,7 +1473,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures cdi 1.7.0 to adapt to many kinds of systems.
+\`configure' configures cdi 1.7.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1543,7 +1543,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of cdi 1.7.0:";;
+     short | recursive ) echo "Configuration of cdi 1.7.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1752,7 +1752,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-cdi configure 1.7.0
+cdi configure 1.7.1
 generated by GNU Autoconf 2.68
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2597,7 +2597,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by cdi $as_me 1.7.0, which was
+It was created by cdi $as_me 1.7.1, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
@@ -3549,7 +3549,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='cdi'
- VERSION='1.7.0'
+ VERSION='1.7.1'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -23418,7 +23418,7 @@ Usage: $0 [OPTIONS]
 Report bugs to <bug-libtool at gnu.org>."
 
 lt_cl_version="\
-cdi config.lt 1.7.0
+cdi config.lt 1.7.1
 configured by $0, generated by GNU Autoconf 2.68.
 
 Copyright (C) 2011 Free Software Foundation, Inc.
@@ -26087,18 +26087,143 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-#
-# Check for non-standard builtin
-ac_fn_c_check_decl "$LINENO" "__builtin_ctz" "ac_cv_have_decl___builtin_ctz" "$ac_includes_default"
-if test "x$ac_cv_have_decl___builtin_ctz" = xyes; then :
+# check for sysconf names
+ac_fn_c_check_decl "$LINENO" "_SC_LARGE_PAGESIZE" "ac_cv_have_decl__SC_LARGE_PAGESIZE" "$ac_includes_default
+#include <limits.h>
+#include <unistd.h>
+"
+if test "x$ac_cv_have_decl__SC_LARGE_PAGESIZE" = xyes; then :
   ac_have_decl=1
 else
   ac_have_decl=0
 fi
 
 cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL___BUILTIN_CTZ $ac_have_decl
+#define HAVE_DECL__SC_LARGE_PAGESIZE $ac_have_decl
 _ACEOF
+ac_fn_c_check_decl "$LINENO" "PAGESIZE" "ac_cv_have_decl_PAGESIZE" "$ac_includes_default
+#include <limits.h>
+#include <unistd.h>
+"
+if test "x$ac_cv_have_decl_PAGESIZE" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PAGESIZE $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "PAGE_SIZE" "ac_cv_have_decl_PAGE_SIZE" "$ac_includes_default
+#include <limits.h>
+#include <unistd.h>
+"
+if test "x$ac_cv_have_decl_PAGE_SIZE" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PAGE_SIZE $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "_SC_PAGE_SIZE" "ac_cv_have_decl__SC_PAGE_SIZE" "$ac_includes_default
+#include <limits.h>
+#include <unistd.h>
+"
+if test "x$ac_cv_have_decl__SC_PAGE_SIZE" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__SC_PAGE_SIZE $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "_SC_PAGESIZE" "ac_cv_have_decl__SC_PAGESIZE" "$ac_includes_default
+#include <limits.h>
+#include <unistd.h>
+"
+if test "x$ac_cv_have_decl__SC_PAGESIZE" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__SC_PAGESIZE $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "_PC_REC_XFER_ALIGN" "ac_cv_have_decl__PC_REC_XFER_ALIGN" "$ac_includes_default
+#include <limits.h>
+#include <unistd.h>
+"
+if test "x$ac_cv_have_decl__PC_REC_XFER_ALIGN" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__PC_REC_XFER_ALIGN $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "POSIX_REC_XFER_ALIGN" "ac_cv_have_decl_POSIX_REC_XFER_ALIGN" "$ac_includes_default
+#include <limits.h>
+#include <unistd.h>
+"
+if test "x$ac_cv_have_decl_POSIX_REC_XFER_ALIGN" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_POSIX_REC_XFER_ALIGN $ac_have_decl
+_ACEOF
+
+#
+# Check for non-standard builtin
+for builtin in __builtin_ctz
+do :
+
+   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether __builtin_ctz is declared" >&5
+$as_echo_n "checking whether __builtin_ctz is declared... " >&6; }
+if ${acx_cv_have_decl___builtin_ctz+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+  unsigned lbz = __builtin_ctz(56U)
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  acx_cv_have_decl___builtin_ctz=yes
+else
+  acx_cv_have_decl___builtin_ctz=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_have_decl___builtin_ctz" >&5
+$as_echo "$acx_cv_have_decl___builtin_ctz" >&6; }
+   if test "x$acx_cv_have_decl___builtin_ctz" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL___BUILTIN_CTZ 1
+_ACEOF
+
+      break
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL___BUILTIN_CTZ 0
+_ACEOF
+
+fi
+done
 
 
 # Check compiler version
@@ -29440,98 +29565,6 @@ fi
   { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MPI launch command unavailable" >&5
 $as_echo "$as_me: WARNING: MPI launch command unavailable" >&2;}
 fi
-   ac_fn_c_check_decl "$LINENO" "_SC_LARGE_PAGESIZE" "ac_cv_have_decl__SC_LARGE_PAGESIZE" "$ac_includes_default
-#include <limits.h>
-#include <unistd.h>
-"
-if test "x$ac_cv_have_decl__SC_LARGE_PAGESIZE" = xyes; then :
-  ac_have_decl=1
-else
-  ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL__SC_LARGE_PAGESIZE $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "PAGESIZE" "ac_cv_have_decl_PAGESIZE" "$ac_includes_default
-#include <limits.h>
-#include <unistd.h>
-"
-if test "x$ac_cv_have_decl_PAGESIZE" = xyes; then :
-  ac_have_decl=1
-else
-  ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_PAGESIZE $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "PAGE_SIZE" "ac_cv_have_decl_PAGE_SIZE" "$ac_includes_default
-#include <limits.h>
-#include <unistd.h>
-"
-if test "x$ac_cv_have_decl_PAGE_SIZE" = xyes; then :
-  ac_have_decl=1
-else
-  ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_PAGE_SIZE $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "_SC_PAGE_SIZE" "ac_cv_have_decl__SC_PAGE_SIZE" "$ac_includes_default
-#include <limits.h>
-#include <unistd.h>
-"
-if test "x$ac_cv_have_decl__SC_PAGE_SIZE" = xyes; then :
-  ac_have_decl=1
-else
-  ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL__SC_PAGE_SIZE $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "_SC_PAGESIZE" "ac_cv_have_decl__SC_PAGESIZE" "$ac_includes_default
-#include <limits.h>
-#include <unistd.h>
-"
-if test "x$ac_cv_have_decl__SC_PAGESIZE" = xyes; then :
-  ac_have_decl=1
-else
-  ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL__SC_PAGESIZE $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "_PC_REC_XFER_ALIGN" "ac_cv_have_decl__PC_REC_XFER_ALIGN" "$ac_includes_default
-#include <limits.h>
-#include <unistd.h>
-"
-if test "x$ac_cv_have_decl__PC_REC_XFER_ALIGN" = xyes; then :
-  ac_have_decl=1
-else
-  ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL__PC_REC_XFER_ALIGN $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "POSIX_REC_XFER_ALIGN" "ac_cv_have_decl_POSIX_REC_XFER_ALIGN" "$ac_includes_default
-#include <limits.h>
-#include <unistd.h>
-"
-if test "x$ac_cv_have_decl_POSIX_REC_XFER_ALIGN" = xyes; then :
-  ac_have_decl=1
-else
-  ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_POSIX_REC_XFER_ALIGN $ac_have_decl
-_ACEOF
-
 
 
 pkg_failed=no
@@ -31428,7 +31461,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by cdi $as_me 1.7.0, which was
+This file was extended by cdi $as_me 1.7.1, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -31494,7 +31527,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-cdi config.status 1.7.0
+cdi config.status 1.7.1
 configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
diff --git a/libcdi/configure.ac b/libcdi/configure.ac
index d95aa34..c6ed99b 100644
--- a/libcdi/configure.ac
+++ b/libcdi/configure.ac
@@ -4,7 +4,7 @@
 #  autoconf 2.68
 #  libtool  2.4.2
 
-AC_INIT([cdi], [1.7.0], [http://mpimet.mpg.de/cdi])
+AC_INIT([cdi], [1.7.1], [http://mpimet.mpg.de/cdi])
 
 AC_DEFINE_UNQUOTED(CDI, ["$PACKAGE_VERSION"], [CDI version])
 
@@ -85,9 +85,26 @@ AC_SUBST([UUID_C_LIB])
 AC_CHECK_DECLS([isnan],,,[AC_INCLUDES_DEFAULT
 @%:@include <math.h>])
 
+# check for sysconf names
+AC_CHECK_DECLS([_SC_LARGE_PAGESIZE, PAGESIZE, PAGE_SIZE, _SC_PAGE_SIZE, dnl
+_SC_PAGESIZE, _PC_REC_XFER_ALIGN, POSIX_REC_XFER_ALIGN],,,[AC_INCLUDES_DEFAULT
+@%:@include <limits.h>
+@%:@include <unistd.h>])
 #
 # Check for non-standard builtin
-AC_CHECK_DECLS([__builtin_ctz])
+AS_FOR([builtin_macro],[builtin],[__builtin_ctz],
+  [AS_VAR_PUSHDEF([builtin_cache],[acx_cv_have_decl_]builtin_macro)
+   AC_CACHE_CHECK([whether ]builtin_macro[ is declared],
+     [builtin_cache],
+     [AC_LINK_IFELSE([AC_LANG_PROGRAM(,[  unsigned lbz = builtin_macro][[(56U)]])],
+        [AS_VAR_SET([builtin_cache],[yes])],
+        [AS_VAR_SET([builtin_cache],[no])])])
+   AS_VAR_IF([builtin_cache],[yes],
+     [AC_DEFINE_UNQUOTED([HAVE_DECL_]AS_TR_CPP([builtin_macro]),[1])
+      break],
+     [AC_DEFINE_UNQUOTED([HAVE_DECL_]AS_TR_CPP([builtin_macro]),[0])])])
+AH_TEMPLATE([HAVE_DECL___BUILTIN_CTZ],
+  [Define to 1 if __builtin_ctz is available, 0 if not])
 
 # Check compiler version
 case "$CC" in
@@ -195,10 +212,6 @@ main(int argc, char **argv)
      ])
    AS_IF([test "x$MPI_LAUNCH" = xtrue],
      [AC_MSG_WARN([MPI launch command unavailable])])
-   AC_CHECK_DECLS([_SC_LARGE_PAGESIZE, PAGESIZE, PAGE_SIZE, _SC_PAGE_SIZE, dnl
-_SC_PAGESIZE, _PC_REC_XFER_ALIGN, POSIX_REC_XFER_ALIGN],,,[AC_INCLUDES_DEFAULT
-@%:@include <limits.h>
-@%:@include <unistd.h>])
 
    PKG_CHECK_MODULES([YAXT],[yaxt],
      [AC_DEFINE([HAVE_YAXT],,[yaxt library is available])],
diff --git a/libcdi/doc/cdi_cman.pdf b/libcdi/doc/cdi_cman.pdf
index 20571a0..5334413 100644
Binary files a/libcdi/doc/cdi_cman.pdf and b/libcdi/doc/cdi_cman.pdf differ
diff --git a/libcdi/doc/cdi_fman.pdf b/libcdi/doc/cdi_fman.pdf
index 0e2f0af..2941678 100644
Binary files a/libcdi/doc/cdi_fman.pdf and b/libcdi/doc/cdi_fman.pdf differ
diff --git a/libcdi/interfaces/cdi.hpp b/libcdi/interfaces/cdi.hpp
index 96bdbb0..4c6fb88 100644
--- a/libcdi/interfaces/cdi.hpp
+++ b/libcdi/interfaces/cdi.hpp
@@ -14,7 +14,7 @@ class CdiGrid {
     bool hasXValues, hasYValues, hasBounds;
     std::vector<double> xvalues, yvalues, xbounds, ybounds;
 
-
+  // [xy]stdname cannot be set arbitrarily
     std::string xname, xlongname, xstdname, xunits;
     std::string yname, ylongname, ystdname, yunits;      
     std::string name;
diff --git a/libcdi/src/Makefile.am b/libcdi/src/Makefile.am
index b00051d..eb933b6 100644
--- a/libcdi/src/Makefile.am
+++ b/libcdi/src/Makefile.am
@@ -37,7 +37,7 @@ libcdi_la_SOURCES = 	 \
 	cksum.h		\
 	cdi_cksum.c	\
 	cdi_cksum.h	\
-	create_uuid.h	 \
+	cdi_uuid.h	 \
 	dtypes.h	 \
 	error.c        	 \
 	error.h	 	 \
@@ -55,8 +55,8 @@ libcdi_la_SOURCES = 	 \
 	grid.h	 	 \
 	ieg.h	 	 \
 	ieglib.c         \
-	input_file.c	\
-	input_file.h	\
+	input_file.c	 \
+	input_file.h     \
 	institution.c  	 \
 	institution.h  	 \
 	model.c        	 \
@@ -79,7 +79,6 @@ libcdi_la_SOURCES = 	 \
 	stream_ext.h	 \
 	stream_grb.c     \
 	stream_grb.h     \
-	stream_gribapi.c \
 	stream_gribapi.h \
 	stream_history.c \
 	stream_ieg.c     \
@@ -92,6 +91,10 @@ libcdi_la_SOURCES = 	 \
 	stream_srv.c     \
 	stream_srv.h	 \
 	stream_var.c     \
+        grb_write.c      \
+        grb_read.c       \
+        cdf_write.c      \
+        cdf_read.c       \
         subtype.c        \
         subtype.h        \
 	swap.h	 	 \
@@ -116,7 +119,9 @@ libcdi_la_SOURCES = 	 \
 	zaxis.c		 \
 	zaxis.h		 \
 	stream.c         \
-	swap.c          \
+	stream_write.c   \
+	stream_read.c    \
+	swap.c           \
 	iterator.c          \
 	iterator.h          \
 	iterator_fallback.c \
@@ -131,7 +136,7 @@ libcdi_la_USE_FC_extra_sources = \
 
 # these only contain code iff grib_api is available
 libcdi_la_HAVE_LIBGRIB_API_extra_sources = \
-	gribapi_utilities.c
+	gribapi_utilities.c stream_gribapi.c
 
 if USE_FC
 libcdi_la_SOURCES += 	 \
diff --git a/libcdi/src/Makefile.in b/libcdi/src/Makefile.in
index 3d93ab7..ab7d81c 100644
--- a/libcdi/src/Makefile.in
+++ b/libcdi/src/Makefile.in
@@ -171,28 +171,29 @@ am__libcdi_la_SOURCES_DIST = basetime.c basetime.h binary.c binary.h \
 	calendar.c calendar.h cdf.c cdf.h cdf_int.c cdf_int.h cdi.h \
 	cdi_error.c cdi_limits.h cdi_util.c cgribex.h cgribexlib.c \
 	datetime.h dmemory.c dmemory.h cksum.c cksum.h cdi_cksum.c \
-	cdi_cksum.h create_uuid.h dtypes.h error.c error.h exse.h \
-	extra.h extralib.c file.c file.h gaussgrid.c gaussgrid.h \
-	gribapi.c gribapi.h gribapi_utilities.h grid.c grid.h ieg.h \
-	ieglib.c input_file.c input_file.h institution.c institution.h \
-	model.c model.h namespace.c namespace.h serialize.h \
-	serialize.c referenceCounting.c referenceCounting.h \
-	resource_handle.c resource_handle.h service.h servicelib.c \
-	stream_cdf.c stream_cdf.h stream_cgribex.c stream_cgribex.h \
-	stream_ext.c stream_ext.h stream_grb.c stream_grb.h \
-	stream_gribapi.c stream_gribapi.h stream_history.c \
-	stream_ieg.c stream_ieg.h stream_fcommon.c stream_fcommon.h \
-	cdi_int.c cdi_int.h stream_record.c stream_srv.c stream_srv.h \
-	stream_var.c subtype.c subtype.h swap.h table.c table.h \
-	tablepar.h taxis.c taxis.h timebase.c timebase.h tsteps.c \
-	util.c varscan.c varscan.h version.c vlist.c vlist.h \
+	cdi_cksum.h cdi_uuid.h dtypes.h error.c error.h exse.h extra.h \
+	extralib.c file.c file.h gaussgrid.c gaussgrid.h gribapi.c \
+	gribapi.h gribapi_utilities.h grid.c grid.h ieg.h ieglib.c \
+	input_file.c input_file.h institution.c institution.h model.c \
+	model.h namespace.c namespace.h serialize.h serialize.c \
+	referenceCounting.c referenceCounting.h resource_handle.c \
+	resource_handle.h service.h servicelib.c stream_cdf.c \
+	stream_cdf.h stream_cgribex.c stream_cgribex.h stream_ext.c \
+	stream_ext.h stream_grb.c stream_grb.h stream_gribapi.h \
+	stream_history.c stream_ieg.c stream_ieg.h stream_fcommon.c \
+	stream_fcommon.h cdi_int.c cdi_int.h stream_record.c \
+	stream_srv.c stream_srv.h stream_var.c grb_write.c grb_read.c \
+	cdf_write.c cdf_read.c subtype.c subtype.h swap.h table.c \
+	table.h tablepar.h taxis.c taxis.h timebase.c timebase.h \
+	tsteps.c util.c varscan.c varscan.h version.c vlist.c vlist.h \
 	vlist_att.c vlist_att.h vlist_var.c vlist_var.h zaxis.c \
-	zaxis.h stream.c swap.c iterator.c iterator.h \
-	iterator_fallback.c iterator_fallback.h iterator_grib.c \
-	iterator_grib.h cfortran.h cdiFortran.c gribapi_utilities.c
+	zaxis.h stream.c stream_write.c stream_read.c swap.c \
+	iterator.c iterator.h iterator_fallback.c iterator_fallback.h \
+	iterator_grib.c iterator_grib.h cfortran.h cdiFortran.c \
+	gribapi_utilities.c stream_gribapi.c
 am__objects_1 = cdiFortran.lo
 @USE_FC_TRUE at am__objects_2 = $(am__objects_1)
-am__objects_3 = gribapi_utilities.lo
+am__objects_3 = gribapi_utilities.lo stream_gribapi.lo
 @HAVE_LIBGRIB_API_TRUE at am__objects_4 = $(am__objects_3)
 am_libcdi_la_OBJECTS = basetime.lo binary.lo calendar.lo cdf.lo \
 	cdf_int.lo cdi_error.lo cdi_util.lo cgribexlib.lo dmemory.lo \
@@ -201,11 +202,12 @@ am_libcdi_la_OBJECTS = basetime.lo binary.lo calendar.lo cdf.lo \
 	institution.lo model.lo namespace.lo serialize.lo \
 	referenceCounting.lo resource_handle.lo servicelib.lo \
 	stream_cdf.lo stream_cgribex.lo stream_ext.lo stream_grb.lo \
-	stream_gribapi.lo stream_history.lo stream_ieg.lo \
-	stream_fcommon.lo cdi_int.lo stream_record.lo stream_srv.lo \
-	stream_var.lo subtype.lo table.lo taxis.lo timebase.lo \
-	tsteps.lo util.lo varscan.lo version.lo vlist.lo vlist_att.lo \
-	vlist_var.lo zaxis.lo stream.lo swap.lo iterator.lo \
+	stream_history.lo stream_ieg.lo stream_fcommon.lo cdi_int.lo \
+	stream_record.lo stream_srv.lo stream_var.lo grb_write.lo \
+	grb_read.lo cdf_write.lo cdf_read.lo subtype.lo table.lo \
+	taxis.lo timebase.lo tsteps.lo util.lo varscan.lo version.lo \
+	vlist.lo vlist_att.lo vlist_var.lo zaxis.lo stream.lo \
+	stream_write.lo stream_read.lo swap.lo iterator.lo \
 	iterator_fallback.lo iterator_grib.lo $(am__objects_2) \
 	$(am__objects_4)
 libcdi_la_OBJECTS = $(am_libcdi_la_OBJECTS)
@@ -516,22 +518,23 @@ libcdi_la_SOURCES = basetime.c basetime.h binary.c binary.h calendar.c \
 	calendar.h cdf.c cdf.h cdf_int.c cdf_int.h cdi.h cdi_error.c \
 	cdi_limits.h cdi_util.c cgribex.h cgribexlib.c datetime.h \
 	dmemory.c dmemory.h cksum.c cksum.h cdi_cksum.c cdi_cksum.h \
-	create_uuid.h dtypes.h error.c error.h exse.h extra.h \
-	extralib.c file.c file.h gaussgrid.c gaussgrid.h gribapi.c \
-	gribapi.h gribapi_utilities.h grid.c grid.h ieg.h ieglib.c \
-	input_file.c input_file.h institution.c institution.h model.c \
-	model.h namespace.c namespace.h serialize.h serialize.c \
+	cdi_uuid.h dtypes.h error.c error.h exse.h extra.h extralib.c \
+	file.c file.h gaussgrid.c gaussgrid.h gribapi.c gribapi.h \
+	gribapi_utilities.h grid.c grid.h ieg.h ieglib.c input_file.c \
+	input_file.h institution.c institution.h model.c model.h \
+	namespace.c namespace.h serialize.h serialize.c \
 	referenceCounting.c referenceCounting.h resource_handle.c \
 	resource_handle.h service.h servicelib.c stream_cdf.c \
 	stream_cdf.h stream_cgribex.c stream_cgribex.h stream_ext.c \
-	stream_ext.h stream_grb.c stream_grb.h stream_gribapi.c \
-	stream_gribapi.h stream_history.c stream_ieg.c stream_ieg.h \
-	stream_fcommon.c stream_fcommon.h cdi_int.c cdi_int.h \
-	stream_record.c stream_srv.c stream_srv.h stream_var.c \
-	subtype.c subtype.h swap.h table.c table.h tablepar.h taxis.c \
-	taxis.h timebase.c timebase.h tsteps.c util.c varscan.c \
-	varscan.h version.c vlist.c vlist.h vlist_att.c vlist_att.h \
-	vlist_var.c vlist_var.h zaxis.c zaxis.h stream.c swap.c \
+	stream_ext.h stream_grb.c stream_grb.h stream_gribapi.h \
+	stream_history.c stream_ieg.c stream_ieg.h stream_fcommon.c \
+	stream_fcommon.h cdi_int.c cdi_int.h stream_record.c \
+	stream_srv.c stream_srv.h stream_var.c grb_write.c grb_read.c \
+	cdf_write.c cdf_read.c subtype.c subtype.h swap.h table.c \
+	table.h tablepar.h taxis.c taxis.h timebase.c timebase.h \
+	tsteps.c util.c varscan.c varscan.h version.c vlist.c vlist.h \
+	vlist_att.c vlist_att.h vlist_var.c vlist_var.h zaxis.c \
+	zaxis.h stream.c stream_write.c stream_read.c swap.c \
 	iterator.c iterator.h iterator_fallback.c iterator_fallback.h \
 	iterator_grib.c iterator_grib.h $(am__append_2) \
 	$(am__append_3)
@@ -544,7 +547,7 @@ libcdi_la_USE_FC_extra_sources = \
 
 # these only contain code iff grib_api is available
 libcdi_la_HAVE_LIBGRIB_API_extra_sources = \
-	gribapi_utilities.c
+	gribapi_utilities.c stream_gribapi.c
 
 libcdiresunpack_la_SOURCES = \
 	resource_unpack.c
@@ -693,6 +696,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/calendar.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdf.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdf_int.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdf_read.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdf_write.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdiFortran.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdi_cksum.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdi_error.Plo at am__quote@
@@ -706,6 +711,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/extralib.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/file.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gaussgrid.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/grb_read.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/grb_write.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gribapi.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gribapi_utilities.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/grid.Plo at am__quote@
@@ -752,9 +759,11 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_gribapi.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_history.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_ieg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_read.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_record.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_srv.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_var.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_write.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/subtype.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/swap.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/table.Plo at am__quote@
diff --git a/libcdi/src/basetime.c b/libcdi/src/basetime.c
index 5d0efba..3d4d5e3 100644
--- a/libcdi/src/basetime.c
+++ b/libcdi/src/basetime.c
@@ -32,4 +32,3 @@ void basetimeInit(basetime_t *basetime)
  * require-trailing-newline: t
  * End:
  */
- 
\ No newline at end of file
diff --git a/libcdi/src/binary.c b/libcdi/src/binary.c
index 9772272..dac4086 100644
--- a/libcdi/src/binary.c
+++ b/libcdi/src/binary.c
@@ -16,7 +16,7 @@ UINT32 get_UINT32(unsigned char *x)
   switch (HOST_ENDIANNESS)
     {
     case CDI_BIGENDIAN:
-      return((UINT32)(((UINT32)x[0]<<24)+((UINT32)x[1]<<16)+((UINT32)x[2]<< 8)+ (UINT32)x[3]));
+      return ((UINT32)(((UINT32)x[0]<<24)+((UINT32)x[1]<<16)+((UINT32)x[2]<< 8)+ (UINT32)x[3]));
     case CDI_LITTLEENDIAN:
       return ((UINT32)(((UINT32)x[3]<<24)+((UINT32)x[2]<<16)+((UINT32)x[1]<< 8)+ (UINT32)x[0]));
     default:
@@ -31,9 +31,9 @@ UINT32 get_SUINT32(unsigned char *x)
   switch (HOST_ENDIANNESS)
     {
     case CDI_BIGENDIAN:
-      return((UINT32)(((UINT32)x[3]<<24)+((UINT32)x[2]<<16)+((UINT32)x[1]<< 8)+ (UINT32)x[0]));
+      return ((UINT32)(((UINT32)x[3]<<24)+((UINT32)x[2]<<16)+((UINT32)x[1]<< 8)+ (UINT32)x[0]));
     case CDI_LITTLEENDIAN:
-      return((UINT32)(((UINT32)x[0]<<24)+((UINT32)x[1]<<16)+((UINT32)x[2]<< 8)+ (UINT32)x[3]));
+      return ((UINT32)(((UINT32)x[0]<<24)+((UINT32)x[1]<<16)+((UINT32)x[2]<< 8)+ (UINT32)x[3]));
     default:
       Error("unhandled endianness %d", HOST_ENDIANNESS);
       return UINT32_C(0xFFFFFFFF);
@@ -46,11 +46,11 @@ UINT64 get_UINT64(unsigned char *x)
   switch (HOST_ENDIANNESS)
     {
     case CDI_BIGENDIAN:
-      return((UINT64)(((UINT64)x[0]<<56)+((UINT64)x[1]<<48)+((UINT64)x[2]<<40)+((UINT64)x[3]<<32)+
-                      ((UINT64)x[4]<<24)+((UINT64)x[5]<<16)+((UINT64)x[6]<< 8)+ (UINT64)x[7]));
+      return ((UINT64)(((UINT64)x[0]<<56)+((UINT64)x[1]<<48)+((UINT64)x[2]<<40)+((UINT64)x[3]<<32)+
+                       ((UINT64)x[4]<<24)+((UINT64)x[5]<<16)+((UINT64)x[6]<< 8)+ (UINT64)x[7]));
     case CDI_LITTLEENDIAN:
-      return((UINT64)(((UINT64)x[7]<<56)+((UINT64)x[6]<<48)+((UINT64)x[5]<<40)+((UINT64)x[4]<<32)+
-                      ((UINT64)x[3]<<24)+((UINT64)x[2]<<16)+((UINT64)x[1]<< 8)+ (UINT64)x[0]));
+      return ((UINT64)(((UINT64)x[7]<<56)+((UINT64)x[6]<<48)+((UINT64)x[5]<<40)+((UINT64)x[4]<<32)+
+                       ((UINT64)x[3]<<24)+((UINT64)x[2]<<16)+((UINT64)x[1]<< 8)+ (UINT64)x[0]));
     default:
       Error("unhandled endianness %d", HOST_ENDIANNESS);
       return UINT64_C(0xFFFFFFFFFFFFFFFF);
@@ -63,11 +63,11 @@ UINT64 get_SUINT64(unsigned char *x)
   switch (HOST_ENDIANNESS)
     {
     case CDI_BIGENDIAN:
-      return((UINT64)(((UINT64)x[7]<<56)+((UINT64)x[6]<<48)+((UINT64)x[5]<<40)+((UINT64)x[4]<<32)+
-                      ((UINT64)x[3]<<24)+((UINT64)x[2]<<16)+((UINT64)x[1]<< 8)+ (UINT64)x[0]));
+      return ((UINT64)(((UINT64)x[7]<<56)+((UINT64)x[6]<<48)+((UINT64)x[5]<<40)+((UINT64)x[4]<<32)+
+                       ((UINT64)x[3]<<24)+((UINT64)x[2]<<16)+((UINT64)x[1]<< 8)+ (UINT64)x[0]));
     case CDI_LITTLEENDIAN:
-      return((UINT64)(((UINT64)x[0]<<56)+((UINT64)x[1]<<48)+((UINT64)x[2]<<40)+((UINT64)x[3]<<32)+
-                      ((UINT64)x[4]<<24)+((UINT64)x[5]<<16)+((UINT64)x[6]<< 8)+ (UINT64)x[7]));
+      return ((UINT64)(((UINT64)x[0]<<56)+((UINT64)x[1]<<48)+((UINT64)x[2]<<40)+((UINT64)x[3]<<32)+
+                       ((UINT64)x[4]<<24)+((UINT64)x[5]<<16)+((UINT64)x[6]<< 8)+ (UINT64)x[7]));
     default:
       Error("unhandled endianness %d", HOST_ENDIANNESS);
       return UINT64_C(0xFFFFFFFFFFFFFFFF);
diff --git a/libcdi/src/calendar.h b/libcdi/src/calendar.h
index c5836e9..cd7ea77 100644
--- a/libcdi/src/calendar.h
+++ b/libcdi/src/calendar.h
@@ -1,15 +1,22 @@
 #ifndef _CALENDAR_H
 #define _CALENDAR_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 void encode_caldaysec(int calendar, int year, int month, int day, int hour, int minute, int second,
 		      int *julday, int *secofday);
-void decode_caldaysec(int calendar, int julday, int secofday, 
+void decode_caldaysec(int calendar, int julday, int secofday,
 		      int *year, int *month, int *day, int *hour, int *minute, int *second);
 
 int calendar_dpy(int calendar);
 int days_per_year(int calendar, int year);
 int days_per_month(int calendar, int year, int month);
 
+#if defined (__cplusplus)
+}
+#endif
 
 #endif  /* _CALENDAR_H */
 /*
diff --git a/libcdi/src/cdf_read.c b/libcdi/src/cdf_read.c
new file mode 100644
index 0000000..5c872f7
--- /dev/null
+++ b/libcdi/src/cdf_read.c
@@ -0,0 +1,720 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_LIBNETCDF
+
+#include <limits.h>
+#include <float.h>
+
+#include "dmemory.h"
+#include "cdi.h"
+#include "cdi_int.h"
+#include "stream_cdf.h"
+#include "cdf.h"
+#include "cdf_int.h"
+#include "vlist.h"
+
+
+#undef  UNDEFID
+#define UNDEFID  CDI_UNDEFID
+
+
+static
+void cdfReadGridTraj(stream_t *streamptr, int gridID)
+{
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+
+  int gridindex = vlistGridIndex(vlistID, gridID);
+  int lonID = streamptr->xdimID[gridindex];
+  int latID = streamptr->ydimID[gridindex];
+
+  int tsID = streamptr->curTsID;
+  size_t index = (size_t)tsID;
+
+  double xlon, xlat;
+  cdf_get_var1_double(fileID, lonID, &index, &xlon);
+  cdf_get_var1_double(fileID, latID, &index, &xlat);
+
+  gridDefXvals(gridID, &xlon);
+  gridDefYvals(gridID, &xlat);
+}
+
+static
+void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], size_t (*count)[4])
+{
+  int vlistID = streamptr->vlistID;
+  int tsID = streamptr->curTsID;
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
+
+  if ( CDI_Debug ) Message("tsID = %d", tsID);
+
+  int xid = UNDEFID, yid = UNDEFID;
+  if ( gridInqType(gridID) == GRID_TRAJECTORY )
+    {
+      cdfReadGridTraj(streamptr, gridID);
+    }
+  else
+    {
+      xid = streamptr->xdimID[gridindex];
+      yid = streamptr->ydimID[gridindex];
+    }
+  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+  int zid = streamptr->zaxisID[zaxisindex];
+
+  int ndims = 0;
+#define addDimension(startCoord, length) do \
+    { \
+      (*start)[ndims] = startCoord; \
+      (*count)[ndims] = length; \
+      ndims++; \
+    } while(0)
+  if ( tsteptype != TSTEP_CONSTANT ) addDimension((size_t)tsID, 1);
+  if ( zid != UNDEFID ) addDimension(0, (size_t)zaxisInqSize(zaxisID));
+  if ( yid != UNDEFID ) addDimension(0, (size_t)gridInqYsize(gridID));
+  if ( xid != UNDEFID ) addDimension(0, (size_t)gridInqXsize(gridID));
+#undef addDimension
+
+  assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
+  assert(ndims <= (int)(sizeof(*count)/sizeof(**count)));
+
+  if ( CDI_Debug )
+    for (int idim = 0; idim < ndims; idim++)
+      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
+}
+
+//Scans the data array for missVals, optionally applying first a scale factor and then an offset.
+//Returns the number of missing + out-of-range values encountered.
+static
+size_t cdfDoInputDataTransformationDP(size_t valueCount, double *data, bool haveMissVal, double missVal, double scaleFactor, double offset, double validMin, double validMax)
+ {
+  const bool haveOffset   = IS_NOT_EQUAL(offset, 0);
+  const bool haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1);
+  size_t missValCount = 0;
+
+  if ( IS_EQUAL(validMin, VALIDMISS) ) validMin = DBL_MIN;
+  if ( IS_EQUAL(validMax, VALIDMISS) ) validMax = DBL_MAX;
+
+  bool haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin,DBL_MIN));
+  assert(!haveRangeCheck || haveMissVal);
+
+  switch ((int)haveMissVal | ((int)haveScaleFactor << 1)
+          | ((int)haveOffset << 2) | ((int)haveRangeCheck << 3))
+    {
+    case 15: /* haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset */
+      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;
+        }
+      break;
+    case 13: /* haveRangeCheck & haveMissVal & haveOffset */
+      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;
+        }
+      break;
+    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;
+        }
+      break;
+    case 9: /* haveRangeCheck & haveMissVal */
+      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 : data[i];
+        }
+      break;
+    case 7: /* haveMissVal & haveScaleFactor & haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        if ( DBL_IS_EQUAL(data[i], missVal) )
+          missValCount++;
+        else
+          data[i] = data[i] * scaleFactor + offset;
+      break;
+    case 6: /* haveOffset & haveScaleFactor */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] = data[i] * scaleFactor + offset;
+      break;
+    case 5: /* haveMissVal & haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        if ( DBL_IS_EQUAL(data[i], missVal) )
+          missValCount++;
+        else
+          data[i] += offset;
+      break;
+    case 4: /* haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] += offset;
+      break;
+    case 3: /* haveMissVal & haveScaleFactor */
+      for ( size_t i = 0; i < valueCount; i++ )
+        if ( DBL_IS_EQUAL(data[i], missVal) )
+          missValCount++;
+        else
+          data[i] *= scaleFactor;
+      break;
+    case 2: /* haveScaleFactor */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] *= scaleFactor;
+      break;
+    case 1: /* haveMissVal */
+      for ( size_t i = 0; i < valueCount; i++ )
+        missValCount += (unsigned)DBL_IS_EQUAL(data[i], missVal);
+      break;
+    }
+
+  return missValCount;
+}
+
+static
+size_t cdfDoInputDataTransformationSP(size_t valueCount, float *data, bool haveMissVal, double missVal, double scaleFactor, double offset, double validMin, double validMax)
+ {
+  const bool haveOffset   = IS_NOT_EQUAL(offset, 0);
+  const bool haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1);
+  size_t missValCount = 0;
+
+  if ( IS_EQUAL(validMin, VALIDMISS) ) validMin = DBL_MIN;
+  if ( IS_EQUAL(validMax, VALIDMISS) ) validMax = DBL_MAX;
+
+  bool haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin,DBL_MIN));
+  assert(!haveRangeCheck || haveMissVal);
+
+  switch ((int)haveMissVal | ((int)haveScaleFactor << 1)
+          | ((int)haveOffset << 2) | ((int)haveRangeCheck << 3))
+    {
+    case 15: /* haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset */
+      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);
+        }
+      break;
+    case 13: /* haveRangeCheck & haveMissVal & haveOffset */
+      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);
+        }
+      break;
+    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);
+        }
+      break;
+    case 9: /* haveRangeCheck & haveMissVal */
+      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 : data[i];
+        }
+      break;
+    case 7: /* haveMissVal & haveScaleFactor & haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        if ( DBL_IS_EQUAL(data[i], missVal) )
+          missValCount++;
+        else
+          data[i] = (float)(data[i] * scaleFactor + offset);
+      break;
+    case 6: /* haveOffset & haveScaleFactor */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] = (float)(data[i] * scaleFactor + offset);
+      break;
+    case 5: /* haveMissVal & haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        if ( DBL_IS_EQUAL(data[i], missVal) )
+          missValCount++;
+        else
+          data[i] = (float)(data[i] + offset);
+      break;
+    case 4: /* haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] = (float)(data[i] + offset);
+      break;
+    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);
+      break;
+    case 2: /* haveScaleFactor */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] = (float)(data[i] * scaleFactor);
+      break;
+    case 1: /* haveMissVal */
+      for ( size_t i = 0; i < valueCount; i++ )
+        missValCount += (unsigned)DBL_IS_EQUAL(data[i], missVal);
+      break;
+    }
+
+  return missValCount;
+}
+
+static
+size_t min_size(size_t a, size_t b)
+{
+  return a < b ? a : b;
+}
+
+static
+void transpose2dArrayDP(size_t inWidth, size_t inHeight, double *data)
+{
+  const size_t cacheBlockSize = 256;   // Purely an optimization parameter. Current value of 32 means we are handling 8kB blocks,
+                                       // which should be a decent compromise on many architectures.
+#ifdef __cplusplus
+  double *out[inHeight];
+  double *temp[inWidth];
+  temp[0] = (double *) Malloc(inHeight*inWidth*sizeof(double));
+  memcpy(temp[0], data, inHeight*inWidth*sizeof(double));
+  for(int i = 0; i < inHeight; i++) out[i] = data + (inWidth*i);
+  for(int i = 1; i < inWidth; i++) temp[i] = temp[0] + (inHeight*i);
+#else
+  double (*out)[inHeight] = (double (*)[inHeight])data;
+  double (*temp)[inWidth] = (double (*)[inWidth]) Malloc(inHeight*sizeof(*temp));
+  memcpy(temp, data, inHeight*sizeof(*temp));
+#endif
+
+  /*
+  for ( size_t y = 0; y < inHeight; ++y )
+    for ( size_t x = 0; x < inWidth; ++x )
+      out[x][y] = temp[y][x];
+  */
+
+  for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
+    {
+      for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
+        {
+          for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
+            {
+              for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
+                {
+                  out[x][y] = temp[y][x];
+                }
+            }
+        }
+    }
+
+  Free(temp[0]);
+}
+
+static
+void transpose2dArraySP(size_t inWidth, size_t inHeight, float *data)
+{
+  const size_t cacheBlockSize = 256;   // Purely an optimization parameter. Current value of 32 means we are handling 8kB blocks,
+                                       // which should be a decent compromise on many architectures.
+#ifdef __cplusplus
+  float *out[inHeight];
+  float *temp[inWidth];
+  temp[0] = (float *) Malloc(inHeight*inWidth*sizeof(float));
+  memcpy(temp[0], data, inHeight*inWidth*sizeof(float));
+  for(int i = 0; i < inHeight; i++) out[i] = data + (inWidth*i);
+  for(int i = 1; i < inWidth; i++) temp[i] = temp[0] + (inHeight*i);
+#else
+  float (*out)[inHeight] = (float (*)[inHeight])data;
+  float (*temp)[inWidth] = (float (*)[inWidth]) Malloc(inHeight*sizeof(*temp));
+  memcpy(temp, data, inHeight*sizeof(*temp));
+#endif
+
+  /*
+  for ( size_t y = 0; y < inHeight; ++y )
+    for ( size_t x = 0; x < inWidth; ++x )
+      out[x][y] = temp[y][x];
+  */
+
+  for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
+    {
+      for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
+        {
+          for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
+            {
+              for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
+                {
+                  out[x][y] = temp[y][x];
+                }
+            }
+        }
+    }
+
+  Free(temp);
+}
+
+static
+void cdfInqDimIds(stream_t *streamptr, int varId, int (*outDimIds)[3])
+{
+  int gridId = vlistInqVarGrid(streamptr->vlistID, varId);
+  int gridindex = vlistGridIndex(streamptr->vlistID, gridId);
+
+  (*outDimIds)[0] = (*outDimIds)[1] = (*outDimIds)[2] = UNDEFID;
+  switch ( gridInqType(gridId) )
+    {
+      case GRID_TRAJECTORY:
+        cdfReadGridTraj(streamptr, gridId);
+        break;
+
+      case GRID_UNSTRUCTURED:
+        (*outDimIds)[0] = streamptr->xdimID[gridindex];
+        break;
+
+      default:
+        (*outDimIds)[0] = streamptr->xdimID[gridindex];
+        (*outDimIds)[1] = streamptr->ydimID[gridindex];
+        break;
+    }
+
+  int zaxisID = vlistInqVarZaxis(streamptr->vlistID, varId);
+  int zaxisindex = vlistZaxisIndex(streamptr->vlistID, zaxisID);
+  (*outDimIds)[2] = streamptr->zaxisID[zaxisindex];
+}
+
+static
+int cdfGetSkipDim(int fileId, int ncvarid, int (*dimIds)[3])
+{
+  if((*dimIds)[0] != UNDEFID) return 0;
+  if((*dimIds)[1] != UNDEFID) return 0;
+  int nvdims;
+  cdf_inq_varndims(fileId, ncvarid, &nvdims);
+  if(nvdims != 3) return 0;
+
+  int varDimIds[3];
+  cdf_inq_vardimid(fileId, ncvarid, varDimIds);
+  size_t size = 0;
+  if ( (*dimIds)[2] == varDimIds[2] )
+    {
+      cdf_inq_dimlen(fileId, varDimIds[1], &size);
+      if ( size == 1 ) return 1;
+    }
+  else if ( (*dimIds)[2] == varDimIds[1] )
+    {
+      cdf_inq_dimlen(fileId, varDimIds[2], &size);
+      if ( size == 1 ) return 2;
+    }
+  return 0;
+}
+
+static
+void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, bool *outSwapXY, size_t (*start)[4], size_t (*count)[4])
+{
+  int tsID = streamptr->curTsID;
+  if ( CDI_Debug ) Message("tsID = %d", tsID);
+
+  int fileId = streamptr->fileID;
+  int vlistId = streamptr->vlistID;
+  int ncvarid = streamptr->vars[varId].ncvarid;
+
+  int gridId = vlistInqVarGrid(vlistId, varId);
+  int tsteptype = vlistInqVarTsteptype(vlistId, varId);
+  int gridsize = gridInqSize(gridId);
+
+  streamptr->numvals += gridsize;
+
+  int dimIds[3];    //this array joins the old variables xid, yid, and zid
+  cdfInqDimIds(streamptr, varId, &dimIds);
+
+  int skipdim = cdfGetSkipDim(fileId, ncvarid, &dimIds);
+
+  int dimorder[3];
+  vlistInqVarDimorder(vlistId, varId, &dimorder);
+
+  *outSwapXY = (dimorder[2] == 2 || dimorder[0] == 1) && dimIds[0] != UNDEFID && dimIds[1] != UNDEFID ;
+
+  int ndims = 0;
+
+#define addDimension(startIndex, extent) do {   \
+      (*start)[ndims] = startIndex; \
+      (*count)[ndims] = extent; \
+      ndims++; \
+  } while(0)
+
+  if ( tsteptype != TSTEP_CONSTANT ) addDimension((size_t)tsID, 1);
+  if ( skipdim == 1 ) addDimension(0, 1);
+
+  for ( int id = 0; id < 3; ++id )
+    {
+      size_t size;
+      int curDimId = dimIds[dimorder[id]-1];
+      if ( curDimId == UNDEFID ) continue;
+      switch ( dimorder[id] )
+        {
+          Error("Internal errror: Malformed dimension order encountered. Please report this bug.\n");
+          case 1:
+          case 2:
+            cdf_inq_dimlen(fileId, curDimId, &size);
+            addDimension(0, size);
+            break;
+
+          case 3:
+            addDimension((size_t)levelId, 1);
+            break;
+
+          default:
+            Error("Internal errror: Malformed dimension order encountered. Please report this bug.\n");
+        }
+    }
+
+  if ( skipdim == 2 ) addDimension(0, 1);
+
+  assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
+  assert(ndims <= (int)(sizeof(*count)/sizeof(**count)));
+
+#undef addDimension
+
+  if ( CDI_Debug )
+    for (int idim = 0; idim < ndims; idim++)
+      Message("dim = %d  start = %d  count = %d", idim, (*start)[idim], (*count)[idim]);
+
+  int nvdims;
+  cdf_inq_varndims(fileId, ncvarid, &nvdims);
+
+  if ( nvdims != ndims )
+    Error("Internal error, variable %s has an unsupported array structure!", vlistInqVarNamePtr(vlistId, varId));
+}
+
+static
+void cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+{
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
+
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+
+  int ncvarid = streamptr->vars[varID].ncvarid;
+
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  int zaxisID = vlistInqVarZaxis(vlistID, varID);
+
+  size_t start[4];
+  size_t count[4];
+  cdfGetSlapDescription(streamptr, varID, &start, &count);
+
+  cdf_get_vara_double(fileID, ncvarid, start, count, data);
+
+  size_t size = (size_t)gridInqSize(gridID)*(size_t)zaxisInqSize(zaxisID);
+  double missval = vlistInqVarMissval(vlistID, varID);
+  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
+  double validRange[2];
+  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
+    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
+  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
+  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
+  size_t nmiss_ = cdfDoInputDataTransformationDP(size, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
+  assert(nmiss_ <= INT_MAX);
+  *nmiss = (int)nmiss_;
+}
+
+static
+void cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss)
+{
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
+
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+
+  int ncvarid = streamptr->vars[varID].ncvarid;
+
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  int zaxisID = vlistInqVarZaxis(vlistID, varID);
+
+  size_t start[4];
+  size_t count[4];
+  cdfGetSlapDescription(streamptr, varID, &start, &count);
+
+  cdf_get_vara_float(fileID, ncvarid, start, count, data);
+
+  size_t size = (size_t)gridInqSize(gridID) * (size_t)zaxisInqSize(zaxisID);
+  double missval = vlistInqVarMissval(vlistID, varID);
+  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
+  double validRange[2];
+  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
+    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
+  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
+  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
+  size_t nmiss_ = cdfDoInputDataTransformationSP(size, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
+  assert(nmiss_ <= INT_MAX);
+  *nmiss = (int)nmiss_;
+}
+
+
+void cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss)
+{
+  if ( memtype == MEMTYPE_DOUBLE )
+    cdfReadVarDP(streamptr, varID, (double*) data, nmiss);
+  else
+    cdfReadVarSP(streamptr, varID, (float*) data, nmiss);
+}
+
+static
+void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data, int *nmiss)
+{
+  size_t start[4];
+  size_t count[4];
+
+  if ( CDI_Debug )
+    Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
+
+  int vlistID = streamptr->vlistID;
+  int fileID = streamptr->fileID;
+
+  bool swapxy;
+  cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
+
+  int ncvarid = streamptr->vars[varID].ncvarid;
+  int gridId = vlistInqVarGrid(vlistID, varID);
+  size_t gridsize = (size_t)gridInqSize(gridId);
+  size_t xsize = (size_t)gridInqXsize(gridId);
+  size_t ysize = (size_t)gridInqYsize(gridId);
+
+  if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT32 )
+    {
+      float *data_fp = (float *) Malloc(gridsize*sizeof(*data_fp));
+      cdf_get_vara_float(fileID, ncvarid, start, count, data_fp);
+      for ( size_t i = 0; i < gridsize; i++ )
+        data[i] = (double) data_fp[i];
+      Free(data_fp);
+    }
+  else if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
+    {
+      nc_type xtype;
+      cdf_inq_vartype(fileID, ncvarid, &xtype);
+      if ( xtype == NC_BYTE )
+        {
+          for ( size_t i = 0; i < gridsize; i++ )
+            if ( data[i] < 0 ) data[i] += 256;
+        }
+    }
+  else
+    {
+      cdf_get_vara_double(fileID, ncvarid, start, count, data);
+    }
+
+  if ( swapxy ) transpose2dArrayDP(ysize, xsize, data);
+
+  double missval = vlistInqVarMissval(vlistID, varID);
+  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
+  double validRange[2];
+  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
+    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
+  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
+  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
+  size_t nmiss_ = cdfDoInputDataTransformationDP(gridsize, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
+  assert(nmiss_ <= INT_MAX);
+  *nmiss = (int)nmiss_;
+}
+
+static
+void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data, int *nmiss)
+{
+  size_t start[4];
+  size_t count[4];
+
+  if ( CDI_Debug )
+    Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
+
+  int vlistID = streamptr->vlistID;
+  int fileID = streamptr->fileID;
+
+  bool swapxy;
+  cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
+
+  int ncvarid = streamptr->vars[varID].ncvarid;
+  int gridId = vlistInqVarGrid(vlistID, varID);
+  size_t gridsize = (size_t)gridInqSize(gridId);
+  size_t xsize = (size_t)gridInqXsize(gridId);
+  size_t ysize = (size_t)gridInqYsize(gridId);
+
+  if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT64 )
+    {
+      double *data_dp = (double *) Malloc(gridsize*sizeof(*data_dp));
+      cdf_get_vara_double(fileID, ncvarid, start, count, data_dp);
+      for ( size_t i = 0; i < gridsize; i++ )
+        data[i] = (float) data_dp[i];
+      Free(data_dp);
+    }
+  else if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
+    {
+      nc_type xtype;
+      cdf_inq_vartype(fileID, ncvarid, &xtype);
+      if ( xtype == NC_BYTE )
+        {
+          for ( size_t i = 0; i < gridsize; i++ )
+            if ( data[i] < 0 ) data[i] += 256;
+        }
+    }
+  else
+    {
+      cdf_get_vara_float(fileID, ncvarid, start, count, data);
+    }
+
+  if ( swapxy ) transpose2dArraySP(ysize, xsize, data);
+
+  double missval = vlistInqVarMissval(vlistID, varID);
+  bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
+  double validRange[2];
+  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
+    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
+  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
+  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
+  size_t nmiss_ = cdfDoInputDataTransformationSP(gridsize, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
+  assert(nmiss_ <= INT_MAX);
+  *nmiss = (int)nmiss_;
+}
+
+
+void cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss)
+{
+  if ( memtype == MEMTYPE_DOUBLE )
+    cdfReadVarSliceDP(streamptr, varID, levelID, (double*) data, nmiss);
+  else
+    cdfReadVarSliceSP(streamptr, varID, levelID, (float*) data, nmiss);
+}
+
+
+void cdf_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss)
+{
+  if ( CDI_Debug ) Message("streamID = %d", streamptr->self);
+
+  int tsID    = streamptr->curTsID;
+  int vrecID  = streamptr->tsteps[tsID].curRecID;
+  int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
+  int varID   = streamptr->tsteps[tsID].records[recID].varID;
+  int levelID = streamptr->tsteps[tsID].records[recID].levelID;
+
+  if ( memtype == MEMTYPE_DOUBLE )
+    cdfReadVarSliceDP(streamptr, varID, levelID, (double*) data, nmiss);
+  else
+    cdfReadVarSliceSP(streamptr, varID, levelID, (float*) data, nmiss);
+}
+
+#endif
diff --git a/libcdi/src/cdf_write.c b/libcdi/src/cdf_write.c
new file mode 100644
index 0000000..942f0c7
--- /dev/null
+++ b/libcdi/src/cdf_write.c
@@ -0,0 +1,1272 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_LIBNETCDF
+
+#include "dmemory.h"
+#include "cdi.h"
+#include "cdi_int.h"
+#include "stream_cdf.h"
+#include "cdf.h"
+#include "cdf_int.h"
+#include "vlist.h"
+
+
+#undef  UNDEFID
+#define UNDEFID  CDI_UNDEFID
+
+
+void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level)
+{
+#if  defined  (HAVE_NETCDF4)
+  int retval;
+  /* Set chunking, shuffle, and deflate. */
+  int shuffle = 1;
+  int deflate = 1;
+
+  if ( deflate_level < 1 || deflate_level > 9 ) deflate_level = 1;
+
+  if ((retval = nc_def_var_deflate(ncid, ncvarid, shuffle, deflate, deflate_level)))
+    {
+      Error("nc_def_var_deflate failed, status = %d", retval);
+    }
+#else
+  
+  static int lwarn = TRUE;
+  if ( lwarn )
+    {
+      lwarn = FALSE;
+      Warning("Deflate compression failed, NetCDF4 not available!");
+    }
+#endif
+}
+
+static
+int cdfDefDatatype(int datatype, int filetype)
+{
+  int xtype = NC_FLOAT;
+
+  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
+    Error("CDI/NetCDF library does not support complex numbers!");
+
+  if ( filetype == FILETYPE_NC4 )
+    {
+      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
+      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
+      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
+#if  defined  (HAVE_NETCDF4)
+      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_UBYTE;
+      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_USHORT;
+      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_UINT;
+#else
+      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
+      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
+      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
+#endif
+      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
+      else                                    xtype = NC_FLOAT;
+    }
+  else
+    {
+      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
+      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
+      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
+      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
+      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
+      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
+      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
+      else                                    xtype = NC_FLOAT;
+    }
+
+  return xtype;
+}
+
+static
+void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
+{
+  if ( streamptr->vars[varID].defmiss == FALSE )
+    {
+      int vlistID = streamptr->vlistID;
+      int fileID  = streamptr->fileID;
+      int ncvarid = streamptr->vars[varID].ncvarid;
+      double missval = vlistInqVarMissval(vlistID, varID);
+
+      if ( lcheck && streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+      int xtype = cdfDefDatatype(dtype, streamptr->filetype);
+
+      if ( xtype == NC_BYTE && missval > 127 && missval < 256 ) xtype = NC_INT;
+
+      cdf_put_att_double(fileID, ncvarid, "_FillValue", (nc_type) xtype, 1, &missval);
+      cdf_put_att_double(fileID, ncvarid, "missing_value", (nc_type) xtype, 1, &missval);
+
+      if ( lcheck && streamptr->ncmode == 2 ) cdf_enddef(fileID);
+
+      streamptr->vars[varID].defmiss = TRUE;
+    }
+}
+
+static
+void cdfDefInstitut(stream_t *streamptr)
+{
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+  int instID  = vlistInqInstitut(vlistID);
+
+  if ( instID != UNDEFID )
+    {
+      const char *longname = institutInqLongnamePtr(instID);
+      if ( longname )
+	{
+	  size_t len = strlen(longname);
+	  if ( len > 0 )
+	    {
+	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+	      cdf_put_att_text(fileID, NC_GLOBAL, "institution", len, longname);
+	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
+	    }
+	}
+    }
+}
+
+static
+void cdfDefSource(stream_t *streamptr)
+{
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+  int modelID = vlistInqModel(vlistID);
+
+  if ( modelID != UNDEFID )
+    {
+      const char *longname = modelInqNamePtr(modelID);
+      if ( longname )
+	{
+          size_t len = strlen(longname);
+	  if ( len > 0 )
+	    {
+	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+	      cdf_put_att_text(fileID, NC_GLOBAL, "source", len, longname);
+	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
+	    }
+	}
+    }
+}
+
+static inline
+void *resizeBuf(void **buf, size_t *bufSize, size_t reqSize)
+{
+  if (reqSize > *bufSize)
+    {
+      *buf = Realloc(*buf, reqSize);
+      *bufSize = reqSize;
+    }
+  return *buf;
+}
+
+static
+void cdfDefineAttributes(int vlistID, int varID, int fileID, int ncvarID)
+{
+  int atttype, attlen;
+  size_t len;
+  char attname[CDI_MAX_NAME+1];
+  void *attBuf = NULL;
+  size_t attBufSize = 0;
+
+  int natts;
+  vlistInqNatts(vlistID, varID, &natts);
+
+  for ( int iatt = 0; iatt < natts; iatt++ )
+    {
+      vlistInqAtt(vlistID, varID, iatt, attname, &atttype, &attlen);
+
+      if ( attlen == 0 ) continue;
+
+      if ( atttype == DATATYPE_TXT )
+        {
+          size_t attSize = (size_t)attlen*sizeof(char);
+          char *atttxt = (char *)resizeBuf(&attBuf, &attBufSize, attSize);
+          vlistInqAttTxt(vlistID, varID, attname, attlen, atttxt);
+          len = (size_t)attlen;
+          cdf_put_att_text(fileID, ncvarID, attname, len, atttxt);
+        }
+      else if ( atttype == DATATYPE_INT16 || atttype == DATATYPE_INT32 )
+        {
+          size_t attSize = (size_t)attlen*sizeof(int);
+          int *attint = (int *)resizeBuf(&attBuf, &attBufSize, attSize);
+          vlistInqAttInt(vlistID, varID, attname, attlen, &attint[0]);
+          len = (size_t)attlen;
+          cdf_put_att_int(fileID, ncvarID, attname, atttype == DATATYPE_INT16 ? NC_SHORT : NC_INT, len, attint);
+        }
+      else if ( atttype == DATATYPE_FLT32 || atttype == DATATYPE_FLT64 )
+        {
+          size_t attSize = (size_t)attlen * sizeof(double);
+          double *attflt = (double *)resizeBuf(&attBuf, &attBufSize, attSize);
+          vlistInqAttFlt(vlistID, varID, attname, attlen, attflt);
+          len = (size_t)attlen;
+          if ( atttype == DATATYPE_FLT32 )
+            {
+              float attflt_sp[len];
+              for ( size_t i = 0; i < len; ++i ) attflt_sp[i] = (float)attflt[i];
+              cdf_put_att_float(fileID, ncvarID, attname, NC_FLOAT, len, attflt_sp);
+            }
+          else
+            cdf_put_att_double(fileID, ncvarID, attname, NC_DOUBLE, len, attflt);
+        }
+    }
+  
+  Free(attBuf);
+}
+
+static
+void cdfDefGlobalAtts(stream_t *streamptr)
+{
+  if ( streamptr->globalatts ) return;
+
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+
+  cdfDefSource(streamptr);
+  cdfDefInstitut(streamptr);
+
+  int natts;
+  vlistInqNatts(vlistID, CDI_GLOBAL, &natts);
+
+  if ( natts > 0 && streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+  cdfDefineAttributes(vlistID, CDI_GLOBAL, fileID, NC_GLOBAL);
+
+  if ( natts > 0 && streamptr->ncmode == 2 ) cdf_enddef(fileID);
+
+  streamptr->globalatts = 1;
+}
+
+static
+void cdfDefLocalAtts(stream_t *streamptr)
+{
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+
+  if ( streamptr->localatts ) return;
+  if ( vlistInqInstitut(vlistID) != UNDEFID ) return;
+
+  streamptr->localatts = 1;
+
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+  for ( int varID = 0; varID < streamptr->nvars; varID++ )
+    {
+      int instID = vlistInqVarInstitut(vlistID, varID);
+      if ( instID != UNDEFID )
+	{
+          int ncvarid = streamptr->vars[varID].ncvarid;
+  	  const char *name = institutInqNamePtr(instID);
+	  if ( name )
+	    {
+              size_t len = strlen(name);
+	      cdf_put_att_text(fileID, ncvarid, "institution", len, name);
+	    }
+	}
+      }
+
+  if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
+}
+
+static
+int cdfDefVar(stream_t *streamptr, int varID)
+{
+  int ncvarid = -1;
+  int xid = UNDEFID, yid = UNDEFID;
+  size_t xsize = 0, ysize = 0;
+  char varname[CDI_MAX_NAME];
+  int dims[4];
+  int lchunk = FALSE;
+  size_t chunks[4] = {0,0,0,0};
+  int ndims = 0;
+  int tablenum;
+  int dimorder[3];
+  size_t iax = 0;
+  char axis[5];
+  int ensID, ensCount, forecast_type;
+  int retval;
+
+  int fileID  = streamptr->fileID;
+
+  if ( CDI_Debug )
+    Message("streamID = %d, fileID = %d, varID = %d", streamptr->self, fileID, varID);
+
+  if ( streamptr->vars[varID].ncvarid != UNDEFID )
+    return streamptr->vars[varID].ncvarid;
+
+  int vlistID   = streamptr->vlistID;
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  int code      = vlistInqVarCode(vlistID, varID);
+  int param     = vlistInqVarParam(vlistID, varID);
+  int pnum, pcat, pdis;
+  cdiDecodeParam(param, &pnum, &pcat, &pdis);
+
+  int chunktype = vlistInqVarChunkType(vlistID, varID);
+
+  vlistInqVarDimorder(vlistID, varID, &dimorder);
+
+  int gridsize  = gridInqSize(gridID);
+  if ( gridsize > 1 ) lchunk = TRUE;
+  int gridtype  = gridInqType(gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
+  if ( gridtype != GRID_TRAJECTORY )
+    {
+      xid = streamptr->xdimID[gridindex];
+      yid = streamptr->ydimID[gridindex];
+      if ( xid != UNDEFID ) cdf_inq_dimlen(fileID, xid, &xsize);
+      if ( yid != UNDEFID ) cdf_inq_dimlen(fileID, yid, &ysize);
+    }
+
+  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+  int zid = streamptr->zaxisID[zaxisindex];
+  int zaxis_is_scalar = FALSE;
+  if ( zid == UNDEFID ) zaxis_is_scalar = zaxisInqScalar(zaxisID);
+
+  if ( dimorder[0] != 3 ) lchunk = FALSE; /* ZYX and ZXY */
+
+  if ( ((dimorder[0]>0)+(dimorder[1]>0)+(dimorder[2]>0)) < ((xid!=UNDEFID)+(yid!=UNDEFID)+(zid!=UNDEFID)) )
+    {
+      printf("zid=%d  yid=%d  xid=%d\n", zid, yid, xid);
+      Error("Internal problem, dimension order missing!");
+    }
+
+  int tid = streamptr->basetime.ncdimid;
+
+  if ( tsteptype != TSTEP_CONSTANT )
+    {
+      if ( tid == UNDEFID ) Error("Internal problem, time undefined!");
+      chunks[ndims] = 1;
+      dims[ndims++] = tid;
+      axis[iax++] = 'T';
+    }
+  /*
+  if ( zid != UNDEFID ) axis[iax++] = 'Z';
+  if ( zid != UNDEFID ) chunks[ndims] = 1;
+  if ( zid != UNDEFID ) dims[ndims++] = zid;
+
+  if ( yid != UNDEFID ) chunks[ndims] = ysize;
+  if ( yid != UNDEFID ) dims[ndims++] = yid;
+
+  if ( xid != UNDEFID ) chunks[ndims] = xsize;
+  if ( xid != UNDEFID ) dims[ndims++] = xid;
+  */
+  for ( int id = 0; id < 3; ++id )
+    {
+      if ( dimorder[id] == 3 && zid != UNDEFID )
+        {
+          axis[iax++] = 'Z';
+          chunks[ndims] = 1;
+          dims[ndims] = zid;
+          ndims++;
+        }
+      else if ( dimorder[id] == 2 && yid != UNDEFID )
+        {
+          if ( chunktype == CHUNK_LINES )
+            chunks[ndims] = 1;
+          else
+            chunks[ndims] = ysize;
+          dims[ndims] = yid;
+          ndims++;
+        }
+      else if ( dimorder[id] == 1 && xid != UNDEFID )
+        {
+          chunks[ndims] = xsize;
+          dims[ndims] = xid;
+          ndims++;
+        }
+    }
+
+  if ( CDI_Debug )
+    fprintf(stderr, "chunktype %d  chunks %d %d %d %d\n", chunktype, (int)chunks[0], (int)chunks[1], (int)chunks[2], (int)chunks[3]);
+
+  int tableID  = vlistInqVarTable(vlistID, varID);
+
+  const char *name     = vlistInqVarNamePtr(vlistID, varID);
+  const char *longname = vlistInqVarLongnamePtr(vlistID, varID);
+  const char *stdname  = vlistInqVarStdnamePtr(vlistID, varID);
+  const char *units    = vlistInqVarUnitsPtr(vlistID, varID);
+
+  if ( name     == NULL )     name = tableInqParNamePtr(tableID, code);
+  if ( longname == NULL ) longname = tableInqParLongnamePtr(tableID, code);
+  if ( units    == NULL )    units = tableInqParUnitsPtr(tableID, code);
+  if ( name )
+    {
+      int checkname;
+      int iz;
+      int status;
+
+      sprintf(varname, "%s", name);
+
+      checkname = TRUE;
+      iz = 0;
+
+      while ( checkname )
+        {
+          if ( iz ) sprintf(varname, "%s_%d", name, iz+1);
+
+          status = nc_inq_varid(fileID, varname, &ncvarid);
+          if ( status != NC_NOERR )
+            {
+              checkname = FALSE;
+            }
+
+          if ( checkname ) iz++;
+
+          if ( iz >= CDI_MAX_NAME ) Error("Double entry of variable name '%s'!", name);
+        }
+
+      if ( strcmp(name, varname) != 0 )
+        {
+          if ( iz == 1 )
+            Warning("Changed double entry of variable name '%s' to '%s'!", name, varname);
+          else
+            Warning("Changed multiple entry of variable name '%s' to '%s'!", name, varname);
+        }
+
+      name = varname;
+    }
+  else
+    {
+      if ( code < 0 ) code = -code;
+      if ( pnum < 0 ) pnum = -pnum;
+
+      if ( pdis == 255 )
+	sprintf(varname, "var%d", code);
+      else
+	sprintf(varname, "param%d.%d.%d", pnum, pcat, pdis);
+
+      char *varname2 = varname+strlen(varname);
+
+      int checkname = TRUE;
+      int iz = 0;
+
+      while ( checkname )
+        {
+          if ( iz ) sprintf(varname2, "_%d", iz+1);
+
+          int status = nc_inq_varid(fileID, varname, &ncvarid);
+          if ( status != NC_NOERR ) checkname = FALSE;
+
+          if ( checkname ) iz++;
+
+          if ( iz >= CDI_MAX_NAME ) break;
+        }
+
+      name = varname;
+      code = 0;
+      pdis = 255;
+    }
+
+  /* if ( streamptr->ncmode == 2 ) cdf_redef(fileID); */
+
+  int dtype = vlistInqVarDatatype(vlistID, varID);
+  int xtype = cdfDefDatatype(dtype, streamptr->filetype);
+
+  cdf_def_var(fileID, name, (nc_type) xtype, ndims, dims, &ncvarid);
+
+#if  defined  (HAVE_NETCDF4)
+  if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
+    {
+      if ( chunktype == CHUNK_AUTO )
+        retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
+      else
+        retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, chunks);
+
+      if ( retval ) Error("nc_def_var_chunking failed, status = %d", retval);
+    }
+#endif
+
+  if ( streamptr->comptype == COMPRESS_ZIP )
+    {
+      if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
+        {
+          cdfDefVarDeflate(fileID, ncvarid, streamptr->complevel);
+        }
+      else
+        {
+          if ( lchunk )
+            {
+              static int lwarn = TRUE;
+
+              if ( lwarn )
+                {
+                  lwarn = FALSE;
+                  Warning("Deflate compression is only available for NetCDF4!");
+                }
+            }
+        }
+    }
+
+  if ( streamptr->comptype == COMPRESS_SZIP )
+    {
+      if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
+        {
+#if defined (NC_SZIP_NN_OPTION_MASK)
+          cdfDefVarSzip(fileID, ncvarid);
+#else
+          static int lwarn = TRUE;
+
+          if ( lwarn )
+            {
+              lwarn = FALSE;
+              Warning("NetCDF4/SZIP compression not available!");
+            }
+#endif
+        }
+      else
+        {
+          static int lwarn = TRUE;
+
+          if ( lwarn )
+            {
+              lwarn = FALSE;
+              Warning("SZIP compression is only available for NetCDF4!");
+            }
+        }
+    }
+
+  if ( stdname && *stdname )
+    cdf_put_att_text(fileID, ncvarid, "standard_name", strlen(stdname), stdname);
+
+  if ( longname && *longname )
+    cdf_put_att_text(fileID, ncvarid, "long_name", strlen(longname), longname);
+
+  if ( units && *units )
+    cdf_put_att_text(fileID, ncvarid, "units", strlen(units), units);
+
+  if ( code > 0 && pdis == 255 )
+    cdf_put_att_int(fileID, ncvarid, "code", NC_INT, 1, &code);
+
+  if ( pdis != 255 )
+    {
+      char paramstr[32];
+      cdiParamToString(param, paramstr, sizeof(paramstr));
+      cdf_put_att_text(fileID, ncvarid, "param", strlen(paramstr), paramstr);
+    }
+
+  if ( tableID != UNDEFID )
+    {
+      tablenum = tableInqNum(tableID);
+      if ( tablenum > 0 )
+        cdf_put_att_int(fileID, ncvarid, "table", NC_INT, 1, &tablenum);
+    }
+
+  char coordinates[CDI_MAX_NAME];
+  coordinates[0] = 0;
+
+  if ( zaxis_is_scalar )
+    {
+      int nczvarID = streamptr->nczvarID[zaxisindex];
+      if ( nczvarID != CDI_UNDEFID )
+        {
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, nczvarID, coordinates+len);
+        }
+    }
+
+  if ( gridtype != GRID_GENERIC && gridtype != GRID_LONLAT  && gridtype != GRID_CURVILINEAR )
+    {
+      size_t len = strlen(gridNamePtr(gridtype));
+      if ( len > 0 )
+        cdf_put_att_text(fileID, ncvarid, "grid_type", len, gridNamePtr(gridtype));
+    }
+
+  if ( gridIsRotated(gridID) )
+    {
+      char mapping[] = "rotated_pole";
+      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
+    }
+
+  if ( gridtype == GRID_SINUSOIDAL )
+    {
+      char mapping[] = "sinusoidal";
+      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
+    }
+  else if ( gridtype == GRID_LAEA )
+    {
+      char mapping[] = "laea";
+      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
+    }
+  else if ( gridtype == GRID_LCC2 )
+    {
+      char mapping[] = "Lambert_Conformal";
+      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
+    }
+  else if ( gridtype == GRID_TRAJECTORY )
+    {
+      cdf_put_att_text(fileID, ncvarid, "coordinates", 9, "tlon tlat" );
+    }
+  else if ( gridtype == GRID_LONLAT && xid == UNDEFID && yid == UNDEFID && gridsize == 1 )
+    {
+      int ncxvarID = streamptr->ncxvarID[gridindex];
+      int ncyvarID = streamptr->ncyvarID[gridindex];
+      if ( ncyvarID != CDI_UNDEFID )
+        {
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, ncyvarID, coordinates+len);
+        }
+      if ( ncxvarID != CDI_UNDEFID )
+        {
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, ncxvarID, coordinates+len);
+        }
+    }
+  else if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
+    {
+      char cellarea[CDI_MAX_NAME] = "area: ";
+      int ncxvarID = streamptr->ncxvarID[gridindex];
+      int ncyvarID = streamptr->ncyvarID[gridindex];
+      int ncavarID = streamptr->ncavarID[gridindex];
+      if ( ncyvarID != CDI_UNDEFID )
+        {
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, ncyvarID, coordinates+len);
+        }
+      if ( ncxvarID != CDI_UNDEFID )
+        {
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, ncxvarID, coordinates+len);
+        }
+
+      if ( ncavarID != CDI_UNDEFID )
+        {
+          size_t len = strlen(cellarea);
+          cdf_inq_varname(fileID, ncavarID, cellarea+len);
+          len = strlen(cellarea);
+          cdf_put_att_text(fileID, ncvarid, "cell_measures", len, cellarea);
+        }
+
+      if ( gridtype == GRID_UNSTRUCTURED )
+        {
+          int position = gridInqPosition(gridID);
+          if ( position > 0 )
+            cdf_put_att_int(fileID, ncvarid, "number_of_grid_in_reference", NC_INT, 1, &position);
+        }
+    }
+  else if ( gridtype == GRID_SPECTRAL || gridtype == GRID_FOURIER )
+    {
+      int gridTruncation = gridInqTrunc(gridID);
+      axis[iax++] = '-';
+      axis[iax++] = '-';
+      cdf_put_att_text(fileID, ncvarid, "axis", iax, axis);
+      cdf_put_att_int(fileID, ncvarid, "truncation", NC_INT, 1, &gridTruncation);
+    }
+
+  size_t len = strlen(coordinates);
+  if ( len ) cdf_put_att_text(fileID, ncvarid, "coordinates", len, coordinates);
+
+  /*  if ( xtype == NC_BYTE || xtype == NC_SHORT || xtype == NC_INT ) */
+    {
+      int laddoffset, lscalefactor;
+      double addoffset, scalefactor;
+      int astype = NC_DOUBLE;
+
+      addoffset    = vlistInqVarAddoffset(vlistID, varID);
+      scalefactor  = vlistInqVarScalefactor(vlistID, varID);
+      laddoffset   = IS_NOT_EQUAL(addoffset, 0);
+      lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+
+      if ( laddoffset || lscalefactor )
+        {
+          if ( IS_EQUAL(addoffset,   (double) ((float) addoffset)) &&
+               IS_EQUAL(scalefactor, (double) ((float) scalefactor)) )
+            {
+              astype = NC_FLOAT;
+            }
+
+          if ( xtype == (int) NC_FLOAT ) astype = NC_FLOAT;
+
+          cdf_put_att_double(fileID, ncvarid, "add_offset",   (nc_type) astype, 1, &addoffset);
+          cdf_put_att_double(fileID, ncvarid, "scale_factor", (nc_type) astype, 1, &scalefactor);
+        }
+    }
+
+  if ( dtype == DATATYPE_UINT8 && xtype == NC_BYTE )
+    {
+      int validrange[2] = {0, 255};
+      cdf_put_att_int(fileID, ncvarid, "valid_range", NC_SHORT, 2, validrange);
+      cdf_put_att_text(fileID, ncvarid, "_Unsigned", 4, "true");
+    }
+
+  streamptr->vars[varID].ncvarid = ncvarid;
+
+  if ( vlistInqVarMissvalUsed(vlistID, varID) )
+    cdfDefVarMissval(streamptr, varID, vlistInqVarDatatype(vlistID, varID), 0);
+
+  if ( zid == -1 )
+    {
+      if ( zaxisInqType(zaxisID) == ZAXIS_CLOUD_BASE          ||
+           zaxisInqType(zaxisID) == ZAXIS_CLOUD_TOP           ||
+           zaxisInqType(zaxisID) == ZAXIS_ISOTHERM_ZERO       ||
+           zaxisInqType(zaxisID) == ZAXIS_TOA                 ||
+           zaxisInqType(zaxisID) == ZAXIS_SEA_BOTTOM          ||
+           zaxisInqType(zaxisID) == ZAXIS_LAKE_BOTTOM         ||
+           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM     ||
+           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM_TA  ||
+           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM_TW  ||
+           zaxisInqType(zaxisID) == ZAXIS_MIX_LAYER           ||
+           zaxisInqType(zaxisID) == ZAXIS_ATMOSPHERE )
+        {
+          zaxisInqName(zaxisID, varname);
+          cdf_put_att_text(fileID, ncvarid, "level_type", strlen(varname), varname);
+        }
+    }
+
+  if ( vlistInqVarEnsemble( vlistID,  varID, &ensID, &ensCount, &forecast_type ) )
+    {
+      /* void cdf_put_att_int(  int ncid, int varid, const char *name, nc_type xtype,
+	                        size_t len, const int *ip )
+       */
+	cdf_put_att_int(fileID, ncvarid, "realization", NC_INT, 1, &ensID);
+	cdf_put_att_int(fileID, ncvarid, "ensemble_members", NC_INT, 1, &ensCount);
+	cdf_put_att_int(fileID, ncvarid, "forecast_init_type", NC_INT, 1, &forecast_type);
+
+#ifdef DBG
+	if( DBG )
+	  {
+	    fprintf( stderr, "cdfDefVar :\n EnsID  %d\n Enscount %d\n Forecast init type %d\n",  ensID,
+		     ensCount,  forecast_type );
+	  }
+#endif
+    }
+
+  /* Attributes */
+  cdfDefineAttributes(vlistID, varID, fileID, ncvarid);
+
+  /* if ( streamptr->ncmode == 2 ) cdf_enddef(fileID); */
+
+  return ncvarid;
+}
+
+
+void cdfEndDef(stream_t *streamptr)
+{
+  cdfDefGlobalAtts(streamptr);
+  cdfDefLocalAtts(streamptr);
+
+  if ( streamptr->accessmode == 0 )
+    {
+      int fileID  = streamptr->fileID;
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+      int nvars =  streamptr->nvars;
+      for ( int varID = 0; varID < nvars; varID++ )
+	cdfDefVar(streamptr, varID);
+
+      if ( streamptr->ncmode == 2 )
+        {
+          if ( CDI_netcdf_hdr_pad == 0UL )
+            cdf_enddef(fileID);
+          else
+            cdf__enddef(fileID, CDI_netcdf_hdr_pad);
+        }
+
+      streamptr->accessmode = 1;
+    }
+}
+
+static
+void cdfWriteGridTraj(stream_t *streamptr, int gridID)
+{
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+
+  int gridindex = vlistGridIndex(vlistID, gridID);
+  int lonID = streamptr->xdimID[gridindex];
+  int latID = streamptr->ydimID[gridindex];
+
+  double xlon = gridInqXval(gridID, 0);
+  double xlat = gridInqYval(gridID, 0);
+  int tsID = streamptr->curTsID;
+  size_t index = (size_t)tsID;
+
+  cdf_put_var1_double(fileID, lonID, &index, &xlon);
+  cdf_put_var1_double(fileID, latID, &index, &xlat);
+}
+
+static
+void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dtype, size_t nvals, size_t xsize, size_t ysize,
+                        int swapxy, size_t *start, size_t *count, int memtype, const void *data, int nmiss)
+{
+  const double *pdata_dp = (const double *) data;
+  double *mdata_dp = NULL;
+  double *sdata_dp = NULL;
+  const float *pdata_sp = (const float *) data;
+  float *mdata_sp = NULL;
+  float *sdata_sp = NULL;
+
+  /*  if ( dtype == DATATYPE_INT8 || dtype == DATATYPE_INT16 || dtype == DATATYPE_INT32 ) */
+    {
+      double missval      = vlistInqVarMissval(vlistID, varID);
+      double addoffset    = vlistInqVarAddoffset(vlistID, varID);
+      double scalefactor  = vlistInqVarScalefactor(vlistID, varID);
+      bool laddoffset     = IS_NOT_EQUAL(addoffset, 0);
+      bool lscalefactor   = IS_NOT_EQUAL(scalefactor, 1);
+
+      if ( laddoffset || lscalefactor )
+        {
+          if ( memtype == MEMTYPE_FLOAT )
+            {
+              mdata_sp = (float *) Malloc(nvals*sizeof(float));
+              memcpy(mdata_sp, pdata_sp, nvals*sizeof(float));
+              pdata_sp = mdata_sp;
+
+              if ( nmiss > 0 )
+                {
+                  for ( size_t i = 0; i < nvals; i++ )
+                    {
+                      double temp = mdata_sp[i];
+                      if ( !DBL_IS_EQUAL(temp, missval) )
+                        {
+                          if ( laddoffset )   temp -= addoffset;
+                          if ( lscalefactor ) temp /= scalefactor;
+                          mdata_sp[i] = (float)temp;
+                        }
+                    }
+                }
+              else
+                {
+                  for ( size_t i = 0; i < nvals; i++ )
+                    {
+                      double temp = mdata_sp[i];
+                      if ( laddoffset )   temp -= addoffset;
+                      if ( lscalefactor ) temp /= scalefactor;
+                      mdata_sp[i] = (float)temp;
+                    }
+                }
+            }
+          else
+            {
+              mdata_dp = (double *) Malloc(nvals*sizeof(double));
+              memcpy(mdata_dp, pdata_dp, nvals*sizeof(double));
+              pdata_dp = mdata_dp;
+
+              if ( nmiss > 0 )
+                {
+                  for ( size_t i = 0; i < nvals; i++ )
+                    {
+                      if ( !DBL_IS_EQUAL(mdata_dp[i], missval) )
+                        {
+                          if ( laddoffset )   mdata_dp[i] -= addoffset;
+                          if ( lscalefactor ) mdata_dp[i] /= scalefactor;
+                        }
+                    }
+                }
+              else
+                {
+                  for ( size_t i = 0; i < nvals; i++ )
+                    {
+                      if ( laddoffset )   mdata_dp[i] -= addoffset;
+                      if ( lscalefactor ) mdata_dp[i] /= scalefactor;
+                    }
+                }
+            }
+        }
+
+      if ( dtype == DATATYPE_UINT8 || dtype == DATATYPE_INT8 ||
+           dtype == DATATYPE_INT16 || dtype == DATATYPE_INT32 )
+        {
+          if ( memtype == MEMTYPE_FLOAT )
+            {
+              if ( mdata_sp == NULL )
+                {
+                  mdata_sp = (float *) Malloc(nvals*sizeof(float));
+                  memcpy(mdata_sp, pdata_sp, nvals*sizeof(float));
+                  pdata_sp = mdata_sp;
+                }
+
+              for ( size_t i = 0; i < nvals; i++ ) mdata_sp[i] = roundf(mdata_sp[i]);
+
+              if ( dtype == DATATYPE_UINT8 )
+                {
+                  nc_type xtype;
+                  cdf_inq_vartype(fileID, ncvarid, &xtype);
+                  if ( xtype == NC_BYTE )
+                    {
+                      for ( size_t i = 0; i < nvals; ++i )
+                        if ( mdata_sp[i] > 127 ) mdata_sp[i] -= 256;
+                    }
+                }
+            }
+          else
+            {
+              if ( mdata_dp == NULL )
+                {
+                  mdata_dp = (double *) Malloc(nvals*sizeof(double));
+                  memcpy(mdata_dp, pdata_dp, nvals*sizeof(double));
+                  pdata_dp = mdata_dp;
+                }
+
+              for ( size_t i = 0; i < nvals; i++ ) mdata_dp[i] = round(mdata_dp[i]);
+
+              if ( dtype == DATATYPE_UINT8 )
+                {
+                  nc_type xtype;
+                  cdf_inq_vartype(fileID, ncvarid, &xtype);
+                  if ( xtype == NC_BYTE )
+                    {
+                      for ( size_t i = 0; i < nvals; ++i )
+                        if ( mdata_dp[i] > 127 ) mdata_dp[i] -= 256;
+                    }
+                }
+            }
+        }
+
+      if ( CDF_Debug && memtype != MEMTYPE_FLOAT )
+        {
+          double fmin, fmax;
+          fmin =  1.0e200;
+          fmax = -1.0e200;
+          for ( size_t i = 0; i < nvals; ++i )
+            {
+              if ( !DBL_IS_EQUAL(pdata_dp[i], missval) )
+                {
+                  if ( pdata_dp[i] < fmin ) fmin = pdata_dp[i];
+                  if ( pdata_dp[i] > fmax ) fmax = pdata_dp[i];
+                }
+            }
+          Message("nvals = %zu, nmiss = %d, missval = %g, minval = %g, maxval = %g",
+                  nvals, nmiss, missval, fmin, fmax);
+        }
+    }
+
+  if ( swapxy ) // implemented only for cdf_write_var_slice() 
+    {
+      size_t gridsize = xsize*ysize;
+      if ( memtype == MEMTYPE_FLOAT )
+        {
+          sdata_sp = (float *) Malloc(gridsize*sizeof(float));
+          for ( size_t j = 0; j < ysize; ++j )
+            for ( size_t i = 0; i < xsize; ++i )
+              sdata_sp[i*ysize+j] = pdata_sp[j*xsize+i];
+          pdata_sp = sdata_sp;
+        }
+      else
+        {
+          sdata_dp = (double *) Malloc(gridsize*sizeof (double));
+          for ( size_t j = 0; j < ysize; ++j )
+            for ( size_t i = 0; i < xsize; ++i )
+              sdata_dp[i*ysize+j] = pdata_dp[j*xsize+i];
+          pdata_dp = sdata_dp;
+        }
+    }
+
+  if ( memtype == MEMTYPE_FLOAT )
+    cdf_put_vara_float(fileID, ncvarid, start, count, pdata_sp);
+  else
+    cdf_put_vara_double(fileID, ncvarid, start, count, pdata_dp);
+
+  if ( mdata_dp ) Free(mdata_dp);
+  if ( sdata_dp ) Free(sdata_dp);
+  if ( mdata_sp ) Free(mdata_sp);
+  if ( sdata_sp ) Free(sdata_sp);
+}
+
+
+void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
+{
+  if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
+
+  size_t xsize = 0, ysize = 0;
+  size_t size;
+  size_t start[5];
+  size_t count[5];
+  int swapxy = FALSE;
+  int ndims = 0;
+  int idim;
+
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
+
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+
+  long ntsteps = streamptr->ntsteps;
+  if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
+
+  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
+
+  int ncvarid = cdfDefVar(streamptr, varID);
+
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+
+  int xid = UNDEFID, yid = UNDEFID;
+  if ( gridInqType(gridID) == GRID_TRAJECTORY )
+    {
+      cdfWriteGridTraj(streamptr, gridID);
+    }
+  else
+    {
+      int gridindex = vlistGridIndex(vlistID, gridID);
+      xid = streamptr->xdimID[gridindex];
+      yid = streamptr->ydimID[gridindex];
+    }
+
+  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+  int zid = streamptr->zaxisID[zaxisindex];
+
+  if ( tsteptype != TSTEP_CONSTANT )
+    {
+      start[ndims] = (size_t)ntsteps - 1;
+      count[ndims] = 1;
+      ndims++;
+    }
+
+  if ( zid != UNDEFID )
+    {
+      start[ndims] = 0;
+      count[ndims] = (size_t)zaxisInqSize(zaxisID);
+      ndims++;
+    }
+
+  if ( yid != UNDEFID )
+    {
+      start[ndims] = 0;
+      cdf_inq_dimlen(fileID, yid, &size);
+      /*      count[ndims] = gridInqYsize(gridID); */
+      count[ndims] = size;
+      ndims++;
+    }
+
+  if ( xid != UNDEFID )
+    {
+      start[ndims] = 0;
+      cdf_inq_dimlen(fileID, xid, &size);
+      /*      count[ndims] = gridInqXsize(gridID); */
+      count[ndims] = size;
+      ndims++;
+    }
+
+  if ( CDI_Debug )
+    for (idim = 0; idim < ndims; idim++)
+      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
+
+  if ( streamptr->ncmode == 1 )
+    {
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+    }
+
+  int dtype = vlistInqVarDatatype(vlistID, varID);
+
+  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
+
+  size_t nvals = (size_t)(gridInqSize(gridID)) * (size_t)(zaxisInqSize(zaxisID));
+
+  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
+}
+
+
+void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
+                         const int rect[][2], const void *data, int nmiss)
+{
+  if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
+
+  int xid = UNDEFID, yid = UNDEFID;
+  size_t xsize = 0, ysize = 0;
+  size_t start[5];
+  size_t count[5];
+  int swapxy = FALSE;
+  int ndims = 0;
+  int idim;
+  int streamID = streamptr->self;
+
+  if ( CDI_Debug )
+    Message("streamID = %d  varID = %d", streamID, varID);
+
+  int vlistID = streamInqVlist(streamID);
+  int fileID  = streamInqFileID(streamID);
+
+  long ntsteps = streamptr->ntsteps;
+  if ( CDI_Debug )
+    Message("ntsteps = %ld", ntsteps);
+
+  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
+
+  int ncvarid = cdfDefVar(streamptr, varID);
+
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+
+  if ( gridInqType(gridID) == GRID_TRAJECTORY )
+    {
+      cdfWriteGridTraj(streamptr, gridID);
+    }
+  else
+    {
+      int gridindex = vlistGridIndex(vlistID, gridID);
+      xid = streamptr->xdimID[gridindex];
+      yid = streamptr->ydimID[gridindex];
+    }
+
+  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+  int zid = streamptr->zaxisID[zaxisindex];
+
+  if ( tsteptype != TSTEP_CONSTANT )
+    {
+      start[ndims] = (size_t)ntsteps - 1;
+      count[ndims] = 1;
+      ndims++;
+    }
+  if ( zid != UNDEFID )
+    {
+      int size = zaxisInqSize(zaxisID);
+      xassert(rect[2][0] >= 0 && rect[2][0] <= rect[2][1]
+              && rect[2][1] <= size);
+      start[ndims] = (size_t)rect[2][0];
+      count[ndims] = (size_t)rect[2][1] - (size_t)rect[2][0] + 1;
+      ndims++;
+    }
+  if ( yid != UNDEFID )
+    {
+      size_t size;
+      cdf_inq_dimlen(fileID, yid, &size);
+      xassert(rect[1][0] >= 0 && rect[1][0] <= rect[1][1]
+              && (size_t)rect[1][1] <= size);
+      start[ndims] = (size_t)rect[1][0];
+      count[ndims] = (size_t)rect[1][1] - (size_t)rect[1][0] + 1;
+      ndims++;
+    }
+  if ( xid != UNDEFID )
+    {
+      size_t size;
+      cdf_inq_dimlen(fileID, xid, &size);
+      xassert(rect[0][0] >= 0 && rect[0][0] <= rect[0][1]
+              && (size_t)rect[0][1] <= size);
+      start[ndims] = (size_t)rect[0][0];
+      count[ndims] = (size_t)rect[0][1] - (size_t)rect[0][0] + 1;
+      ndims++;
+    }
+
+  if ( CDI_Debug )
+    for (idim = 0; idim < ndims; idim++)
+      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
+
+  if ( streamptr->ncmode == 1 )
+    {
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+    }
+
+  int dtype = vlistInqVarDatatype(vlistID, varID);
+
+  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
+
+  size_t nvals = (size_t)(gridInqSize(gridID)) * (size_t)(zaxisInqSize(zaxisID));
+
+  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals,
+                     xsize, ysize, swapxy, start, count, memtype, data, nmiss);
+}
+
+
+void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
+{
+  if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
+
+  size_t xsize = 0, ysize = 0;
+  size_t start[5];
+  size_t count[5];
+  int dimorder[3];
+  int xid = UNDEFID, yid = UNDEFID;
+
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
+
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+
+  long ntsteps = streamptr->ntsteps;
+  if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
+
+  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
+
+  int ncvarid = cdfDefVar(streamptr, varID);
+
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  vlistInqVarDimorder(vlistID, varID, &dimorder);
+
+  if ( gridInqType(gridID) == GRID_TRAJECTORY )
+    {
+      cdfWriteGridTraj(streamptr, gridID);
+    }
+  else
+    {
+      int gridindex = vlistGridIndex(vlistID, gridID);
+      xid = streamptr->xdimID[gridindex];
+      yid = streamptr->ydimID[gridindex];
+    }
+
+  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+  int zid = streamptr->zaxisID[zaxisindex];
+
+  int swapxy = (dimorder[2] == 2 || dimorder[0] == 1) && xid != UNDEFID && yid != UNDEFID;
+
+  size_t ndims = 0;
+  if ( tsteptype != TSTEP_CONSTANT )
+    {
+      start[ndims] = (size_t)ntsteps - 1;
+      count[ndims] = 1;
+      ndims++;
+    }
+
+  for ( int id = 0; id < 3; ++id )
+    {
+      if ( dimorder[id] == 3 && zid != UNDEFID )
+        {
+          start[ndims] = (size_t)levelID;
+          count[ndims] = 1;
+          ndims++;
+        }
+      else if ( dimorder[id] == 2 && yid != UNDEFID )
+        {
+          start[ndims] = 0;
+          cdf_inq_dimlen(fileID, yid, &ysize);
+          count[ndims] = ysize;
+          ndims++;
+        }
+      else if ( dimorder[id] == 1 && xid != UNDEFID )
+        {
+          start[ndims] = 0;
+          cdf_inq_dimlen(fileID, xid, &xsize);
+          count[ndims] = xsize;
+          ndims++;
+        }
+    }
+
+  if ( CDI_Debug )
+    for (size_t idim = 0; idim < ndims; idim++)
+      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
+
+  int dtype = vlistInqVarDatatype(vlistID, varID);
+
+  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
+
+  size_t nvals = (size_t)(gridInqSize(gridID));
+
+  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
+}
+
+
+void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss)
+{
+  int varID   = streamptr->record->varID;
+  int levelID = streamptr->record->levelID;
+
+  cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+}
+
+#endif
diff --git a/libcdi/src/cdi.h b/libcdi/src/cdi.h
index 60d383e..7231b6a 100644
--- a/libcdi/src/cdi.h
+++ b/libcdi/src/cdi.h
@@ -9,11 +9,12 @@
 
 #include <stdio.h>
 #include <sys/types.h>
-/*
+
 #ifdef __cplusplus
 extern "C" {
 #endif
-*/
+
+
 #define  CDI_MAX_NAME           256   /* max length of a name                 */
 
 #define  CDI_UNDEFID             -1
@@ -38,7 +39,7 @@ extern "C" {
 #define  CDI_EUFTYPE            -21   /* Unsupported file type                */
 #define  CDI_ELIBNAVAIL         -22   /* xxx library not available            */
 #define  CDI_EUFSTRUCT          -23   /* Unsupported file structure           */
-#define  CDI_EUNC4              -24   /* Unsupported netCDF4 structure        */
+#define  CDI_EUNC4              -24   /* Unsupported NetCDF4 structure        */
 #define  CDI_ELIMIT             -99   /* Internal limits exceeded             */
 
 /* File types */
@@ -46,10 +47,10 @@ extern "C" {
 #define  FILETYPE_UNDEF          -1   /* Unknown/not yet defined file type */
 #define  FILETYPE_GRB             1   /* File type GRIB                       */
 #define  FILETYPE_GRB2            2   /* File type GRIB version 2             */
-#define  FILETYPE_NC              3   /* File type netCDF                     */
-#define  FILETYPE_NC2             4   /* File type netCDF version 2 (64-bit)  */
-#define  FILETYPE_NC4             5   /* File type netCDF version 4           */
-#define  FILETYPE_NC4C            6   /* File type netCDF version 4 (classic) */
+#define  FILETYPE_NC              3   /* File type NetCDF                     */
+#define  FILETYPE_NC2             4   /* File type NetCDF version 2 (64-bit)  */
+#define  FILETYPE_NC4             5   /* File type NetCDF version 4           */
+#define  FILETYPE_NC4C            6   /* File type NetCDF version 4 (classic) */
 #define  FILETYPE_SRV             7   /* File type SERVICE                    */
 #define  FILETYPE_EXT             8   /* File type EXTRA                      */
 #define  FILETYPE_IEG             9   /* File type IEG                        */
@@ -148,7 +149,7 @@ extern "C" {
 #define  ZAXIS_HYBRID               2  /* Hybrid level                                          */
 #define  ZAXIS_HYBRID_HALF          3  /* Hybrid half level                                     */
 #define  ZAXIS_PRESSURE             4  /* Isobaric pressure level in Pascal                     */
-#define  ZAXIS_HEIGHT               5  /* Height above ground in meters                         */
+#define  ZAXIS_HEIGHT               5  /* Height above ground                                   */
 #define  ZAXIS_DEPTH_BELOW_SEA      6  /* Depth below sea level in meters                       */
 #define  ZAXIS_DEPTH_BELOW_LAND     7  /* Depth below land surface in centimeters               */
 #define  ZAXIS_ISENTROPIC           8  /* Isentropic                                            */
@@ -384,6 +385,7 @@ void    streamInqRecord(int streamID, int *varID, int *levelID);
 void    streamWriteRecord(int streamID, const double data[], int nmiss);
 void    streamWriteRecordF(int streamID, const float data[], int nmiss);
 void    streamReadRecord(int streamID, double data[], int *nmiss);
+void    streamReadRecordF(int streamID, float data[], int *nmiss);
 void    streamCopyRecord(int streamIDdest, int streamIDsrc);
 
 void    streamInqGRIBinfo(int streamID, int *intnum, float *fltnum, off_t *bignum);
@@ -406,11 +408,15 @@ int cdiIterator_nextField(CdiIterator *me);      //Points the iterator at the ne
 //All outXXX arguments to these functions may be NULL.
 char *cdiIterator_inqStartTime(CdiIterator *me);      //Returns the (start) time as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
 char *cdiIterator_inqEndTime(CdiIterator *me);      //Returns the end time of an integration period as an ISO-8601 coded string, or NULL if there is no end time. The caller is responsible to Free() the returned string.
+char *cdiIterator_inqRTime(CdiIterator *me);      //Returns the reference date as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
 char *cdiIterator_inqVTime(CdiIterator *me);      //Returns the validity date as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
 int cdiIterator_inqLevelType(CdiIterator *me, int levelSelector, char **outName_optional, char **outLongName_optional, char **outStdName_optional, char **outUnit_optional);      //callers are responsible to Free() strings that they request
 int cdiIterator_inqLevel(CdiIterator *me, int levelSelector, double *outValue1_optional, double *outValue2_optional);       //outValue2 is only written to if the level is a hybrid level
 int cdiIterator_inqLevelUuid(CdiIterator *me, int *outVgridNumber_optional, int *outLevelCount_optional, unsigned char outUuid_optional[CDI_UUID_SIZE]);   //outUuid must point to a buffer of 16 bytes, returns an error code if no generalized zaxis is used.
+int cdiIterator_inqTile(CdiIterator *me, int *outTileIndex, int *outTileAttribute); //Returns CDI_EINVAL if there is no tile information connected to the current field, *outTileIndex and *outTileAttribute will be set to -1 in this case.
+int cdiIterator_inqTileCount(CdiIterator *me, int *outTileCount, int *outTileAttributeCount); //outTileAttributeCount is the count for the tile associated with the current field, a total attribute count cannot be inquired. Returns CDI_EINVAL if there is no tile information connected to the current field, *outTileCount and *outTileAttributeCount will be set to 0 in this case.
 CdiParam cdiIterator_inqParam(CdiIterator *me);
+void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber);	//Some FORTRAN compilers produce wrong code for the cdiIterator_inqParam()-wrapper, rendering it unusable from FORTRAN. This function is the workaround.
 int cdiIterator_inqDatatype(CdiIterator *me);
 int cdiIterator_inqTsteptype(CdiIterator *me);
 char *cdiIterator_inqVariableName(CdiIterator *me);        //The caller is responsible to Free() the returned buffer.
@@ -580,7 +586,7 @@ void    vlistDefVarName(int vlistID, int varID, const char *name);
 void    vlistInqVarName(int vlistID, int varID, char *name);
 
 /*      vlistCopyVarName: Safe and convenient version of vlistInqVarName */
-char *vlistCopyVarName(int vlistId, int varId);
+char   *vlistCopyVarName(int vlistId, int varId);
 
 /*      vlistDefVarStdname: Define the standard name of a Variable */
 void    vlistDefVarStdname(int vlistID, int varID, const char *stdname);
@@ -660,6 +666,10 @@ double  vlistInqVarDblKey(int vlistID, int varID, const char *name);
 /* vlistInqVarIntKey: raw access to GRIB meta-data */
 int     vlistInqVarIntKey(int vlistID, int varID, const char *name);
 
+/* needed only for CDO operator after */
+const char *vlistInqVarNamePtr(int vlistID, int varID);
+const char *vlistInqVarLongnamePtr(int vlistID, int varID);
+const char *vlistInqVarUnitsPtr(int vlistID, int varID);
 
 /* VLIST attributes */
 
@@ -1136,6 +1146,7 @@ int     tableInqParName(int tableID, int code, char *name);
 int     tableInqParLongname(int tableID, int code, char *longname);
 int     tableInqParUnits(int tableID, int code, char *units);
 
+/* needed only for CDO operator after */
 const char *tableInqParNamePtr(int tableID, int parID);
 const char *tableInqParLongnamePtr(int tableID, int parID);
 const char *tableInqParUnitsPtr(int tableID, int parID);
@@ -1179,18 +1190,19 @@ int     subtypeInqSubEntry(int subtypeID, subtype_query_t criterion);
 /*      subtypeInqTile: Specialized version of subtypeInqSubEntry looking for tile/attribute pair. */
 int     subtypeInqTile(int subtypeID, int tileindex, int attribute);
 
+/*      subtypeInqAttribute: Inquire the value of a subtype attribute. Returns CDI_EINVAL if the attribute does not exist.*/
+int     subtypeInqAttribute(int subtypeID, int index, const char *key, int *outValue);
+
 /*      vlistInqVarSubtype: Return subtype ID for a given variable. */
 int     vlistInqVarSubtype(int vlistID, int varID);
 
-
 void gribapiLibraryVersion(int *major_version, int *minor_version, int *revision_version);
 
 
-/*
 #if defined (__cplusplus)
 }
 #endif
-*/
+
 #endif  /* CDI_H_ */
 /*
  * Local Variables:
diff --git a/libcdi/src/cdi.inc b/libcdi/src/cdi.inc
index 057f9f0..eb83f8c 100644
--- a/libcdi/src/cdi.inc
+++ b/libcdi/src/cdi.inc
@@ -1,10 +1,10 @@
 ! This file was automatically generated, don't edit!
 !
-! Fortran interface for CDI library version 1.7.0
+! Fortran interface for CDI library version 1.7.1
 !
 ! Author:
 ! -------
-! Uwe Schulzweida, MPI-MET, Hamburg,   October 2015
+! Uwe Schulzweida, MPI-MET, Hamburg,   February 2016
 !
 
       INTEGER    CDI_MAX_NAME          
@@ -703,6 +703,12 @@
 !                                     INTEGER         nmiss)
       EXTERNAL        streamReadRecord
 
+!                     streamReadRecordF
+!                                    (INTEGER         streamID,
+!                                     REAL            data(*),
+!                                     INTEGER         nmiss)
+      EXTERNAL        streamReadRecordF
+
 !                     streamCopyRecord
 !                                    (INTEGER         streamIDdest,
 !                                     INTEGER         streamIDsrc)
@@ -1316,6 +1322,24 @@
       EXTERNAL        vlistInqVarIntKey
 
 !
+!  needed only for CDO operator after
+!
+      CHARACTER(80)   vlistInqVarNamePtr
+!                                    (INTEGER         vlistID,
+!                                     INTEGER         varID)
+      EXTERNAL        vlistInqVarNamePtr
+
+      CHARACTER(80)   vlistInqVarLongnamePtr
+!                                    (INTEGER         vlistID,
+!                                     INTEGER         varID)
+      EXTERNAL        vlistInqVarLongnamePtr
+
+      CHARACTER(80)   vlistInqVarUnitsPtr
+!                                    (INTEGER         vlistID,
+!                                     INTEGER         varID)
+      EXTERNAL        vlistInqVarUnitsPtr
+
+!
 !  VLIST attributes
 !
       INTEGER         vlistInqNatts
@@ -2394,6 +2418,9 @@
 !                                     CHARACTER*(*)   units)
       EXTERNAL        tableInqParUnits
 
+!
+!  needed only for CDO operator after
+!
       CHARACTER(80)   tableInqParNamePtr
 !                                    (INTEGER         tableID,
 !                                     INTEGER         parID)
@@ -2475,6 +2502,13 @@
 !                                     INTEGER         attribute)
       EXTERNAL        subtypeInqTile
 
+      INTEGER         subtypeInqAttribute
+!                                    (INTEGER         subtypeID,
+!                                     INTEGER         index,
+!                                     CHARACTER*(*)   key,
+!                                     INTEGER         outValue)
+      EXTERNAL        subtypeInqAttribute
+
       INTEGER         vlistInqVarSubtype
 !                                    (INTEGER         vlistID,
 !                                     INTEGER         varID)
diff --git a/libcdi/src/cdiFortran.c b/libcdi/src/cdiFortran.c
index dd53644..e8fd509 100644
--- a/libcdi/src/cdiFortran.c
+++ b/libcdi/src/cdiFortran.c
@@ -153,6 +153,7 @@ FCALLSCSUB3 (streamInqRecord, STREAMINQRECORD, streaminqrecord, INT, PINT, PINT)
 FCALLSCSUB3 (streamWriteRecord, STREAMWRITERECORD, streamwriterecord, INT, DOUBLEV, INT)
 FCALLSCSUB3 (streamWriteRecordF, STREAMWRITERECORDF, streamwriterecordf, INT, FLOATV, INT)
 FCALLSCSUB3 (streamReadRecord, STREAMREADRECORD, streamreadrecord, INT, DOUBLEV, PINT)
+FCALLSCSUB3 (streamReadRecordF, STREAMREADRECORDF, streamreadrecordf, INT, FLOATV, PINT)
 FCALLSCSUB2 (streamCopyRecord, STREAMCOPYRECORD, streamcopyrecord, INT, INT)
 
 /*  File driven I/O (may yield better performance than using the streamXXX functions)  */
@@ -280,6 +281,12 @@ FCALLSCFUN3 (INT, vlistHasVarKey, VLISTHASVARKEY, vlisthasvarkey, INT, INT, STRI
 FCALLSCFUN3 (DOUBLE, vlistInqVarDblKey, VLISTINQVARDBLKEY, vlistinqvardblkey, INT, INT, STRING)
 FCALLSCFUN3 (INT, vlistInqVarIntKey, VLISTINQVARINTKEY, vlistinqvarintkey, INT, INT, STRING)
 
+/*  needed only for CDO operator after  */
+
+FCALLSCFUN2 (STRING, vlistInqVarNamePtr, VLISTINQVARNAMEPTR, vlistinqvarnameptr, INT, INT)
+FCALLSCFUN2 (STRING, vlistInqVarLongnamePtr, VLISTINQVARLONGNAMEPTR, vlistinqvarlongnameptr, INT, INT)
+FCALLSCFUN2 (STRING, vlistInqVarUnitsPtr, VLISTINQVARUNITSPTR, vlistinqvarunitsptr, INT, INT)
+
 /*  VLIST attributes  */
 
 FCALLSCFUN3 (INT, vlistInqNatts, VLISTINQNATTS, vlistinqnatts, INT, INT, PINT)
@@ -522,6 +529,9 @@ FCALLSCFUN3 (INT, tableInqParCode, TABLEINQPARCODE, tableinqparcode, INT, PSTRIN
 FCALLSCFUN3 (INT, tableInqParName, TABLEINQPARNAME, tableinqparname, INT, INT, PSTRING)
 FCALLSCFUN3 (INT, tableInqParLongname, TABLEINQPARLONGNAME, tableinqparlongname, INT, INT, PSTRING)
 FCALLSCFUN3 (INT, tableInqParUnits, TABLEINQPARUNITS, tableinqparunits, INT, INT, PSTRING)
+
+/*  needed only for CDO operator after  */
+
 FCALLSCFUN2 (STRING, tableInqParNamePtr, TABLEINQPARNAMEPTR, tableinqparnameptr, INT, INT)
 FCALLSCFUN2 (STRING, tableInqParLongnamePtr, TABLEINQPARLONGNAMEPTR, tableinqparlongnameptr, INT, INT)
 FCALLSCFUN2 (STRING, tableInqParUnitsPtr, TABLEINQPARUNITSPTR, tableinqparunitsptr, INT, INT)
@@ -554,6 +564,7 @@ FCALLSCSUB2 (subtypeDefActiveIndex, SUBTYPEDEFACTIVEINDEX, subtypedefactiveindex
          query objects.  */
 
 FCALLSCFUN3 (INT, subtypeInqTile, SUBTYPEINQTILE, subtypeinqtile, INT, INT, INT)
+FCALLSCFUN4 (INT, subtypeInqAttribute, SUBTYPEINQATTRIBUTE, subtypeinqattribute, INT, INT, STRING, PINT)
 FCALLSCFUN2 (INT, vlistInqVarSubtype, VLISTINQVARSUBTYPE, vlistinqvarsubtype, INT, INT)
 FCALLSCSUB3 (gribapiLibraryVersion, GRIBAPILIBRARYVERSION, gribapilibraryversion, PINT, PINT, PINT)
 
diff --git a/libcdi/src/cdi_error.c b/libcdi/src/cdi_error.c
index 36be80a..d0fd603 100644
--- a/libcdi/src/cdi_error.c
+++ b/libcdi/src/cdi_error.c
@@ -13,7 +13,7 @@ const char *cdiStringError(int cdiErrno)
   static const char _EUFTYPE[]     = "Unsupported file type";
   static const char _ELIBNAVAIL[]  = "Unsupported file type (library support not compiled in)";
   static const char _EUFSTRUCT[]   = "Unsupported file structure";
-  static const char _EUNC4[]       = "Unsupported netCDF4 structure";
+  static const char _EUNC4[]       = "Unsupported NetCDF4 structure";
   static const char _ELIMIT[]      = "Internal limits exceeded";
 
   switch (cdiErrno) {
diff --git a/libcdi/src/cdi_int.c b/libcdi/src/cdi_int.c
index 332b641..954122c 100644
--- a/libcdi/src/cdi_int.c
+++ b/libcdi/src/cdi_int.c
@@ -39,6 +39,7 @@ int cdiInventoryMode        = 1;
 int CDI_Version_Info        = 1;
 int CDI_cmor_mode           = 0;
 size_t CDI_netcdf_hdr_pad   = 0UL;
+bool CDI_netcdf_lazy_grid_load = false;
 
 char *cdiPartabPath   = NULL;
 int   cdiPartabIntern = 1;
@@ -49,10 +50,10 @@ static const char Filetypes[][9] = {
   "UNKNOWN",
   "GRIB",
   "GRIB2",
-  "netCDF",
-  "netCDF2",
-  "netCDF4",
-  "netCDF4c",
+  "NetCDF",
+  "NetCDF2",
+  "NetCDF4",
+  "NetCDF4c",
   "SERVICE",
   "EXTRA",
   "IEG",
@@ -129,7 +130,7 @@ void cdiPrintVersion(void)
   fprintf(stderr, "GRIB_API library version : %s\n", gribapiLibraryVersionString());
 #endif
 #if  defined  (HAVE_LIBNETCDF)
-  fprintf(stderr, "  netCDF library version : %s\n", cdfLibraryVersion());
+  fprintf(stderr, "  NetCDF library version : %s\n", cdfLibraryVersion());
 #endif
 #if  defined  (HAVE_LIBHDF5)
   fprintf(stderr, "    HDF5 library version : %s\n", hdfLibraryVersion());
@@ -423,6 +424,8 @@ void cdiDefGlobal(const char *string, int val)
   else if ( strcmp(string, "NC_CHUNKSIZEHINT") == 0 ) cdiNcChunksizehint = val;
   else if ( strcmp(string, "CMOR_MODE")        == 0 ) CDI_cmor_mode = val;
   else if ( strcmp(string, "NETCDF_HDR_PAD")   == 0 ) CDI_netcdf_hdr_pad = (size_t) val;
+  else if ( strcmp(string, "NETCDF_LAZY_GRID_LOAD") == 0)
+    CDI_netcdf_lazy_grid_load = (bool)val;
   else Warning("Unsupported global key: %s", string);
 }
 
diff --git a/libcdi/src/cdi_int.h b/libcdi/src/cdi_int.h
index b53a829..f558ac6 100644
--- a/libcdi/src/cdi_int.h
+++ b/libcdi/src/cdi_int.h
@@ -151,7 +151,7 @@ typedef struct
   int       ilevel;
   int       ilevel2;
   int       ltype;
-  int       tsteptype;
+  short     tsteptype;
   short     used;
   short     varID;
   short     levelID;
@@ -282,6 +282,13 @@ typedef struct
   int                    subtype_index;  /* tile index for this key-value pair */
 } opt_key_val_pair_t;
 
+//enum for differenciating between the different times that we handle
+typedef enum {
+  kCdiTimeType_referenceTime,
+  kCdiTimeType_startTime,
+  kCdiTimeType_endTime
+} CdiTimeType;
+
 
 
 
@@ -309,6 +316,7 @@ extern int cdiInventoryMode;
 extern int CDI_Version_Info;
 extern int CDI_cmor_mode;
 extern size_t CDI_netcdf_hdr_pad;
+extern bool CDI_netcdf_lazy_grid_load;
 extern int STREAM_Debug;
 
 
@@ -375,21 +383,8 @@ int     getByteswap(int byteorder);
 
 void cdiStreamGetIndexList(unsigned numIDs, int IDs[]);
 
-
 void  cdiInitialize(void);
 
-void uuid2str(const unsigned char uuid[], char uuidstr[]);
-int str2uuid(const char *uuidstr, unsigned char uuid[]);
-
-static inline int cdiUUIDIsNull(const unsigned char uuid[])
-{
-  int isNull = 1;
-  for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
-    isNull &= (uuid[i] == 0);
-  return isNull;
-}
-
-
 char *cdiEscapeSpaces(const char *string);
 char *cdiUnescapeSpaces(const char *string, const char **outStringEnd);
 
@@ -420,9 +415,10 @@ streamOpenID(const char *filename, char filemode, int filetype,
 
 void
 cdiStreamDefVlist_(int streamID, int vlistID);
-void
-cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data,
-                   int nmiss);
+
+int
+cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, int nmiss);
+
 void
 cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
                         const int rect[][2], const void *data, int nmiss);
@@ -436,14 +432,33 @@ void cdiStreamSync_(stream_t *streamptr);
 
 const char *cdiUnitNamePtr(int cdi_unit);
 
+enum {
+  /* 8192 is known to work on most systems (4096 isn't on Alpha) */
+  commonPageSize = 8192,
+};
+
+size_t cdiGetPageSize(bool largePageAlign);
+
 void zaxisGetIndexList(int nzaxis, int *zaxisIndexList);
 
 void zaxisDefLtype2(int zaxisID, int ltype2);
 int  zaxisInqLtype2(int zaxisID);
 
-/* used by CDO */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// functions used in CDO !!!
+
 void cdiDefTableID(int tableID);
 
+void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *xvals);
+void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *yvals);
+
+#if defined (__cplusplus)
+}
+#endif
+
 #endif  /* _CDI_INT_H */
 /*
  * Local Variables:
diff --git a/libcdi/src/cdi_util.c b/libcdi/src/cdi_util.c
index 600a974..6b5951f 100644
--- a/libcdi/src/cdi_util.c
+++ b/libcdi/src/cdi_util.c
@@ -2,8 +2,10 @@
 #  include "config.h"
 #endif
 
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 #include "cdi.h"
 #include "cdi_int.h"
@@ -114,6 +116,52 @@ const char *cdiUnitNamePtr(int cdi_unit)
   return name;
 }
 
+size_t
+cdiGetPageSize(bool largePageAlign)
+{
+  long pagesize = -1L;
+#if HAVE_DECL__SC_LARGE_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE || HAVE_DECL__SC_PAGESIZE
+  bool nameAssigned = false;
+  int name;
+#  if HAVE_DECL__SC_LARGE_PAGESIZE
+  if (largePageAlign)
+    {
+      name = _SC_LARGE_PAGESIZE;
+      nameAssigned = true;
+    }
+  else
+#  else
+    (void)largePageAlign;
+#  endif
+    {
+#  if HAVE_DECL__SC_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE
+      name =
+#    if HAVE_DECL__SC_PAGESIZE
+        _SC_PAGESIZE
+#    elif HAVE_DECL__SC_PAGE_SIZE
+        _SC_PAGE_SIZE
+#    endif
+        ;
+      nameAssigned = true;
+#  endif
+    }
+  if (nameAssigned)
+    pagesize = sysconf(name);
+#endif
+  if (pagesize == -1L)
+    pagesize =
+#if HAVE_DECL_PAGESIZE
+      PAGESIZE
+#elif HAVE_DECL_PAGE_SIZE
+      PAGE_SIZE
+#else
+      commonPageSize
+#endif
+      ;
+  return (size_t)pagesize;
+}
+
+
 /*
  * Local Variables:
  * c-file-style: "Java"
diff --git a/libcdi/src/cdi_uuid.h b/libcdi/src/cdi_uuid.h
new file mode 100644
index 0000000..6f215ca
--- /dev/null
+++ b/libcdi/src/cdi_uuid.h
@@ -0,0 +1,42 @@
+#ifndef CDI_UUID_H
+#define CDI_UUID_H
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "cdi.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline int cdiUUIDIsNull(const unsigned char uuid[])
+{
+  int isNull = 1;
+  for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
+    isNull &= (uuid[i] == 0);
+  return isNull;
+}
+
+void cdiCreateUUID(unsigned char uuid[CDI_UUID_SIZE]);
+
+void cdiUUID2Str(const unsigned char uuid[], char uuidstr[]);
+int cdiStr2UUID(const char *uuidstr, unsigned char uuid[]);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif
+
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
diff --git a/libcdi/src/cdilib.c b/libcdi/src/cdilib.c
index 4f455df..5220402 100644
--- a/libcdi/src/cdilib.c
+++ b/libcdi/src/cdilib.c
@@ -1,7 +1,7 @@
 
-/* Automatically generated by m214003 at 2015-10-25, do not edit */
+/* Automatically generated by m214003 at 2016-02-19, do not edit */
 
-/* CDILIB_VERSION="1.7.0" */
+/* CDILIB_VERSION="1.7.1" */
 
 #ifdef _ARCH_PWR6
 #pragma options nostrict
@@ -68,9 +68,9 @@
 #define  WITH_CALLER_NAME
 #endif
 
-#define  _FATAL     1     /* Error flag: exit on error  */
-#define  _VERBOSE   2     /* Error flag: report errors  */
-#define  _DEBUG     4     /* Error flag: debug          */
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 extern int _ExitOnError;  /* If set to 1, exit on error (default 1)       */
 extern int _Verbose;      /* If set to 1, errors are reported (default 1) */
@@ -126,6 +126,10 @@ cdiAbortC_serial(const char *caller, const char *filename,
                  const char *errorString, va_list ap)
   __attribute__((noreturn));
 
+#if defined (__cplusplus)
+}
+#endif
+
 #endif  /* _ERROR_H */
 /*
  * Local Variables:
@@ -147,11 +151,12 @@ cdiAbortC_serial(const char *caller, const char *filename,
 
 #include <stdio.h>
 #include <sys/types.h>
-/*
+
 #ifdef __cplusplus
 extern "C" {
 #endif
-*/
+
+
 #define  CDI_MAX_NAME           256   /* max length of a name                 */
 
 #define  CDI_UNDEFID             -1
@@ -176,7 +181,7 @@ extern "C" {
 #define  CDI_EUFTYPE            -21   /* Unsupported file type                */
 #define  CDI_ELIBNAVAIL         -22   /* xxx library not available            */
 #define  CDI_EUFSTRUCT          -23   /* Unsupported file structure           */
-#define  CDI_EUNC4              -24   /* Unsupported netCDF4 structure        */
+#define  CDI_EUNC4              -24   /* Unsupported NetCDF4 structure        */
 #define  CDI_ELIMIT             -99   /* Internal limits exceeded             */
 
 /* File types */
@@ -184,10 +189,10 @@ extern "C" {
 #define  FILETYPE_UNDEF          -1   /* Unknown/not yet defined file type */
 #define  FILETYPE_GRB             1   /* File type GRIB                       */
 #define  FILETYPE_GRB2            2   /* File type GRIB version 2             */
-#define  FILETYPE_NC              3   /* File type netCDF                     */
-#define  FILETYPE_NC2             4   /* File type netCDF version 2 (64-bit)  */
-#define  FILETYPE_NC4             5   /* File type netCDF version 4           */
-#define  FILETYPE_NC4C            6   /* File type netCDF version 4 (classic) */
+#define  FILETYPE_NC              3   /* File type NetCDF                     */
+#define  FILETYPE_NC2             4   /* File type NetCDF version 2 (64-bit)  */
+#define  FILETYPE_NC4             5   /* File type NetCDF version 4           */
+#define  FILETYPE_NC4C            6   /* File type NetCDF version 4 (classic) */
 #define  FILETYPE_SRV             7   /* File type SERVICE                    */
 #define  FILETYPE_EXT             8   /* File type EXTRA                      */
 #define  FILETYPE_IEG             9   /* File type IEG                        */
@@ -286,7 +291,7 @@ extern "C" {
 #define  ZAXIS_HYBRID               2  /* Hybrid level                                          */
 #define  ZAXIS_HYBRID_HALF          3  /* Hybrid half level                                     */
 #define  ZAXIS_PRESSURE             4  /* Isobaric pressure level in Pascal                     */
-#define  ZAXIS_HEIGHT               5  /* Height above ground in meters                         */
+#define  ZAXIS_HEIGHT               5  /* Height above ground                                   */
 #define  ZAXIS_DEPTH_BELOW_SEA      6  /* Depth below sea level in meters                       */
 #define  ZAXIS_DEPTH_BELOW_LAND     7  /* Depth below land surface in centimeters               */
 #define  ZAXIS_ISENTROPIC           8  /* Isentropic                                            */
@@ -522,6 +527,7 @@ void    streamInqRecord(int streamID, int *varID, int *levelID);
 void    streamWriteRecord(int streamID, const double data[], int nmiss);
 void    streamWriteRecordF(int streamID, const float data[], int nmiss);
 void    streamReadRecord(int streamID, double data[], int *nmiss);
+void    streamReadRecordF(int streamID, float data[], int *nmiss);
 void    streamCopyRecord(int streamIDdest, int streamIDsrc);
 
 void    streamInqGRIBinfo(int streamID, int *intnum, float *fltnum, off_t *bignum);
@@ -544,11 +550,15 @@ int cdiIterator_nextField(CdiIterator *me);      //Points the iterator at the ne
 //All outXXX arguments to these functions may be NULL.
 char *cdiIterator_inqStartTime(CdiIterator *me);      //Returns the (start) time as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
 char *cdiIterator_inqEndTime(CdiIterator *me);      //Returns the end time of an integration period as an ISO-8601 coded string, or NULL if there is no end time. The caller is responsible to Free() the returned string.
+char *cdiIterator_inqRTime(CdiIterator *me);      //Returns the reference date as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
 char *cdiIterator_inqVTime(CdiIterator *me);      //Returns the validity date as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
 int cdiIterator_inqLevelType(CdiIterator *me, int levelSelector, char **outName_optional, char **outLongName_optional, char **outStdName_optional, char **outUnit_optional);      //callers are responsible to Free() strings that they request
 int cdiIterator_inqLevel(CdiIterator *me, int levelSelector, double *outValue1_optional, double *outValue2_optional);       //outValue2 is only written to if the level is a hybrid level
 int cdiIterator_inqLevelUuid(CdiIterator *me, int *outVgridNumber_optional, int *outLevelCount_optional, unsigned char outUuid_optional[CDI_UUID_SIZE]);   //outUuid must point to a buffer of 16 bytes, returns an error code if no generalized zaxis is used.
+int cdiIterator_inqTile(CdiIterator *me, int *outTileIndex, int *outTileAttribute); //Returns CDI_EINVAL if there is no tile information connected to the current field, *outTileIndex and *outTileAttribute will be set to -1 in this case.
+int cdiIterator_inqTileCount(CdiIterator *me, int *outTileCount, int *outTileAttributeCount); //outTileAttributeCount is the count for the tile associated with the current field, a total attribute count cannot be inquired. Returns CDI_EINVAL if there is no tile information connected to the current field, *outTileCount and *outTileAttributeCount will be set to 0 in this case.
 CdiParam cdiIterator_inqParam(CdiIterator *me);
+void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber);	//Some FORTRAN compilers produce wrong code for the cdiIterator_inqParam()-wrapper, rendering it unusable from FORTRAN. This function is the workaround.
 int cdiIterator_inqDatatype(CdiIterator *me);
 int cdiIterator_inqTsteptype(CdiIterator *me);
 char *cdiIterator_inqVariableName(CdiIterator *me);        //The caller is responsible to Free() the returned buffer.
@@ -718,7 +728,7 @@ void    vlistDefVarName(int vlistID, int varID, const char *name);
 void    vlistInqVarName(int vlistID, int varID, char *name);
 
 /*      vlistCopyVarName: Safe and convenient version of vlistInqVarName */
-char *vlistCopyVarName(int vlistId, int varId);
+char   *vlistCopyVarName(int vlistId, int varId);
 
 /*      vlistDefVarStdname: Define the standard name of a Variable */
 void    vlistDefVarStdname(int vlistID, int varID, const char *stdname);
@@ -798,6 +808,10 @@ double  vlistInqVarDblKey(int vlistID, int varID, const char *name);
 /* vlistInqVarIntKey: raw access to GRIB meta-data */
 int     vlistInqVarIntKey(int vlistID, int varID, const char *name);
 
+/* needed only for CDO operator after */
+const char *vlistInqVarNamePtr(int vlistID, int varID);
+const char *vlistInqVarLongnamePtr(int vlistID, int varID);
+const char *vlistInqVarUnitsPtr(int vlistID, int varID);
 
 /* VLIST attributes */
 
@@ -1274,6 +1288,7 @@ int     tableInqParName(int tableID, int code, char *name);
 int     tableInqParLongname(int tableID, int code, char *longname);
 int     tableInqParUnits(int tableID, int code, char *units);
 
+/* needed only for CDO operator after */
 const char *tableInqParNamePtr(int tableID, int parID);
 const char *tableInqParLongnamePtr(int tableID, int parID);
 const char *tableInqParUnitsPtr(int tableID, int parID);
@@ -1317,18 +1332,19 @@ int     subtypeInqSubEntry(int subtypeID, subtype_query_t criterion);
 /*      subtypeInqTile: Specialized version of subtypeInqSubEntry looking for tile/attribute pair. */
 int     subtypeInqTile(int subtypeID, int tileindex, int attribute);
 
+/*      subtypeInqAttribute: Inquire the value of a subtype attribute. Returns CDI_EINVAL if the attribute does not exist.*/
+int     subtypeInqAttribute(int subtypeID, int index, const char *key, int *outValue);
+
 /*      vlistInqVarSubtype: Return subtype ID for a given variable. */
 int     vlistInqVarSubtype(int vlistID, int varID);
 
-
 void gribapiLibraryVersion(int *major_version, int *minor_version, int *revision_version);
 
 
-/*
 #if defined (__cplusplus)
 }
 #endif
-*/
+
 #endif  /* CDI_H_ */
 /*
  * Local Variables:
@@ -1405,7 +1421,6 @@ void basetimeInit(basetime_t *basetime)
  * require-trailing-newline: t
  * End:
  */
- 
 #ifndef _FILE_H
 #define _FILE_H
 
@@ -1600,7 +1615,7 @@ UINT32 get_UINT32(unsigned char *x)
   switch (HOST_ENDIANNESS)
     {
     case CDI_BIGENDIAN:
-      return((UINT32)(((UINT32)x[0]<<24)+((UINT32)x[1]<<16)+((UINT32)x[2]<< 8)+ (UINT32)x[3]));
+      return ((UINT32)(((UINT32)x[0]<<24)+((UINT32)x[1]<<16)+((UINT32)x[2]<< 8)+ (UINT32)x[3]));
     case CDI_LITTLEENDIAN:
       return ((UINT32)(((UINT32)x[3]<<24)+((UINT32)x[2]<<16)+((UINT32)x[1]<< 8)+ (UINT32)x[0]));
     default:
@@ -1615,9 +1630,9 @@ UINT32 get_SUINT32(unsigned char *x)
   switch (HOST_ENDIANNESS)
     {
     case CDI_BIGENDIAN:
-      return((UINT32)(((UINT32)x[3]<<24)+((UINT32)x[2]<<16)+((UINT32)x[1]<< 8)+ (UINT32)x[0]));
+      return ((UINT32)(((UINT32)x[3]<<24)+((UINT32)x[2]<<16)+((UINT32)x[1]<< 8)+ (UINT32)x[0]));
     case CDI_LITTLEENDIAN:
-      return((UINT32)(((UINT32)x[0]<<24)+((UINT32)x[1]<<16)+((UINT32)x[2]<< 8)+ (UINT32)x[3]));
+      return ((UINT32)(((UINT32)x[0]<<24)+((UINT32)x[1]<<16)+((UINT32)x[2]<< 8)+ (UINT32)x[3]));
     default:
       Error("unhandled endianness %d", HOST_ENDIANNESS);
       return UINT32_C(0xFFFFFFFF);
@@ -1630,11 +1645,11 @@ UINT64 get_UINT64(unsigned char *x)
   switch (HOST_ENDIANNESS)
     {
     case CDI_BIGENDIAN:
-      return((UINT64)(((UINT64)x[0]<<56)+((UINT64)x[1]<<48)+((UINT64)x[2]<<40)+((UINT64)x[3]<<32)+
-                      ((UINT64)x[4]<<24)+((UINT64)x[5]<<16)+((UINT64)x[6]<< 8)+ (UINT64)x[7]));
+      return ((UINT64)(((UINT64)x[0]<<56)+((UINT64)x[1]<<48)+((UINT64)x[2]<<40)+((UINT64)x[3]<<32)+
+                       ((UINT64)x[4]<<24)+((UINT64)x[5]<<16)+((UINT64)x[6]<< 8)+ (UINT64)x[7]));
     case CDI_LITTLEENDIAN:
-      return((UINT64)(((UINT64)x[7]<<56)+((UINT64)x[6]<<48)+((UINT64)x[5]<<40)+((UINT64)x[4]<<32)+
-                      ((UINT64)x[3]<<24)+((UINT64)x[2]<<16)+((UINT64)x[1]<< 8)+ (UINT64)x[0]));
+      return ((UINT64)(((UINT64)x[7]<<56)+((UINT64)x[6]<<48)+((UINT64)x[5]<<40)+((UINT64)x[4]<<32)+
+                       ((UINT64)x[3]<<24)+((UINT64)x[2]<<16)+((UINT64)x[1]<< 8)+ (UINT64)x[0]));
     default:
       Error("unhandled endianness %d", HOST_ENDIANNESS);
       return UINT64_C(0xFFFFFFFFFFFFFFFF);
@@ -1647,11 +1662,11 @@ UINT64 get_SUINT64(unsigned char *x)
   switch (HOST_ENDIANNESS)
     {
     case CDI_BIGENDIAN:
-      return((UINT64)(((UINT64)x[7]<<56)+((UINT64)x[6]<<48)+((UINT64)x[5]<<40)+((UINT64)x[4]<<32)+
-                      ((UINT64)x[3]<<24)+((UINT64)x[2]<<16)+((UINT64)x[1]<< 8)+ (UINT64)x[0]));
+      return ((UINT64)(((UINT64)x[7]<<56)+((UINT64)x[6]<<48)+((UINT64)x[5]<<40)+((UINT64)x[4]<<32)+
+                       ((UINT64)x[3]<<24)+((UINT64)x[2]<<16)+((UINT64)x[1]<< 8)+ (UINT64)x[0]));
     case CDI_LITTLEENDIAN:
-      return((UINT64)(((UINT64)x[0]<<56)+((UINT64)x[1]<<48)+((UINT64)x[2]<<40)+((UINT64)x[3]<<32)+
-                      ((UINT64)x[4]<<24)+((UINT64)x[5]<<16)+((UINT64)x[6]<< 8)+ (UINT64)x[7]));
+      return ((UINT64)(((UINT64)x[0]<<56)+((UINT64)x[1]<<48)+((UINT64)x[2]<<40)+((UINT64)x[3]<<32)+
+                       ((UINT64)x[4]<<24)+((UINT64)x[5]<<16)+((UINT64)x[6]<< 8)+ (UINT64)x[7]));
     default:
       Error("unhandled endianness %d", HOST_ENDIANNESS);
       return UINT64_C(0xFFFFFFFFFFFFFFFF);
@@ -1861,15 +1876,22 @@ int binWriteFlt64(int fileID, int byteswap, size_t size, FLT64 *ptr)
 #ifndef _CALENDAR_H
 #define _CALENDAR_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 void encode_caldaysec(int calendar, int year, int month, int day, int hour, int minute, int second,
 		      int *julday, int *secofday);
-void decode_caldaysec(int calendar, int julday, int secofday, 
+void decode_caldaysec(int calendar, int julday, int secofday,
 		      int *year, int *month, int *day, int *hour, int *minute, int *second);
 
 int calendar_dpy(int calendar);
 int days_per_year(int calendar, int year);
 int days_per_month(int calendar, int year, int month);
 
+#if defined (__cplusplus)
+}
+#endif
 
 #endif  /* _CALENDAR_H */
 /*
@@ -1886,6 +1908,10 @@ int days_per_month(int calendar, int year, int month);
 
 #include <inttypes.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* date format:  YYYYMMDD */
 /* time format:  hhmmss   */
 
@@ -1905,6 +1931,10 @@ double julday_sub(int julday1, int secofday1, int julday2, int secofday2, int *d
 void encode_juldaysec(int calendar, int year, int month, int day, int hour, int minute, int second, int *julday, int *secofday);
 void decode_juldaysec(int calendar, int julday, int secofday, int *year, int *month, int *day, int *hour, int *minute, int *second);
 
+#if defined (__cplusplus)
+}
+#endif
+
 #endif  /* _TIMEBASE_H */
 
 /*
@@ -2812,7 +2842,7 @@ typedef struct
   int       ilevel;
   int       ilevel2;
   int       ltype;
-  int       tsteptype;
+  short     tsteptype;
   short     used;
   short     varID;
   short     levelID;
@@ -2943,6 +2973,13 @@ typedef struct
   int                    subtype_index;  /* tile index for this key-value pair */
 } opt_key_val_pair_t;
 
+//enum for differenciating between the different times that we handle
+typedef enum {
+  kCdiTimeType_referenceTime,
+  kCdiTimeType_startTime,
+  kCdiTimeType_endTime
+} CdiTimeType;
+
 
 
 
@@ -2970,6 +3007,7 @@ extern int cdiInventoryMode;
 extern int CDI_Version_Info;
 extern int CDI_cmor_mode;
 extern size_t CDI_netcdf_hdr_pad;
+extern bool CDI_netcdf_lazy_grid_load;
 extern int STREAM_Debug;
 
 
@@ -3036,21 +3074,8 @@ int     getByteswap(int byteorder);
 
 void cdiStreamGetIndexList(unsigned numIDs, int IDs[]);
 
-
 void  cdiInitialize(void);
 
-void uuid2str(const unsigned char uuid[], char uuidstr[]);
-int str2uuid(const char *uuidstr, unsigned char uuid[]);
-
-static inline int cdiUUIDIsNull(const unsigned char uuid[])
-{
-  int isNull = 1;
-  for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
-    isNull &= (uuid[i] == 0);
-  return isNull;
-}
-
-
 char *cdiEscapeSpaces(const char *string);
 char *cdiUnescapeSpaces(const char *string, const char **outStringEnd);
 
@@ -3081,9 +3106,10 @@ streamOpenID(const char *filename, char filemode, int filetype,
 
 void
 cdiStreamDefVlist_(int streamID, int vlistID);
-void
-cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data,
-                   int nmiss);
+
+int
+cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, int nmiss);
+
 void
 cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
                         const int rect[][2], const void *data, int nmiss);
@@ -3097,14 +3123,33 @@ void cdiStreamSync_(stream_t *streamptr);
 
 const char *cdiUnitNamePtr(int cdi_unit);
 
+enum {
+  /* 8192 is known to work on most systems (4096 isn't on Alpha) */
+  commonPageSize = 8192,
+};
+
+size_t cdiGetPageSize(bool largePageAlign);
+
 void zaxisGetIndexList(int nzaxis, int *zaxisIndexList);
 
 void zaxisDefLtype2(int zaxisID, int ltype2);
 int  zaxisInqLtype2(int zaxisID);
 
-/* used by CDO */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// functions used in CDO !!!
+
 void cdiDefTableID(int tableID);
 
+void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *xvals);
+void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *yvals);
+
+#if defined (__cplusplus)
+}
+#endif
+
 #endif  /* _CDI_INT_H */
 /*
  * Local Variables:
@@ -3511,7 +3556,7 @@ union namespaceSwitchValue
 void             namespaceCleanup      ( void );
 int              namespaceGetNumber    ( void );
 //void             namespaceSetActive(int namespaceID);
-int              namespaceGetActive    ( void );
+//int              namespaceGetActive    ( void );
 int              namespaceIdxEncode    ( namespaceTuple_t );
 int              namespaceIdxEncode2   ( int, int );
 namespaceTuple_t namespaceResHDecode   ( int );
@@ -4484,7 +4529,7 @@ const char *cdiStringError(int cdiErrno)
   static const char _EUFTYPE[]     = "Unsupported file type";
   static const char _ELIBNAVAIL[]  = "Unsupported file type (library support not compiled in)";
   static const char _EUFSTRUCT[]   = "Unsupported file structure";
-  static const char _EUNC4[]       = "Unsupported netCDF4 structure";
+  static const char _EUNC4[]       = "Unsupported NetCDF4 structure";
   static const char _ELIMIT[]      = "Internal limits exceeded";
 
   switch (cdiErrno) {
@@ -4525,6 +4570,10 @@ const char *cdiStringError(int cdiErrno)
 #define  WITH_FUNCTION_NAME
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern size_t  memTotal(void);
 extern void    memDebug(int debug);
 extern void    memExitOnError(void);
@@ -4536,6 +4585,10 @@ extern void   *memCalloc (size_t nmemb, size_t size, const char *file, const cha
 extern void   *memMalloc (size_t size, const char *file, const char *functionname, int line);
 extern void    memFree   (void *ptr, const char *file, const char *functionname, int line);
 
+#if defined (__cplusplus)
+}
+#endif
+
 #if  defined  WITH_FUNCTION_NAME
 #  define  Realloc(p, s)  memRealloc((p), (s), __FILE__, __func__, __LINE__)
 #  define   Calloc(n, s)   memCalloc((n), (s), __FILE__, __func__, __LINE__)
@@ -4701,21 +4754,21 @@ void   cdfDefRecord(stream_t * streamptr);
 
 void   cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
 
-void   cdfReadRecord(stream_t *streamptr, double *data, int *nmiss);
+void   cdf_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss);
 void   cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss);
 
-void   cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss);
-void   cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss);
-
+void   cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss);
 void   cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss);
 
-void   cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data, int *nmiss);
-void   cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data, int *nmiss);
+void   cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss);
 void   cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss);
 
 void   cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
                            const int rect[][2], const void *data, int nmiss);
 
+void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level);
+void cdfDefTime(stream_t* streamptr);
+
 #endif
 /*
  * Local Variables:
@@ -4903,6 +4956,9 @@ void   cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
 #define  ISEC4_NumNonMissValues     (isec4[20])  /* Number of non-missing values                  */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 
 void  gribFixZSE(int flag);     /* 1: Fix ZeroShiftError of simple packed spherical harmonics */
@@ -4916,11 +4972,11 @@ void  gribSetValueCheck(int vcheck);
 
 void  gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
                float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
-               int kleng, int *kword, char *hoper, int *kret);
+               int kleng, int *kword, const char *hoper, int *kret);
 
 void  gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
                double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
-               int kleng, int *kword, char *hoper, int *kret);
+               int kleng, int *kword, const char *hoper, int *kret);
 
 
 const char *cgribexLibraryVersion(void);
@@ -4971,7 +5027,13 @@ int   gribVersion(unsigned char *buffer, size_t buffersize);
 
 int   grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer, int *intnum, float *fltnum, off_t *bignum);
 
-double calculate_pfactor(const double* spectralField, long fieldTruncation, long subsetTruncation);
+double calculate_pfactor_float(const float* spectralField, long fieldTruncation, long subsetTruncation);
+double calculate_pfactor_double(const double* spectralField, long fieldTruncation, long subsetTruncation);
+
+
+#if defined (__cplusplus)
+}
+#endif
 
 #endif  /* _CGRIBEX_H */ 
 
@@ -5005,6 +5067,7 @@ int cdiInventoryMode        = 1;
 int CDI_Version_Info        = 1;
 int CDI_cmor_mode           = 0;
 size_t CDI_netcdf_hdr_pad   = 0UL;
+bool CDI_netcdf_lazy_grid_load = false;
 
 char *cdiPartabPath   = NULL;
 int   cdiPartabIntern = 1;
@@ -5015,10 +5078,10 @@ static const char Filetypes[][9] = {
   "UNKNOWN",
   "GRIB",
   "GRIB2",
-  "netCDF",
-  "netCDF2",
-  "netCDF4",
-  "netCDF4c",
+  "NetCDF",
+  "NetCDF2",
+  "NetCDF4",
+  "NetCDF4c",
   "SERVICE",
   "EXTRA",
   "IEG",
@@ -5095,7 +5158,7 @@ void cdiPrintVersion(void)
   fprintf(stderr, "GRIB_API library version : %s\n", gribapiLibraryVersionString());
 #endif
 #if  defined  (HAVE_LIBNETCDF)
-  fprintf(stderr, "  netCDF library version : %s\n", cdfLibraryVersion());
+  fprintf(stderr, "  NetCDF library version : %s\n", cdfLibraryVersion());
 #endif
 #if  defined  (HAVE_LIBHDF5)
   fprintf(stderr, "    HDF5 library version : %s\n", hdfLibraryVersion());
@@ -5389,6 +5452,8 @@ void cdiDefGlobal(const char *string, int val)
   else if ( strcmp(string, "NC_CHUNKSIZEHINT") == 0 ) cdiNcChunksizehint = val;
   else if ( strcmp(string, "CMOR_MODE")        == 0 ) CDI_cmor_mode = val;
   else if ( strcmp(string, "NETCDF_HDR_PAD")   == 0 ) CDI_netcdf_hdr_pad = (size_t) val;
+  else if ( strcmp(string, "NETCDF_LAZY_GRID_LOAD") == 0)
+    CDI_netcdf_lazy_grid_load = (bool)val;
   else Warning("Unsupported global key: %s", string);
 }
 
@@ -5421,8 +5486,10 @@ double cdiInqMissval(void)
 #if defined (HAVE_CONFIG_H)
 #endif
 
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 
 void cdiDecodeParam(int param, int *pnum, int *pcat, int *pdis)
@@ -5531,6 +5598,52 @@ const char *cdiUnitNamePtr(int cdi_unit)
   return name;
 }
 
+size_t
+cdiGetPageSize(bool largePageAlign)
+{
+  long pagesize = -1L;
+#if HAVE_DECL__SC_LARGE_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE || HAVE_DECL__SC_PAGESIZE
+  bool nameAssigned = false;
+  int name;
+#  if HAVE_DECL__SC_LARGE_PAGESIZE
+  if (largePageAlign)
+    {
+      name = _SC_LARGE_PAGESIZE;
+      nameAssigned = true;
+    }
+  else
+#  else
+    (void)largePageAlign;
+#  endif
+    {
+#  if HAVE_DECL__SC_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE
+      name =
+#    if HAVE_DECL__SC_PAGESIZE
+        _SC_PAGESIZE
+#    elif HAVE_DECL__SC_PAGE_SIZE
+        _SC_PAGE_SIZE
+#    endif
+        ;
+      nameAssigned = true;
+#  endif
+    }
+  if (nameAssigned)
+    pagesize = sysconf(name);
+#endif
+  if (pagesize == -1L)
+    pagesize =
+#if HAVE_DECL_PAGESIZE
+      PAGESIZE
+#elif HAVE_DECL_PAGE_SIZE
+      PAGE_SIZE
+#else
+      commonPageSize
+#endif
+      ;
+  return (size_t)pagesize;
+}
+
+
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -5541,9 +5654,9 @@ const char *cdiUnitNamePtr(int cdi_unit)
  * End:
  */
 
-/* Automatically generated by m214003 at 2015-09-14, do not edit */
+/* Automatically generated by m214003 at 2016-02-19, do not edit */
 
-/* CGRIBEXLIB_VERSION="1.7.3" */
+/* CGRIBEXLIB_VERSION="1.7.4" */
 
 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) || defined (__clang__)
 #pragma GCC diagnostic push
@@ -5574,8 +5687,8 @@ const char *cdiUnitNamePtr(int cdi_unit)
 #define TEMPLATE(X,Y) CAT(X,Y)
 
 #endif 
-#ifndef _GRIB_INT_H
-#define _GRIB_INT_H
+#ifndef GRIB_INT_H
+#define GRIB_INT_H
 
 #if defined (HAVE_CONFIG_H)
 #endif
@@ -5644,24 +5757,25 @@ const char *cdiUnitNamePtr(int cdi_unit)
 #endif
 #endif
 
-#ifndef DBL_IS_EQUAL
-/*#define DBL_IS_EQUAL(x,y) (!(x < y || y < x)) */
-#  define DBL_IS_EQUAL(x,y) (DBL_IS_NAN(x)||DBL_IS_NAN(y)?(DBL_IS_NAN(x)&&DBL_IS_NAN(y)?1:0):!(x < y || y < x))
-#endif
-
 #ifndef IS_EQUAL
 #  define IS_NOT_EQUAL(x,y) (x < y || y < x)
 #  define IS_EQUAL(x,y)     (!IS_NOT_EQUAL(x,y))
 #endif
 
 /* dummy use of unused parameters to silence compiler warnings */
-#define  UNUSED(x) (void)x
+#ifndef UNUSED
+#  define  UNUSED(x) (void)(x)
+#endif
 
 #define  JP23SET    0x7FFFFF  /* 2**23 - 1 (---> 8388607)  */
 
 #define  POW_2_M24  0.000000059604644775390625  /*  pow(2.0, -24.0) */
 
-double intpow2(int x);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define intpow2(x) (ldexp(1.0, (x)))
 
 int gribrec_len(unsigned b1, unsigned b2, unsigned b3);
 int correct_bdslen(int bdslen, long recsize, long gribpos);
@@ -5708,8 +5822,8 @@ void   scale_complex_double(double *fpdata, int pcStart, int pcScale, int trunc,
 void   scale_complex_float(float *fpdata, int pcStart, int pcScale, int trunc, int inv);
 void   scatter_complex_double(double *fpdata, int pcStart, int trunc, int nsp);
 void   scatter_complex_float(float *fpdata, int pcStart, int trunc, int nsp);
-void   gather_complex_double(double *fpdata, int pcStart, int trunc, int nsp);
-void   gather_complex_float(float *fpdata, int pcStart, int trunc, int nsp);
+void   gather_complex_double(double *fpdata, size_t pcStart, size_t trunc, size_t nsp);
+void   gather_complex_float(float *fpdata, size_t pcStart, size_t trunc, size_t nsp);
 
 void   scm0_double(double *pdl, double *pdr, double *pfl, double *pfr, int klg);
 int    qu2reg2(double *pfield, int *kpoint, int klat, int klon,
@@ -5749,7 +5863,11 @@ int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **i
 		  unsigned char **lusp, unsigned char **gdsp, unsigned char **pdsp,
 		  unsigned char **drsp, unsigned char **bmsp, unsigned char **bdsp);
 
-#endif  /* _GRIB_INT_H */
+#if defined (__cplusplus)
+}
+#endif
+
+#endif  /* GRIB_INT_H */
 #ifndef _GRIBDECODE_H
 #define _GRIBDECODE_H
 
@@ -5851,7 +5969,7 @@ int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **i
 #define  GDS_ScanFlag        GET_UINT1(gds[27])
 #define  GDS_LatSP           GET_INT3(gds[32], gds[33], gds[34])
 #define  GDS_LonSP           GET_INT3(gds[35], gds[36], gds[37])
-#define  GDS_RotAngle        GET_Real(&(gds[38]))
+#define  GDS_RotAngle        (GET_Real(&(gds[38])))
 
 /* GRIB1 Lambert */
 #define  GDS_Lambert_Lov     GET_INT3(gds[17], gds[18], gds[19])
@@ -5876,9 +5994,9 @@ int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **i
 #define  BDS_Len	    ((int) ((bds[0]<<16)+(bds[1]<<8)+bds[2]))
 #define  BDS_Flag	    (bds[3])
 #define  BDS_BinScale       GET_INT2(bds[ 4], bds[ 5])
-#define  BDS_RefValue       decfp2((int)bds[ 6], GET_UINT3(bds[ 7], bds[ 8], bds[ 9]))
+#define  BDS_RefValue       (decfp2((int)bds[ 6], GET_UINT3(bds[ 7], bds[ 8], bds[ 9])))
 #define  BDS_NumBits        ((int) bds[10])
-#define  BDS_RealCoef       decfp2((int)bds[zoff+11], GET_UINT3(bds[zoff+12], bds[zoff+13], bds[zoff+14]))
+#define  BDS_RealCoef       (decfp2((int)bds[zoff+11], GET_UINT3(bds[zoff+12], bds[zoff+13], bds[zoff+14])))
 #define  BDS_PackData       ((int) ((bds[zoff+11]<<8) + bds[zoff+12]))
 #define  BDS_Power          GET_INT2(bds[zoff+13], bds[zoff+14])
 #define  BDS_Z              (bds[13])
@@ -5897,21 +6015,20 @@ int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **i
 
 #define PutnZero(n) \
 { \
-  int i; \
-  for ( i = z; i < z+n; i++ ) lGrib[i] = 0; \
+  for ( size_t i = z >= 0 ? (size_t)z : 0; i < (size_t)(z+n); i++ ) lGrib[i] = 0; \
   z += n; \
 }
 
-#define Put1Byte(Value)  (lGrib[z++] = (Value))
-#define Put2Byte(Value) ((lGrib[z++] = (Value) >>  8), \
-                         (lGrib[z++] = (Value)))
-#define Put3Byte(Value) ((lGrib[z++] = (Value) >> 16), \
-                         (lGrib[z++] = (Value) >>  8), \
-                         (lGrib[z++] = (Value)))
-#define Put4Byte(Value) ((lGrib[z++] = (Value) >> 24), \
-                         (lGrib[z++] = (Value) >> 16), \
-                         (lGrib[z++] = (Value) >>  8), \
-                         (lGrib[z++] = (Value)))
+#define Put1Byte(Value)  (lGrib[z++] = (GRIBPACK)(Value))
+#define Put2Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
+                         (lGrib[z++] = (GRIBPACK)(Value)))
+#define Put3Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >> 16)),      \
+                         (lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
+                         (lGrib[z++] = (GRIBPACK)(Value)))
+#define Put4Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >> 24)),      \
+                         (lGrib[z++] = (GRIBPACK)((Value) >> 16)),      \
+                         (lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
+                         (lGrib[z++] = (GRIBPACK)(Value)))
 
 #define Put1Int(Value)  {ival = Value; if ( ival < 0 ) ival =     0x80 - ival; Put1Byte(ival);}
 #define Put2Int(Value)  {ival = Value; if ( ival < 0 ) ival =   0x8000 - ival; Put2Byte(ival);}
@@ -5925,278 +6042,21 @@ int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **i
 }
 
 #endif  /* _GRIB_ENCODE_H */
-#include <stdio.h>
-#include <math.h>
-
-
-const double _pow2tab[158] = {
- /* pow(2.0,  0.0) */  1.0,
- /* pow(2.0,  1.0) */  2.0,
- /* pow(2.0,  2.0) */  4.0,
- /* pow(2.0,  3.0) */  8.0,
- /* pow(2.0,  4.0) */  16.0,
- /* pow(2.0,  5.0) */  32.0,
- /* pow(2.0,  6.0) */  64.0,
- /* pow(2.0,  7.0) */  128.0,
- /* pow(2.0,  8.0) */  256.0,
- /* pow(2.0,  9.0) */  512.0,
- /* pow(2.0, 10.0) */  1024.0,
- /* pow(2.0, 11.0) */  2048.0,
- /* pow(2.0, 12.0) */  4096.0,
- /* pow(2.0, 13.0) */  8192.0,
- /* pow(2.0, 14.0) */  16384.0,
- /* pow(2.0, 15.0) */  32768.0,
- /* pow(2.0, 16.0) */  65536.0,
- /* pow(2.0, 17.0) */  131072.0,
- /* pow(2.0, 18.0) */  262144.0,
- /* pow(2.0, 19.0) */  524288.0,
- /* pow(2.0, 20.0) */  1048576.0,
- /* pow(2.0, 21.0) */  2097152.0,
- /* pow(2.0, 22.0) */  4194304.0,
- /* pow(2.0, 23.0) */  8388608.0,
- /* pow(2.0, 24.0) */  16777216.0,
- /* pow(2.0, 25.0) */  33554432.0,
- /* pow(2.0, 26.0) */  67108864.0,
- /* pow(2.0, 27.0) */  134217728.0,
- /* pow(2.0, 28.0) */  268435456.0,
- /* pow(2.0, 29.0) */  536870912.0,
- /* pow(2.0, 30.0) */  1073741824.0,
- /* pow(2.0, 31.0) */  2147483648.0,
- /* pow(2.0, 32.0) */  4294967296.0,
- /* pow(2.0, 33.0) */  8589934592.0,
- /* pow(2.0, 34.0) */  17179869184.0,
- /* pow(2.0, 35.0) */  34359738368.0,
- /* pow(2.0, 36.0) */  68719476736.0,
- /* pow(2.0, 37.0) */  137438953472.0,
- /* pow(2.0, 38.0) */  274877906944.0,
- /* pow(2.0, 39.0) */  549755813888.0,
- /* pow(2.0, 40.0) */  1099511627776.0,
- /* pow(2.0, 41.0) */  2199023255552.0,
- /* pow(2.0, 42.0) */  4398046511104.0,
- /* pow(2.0, 43.0) */  8796093022208.0,
- /* pow(2.0, 44.0) */  17592186044416.0,
- /* pow(2.0, 45.0) */  35184372088832.0,
- /* pow(2.0, 46.0) */  70368744177664.0,
- /* pow(2.0, 47.0) */  140737488355328.0,
- /* pow(2.0, 48.0) */  281474976710656.0,
- /* pow(2.0, 49.0) */  562949953421312.0,
- /* pow(2.0, 50.0) */  1125899906842624.0,
- /* pow(2.0, 51.0) */  2251799813685248.0,
- /* pow(2.0, 52.0) */  4503599627370496.0,
- /* pow(2.0, 53.0) */  9007199254740992.0,
- /* pow(2.0, 54.0) */  18014398509481984.0,
- /* pow(2.0, 55.0) */  36028797018963968.0,
- /* pow(2.0, 56.0) */  72057594037927936.0,
- /* pow(2.0, 57.0) */  144115188075855872.0,
- /* pow(2.0, 58.0) */  288230376151711744.0,
- /* pow(2.0, 59.0) */  576460752303423488.0,
- /* pow(2.0, 60.0) */  1152921504606846976.0,
- /* pow(2.0, 61.0) */  2305843009213693952.0,
- /* pow(2.0, 62.0) */  4611686018427387904.0,
- /* pow(2.0, 63.0) */  9223372036854775808.0,
- /* pow(2.0, 64.0) */  18446744073709551616.0,
- /* pow(2.0, 65.0) */  36893488147419103232.0,
- /* pow(2.0, 66.0) */  73786976294838206464.0,
- /* pow(2.0, 67.0) */  147573952589676412928.0,
- /* pow(2.0, 68.0) */  295147905179352825856.0,
- /* pow(2.0, 69.0) */  590295810358705651712.0,
- /* pow(2.0, 70.0) */  1180591620717411303424.0,
- /* pow(2.0, 71.0) */  2361183241434822606848.0,
- /* pow(2.0, 72.0) */  4722366482869645213696.0,
- /* pow(2.0, 73.0) */  9444732965739290427392.0,
- /* pow(2.0, 74.0) */  18889465931478580854784.0,
- /* pow(2.0, 75.0) */  37778931862957161709568.0,
- /* pow(2.0, 76.0) */  75557863725914323419136.0,
- /* pow(2.0, 77.0) */  151115727451828646838272.0,
- /* pow(2.0, 78.0) */  302231454903657293676544.0,
- /* pow(2.0, 79.0) */  604462909807314587353088.0,
- /* pow(2.0, 80.0) */  1208925819614629174706176.0,
- /* pow(2.0, 81.0) */  2417851639229258349412352.0,
- /* pow(2.0, 82.0) */  4835703278458516698824704.0,
- /* pow(2.0, 83.0) */  9671406556917033397649408.0,
- /* pow(2.0, 84.0) */  19342813113834066795298816.0,
- /* pow(2.0, 85.0) */  38685626227668133590597632.0,
- /* pow(2.0, 86.0) */  77371252455336267181195264.0,
- /* pow(2.0, 87.0) */  154742504910672534362390528.0,
- /* pow(2.0, 88.0) */  309485009821345068724781056.0,
- /* pow(2.0, 89.0) */  618970019642690137449562112.0,
- /* pow(2.0, 90.0) */  1237940039285380274899124224.0,
- /* pow(2.0, 91.0) */  2475880078570760549798248448.0,
- /* pow(2.0, 92.0) */  4951760157141521099596496896.0,
- /* pow(2.0, 93.0) */  9903520314283042199192993792.0,
- /* pow(2.0, 94.0) */  19807040628566084398385987584.0,
- /* pow(2.0, 95.0) */  39614081257132168796771975168.0,
- /* pow(2.0, 96.0) */  79228162514264337593543950336.0,
- /* pow(2.0, 97.0) */  158456325028528675187087900672.0,
- /* pow(2.0, 98.0) */  316912650057057350374175801344.0,
- /* pow(2.0, 99.0) */  633825300114114700748351602688.0,
- /* pow(2.0, 100.0) */  1267650600228229401496703205376.0,
- /* pow(2.0, 101.0) */  2535301200456458802993406410752.0,
- /* pow(2.0, 102.0) */  5070602400912917605986812821504.0,
- /* pow(2.0, 103.0) */  10141204801825835211973625643008.0,
- /* pow(2.0, 104.0) */  20282409603651670423947251286016.0,
- /* pow(2.0, 105.0) */  40564819207303340847894502572032.0,
- /* pow(2.0, 106.0) */  81129638414606681695789005144064.0,
- /* pow(2.0, 107.0) */  162259276829213363391578010288128.0,
- /* pow(2.0, 108.0) */  324518553658426726783156020576256.0,
- /* pow(2.0, 109.0) */  649037107316853453566312041152512.0,
- /* pow(2.0, 110.0) */  1298074214633706907132624082305024.0,
- /* pow(2.0, 111.0) */  2596148429267413814265248164610048.0,
- /* pow(2.0, 112.0) */  5192296858534827628530496329220096.0,
- /* pow(2.0, 113.0) */  10384593717069655257060992658440192.0,
- /* pow(2.0, 114.0) */  20769187434139310514121985316880384.0,
- /* pow(2.0, 115.0) */  41538374868278621028243970633760768.0,
- /* pow(2.0, 116.0) */  83076749736557242056487941267521536.0,
- /* pow(2.0, 117.0) */  166153499473114484112975882535043072.0,
- /* pow(2.0, 118.0) */  332306998946228968225951765070086144.0,
- /* pow(2.0, 119.0) */  664613997892457936451903530140172288.0,
- /* pow(2.0, 120.0) */  1329227995784915872903807060280344576.0,
- /* pow(2.0, 121.0) */  2658455991569831745807614120560689152.0,
- /* pow(2.0, 122.0) */  5316911983139663491615228241121378304.0,
- /* pow(2.0, 123.0) */  10633823966279326983230456482242756608.0,
- /* pow(2.0, 124.0) */  21267647932558653966460912964485513216.0,
- /* pow(2.0, 125.0) */  42535295865117307932921825928971026432.0,
- /* pow(2.0, 126.0) */  85070591730234615865843651857942052864.0,
- /* pow(2.0, 127.0) */  170141183460469231731687303715884105728.0,
- /* pow(2.0, 128.0) */  340282366920938463463374607431768211456.0,
- /* pow(2.0, 129.0) */  680564733841876926926749214863536422912.0,
- /* pow(2.0, 130.0) */  1361129467683753853853498429727072845824.0,
- /* pow(2.0, 131.0) */  2722258935367507707706996859454145691648.0,
- /* pow(2.0, 132.0) */  5444517870735015415413993718908291383296.0,
- /* pow(2.0, 133.0) */  10889035741470030830827987437816582766592.0,
- /* pow(2.0, 134.0) */  21778071482940061661655974875633165533184.0,
- /* pow(2.0, 135.0) */  43556142965880123323311949751266331066368.0,
- /* pow(2.0, 136.0) */  87112285931760246646623899502532662132736.0,
- /* pow(2.0, 137.0) */  174224571863520493293247799005065324265472.0,
- /* pow(2.0, 138.0) */  348449143727040986586495598010130648530944.0,
- /* pow(2.0, 139.0) */  696898287454081973172991196020261297061888.0,
- /* pow(2.0, 140.0) */  1393796574908163946345982392040522594123776.0,
- /* pow(2.0, 141.0) */  2787593149816327892691964784081045188247552.0,
- /* pow(2.0, 142.0) */  5575186299632655785383929568162090376495104.0,
- /* pow(2.0, 143.0) */  11150372599265311570767859136324180752990208.0,
- /* pow(2.0, 144.0) */  22300745198530623141535718272648361505980416.0,
- /* pow(2.0, 145.0) */  44601490397061246283071436545296723011960832.0,
- /* pow(2.0, 146.0) */  89202980794122492566142873090593446023921664.0,
- /* pow(2.0, 147.0) */  178405961588244985132285746181186892047843328.0,
- /* pow(2.0, 148.0) */  356811923176489970264571492362373784095686656.0,
- /* pow(2.0, 149.0) */  713623846352979940529142984724747568191373312.0,
- /* pow(2.0, 150.0) */  1427247692705959881058285969449495136382746624.0,
- /* pow(2.0, 151.0) */  2854495385411919762116571938898990272765493248.0,
- /* pow(2.0, 152.0) */  5708990770823839524233143877797980545530986496.0,
- /* pow(2.0, 153.0) */  11417981541647679048466287755595961091061972992.0,
- /* pow(2.0, 154.0) */  22835963083295358096932575511191922182123945984.0,
- /* pow(2.0, 155.0) */  45671926166590716193865151022383844364247891968.0,
- /* pow(2.0, 156.0) */  91343852333181432387730302044767688728495783936.0,
- /* pow(2.0, 157.0) */  182687704666362864775460604089535377456991567872.0,
-};
-
-
-const double _pow16tab[71] = {
- /* pow(16.0,  0.0) */  1.0,
- /* pow(16.0,  1.0) */  16.0,
- /* pow(16.0,  2.0) */  256.0,
- /* pow(16.0,  3.0) */  4096.0,
- /* pow(16.0,  4.0) */  65536.0,
- /* pow(16.0,  5.0) */  1048576.0,
- /* pow(16.0,  6.0) */  16777216.0,
- /* pow(16.0,  7.0) */  268435456.0,
- /* pow(16.0,  8.0) */  4294967296.0,
- /* pow(16.0,  9.0) */  68719476736.0,
- /* pow(16.0, 10.0) */  1099511627776.0,
- /* pow(16.0, 11.0) */  17592186044416.0,
- /* pow(16.0, 12.0) */  281474976710656.0,
- /* pow(16.0, 13.0) */  4503599627370496.0,
- /* pow(16.0, 14.0) */  72057594037927936.0,
- /* pow(16.0, 15.0) */  1152921504606846976.0,
- /* pow(16.0, 16.0) */  18446744073709551616.0,
- /* pow(16.0, 17.0) */  295147905179352825856.0,
- /* pow(16.0, 18.0) */  4722366482869645213696.0,
- /* pow(16.0, 19.0) */  75557863725914323419136.0,
- /* pow(16.0, 20.0) */  1208925819614629174706176.0,
- /* pow(16.0, 21.0) */  19342813113834066795298816.0,
- /* pow(16.0, 22.0) */  309485009821345068724781056.0,
- /* pow(16.0, 23.0) */  4951760157141521099596496896.0,
- /* pow(16.0, 24.0) */  79228162514264337593543950336.0,
- /* pow(16.0, 25.0) */  1267650600228229401496703205376.0,
- /* pow(16.0, 26.0) */  20282409603651670423947251286016.0,
- /* pow(16.0, 27.0) */  324518553658426726783156020576256.0,
- /* pow(16.0, 28.0) */  5192296858534827628530496329220096.0,
- /* pow(16.0, 29.0) */  83076749736557242056487941267521536.0,
- /* pow(16.0, 30.0) */  1329227995784915872903807060280344576.0,
- /* pow(16.0, 31.0) */  21267647932558653966460912964485513216.0,
- /* pow(16.0, 32.0) */  340282366920938463463374607431768211456.0,
- /* pow(16.0, 33.0) */  5444517870735015415413993718908291383296.0,
- /* pow(16.0, 34.0) */  87112285931760246646623899502532662132736.0,
- /* pow(16.0, 35.0) */  1393796574908163946345982392040522594123776.0,
- /* pow(16.0, 36.0) */  22300745198530623141535718272648361505980416.0,
- /* pow(16.0, 37.0) */  356811923176489970264571492362373784095686656.0,
- /* pow(16.0, 38.0) */  5708990770823839524233143877797980545530986496.0,
- /* pow(16.0, 39.0) */  91343852333181432387730302044767688728495783936.0,
- /* pow(16.0, 40.0) */  1461501637330902918203684832716283019655932542976.0,
- /* pow(16.0, 41.0) */  23384026197294446691258957323460528314494920687616.0,
- /* pow(16.0, 42.0) */  374144419156711147060143317175368453031918731001856.0,
- /* pow(16.0, 43.0) */  5986310706507378352962293074805895248510699696029696.0,
- /* pow(16.0, 44.0) */  95780971304118053647396689196894323976171195136475136.0,
- /* pow(16.0, 45.0) */  1532495540865888858358347027150309183618739122183602176.0,
- /* pow(16.0, 46.0) */  24519928653854221733733552434404946937899825954937634816.0,
- /* pow(16.0, 47.0) */  392318858461667547739736838950479151006397215279002157056.0,
- /* pow(16.0, 48.0) */  6277101735386680763835789423207666416102355444464034512896.0,
- /* pow(16.0, 49.0) */  100433627766186892221372630771322662657637687111424552206336.0,
- /* pow(16.0, 50.0) */  1606938044258990275541962092341162602522202993782792835301376.0,
- /* pow(16.0, 51.0) */  25711008708143844408671393477458601640355247900524685364822016.0,
- /* pow(16.0, 52.0) */  411376139330301510538742295639337626245683966408394965837152256.0,
- /* pow(16.0, 53.0) */  6582018229284824168619876730229402019930943462534319453394436096.0,
- /* pow(16.0, 54.0) */  105312291668557186697918027683670432318895095400549111254310977536.0,
- /* pow(16.0, 55.0) */  1684996666696914987166688442938726917102321526408785780068975640576.0,
- /* pow(16.0, 56.0) */  26959946667150639794667015087019630673637144422540572481103610249216.0,
- /* pow(16.0, 57.0) */  431359146674410236714672241392314090778194310760649159697657763987456.0,
- /* pow(16.0, 58.0) */  6901746346790563787434755862277025452451108972170386555162524223799296.0,
- /* pow(16.0, 59.0) */  110427941548649020598956093796432407239217743554726184882600387580788736.0,
- /* pow(16.0, 60.0) */  1766847064778384329583297500742918515827483896875618958121606201292619776.0,
- /* pow(16.0, 61.0) */  28269553036454149273332760011886696253239742350009903329945699220681916416.0,
- /* pow(16.0, 62.0) */  452312848583266388373324160190187140051835877600158453279131187530910662656.0,
- /* pow(16.0, 63.0) */  7237005577332262213973186563042994240829374041602535252466099000494570602496.0,
- /* pow(16.0, 64.0) */  115792089237316195423570985008687907853269984665640564039457584007913129639936.0,
- /* pow(16.0, 65.0) */  1852673427797059126777135760139006525652319754650249024631321344126610074238976.0,
- /* pow(16.0, 66.0) */  29642774844752946028434172162224104410437116074403984394101141506025761187823616.0,
- /* pow(16.0, 67.0) */  474284397516047136454946754595585670566993857190463750305618264096412179005177856.0,
- /* pow(16.0, 68.0) */  7588550360256754183279148073529370729071901715047420004889892225542594864082845696.0,
- /* pow(16.0, 69.0) */  121416805764108066932466369176469931665150427440758720078238275608681517825325531136.0,
- /* pow(16.0, 70.0) */  1942668892225729070919461906823518906642406839052139521251812409738904285205208498176.0,
-};
-
-static int _pow2tab_size = sizeof(_pow2tab)/sizeof(double);
-
-void gen_pow2tab(void)
-{
-  int jloop;
-
-  for ( jloop = 0; jloop < 158; jloop++ )
-    printf(" /* pow(2.0, %2d.0) */  %.1f,\n", jloop,  pow(2.0, (double) jloop));
-}
-
-
-void gen_pow16tab(void)
-{
-  double pval;
-  int iexp;
-
-  for ( iexp = 0; iexp < 71; iexp++ )
-    {
-      pval = pow(16.0, (double)(iexp));
-      printf(" /* pow(16.0, %2d.0) */  %.1f,\n", iexp, pval);
-    }
-}
-
-
-double intpow2(int x)
-{
-  if ( x < _pow2tab_size )
-    return (_pow2tab[x]);
-  else
-    return (pow(2.0, (double) x));
-}
+#ifndef CODEC_COMMON_H
+#define CODEC_COMMON_H
+#define gribSwapByteOrder_uint16(ui16)  ((uint16_t)((ui16<<8) | (ui16>>8)))
+#endif  /* CODEC_COMMON_H */
 /* 
+icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -openmp -DOMP_SIMD minmax_val.c
+ result on hama2 (icc 16.0.0):
+     float:
+minmax_val: fmin: -500000  fmax: 499999  time:   0.63s
+    double:
+minmax_val: fmin: -500000  fmax: 499999  time:   2.98s
+orig      : fmin: -500000  fmax: 499999  time:   2.83s
+simd      : fmin: -500000  fmax: 499999  time:   2.82s
+avx       : fmin: -500000  fmax: 499999  time:   3.17s
+
 gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL minmax_val.c
  result on bailung (gcc 4.8.2):
   orig    : fmin: -500000  fmax: 499999  time:   4.82s
@@ -6214,16 +6074,6 @@ icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -openmp
   simd    : fmin: -500000  fmax: 499999  time:   2.83s
   avx     : fmin: -500000  fmax: 499999  time:   2.92s
 
-icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -openmp -DOMP_SIMD minmax_val.c
- result on hama (icc 15.0.1):
- float:
-  minmax_val: fmin: -500000  fmax: 499999  time:   0.60s
- double:
-  minmax_val: fmin: -500000  fmax: 499999  time:   3.06s
-  orig      : fmin: -500000  fmax: 499999  time:   2.66s
-  simd      : fmin: -500000  fmax: 499999  time:   6.65s
-  avx       : fmin: -500000  fmax: 499999  time:   3.11s
-
 xlc_r -g -O3 -qhot -q64 -qarch=auto -qtune=auto -qreport -DTEST_MINMAXVAL minmax_val.c
  result on blizzard (xlc 12):
   orig    : fmin: -500000  fmax: 499999  time:   7.26s
@@ -6469,10 +6319,9 @@ void sse2_minmax_val_double(const double *restrict buf, size_t nframes, double *
 
 #if defined(_ARCH_PWR6)
 static
-void pwr6_minmax_val_double_unrolled6(const double *restrict data, long idatasize, double *fmin, double *fmax)
+void pwr6_minmax_val_double_unrolled6(const double *restrict data, size_t datasize, double *fmin, double *fmax)
 {
 #define __UNROLL_DEPTH_1 6
-  size_t datasize = idatasize;
 
   // to allow pipelining we have to unroll 
 
@@ -6516,9 +6365,9 @@ void pwr6_minmax_val_double_unrolled6(const double *restrict data, long idatasiz
 
 #if defined(TEST_MINMAXVAL) && defined(__GNUC__)
 static
-void minmax_val_double_orig(const double *restrict data, long idatasize, double *fmin, double *fmax) __attribute__ ((noinline));
+void minmax_val_double_orig(const double *restrict data, size_t datasize, double *fmin, double *fmax) __attribute__ ((noinline));
 static
-void minmax_val_double_simd(const double *restrict data, long idatasize, double *fmin, double *fmax) __attribute__ ((noinline));
+void minmax_val_double_simd(const double *restrict data, size_t datasize, double *fmin, double *fmax) __attribute__ ((noinline));
 #endif
 
 #if defined(GNUC_PUSH_POP)
@@ -6526,10 +6375,8 @@ void minmax_val_double_simd(const double *restrict data, long idatasize, double
 #pragma GCC optimize ("O3", "fast-math")
 #endif
 static
-void minmax_val_double_orig(const double *restrict data, long idatasize, double *fmin, double *fmax)
+void minmax_val_double_orig(const double *restrict data, size_t datasize, double *fmin, double *fmax)
 {
-  size_t i;
-  size_t datasize = idatasize;
   double dmin = *fmin, dmax = *fmax;
 
 #if   defined(CRAY)
@@ -6541,7 +6388,7 @@ void minmax_val_double_orig(const double *restrict data, long idatasize, double
 #elif defined (__ICC)
 #pragma ivdep
 #endif
-  for ( i = 0; i < datasize; ++i )
+  for ( size_t i = 0; i < datasize; ++i )
     {
       dmin = dmin < data[i] ? dmin : data[i];
       dmax = dmax > data[i] ? dmax : data[i];
@@ -6554,8 +6401,7 @@ void minmax_val_double_orig(const double *restrict data, long idatasize, double
 static
 void minmax_val_float(const float *restrict data, long idatasize, float *fmin, float *fmax)
 {
-  size_t i;
-  size_t datasize = idatasize;
+  size_t datasize = (size_t)idatasize;
   float dmin = *fmin, dmax = *fmax;
 
 #if   defined(CRAY)
@@ -6567,7 +6413,7 @@ void minmax_val_float(const float *restrict data, long idatasize, float *fmin, f
 #elif defined (__ICC)
 #pragma ivdep
 #endif
-  for ( i = 0; i < datasize; ++i )
+  for ( size_t i = 0; i < datasize; ++i )
     {
       dmin = dmin < data[i] ? dmin : data[i];
       dmax = dmax > data[i] ? dmax : data[i];
@@ -6583,25 +6429,19 @@ void minmax_val_float(const float *restrict data, long idatasize, float *fmin, f
 // TEST
 #if defined(OMP_SIMD)
 
-//#pragma omp declare reduction(xmin : double : omp_out = omp_in > omp_out ? omp_out : omp_in) initializer( omp_priv = { 1.e300 })
-//#pragma omp declare reduction(xmax : double : omp_out = omp_in < omp_out ? omp_out : omp_in) initializer( omp_priv = { -1.e300 })
-
 #if defined(GNUC_PUSH_POP)
 #pragma GCC push_options
 #pragma GCC optimize ("O3", "fast-math")
 #endif
 static
-void minmax_val_double_simd(const double *restrict data, long idatasize, double *fmin, double *fmax)
+void minmax_val_double_simd(const double *restrict data, size_t datasize, double *fmin, double *fmax)
 {
-  size_t i;
-  size_t datasize = idatasize;
   double dmin = *fmin, dmax = *fmax;
 
 #if defined(_OPENMP)
-  //#pragma omp simd reduction(xmin:dmin) reduction(xmax:dmax)
-#pragma omp simd
+#pragma omp simd reduction(min:dmin) reduction(max:dmax)
 #endif
-  for ( i = 0; i < datasize; ++i )
+  for ( size_t i = 0; i < datasize; ++i )
     {
       dmin = dmin < data[i] ? dmin : data[i];
       dmax = dmax > data[i] ? dmax : data[i];
@@ -6621,9 +6461,9 @@ void minmax_val_double(const double *restrict data, long idatasize, double *fmin
 #if defined(_GET_X86_COUNTER) || defined(_GET_MACH_COUNTER) 
   uint64_t start_minmax, end_minmax;
 #endif
-  size_t datasize = idatasize;
+  size_t datasize = (size_t)idatasize;
 
-  if ( idatasize < 1 ) return;
+  if ( idatasize >= 1 ) ; else return;
 
 #if defined(_GET_X86_COUNTER) 
   start_minmax = _rdtsc();
@@ -6732,7 +6572,7 @@ int main(void)
 
   {
     float fmin, fmax;
-    float *data_sp = (float*) Malloc(datasize*sizeof(float));
+    float *data_sp = (float*) malloc(datasize*sizeof(float));
 
     for ( long i = 0; i < datasize/2; i++ )        data_sp[i] = (float) (i);
     for ( long i = datasize/2; i < datasize; i++ ) data_sp[i] = (float) (-datasize + i);
@@ -6747,12 +6587,12 @@ int main(void)
       }
     t_end = dtime();
     printf("minmax_val: fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
-    Free(data_sp);
+    free(data_sp);
   }
 
   {
     double fmin, fmax;
-    double *data_dp = (double*) Malloc(datasize*sizeof(double));
+    double *data_dp = (double*) malloc(datasize*sizeof(double));
 
     // for ( long i = datasize-1; i >= 0; i-- ) data[i] = (double) (-datasize/2 + i);
     for ( long i = 0; i < datasize/2; i++ )        data_dp[i] = (double) (i);
@@ -6818,7 +6658,7 @@ int main(void)
     t_end = dtime();
     printf("pwr6u6  : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
 #endif
-    Free(data_dp);
+    free(data_dp);
   }
 
   return (0);
@@ -6829,20 +6669,48 @@ int main(void)
 #undef _ENABLE_AVX
 #undef _ENABLE_SSE2
 #undef GNUC_PUSH_POP
-/* 
+/*
+### new version with gribSwapByteOrder_uint16()
 icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_ENCODE encode_array.c
- result on hama (icc 15.0.1):
-  float:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 8.7936s
+ result on hama2 (icc 16.0.0):
+   float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 1.8731s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 2.0898s
+  double:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.68089s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.30798s
+     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.23864s
+
+gcc -g -Wall -O3 -std=c99 -DTEST_ENCODE encode_array.c
+ result on hama2 (gcc 5.2.0):
+   float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.96739s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.30871s
   double:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 13.6093s
-     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.90009s
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 6.24448s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 8.66679s
 
-gcc -g -Wall -O3 -march=native -std=c99 -DTEST_ENCODE encode_array.c
- result on hama (gcc 4.8.2):
-  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 16.0471s
-  sse41   : val1: 1  val2: 1  val3: 2  valn: 66  time: 15.4391s
+###
+icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_ENCODE encode_array.c
+ result on hama2 (icc 16.0.0):
+   float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 9.10691s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 8.63584s
+  double:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 13.5768s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 9.17742s
+     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.9488s
+
+gcc -g -Wall -O3 -std=c99 -DTEST_ENCODE encode_array.c
+ result on hama2 (gcc 5.2.0):
+   float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 5.32775s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 7.87125s
+  double:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 7.85873s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 12.9979s
 
+###
 gcc -g -Wall -O3 -march=native -std=c99 -DTEST_ENCODE encode_array.c
  result on bailung (gcc 4.7):
   orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 8.4166s
@@ -7207,14 +7075,11 @@ void pout(char *name, int s, unsigned char *lgrib, long datasize, double tt)
 int main(void)
 {
   long datasize = 1000000;
-  float *dataf = NULL;
-  double *data = NULL;
   double t_begin, t_end;
-  unsigned char *lgrib;
 
-  dataf = (float*) Malloc(datasize*sizeof(float));
-  data  = (double*) Malloc(datasize*sizeof(double));
-  lgrib = (unsigned char*) Malloc(2*datasize*sizeof(unsigned char));
+  float *dataf = (float*) malloc(datasize*sizeof(float));
+  double *data = (double*) malloc(datasize*sizeof(double));
+  unsigned char *lgrib = (unsigned char*) malloc(2*datasize*sizeof(unsigned char));
 
   for ( long i = 0; i < datasize; ++i ) dataf[i] = (float) (-datasize/2 + i);
   for ( long i = 0; i < datasize; ++i ) data[i] = (double) (-datasize/2 + i);
@@ -7232,7 +7097,6 @@ int main(void)
       encode_array_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
     }
 
-
 #if   defined(__ICC)
   printf("icc\n");
 #elif defined(__clang__)
@@ -7308,240 +7172,6 @@ int main(void)
 #undef DISABLE_SIMD
 #undef _ENABLE_AVX
 #undef _ENABLE_SSE4_1
-//#undef _GET_X86_COUNTER
-//#undef _GET_MACH_COUNTER
-//#undef _GET_IBM_COUNTER
-//#undef _ARCH_PWR6
-
-#if defined _GET_IBM_COUNTER
-#include <libhpc.h>
-#elif defined _GET_X86_COUNTER
-#include <x86intrin.h>
-#elif defined _GET_MACH_COUNTER
-#include <mach/mach_time.h>
-#endif
-
-#ifdef __cplusplus
-#define __STDC_FORMAT_MACROS
-#endif
-#include <inttypes.h>
-
-#if   defined(__GNUC__) && (__GNUC__ >= 4)
-#elif defined(__ICC)    && (__ICC >= 1100)
-#elif defined(__clang__)
-#else
-#define DISABLE_SIMD
-#endif
-
-#define DISABLE_SIMD
-
-#ifdef DISABLE_SIMD
-# ifdef ENABLE_AVX
-#  define _ENABLE_AVX
-# endif
-# ifdef ENABLE_SSE4_1
-#  define _ENABLE_SSE4_1
-# endif
-#endif
-
-#ifndef DISABLE_SIMD
-# ifdef __AVX__
-#  define _ENABLE_AVX
-# endif
-# ifdef __SSE4_1__
-#  define _ENABLE_SSE4_1
-# endif
-#endif
-
-#if defined _ENABLE_AVX
-#include <immintrin.h>
-#elif defined _ENABLE_SSE4_1
-#include <smmintrin.h>
-#endif
-
-#if defined _ENABLE_AVX
-
-static
-void avx_decode_array_2byte_double(size_t datasize, const unsigned char * restrict igrib,
-				     double * restrict fpdata, double fmin, double zscale)
-{
-  size_t i, j;
-  size_t nframes = datasize;
-  size_t residual;
-  size_t ofs;
-
-  double dval;
-
-  double *data = fpdata;
-  __m128i *sgrib;
-  
-  __m128i mask = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
-
-  __m256d ymm0 = _mm256_set1_pd(fmin);
-  __m256d ymm1 = _mm256_set1_pd(zscale);
-  
-  __m128i xmm0, xmm1, xmm2, xmm3;
-  __m256d ymm2, ymm3;
-
-  i = -1;
-  while ( ((unsigned long) data) % 32 != 0 && datasize > 0)
-    {
-      i++;
-      dval = (((int)igrib[2*i] <<  8) | (int)igrib[2*i+1]);
-      fpdata[i] = fmin + zscale * dval;
-      data++;
-      nframes--;
-    }
-  
-  if (i == -1) i = 0;
-  sgrib = (__m128i *) (igrib+i);
-
-  while (nframes >= 16)
-    { 
-      xmm0 = _mm_loadu_si128((__m128i *) sgrib);
-      xmm0 = _mm_shuffle_epi8(xmm0, mask);
-      xmm1 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(1, 0, 3, 2));
-      xmm2 = _mm_cvtepu16_epi32(xmm0);
-      xmm3 = _mm_cvtepu16_epi32(xmm1);
-
-      ymm2 = _mm256_cvtepi32_pd(xmm2);
-      ymm2 = _mm256_add_pd(_mm256_mul_pd(ymm2, ymm1), ymm0);
-      (void) _mm256_stream_pd(data, ymm2);
-      ymm3 = _mm256_cvtepi32_pd(xmm3);
-      ymm3 = _mm256_add_pd(_mm256_mul_pd(ymm3, ymm1), ymm0);
-      (void) _mm256_stream_pd(data+4, ymm3);  
-      
-      xmm0 = _mm_loadu_si128((__m128i *) sgrib + 1);
-      xmm0 = _mm_shuffle_epi8(xmm0, mask);
-      xmm1 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(1, 0, 3, 2));
-      xmm2 = _mm_cvtepu16_epi32(xmm0);
-      xmm3 = _mm_cvtepu16_epi32(xmm1);
-      
-      ymm2 = _mm256_cvtepi32_pd(xmm2);
-      ymm2 = _mm256_add_pd(_mm256_mul_pd(ymm2, ymm1), ymm0);
-      (void) _mm256_stream_pd(data+8, ymm2);
-      ymm3 = _mm256_cvtepi32_pd(xmm3);
-      ymm3 = _mm256_add_pd(_mm256_mul_pd(ymm3, ymm1), ymm0);
-      (void) _mm256_stream_pd(data+12, ymm3);  
-      
-      data += 16;
-      sgrib += 2;
-      nframes -= 16;
-    }
-
-  residual = nframes;
-  ofs = datasize - residual;
-  for ( j = 0; j < residual; j++ )
-    {
-      dval = (((int)igrib[2*(ofs+j)] <<  8) | (int)igrib[2*(ofs+j)+1]);
-      fpdata[ofs+j] = fmin + zscale * dval;
-    }
-
-  return;
-}
-
-#elif defined _ENABLE_SSE4_1
-
-static
-void sse41_decode_array_2byte_double(size_t datasize, const unsigned char * restrict igrib,
-				     double * restrict fpdata, double fmin, double zscale)
-{
-  size_t i, j;
-  size_t nframes = datasize;
-  size_t residual;
-  size_t ofs;
-
-  double dval;
-
-  double *data = fpdata;
-  __m128i *sgrib;
-  
-  __m128i mask = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
-  __m128d dmm8 = _mm_set1_pd(fmin);
-  __m128d dmm9 = _mm_set1_pd(zscale);
-  
-  __m128i xmm4, xmm5;
-  __m128i xmm6, xmm7;
-  
-  __m128d dmm0, dmm1, dmm2, dmm3;
-  __m128d dmm4, dmm5, dmm6, dmm7;
-
-  i = -1;
-  while ( ((unsigned long) data) % 32 != 0 && datasize > 0)
-    {
-      i++;
-      dval = (((int)igrib[2*i] <<  8) | (int)igrib[2*i+1]);
-      fpdata[i] = fmin + zscale * dval;
-      data++;
-      nframes--;
-    }
-  
-  if (i == -1) i = 0;
-  sgrib = (__m128i *) (igrib+i);
-  
-  while (nframes >= 16)
-    {
-      xmm5 = _mm_loadu_si128((__m128i *) sgrib);
-      xmm5 = _mm_shuffle_epi8(xmm5, mask);
-      xmm4 = _mm_srli_si128(xmm5, 8);
-      xmm6 = _mm_cvtepu16_epi32(xmm5);
-      dmm0 = _mm_cvtepi32_pd(xmm6);
-      dmm0 = _mm_add_pd(_mm_mul_pd(dmm0, dmm9), dmm8);
-      (void) _mm_stream_pd(data, dmm0);
-      xmm7 = _mm_srli_si128(xmm6, 8);
-      dmm1 = _mm_cvtepi32_pd(xmm7);
-      dmm1 = _mm_add_pd(_mm_mul_pd(dmm1, dmm9), dmm8);
-      (void) _mm_stream_pd(data+2, dmm1);
-      xmm6 = _mm_cvtepu16_epi32(xmm4);
-      dmm2 = _mm_cvtepi32_pd(xmm6);
-      dmm2 = _mm_add_pd(_mm_mul_pd(dmm2, dmm9), dmm8);
-      (void) _mm_stream_pd(data+4, dmm2);
-      xmm7 = _mm_srli_si128(xmm6, 8);
-      dmm3 = _mm_cvtepi32_pd(xmm7);
-      dmm3 = _mm_add_pd(_mm_mul_pd(dmm3, dmm9), dmm8);
-      (void) _mm_stream_pd(data+6, dmm3);
-      
-      xmm5 = _mm_loadu_si128((__m128i *) sgrib+1);
-      xmm5 = _mm_shuffle_epi8(xmm5, mask);
-      xmm4 = _mm_srli_si128(xmm5, 8);
-      xmm6 = _mm_cvtepu16_epi32(xmm5);
-      dmm4 = _mm_cvtepi32_pd(xmm6);
-      dmm4 = _mm_add_pd(_mm_mul_pd(dmm4, dmm9), dmm8);
-      (void) _mm_stream_pd(data+8, dmm4);
-      xmm7 = _mm_srli_si128(xmm6, 8);
-      dmm5 = _mm_cvtepi32_pd(xmm7);
-      dmm5 = _mm_add_pd(_mm_mul_pd(dmm5, dmm9), dmm8);
-      (void) _mm_stream_pd(data+10, dmm5);
-      xmm6 = _mm_cvtepu16_epi32(xmm4);
-      dmm6 = _mm_cvtepi32_pd(xmm6);
-      dmm6 = _mm_add_pd(_mm_mul_pd(dmm6, dmm9), dmm8);
-      (void) _mm_stream_pd(data+12, dmm6);
-      xmm7 = _mm_srli_si128(xmm6, 8);
-      dmm7 = _mm_cvtepi32_pd(xmm7);
-      dmm7 = _mm_add_pd(_mm_mul_pd(dmm7, dmm9), dmm8);
-      (void) _mm_stream_pd(data+14, dmm7);
-
-      data += 16;
-      sgrib += 2;
-      nframes -= 16;
-    }
-
-  residual = nframes;
-  ofs = datasize - residual;
-  for ( j = 0; j < residual; j++ )
-    {
-      dval = (((int)igrib[2*(ofs+j)] <<  8) | (int)igrib[2*(ofs+j)+1]);
-      fpdata[ofs+j] = fmin + zscale * dval;
-    }
-
-  return;
-}
-
-#endif
-
-#undef DISABLE_SIMD
-#undef _ENABLE_AVX
-#undef _ENABLE_SSE4_1
 
 
 void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
@@ -7612,12 +7242,7 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
         - replace 1.0 / pow(16.0, (double)(iexp - 70)) by rpow16m70tab[iexp]
   */
 
-  double rpowref;
-  double zref, zeps;
-  int iexp, isign;
-  int iround;
   // extern int CGRIBEX_Debug;
-  extern const double _pow16tab[71];
 
   /* ----------------------------------------------------------------- */
   /*   Section 1 . Initialise                                          */
@@ -7625,7 +7250,7 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
 
   /*  Check conversion type parameter. */
 
-  iround = kround;
+  int iround = kround;
   if ( iround != 0 && iround != 1 )
     {
       Error("Invalid conversion type = %d", iround);
@@ -7650,42 +7275,35 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
   /* ----------------------------------------------------------------- */
   /*   Section 3 . Convert other values.                               */
   /* ----------------------------------------------------------------- */
+  {
+    double zeps = kbits != 32 ? 1.0e-12 : 1.0e-8;
+    double zref = pval;
 
-  zeps = 1.0e-12;
-  if ( kbits == 32 ) zeps = 1.0e-8;
-  zref = pval;
+    /*  Sign of value. */
 
-  /*  Sign of value. */
-
-  isign = 0;
-  if ( zref < 0.0 )
-    {
-      isign = 128;
-      zref  = - zref;
-    }
+    int isign = zref >= 0.0 ? 0 : 128;
+    zref = fabs(zref);
 
-  /*  Exponent. */
+    /*  Exponent. */
 
-  iexp = (int) (log(zref)/log(16.0) + 65.0 + zeps);
+    int iexp = (int) (log(zref)/log(16.0) + 65.0 + zeps);
 
-  /* only ANSI C99 has log2 */
-  /* iexp = (int) (log2(zref) * 0.25 + 65.0 + zeps); */
+    /* only ANSI C99 has log2 */
+    /* iexp = (int) (log2(zref) * 0.25 + 65.0 + zeps); */
 
-  if ( iexp < 0   ) iexp = 0;
-  if ( iexp > 127 ) iexp = 127;
+    if ( iexp < 0   ) iexp = 0;
+    if ( iexp > 127 ) iexp = 127;
 
-  /*
-  rpowref = zref / pow(16.0, (double)(iexp - 70));
-  */
+    double rpowref;
+    /*
+      rpowref = zref / pow(16.0, (double)(iexp - 70));
+    */
 
-  if ( (iexp - 70) < 0 )
-    rpowref = zref * _pow16tab[-(iexp - 70)];
-  else
-    rpowref = zref / _pow16tab[(iexp - 70)];
+    rpowref = ldexp(zref, 4 * -(iexp - 70));
 
-  /*  Mantissa. */
+    /*  Mantissa. */
 
-  if ( iround == 0 )
+    if ( iround == 0 )
     {
       /*  Closest number in GRIB format less than original number. */
       /*  Truncate for positive numbers. */
@@ -7696,7 +7314,7 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
       else
 	*kmant = (int)lround(rpowref + 0.5);
     }
-  else
+    else
     {
       /*  Closest number in GRIB format to the original number   */
       /*  (equal to, greater than or less than original number). */
@@ -7704,12 +7322,12 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
       *kmant = (int)lround(rpowref);
     }
 
-  /*  Check that mantissa value does not exceed 24 bits. */
-  /*  If it does, adjust the exponent upwards and recalculate */
-  /*  the mantissa. */
-  /*  16777215 = 2**24 - 1 */
+    /*  Check that mantissa value does not exceed 24 bits. */
+    /*  If it does, adjust the exponent upwards and recalculate */
+    /*  the mantissa. */
+    /*  16777215 = 2**24 - 1 */
 
-  if ( *kmant > 16777215 )
+    if ( *kmant > 16777215 )
     {
 
     LABEL350:
@@ -7719,47 +7337,44 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
       /*  Check for exponent overflow during adjustment  */
 
       if ( iexp > 127 )
-	{
-          Message("Exponent overflow");
-          Message("Original number = %30.20f", pval);
-          Message("Sign = %3d, Exponent = %3d, Mantissa = %12d",
-		  isign, iexp, *kmant);
+      {
+        Message("Exponent overflow");
+        Message("Original number = %30.20f", pval);
+        Message("Sign = %3d, Exponent = %3d, Mantissa = %12d",
+                isign, iexp, *kmant);
 
-	  Error("Exponent overflow");
+        Error("Exponent overflow");
 
-	  /*  If not aborting, arbitrarily set value to zero  */
+        /*  If not aborting, arbitrarily set value to zero  */
 
-          Message("Value arbitrarily set to zero.");
-          *kexp  = 0;
-          *kmant = 0;
-          // iexp  = 0;
-          // isign = 0;
-          goto LABEL900;
-	}
+        Message("Value arbitrarily set to zero.");
+        *kexp  = 0;
+        *kmant = 0;
+        // iexp  = 0;
+        // isign = 0;
+        goto LABEL900;
+      }
 
-      if ( (iexp - 70) < 0 )
-	rpowref = zref * _pow16tab[-(iexp - 70)];
-      else
-	rpowref = zref / _pow16tab[(iexp - 70)];
+      rpowref = ldexp(zref, 4 * -(iexp - 70));
 
       if ( iround == 0 )
-	{
-	  /*  Closest number in GRIB format less than original number. */
-	  /*  Truncate for positive numbers. */
-	  /*  Round up for negative numbers. */
+      {
+        /*  Closest number in GRIB format less than original number. */
+        /*  Truncate for positive numbers. */
+        /*  Round up for negative numbers. */
 
-	  if ( isign == 0 )
-	    *kmant = (int)rpowref;
-	  else
-	    *kmant = (int)lround(rpowref + 0.5);
-	}
+        if ( isign == 0 )
+          *kmant = (int)rpowref;
+        else
+          *kmant = (int)lround(rpowref + 0.5);
+      }
       else
-	{
-	  /*  Closest number in GRIB format to the original number */
-	  /*  (equal to, greater or less than original number). */
+      {
+        /*  Closest number in GRIB format to the original number */
+        /*  (equal to, greater or less than original number). */
 
-	  *kmant = (int)lround(rpowref);
-	}
+        *kmant = (int)lround(rpowref);
+      }
 
       /*  Repeat calculation (with modified exponent) if still have */
       /*  mantissa overflow. */
@@ -7767,9 +7382,10 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
       if ( *kmant > 16777215 ) goto LABEL350;
     }
 
-  /*  Add sign bit to exponent. */
+    /*  Add sign bit to exponent. */
 
-  *kexp = iexp + isign;
+    *kexp = iexp + isign;
+  }
 
   /* ----------------------------------------------------------------- */
   /*   Section 9. Return                                               */
@@ -7792,6 +7408,7 @@ LABEL900:
   */
   return;
 } /* confp3 */
+#include <math.h>
 
 
 double decfp2(int kexp, int kmant)
@@ -7853,7 +7470,7 @@ double decfp2(int kexp, int kmant)
     Uwe Schulzweida   MPIfM   01/04/2001
 
      - Convert to C from EMOS library version 130
-     
+
     Uwe Schulzweida   MPIfM   02/08/2002
 
      - speed up by factor 2 on NEC SX6
@@ -7862,10 +7479,7 @@ double decfp2(int kexp, int kmant)
   */
 
   double pval;
-  int iexp, isign;
   //extern int CGRIBEX_Debug;
-  extern const double _pow16tab[71];
-  
   /* ----------------------------------------------------------------- */
   /*   Section 1 . Convert value of 0.0. Ignore sign bit.              */
   /* ----------------------------------------------------------------- */
@@ -7886,14 +7500,10 @@ double decfp2(int kexp, int kmant)
 
   /*  Sign of value. */
 
-  iexp  = kexp;
-  isign = 1;
+  int iexp  = kexp,
+    isign = (iexp < 128) * 2 - 1;
 
-  if ( iexp >= 128 )
-    {
-      iexp -= 128;
-      isign = -1;
-    }
+  iexp -= iexp < 128 ? 0 : 128;
 
   /*  Decode value. */
 
@@ -7901,12 +7511,7 @@ double decfp2(int kexp, int kmant)
 
   iexp -= 64;
 
-  if ( iexp < 0 )
-    pval = 1./_pow16tab[-iexp];
-  else
-    pval = _pow16tab[iexp];
-
-  pval *= isign * POW_2_M24 * kmant;
+  pval = ldexp(1.0, 4 * iexp) * isign * POW_2_M24 * kmant;
 
   /* ----------------------------------------------------------------- */
   /*   Section 9. Return to calling routine.                           */
@@ -8106,7 +7711,7 @@ void gprintf(const char *caller, const char *fmt, ...)
 void
 gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
 	 double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
-	 int kleng, int *kword, char *hoper, int *kret)
+	 int kleng, int *kword, const char *hoper, int *kret)
 {
   int yfunc = *hoper;
 
@@ -8137,7 +7742,7 @@ gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
 void
 gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
 	 float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
-	 int kleng, int *kword, char *hoper, int *kret)
+	 int kleng, int *kword, const char *hoper, int *kret)
 {
   int yfunc = *hoper;
 
@@ -8164,86 +7769,6 @@ gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
     }
 }
 
-
-void
-gribExSP_old(int *isec0, int *isec1, int *isec2, float *fsec2sp, int *isec3,
-	     float *fsec3sp, int *isec4, float *fsec4sp, int klenp, int *kgrib,
-	     int kleng, int *kword, char *hoper, int *kret)
-{
-  int inum, j;
-  double fsec2dp[1024];
-  double fsec3dp[2];
-  double *fsec4dp = NULL;
-  int yfunc = *hoper;
-
-  if ( yfunc == 'C' )
-    {
-      inum = 10 + isec2[11];
-      for ( j = 0; j < inum; j++ ) fsec2dp[j] = fsec2sp[j];
-
-      fsec3dp[0] = fsec3sp[0];
-      fsec3dp[1] = fsec3sp[1];
-
-      inum = isec4[0];
-      fsec4dp = (double*) Malloc(inum*sizeof(double));
-      if ( fsec4dp == NULL ) SysError("No Memory!");
-
-      for ( j = 0; j < inum; j++ ) fsec4dp[j] = fsec4sp[j];
-
-      gribExDP(isec0, isec1, isec2, fsec2dp, isec3,
-	       fsec3dp, isec4, fsec4dp, klenp, kgrib,
-	       kleng, kword, hoper, kret);
-
-      Free(fsec4dp);
-    }
-  else if ( yfunc == 'D' || yfunc == 'J' || yfunc == 'R' )
-    {
-      if ( yfunc == 'D' || yfunc == 'R' )
-	{
-	  fsec4dp = (double*) Malloc(klenp*sizeof(double));
-	  if ( fsec4dp == NULL ) SysError("No Memory!");
-	}
-
-      for ( j = 0; j < 10; j++ ) fsec2dp[j] = 0.0;
-      for ( j = 0; j <  2; j++ ) fsec3dp[j] = 0.0;
-
-      gribExDP(isec0, isec1, isec2, fsec2dp, isec3,
-	       fsec3dp, isec4, fsec4dp, klenp, kgrib,
-	       kleng, kword, hoper, kret);
-
-      inum = 10 + isec2[11];
-      for ( j = 0; j < inum; j++ ) fsec2sp[j] = fsec2dp[j];
-
-      fsec3sp[0] = fsec3dp[0];
-      fsec3sp[1] = fsec3dp[1];
-
-      if ( yfunc == 'D' || yfunc == 'R' )
-	{
-	  inum = isec4[0];
-	  for ( j = 0; j < inum; j++ )
-	    {
-	      if ( fsec4dp[j] > -FLT_MIN && fsec4dp[j] < FLT_MIN )
-		fsec4sp[j] = 0;
-	      else if ( fsec4dp[j] > FLT_MAX )
-		fsec4sp[j] = FLT_MAX;
-	      else if ( fsec4dp[j] < -FLT_MAX )
-		fsec4sp[j] = -FLT_MAX;
-	      else
-		fsec4sp[j] = fsec4dp[j];
-	    }
-
-	  Free(fsec4dp);
-	}
-    }
-  else if ( yfunc == 'V' )
-    fprintf(stderr, " c-gribex: Version is %s\n", cgribexLibraryVersion());
-  else
-    {
-      Error("oper %c unsupported!", yfunc);
-      *kret=-9;
-    }
-}
-
 int CGRIBEX_Fix_ZSE  = 0;    /* 1: Fix ZeroShiftError of simple packed spherical harmonics */
 int CGRIBEX_Const    = 0;    /* 1: Don't pack constant fields on regular grids */
 int CGRIBEX_Debug    = 0;    /* 1: Debugging */
@@ -9524,7 +9049,7 @@ void gribPrintSec2SP(int *isec0, int *isec2, float  *fsec2sp)
 
   inum = 10 + isec2[11];
 
-  fsec2 = (double*) Malloc(inum*sizeof(double));
+  fsec2 = (double*) Malloc((size_t)inum*sizeof(double));
   if ( fsec2 == NULL ) SysError("No Memory!");
 
   for ( j = 0; j < inum; j++ )
@@ -9871,29 +9396,30 @@ int gribCheckSeek(int fileID, long *offset, int *version)
 int gribFileSeekOld(int fileID, long *offset)
 {
   /* position file pointer after GRIB */
-  int ch;
-  int buffersize = 4096;
-  unsigned char buffer[4096];
+  enum { buffersize = 4096 };
+  unsigned char buffer[buffersize];
   int retry = 4096;
-  int i;
 
   *offset = 0;
 
   void *fileptr = filePtr(fileID);
 
-  ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[0] = ch;
-  ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[1] = ch;
-  ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[2] = ch;
-  ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[3] = ch;
+  for ( size_t i = 0; i < 4; ++i)
+    {
+      int ch = filePtrGetc(fileptr);
+      if ( ch == EOF ) return (-1);
+      buffer[i] = (unsigned char)ch;
+    }
   /*
   fileRead(fileID, buffer, 4);
   */
 
   while ( retry-- )
     {
+      size_t i;
       for ( i = 0; i < buffersize-4; ++i )
 	{
-	  if (buffer[i  ] == 'G' && 
+	  if (buffer[i  ] == 'G' &&
 	      buffer[i+1] == 'R' &&
 	      buffer[i+2] == 'I' &&
 	      buffer[i+3] == 'B')
@@ -9904,7 +9430,7 @@ int gribFileSeekOld(int fileID, long *offset)
 	    }
 	  else
 	    {
-	      ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[i+4] = ch;
+	      int ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[i+4] = (unsigned char)ch;
 	      (*offset)++;
 	    }
 	}
@@ -9958,13 +9484,13 @@ int gribFileSeek(int fileID, long *offset)
 int gribFileSeekTest(int fileID, long *offset)
 {
   /* position file pointer after GRIB */
-  const long GRIB = 0x47524942;
+  const long GRIB = 0x47524942L;
   long code = 0;
   int ch;
   int i = 0;
-  const int buffersize = 8;
-  unsigned char buffer[8];
-  int retry = 4096*4096;
+  enum { buffersize = 8 };
+  unsigned char buffer[buffersize];
+  unsigned long retry = 4096L*4096L;
   int nread = 0;
 
   *offset = 0;
@@ -9981,7 +9507,7 @@ int gribFileSeekTest(int fileID, long *offset)
 	}
 
       ch = buffer[i++];
-      code = ( (code << 8) + ch ) & 0xFFFFFFFF;
+      code = ( (code << 8) + ch ) & 0xFFFFFFFFL;
 
       if ( code == GRIB )
 	{
@@ -10002,6 +9528,14 @@ int gribFileSeekTest(int fileID, long *offset)
   return 1;
 }
 
+static inline int
+read3ByteMSBFirst(void *fileptr)
+{
+  unsigned b1 = (unsigned)(filePtrGetc(fileptr));
+  unsigned b2 = (unsigned)(filePtrGetc(fileptr));
+  unsigned b3 = (unsigned)(filePtrGetc(fileptr));
+  return (int)((b1 << 16) + (b2 << 8) + b3);
+}
 
 int gribReadSize(int fileID)
 {
@@ -10027,7 +9561,7 @@ int gribReadSize(int fileID)
     {
       int pdssize = 0, gdssize = 0, bmssize = 0, bdssize = 0;
       int issize = 4, essize = 4;
-      int flag;
+      int flag = 0;
 
       pdssize = gribsize;
       fileSetPos(fileID, (off_t) 3, SEEK_CUR);
@@ -10039,22 +9573,19 @@ int gribReadSize(int fileID)
 
       if ( flag & 128 )
 	{
-	  b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	  gdssize = (b1 << 16) + (b2 << 8) + b3;
+	  gdssize = read3ByteMSBFirst(fileptr);
 	  fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
 	  if ( CGRIBEX_Debug ) Message("gdssize     = %d", gdssize);
 	}
 
       if ( flag & 64 )
 	{
-	  b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	  bmssize = (b1 << 16) + (b2 << 8) + b3;
+	  bmssize = read3ByteMSBFirst(fileptr);
 	  fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
 	  if ( CGRIBEX_Debug ) Message("bmssize     = %d", bmssize);
 	}
 
-      b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-      bdssize = (b1 << 16) + (b2 << 8) + b3;
+      bdssize = read3ByteMSBFirst(fileptr);
       if ( CGRIBEX_Debug ) Message("bdssize     = %d", bdssize);
 
       gribsize = issize + pdssize + gdssize + bmssize + bdssize + essize;
@@ -10067,8 +9598,7 @@ int gribReadSize(int fileID)
 	  int issize = 4, essize = 4;
 	  int flag;
 
-	  b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	  pdssize = (b1 << 16) + (b2 << 8) + b3;
+	  pdssize = read3ByteMSBFirst(fileptr);
 	  if ( CGRIBEX_Debug ) Message("pdssize     = %d", pdssize);
 
 	  for ( int i = 0; i < 5; ++i ) flag = filePtrGetc(fileptr);
@@ -10078,22 +9608,19 @@ int gribReadSize(int fileID)
 
 	  if ( flag & 128 )
 	    {
-	      b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	      gdssize = (b1 << 16) + (b2 << 8) + b3;
+	      gdssize = read3ByteMSBFirst(fileptr);
 	      fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
 	      if ( CGRIBEX_Debug ) Message("gdssize     = %d", gdssize);
 	    }
 	  
 	  if ( flag & 64 )
 	    {
-	      b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	      bmssize = (b1 << 16) + (b2 << 8) + b3;
+	      bmssize = read3ByteMSBFirst(fileptr);
 	      fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
 	      if ( CGRIBEX_Debug ) Message("bmssize     = %d", bmssize);
 	    }
 
-	  b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	  bdssize = (b1 << 16) + (b2 << 8) + b3;
+	  bdssize = read3ByteMSBFirst(fileptr);
 	  bdssize = correct_bdslen(bdssize, gribsize, issize+pdssize+gdssize+bmssize);
 	  if ( CGRIBEX_Debug ) Message("bdssize     = %d", bdssize);
 
@@ -10162,7 +9689,7 @@ int gribRead(int fileID, unsigned char *buffer, size_t *buffersize)
   if      ( ierr == -1 ) { *buffersize = 0; return -1; }
   else if ( ierr ==  1 ) { *buffersize = 0; return -2; }
 
-  size_t recSize  = gribReadSize(fileID);
+  size_t recSize  = (size_t)gribReadSize(fileID);
   size_t readSize = recSize;
 
   if ( readSize > *buffersize )
@@ -10193,7 +9720,7 @@ int gribWrite(int fileID, unsigned char *buffer, size_t buffersize)
 {
   int  nwrite = 0;
 
-  if ( (nwrite = fileWrite(fileID, buffer, buffersize)) != (int) buffersize )
+  if ( (nwrite = (int)(fileWrite(fileID, buffer, buffersize))) != (int) buffersize )
     {
       perror(__func__);
       nwrite = -1;
@@ -10213,7 +9740,7 @@ int gribrec_len(unsigned b1, unsigned b2, unsigned b3)
   */
   int needRescaling = b1 & (1 << 7);
   
-  int gribsize = (((b1&127) << 16)+(b2<<8) + b3);
+  int gribsize = (int)((((b1&127) << 16)+(b2<<8) + b3));
 
   if ( needRescaling ) gribsize *= 120;
 
@@ -11078,6 +10605,7 @@ void ref2ibm(double *pref, int kbits)
 
   return;
 } /* ref2ibm */
+#include <math.h>
 #include <string.h>
 
 
@@ -11091,7 +10619,7 @@ int correct_bdslen(int bdslen, long recsize, long gribpos)
     due to the count being only 24 bits. It is only possible because
     the (default) rounding for GRIB products is 120 bytes.
   */
-  if ( recsize > JP23SET ) bdslen = recsize - gribpos - bdslen;
+  if ( recsize > JP23SET ) bdslen = (int)(recsize - gribpos - bdslen);
   return (bdslen);
 }
 
@@ -11455,19 +10983,20 @@ int grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer,
 	      bufpointer[0], bufpointer[1], bufpointer[2], bufpointer[3]);
     }
 
-  bsf = BDS_BinScale;
-  if ( bsf > 32767 ) bsf = 32768-bsf;
-  bsf = pow(2.0,(double)bsf);
+  {
+    int bs = BDS_BinScale;
+    if ( bs > 32767 ) bs = 32768-bs;
+    bsf = ldexpf(1.0f, bs);
+  }
 
   bignum[0] = dpos;
-  if ( bms ) bignum[1] = bpos;
-  else       bignum[1] = -999;
+  bignum[1] = bms ? bpos : -999;
   intnum[0] = BDS_NumBits;
 
   /*  fltnum[0] = 1.0; */
-  fltnum[0] = pow(10.0, (double)PDS_DecimalScale);
+  fltnum[0] = powf(10.0f, (float)PDS_DecimalScale);
   fltnum[1] = bsf;
-  fltnum[2] = BDS_RefValue;
+  fltnum[2] = (float)BDS_RefValue;
   /*
   printf("intnum %d %d %d\n", intnum[0], intnum[1], intnum[2]);
   printf("fltnum %g %g %g\n", fltnum[0], fltnum[1], fltnum[2]);
@@ -11608,7 +11137,7 @@ void gribPrintALL(int nrec, long offset, long recpos, long recsize, unsigned cha
 {
   int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 0 || gribversion == 1 )
     grib1PrintALL(nrec, offset, recpos, recsize, gribbuffer);
@@ -11700,7 +11229,7 @@ void gribPrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer
 {
   int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 0 || gribversion == 1 )
     grib1PrintPDS(nrec, recpos, recsize, gribbuffer);
@@ -11761,7 +11290,7 @@ void gribPrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer
 {
   int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 0 || gribversion == 1 )
     grib1PrintGDS(nrec, recpos, recsize, gribbuffer);
@@ -11826,7 +11355,7 @@ void gribPrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer
 {
   int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 0 || gribversion == 1 )
     grib1PrintBMS(nrec, recpos, recsize, gribbuffer);
@@ -11916,7 +11445,7 @@ void gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer
 {
   int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 0 || gribversion == 1 )
     grib1PrintBDS(nrec, recpos, recsize, gribbuffer);
@@ -11979,7 +11508,6 @@ void gribCheck1(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
 static
 void repair1(unsigned char *gbuf, long gbufsize)
 {
-  long i;
   int nerr;
   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
   /* int recLen; */
@@ -12035,15 +11563,13 @@ void repair1(unsigned char *gbuf, long gbufsize)
 
   source = bds + datstart;
 
-  sourceLen = ((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8;
+  sourceLen = (size_t)(((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8);
 
   if ( bds_nbits == 24 )
     {
-      long nelem;
-      unsigned char *pbuf;
-      nelem = sourceLen/3;
-      pbuf = (unsigned char*) Malloc(sourceLen);
-      for ( i = 0; i < nelem; i++ )
+      unsigned char *pbuf = (unsigned char*) Malloc(sourceLen);;
+      size_t nelem = sourceLen/3;
+      for ( size_t i = 0; i < nelem; i++ )
 	{
 	  pbuf[3*i  ] = source[        i];
 	  pbuf[3*i+1] = source[  nelem+i];
@@ -12150,9 +11676,8 @@ int gribGetZip(long recsize, unsigned char *gribbuffer, long *urecsize)
   int bds_flag, lcompress;
   long gribsize = 0;
   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  int gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 2 ) return (compress);
 
@@ -12507,22 +12032,20 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 #if ! (defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC))
   static int libszwarn = 1;
 #endif
-  int nerr;
   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  int bdsLen, recLen, gribLen = 0;
+  size_t gribLen = 0;
   unsigned char *dest, *source;
   size_t destLen, sourceLen;
   int /* bds_len, */ bds_nbits, bds_flag, lspherc, lcomplex /*, lcompress*/;
-  int bds_head = 11;
+  enum { bds_head = 11 };
   int bds_ext = 0;
   int bds_zoffset, bds_zstart;
-  int datstart = 0;
   int llarge = FALSE;
 
   UNUSED(dbufsize);
 
   long gribrecsize;
-  nerr = grib1Sections(sbuf, sbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  int nerr = grib1Sections(sbuf, sbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
   if ( nerr < 0 )
     {
       fprintf(stdout, "GRIB message error\n");
@@ -12537,7 +12060,7 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 
   bds_zstart = 14;
 
-  recLen = gribrec_len(bds[bds_zstart], bds[bds_zstart+1], bds[bds_zstart+2]);
+  int recLen = gribrec_len(bds[bds_zstart], bds[bds_zstart+1], bds[bds_zstart+2]);
   if ( recLen > JP23SET ) llarge = TRUE;
 
   bds_zoffset = 12;
@@ -12565,7 +12088,7 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 	}
     }
 
-  datstart = bds_head + bds_ext;
+  size_t datstart = bds_head + (size_t)bds_ext;
 
   source = bds + datstart + bds_zoffset;
   if ( llarge )
@@ -12587,14 +12110,14 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
     }
 
   dest = bds + datstart;
-   if ( llarge )
+  if ( llarge )
     destLen = ((size_t) ((bds[17]<<24)+(bds[18]<<16)+(bds[19]<<8)+bds[20]));
   else
     destLen = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
 
-  BDS_Flag -= 16;
+  BDS_Flag = (unsigned char)(BDS_Flag - 16);
 
-  bdsLen = datstart + destLen;
+  size_t bdsLen = datstart + destLen;
 
 #if  defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC)
   {
@@ -12689,7 +12212,7 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 	    pbuf[3*i+2] = dest[2*nelem+i];
 	  }
 	memcpy(dest, pbuf, tmpLen);
-        Free(pbuf);
+	Free(pbuf);
       }
 #endif
 
@@ -12725,7 +12248,7 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 	*/
 	while ( gribLen%120 ) dbuf[gribLen++] = 0;
 
-	if ( gribLen != recLen )
+	if ( gribLen != (size_t)recLen )
 	  fprintf(stderr, "Internal problem, recLen and gribLen differ!\n");
 	
 	itemp = gribLen / (-120);
@@ -12766,119 +12289,12 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
     }
 #endif
 
-  return (gribLen);
+  return (int)gribLen;
 }
 #include <stdio.h>
 #include <math.h>
 
 
-/* calculate_pfactor: source code from grib_api-1.8.0 */
-double calculate_pfactor(const double* spectralField, long fieldTruncation, long subsetTruncation)
-{
-  /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
-  long loop, index, m, n = 0;
-  double pFactor, zeps = 1.0e-15;
-  long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
-  double* weights, range, * norms;
-  double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0, x, y;
-  double numerator = 0.0, denominator = 0.0, slope;
-
-  /*
-  // Setup the weights
-   */
-
-  range = (double) (ismax - ismin +1);
-
-  weights = (double*) Malloc((ismax+1)*sizeof(double));
-  for( loop = ismin; loop <= ismax; loop++ )
-    weights[loop] = range / (double) (loop-ismin+1);
-  /*
-  // Compute norms
-  // Handle values 2 at a time (real and imaginary parts).
-   */
-  norms = (double*) Malloc((ismax+1)*sizeof(double));
-
-  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
-  /*
-  // Form norms for the rows which contain part of the unscaled subset.
-   */
-
-  index = -2;
-  for( m = 0; m < subsetTruncation; m++ )
-    for( n = m; n <= fieldTruncation; n++ ) {
-      index += 2;
-      if( n >= subsetTruncation ) {
-        double tval = spectralField[index];
-        tval=tval<0?-tval:tval;
-        norms[n] = norms[n] > tval ? norms[n] : tval;
-        tval = spectralField[index+1];
-        tval=tval<0?-tval:tval;
-        norms[n] = norms[n] > tval ? norms[n] : tval;
-      }
-    }
-  /*
-  // Form norms for the rows which do not contain part of the unscaled subset.
-   */
-
-  for( m = subsetTruncation; m <= fieldTruncation; m++ )
-    for( n = m; n <= fieldTruncation; n++ ) {
-      double tval = spectralField[index];
-      index += 2;
-      tval=tval<0?-tval:tval;
-      norms[n] = norms[n] > tval ? norms[n] : tval;
-      tval = spectralField[index+1];
-      tval=tval<0?-tval:tval;
-      norms[n] = norms[n] > tval ? norms[n] : tval;
-    }
-
-  /*
-  // Ensure the norms have a value which is not too small in case of
-  // problems with math functions (e.g. LOG).
-   */
-
-  for( loop = ismin; loop <= ismax; loop++ ) {
-    norms[n] = norms[n] > zeps ? norms[n] : zeps;
-    if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
-  }
-
-  /*
-  // Do linear fit to find the slope
-   */
-
-  for( loop = ismin; loop <= ismax; loop++ ) {
-    x = log( (double) (loop*(loop+1)) );
-    y = log( norms[loop] );
-    weightedSumOverX = weightedSumOverX + x * weights[loop];
-    weightedSumOverY = weightedSumOverY + y * weights[loop];
-    sumOfWeights = sumOfWeights + weights[loop];
-  }
-  weightedSumOverX = weightedSumOverX / sumOfWeights;
-  weightedSumOverY = weightedSumOverY / sumOfWeights;
-
-  /*
-  // Perform a least square fit for the equation
-   */
-
-  for( loop = ismin; loop <= ismax; loop++ ) {
-
-    x = log( (double)(loop*(loop+1)) );
-    y = log( norms[loop] );
-    numerator =
-      numerator + weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
-    denominator =
-      denominator + weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
-  }
-  slope = numerator / denominator;
-
-  Free(weights);
-  Free(norms);
-
-  pFactor = -slope;
-  if( pFactor < -9999.9 ) pFactor = -9999.9;
-  if( pFactor > 9999.9 )  pFactor = 9999.9;
-
-  return pFactor;
-}
 
 static
 int rowina2(double *p, int ko, int ki, double *pw,
@@ -13065,10 +12481,10 @@ int qu2reg2(double *pfield, int *kpoint, int klat, int klon,
    int iregno, iquano, j210, j220, j230, j240, j225;
 
 
-   zline = (double*) Malloc(2*klon*sizeof(double));
+   zline = (double*) Malloc(2*(size_t)klon*sizeof(double));
    if ( zline == NULL ) SysError("No Memory!");
 
-   zwork = (double*) Malloc(3*(2*klon+3)*sizeof(double));
+   zwork = (double*) Malloc(3*(2*(size_t)klon+3)*sizeof(double));
    if ( zwork == NULL ) SysError("No Memory!");
 
    /* Parameter adjustments */
@@ -13219,12 +12635,118 @@ L900:
 #define T double
 #ifdef T
 
+/* calculate_pfactor: source code from grib_api-1.8.0 */
+double TEMPLATE(calculate_pfactor,T)(const T *spectralField, long fieldTruncation, long subsetTruncation)
+{
+  /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
+  long loop, index, m, n = 0;
+  double pFactor, zeps = 1.0e-15;
+  long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
+  double* weights, range, * norms;
+  double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0, x, y;
+  double numerator = 0.0, denominator = 0.0, slope;
+
+  /*
+  // Setup the weights
+   */
+
+  range = (double) (ismax - ismin +1);
+
+  weights = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+  for( loop = ismin; loop <= ismax; loop++ )
+    weights[loop] = range / (double) (loop-ismin+1);
+  /*
+  // Compute norms
+  // Handle values 2 at a time (real and imaginary parts).
+   */
+  norms = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+
+  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
+  /*
+  // Form norms for the rows which contain part of the unscaled subset.
+   */
+
+  index = -2;
+  for( m = 0; m < subsetTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      index += 2;
+      if( n >= subsetTruncation ) {
+        double tval = spectralField[index];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+        tval = spectralField[index+1];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+      }
+    }
+  /*
+  // Form norms for the rows which do not contain part of the unscaled subset.
+   */
+
+  for( m = subsetTruncation; m <= fieldTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      double tval = spectralField[index];
+      index += 2;
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
+      tval = spectralField[index+1];
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
+    }
+
+  /*
+  // Ensure the norms have a value which is not too small in case of
+  // problems with math functions (e.g. LOG).
+   */
+
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    norms[n] = norms[n] > zeps ? norms[n] : zeps;
+    if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
+  }
+
+  /*
+  // Do linear fit to find the slope
+   */
+
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    x = log( (double) (loop*(loop+1)) );
+    y = log( norms[loop] );
+    weightedSumOverX = weightedSumOverX + x * weights[loop];
+    weightedSumOverY = weightedSumOverY + y * weights[loop];
+    sumOfWeights = sumOfWeights + weights[loop];
+  }
+  weightedSumOverX = weightedSumOverX / sumOfWeights;
+  weightedSumOverY = weightedSumOverY / sumOfWeights;
+
+  /*
+  // Perform a least square fit for the equation
+   */
+
+  for( loop = ismin; loop <= ismax; loop++ ) {
+
+    x = log( (double)(loop*(loop+1)) );
+    y = log( norms[loop] );
+    numerator =
+      numerator + weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
+    denominator =
+      denominator + weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
+  }
+  slope = numerator / denominator;
+
+  Free(weights);
+  Free(norms);
+
+  pFactor = -slope;
+  if( pFactor < -9999.9 ) pFactor = -9999.9;
+  if( pFactor > 9999.9 )  pFactor = 9999.9;
+
+  return pFactor;
+}
+
 void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, int inv)
 {
   double power;
-  double *scale = (double*) Malloc((trunc+1)*sizeof(double));
-  int  n, m;
-  int  index;
+  double *scale = (double*) Malloc(((size_t)trunc+1)*sizeof(double));
 
   if ( scale == NULL ) SysError("No Memory!");
 
@@ -13241,38 +12763,33 @@ void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, i
   power = (double) pcScale / 1000.;
   scale[0] = 1.0;
 
-  for ( n = 1; n <= trunc; n++ )
-    {
-      if (pcScale != 1000)
-         scale[n] = pow((double) (n*(n+1)), power);
-      else
-         scale[n] =     (double) (n*(n+1));
-    }
+  if (pcScale != 1000)
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] = pow((double) (n*(n+1)), power);
+  else
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] =     (double) (n*(n+1));
 
   if ( inv )
-    for ( n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
+    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
 
   /* Scale the values */
 
-  index = 0;
+  size_t index = 0;
 
-  for ( m = 0;   m < pcStart; m++ )
-    for ( n = m; n <= trunc; n++ )
-      {
-	if ( n >= pcStart )
-	  {
-	    fpdata[index  ] *= scale[n];
-	    fpdata[index+1] *= scale[n];
-	  }
-	index += 2;
-      }
+  for ( int m = 0;   m < pcStart; m++ )
+    for ( int n = m; n <= trunc; n++, index += 2 )
+      if ( n >= pcStart )
+        {
+          fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+          fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
+        }
 
-  for ( m = pcStart; m <= trunc; m++ )
-    for ( n = m;     n <= trunc; n++ )
+  for ( int m = pcStart; m <= trunc; m++ )
+    for ( int n = m;     n <= trunc; n++, index += 2 )
       {
-	fpdata[index  ] *= scale[n];
-	fpdata[index+1] *= scale[n];
-	index += 2;
+	fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+	fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
       }
 
   Free(scale);
@@ -13281,7 +12798,7 @@ void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, i
 
 void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 {
-  T *fphelp = (T*) Malloc(nsp*sizeof(T));
+  T *fphelp = (T*) Malloc((size_t)nsp*sizeof(T));
   int  m, n;
   int  index, inext;
 
@@ -13318,18 +12835,13 @@ void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 }
 
 
-void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
+void TEMPLATE(gather_complex,T)(T *fpdata, size_t pcStart, size_t trunc, size_t nsp)
 {
-  T *fphelp = (T*) Malloc(nsp*sizeof(T));
-  int  m, n;
-  int  index, inext;
+  T *restrict fphelp = (T*) Malloc(nsp*sizeof(T));
+  size_t inext = 0;
 
-  if ( fphelp == NULL ) SysError("No Memory!");
-
-  index = inext = 0;
-
-  for ( m = 0;   m <= pcStart; m++ )
-    for ( n = m; n <= trunc; n++ )
+  for ( size_t m = 0, index = 0;   m <= pcStart; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
       {
 	if ( pcStart >= n )
 	  {
@@ -13339,9 +12851,8 @@ void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 	index += 2;
       }
 
-  index = 0;
-  for ( m = 0;   m <= trunc; m++ )
-    for ( n = m; n <= trunc; n++ )
+  for ( size_t m = 0, index = 0; m <= trunc; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
       {
 	if ( n > pcStart )
 	  {
@@ -13351,7 +12862,7 @@ void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 	index += 2;
       }
 
-  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
   Free(fphelp);
 }
@@ -13572,8 +13083,8 @@ C     -----------------------------------------------------------------
 		{
 		  /*  Interpolate using the weighted values on either side */
 		  /*  of the output point position */
-		  p[jl] = (1.0 - zwt) * pw[ip+1 + pw_dim1] +
-		                  zwt * pw[ip+2 + pw_dim1];
+		  p[jl] = (T)((1.0 - zwt) * pw[ip+1 + pw_dim1]
+                              + zwt * pw[ip+2 + pw_dim1]);
 		}
 	    }
 	}
@@ -13603,14 +13114,14 @@ C     -----------------------------------------------------------------
       for ( jl = 1; jl <= i_1; ++jl )
 	{
           pw[jl + (pw_dim1 << 1)] =
-	        - pw[jl - 1 + pw_dim1] / 3.0 -
-	          pw[jl     + pw_dim1] * 0.5 +
-	          pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0;
+            (T)(- pw[jl - 1 + pw_dim1] / 3.0 -
+                pw[jl     + pw_dim1] * 0.5 +
+                pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0);
           pw[jl + 1 + pw_dim1 * 3] =
-                  pw[jl - 1 + pw_dim1] / 6.0 -
-                  pw[jl     + pw_dim1] +
-                  pw[jl + 1 + pw_dim1] * 0.5 +
-                  pw[jl + 2 + pw_dim1] / 3.0;
+            (T)(pw[jl - 1 + pw_dim1] / 6.0 -
+                pw[jl     + pw_dim1] +
+                pw[jl + 1 + pw_dim1] * 0.5 +
+                pw[jl + 2 + pw_dim1] / 3.0);
 	}
 
       TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
@@ -13625,10 +13136,10 @@ C     -----------------------------------------------------------------
           ip = (int) zwt + 1;
           zwt = zwt + 1.0 - ip;
           zwt1 = 1.0 - zwt;
-          p[jl] = ((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
-                  zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
-                  ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
-                  zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt;
+          p[jl] = (T)(((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
+                       zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
+                      ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
+                       zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt);
 	}
 
     }
@@ -13757,14 +13268,11 @@ C
    T *zline = NULL;
    T *zwork = NULL;
 
-   ztemp = (T*) Malloc(klon*klat*sizeof(T));
-   if ( ztemp == NULL ) SysError("No Memory!");
+   ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
 
-   zline = (T*) Malloc(2*klon*sizeof(T));
-   if ( zline == NULL ) SysError("No Memory!");
+   zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
 
-   zwork = (T*) Malloc(3*(2*klon+3)*sizeof(T));
-   if ( zwork == NULL ) SysError("No Memory!");
+   zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
 
    /* Parameter adjustments */
    --pfield;
@@ -13876,18 +13384,130 @@ L900:
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 #ifdef T
 #undef T
 #endif
 #define T float
 #ifdef T
 
+/* calculate_pfactor: source code from grib_api-1.8.0 */
+double TEMPLATE(calculate_pfactor,T)(const T *spectralField, long fieldTruncation, long subsetTruncation)
+{
+  /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
+  long loop, index, m, n = 0;
+  double pFactor, zeps = 1.0e-15;
+  long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
+  double* weights, range, * norms;
+  double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0, x, y;
+  double numerator = 0.0, denominator = 0.0, slope;
+
+  /*
+  // Setup the weights
+   */
+
+  range = (double) (ismax - ismin +1);
+
+  weights = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+  for( loop = ismin; loop <= ismax; loop++ )
+    weights[loop] = range / (double) (loop-ismin+1);
+  /*
+  // Compute norms
+  // Handle values 2 at a time (real and imaginary parts).
+   */
+  norms = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+
+  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
+  /*
+  // Form norms for the rows which contain part of the unscaled subset.
+   */
+
+  index = -2;
+  for( m = 0; m < subsetTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      index += 2;
+      if( n >= subsetTruncation ) {
+        double tval = spectralField[index];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+        tval = spectralField[index+1];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+      }
+    }
+  /*
+  // Form norms for the rows which do not contain part of the unscaled subset.
+   */
+
+  for( m = subsetTruncation; m <= fieldTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      double tval = spectralField[index];
+      index += 2;
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
+      tval = spectralField[index+1];
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
+    }
+
+  /*
+  // Ensure the norms have a value which is not too small in case of
+  // problems with math functions (e.g. LOG).
+   */
+
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    norms[n] = norms[n] > zeps ? norms[n] : zeps;
+    if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
+  }
+
+  /*
+  // Do linear fit to find the slope
+   */
+
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    x = log( (double) (loop*(loop+1)) );
+    y = log( norms[loop] );
+    weightedSumOverX = weightedSumOverX + x * weights[loop];
+    weightedSumOverY = weightedSumOverY + y * weights[loop];
+    sumOfWeights = sumOfWeights + weights[loop];
+  }
+  weightedSumOverX = weightedSumOverX / sumOfWeights;
+  weightedSumOverY = weightedSumOverY / sumOfWeights;
+
+  /*
+  // Perform a least square fit for the equation
+   */
+
+  for( loop = ismin; loop <= ismax; loop++ ) {
+
+    x = log( (double)(loop*(loop+1)) );
+    y = log( norms[loop] );
+    numerator =
+      numerator + weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
+    denominator =
+      denominator + weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
+  }
+  slope = numerator / denominator;
+
+  Free(weights);
+  Free(norms);
+
+  pFactor = -slope;
+  if( pFactor < -9999.9 ) pFactor = -9999.9;
+  if( pFactor > 9999.9 )  pFactor = 9999.9;
+
+  return pFactor;
+}
+
 void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, int inv)
 {
   double power;
-  double *scale = (double*) Malloc((trunc+1)*sizeof(double));
-  int  n, m;
-  int  index;
+  double *scale = (double*) Malloc(((size_t)trunc+1)*sizeof(double));
 
   if ( scale == NULL ) SysError("No Memory!");
 
@@ -13904,38 +13524,33 @@ void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, i
   power = (double) pcScale / 1000.;
   scale[0] = 1.0;
 
-  for ( n = 1; n <= trunc; n++ )
-    {
-      if (pcScale != 1000)
-         scale[n] = pow((double) (n*(n+1)), power);
-      else
-         scale[n] =     (double) (n*(n+1));
-    }
+  if (pcScale != 1000)
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] = pow((double) (n*(n+1)), power);
+  else
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] =     (double) (n*(n+1));
 
   if ( inv )
-    for ( n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
+    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
 
   /* Scale the values */
 
-  index = 0;
+  size_t index = 0;
 
-  for ( m = 0;   m < pcStart; m++ )
-    for ( n = m; n <= trunc; n++ )
-      {
-	if ( n >= pcStart )
-	  {
-	    fpdata[index  ] *= scale[n];
-	    fpdata[index+1] *= scale[n];
-	  }
-	index += 2;
-      }
+  for ( int m = 0;   m < pcStart; m++ )
+    for ( int n = m; n <= trunc; n++, index += 2 )
+      if ( n >= pcStart )
+        {
+          fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+          fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
+        }
 
-  for ( m = pcStart; m <= trunc; m++ )
-    for ( n = m;     n <= trunc; n++ )
+  for ( int m = pcStart; m <= trunc; m++ )
+    for ( int n = m;     n <= trunc; n++, index += 2 )
       {
-	fpdata[index  ] *= scale[n];
-	fpdata[index+1] *= scale[n];
-	index += 2;
+	fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+	fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
       }
 
   Free(scale);
@@ -13944,7 +13559,7 @@ void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, i
 
 void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 {
-  T *fphelp = (T*) Malloc(nsp*sizeof(T));
+  T *fphelp = (T*) Malloc((size_t)nsp*sizeof(T));
   int  m, n;
   int  index, inext;
 
@@ -13981,18 +13596,13 @@ void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 }
 
 
-void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
+void TEMPLATE(gather_complex,T)(T *fpdata, size_t pcStart, size_t trunc, size_t nsp)
 {
-  T *fphelp = (T*) Malloc(nsp*sizeof(T));
-  int  m, n;
-  int  index, inext;
-
-  if ( fphelp == NULL ) SysError("No Memory!");
+  T *restrict fphelp = (T*) Malloc(nsp*sizeof(T));
+  size_t inext = 0;
 
-  index = inext = 0;
-
-  for ( m = 0;   m <= pcStart; m++ )
-    for ( n = m; n <= trunc; n++ )
+  for ( size_t m = 0, index = 0;   m <= pcStart; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
       {
 	if ( pcStart >= n )
 	  {
@@ -14002,9 +13612,8 @@ void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 	index += 2;
       }
 
-  index = 0;
-  for ( m = 0;   m <= trunc; m++ )
-    for ( n = m; n <= trunc; n++ )
+  for ( size_t m = 0, index = 0; m <= trunc; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
       {
 	if ( n > pcStart )
 	  {
@@ -14014,7 +13623,7 @@ void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 	index += 2;
       }
 
-  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
   Free(fphelp);
 }
@@ -14235,8 +13844,8 @@ C     -----------------------------------------------------------------
 		{
 		  /*  Interpolate using the weighted values on either side */
 		  /*  of the output point position */
-		  p[jl] = (1.0 - zwt) * pw[ip+1 + pw_dim1] +
-		                  zwt * pw[ip+2 + pw_dim1];
+		  p[jl] = (T)((1.0 - zwt) * pw[ip+1 + pw_dim1]
+                              + zwt * pw[ip+2 + pw_dim1]);
 		}
 	    }
 	}
@@ -14266,14 +13875,14 @@ C     -----------------------------------------------------------------
       for ( jl = 1; jl <= i_1; ++jl )
 	{
           pw[jl + (pw_dim1 << 1)] =
-	        - pw[jl - 1 + pw_dim1] / 3.0 -
-	          pw[jl     + pw_dim1] * 0.5 +
-	          pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0;
+            (T)(- pw[jl - 1 + pw_dim1] / 3.0 -
+                pw[jl     + pw_dim1] * 0.5 +
+                pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0);
           pw[jl + 1 + pw_dim1 * 3] =
-                  pw[jl - 1 + pw_dim1] / 6.0 -
-                  pw[jl     + pw_dim1] +
-                  pw[jl + 1 + pw_dim1] * 0.5 +
-                  pw[jl + 2 + pw_dim1] / 3.0;
+            (T)(pw[jl - 1 + pw_dim1] / 6.0 -
+                pw[jl     + pw_dim1] +
+                pw[jl + 1 + pw_dim1] * 0.5 +
+                pw[jl + 2 + pw_dim1] / 3.0);
 	}
 
       TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
@@ -14288,10 +13897,10 @@ C     -----------------------------------------------------------------
           ip = (int) zwt + 1;
           zwt = zwt + 1.0 - ip;
           zwt1 = 1.0 - zwt;
-          p[jl] = ((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
-                  zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
-                  ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
-                  zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt;
+          p[jl] = (T)(((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
+                       zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
+                      ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
+                       zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt);
 	}
 
     }
@@ -14420,14 +14029,11 @@ C
    T *zline = NULL;
    T *zwork = NULL;
 
-   ztemp = (T*) Malloc(klon*klat*sizeof(T));
-   if ( ztemp == NULL ) SysError("No Memory!");
+   ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
 
-   zline = (T*) Malloc(2*klon*sizeof(T));
-   if ( zline == NULL ) SysError("No Memory!");
+   zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
 
-   zwork = (T*) Malloc(3*(2*klon+3)*sizeof(T));
-   if ( zwork == NULL ) SysError("No Memory!");
+   zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
 
    /* Parameter adjustments */
    --pfield;
@@ -14538,6 +14144,12 @@ L900:
 } /* qu2reg3 */
 
 #endif /* T */
+
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 #include <string.h>
 
 
@@ -14831,31 +14443,31 @@ void gribPrintSec3_float(int *isec0, int *isec3, float *fsec3) {gribPrintSec3SP(
 void gribPrintSec4_float(int *isec0, int *isec4, float *fsec4) {gribPrintSec4SP(isec0, isec4, fsec4);}
 
 
-
 #ifdef T
 #undef T
 #endif
 #define T double
 #ifdef T
 
+#include <inttypes.h>
+
 static 
-void TEMPLATE(decode_array_common,T)(const unsigned char * restrict igrib, long jlend, int NumBits, 
-				     T fmin, T zscale, T * restrict fpdata)
+void TEMPLATE(decode_array_common,T)(const unsigned char *restrict igrib, long jlend, int NumBits, 
+				     T fmin, T zscale, T *restrict fpdata)
 {
   /* code from wgrib routine BDS_unpack */
   const unsigned char *bits = igrib;
-  unsigned int jmask;
   long i;
   unsigned int tbits = 0;
   int n_bits = NumBits;
   int t_bits = 0;
-      
-  jmask = (1 << n_bits) - 1;
+
+  unsigned jmask = (1U << n_bits) - 1U;
   for ( i = 0; i < jlend; i++ )
     {
       if (n_bits - t_bits > 8)
 	{
-	  tbits = (tbits << 16) | (bits[0] << 8) | (bits[1]);
+	  tbits = (tbits << 16) | ((unsigned)bits[0] << 8) | ((unsigned)bits[1]);
 	  bits += 2;
 	  t_bits += 16;
 	}
@@ -14866,35 +14478,32 @@ void TEMPLATE(decode_array_common,T)(const unsigned char * restrict igrib, long
 	  t_bits += 8;
 	}
       t_bits -= n_bits;
-      fpdata[i] = (tbits >> t_bits) & jmask;
+      fpdata[i] = (float)((tbits >> t_bits) & jmask);
     }
   /* at least this vectorizes :) */
   for ( i = 0; i < jlend; i++ )
     fpdata[i] = fmin + zscale*fpdata[i];
 }
 
-#if !defined(_MASK_AND_SHIFT_)
-#define _MASK_AND_SHIFT_
-static unsigned int mask[] = {0,1,3,7,15,31,63,127,255};
-static double shift[9] = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
-#endif
-
-static 
-void TEMPLATE(decode_array_common2,T)(const unsigned char * restrict igrib, long jlend, int NumBits, 
-				      T fmin, T zscale, T * restrict fpdata)
+static
+void TEMPLATE(decode_array_common2,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
+				      T fmin, T zscale, T *restrict fpdata)
 {
+  static const unsigned mask[] = {0,1,3,7,15,31,63,127,255};
+  static const double shift[9]
+    = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
+
   /* code from wgrib routine BDS_unpack */
   const unsigned char *bits = igrib;
   long i;
   int n_bits = NumBits;
   int c_bits, j_bits;
-  double jj;
 
   /* older unoptimized code, not often used */
   c_bits = 8;
   for ( i = 0; i < jlend; i++ )
     {
-      jj = 0.0;
+      double jj = 0.0;
       j_bits = n_bits;
       while (c_bits <= j_bits)
 	{
@@ -14915,12 +14524,36 @@ void TEMPLATE(decode_array_common2,T)(const unsigned char * restrict igrib, long
       if (j_bits)
 	{
 	  c_bits -= j_bits;
-	  jj = (jj * shift[j_bits]) + (double) ((*bits >> c_bits) & mask[j_bits]);
+	  jj = (jj * shift[j_bits]) + (double) (((unsigned)*bits >> c_bits) & mask[j_bits]);
 	}
-      
-      fpdata[i] = fmin + zscale*jj;
+      fpdata[i] = (T)(fmin + zscale*jj);
+    }
+}
+
+static
+void TEMPLATE(decode_array_2byte,T)(size_t jlend, const unsigned char *restrict igrib,
+                                    T *fpdata, T fmin, T zscale)
+{
+  U_BYTEORDER;
+  const uint16_t *restrict sgrib = (uint16_t *) (igrib);
+
+  if ( IS_BIGENDIAN() )
+    {
+      for ( size_t i = 0; i < jlend; i++ )
+        {
+          fpdata[i] = fmin + zscale * sgrib[i];
+        }
+    }
+  else
+    {
+      uint16_t ui16;
+      for ( size_t i = 0; i < jlend; i++ )
+        {
+          ui16 = gribSwapByteOrder_uint16(sgrib[i]);
+          fpdata[i] = fmin + zscale * ui16;
+        }
     }
-} 
+}
 
 static 
 void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, int numBits, 
@@ -14931,7 +14564,6 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
 #endif
 
   long i;
-  T dval;
 #if defined (VECTORCODE)
   GRIBPACK *lgrib = NULL;
 
@@ -14955,26 +14587,26 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
   else if ( numBits ==  8 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (int)lgrib[i];
+	T dval = (int)lgrib[i];
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 16 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
+	T dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 24 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
+	T dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
 	  	 (int)lgrib[3*i+2]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 32 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
+	T dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
 		((unsigned int)lgrib[4*i+2] <<  8) +  (unsigned int)lgrib[4*i+3]);
 	fpdata[i] = fmin + zscale * dval;
       }
@@ -15002,75 +14634,25 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
   else if ( numBits ==  8 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (int)igrib[i];
+	T dval = (int)igrib[i];
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 16 )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(6, "unpack 16 bit base");
-#elif defined _GET_X86_COUNTER 
-      start_decode = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      start_decode = mach_absolute_time();
-#endif
-      
-      if ( sizeof(T) == sizeof(double) )
-      	{ 
-#if defined _ENABLE_AVX
-	  printf("AVX selected ...\n");
-	  avx_decode_array_2byte_double((size_t) jlend, igrib, fpdata, fmin, zscale);
-#elif defined _ENABLE_SSE4_1
-	  printf("SSE4 selected ...\n");
-	  sse41_decode_array_2byte_double((size_t) jlend, igrib, fpdata, fmin, zscale);
-#else
-	  for ( i = 0; i < jlend; i++ )
-	    {
-	      dval = (((int)igrib[2*i  ] <<  8) |  (int)igrib[2*i+1]);
-	      fpdata[i] = fmin + zscale * dval;
-	    }
-#endif
-	}
-      else
-	{
-	  for ( i = 0; i < jlend; i++ )
-	    {
-	      dval = (((int)igrib[2*i  ] <<  8) |  (int)igrib[2*i+1]);
-	      fpdata[i] = fmin + zscale * dval;
-	    }
-	}
-
-#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
-#if defined _GET_X86_COUNTER 
-      end_decode = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      end_decode = mach_absolute_time();
-#endif
-#if defined _ENABLE_AVX
-      printf("AVX encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#elif defined _ENABLE_SSE4_1
-      printf("SSE 4.1 encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#else
-      printf("loop encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#endif  
-#endif
-      
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(6);
-#endif
+      TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
     }
   else if ( numBits == 24 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
-		 (int)igrib[3*i+2]);
+	T dval = (T)(((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
+                     (int)igrib[3*i+2]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 32 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
-		((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
+	T dval = (T)(((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
+                     ((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits <= 25 )
@@ -15090,30 +14672,37 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 #ifdef T
 #undef T
 #endif
 #define T float
 #ifdef T
 
+#include <inttypes.h>
+
 static 
-void TEMPLATE(decode_array_common,T)(const unsigned char * restrict igrib, long jlend, int NumBits, 
-				     T fmin, T zscale, T * restrict fpdata)
+void TEMPLATE(decode_array_common,T)(const unsigned char *restrict igrib, long jlend, int NumBits, 
+				     T fmin, T zscale, T *restrict fpdata)
 {
   /* code from wgrib routine BDS_unpack */
   const unsigned char *bits = igrib;
-  unsigned int jmask;
   long i;
   unsigned int tbits = 0;
   int n_bits = NumBits;
   int t_bits = 0;
-      
-  jmask = (1 << n_bits) - 1;
+
+  unsigned jmask = (1U << n_bits) - 1U;
   for ( i = 0; i < jlend; i++ )
     {
       if (n_bits - t_bits > 8)
 	{
-	  tbits = (tbits << 16) | (bits[0] << 8) | (bits[1]);
+	  tbits = (tbits << 16) | ((unsigned)bits[0] << 8) | ((unsigned)bits[1]);
 	  bits += 2;
 	  t_bits += 16;
 	}
@@ -15124,35 +14713,32 @@ void TEMPLATE(decode_array_common,T)(const unsigned char * restrict igrib, long
 	  t_bits += 8;
 	}
       t_bits -= n_bits;
-      fpdata[i] = (tbits >> t_bits) & jmask;
+      fpdata[i] = (float)((tbits >> t_bits) & jmask);
     }
   /* at least this vectorizes :) */
   for ( i = 0; i < jlend; i++ )
     fpdata[i] = fmin + zscale*fpdata[i];
 }
 
-#if !defined(_MASK_AND_SHIFT_)
-#define _MASK_AND_SHIFT_
-static unsigned int mask[] = {0,1,3,7,15,31,63,127,255};
-static double shift[9] = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
-#endif
-
-static 
-void TEMPLATE(decode_array_common2,T)(const unsigned char * restrict igrib, long jlend, int NumBits, 
-				      T fmin, T zscale, T * restrict fpdata)
+static
+void TEMPLATE(decode_array_common2,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
+				      T fmin, T zscale, T *restrict fpdata)
 {
+  static const unsigned mask[] = {0,1,3,7,15,31,63,127,255};
+  static const double shift[9]
+    = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
+
   /* code from wgrib routine BDS_unpack */
   const unsigned char *bits = igrib;
   long i;
   int n_bits = NumBits;
   int c_bits, j_bits;
-  double jj;
 
   /* older unoptimized code, not often used */
   c_bits = 8;
   for ( i = 0; i < jlend; i++ )
     {
-      jj = 0.0;
+      double jj = 0.0;
       j_bits = n_bits;
       while (c_bits <= j_bits)
 	{
@@ -15173,12 +14759,36 @@ void TEMPLATE(decode_array_common2,T)(const unsigned char * restrict igrib, long
       if (j_bits)
 	{
 	  c_bits -= j_bits;
-	  jj = (jj * shift[j_bits]) + (double) ((*bits >> c_bits) & mask[j_bits]);
+	  jj = (jj * shift[j_bits]) + (double) (((unsigned)*bits >> c_bits) & mask[j_bits]);
 	}
-      
-      fpdata[i] = fmin + zscale*jj;
+      fpdata[i] = (T)(fmin + zscale*jj);
+    }
+}
+
+static
+void TEMPLATE(decode_array_2byte,T)(size_t jlend, const unsigned char *restrict igrib,
+                                    T *fpdata, T fmin, T zscale)
+{
+  U_BYTEORDER;
+  const uint16_t *restrict sgrib = (uint16_t *) (igrib);
+
+  if ( IS_BIGENDIAN() )
+    {
+      for ( size_t i = 0; i < jlend; i++ )
+        {
+          fpdata[i] = fmin + zscale * sgrib[i];
+        }
+    }
+  else
+    {
+      uint16_t ui16;
+      for ( size_t i = 0; i < jlend; i++ )
+        {
+          ui16 = gribSwapByteOrder_uint16(sgrib[i]);
+          fpdata[i] = fmin + zscale * ui16;
+        }
     }
-} 
+}
 
 static 
 void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, int numBits, 
@@ -15189,7 +14799,6 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
 #endif
 
   long i;
-  T dval;
 #if defined (VECTORCODE)
   GRIBPACK *lgrib = NULL;
 
@@ -15213,26 +14822,26 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
   else if ( numBits ==  8 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (int)lgrib[i];
+	T dval = (int)lgrib[i];
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 16 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
+	T dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 24 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
+	T dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
 	  	 (int)lgrib[3*i+2]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 32 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
+	T dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
 		((unsigned int)lgrib[4*i+2] <<  8) +  (unsigned int)lgrib[4*i+3]);
 	fpdata[i] = fmin + zscale * dval;
       }
@@ -15260,75 +14869,25 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
   else if ( numBits ==  8 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (int)igrib[i];
+	T dval = (int)igrib[i];
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 16 )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(6, "unpack 16 bit base");
-#elif defined _GET_X86_COUNTER 
-      start_decode = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      start_decode = mach_absolute_time();
-#endif
-      
-      if ( sizeof(T) == sizeof(double) )
-      	{ 
-#if defined _ENABLE_AVX
-	  printf("AVX selected ...\n");
-	  avx_decode_array_2byte_double((size_t) jlend, igrib, fpdata, fmin, zscale);
-#elif defined _ENABLE_SSE4_1
-	  printf("SSE4 selected ...\n");
-	  sse41_decode_array_2byte_double((size_t) jlend, igrib, fpdata, fmin, zscale);
-#else
-	  for ( i = 0; i < jlend; i++ )
-	    {
-	      dval = (((int)igrib[2*i  ] <<  8) |  (int)igrib[2*i+1]);
-	      fpdata[i] = fmin + zscale * dval;
-	    }
-#endif
-	}
-      else
-	{
-	  for ( i = 0; i < jlend; i++ )
-	    {
-	      dval = (((int)igrib[2*i  ] <<  8) |  (int)igrib[2*i+1]);
-	      fpdata[i] = fmin + zscale * dval;
-	    }
-	}
-
-#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
-#if defined _GET_X86_COUNTER 
-      end_decode = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      end_decode = mach_absolute_time();
-#endif
-#if defined _ENABLE_AVX
-      printf("AVX encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#elif defined _ENABLE_SSE4_1
-      printf("SSE 4.1 encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#else
-      printf("loop encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#endif  
-#endif
-      
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(6);
-#endif
+      TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
     }
   else if ( numBits == 24 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
-		 (int)igrib[3*i+2]);
+	T dval = (T)(((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
+                     (int)igrib[3*i+2]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 32 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
-		((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
+	T dval = (T)(((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
+                     ((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits <= 25 )
@@ -15348,6 +14907,12 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 
 #ifdef T
 #undef T
@@ -15362,7 +14927,6 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
   int  ReducedGrid = FALSE, VertCoorTab = FALSE;
   int  locnv = 0, locnl;
   int  jlenl;
-  long i;
   int iexp, imant;
   int ipvpl, ipl;
   int gdsLen = 0;
@@ -15414,7 +14978,7 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 	{
 	  *numGridVals = 0;
 	  ISEC2_Reduced = TRUE;
-	  for ( i = 0; i < jlenl; i++ )
+	  for ( int i = 0; i < jlenl; i++ )
 	    {
 	      ISEC2_RowLon(i) = GET_UINT2(gds[locnl+2*i], gds[locnl+2*i+1]);
 	      *numGridVals += ISEC2_RowLon(i);
@@ -15454,7 +15018,7 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 	{
 	  ISEC2_LatSP     = GDS_LatSP;
 	  ISEC2_LonSP     = GDS_LonSP;
-	  FSEC2_RotAngle  = GDS_RotAngle;
+	  FSEC2_RotAngle  = (T)GDS_RotAngle;
 	}
       /*
 	if ( Lons != Longitudes || Lats != Latitudes )
@@ -15564,31 +15128,34 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 
       igrib = &gds[locnv];
       if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
-      for ( i = 0; i < ISEC2_NumVCP; i++ )
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
 	{
 	  iexp   = (lgrib[4*i  ]);
 	  imant  =((lgrib[4*i+1]) << 16) +
 	          ((lgrib[4*i+2]) <<  8) +
 	           (lgrib[4*i+3]);
-	  fsec2[10+i] = POW_2_M24 * imant * pow(16.0, (double)(iexp - 64));
+	  fsec2[10+i] = POW_2_M24 * imant * ldexp(1.0, 4 * (iexp - 64));
 	}
 
       Free(lgrib);
 #else
-      for ( i = 0; i < ISEC2_NumVCP; i++ )
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
 	{
 	  iexp   = (gds[locnv+4*i  ]);
 	  imant  =((gds[locnv+4*i+1]) << 16) +
 	          ((gds[locnv+4*i+2]) <<  8) +
 	           (gds[locnv+4*i+3]);
-	  fsec2[10+i] = decfp2(iexp,imant);
+	  fsec2[10+i] = (T)decfp2(iexp,imant);
 	}
 #endif
     }
 
-  return (gdsLen);
+  return gdsLen;
 }
 
+#define ldexp_double ldexp
+#define ldexp_float ldexpf
+
 static
 int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *isec4, 
 			  T *fsec4, int fsec4len, int dfunc, int bdsLenIn, int numGridVals, int llarge, int *iret)
@@ -15598,15 +15165,13 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
   int lcompress;
   int jup, kup, mup;
   int locnd;
-  long jlend;
-  long i;
   int bds_flag, jscale, imiss;
   int bds_ubits;
   int ioff = 0;
   int iexp, imant;
   int zoff;
   int bds_head = 11;
-  double zscale = 0.;
+  T zscale = 0.;
   T fmin = 0.;
   T *fpdata = fsec4;
   int bdsLen;
@@ -15677,16 +15242,11 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 
   /* convert reference value and scale factor. */
 
-  if ( ! (dfunc == 'J') )
-    if ( imiss == 0 )
-      {
-	fmin = BDS_RefValue;
-	
-	if ( jscale < 0 )
-	  zscale = 1.0/intpow2(-jscale);
-	else
-	  zscale = intpow2(jscale);
-      }
+  if ( ! (dfunc == 'J') && imiss == 0 )
+    {
+      fmin = BDS_RefValue;
+      zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
+    }
 
   /* get number of bits in each data value. */
 
@@ -15720,7 +15280,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  if ( dfunc != 'J' )
 	    {
 	      if ( imiss ) *fpdata++ = 0.0;
-	      else         *fpdata++ = BDS_RealCoef;
+	      else         *fpdata++ = (T)BDS_RealCoef;
 	    }
 	}
       else /* complex packed spherical harmonics */
@@ -15747,7 +15307,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  ioff   = (jup+1)*(jup+2);
 
 	  if ( dfunc != 'J' )
-	    for ( i = 0; i < ioff; i++ )
+	    for ( int i = 0; i < ioff; i++ )
 	      {
 		if ( imiss )
 		  *fpdata++ = 0.0;
@@ -15758,7 +15318,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 		            ((bds[locnd+4*i+2]) <<  8) +
 		             (bds[locnd+4*i+3]);
 
-		    *fpdata++ = decfp2(iexp,imant);
+		    *fpdata++ = (T)decfp2(iexp,imant);
 		  }
 	      }
 	  
@@ -15772,7 +15332,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 1999;
 	  gprintf(__func__, " Second order packed grids unsupported!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
     }
 
@@ -15781,7 +15341,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
   /* Take into account that spherical harmonics can be packed  */
   /* simple (lcomplex = 0) or complex (lcomplex = 1)           */
 
-  jlend = bdsLen - locnd;
+  int jlend = bdsLen - locnd;
 
   if ( ISEC4_NumBits == 0 )
     {
@@ -15790,7 +15350,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 2001;
 	  gprintf(__func__, " Number of bits per data value = 0!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
 
       if ( numGridVals == 0 )
@@ -15798,7 +15358,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 2002;
 	  gprintf(__func__, " Constant field unsupported for this grid type!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
 
       jlend = numGridVals;
@@ -15821,7 +15381,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
       else
         len = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
 
-      ISEC4_NumValues = len*8/ISEC4_NumBits;
+      ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
 
       if ( lspherc )
 	{
@@ -15832,7 +15392,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	}
     }
 
-  if ( dfunc == 'J' ) return (bdsLen);
+  if ( dfunc == 'J' ) return bdsLen;
 
   /* check length of output array. */
   
@@ -15842,10 +15402,10 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
       gprintf(__func__, " Output array too small. Length = %d", fsec4len);
       gprintf(__func__, " Number of values = %d", ISEC4_NumValues);
       gprintf(__func__, " Return code =  %d", *iret);
-      return (0);
+      return 0;
     }
 
-  if ( imiss ) memset((char *)fpdata, 0, jlend*sizeof(T));
+  if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
   else
     {
       igrib += locnd;
@@ -15855,9 +15415,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 
   if ( lspherc && lcomplex )
     {
-      int pcStart, pcScale;
-      pcStart = isec4[19];
-      pcScale = isec4[16];
+      int pcStart = isec4[19], pcScale = isec4[16];
       TEMPLATE(scatter_complex,T)(fsec4, pcStart, ISEC2_PentaJ, ISEC4_NumValues);
       TEMPLATE(scale_complex,T)(fsec4, pcStart, pcScale, ISEC2_PentaJ, 1);
     }
@@ -15869,17 +15427,17 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	if ( IS_NOT_EQUAL(fsec4[1], 0.0) )
 	  {
 	    T zserr = fsec4[1];
-	    for ( i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
+	    for ( int i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
 	  }
       }
 
   if ( decscale )
     {
       T scale = (T) pow(10.0, (double)-decscale);
-      for ( i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
+      for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
     }
 
-  return (bdsLen);
+  return bdsLen;
 }
 
 
@@ -15889,7 +15447,6 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 {
   UCHAR *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
   int isLen = 0, pdsLen = 0, gdsLen = 0, bmsLen = 0, bdsLen = 0, esLen = 0;
-  int gribLen = 0;
   int gdsIncluded = FALSE;
   int bmsIncluded = FALSE;
   int bitmapSize = 0;
@@ -16080,7 +15637,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
 	  {
 	    lmissvalinfo = 0;
-	    FSEC3_MissVal = GRIB_MISSVAL;
+	    FSEC3_MissVal = (T)GRIB_MISSVAL;
 	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
 	  }
 
@@ -16089,16 +15646,12 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
       if ( dfunc != 'J' || bitmapSize == ISEC4_NumNonMissValues )
 	{
-	  long i, j;
-	  GRIBPACK *pbitmap;
 	  GRIBPACK bitmap;
-	  GRIBPACK *imask;
-
 	  /*
 	  unsigned char *bitmap;
 	  bitmap = BMS_Bitmap;
-	  j = ISEC4_NumNonMissValues;
-	  for ( i = ISEC4_NumValues-1; i >= 0; i-- )
+	  int j = ISEC4_NumNonMissValues;
+	  for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
 	    {
 	      if ( (bitmap[i/8]>>(7-(i&7)))&1 )
 		fsec4[i] = fsec4[--j];
@@ -16107,13 +15660,13 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	    }
 	  */
 
-	  imask = (GRIBPACK*) Malloc(imaskSize*sizeof(GRIBPACK));
+	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
 
 #if defined (VECTORCODE)
 	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
-	  pbitmap = imask;
+	  GRIBPACK *pbitmap = imask;
 #else
-	  pbitmap = BMS_Bitmap;
+	  GRIBPACK *pbitmap = BMS_Bitmap;
 #endif
 
 #if defined (CRAY)
@@ -16125,7 +15678,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 #ifdef __uxpch__
 #pragma loop novrec
 #endif
-	  for ( i = imaskSize/8-1; i >= 0; i-- )
+	  for ( int i = imaskSize/8-1; i >= 0; i-- )
 	    {
 	      bitmap = pbitmap[i];
 	      imask[i*8+0] = 1 & (bitmap >> 7);
@@ -16138,8 +15691,8 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	      imask[i*8+7] = 1 & (bitmap);
 	    }
 
-	  j = 0;
-	  for ( i = 0; i < ISEC4_NumValues; i++ )
+	  int j = 0;
+	  for ( int i = 0; i < ISEC4_NumValues; i++ )
 	    if ( imask[i] ) j++;
 
 	  if ( ISEC4_NumNonMissValues != j )
@@ -16162,7 +15715,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 #ifdef __uxpch__
 #pragma loop novrec
 #endif
-	      for ( i = ISEC4_NumValues-1; i >= 0; i-- )
+	      for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
 		fsec4[i] = imask[i] ? fsec4[--j] : FSEC3_MissVal;
 	    }
 
@@ -16172,24 +15725,18 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   if ( ISEC2_Reduced )
     {
-      int nlon, nlat;
-      int lperio = 1, lveggy;
-      int ilat;
       int nvalues = 0;
-
-      nlat = ISEC2_NumLat;
-      nlon = ISEC2_RowLonPtr[0];
-      for ( ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
-      for ( ilat = 1; ilat < nlat; ++ilat )
+      int nlat = ISEC2_NumLat;
+      int nlon = ISEC2_RowLonPtr[0];
+      for ( int ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
+      for ( int ilat = 1; ilat < nlat; ++ilat )
 	if ( ISEC2_RowLon(ilat) > nlon ) nlon = ISEC2_RowLon(ilat);
 
       // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
       // if ( dlon < 0 ) dlon += 360000;
 	  
-      if ( nvalues != ISEC4_NumValues )
-	{
-	  *iret = -801;
-	}
+      if ( nvalues != ISEC4_NumValues ) *iret = -801;
+
       //printf("nlat %d  nlon %d \n", nlat, nlon);
       //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
 
@@ -16204,18 +15751,20 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	  ISEC4_NumValues = nlon*nlat;
 
 	  lsect3 = bitmapSize > 0;
-	  lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
-	          ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
-	           (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30));
+          int lperio = 1;
+	  int lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
+                      ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
+                       (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30) ||
+                       (ISEC1_Parameter == 39) || (ISEC1_Parameter == 40) ||
+                       (ISEC1_Parameter == 41) || (ISEC1_Parameter == 42) ||
+                       (ISEC1_Parameter == 43));
 	
 	  (void) TEMPLATE(qu2reg3,T)(fsec4, ISEC2_RowLonPtr, nlat, nlon, FSEC3_MissVal, iret, lsect3, lperio, lveggy);
 	      
 	  if ( bitmapSize > 0 )
 	    {
-	      long i;
-	      int j = 0;
-	      
-	      for ( i = 0; i < ISEC4_NumValues; i++ )
+	      int j = 0;	      
+	      for ( int i = 0; i < ISEC4_NumValues; i++ )
 		if ( IS_NOT_EQUAL(fsec4[i], FSEC3_MissVal) ) j++;
 		  
 	      ISEC4_NumNonMissValues = j;
@@ -16227,7 +15776,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
   esLen = 4;
 
-  gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
+  int gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
 
   if ( ISEC0_GRIB_Len )
     if ( ISEC0_GRIB_Len < gribLen )
@@ -16235,8 +15784,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   ISEC0_GRIB_Len = gribLen;
 
-  *kword = gribLen / sizeof(int);
-  if ( (size_t) gribLen != *kword * sizeof(int) ) *kword += 1;
+  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
 
   /*
     ----------------------------------------------------------------
@@ -16281,6 +15829,12 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 #ifdef T
 #undef T
 #endif
@@ -16294,7 +15848,6 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
   int  ReducedGrid = FALSE, VertCoorTab = FALSE;
   int  locnv = 0, locnl;
   int  jlenl;
-  long i;
   int iexp, imant;
   int ipvpl, ipl;
   int gdsLen = 0;
@@ -16346,7 +15899,7 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 	{
 	  *numGridVals = 0;
 	  ISEC2_Reduced = TRUE;
-	  for ( i = 0; i < jlenl; i++ )
+	  for ( int i = 0; i < jlenl; i++ )
 	    {
 	      ISEC2_RowLon(i) = GET_UINT2(gds[locnl+2*i], gds[locnl+2*i+1]);
 	      *numGridVals += ISEC2_RowLon(i);
@@ -16386,7 +15939,7 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 	{
 	  ISEC2_LatSP     = GDS_LatSP;
 	  ISEC2_LonSP     = GDS_LonSP;
-	  FSEC2_RotAngle  = GDS_RotAngle;
+	  FSEC2_RotAngle  = (T)GDS_RotAngle;
 	}
       /*
 	if ( Lons != Longitudes || Lats != Latitudes )
@@ -16496,31 +16049,34 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 
       igrib = &gds[locnv];
       if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
-      for ( i = 0; i < ISEC2_NumVCP; i++ )
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
 	{
 	  iexp   = (lgrib[4*i  ]);
 	  imant  =((lgrib[4*i+1]) << 16) +
 	          ((lgrib[4*i+2]) <<  8) +
 	           (lgrib[4*i+3]);
-	  fsec2[10+i] = POW_2_M24 * imant * pow(16.0, (double)(iexp - 64));
+	  fsec2[10+i] = POW_2_M24 * imant * ldexp(1.0, 4 * (iexp - 64));
 	}
 
       Free(lgrib);
 #else
-      for ( i = 0; i < ISEC2_NumVCP; i++ )
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
 	{
 	  iexp   = (gds[locnv+4*i  ]);
 	  imant  =((gds[locnv+4*i+1]) << 16) +
 	          ((gds[locnv+4*i+2]) <<  8) +
 	           (gds[locnv+4*i+3]);
-	  fsec2[10+i] = decfp2(iexp,imant);
+	  fsec2[10+i] = (T)decfp2(iexp,imant);
 	}
 #endif
     }
 
-  return (gdsLen);
+  return gdsLen;
 }
 
+#define ldexp_double ldexp
+#define ldexp_float ldexpf
+
 static
 int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *isec4, 
 			  T *fsec4, int fsec4len, int dfunc, int bdsLenIn, int numGridVals, int llarge, int *iret)
@@ -16530,15 +16086,13 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
   int lcompress;
   int jup, kup, mup;
   int locnd;
-  long jlend;
-  long i;
   int bds_flag, jscale, imiss;
   int bds_ubits;
   int ioff = 0;
   int iexp, imant;
   int zoff;
   int bds_head = 11;
-  double zscale = 0.;
+  T zscale = 0.;
   T fmin = 0.;
   T *fpdata = fsec4;
   int bdsLen;
@@ -16609,16 +16163,11 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 
   /* convert reference value and scale factor. */
 
-  if ( ! (dfunc == 'J') )
-    if ( imiss == 0 )
-      {
-	fmin = BDS_RefValue;
-	
-	if ( jscale < 0 )
-	  zscale = 1.0/intpow2(-jscale);
-	else
-	  zscale = intpow2(jscale);
-      }
+  if ( ! (dfunc == 'J') && imiss == 0 )
+    {
+      fmin = BDS_RefValue;
+      zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
+    }
 
   /* get number of bits in each data value. */
 
@@ -16652,7 +16201,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  if ( dfunc != 'J' )
 	    {
 	      if ( imiss ) *fpdata++ = 0.0;
-	      else         *fpdata++ = BDS_RealCoef;
+	      else         *fpdata++ = (T)BDS_RealCoef;
 	    }
 	}
       else /* complex packed spherical harmonics */
@@ -16679,7 +16228,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  ioff   = (jup+1)*(jup+2);
 
 	  if ( dfunc != 'J' )
-	    for ( i = 0; i < ioff; i++ )
+	    for ( int i = 0; i < ioff; i++ )
 	      {
 		if ( imiss )
 		  *fpdata++ = 0.0;
@@ -16690,7 +16239,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 		            ((bds[locnd+4*i+2]) <<  8) +
 		             (bds[locnd+4*i+3]);
 
-		    *fpdata++ = decfp2(iexp,imant);
+		    *fpdata++ = (T)decfp2(iexp,imant);
 		  }
 	      }
 	  
@@ -16704,7 +16253,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 1999;
 	  gprintf(__func__, " Second order packed grids unsupported!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
     }
 
@@ -16713,7 +16262,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
   /* Take into account that spherical harmonics can be packed  */
   /* simple (lcomplex = 0) or complex (lcomplex = 1)           */
 
-  jlend = bdsLen - locnd;
+  int jlend = bdsLen - locnd;
 
   if ( ISEC4_NumBits == 0 )
     {
@@ -16722,7 +16271,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 2001;
 	  gprintf(__func__, " Number of bits per data value = 0!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
 
       if ( numGridVals == 0 )
@@ -16730,7 +16279,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 2002;
 	  gprintf(__func__, " Constant field unsupported for this grid type!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
 
       jlend = numGridVals;
@@ -16753,7 +16302,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
       else
         len = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
 
-      ISEC4_NumValues = len*8/ISEC4_NumBits;
+      ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
 
       if ( lspherc )
 	{
@@ -16764,7 +16313,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	}
     }
 
-  if ( dfunc == 'J' ) return (bdsLen);
+  if ( dfunc == 'J' ) return bdsLen;
 
   /* check length of output array. */
   
@@ -16774,10 +16323,10 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
       gprintf(__func__, " Output array too small. Length = %d", fsec4len);
       gprintf(__func__, " Number of values = %d", ISEC4_NumValues);
       gprintf(__func__, " Return code =  %d", *iret);
-      return (0);
+      return 0;
     }
 
-  if ( imiss ) memset((char *)fpdata, 0, jlend*sizeof(T));
+  if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
   else
     {
       igrib += locnd;
@@ -16787,9 +16336,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 
   if ( lspherc && lcomplex )
     {
-      int pcStart, pcScale;
-      pcStart = isec4[19];
-      pcScale = isec4[16];
+      int pcStart = isec4[19], pcScale = isec4[16];
       TEMPLATE(scatter_complex,T)(fsec4, pcStart, ISEC2_PentaJ, ISEC4_NumValues);
       TEMPLATE(scale_complex,T)(fsec4, pcStart, pcScale, ISEC2_PentaJ, 1);
     }
@@ -16801,17 +16348,17 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	if ( IS_NOT_EQUAL(fsec4[1], 0.0) )
 	  {
 	    T zserr = fsec4[1];
-	    for ( i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
+	    for ( int i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
 	  }
       }
 
   if ( decscale )
     {
       T scale = (T) pow(10.0, (double)-decscale);
-      for ( i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
+      for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
     }
 
-  return (bdsLen);
+  return bdsLen;
 }
 
 
@@ -16821,7 +16368,6 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 {
   UCHAR *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
   int isLen = 0, pdsLen = 0, gdsLen = 0, bmsLen = 0, bdsLen = 0, esLen = 0;
-  int gribLen = 0;
   int gdsIncluded = FALSE;
   int bmsIncluded = FALSE;
   int bitmapSize = 0;
@@ -17012,7 +16558,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
 	  {
 	    lmissvalinfo = 0;
-	    FSEC3_MissVal = GRIB_MISSVAL;
+	    FSEC3_MissVal = (T)GRIB_MISSVAL;
 	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
 	  }
 
@@ -17021,16 +16567,12 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
       if ( dfunc != 'J' || bitmapSize == ISEC4_NumNonMissValues )
 	{
-	  long i, j;
-	  GRIBPACK *pbitmap;
 	  GRIBPACK bitmap;
-	  GRIBPACK *imask;
-
 	  /*
 	  unsigned char *bitmap;
 	  bitmap = BMS_Bitmap;
-	  j = ISEC4_NumNonMissValues;
-	  for ( i = ISEC4_NumValues-1; i >= 0; i-- )
+	  int j = ISEC4_NumNonMissValues;
+	  for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
 	    {
 	      if ( (bitmap[i/8]>>(7-(i&7)))&1 )
 		fsec4[i] = fsec4[--j];
@@ -17039,13 +16581,13 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	    }
 	  */
 
-	  imask = (GRIBPACK*) Malloc(imaskSize*sizeof(GRIBPACK));
+	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
 
 #if defined (VECTORCODE)
 	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
-	  pbitmap = imask;
+	  GRIBPACK *pbitmap = imask;
 #else
-	  pbitmap = BMS_Bitmap;
+	  GRIBPACK *pbitmap = BMS_Bitmap;
 #endif
 
 #if defined (CRAY)
@@ -17057,7 +16599,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 #ifdef __uxpch__
 #pragma loop novrec
 #endif
-	  for ( i = imaskSize/8-1; i >= 0; i-- )
+	  for ( int i = imaskSize/8-1; i >= 0; i-- )
 	    {
 	      bitmap = pbitmap[i];
 	      imask[i*8+0] = 1 & (bitmap >> 7);
@@ -17070,8 +16612,8 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	      imask[i*8+7] = 1 & (bitmap);
 	    }
 
-	  j = 0;
-	  for ( i = 0; i < ISEC4_NumValues; i++ )
+	  int j = 0;
+	  for ( int i = 0; i < ISEC4_NumValues; i++ )
 	    if ( imask[i] ) j++;
 
 	  if ( ISEC4_NumNonMissValues != j )
@@ -17094,7 +16636,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 #ifdef __uxpch__
 #pragma loop novrec
 #endif
-	      for ( i = ISEC4_NumValues-1; i >= 0; i-- )
+	      for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
 		fsec4[i] = imask[i] ? fsec4[--j] : FSEC3_MissVal;
 	    }
 
@@ -17104,24 +16646,18 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   if ( ISEC2_Reduced )
     {
-      int nlon, nlat;
-      int lperio = 1, lveggy;
-      int ilat;
       int nvalues = 0;
-
-      nlat = ISEC2_NumLat;
-      nlon = ISEC2_RowLonPtr[0];
-      for ( ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
-      for ( ilat = 1; ilat < nlat; ++ilat )
+      int nlat = ISEC2_NumLat;
+      int nlon = ISEC2_RowLonPtr[0];
+      for ( int ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
+      for ( int ilat = 1; ilat < nlat; ++ilat )
 	if ( ISEC2_RowLon(ilat) > nlon ) nlon = ISEC2_RowLon(ilat);
 
       // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
       // if ( dlon < 0 ) dlon += 360000;
 	  
-      if ( nvalues != ISEC4_NumValues )
-	{
-	  *iret = -801;
-	}
+      if ( nvalues != ISEC4_NumValues ) *iret = -801;
+
       //printf("nlat %d  nlon %d \n", nlat, nlon);
       //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
 
@@ -17136,18 +16672,20 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	  ISEC4_NumValues = nlon*nlat;
 
 	  lsect3 = bitmapSize > 0;
-	  lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
-	          ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
-	           (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30));
+          int lperio = 1;
+	  int lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
+                      ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
+                       (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30) ||
+                       (ISEC1_Parameter == 39) || (ISEC1_Parameter == 40) ||
+                       (ISEC1_Parameter == 41) || (ISEC1_Parameter == 42) ||
+                       (ISEC1_Parameter == 43));
 	
 	  (void) TEMPLATE(qu2reg3,T)(fsec4, ISEC2_RowLonPtr, nlat, nlon, FSEC3_MissVal, iret, lsect3, lperio, lveggy);
 	      
 	  if ( bitmapSize > 0 )
 	    {
-	      long i;
-	      int j = 0;
-	      
-	      for ( i = 0; i < ISEC4_NumValues; i++ )
+	      int j = 0;	      
+	      for ( int i = 0; i < ISEC4_NumValues; i++ )
 		if ( IS_NOT_EQUAL(fsec4[i], FSEC3_MissVal) ) j++;
 		  
 	      ISEC4_NumNonMissValues = j;
@@ -17159,7 +16697,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
   esLen = 4;
 
-  gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
+  int gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
 
   if ( ISEC0_GRIB_Len )
     if ( ISEC0_GRIB_Len < gribLen )
@@ -17167,8 +16705,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   ISEC0_GRIB_Len = gribLen;
 
-  *kword = gribLen / sizeof(int);
-  if ( (size_t) gribLen != *kword * sizeof(int) ) *kword += 1;
+  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
 
   /*
     ----------------------------------------------------------------
@@ -17213,6 +16750,12 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 /* GRIB block 0 - indicator block */
 static
 void encodeIS(GRIBPACK *lGrib, long *gribLen)
@@ -17275,20 +16818,20 @@ void encodeES(GRIBPACK *lGrib, long *gribLen, long bdsstart)
       itemp = z / (-120);
       itemp = JP23SET - itemp + 1;
 
-      lGrib[4] = itemp >> 16;
-      lGrib[5] = itemp >>  8;
-      lGrib[6] = itemp;
+      lGrib[4] = (GRIBPACK)(itemp >> 16);
+      lGrib[5] = (GRIBPACK)(itemp >>  8);
+      lGrib[6] = (GRIBPACK)itemp;
 
       bdslen = z - bdslen;
-      lGrib[bdsstart  ] = bdslen >> 16;
-      lGrib[bdsstart+1] = bdslen >>  8;
-      lGrib[bdsstart+2] = bdslen;
+      lGrib[bdsstart  ] = (GRIBPACK)(bdslen >> 16);
+      lGrib[bdsstart+1] = (GRIBPACK)(bdslen >>  8);
+      lGrib[bdsstart+2] = (GRIBPACK)bdslen;
     }
   else
     {
-      lGrib[4] = z >> 16;
-      lGrib[5] = z >>  8;
-      lGrib[6] = z;
+      lGrib[4] = (GRIBPACK)(z >> 16);
+      lGrib[5] = (GRIBPACK)(z >>  8);
+      lGrib[6] = (GRIBPACK)z;
 
       while ( z%8 ) lGrib[z++] = 0;
     }
@@ -17560,6 +17103,7 @@ int  BitsPerInt = (int) (sizeof(int) * 8);
 #define T double
 #ifdef T
 
+
 static
 void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datasize, GRIBPACK *lGrib,
 				     const T *data, T zref, T factor, size_t *gz)
@@ -17577,7 +17121,7 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
   for ( i = packStart; i < datasize; i++ )
     {
       /* note float -> unsigned int .. truncate */
-      ival = (unsigned int) ((data[i] - zref) * factor + 0.5);
+      ival = (unsigned int) ((data[i] - zref) * factor + (T)0.5);
       /*
 	if ( ival > max_nbpv_pow2 ) ival = max_nbpv_pow2;
 	if ( ival < 0 ) ival = 0;
@@ -17593,7 +17137,7 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
 	  else
 	    {
 	      jbits -= cbits;
-	      lGrib[z++] = (c << cbits) + ((ival >> jbits) & mask[cbits]);
+	      lGrib[z++] = (GRIBPACK)((c << cbits) + ((ival >> jbits) & mask[cbits]));
 	      cbits = 8;
 	      c = 0;
 	    }
@@ -17605,11 +17149,39 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
 	  cbits -= jbits;
 	}
     }
-  if ( cbits != 8 ) lGrib[z++] = c << cbits;
+  if ( cbits != 8 ) lGrib[z++] = (GRIBPACK)(c << cbits);
 
   *gz = z;
 }
 
+
+static
+void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
+				    const T *restrict data, T zref, T factor, size_t *gz)
+{
+  U_BYTEORDER;
+  uint16_t *restrict sgrib = (uint16_t *) (lGrib+*gz);
+
+  if ( IS_BIGENDIAN() )
+    {
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          sgrib[i] = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+        }
+    }
+  else
+    {
+      uint16_t ui16;
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          ui16 = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+          sgrib[i] = gribSwapByteOrder_uint16(ui16);
+        }
+    }
+
+  *gz += 2*datasize;
+}
+/*
 static
 void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 				    const T *restrict data, T zref, T factor, size_t *gz)
@@ -17629,7 +17201,7 @@ void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 #endif
   for ( i = 0; i < datasize; i++ )
     {
-      tmp = ((data[i] - zref) * factor + 0.5);
+      tmp = ((data[i] - zref) * factor + (T)0.5);
       ui16 = (uint16_t) tmp;
       lGrib[z  ] = ui16 >>  8;
       lGrib[z+1] = ui16;
@@ -17638,7 +17210,7 @@ void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 
   *gz = z;
 }
-
+*/
 static
 void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize, 
 			      GRIBPACK *restrict lGrib,
@@ -17648,7 +17220,6 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER 
   uint64_t start_minmax, end_minmax;
 #endif
-
   uint32_t ui32;
   size_t i, z = *gz;
   T tmp;
@@ -17673,8 +17244,8 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
-	  lGrib[z  ] = (uint16_t) tmp;
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
+	  lGrib[z  ] = (GRIBPACK)tmp;
           z++;
 	}
 
@@ -17691,10 +17262,9 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #elif defined _GET_MACH_COUNTER 
       start_minmax = mach_absolute_time();
 #endif
-
       if ( sizeof(T) == sizeof(double) )
       	{
-          grib_encode_array_2byte_double(datasize, lGrib, (const double * restrict) data, zref, factor, &z);
+          grib_encode_array_2byte_double(datasize, lGrib, (const double *) data, zref, factor, &z);
         }
       else
         {
@@ -17737,11 +17307,11 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
           ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  ui32 >> 16;
-          lGrib[z+1] =  ui32 >>  8;
-          lGrib[z+2] =  ui32;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+2] =  (GRIBPACK)ui32;
           z += 3;
 	}
 
@@ -17766,12 +17336,12 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
           ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  ui32 >> 24;
-          lGrib[z+1] =  ui32 >> 16;
-          lGrib[z+2] =  ui32 >>  8;
-          lGrib[z+3] =  ui32;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 24);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+2] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+3] =  (GRIBPACK)ui32;
           z += 4;
 	}
 
@@ -17805,12 +17375,11 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _ARCH_PWR6
 #define __UNROLL_DEPTH_2 8
 #else
-#define __UNROLL_DEPTH_2 8
+#define __UNROLL_DEPTH_2 128
 #endif
   size_t residual;
   size_t ofs;
   T dval[__UNROLL_DEPTH_2];
-  unsigned long ival;
 
   data += packStart;
   datasize -= packStart;
@@ -17821,29 +17390,37 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 
   if      ( numBits ==  8 )
     {
-      unsigned char *cgrib = (unsigned char *) (lGrib + z);
 #ifdef _GET_IBM_COUNTER 
       hpmStart(2, "pack 8 bit unrolled");
 #endif
+      unsigned char *cgrib = (unsigned char *) (lGrib + z);
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *cgrib++ =  (unsigned long) dval[j];
+#else
+	      *cgrib++ =  (unsigned char) dval[j];
+#endif
 	    }
 	  z += __UNROLL_DEPTH_2;
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       for (j = 0; j < residual; j++) 
 	{
+#ifdef _ARCH_PWR6
 	  *cgrib++ = (unsigned long) dval[j];
+#else
+	  *cgrib++ = (unsigned char) dval[j];
+#endif
 	}
       z += residual;
 
@@ -17853,21 +17430,31 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
     }
   else if ( numBits == 16 )
     {
-      unsigned short *sgrib = (unsigned short *) (lGrib + z);
 #ifdef _GET_IBM_COUNTER 
       hpmStart(3, "pack 16 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint16_t ival;
+#endif
+      uint16_t *sgrib = (uint16_t *) (lGrib+z);
+
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  if ( IS_BIGENDIAN() )
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
+#ifdef _ARCH_PWR6
 		  *sgrib++ = (unsigned long) dval[j];
+#else
+		  *sgrib++ = (uint16_t) dval[j];
+#endif
 		}
 	      z += 2*__UNROLL_DEPTH_2;
 	    }
@@ -17875,22 +17462,25 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
-		  ival = (unsigned long) dval[j];
-		  lGrib[z  ] = ival >>  8;
-		  lGrib[z+1] = ival;
-		  z += 2;
+		  ival = (uint16_t) dval[j];
+                  *sgrib++ = gribSwapByteOrder_uint16(ival);
 		}
+	      z += 2*__UNROLL_DEPTH_2;
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       if ( IS_BIGENDIAN() )
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *sgrib++ = (unsigned long) dval[j];
+#else
+              *sgrib++ = (uint16_t) dval[j];
+#endif
 	    }
 	  z += 2*residual;
 	}
@@ -17898,9 +17488,9 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
-	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] = ival >>  8;
-	      lGrib[z+1] = ival;
+              ival = (uint16_t) dval[j];
+	      lGrib[z  ] = (GRIBPACK)(ival >>  8);
+	      lGrib[z+1] = (GRIBPACK)ival;
 	      z += 2;
 	    }
 	}
@@ -17913,31 +17503,40 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _GET_IBM_COUNTER 
       hpmStart(4, "pack 24 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] =  ival >> 16;
-	      lGrib[z+1] =  ival >>  8;
-	      lGrib[z+2] =  ival;
+#else
+	      ival = (uint32_t) dval[j];
+#endif
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+2] =  (GRIBPACK)ival;
 	      z += 3;
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  ival = (unsigned long) dval[j];
-	  lGrib[z  ] =  ival >> 16;
-	  lGrib[z+1] =  ival >>  8;
-	  lGrib[z+2] =  ival;
+	  ival = (uint32_t) dval[j];
+	  lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	  lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	  lGrib[z+2] =  (GRIBPACK)ival;
 	  z += 3;
 	}
 #ifdef _GET_IBM_COUNTER 
@@ -17949,18 +17548,27 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _GET_IBM_COUNTER 
       hpmStart(5, "pack 32 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
       unsigned int *igrib = (unsigned int *) (lGrib + z);
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
-	{
+ {
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  if ( IS_BIGENDIAN() )
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
+#ifdef _ARCH_PWR6
 		  *igrib = (unsigned long) dval[j];
+#else
+		  *igrib = (uint32_t) dval[j];
+#endif
 		  igrib++;
 		  z += 4;
 		}
@@ -17969,37 +17577,41 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
-		  ival = (unsigned long) dval[j];
-		  lGrib[z  ] =  ival >> 24;
-		  lGrib[z+1] =  ival >> 16;
-		  lGrib[z+2] =  ival >>  8;
-		  lGrib[z+3] =  ival;
+                  ival = (uint32_t) dval[j];
+		  lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+		  lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+		  lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+		  lGrib[z+3] =  (GRIBPACK)ival;
 		  z += 4;
 		}
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       if ( IS_BIGENDIAN() )
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *igrib = (unsigned long) dval[j];
+#else
+	      *igrib = (uint32_t) dval[j];
+#endif
 	      igrib++;
 	      z += 4;
 	    }
 	}
       else
 	{
-	  for (j = 0; j < residual; j++) 
+          for (j = 0; j < residual; j++) 
 	    {
-	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] =  ival >> 24;
-	      lGrib[z+1] =  ival >> 16;
-	      lGrib[z+2] =  ival >>  8;
-	      lGrib[z+3] =  ival;
+	      ival = (uint32_t) dval[j];
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+	      lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+3] =  (GRIBPACK)ival;
 	      z += 4;
 	    }
 	}
@@ -18025,12 +17637,19 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 #ifdef T
 #undef T
 #endif
 #define T float
 #ifdef T
 
+
 static
 void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datasize, GRIBPACK *lGrib,
 				     const T *data, T zref, T factor, size_t *gz)
@@ -18048,7 +17667,7 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
   for ( i = packStart; i < datasize; i++ )
     {
       /* note float -> unsigned int .. truncate */
-      ival = (unsigned int) ((data[i] - zref) * factor + 0.5);
+      ival = (unsigned int) ((data[i] - zref) * factor + (T)0.5);
       /*
 	if ( ival > max_nbpv_pow2 ) ival = max_nbpv_pow2;
 	if ( ival < 0 ) ival = 0;
@@ -18064,7 +17683,7 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
 	  else
 	    {
 	      jbits -= cbits;
-	      lGrib[z++] = (c << cbits) + ((ival >> jbits) & mask[cbits]);
+	      lGrib[z++] = (GRIBPACK)((c << cbits) + ((ival >> jbits) & mask[cbits]));
 	      cbits = 8;
 	      c = 0;
 	    }
@@ -18076,11 +17695,39 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
 	  cbits -= jbits;
 	}
     }
-  if ( cbits != 8 ) lGrib[z++] = c << cbits;
+  if ( cbits != 8 ) lGrib[z++] = (GRIBPACK)(c << cbits);
 
   *gz = z;
 }
 
+
+static
+void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
+				    const T *restrict data, T zref, T factor, size_t *gz)
+{
+  U_BYTEORDER;
+  uint16_t *restrict sgrib = (uint16_t *) (lGrib+*gz);
+
+  if ( IS_BIGENDIAN() )
+    {
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          sgrib[i] = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+        }
+    }
+  else
+    {
+      uint16_t ui16;
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          ui16 = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+          sgrib[i] = gribSwapByteOrder_uint16(ui16);
+        }
+    }
+
+  *gz += 2*datasize;
+}
+/*
 static
 void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 				    const T *restrict data, T zref, T factor, size_t *gz)
@@ -18100,7 +17747,7 @@ void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 #endif
   for ( i = 0; i < datasize; i++ )
     {
-      tmp = ((data[i] - zref) * factor + 0.5);
+      tmp = ((data[i] - zref) * factor + (T)0.5);
       ui16 = (uint16_t) tmp;
       lGrib[z  ] = ui16 >>  8;
       lGrib[z+1] = ui16;
@@ -18109,7 +17756,7 @@ void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 
   *gz = z;
 }
-
+*/
 static
 void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize, 
 			      GRIBPACK *restrict lGrib,
@@ -18119,7 +17766,6 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER 
   uint64_t start_minmax, end_minmax;
 #endif
-
   uint32_t ui32;
   size_t i, z = *gz;
   T tmp;
@@ -18144,8 +17790,8 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
-	  lGrib[z  ] = (uint16_t) tmp;
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
+	  lGrib[z  ] = (GRIBPACK)tmp;
           z++;
 	}
 
@@ -18162,10 +17808,9 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #elif defined _GET_MACH_COUNTER 
       start_minmax = mach_absolute_time();
 #endif
-
       if ( sizeof(T) == sizeof(double) )
       	{
-          grib_encode_array_2byte_double(datasize, lGrib, (const double * restrict) data, zref, factor, &z);
+          grib_encode_array_2byte_double(datasize, lGrib, (const double *) data, zref, factor, &z);
         }
       else
         {
@@ -18208,11 +17853,11 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
           ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  ui32 >> 16;
-          lGrib[z+1] =  ui32 >>  8;
-          lGrib[z+2] =  ui32;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+2] =  (GRIBPACK)ui32;
           z += 3;
 	}
 
@@ -18237,12 +17882,12 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
           ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  ui32 >> 24;
-          lGrib[z+1] =  ui32 >> 16;
-          lGrib[z+2] =  ui32 >>  8;
-          lGrib[z+3] =  ui32;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 24);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+2] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+3] =  (GRIBPACK)ui32;
           z += 4;
 	}
 
@@ -18276,12 +17921,11 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _ARCH_PWR6
 #define __UNROLL_DEPTH_2 8
 #else
-#define __UNROLL_DEPTH_2 8
+#define __UNROLL_DEPTH_2 128
 #endif
   size_t residual;
   size_t ofs;
   T dval[__UNROLL_DEPTH_2];
-  unsigned long ival;
 
   data += packStart;
   datasize -= packStart;
@@ -18292,29 +17936,37 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 
   if      ( numBits ==  8 )
     {
-      unsigned char *cgrib = (unsigned char *) (lGrib + z);
 #ifdef _GET_IBM_COUNTER 
       hpmStart(2, "pack 8 bit unrolled");
 #endif
+      unsigned char *cgrib = (unsigned char *) (lGrib + z);
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *cgrib++ =  (unsigned long) dval[j];
+#else
+	      *cgrib++ =  (unsigned char) dval[j];
+#endif
 	    }
 	  z += __UNROLL_DEPTH_2;
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       for (j = 0; j < residual; j++) 
 	{
+#ifdef _ARCH_PWR6
 	  *cgrib++ = (unsigned long) dval[j];
+#else
+	  *cgrib++ = (unsigned char) dval[j];
+#endif
 	}
       z += residual;
 
@@ -18324,21 +17976,31 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
     }
   else if ( numBits == 16 )
     {
-      unsigned short *sgrib = (unsigned short *) (lGrib + z);
 #ifdef _GET_IBM_COUNTER 
       hpmStart(3, "pack 16 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint16_t ival;
+#endif
+      uint16_t *sgrib = (uint16_t *) (lGrib+z);
+
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  if ( IS_BIGENDIAN() )
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
+#ifdef _ARCH_PWR6
 		  *sgrib++ = (unsigned long) dval[j];
+#else
+		  *sgrib++ = (uint16_t) dval[j];
+#endif
 		}
 	      z += 2*__UNROLL_DEPTH_2;
 	    }
@@ -18346,22 +18008,25 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
-		  ival = (unsigned long) dval[j];
-		  lGrib[z  ] = ival >>  8;
-		  lGrib[z+1] = ival;
-		  z += 2;
+		  ival = (uint16_t) dval[j];
+                  *sgrib++ = gribSwapByteOrder_uint16(ival);
 		}
+	      z += 2*__UNROLL_DEPTH_2;
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       if ( IS_BIGENDIAN() )
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *sgrib++ = (unsigned long) dval[j];
+#else
+              *sgrib++ = (uint16_t) dval[j];
+#endif
 	    }
 	  z += 2*residual;
 	}
@@ -18369,9 +18034,9 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
-	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] = ival >>  8;
-	      lGrib[z+1] = ival;
+              ival = (uint16_t) dval[j];
+	      lGrib[z  ] = (GRIBPACK)(ival >>  8);
+	      lGrib[z+1] = (GRIBPACK)ival;
 	      z += 2;
 	    }
 	}
@@ -18384,31 +18049,40 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _GET_IBM_COUNTER 
       hpmStart(4, "pack 24 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] =  ival >> 16;
-	      lGrib[z+1] =  ival >>  8;
-	      lGrib[z+2] =  ival;
+#else
+	      ival = (uint32_t) dval[j];
+#endif
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+2] =  (GRIBPACK)ival;
 	      z += 3;
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  ival = (unsigned long) dval[j];
-	  lGrib[z  ] =  ival >> 16;
-	  lGrib[z+1] =  ival >>  8;
-	  lGrib[z+2] =  ival;
+	  ival = (uint32_t) dval[j];
+	  lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	  lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	  lGrib[z+2] =  (GRIBPACK)ival;
 	  z += 3;
 	}
 #ifdef _GET_IBM_COUNTER 
@@ -18420,18 +18094,27 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _GET_IBM_COUNTER 
       hpmStart(5, "pack 32 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
       unsigned int *igrib = (unsigned int *) (lGrib + z);
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
-	{
+ {
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  if ( IS_BIGENDIAN() )
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
+#ifdef _ARCH_PWR6
 		  *igrib = (unsigned long) dval[j];
+#else
+		  *igrib = (uint32_t) dval[j];
+#endif
 		  igrib++;
 		  z += 4;
 		}
@@ -18440,37 +18123,41 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
-		  ival = (unsigned long) dval[j];
-		  lGrib[z  ] =  ival >> 24;
-		  lGrib[z+1] =  ival >> 16;
-		  lGrib[z+2] =  ival >>  8;
-		  lGrib[z+3] =  ival;
+                  ival = (uint32_t) dval[j];
+		  lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+		  lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+		  lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+		  lGrib[z+3] =  (GRIBPACK)ival;
 		  z += 4;
 		}
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       if ( IS_BIGENDIAN() )
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *igrib = (unsigned long) dval[j];
+#else
+	      *igrib = (uint32_t) dval[j];
+#endif
 	      igrib++;
 	      z += 4;
 	    }
 	}
       else
 	{
-	  for (j = 0; j < residual; j++) 
+          for (j = 0; j < residual; j++) 
 	    {
-	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] =  ival >> 24;
-	      lGrib[z+1] =  ival >> 16;
-	      lGrib[z+2] =  ival >>  8;
-	      lGrib[z+3] =  ival;
+	      ival = (uint32_t) dval[j];
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+	      lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+3] =  (GRIBPACK)ival;
 	      z += 4;
 	    }
 	}
@@ -18496,6 +18183,12 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 
 #ifdef T
 #undef T
@@ -18596,8 +18289,8 @@ void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
 	}
       else
 	{
-	  lonIncr = ISEC2_LonIncr;
-	  latIncr = ISEC2_LatIncr;
+	  lonIncr = (unsigned)ISEC2_LonIncr;
+	  latIncr = (unsigned)ISEC2_LatIncr;
 	}
       Put2Byte(lonIncr);               /* 23-24 i - direction increment  */
       if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN )
@@ -18710,7 +18403,7 @@ void TEMPLATE(encodeBMS,T)(GRIBPACK *lGrib, long *gribLen, T *fsec3, int *isec4,
       if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
 	{
 	  data[fsec4size++] = data[i];
-	  bitmap[i/8] |= 1<<(7-(i&7));
+	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
 	}
     }
 #endif
@@ -18736,36 +18429,33 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
   /* Uwe Schulzweida, 11/04/2003 : Check that number of bits per value is not exceeded */
   /* Uwe Schulzweida,  6/05/2003 : Copy result to fpval to prevent integer overflow */
 
-  size_t z = *gribLen;
-  long i, jloop;
+  size_t z = (size_t)*gribLen;
+  long i;
   int numBits;
   int ival;
-  int blockLength, PackStart = 0, Flag = 0;
+  long PackStart = 0, Flag = 0;
   int binscale = 0;
   int nbpv;
   int bds_head = 11;
   int bds_ext = 0;
   /* ibits = BitsPerInt; */
-  unsigned int max_nbpv_pow2;
   int exponent, mantissa;
-  int unused_bits = 0;
   int lspherc = FALSE, lcomplex = FALSE;
   int isubset = 0, itemp = 0, itrunc = 0;
   T factor = 1, fmin, fmax;
   double zref;
-  double range, rangec;
+  double range;
   double jpepsln = 1.0e-12;     /* -----> tolerance used to check equality     */
                                 /*        of floating point numbers - needed   */
 		                /*        on some platforms (eg vpp700, linux) */
-  extern const double _pow2tab[158];
   extern int CGRIBEX_Const;         /* 1: Don't pack constant fields on regular grids */
 
   if ( isec2 )
     {
       /* If section 2 is present, it says if data is spherical harmonic */
 
-      if ( isec2[0] == 50 || isec2[0] == 60 || 
-	   isec2[0] == 70 || isec2[0] == 80 ) lspherc = TRUE;
+      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
+                   isec2[0] == 70 || isec2[0] == 80 );
 
       if ( lspherc )
 	isec4[2] = 128;
@@ -18848,7 +18538,7 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
       pcStart = isubset;
       pcScale = isec4[16];
       TEMPLATE(scale_complex,T)(data, pcStart, pcScale, itrunc, 0);
-      TEMPLATE(gather_complex,T)(data, pcStart, itrunc, datasize);
+      TEMPLATE(gather_complex,T)(data, (size_t)pcStart, (size_t)itrunc, (size_t)datasize);
     }
 
   fmin = fmax = data[PackStart];
@@ -18864,10 +18554,10 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
     }
 
 
-  blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
-  if ( (blockLength%2) == 1 ) blockLength++;
+  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
+  blockLength += blockLength & 1;
 
-  unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
+  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
 
   Flag += unused_bits;
 
@@ -18905,57 +18595,54 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
     }
   else if ( range > 1.0 )
     {
-      rangec = range + jpepsln;
-      for ( jloop = 1; jloop < 128; jloop++ )
-	{
-	  if ( _pow2tab[jloop] > rangec ) break;
-	}
-      if ( jloop == 128 )
-	{
-	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-	  gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-	  return (707);
-	}
+      double rangec = range + jpepsln,
+        p2 = 2.0;
+      long jloop = 1;
+      while ( jloop < 128 && p2 <= rangec )
+        {
+          p2 *= 2.0;
+          ++jloop;
+        }
+      if (jloop < 128)
+        binscale = jloop - nbpv;
       else
-	{
-	  binscale = jloop - nbpv;
-	}
+        {
+          gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+          gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+          return (707);
+        }
     }
   else
     {
-      rangec = range - jpepsln;
-      for ( jloop = 1; jloop < 127; jloop++ )
+      double rangec = range - jpepsln, p05 = 0.5;
+      long jloop = 1;
+      while ( jloop < 127 && p05 >= rangec )
 	{
-	  if ( 1.0/_pow2tab[jloop] < rangec ) break;
+          p05 *= 0.5;
+          jloop++;
 	}
-      if ( jloop == 127 )
+      if ( jloop < 127 )
 	{
-	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-	  return (707);
+	  binscale = 1 - jloop - nbpv;
 	}
       else
 	{
-	  binscale = 1 - jloop - nbpv;
+	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+	  return (707);
 	}
     }
 
-  //max_nbpv_pow2 = (unsigned) (intpow2(nbpv) - 1);
-  max_nbpv_pow2 = (unsigned) ((1ULL << nbpv) - 1);
+  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
 
   if ( binscale != 0 )
     {
       if ( binscale < 0 )
-	{
-	  if ( (unsigned)(range*intpow2(-binscale)+0.5) > max_nbpv_pow2 ) binscale++;
-	}
+        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
       else
-	{
-	  if ( (unsigned)(range/intpow2(binscale)+0.5) > max_nbpv_pow2 ) binscale--;
-	}
+        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale--;
 
-      if ( binscale < 0 ) factor =     intpow2(-binscale);
-      else                factor = 1.0/intpow2( binscale);
+      factor = intpow2(-binscale);
     }
 
   ref2ibm(&zref, BitsPerInt);
@@ -18972,7 +18659,7 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
       if ( lcomplex )
 	{
 	  int jup = isubset;
-	  int ioff = z + bds_ext;
+	  int ioff = (int)z + bds_ext;
 	  if ( ioff > 0xFFFF ) ioff = 0;
 	  Put2Byte(ioff);
 	  Put2Int(isec4[16]);
@@ -18990,14 +18677,14 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
   *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
 
 #if  defined  (_ARCH_PWR6)
-  TEMPLATE(encode_array_unrolled,T)(nbpv, PackStart, datasize, lGrib, data, (T)zref, factor, &z);
+  TEMPLATE(encode_array_unrolled,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
 #else
-  TEMPLATE(encode_array,T)(nbpv, PackStart, datasize, lGrib, data, (T)zref, factor, &z);
+  TEMPLATE(encode_array,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
 #endif
 
   if ( unused_bits >= 8 ) Put1Byte(0);  /*  Fillbyte                     */
 
-  *gribLen = z;
+  *gribLen = (long)z;
 
   return (0);
 }
@@ -19012,9 +18699,7 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   GRIBPACK *lpds;
   unsigned char *CGrib;
   long fsec4size = 0;
-  int numBytes;
   int bmsIncluded;
-  size_t len;
   GRIBPACK *lGrib;
   long datstart, datsize, bdsstart;
   int status = 0;
@@ -19029,15 +18714,15 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   bmsIncluded = ISEC1_Sec2Or3Flag & 64;
 
   /* set max header len */
-  len = 16384;
+  size_t len = 16384;
 
   /* add data len */
-  numBytes = (ISEC4_NumBits+7)>>3;
+  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
 
-  len += numBytes*klenp;
+  len += numBytes*(size_t)klenp;
 
   /* add bitmap len */
-  if ( bmsIncluded ) len += (klenp+7)>>3;
+  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
 
 #if defined (VECTORCODE)
   lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
@@ -19093,7 +18778,7 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   encodeES(lGrib, &gribLen, bdsstart);
 
-  if ( (size_t) gribLen > kleng*sizeof(int) )
+  if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
     Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
 
 #if defined (VECTORCODE)
@@ -19105,17 +18790,22 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   Free(lGrib);
 #endif
 
-  ISEC0_GRIB_Len     = gribLen;
+  ISEC0_GRIB_Len     = (int)gribLen;
   ISEC0_GRIB_Version = 1;
 
-  *kword = gribLen / sizeof(int);
-  if ( (size_t) gribLen != *kword * sizeof(int) ) *kword += 1;
+  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
 
   *kret = status;
 }
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 #ifdef T
 #undef T
 #endif
@@ -19215,8 +18905,8 @@ void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
 	}
       else
 	{
-	  lonIncr = ISEC2_LonIncr;
-	  latIncr = ISEC2_LatIncr;
+	  lonIncr = (unsigned)ISEC2_LonIncr;
+	  latIncr = (unsigned)ISEC2_LatIncr;
 	}
       Put2Byte(lonIncr);               /* 23-24 i - direction increment  */
       if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN )
@@ -19329,7 +19019,7 @@ void TEMPLATE(encodeBMS,T)(GRIBPACK *lGrib, long *gribLen, T *fsec3, int *isec4,
       if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
 	{
 	  data[fsec4size++] = data[i];
-	  bitmap[i/8] |= 1<<(7-(i&7));
+	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
 	}
     }
 #endif
@@ -19355,36 +19045,33 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
   /* Uwe Schulzweida, 11/04/2003 : Check that number of bits per value is not exceeded */
   /* Uwe Schulzweida,  6/05/2003 : Copy result to fpval to prevent integer overflow */
 
-  size_t z = *gribLen;
-  long i, jloop;
+  size_t z = (size_t)*gribLen;
+  long i;
   int numBits;
   int ival;
-  int blockLength, PackStart = 0, Flag = 0;
+  long PackStart = 0, Flag = 0;
   int binscale = 0;
   int nbpv;
   int bds_head = 11;
   int bds_ext = 0;
   /* ibits = BitsPerInt; */
-  unsigned int max_nbpv_pow2;
   int exponent, mantissa;
-  int unused_bits = 0;
   int lspherc = FALSE, lcomplex = FALSE;
   int isubset = 0, itemp = 0, itrunc = 0;
   T factor = 1, fmin, fmax;
   double zref;
-  double range, rangec;
+  double range;
   double jpepsln = 1.0e-12;     /* -----> tolerance used to check equality     */
                                 /*        of floating point numbers - needed   */
 		                /*        on some platforms (eg vpp700, linux) */
-  extern const double _pow2tab[158];
   extern int CGRIBEX_Const;         /* 1: Don't pack constant fields on regular grids */
 
   if ( isec2 )
     {
       /* If section 2 is present, it says if data is spherical harmonic */
 
-      if ( isec2[0] == 50 || isec2[0] == 60 || 
-	   isec2[0] == 70 || isec2[0] == 80 ) lspherc = TRUE;
+      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
+                   isec2[0] == 70 || isec2[0] == 80 );
 
       if ( lspherc )
 	isec4[2] = 128;
@@ -19467,7 +19154,7 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
       pcStart = isubset;
       pcScale = isec4[16];
       TEMPLATE(scale_complex,T)(data, pcStart, pcScale, itrunc, 0);
-      TEMPLATE(gather_complex,T)(data, pcStart, itrunc, datasize);
+      TEMPLATE(gather_complex,T)(data, (size_t)pcStart, (size_t)itrunc, (size_t)datasize);
     }
 
   fmin = fmax = data[PackStart];
@@ -19483,10 +19170,10 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
     }
 
 
-  blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
-  if ( (blockLength%2) == 1 ) blockLength++;
+  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
+  blockLength += blockLength & 1;
 
-  unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
+  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
 
   Flag += unused_bits;
 
@@ -19524,57 +19211,54 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
     }
   else if ( range > 1.0 )
     {
-      rangec = range + jpepsln;
-      for ( jloop = 1; jloop < 128; jloop++ )
-	{
-	  if ( _pow2tab[jloop] > rangec ) break;
-	}
-      if ( jloop == 128 )
-	{
-	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-	  gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-	  return (707);
-	}
+      double rangec = range + jpepsln,
+        p2 = 2.0;
+      long jloop = 1;
+      while ( jloop < 128 && p2 <= rangec )
+        {
+          p2 *= 2.0;
+          ++jloop;
+        }
+      if (jloop < 128)
+        binscale = jloop - nbpv;
       else
-	{
-	  binscale = jloop - nbpv;
-	}
+        {
+          gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+          gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+          return (707);
+        }
     }
   else
     {
-      rangec = range - jpepsln;
-      for ( jloop = 1; jloop < 127; jloop++ )
+      double rangec = range - jpepsln, p05 = 0.5;
+      long jloop = 1;
+      while ( jloop < 127 && p05 >= rangec )
 	{
-	  if ( 1.0/_pow2tab[jloop] < rangec ) break;
+          p05 *= 0.5;
+          jloop++;
 	}
-      if ( jloop == 127 )
+      if ( jloop < 127 )
 	{
-	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-	  return (707);
+	  binscale = 1 - jloop - nbpv;
 	}
       else
 	{
-	  binscale = 1 - jloop - nbpv;
+	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+	  return (707);
 	}
     }
 
-  //max_nbpv_pow2 = (unsigned) (intpow2(nbpv) - 1);
-  max_nbpv_pow2 = (unsigned) ((1ULL << nbpv) - 1);
+  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
 
   if ( binscale != 0 )
     {
       if ( binscale < 0 )
-	{
-	  if ( (unsigned)(range*intpow2(-binscale)+0.5) > max_nbpv_pow2 ) binscale++;
-	}
+        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
       else
-	{
-	  if ( (unsigned)(range/intpow2(binscale)+0.5) > max_nbpv_pow2 ) binscale--;
-	}
+        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale--;
 
-      if ( binscale < 0 ) factor =     intpow2(-binscale);
-      else                factor = 1.0/intpow2( binscale);
+      factor = intpow2(-binscale);
     }
 
   ref2ibm(&zref, BitsPerInt);
@@ -19591,7 +19275,7 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
       if ( lcomplex )
 	{
 	  int jup = isubset;
-	  int ioff = z + bds_ext;
+	  int ioff = (int)z + bds_ext;
 	  if ( ioff > 0xFFFF ) ioff = 0;
 	  Put2Byte(ioff);
 	  Put2Int(isec4[16]);
@@ -19609,14 +19293,14 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
   *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
 
 #if  defined  (_ARCH_PWR6)
-  TEMPLATE(encode_array_unrolled,T)(nbpv, PackStart, datasize, lGrib, data, (T)zref, factor, &z);
+  TEMPLATE(encode_array_unrolled,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
 #else
-  TEMPLATE(encode_array,T)(nbpv, PackStart, datasize, lGrib, data, (T)zref, factor, &z);
+  TEMPLATE(encode_array,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
 #endif
 
   if ( unused_bits >= 8 ) Put1Byte(0);  /*  Fillbyte                     */
 
-  *gribLen = z;
+  *gribLen = (long)z;
 
   return (0);
 }
@@ -19631,9 +19315,7 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   GRIBPACK *lpds;
   unsigned char *CGrib;
   long fsec4size = 0;
-  int numBytes;
   int bmsIncluded;
-  size_t len;
   GRIBPACK *lGrib;
   long datstart, datsize, bdsstart;
   int status = 0;
@@ -19648,15 +19330,15 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   bmsIncluded = ISEC1_Sec2Or3Flag & 64;
 
   /* set max header len */
-  len = 16384;
+  size_t len = 16384;
 
   /* add data len */
-  numBytes = (ISEC4_NumBits+7)>>3;
+  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
 
-  len += numBytes*klenp;
+  len += numBytes*(size_t)klenp;
 
   /* add bitmap len */
-  if ( bmsIncluded ) len += (klenp+7)>>3;
+  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
 
 #if defined (VECTORCODE)
   lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
@@ -19712,7 +19394,7 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   encodeES(lGrib, &gribLen, bdsstart);
 
-  if ( (size_t) gribLen > kleng*sizeof(int) )
+  if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
     Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
 
 #if defined (VECTORCODE)
@@ -19724,23 +19406,28 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   Free(lGrib);
 #endif
 
-  ISEC0_GRIB_Len     = gribLen;
+  ISEC0_GRIB_Len     = (int)gribLen;
   ISEC0_GRIB_Version = 1;
 
-  *kword = gribLen / sizeof(int);
-  if ( (size_t) gribLen != *kword * sizeof(int) ) *kword += 1;
+  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
 
   *kret = status;
 }
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 void encode_dummy(void)
 {
   (void) encode_array_unrolled_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
   (void) encode_array_unrolled_float(0, 0, 0, NULL, NULL, 0, 0, NULL);
 }
-static const char grb_libvers[] = "1.7.3" " of ""Sep 14 2015"" ""10:58:44";
+static const char grb_libvers[] = "1.7.4" " of ""Feb 19 2016"" ""11:03:41";
 const char *
 cgribexLibraryVersion(void)
 {
@@ -20526,6 +20213,7 @@ void SysError_(const char *caller, const char *fmt, ...)
 void SysError_(const char *caller, const char *fmt, ...)
 {
   va_list args;
+  int saved_errno = errno;
 
   va_start(args, fmt);
 
@@ -20536,8 +20224,11 @@ void SysError_(const char *caller, const char *fmt, ...)
 
   va_end(args);
 
-  if ( errno )
-    perror("System error message ");
+  if ( saved_errno )
+    {
+      errno = saved_errno;
+      perror("System error message");
+    }
 
   exit(EXIT_FAILURE);
 }
@@ -22680,7 +22371,15 @@ size_t fileWrite(int fileID, const void *restrict ptr, size_t size)
 #ifndef _GAUSSGRID_H
 #define _GAUSSGRID_H
 
-void   gaussaw(double *restrict pa, double *restrict pw, size_t nlat);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gaussaw(double *restrict pa, double *restrict pw, size_t nlat);
+
+#if defined (__cplusplus)
+}
+#endif
 
 #endif  /* _GAUSSGRID_H */
 /*
@@ -23170,7 +22869,44 @@ void gribContainersDelete(stream_t * streamptr)
 
 typedef unsigned char mask_t;
 
-typedef struct {
+typedef struct grid_t grid_t;
+
+struct gridVirtTable
+{
+  void (*destroy)(grid_t *gridptr);
+  grid_t *(*copy)(grid_t *gridptr);
+  void (*copyScalarFields)(grid_t *gridptrOrig, grid_t *gridptrDup);
+  void (*copyArrayFields)(grid_t *gridptrOrig, grid_t *gridptrDup);
+  void (*defXVals)(grid_t *gridptr, const double *xvals);
+  void (*defYVals)(grid_t *gridptr, const double *yvals);
+  void (*defMask)(grid_t *gridptr, const int *mask);
+  void (*defMaskGME)(grid_t *gridptr, const int *mask);
+  void (*defXBounds)(grid_t *gridptr, const double *xbounds);
+  void (*defYBounds)(grid_t *gridptr, const double *ybounds);
+  void (*defArea)(grid_t *gridptr, const double *area);
+  double (*inqXVal)(grid_t *gridptr, int index);
+  double (*inqYVal)(grid_t *gridptr, int index);
+  int (*inqXVals)(grid_t *gridptr, double *xvals);
+  int (*inqYVals)(grid_t *gridptr, double *yvals);
+  const double *(*inqXValsPtr)(grid_t *gridptr);
+  const double *(*inqYValsPtr)(grid_t *gridptr);
+  /* return if for both grids, all xval and all yval are equal */
+  int (*compareXYFull)(grid_t *gridRef, grid_t *gridTest);
+  /* return if for both grids, x[0], y[0], x[size-1] and y[size-1] are
+   * respectively equal */
+  int (*compareXYAO)(grid_t *gridRef, grid_t *gridTest);
+  void (*inqArea)(grid_t *gridptr, double *area);
+  const double *(*inqAreaPtr)(grid_t *gridptr);
+  int (*hasArea)(grid_t *gridptr);
+  int (*inqMask)(grid_t *gridptr, int *mask);
+  int (*inqMaskGME)(grid_t *gridptr, int *mask_gme);
+  int (*inqXBounds)(grid_t *gridptr, double *xbounds);
+  int (*inqYBounds)(grid_t *gridptr, double *ybounds);
+  const double *(*inqXBoundsPtr)(grid_t *gridptr);
+  const double *(*inqYBoundsPtr)(grid_t *gridptr);
+};
+
+struct grid_t {
   int     self;
   int     type;                   /* grid type                      */
   int     prec;                   /* grid precision                 */
@@ -23222,24 +22958,28 @@ typedef struct {
   int     xsize;                  /* number of values along X */
   int     ysize;                  /* number of values along Y */
   int     np;                     /* number of parallels between a pole and the equator */
-  int     locked;
-  int     lcomplex;
-  int     hasdims;
+  short   lcomplex;
+  short   hasdims;
+  const char *xstdname;
+  const char *ystdname;
   char    xname[CDI_MAX_NAME];
   char    yname[CDI_MAX_NAME];
   char    xlongname[CDI_MAX_NAME];
   char    ylongname[CDI_MAX_NAME];
-  char    xstdname[CDI_MAX_NAME];
-  char    ystdname[CDI_MAX_NAME];
   char    xunits[CDI_MAX_NAME];
   char    yunits[CDI_MAX_NAME];
   char   *name;
-}
-grid_t;
+  const struct gridVirtTable *vtable;
+  void *extraData;
+};
 
 
 void grid_init(grid_t *gridptr);
+void
+cdiGridTypeInit(grid_t *gridptr, int gridtype, int size);
 void grid_free(grid_t *gridptr);
+grid_t *gridID2Ptr(int gridID);
+extern const struct gridVirtTable cdiGridVtable;
 
 unsigned cdiGridCount(void);
 
@@ -23260,16 +23000,13 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
            int * unpackBufferPos, int originNamespace, void *context,
            int force_id);
 
-int  varDefGrid(int vlistID, const grid_t *grid, int mode);
-
-/* These are used by CDO. */
-void gridGenXvals(int xsize, double xfirst, double xlast,
-                  double xinc, double *xvals);
-void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast,
-                  double yinc, double *yvals);
-
-
+struct addIffNewRes
+{
+  int Id;
+  int isNew;
+};
 
+struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode);
 
 #endif
 /*
@@ -23306,7 +23043,7 @@ void gribGetDoubleArray(grib_handle* gribHandle, const char* key, double* array)
 void gribGetLongArray(grib_handle* gribHandle, const char* key, long* array);   //The caller is responsible to ensure a sufficiently large buffer.
 
 long gribEditionNumber(grib_handle* gh);
-char* gribMakeTimeString(grib_handle* gh, bool getEndTime);     //For statistical fields, setting getEndTime produces the time of the end of the integration period, otherwise the time of the start of the integration period is returned. Returns NULL if getEndTime is set and the field does not have an integration period.
+char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType);     //Returns NULL if timeType is kCdiTimeType_endTime and the field does not have an integration period (statistical data).
 int gribapiTimeIsFC(grib_handle *gh);
 int gribapiGetTsteptype(grib_handle *gh);
 int gribGetDatatype(grib_handle* gribHandle);
@@ -23597,7 +23334,8 @@ static int getAvailabilityOfRelativeTimes(grib_handle* gh, bool* outHaveForecast
         *outHaveForecastTime = false, *outHaveTimeRange = false;
         return 0;
 
-      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 15: case 32: case 33: case 40: case 41: case 44: case 45: case 48: case 51: case 53: case 54: case 60: case 1000: case 1002: case 1100: case 40033:
+      //case 55 and case 40455 are the same: 55 is the proposed standard value, 40455 is the value in the local use range that is used by the dwd until the standard is updated.
+      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 15: case 32: case 33: case 40: case 41: case 44: case 45: case 48: case 51: case 53: case 54: case 55: case 60: case 1000: case 1002: case 1100: case 40033: case 40455:
         *outHaveForecastTime = true, *outHaveTimeRange = false;
         return 0;
 
@@ -23610,24 +23348,15 @@ static int getAvailabilityOfRelativeTimes(grib_handle* gh, bool* outHaveForecast
     }
 }
 
-char* gribMakeTimeString(grib_handle* gh, bool getEndTime)
+char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType)
 {
   //Get the parts of the reference date.
-#ifdef __cplusplus
-    struct tm date;
-    date.tm_mon = (int) gribGetLong(gh, "month") - 1;   //months are zero based in struct tm and one based in GRIBy
+  struct tm date;
+  date.tm_mon = (int)gribGetLong(gh, "month") - 1;   //months are zero based in struct tm and one based in GRIB
+  date.tm_mday = (int)gribGetLong(gh, "day");
+  date.tm_hour = (int)gribGetLong(gh, "hour");
+  date.tm_min = (int)gribGetLong(gh, "minute");
 
-    date.tm_mday = (int)gribGetLong(gh, "day");
-    date.tm_hour = (int)gribGetLong(gh, "hour");
-    date.tm_min = (int)gribGetLong(gh, "minute");
-#else
-  struct tm date = {
-    .tm_mon = (int)gribGetLong(gh, "month") - 1,   //months are zero based in struct tm and one based in GRIBy
-    .tm_mday = (int)gribGetLong(gh, "day"),
-    .tm_hour = (int)gribGetLong(gh, "hour"),
-    .tm_min = (int)gribGetLong(gh, "minute")
-  };
-#endif
   if(gribEditionNumber(gh) == 1)
     {
       date.tm_year = (int)gribGetLong(gh, "yearOfCentury");  //years are -1900 based both in struct tm and GRIB1
@@ -23637,23 +23366,27 @@ char* gribMakeTimeString(grib_handle* gh, bool getEndTime)
       date.tm_year = (int)gribGetLong(gh, "year") - 1900;   //years are -1900 based in struct tm and zero based in GRIB2
       date.tm_sec = (int)gribGetLong(gh, "second");
 
-      //Determine whether we have a forecast time and a time range.
-      bool haveForecastTime, haveTimeRange;
-      if(getAvailabilityOfRelativeTimes(gh, &haveForecastTime, &haveTimeRange)) return NULL;
-      if(getEndTime && !haveTimeRange) return NULL;     //tell the caller that the requested time does not exist
-
-      //If we have relative times, apply them to the date
-      if(haveForecastTime)
+      //If the start or end time are requested, we need to take the relative times into account.
+      if(timeType != kCdiTimeType_referenceTime)
         {
-          long offset = gribGetLongDefault(gh, "forecastTime", 0);  //if(stepUnits == indicatorOfUnitOfTimeRange) assert(startStep == forecastTime)
-          long offsetUnit = gribGetLongDefault(gh, "indicatorOfUnitOfTimeRange", 255);
-          if(addToDate(&date, offset, offsetUnit)) return NULL;
-          if(getEndTime)
+          //Determine whether we have a forecast time and a time range.
+          bool haveForecastTime, haveTimeRange;
+          if(getAvailabilityOfRelativeTimes(gh, &haveForecastTime, &haveTimeRange)) return NULL;
+          if(timeType == kCdiTimeType_endTime && !haveTimeRange) return NULL;     //tell the caller that the requested time does not exist
+
+          //If we have relative times, apply the relative times to the date
+          if(haveForecastTime)
             {
-              assert(haveTimeRange);
-              long range = gribGetLongDefault(gh, "lengthOfTimeRange", 0);       //if(stepUnits == indicatorOfUnitForTimeRange) assert(endStep == startStep + lengthOfTimeRange)
-              long rangeUnit = gribGetLongDefault(gh, "indicatorOfUnitForTimeRange", 255);
-              if(addToDate(&date, range, rangeUnit)) return NULL;
+              long offset = gribGetLongDefault(gh, "forecastTime", 0);  //if(stepUnits == indicatorOfUnitOfTimeRange) assert(startStep == forecastTime)
+              long offsetUnit = gribGetLongDefault(gh, "indicatorOfUnitOfTimeRange", 255);
+              if(addToDate(&date, offset, offsetUnit)) return NULL;
+              if(timeType == kCdiTimeType_endTime)
+                {
+                  assert(haveTimeRange);
+                  long range = gribGetLongDefault(gh, "lengthOfTimeRange", 0);       //if(stepUnits == indicatorOfUnitForTimeRange) assert(endStep == startStep + lengthOfTimeRange)
+                  long rangeUnit = gribGetLongDefault(gh, "indicatorOfUnitForTimeRange", 255);
+                  if(addToDate(&date, range, rangeUnit)) return NULL;
+                }
             }
         }
     }
@@ -23784,7 +23517,8 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
       ISEC4_NumValues = ISEC2_NumLon*ISEC2_NumLat;
     }
   */
-  memset(grid, 0, sizeof(grid_t));
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, 0);
 
   size_t datasize;
   FAIL_ON_GRIB_ERROR(grib_get_size, gh, "values", &datasize);
@@ -24104,6 +23838,46 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
  * require-trailing-newline: t
  * End:
  */
+#ifndef CDI_UUID_H
+#define CDI_UUID_H
+
+#if defined (HAVE_CONFIG_H)
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline int cdiUUIDIsNull(const unsigned char uuid[])
+{
+  int isNull = 1;
+  for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
+    isNull &= (uuid[i] == 0);
+  return isNull;
+}
+
+void cdiCreateUUID(unsigned char uuid[CDI_UUID_SIZE]);
+
+void cdiUUID2Str(const unsigned char uuid[], char uuidstr[]);
+int cdiStr2UUID(const char *uuidstr, unsigned char uuid[]);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif
+
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
 #ifndef RESOURCE_UNPACK_H
 #define RESOURCE_UNPACK_H
 
@@ -24252,7 +24026,10 @@ var_t;
 
 typedef struct
 {
-  int         locked;
+  //set when a vlist is passed to streamDefVlist() to safeguard against modifications of the wrong vlist object
+  bool    immutable;
+  //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         ngrids;
@@ -24274,15 +24051,15 @@ vlist_t;
 
 
 vlist_t *vlist_to_pointer(int vlistID);
+void cdiVlistMakeInternal(int vlistID);
+void cdiVlistMakeImmutable(int vlistID);
 void vlistCheckVarID(const char *caller, int vlistID, int varID);
-const char *vlistInqVarNamePtr(int vlistID, int varID);
-const char *vlistInqVarLongnamePtr(int vlistID, int varID);
 const char *vlistInqVarStdnamePtr(int vlistID, int varID);
-const char *vlistInqVarUnitsPtr(int vlistID, int varID);
 void     vlistDestroyVarName(int vlistID, int varID);
 void     vlistDestroyVarLongname(int vlistID, int varID);
 void     vlistDestroyVarStdname(int vlistID, int varID);
 void     vlistDestroyVarUnits(int vlistID, int varID);
+void     cdiVlistDestroy_(int vlistID);
 void     vlistDefVarTsteptype(int vlistID, int varID, int tsteptype);
 int      vlistInqVarMissvalUsed(int vlistID, int varID);
 int      vlistHasTime(int vlistID);
@@ -24303,9 +24080,6 @@ void vlistInqVarDimorder(int vlistID, int varID, int (*outDimorder)[3]);
 
 int vlist_att_compare(vlist_t *a, int varIDA, vlist_t *b, int varIDB, int attnum);
 
-void vlist_lock(int vlistID);
-void vlist_unlock(int vlistID);
-
 void resize_opt_grib_entries(var_t *var, int nentries);
 
 
@@ -24384,6 +24158,7 @@ resOps vlistOps;
 #if defined (HAVE_CONFIG_H)
 #endif
 
+#include <assert.h>
 #include <string.h>
 #include <float.h>  /* FLT_EPSILON */
 #include <limits.h> /* INT_MAX     */
@@ -24413,6 +24188,23 @@ static const char Grids[][17] = {
   /* 15 */  "projection",
 };
 
+/* must match table below */
+enum xystdname_idx {
+  grid_xystdname_grid_latlon,
+  grid_xystdname_latlon,
+  grid_xystdname_projection,
+};
+static const char xystdname_tab[][2][24] = {
+  [grid_xystdname_grid_latlon] = { "grid_longitude",
+                                   "grid_latitude" },
+  [grid_xystdname_latlon] = { "longitude",
+                              "latitude" },
+  [grid_xystdname_projection] = { "projection_x_coordinate",
+                                  "projection_y_coordinate" },
+
+};
+
+
 
 static int    gridCompareP    ( void * gridptr1, void * gridptr2 );
 static void   gridDestroyP    ( void * gridptr );
@@ -24433,7 +24225,13 @@ static const resOps gridOps = {
 
 static int  GRID_Debug = 0;   /* If set to 1, debugging */
 
+grid_t *gridID2Ptr(int gridID)
+{
+  return (grid_t *)reshGetVal(gridID, &gridOps);
+}
 #define gridID2Ptr(gridID) (grid_t *)reshGetVal(gridID, &gridOps)
+#define gridMark4Update(gridID) reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE)
+
 
 void grid_init(grid_t *gridptr)
 {
@@ -24496,7 +24294,6 @@ void grid_init(grid_t *gridptr)
   gridptr->xpole        = 0.0;
   gridptr->ypole        = 0.0;
   gridptr->angle        = 0.0;
-  gridptr->locked       = FALSE;
   gridptr->lcomplex     = 0;
   gridptr->hasdims      = TRUE;
   gridptr->xname[0]     = 0;
@@ -24505,26 +24302,30 @@ void grid_init(grid_t *gridptr)
   gridptr->ylongname[0] = 0;
   gridptr->xunits[0]    = 0;
   gridptr->yunits[0]    = 0;
-  gridptr->xstdname[0]  = 0;
-  gridptr->ystdname[0]  = 0;
+  gridptr->xstdname  = NULL;
+  gridptr->ystdname  = NULL;
   memset(gridptr->uuid, 0, CDI_UUID_SIZE);
   gridptr->name         = NULL;
+  gridptr->vtable       = &cdiGridVtable;
+  gridptr->extraData    = NULL;
 }
 
 
-void grid_free(grid_t *gridptr)
+static void
+grid_free_components(grid_t *gridptr)
 {
-  if ( gridptr->mask      ) Free(gridptr->mask);
-  if ( gridptr->mask_gme  ) Free(gridptr->mask_gme);
-  if ( gridptr->xvals     ) Free(gridptr->xvals);
-  if ( gridptr->yvals     ) Free(gridptr->yvals);
-  if ( gridptr->area      ) Free(gridptr->area);
-  if ( gridptr->xbounds   ) Free(gridptr->xbounds);
-  if ( gridptr->ybounds   ) Free(gridptr->ybounds);
-  if ( gridptr->rowlon    ) Free(gridptr->rowlon);
-  if ( gridptr->reference ) Free(gridptr->reference);
-  if ( gridptr->name      ) Free(gridptr->name);
+  void *p2free[] = { gridptr->mask, gridptr->mask_gme,
+                   gridptr->xvals, gridptr->yvals,
+                   gridptr->xbounds, gridptr->ybounds,
+                   gridptr->rowlon, gridptr->area,
+                   gridptr->reference, gridptr->name };
+  for (size_t i = 0; i < sizeof (p2free) / sizeof (p2free[0]); ++i)
+    if (p2free[i]) Free(p2free[i]);
+}
 
+void grid_free(grid_t *gridptr)
+{
+  grid_free_components(gridptr);
   grid_init(gridptr);
 }
 
@@ -24557,14 +24358,23 @@ void gridInit (void)
   if ( env ) GRID_Debug = atoi(env);
 }
 
-static
-void grid_copy(grid_t *gridptr2, grid_t *gridptr1)
+static void
+grid_copy_base_scalar_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
 {
-  int gridID2;
+  memcpy(gridptrDup, gridptrOrig, sizeof(grid_t));
+  gridptrDup->self = CDI_UNDEFID;
+  if (gridptrOrig->reference)
+    gridptrDup->reference = strdupx(gridptrOrig->reference);
+}
 
-  gridID2 = gridptr2->self;
-  memcpy(gridptr2, gridptr1, sizeof(grid_t));
-  gridptr2->self = gridID2;
+
+static grid_t *
+grid_copy_base(grid_t *gridptrOrig)
+{
+  grid_t *gridptrDup = (grid_t *)Malloc(sizeof (*gridptrDup));
+  gridptrOrig->vtable->copyScalarFields(gridptrOrig, gridptrDup);
+  gridptrOrig->vtable->copyArrayFields(gridptrOrig, gridptrDup);
+  return gridptrDup;
 }
 
 unsigned cdiGridCount(void)
@@ -24572,8 +24382,145 @@ unsigned cdiGridCount(void)
   return reshCountType(&gridOps);
 }
 
+static inline void
+gridSetXname(grid_t *gridptr, const char *xname)
+{
+  strncpy(gridptr->xname, xname, CDI_MAX_NAME);
+  gridptr->xname[CDI_MAX_NAME - 1] = 0;
+}
+
+static inline void
+gridSetXlongname(grid_t *gridptr, const char *xlongname)
+{
+  strncpy(gridptr->xlongname, xlongname, CDI_MAX_NAME);
+  gridptr->xlongname[CDI_MAX_NAME - 1] = 0;
+}
+
+static inline void
+gridSetXunits(grid_t *gridptr, const char *xunits)
+{
+  strncpy(gridptr->xunits, xunits, CDI_MAX_NAME);
+  gridptr->xunits[CDI_MAX_NAME - 1] = 0;
+}
+
+static inline void
+gridSetYname(grid_t *gridptr, const char *yname)
+{
+  strncpy(gridptr->yname, yname, CDI_MAX_NAME);
+  gridptr->yname[CDI_MAX_NAME - 1] = 0;
+}
+
+static inline void
+gridSetYlongname(grid_t *gridptr, const char *ylongname)
+{
+  strncpy(gridptr->ylongname, ylongname, CDI_MAX_NAME);
+  gridptr->ylongname[CDI_MAX_NAME - 1] = 0;
+}
+
+static inline void
+gridSetYunits(grid_t *gridptr, const char *yunits)
+{
+  strncpy(gridptr->yunits, yunits, CDI_MAX_NAME);
+  gridptr->yunits[CDI_MAX_NAME - 1] = 0;
+}
+
+void
+cdiGridTypeInit(grid_t *gridptr, int gridtype, int size)
+{
+
+  gridptr->type = gridtype;
+  gridptr->size = size;
+
+  switch (gridtype)
+    {
+    case GRID_CURVILINEAR:
+      gridptr->nvertex = 4;
+      /* Fall through */
+    case GRID_LONLAT:
+    case GRID_GAUSSIAN:
+    case GRID_GAUSSIAN_REDUCED:
+    case GRID_TRAJECTORY:
+      {
+        if ( gridtype == GRID_TRAJECTORY )
+          {
+            gridSetXname(gridptr, "tlon");
+            gridSetYname(gridptr, "tlat");
+          }
+        else
+          {
+            gridSetXname(gridptr, "lon");
+            gridSetYname(gridptr, "lat");
+          }
+        gridSetXlongname(gridptr, "longitude");
+        gridSetYlongname(gridptr, "latitude");
+
+        /*
+        if ( gridtype == GRID_CURVILINEAR )
+          {
+            gridptr->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
+            gridptr->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
+            gridDefXunits(gridID, "degrees");
+            gridDefYunits(gridID, "degrees");
+          }
+        else
+        */
+          {
+            gridptr->xstdname = xystdname_tab[grid_xystdname_latlon][0];
+            gridptr->ystdname = xystdname_tab[grid_xystdname_latlon][1];
+            gridSetXunits(gridptr, "degrees_east");
+            gridSetYunits(gridptr, "degrees_north");
+          }
+
+        break;
+      }
+    case GRID_UNSTRUCTURED:
+      gridptr->xsize = size;
+      /* Fall through */
+    case GRID_GME:
+      {
+        gridSetXname(gridptr, "lon");
+        gridSetYname(gridptr, "lat");
+        gridptr->xstdname = xystdname_tab[grid_xystdname_latlon][0];
+        gridptr->ystdname = xystdname_tab[grid_xystdname_latlon][1];
+        gridSetXunits(gridptr, "degrees_east");
+        gridSetYunits(gridptr, "degrees_north");
+        break;
+      }
+    case GRID_GENERIC:
+      {
+
+        /* gridptr->xsize = size; */
+        gridSetXname(gridptr, "x");
+        gridSetYname(gridptr, "y");
+        /*
+        strcpy(gridptr->xstdname, "grid_longitude");
+        strcpy(gridptr->ystdname, "grid_latitude");
+        gridptr->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
+        gridptr->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
+        gridDefXunits(gridID, "degrees");
+        gridDefYunits(gridID, "degrees");
+        */
+        break;
+      }
+    case GRID_LCC2:
+    case GRID_SINUSOIDAL:
+    case GRID_LAEA:
+      {
+        gridSetXname(gridptr, "x");
+        gridSetYname(gridptr, "y");
+        gridptr->xstdname = xystdname_tab[grid_xystdname_projection][0];
+        gridptr->ystdname = xystdname_tab[grid_xystdname_projection][1];
+        gridSetXunits(gridptr, "m");
+        gridSetYunits(gridptr, "m");
+        break;
+      }
+    }
+
+}
+
+
 // used also in CDO
-void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *xvals)
+void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *restrict xvals)
 {
   if ( (! (fabs(xinc) > 0)) && xsize > 1 )
     {
@@ -24593,7 +24540,7 @@ void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *x
 }
 
 static
-void calc_gaussgrid(double *yvals, int ysize, double yfirst, double ylast)
+void calc_gaussgrid(double *restrict yvals, int ysize, double yfirst, double ylast)
 {
   double *restrict yw = (double *) Malloc((size_t)ysize * sizeof(double));
   gaussaw(yvals, yw, (size_t)ysize);
@@ -24614,7 +24561,7 @@ void calc_gaussgrid(double *yvals, int ysize, double yfirst, double ylast)
 }
 
 // used also in CDO
-void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *yvals)
+void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
 {
   const double deleps = 0.002;
 
@@ -24629,7 +24576,7 @@ void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double y
 	      {
 		double *restrict ytmp = NULL;
 		int nstart, lfound = 0;
-		int ny = (int) (180./fabs(ylast-yfirst)/(ysize-1) + 0.5);
+		int ny = (int) (180./(fabs(ylast-yfirst)/(ysize-1)) + 0.5);
 		ny -= ny%2;
 		if ( ny > ysize && ny < 4096 )
 		  {
@@ -24758,89 +24705,7 @@ int gridCreate(int gridtype, int size)
 
   if ( CDI_Debug ) Message("gridID: %d", gridID);
 
-  gridptr->type = gridtype;
-  gridptr->size = size;
-
-  /*  if ( gridtype == GRID_GENERIC )     gridptr->xsize = size; */
-  if ( gridtype == GRID_UNSTRUCTURED )  gridptr->xsize = size;
-  if ( gridtype == GRID_CURVILINEAR  )  gridptr->nvertex = 4;
-
-  switch (gridtype)
-    {
-    case GRID_LONLAT:
-    case GRID_GAUSSIAN:
-    case GRID_GAUSSIAN_REDUCED:
-    case GRID_CURVILINEAR:
-    case GRID_TRAJECTORY:
-      {
-        if ( gridtype == GRID_TRAJECTORY )
-          {
-            gridDefXname(gridID, "tlon");
-            gridDefYname(gridID, "tlat");
-          }
-        else
-          {
-            gridDefXname(gridID, "lon");
-            gridDefYname(gridID, "lat");
-          }
-        gridDefXlongname(gridID, "longitude");
-        gridDefYlongname(gridID, "latitude");
-
-        /*
-        if ( gridtype == GRID_CURVILINEAR )
-          {
-            strcpy(gridptr->xstdname, "grid_longitude");
-            strcpy(gridptr->ystdname, "grid_latitude");
-            gridDefXunits(gridID, "degrees");
-            gridDefYunits(gridID, "degrees");
-          }
-        else
-        */
-          {
-            strcpy(gridptr->xstdname, "longitude");
-            strcpy(gridptr->ystdname, "latitude");
-            gridDefXunits(gridID, "degrees_east");
-            gridDefYunits(gridID, "degrees_north");
-          }
-
-        break;
-      }
-    case GRID_GME:
-    case GRID_UNSTRUCTURED:
-      {
-        gridDefXname(gridID, "lon");
-        gridDefYname(gridID, "lat");
-        strcpy(gridptr->xstdname, "longitude");
-        strcpy(gridptr->ystdname, "latitude");
-        gridDefXunits(gridID, "degrees_east");
-        gridDefYunits(gridID, "degrees_north");
-        break;
-      }
-    case GRID_GENERIC:
-      {
-        gridDefXname(gridID, "x");
-        gridDefYname(gridID, "y");
-        /*
-        strcpy(gridptr->xstdname, "grid_longitude");
-        strcpy(gridptr->ystdname, "grid_latitude");
-        gridDefXunits(gridID, "degrees");
-        gridDefYunits(gridID, "degrees");
-        */
-        break;
-      }
-    case GRID_LCC2:
-    case GRID_SINUSOIDAL:
-    case GRID_LAEA:
-      {
-        gridDefXname(gridID, "x");
-        gridDefYname(gridID, "y");
-        strcpy(gridptr->xstdname, "projection_x_coordinate");
-        strcpy(gridptr->ystdname, "projection_y_coordinate");
-        gridDefXunits(gridID, "m");
-        gridDefYunits(gridID, "m");
-        break;
-      }
-    }
+  cdiGridTypeInit(gridptr, gridtype, size);
 
   return (gridID);
 }
@@ -24854,16 +24719,7 @@ void gridDestroyKernel( grid_t * gridptr )
 
   id = gridptr->self;
 
-  if ( gridptr->mask      ) Free(gridptr->mask);
-  if ( gridptr->mask_gme  ) Free(gridptr->mask_gme);
-  if ( gridptr->xvals     ) Free(gridptr->xvals);
-  if ( gridptr->yvals     ) Free(gridptr->yvals);
-  if ( gridptr->area      ) Free(gridptr->area);
-  if ( gridptr->xbounds   ) Free(gridptr->xbounds);
-  if ( gridptr->ybounds   ) Free(gridptr->ybounds);
-  if ( gridptr->rowlon    ) Free(gridptr->rowlon);
-  if ( gridptr->reference ) Free(gridptr->reference);
-
+  grid_free_components(gridptr);
   Free( gridptr );
 
   reshRemove ( id, &gridOps );
@@ -24882,13 +24738,12 @@ void gridDestroyKernel( grid_t * gridptr )
 void gridDestroy(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  gridDestroyKernel ( gridptr );
+  gridptr->vtable->destroy(gridptr);
 }
 
 void gridDestroyP ( void * gridptr )
 {
-  gridDestroyKernel (( grid_t * ) gridptr );
+  ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
 }
 
 
@@ -24923,16 +24778,15 @@ The function @func{gridDefXname} defines the name of a X-axis.
 */
 void gridDefXname(int gridID, const char *xname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( xname )
+  if ( xname && *xname )
     {
-      strncpy(gridptr->xname, xname, CDI_MAX_NAME);
-      gridptr->xname[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetXname(gridptr, xname);
+      gridMark4Update(gridID);
     }
 }
 
+
 /*
 @Function  gridDefXlongname
 @Title     Define the longname of a X-axis
@@ -24949,12 +24803,11 @@ The function @func{gridDefXlongname} defines the longname of a X-axis.
 */
 void gridDefXlongname(int gridID, const char *xlongname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
   if ( xlongname )
     {
-      strncpy(gridptr->xlongname, xlongname, CDI_MAX_NAME);
-      gridptr->xlongname[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetXlongname(gridptr, xlongname);
+      gridMark4Update(gridID);
     }
 }
 
@@ -24974,13 +24827,11 @@ The function @func{gridDefXunits} defines the units of a X-axis.
 */
 void gridDefXunits(int gridID, const char *xunits)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
   if ( xunits )
     {
-      strncpy(gridptr->xunits, xunits, CDI_MAX_NAME);
-      gridptr->xunits[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetXunits(gridptr, xunits);
+      gridMark4Update(gridID);
     }
 }
 
@@ -25000,13 +24851,11 @@ The function @func{gridDefYname} defines the name of a Y-axis.
 */
 void gridDefYname(int gridID, const char *yname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( yname )
+  if ( yname && *yname )
     {
-      strncpy(gridptr->yname, yname, CDI_MAX_NAME);
-      gridptr->yname[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetYname(gridptr, yname);
+      gridMark4Update(gridID);
     }
 }
 
@@ -25026,13 +24875,11 @@ The function @func{gridDefYlongname} defines the longname of a Y-axis.
 */
 void gridDefYlongname(int gridID, const char *ylongname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
   if ( ylongname )
     {
-      strncpy(gridptr->ylongname, ylongname, CDI_MAX_NAME);
-      gridptr->ylongname[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetYlongname(gridptr, ylongname);
+      gridMark4Update(gridID);
     }
 }
 
@@ -25052,13 +24899,11 @@ The function @func{gridDefYunits} defines the units of a Y-axis.
 */
 void gridDefYunits(int gridID, const char *yunits)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
   if ( yunits )
     {
-      strncpy(gridptr->yunits, yunits, CDI_MAX_NAME);
-      gridptr->yunits[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetYunits(gridptr, yunits);
+      gridMark4Update(gridID);
     }
 }
 
@@ -25144,8 +24989,10 @@ void gridInqXunits(int gridID, char *xunits)
 void gridInqXstdname(int gridID, char *xstdname)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  strcpy(xstdname, gridptr->xstdname);
+  if ( gridptr->xstdname )
+    strcpy(xstdname, gridptr->xstdname);
+  else
+    xstdname[0] = 0;
 }
 
 /*
@@ -25229,8 +25076,10 @@ void gridInqYunits(int gridID, char *yunits)
 void gridInqYstdname(int gridID, char *ystdname)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  strcpy(ystdname, gridptr->ystdname);
+  if ( gridptr->ystdname )
+    strcpy(ystdname, gridptr->ystdname);
+  else
+    ystdname[0] = 0;
 }
 
 /*
@@ -25291,7 +25140,7 @@ int gridInqSize(int gridID)
       ysize = gridptr->ysize;
 
       if ( ysize )
-        size = xsize *ysize;
+        size = xsize * ysize;
       else
         size = xsize;
 
@@ -25339,7 +25188,7 @@ void gridDefTrunc(int gridID, int trunc)
 
   if (gridptr->trunc != trunc)
     {
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
       gridptr->trunc = trunc;
     }
 }
@@ -25366,16 +25215,17 @@ void gridDefXsize(int gridID, int xsize)
   if ( xsize > gridSize )
     Error("xsize %d is greater then gridsize %d", xsize, gridSize);
 
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED && xsize != gridSize )
+  int gridType = gridInqType(gridID);
+  if ( gridType == GRID_UNSTRUCTURED && xsize != gridSize )
     Error("xsize %d must be equal to gridsize %d for gridtype: UNSTRUCTURED", xsize, gridSize);
 
   if (gridptr->xsize != xsize)
     {
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
       gridptr->xsize = xsize;
     }
 
-  if ( gridInqType(gridID) != GRID_UNSTRUCTURED )
+  if ( gridType != GRID_UNSTRUCTURED )
     {
       long axisproduct = gridptr->xsize*gridptr->ysize;
       if ( axisproduct > 0 && axisproduct != gridSize )
@@ -25400,7 +25250,7 @@ void gridDefPrec(int gridID, int prec)
 
   if (gridptr->prec != prec)
     {
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
       gridptr->prec = prec;
     }
 }
@@ -25473,7 +25323,7 @@ void gridDefYsize(int gridID, int ysize)
 
   if (gridptr->ysize != ysize)
     {
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
       gridptr->ysize = ysize;
     }
 
@@ -25530,7 +25380,7 @@ void gridDefNP(int gridID, int np)
 
   if (gridptr->np != np)
     {
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
       gridptr->np = np;
     }
 }
@@ -25576,7 +25426,7 @@ void gridDefRowlon(int gridID, int nrowlon, const int rowlon[])
   gridptr->rowlon = (int *) Malloc((size_t)nrowlon * sizeof(int));
   gridptr->nrowlon = nrowlon;
   memcpy(gridptr->rowlon, rowlon, (size_t)nrowlon * sizeof(int));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+  gridMark4Update(gridID);
 }
 
 /*
@@ -25598,34 +25448,48 @@ void gridInqRowlon(int gridID, int *rowlon)
   memcpy(rowlon, gridptr->rowlon, (size_t)gridptr->nrowlon * sizeof(int));
 }
 
-
-int gridInqMask(int gridID, int *mask)
+static int
+gridInqMaskSerialGeneric(grid_t *gridptr, mask_t **internalMask,
+                        int *restrict mask)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
   long size = gridptr->size;
 
   if ( CDI_Debug && size == 0 )
-    Warning("Size undefined for gridID = %d", gridID);
-
-  if (mask && gridptr->mask)
-    for (long i = 0; i < size; ++i)
-      mask[i] = (int)gridptr->mask[i];
+    Warning("Size undefined for gridID = %d", gridptr->self);
 
-  if ( gridptr->mask == NULL ) size = 0;
+  const mask_t *restrict mask_src = *internalMask;
+  if (mask_src)
+    {
+      if (mask && size > 0)
+        for (size_t i = 0; i < (size_t)size; ++i)
+          mask[i] = (int)mask_src[i];
+    }
+  else
+    size = 0;
 
   return (int)size;
 }
 
+static int
+gridInqMaskSerial(grid_t *gridptr, int *mask)
+{
+  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask, mask);
+}
+
 
-void gridDefMask(int gridID, const int *mask)
+int gridInqMask(int gridID, int *mask)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqMask(gridptr, mask);
+}
 
+static void
+gridDefMaskSerial(grid_t *gridptr, const int *mask)
+{
   long size = gridptr->size;
 
   if ( size == 0 )
-    Error("Size undefined for gridID = %d", gridID);
+    Error("Size undefined for gridID = %d", gridptr->self);
 
   if ( mask == NULL )
     {
@@ -25647,34 +25511,32 @@ void gridDefMask(int gridID, const int *mask)
     }
 }
 
-
-int gridInqMaskGME(int gridID, int *mask)
+void gridDefMask(int gridID, const int *mask)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  long size = gridptr->size;
-
-  if ( CDI_Debug && size == 0 )
-    Warning("Size undefined for gridID = %d", gridID);
-
-  if ( mask && gridptr->mask_gme )
-    for (long i = 0; i < size; ++i)
-      mask[i] = (int)gridptr->mask_gme[i];
-
-  if ( gridptr->mask_gme == NULL ) size = 0;
-
-  return (int)size;
+  gridptr->vtable->defMask(gridptr, mask);
+  gridMark4Update(gridID);
 }
 
+static int
+gridInqMaskGMESerial(grid_t *gridptr, int *mask_gme)
+{
+  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask_gme, mask_gme);
+}
 
-void gridDefMaskGME(int gridID, const int *mask)
+int gridInqMaskGME(int gridID, int *mask)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqMaskGME(gridptr, mask);
+}
 
+static void
+gridDefMaskGMESerial(grid_t *gridptr, const int *mask)
+{
   long size = gridptr->size;
 
   if ( size == 0 )
-    Error("Size undefined for gridID = %d", gridID);
+    Error("Size undefined for gridID = %d", gridptr->self);
 
   if ( gridptr->mask_gme == NULL )
     gridptr->mask_gme = (mask_t *) Malloc((size_t)size * sizeof (mask_t));
@@ -25685,6 +25547,41 @@ void gridDefMaskGME(int gridID, const int *mask)
     gridptr->mask_gme[i] = (mask_t)(mask[i] != 0);
 }
 
+void gridDefMaskGME(int gridID, const int *mask)
+{
+  grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defMaskGME(gridptr, mask);
+  gridMark4Update(gridID);
+}
+
+
+static int
+gridInqXValsSerial(grid_t *gridptr, double *xvals)
+{
+  long size;
+  if ( gridptr->type == GRID_CURVILINEAR || gridptr->type == GRID_UNSTRUCTURED )
+    size = gridptr->size;
+  else if ( gridptr->type == GRID_GAUSSIAN_REDUCED )
+    size = 2;
+  else
+    size = gridptr->xsize;
+
+  if ( CDI_Debug && size == 0 )
+    Warning("size undefined for gridID = %d", gridptr->self);
+
+  if ( gridptr->xvals )
+    {
+      if ( size && xvals )
+        {
+          const double *gridptr_xvals = gridptr->vtable->inqXValsPtr(gridptr);
+          memcpy(xvals, gridptr_xvals, (size_t)size * sizeof (double));
+        }
+    }
+  else
+    size = 0;
+  return (int)size;
+}
+
 /*
 @Function  gridInqXvals
 @Title     Get all values of a X-axis
@@ -25708,24 +25605,31 @@ Otherwise, 0 is returned and @func{xvals} is empty.
 int gridInqXvals(int gridID, double *xvals)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqXVals(gridptr, xvals);
+}
+
+
+static void
+gridDefXValsSerial(grid_t *gridptr, const double *xvals)
+{
+  int gridtype = gridptr->type;
 
   long size;
-  if ( gridptr->type == GRID_CURVILINEAR || gridptr->type == GRID_UNSTRUCTURED )
+  if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
     size = gridptr->size;
-  else if ( gridptr->type == GRID_GAUSSIAN_REDUCED )
+  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
     size = 2;
   else
     size = gridptr->xsize;
 
-  if ( CDI_Debug && size == 0 )
-    Warning("size undefined for gridID = %d", gridID);
-
-  if ( size && xvals && gridptr->xvals )
-    memcpy(xvals, gridptr->xvals, (size_t)size * sizeof (double));
-
-  if ( gridptr->xvals == NULL ) size = 0;
+  if ( size == 0 )
+    Error("Size undefined for gridID = %d", gridptr->self);
 
-  return (int)size;
+  if (gridptr->xvals && CDI_Debug)
+    Warning("values already defined!");
+  gridptr->xvals = (double *)Realloc(gridptr->xvals,
+                                      (size_t)size * sizeof(double));
+  memcpy(gridptr->xvals, xvals, (size_t)size * sizeof (double));
 }
 
 /*
@@ -25745,26 +25649,33 @@ The function @func{gridDefXvals} defines all values of the X-axis.
 void gridDefXvals(int gridID, const double *xvals)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defXVals(gridptr, xvals);
+  gridMark4Update(gridID);
+}
+
+static int
+gridInqYValsSerial(grid_t *gridptr, double *yvals)
+{
   int gridtype = gridptr->type;
+  long size
+    = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
+    ? gridptr->size : gridptr->ysize;
 
-  long size;
+  if ( CDI_Debug && size == 0 )
+    Warning("size undefined for gridID = %d!", gridptr->self);
 
-  if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
-    size = gridptr->size;
-  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
-    size = 2;
+  if ( gridptr->yvals )
+    {
+      if ( size && yvals )
+        {
+          const double *gridptr_yvals = gridptr->vtable->inqYValsPtr(gridptr);
+          memcpy(yvals, gridptr_yvals, (size_t)size * sizeof (double));
+        }
+    }
   else
-    size = gridptr->xsize;
+    size = 0;
 
-  if ( size == 0 )
-    Error("Size undefined for gridID = %d", gridID);
-
-  if (gridptr->xvals && CDI_Debug)
-    Warning("values already defined!");
-  gridptr->xvals = (double *) Realloc(gridptr->xvals,
-                                      (size_t)size * sizeof(double));
-  memcpy(gridptr->xvals, xvals, (size_t)size * sizeof (double));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+  return (int)size;
 }
 
 /*
@@ -25790,23 +25701,28 @@ Otherwise, 0 is returned and @func{yvals} is empty.
 int gridInqYvals(int gridID, double *yvals)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqYVals(gridptr, yvals);
+}
 
+static void
+gridDefYValsSerial(grid_t *gridptr, const double *yvals)
+{
   int gridtype = gridptr->type;
   long size
     = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
     ? gridptr->size : gridptr->ysize;
 
-  if ( CDI_Debug && size == 0 )
-    Warning("size undefined for gridID = %d!", gridID);
-
-  if ( size && yvals && gridptr->yvals )
-    memcpy(yvals, gridptr->yvals, (size_t)size * sizeof (double));
+  if ( size == 0 )
+    Error("Size undefined for gridID = %d!", gridptr->self);
 
-  if ( gridptr->yvals == NULL ) size = 0;
+  if (gridptr->yvals && CDI_Debug)
+    Warning("Values already defined!");
 
-  return (int)size;
+  gridptr->yvals = (double *)Realloc(gridptr->yvals, (size_t)size * sizeof (double));
+  memcpy(gridptr->yvals, yvals, (size_t)size * sizeof (double));
 }
 
+
 /*
 @Function  gridDefYvals
 @Title     Define the values of a Y-axis
@@ -25824,32 +25740,29 @@ The function @func{gridDefYvals} defines all values of the Y-axis.
 void gridDefYvals(int gridID, const double *yvals)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defYVals(gridptr, yvals);
+  gridMark4Update(gridID);
+}
 
-  int gridtype = gridptr->type;
-  long size
-    = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
-    ? gridptr->size : gridptr->ysize;
-
-  if ( size == 0 )
-    Error("Size undefined for gridID = %d!", gridID);
-
-  if (gridptr->yvals && CDI_Debug)
-    Warning("Values already defined!");
-
-  gridptr->yvals = (double *) Realloc(gridptr->yvals, (size_t)size * sizeof (double));
-  memcpy(gridptr->yvals, yvals, (size_t)size * sizeof (double));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+static double
+gridInqXValSerial(grid_t *gridptr, int index)
+{
+  double xval = gridptr->xvals ? gridptr->xvals[index] : 0;
+  return xval;
 }
 
 
 double gridInqXval(int gridID, int index)
 {
-  double xval = 0;
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqXVal(gridptr, index);
+}
 
-  if ( gridptr->xvals ) xval = gridptr->xvals[index];
-
-  return xval;
+static double
+gridInqYValSerial(grid_t *gridptr, int index)
+{
+  double yval = gridptr->yvals ? gridptr->yvals[index] : 0;
+  return yval;
 }
 
 /*
@@ -25864,12 +25777,8 @@ double gridInqXval(int gridID, int index)
 */
 double gridInqYval(int gridID, int index)
 {
-  double yval = 0;
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( gridptr->yvals ) yval = gridptr->yvals[index];
-
-  return yval;
+  return gridptr->vtable->inqYVal(gridptr, index);
 }
 
 /*
@@ -25886,7 +25795,7 @@ double gridInqXinc(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
   double xinc = gridptr->xinc;
-  const double *restrict xvals = gridptr->xvals;
+  const double *restrict xvals = gridptr->vtable->inqXValsPtr(gridptr);
 
   if ( (! (fabs(xinc) > 0)) && xvals )
     {
@@ -25894,7 +25803,7 @@ double gridInqXinc(int gridID)
       if ( xsize > 1 )
         {
           xinc = fabs(xvals[xsize-1] - xvals[0])/(xsize-1);
-          for ( size_t i = 2; i < (size_t)xsize; i++ )
+          for (size_t i = 2; i < (size_t)xsize; i++ )
             if ( fabs(fabs(xvals[i-1] - xvals[i]) - xinc) > 0.01*xinc )
               {
                 xinc = 0;
@@ -25922,7 +25831,7 @@ double gridInqYinc(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
   double yinc = gridptr->yinc;
-  const double *yvals = gridptr->yvals;
+  const double *yvals = gridptr->vtable->inqYValsPtr(gridptr);
 
   if ( (! (fabs(yinc) > 0)) && yvals )
     {
@@ -25931,8 +25840,8 @@ double gridInqYinc(int gridID)
         {
           yinc = yvals[1] - yvals[0];
           double abs_yinc = fabs(yinc);
-          for ( size_t i = 2; i < (size_t)ysize; i++ )
-            if ( fabs(fabs(yvals[i] - yvals[i-1]) - abs_yinc) > (0.01*abs_yinc))
+          for (size_t i = 2; i < (size_t)ysize; i++ )
+            if ( fabs(fabs(yvals[i] - yvals[i-1]) - abs_yinc) > (0.01*abs_yinc) )
               {
                 yinc = 0;
                 break;
@@ -25978,14 +25887,14 @@ void gridDefXpole(int gridID, double xpole)
   // Xpole -> grid_north_pole_longitude
   grid_t *gridptr = gridID2Ptr(gridID);
 
-  if ( memcmp(gridptr->xstdname, "grid", 4) != 0 )
-    strcpy(gridptr->xstdname, "grid_longitude");
+  if ( gridptr->xstdname && memcmp(gridptr->xstdname, "grid", 4) != 0 )
+    gridptr->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
 
   if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->xpole, xpole) )
     {
       gridptr->isRotated = TRUE;
       gridptr->xpole = xpole;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -26022,14 +25931,14 @@ void gridDefYpole(int gridID, double ypole)
   // Ypole -> grid_north_pole_latitude
   grid_t *gridptr = gridID2Ptr(gridID);
 
-  if ( memcmp(gridptr->ystdname, "grid", 4) != 0 )
-    strcpy(gridptr->ystdname, "grid_latitude");
+  if ( gridptr->ystdname && memcmp(gridptr->ystdname, "grid", 4) != 0 )
+    gridptr->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
 
   if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->ypole, ypole) )
     {
       gridptr->isRotated = TRUE;
       gridptr->ypole = ypole;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -26070,7 +25979,7 @@ void gridDefAngle(int gridID, double angle)
     {
       gridptr->isRotated = TRUE;
       gridptr->angle = angle;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -26108,7 +26017,7 @@ void gridDefGMEnd(int gridID, int nd)
   if (gridptr->nd != nd)
     {
       gridptr->nd = nd;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -26146,7 +26055,7 @@ void gridDefGMEni(int gridID, int ni)
   if (gridptr->ni != ni)
     {
       gridptr->ni = ni;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -26184,7 +26093,7 @@ void gridDefGMEni2(int gridID, int ni2)
   if (gridptr->ni2 != ni2)
     {
       gridptr->ni2 = ni2;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -26212,7 +26121,7 @@ void gridDefGMEni3(int gridID, int ni3)
   if (gridptr->ni3 != ni3)
     {
       gridptr->ni3 = ni3;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -26236,7 +26145,7 @@ void gridChangeType(int gridID, int gridtype)
   if (gridptr->type != gridtype)
     {
       gridptr->type = gridtype;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -26244,18 +26153,20 @@ static
 void grid_check_cyclic(grid_t *gridptr)
 {
   gridptr->isCyclic = FALSE;
-
-  int xsize = gridptr->xsize,
-    ysize = gridptr->ysize;
-  const double *xvals = gridptr->xvals,
-    *xbounds = gridptr->xbounds;
+  enum { numVertices = 4 };
+  size_t xsize = gridptr->xsize >= 0 ? (size_t)gridptr->xsize : 0,
+    ysize = gridptr->ysize >= 0 ? (size_t)gridptr->ysize : 0;
+  const double *xvals = gridptr->vtable->inqXValsPtr(gridptr),
+    (*xbounds)[numVertices]
+    = (const double (*)[numVertices])gridptr->vtable->inqXBoundsPtr(gridptr);
 
   if ( gridptr->type == GRID_GAUSSIAN || gridptr->type == GRID_LONLAT )
     {
       if ( xvals && xsize > 1 )
         {
           double xinc = xvals[1] - xvals[0];
-          if ( IS_EQUAL(xinc, 0) ) xinc = (xvals[xsize-1] - xvals[0])/(xsize-1);
+          if ( IS_EQUAL(xinc, 0) )
+            xinc = (xvals[xsize-1] - xvals[0])/(double)(xsize-1);
 
           double x0 = 2*xvals[xsize-1]-xvals[xsize-2]-360;
 
@@ -26267,10 +26178,10 @@ void grid_check_cyclic(grid_t *gridptr)
     {
       if ( xvals && xsize > 1 )
         {
-          long nc = 0;
-          for ( int j = 0; j < ysize; ++j )
+          size_t nc = 0;
+          for ( size_t j = 0; j < ysize; ++j )
             {
-              long i1 = j*xsize,
+              size_t i1 = j*xsize,
                 i2 = j*xsize+1,
                 in = j*xsize+(xsize-1);
               double val1 = xvals[i1],
@@ -26289,23 +26200,22 @@ void grid_check_cyclic(grid_t *gridptr)
 
               nc += fabs(x0-val1) < 0.5*xinc;
             }
-          gridptr->isCyclic = nc > 0.5*ysize ? TRUE : FALSE;
+          gridptr->isCyclic = nc > ysize/2 ? TRUE : FALSE;
         }
 
       if ( xbounds && xsize > 1 )
 	{
-          gridptr->isCyclic = TRUE;
-	  for ( int j = 0; j < ysize; ++j )
+          short isCyclic = TRUE;
+	  for ( size_t j = 0; j < ysize; ++j )
 	    {
-	      long i1 = j*xsize*4,
-                i2 = j*xsize*4+(xsize-1)*4;
-	      long nc = 0;
-	      for (unsigned k1 = 0; k1 < 4; ++k1 )
+	      size_t i1 = j*xsize,
+                i2 = j*xsize+(xsize-1);
+	      for (size_t k1 = 0; k1 < numVertices; ++k1 )
 		{
-		  double val1 = xbounds[i1+k1];
-		  for (unsigned k2 = 0; k2 < 4; ++k2 )
+		  double val1 = xbounds[i1][k1];
+		  for (size_t k2 = 0; k2 < numVertices; ++k2 )
 		    {
-		      double val2 = xbounds[i2+k2];
+		      double val2 = xbounds[i2][k2];
 
 		      if ( val1 <    1 && val2 > 300 ) val1 += 360;
 		      if ( val2 <    1 && val1 > 300 ) val2 += 360;
@@ -26314,19 +26224,16 @@ void grid_check_cyclic(grid_t *gridptr)
                       if ( fabs(val2-val1) > 180 ) val1 += 360;
 
 		      if ( fabs(val1-val2) < 0.001 )
-			{
-			  nc++;
-			  break;
-			}
+                        goto foundCloseVertices;
 		    }
 		}
-
-	      if ( nc < 1 )
-		{
-		  gridptr->isCyclic = FALSE;
-		  break;
-		}
+              /* all vertices more than 0.001 degrees apart */
+              isCyclic = FALSE;
+              break;
+              foundCloseVertices:
+              ;
 	    }
+          gridptr->isCyclic = isCyclic;
 	}
     }
 }
@@ -26350,67 +26257,60 @@ int gridIsRotated(int gridID)
 }
 
 static
-int compareXYvals(int gridID, long xsize, long ysize, double *xvals0, double *yvals0)
+int compareXYvals(grid_t *gridRef, grid_t *gridTest)
 {
-  long i;
   int differ = 0;
 
-  if ( !differ && xsize == gridInqXvals(gridID, NULL) )
+  int xsizeTest = gridTest->xsize, ysizeTest = gridTest->ysize;
+  if ( !differ && xsizeTest > 0 && xsizeTest == gridRef->vtable->inqXVals(gridRef, NULL) )
     {
-      double *xvals = (double *) Malloc((size_t)xsize * sizeof (double));
+      const double *restrict xvalsRef = gridRef->vtable->inqXValsPtr(gridRef),
+        *restrict xvalsTest = gridTest->vtable->inqXValsPtr(gridTest);
 
-      gridInqXvals(gridID, xvals);
-
-      for ( i = 0; i < xsize; ++i )
-	if ( fabs(xvals0[i] - xvals[i]) > 1.e-10 )
+      for ( size_t i = 0; i < (size_t)xsizeTest; ++i )
+	if ( fabs(xvalsTest[i] - xvalsRef[i]) > 1.e-10 )
 	  {
 	    differ = 1;
 	    break;
 	  }
-
-      Free(xvals);
     }
 
-  if ( !differ && ysize == gridInqYvals(gridID, NULL) )
+  if ( !differ && ysizeTest > 0 && ysizeTest == gridRef->vtable->inqYVals(gridRef, NULL) )
     {
-      double *yvals = (double *) Malloc((size_t)ysize * sizeof (double));
-
-      gridInqYvals(gridID, yvals);
-
-      for ( i = 0; i < ysize; ++i )
-	if ( fabs(yvals0[i] - yvals[i]) > 1.e-10 )
+      const double *restrict yvalsRef = gridRef->vtable->inqYValsPtr(gridRef),
+        *restrict yvalsTest = gridTest->vtable->inqYValsPtr(gridTest);
+      for ( size_t i = 0; i < (size_t)ysizeTest; ++i )
+	if ( fabs(yvalsTest[i] - yvalsRef[i]) > 1.e-10 )
 	  {
 	    differ = 1;
 	    break;
 	  }
-
-      Free(yvals);
     }
 
   return (differ);
 }
 
 static
-int compareXYvals2(int gridID, int gridsize, double *xvals, double *yvals)
+int compareXYvals2(grid_t *gridRef, grid_t *gridTest)
 {
-  int differ = 0;
+  int gridsize = gridTest->size;
+  int differ
+    = ((gridTest->xvals == NULL) ^ (gridRef->xvals == NULL))
+    || ((gridTest->yvals == NULL) ^ (gridRef->yvals == NULL));
 
-  if ( !differ && ((xvals == NULL && gridInqXvalsPtr(gridID) != NULL) || (xvals != NULL && gridInqXvalsPtr(gridID) == NULL)) ) differ = 1;
-  if ( !differ && ((yvals == NULL && gridInqYvalsPtr(gridID) != NULL) || (yvals != NULL && gridInqYvalsPtr(gridID) == NULL)) ) differ = 1;
+  typedef double (*inqVal)(grid_t *grid, int index);
+  inqVal inqXValRef = gridRef->vtable->inqXVal,
+    inqYValRef = gridRef->vtable->inqXVal,
+    inqXValTest = gridTest->vtable->inqXVal,
+    inqYValTest = gridTest->vtable->inqYVal;
 
-  if ( !differ && xvals && gridInqXvalsPtr(gridID) )
-    {
-      if ( fabs(xvals[0] - gridInqXval(gridID, 0)) > 1.e-9 ||
-	   fabs(xvals[gridsize-1] - gridInqXval(gridID, gridsize-1)) > 1.e-9 )
-	differ = 1;
-    }
+  if ( !differ && gridTest->xvals )
+    differ = fabs(inqXValTest(gridTest, 0) - inqXValRef(gridRef, 0)) > 1.e-9
+      || fabs(inqXValTest(gridTest, gridsize-1) - inqXValRef(gridRef, gridsize-1)) > 1.e-9;
 
-  if ( !differ && yvals && gridInqYvalsPtr(gridID) )
-    {
-      if ( fabs(yvals[0] - gridInqYval(gridID, 0)) > 1.e-9 ||
-	   fabs(yvals[gridsize-1] - gridInqYval(gridID, gridsize-1)) > 1.e-9 )
-	differ = 1;
-    }
+  if ( !differ && gridTest->yvals )
+    differ = fabs(inqYValTest(gridTest, 0) - inqYValRef(gridRef, 0)) > 1.e-9
+      || fabs(inqYValTest(gridTest, gridsize-1) - inqYValRef(gridRef, gridsize-1)) > 1.e-9;
 
   return differ;
 }
@@ -26419,10 +26319,11 @@ int compareXYvals2(int gridID, int gridsize, double *xvals, double *yvals)
 int gridCompare(int gridID, const grid_t *grid)
 {
   int differ = 1;
+  grid_t *gridRef = gridID2Ptr(gridID);
 
-  if ( grid->type == gridInqType(gridID) || grid->type == GRID_GENERIC )
+  if ( grid->type == gridRef->type || grid->type == GRID_GENERIC )
     {
-      if ( grid->size == gridInqSize(gridID) )
+      if ( grid->size == gridRef->size )
 	{
 	  differ = 0;
 	  if ( grid->type == GRID_LONLAT )
@@ -26442,7 +26343,7 @@ int gridCompare(int gridID, const grid_t *grid)
 	      printf("grid.xinc   %f\n", gridInqXinc(gridID));
 	      printf("grid.yinc   %f\n", gridInqYinc(gridID));
 	      */
-	      if ( grid->xsize == gridInqXsize(gridID) && grid->ysize == gridInqYsize(gridID) )
+	      if ( grid->xsize == gridRef->xsize && grid->ysize == grid->ysize )
 		{
 		  if ( grid->xdef == 2 && grid->ydef == 2 )
 		    {
@@ -26456,38 +26357,33 @@ int gridCompare(int gridID, const grid_t *grid)
 			      differ = 1;
 			    }
 			  if ( !differ && fabs(grid->xinc) > 0 &&
-			       fabs(fabs(grid->xinc) - fabs(gridInqXinc(gridID))) > fabs(grid->xinc/1000))
+			       fabs(fabs(grid->xinc) - fabs(gridRef->xinc)) > fabs(grid->xinc/1000))
 			    {
 			      differ = 1;
 			    }
 			  if ( !differ && fabs(grid->yinc) > 0 &&
-			       fabs(fabs(grid->yinc) - fabs(gridInqYinc(gridID))) > fabs(grid->yinc/1000))
+			       fabs(fabs(grid->yinc) - fabs(gridRef->yinc)) > fabs(grid->yinc/1000))
 			    {
 			      differ = 1;
 			    }
 			}
 		    }
-		  else
-		    {
-		      if ( grid->xvals && grid->yvals )
-			differ = compareXYvals(gridID, grid->xsize, grid->ysize, grid->xvals, grid->yvals);
-		    }
+		  else if ( grid->xvals && grid->yvals )
+                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
 		}
 	      else
 		differ = 1;
 	    }
 	  else if ( grid->type == GRID_GENERIC )
 	    {
-	      if ( grid->xsize == gridInqXsize(gridID) && grid->ysize == gridInqYsize(gridID) )
+	      if ( grid->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
 		{
-		  if ( grid->xdef == 1 && grid->ydef == 1 )
-		    {
-		      if ( grid->xvals && grid->yvals )
-			differ = compareXYvals(gridID, grid->xsize, grid->ysize, grid->xvals, grid->yvals);
-		    }
+		  if ( grid->xdef == 1 && grid->ydef == 1
+                       && grid->xvals && grid->yvals )
+                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
 		}
 	      else if ( (grid->ysize == 0 || grid->ysize == 1) &&
-			grid->xsize == gridInqXsize(gridID)*gridInqYsize(gridID) )
+			grid->xsize == gridRef->xsize*gridRef->ysize )
 		{
 		}
 	      else
@@ -26495,7 +26391,7 @@ int gridCompare(int gridID, const grid_t *grid)
 	    }
 	  else if ( grid->type == GRID_GAUSSIAN )
 	    {
-	      if ( grid->xsize == gridInqXsize(gridID) && grid->ysize == gridInqYsize(gridID) )
+	      if ( grid->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
 		{
 		  if ( grid->xdef == 2 && grid->ydef == 2 )
 		    {
@@ -26503,16 +26399,13 @@ int gridCompare(int gridID, const grid_t *grid)
 			   ! (IS_EQUAL(grid->yfirst, 0) && IS_EQUAL(grid->ylast, 0)) )
 			if ( fabs(grid->xfirst - gridInqXval(gridID, 0)) > 0.0015 ||
 			     fabs(grid->yfirst - gridInqYval(gridID, 0)) > 0.0015 ||
-			     (fabs(grid->xinc)>0 && fabs(fabs(grid->xinc) - fabs(gridInqXinc(gridID))) > fabs(grid->xinc/1000)) )
+			     (fabs(grid->xinc)>0 && fabs(fabs(grid->xinc) - fabs(gridRef->xinc)) > fabs(grid->xinc/1000)) )
 			  {
 			    differ = 1;
 			  }
 		    }
-		  else
-		    {
-		      if ( grid->xvals && grid->yvals )
-			differ = compareXYvals(gridID, grid->xsize, grid->ysize, grid->xvals, grid->yvals);
-		    }
+		  else if ( grid->xvals && grid->yvals )
+                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
 		}
 	      else
 		differ = 1;
@@ -26534,31 +26427,36 @@ int gridCompare(int gridID, const grid_t *grid)
 	      printf("grid.nv     %d\n", grid->nvertex);
 	      printf("grid nv     %d\n", gridInqNvertex(gridID));
 	      */
-	      if ( grid->xsize == gridInqXsize(gridID) && grid->ysize == gridInqYsize(gridID) )
-		differ = compareXYvals2(gridID, grid->size, grid->xvals, grid->yvals);
+	      if ( grid->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
+                differ = gridRef->vtable->compareXYAO(gridRef, (grid_t *)grid);
 	    }
 	  else if ( grid->type == GRID_UNSTRUCTURED )
 	    {
-              unsigned char uuidOfHGrid[CDI_UUID_SIZE];
-              gridInqUUID(gridID, uuidOfHGrid);
-
-              if ( !differ && uuidOfHGrid[0] && grid->uuid[0] && memcmp(uuidOfHGrid, grid->uuid, CDI_UUID_SIZE) != 0 ) differ = 1;
+              /* FIXME: not octet 0 but octet 7 is guaranteed  non-zero
+               * for any non-NULL UUID */
+              differ = differ || ( gridRef->uuid[0] && grid->uuid[0] && memcmp(gridRef->uuid, grid->uuid, CDI_UUID_SIZE) != 0 );
 
               if ( !differ &&
-                   ((grid->xvals == NULL && gridInqXvalsPtr(gridID) != NULL) || (grid->xvals != NULL && gridInqXvalsPtr(gridID) == NULL)) &&
-                   ((grid->yvals == NULL && gridInqYvalsPtr(gridID) != NULL) || (grid->yvals != NULL && gridInqYvalsPtr(gridID) == NULL)) )
+                   ((grid->xvals == NULL) ^ (gridRef->xvals == NULL)) &&
+                   ((grid->yvals == NULL) ^ (gridRef->yvals == NULL)) )
                 {
-                  if ( !differ && grid->nvertex && gridInqNvertex(gridID) && grid->nvertex != gridInqNvertex(gridID) ) differ = 1;
-                  if ( !differ && grid->number && gridInqNumber(gridID) && grid->number != gridInqNumber(gridID) ) differ = 1;
-                  if ( !differ && grid->number && gridInqNumber(gridID) && grid->position != gridInqPosition(gridID) ) differ = 1;
+                  int nvertexA, nvertexB, numberA, numberB;
+                  differ = ( (nvertexA = grid->nvertex)
+                             && (nvertexB = gridRef->nvertex)
+                             && (nvertexA != nvertexB) )
+                    || (numberA = grid->number, numberB = gridRef->number,
+                        ( (numberA)
+                          && numberB
+                          && (numberA != numberB) )
+                        || ( (numberA && numberB)
+                             && (grid->position) != (gridRef->position) ) );
                 }
-              else
+              else if ( !differ )
                 {
-                  if ( !differ && grid->nvertex != gridInqNvertex(gridID) ) differ = 1;
-                  if ( !differ && grid->number != gridInqNumber(gridID) ) differ = 1;
-                  if ( !differ && grid->number > 0 && grid->position != gridInqPosition(gridID) ) differ = 1;
-                  if ( !differ )
-                    differ = compareXYvals2(gridID, grid->size, grid->xvals, grid->yvals);
+                  differ = grid->nvertex != gridRef->nvertex
+                    || grid->number != gridRef->number
+                    || (grid->number > 0 && grid->position != gridRef->position)
+                    || gridRef->vtable->compareXYAO(gridRef, (grid_t *)grid);
                 }
               }
 	}
@@ -26602,7 +26500,6 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
   if ( g1->size          != g2->size         ) return differ;
   if ( g1->xsize         != g2->xsize        ) return differ;
   if ( g1->ysize         != g2->ysize        ) return differ;
-  if ( g1->locked        != g2->locked       ) return differ;
   if ( g1->lcomplex      != g2->lcomplex     ) return differ;
 
   if ( g1->rowlon )
@@ -26638,23 +26535,27 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
   if ( IS_NOT_EQUAL(g1->ypole         , g2->ypole)         ) return differ;
   if ( IS_NOT_EQUAL(g1->angle         , g2->angle)         ) return differ;
 
-  if ( g1->xvals )
+  const double *restrict g1_xvals = g1->vtable->inqXValsPtr(g1),
+    *restrict g2_xvals = g2->vtable->inqXValsPtr(g2);
+  if ( g1_xvals )
     {
       if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
-	size = g1->size;
+        size = g1->size;
       else
-	size = g1->xsize;
+        size = g1->xsize;
       xassert ( size );
 
-      if ( !g2->xvals ) return differ;
+      if ( !g2_xvals ) return differ;
 
       for ( i = 0; i < size; i++ )
-	if ( IS_NOT_EQUAL(g1->xvals[i], g2->xvals[i]) ) return differ;
+        if ( IS_NOT_EQUAL(g1_xvals[i], g2_xvals[i]) ) return differ;
     }
-  else if ( g2->xvals )
+  else if ( g2_xvals )
     return differ;
 
-  if ( g1->yvals )
+  const double *restrict g1_yvals = g1->vtable->inqXValsPtr(g1),
+    *restrict g2_yvals = g2->vtable->inqXValsPtr(g2);
+  if ( g1_yvals )
     {
       if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
 	size = g1->size;
@@ -26662,66 +26563,74 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
 	size = g1->ysize;
       xassert ( size );
 
-      if ( !g2->yvals ) return differ;
+      if ( !g2_yvals ) return differ;
 
       for ( i = 0; i < size; i++ )
-        if ( IS_NOT_EQUAL(g1->yvals[i], g2->yvals[i]) ) return differ;
+        if ( IS_NOT_EQUAL(g1_yvals[i], g2_yvals[i]) ) return differ;
     }
-  else if ( g2->yvals )
+  else if ( g2_yvals )
     return differ;
 
-  if ( g1->area )
+  const double *restrict g1_area = g1->vtable->inqAreaPtr(g1),
+    *restrict g2_area = g2->vtable->inqAreaPtr(g2);
+  if ( g1_area )
     {
       xassert ( g1->size );
 
-      if ( !g2->area ) return differ;
+      if ( !g2_area ) return differ;
 
       for ( i = 0; i < g1->size; i++ )
-	if ( IS_NOT_EQUAL(g1->area[i], g2->area[i]) ) return differ;
+	if ( IS_NOT_EQUAL(g1_area[i], g2_area[i]) ) return differ;
     }
-  else if ( g2->area )
+  else if ( g2_area )
     return differ;
 
-  if ( g1->xbounds )
-    {
-      xassert ( g1->nvertex );
-      if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
-	size = g1->nvertex * g1->size;
-      else
-	size = g1->nvertex * g1->xsize;
-      xassert ( size );
+  {
+    const double *restrict g1_xbounds, *restrict g2_xbounds;
+    if ( (g1_xbounds = g1->vtable->inqXBoundsPtr(g1)) )
+      {
+        xassert ( g1->nvertex );
+        if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
+          size = g1->nvertex * g1->size;
+        else
+          size = g1->nvertex * g1->xsize;
+        xassert ( size );
 
-      if ( !g2->xbounds ) return differ;
+        if ( !(g2_xbounds = g2->vtable->inqXBoundsPtr(g2)) ) return differ;
 
-      for ( i = 0; i < size; i++ )
-	if ( IS_NOT_EQUAL(g1->xbounds[i], g2->xbounds[i]) ) return differ;
-    }
-  else if ( g2->xbounds )
-    return differ;
+        for ( i = 0; i < size; i++ )
+          if ( IS_NOT_EQUAL(g1_xbounds[i], g2_xbounds[i]) ) return differ;
+      }
+    else if ( g2->vtable->inqXBoundsPtr(g2) )
+      return differ;
+  }
 
-  if ( g1->ybounds )
-    {
-      xassert ( g1->nvertex );
-      if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
-	size = g1->nvertex * g1->size;
-      else
-	size = g1->nvertex * g1->ysize;
-      xassert ( size );
+  {
+    const double *restrict g1_ybounds, *restrict g2_ybounds;
+    if ( (g1_ybounds = g1->vtable->inqYBoundsPtr(g1)) )
+      {
+        xassert ( g1->nvertex );
+        if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
+          size = g1->nvertex * g1->size;
+        else
+          size = g1->nvertex * g1->ysize;
+        xassert ( size );
 
-      if ( !g2->ybounds ) return differ;
+        if ( ! (g2_ybounds = g2->vtable->inqYBoundsPtr(g2)) ) return differ;
 
-      for ( i = 0; i < size; i++ )
-	if ( IS_NOT_EQUAL(g1->ybounds[i], g2->ybounds[i]) ) return differ;
-    }
-  else if ( g2->ybounds )
-    return differ;
+        for ( i = 0; i < size; i++ )
+          if ( IS_NOT_EQUAL(g1->ybounds[i], g2->ybounds[i]) ) return differ;
+      }
+    else if ( g2->vtable->inqYBoundsPtr(g2) )
+      return differ;
+  }
 
   if (strcmp(g1->xname, g2->xname)) return differ;
   if (strcmp(g1->yname, g2->yname)) return differ;
   if (strcmp(g1->xlongname, g2->xlongname)) return differ;
   if (strcmp(g1->ylongname, g2->ylongname)) return differ;
-  if (strcmp(g1->xstdname, g2->xstdname)) return differ;
-  if (strcmp(g1->ystdname, g2->ystdname)) return differ;
+  if (g1->xstdname != g2->xstdname) return differ;
+  if (g1->ystdname != g2->ystdname) return differ;
   if (strcmp(g1->xunits, g2->xunits)) return differ;
   if (strcmp(g1->yunits, g2->yunits)) return differ;
 
@@ -26757,16 +26666,13 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
   return equal;
 }
 
-
-int gridGenerate(const grid_t *grid)
+static void gridComplete(grid_t *grid)
 {
-  int gridID = gridCreate(grid->type, grid->size);
-
-  grid_t *gridptr = gridID2Ptr(gridID);
-
+  int gridID = grid->self;
   gridDefPrec(gridID, grid->prec);
 
-  switch (grid->type)
+  int gridtype = grid->type;
+  switch (gridtype)
     {
     case GRID_LONLAT:
     case GRID_GAUSSIAN:
@@ -26782,42 +26688,32 @@ int gridGenerate(const grid_t *grid)
 	if ( grid->xsize > 0 ) gridDefXsize(gridID, grid->xsize);
 	if ( grid->ysize > 0 ) gridDefYsize(gridID, grid->ysize);
 
-        if ( grid->type == GRID_GAUSSIAN ) gridDefNP(gridID, grid->np);
+        if ( gridtype == GRID_GAUSSIAN ) gridDefNP(gridID, grid->np);
 
 	if ( grid->nvertex > 0 )
 	  gridDefNvertex(gridID, grid->nvertex);
 
-	if ( grid->xdef == 1 )
-	  {
-	    gridDefXvals(gridID, grid->xvals);
-	    if ( grid->xbounds )
-	      gridDefXbounds(gridID, grid->xbounds);
-	  }
-	else if ( grid->xdef == 2 )
+	if ( grid->xdef == 2 )
 	  {
+            assert(gridtype != GRID_UNSTRUCTURED
+                   && gridtype != GRID_CURVILINEAR);
 	    double *xvals
               = (double *) Malloc((size_t)grid->xsize * sizeof (double));
 	    gridGenXvals(grid->xsize, grid->xfirst, grid->xlast, grid->xinc, xvals);
-	    gridDefXvals(gridID, xvals);
-	    Free(xvals);
+	    grid->xvals = xvals;
 	    /*
 	    gridDefXinc(gridID, grid->xinc);
 	    */
 	  }
 
-	if ( grid->ydef == 1 )
-	  {
-	    gridDefYvals(gridID, grid->yvals);
-	    if ( grid->ybounds && grid->nvertex )
-	      gridDefYbounds(gridID, grid->ybounds);
-	  }
-	else if ( grid->ydef == 2 )
+	if ( grid->ydef == 2 )
 	  {
+            assert(gridtype != GRID_UNSTRUCTURED
+                   && gridtype != GRID_CURVILINEAR);
 	    double *yvals
               = (double *) Malloc((size_t)grid->ysize * sizeof (double));
-	    gridGenYvals(grid->type, grid->ysize, grid->yfirst, grid->ylast, grid->yinc, yvals);
-	    gridDefYvals(gridID, yvals);
-	    Free(yvals);
+	    gridGenYvals(gridtype, grid->ysize, grid->yfirst, grid->ylast, grid->yinc, yvals);
+	    grid->yvals = yvals;
 	    /*
 	    gridDefYinc(gridID, grid->yinc);
 	    */
@@ -26829,8 +26725,8 @@ int gridGenerate(const grid_t *grid)
 	    gridDefYname(gridID, "rlat");
 	    gridDefXlongname(gridID, "longitude in rotated pole grid");
 	    gridDefYlongname(gridID, "latitude in rotated pole grid");
-	    strcpy(gridptr->xstdname, "grid_longitude");
-	    strcpy(gridptr->ystdname, "grid_latitude");
+            grid->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
+            grid->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
 	    gridDefXunits(gridID, "degrees");
 	    gridDefYunits(gridID, "degrees");
 
@@ -26839,39 +26735,30 @@ int gridGenerate(const grid_t *grid)
 	    gridDefAngle(gridID, grid->angle);
 	  }
 
-	if ( grid->area )
-	  {
-	    gridDefArea(gridID, grid->area);
-	  }
-
-	if ( grid->type == GRID_LAEA )
-	  gridDefLaea(gridID, grid->laea_a, grid->laea_lon_0, grid->laea_lat_0);
-
-	if ( grid->type == GRID_LCC2 )
-	  gridDefLcc2(gridID, grid->lcc2_a, grid->lcc2_lon_0, grid->lcc2_lat_0, grid->lcc2_lat_1, grid->lcc2_lat_2);
-
-	if ( grid->type == GRID_LCC )
-	  gridDefLCC(gridID, grid->lcc_originLon, grid->lcc_originLat, grid->lcc_lonParY,
-		     grid->lcc_lat1, grid->lcc_lat2, grid->lcc_xinc, grid->lcc_yinc,
-		     grid->lcc_projflag, grid->lcc_scanflag);
-
-	if ( grid->type == GRID_UNSTRUCTURED )
+        switch (gridtype)
           {
-            int number = grid->number;
-            int position = grid->position;
-            if ( position < 0 ) position = 0;
-            if ( number > 0 )
-              {
-                gridDefNumber(gridID, number);
-                gridDefPosition(gridID, position);
-              }
-            gridDefUUID(gridID, grid->uuid);
-            if ( grid->reference ) gridDefReference(gridID, grid->reference);
-          }
-
-	if ( grid->type == GRID_PROJECTION )
-	  {
-	    gridptr->name = strdup(grid->name);
+          case GRID_LAEA:
+            gridDefLaea(gridID, grid->laea_a, grid->laea_lon_0, grid->laea_lat_0);
+            break;
+          case GRID_LCC2:
+            gridDefLcc2(gridID, grid->lcc2_a, grid->lcc2_lon_0, grid->lcc2_lat_0, grid->lcc2_lat_1, grid->lcc2_lat_2);
+            break;
+          case GRID_LCC:
+            gridDefLCC(gridID, grid->lcc_originLon, grid->lcc_originLat, grid->lcc_lonParY,
+                       grid->lcc_lat1, grid->lcc_lat2, grid->lcc_xinc, grid->lcc_yinc,
+                       grid->lcc_projflag, grid->lcc_scanflag);
+            break;
+          case GRID_UNSTRUCTURED:
+            {
+              int number = grid->number;
+              int position = grid->position >= 0 ? grid->position : 0;
+              if ( number > 0 )
+                {
+                  gridDefNumber(gridID, number);
+                  gridDefPosition(gridID, position);
+                }
+            }
+            break;
 	  }
 
 	break;
@@ -26880,29 +26767,19 @@ int gridGenerate(const grid_t *grid)
       {
 	gridDefNP(gridID, grid->np);
 	gridDefYsize(gridID, grid->ysize);
-	gridDefRowlon(gridID, grid->ysize, grid->rowlon);
 
         if ( grid->xdef == 2 )
           {
-            double xvals[2];
-            xvals[0] = grid->xfirst;
-            xvals[1] = grid->xlast;
+            double xvals[2] = { grid->xfirst, grid->xlast };
             gridDefXvals(gridID, xvals);
           }
 
-	if ( grid->ydef == 1 )
-	  {
-	    gridDefYvals(gridID, grid->yvals);
-	    if ( grid->ybounds && grid->nvertex )
-	      gridDefYbounds(gridID, grid->ybounds);
-	  }
-	else if ( grid->ydef == 2 )
+        if ( grid->ydef == 2 )
 	  {
 	    double *yvals
               = (double *) Malloc((size_t)grid->ysize * sizeof (double));
-	    gridGenYvals(grid->type, grid->ysize, grid->yfirst, grid->ylast, grid->yinc, yvals);
-	    gridDefYvals(gridID, yvals);
-	    Free(yvals);
+	    gridGenYvals(gridtype, grid->ysize, grid->yfirst, grid->ylast, grid->yinc, yvals);
+            grid->yvals = yvals;
 	    /*
 	    gridDefYinc(gridID, grid->yinc);
 	    */
@@ -26949,127 +26826,209 @@ int gridGenerate(const grid_t *grid)
       }
     default:
       {
-	Error("Gridtype %s unsupported!", gridNamePtr(grid->type));
+	Error("Gridtype %s unsupported!", gridNamePtr(gridtype));
 	break;
       }
     }
 
-  if ( grid->xname[0]     ) gridDefXname(gridID, grid->xname);
-  if ( grid->xlongname[0] ) gridDefXlongname(gridID, grid->xlongname);
-  if ( grid->xunits[0]    ) gridDefXunits(gridID, grid->xunits);
-  if ( grid->yname[0]     ) gridDefYname(gridID, grid->yname);
-  if ( grid->ylongname[0] ) gridDefYlongname(gridID, grid->ylongname);
-  if ( grid->yunits[0]    ) gridDefYunits(gridID, grid->yunits);
+  grid->xname[CDI_MAX_NAME - 1] = 0;
+  grid->xlongname[CDI_MAX_NAME - 1] = 0;
+  grid->xunits[CDI_MAX_NAME - 1] = 0;
+  grid->yname[CDI_MAX_NAME - 1] = 0;
+  grid->ylongname[CDI_MAX_NAME - 1] = 0;
+  grid->yunits[CDI_MAX_NAME - 1] = 0;
 
-  return (gridID);
 }
 
-/*
- at Function  gridDuplicate
- at Title     Duplicate a horizontal Grid
-
- at Prototype int gridDuplicate(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-
- at Description
-The function @func{gridDuplicate} duplicates a horizontal Grid.
-
- at Result
- at func{gridDuplicate} returns an identifier to the duplicated Grid.
+#define GRID_STR_SERIALIZE(gridP) { gridP->xname, gridP->yname, \
+    gridP->xlongname, gridP->ylongname, \
+    gridP->xunits, gridP->yunits }
 
- at EndFunction
-*/
-int gridDuplicate(int gridID)
+int gridGenerate(const grid_t *grid)
 {
-  grid_t *gridptr = (grid_t *)reshGetVal(gridID, &gridOps);
-
-  int gridtype = gridInqType(gridID);
-  int gridsize = gridInqSize(gridID);
-
-  int gridIDnew = gridCreate(gridtype, gridsize);
-  grid_t *gridptrnew = (grid_t *)reshGetVal(gridIDnew, &gridOps);
-
-  grid_copy(gridptrnew, gridptr);
-
-  strcpy(gridptrnew->xname, gridptr->xname);
-  strcpy(gridptrnew->yname, gridptr->yname);
-  strcpy(gridptrnew->xlongname, gridptr->xlongname);
-  strcpy(gridptrnew->ylongname, gridptr->ylongname);
-  strcpy(gridptrnew->xunits, gridptr->xunits);
-  strcpy(gridptrnew->yunits, gridptr->yunits);
-  strcpy(gridptrnew->xstdname, gridptr->xstdname);
-  strcpy(gridptrnew->ystdname, gridptr->ystdname);
-
-  if (gridptr->reference)
-    gridptrnew->reference = strdupx(gridptr->reference);
+  int gridtype = grid->type;
+  int gridID = gridCreate(gridtype, grid->size);
+  grid_t *restrict gridptr = gridID2Ptr(gridID);
+  gridptr->prec = grid->prec;
+  gridptr->xsize = grid->xsize;
+  gridptr->ysize = grid->ysize;
+  gridptr->np = grid->np;
+  gridptr->nvertex = grid->nvertex;
+  gridptr->xdef = grid->xdef;
+  int valdef_group1 = 0;
+  static const int valdef_group1_tab[] = {
+    GRID_LONLAT, GRID_GAUSSIAN, GRID_UNSTRUCTURED, GRID_CURVILINEAR,
+    GRID_GENERIC, GRID_LCC, GRID_LCC2, GRID_SINUSOIDAL, GRID_LAEA,
+    GRID_PROJECTION
+  };
+  for ( size_t i = 0; i < sizeof (valdef_group1_tab) / sizeof (valdef_group1_tab[0]); ++i)
+    valdef_group1 |= (gridtype == valdef_group1_tab[i]);
+  if ( valdef_group1 && grid->xdef == 1 )
+    {
+      gridDefXvals(gridID, grid->xvals);
+      if ( grid->xbounds )
+        gridDefXbounds(gridID, grid->xbounds);
+    }
+  gridptr->xfirst = grid->xfirst;
+  gridptr->xlast = grid->xlast;
+  gridptr->xinc = grid->xinc;
+  gridptr->ydef = grid->ydef;
+  if ( (valdef_group1 || gridtype == GRID_GAUSSIAN_REDUCED) && grid->ydef == 1)
+    {
+      gridDefYvals(gridID, grid->yvals);
+      if ( grid->ybounds )
+        gridDefYbounds(gridID, grid->ybounds);
+    }
+  gridptr->yfirst = grid->yfirst;
+  gridptr->ylast = grid->ylast;
+  gridptr->yinc = grid->yinc;
+  gridptr->isRotated = grid->isRotated;
+  gridptr->xpole = grid->xpole;
+  gridptr->ypole = grid->ypole;
+  gridptr->angle = grid->angle;
+  if ( valdef_group1 && grid->area)
+    gridDefArea(gridID, grid->area);
+  gridptr->laea_a = grid->laea_a;
+  gridptr->laea_lon_0 = grid->laea_lon_0;
+  gridptr->laea_lat_0 = grid->laea_lat_0;
+  gridptr->lcc2_a = grid->lcc2_a;
+  gridptr->lcc2_lon_0 = grid->lcc2_lon_0;
+  gridptr->lcc2_lat_0 = grid->lcc2_lat_0;
+  gridptr->lcc2_lat_1 = grid->lcc2_lat_1;
+  gridptr->lcc2_lat_2 = grid->lcc2_lat_2;
+  gridptr->lcc_originLon = grid->lcc_originLon;
+  gridptr->lcc_originLat = grid->lcc_originLat;
+  gridptr->lcc_lonParY = grid->lcc_lonParY;
+  gridptr->lcc_lat1 = grid->lcc_lat1;
+  gridptr->lcc_lat2 = grid->lcc_lat2;
+  gridptr->lcc_xinc = grid->lcc_xinc;
+  gridptr->lcc_yinc = grid->lcc_yinc;
+  gridptr->lcc_projflag = grid->lcc_projflag;
+  gridptr->lcc_scanflag = grid->lcc_scanflag;
+  gridptr->number = grid->number;
+  gridptr->position = grid->position;
+  memcpy(gridptr->uuid, grid->uuid, CDI_UUID_SIZE);
+  if ( gridtype == GRID_UNSTRUCTURED && grid->reference )
+    gridDefReference(gridID, grid->reference);
+  if ( gridtype == GRID_PROJECTION )
+    gridptr->name = strdup(grid->name);
+  if ( gridtype == GRID_GAUSSIAN_REDUCED )
+    gridDefRowlon(gridID, grid->ysize, grid->rowlon);
+  gridptr->trunc = grid->trunc;
+  gridptr->lcomplex = grid->lcomplex;
+  gridptr->nd = grid->nd;
+  gridptr->ni = grid->ni;
+  gridptr->ni2 = grid->ni2;
+  gridptr->ni3 = grid->ni3;
+  const char *grid_str_tab[] = GRID_STR_SERIALIZE(grid);
+  char *gridptr_str_tab[] = GRID_STR_SERIALIZE(gridptr);
+  for (size_t i = 0; i < sizeof (grid_str_tab) / sizeof (grid_str_tab[0]); ++i)
+    if ( grid_str_tab[i][0] )
+      memcpy(gridptr_str_tab[i], grid_str_tab[i], CDI_MAX_NAME);
+  gridComplete(gridptr);
+  return (gridID);
+}
 
-  size_t nrowlon = (size_t)gridptr->nrowlon;
+static void
+grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
+{
+  size_t nrowlon = (size_t)gridptrOrig->nrowlon;
+  size_t gridsize = (size_t)gridptrOrig->size;
+  int gridtype = gridptrOrig->type;
   int irregular = gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED;
   if ( nrowlon )
     {
-      gridptrnew->rowlon = (int *) Malloc(nrowlon * sizeof (int));
-      memcpy(gridptrnew->rowlon, gridptr->rowlon, nrowlon * sizeof(int));
+      gridptrDup->rowlon = (int *)Malloc(nrowlon * sizeof (int));
+      memcpy(gridptrDup->rowlon, gridptrOrig->rowlon, nrowlon * sizeof(int));
     }
 
-  if ( gridptr->xvals != NULL )
+  if ( gridptrOrig->xvals != NULL )
     {
-      size_t size  = (size_t)(irregular ? gridsize : gridptr->xsize);
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->xsize;
 
-      gridptrnew->xvals = (double *) Malloc(size * sizeof (double));
-      memcpy(gridptrnew->xvals, gridptr->xvals, size * sizeof (double));
+      gridptrDup->xvals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->xvals, gridptrOrig->xvals, size * sizeof (double));
     }
 
-  if ( gridptr->yvals != NULL )
+  if ( gridptrOrig->yvals != NULL )
     {
-      size_t size  = (size_t)(irregular ? gridsize : gridptr->ysize);
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->ysize;
 
-      gridptrnew->yvals = (double *) Malloc(size * sizeof (double));
-      memcpy(gridptrnew->yvals, gridptr->yvals, size * sizeof (double));
+      gridptrDup->yvals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->yvals, gridptrOrig->yvals, size * sizeof (double));
     }
 
-  if ( gridptr->xbounds != NULL )
+  if ( gridptrOrig->xbounds != NULL )
     {
-      size_t size  = (size_t)(irregular ? gridsize : gridptr->xsize)
-        * (size_t)gridptr->nvertex;
+      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->xsize)
+        * (size_t)gridptrOrig->nvertex;
 
-      gridptrnew->xbounds = (double *) Malloc(size * sizeof (double));
-      memcpy(gridptrnew->xbounds, gridptr->xbounds, size * sizeof (double));
+      gridptrDup->xbounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->xbounds, gridptrOrig->xbounds, size * sizeof (double));
     }
 
-  if ( gridptr->ybounds != NULL )
+  if ( gridptrOrig->ybounds != NULL )
     {
-      size_t size = (size_t)(irregular ? gridsize : gridptr->ysize)
-        * (size_t)gridptr->nvertex;
+      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->ysize)
+        * (size_t)gridptrOrig->nvertex;
 
-      gridptrnew->ybounds = (double *) Malloc(size * sizeof (double));
-      memcpy(gridptrnew->ybounds, gridptr->ybounds, size * sizeof (double));
+      gridptrDup->ybounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->ybounds, gridptrOrig->ybounds, size * sizeof (double));
     }
 
-  if ( gridptr->area != NULL )
-    {
-      size_t size = (size_t)gridsize;
+  {
+    const double *gridptrOrig_area
+      = gridptrOrig->vtable->inqAreaPtr(gridptrOrig);
+    if ( gridptrOrig_area != NULL )
+      {
+        size_t size = gridsize;
 
-      gridptrnew->area = (double *) Malloc(size * sizeof (double));
-      memcpy(gridptrnew->area, gridptr->area, size * sizeof (double));
-    }
+        gridptrDup->area = (double *)Malloc(size * sizeof (double));
+        memcpy(gridptrDup->area, gridptrOrig_area, size * sizeof (double));
+      }
+  }
 
-  if ( gridptr->mask != NULL )
+  if ( gridptrOrig->mask != NULL )
     {
-      size_t size = (size_t)gridsize;
+      size_t size = gridsize;
 
-      gridptrnew->mask = (mask_t *) Malloc(size * sizeof(mask_t));
-      memcpy(gridptrnew->mask, gridptr->mask, size * sizeof (mask_t));
+      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
+      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
     }
 
-  if ( gridptr->mask_gme != NULL )
+  if ( gridptrOrig->mask_gme != NULL )
     {
-      size_t size = (size_t)gridsize;
+      size_t size = gridsize;
 
-      gridptrnew->mask_gme = (mask_t *) Malloc(size * sizeof (mask_t));
-      memcpy(gridptrnew->mask_gme, gridptr->mask_gme, size * sizeof(mask_t));
+      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
+      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
     }
 
+}
+
+
+/*
+ at Function  gridDuplicate
+ at Title     Duplicate a horizontal Grid
+
+ at Prototype int gridDuplicate(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+
+ at Description
+The function @func{gridDuplicate} duplicates a horizontal Grid.
+
+ at Result
+ at func{gridDuplicate} returns an identifier to the duplicated Grid.
+
+ at EndFunction
+*/
+int gridDuplicate(int gridID)
+{
+  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptrnew = gridptr->vtable->copy(gridptr);
+  int gridIDnew = reshPut(gridptrnew, &gridOps);
+  gridptrnew->self = gridIDnew;
   return (gridIDnew);
 }
 
@@ -27085,71 +27044,72 @@ void gridCompress(int gridID)
 	{
           size_t gridsize = (size_t)gridInqSize(gridID);
 	  size_t nv = (size_t)gridptr->nvertex;
-
-	  size_t j = 0;
-          double *area = gridptr->area,
-            *xvals = gridptr->xvals,
-            *yvals = gridptr->yvals,
-            *xbounds = gridptr->xbounds,
-            *ybounds = gridptr->ybounds;
-          mask_t *mask_gme = gridptr->mask_gme;
-	  for (size_t i = 0; i < gridsize; i++ )
-	    {
-	      if (mask_gme[i])
-		{
-		  if (xvals) xvals[j] = xvals[i];
-		  if (yvals) yvals[j] = yvals[i];
-		  if (area) area[j]  = area[i];
-		  if (xbounds != NULL)
-		    for (size_t iv = 0; iv < nv; iv++)
-		      xbounds[j * nv + iv] = xbounds[i * nv + iv];
-		  if (ybounds != NULL)
-		    for (size_t iv = 0; iv < nv; iv++)
-		      ybounds[j * nv + iv] = ybounds[i * nv + iv];
-
-		  j++;
-		}
-	    }
+          double *restrict area
+            = (double *)gridptr->vtable->inqAreaPtr(gridptr),
+            *restrict xvals = (double *)gridptr->vtable->inqXValsPtr((grid_t *)gridptr),
+            *restrict yvals = (double *)gridptr->vtable->inqYValsPtr((grid_t *)gridptr),
+            *restrict xbounds = (double *)gridptr->vtable->inqXBoundsPtr(gridptr),
+            *restrict ybounds = (double *)gridptr->vtable->inqYBoundsPtr(gridptr);
+          mask_t *restrict mask_gme = gridptr->mask_gme;
+          size_t *restrict selection = (size_t *)Malloc(gridsize * sizeof (selection[0]));
+          size_t nselect;
+          {
+            size_t j = 0;
+            for (size_t i = 0; i < gridsize; i++ )
+              selection[j] = i, j += (mask_gme[i] != 0);
+            nselect = j;
+          }
+          selection = (size_t *)Realloc(selection, nselect * sizeof (selection[0]));
+          if (xvals)
+            for (size_t i = 0; i < nselect; i++ )
+	      xvals[i] = xvals[selection[i]];
+          if (yvals)
+            for (size_t i = 0; i < nselect; i++ )
+              yvals[i] = yvals[selection[i]];
+          if (area)
+            for (size_t i = 0; i < nselect; i++ )
+              area[i] = area[selection[i]];
+          if (xbounds)
+            for (size_t i = 0; i < nselect; i++ )
+              for (size_t iv = 0; iv < nv; iv++)
+                xbounds[i * nv + iv] = xbounds[selection[i] * nv + iv];
+          if (ybounds)
+            for (size_t i = 0; i < nselect; i++ )
+              for (size_t iv = 0; iv < nv; iv++)
+                ybounds[i * nv + iv] = ybounds[selection[i] * nv + iv];
+          Free(selection);
 
 	  /* fprintf(stderr, "grid compress %d %d %d\n", i, j, gridsize); */
-	  gridsize = j;
+	  gridsize = nselect;
 	  gridptr->size  = (int)gridsize;
 	  gridptr->xsize = (int)gridsize;
 	  gridptr->ysize = (int)gridsize;
 
-	  if ( gridptr->xvals )
-	    gridptr->xvals = (double *) Realloc(gridptr->xvals, gridsize*sizeof(double));
-
-	  if ( gridptr->yvals )
-	    gridptr->yvals = (double *) Realloc(gridptr->yvals, gridsize*sizeof(double));
-
-	  if ( gridptr->area )
-	    gridptr->area  = (double *) Realloc(gridptr->area, gridsize*sizeof(double));
-
-	  if ( gridptr->xbounds )
-	    gridptr->xbounds = (double *) Realloc(gridptr->xbounds, nv*gridsize*sizeof(double));
-
-	  if ( gridptr->ybounds )
-	    gridptr->ybounds = (double *) Realloc(gridptr->ybounds, nv*gridsize*sizeof(double));
+          double **resizeP[] = { &gridptr->xvals, &gridptr->yvals,
+                                 &gridptr->area,
+                                 &gridptr->xbounds, &gridptr->ybounds };
+          size_t newSize[] = { gridsize, gridsize, gridsize, nv*gridsize,
+                               nv*gridsize };
+          for ( size_t i = 0; i < sizeof (resizeP) / sizeof (resizeP[0]); ++i)
+            if ( *(resizeP[i]) )
+              *(resizeP[i]) = (double *)Realloc(*(resizeP[i]), newSize[i]*sizeof(double));
 
 	  Free(gridptr->mask_gme);
 	  gridptr->mask_gme = NULL;
-          reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+          gridMark4Update(gridID);
 	}
     }
   else
     Warning("Unsupported grid type: %s", gridNamePtr(gridtype));
 }
 
-
-void gridDefArea(int gridID, const double *area)
+static void
+gridDefAreaSerial(grid_t *gridptr, const double *area)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
   size_t size = (size_t)gridptr->size;
 
   if ( size == 0 )
-    Error("size undefined for gridID = %d", gridID);
+    Error("size undefined for gridID = %d", gridptr->self);
 
   if ( gridptr->area == NULL )
     gridptr->area = (double *) Malloc(size*sizeof(double));
@@ -27157,34 +27117,52 @@ void gridDefArea(int gridID, const double *area)
     Warning("values already defined!");
 
   memcpy(gridptr->area, area, size * sizeof(double));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
 }
 
 
-void gridInqArea(int gridID, double *area)
+void gridDefArea(int gridID, const double *area)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defArea(gridptr, area);
+  gridMark4Update(gridID);
+}
 
+static void
+gridInqAreaSerial(grid_t *gridptr, double *area)
+{
   if (gridptr->area)
     memcpy(area, gridptr->area, (size_t)gridptr->size * sizeof (double));
 }
 
 
-int gridHasArea(int gridID)
+void gridInqArea(int gridID, double *area)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->inqArea(gridptr, area);
+}
 
-  int hasArea = (gridptr->area != NULL);
+static int
+gridHasAreaBase(grid_t *gridptr)
+{
+  return gridptr->area != NULL;
+}
 
-  return (hasArea);
+int gridHasArea(int gridID)
+{
+  grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->hasArea(gridptr);
 }
 
 
+static const double *gridInqAreaPtrBase(grid_t *gridptr)
+{
+  return gridptr->area;
+}
+
 const double *gridInqAreaPtr(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  return (gridptr->area);
+  return gridptr->vtable->inqAreaPtr(gridptr);
 }
 
 
@@ -27195,7 +27173,7 @@ void gridDefNvertex(int gridID, int nvertex)
   if (gridptr->nvertex != nvertex)
     {
       gridptr->nvertex = nvertex;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -27207,6 +27185,38 @@ int gridInqNvertex(int gridID)
   return (gridptr->nvertex);
 }
 
+static void
+gridDefBoundsGeneric(grid_t *gridptr, const double *bounds, int regularSize,
+                     double **field)
+{
+  int irregular = gridptr->type == GRID_CURVILINEAR
+    || gridptr->type == GRID_UNSTRUCTURED;
+  size_t nvertex = (size_t)gridptr->nvertex;
+  if ( nvertex == 0 )
+    {
+      Warning("nvertex undefined for gridID = %d. Cannot define bounds!",
+              gridptr->self);
+      return;
+    }
+  size_t size = nvertex * (size_t)(irregular ? gridptr->size : regularSize);
+  if ( size == 0 )
+    Error("size undefined for gridID = %d", gridptr->self);
+
+  if (*field == NULL)
+    *field = (double *)Malloc(size * sizeof (double));
+  else if ( CDI_Debug )
+    Warning("values already defined!");
+
+  memcpy(*field, bounds, size * sizeof (double));
+}
+
+
+static void
+gridDefXBoundsSerial(grid_t *gridptr, const double *xbounds)
+{
+  gridDefBoundsGeneric(gridptr, xbounds, gridptr->xsize, &gridptr->xbounds);
+}
+
 /*
 @Function  gridDefXbounds
 @Title     Define the bounds of a X-axis
@@ -27224,28 +27234,29 @@ The function @func{gridDefXbounds} defines all bounds of the X-axis.
 void gridDefXbounds(int gridID, const double *xbounds)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defXBounds(gridptr, xbounds);
+  gridMark4Update(gridID);
+}
 
+static int
+gridInqXBoundsSerial(grid_t *gridptr, double *xbounds)
+{
   size_t nvertex = (size_t)gridptr->nvertex;
-  if ( nvertex == 0 )
-    {
-      Warning("nvertex undefined for gridID = %d. Cannot define bounds!", gridID);
-      return;
-    }
 
   int irregular = gridptr->type == GRID_CURVILINEAR
     || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex
-    * (size_t)(irregular ? gridptr->size : gridptr->xsize);
-  if ( size == 0 )
-    Error("size undefined for gridID = %d", gridID);
+  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->xsize);
 
-  if (gridptr->xbounds == NULL)
-    gridptr->xbounds = (double *) Malloc(size * sizeof (double));
-  else if ( CDI_Debug )
-    Warning("values already defined!");
+  const double *gridptr_xbounds = gridptr->vtable->inqXBoundsPtr(gridptr);
+  if ( gridptr_xbounds )
+    {
+      if ( size && xbounds )
+        memcpy(xbounds, gridptr_xbounds, size * sizeof (double));
+    }
+  else
+    size = 0;
 
-  memcpy(gridptr->xbounds, xbounds, size * sizeof (double));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+  return ((int)size);
 }
 
 /*
@@ -27271,27 +27282,26 @@ Otherwise, 0 is returned and @func{xbounds} is empty.
 int gridInqXbounds(int gridID, double *xbounds)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqXBounds(gridptr, xbounds);
+}
 
-  size_t nvertex = (size_t)gridptr->nvertex;
-
-  int irregular = gridptr->type == GRID_CURVILINEAR
-    || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->xsize);
-
-  if ( size && xbounds && gridptr->xbounds )
-    memcpy(xbounds, gridptr->xbounds, size * sizeof (double));
-
-  if ( gridptr->xbounds == NULL ) size = 0;
-
-  return ((int)size);
+static const double *
+gridInqXBoundsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->xbounds;
 }
 
 
 const double *gridInqXboundsPtr(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqXBoundsPtr(gridptr);
+}
 
-  return (gridptr->xbounds);
+static void
+gridDefYBoundsSerial(grid_t *gridptr, const double *ybounds)
+{
+  gridDefBoundsGeneric(gridptr, ybounds, gridptr->ysize, &gridptr->ybounds);
 }
 
 /*
@@ -27311,30 +27321,32 @@ The function @func{gridDefYbounds} defines all bounds of the Y-axis.
 void gridDefYbounds(int gridID, const double *ybounds)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defYBounds(gridptr, ybounds);
+  gridMark4Update(gridID);
+}
 
+static int
+gridInqYBoundsSerial(grid_t *gridptr, double *ybounds)
+{
   size_t nvertex = (size_t)gridptr->nvertex;
-  if ( nvertex == 0 )
-    {
-      Warning("nvertex undefined for gridID = %d. Cannot define bounds!", gridID);
-      return;
-    }
 
   int irregular = gridptr->type == GRID_CURVILINEAR
     || gridptr->type == GRID_UNSTRUCTURED;
   size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->ysize);
 
-  if ( size == 0 )
-    Error("size undefined for gridID = %d", gridID);
-
-  if ( gridptr->ybounds == NULL )
-    gridptr->ybounds = (double *) Malloc(size * sizeof (double));
-  else if ( CDI_Debug )
-    Warning("values already defined!");
+  const double *gridptr_ybounds = gridptr->vtable->inqYBoundsPtr(gridptr);
+  if ( gridptr_ybounds )
+    {
+      if ( size && ybounds )
+        memcpy(ybounds, gridptr_ybounds, size * sizeof (double));
+    }
+  else
+    size = 0;
 
-  memcpy(gridptr->ybounds, ybounds, size * sizeof (double));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+  return ((int)size);
 }
 
+
 /*
 @Function  gridInqYbounds
 @Title     Get the bounds of a Y-axis
@@ -27358,35 +27370,98 @@ Otherwise, 0 is returned and @func{ybounds} is empty.
 int gridInqYbounds(int gridID, double *ybounds)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqYBounds(gridptr, ybounds);
+}
 
-  size_t nvertex = (size_t)gridptr->nvertex;
-
-  int irregular = gridptr->type == GRID_CURVILINEAR
-    || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->ysize);
-
-  if ( size && ybounds && gridptr->ybounds )
-    memcpy(ybounds, gridptr->ybounds, size * sizeof (double));
-
-  if ( gridptr->ybounds == NULL ) size = 0;
-
-  return ((int)size);
+static const double *
+gridInqYBoundsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->ybounds;
 }
 
 
 const double *gridInqYboundsPtr(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqYBoundsPtr(gridptr);
+}
+
+static void
+printDblsPrefixAutoBrk(FILE *fp, const char prefix[], size_t nbyte0,
+                       size_t n, const double vals[])
+{
+  fputs(prefix, fp);
+  size_t nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
+    {
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%.9g ", vals[i]);
+    }
+  fputs("\n", fp);
+}
+
+static void
+printIntsPrefixAutoBrk(FILE *fp, const char prefix[], size_t nbyte0,
+                       size_t n, const int vals[])
+{
+  fputs(prefix, fp);
+  size_t nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
+    {
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%d ", vals[i]);
+    }
+  fputs("\n", fp);
+}
 
-  return (gridptr->ybounds);
+static void
+printBounds(FILE *fp, const char prefix[], size_t nbyte0,
+            size_t n, size_t nvertex, const double bounds[])
+{
+  fputs(prefix, fp);
+  if ( n > 0 )
+    {
+      for ( size_t iv = 0; iv < nvertex; iv++ )
+        fprintf(fp, "%.9g ", bounds[iv]);
+      for ( size_t i = 1; i < (size_t)n; i++ )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          for ( size_t iv = 0; iv < nvertex; iv++ )
+            fprintf(fp, "%.9g ", bounds[i*nvertex+iv]);
+        }
+      fputs("\n", fp);
+    }
 }
 
+static void
+printMask(FILE *fp, const char prefix[], size_t nbyte0,
+          size_t n, const mask_t mask[])
+{
+  fputs(prefix, fp);
+  size_t nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
+    {
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%d ", (int)mask[i]);
+    }
+  fputs("\n", fp);
+}
 
 static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 {
   int xdim, ydim;
-  int nbyte;
-  int i, iv;
   unsigned char uuidOfHGrid[CDI_UUID_SIZE];
   int gridID = gridptr->self;
   const double *area    = gridInqAreaPtr(gridID);
@@ -27402,12 +27477,11 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
   int ysize    = gridInqYsize(gridID);
   int nvertex  = gridInqNvertex(gridID);
 
-  int nbyte0 = 0;
-  fprintf(fp, "#\n");
-  fprintf(fp, "# gridID %d\n", index);
-  fprintf(fp, "#\n");
-  fprintf(fp, "gridtype  = %s\n", gridNamePtr(type));
-  fprintf(fp, "gridsize  = %d\n", gridsize);
+  fprintf(fp, "#\n"
+          "# gridID %d\n"
+          "#\n"
+          "gridtype  = %s\n"
+          "gridsize  = %d\n", index, gridNamePtr(type), gridsize);
 
   if ( type != GRID_GME )
     {
@@ -27491,20 +27565,21 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 	  {
 	    double a = 0, lon_0 = 0, lat_0 = 0;
 	    gridInqLaea(gridID, &a, &lon_0, &lat_0);
-	    fprintf(fp, "a         = %g\n", a);
-	    fprintf(fp, "lon_0     = %g\n", lon_0);
-	    fprintf(fp, "lat_0     = %g\n", lat_0);
+	    fprintf(fp, "a         = %g\n"
+                    "lon_0     = %g\n"
+                    "lat_0     = %g\n", a, lon_0, lat_0);
 	  }
 
 	if ( type == GRID_LCC2 )
 	  {
 	    double a = 0, lon_0 = 0, lat_0 = 0, lat_1 = 0, lat_2 = 0;
 	    gridInqLcc2(gridID, &a, &lon_0, &lat_0, &lat_1, &lat_2);
-	    fprintf(fp, "a         = %g\n", a);
-	    fprintf(fp, "lon_0     = %g\n", lon_0);
-	    fprintf(fp, "lat_0     = %g\n", lat_0);
-	    fprintf(fp, "lat_1     = %g\n", lat_1);
-	    fprintf(fp, "lat_2     = %g\n", lat_2);
+	    fprintf(fp, "a         = %g\n"
+                    "lon_0     = %g\n"
+                    "lat_0     = %g\n"
+                    "lat_1     = %g\n"
+                    "lat_2     = %g\n",
+                    a, lon_0, lat_0, lat_1, lat_2);
 	  }
 
 	if ( gridptr->isRotated )
@@ -27528,38 +27603,23 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 
 	    if ( IS_NOT_EQUAL(xinc, 0) && opt )
 	      {
-	  	fprintf(fp, "xfirst    = %g\n", xfirst);
-		fprintf(fp, "xinc      = %g\n", xinc);
+                fprintf(fp, "xfirst    = %g\n"
+                        "xinc      = %g\n", xfirst, xinc);
 	      }
 	    else
 	      {
-		nbyte0 = fprintf(fp, "xvals     = ");
-		nbyte = nbyte0;
-		for ( i = 0; i < xdim; i++ )
-		  {
-		    if ( nbyte > 80 )
-		      {
-			fprintf(fp, "\n");
-			fprintf(fp, "%*s", nbyte0, "");
-			nbyte = nbyte0;
-		      }
-		    nbyte += fprintf(fp, "%.9g ", xvals[i]);
-		  }
-		fprintf(fp, "\n");
+                static const char prefix[] = "xvals     = ";
+                printDblsPrefixAutoBrk(fp, prefix, sizeof (prefix),
+                                       (size_t)(xdim > 0 ? xdim : 0), xvals);
 	      }
 	  }
 
 	if ( xbounds )
 	  {
-	    nbyte0 = fprintf(fp, "xbounds   = ");
-	    for ( i = 0; i < xdim; i++ )
-	      {
-		if ( i ) fprintf(fp, "%*s", nbyte0, "");
-
-		for ( iv = 0; iv < nvertex; iv++ )
-		  fprintf(fp, "%.9g ", xbounds[i*nvertex+iv]);
-		fprintf(fp, "\n");
-	      }
+            static const char prefix[] = "xbounds   = ";
+            printBounds(fp, prefix, sizeof (prefix),
+                        (size_t)(xdim > 0 ? xdim : 0),
+                        (size_t)(nvertex > 0 ? nvertex : 0), xbounds);
 	  }
 
 	if ( yvals )
@@ -27575,75 +27635,39 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 
 	    if ( IS_NOT_EQUAL(yinc, 0) && opt )
 	      {
-	  	fprintf(fp, "yfirst    = %g\n", yfirst);
-		fprintf(fp, "yinc      = %g\n", yinc);
+	  	fprintf(fp, "yfirst    = %g\n"
+                        "yinc      = %g\n", yfirst, yinc);
 	      }
 	    else
 	      {
-		nbyte0 = fprintf(fp, "yvals     = ");
-		nbyte = nbyte0;
-		for ( i = 0; i < ydim; i++ )
-		  {
-		    if ( nbyte > 80 )
-		      {
-			fprintf(fp, "\n");
-			fprintf(fp, "%*s", nbyte0, "");
-			nbyte = nbyte0;
-		      }
-		    nbyte += fprintf(fp, "%.9g ", yvals[i]);
-		  }
-		fprintf(fp, "\n");
+                static const char prefix[] = "yvals     = ";
+                printDblsPrefixAutoBrk(fp, prefix, sizeof (prefix),
+                                       (size_t)(ydim > 0 ? ydim : 0), yvals);
 	      }
 	  }
 
 	if ( ybounds )
 	  {
-	    nbyte0 = fprintf(fp, "ybounds   = ");
-	    for ( i = 0; i < ydim; i++ )
-	      {
-		if ( i ) fprintf(fp, "%*s", nbyte0, "");
-
-		for ( iv = 0; iv < nvertex; iv++ )
-		  fprintf(fp, "%.9g ", ybounds[i*nvertex+iv]);
-		fprintf(fp, "\n");
-	      }
+            static const char prefix[] = "ybounds   = ";
+            printBounds(fp, prefix, sizeof (prefix),
+                        (size_t)(ydim > 0 ? ydim : 0),
+                        (size_t)(nvertex > 0 ? nvertex : 0), ybounds);
 	  }
 
 	if ( area )
 	  {
-	    nbyte0 = fprintf(fp, "area      = ");
-	    nbyte  = nbyte0;
-	    for ( i = 0; i < gridsize; i++ )
-	      {
-		if ( nbyte > 80 )
-		  {
-		    fprintf(fp, "\n");
-		    fprintf(fp, "%*s", nbyte0, "");
-		    nbyte = nbyte0;
-		  }
-		nbyte += fprintf(fp, "%.9g ", area[i]);
-	      }
-	    fprintf(fp, "\n");
+            static const char prefix[] = "area      = ";
+            printDblsPrefixAutoBrk(fp, prefix, sizeof (prefix),
+                                   (size_t)(gridsize > 0 ? gridsize : 0), area);
 	  }
 
         if ( type == GRID_GAUSSIAN_REDUCED )
           {
-            int *rowlon;
-            nbyte0 = fprintf(fp, "rowlon    = ");
-            nbyte  = nbyte0;
-            rowlon = (int *) Malloc((size_t)ysize*sizeof(int));
+            static const char prefix[] = "rowlon    = ";
+            int *rowlon = (int *)Malloc((size_t)ysize*sizeof(int));
             gridInqRowlon(gridID, rowlon);
-            for ( i = 0; i < ysize; i++ )
-              {
-                if ( nbyte > 80 )
-                  {
-                    fprintf(fp, "\n");
-                    fprintf(fp, "%*s", nbyte0, "");
-                    nbyte = nbyte0;
-                  }
-                nbyte += fprintf(fp, "%d ", rowlon[i]);
-              }
-            fprintf(fp, "\n");
+            printIntsPrefixAutoBrk(fp, prefix, sizeof (prefix),
+                                   (size_t)(ysize > 0 ? ysize : 0), rowlon);
             Free(rowlon);
           }
 
@@ -27656,27 +27680,26 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
 		   &projflag, &scanflag);
 
-	fprintf(fp, "xsize     = %d\n", xsize);
-	fprintf(fp, "ysize     = %d\n", ysize);
-
-	fprintf(fp, "originLon = %g\n", originLon);
-	fprintf(fp, "originLat = %g\n", originLat);
-	fprintf(fp, "lonParY   = %g\n", lonParY);
-	fprintf(fp, "lat1      = %g\n", lat1);
-	fprintf(fp, "lat2      = %g\n", lat2);
-	fprintf(fp, "xinc      = %g\n", xincm);
-	fprintf(fp, "yinc      = %g\n", yincm);
-	if ( (projflag & 128) == 0 )
-	  fprintf(fp, "projection = northpole\n");
-	else
-	  fprintf(fp, "projection = southpole\n");
-
+	fprintf(fp,
+                "xsize     = %d\n"
+                "ysize     = %d\n"
+                "originLon = %g\n"
+                "originLat = %g\n"
+                "lonParY   = %g\n"
+                "lat1      = %g\n"
+                "lat2      = %g\n"
+                "xinc      = %g\n"
+                "yinc      = %g\n"
+                "projection = %s\n"
+                , xsize, ysize, originLon, originLat, lonParY, lat1, lat2,
+                xincm, yincm,
+                (projflag & 128) == 0 ? "northpole" : "southpole");
 	break;
       }
     case GRID_SPECTRAL:
       {
-        fprintf(fp, "truncation = %d\n", trunc);
-        fprintf(fp, "complexpacking = %d\n", gridptr->lcomplex );
+        fprintf(fp, "truncation = %d\n"
+                "complexpacking = %d\n", trunc, gridptr->lcomplex );
         break;
       }
     case GRID_FOURIER:
@@ -27700,26 +27723,16 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
   if ( !cdiUUIDIsNull(uuidOfHGrid) )
     {
       char uuidOfHGridStr[37];
-      uuid2str(uuidOfHGrid, uuidOfHGridStr);
+      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
       if ( uuidOfHGridStr[0] != 0 && strlen(uuidOfHGridStr) == 36 )
         fprintf(fp, "uuid      = %s\n", uuidOfHGridStr);
     }
 
   if ( gridptr->mask )
     {
-      nbyte0 = fprintf(fp, "mask      = ");
-      nbyte  = nbyte0;
-      for ( i = 0; i < gridsize; i++ )
-        {
-          if ( nbyte > 80 )
-            {
-              fprintf(fp, "\n");
-              fprintf(fp, "%*s", nbyte0, "");
-              nbyte = nbyte0;
-            }
-          nbyte += fprintf(fp, "%d ", (int) gridptr->mask[i]);
-        }
-      fprintf(fp, "\n");
+      static const char prefix[] = "mask      = ";
+      printMask(fp, prefix, sizeof (prefix),
+                (size_t)(gridsize > 0 ? gridsize : 0), gridptr->mask);
     }
 }
 
@@ -27735,72 +27748,64 @@ void gridPrint ( int gridID, int index, int opt )
 void gridPrintP ( void * voidptr, FILE * fp )
 {
   grid_t * gridptr = ( grid_t * ) voidptr;
-  int nbyte0, nbyte, i;
 
   xassert ( gridptr );
 
   gridPrintKernel ( gridptr , gridptr->self, 0, fp );
 
-  fprintf ( fp, "precision = %d\n", gridptr->prec);
-  fprintf ( fp, "nd        = %d\n", gridptr->nd );
-  fprintf ( fp, "ni        = %d\n", gridptr->ni );
-  fprintf ( fp, "ni2       = %d\n", gridptr->ni2 );
-  fprintf ( fp, "ni3       = %d\n", gridptr->ni3 ); 
-  fprintf ( fp, "number    = %d\n", gridptr->number );
-  fprintf ( fp, "position  = %d\n", gridptr->position );
-  fprintf ( fp, "trunc     = %d\n", gridptr->trunc );
-  fprintf ( fp, "lcomplex  = %d\n", gridptr->lcomplex );
-  fprintf ( fp, "nrowlon   = %d\n", gridptr->nrowlon );
+  fprintf(fp,
+          "precision = %d\n"
+          "nd        = %d\n"
+          "ni        = %d\n"
+          "ni2       = %d\n"
+          "ni3       = %d\n"
+          "number    = %d\n"
+          "position  = %d\n"
+          "trunc     = %d\n"
+          "lcomplex  = %d\n"
+          "nrowlon   = %d\n",
+          gridptr->prec, gridptr->nd, gridptr->ni, gridptr->ni2,
+          gridptr->ni3, gridptr->number, gridptr->position, gridptr->trunc,
+          gridptr->lcomplex, gridptr->nrowlon );
 
   if ( gridptr->rowlon )
     {
-      nbyte0 = fprintf(fp, "rowlon    = ");
-      nbyte  = nbyte0;
-      for ( i = 0; i < gridptr->nrowlon; i++ )
-        {
-          if ( nbyte > 80 )
-            {
-              fprintf(fp, "\n");
-              fprintf(fp, "%*s", nbyte0, "");
-              nbyte = nbyte0;
-            }
-          nbyte += fprintf(fp, "%d ", gridptr->rowlon[i]);
-        }
-      fprintf(fp, "\n");
+      static const char prefix[] = "rowlon    = ";
+      printIntsPrefixAutoBrk(fp, prefix, sizeof (prefix),
+                             (size_t)(gridptr->nrowlon > 0
+                                      ? gridptr->nrowlon : 0), gridptr->rowlon);
     }
 
   if ( gridptr->mask_gme )
     {
-      nbyte0 = fprintf(fp, "mask_gme  = ");
-      nbyte  = nbyte0;
-      for ( i = 0; i < gridptr->size; i++ )
-        {
-          if ( nbyte > 80 )
-            {
-              fprintf(fp, "\n");
-              fprintf(fp, "%*s", nbyte0, "");
-              nbyte = nbyte0;
-            }
-          nbyte += fprintf(fp, "%d ", (int) gridptr->mask_gme[i]);
-        }
-      fprintf(fp, "\n");
+      static const char prefix[] = "mask_gme  = ";
+      printMask(fp, prefix, sizeof (prefix),
+                (size_t)(gridptr->size > 0 ? gridptr->size : 0),
+                gridptr->mask_gme);
     }
 }
 
+static const double *gridInqXValsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->xvals;
+}
 
 const double *gridInqXvalsPtr(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  return ( gridptr->xvals );
+  return gridptr->vtable->inqXValsPtr(gridptr);
 }
 
 
+static const double *gridInqYValsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->yvals;
+}
+
 const double *gridInqYvalsPtr(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  return ( gridptr->yvals );
+  return gridptr->vtable->inqYValsPtr(gridptr);
 }
 
 /*
@@ -27846,7 +27851,7 @@ void gridDefLCC(int gridID, double originLon, double originLat, double lonParY,
       gridptr->lcc_projflag  = projflag;
       gridptr->lcc_scanflag  = scanflag;
       gridptr->lcc_defined   = TRUE;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -27915,7 +27920,7 @@ void gridDefLcc2(int gridID, double earth_radius, double lon_0, double lat_0, do
       gridptr->lcc2_lat_1   = lat_1;
       gridptr->lcc2_lat_2   = lat_2;
       gridptr->lcc2_defined = TRUE;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -27955,7 +27960,7 @@ void gridDefLaea(int gridID, double earth_radius, double lon_0, double lat_0)
       gridptr->laea_lon_0   = lon_0;
       gridptr->laea_lat_0   = lat_0;
       gridptr->laea_defined = TRUE;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -27988,8 +27993,8 @@ void gridDefComplexPacking(int gridID, int lcomplex)
 
   if (gridptr->lcomplex != lcomplex)
     {
-      gridptr->lcomplex = lcomplex;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridptr->lcomplex = (short)(lcomplex != 0);
+      gridMark4Update(gridID);
     }
 }
 
@@ -28006,10 +28011,10 @@ void gridDefHasDims(int gridID, int hasdims)
 {
   grid_t* gridptr = gridID2Ptr(gridID);
 
-  if (gridptr->hasdims != hasdims)
+  if (gridptr->hasdims != (hasdims != 0))
     {
-      gridptr->hasdims = hasdims;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridptr->hasdims = hasdims != 0;
+      gridMark4Update(gridID);
     }
 }
 
@@ -28042,7 +28047,7 @@ void gridDefNumber(int gridID, const int number)
   if (gridptr->number != number)
     {
       gridptr->number = number;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -28064,8 +28069,7 @@ The function @func{gridInqNumber} returns the reference number to an unstructure
 int gridInqNumber(int gridID)
 {
   grid_t* gridptr = gridID2Ptr(gridID);
-
-  return (gridptr->number);
+  return gridptr->number;
 }
 
 /*
@@ -28089,7 +28093,7 @@ void gridDefPosition(int gridID, int position)
   if (gridptr->position != position)
     {
       gridptr->position = position;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -28142,7 +28146,7 @@ void gridDefReference(int gridID, const char *reference)
         }
 
       gridptr->reference = strdupx(reference);
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -28193,7 +28197,7 @@ void gridDefUUID(int gridID, const unsigned char uuid[CDI_UUID_SIZE])
   grid_t* gridptr = gridID2Ptr(gridID);
 
   memcpy(gridptr->uuid, uuid, CDI_UUID_SIZE);
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+  gridMark4Update(gridID);
 }
 
 /*
@@ -28231,7 +28235,7 @@ gridTxCode ()
   return GRID;
 }
 
-enum { gridNint    = 27,
+enum { gridNint    = 28,
        gridNdouble = 24,
        gridHasMaskFlag = 1 << 0,
        gridHasGMEMaskFlag = 1 << 1,
@@ -28250,9 +28254,13 @@ static int gridGetComponentFlags(const grid_t * gridP)
 {
   int flags = (gridHasMaskFlag & (int)((unsigned)(gridP->mask == NULL) - 1U))
     | (gridHasGMEMaskFlag & (int)((unsigned)(gridP->mask_gme == NULL) - 1U))
-    | (gridHasXValsFlag & (int)((unsigned)(gridP->xvals == NULL) - 1U))
-    | (gridHasYValsFlag & (int)((unsigned)(gridP->yvals == NULL) - 1U))
-    | (gridHasAreaFlag & (int)((unsigned)(gridP->area == NULL) - 1U))
+    | (gridHasXValsFlag
+       & (int)((unsigned)(gridP->vtable->inqXValsPtr((grid_t *)gridP) == NULL) - 1U))
+    | (gridHasYValsFlag
+       & (int)((unsigned)(gridP->vtable->inqYValsPtr((grid_t *)gridP) == NULL) - 1U))
+    | (gridHasAreaFlag
+       & (int)((unsigned)(gridP->vtable->inqAreaPtr((grid_t *)gridP) == NULL)
+               - 1U))
     | (gridHasXBoundsFlag & (int)((unsigned)(gridP->xbounds == NULL) - 1U))
     | (gridHasYBoundsFlag & (int)((unsigned)(gridP->ybounds == NULL) - 1U))
     | (gridHasReferenceFlag & (int)((unsigned)(gridP->reference == NULL) - 1U))
@@ -28262,9 +28270,8 @@ static int gridGetComponentFlags(const grid_t * gridP)
 }
 
 
-#define GRID_STR_SERIALIZE { gridP->xname, gridP->yname, \
+#define GRID_STR_SERIALIZE(gridP) { gridP->xname, gridP->yname, \
     gridP->xlongname, gridP->ylongname, \
-    gridP->xstdname, gridP->ystdname, \
     gridP->xunits, gridP->yunits }
 
 static int
@@ -28285,7 +28292,7 @@ gridGetPackSize(void * voidP, void *context)
 
   packBuffSize += serializeGetSize(gridNdouble, DATATYPE_FLT64, context);
 
-  if (gridP->xvals)
+  if (gridP->vtable->inqXValsPtr(gridP))
     {
       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
 	count = gridP->size;
@@ -28296,7 +28303,7 @@ gridGetPackSize(void * voidP, void *context)
         + serializeGetSize(1, DATATYPE_UINT32, context);
     }
 
-  if (gridP->yvals)
+  if (gridP->vtable->inqYValsPtr(gridP))
     {
       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
 	count = gridP->size;
@@ -28307,7 +28314,7 @@ gridGetPackSize(void * voidP, void *context)
         + serializeGetSize(1, DATATYPE_UINT32, context);
     }
 
-  if (gridP->area)
+  if (gridP->vtable->inqAreaPtr(gridP))
     {
       xassert(gridP->size);
       packBuffSize +=
@@ -28342,7 +28349,7 @@ gridGetPackSize(void * voidP, void *context)
     }
 
   {
-    const char *strTab[] = GRID_STR_SERIALIZE;
+    const char *strTab[] = GRID_STR_SERIALIZE(gridP);
     int numStr = (int)(sizeof (strTab) / sizeof (strTab[0]));
     packBuffSize
       += serializeStrTabGetPackSize(strTab, numStr, context);
@@ -28424,9 +28431,10 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
     gridP->size          =   intBuffer[21];
     gridP->xsize         =   intBuffer[22];
     gridP->ysize         =   intBuffer[23];
-    gridP->locked        =   intBuffer[24];
-    gridP->lcomplex      =   intBuffer[25];
-    memberMask           =   intBuffer[26];
+    gridP->lcomplex      =   (short)intBuffer[24];
+    memberMask           =   intBuffer[25];
+    gridP->xstdname      =   xystdname_tab[intBuffer[26]][0];
+    gridP->ystdname      =   xystdname_tab[intBuffer[27]][1];
   }
 
   if (memberMask & gridHasRowLonFlag)
@@ -28539,7 +28547,7 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
     }
 
   {
-    char *strTab[] = GRID_STR_SERIALIZE;
+    char *strTab[] = GRID_STR_SERIALIZE(gridP);
     int numStr = sizeof (strTab) / sizeof (strTab[0]);
     serializeStrTabUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
                           strTab, numStr, context);
@@ -28626,9 +28634,12 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
     intBuffer[21] = gridP->size;
     intBuffer[22] = gridP->xsize;
     intBuffer[23] = gridP->ysize;
-    intBuffer[24] = gridP->locked;
-    intBuffer[25] = gridP->lcomplex;
-    intBuffer[26] = memberMask = gridGetComponentFlags(gridP);
+    intBuffer[24] = gridP->lcomplex;
+    intBuffer[25] = memberMask = gridGetComponentFlags(gridP);
+    intBuffer[26] = (int)((const char (*)[2][24])gridP->xstdname
+                          - xystdname_tab);
+    intBuffer[27] = (int)((const char (*)[2][24])gridP->ystdname
+                          - (const char (*)[2][24])xystdname_tab[0][1]);
 
     serializePack(intBuffer, gridNint, DATATYPE_INT,
                   packBuffer, packBufferSize, packBufferPos, context);
@@ -28691,9 +28702,10 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
 	size = gridP->xsize;
       xassert(size);
 
-      serializePack(gridP->xvals, size, DATATYPE_FLT64,
+      const double *gridP_xvals = gridP->vtable->inqXValsPtr(gridP);
+      serializePack(gridP_xvals, size, DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP->xvals);
+      d = cdiCheckSum(DATATYPE_FLT, size, gridP_xvals);
       serializePack(&d, 1, DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
@@ -28705,9 +28717,10 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
       else
 	size = gridP->ysize;
       xassert(size);
-      serializePack(gridP->yvals, size, DATATYPE_FLT64,
+      const double *gridP_yvals = gridP->vtable->inqYValsPtr(gridP);
+      serializePack(gridP_yvals, size, DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP->yvals);
+      d = cdiCheckSum(DATATYPE_FLT, size, gridP_yvals);
       serializePack(&d, 1, DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
@@ -28756,7 +28769,7 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
     }
 
   {
-    const char *strTab[] = GRID_STR_SERIALIZE;
+    const char *strTab[] = GRID_STR_SERIALIZE(gridP);
     int numStr = sizeof (strTab) / sizeof (strTab[0]);
     serializeStrTabPack(strTab, numStr,
                         packBuffer, packBufferSize, packBufferPos, context);
@@ -28803,16 +28816,16 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
 #undef GRID_STR_SERIALIZE
 
 
-struct varDefGridSearchState
+struct gridCompareSearchState
 {
   int resIDValue;
   const grid_t *queryKey;
 };
 
 static enum cdiApplyRet
-varDefGridSearch(int id, void *res, void *data)
+gridCompareSearch(int id, void *res, void *data)
 {
-  struct varDefGridSearchState *state = (struct varDefGridSearchState*)data;
+  struct gridCompareSearchState *state = (struct gridCompareSearchState*)data;
   (void)res;
   if (gridCompare(id, state->queryKey) == 0)
     {
@@ -28823,40 +28836,43 @@ varDefGridSearch(int id, void *res, void *data)
     return CDI_APPLY_GO_ON;
 }
 
-int varDefGrid(int vlistID, const grid_t *grid, int mode)
+/* Add grid (which must be Malloc'ed to vlist if not already found */
+struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
 {
   /*
     mode: 0 search in vlist and grid table
           1 search in grid table
    */
   int gridglobdefined = FALSE;
-  int griddefined;
+  int griddefined = FALSE;
   int gridID = CDI_UNDEFID;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  griddefined = FALSE;
   unsigned ngrids = (unsigned)vlistptr->ngrids;
 
   if ( mode == 0 )
     for (unsigned index = 0; index < ngrids; index++ )
       {
-	gridID = vlistptr->gridIDs[index];
-	if ( gridID == UNDEFID )
-	  Error("Internal problem: undefined gridID %d!", gridID);
+	if ( (gridID = vlistptr->gridIDs[index]) != UNDEFID )
+          {
+            if ( gridCompare(gridID, grid) == 0 )
+              {
+                griddefined = TRUE;
+                break;
+              }
+          }
+        else
+          Error("Internal problem: undefined gridID in vlist "
+                "%d, position %u!", vlistID, index);
 
-	if ( gridCompare(gridID, grid) == 0 )
-	  {
-	    griddefined = TRUE;
-	    break;
-	  }
       }
 
   if ( ! griddefined )
     {
-      struct varDefGridSearchState query;
+      struct gridCompareSearchState query;
       query.queryKey = grid;// = { .queryKey = grid };
       if ((gridglobdefined
-           = (cdiResHFilterApply(&gridOps, varDefGridSearch, &query)
+           = (cdiResHFilterApply(&gridOps, gridCompareSearch, &query)
               == CDI_APPLY_STOP)))
         gridID = query.resIDValue;
 
@@ -28871,14 +28887,50 @@ int varDefGrid(int vlistID, const grid_t *grid, int mode)
 
   if ( ! griddefined )
     {
-      if ( ! gridglobdefined ) gridID = gridGenerate(grid);
-      ngrids = (unsigned)vlistptr->ngrids;
+      if ( ! gridglobdefined )
+        {
+          grid->self = gridID = reshPut(grid, &gridOps);
+          gridComplete(grid);
+        }
       vlistptr->gridIDs[ngrids] = gridID;
       vlistptr->ngrids++;
     }
 
-  return (gridID);
-}
+  return (struct addIffNewRes){ .Id = gridID,
+      .isNew = !griddefined && !gridglobdefined };
+}
+
+const struct gridVirtTable cdiGridVtable
+  = {
+  .destroy = gridDestroyKernel,
+  .copy = grid_copy_base,
+  .copyScalarFields = grid_copy_base_scalar_fields,
+  .copyArrayFields = grid_copy_base_array_fields,
+  .defXVals = gridDefXValsSerial,
+  .defYVals = gridDefYValsSerial,
+  .defMask = gridDefMaskSerial,
+  .defMaskGME = gridDefMaskGMESerial,
+  .defXBounds = gridDefXBoundsSerial,
+  .defYBounds = gridDefYBoundsSerial,
+  .defArea = gridDefAreaSerial,
+  .inqXVal = gridInqXValSerial,
+  .inqYVal = gridInqYValSerial,
+  .inqXVals = gridInqXValsSerial,
+  .inqYVals = gridInqYValsSerial,
+  .inqXValsPtr = gridInqXValsPtrSerial,
+  .inqYValsPtr = gridInqYValsPtrSerial,
+  .compareXYFull = compareXYvals,
+  .compareXYAO = compareXYvals2,
+  .inqArea = gridInqAreaSerial,
+  .inqAreaPtr = gridInqAreaPtrBase,
+  .hasArea = gridHasAreaBase,
+  .inqMask = gridInqMaskSerial,
+  .inqMaskGME = gridInqMaskGMESerial,
+  .inqXBounds = gridInqXBoundsSerial,
+  .inqYBounds = gridInqYBoundsSerial,
+  .inqXBoundsPtr = gridInqXBoundsPtrSerial,
+  .inqYBoundsPtr = gridInqYBoundsPtrSerial,
+};
 
 /*
  * Local Variables:
@@ -29180,15 +29232,9 @@ int iegInqDataDP(void *ieg, double *data)
 static int
 iegDefData(iegrec_t *iegp, int prec, const void *data)
 {
-  int dprec;
-  void *buffer;
+  int dprec = iegDefaultDprec ? iegDefaultDprec : iegp->dprec;
 
-  if ( iegDefaultDprec ) dprec = iegDefaultDprec;
-  else                   dprec = iegp->dprec;
-
-  if ( ! dprec ) dprec = prec;
-
-  iegp->dprec = dprec;
+  iegp->dprec = dprec = dprec ? dprec : prec;
 
   size_t datasize = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
   size_t blocklen = datasize * (size_t)dprec;
@@ -29197,16 +29243,14 @@ iegDefData(iegrec_t *iegp, int prec, const void *data)
 
   size_t buffersize = iegp->buffersize;
 
+  void *buffer = iegp->buffer;
   if ( buffersize != blocklen )
     {
       buffersize = blocklen;
-      buffer = iegp->buffer;
       buffer = Realloc(buffer, buffersize);
       iegp->buffer = buffer;
       iegp->buffersize = buffersize;
     }
-  else
-    buffer = iegp->buffer;
 
   switch ( dprec )
     {
@@ -29782,7 +29826,7 @@ void instituteDefaultEntries ( void )
     = { ECMWF   = institutDef( 98,   0, "ECMWF",     "European Centre for Medium-Range Weather Forecasts"),
         MPIMET  = institutDef( 98, 232, "MPIMET",    "Max-Planck-Institute for Meteorology"),
         institutDef( 98, 255, "MPIMET",    "Max-Planck-Institute for Meteorology"),
-        institutDef( 98, 232, "MPIMET",    "Max-Planck Institute for Meteorology"),
+        institutDef( 98, 232, "MPIMET",    "Max Planck Institute for Meteorology"),
         institutDef( 78,   0, "DWD",       "Deutscher Wetterdienst"),
         institutDef( 78, 255, "DWD",       "Deutscher Wetterdienst"),
         MCH     = institutDef(215, 255, "MCH",       "MeteoSwiss"),
@@ -30149,11 +30193,13 @@ CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *me);
 
 int cdiFallbackIterator_nextField(CdiIterator *me);
 
-char *cdiFallbackIterator_inqTime(CdiIterator *me, bool getEndTime);
+char *cdiFallbackIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
 int cdiFallbackIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
 int cdiFallbackIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
 int cdiFallbackIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
 char *cdiFallbackIterator_copyVariableName(CdiIterator *me);
+int cdiFallbackIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute);
+int cdiFallbackIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount);
 
 void cdiFallbackIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
 void cdiFallbackIterator_readFieldF(CdiIterator *me, float *buffer, size_t *nmiss);
@@ -30195,10 +30241,12 @@ CdiGribIterator *cdiGribIterator_deserialize(const char *me);
 
 int cdiGribIterator_nextField(CdiIterator *me);
 
-char *cdiGribIterator_inqTime(CdiIterator *me, bool getEndTime);
+char *cdiGribIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
 int cdiGribIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
 int cdiGribIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
 int cdiGribIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
+int cdiGribIterator_inqTile(CdiIterator *me, int *outTileIndex, int *outTileAttribute);
+int cdiGribIterator_inqTileCount(CdiIterator *me, int *outTileCount, int *outTileAttributeCount);
 char *cdiGribIterator_copyVariableName(CdiIterator *me);
 
 void cdiGribIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
@@ -30644,7 +30692,7 @@ int cdiIterator_nextField(CdiIterator* me)
     }
 }
 
-static char* cdiIterator_inqTime(CdiIterator* me, bool getEndTime)
+static char* cdiIterator_inqTime(CdiIterator* me, CdiTimeType timeType)
 {
   sanityCheck(me);
   switch(me->filetype)
@@ -30652,7 +30700,7 @@ static char* cdiIterator_inqTime(CdiIterator* me, bool getEndTime)
 #ifdef HAVE_LIBGRIB_API
         case FILETYPE_GRB:
         case FILETYPE_GRB2:
-          return cdiGribIterator_inqTime(me, getEndTime);
+          return cdiGribIterator_inqTime(me, timeType);
 #endif
 
 #ifdef HAVE_LIBNETCDF
@@ -30670,7 +30718,7 @@ static char* cdiIterator_inqTime(CdiIterator* me, bool getEndTime)
 #ifdef HAVE_LIBIEG
         case FILETYPE_IEG:
 #endif
-          return cdiFallbackIterator_inqTime(me, getEndTime);
+          return cdiFallbackIterator_inqTime(me, timeType);
 
       default:
         Error(kUnexpectedFileTypeMessage);
@@ -30701,7 +30749,7 @@ This is due to the fact that GRIB-API version 1.12.3 still does not implement th
 */
 char* cdiIterator_inqStartTime(CdiIterator* me)
 {
-  return cdiIterator_inqTime(me, false);
+  return cdiIterator_inqTime(me, kCdiTimeType_startTime);
 }
 
 /*
@@ -30727,7 +30775,34 @@ This is due to the fact that GRIB-API version 1.12.3 still does not implement th
 */
 char* cdiIterator_inqEndTime(CdiIterator* me)
 {
-  return cdiIterator_inqTime(me, true);
+  return cdiIterator_inqTime(me, kCdiTimeType_endTime);
+}
+
+/*
+ at Function cdiIterator_inqRTime
+ at Title Get the validity time of the current field
+
+ at Prototype char* cdiIterator_inqRTime(CdiIterator* me)
+ at Parameter
+    @item iterator The iterator to operate on.
+
+ at Result A malloc'ed string containing the validity time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
+
+ at Description
+The returned time is the validity time as it is returned by taxisInqVtime(), only more precise.
+That is, if the field is a time point, its time is returned,
+if it is a statistical field with an integration period, the end time of the integration period is returned.
+
+Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
+The caller is responsible to Free() the resulting string.
+
+If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
+as it is implemented by the standard C mktime() function.
+This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
+*/
+char* cdiIterator_inqRTime(CdiIterator* me)
+{
+  return cdiIterator_inqTime(me, kCdiTimeType_referenceTime);
 }
 
 /*
@@ -30912,6 +30987,105 @@ int cdiIterator_inqLevelUuid(CdiIterator* me, int* outVgridNumber, int* outLevel
 }
 
 /*
+ at Function cdiIterator_inqTile
+ at Title Inquire the tile information for the current field
+
+ at Prototype int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute)
+ at Parameter
+    @item iterator The iterator to operate on.
+    @item outTileIndex The index of the current tile, -1 if no tile information is available.
+    @item outTileAttribute The attribute of the current tile, -1 if no tile information is available.
+
+ at Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
+
+ at Description
+Inquire the tile index and attribute for the current field.
+*/
+int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute)
+{
+  sanityCheck(me);
+  switch(me->filetype)
+    {
+      #ifdef HAVE_LIBGRIB_API
+        case FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_inqTile(me, outTileIndex, outTileAttribute);
+      #endif
+
+      #ifdef HAVE_LIBNETCDF
+        case FILETYPE_NC:
+        case FILETYPE_NC2:
+        case FILETYPE_NC4:
+        case FILETYPE_NC4C:
+      #endif
+      #ifdef HAVE_LIBSERVICE
+        case FILETYPE_SRV:
+      #endif
+      #ifdef HAVE_LIBEXTRA
+        case FILETYPE_EXT:
+      #endif
+      #ifdef HAVE_LIBIEG
+        case FILETYPE_IEG:
+      #endif
+          return cdiFallbackIterator_inqTile(me, outTileIndex, outTileAttribute);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_ELIBNAVAIL;
+    }
+}
+
+/**
+ at Function cdiIterator_inqTileCount
+ at Title Inquire the tile count and tile attribute counts for the current field
+
+ at Prototype int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount)
+ at Parameter
+    @item iterator The iterator to operate on.
+    @item outTileCount The number of tiles used for this variable, zero if no tile information is available.
+    @item outTileAttributeCount The number of attributes available for the tile of this field, zero if no tile information is available.
+          Note: This is not the global attribute count, which would be impossible to infer without reading the entire file if it's a GRIB file.
+
+ at Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
+
+ at Description
+Inquire the tile count and tile attribute counts for the current field.
+*/
+int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount)
+{
+  sanityCheck(me);
+  switch(me->filetype)
+    {
+      #ifdef HAVE_LIBGRIB_API
+        case FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
+      #endif
+
+      #ifdef HAVE_LIBNETCDF
+        case FILETYPE_NC:
+        case FILETYPE_NC2:
+        case FILETYPE_NC4:
+        case FILETYPE_NC4C:
+      #endif
+      #ifdef HAVE_LIBSERVICE
+        case FILETYPE_SRV:
+      #endif
+      #ifdef HAVE_LIBEXTRA
+        case FILETYPE_EXT:
+      #endif
+      #ifdef HAVE_LIBIEG
+        case FILETYPE_IEG:
+      #endif
+          return cdiFallbackIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_ELIBNAVAIL;
+    }
+}
+
+/*
 @Function cdiIterator_inqParam
 @Title Get discipline, category, and number
 
@@ -30931,6 +31105,31 @@ CdiParam cdiIterator_inqParam(CdiIterator* me)
 }
 
 /*
+ at Function cdiIterator_inqParamParts
+ at Title Get discipline, category, and number
+
+ at Prototype void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber)
+ at Parameter
+    @item iterator The iterator to operate on.
+    @item outDiscipline This is used to return the discipline.
+    @item outCategory This is used to return the category.
+    @item outNumber This is used to return the number.
+
+ at Description
+    Simple metadata inspection function.
+
+    Some FORTRAN compilers produce wrong code for the cdiIterator_inqParam()-wrapper,
+    rendering it unusable from FORTRAN. This function is the workaround.
+*/
+void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber)
+{
+  CdiParam result = cdiIterator_inqParam(me);
+  if(outDiscipline) *outDiscipline = result.discipline;
+  if(outCategory) *outCategory = result.category;
+  if(outNumber) *outNumber = result.number;
+}
+
+/*
 @Function cdiIterator_inqDatatype
 @Title Get the datatype of the current field
 
@@ -31203,11 +31402,12 @@ void baseIterDestruct(CdiIterator* me)
 
 struct CdiFallbackIterator {
   CdiIterator super;
-  int streamId, vlistId;
+  int streamId, vlistId, subtypeId;
   char *path;   //needed for clone() & serialize()
 
   int variableCount, curVariable;
   int curLevelCount, curLevel;
+  int curSubtypeCount, curSubtype;
   int curTimestep;
 };
 
@@ -31231,12 +31431,15 @@ static CdiFallbackIterator *cdiFallbackIterator_condestruct(CdiFallbackIterator
   if(me->vlistId == CDI_UNDEFID) goto closeStream;
   me->variableCount = vlistNvars(me->vlistId);
   if(me->variableCount <= 0) goto closeStream;
+  me->subtypeId = CDI_UNDEFID;   //Will be set in cdiFallbackIterator_nextField()
+  me->curSubtypeCount = -1;      //Will be set in cdiFallbackIterator_nextField()
   me->curLevelCount = -1;        //Will be set in cdiFallbackIterator_nextField()
 
   //These values are chosen so that the natural increment at the start of cdiFallbackIterator_nextField() will correctly position us at the first slice.
   me->curTimestep = 0;
   if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
-  me->curVariable = 0;
+  me->curVariable = -1;
+  me->curSubtype = -1;
   me->curLevel = -1;
   me->path = strdup(path);
   if(!me->path) goto closeStream;
@@ -31262,14 +31465,20 @@ CdiIterator *cdiFallbackIterator_new(const char *path, int filetype)
   return &cdiFallbackIterator_condestruct(NULL, path, filetype)->super;
 }
 
-//Fetches the info that is published by the variables in the base class from the current field.
-static void fetchSuperInfo(CdiFallbackIterator *me)
+//Fetches the info that is derived from the current variable. Most of this is published by the data members in the base class.
+static void fetchVariableInfo(CdiFallbackIterator *me)
 {
+  //Fetch data that's published via base class data members.
   me->super.datatype = vlistInqVarDatatype(me->vlistId, me->curVariable);
   me->super.timesteptype = vlistInqVarTsteptype(me->vlistId, me->curVariable);
   me->super.gridId = vlistInqVarGrid(me->vlistId, me->curVariable);
   int param = vlistInqVarParam(me->vlistId, me->curVariable);
   cdiDecodeParam(param, &me->super.param.number, &me->super.param.category, &me->super.param.discipline);
+
+  //Fetch the current level and subtype counts.
+  me->curLevelCount = zaxisInqSize(vlistInqVarZaxis(me->vlistId, me->curVariable));
+  me->subtypeId = vlistInqVarSubtype(me->vlistId, me->curVariable);
+  me->curSubtypeCount = (me->subtypeId == CDI_UNDEFID) ? 1 : subtypeInqSize(me->subtypeId);
 }
 
 CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *super)
@@ -31285,10 +31494,12 @@ CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *super)
   clone->curVariable = me->curVariable;
   clone->curLevelCount = me->curLevelCount;
   clone->curLevel = me->curLevel;
+  clone->curSubtypeCount = me->curSubtypeCount;
+  clone->curSubtype = me->curSubtype;
   clone->curTimestep = me->curTimestep;
 
   clone->super.isAdvanced = super->isAdvanced;
-  if(super->isAdvanced) fetchSuperInfo(clone);
+  if(super->isAdvanced) fetchVariableInfo(clone);
 
   return clone;
 }
@@ -31299,8 +31510,8 @@ char *cdiFallbackIterator_serialize(CdiIterator *super)
 
   char *escapedPath = cdiEscapeSpaces(me->path);
   char *result = (char *) Malloc(strlen(escapedPath)
-                         + 5 * (3 * sizeof (int) * CHAR_BIT / 8 + 1) + 1);
-  sprintf(result, "%s %d %d %d %d %d", escapedPath, me->variableCount, me->curVariable, me->curLevelCount, me->curLevel, me->curTimestep);
+                         + 7 * (3 * sizeof (int) * CHAR_BIT / 8 + 1) + 1);
+  sprintf(result, "%s %d %d %d %d %d %d %d", escapedPath, me->variableCount, me->curVariable, me->curLevelCount, me->curLevel, me->curSubtypeCount, me->curSubtype, me->curTimestep);
   Free(escapedPath);
   return result;
 }
@@ -31334,11 +31545,13 @@ CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *description)
   decodeValue(me->curVariable, description);
   decodeValue(me->curLevelCount, description);
   decodeValue(me->curLevel, description);
+  decodeValue(me->curSubtypeCount, description);
+  decodeValue(me->curSubtype, description);
   decodeValue(me->curTimestep, description);
 #undef decodeValue
 
   if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
-  if(me->super.isAdvanced) fetchSuperInfo(me);
+  if(me->super.isAdvanced) fetchVariableInfo(me);
 
   return me;
 
@@ -31356,15 +31569,20 @@ fail:
 static int advance(CdiFallbackIterator *me)
 {
   me->curLevel++;
-  if(me->curLevel == me->curLevelCount)
+  if(me->curLevel >= me->curLevelCount)
     {
       me->curLevel = 0;
-      me->curVariable++;
-      if(me->curVariable == me->variableCount)
+      me->curSubtype++;
+      if(me->curSubtype >= me->curSubtypeCount)
         {
-          me->curVariable = 0;
-          me->curTimestep++;
-          if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) return CDI_EEOF;
+          me->curSubtype = 0;
+          me->curVariable++;
+          if(me->curVariable >= me->variableCount)
+            {
+              me->curVariable = 0;
+              me->curTimestep++;
+              if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) return CDI_EEOF;
+            }
         }
     }
   return CDI_NOERR;
@@ -31376,21 +31594,37 @@ int cdiFallbackIterator_nextField(CdiIterator *super)
   int result = advance(me);
   if(result) return result;
 
-  if(!me->curLevel)
-    { //Fetch the information that may have changed (we are processing a new variable/timestep if this point is reached).
-      fetchSuperInfo(me);
-      me->curLevelCount = zaxisInqSize(vlistInqVarZaxis(me->vlistId, me->curVariable));
-    }
+  if(!me->curLevel && !me->curSubtype) fetchVariableInfo(me);   //Check whether we are processing a new variable/timestep and fetch the information that may have changed in this case.
   return CDI_NOERR;
 }
 
-char *cdiFallbackIterator_inqTime(CdiIterator *super, bool getEndTime)
+char *cdiFallbackIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
 {
   CdiFallbackIterator *me = (CdiFallbackIterator *)(void *)super;
-  if(getEndTime) return NULL;   //The stream interface does not export the start/end times of statistical fields, so we treat all data as point of time data, returning the validity time as the start time.
+
+  //retrieve the time information
   int taxisId = vlistInqTaxis(me->vlistId);
-  int date = taxisInqVdate(taxisId);
-  int time = taxisInqVtime(taxisId);
+  int date = 0, time = 0;
+  switch(timeType)
+    {
+      case kCdiTimeType_referenceTime:
+        date = taxisInqRdate(taxisId);
+        time = taxisInqRtime(taxisId);
+        break;
+
+      case kCdiTimeType_startTime:
+        date = taxisInqVdate(taxisId);
+        time = taxisInqVtime(taxisId);
+        break;
+
+      case kCdiTimeType_endTime:
+        return NULL;   //The stream interface does not export the start/end times of statistical fields, so we treat all data as point of time data, returning the validity time as the start time.
+
+      default:
+        assert(0 && "internal error, please report this bug");
+    }
+
+  //decode the time information and reencode it into an ISO-compliant string
   int year, month, day, hour, minute, second;
   cdiDecodeDate(date, &year, &month, &day);
   cdiDecodeTime(time, &hour, &minute, &second);
@@ -31470,6 +31704,58 @@ int cdiFallbackIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *
   return CDI_NOERR;
 }
 
+int cdiFallbackIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
+{
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+#ifndef __cplusplus
+  if(!outTileIndex) outTileIndex = &(int){0};
+  if(!outTileAttribute) outTileAttribute = &(int){0};
+#else
+  int dummy = 0;
+  if(!outTileIndex) outTileIndex = &dummy;
+  if(!outTileAttribute) outTileAttribute = &dummy;
+#endif
+
+  int error = CDI_NOERR;
+  if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
+    {
+      error = CDI_EINVAL;
+    }
+  else
+    {
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileIndex", outTileIndex)) error = CDI_EINVAL;
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileAttribute", outTileAttribute)) error = CDI_EINVAL;
+    }
+  if(error) *outTileIndex = *outTileAttribute = -1; //Guarantee defined values in case of an error.
+  return error;
+}
+
+int cdiFallbackIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
+{
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+#ifndef __cplusplus
+  if(!outTileCount) outTileCount = &(int){0};
+  if(!outTileAttributeCount) outTileAttributeCount = &(int){0};
+#else
+  int temp = 0;
+  if(!outTileCount) outTileCount = &temp;
+  if(!outTileAttributeCount) outTileAttributeCount = &temp;
+#endif
+
+  int error = CDI_NOERR;
+  if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
+    {
+      error = CDI_EINVAL;
+    }
+  else
+    {
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTiles", outTileCount)) error = CDI_EINVAL;
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTileAttributes", outTileAttributeCount)) error = CDI_EINVAL;
+    }
+  if(error) *outTileCount = *outTileAttributeCount = -1; //Guarantee defined values in case of an error.
+  return CDI_NOERR;
+}
+
 char *cdiFallbackIterator_copyVariableName(CdiIterator *super)
 {
   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
@@ -31512,19 +31798,19 @@ void cdiFallbackIterator_delete(CdiIterator *super)
 
 int   grbBitsPerValue(int datatype);
 
-int   grbInqContents(stream_t * streamptr);
-int   grbInqTimestep(stream_t * streamptr, int tsID);
+int   grbInqContents(stream_t *streamptr);
+int   grbInqTimestep(stream_t *streamptr, int tsID);
 
-int   grbInqRecord(stream_t * streamptr, int *varID, int *levelID);
-void  grbDefRecord(stream_t * streamptr);
-void  grbReadRecord(stream_t * streamptr, double *data, int *nmiss);
-void  grb_write_record(stream_t * streamptr, int memtype, const void *data, int nmiss);
-void  grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1);
+int   grbInqRecord(stream_t *streamptr, int *varID, int *levelID);
+void  grbDefRecord(stream_t *streamptr);
+void  grb_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss);
+void  grb_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss);
+void  grbCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
 
-void  grbReadVarDP(stream_t * streamptr, int varID, double *data, int *nmiss);
-void  grb_write_var(stream_t * streamptr, int varID, int memtype, const void *data, int nmiss);
+void  grb_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss);
+void  grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss);
 
-void  grbReadVarSliceDP(stream_t * streamptr, int varID, int levelID, double *data, int *nmiss);
+void  grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss);
 void  grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss);
 
 int   grib1ltypeToZaxisType(int grib_ltype);
@@ -31585,14 +31871,14 @@ const resOps *getZaxisOps(void);
 struct CdiGribIterator {
   CdiIterator super;
 
-  CdiInputFile* file;
+  CdiInputFile *file;
   off_t fileOffset;
-  unsigned char* gribBuffer;
+  unsigned char *gribBuffer;
   size_t bufferSize, curRecordSize;
 #ifdef HAVE_LIBGRIB_API
-  grib_handle* gribHandle;
+  grib_handle *gribHandle;
 #else
-  void* gribHandle;
+  void *gribHandle;
 #endif
 };
 
@@ -31652,7 +31938,7 @@ CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *super)
   CdiGribIterator *me = (CdiGribIterator*)super;
 
   //Allocate memory and copy data. (operations that may fail)
-  CdiGribIterator* result = (struct CdiGribIterator *) Malloc(sizeof(*result));
+  CdiGribIterator *result = (struct CdiGribIterator *) Malloc(sizeof(*result));
   if(!result) goto fail;
 
   result->file = me->file;
@@ -31703,9 +31989,9 @@ char *cdiGribIterator_serialize(CdiIterator *super)
 {
   CdiGribIterator *me = (CdiGribIterator*)super;
 
-  const char* path = cdiInputFile_getPath(me->file);
-  char* escapedPath = cdiEscapeSpaces(path);
-  char* result = (char *) Malloc(strlen(escapedPath) + 3 * sizeof(int) * CHAR_BIT/8);
+  const char *path = cdiInputFile_getPath(me->file);
+  char *escapedPath = cdiEscapeSpaces(path);
+  char *result = (char *) Malloc(strlen(escapedPath) + 3 * sizeof(int) * CHAR_BIT/8);
   sprintf(result, "%s %zu", escapedPath, me->fileOffset);
   Free(escapedPath);
   return result;
@@ -31714,8 +32000,8 @@ char *cdiGribIterator_serialize(CdiIterator *super)
 
 CdiGribIterator *cdiGribIterator_deserialize(const char *description)
 {
-  char* path;
-  CdiGribIterator* me = (CdiGribIterator *) Malloc(sizeof(*me));
+  char *path;
+  CdiGribIterator *me = (CdiGribIterator *) Malloc(sizeof(*me));
   if(!me) goto fail;
 
   description = baseIter_constructFromString(&me->super, description);
@@ -31800,7 +32086,7 @@ static ssize_t scanToGribMarker(CdiGribIterator *me)
       if(scannedBytes + scanSize > kMaxScanSize) scanSize = kMaxScanSize - scannedBytes;
       assert(scanSize <= me->bufferSize);
       int status = cdiInputFile_read(me->file, me->fileOffset + (off_t)scannedBytes, scanSize, &scanSize, me->gribBuffer);
-      if(status != CDI_NOERR && status != CDI_EEOF) return status;
+      if(status != CDI_NOERR && status != CDI_EEOF) return -1;
 
       const unsigned char *startPosition = positionOfGribMarker(me->gribBuffer, scanSize);
       if(startPosition)
@@ -31810,21 +32096,21 @@ static ssize_t scanToGribMarker(CdiGribIterator *me)
 
       //Get the offset for the next iteration if there is a next iteration.
       scanSize -= 3;        //so that we won't miss a 'GRIB' sequence that happens to be cut off
-      scannedBytes += scanSize;
-      scannedBytes &= ~(size_t)0xf; //make 16 bytes aligned
+      scanSize &= ~(size_t)0xf; //make 16 bytes aligned
+      if((ssize_t)scanSize <= 0) return -1; //ensure that we make progress
     }
   return -1;
 }
 
 static unsigned decode24(void *beData)
 {
-  unsigned char* bytes = (unsigned char *)beData;
+  unsigned char *bytes = (unsigned char *)beData;
   return ((unsigned)bytes[0] << 16) + ((unsigned)bytes[1] << 8) + (unsigned)bytes[2];
 }
 
 static uint64_t decode64(void *beData)
 {
-  unsigned char* bytes = (unsigned char *)beData;
+  unsigned char *bytes = (unsigned char *)beData;
   uint64_t result = 0;
   for(size_t i = 0; i < 8; i++) result = (result << 8) + bytes[i];
   return result;
@@ -31931,10 +32217,10 @@ int cdiGribIterator_nextField(CdiIterator *super)
   return CDI_NOERR;
 }
 
-char *cdiGribIterator_inqTime(CdiIterator *super, bool getEndTime)
+char *cdiGribIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
 {
   CdiGribIterator *me = (CdiGribIterator*)super;
-  return gribMakeTimeString(me->gribHandle, getEndTime);
+  return gribMakeTimeString(me->gribHandle, timeType);
 }
 
 int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
@@ -31945,13 +32231,13 @@ int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outN
   int zaxisType = ZAXIS_GENERIC;
   if(gribEditionNumber(me->gribHandle) <= 1)
     {
-      int levelType = gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", 255);
+      int levelType = (int)gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", 255);
       if(levelSelector && !isGrib1DualLevel(levelType)) levelType = 255;
       zaxisType = grib1ltypeToZaxisType(levelType);
     }
   else
     {
-      int levelType = gribGetLongDefault(me->gribHandle, levelSelector ? "typeOfSecondFixedSurface" : "typeOfFirstFixedSurface", 255);
+      int levelType = (int)gribGetLongDefault(me->gribHandle, levelSelector ? "typeOfSecondFixedSurface" : "typeOfFirstFixedSurface", 255);
       zaxisType = grib2ltypeToZaxisType(levelType);
     }
 
@@ -31969,6 +32255,7 @@ int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outN
 static double logicalLevelValue2(long gribType, long storedValue, long power)
 {
   double factor = 1;
+  assert(power >= 0);
   while(power--) factor *= 10;      //this is precise up to factor == 22.
   switch(gribType)
     {
@@ -32014,7 +32301,7 @@ static int readLevel2(grib_handle *gribHandle, const char *levelTypeKey, const c
 
       default:
         {
-          long power = gribGetLongDefault(gribHandle, powerKey, 0);  //1 byte
+          long power = 255 & gribGetLongDefault(gribHandle, powerKey, 0);  //1 byte
           if(power == 255) power = 0;
           long value = gribGetLongDefault(gribHandle, valueKey, 0);   //4 bytes
           *outValue1 = logicalLevelValue2(levelType, value, power);
@@ -32089,6 +32376,46 @@ int cdiGribIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *outL
   return CDI_NOERR;
 }
 
+int cdiGribIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
+{
+  CdiGribIterator *me = (CdiGribIterator*)super;
+  int trash;
+  if(!outTileIndex) outTileIndex = &trash;
+  if(!outTileAttribute) outTileAttribute = &trash;
+
+  //Get the values if possible.
+  int error = CDI_NOERR;
+  long value;
+  if(grib_get_long(me->gribHandle, "tileIndex", &value)) error = CDI_EINVAL;
+  *outTileIndex = (int)value;
+  if(grib_get_long(me->gribHandle, "tileAttribute", &value)) error = CDI_EINVAL;
+  *outTileAttribute = (int)value;
+
+  //Ensure defined return values in case of failure.
+  if(error) *outTileIndex = *outTileAttribute = -1;
+  return error;
+}
+
+int cdiGribIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
+{
+  CdiGribIterator *me = (CdiGribIterator*)super;
+  int trash;
+  if(!outTileCount) outTileCount = &trash;
+  if(!outTileAttributeCount) outTileAttributeCount = &trash;
+
+  //Get the values if possible.
+  int error = CDI_NOERR;
+  long value;
+  if(grib_get_long(me->gribHandle, "numberOfTiles", &value)) error = CDI_EINVAL;
+  *outTileCount = (int)value;
+  if(grib_get_long(me->gribHandle, "numberOfTileAttributes", &value)) error = CDI_EINVAL;
+  *outTileAttributeCount = (int)value;
+
+  //Ensure defined return values in case of failure.
+  if(error) *outTileCount = *outTileAttributeCount = 0;
+  return error;
+}
+
 char *cdiGribIterator_copyVariableName(CdiIterator *super)
 {
   CdiGribIterator *me = (CdiGribIterator*)super;
@@ -32113,7 +32440,7 @@ void cdiGribIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss
   CdiGribIterator *me = (CdiGribIterator*)super;
 
   size_t valueCount = gribGetArraySize(me->gribHandle, "values");
-  double* temp = (double *) Malloc(valueCount*sizeof(*temp));
+  double *temp = (double *) Malloc(valueCount*sizeof(*temp));
   cdiGribIterator_readField(super, temp, nmiss);
   for(size_t i = valueCount; i--; ) buffer[i] = (float)temp[i];
   Free(temp);
@@ -32136,8 +32463,8 @@ void cdiGribIterator_delete(CdiGribIterator *me)
 #ifdef HAVE_LIBGRIB_API
   if(me) cdiGribIterator_condestruct(me, NULL, 0);
 #else
-  (void)me;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  if (me)
+    xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
 #endif
 }
 
@@ -34816,9 +35143,6 @@ void   iegWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const dou
 #endif
 
 #include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-
 
 
 
@@ -34936,6 +35260,7 @@ int cdiGetFiletype(const char *filename, int *byteorder)
       if ( CDI_Debug ) Message("found IEG file = %s", filename);
     }
 #endif
+#if  defined  (HAVE_LIBCGRIBEX)
   else if ( gribCheckSeek(fileID, &recpos, &version) == 0 )
     {
       if ( version <= 1 )
@@ -34949,6 +35274,7 @@ int cdiGetFiletype(const char *filename, int *byteorder)
 	  if ( CDI_Debug ) Message("found seeked GRIB2 file = %s", filename);
 	}
     }
+#endif
 
   fileClose(fileID);
 
@@ -34979,9 +35305,6 @@ The valid CDI file format types are @func{FILETYPE_GRB}, @func{FILETYPE_GRB2}, @
 int streamInqFiletype(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->filetype);
 }
 
@@ -35025,9 +35348,6 @@ with the file format type @func{FILETYPE_SRV}, @func{FILETYPE_EXT} or @func{FILE
 void streamDefByteorder(int streamID, int byteorder)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   streamptr->byteorder = byteorder;
   int filetype = streamptr->filetype;
 
@@ -35085,9 +35405,6 @@ The valid CDI byte order types are @func{CDI_BIGENDIAN} and @func{CDI_LITTLEENDI
 int streamInqByteorder(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->byteorder);
 }
 
@@ -35111,9 +35428,6 @@ const char *streamFilesuffix(int filetype)
 const char *streamFilename(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->filename);
 }
 
@@ -35122,9 +35436,6 @@ long cdiInqTimeSize(int streamID)
 {
   int tsID = 0, nrecs;
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   long ntsteps = streamptr->ntsteps;
 
   if ( ntsteps == (long)CDI_UNDEFID )
@@ -35218,7 +35529,12 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
     case FILETYPE_GRB:
     case FILETYPE_GRB2:
       {
+#ifndef __cplusplus
         fileID = gribOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = gribOpen(filename, temp);
+#endif
         if ( fileID < 0 ) fileID = CDI_ESYSTEM;
         if (recordBufIsToBeCreated)
           {
@@ -35231,7 +35547,12 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 #if  defined  (HAVE_LIBSERVICE)
     case FILETYPE_SRV:
       {
+#ifndef __cplusplus
         fileID = fileOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = fileOpen(filename, temp);
+#endif
         if ( fileID < 0 ) fileID = CDI_ESYSTEM;
         if (recordBufIsToBeCreated)
           {
@@ -35245,7 +35566,13 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 #if  defined  (HAVE_LIBEXTRA)
     case FILETYPE_EXT:
       {
+#ifndef __cplusplus
         fileID = fileOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = fileOpen(filename, temp);
+#endif
+
         if ( fileID < 0 ) fileID = CDI_ESYSTEM;
         if (recordBufIsToBeCreated)
           {
@@ -35259,7 +35586,12 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 #if  defined  (HAVE_LIBIEG)
     case FILETYPE_IEG:
       {
+#ifndef __cplusplus
         fileID = fileOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = fileOpen(filename, temp);
+#endif
         if ( fileID < 0 ) fileID = CDI_ESYSTEM;
         if (recordBufIsToBeCreated)
           {
@@ -35273,18 +35605,33 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 #if  defined  (HAVE_LIBNETCDF)
     case FILETYPE_NC:
       {
+#ifndef __cplusplus
         fileID = cdfOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = cdfOpen(filename, temp);
+#endif
         break;
       }
     case FILETYPE_NC2:
       {
+#ifndef __cplusplus
         fileID = cdfOpen64(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = cdfOpen64(filename, temp);
+#endif
         break;
       }
     case FILETYPE_NC4:
     case FILETYPE_NC4C:
       {
+#ifndef __cplusplus
         fileID = cdf4Open(filename, (char [2]){filemode, 0}, &filetype);
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = cdf4Open(filename, temp, &filetype);
+#endif
         break;
       }
 #endif
@@ -35301,9 +35648,7 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 }
 
 
-int
-streamOpenID(const char *filename, char filemode, int filetype,
-             int resH)
+int streamOpenID(const char *filename, char filemode, int filetype, int resH)
 {
   int fileID = CDI_UNDEFID;
   int status;
@@ -35326,37 +35671,49 @@ streamOpenID(const char *filename, char filemode, int filetype,
     fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
   }
 
-  if (fileID < 0)
+  if ( fileID < 0 )
     {
-      Free(streamptr->record);
-      stream_delete_entry(streamptr);
       streamID = fileID;
     }
   else
     {
-      streamID  = streamptr->self;
+      streamID = streamptr->self;
 
-      if ( streamID < 0 ) return (CDI_ELIMIT);
+      if ( streamID < 0 ) return CDI_ELIMIT;
 
       streamptr->filemode = filemode;
       streamptr->filename = strdupx(filename);
       streamptr->fileID   = fileID;
 
       if ( filemode == 'r' )
-	{
-	  int vlistID = vlistCreate();
-	  if ( vlistID < 0 ) return(CDI_ELIMIT);
-
-	  streamptr->vlistID = vlistID;
-	  /* cdiReadByteorder(streamID); */
-	  status = cdiInqContents(streamptr);
-	  if ( status < 0 ) return (status);
-	  vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
-	  vlistptr->ntsteps = streamptr->ntsteps;
-	}
+        {
+          int vlistID = vlistCreate();
+          if ( vlistID < 0 ) return(CDI_ELIMIT);
+
+          cdiVlistMakeInternal(vlistID);
+          streamptr->vlistID = vlistID;
+          /* cdiReadByteorder(streamID); */
+          status = cdiInqContents(streamptr);
+          if ( status < 0 )
+            {
+              streamID = status;
+            }
+          else
+            {
+              vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
+              vlistptr->ntsteps = streamptr->ntsteps;
+              cdiVlistMakeImmutable(vlistID);
+            }
+        }
     }
 
-  return (streamID);
+  if ( streamID < 0 )
+    {
+      Free(streamptr->record);
+      stream_delete_entry(streamptr);
+    }
+
+  return streamID;
 }
 
 static int streamOpen(const char *filename, const char *filemode, int filetype)
@@ -35398,11 +35755,13 @@ static int streamOpenA(const char *filename, const char *filemode, int filetype)
   streamptr->fileID   = fileID;
 
   streamptr->vlistID = vlistCreate();
+  cdiVlistMakeInternal(streamptr->vlistID);
   /* cdiReadByteorder(streamID); */
   status = cdiInqContents(streamptr);
   if ( status < 0 ) return (status);
   vlistptr = vlist_to_pointer(streamptr->vlistID);
   vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
+  if(!strcmp(filemode, "r")) cdiVlistMakeImmutable(streamptr->vlistID);
 
   {
     void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
@@ -35503,7 +35862,7 @@ open stream. Otherwise, a negative number with the error status is returned.
 @EndList
 
 @Example
-Here is an example using @func{streamOpenRead} to open an existing netCDF
+Here is an example using @func{streamOpenRead} to open an existing NetCDF
 file named @func{foo.nc} for reading:
 
 @Source
@@ -35584,7 +35943,7 @@ open stream. Otherwise, a negative number with the error status is returned.
 @EndList
 
 @Example
-Here is an example using @func{streamOpenWrite} to create a new netCDF file named @func{foo.nc} for writing:
+Here is an example using @func{streamOpenWrite} to create a new NetCDF file named @func{foo.nc} for writing:
 
 @Source
    ...
@@ -35769,8 +36128,6 @@ void streamClose(int streamID)
   int index;
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  stream_check_ptr(__func__, streamptr);
-
   if ( CDI_Debug )
     Message("streamID = %d filename = %s", streamID, streamptr->filename);
 
@@ -35828,8 +36185,7 @@ void streamClose(int streamID)
 	    taxisDestroy(vlistInqTaxis(vlistID));
 	  }
 
-      vlist_unlock(vlistID);
-      vlistDestroy(vlistID);
+      cdiVlistDestroy_(vlistID);
     }
 
   stream_delete_entry(streamptr);
@@ -35907,8 +36263,6 @@ void streamSync(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  stream_check_ptr(__func__, streamptr);
-
   void (*myStreamSync_)(stream_t *streamptr)
     = (void (*)(stream_t *))namespaceSwitchGet(NSSWITCH_STREAM_SYNC).func;
   myStreamSync_(streamptr);
@@ -35919,11 +36273,11 @@ int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
 {
   int taxisID = 0;
 
+  stream_check_ptr(__func__, streamptr);
+
   if ( CDI_Debug )
     Message("streamID = %d  tsID = %d", streamptr->self, tsID);
 
-  stream_check_ptr(__func__, streamptr);
-
   int vlistID = streamptr->vlistID;
 
   int time_is_varying = vlistHasTime(vlistID);
@@ -35960,7 +36314,7 @@ int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
        streamptr->filetype == FILETYPE_NC2 ||
        streamptr->filetype == FILETYPE_NC4 ||
        streamptr->filetype == FILETYPE_NC4C)
-      && vlistHasTime(vlistID))
+      && time_is_varying)
     {
       void (*myCdfDefTimestep)(stream_t *streamptr, int tsID)
         = (void (*)(stream_t *, int))
@@ -36029,9 +36383,6 @@ int streamInqTimestep(int streamID, int tsID)
   int nrecs = 0;
   int taxisID;
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   int vlistID = streamptr->vlistID;
 
   if ( tsID < streamptr->rtsteps )
@@ -36114,752 +36465,189 @@ int streamInqTimestep(int streamID, int tsID)
   return (nrecs);
 }
 
-/* the single image implementation */
-static
-void cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmiss)
+#if 0
+void streamWriteContents(int streamID, char *cname)
 {
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-  check_parg(data);
-  check_parg(nmiss);
+  int vlistID = streamptr->vlistID;
 
-  stream_t *streamptr = stream_to_pointer(streamID);
+  FILE *cnp = fopen(cname, "w");
 
-  stream_check_ptr(__func__, streamptr);
+  if ( cnp == NULL ) SysError(cname);
+
+  fprintf(cnp, "#CDI library version %s\n", cdiLibraryVersion());
+  fprintf(cnp, "#\n");
 
+  fprintf(cnp, "filename: %s\n", streamptr->filename);
   int filetype = streamptr->filetype;
+  fprintf(cnp, "filetype: %s\n", strfiletype(filetype));
 
-  *nmiss = 0;
+  fprintf(cnp, "#\n");
+  fprintf(cnp, "#grids:\n");
 
-  switch (filetype)
+  int ngrids = vlistNgrids(vlistID);
+  for ( int i = 0; i < ngrids; i++ )
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("grbReadVar not implemented for memtype float!");
-        grbReadVarDP(streamptr, varID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("srvReadVar not implemented for memtype float!");
-        srvReadVarDP(streamptr, varID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("extReadVar not implemented for memtype float!");
-        extReadVarDP(streamptr, varID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("iegReadVar not implemented for memtype float!");
-        iegReadVarDP(streamptr, varID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-        if ( memtype == MEMTYPE_FLOAT )
-          cdfReadVarSP(streamptr, varID, (float *)data, nmiss);
-        else
-          cdfReadVarDP(streamptr, varID, (double *)data, nmiss);
+      int gridID   = vlistGrid(vlistID, i);
+      int gridtype = gridInqType(gridID);
+      int xsize    = gridInqXsize(gridID);
+      int ysize    = gridInqYsize(gridID);
+      fprintf(cnp, "%4d:%4d:%4d:%4d\n", i+1, gridtype, xsize, ysize);
+    }
 
+  fprintf(cnp, "#\n");
+
+  fprintf(cnp, "varID:code:gridID:zaxisID:tsteptype:datatype\n");
+
+  int nvars = vlistNvars(vlistID);
+  for ( int varID = 0; varID < nvars; varID++ )
+    {
+      int code      = vlistInqVarCode(vlistID, varID);
+      int gridID    = vlistInqVarGrid(vlistID, varID);
+      int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+      int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+      int datatype  = vlistInqVarDatatype(vlistID, varID);
+      fprintf(cnp, "%4d:%4d:%4d:%4d:%4d:%4d:\n",
+	      varID+1, code, gridID, zaxisID, tsteptype, datatype);
+    }
+
+  fprintf(cnp, "#\n");
+
+  fprintf(cnp, "tsID:nrecs:date:time\n");
+
+  int tsID = 0;
+  while (1)
+    {
+      int nrecs      = streamptr->tsteps[tsID].nallrecs;
+      int date       = streamptr->tsteps[tsID].taxis.vdate;
+      int time       = streamptr->tsteps[tsID].taxis.vtime;
+      off_t position = streamptr->tsteps[tsID].position;
+
+      fprintf(cnp, "%4d:%4d:%4d:%4d:%ld\n",
+	      tsID, nrecs, date, time, (long) position);
+
+      if ( streamptr->tsteps[tsID].next )
+	tsID++;
+      else
 	break;
-      }
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
-      }
     }
-}
 
-/*
- at Function  streamReadVar
- at Title     Read a variable
+  fprintf(cnp, "#\n");
 
- at Prototype void streamReadVar(int streamID, int varID, double *data, int *nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
+  fprintf(cnp, "tsID:recID:varID:levID:size:pos\n");
 
- at Description
-The function streamReadVar reads all the values of one time step of a variable
-from an open dataset.
- at EndFunction
-*/
-void streamReadVar(int streamID, int varID, double *data, int *nmiss)
+  tsID = 0;
+  while (1)
+    {
+      int nrecs = streamptr->tsteps[tsID].nallrecs;
+      for ( int recID = 0; recID < nrecs; recID++ )
+	{
+	  int varID   = streamptr->tsteps[tsID].records[recID].varID;
+	  int levelID = streamptr->tsteps[tsID].records[recID].levelID;
+	  off_t recpos = streamptr->tsteps[tsID].records[recID].position;
+	  long recsize = (long)streamptr->tsteps[tsID].records[recID].size;
+	  fprintf(cnp, "%4d:%4d:%4d:%4d:%4ld:%ld\n",
+		  tsID, recID, varID, levelID, recsize, (long) recpos);
+	}
+
+      if ( streamptr->tsteps[tsID].next )
+	tsID++;
+      else
+	break;
+    }
+
+  fclose(cnp);
+}
+#endif
+
+// This function is used in CDO!
+off_t streamNvals(int streamID)
 {
-  cdiStreamReadVar(streamID, varID, MEMTYPE_DOUBLE, data, nmiss);
+  stream_t *streamptr = stream_to_pointer(streamID);
+
+  return (streamptr->numvals);
 }
 
 /*
- at Function  streamReadVarF
- at Title     Read a variable
+ at Function  streamDefVlist
+ at Title     Define the variable list
 
- at Prototype void streamReadVar(int streamID, int varID, float *data, int *nmiss)
+ at Prototype void streamDefVlist(int streamID, int vlistID)
 @Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
+    @Item  streamID Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
 
 @Description
-The function streamReadVar reads all the values of one time step of a variable
-from an open dataset.
+The function @func{streamDefVlist} defines the variable list of a stream.
+
+To safeguard against errors by modifying the wrong vlist object,
+this function makes the passed vlist object immutable.
+All further vlist changes have to use the vlist object returned by streamInqVlist().
+
 @EndFunction
 */
-void streamReadVarF(int streamID, int varID, float *data, int *nmiss)
+void streamDefVlist(int streamID, int vlistID)
 {
-  cdiStreamReadVar(streamID, varID, MEMTYPE_FLOAT, data, nmiss);
+  void (*myStreamDefVlist)(int streamID, int vlistID)
+    = (void (*)(int, int))namespaceSwitchGet(NSSWITCH_STREAM_DEF_VLIST_).func;
+  myStreamDefVlist(streamID, vlistID);
 }
 
-/* the single image implementation */
-void cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, int nmiss)
+/* the single image implementation of streamDefVlist */
+void
+cdiStreamDefVlist_(int streamID, int vlistID)
 {
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
-
-  check_parg(data);
-
   stream_t *streamptr = stream_to_pointer(streamID);
-  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
-    Error("Writing of non-trivial subtypes not yet implemented!");
 
-  stream_check_ptr(__func__, streamptr);
-
-  // check taxis
-  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
-
-  int filetype = streamptr->filetype;
-
-  switch (filetype)
+  if ( streamptr->vlistID == CDI_UNDEFID )
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        grb_write_var(streamptr, varID, memtype, data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("srvWriteVar not implemented for memtype float!");
-        srvWriteVarDP(streamptr, varID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("extWriteVar not implemented for memtype float!");
-        extWriteVarDP(streamptr, varID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("iegWriteVar not implemented for memtype float!");
-        iegWriteVarDP(streamptr, varID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-	if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
-        cdf_write_var(streamptr, varID, memtype, (double *)data, nmiss);
-	break;
-      }
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
-      }
+      int vlistCopy = vlistDuplicate(vlistID);
+      cdiVlistMakeInternal(vlistCopy);
+      cdiVlistMakeImmutable(vlistID);
+      cdiStreamSetupVlist(streamptr, vlistCopy);
     }
+  else
+    Warning("vlist already defined for %s!", streamptr->filename);
 }
 
 /*
- at Function  streamWriteVar
- at Title     Write a variable
+ at Function  streamInqVlist
+ at Title     Get the variable list
 
- at Prototype void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
+ at Prototype int streamInqVlist(int streamID)
 @Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to a block of double precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
 
 @Description
-The function streamWriteVar writes the values of one time step of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
- at EndFunction
-*/
-void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
-{
-  void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype,
-                               const void *data, int nmiss)
-    = (void (*)(int, int, int, const void *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
-  myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, data, nmiss);
-}
-
-/*
- at Function  streamWriteVarF
- at Title     Write a variable
+The function @func{streamInqVlist} returns the variable list of a stream.
 
- at Prototype void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to a block of single precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
+ at Result
+ at func{streamInqVlist} returns an identifier to the variable list.
 
- at Description
-The function streamWriteVarF writes the values of one time step of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
-Only support for netCDF was implemented in this function.
 @EndFunction
 */
-void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
+int streamInqVlist(int streamID)
 {
-  void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype,
-                               const void *data, int nmiss)
-    = (void (*)(int, int, int, const void *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
-  myCdiStreamWriteVar_(streamID, varID, MEMTYPE_FLOAT, data, nmiss);
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return (streamptr->vlistID);
 }
 
-static
-int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, void *data, int *nmiss)
-{
-  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
-  // A value > 0 is returned in this case, otherwise it returns zero.
-  int status = 0;
-
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
-
-  check_parg(data);
-  check_parg(nmiss);
 
+void streamDefCompType(int streamID, int comptype)
+{
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
-  int filetype = streamptr->filetype;
-
-  *nmiss = 0;
-
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        grbReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        srvReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        extReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        iegReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-        if ( memtype == MEMTYPE_FLOAT )
-          cdfReadVarSliceSP(streamptr, varID, levelID, (float *)data, nmiss);
-        else
-          cdfReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
-        break;
-      }
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(filetype));
-        status = 2;
-	break;
-      }
-    }
-
-  return status;
-}
-
-/*
- at Function  streamReadVarSlice
- at Title     Read a horizontal slice of a variable
-
- at Prototype void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamReadVarSlice reads all the values of a horizontal slice of a variable
-from an open dataset.
- at EndFunction
-*/
-void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
-{
-  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, data, nmiss) )
-    {
-      Warning("Unexpected error returned from cdiStreamReadVarSlice()!");
-      size_t elementCount = (size_t)gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      memset(data, 0, elementCount * sizeof(*data));
-    }
-}
-
-/*
- at Function  streamReadVarSliceF
- at Title     Read a horizontal slice of a variable
-
- at Prototype void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamReadVarSliceF reads all the values of a horizontal slice of a variable
-from an open dataset.
- at EndFunction
-*/
-void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
-{
-  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, data, nmiss) )
-    {
-      // In case the file format does not support single precision reading,
-      // we fall back to double precision reading, converting the data on the fly.
-      size_t elementCount = (size_t)gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      double *conversionBuffer = (double *) Malloc(elementCount * sizeof(*conversionBuffer));
-      streamReadVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
-      for (size_t i = elementCount; i--; ) data[i] = (float)conversionBuffer[i];
-      Free(conversionBuffer);
-    }
-}
-
-static
-void cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, int nmiss)
-{
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
-
-  check_parg(data);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
-  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
-    Error("Writing of non-trivial subtypes not yet implemented!");
-
-  stream_check_ptr(__func__, streamptr);
-
-  // check taxis
-  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
-
-  int filetype = streamptr->filetype;
-
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("srvWriteVarSlice not implemented for memtype float!");
-        srvWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("extWriteVarSlice not implemented for memtype float!");
-        extWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("iegWriteVarSlice not implemented for memtype float!");
-        iegWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
-      cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
-      break;
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
-      }
-    }
-}
-
-/*
- at Function  streamWriteVarSlice
- at Title     Write a horizontal slice of a variable
-
- at Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to a block of double precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamWriteVarSlice writes the values of a horizontal slice of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
- at EndFunction
-*/
-void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
-{
-  cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, data, nmiss);
-}
-
-/*
- at Function  streamWriteVarSliceF
- at Title     Write a horizontal slice of a variable
-
- at Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to a block of single precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamWriteVarSliceF writes the values of a horizontal slice of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
-Only support for netCDF was implemented in this function.
- at EndFunction
-*/
-void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
-{
-  cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, data, nmiss);
-}
-
-
-void
-streamWriteVarChunk(int streamID, int varID,
-                    const int rect[][2], const double *data, int nmiss)
-{
-  void (*myCdiStreamWriteVarChunk_)(int streamID, int varID, int memtype,
-                                    const int rect[][2], const void *data,
-                                    int nmiss)
-    = (void (*)(int, int, int, const int [][2], const void *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_CHUNK_).func;
-  myCdiStreamWriteVarChunk_(streamID, varID, MEMTYPE_DOUBLE, rect, data, nmiss);
-}
-
-/* single image implementation */
-void
-cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
-                        const int rect[][2], const void *data, int nmiss)
-{
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
-  // streamDefineTaxis(streamID);
-
-  int filetype = streamptr->filetype;
-
-  switch (filetype)
-    {
-#if defined (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-#endif
-#if defined (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-#endif
-#if defined (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-#endif
-#if defined (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-#endif
-#if  defined (HAVE_LIBGRIB) || defined (HAVE_LIBSERVICE)      \
-  || defined (HAVE_LIBEXTRA) || defined (HAVE_LIBIEG)
-      xabort("streamWriteVarChunk not implemented for filetype %s!",
-             strfiletype(filetype));
-      break;
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
-      cdf_write_var_chunk(streamptr, varID, memtype, rect, data, nmiss);
-      break;
-#endif
-    default:
-      Error("%s support not compiled in!", strfiletype(filetype));
-      break;
-    }
-}
-
-#if 0
-void streamWriteContents(int streamID, char *cname)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
-  int vlistID = streamptr->vlistID;
-
-  FILE *cnp = fopen(cname, "w");
-
-  if ( cnp == NULL ) SysError(cname);
-
-  fprintf(cnp, "#CDI library version %s\n", cdiLibraryVersion());
-  fprintf(cnp, "#\n");
-
-  fprintf(cnp, "filename: %s\n", streamptr->filename);
-  int filetype = streamptr->filetype;
-  fprintf(cnp, "filetype: %s\n", strfiletype(filetype));
-
-  fprintf(cnp, "#\n");
-  fprintf(cnp, "#grids:\n");
-
-  int ngrids = vlistNgrids(vlistID);
-  for ( int i = 0; i < ngrids; i++ )
-    {
-      int gridID   = vlistGrid(vlistID, i);
-      int gridtype = gridInqType(gridID);
-      int xsize    = gridInqXsize(gridID);
-      int ysize    = gridInqYsize(gridID);
-      fprintf(cnp, "%4d:%4d:%4d:%4d\n", i+1, gridtype, xsize, ysize);
-    }
-
-  fprintf(cnp, "#\n");
-
-  fprintf(cnp, "varID:code:gridID:zaxisID:tsteptype:datatype\n");
-
-  int nvars = vlistNvars(vlistID);
-  for ( int varID = 0; varID < nvars; varID++ )
-    {
-      int code      = vlistInqVarCode(vlistID, varID);
-      int gridID    = vlistInqVarGrid(vlistID, varID);
-      int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-      int tsteptype = vlistInqVarTsteptype(vlistID, varID);
-      int datatype  = vlistInqVarDatatype(vlistID, varID);
-      fprintf(cnp, "%4d:%4d:%4d:%4d:%4d:%4d:\n",
-	      varID+1, code, gridID, zaxisID, tsteptype, datatype);
-    }
-
-  fprintf(cnp, "#\n");
-
-  fprintf(cnp, "tsID:nrecs:date:time\n");
-
-  int tsID = 0;
-  while (1)
-    {
-      int nrecs      = streamptr->tsteps[tsID].nallrecs;
-      int date       = streamptr->tsteps[tsID].taxis.vdate;
-      int time       = streamptr->tsteps[tsID].taxis.vtime;
-      off_t position = streamptr->tsteps[tsID].position;
-
-      fprintf(cnp, "%4d:%4d:%4d:%4d:%ld\n",
-	      tsID, nrecs, date, time, (long) position);
-
-      if ( streamptr->tsteps[tsID].next )
-	tsID++;
-      else
-	break;
-    }
-
-  fprintf(cnp, "#\n");
-
-  fprintf(cnp, "tsID:recID:varID:levID:size:pos\n");
-
-  tsID = 0;
-  while (1)
-    {
-      int nrecs = streamptr->tsteps[tsID].nallrecs;
-      for ( int recID = 0; recID < nrecs; recID++ )
-	{
-	  int varID   = streamptr->tsteps[tsID].records[recID].varID;
-	  int levelID = streamptr->tsteps[tsID].records[recID].levelID;
-	  off_t recpos = streamptr->tsteps[tsID].records[recID].position;
-	  long recsize = (long)streamptr->tsteps[tsID].records[recID].size;
-	  fprintf(cnp, "%4d:%4d:%4d:%4d:%4ld:%ld\n",
-		  tsID, recID, varID, levelID, recsize, (long) recpos);
-	}
-
-      if ( streamptr->tsteps[tsID].next )
-	tsID++;
-      else
-	break;
-    }
-
-  fclose(cnp);
-}
-#endif
-
-// This function is used in CDO!
-off_t streamNvals(int streamID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
-  return (streamptr->numvals);
-}
-
-/*
- at Function  streamDefVlist
- at Title     Define the variable list
-
- at Prototype void streamDefVlist(int streamID, int vlistID)
- at Parameter
-    @Item  streamID Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
-
- at Description
-The function @func{streamDefVlist} defines the variable list of a stream.
-
- at EndFunction
-*/
-void streamDefVlist(int streamID, int vlistID)
-{
-  void (*myStreamDefVlist)(int streamID, int vlistID)
-    = (void (*)(int, int))namespaceSwitchGet(NSSWITCH_STREAM_DEF_VLIST_).func;
-  myStreamDefVlist(streamID, vlistID);
-}
-
-/* the single image implementation of streamDefVlist */
-void
-cdiStreamDefVlist_(int streamID, int vlistID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
-  if ( streamptr->vlistID == CDI_UNDEFID )
-    cdiStreamSetupVlist(streamptr, vlistDuplicate(vlistID));
-  else
-    Warning("vlist already defined for %s!", streamptr->filename);
-}
-
-/*
- at Function  streamInqVlist
- at Title     Get the variable list
-
- at Prototype int streamInqVlist(int streamID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
-
- at Description
-The function @func{streamInqVlist} returns the variable list of a stream.
-
- at Result
- at func{streamInqVlist} returns an identifier to the variable list.
-
- at EndFunction
-*/
-int streamInqVlist(int streamID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
-  return (streamptr->vlistID);
-}
-
-
-void streamDefCompType(int streamID, int comptype)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
-  if (streamptr->comptype != comptype)
-    {
-      streamptr->comptype = comptype;
-      reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
-    }
-}
+  if (streamptr->comptype != comptype)
+    {
+      streamptr->comptype = comptype;
+      reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
+    }
+}
 
 
 void streamDefCompLevel(int streamID, int complevel)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   if (streamptr->complevel != complevel)
     {
       streamptr->complevel = complevel;
@@ -36871,9 +36659,6 @@ void streamDefCompLevel(int streamID, int complevel)
 int streamInqCompType(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->comptype);
 }
 
@@ -36881,9 +36666,6 @@ int streamInqCompType(int streamID)
 int streamInqCompLevel(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->complevel);
 }
 
@@ -36936,7 +36718,6 @@ cdiStreamSetupVlist(stream_t *streamptr, int vlistID)
 void
 cdiStreamSetupVlist_(stream_t *streamptr, int vlistID)
 {
-  vlist_lock(vlistID);
   int nvars = vlistNvars(vlistID);
   streamptr->vlistID = vlistID;
   for (int varID = 0; varID < nvars; varID++ )
@@ -36966,10 +36747,14 @@ cdiStreamSetupVlist_(stream_t *streamptr, int vlistID)
         }
         break;
 #endif
+#ifdef HAVE_LIBGRIB
       case FILETYPE_GRB:
       case FILETYPE_GRB2:
         gribContainersNew(streamptr);
         break;
+#endif
+      default:
+        ;
       }
 }
 
@@ -37151,8 +36936,6 @@ streamUnpack(char * unpackBuffer, int unpackBufferSize,
   return retval;
 }
 
-
-
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -37162,952 +36945,1491 @@ streamUnpack(char * unpackBuffer, int unpackBufferSize,
  * require-trailing-newline: t
  * End:
  */
-#ifndef _VARSCAN_H
-#define _VARSCAN_H
-
-#ifndef _GRID_H
+#ifdef HAVE_CONFIG_H
 #endif
 
 
-void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds,
-		  int level1, int level2, int level_sf, int level_unit, int prec,
-		  int *pvarID, int *plevelID, int tsteptype, int numavg, int ltype1, int ltype2,
-		  const char *name, const char *stdname, const char *longname, const char *units,
-                  const var_tile_t *tiles, int *tile_index);
 
-void varDefVCT(size_t vctsize, double *vctptr);
-void varDefZAxisReference(int nlev, int nvgrid, unsigned char uuid[CDI_UUID_SIZE]);
+/* the single image implementation */
+int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, int nmiss)
+{
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
 
-int  varDefZaxis(int vlistID, int zaxistype, int nlevels, double *levels, int lbounds,
-		 double *levels1, double *levels2, int vctsize, double *vct, char *name,
-		 char *longname, const char *units, int prec, int mode, int ltype);
+  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
 
-void varDefMissval(int varID, double missval);
-void varDefCompType(int varID, int comptype);
-void varDefCompLevel(int varID, int complevel);
-void varDefInst(int varID, int instID);
-int  varInqInst(int varID);
-void varDefModel(int varID, int modelID);
-int  varInqModel(int varID);
-void varDefTable(int varID, int tableID);
-int  varInqTable(int varID);
-void varDefEnsembleInfo(int varID, int ens_idx, int ens_count, int forecast_type);
-
-void varDefTypeOfGeneratingProcess(int varID, int typeOfGeneratingProcess);
-void varDefProductDefinitionTemplate(int varID, int productDefinitionTemplate);
+  check_parg(data);
 
+  stream_t *streamptr = stream_to_pointer(streamID);
+  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
+    Error("Writing of non-trivial subtypes not yet implemented!");
 
-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);
+  // check taxis
+  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
 
-int  zaxisCompare(int zaxisID, int zaxistype, int nlevels, int lbounds, const double *levels, const char *longname, const char *units, int ltype);
+  int filetype = streamptr->filetype;
 
+  switch (filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      {
+        grb_write_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
 #endif
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
 #endif
-
-#ifdef HAVE_LIBNETCDF
-
-//#define TEST_GROUPS 1
-
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <math.h>
-#include <float.h>
-
-#include <netcdf.h>
-
-
-//#define PROJECTION_TEST
-extern int CDI_cmor_mode;
-
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
-
-
-#if defined HAVE_LIBNETCDF
-static void cdfDefGlobalAtts(stream_t *streamptr);
-static void cdfDefLocalAtts(stream_t *streamptr);
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
 #endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      {
+        cdf_write_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
+      }
+    }
 
-#define  BNDS_NAME  "bnds"
-
-#define  X_AXIS  1
-#define  Y_AXIS  2
-#define  Z_AXIS  3
-#define  T_AXIS  4
-
-#define  POSITIVE_UP    1
-#define  POSITIVE_DOWN  2
-
-typedef struct {
-  int     ncvarid;
-  int     dimtype;
-  size_t  len;
-  char    name[CDI_MAX_NAME];
+  return status;
 }
-ncdim_t;
 
-#define  MAX_COORDVARS  4
-#define  MAX_AUXVARS    4
+/*
+ at Function  streamWriteVar
+ at Title     Write a variable
 
-typedef struct {
-  int      ncid;
-  int      ignore;
-  short    isvar;
-  short    islon;
-  int      islat;
-  int      islev;
-  int      istime;
-  int      warn;
-  int      tsteptype;
-  int      param;
-  int      code;
-  int      tabnum;
-  int      climatology;
-  int      bounds;
-  int      lformula;
-  int      lformulaterms;
-  int      gridID;
-  int      zaxisID;
-  int      gridtype;
-  int      zaxistype;
-  int      xdim;
-  int      ydim;
-  int      zdim;
-  int      xvarid;
-  int      yvarid;
-  int      zvarid;
-  int      tvarid;
-  int      psvarid;
-  int      ncoordvars;
-  int      coordvarids[MAX_COORDVARS];
-  int      nauxvars;
-  int      auxvarids[MAX_AUXVARS];
-  int      cellarea;
-  int      calendar;
-  int      tableID;
-  int      truncation;
-  int      position;
-  int      defmissval;
-  int      deffillval;
-  int      xtype;
-  int      ndims;
-  int      gmapid;
-  int      positive;
-  int      dimids[8];
-  int      dimtype[8];
-  int      chunks[8];
-  int      chunked;
-  int      chunktype;
-  int      natts;
-  int      deflate;
-  int      lunsigned;
-  int      lvalidrange;
-  int     *atts;
-  size_t   vctsize;
-  double  *vct;
-  double   missval;
-  double   fillval;
-  double   addoffset;
-  double   scalefactor;
-  double   validrange[2];
-  char     name[CDI_MAX_NAME];
-  char     longname[CDI_MAX_NAME];
-  char     stdname[CDI_MAX_NAME];
-  char     units[CDI_MAX_NAME];
-  char     extra[CDI_MAX_NAME];
-  ensinfo_t   *ensdata;    /* Ensemble information */
-}
-ncvar_t;
+ at Prototype void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to a block of double precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
 
-static
-void strtolower(char *str)
+ at Description
+The function streamWriteVar writes the values of one time step of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
 {
-  if ( str )
-    for (size_t i = 0; str[i]; ++i)
-      str[i] = (char)tolower((int)str[i]);
+  void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype,
+                               const void *data, int nmiss)
+    = (void (*)(int, int, int, const void *, int))
+    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
+
+  myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
 }
 
-static
-int get_timeunit(size_t len, const char *ptu)
-{
-  int timeunit = -1;
+/*
+ at Function  streamWriteVarF
+ at Title     Write a variable
 
-  if ( len > 2 )
-    {
-      if      ( memcmp(ptu, "sec",    3) == 0 )          timeunit = TUNIT_SECOND;
-      else if ( memcmp(ptu, "minute", 6) == 0 )          timeunit = TUNIT_MINUTE;
-      else if ( memcmp(ptu, "hour",   4) == 0 )          timeunit = TUNIT_HOUR;
-      else if ( memcmp(ptu, "day",    3) == 0 )          timeunit = TUNIT_DAY;
-      else if ( memcmp(ptu, "month",  5) == 0 )          timeunit = TUNIT_MONTH;
-      else if ( memcmp(ptu, "calendar_month", 14) == 0 ) timeunit = TUNIT_MONTH;
-      else if ( memcmp(ptu, "year",   4) == 0 )          timeunit = TUNIT_YEAR;
-    }
-  else if ( len == 1 )
-    {
-      if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND;
-    }
+ at Prototype void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to a block of single precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
 
-  return (timeunit);
+ at Description
+The function streamWriteVarF writes the values of one time step of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
+{
+  int (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype,
+                              const void *data, int nmiss)
+    = (int (*)(int, int, int, const void *, int))
+    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
+  
+  if ( myCdiStreamWriteVar_(streamID, varID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
+    {
+      // In case the file format does not support single precision writing,
+      // we fall back to double precision writing, converting the data on the fly.
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
+      myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) conversionBuffer, nmiss);
+      Free(conversionBuffer);
+    }
 }
 
 static
-int isTimeUnits(const char *timeunits)
+int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, int nmiss)
 {
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
+  // A value > 0 is returned in this case, otherwise it returns zero.
   int status = 0;
 
-  if ( strncmp(timeunits, "sec",    3) == 0 ||
-       strncmp(timeunits, "minute", 6) == 0 ||
-       strncmp(timeunits, "hour",   4) == 0 ||
-       strncmp(timeunits, "day",    3) == 0 ||
-       strncmp(timeunits, "month",  5) == 0 ) status = 1;
+  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
 
-  return (status);
-}
+  check_parg(data);
 
-static
-int isTimeAxisUnits(const char *timeunits)
-{
-  char *ptu, *tu;
-  int timetype = -1;
-  int timeunit;
-  int status = FALSE;
+  stream_t *streamptr = stream_to_pointer(streamID);
+  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
+    Error("Writing of non-trivial subtypes not yet implemented!");
 
-  size_t len = strlen(timeunits);
-  tu = (char *) Malloc((len+1)*sizeof(char));
-  memcpy(tu, timeunits, (len+1) * sizeof(char));
-  ptu = tu;
+  // check taxis
+  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
 
-  for (size_t i = 0; i < len; i++ ) ptu[i] = (char)tolower((int)ptu[i]);
+  int filetype = streamptr->filetype;
 
-  timeunit = get_timeunit(len, ptu);
-  if ( timeunit != -1 )
+  switch (filetype)
     {
-
-      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
-      if ( *ptu )
-        {
-          while ( isspace(*ptu) ) ptu++;
-
-          if ( memcmp(ptu, "as", 2) == 0 )
-            timetype = TAXIS_ABSOLUTE;
-          else if ( memcmp(ptu, "since", 5) == 0 )
-            timetype = TAXIS_RELATIVE;
-
-          if ( timetype != -1 ) status = TRUE;
-        }
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      {
+        grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+      break;
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
+      }
     }
 
-  Free(tu);
-
-  return (status);
+  return status;
 }
 
-static
-void scanTimeString(const char *ptu, int *rdate, int *rtime)
-{
-  int year = 1, month = 1, day = 1;
-  int hour = 0, minute = 0, second = 0;
-  int v1 = 1, v2 = 1, v3 = 1;
+/*
+ at Function  streamWriteVarSlice
+ at Title     Write a horizontal slice of a variable
 
-  *rdate = 0;
-  *rtime = 0;
+ at Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to a block of double precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
 
-  if ( *ptu )
-    {
-      v1 = atoi(ptu);
-      if ( v1 < 0 ) ptu++;
-      while ( isdigit((int) *ptu) ) ptu++;
-      if ( *ptu )
-        {
-          v2 = atoi(++ptu);
-          while ( isdigit((int) *ptu) ) ptu++;
-          if ( *ptu )
-            {
-              v3 = atoi(++ptu);
-              while ( isdigit((int) *ptu) ) ptu++;
-            }
-        }
-    }
+ at Description
+The function streamWriteVarSlice writes the values of a horizontal slice of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
+{
+  cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+}
 
-  if ( v3 > 999 && v1 < 32 )
-    { year = v3; month = v2; day = v1; }
-  else
-    { year = v1; month = v2; day = v3; }
+/*
+ at Function  streamWriteVarSliceF
+ at Title     Write a horizontal slice of a variable
 
-  while ( isspace((int) *ptu) ) ptu++;
+ at Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to a block of single precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
 
-  if ( *ptu )
+ at Description
+The function streamWriteVarSliceF writes the values of a horizontal slice of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
+{
+  if ( cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
     {
-      while ( ! isdigit((int) *ptu) ) ptu++;
-
-      hour = atoi(ptu);
-      while ( isdigit((int) *ptu) ) ptu++;
-      if ( *ptu == ':' )
-        {
-          ptu++;
-          minute = atoi(ptu);
-          while ( isdigit((int) *ptu) ) ptu++;
-          if ( *ptu == ':' )
-            {
-              ptu++;
-              second = atoi(ptu);
-            }
-        }
+      // In case the file format does not support single precision writing,
+      // we fall back to double precision writing, converting the data on the fly.
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
+      streamWriteVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
+      Free(conversionBuffer);
     }
-
-  *rdate = cdiEncodeDate(year, month, day);
-  *rtime = cdiEncodeTime(hour, minute, second);
 }
 
-static
-int scanTimeUnit(const char *unitstr)
-{
-  int timeunit = -1;
-  size_t len = strlen(unitstr);
-  timeunit = get_timeunit(len, unitstr);
-  if ( timeunit == -1 )
-    Message("Unsupported TIMEUNIT: %s!", unitstr);
 
-  return (timeunit);
+void
+streamWriteVarChunk(int streamID, int varID,
+                    const int rect[][2], const double *data, int nmiss)
+{
+  void (*myCdiStreamWriteVarChunk_)(int streamID, int varID, int memtype,
+                                    const int rect[][2], const void *data,
+                                    int nmiss)
+    = (void (*)(int, int, int, const int [][2], const void *, int))
+    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_CHUNK_).func;
+  myCdiStreamWriteVarChunk_(streamID, varID, MEMTYPE_DOUBLE, rect, data, nmiss);
 }
 
-static
-void setForecastTime(const char *timestr, taxis_t *taxis)
+/* single image implementation */
+void
+cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
+                        const int rect[][2], const void *data, int nmiss)
 {
-  int len;
+  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
 
-  (*taxis).fdate = 0;
-  (*taxis).ftime = 0;
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-  len = (int) strlen(timestr);
-  if ( len == 0 ) return;
+  // streamDefineTaxis(streamID);
 
-  int fdate = 0, ftime = 0;
-  scanTimeString(timestr, &fdate, &ftime);
+  int filetype = streamptr->filetype;
 
-  (*taxis).fdate = fdate;
-  (*taxis).ftime = ftime;
+  switch (filetype)
+    {
+#if defined (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+#endif
+#if defined (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+#endif
+#if defined (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+#endif
+#if defined (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+#endif
+#if  defined (HAVE_LIBGRIB) || defined (HAVE_LIBSERVICE)      \
+  || defined (HAVE_LIBEXTRA) || defined (HAVE_LIBIEG)
+      xabort("streamWriteVarChunk not implemented for filetype %s!",
+             strfiletype(filetype));
+      break;
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      cdf_write_var_chunk(streamptr, varID, memtype, rect, data, nmiss);
+      break;
+#endif
+    default:
+      Error("%s support not compiled in!", strfiletype(filetype));
+      break;
+    }
 }
 
 static
-int setBaseTime(const char *timeunits, taxis_t *taxis)
+int stream_write_record(int streamID, int memtype, const void *data, int nmiss)
 {
-  char *ptu, *tu;
-  int timetype = TAXIS_ABSOLUTE;
-  int rdate = -1, rtime = -1;
-  int timeunit;
-
-  size_t len = strlen(timeunits);
-  tu = (char *) Malloc((len+1) * sizeof (char));
-  memcpy(tu, timeunits, (len+1) * sizeof (char));
-  ptu = tu;
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
 
-  for ( size_t i = 0; i < len; i++ ) ptu[i] = (char)tolower((int) ptu[i]);
+  check_parg(data);
 
-  timeunit = get_timeunit(len, ptu);
-  if ( timeunit == -1 )
-    {
-      Message("Unsupported TIMEUNIT: %s!", timeunits);
-      return (1);
-    }
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-  while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
-  if ( *ptu )
+  switch (streamptr->filetype)
     {
-      while ( isspace(*ptu) ) ptu++;
-
-      if ( memcmp(ptu, "as", 2) == 0 )
-        timetype = TAXIS_ABSOLUTE;
-      else if ( memcmp(ptu, "since", 5) == 0 )
-        timetype = TAXIS_RELATIVE;
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      grb_write_record(streamptr, memtype, data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      srvWriteRecord(streamptr, (const double *)data);
+      break;
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      extWriteRecord(streamptr, (const double *)data);
+      break;
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      iegWriteRecord(streamptr, (const double *)data);
+      break;
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      {
+	cdf_write_record(streamptr, memtype, data, nmiss);
+	break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
+	break;
+      }
+    }
 
-      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
-      if ( *ptu )
-        {
-          while ( isspace(*ptu) ) ptu++;
+  return status;
+}
 
-          if ( timetype == TAXIS_ABSOLUTE )
-            {
-              if ( memcmp(ptu, "%y%m%d.%f", 9) != 0 && timeunit == TUNIT_DAY )
-                {
-                  Message("Unsupported format %s for TIMEUNIT day!", ptu);
-                  timeunit = -1;
-                }
-              else if ( memcmp(ptu, "%y%m.%f", 7) != 0 && timeunit == TUNIT_MONTH )
-                {
-                  Message("Unsupported format %s for TIMEUNIT month!", ptu);
-                  timeunit = -1;
-                }
-            }
-          else if ( timetype == TAXIS_RELATIVE )
-            {
-              scanTimeString(ptu, &rdate, &rtime);
+/*
+ at Function  streamWriteRecord
+ at Title     Write a horizontal slice of a variable
 
-              (*taxis).rdate = rdate;
-              (*taxis).rtime = rtime;
+ at Prototype void streamWriteRecord(int streamID, const double *data, int nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  data      Pointer to a block of double precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
 
-              if ( CDI_Debug )
-                Message("rdate = %d  rtime = %d", rdate, rtime);
-            }
-        }
-    }
+ at Description
+The function streamWriteRecord writes the values of a horizontal slice (record) of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteRecord(int streamID, const double *data, int nmiss)
+{
+  stream_write_record(streamID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+}
 
-  (*taxis).type = timetype;
-  (*taxis).unit = timeunit;
 
-  Free(tu);
+void streamWriteRecordF(int streamID, const float *data, int nmiss)
+{
+  if ( stream_write_record(streamID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
+    {
+      // In case the file format does not support single precision writing,
+      // we fall back to double precision writing, converting the data on the fly.
+      stream_t *streamptr = stream_to_pointer(streamID);
+      int varID  = streamptr->record->varID;
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
+      streamWriteRecord(streamID, conversionBuffer, nmiss);
+      Free(conversionBuffer);
+    }
+}
 
-  if ( CDI_Debug )
-    Message("timetype = %d  unit = %d", timetype, timeunit);
+#ifdef HAVE_CONFIG_H
+#endif
 
-  return (0);
-}
 
+
+/* the single image implementation */
 static
-void cdfGetAttInt(int fileID, int ncvarid, const char *attname, int attlen, int *attint)
+int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmiss)
 {
-  nc_type atttype;
-  size_t nc_attlen;
-
-  *attint = 0;
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
 
-  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
-  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
 
-  if ( atttype != NC_CHAR )
-    {
-      int *pintatt = NULL;
+  check_parg(data);
+  check_parg(nmiss);
 
-      if ( (int)nc_attlen > attlen )
-        pintatt = (int *) Malloc(nc_attlen * sizeof (int));
-      else
-        pintatt = attint;
+  stream_t *streamptr = stream_to_pointer(streamID);
+  int filetype = streamptr->filetype;
 
-      cdf_get_att_int(fileID, ncvarid, attname, pintatt);
+  *nmiss = 0;
 
-      if ( (int)nc_attlen > attlen )
-        {
-          memcpy(attint, pintatt, (size_t)attlen * sizeof (int));
-          Free(pintatt);
-        }
+  switch (filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      {
+        grb_read_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvReadVarDP(streamptr, varID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extReadVarDP(streamptr, varID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegReadVarDP(streamptr, varID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      {
+        cdf_read_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
+      }
     }
-}
 
-static
-void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
-{
-  nc_type atttype;
-  size_t nc_attlen;
+  return status;
+}
 
-  *attdouble = 0;
+/*
+ at Function  streamReadVar
+ at Title     Read a variable
 
-  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
-  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+ at Prototype void streamReadVar(int streamID, int varID, double *data, int *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
 
-  if ( atttype != NC_CHAR )
-    {
-      double *pdoubleatt = NULL;
+ at Description
+The function streamReadVar reads all the values of one time step of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVar(int streamID, int varID, double *data, int *nmiss)
+{
+  cdiStreamReadVar(streamID, varID, MEMTYPE_DOUBLE, data, nmiss);
+}
 
-      if ( (int)nc_attlen > attlen )
-        pdoubleatt = (double *) Malloc(nc_attlen * sizeof (double));
-      else
-        pdoubleatt = attdouble;
+/*
+ at Function  streamReadVarF
+ at Title     Read a variable
 
-      cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);
+ at Prototype void streamReadVar(int streamID, int varID, float *data, int *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
 
-      if ( (int)nc_attlen > attlen )
-        {
-          memcpy(attdouble, pdoubleatt, (size_t)attlen * sizeof (double));
-          Free(pdoubleatt);
-        }
+ at Description
+The function streamReadVar reads all the values of one time step of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVarF(int streamID, int varID, float *data, int *nmiss)
+{
+  if ( cdiStreamReadVar(streamID, varID, MEMTYPE_FLOAT, data, nmiss) )
+    {
+      // In case the file format does not support single precision reading,
+      // we fall back to double precision reading, converting the data on the fly.
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      streamReadVar(streamID, varID, conversionBuffer, nmiss);
+      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
+      Free(conversionBuffer);
     }
 }
 
+
 static
-void cdfGetAttText(int fileID, int ncvarid,const char *attname, int attlen, char *atttext)
+int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, void *data, int *nmiss)
 {
-  nc_type atttype;
-  size_t nc_attlen;
-
-  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
-  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
 
-  if ( atttype == NC_CHAR )
-    {
-      char attbuf[65636];
-      if ( nc_attlen < sizeof(attbuf) )
-        {
-          cdf_get_att_text(fileID, ncvarid, attname, attbuf);
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
 
-          if ( (int) nc_attlen > (attlen-1) ) nc_attlen = (size_t)(attlen-1);
+  check_parg(data);
+  check_parg(nmiss);
 
-          attbuf[nc_attlen++] = 0;
-          memcpy(atttext, attbuf, nc_attlen);
-        }
-      else
-        {
-          atttext[0] = 0;
-        }
-    }
-#if  defined  (HAVE_NETCDF4)
-  else if ( atttype == NC_STRING )
-    {
-      if ( nc_attlen == 1 )
-        {
-          char *attbuf = NULL;
-          cdf_get_att_string(fileID, ncvarid, attname, &attbuf);
+  stream_t *streamptr = stream_to_pointer(streamID);
+  int filetype = streamptr->filetype;
 
-          size_t ssize = strlen(attbuf) + 1;
+  *nmiss = 0;
 
-          if ( ssize > (size_t)attlen ) ssize = (size_t)attlen;
-          memcpy(atttext, attbuf, ssize);
-          atttext[ssize - 1] = 0;
-          Free(attbuf);
-        }
-      else
-        {
-          atttext[0] = 0;
-        }
-    }
+  switch (filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      {
+        grb_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+	break;
+      }
 #endif
-}
-
-static
-int xtypeIsText(int xtype)
-{
-  int isText = FALSE;
-
-  if ( xtype == NC_CHAR )
-    isText = TRUE;
-#if  defined  (HAVE_NETCDF4)
-  else if ( xtype == NC_STRING )
-    isText = TRUE;
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      {
+        cdf_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+        break;
+      }
 #endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+        status = 2;
+	break;
+      }
+    }
 
-  return isText;
+  return status;
 }
 
-static
-int xtypeIsFloat(int xtype)
-{
-  int isFloat = FALSE;
-
-  if ( xtype == NC_FLOAT || xtype == NC_DOUBLE ) isFloat = TRUE;
+/*
+ at Function  streamReadVarSlice
+ at Title     Read a horizontal slice of a variable
 
-  return isFloat;
-}
+ at Prototype void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
 
-static
-int cdfInqDatatype(int xtype, int lunsigned)
+ at Description
+The function streamReadVarSlice reads all the values of a horizontal slice of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
 {
-  int datatype = -1;
+  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, data, nmiss) )
+    {
+      Warning("Unexpected error returned from cdiStreamReadVarSlice()!");
+      size_t elementCount = (size_t)gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      memset(data, 0, elementCount * sizeof(*data));
+    }
+}
 
-#if  defined  (HAVE_NETCDF4)
-  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
-#endif
+/*
+ at Function  streamReadVarSliceF
+ at Title     Read a horizontal slice of a variable
 
-  if      ( xtype == NC_BYTE   )  datatype = DATATYPE_INT8;
-  /* else if ( xtype == NC_CHAR   )  datatype = DATATYPE_UINT8; */
-  else if ( xtype == NC_SHORT  )  datatype = DATATYPE_INT16;
-  else if ( xtype == NC_INT    )  datatype = DATATYPE_INT32;
-  else if ( xtype == NC_FLOAT  )  datatype = DATATYPE_FLT32;
-  else if ( xtype == NC_DOUBLE )  datatype = DATATYPE_FLT64;
-#if  defined  (HAVE_NETCDF4)
-  else if ( xtype == NC_UBYTE  )  datatype = DATATYPE_UINT8;
-  else if ( xtype == NC_LONG   )  datatype = DATATYPE_INT32;
-  else if ( xtype == NC_USHORT )  datatype = DATATYPE_UINT16;
-  else if ( xtype == NC_UINT   )  datatype = DATATYPE_UINT32;
-  else if ( xtype == NC_INT64  )  datatype = DATATYPE_FLT64;
-  else if ( xtype == NC_UINT64 )  datatype = DATATYPE_FLT64;
-#endif
+ at Prototype void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
 
-  return (datatype);
+ at Description
+The function streamReadVarSliceF reads all the values of a horizontal slice of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
+{
+  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, data, nmiss) )
+    {
+      // In case the file format does not support single precision reading,
+      // we fall back to double precision reading, converting the data on the fly.
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      streamReadVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
+      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
+      Free(conversionBuffer);
+    }
 }
 
 static
-int cdfDefDatatype(int datatype, int filetype)
+int stream_read_record(int streamID, int memtype, void *data, int *nmiss)
 {
-  int xtype;
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
 
-  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
-    Error("CDI/netCDF library does not support complex numbers!");
+  check_parg(data);
+  check_parg(nmiss);
 
-  if ( filetype == FILETYPE_NC4 )
+  stream_t *streamptr = stream_to_pointer(streamID);
+
+  *nmiss = 0;
+
+  switch (streamptr->filetype)
     {
-      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
-      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
-#if  defined  (HAVE_NETCDF4)
-      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_UBYTE;
-      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_USHORT;
-      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_UINT;
-#else
-      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      grb_read_record(streamptr, memtype, data, nmiss);
+      break;
 #endif
-      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
-      else                                    xtype = NC_FLOAT;
-    }
-  else
-    {
-      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
-      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
-      else                                    xtype = NC_FLOAT;
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      srvReadRecord(streamptr, (double *)data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      extReadRecord(streamptr, (double *)data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      iegReadRecord(streamptr, (double *)data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      cdf_read_record(streamptr, memtype, data, nmiss);
+      break;
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
+	break;
+      }
     }
 
-  return (xtype);
+  return status;
 }
 
-static inline void *
-resizeBuf(void **buf, size_t *bufSize, size_t reqSize)
+
+void streamReadRecord(int streamID, double *data, int *nmiss)
 {
-  if (reqSize > *bufSize)
-    {
-      *buf = Realloc(*buf, reqSize);
-      *bufSize = reqSize;
-    }
-  return *buf;
+  stream_read_record(streamID, MEMTYPE_DOUBLE, (void *) data, nmiss);
 }
 
-static
-void defineAttributes(int vlistID, int varID, int fileID, int ncvarID)
-{
-  int natts, iatt;
-  int atttype, attlen;
-  size_t len;
-  char attname[CDI_MAX_NAME+1];
-  void *attBuf = NULL;
-  size_t attBufSize = 0;
 
-  vlistInqNatts(vlistID, varID, &natts);
-
-  for ( iatt = 0; iatt < natts; iatt++ )
+void streamReadRecordF(int streamID, float *data, int *nmiss)
+{
+  if ( stream_read_record(streamID, MEMTYPE_FLOAT, (void *) data, nmiss) )
     {
-      vlistInqAtt(vlistID, varID, iatt, attname, &atttype, &attlen);
-
-      if ( attlen == 0 ) continue;
-
-      if ( atttype == DATATYPE_TXT )
-        {
-          size_t attSize = (size_t)attlen*sizeof(char);
-          char *atttxt = (char *)resizeBuf(&attBuf, &attBufSize, attSize);
-          vlistInqAttTxt(vlistID, varID, attname, attlen, atttxt);
-          len = (size_t)attlen;
-          cdf_put_att_text(fileID, ncvarID, attname, len, atttxt);
-        }
-      else if ( atttype == DATATYPE_INT16 || atttype == DATATYPE_INT32 )
-        {
-          size_t attSize = (size_t)attlen*sizeof(int);
-          int *attint = (int *)resizeBuf(&attBuf, &attBufSize, attSize);
-          vlistInqAttInt(vlistID, varID, attname, attlen, &attint[0]);
-          len = (size_t)attlen;
-          cdf_put_att_int(fileID, ncvarID, attname, atttype == DATATYPE_INT16 ? NC_SHORT : NC_INT, len, attint);
-        }
-      else if ( atttype == DATATYPE_FLT32 || atttype == DATATYPE_FLT64 )
-        {
-          size_t attSize = (size_t)attlen * sizeof(double);
-          double *attflt = (double *)resizeBuf(&attBuf, &attBufSize, attSize);
-          vlistInqAttFlt(vlistID, varID, attname, attlen, attflt);
-          len = (size_t)attlen;
-          if ( atttype == DATATYPE_FLT32 )
-            {
-              float attflt_sp[len];
-              for ( size_t i = 0; i < len; ++i ) attflt_sp[i] = (float)attflt[i];
-              cdf_put_att_float(fileID, ncvarID, attname, NC_FLOAT, len, attflt_sp);
-            }
-          else
-            cdf_put_att_double(fileID, ncvarID, attname, NC_DOUBLE, len, attflt);
-        }
+      // In case the file format does not support single precision reading,
+      // we fall back to double precision reading, converting the data on the fly.
+      stream_t *streamptr = stream_to_pointer(streamID);
+      int tsID   = streamptr->curTsID;
+      int vrecID = streamptr->tsteps[tsID].curRecID;
+      int recID  = streamptr->tsteps[tsID].recIDs[vrecID];
+      int varID  = streamptr->tsteps[tsID].records[recID].varID;
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      streamReadRecord(streamID, conversionBuffer, nmiss);
+      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
+      Free(conversionBuffer);
     }
-  Free(attBuf);
 }
+#ifndef _VARSCAN_H
+#define _VARSCAN_H
 
+#ifndef _GRID_H
+#endif
 
-void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
-{
-  int memtype  = MEMTYPE_DOUBLE;
-  int vlistID1 = streamptr1->vlistID;
-  int tsID     = streamptr1->curTsID;
-  int vrecID   = streamptr1->tsteps[tsID].curRecID;
-  int recID    = streamptr1->tsteps[tsID].recIDs[vrecID];
-  int ivarID   = streamptr1->tsteps[tsID].records[recID].varID;
-  int gridID   = vlistInqVarGrid(vlistID1, ivarID);
-  int datasize = gridInqSize(gridID);
-
-  double *data = (double *) Malloc((size_t)datasize * sizeof (double));
-
-  int nmiss;
-  cdfReadRecord(streamptr1, data, &nmiss);
-  cdf_write_record(streamptr2, memtype, data, nmiss);
 
-  Free(data);
-}
+void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds,
+		  int level1, int level2, int level_sf, int level_unit, int prec,
+		  int *pvarID, int *plevelID, int tsteptype, int numavg, int ltype1, int ltype2,
+		  const char *name, const char *stdname, const char *longname, const char *units,
+                  const var_tile_t *tiles, int *tile_index);
 
-/* not used
-int cdfInqRecord(stream_t *streamptr, int *varID, int *levelID)
-{
-  int tsID, recID;
+void varDefVCT(size_t vctsize, double *vctptr);
+void varDefZAxisReference(int nlev, int nvgrid, unsigned char uuid[CDI_UUID_SIZE]);
 
-  recID = streamptr->tsteps[0].curRecID++;
-  printf("cdfInqRecord recID %d %d\n", recID, streamptr->tsteps[0].curRecID);
-  printf("cdfInqRecord tsID %d\n", streamptr->curTsID);
+int  varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, int lbounds,
+		 const double *levels1, const double *levels2, int vctsize, const double *vct, char *name,
+		 const char *longname, const char *units, int prec, int mode, int ltype);
 
-  if ( streamptr->tsteps[0].curRecID >= streamptr->tsteps[0].nrecs )
-    {
-      streamptr->tsteps[0].curRecID = 0;
-    }
+void varDefMissval(int varID, double missval);
+void varDefCompType(int varID, int comptype);
+void varDefCompLevel(int varID, int complevel);
+void varDefInst(int varID, int instID);
+int  varInqInst(int varID);
+void varDefModel(int varID, int modelID);
+int  varInqModel(int varID);
+void varDefTable(int varID, int tableID);
+int  varInqTable(int varID);
+void varDefEnsembleInfo(int varID, int ens_idx, int ens_count, int forecast_type);
 
-  *varID   = streamptr->tsteps[0].records[recID].varID;
-  *levelID = streamptr->tsteps[0].records[recID].levelID;
+void varDefTypeOfGeneratingProcess(int varID, int typeOfGeneratingProcess);
+void varDefProductDefinitionTemplate(int varID, int productDefinitionTemplate);
 
-  streamptr->record->varID   = *varID;
-  streamptr->record->levelID = *levelID;
 
-  if ( CDI_Debug )
-    Message("recID = %d  varID = %d  levelID = %d", recID, *varID, *levelID);
+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);
 
-  return (recID+1);
-}
-*/
+int  zaxisCompare(int zaxisID, int zaxistype, int nlevels, int lbounds, const double *levels, const char *longname, const char *units, int ltype);
 
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-void cdfDefRecord(stream_t *streamptr)
-{
-  (void)streamptr;
-}
+#ifdef HAVE_LIBNETCDF
 
+//#define TEST_GROUPS 1
 
-static
-void cdfWriteGridTraj(stream_t *streamptr, int gridID)
-{
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
+#include <limits.h>
+#include <ctype.h>
+#include <math.h>
+#include <float.h>
+#ifdef HAVE_MMAP
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
+#ifdef HAVE_LIBPTHREAD
+#include <pthread.h>
+#endif
 
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  int lonID = streamptr->xdimID[gridindex],
-    latID = streamptr->ydimID[gridindex];
+#include <netcdf.h>
 
-  double xlon = gridInqXval(gridID, 0),
-    xlat = gridInqYval(gridID, 0);
-  int tsID = streamptr->curTsID;
-  size_t index = (size_t)tsID;
 
-  cdf_put_var1_double(fileID, lonID, &index, &xlon);
-  cdf_put_var1_double(fileID, latID, &index, &xlat);
-}
+//#define PROJECTION_TEST
 
-static
-void cdfReadGridTraj(stream_t *streamptr, int gridID)
-{
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
+#undef  UNDEFID
+#define UNDEFID  CDI_UNDEFID
 
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  int lonID = streamptr->xdimID[gridindex];
-  int latID = streamptr->ydimID[gridindex];
+#define  BNDS_NAME  "bnds"
 
-  int tsID = streamptr->curTsID;
-  size_t index = (size_t)tsID;
+#define  X_AXIS  1
+#define  Y_AXIS  2
+#define  Z_AXIS  3
+#define  T_AXIS  4
 
-  double xlon, xlat;
-  cdf_get_var1_double(fileID, lonID, &index, &xlon);
-  cdf_get_var1_double(fileID, latID, &index, &xlat);
+#define  POSITIVE_UP    1
+#define  POSITIVE_DOWN  2
 
-  gridDefXvals(gridID, &xlon);
-  gridDefYvals(gridID, &xlat);
+typedef struct {
+  int     ncvarid;
+  int     dimtype;
+  size_t  len;
+  char    name[CDI_MAX_NAME];
 }
+ncdim_t;
+#define  MAX_COORDVARS  4
+#define  MAX_AUXVARS    4
 
+typedef struct {
+  int      ncid;
+  int      ignore;
+  short    isvar;
+  short    islon;
+  int      islat;
+  int      islev;
+  int      istime;
+  int      warn;
+  int      tsteptype;
+  int      param;
+  int      code;
+  int      tabnum;
+  int      climatology;
+  int      bounds;
+  int      lformula;
+  int      lformulaterms;
+  int      gridID;
+  int      zaxisID;
+  int      gridtype;
+  int      zaxistype;
+  int      xdim;
+  int      ydim;
+  int      zdim;
+  int      xvarid;
+  int      yvarid;
+  int      zvarid;
+  int      tvarid;
+  int      psvarid;
+  int      ncoordvars;
+  int      coordvarids[MAX_COORDVARS];
+  int      nauxvars;
+  int      auxvarids[MAX_AUXVARS];
+  int      cellarea;
+  int      calendar;
+  int      tableID;
+  int      truncation;
+  int      position;
+  int      defmissval;
+  int      deffillval;
+  int      xtype;
+  int      ndims;
+  int      gmapid;
+  int      positive;
+  int      dimids[8];
+  int      dimtype[8];
+  int      chunks[8];
+  int      chunked;
+  int      chunktype;
+  int      natts;
+  int      deflate;
+  int      lunsigned;
+  int      lvalidrange;
+  int     *atts;
+  size_t   vctsize;
+  double  *vct;
+  double   missval;
+  double   fillval;
+  double   addoffset;
+  double   scalefactor;
+  double   validrange[2];
+  char     name[CDI_MAX_NAME];
+  char     longname[CDI_MAX_NAME];
+  char     stdname[CDI_MAX_NAME];
+  char     units[CDI_MAX_NAME];
+  char     extra[CDI_MAX_NAME];
+  ensinfo_t   *ensdata;    /* Ensemble information */
+}
+ncvar_t;
 
 static
-void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level)
+void strtolower(char *str)
 {
-#if  defined  (HAVE_NETCDF4)
-  int retval;
-  /* Set chunking, shuffle, and deflate. */
-  int shuffle = 1;
-  int deflate = 1;
+  if ( str )
+    for (size_t i = 0; str[i]; ++i)
+      str[i] = (char)tolower((int)str[i]);
+}
 
-  if ( deflate_level < 1 || deflate_level > 9 ) deflate_level = 1;
+static
+int get_timeunit(size_t len, const char *ptu)
+{
+  int timeunit = -1;
 
-  if ((retval = nc_def_var_deflate(ncid, ncvarid, shuffle, deflate, deflate_level)))
+  if ( len > 2 )
     {
-      Error("nc_def_var_deflate failed, status = %d", retval);
+      if      ( memcmp(ptu, "sec",    3) == 0 )          timeunit = TUNIT_SECOND;
+      else if ( memcmp(ptu, "minute", 6) == 0 )          timeunit = TUNIT_MINUTE;
+      else if ( memcmp(ptu, "hour",   4) == 0 )          timeunit = TUNIT_HOUR;
+      else if ( memcmp(ptu, "day",    3) == 0 )          timeunit = TUNIT_DAY;
+      else if ( memcmp(ptu, "month",  5) == 0 )          timeunit = TUNIT_MONTH;
+      else if ( memcmp(ptu, "calendar_month", 14) == 0 ) timeunit = TUNIT_MONTH;
+      else if ( memcmp(ptu, "year",   4) == 0 )          timeunit = TUNIT_YEAR;
     }
-#else
-  static int lwarn = TRUE;
-
-  if ( lwarn )
+  else if ( len == 1 )
     {
-      lwarn = FALSE;
-      Warning("Deflate compression failed, netCDF4 not available!");
+      if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND;
     }
-#endif
+
+  return timeunit;
 }
 
+static
+bool isTimeUnits(const char *timeunits)
+{
+  bool status = false;
+
+  if ( strncmp(timeunits, "sec",    3) == 0 ||
+       strncmp(timeunits, "minute", 6) == 0 ||
+       strncmp(timeunits, "hour",   4) == 0 ||
+       strncmp(timeunits, "day",    3) == 0 ||
+       strncmp(timeunits, "month",  5) == 0 ) status = true;
+
+  return status;
+}
 
-#if defined(NC_SZIP_NN_OPTION_MASK)
 static
-void cdfDefVarSzip(int ncid, int ncvarid)
+bool isTimeAxisUnits(const char *timeunits)
 {
-  int retval;
-  /* Set options_mask and bits_per_pixel. */
-  int options_mask = NC_SZIP_NN_OPTION_MASK;
-  int bits_per_pixel = 16;
+  char *ptu, *tu;
+  int timetype = -1;
+  int timeunit;
+  bool status = false;
 
-  if ((retval = nc_def_var_szip(ncid, ncvarid, options_mask, bits_per_pixel)))
+  size_t len = strlen(timeunits);
+  tu = (char *) Malloc((len+1)*sizeof(char));
+  memcpy(tu, timeunits, (len+1) * sizeof(char));
+  ptu = tu;
+
+  for (size_t i = 0; i < len; i++ ) ptu[i] = (char)tolower((int)ptu[i]);
+
+  timeunit = get_timeunit(len, ptu);
+  if ( timeunit != -1 )
     {
-      if ( retval == NC_EINVAL )
+
+      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
+      if ( *ptu )
         {
-          static int lwarn = TRUE;
+          while ( isspace(*ptu) ) ptu++;
 
-          if ( lwarn )
-            {
-              lwarn = FALSE;
-              Warning("netCDF4/Szip compression not compiled in!");
-            }
+          if ( memcmp(ptu, "as", 2) == 0 )
+            timetype = TAXIS_ABSOLUTE;
+          else if ( memcmp(ptu, "since", 5) == 0 )
+            timetype = TAXIS_RELATIVE;
+
+          if ( timetype != -1 ) status = true;
         }
-      else
-        Error("nc_def_var_szip failed, status = %d", retval);
     }
+
+  Free(tu);
+
+  return status;
 }
-#endif
 
 static
-void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
+void scanTimeString(const char *ptu, int *rdate, int *rtime)
 {
-  if ( streamptr->vars[varID].defmiss == FALSE )
-    {
-      int fileID;
-      int ncvarid;
-      double missval;
-      int vlistID;
-      int xtype;
-
-      vlistID = streamptr->vlistID;
-      fileID  = streamptr->fileID;
-      ncvarid = streamptr->vars[varID].ncvarid;
-      missval = vlistInqVarMissval(vlistID, varID);
+  int year = 1, month = 1, day = 1;
+  int hour = 0, minute = 0, second = 0;
+  int v1 = 1, v2 = 1, v3 = 1;
 
-      if ( lcheck && streamptr->ncmode == 2 ) cdf_redef(fileID);
+  *rdate = 0;
+  *rtime = 0;
 
-      xtype = cdfDefDatatype(dtype, streamptr->filetype);
+  if ( *ptu )
+    {
+      v1 = atoi(ptu);
+      if ( v1 < 0 ) ptu++;
+      while ( isdigit((int) *ptu) ) ptu++;
+      if ( *ptu )
+        {
+          v2 = atoi(++ptu);
+          while ( isdigit((int) *ptu) ) ptu++;
+          if ( *ptu )
+            {
+              v3 = atoi(++ptu);
+              while ( isdigit((int) *ptu) ) ptu++;
+            }
+        }
+    }
 
-      if ( xtype == NC_BYTE && missval > 127 && missval < 256 ) xtype = NC_INT;
+  if ( v3 > 999 && v1 < 32 )
+    { year = v3; month = v2; day = v1; }
+  else
+    { year = v1; month = v2; day = v3; }
 
-      cdf_put_att_double(fileID, ncvarid, "_FillValue", (nc_type) xtype, 1, &missval);
-      cdf_put_att_double(fileID, ncvarid, "missing_value", (nc_type) xtype, 1, &missval);
+  while ( isspace((int) *ptu) ) ptu++;
 
-      if ( lcheck && streamptr->ncmode == 2 ) cdf_enddef(fileID);
+  if ( *ptu )
+    {
+      while ( ! isdigit((int) *ptu) ) ptu++;
 
-      streamptr->vars[varID].defmiss = TRUE;
+      hour = atoi(ptu);
+      while ( isdigit((int) *ptu) ) ptu++;
+      if ( *ptu == ':' )
+        {
+          ptu++;
+          minute = atoi(ptu);
+          while ( isdigit((int) *ptu) ) ptu++;
+          if ( *ptu == ':' )
+            {
+              ptu++;
+              second = atoi(ptu);
+            }
+        }
     }
-}
 
+  *rdate = cdiEncodeDate(year, month, day);
+  *rtime = cdiEncodeTime(hour, minute, second);
+}
 
-void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss)
+static
+int scanTimeUnit(const char *unitstr)
 {
-  int varID;
-  int levelID;
-
-  varID   = streamptr->record->varID;
-  levelID = streamptr->record->levelID;
-
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
+  size_t len = strlen(unitstr);
+  int timeunit = get_timeunit(len, unitstr);
+  if ( timeunit == -1 )
+    Message("Unsupported TIMEUNIT: %s!", unitstr);
 
-  cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+  return timeunit;
 }
 
-void cdfReadRecord(stream_t *streamptr, double *data, int *nmiss)
+static
+void setForecastTime(const char *timestr, taxis_t *taxis)
 {
-  if ( CDI_Debug ) Message("streamID = %d", streamptr->self);
+  (*taxis).fdate = 0;
+  (*taxis).ftime = 0;
 
-  int tsID    = streamptr->curTsID;
-  int vrecID  = streamptr->tsteps[tsID].curRecID;
-  int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-  int varID   = streamptr->tsteps[tsID].records[recID].varID;
-  int levelID = streamptr->tsteps[tsID].records[recID].levelID;
+  int len = (int) strlen(timestr);
+  if ( len == 0 ) return;
+
+  int fdate = 0, ftime = 0;
+  scanTimeString(timestr, &fdate, &ftime);
 
-  cdfReadVarSliceDP(streamptr, varID, levelID, data, nmiss);
+  (*taxis).fdate = fdate;
+  (*taxis).ftime = ftime;
 }
 
 static
-void cdfDefTimeValue(stream_t *streamptr, int tsID)
+int setBaseTime(const char *timeunits, taxis_t *taxis)
 {
-  int fileID = streamptr->fileID;
+  int timetype = TAXIS_ABSOLUTE;
+  int rdate = -1, rtime = -1;
 
-  if ( CDI_Debug )
-    Message("streamID = %d, fileID = %d", streamptr->self, fileID);
+  size_t len = strlen(timeunits);
+  char *tu = (char *) Malloc((len+1) * sizeof (char));
+  memcpy(tu, timeunits, (len+1) * sizeof (char));
+  char *ptu = tu;
 
-  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+  for ( size_t i = 0; i < len; i++ ) ptu[i] = (char)tolower((int) ptu[i]);
 
-  if ( streamptr->ncmode == 1 )
+  int timeunit = get_timeunit(len, ptu);
+  if ( timeunit == -1 )
     {
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+      Message("Unsupported TIMEUNIT: %s!", timeunits);
+      return (1);
     }
 
-  size_t index = (size_t)tsID;
-
-  double timevalue = cdiEncodeTimeval(taxis->vdate, taxis->vtime, &streamptr->tsteps[0].taxis);
-  if ( CDI_Debug ) Message("tsID = %d  timevalue = %f", tsID, timevalue);
+  while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
+  if ( *ptu )
+    {
+      while ( isspace(*ptu) ) ptu++;
 
-  int ncvarid = streamptr->basetime.ncvarid;
-  cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
+      if ( memcmp(ptu, "as", 2) == 0 )
+        timetype = TAXIS_ABSOLUTE;
+      else if ( memcmp(ptu, "since", 5) == 0 )
+        timetype = TAXIS_RELATIVE;
 
-  if ( taxis->has_bounds )
-    {
-      size_t start[2], count[2];
+      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
+      if ( *ptu )
+        {
+          while ( isspace(*ptu) ) ptu++;
 
-      ncvarid = streamptr->basetime.ncvarboundsid;
+          if ( timetype == TAXIS_ABSOLUTE )
+            {
+              if ( memcmp(ptu, "%y%m%d.%f", 9) != 0 && timeunit == TUNIT_DAY )
+                {
+                  Message("Unsupported format %s for TIMEUNIT day!", ptu);
+                  timeunit = -1;
+                }
+              else if ( memcmp(ptu, "%y%m.%f", 7) != 0 && timeunit == TUNIT_MONTH )
+                {
+                  Message("Unsupported format %s for TIMEUNIT month!", ptu);
+                  timeunit = -1;
+                }
+            }
+          else if ( timetype == TAXIS_RELATIVE )
+            {
+              scanTimeString(ptu, &rdate, &rtime);
 
-      timevalue = cdiEncodeTimeval(taxis->vdate_lb, taxis->vtime_lb, &streamptr->tsteps[0].taxis);
-      start[0] = (size_t)tsID; count[0] = 1; start[1] = 0; count[1] = 1;
-      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
+              (*taxis).rdate = rdate;
+              (*taxis).rtime = rtime;
 
-      timevalue = cdiEncodeTimeval(taxis->vdate_ub, taxis->vtime_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);
+              if ( CDI_Debug )
+                Message("rdate = %d  rtime = %d", rdate, rtime);
+            }
+        }
     }
 
-  ncvarid = streamptr->basetime.leadtimeid;
-  if ( taxis->type == TAXIS_FORECAST && ncvarid != UNDEFID )
-    {
-      timevalue = taxis->fc_period;
-      cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
-    }
+  (*taxis).type = timetype;
+  (*taxis).unit = timeunit;
 
-  /*
-printf("fileID = %d %d %d %f\n", fileID, time_varid, index, timevalue);
-  */
+  Free(tu);
+
+  if ( CDI_Debug )
+    Message("timetype = %d  unit = %d", timetype, timeunit);
+
+  return 0;
 }
 
 static
-int cdfDefTimeBounds(int fileID, int nctimevarid, int nctimedimid, char* taxis_name, taxis_t* taxis)
+void cdfGetAttInt(int fileID, int ncvarid, const char *attname, int attlen, int *attint)
 {
-  int time_bndsid = -1;
-  int dims[2];
-  char tmpstr[CDI_MAX_NAME];
-
+  nc_type atttype;
+  size_t nc_attlen;
+
+  *attint = 0;
+
+  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
+  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+
+  if ( atttype != NC_CHAR )
+    {
+      int *pintatt = NULL;
+
+      if ( (int)nc_attlen > attlen )
+        pintatt = (int *) Malloc(nc_attlen * sizeof (int));
+      else
+        pintatt = attint;
+
+      cdf_get_att_int(fileID, ncvarid, attname, pintatt);
+
+      if ( (int)nc_attlen > attlen )
+        {
+          memcpy(attint, pintatt, (size_t)attlen * sizeof (int));
+          Free(pintatt);
+        }
+    }
+}
+
+static
+void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
+{
+  nc_type atttype;
+  size_t nc_attlen;
+
+  *attdouble = 0;
+
+  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
+  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+
+  if ( atttype != NC_CHAR )
+    {
+      double *pdoubleatt = NULL;
+
+      if ( (int)nc_attlen > attlen )
+        pdoubleatt = (double *) Malloc(nc_attlen * sizeof (double));
+      else
+        pdoubleatt = attdouble;
+
+      cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);
+
+      if ( (int)nc_attlen > attlen )
+        {
+          memcpy(attdouble, pdoubleatt, (size_t)attlen * sizeof (double));
+          Free(pdoubleatt);
+        }
+    }
+}
+
+static
+void cdfGetAttText(int fileID, int ncvarid,const char *attname, int attlen, char *atttext)
+{
+  nc_type atttype;
+  size_t nc_attlen;
+
+  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
+  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+
+  if ( atttype == NC_CHAR )
+    {
+      char attbuf[65636];
+      if ( nc_attlen < sizeof(attbuf) )
+        {
+          cdf_get_att_text(fileID, ncvarid, attname, attbuf);
+
+          if ( (int) nc_attlen > (attlen-1) ) nc_attlen = (size_t)(attlen-1);
+
+          attbuf[nc_attlen++] = 0;
+          memcpy(atttext, attbuf, nc_attlen);
+        }
+      else
+        {
+          atttext[0] = 0;
+        }
+    }
+#if  defined  (HAVE_NETCDF4)
+  else if ( atttype == NC_STRING )
+    {
+      if ( nc_attlen == 1 )
+        {
+          char *attbuf = NULL;
+          cdf_get_att_string(fileID, ncvarid, attname, &attbuf);
+
+          size_t ssize = strlen(attbuf) + 1;
+
+          if ( ssize > (size_t)attlen ) ssize = (size_t)attlen;
+          memcpy(atttext, attbuf, ssize);
+          atttext[ssize - 1] = 0;
+          Free(attbuf);
+        }
+      else
+        {
+          atttext[0] = 0;
+        }
+    }
+#endif
+}
+
+static
+int xtypeIsText(int xtype)
+{
+  int isText = FALSE;
+
+  if ( xtype == NC_CHAR )
+    isText = TRUE;
+#if  defined  (HAVE_NETCDF4)
+  else if ( xtype == NC_STRING )
+    isText = TRUE;
+#endif
+
+  return isText;
+}
+
+static
+int xtypeIsFloat(int xtype)
+{
+  int isFloat = FALSE;
+
+  if ( xtype == NC_FLOAT || xtype == NC_DOUBLE ) isFloat = TRUE;
+
+  return isFloat;
+}
+
+static
+int cdfInqDatatype(int xtype, int lunsigned)
+{
+  int datatype = -1;
+
+#if  defined  (HAVE_NETCDF4)
+  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
+#endif
+
+  if      ( xtype == NC_BYTE   )  datatype = DATATYPE_INT8;
+  /* else if ( xtype == NC_CHAR   )  datatype = DATATYPE_UINT8; */
+  else if ( xtype == NC_SHORT  )  datatype = DATATYPE_INT16;
+  else if ( xtype == NC_INT    )  datatype = DATATYPE_INT32;
+  else if ( xtype == NC_FLOAT  )  datatype = DATATYPE_FLT32;
+  else if ( xtype == NC_DOUBLE )  datatype = DATATYPE_FLT64;
+#if  defined  (HAVE_NETCDF4)
+  else if ( xtype == NC_UBYTE  )  datatype = DATATYPE_UINT8;
+  else if ( xtype == NC_LONG   )  datatype = DATATYPE_INT32;
+  else if ( xtype == NC_USHORT )  datatype = DATATYPE_UINT16;
+  else if ( xtype == NC_UINT   )  datatype = DATATYPE_UINT32;
+  else if ( xtype == NC_INT64  )  datatype = DATATYPE_FLT64;
+  else if ( xtype == NC_UINT64 )  datatype = DATATYPE_FLT64;
+#endif
+
+  return datatype;
+}
+
+
+void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
+{
+  int memtype  = MEMTYPE_DOUBLE;
+  int vlistID1 = streamptr1->vlistID;
+  int tsID     = streamptr1->curTsID;
+  int vrecID   = streamptr1->tsteps[tsID].curRecID;
+  int recID    = streamptr1->tsteps[tsID].recIDs[vrecID];
+  int ivarID   = streamptr1->tsteps[tsID].records[recID].varID;
+  int gridID   = vlistInqVarGrid(vlistID1, ivarID);
+  int datasize = gridInqSize(gridID);
+  int datatype = vlistInqVarDatatype(vlistID1, ivarID);
+
+  if ( datatype == DATATYPE_FLT32 ) memtype = MEMTYPE_FLOAT;
+
+  void *data = NULL;
+  if ( memtype == MEMTYPE_DOUBLE )
+    data = Malloc((size_t)datasize*sizeof(double));
+  else
+    data = Malloc((size_t)datasize*sizeof(float));
+
+  int nmiss;
+  cdf_read_record(streamptr1, memtype, data, &nmiss);
+  cdf_write_record(streamptr2, memtype, data, nmiss);
+
+  Free(data);
+}
+
+/* not used
+int cdfInqRecord(stream_t *streamptr, int *varID, int *levelID)
+{
+  int tsID, recID;
+
+  recID = streamptr->tsteps[0].curRecID++;
+  printf("cdfInqRecord recID %d %d\n", recID, streamptr->tsteps[0].curRecID);
+  printf("cdfInqRecord tsID %d\n", streamptr->curTsID);
+
+  if ( streamptr->tsteps[0].curRecID >= streamptr->tsteps[0].nrecs )
+    {
+      streamptr->tsteps[0].curRecID = 0;
+    }
+
+  *varID   = streamptr->tsteps[0].records[recID].varID;
+  *levelID = streamptr->tsteps[0].records[recID].levelID;
+
+  streamptr->record->varID   = *varID;
+  streamptr->record->levelID = *levelID;
+
+  if ( CDI_Debug )
+    Message("recID = %d  varID = %d  levelID = %d", recID, *varID, *levelID);
+
+  return (recID+1);
+}
+*/
+
+
+void cdfDefRecord(stream_t *streamptr)
+{
+  (void)streamptr;
+}
+
+#if defined(NC_SZIP_NN_OPTION_MASK)
+static
+void cdfDefVarSzip(int ncid, int ncvarid)
+{
+  int retval;
+  /* Set options_mask and bits_per_pixel. */
+  int options_mask = NC_SZIP_NN_OPTION_MASK;
+  int bits_per_pixel = 16;
+
+  if ((retval = nc_def_var_szip(ncid, ncvarid, options_mask, bits_per_pixel)))
+    {
+      if ( retval == NC_EINVAL )
+        {
+          static int lwarn = TRUE;
+
+          if ( lwarn )
+            {
+              lwarn = FALSE;
+              Warning("NetCDF4/Szip compression not compiled in!");
+            }
+        }
+      else
+        Error("nc_def_var_szip failed, status = %d", retval);
+    }
+}
+#endif
+
+static
+void cdfDefTimeValue(stream_t *streamptr, int tsID)
+{
+  int fileID = streamptr->fileID;
+
+  if ( CDI_Debug )
+    Message("streamID = %d, fileID = %d", streamptr->self, fileID);
+
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+
+  if ( streamptr->ncmode == 1 )
+    {
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+    }
+
+  size_t index = (size_t)tsID;
+
+  double timevalue = cdiEncodeTimeval(taxis->vdate, taxis->vtime, &streamptr->tsteps[0].taxis);
+  if ( CDI_Debug ) Message("tsID = %d  timevalue = %f", tsID, timevalue);
+
+  int ncvarid = streamptr->basetime.ncvarid;
+  cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
+
+  if ( taxis->has_bounds )
+    {
+      size_t start[2], count[2];
+
+      ncvarid = streamptr->basetime.ncvarboundsid;
+
+      timevalue = cdiEncodeTimeval(taxis->vdate_lb, taxis->vtime_lb, &streamptr->tsteps[0].taxis);
+      start[0] = (size_t)tsID; count[0] = 1; start[1] = 0; count[1] = 1;
+      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
+
+      timevalue = cdiEncodeTimeval(taxis->vdate_ub, taxis->vtime_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);
+    }
+
+  ncvarid = streamptr->basetime.leadtimeid;
+  if ( taxis->type == TAXIS_FORECAST && ncvarid != UNDEFID )
+    {
+      timevalue = taxis->fc_period;
+      cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
+    }
+
+  /*
+printf("fileID = %d %d %d %f\n", fileID, time_varid, index, timevalue);
+  */
+}
+
+static
+int cdfDefTimeBounds(int fileID, int nctimevarid, int nctimedimid, char* taxis_name, taxis_t* taxis)
+{
+  int time_bndsid = -1;
+  int dims[2];
+  char tmpstr[CDI_MAX_NAME];
+
   dims[0] = nctimedimid;
 
   /* fprintf(stderr, "time has bounds\n"); */
@@ -38213,7 +38535,7 @@ void cdfDefCalendar(int fileID, int ncvarid, int calendar)
   if ( len ) cdf_put_att_text(fileID, ncvarid, "calendar", len, calstr);
 }
 
-static
+
 void cdfDefTime(stream_t* streamptr)
 {
   int time_varid;
@@ -38315,7 +38637,6 @@ void cdfDefComplex(stream_t *streamptr, int gridID)
 {
   char axisname[] = "nc2";
   int dimID = UNDEFID;
-  int gridID0, gridtype0;
   int vlistID = streamptr->vlistID;
   int fileID  = streamptr->fileID;
 
@@ -38325,8 +38646,8 @@ void cdfDefComplex(stream_t *streamptr, int gridID)
     {
       if ( streamptr->xdimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_SPECTRAL || gridtype0 == GRID_FOURIER )
             {
               dimID = streamptr->xdimID[index];
@@ -38360,16 +38681,12 @@ void cdfDefSP(stream_t *streamptr, int gridID)
   */
   char axisname[5] = "nspX";
   int index, iz = 0;
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
-  int ngrids;
-  int fileID;
-  int vlistID;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqSize(gridID)/2;
 
@@ -38377,8 +38694,8 @@ void cdfDefSP(stream_t *streamptr, int gridID)
     {
       if ( streamptr->ydimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_SPECTRAL )
             {
               size_t dimlen0 = (size_t)gridInqSize(gridID0)/2;
@@ -38406,7 +38723,7 @@ void cdfDefSP(stream_t *streamptr, int gridID)
       streamptr->ncmode = 2;
     }
 
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
   streamptr->ydimID[gridindex] = dimID;
 }
 
@@ -38416,16 +38733,12 @@ void cdfDefFC(stream_t *streamptr, int gridID)
 {
   char axisname[5] = "nfcX";
   int index, iz = 0;
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
-  int ngrids;
-  int fileID;
-  int vlistID;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqSize(gridID)/2;
 
@@ -38433,8 +38746,8 @@ void cdfDefFC(stream_t *streamptr, int gridID)
     {
       if ( streamptr->ydimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_FOURIER )
             {
               size_t dimlen0 = (size_t)gridInqSize(gridID0)/2;
@@ -38462,142 +38775,117 @@ void cdfDefFC(stream_t *streamptr, int gridID)
       streamptr->ncmode = 2;
     }
 
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
   streamptr->ydimID[gridindex] = dimID;
 }
 
+struct cdfDefTrajLatLonInqs {
+  int (*gridInqDimSize)(int gridID);
+  void (*gridInqDimName)(int gridID, char *dimname);
+  void (*gridInqDimStdname)(int gridID, char *dimstdname);
+  void (*gridInqDimLongname)(int gridID, char *dimlongname);
+  void (*gridInqDimUnits)(int gridID, char *dimunits);
+};
 
-static
-void cdfDefTrajLon(stream_t *streamptr, int gridID)
-{
-  char units[CDI_MAX_NAME];
-  char longname[CDI_MAX_NAME];
-  char stdname[CDI_MAX_NAME];
-  char axisname[CDI_MAX_NAME];
-  int gridtype, gridindex;
-  int dimID = UNDEFID;
-  int fileID;
-  int dimlen;
-  size_t len;
-  int ncvarid;
-  int vlistID;
-  int xtype = NC_DOUBLE;
-
-  if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
-
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
 
-  gridtype = gridInqType(gridID);
-  dimlen = gridInqXsize(gridID);
-  if ( dimlen != 1 ) Error("Xsize isn't 1 for %s grid!", gridNamePtr(gridtype));
+static void
+cdfDefTrajLatLon(stream_t *streamptr, int gridID,
+                 const struct cdfDefTrajLatLonInqs *inqs,
+                 int *dimID, const char *sizeName)
+{
+  nc_type xtype = gridInqPrec(gridID) == DATATYPE_FLT32 ? NC_FLOAT : NC_DOUBLE;
 
-  gridindex = vlistGridIndex(vlistID, gridID);
-  ncvarid = streamptr->xdimID[gridindex];
+  int vlistID = streamptr->vlistID;
+  int dimlen = inqs->gridInqDimSize(gridID);
+  if ( dimlen != 1 )
+    Error("%s isn't 1 for %s grid!", sizeName, gridNamePtr(gridInqType(gridID)));
 
-  gridInqXname(gridID, axisname);
-  gridInqXlongname(gridID, longname);
-  gridInqXstdname(gridID, stdname);
-  gridInqXunits(gridID, units);
+  int gridindex = vlistGridIndex(vlistID, gridID);
+  int ncvarid = dimID[gridindex];
 
   if ( ncvarid == UNDEFID )
     {
-      dimID = streamptr->basetime.ncvarid;
-
+      size_t len;
+      int dimNcID = streamptr->basetime.ncvarid;
+      int fileID  = streamptr->fileID;
       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-      cdf_def_var(fileID, axisname, (nc_type) xtype, 1, &dimID, &ncvarid);
-
-      if ( (len = strlen(stdname)) )
-        cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
-      if ( (len = strlen(longname)) )
-        cdf_put_att_text(fileID, ncvarid, "long_name", len, longname);
-      if ( (len = strlen(units)) )
-        cdf_put_att_text(fileID, ncvarid, "units", len, units);
-
+      {
+        char axisname[CDI_MAX_NAME];
+        inqs->gridInqDimName(gridID, axisname);
+        cdf_def_var(fileID, axisname, xtype, 1, &dimNcID, &ncvarid);
+      }
+      {
+        char stdname[CDI_MAX_NAME];
+        inqs->gridInqDimStdname(gridID, stdname);
+        if ( (len = strlen(stdname)) )
+          cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
+      }
+      {
+        char longname[CDI_MAX_NAME];
+        inqs->gridInqDimLongname(gridID, longname);
+        if ( (len = strlen(longname)) )
+          cdf_put_att_text(fileID, ncvarid, "long_name", len, longname);
+      }
+      {
+        char units[CDI_MAX_NAME];
+        inqs->gridInqDimUnits(gridID, units);
+        if ( (len = strlen(units)) )
+          cdf_put_att_text(fileID, ncvarid, "units", len, units);
+      }
       cdf_enddef(fileID);
       streamptr->ncmode = 2;
     }
 
-  streamptr->xdimID[gridindex] = ncvarid; /* var ID for trajectory !!! */
+  dimID[gridindex] = ncvarid; /* var ID for trajectory !!! */
 }
 
-
 static
-void cdfDefTrajLat(stream_t *streamptr, int gridID)
+void cdfDefTrajLon(stream_t *streamptr, int gridID)
 {
-  char units[] = "degrees_north";
-  char longname[] = "latitude";
-  char stdname[] = "latitude";
-  char axisname[] = "tlat";
-  int gridtype, gridindex;
-  int dimID = UNDEFID;
-  int fileID;
-  int dimlen;
-  size_t len;
-  int ncvarid;
-  int vlistID;
-  int xtype = NC_DOUBLE;
-
-  if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
-
-  vlistID = streamptr->vlistID;
-  fileID = streamptr->fileID;
-
-  gridtype = gridInqType(gridID);
-  dimlen = gridInqYsize(gridID);
-  if ( dimlen != 1 ) Error("Ysize isn't 1 for %s grid!", gridNamePtr(gridtype));
-
-  gridindex = vlistGridIndex(vlistID, gridID);
-  ncvarid = streamptr->ydimID[gridindex];
-
-  gridInqYname(gridID, axisname);
-  gridInqYlongname(gridID, longname);
-  gridInqYstdname(gridID, stdname);
-  gridInqYunits(gridID, units);
-
-  if ( ncvarid == UNDEFID )
-    {
-      dimID = streamptr->basetime.ncvarid;
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      cdf_def_var(fileID, axisname, (nc_type) xtype, 1, &dimID, &ncvarid);
-
-      if ( (len = strlen(stdname)) )
-        cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
-      if ( (len = strlen(longname)) )
-        cdf_put_att_text(fileID, ncvarid, "long_name", len, longname);
-      if ( (len = strlen(units)) )
-        cdf_put_att_text(fileID, ncvarid, "units", len, units);
+  static const struct cdfDefTrajLatLonInqs inqs =
+    { .gridInqDimSize = gridInqXsize,
+      .gridInqDimName = gridInqXname,
+      .gridInqDimStdname = gridInqXstdname,
+      .gridInqDimLongname = gridInqXlongname,
+      .gridInqDimUnits = gridInqXunits
+    };
+  cdfDefTrajLatLon(streamptr, gridID, &inqs, streamptr->xdimID, "Xsize");
+}
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-    }
 
-  streamptr->ydimID[gridindex] = ncvarid; /* var ID for trajectory !!! */
+static
+void cdfDefTrajLat(stream_t *streamptr, int gridID)
+{
+  static const struct cdfDefTrajLatLonInqs inqs =
+    { .gridInqDimSize = gridInqYsize,
+      .gridInqDimName = gridInqYname,
+      .gridInqDimStdname = gridInqYstdname,
+      .gridInqDimLongname = gridInqYlongname,
+      gridInqYunits
+  };
+  cdfDefTrajLatLon(streamptr, gridID, &inqs, streamptr->ydimID, "Ysize");
 }
 
 
 static
 int checkGridName(int type, char *axisname, int fileID, int vlistID, int gridID, int ngrids, int mode)
 {
-  int iz, index;
+  int index;
   int gridID0;
   int ncdimid;
   char axisname0[CDI_MAX_NAME];
   char axisname2[CDI_MAX_NAME];
-  int checkname;
   int status;
 
   /* check that the name is not already defined */
-  checkname = TRUE;
-  iz = 0;
+  int checkname = TRUE;
+  unsigned iz = 0;
 
   do
     {
       strcpy(axisname2, axisname);
-      if ( iz ) sprintf(&axisname2[strlen(axisname2)], "_%d", iz+1);
+      if ( iz ) sprintf(&axisname2[strlen(axisname2)], "_%u", iz+1);
 
       //status = nc_inq_varid(fileID, axisname2, &ncvarid);
       if ( type == 'V' ) /* type Var oder Dim */
@@ -38636,12 +38924,11 @@ int checkGridName(int type, char *axisname, int fileID, int vlistID, int gridID,
   while (checkname && iz <= 99);
 
 
-  if ( iz ) sprintf(&axisname[strlen(axisname)], "_%d", iz+1);
+  if ( iz ) sprintf(&axisname[strlen(axisname)], "_%u", iz+1);
 
-  return (iz);
+  return (int)iz;
 }
 
-
 static
 void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
 {
@@ -38651,40 +38938,37 @@ void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
   char axisname[CDI_MAX_NAME];
   int index;
   /*  int index2; */
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
   int dimIDs[2];
   int ngrids = 0;
-  int fileID;
   size_t len;
   int ncvarid = UNDEFID, ncbvarid = UNDEFID;
   int nvdimID = UNDEFID;
-  int vlistID;
-  int xtype = NC_DOUBLE;
+  nc_type xtype = NC_DOUBLE;
 
   if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
   if ( ndims ) ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqXsize(gridID);
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
 
   gridInqXname(gridID, axisname);
+  if ( axisname[0] == 0 ) Error("axis name undefined!");
+
   gridInqXlongname(gridID, longname);
   gridInqXstdname(gridID, stdname);
   gridInqXunits(gridID, units);
 
-  if ( axisname[0] == 0 ) Error("axis name undefined!");
-
   for ( index = 0; index < ngrids; index++ )
     {
       if ( streamptr->xdimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_GAUSSIAN    ||
                gridtype0 == GRID_LONLAT      ||
                gridtype0 == GRID_CURVILINEAR ||
@@ -38710,28 +38994,21 @@ void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
 
   if ( dimID == UNDEFID )
     {
-      int status;
-      status = checkGridName('V', axisname, fileID, vlistID, gridID, ngrids, 'X');
+      int status = checkGridName('V', axisname, fileID, vlistID, gridID, ngrids, 'X');
       if ( status == 0 && ndims )
         status = checkGridName('D', axisname, fileID, vlistID, gridID, ngrids, 'X');
 
       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-      if ( ndims )
-        {
-          cdf_def_dim(fileID, axisname, dimlen, &dimID);
+      if ( ndims ) cdf_def_dim(fileID, axisname, dimlen, &dimID);
 
-          if ( gridInqXboundsPtr(gridID) || gridInqYboundsPtr(gridID) )
-            {
-              size_t nvertex = 2;
-              if ( nc_inq_dimid(fileID, BNDS_NAME, &nvdimID) != NC_NOERR )
-                cdf_def_dim(fileID, BNDS_NAME, nvertex, &nvdimID);
-            }
-        }
-
-      if ( gridInqXvalsPtr(gridID) )
+      int gen_bounds = FALSE;
+      int grid_is_cyclic = gridIsCircular(gridID);
+      const double *pvals = gridInqXvalsPtr(gridID);
+      double *pbounds = NULL;
+      if ( pvals )
         {
-          cdf_def_var(fileID, axisname, (nc_type) xtype, ndims, &dimID, &ncvarid);
+          cdf_def_var(fileID, axisname, xtype, ndims, &dimID, &ncvarid);
 
           if ( (len = strlen(stdname)) )
             cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
@@ -38742,13 +39019,34 @@ void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
 
           cdf_put_att_text(fileID, ncvarid, "axis", 1, "X");
 
-          if ( gridInqXboundsPtr(gridID) && nvdimID != UNDEFID )
+          if ( gridInqXboundsPtr(gridID) )
+            pbounds = (double*) gridInqXboundsPtr(gridID);
+
+          if ( CDI_cmor_mode && grid_is_cyclic && !pbounds )
+            {
+              gen_bounds = TRUE;
+              pbounds = (double*) malloc(2*dimlen*sizeof(double));
+              for ( size_t i = 0; i < dimlen-1; ++i )
+                {
+                  pbounds[i*2+1]   = (pvals[i] + pvals[i+1])/2;
+                  pbounds[(i+1)*2] = (pvals[i] + pvals[i+1])/2;
+                }
+              pbounds[0] = (pvals[0] + pvals[dimlen-1]-360)/2;
+              pbounds[2*dimlen-1] = (pvals[dimlen-1] + pvals[0]+360)/2;
+            }
+          if ( pbounds )
+            {
+              size_t nvertex = 2;
+              if ( nc_inq_dimid(fileID, BNDS_NAME, &nvdimID) != NC_NOERR )
+                cdf_def_dim(fileID, BNDS_NAME, nvertex, &nvdimID);
+            }
+          if ( pbounds && nvdimID != UNDEFID )
             {
               strcat(axisname, "_");
               strcat(axisname, BNDS_NAME);
               dimIDs[0] = dimID;
               dimIDs[1] = nvdimID;
-              cdf_def_var(fileID, axisname, (nc_type) xtype, 2, dimIDs, &ncbvarid);
+              cdf_def_var(fileID, axisname, xtype, 2, dimIDs, &ncbvarid);
               cdf_put_att_text(fileID, ncvarid, "bounds", strlen(axisname), axisname);
             }
           /*
@@ -38763,8 +39061,9 @@ void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
       cdf_enddef(fileID);
       streamptr->ncmode = 2;
 
-      if ( ncvarid  != UNDEFID ) cdf_put_var_double(fileID, ncvarid, gridInqXvalsPtr(gridID));
-      if ( ncbvarid != UNDEFID ) cdf_put_var_double(fileID, ncbvarid, gridInqXboundsPtr(gridID));
+      if ( ncvarid  != UNDEFID ) cdf_put_var_double(fileID, ncvarid, pvals);
+      if ( ncbvarid != UNDEFID ) cdf_put_var_double(fileID, ncbvarid, pbounds);
+      if ( gen_bounds ) Free(pbounds);
 
       if ( ndims == 0 ) streamptr->ncxvarID[gridindex] = ncvarid;
     }
@@ -38772,7 +39071,6 @@ void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
   streamptr->xdimID[gridindex] = dimID;
 }
 
-
 static
 void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
 {
@@ -38782,40 +39080,37 @@ void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
   char axisname[CDI_MAX_NAME];
   int index;
   /*  int index2; */
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
   int dimIDs[2];
   int ngrids = 0;
-  int fileID;
   size_t len;
   int ncvarid = UNDEFID, ncbvarid = UNDEFID;
   int nvdimID = UNDEFID;
-  int vlistID;
-  int xtype = NC_DOUBLE;
+  nc_type xtype = NC_DOUBLE;
 
   if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
   if ( ndims ) ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqYsize(gridID);
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
 
   gridInqYname(gridID, axisname);
+  if ( axisname[0] == 0 ) Error("axis name undefined!");
+
   gridInqYlongname(gridID, longname);
   gridInqYstdname(gridID, stdname);
   gridInqYunits(gridID, units);
 
-  if ( axisname[0] == 0 ) Error("axis name undefined!");
-
   for ( index = 0; index < ngrids; index++ )
     {
       if ( streamptr->ydimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_GAUSSIAN    ||
                gridtype0 == GRID_LONLAT      ||
                gridtype0 == GRID_CURVILINEAR ||
@@ -38848,21 +39143,15 @@ void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
 
       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-      if ( ndims )
-        {
-          cdf_def_dim(fileID, axisname, dimlen, &dimID);
+      if ( ndims ) cdf_def_dim(fileID, axisname, dimlen, &dimID);
 
-          if ( gridInqXboundsPtr(gridID) || gridInqYboundsPtr(gridID) )
-            {
-              size_t nvertex = 2;
-              if ( nc_inq_dimid(fileID, BNDS_NAME, &nvdimID) != NC_NOERR )
-                cdf_def_dim(fileID, BNDS_NAME, nvertex, &nvdimID);
-            }
-        }
-
-      if ( gridInqYvalsPtr(gridID) )
+      int gen_bounds = FALSE;
+      int grid_is_cyclic = gridIsCircular(gridID);
+      const double *pvals = gridInqYvalsPtr(gridID);
+      double *pbounds = NULL;
+      if ( pvals )
         {
-          cdf_def_var(fileID, axisname, (nc_type) xtype, ndims, &dimID, &ncvarid);
+          cdf_def_var(fileID, axisname, xtype, ndims, &dimID, &ncvarid);
 
           if ( (len = strlen(stdname)) )
             cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
@@ -38873,13 +39162,34 @@ void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
 
           cdf_put_att_text(fileID, ncvarid, "axis", 1, "Y");
 
-          if ( gridInqYboundsPtr(gridID) && nvdimID != UNDEFID )
+          if ( gridInqYboundsPtr(gridID) )
+            pbounds = (double*) gridInqYboundsPtr(gridID);
+
+          if ( CDI_cmor_mode && grid_is_cyclic && !pbounds )
+            {
+              gen_bounds = TRUE;
+              pbounds = (double*) malloc(2*dimlen*sizeof(double));
+              for ( size_t i = 0; i < dimlen-1; ++i )
+                {
+                  pbounds[i*2+1]   = (pvals[i] + pvals[i+1])/2;
+                  pbounds[(i+1)*2] = (pvals[i] + pvals[i+1])/2;
+                }
+              pbounds[0] = (pvals[0] < 0) ? -90 : 90;
+              pbounds[2*dimlen-1] = (pvals[dimlen-1] < 0) ? -90 : 90;
+            }
+          if ( pbounds )
+            {
+              size_t nvertex = 2;
+              if ( nc_inq_dimid(fileID, BNDS_NAME, &nvdimID) != NC_NOERR )
+                cdf_def_dim(fileID, BNDS_NAME, nvertex, &nvdimID);
+            }
+          if ( pbounds && nvdimID != UNDEFID )
             {
               strcat(axisname, "_");
               strcat(axisname, BNDS_NAME);
               dimIDs[0] = dimID;
               dimIDs[1] = nvdimID;
-              cdf_def_var(fileID, axisname, (nc_type) xtype, 2, dimIDs, &ncbvarid);
+              cdf_def_var(fileID, axisname, xtype, 2, dimIDs, &ncbvarid);
               cdf_put_att_text(fileID, ncvarid, "bounds", strlen(axisname), axisname);
             }
           /*
@@ -38894,8 +39204,9 @@ void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
       cdf_enddef(fileID);
       streamptr->ncmode = 2;
 
-      if ( ncvarid  != UNDEFID ) cdf_put_var_double(fileID, ncvarid, gridInqYvalsPtr(gridID));
-      if ( ncbvarid != UNDEFID ) cdf_put_var_double(fileID, ncbvarid, gridInqYboundsPtr(gridID));
+      if ( ncvarid  != UNDEFID ) cdf_put_var_double(fileID, ncvarid, pvals);
+      if ( ncbvarid != UNDEFID ) cdf_put_var_double(fileID, ncbvarid, pbounds);
+      if ( gen_bounds ) Free(pbounds);
 
       if ( ndims == 0 ) streamptr->ncyvarID[gridindex] = ncvarid;
     }
@@ -38903,7 +39214,6 @@ void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
   streamptr->ydimID[gridindex] = dimID;
 }
 
-
 static
 void cdfGridCompress(int fileID, int ncvarid, int gridsize, int filetype, int comptype)
 {
@@ -38931,29 +39241,25 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
   char xdimname[4] = "x";
   char ydimname[4] = "y";
   int index;
-  int gridID0, gridtype0, gridindex;
   int xdimID = UNDEFID;
   int ydimID = UNDEFID;
   int dimIDs[3];
-  int ngrids;
-  int fileID;
   size_t len;
   int ncxvarid = UNDEFID, ncyvarid = UNDEFID;
   int ncbxvarid = UNDEFID, ncbyvarid = UNDEFID, ncavarid = UNDEFID;
   int nvdimID = UNDEFID;
-  int vlistID;
-  int xtype = NC_DOUBLE;
+  nc_type xtype = NC_DOUBLE;
 
   if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t xdimlen = (size_t)gridInqXsize(gridID);
   size_t ydimlen = (size_t)gridInqYsize(gridID);
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
 
   gridInqXname(gridID, xaxisname);
   gridInqXlongname(gridID, xlongname);
@@ -38968,8 +39274,8 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
     {
       if ( streamptr->xdimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_GAUSSIAN    ||
                gridtype0 == GRID_LONLAT      ||
                gridtype0 == GRID_CURVILINEAR ||
@@ -39021,7 +39327,7 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
 
       if ( gridInqXvalsPtr(gridID) )
         {
-          cdf_def_var(fileID, xaxisname, (nc_type) xtype, 2, dimIDs, &ncxvarid);
+          cdf_def_var(fileID, xaxisname, xtype, 2, dimIDs, &ncxvarid);
           cdfGridCompress(fileID, ncxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
 
           if ( (len = strlen(xstdname)) )
@@ -39041,7 +39347,7 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
               dimIDs[0] = ydimID;
               dimIDs[1] = xdimID;
               dimIDs[2] = nvdimID;
-              cdf_def_var(fileID, xaxisname, (nc_type) xtype, 3, dimIDs, &ncbxvarid);
+              cdf_def_var(fileID, xaxisname, xtype, 3, dimIDs, &ncbxvarid);
               cdfGridCompress(fileID, ncbxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
 
               cdf_put_att_text(fileID, ncxvarid, "bounds", strlen(xaxisname), xaxisname);
@@ -39050,7 +39356,7 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
 
       if ( gridInqYvalsPtr(gridID) )
         {
-          cdf_def_var(fileID, yaxisname, (nc_type) xtype, 2, dimIDs, &ncyvarid);
+          cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncyvarid);
           cdfGridCompress(fileID, ncyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
 
           if ( (len = strlen(ystdname)) )
@@ -39070,7 +39376,7 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
               dimIDs[0] = ydimID;
               dimIDs[1] = xdimID;
               dimIDs[2] = nvdimID;
-              cdf_def_var(fileID, yaxisname, (nc_type) xtype, 3, dimIDs, &ncbyvarid);
+              cdf_def_var(fileID, yaxisname, xtype, 3, dimIDs, &ncbyvarid);
               cdfGridCompress(fileID, ncbyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
 
               cdf_put_att_text(fileID, ncyvarid, "bounds", strlen(yaxisname), yaxisname);
@@ -39084,7 +39390,7 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
           static const char longname[] = "area of grid cell";
           static const char stdname[] = "cell_area";
 
-          cdf_def_var(fileID, yaxisname_, (nc_type) xtype, 2, dimIDs, &ncavarid);
+          cdf_def_var(fileID, yaxisname_, xtype, 2, dimIDs, &ncavarid);
 
           cdf_put_att_text(fileID, ncavarid, "standard_name", sizeof (stdname) - 1, stdname);
           cdf_put_att_text(fileID, ncavarid, "long_name", sizeof (longname) - 1, longname);
@@ -39108,23 +39414,18 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
   streamptr->ncavarID[gridindex] = ncavarid;
 }
 
-
 static
 void cdfDefRgrid(stream_t *streamptr, int gridID)
 {
   char axisname[7] = "rgridX";
   int index, iz = 0;
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
-  int ngrids;
-  int fileID;
-  int vlistID;
   int lwarn = TRUE;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqSize(gridID);
 
@@ -39132,8 +39433,8 @@ void cdfDefRgrid(stream_t *streamptr, int gridID)
     {
       if ( streamptr->xdimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_GAUSSIAN_REDUCED )
             {
               size_t dimlen0 = (size_t)gridInqSize(gridID0);
@@ -39153,7 +39454,7 @@ void cdfDefRgrid(stream_t *streamptr, int gridID)
     {
       if ( lwarn )
         {
-          Warning("Creating a netCDF file with data on a gaussian reduced grid.");
+          Warning("Creating a NetCDF file with data on a gaussian reduced grid.");
           Warning("The further processing of the resulting file is unsupported!");
           lwarn = FALSE;
         }
@@ -39169,25 +39470,20 @@ void cdfDefRgrid(stream_t *streamptr, int gridID)
       streamptr->ncmode = 2;
     }
 
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
   streamptr->xdimID[gridindex] = dimID;
 }
 
-
 static
 void cdfDefGdim(stream_t *streamptr, int gridID)
 {
   int index, iz = 0;
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
-  int ngrids;
-  int fileID;
-  int vlistID;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqSize(gridID);
 
@@ -39196,8 +39492,8 @@ void cdfDefGdim(stream_t *streamptr, int gridID)
       {
         if ( streamptr->xdimID[index] != UNDEFID )
           {
-            gridID0 = vlistGrid(vlistID, index);
-            gridtype0 = gridInqType(gridID0);
+            int gridID0 = vlistGrid(vlistID, index);
+            int gridtype0 = gridInqType(gridID0);
             if ( gridtype0 == GRID_GENERIC )
               {
                 size_t dimlen0 = (size_t)gridInqSize(gridID0);
@@ -39217,8 +39513,8 @@ void cdfDefGdim(stream_t *streamptr, int gridID)
       {
         if ( streamptr->ydimID[index] != UNDEFID )
           {
-            gridID0 = vlistGrid(vlistID, index);
-            gridtype0 = gridInqType(gridID0);
+            int gridID0 = vlistGrid(vlistID, index);
+            int gridtype0 = gridInqType(gridID0);
             if ( gridtype0 == GRID_GENERIC )
               {
                 size_t dimlen0 = (size_t)gridInqSize(gridID0);
@@ -39252,11 +39548,10 @@ void cdfDefGdim(stream_t *streamptr, int gridID)
       streamptr->ncmode = 2;
     }
 
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
   streamptr->xdimID[gridindex] = dimID;
 }
 
-
 static
 void cdfDefGridReference(stream_t *streamptr, int gridID)
 {
@@ -39287,7 +39582,7 @@ void cdfDefGridUUID(stream_t *streamptr, int gridID)
   if ( !cdiUUIDIsNull(uuidOfHGrid) )
     {
       char uuidOfHGridStr[37];
-      uuid2str(uuidOfHGrid, uuidOfHGridStr);
+      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
       if ( uuidOfHGridStr[0] != 0 && strlen(uuidOfHGridStr) == 36 )
         {
           int fileID  = streamptr->fileID;
@@ -39307,7 +39602,7 @@ void cdfDefZaxisUUID(stream_t *streamptr, int zaxisID)
   if ( uuidOfVGrid[0] != 0 )
     {
       char uuidOfVGridStr[37];
-      uuid2str(uuidOfVGrid, uuidOfVGridStr);
+      cdiUUID2Str(uuidOfVGrid, uuidOfVGridStr);
       if ( uuidOfVGridStr[0] != 0 && strlen(uuidOfVGridStr) == 36 )
         {
           int fileID  = streamptr->fileID;
@@ -39330,26 +39625,22 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
   char xaxisname[CDI_MAX_NAME];
   char yaxisname[CDI_MAX_NAME];
   int index;
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
-  int ngrids;
-  int fileID;
   size_t len;
   int ncxvarid = UNDEFID, ncyvarid = UNDEFID;
   int ncbxvarid = UNDEFID, ncbyvarid = UNDEFID, ncavarid = UNDEFID;
   int nvdimID = UNDEFID;
-  int vlistID;
-  int xtype = NC_DOUBLE;
+  nc_type xtype = NC_DOUBLE;
 
   if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqSize(gridID);
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
 
   gridInqXname(gridID, xaxisname);
   gridInqXlongname(gridID, xlongname);
@@ -39364,8 +39655,8 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
     {
       if ( streamptr->xdimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_UNSTRUCTURED )
             {
               size_t dimlen0 = (size_t)gridInqSize(gridID0);
@@ -39409,7 +39700,7 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
 
       if ( gridInqXvalsPtr(gridID) )
         {
-          cdf_def_var(fileID, xaxisname, (nc_type) xtype, 1, &dimID, &ncxvarid);
+          cdf_def_var(fileID, xaxisname, xtype, 1, &dimID, &ncxvarid);
           cdfGridCompress(fileID, ncxvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
 
           if ( (len = strlen(xstdname)) )
@@ -39426,7 +39717,7 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
               dimIDs[1] = nvdimID;
               strcat(xaxisname, "_");
               strcat(xaxisname, BNDS_NAME);
-              cdf_def_var(fileID, xaxisname, (nc_type) xtype, 2, dimIDs, &ncbxvarid);
+              cdf_def_var(fileID, xaxisname, xtype, 2, dimIDs, &ncbxvarid);
               cdfGridCompress(fileID, ncbxvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
 
               cdf_put_att_text(fileID, ncxvarid, "bounds", strlen(xaxisname), xaxisname);
@@ -39435,7 +39726,7 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
 
       if ( gridInqYvalsPtr(gridID) )
         {
-          cdf_def_var(fileID, yaxisname, (nc_type) xtype, 1, &dimID, &ncyvarid);
+          cdf_def_var(fileID, yaxisname, xtype, 1, &dimID, &ncyvarid);
           cdfGridCompress(fileID, ncyvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
 
           if ( (len = strlen(ystdname)) )
@@ -39452,7 +39743,7 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
               dimIDs[1] = nvdimID;
               strcat(yaxisname, "_");
               strcat(yaxisname, BNDS_NAME);
-              cdf_def_var(fileID, yaxisname, (nc_type) xtype, 2, dimIDs, &ncbyvarid);
+              cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncbyvarid);
               cdfGridCompress(fileID, ncbyvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
 
               cdf_put_att_text(fileID, ncyvarid, "bounds", strlen(yaxisname), yaxisname);
@@ -39466,7 +39757,7 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
           static const char longname[] = "area of grid cell";
           static const char stdname[] = "cell_area";
 
-          cdf_def_var(fileID, yaxisname_, (nc_type) xtype, 1, &dimID, &ncavarid);
+          cdf_def_var(fileID, yaxisname_, xtype, 1, &dimID, &ncavarid);
 
           cdf_put_att_text(fileID, ncavarid, "standard_name", sizeof (stdname) - 1, stdname);
           cdf_put_att_text(fileID, ncavarid, "long_name", sizeof (longname) - 1, longname);
@@ -39497,6 +39788,8 @@ void cdf_def_vct_echam(stream_t *streamptr, int zaxisID)
   if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
     {
       int ilev = zaxisInqVctSize(zaxisID)/2;
+      if ( ilev == 0 ) return;
+
       int mlev = ilev - 1;
       size_t start;
       size_t count = 1;
@@ -39512,12 +39805,6 @@ void cdf_def_vct_echam(stream_t *streamptr, int zaxisID)
           return;
         }
 
-      if ( ilev == 0 )
-        {
-          Warning("VCT missing");
-          return;
-        }
-
       int fileID = streamptr->fileID;
 
       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
@@ -39579,6 +39866,8 @@ void cdf_def_vct_cf(stream_t *streamptr, int zaxisID, int nclevID, int ncbndsID)
   if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
     {
       int ilev = zaxisInqVctSize(zaxisID)/2;
+      if ( ilev == 0 ) return;
+
       int mlev = ilev - 1;
       int hyaiid = 0, hybiid = 0, hyamid, hybmid;
       char tmpname[CDI_MAX_NAME];
@@ -39590,12 +39879,6 @@ void cdf_def_vct_cf(stream_t *streamptr, int zaxisID, int nclevID, int ncbndsID)
           return;
         }
 
-      if ( ilev == 0 )
-        {
-          Warning("VCT missing");
-          return;
-        }
-
       int fileID = streamptr->fileID;
 
       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
@@ -40087,8 +40370,8 @@ void cdfDefMapping(stream_t *streamptr, int gridID)
 
   if ( gridInqType(gridID) == GRID_SINUSOIDAL )
     {
-      char varname[] = "sinusoidal";
-      char mapname[] = "sinusoidal";
+      static const char varname[] = "sinusoidal";
+      static const char mapname[] = "sinusoidal";
 
       cdf_redef(fileID);
 
@@ -40106,8 +40389,8 @@ void cdfDefMapping(stream_t *streamptr, int gridID)
     }
   else if ( gridInqType(gridID) == GRID_LAEA )
     {
-      char varname[] = "laea";
-      char mapname[] = "lambert_azimuthal_equal_area";
+      static const char varname[] = "laea";
+      static const char mapname[] = "lambert_azimuthal_equal_area";
 
       cdf_redef(fileID);
 
@@ -40128,8 +40411,8 @@ void cdfDefMapping(stream_t *streamptr, int gridID)
     }
   else if ( gridInqType(gridID) == GRID_LCC2 )
     {
-      char varname[] = "Lambert_Conformal";
-      char mapname[] = "lambert_conformal_conic";
+      static const char varname[] = "Lambert_Conformal";
+      static const char mapname[] = "lambert_conformal_conic";
 
       cdf_redef(fileID);
 
@@ -40261,5581 +40544,6737 @@ void cdfDefGrid(stream_t *streamptr, int gridID)
 }
 
 static
-int cdfDefVar(stream_t *streamptr, int varID)
+void scale_add(size_t size, double *data, double addoffset, double scalefactor)
 {
-  int ncvarid = -1;
-  int xid = UNDEFID, yid = UNDEFID;
-  size_t xsize = 0, ysize = 0;
-  char varname[CDI_MAX_NAME];
-  int dims[4];
-  int lchunk = FALSE;
-  size_t chunks[4] = {0,0,0,0};
-  int ndims = 0;
-  int tablenum;
-  int dimorder[3];
-  size_t iax = 0;
-  char axis[5];
-  int ensID, ensCount, forecast_type;
-  int retval;
-
-  int fileID  = streamptr->fileID;
+  int laddoffset;
+  int lscalefactor;
 
-  if ( CDI_Debug )
-    Message("streamID = %d, fileID = %d, varID = %d", streamptr->self, fileID, varID);
+  laddoffset   = IS_NOT_EQUAL(addoffset, 0);
+  lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
 
-  if ( streamptr->vars[varID].ncvarid != UNDEFID )
-    return streamptr->vars[varID].ncvarid;
+  if ( laddoffset || lscalefactor )
+    {
+      for (size_t i = 0; i < size; ++i )
+        {
+          if ( lscalefactor ) data[i] *= scalefactor;
+          if ( laddoffset )   data[i] += addoffset;
+        }
+    }
+}
 
-  int vlistID   = streamptr->vlistID;
-  int gridID    = vlistInqVarGrid(vlistID, varID);
-  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
-  int code      = vlistInqVarCode(vlistID, varID);
-  int param     = vlistInqVarParam(vlistID, varID);
-  int pnum, pcat, pdis;
-  cdiDecodeParam(param, &pnum, &pcat, &pdis);
+static
+void cdfCreateRecords(stream_t *streamptr, int tsID)
+{
+  if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
 
-  int chunktype = vlistInqVarChunkType(vlistID, varID);
+  if ( streamptr->tsteps[tsID].nallrecs > 0 ) return;
 
-  vlistInqVarDimorder(vlistID, varID, &dimorder);
+  int vlistID  = streamptr->vlistID;
 
-  int gridsize  = gridInqSize(gridID);
-  if ( gridsize > 1 ) lchunk = TRUE;
-  int gridtype  = gridInqType(gridID);
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  if ( gridtype != GRID_TRAJECTORY )
-    {
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
-      if ( xid != UNDEFID ) cdf_inq_dimlen(fileID, xid, &xsize);
-      if ( yid != UNDEFID ) cdf_inq_dimlen(fileID, yid, &ysize);
-    }
+  tsteps_t* sourceTstep = streamptr->tsteps;
+  tsteps_t* destTstep = sourceTstep + tsID;
 
-  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-  int zid = streamptr->zaxisID[zaxisindex];
-  int zaxis_is_scalar = FALSE;
-  if ( zid == UNDEFID ) zaxis_is_scalar = zaxisInqScalar(zaxisID);
+  int nvars = vlistNvars(vlistID);
+  int nrecs = vlistNrecs(vlistID);
 
-  if ( dimorder[0] != 3 ) lchunk = FALSE; /* ZYX and ZXY */
+  if ( nrecs <= 0 ) return;
 
-  if ( ((dimorder[0]>0)+(dimorder[1]>0)+(dimorder[2]>0)) < ((xid!=UNDEFID)+(yid!=UNDEFID)+(zid!=UNDEFID)) )
+  if ( tsID == 0 )
     {
-      printf("zid=%d  yid=%d  xid=%d\n", zid, yid, xid);
-      Error("Internal problem, dimension order missing!");
-    }
+      int nvrecs = nrecs; /* use all records at first timestep */
 
-  int tid = streamptr->basetime.ncdimid;
+      streamptr->nrecs += nrecs;
 
-  if ( tsteptype != TSTEP_CONSTANT )
-    {
-      if ( tid == UNDEFID ) Error("Internal problem, time undefined!");
-      chunks[ndims] = 1;
-      dims[ndims++] = tid;
-      axis[iax++] = 'T';
-    }
-  /*
-  if ( zid != UNDEFID ) axis[iax++] = 'Z';
-  if ( zid != UNDEFID ) chunks[ndims] = 1;
-  if ( zid != UNDEFID ) dims[ndims++] = zid;
+      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
+      destTstep->nrecs      = nrecs;
+      destTstep->nallrecs   = nrecs;
+      destTstep->recordSize = nrecs;
+      destTstep->curRecID   = UNDEFID;
+      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs*sizeof (int));;
+      for ( int recID = 0; recID < nvrecs; recID++ ) destTstep->recIDs[recID] = recID;
 
-  if ( yid != UNDEFID ) chunks[ndims] = ysize;
-  if ( yid != UNDEFID ) dims[ndims++] = yid;
+      record_t *records = destTstep->records;
 
-  if ( xid != UNDEFID ) chunks[ndims] = xsize;
-  if ( xid != UNDEFID ) dims[ndims++] = xid;
-  */
-  for ( int id = 0; id < 3; ++id )
-    {
-      if ( dimorder[id] == 3 && zid != UNDEFID )
-        {
-          axis[iax++] = 'Z';
-          chunks[ndims] = 1;
-          dims[ndims] = zid;
-          ndims++;
-        }
-      else if ( dimorder[id] == 2 && yid != UNDEFID )
-        {
-          if ( chunktype == CHUNK_LINES )
-            chunks[ndims] = 1;
-          else
-            chunks[ndims] = ysize;
-          dims[ndims] = yid;
-          ndims++;
-        }
-      else if ( dimorder[id] == 1 && xid != UNDEFID )
+      for ( int varID = 0, recID = 0; varID < nvars; varID++ )
         {
-          chunks[ndims] = xsize;
-          dims[ndims] = xid;
-          ndims++;
+          int zaxisID = vlistInqVarZaxis(vlistID, varID);
+          int nlev    = zaxisInqSize(zaxisID);
+          for ( int levelID = 0; levelID < nlev; levelID++ )
+            {
+              recordInitEntry(&records[recID]);
+              records[recID].varID   = (short)varID;
+              records[recID].levelID = (short)levelID;
+              recID++;
+            }
         }
     }
-
-  if ( CDI_Debug )
-    fprintf(stderr, "chunktype %d  chunks %d %d %d %d\n", chunktype, (int)chunks[0], (int)chunks[1], (int)chunks[2], (int)chunks[3]);
-
-  int tableID  = vlistInqVarTable(vlistID, varID);
-
-  const char *name     = vlistInqVarNamePtr(vlistID, varID);
-  const char *longname = vlistInqVarLongnamePtr(vlistID, varID);
-  const char *stdname  = vlistInqVarStdnamePtr(vlistID, varID);
-  const char *units    = vlistInqVarUnitsPtr(vlistID, varID);
-
-  if ( name     == NULL )     name = tableInqParNamePtr(tableID, code);
-  if ( longname == NULL ) longname = tableInqParLongnamePtr(tableID, code);
-  if ( units    == NULL )    units = tableInqParUnitsPtr(tableID, code);
-  if ( name )
+  else if ( tsID == 1 )
     {
-      int checkname;
-      int iz;
-      int status;
-
-      sprintf(varname, "%s", name);
-
-      checkname = TRUE;
-      iz = 0;
-
-      while ( checkname )
+      int nvrecs = 0;
+      for ( int varID = 0; varID < nvars; varID++ )
         {
-          if ( iz ) sprintf(varname, "%s_%d", name, iz+1);
-
-          status = nc_inq_varid(fileID, varname, &ncvarid);
-          if ( status != NC_NOERR )
+          if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
             {
-              checkname = FALSE;
+              int zaxisID = vlistInqVarZaxis(vlistID, varID);
+              nvrecs += zaxisInqSize(zaxisID);
             }
+        }
 
-          if ( checkname ) iz++;
+      streamptr->nrecs += nvrecs;
 
-          if ( iz >= CDI_MAX_NAME ) Error("Double entry of variable name '%s'!", name);
-        }
+      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
+      destTstep->nrecs      = nvrecs;
+      destTstep->nallrecs   = nrecs;
+      destTstep->recordSize = nrecs;
+      destTstep->curRecID   = UNDEFID;
 
-      if ( strcmp(name, varname) != 0 )
+      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
+
+      if ( nvrecs )
         {
-          if ( iz == 1 )
-            Warning("Changed double entry of variable name '%s' to '%s'!", name, varname);
-          else
-            Warning("Changed multiple entry of variable name '%s' to '%s'!", name, varname);
+          destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
+          for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
+            {
+              int varID = destTstep->records[recID].varID;
+              if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
+                {
+                  destTstep->recIDs[vrecID++] = recID;
+                }
+            }
         }
-
-      name = varname;
     }
   else
     {
-      if ( code < 0 ) code = -code;
-      if ( pnum < 0 ) pnum = -pnum;
-
-      if ( pdis == 255 )
-	sprintf(varname, "var%d", code);
-      else
-	sprintf(varname, "param%d.%d.%d", pnum, pcat, pdis);
-
-      char *varname2 = varname+strlen(varname);
+      if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
 
-      int checkname = TRUE;
-      int iz = 0;
+      int nvrecs = streamptr->tsteps[1].nrecs;
 
-      while ( checkname )
-        {
-          if ( iz ) sprintf(varname2, "_%d", iz+1);
+      streamptr->nrecs += nvrecs;
 
-          int status = nc_inq_varid(fileID, varname, &ncvarid);
-          if ( status != NC_NOERR ) checkname = FALSE;
+      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
+      destTstep->nrecs      = nvrecs;
+      destTstep->nallrecs   = nrecs;
+      destTstep->recordSize = nrecs;
+      destTstep->curRecID   = UNDEFID;
 
-          if ( checkname ) iz++;
+      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
 
-          if ( iz >= CDI_MAX_NAME ) break;
-        }
+      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs * sizeof(int));
 
-      name = varname;
-      code = 0;
-      pdis = 255;
+      memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
     }
+}
 
-  /* if ( streamptr->ncmode == 2 ) cdf_redef(fileID); */
-
-  int dtype = vlistInqVarDatatype(vlistID, varID);
-  int xtype = cdfDefDatatype(dtype, streamptr->filetype);
-
-  cdf_def_var(fileID, name, (nc_type) xtype, ndims, dims, &ncvarid);
 
-#if  defined  (HAVE_NETCDF4)
-  if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
+static
+int cdfTimeDimID(int fileID, int ndims, int nvars)
+{
+  for ( int dimid = 0; dimid < ndims; dimid++ )
     {
-      if ( chunktype == CHUNK_AUTO )
-        retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
-      else
-        retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, chunks);
-
-      if ( retval ) Error("nc_def_var_chunking failed, status = %d", retval);
+      char dimname[80];
+      cdf_inq_dimname(fileID, dimid, dimname);
+      if ( memcmp(dimname, "time", 4) == 0 )
+        return dimid;
     }
-#endif
 
-  if ( streamptr->comptype == COMPRESS_ZIP )
+
+  for ( int varid = 0; varid < nvars; varid++ )
     {
-      if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
-        {
-          cdfDefVarDeflate(fileID, ncvarid, streamptr->complevel);
-        }
-      else
+      int nvdims, nvatts, dimids[9];
+      cdf_inq_var(fileID, varid, NULL, NULL, &nvdims, dimids, &nvatts);
+      if ( nvdims == 1 )
         {
-          if ( lchunk )
+          for ( int iatt = 0; iatt < nvatts; iatt++ )
             {
-              static int lwarn = TRUE;
-
-              if ( lwarn )
+              char sbuf[CDI_MAX_NAME];
+              cdf_inq_attname(fileID, varid, iatt, sbuf);
+              if ( strncmp(sbuf, "units", 5) == 0 )
                 {
-                  lwarn = FALSE;
-                  Warning("Deflate compression is only available for netCDF4!");
+                  cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
+                  strtolower(sbuf);
+
+                  if ( isTimeUnits(sbuf) )
+                    return dimids[0];
                 }
             }
         }
     }
 
-  if ( streamptr->comptype == COMPRESS_SZIP )
+  return UNDEFID;
+}
+
+static
+void init_ncdims(long ndims, ncdim_t *ncdims)
+{
+  for ( long ncdimid = 0; ncdimid < ndims; ncdimid++ )
     {
-      if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
-        {
-#if defined (NC_SZIP_NN_OPTION_MASK)
-          cdfDefVarSzip(fileID, ncvarid);
-#else
-          static int lwarn = TRUE;
+      ncdims[ncdimid].ncvarid      = UNDEFID;
+      ncdims[ncdimid].dimtype      = UNDEFID;
+      ncdims[ncdimid].len          = 0;
+      ncdims[ncdimid].name[0]      = 0;
+    }
+}
 
-          if ( lwarn )
-            {
-              lwarn = FALSE;
-              Warning("netCDF4/SZIP compression not available!");
-            }
-#endif
-        }
-      else
-        {
-          static int lwarn = TRUE;
+static
+void init_ncvars(long nvars, ncvar_t *ncvars)
+{
+  for ( long ncvarid = 0; ncvarid < nvars; ++ncvarid )
+    {
+      ncvars[ncvarid].ncid            = UNDEFID;
+      ncvars[ncvarid].ignore          = FALSE;
+      ncvars[ncvarid].isvar           = UNDEFID;
+      ncvars[ncvarid].islon           = FALSE;
+      ncvars[ncvarid].islat           = FALSE;
+      ncvars[ncvarid].islev           = FALSE;
+      ncvars[ncvarid].istime          = FALSE;
+      ncvars[ncvarid].warn            = FALSE;
+      ncvars[ncvarid].tsteptype       = TSTEP_CONSTANT;
+      ncvars[ncvarid].param           = UNDEFID;
+      ncvars[ncvarid].code            = UNDEFID;
+      ncvars[ncvarid].tabnum          = 0;
+      ncvars[ncvarid].calendar        = FALSE;
+      ncvars[ncvarid].climatology     = FALSE;
+      ncvars[ncvarid].bounds          = UNDEFID;
+      ncvars[ncvarid].lformula        = FALSE;
+      ncvars[ncvarid].lformulaterms   = FALSE;
+      ncvars[ncvarid].gridID          = UNDEFID;
+      ncvars[ncvarid].zaxisID         = UNDEFID;
+      ncvars[ncvarid].gridtype        = UNDEFID;
+      ncvars[ncvarid].zaxistype       = UNDEFID;
+      ncvars[ncvarid].xdim            = UNDEFID;
+      ncvars[ncvarid].ydim            = UNDEFID;
+      ncvars[ncvarid].zdim            = UNDEFID;
+      ncvars[ncvarid].xvarid          = UNDEFID;
+      ncvars[ncvarid].yvarid          = UNDEFID;
+      ncvars[ncvarid].zvarid          = UNDEFID;
+      ncvars[ncvarid].tvarid          = UNDEFID;
+      ncvars[ncvarid].psvarid         = UNDEFID;
+      ncvars[ncvarid].ncoordvars      = 0;
+      for ( int i = 0; i < MAX_COORDVARS; ++i )
+        ncvars[ncvarid].coordvarids[i]  = UNDEFID;
+      ncvars[ncvarid].nauxvars      = 0;
+      for ( int i = 0; i < MAX_AUXVARS; ++i )
+        ncvars[ncvarid].auxvarids[i]  = UNDEFID;
+      ncvars[ncvarid].cellarea        = UNDEFID;
+      ncvars[ncvarid].tableID         = UNDEFID;
+      ncvars[ncvarid].xtype           = 0;
+      ncvars[ncvarid].ndims           = 0;
+      ncvars[ncvarid].gmapid          = UNDEFID;
+      ncvars[ncvarid].vctsize         = 0;
+      ncvars[ncvarid].vct             = NULL;
+      ncvars[ncvarid].truncation      = 0;
+      ncvars[ncvarid].position        = 0;
+      ncvars[ncvarid].positive        = 0;
+      ncvars[ncvarid].chunked         = 0;
+      ncvars[ncvarid].chunktype       = UNDEFID;
+      ncvars[ncvarid].defmissval      = 0;
+      ncvars[ncvarid].deffillval      = 0;
+      ncvars[ncvarid].missval         = 0;
+      ncvars[ncvarid].fillval         = 0;
+      ncvars[ncvarid].addoffset       = 0;
+      ncvars[ncvarid].scalefactor     = 1;
+      ncvars[ncvarid].name[0]         = 0;
+      ncvars[ncvarid].longname[0]     = 0;
+      ncvars[ncvarid].stdname[0]      = 0;
+      ncvars[ncvarid].units[0]        = 0;
+      ncvars[ncvarid].extra[0]        = 0;
+      ncvars[ncvarid].natts           = 0;
+      ncvars[ncvarid].atts            = NULL;
+      ncvars[ncvarid].deflate         = 0;
+      ncvars[ncvarid].lunsigned       = 0;
+      ncvars[ncvarid].lvalidrange     = 0;
+      ncvars[ncvarid].validrange[0]   = VALIDMISS;
+      ncvars[ncvarid].validrange[1]   = VALIDMISS;
+      ncvars[ncvarid].ensdata         = NULL;
+    }
+}
 
-          if ( lwarn )
-            {
-              lwarn = FALSE;
-              Warning("SZIP compression is only available for netCDF4!");
-            }
-        }
+static
+void cdfSetVar(ncvar_t *ncvars, int ncvarid, short isvar)
+{
+  if ( ncvars[ncvarid].isvar != UNDEFID &&
+       ncvars[ncvarid].isvar != isvar   &&
+       ncvars[ncvarid].warn  == FALSE )
+    {
+      if ( ! ncvars[ncvarid].ignore )
+        Warning("Inconsistent variable definition for %s!", ncvars[ncvarid].name);
+
+      ncvars[ncvarid].warn = TRUE;
+      isvar = FALSE;
     }
 
-  if ( stdname && *stdname )
-    cdf_put_att_text(fileID, ncvarid, "standard_name", strlen(stdname), stdname);
+  ncvars[ncvarid].isvar = isvar;
+}
 
-  if ( longname && *longname )
-    cdf_put_att_text(fileID, ncvarid, "long_name", strlen(longname), longname);
+static
+void cdfSetDim(ncvar_t *ncvars, int ncvarid, int dimid, int dimtype)
+{
+  if ( ncvars[ncvarid].dimtype[dimid] != UNDEFID &&
+       ncvars[ncvarid].dimtype[dimid] != dimtype )
+    {
+      Warning("Inconsistent dimension definition for %s! dimid = %d;  type = %d;  newtype = %d",
+              ncvars[ncvarid].name, dimid, ncvars[ncvarid].dimtype[dimid], dimtype);
+    }
 
-  if ( units && *units )
-    cdf_put_att_text(fileID, ncvarid, "units", strlen(units), units);
+  ncvars[ncvarid].dimtype[dimid] = dimtype;
+}
 
-  if ( code > 0 && pdis == 255 )
-    cdf_put_att_int(fileID, ncvarid, "code", NC_INT, 1, &code);
+static
+bool isLonAxis(const char *units, const char *stdname)
+{
+  bool status = false;
+  char lc_units[16];
 
-  if ( pdis != 255 )
+  memcpy(lc_units, units, 15);
+  lc_units[15] = 0;
+  strtolower(lc_units);
+
+  if ( ((memcmp(lc_units, "degree", 6) == 0 || memcmp(lc_units, "radian", 6) == 0) &&
+        (memcmp(stdname, "grid_longitude", 14) == 0 || memcmp(stdname, "longitude", 9) == 0)) )
     {
-      char paramstr[32];
-      cdiParamToString(param, paramstr, sizeof(paramstr));
-      cdf_put_att_text(fileID, ncvarid, "param", strlen(paramstr), paramstr);
+      status = true;
     }
 
-  if ( tableID != UNDEFID )
+  if ( status == false &&
+       memcmp(stdname, "grid_latitude", 13) && memcmp(stdname, "latitude", 8) &&
+       memcmp(lc_units, "degree", 6) == 0 )
     {
-      tablenum = tableInqNum(tableID);
-      if ( tablenum > 0 )
-        cdf_put_att_int(fileID, ncvarid, "table", NC_INT, 1, &tablenum);
+      int ioff = 6;
+      if ( lc_units[ioff] == 's' ) ioff++;
+      if ( lc_units[ioff] == '_' ) ioff++;
+      if ( lc_units[ioff] == 'e' ) status = true;
     }
 
-  char coordinates[CDI_MAX_NAME];
-  coordinates[0] = 0;
+  return status;
+}
 
-  if ( zaxis_is_scalar )
-    {
-      int nczvarID = streamptr->nczvarID[zaxisindex];
-      if ( nczvarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, nczvarID, coordinates+len);
-        }
-    }
+static
+bool isLatAxis(const char *units, const char *stdname)
+{
+  bool status = false;
+  char lc_units[16];
 
-  if ( gridtype != GRID_GENERIC && gridtype != GRID_LONLAT  && gridtype != GRID_CURVILINEAR )
+  memcpy(lc_units, units, 15);
+  lc_units[15] = 0;
+  strtolower(lc_units);
+
+  if ( ((memcmp(lc_units, "degree", 6) == 0 || memcmp(lc_units, "radian", 6) == 0) &&
+        (memcmp(stdname, "grid_latitude", 13) == 0 || memcmp(stdname, "latitude", 8) == 0)) )
     {
-      size_t len = strlen(gridNamePtr(gridtype));
-      if ( len > 0 )
-        cdf_put_att_text(fileID, ncvarid, "grid_type", len, gridNamePtr(gridtype));
+      status = true;
     }
 
-  if ( gridIsRotated(gridID) )
+  if ( status == false &&
+       memcmp(stdname, "grid_longitude", 14) && memcmp(stdname, "longitude", 9) &&
+       memcmp(lc_units, "degree", 6) == 0 )
     {
-      char mapping[] = "rotated_pole";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
+      int ioff = 6;
+      if ( lc_units[ioff] == 's' ) ioff++;
+      if ( lc_units[ioff] == '_' ) ioff++;
+      if ( lc_units[ioff] == 'n' || lc_units[ioff] == 's' ) status = true;
     }
 
-  if ( gridtype == GRID_SINUSOIDAL )
+  return status;
+}
+
+static
+bool isDBLAxis(/*const char *units,*/ const char *longname)
+{
+  bool status = false;
+
+  if ( strcmp(longname, "depth below land")         == 0 ||
+       strcmp(longname, "depth_below_land")         == 0 ||
+       strcmp(longname, "levels below the surface") == 0 )
     {
-      char mapping[] = "sinusoidal";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
+      /*
+      if ( strcmp(ncvars[ncvarid].units, "cm") == 0 ||
+           strcmp(ncvars[ncvarid].units, "dm") == 0 ||
+           strcmp(ncvars[ncvarid].units, "m")  == 0 )
+      */
+        status = true;
     }
-  else if ( gridtype == GRID_LAEA )
+
+  return status;
+}
+
+static
+bool unitsIsHeight(const char *units)
+{
+  bool status = false;
+  int u0 = units[0];
+
+  if ( (u0=='m' && (!units[1] || strncmp(units, "meter", 5) == 0)) ||
+       (!units[2] && units[1]=='m' && (u0=='c' || u0=='d' || u0=='k')) )
     {
-      char mapping[] = "laea";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
+      status = true;
     }
-  else if ( gridtype == GRID_LCC2 )
-    {
-      char mapping[] = "Lambert_Conformal";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
-    }
-  else if ( gridtype == GRID_TRAJECTORY )
-    {
-      cdf_put_att_text(fileID, ncvarid, "coordinates", 9, "tlon tlat" );
-    }
-  else if ( gridtype == GRID_LONLAT && xid == UNDEFID && yid == UNDEFID && gridsize == 1 )
-    {
-      int ncxvarID = streamptr->ncxvarID[gridindex];
-      int ncyvarID = streamptr->ncyvarID[gridindex];
-      if ( ncyvarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, ncyvarID, coordinates+len);
-        }
-      if ( ncxvarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, ncxvarID, coordinates+len);
-        }
-    }
-  else if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
-    {
-      char cellarea[CDI_MAX_NAME] = "area: ";
-      int ncxvarID = streamptr->ncxvarID[gridindex];
-      int ncyvarID = streamptr->ncyvarID[gridindex];
-      int ncavarID = streamptr->ncavarID[gridindex];
-      if ( ncyvarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, ncyvarID, coordinates+len);
-        }
-      if ( ncxvarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, ncxvarID, coordinates+len);
-        }
-
-      if ( ncavarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(cellarea);
-          cdf_inq_varname(fileID, ncavarID, cellarea+len);
-          len = strlen(cellarea);
-          cdf_put_att_text(fileID, ncvarid, "cell_measures", len, cellarea);
-        }
 
-      if ( gridtype == GRID_UNSTRUCTURED )
-        {
-          int position = gridInqPosition(gridID);
-          if ( position > 0 )
-            cdf_put_att_int(fileID, ncvarid, "number_of_grid_in_reference", NC_INT, 1, &position);
-        }
-    }
-  else if ( gridtype == GRID_SPECTRAL || gridtype == GRID_FOURIER )
-    {
-      int gridTruncation = gridInqTrunc(gridID);
-      axis[iax++] = '-';
-      axis[iax++] = '-';
-      cdf_put_att_text(fileID, ncvarid, "axis", iax, axis);
-      cdf_put_att_int(fileID, ncvarid, "truncation", NC_INT, 1, &gridTruncation);
-    }
+  return status;
+}
 
-  size_t len = strlen(coordinates);
-  if ( len ) cdf_put_att_text(fileID, ncvarid, "coordinates", len, coordinates);
+static
+bool isDepthAxis(const char *stdname, const char *longname)
+{
+  bool status = false;
 
-  /*  if ( xtype == NC_BYTE || xtype == NC_SHORT || xtype == NC_INT ) */
-    {
-      int laddoffset, lscalefactor;
-      double addoffset, scalefactor;
-      int astype = NC_DOUBLE;
+  if ( strcmp(stdname, "depth") == 0 ) status = true;
 
-      addoffset    = vlistInqVarAddoffset(vlistID, varID);
-      scalefactor  = vlistInqVarScalefactor(vlistID, varID);
-      laddoffset   = IS_NOT_EQUAL(addoffset, 0);
-      lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+  if ( status == false )
+    if ( strcmp(longname, "depth_below_sea") == 0 ||
+         strcmp(longname, "depth below sea") == 0 )
+      {
+        status = true;
+      }
 
-      if ( laddoffset || lscalefactor )
-        {
-          if ( IS_EQUAL(addoffset,   (double) ((float) addoffset)) &&
-               IS_EQUAL(scalefactor, (double) ((float) scalefactor)) )
-            {
-              astype = NC_FLOAT;
-            }
+  return status;
+}
 
-          if ( xtype == (int) NC_FLOAT ) astype = NC_FLOAT;
+static
+bool isHeightAxis(const char *stdname, const char *longname)
+{
+  bool status = false;
 
-          cdf_put_att_double(fileID, ncvarid, "add_offset",   (nc_type) astype, 1, &addoffset);
-          cdf_put_att_double(fileID, ncvarid, "scale_factor", (nc_type) astype, 1, &scalefactor);
-        }
-    }
+  if ( strcmp(stdname, "height") == 0 ) status = true;
 
-  if ( dtype == DATATYPE_UINT8 && xtype == NC_BYTE )
-    {
-      int validrange[2] = {0, 255};
-      cdf_put_att_int(fileID, ncvarid, "valid_range", NC_SHORT, 2, validrange);
-      cdf_put_att_text(fileID, ncvarid, "_Unsigned", 4, "true");
-    }
+  if ( status == false )
+    if ( strcmp(longname, "height") == 0 ||
+         strcmp(longname, "height above the surface") == 0 )
+      {
+        status = true;
+      }
 
-  streamptr->vars[varID].ncvarid = ncvarid;
+  return status;
+}
 
-  if ( vlistInqVarMissvalUsed(vlistID, varID) )
-    cdfDefVarMissval(streamptr, varID, vlistInqVarDatatype(vlistID, varID), 0);
+static
+bool unitsIsPressure(const char *units)
+{
+  bool status = false;
 
-  if ( zid == -1 )
+  if ( memcmp(units, "millibar", 8) == 0 ||
+       memcmp(units, "mb", 2)       == 0 ||
+       memcmp(units, "hectopas", 8) == 0 ||
+       memcmp(units, "hPa", 3)      == 0 ||
+       memcmp(units, "Pa", 2)       == 0 )
     {
-      if ( zaxisInqType(zaxisID) == ZAXIS_CLOUD_BASE          ||
-           zaxisInqType(zaxisID) == ZAXIS_CLOUD_TOP           ||
-           zaxisInqType(zaxisID) == ZAXIS_ISOTHERM_ZERO       ||
-           zaxisInqType(zaxisID) == ZAXIS_TOA                 ||
-           zaxisInqType(zaxisID) == ZAXIS_SEA_BOTTOM          ||
-           zaxisInqType(zaxisID) == ZAXIS_LAKE_BOTTOM         ||
-           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM     ||
-           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM_TA  ||
-           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM_TW  ||
-           zaxisInqType(zaxisID) == ZAXIS_MIX_LAYER           ||
-           zaxisInqType(zaxisID) == ZAXIS_ATMOSPHERE )
-        {
-          zaxisInqName(zaxisID, varname);
-          cdf_put_att_text(fileID, ncvarid, "level_type", strlen(varname), varname);
-        }
+      status = true;
     }
 
-  if ( vlistInqVarEnsemble( vlistID,  varID, &ensID, &ensCount, &forecast_type ) )
+  return status;
+}
+
+static
+void scan_hybrid_formula(int ncid, int ncfvarid, int *apvarid, int *bvarid, int *psvarid)
+{
+  *apvarid = -1;
+  *bvarid  = -1;
+  *psvarid = -1;
+  const int attstringlen = 8192; char attstring[8192];
+  cdfGetAttText(ncid, ncfvarid, "formula", attstringlen, attstring);
+  if ( strcmp(attstring, "p = ap + b*ps") == 0 )
     {
-      /* void cdf_put_att_int(  int ncid, int varid, const char *name, nc_type xtype,
-	                        size_t len, const int *ip )
-       */
-	cdf_put_att_int(fileID, ncvarid, "realization", NC_INT, 1, &ensID);
-	cdf_put_att_int(fileID, ncvarid, "ensemble_members", NC_INT, 1, &ensCount);
-	cdf_put_att_int(fileID, ncvarid, "forecast_init_type", NC_INT, 1, &forecast_type);
+      int lstop = FALSE;
+      int dimvarid;
+      cdfGetAttText(ncid, ncfvarid, "formula_terms", attstringlen, attstring);
+      char *pstring = attstring;
 
-#ifdef DBG
-	if( DBG )
-	  {
-	    fprintf( stderr, "cdfDefVar :\n EnsID  %d\n Enscount %d\n Forecast init type %d\n",  ensID,
-		     ensCount,  forecast_type );
-	  }
-#endif
-    }
+      for ( int i = 0; i < 3; i++ )
+        {
+          while ( isspace((int) *pstring) ) pstring++;
+          if ( *pstring == 0 ) break;
+          char *tagname = pstring;
+          while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
+          if ( *pstring == 0 ) lstop = TRUE;
+          *pstring++ = 0;
 
-  /* Attributes */
-  defineAttributes(vlistID, varID, fileID, ncvarid);
+          while ( isspace((int) *pstring) ) pstring++;
+          if ( *pstring == 0 ) break;
+          char *varname = pstring;
+          while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
+          if ( *pstring == 0 ) lstop = TRUE;
+          *pstring++ = 0;
 
-  /* if ( streamptr->ncmode == 2 ) cdf_enddef(fileID); */
+          int status = nc_inq_varid(ncid, varname, &dimvarid);
+          if ( status == NC_NOERR )
+            {
+              if      ( strcmp(tagname, "ap:") == 0 ) *apvarid = dimvarid;
+              else if ( strcmp(tagname, "b:")  == 0 ) *bvarid  = dimvarid;
+              else if ( strcmp(tagname, "ps:") == 0 ) *psvarid = dimvarid;
+            }
+          else if ( strcmp(tagname, "ps:") != 0 )
+            {
+              Warning("%s - %s", nc_strerror(status), varname);
+            }
 
-  return ncvarid;
+          if ( lstop ) break;
+        }
+    }
 }
 
 static
-void scale_add(size_t size, double *data, double addoffset, double scalefactor)
+bool isHybridSigmaPressureCoordinate(int ncid, int ncvarid, ncvar_t *ncvars, const ncdim_t *ncdims)
 {
-  int laddoffset;
-  int lscalefactor;
-
-  laddoffset   = IS_NOT_EQUAL(addoffset, 0);
-  lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+  bool status = false;
+  int ncfvarid = ncvarid;
+  ncvar_t *ncvar = &ncvars[ncvarid];
 
-  if ( laddoffset || lscalefactor )
+  if ( strcmp(ncvar->stdname, "atmosphere_hybrid_sigma_pressure_coordinate") == 0 )
     {
-      for (size_t i = 0; i < size; ++i )
+      cdiConvention = CDI_CONVENTION_CF;
+
+      status = true;
+      ncvar->zaxistype = ZAXIS_HYBRID;
+      int dimid = ncvar->dimids[0];
+      size_t dimlen = ncdims[dimid].len;
+
+      int apvarid1 = -1, bvarid1 = -1, psvarid1 = -1;
+      if ( ncvars[ncfvarid].lformula && ncvars[ncfvarid].lformulaterms )
+        scan_hybrid_formula(ncid, ncfvarid, &apvarid1, &bvarid1, &psvarid1);
+      if ( apvarid1 != -1 ) ncvars[apvarid1].isvar = FALSE;
+      if ( bvarid1  != -1 ) ncvars[bvarid1].isvar  = FALSE;
+      if ( psvarid1 != -1 ) ncvar->psvarid = psvarid1;
+
+      if ( ncvar->bounds != UNDEFID && ncvars[ncvar->bounds].lformula && ncvars[ncvar->bounds].lformulaterms )
         {
-          if ( lscalefactor ) data[i] *= scalefactor;
-          if ( laddoffset )   data[i] += addoffset;
+          ncfvarid = ncvar->bounds;
+          int apvarid2 = -1, bvarid2 = -1, psvarid2 = -1;
+          if ( ncvars[ncfvarid].lformula && ncvars[ncfvarid].lformulaterms )
+            scan_hybrid_formula(ncid, ncfvarid, &apvarid2, &bvarid2, &psvarid2);
+          if ( apvarid2 != -1 && bvarid2 != -1 )
+            {
+              ncvars[apvarid2].isvar = FALSE;
+              ncvars[bvarid2].isvar  = FALSE;
+
+              if ( dimid == ncvars[apvarid2].dimids[0] && ncdims[ncvars[apvarid2].dimids[1]].len == 2 )
+                {
+                  double abuf[dimlen*2], bbuf[dimlen*2];
+                  cdf_get_var_double(ncid, apvarid2, abuf);
+                  cdf_get_var_double(ncid, bvarid2, bbuf);
+                  /*
+                  for ( int i = 0; i < dimlen; ++i )
+                    printf("%d  %g %g    %g %g\n", i, abuf[i*2], abuf[i*2+1], bbuf[i*2], bbuf[i*2+1]);
+                  */
+                  size_t vctsize = (dimlen+1)*2;
+                  double *vct = (double *) Malloc(vctsize * sizeof(double));
+                  for ( size_t i = 0; i < dimlen; ++i )
+                    {
+                      vct[i] = abuf[i*2];
+                      vct[i+dimlen+1] = bbuf[i*2];
+                    }
+                  vct[dimlen]     = abuf[dimlen*2-1];
+                  vct[dimlen*2+1] = bbuf[dimlen*2-1];
+
+                  ncvar->vct = vct;
+                  ncvar->vctsize = vctsize;
+                }
+            }
         }
     }
+
+  return status;
 }
 
+
 static
-void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], size_t (*count)[4])
+int isGaussGrid(size_t ysize, double yinc, const double *yvals)
 {
-  int vlistID = streamptr->vlistID;
-  int tsID = streamptr->curTsID;
-  int gridID    = vlistInqVarGrid(vlistID, varID);
-  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
-  int gridindex = vlistGridIndex(vlistID, gridID);
-
-  if ( CDI_Debug ) Message("tsID = %d", tsID);
+  int lgauss = FALSE;
+  double *yv, *yw;
 
-  int xid = UNDEFID, yid = UNDEFID;
-  if ( gridInqType(gridID) == GRID_TRAJECTORY )
-    {
-      cdfReadGridTraj(streamptr, gridID);
-    }
-  else
+  if ( IS_EQUAL(yinc, 0) && ysize > 2 ) /* check if gaussian */
     {
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
-    }
-  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-  int zid = streamptr->zaxisID[zaxisindex];
+      size_t i;
+      yv = (double *) Malloc(ysize*sizeof(double));
+      yw = (double *) Malloc(ysize*sizeof(double));
+      gaussaw(yv, yw, ysize);
+      Free(yw);
+      for ( i = 0; i < ysize; i++ )
+        yv[i] = asin(yv[i])/M_PI*180.0;
 
-  int ndims = 0;
-#define addDimension(startCoord, length) do \
-    { \
-      (*start)[ndims] = startCoord; \
-      (*count)[ndims] = length; \
-      ndims++; \
-    } while(0)
-  if ( tsteptype != TSTEP_CONSTANT ) addDimension((size_t)tsID, 1);
-  if ( zid != UNDEFID ) addDimension(0, (size_t)zaxisInqSize(zaxisID));
-  if ( yid != UNDEFID ) addDimension(0, (size_t)gridInqYsize(gridID));
-  if ( xid != UNDEFID ) addDimension(0, (size_t)gridInqXsize(gridID));
-#undef addDimension
+      for ( i = 0; i < ysize; i++ )
+        if ( fabs(yv[i] - yvals[i]) >
+             ((yv[0] - yv[1])/500) ) break;
 
-  assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
-  assert(ndims <= (int)(sizeof(*count)/sizeof(**count)));
+      if ( i == ysize ) lgauss = TRUE;
 
-  if ( CDI_Debug )
-    for (int idim = 0; idim < ndims; idim++)
-      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
+      /* check S->N */
+      if ( lgauss == FALSE )
+        {
+          for ( i = 0; i < ysize; i++ )
+            if ( fabs(yv[i] - yvals[ysize-i-1]) >
+                 ((yv[0] - yv[1])/500) ) break;
+
+          if ( i == ysize ) lgauss = TRUE;
+        }
+
+      Free(yv);
+    }
+
+  return (lgauss);
 }
 
-//Scans the data array for missVals, optionally applying first a scale factor and then an offset.
-//Returns the number of missing + out-of-range values encountered.
 static
-size_t cdfDoInputDataTransformationDP(size_t valueCount, double *data, bool haveMissVal, double missVal, double scaleFactor, double offset, double validMin, double validMax)
- {
-  const bool haveOffset   = IS_NOT_EQUAL(offset, 0);
-  const bool haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1);
-  size_t missValCount = 0;
-
-  if ( IS_EQUAL(validMin, VALIDMISS) ) validMin = DBL_MIN;
-  if ( IS_EQUAL(validMax, VALIDMISS) ) validMax = DBL_MAX;
+void printNCvars(const ncvar_t *ncvars, int nvars, const char *oname)
+{
+  char axis[7];
+  int ncvarid, i;
+  int ndim;
+  static const char iaxis[] = {'t', 'z', 'y', 'x'};
 
-  bool haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin,DBL_MIN));
-  assert(!haveRangeCheck || haveMissVal);
+  fprintf(stderr, "%s:\n", oname);
 
-  switch ((int)haveMissVal | ((int)haveScaleFactor << 1)
-          | ((int)haveOffset << 2) | ((int)haveRangeCheck << 3))
+  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-    case 15: /* haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset */
-      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;
-        }
-      break;
-    case 13: /* haveRangeCheck & haveMissVal & haveOffset */
-      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;
-        }
-      break;
-    case 11: /* haveRangeCheck & haveMissVal & haveScaleFactor */
-      for ( size_t i = 0; i < valueCount; i++ )
+      ndim = 0;
+      if ( ncvars[ncvarid].isvar )
         {
-          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;
+          axis[ndim++] = 'v';
+          axis[ndim++] = ':';
+          for ( i = 0; i < ncvars[ncvarid].ndims; i++ )
+            {/*
+              if      ( ncvars[ncvarid].tvarid != -1 ) axis[ndim++] = iaxis[0];
+              else if ( ncvars[ncvarid].zvarid != -1 ) axis[ndim++] = iaxis[1];
+              else if ( ncvars[ncvarid].yvarid != -1 ) axis[ndim++] = iaxis[2];
+              else if ( ncvars[ncvarid].xvarid != -1 ) axis[ndim++] = iaxis[3];
+              else
+             */
+              if      ( ncvars[ncvarid].dimtype[i] == T_AXIS ) axis[ndim++] = iaxis[0];
+              else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) axis[ndim++] = iaxis[1];
+              else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) axis[ndim++] = iaxis[2];
+              else if ( ncvars[ncvarid].dimtype[i] == X_AXIS ) axis[ndim++] = iaxis[3];
+              else                                             axis[ndim++] = '?';
+            }
         }
-      break;
-    case 9: /* haveRangeCheck & haveMissVal */
-      for ( size_t i = 0; i < valueCount; i++ )
+      else
         {
-          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 : data[i];
+          axis[ndim++] = 'c';
+          axis[ndim++] = ':';
+          if      ( ncvars[ncvarid].istime ) axis[ndim++] = iaxis[0];
+          else if ( ncvars[ncvarid].islev  ) axis[ndim++] = iaxis[1];
+          else if ( ncvars[ncvarid].islat  ) axis[ndim++] = iaxis[2];
+          else if ( ncvars[ncvarid].islon  ) axis[ndim++] = iaxis[3];
+          else                               axis[ndim++] = '?';
         }
-      break;
-    case 7: /* haveMissVal & haveScaleFactor & haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        if ( DBL_IS_EQUAL(data[i], missVal) )
-          missValCount++;
-        else
-          data[i] = data[i] * scaleFactor + offset;
-      break;
-    case 6: /* haveOffset & haveScaleFactor */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] = data[i] * scaleFactor + offset;
-      break;
-    case 5: /* haveMissVal & haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        if ( DBL_IS_EQUAL(data[i], missVal) )
-          missValCount++;
-        else
-          data[i] += offset;
-      break;
-    case 4: /* haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] += offset;
-      break;
-    case 3: /* haveMissVal & haveScaleFactor */
-      for ( size_t i = 0; i < valueCount; i++ )
-        if ( DBL_IS_EQUAL(data[i], missVal) )
-          missValCount++;
-        else
-          data[i] *= scaleFactor;
-      break;
-    case 2: /* haveScaleFactor */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] *= scaleFactor;
-      break;
-    case 1: /* haveMissVal */
-      for ( size_t i = 0; i < valueCount; i++ )
-        missValCount += (unsigned)DBL_IS_EQUAL(data[i], missVal);
-      break;
-    }
 
-  return missValCount;
+      axis[ndim++] = 0;
+
+      fprintf(stderr, "%3d %3d  %-6s %s\n", ncvarid, ndim-3, axis, ncvars[ncvarid].name);
+    }
 }
 
 static
-size_t cdfDoInputDataTransformationSP(size_t valueCount, float *data, bool haveMissVal, double missVal, double scaleFactor, double offset, double validMin, double validMax)
- {
-  const bool haveOffset   = IS_NOT_EQUAL(offset, 0);
-  const bool haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1);
-  size_t missValCount = 0;
-
-  if ( IS_EQUAL(validMin, VALIDMISS) ) validMin = DBL_MIN;
-  if ( IS_EQUAL(validMax, VALIDMISS) ) validMax = DBL_MAX;
+void cdfScanVarAttributes(int nvars, ncvar_t *ncvars, ncdim_t *ncdims,
+                          int timedimid, int modelID, int format)
+{
+  int ncid;
+  int ncdimid;
+  int nvdims, nvatts;
+  int *dimidsp;
+  int iatt;
+  nc_type xtype, atttype;
+  size_t attlen;
+  char name[CDI_MAX_NAME];
+  char attname[CDI_MAX_NAME];
+  const int attstringlen = 8192; char attstring[8192];
 
-  bool haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin,DBL_MIN));
-  assert(!haveRangeCheck || haveMissVal);
+  int nchecked_vars = 0;
+  enum { max_check_vars = 9 };
+  char *checked_vars[max_check_vars];
+  for ( int i = 0; i < max_check_vars; ++i ) checked_vars[i] = NULL;
 
-  switch ((int)haveMissVal | ((int)haveScaleFactor << 1)
-          | ((int)haveOffset << 2) | ((int)haveRangeCheck << 3))
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-    case 15: /* haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset */
-      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);
-        }
-      break;
-    case 13: /* haveRangeCheck & haveMissVal & haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
+      ncid    = ncvars[ncvarid].ncid;
+      dimidsp = ncvars[ncvarid].dimids;
+
+      cdf_inq_var(ncid, ncvarid, name, &xtype, &nvdims, dimidsp, &nvatts);
+      strcpy(ncvars[ncvarid].name, name);
+
+      for ( ncdimid = 0; ncdimid < nvdims; ncdimid++ )
+        ncvars[ncvarid].dimtype[ncdimid] = -1;
+
+      ncvars[ncvarid].xtype = xtype;
+      ncvars[ncvarid].ndims = nvdims;
+
+#if  defined  (HAVE_NETCDF4)
+      if ( format == NC_FORMAT_NETCDF4_CLASSIC || format == NC_FORMAT_NETCDF4 )
         {
-          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);
-        }
-      break;
-    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);
-        }
-      break;
-    case 9: /* haveRangeCheck & haveMissVal */
-      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 : data[i];
-        }
-      break;
-    case 7: /* haveMissVal & haveScaleFactor & haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        if ( DBL_IS_EQUAL(data[i], missVal) )
-          missValCount++;
-        else
-          data[i] = (float)(data[i] * scaleFactor + offset);
-      break;
-    case 6: /* haveOffset & haveScaleFactor */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] = (float)(data[i] * scaleFactor + offset);
-      break;
-    case 5: /* haveMissVal & haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        if ( DBL_IS_EQUAL(data[i], missVal) )
-          missValCount++;
-        else
-          data[i] = (float)(data[i] + offset);
-      break;
-    case 4: /* haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] = (float)(data[i] + offset);
-      break;
-    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);
-      break;
-    case 2: /* haveScaleFactor */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] = (float)(data[i] * scaleFactor);
-      break;
-    case 1: /* haveMissVal */
-      for ( size_t i = 0; i < valueCount; i++ )
-        missValCount += (unsigned)DBL_IS_EQUAL(data[i], missVal);
-      break;
-    }
-
-  return missValCount;
-}
-
-static void
-cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dtype, long nvals, size_t xsize, size_t ysize, int swapxy, size_t *start, size_t *count, int memtype, const void *data, int nmiss)
-{
-  const double *pdata_dp = (const double *) data;
-  double *mdata_dp = NULL;
-  double *sdata_dp = NULL;
-  const float *pdata_sp = (const float *) data;
-  float *mdata_sp = NULL;
-  float *sdata_sp = NULL;
-
-  /*  if ( dtype == DATATYPE_INT8 || dtype == DATATYPE_INT16 || dtype == DATATYPE_INT32 ) */
-    {
-      bool laddoffset, lscalefactor;
-      double addoffset, scalefactor;
-      double missval;
-
-      addoffset    = vlistInqVarAddoffset(vlistID, varID);
-      scalefactor  = vlistInqVarScalefactor(vlistID, varID);
-      laddoffset   = IS_NOT_EQUAL(addoffset, 0);
-      lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
-
-      missval      = vlistInqVarMissval(vlistID, varID);
+          char buf[CDI_MAX_NAME];
+          int shuffle, deflate, deflate_level;
+          size_t chunks[nvdims];
+          int storage_in;
+          nc_inq_var_deflate(ncid, ncvarid, &shuffle, &deflate, &deflate_level);
+          if ( deflate > 0 ) ncvars[ncvarid].deflate = 1;
 
-      if ( laddoffset || lscalefactor )
-        {
-          if ( memtype == MEMTYPE_FLOAT )
+          if ( nc_inq_var_chunking(ncid, ncvarid, &storage_in, chunks) == NC_NOERR )
             {
-              mdata_sp = (float *) Malloc((size_t)nvals*sizeof(float));
-              memcpy(mdata_sp, pdata_sp, (size_t)nvals * sizeof (float));
-              pdata_sp = mdata_sp;
-
-              if ( nmiss > 0 )
+              if ( storage_in == NC_CHUNKED )
                 {
-                  for (long i = 0; i < nvals; i++ )
+                  ncvars[ncvarid].chunked = 1;
+                  for ( int i = 0; i < nvdims; ++i ) ncvars[ncvarid].chunks[i] = (int)chunks[i];
+                  if ( CDI_Debug )
                     {
-                      double temp = mdata_sp[i];
-                      if ( !DBL_IS_EQUAL(temp, missval) )
-                        {
-                          if ( laddoffset )   temp -= addoffset;
-                          if ( lscalefactor ) temp /= scalefactor;
-                          mdata_sp[i] = (float)temp;
-                        }
+                      fprintf(stderr, "%s: chunking %d %d %d  chunks ", name, storage_in, NC_CONTIGUOUS, NC_CHUNKED);
+                      for ( int i = 0; i < nvdims; ++i ) fprintf(stderr, "%ld ", chunks[i]);
+                      fprintf(stderr, "\n");
                     }
-                }
-              else
-                {
-                  for (long i = 0; i < nvals; i++ )
+                  strcat(ncvars[ncvarid].extra, "chunks=");
+                  for ( int i = nvdims-1; i >= 0; --i )
                     {
-                      double temp = mdata_sp[i];
-                      if ( laddoffset )   temp -= addoffset;
-                      if ( lscalefactor ) temp /= scalefactor;
-                      mdata_sp[i] = (float)temp;
+                      sprintf(buf, "%ld", (long) chunks[i]);
+                      strcat(ncvars[ncvarid].extra, buf);
+                      if ( i > 0 ) strcat(ncvars[ncvarid].extra, "x");
                     }
+                  strcat(ncvars[ncvarid].extra, " ");
                 }
             }
+        }
+#endif
+
+      if ( nvdims > 0 )
+        {
+          if ( timedimid == dimidsp[0] )
+            {
+              ncvars[ncvarid].tsteptype = TSTEP_INSTANT;
+              cdfSetDim(ncvars, ncvarid, 0, T_AXIS);
+            }
           else
             {
-              mdata_dp = (double *) Malloc((size_t)nvals * sizeof(double));
-              memcpy(mdata_dp, pdata_dp, (size_t)nvals * sizeof(double));
-              pdata_dp = mdata_dp;
-
-              if ( nmiss > 0 )
-                {
-                  for (long i = 0; i < nvals; i++ )
-                    {
-                      if ( !DBL_IS_EQUAL(mdata_dp[i], missval) )
-                        {
-                          if ( laddoffset )   mdata_dp[i] -= addoffset;
-                          if ( lscalefactor ) mdata_dp[i] /= scalefactor;
-                        }
-                    }
-                }
-              else
+              for ( ncdimid = 1; ncdimid < nvdims; ncdimid++ )
                 {
-                  for (long i = 0; i < nvals; i++ )
+                  if ( timedimid == dimidsp[ncdimid] )
                     {
-                      if ( laddoffset )   mdata_dp[i] -= addoffset;
-                      if ( lscalefactor ) mdata_dp[i] /= scalefactor;
+                      Warning("Time must be the first dimension! Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
+                      ncvars[ncvarid].isvar = FALSE;
                     }
                 }
             }
         }
 
-      if ( dtype == DATATYPE_UINT8 || dtype == DATATYPE_INT8 ||
-           dtype == DATATYPE_INT16 || dtype == DATATYPE_INT32 )
+      for ( iatt = 0; iatt < nvatts; iatt++ )
         {
-          if ( memtype == MEMTYPE_FLOAT )
+          cdf_inq_attname(ncid, ncvarid, iatt, attname);
+          cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
+          cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
+
+          if ( strcmp(attname, "long_name") == 0 && xtypeIsText(atttype) )
             {
-              if ( mdata_sp == NULL )
+              cdfGetAttText(ncid, ncvarid, attname, CDI_MAX_NAME, ncvars[ncvarid].longname);
+            }
+          else if ( strcmp(attname, "standard_name") == 0 && xtypeIsText(atttype) )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, CDI_MAX_NAME, ncvars[ncvarid].stdname);
+            }
+          else if ( strcmp(attname, "units") == 0 && xtypeIsText(atttype) )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, CDI_MAX_NAME, ncvars[ncvarid].units);
+            }
+          else if ( strcmp(attname, "calendar") == 0 )
+            {
+              ncvars[ncvarid].calendar = TRUE;
+            }
+          else if ( strcmp(attname, "param") == 0 && xtypeIsText(atttype) )
+            {
+	      char paramstr[32];
+	      int pnum = 0, pcat = 255, pdis = 255;
+              cdfGetAttText(ncid, ncvarid, attname, sizeof(paramstr), paramstr);
+	      sscanf(paramstr, "%d.%d.%d", &pnum, &pcat, &pdis);
+	      ncvars[ncvarid].param = cdiEncodeParam(pnum, pcat, pdis);
+              cdfSetVar(ncvars, ncvarid, TRUE);
+            }
+          else if ( strcmp(attname, "code") == 0 && !xtypeIsText(atttype) )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].code);
+              cdfSetVar(ncvars, ncvarid, TRUE);
+            }
+          else if ( strcmp(attname, "table") == 0 && !xtypeIsText(atttype) )
+            {
+              int tablenum;
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &tablenum);
+              if ( tablenum > 0 )
                 {
-                  mdata_sp = (float *) Malloc((size_t)nvals * sizeof(float));
-                  memcpy(mdata_sp, pdata_sp, (size_t)nvals * sizeof(float));
-                  pdata_sp = mdata_sp;
+                  ncvars[ncvarid].tabnum = tablenum;
+                  ncvars[ncvarid].tableID = tableInq(modelID, tablenum, NULL);
+                  if ( ncvars[ncvarid].tableID == CDI_UNDEFID )
+                    ncvars[ncvarid].tableID = tableDef(modelID, tablenum, NULL);
+                }
+              cdfSetVar(ncvars, ncvarid, TRUE);
+            }
+          else if ( strcmp(attname, "trunc_type") == 0 && xtypeIsText(atttype) )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              if ( memcmp(attstring, "Triangular", attlen) == 0 )
+                ncvars[ncvarid].gridtype = GRID_SPECTRAL;
+            }
+          else if ( strcmp(attname, "grid_type") == 0 && xtypeIsText(atttype) )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              strtolower(attstring);
+
+              if      ( strcmp(attstring, "gaussian reduced") == 0 )
+                ncvars[ncvarid].gridtype = GRID_GAUSSIAN_REDUCED;
+              else if ( strcmp(attstring, "gaussian") == 0 )
+                ncvars[ncvarid].gridtype = GRID_GAUSSIAN;
+              else if ( strncmp(attstring, "spectral", 8) == 0 )
+                ncvars[ncvarid].gridtype = GRID_SPECTRAL;
+              else if ( strncmp(attstring, "fourier", 7) == 0 )
+                ncvars[ncvarid].gridtype = GRID_FOURIER;
+              else if ( strcmp(attstring, "trajectory") == 0 )
+                ncvars[ncvarid].gridtype = GRID_TRAJECTORY;
+              else if ( strcmp(attstring, "generic") == 0 )
+                ncvars[ncvarid].gridtype = GRID_GENERIC;
+              else if ( strcmp(attstring, "cell") == 0 )
+                ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
+              else if ( strcmp(attstring, "unstructured") == 0 )
+                ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
+              else if ( strcmp(attstring, "curvilinear") == 0 )
+                ncvars[ncvarid].gridtype = GRID_CURVILINEAR;
+              else if ( strcmp(attstring, "sinusoidal") == 0 )
+                ;
+              else if ( strcmp(attstring, "laea") == 0 )
+                ;
+              else if ( strcmp(attstring, "lcc2") == 0 )
+                ;
+              else if ( strcmp(attstring, "linear") == 0 ) // ignore grid type linear
+                ;
+              else
+                {
+                  static int warn = TRUE;
+                  if ( warn )
+                    {
+                      warn = FALSE;
+                      Warning("NetCDF attribute grid_type='%s' unsupported!", attstring);
+                    }
                 }
 
-              for (long i = 0; i < nvals; i++ ) mdata_sp[i] = roundf(mdata_sp[i]);
+              cdfSetVar(ncvars, ncvarid, TRUE);
+            }
+          else if ( strcmp(attname, "level_type") == 0 && xtypeIsText(atttype) )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              strtolower(attstring);
 
-              if ( dtype == DATATYPE_UINT8 )
+              if      ( strcmp(attstring, "toa") == 0 )
+                ncvars[ncvarid].zaxistype = ZAXIS_TOA;
+              else if ( strcmp(attstring, "cloudbase") == 0 )
+                ncvars[ncvarid].zaxistype = ZAXIS_CLOUD_BASE;
+              else if ( strcmp(attstring, "cloudtop") == 0 )
+                ncvars[ncvarid].zaxistype = ZAXIS_CLOUD_TOP;
+              else if ( strcmp(attstring, "isotherm0") == 0 )
+                ncvars[ncvarid].zaxistype = ZAXIS_ISOTHERM_ZERO;
+              else if ( strcmp(attstring, "seabottom") == 0 )
+                ncvars[ncvarid].zaxistype = ZAXIS_SEA_BOTTOM;
+              else if ( strcmp(attstring, "lakebottom") == 0 )
+                ncvars[ncvarid].zaxistype = ZAXIS_LAKE_BOTTOM;
+              else if ( strcmp(attstring, "sedimentbottom") == 0 )
+                ncvars[ncvarid].zaxistype = ZAXIS_SEDIMENT_BOTTOM;
+              else if ( strcmp(attstring, "sedimentbottomta") == 0 )
+                ncvars[ncvarid].zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;
+              else if ( strcmp(attstring, "sedimentbottomtw") == 0 )
+                ncvars[ncvarid].zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;
+              else if ( strcmp(attstring, "mixlayer") == 0 )
+                ncvars[ncvarid].zaxistype = ZAXIS_MIX_LAYER;
+              else if ( strcmp(attstring, "atmosphere") == 0 )
+                ncvars[ncvarid].zaxistype = ZAXIS_ATMOSPHERE;
+              else
                 {
-                  nc_type xtype;
-                  cdf_inq_vartype(fileID, ncvarid, &xtype);
-                  if ( xtype == NC_BYTE )
+                  static int warn = TRUE;
+                  if ( warn )
                     {
-                      for ( long i = 0; i < nvals; ++i )
-                        if ( mdata_sp[i] > 127 ) mdata_sp[i] -= 256;
+                      warn = FALSE;
+                      Warning("NetCDF attribute level_type='%s' unsupported!", attstring);
                     }
                 }
+
+              cdfSetVar(ncvars, ncvarid, TRUE);
             }
-          else
+          else if ( strcmp(attname, "trunc_count") == 0 && !xtypeIsText(atttype) )
             {
-              if ( mdata_dp == NULL )
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
+            }
+          else if ( strcmp(attname, "truncation") == 0 && !xtypeIsText(atttype) )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
+            }
+          else if ( strcmp(attname, "number_of_grid_in_reference") == 0 && !xtypeIsText(atttype) )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].position);
+            }
+          else if ( strcmp(attname, "add_offset") == 0 && !xtypeIsText(atttype) )
+            {
+	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].addoffset);
+	      /*
+		if ( atttype != NC_BYTE && atttype != NC_SHORT && atttype != NC_INT )
+		if ( ncvars[ncvarid].addoffset != 0 )
+		Warning("attribute add_offset not supported for atttype %d", atttype);
+	      */
+	      /* (also used for lon/lat) cdfSetVar(ncvars, ncvarid, TRUE); */
+            }
+          else if ( strcmp(attname, "scale_factor") == 0 && !xtypeIsText(atttype) )
+            {
+	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].scalefactor);
+	      /*
+		if ( atttype != NC_BYTE && atttype != NC_SHORT && atttype != NC_INT )
+		if ( ncvars[ncvarid].scalefactor != 1 )
+		Warning("attribute scale_factor not supported for atttype %d", atttype);
+	      */
+	      /* (also used for lon/lat) cdfSetVar(ncvars, ncvarid, TRUE); */
+            }
+          else if ( strcmp(attname, "climatology") == 0 && xtypeIsText(atttype) )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              int ncboundsid;
+              int status = nc_inq_varid(ncid, attstring, &ncboundsid);
+              if ( status == NC_NOERR )
                 {
-                  mdata_dp = (double *) Malloc((size_t)nvals * sizeof (double));
-                  memcpy(mdata_dp, pdata_dp, (size_t)nvals * sizeof (double));
-                  pdata_dp = mdata_dp;
+                  ncvars[ncvarid].climatology = TRUE;
+                  ncvars[ncvarid].bounds = ncboundsid;
+                  cdfSetVar(ncvars, ncvars[ncvarid].bounds, FALSE);
+                  cdfSetVar(ncvars, ncvarid, FALSE);
+                }
+              else
+                Warning("%s - %s", nc_strerror(status), attstring);
+            }
+          else if ( xtypeIsText(atttype) && strcmp(attname, "bounds") == 0 )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              int ncboundsid;
+              int status = nc_inq_varid(ncid, attstring, &ncboundsid);
+              if ( status == NC_NOERR )
+                {
+                  ncvars[ncvarid].bounds = ncboundsid;
+                  cdfSetVar(ncvars, ncvars[ncvarid].bounds, FALSE);
+                  cdfSetVar(ncvars, ncvarid, FALSE);
                 }
+              else
+                Warning("%s - %s", nc_strerror(status), attstring);
+            }
+          else if ( xtypeIsText(atttype) && strcmp(attname, "formula_terms") == 0 )
+            {
+              ncvars[ncvarid].lformulaterms = TRUE;
+            }
+          else if ( xtypeIsText(atttype) && strcmp(attname, "formula") == 0 )
+            {
+              ncvars[ncvarid].lformula = TRUE;
+            }
+          else if ( strcmp(attname, "cell_measures") == 0 && xtypeIsText(atttype) )
+            {
+              char *cell_measures = NULL, *cell_var = NULL;
 
-              for (long i = 0; i < nvals; i++ ) mdata_dp[i] = round(mdata_dp[i]);
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              char *pstring = attstring;
 
-              if ( dtype == DATATYPE_UINT8 )
+              while ( isspace((int) *pstring) ) pstring++;
+              cell_measures = pstring;
+              while ( isalnum((int) *pstring) ) pstring++;
+              *pstring++ = 0;
+              while ( isspace((int) *pstring) ) pstring++;
+              cell_var = pstring;
+              while ( ! isspace((int) *pstring) && *pstring != 0 ) pstring++;
+              *pstring++ = 0;
+              /*
+              printf("cell_measures >%s<\n", cell_measures);
+              printf("cell_var >%s<\n", cell_var);
+              */
+              if ( memcmp(cell_measures, "area", 4) == 0 )
                 {
-                  nc_type xtype;
-                  cdf_inq_vartype(fileID, ncvarid, &xtype);
-                  if ( xtype == NC_BYTE )
+                  int nc_cell_id;
+                  int status = nc_inq_varid(ncid, cell_var, &nc_cell_id);
+                  if ( status == NC_NOERR )
                     {
-                      for (long i = 0; i < nvals; ++i )
-                        if ( mdata_dp[i] > 127 ) mdata_dp[i] -= 256;
+                      ncvars[ncvarid].cellarea = nc_cell_id;
+                      /* ncvars[nc_cell_id].isvar = UNDEFID; */
+                      cdfSetVar(ncvars, nc_cell_id, FALSE);
                     }
+                  else
+                    Warning("%s - %s", nc_strerror(status), cell_var);
                 }
-            }
-        }
-
-      if ( CDF_Debug && memtype != MEMTYPE_FLOAT )
-        {
-          double fmin, fmax;
-          fmin =  1.0e200;
-          fmax = -1.0e200;
-          for ( long i = 0; i < nvals; ++i )
-            {
-              if ( !DBL_IS_EQUAL(pdata_dp[i], missval) )
+              else
                 {
-                  if ( pdata_dp[i] < fmin ) fmin = pdata_dp[i];
-                  if ( pdata_dp[i] > fmax ) fmax = pdata_dp[i];
+                  Warning("%s has an unexpected contents: %s", attname, cell_measures);
                 }
+              cdfSetVar(ncvars, ncvarid, TRUE);
             }
-          Message("nvals = %d, nmiss = %d, missval = %g, minval = %g, maxval = %g",
-                  nvals, nmiss, missval, fmin, fmax);
-        }
-    }
-
-  if ( swapxy )
-    {
-      if ( memtype == MEMTYPE_FLOAT )
-        {
-          /* malloc and the loop imply nvals >= ysize * xsize,
-           * but that is not checked and the types don't match */
-          sdata_sp = (float *) Malloc((size_t)nvals * sizeof (float));
-          for ( size_t j = 0; j < ysize; ++j )
-            for ( size_t i = 0; i < xsize; ++i )
-              sdata_sp[i*ysize+j] = pdata_sp[j*xsize+i];
-          pdata_sp = sdata_sp;
-        }
-      else
-        {
-          sdata_dp = (double *) Malloc((size_t)nvals * sizeof (double));
-          for ( size_t j = 0; j < ysize; ++j )
-            for ( size_t i = 0; i < xsize; ++i )
-              sdata_dp[i*ysize+j] = pdata_dp[j*xsize+i];
-          pdata_dp = sdata_dp;
-        }
-    }
+          /*
+          else if ( strcmp(attname, "coordinates") == 0 )
+            {
+              char *pstring, *xvarname = NULL, *yvarname = NULL;
 
-  if ( memtype == MEMTYPE_FLOAT )
-    cdf_put_vara_float(fileID, ncvarid, start, count, pdata_sp);
-  else
-    cdf_put_vara_double(fileID, ncvarid, start, count, pdata_dp);
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              pstring = attstring;
 
-  if ( mdata_dp ) Free(mdata_dp);
-  if ( sdata_dp ) Free(sdata_dp);
-  if ( mdata_sp ) Free(mdata_sp);
-  if ( sdata_sp ) Free(sdata_sp);
-}
+              while ( isspace((int) *pstring) ) pstring++;
+              xvarname = pstring;
+              while ( isgraph((int) *pstring) ) pstring++;
+              *pstring++ = 0;
+              while ( isspace((int) *pstring) ) pstring++;
+              yvarname = pstring;
+              while ( isgraph((int) *pstring) ) pstring++;
+              *pstring++ = 0;
 
+              cdf_inq_varid(ncid, xvarname, &ncvars[ncvarid].xvarid);
+              cdf_inq_varid(ncid, yvarname, &ncvars[ncvarid].yvarid);
 
-void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
-{
-  int fileID;
-  int gridID;
-  int zaxisID;
-  int xid = UNDEFID, yid = UNDEFID, zid = UNDEFID;
-  int ncvarid;
-  size_t xsize = 0, ysize = 0;
-  size_t size;
-  size_t start[5];
-  size_t count[5];
-  long nvals;
-  int swapxy = FALSE;
-  int ndims = 0;
-  int idim;
-  int tsteptype;
-  int gridindex, zaxisindex;
-  int dtype;
-  int vlistID;
+              cdfSetVar(ncvars, ncvars[ncvarid].xvarid, FALSE);
+              cdfSetVar(ncvars, ncvars[ncvarid].yvarid, FALSE);
+              cdfSetVar(ncvars, ncvarid, TRUE);
+            }
+          */
+          else if ( (strcmp(attname, "associate")  == 0 || strcmp(attname, "coordinates") == 0) && xtypeIsText(atttype) )
+            {
+              int status;
+              char *varname = NULL;
+              int lstop = FALSE;
+              int dimvarid;
 
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              char *pstring = attstring;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+              for ( int i = 0; i < MAX_COORDVARS; i++ )
+                {
+                  while ( isspace((int) *pstring) ) pstring++;
+                  if ( *pstring == 0 ) break;
+                  varname = pstring;
+                  while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
+                  if ( *pstring == 0 ) lstop = TRUE;
+                  *pstring++ = 0;
 
-  long ntsteps = streamptr->ntsteps;
-  if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
+                  status = nc_inq_varid(ncid, varname, &dimvarid);
+                  if ( status == NC_NOERR )
+                    {
+                      cdfSetVar(ncvars, dimvarid, FALSE);
+                      if ( cdiIgnoreAttCoordinates == FALSE )
+                        {
+                          ncvars[ncvarid].coordvarids[i] = dimvarid;
+                          ncvars[ncvarid].ncoordvars++;
+                        }
+                    }
+                  else
+                    {
+                      int k;
+                      for ( k = 0; k < nchecked_vars; ++k )
+                        if ( strcmp(checked_vars[k], varname) == 0 ) break;
 
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
+                      if ( k == nchecked_vars )
+                        {
+                          if ( nchecked_vars < max_check_vars ) checked_vars[nchecked_vars++] = strdup(varname);
+                          Warning("%s - %s", nc_strerror(status), varname);
+                        }
+                    }
 
-  ncvarid = cdfDefVar(streamptr, varID);
+                  if ( lstop ) break;
+                }
 
-  gridID    = vlistInqVarGrid(vlistID, varID);
-  zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  tsteptype = vlistInqVarTsteptype(vlistID, varID);
-
-  gridindex = vlistGridIndex(vlistID, gridID);
-  if ( gridInqType(gridID) == GRID_TRAJECTORY )
-    {
-      cdfWriteGridTraj(streamptr, gridID);
-    }
-  else
-    {
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
-    }
-
-  zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-  zid = streamptr->zaxisID[zaxisindex];
-
-  if ( tsteptype != TSTEP_CONSTANT )
-    {
-      start[ndims] = (size_t)ntsteps - 1;
-      count[ndims] = 1;
-      ndims++;
-    }
-  if ( zid != UNDEFID )
-    {
-      start[ndims] = 0;
-      count[ndims] = (size_t)zaxisInqSize(zaxisID);
-      ndims++;
-    }
-  if ( yid != UNDEFID )
-    {
-      start[ndims] = 0;
-      cdf_inq_dimlen(fileID, yid, &size);
-      /*      count[ndims] = gridInqYsize(gridID); */
-      count[ndims] = size;
-      ndims++;
-    }
-  if ( xid != UNDEFID )
-    {
-      start[ndims] = 0;
-      cdf_inq_dimlen(fileID, xid, &size);
-      /*      count[ndims] = gridInqXsize(gridID); */
-      count[ndims] = size;
-      ndims++;
-    }
+              cdfSetVar(ncvars, ncvarid, TRUE);
+            }
+          else if ( (strcmp(attname, "auxiliary_variable") == 0) && xtypeIsText(atttype) )
+            {
+              int status;
+              char *varname = NULL;
+              int lstop = FALSE;
+              int dimvarid;
 
-  if ( CDI_Debug )
-    for (idim = 0; idim < ndims; idim++)
-      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              char *pstring = attstring;
 
-  if ( streamptr->ncmode == 1 )
-    {
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-    }
+              for ( int i = 0; i < MAX_AUXVARS; i++ )
+                {
+                  while ( isspace((int) *pstring) ) pstring++;
+                  if ( *pstring == 0 ) break;
+                  varname = pstring;
+                  while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
+                  if ( *pstring == 0 ) lstop = TRUE;
+                  *pstring++ = 0;
 
-  dtype = vlistInqVarDatatype(vlistID, varID);
+                  status = nc_inq_varid(ncid, varname, &dimvarid);
+                  if ( status == NC_NOERR )
+                    {
+                      cdfSetVar(ncvars, dimvarid, FALSE);
+                      //  if ( cdiIgnoreAttCoordinates == FALSE )
+                        {
+                          ncvars[ncvarid].auxvarids[i] = dimvarid;
+                          ncvars[ncvarid].nauxvars++;
+                        }
+                    }
+                  else
+                    Warning("%s - %s", nc_strerror(status), varname);
 
-  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
+                  if ( lstop ) break;
+                }
 
-  nvals = gridInqSize(gridID)*zaxisInqSize(zaxisID);
+              cdfSetVar(ncvars, ncvarid, TRUE);
+            }
+          else if ( strcmp(attname, "grid_mapping") == 0 && xtypeIsText(atttype) )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              int nc_gmap_id;
+              int status = nc_inq_varid(ncid, attstring, &nc_gmap_id);
+              if ( status == NC_NOERR )
+                {
+                  ncvars[ncvarid].gmapid = nc_gmap_id;
+                  cdfSetVar(ncvars, ncvars[ncvarid].gmapid, FALSE);
+                }
+              else
+                Warning("%s - %s", nc_strerror(status), attstring);
 
-  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
+              cdfSetVar(ncvars, ncvarid, TRUE);
+            }
+          else if ( strcmp(attname, "positive") == 0 && xtypeIsText(atttype) )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              strtolower(attstring);
 
-}
+              if    ( memcmp(attstring, "down", 4) == 0 ) ncvars[ncvarid].positive = POSITIVE_DOWN;
+              else if ( memcmp(attstring, "up", 2) == 0 ) ncvars[ncvarid].positive = POSITIVE_UP;
 
+              if ( ncvars[ncvarid].ndims == 1 )
+                {
+                  cdfSetVar(ncvars, ncvarid, FALSE);
+                  cdfSetDim(ncvars, ncvarid, 0, Z_AXIS);
+                  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Z_AXIS;
+                }
+            }
+          else if ( strcmp(attname, "_FillValue") == 0 && !xtypeIsText(atttype) )
+            {
+	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].fillval);
+	      ncvars[ncvarid].deffillval = TRUE;
+	      /* cdfSetVar(ncvars, ncvarid, TRUE); */
+            }
+          else if ( strcmp(attname, "missing_value") == 0 && !xtypeIsText(atttype) )
+            {
+	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].missval);
+	      ncvars[ncvarid].defmissval = TRUE;
+	      /* cdfSetVar(ncvars, ncvarid, TRUE); */
+            }
+          else if ( strcmp(attname, "valid_range") == 0 && attlen == 2 )
+            {
+              if ( ncvars[ncvarid].lvalidrange == FALSE )
+                {
+                  extern int cdiIgnoreValidRange;
+                  int lignore = FALSE;
+                  if ( xtypeIsFloat(atttype) != xtypeIsFloat(xtype) ) lignore = TRUE;
+                  if ( cdiIgnoreValidRange == FALSE && lignore == FALSE )
+                    {
+                      cdfGetAttDouble(ncid, ncvarid, attname, 2, ncvars[ncvarid].validrange);
+                      ncvars[ncvarid].lvalidrange = TRUE;
+                      if ( ((int)ncvars[ncvarid].validrange[0]) == 0 && ((int)ncvars[ncvarid].validrange[1]) == 255 )
+                        ncvars[ncvarid].lunsigned = TRUE;
+                      /* cdfSetVar(ncvars, ncvarid, TRUE); */
+                    }
+                  else if ( lignore )
+                    {
+                      Warning("Inconsistent data type for attribute %s:valid_range, ignored!", name);
+                    }
+                }
+            }
+          else if ( strcmp(attname, "valid_min") == 0 && attlen == 1 )
+            {
+              if ( ncvars[ncvarid].lvalidrange == FALSE )
+                {
+                  extern int cdiIgnoreValidRange;
+                  int lignore = FALSE;
+                  if ( xtypeIsFloat(atttype) != xtypeIsFloat(xtype) ) lignore = TRUE;
+                  if ( cdiIgnoreValidRange == FALSE && lignore == FALSE )
+                    {
+                      cdfGetAttDouble(ncid, ncvarid, attname, 1, &(ncvars[ncvarid].validrange)[0]);
+                      ncvars[ncvarid].lvalidrange = TRUE;
+                    }
+                  else if ( lignore )
+                    {
+                      Warning("Inconsistent data type for attribute %s:valid_min, ignored!", name);
+                    }
+                }
+            }
+          else if ( strcmp(attname, "valid_max") == 0 && attlen == 1 )
+            {
+              if ( ncvars[ncvarid].lvalidrange == FALSE )
+                {
+                  extern int cdiIgnoreValidRange;
+                  int lignore = FALSE;
+                  if ( xtypeIsFloat(atttype) != xtypeIsFloat(xtype) ) lignore = TRUE;
+                  if ( cdiIgnoreValidRange == FALSE && lignore == FALSE )
+                    {
+                      cdfGetAttDouble(ncid, ncvarid, attname, 1, &(ncvars[ncvarid].validrange)[1]);
+                      ncvars[ncvarid].lvalidrange = TRUE;
+                    }
+                  else if ( lignore )
+                    {
+                      Warning("Inconsistent data type for attribute %s:valid_max, ignored!", name);
+                    }
+                }
+            }
+          else if ( strcmp(attname, "_Unsigned") == 0 && xtypeIsText(atttype) )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+              strtolower(attstring);
 
-void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
-                         const int rect[][2], const void *data, int nmiss)
-{
-  int fileID;
-  int gridID;
-  int zaxisID;
-  int xid = UNDEFID, yid = UNDEFID, zid = UNDEFID;
-  int ncvarid;
-  size_t xsize = 0, ysize = 0;
-  size_t start[5];
-  size_t count[5];
-  long nvals;
-  int swapxy = FALSE;
-  int ndims = 0;
-  int idim;
-  int tsteptype;
-  int gridindex, zaxisindex;
-  int dtype;
-  int vlistID;
-  int streamID = streamptr->self;
+              if ( memcmp(attstring, "true", 4) == 0 )
+                {
+                  ncvars[ncvarid].lunsigned = TRUE;
+                  /*
+                  ncvars[ncvarid].lvalidrange = TRUE;
+                  ncvars[ncvarid].validrange[0] = 0;
+                  ncvars[ncvarid].validrange[1] = 255;
+                  */
+                }
+	      /* cdfSetVar(ncvars, ncvarid, TRUE); */
+            }
+          else if ( strcmp(attname, "cdi") == 0 && xtypeIsText(atttype) )
+            {
+	      cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+	      strtolower(attstring);
 
-  if ( CDI_Debug )
-    Message("streamID = %d  varID = %d", streamID, varID);
+	      if ( memcmp(attstring, "ignore", 6) == 0 )
+		{
+		  ncvars[ncvarid].ignore = TRUE;
+		  cdfSetVar(ncvars, ncvarid, FALSE);
+		}
+            }
+          else if ( strcmp(attname, "axis") == 0 && xtypeIsText(atttype) )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+	      attlen = strlen(attstring);
 
-  vlistID = streamInqVlist(streamID);
-  fileID  = streamInqFileID(streamID);
+	      if ( (int) attlen > nvdims && nvdims > 0 && attlen > 1 )
+		{
+		    Warning("Unexpected axis attribute length for %s, ignored!", name);
+		}
+              else if ( nvdims == 0 && attlen == 1 )
+                {
+                  if ( attstring[0] == 'z' || attstring[0] == 'Z' )
+                    {
+                      cdfSetVar(ncvars, ncvarid, FALSE);
+                      ncvars[ncvarid].islev = TRUE;
+                    }
+                }
+	      else
+		{
+		  strtolower(attstring);
+                  int i;
+		  for ( i = 0; i < (int)attlen; ++i )
+		    {
+		      if ( attstring[i] != '-' && attstring[i] != 't' && attstring[i] != 'z' &&
+			   attstring[i] != 'y' && attstring[i] != 'x' )
+			{
+			  Warning("Unexpected character in axis attribute for %s, ignored!", name);
+			  break;
+			}
+		    }
 
-  long ntsteps = streamptr->ntsteps;
-  if ( CDI_Debug )
-    Message("ntsteps = %ld", ntsteps);
+		  if ( i == (int) attlen && (int) attlen == nvdims )
+		    {
+		      while ( attlen-- )
+			{
+			  if ( (int) attstring[attlen] == 't' )
+			    {
+			      if ( attlen != 0 ) Warning("axis attribute 't' not on first position");
+			      cdfSetDim(ncvars, ncvarid, (int)attlen, T_AXIS);
+			    }
+			  else if ( (int) attstring[attlen] == 'z' )
+			    {
+                              ncvars[ncvarid].zdim = dimidsp[attlen];
+                              cdfSetDim(ncvars, ncvarid, (int)attlen, Z_AXIS);
 
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
+                              if ( ncvars[ncvarid].ndims == 1 )
+                                {
+                                  cdfSetVar(ncvars, ncvarid, FALSE);
+                                  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Z_AXIS;
+                                }
+			    }
+			  else if ( (int) attstring[attlen] == 'y' )
+			    {
+			      ncvars[ncvarid].ydim = dimidsp[attlen];
+			      cdfSetDim(ncvars, ncvarid, (int)attlen, Y_AXIS);
 
-  ncvarid = cdfDefVar(streamptr, varID);
+			      if ( ncvars[ncvarid].ndims == 1 )
+				{
+				  cdfSetVar(ncvars, ncvarid, FALSE);
+				  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Y_AXIS;
+				}
+			    }
+			  else if ( (int) attstring[attlen] == 'x' )
+			    {
+			      ncvars[ncvarid].xdim = dimidsp[attlen];
+			      cdfSetDim(ncvars, ncvarid, (int)attlen, X_AXIS);
 
-  gridID    = vlistInqVarGrid(vlistID, varID);
-  zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  tsteptype = vlistInqVarTsteptype(vlistID, varID);
+			      if ( ncvars[ncvarid].ndims == 1 )
+				{
+				  cdfSetVar(ncvars, ncvarid, FALSE);
+				  ncdims[ncvars[ncvarid].dimids[0]].dimtype = X_AXIS;
+				}
+			    }
+			}
+		    }
+		}
+	    }
+	  else if ( ( strcmp(attname, "realization") == 0 )         ||
+	            ( strcmp(attname, "ensemble_members") == 0 )    ||
+	            ( strcmp(attname, "forecast_init_type") == 0 )    )
+	    {
+	      int temp;
 
-  gridindex = vlistGridIndex(vlistID, gridID);
-  if ( gridInqType(gridID) == GRID_TRAJECTORY )
-    {
-      cdfWriteGridTraj(streamptr, gridID);
-    }
-  else
-    {
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
-    }
+	      if( ncvars[ncvarid].ensdata == NULL )
+		ncvars[ncvarid].ensdata = (ensinfo_t *) Malloc( sizeof( ensinfo_t ) );
 
-  zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-  zid = streamptr->zaxisID[zaxisindex];
+	      cdfGetAttInt(ncid, ncvarid, attname, 1, &temp);
 
-  if ( tsteptype != TSTEP_CONSTANT )
-    {
-      start[ndims] = (size_t)ntsteps - 1;
-      count[ndims] = 1;
-      ndims++;
-    }
-  if ( zid != UNDEFID )
-    {
-      int size = zaxisInqSize(zaxisID);
-      xassert(rect[2][0] >= 0 && rect[2][0] <= rect[2][1]
-              && rect[2][1] <= size);
-      start[ndims] = (size_t)rect[2][0];
-      count[ndims] = (size_t)rect[2][1] - (size_t)rect[2][0] + 1;
-      ndims++;
-    }
-  if ( yid != UNDEFID )
-    {
-      size_t size;
-      cdf_inq_dimlen(fileID, yid, &size);
-      xassert(rect[1][0] >= 0 && rect[1][0] <= rect[1][1]
-              && (size_t)rect[1][1] <= size);
-      start[ndims] = (size_t)rect[1][0];
-      count[ndims] = (size_t)rect[1][1] - (size_t)rect[1][0] + 1;
-      ndims++;
-    }
-  if ( xid != UNDEFID )
-    {
-      size_t size;
-      cdf_inq_dimlen(fileID, xid, &size);
-      xassert(rect[0][0] >= 0 && rect[0][0] <= rect[0][1]
-              && (size_t)rect[0][1] <= size);
-      start[ndims] = (size_t)rect[0][0];
-      count[ndims] = (size_t)rect[0][1] - (size_t)rect[0][0] + 1;
-      ndims++;
-    }
+	      if( strcmp(attname, "realization") == 0 )
+		ncvars[ncvarid].ensdata->ens_index = temp;
+	      else if( strcmp(attname, "ensemble_members") == 0 )
+		ncvars[ncvarid].ensdata->ens_count = temp;
+	      else if( strcmp(attname, "forecast_init_type") == 0 )
+		ncvars[ncvarid].ensdata->forecast_init_type = temp;
 
-  if ( CDI_Debug )
-    for (idim = 0; idim < ndims; idim++)
-      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
+	      cdfSetVar(ncvars, ncvarid, TRUE);
+	    }
+	  else
+	    {
+	      if ( ncvars[ncvarid].natts == 0 )
+		ncvars[ncvarid].atts
+                  = (int *) Malloc((size_t)nvatts * sizeof (int));
 
-  if ( streamptr->ncmode == 1 )
-    {
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+	      ncvars[ncvarid].atts[ncvars[ncvarid].natts++] = iatt;
+	      /*
+	      int attrint;
+	      double attrflt;
+	      nc_type attrtype;
+	      cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
+	      cdf_inq_atttype(ncid, ncvarid, attname, &attrtype);
+	      if ( attlen == 1 && (attrtype == NC_INT || attrtype == NC_SHORT) )
+		{
+		  cdfGetAttInt(ncid, ncvarid, attname, 1, &attrint);
+		  printf("int: %s.%s = %d\n", ncvars[ncvarid].name, attname, attrint);
+		}
+	      else if ( attlen == 1 && (attrtype == NC_FLOAT || attrtype == NC_DOUBLE) )
+		{
+		  cdfGetAttDouble(ncid, ncvarid, attname, 1, &attrflt);
+		  printf("flt: %s.%s = %g\n", ncvars[ncvarid].name, attname, attrflt);
+		}
+	      else if ( attrtype == NC_CHAR )
+		{
+		  cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+		  attstring[attlen] = 0;
+		  printf("txt: %s.%s = %s\n", ncvars[ncvarid].name, attname, attstring);
+		}
+	      else
+		printf("att: %s.%s = unknown\n", ncvars[ncvarid].name, attname);
+	      */
+	    }
+	}
     }
 
-  dtype = vlistInqVarDatatype(vlistID, varID);
-
-  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
-
-  nvals = gridInqSize(gridID)*zaxisInqSize(zaxisID);
-
-  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals,
-                     xsize, ysize, swapxy, start, count, memtype, data, nmiss);
+  for ( int i = 0; i < max_check_vars; ++i ) if ( checked_vars[i] ) Free(checked_vars[i]);
 }
 
 static
-size_t min_size(size_t a, size_t b)
+void setDimType(int nvars, ncvar_t *ncvars, ncdim_t *ncdims)
 {
-  return a < b ? a : b;
-}
+  int ndims;
+  int ncvarid, ncdimid;
+  int i;
 
-static
-void transpose2dArrayDP(size_t inWidth, size_t inHeight, double* data)
-{
-  const size_t cacheBlockSize = 256;    // Purely an optimization parameter. Current value of 32 means we are handling 8kB blocks,
-                                       // which should be a decent compromise on many architectures.
-  
-#ifdef __cplusplus
-  double *temp[inHeight];
-  double *out[inWidth];
-  
-  temp[0] =  (double *) Malloc(inHeight * inWidth * sizeof(double));
-  out[0] = data;
-  
-  for(int i = 0; i < inWidth; i++)
-  {
-    out[i] = out[0] + (inHeight * i);
-  }
+  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].isvar == TRUE )
+	{
+	  int lxdim = 0, lydim = 0, lzdim = 0/* , ltdim = 0 */;
+	  ndims = ncvars[ncvarid].ndims;
+	  for ( i = 0; i < ndims; i++ )
+	    {
+	      ncdimid = ncvars[ncvarid].dimids[i];
+	      if      ( ncdims[ncdimid].dimtype == X_AXIS ) cdfSetDim(ncvars, ncvarid, i, X_AXIS);
+	      else if ( ncdims[ncdimid].dimtype == Y_AXIS ) cdfSetDim(ncvars, ncvarid, i, Y_AXIS);
+	      else if ( ncdims[ncdimid].dimtype == Z_AXIS ) cdfSetDim(ncvars, ncvarid, i, Z_AXIS);
+	      else if ( ncdims[ncdimid].dimtype == T_AXIS ) cdfSetDim(ncvars, ncvarid, i, T_AXIS);
+	    }
 
-  for(int i = 1; i < inHeight; i++)
-  {
-    temp[i] = temp[0] + (inWidth * i);
-  }
-  memcpy(temp[0], data, inHeight * inWidth * sizeof(double));
-#else
-  double (*temp)[inWidth] = (double (*)[inWidth]) Malloc(inHeight*sizeof(*temp));
-  double (*out)[inHeight] = (double (*)[inHeight])data;
-  memcpy(temp, data, inHeight*sizeof(*temp));
-#endif
-  
-  /*
-  for ( size_t y = 0; y < inHeight; ++y )
-    for ( size_t x = 0; x < inWidth; ++x )
-      out[x][y] = temp[y][x];
-  */
+	  if ( CDI_Debug )
+	    {
+	      Message("var %d %s", ncvarid, ncvars[ncvarid].name);
+	      for ( i = 0; i < ndims; i++ )
+		printf("  dim%d type=%d  ", i, ncvars[ncvarid].dimtype[i]);
+	      printf("\n");
+	    }
 
-  for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
-    {
-      for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
-        {
-          for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
+	  for ( i = 0; i < ndims; i++ )
+	    {
+	      if      ( ncvars[ncvarid].dimtype[i] == X_AXIS ) lxdim = TRUE;
+	      else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) lydim = TRUE;
+	      else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) lzdim = TRUE;
+	      /* else if ( ncvars[ncvarid].dimtype[i] == T_AXIS ) ltdim = TRUE; */
+	    }
+
+          if ( lxdim == FALSE && ncvars[ncvarid].xvarid != UNDEFID )
             {
-              for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
-                {
-                  out[x][y] = temp[y][x];
-                }
+              if (  ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = TRUE;
             }
-        }
-    }
 
-  Free(temp[0]);
+          if ( lydim == FALSE && ncvars[ncvarid].yvarid != UNDEFID )
+            {
+              if (  ncvars[ncvars[ncvarid].yvarid].ndims == 0 ) lydim = TRUE;
+            }
+
+          //   if ( ndims > 1 )
+            for ( i = ndims-1; i >= 0; i-- )
+              {
+                if ( ncvars[ncvarid].dimtype[i] == -1 )
+                  {
+                    if ( lxdim == FALSE )
+                      {
+                        cdfSetDim(ncvars, ncvarid, i, X_AXIS);
+                        lxdim = TRUE;
+                      }
+                    else if ( lydim == FALSE && ncvars[ncvarid].gridtype != GRID_UNSTRUCTURED )
+                      {
+                        cdfSetDim(ncvars, ncvarid, i, Y_AXIS);
+                        lydim = TRUE;
+                      }
+                    else if ( lzdim == FALSE )
+                      {
+                        cdfSetDim(ncvars, ncvarid, i, Z_AXIS);
+                        lzdim = TRUE;
+                      }
+                  }
+              }
+	}
+    }
 }
 
+/* verify coordinate vars - first scan (dimname == varname) */
 static
-void transpose2dArraySP(size_t inWidth, size_t inHeight, float* data)
+void verify_coordinate_vars_1(int ncid, int ndims, ncdim_t *ncdims, ncvar_t *ncvars, int timedimid)
 {
-  const size_t cacheBlockSize = 256;    // Purely an optimization parameter. Current value of 32 means we are handling 8kB blocks,
-                                       // which should be a decent compromise on many architectures.
-  
-#ifndef __cplusplus 
-  float (*temp)[inWidth] = (float (*)[inWidth]) Malloc(inHeight*sizeof(*temp));
-  float (*out)[inHeight] = (float (*)[inHeight])data;
-  memcpy(temp, data, inHeight*sizeof(*temp));
-  #else
-  float *temp[inWidth];
-  temp[0] =  (float *) Malloc(inWidth * inHeight * sizeof(float));
-  for(int i = 1; i < inHeight; i++)
-  {
-    temp[i] = temp[0] + (inWidth * i);
-  }
+  int ncdimid, ncvarid;
 
-  float **out = (float **)data;
-#endif
-  
-  /*
-  for ( size_t y = 0; y < inHeight; ++y )
-    for ( size_t x = 0; x < inWidth; ++x )
-      out[x][y] = temp[y][x];
-  */
-  
-  for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
+  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
     {
-      for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
-        {
-          for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
-            {
-              for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
+      ncvarid = ncdims[ncdimid].ncvarid;
+      if ( ncvarid != -1 )
+	{
+	  if ( ncvars[ncvarid].dimids[0] == timedimid )
+	    {
+              ncvars[ncvarid].istime = TRUE;
+	      ncdims[ncdimid].dimtype = T_AXIS;
+	      continue;
+	    }
+
+          if ( isHybridSigmaPressureCoordinate(ncid, ncvarid, ncvars, ncdims) ) continue;
+
+	  if ( ncvars[ncvarid].units[0] != 0 )
+	    {
+	      if ( isLonAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].islon = TRUE;
+		  cdfSetVar(ncvars, ncvarid, FALSE);
+		  cdfSetDim(ncvars, ncvarid, 0, X_AXIS);
+		  ncdims[ncdimid].dimtype = X_AXIS;
+		}
+	      else if ( isLatAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].islat = TRUE;
+		  cdfSetVar(ncvars, ncvarid, FALSE);
+		  cdfSetDim(ncvars, ncvarid, 0, Y_AXIS);
+		  ncdims[ncdimid].dimtype = Y_AXIS;
+		}
+	      else if ( unitsIsPressure(ncvars[ncvarid].units) )
+		{
+		  ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
+		}
+	      else if ( strcmp(ncvars[ncvarid].units, "level") == 0 || strcmp(ncvars[ncvarid].units, "1") == 0 )
+		{
+		  if      ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer midpoints") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
+		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at midpoints", 25) == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
+		  else if ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer interfaces") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
+		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at interfaces", 26) == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
+		  else if ( strcmp(ncvars[ncvarid].units, "level") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_GENERIC;
+		}
+	      else if ( isDBLAxis(ncvars[ncvarid].longname) )
                 {
-                  out[x][y] = temp[y][x];
-                }
+                  ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
+		}
+	      else if ( unitsIsHeight(ncvars[ncvarid].units) )
+		{
+		  if ( isDepthAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
+		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
+		  else if ( isHeightAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HEIGHT;
+		}
+	    }
+          else
+            {
+              if ( (strcmp(ncvars[ncvarid].longname, "generalized_height") == 0 ||
+                    strcmp(ncvars[ncvarid].longname, "generalized height") == 0) &&
+                   strcmp(ncvars[ncvarid].stdname, "height") == 0 )
+                  ncvars[ncvarid].zaxistype = ZAXIS_REFERENCE;
             }
-        }
-    }
 
-  Free(temp);
+	  if ( ncvars[ncvarid].islon == FALSE && ncvars[ncvarid].longname[0] != 0 &&
+               ncvars[ncvarid].islat == FALSE && ncvars[ncvarid].longname[1] != 0 )
+	    {
+	      if ( memcmp(ncvars[ncvarid].longname+1, "ongitude", 8) == 0 )
+		{
+		  ncvars[ncvarid].islon = TRUE;
+		  cdfSetVar(ncvars, ncvarid, FALSE);
+		  cdfSetDim(ncvars, ncvarid, 0, X_AXIS);
+		  ncdims[ncdimid].dimtype = X_AXIS;
+		  continue;
+		}
+	      else if ( memcmp(ncvars[ncvarid].longname+1, "atitude", 7) == 0 )
+		{
+		  ncvars[ncvarid].islat = TRUE;
+		  cdfSetVar(ncvars, ncvarid, FALSE);
+		  cdfSetDim(ncvars, ncvarid, 0, Y_AXIS);
+		  ncdims[ncdimid].dimtype = Y_AXIS;
+		  continue;
+		}
+	    }
+
+	  if ( ncvars[ncvarid].zaxistype != UNDEFID )
+	    {
+              ncvars[ncvarid].islev = TRUE;
+	      cdfSetVar(ncvars, ncvarid, FALSE);
+	      cdfSetDim(ncvars, ncvarid, 0, Z_AXIS);
+	      ncdims[ncdimid].dimtype = Z_AXIS;
+	    }
+	}
+    }
 }
 
+/* verify coordinate vars - second scan (all other variables) */
 static
-void cdfInqDimIds(stream_t *streamptr, int varId, int (*outDimIds)[3])
+void verify_coordinate_vars_2(int nvars, ncvar_t *ncvars)
 {
-  int gridId = vlistInqVarGrid(streamptr->vlistID, varId);
-  int gridindex = vlistGridIndex(streamptr->vlistID, gridId);
+  int ncvarid;
 
-  (*outDimIds)[0] = (*outDimIds)[1] = (*outDimIds)[2] = UNDEFID;
-  switch ( gridInqType(gridId) )
+  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-      case GRID_TRAJECTORY:
-        cdfReadGridTraj(streamptr, gridId);
-        break;
-
-      case GRID_UNSTRUCTURED:
-        (*outDimIds)[0] = streamptr->xdimID[gridindex];
-        break;
+      if ( ncvars[ncvarid].isvar == 0 )
+	{
+	  if ( ncvars[ncvarid].units[0] != 0 )
+	    {
+	      if ( isLonAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].islon = TRUE;
+		  continue;
+		}
+	      else if ( isLatAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].islat = TRUE;
+		  continue;
+		}
+	      else if ( unitsIsPressure(ncvars[ncvarid].units) )
+		{
+		  ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
+		  continue;
+		}
+	      else if ( strcmp(ncvars[ncvarid].units, "level") == 0 || strcmp(ncvars[ncvarid].units, "1") == 0 )
+		{
+		  if      ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer midpoints") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
+		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at midpoints", 25) == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
+		  else if ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer interfaces") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
+		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at interfaces", 26) == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
+		  else if ( strcmp(ncvars[ncvarid].units, "level") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_GENERIC;
+		  continue;
+		}
+	      else if ( isDBLAxis(ncvars[ncvarid].longname) )
+		{
+                  ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
+		  continue;
+		}
+	      else if ( unitsIsHeight(ncvars[ncvarid].units) )
+		{
+		  if ( isDepthAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
+		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
+		  else if ( isHeightAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HEIGHT;
+		  continue;
+		}
+            }
 
-      default:
-        (*outDimIds)[0] = streamptr->xdimID[gridindex];
-        (*outDimIds)[1] = streamptr->ydimID[gridindex];
-        break;
+	  /* not needed anymore for rotated grids */
+	  if ( ncvars[ncvarid].islon == FALSE && ncvars[ncvarid].longname[0] != 0 &&
+               ncvars[ncvarid].islat == FALSE && ncvars[ncvarid].longname[1] != 0 )
+	    {
+	      if ( memcmp(ncvars[ncvarid].longname+1, "ongitude", 8) == 0 )
+		{
+		  ncvars[ncvarid].islon = TRUE;
+		  continue;
+		}
+	      else if ( memcmp(ncvars[ncvarid].longname+1, "atitude", 7) == 0 )
+		{
+		  ncvars[ncvarid].islat = TRUE;
+		  continue;
+		}
+	    }
+	}
     }
-
-  int zaxisID = vlistInqVarZaxis(streamptr->vlistID, varId);
-  int zaxisindex = vlistZaxisIndex(streamptr->vlistID, zaxisID);
-  (*outDimIds)[2] = streamptr->zaxisID[zaxisindex];
 }
 
+#if defined (PROJECTION_TEST)
 static
-int cdfGetSkipDim(int fileId, int ncvarid, int (*dimIds)[3])
+void copy_numeric_projatts(int gridID, int ncvarID, int ncfileID)
 {
-  if((*dimIds)[0] != UNDEFID) return 0;
-  if((*dimIds)[1] != UNDEFID) return 0;
-  int nvdims;
-  cdf_inq_varndims(fileId, ncvarid, &nvdims);
-  if(nvdims != 3) return 0;
+  int iatt, nvatts;
+  size_t attlen;
+  char attname[CDI_MAX_NAME];
+  nc_type xtype;
 
-  int varDimIds[3];
-  cdf_inq_vardimid(fileId, ncvarid, varDimIds);
-  size_t size = 0;
-  if ( (*dimIds)[2] == varDimIds[2] )
-    {
-      cdf_inq_dimlen(fileId, varDimIds[1], &size);
-      if ( size == 1 ) return 1;
-    }
-  else if ( (*dimIds)[2] == varDimIds[1] )
+  cdf_inq_varnatts(ncfileID, ncvarID, &nvatts);
+
+  for ( iatt = 0; iatt < nvatts; iatt++ )
     {
-      cdf_inq_dimlen(fileId, varDimIds[2], &size);
-      if ( size == 1 ) return 2;
+      cdf_inq_attname(ncfileID, ncvarID, iatt, attname);
+      cdf_inq_atttype(ncfileID, ncvarID, attname, &xtype);
+      cdf_inq_attlen(ncfileID, ncvarID, attname, &attlen);
+
+      //  printf("%s %d\n", attname, (int)attlen);
     }
-  return 0;
-}
 
+}
+#endif
 
 static
-void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, bool *outSwapXY, size_t (*start)[4], size_t (*count)[4])
+void grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
 {
-  int tsID = streamptr->curTsID;
-  if ( CDI_Debug ) Message("tsID = %d", tsID);
-
-  int fileId = streamptr->fileID;
-  int vlistId = streamptr->vlistID;
-  int ncvarid = streamptr->vars[varId].ncvarid;
+  if ( ncvar->chunked )
+    {
+      int ndims = ncvar->ndims;
 
-  int gridId = vlistInqVarGrid(vlistId, varId);
-  int tsteptype = vlistInqVarTsteptype(vlistId, varId);
-  int gridsize = gridInqSize(gridId);
+      if ( grid->type == GRID_UNSTRUCTURED )
+        {
+          if ( ncvar->chunks[ndims-1] == grid->size )
+            ncvar->chunktype = CHUNK_GRID;
+          else
+            ncvar->chunktype = CHUNK_AUTO;
+        }
+      else
+        {
+          if ( grid->xsize > 1 && grid->ysize > 1 && ndims > 1 &&
+               grid->xsize == ncvar->chunks[ndims-1] &&
+               grid->ysize == ncvar->chunks[ndims-2] )
+            ncvar->chunktype = CHUNK_GRID;
+          else if ( grid->xsize > 1 && grid->xsize == ncvar->chunks[ndims-1] )
+            ncvar->chunktype = CHUNK_LINES;
+          else
+            ncvar->chunktype = CHUNK_AUTO;
+        }
+    }
+}
 
-  streamptr->numvals += gridsize;
+static struct gridVirtTable cdfLazyGridVtable;
+static double *cdfPendingLoad;
+#ifdef HAVE_LIBPTHREAD
+static pthread_once_t cdfLazyInitialized = PTHREAD_ONCE_INIT;
+#else
+static bool cdfLazyInitialized;
+#endif
 
-  int dimIds[3];    //this array joins the old variables xid, yid, and zid
-  cdfInqDimIds(streamptr, varId, &dimIds);
+struct cdfLazyGrid
+{
+  grid_t base;
+  const struct gridVirtTable *baseVtable;
+  struct {
+    int datasetNCId, varNCId;
+  } cellAreaGet, xBoundsGet, yBoundsGet;
+  struct xyValGet {
+    double scalefactor, addoffset;
+    size_t start[3], count[3], size, dimsize;
+    int datasetNCId, varNCId;
+    short ndims;
+  } xValsGet, yValsGet;
+#ifdef HAVE_LIBPTHREAD
+  pthread_mutex_t loadSerialize;
+#endif
+};
 
-  int skipdim = cdfGetSkipDim(fileId, ncvarid, &dimIds);
+#ifdef HAVE_LIBPTHREAD
+#define lock_lazy_load(plGrid) pthread_mutex_lock(&((plGrid)->loadSerialize))
+#define unlock_lazy_load(plGrid) pthread_mutex_unlock(&((plGrid)->loadSerialize))
+#define destroy_lazy_load_lock(plGrid) pthread_mutex_destroy(&((plGrid)->loadSerialize))
+#define init_lazy_load_lock(plGrid) pthread_mutex_init(&((plGrid)->loadSerialize), NULL)
+#else
+#define lock_lazy_load(plGrid)
+#define unlock_lazy_load(plGrid)
+#define destroy_lazy_load_lock(plGrid)
+#define init_lazy_load_lock(plGrid)
+#endif
 
-  int dimorder[3];
-  vlistInqVarDimorder(vlistId, varId, &dimorder);
+static void cdfLazyGridDestroy(struct cdfLazyGrid *lazyGrid)
+{
+  lazyGrid->base.extraData = NULL;
+  if (lazyGrid->base.area == cdfPendingLoad)
+    lazyGrid->base.area = NULL;
+  if (lazyGrid->base.xvals == cdfPendingLoad)
+    lazyGrid->base.xvals = NULL;
+  if (lazyGrid->base.yvals == cdfPendingLoad)
+    lazyGrid->base.yvals = NULL;
+  if (lazyGrid->base.xbounds == cdfPendingLoad)
+    lazyGrid->base.xbounds = NULL;
+  if (lazyGrid->base.ybounds == cdfPendingLoad)
+    lazyGrid->base.ybounds = NULL;
+  destroy_lazy_load_lock(lazyGrid);
+}
 
-  *outSwapXY = (dimorder[2] == 2 || dimorder[0] == 1) && dimIds[0] != UNDEFID && dimIds[1] != UNDEFID ;
+static void cdfLazyGridDelete(grid_t *grid)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  void (*baseDestroy)(grid_t *grid) = cdfGrid->baseVtable->destroy;
+  cdfLazyGridDestroy(cdfGrid);
+  baseDestroy(grid);
+}
 
-  int ndims = 0;
+static void cdfLazyGridDestroyOnce(void)
+{
+  /*
+#ifdef HAVE_MMAP
+  size_t pgSize = cdiGetPageSize(false);
+  munmap(cdfPendingLoad, pgSize);
+#endif
+  */
+}
 
-#define addDimension(startIndex, extent) do {   \
-      (*start)[ndims] = startIndex; \
-      (*count)[ndims] = extent; \
-      ndims++; \
-  } while(0)
+static void
+cdfLazyGridDefArea(grid_t *grid, const double *area)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->area == cdfPendingLoad)
+    grid->area = NULL;
+  cdfGrid->cellAreaGet.datasetNCId = -1;
+  cdfGrid->cellAreaGet.varNCId = -1;
+  cdfGrid->baseVtable->defArea(grid, area);
+  unlock_lazy_load(cdfGrid);
+}
 
-  if ( tsteptype != TSTEP_CONSTANT ) addDimension((size_t)tsID, 1);
-  if ( skipdim == 1 ) addDimension(0, 1);
 
-  for ( int id = 0; id < 3; ++id )
+static const double *
+cdfLazyGridInqAreaPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->area == cdfPendingLoad)
     {
-      size_t size;
-      int curDimId = dimIds[dimorder[id]-1];
-      if ( curDimId == UNDEFID ) continue;
-      switch ( dimorder[id] )
-        {
-          Error("Internal errror: Malformed dimension order encountered. Please report this bug.\n");
-          case 1:
-          case 2:
-            cdf_inq_dimlen(fileId, curDimId, &size);
-            addDimension(0, size);
-            break;
+      grid->area = (double *)Malloc((size_t)grid->size * sizeof(double));
+      cdf_get_var_double(lazyGrid->cellAreaGet.datasetNCId,
+                         lazyGrid->cellAreaGet.varNCId, grid->area);
+    }
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqAreaPtr(grid);
+}
 
-          case 3:
-            addDimension((size_t)levelId, 1);
-            break;
+static void
+cdfLazyGridInqArea(grid_t *grid, double *area)
+{
+  grid->vtable->inqAreaPtr(grid);
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lazyGrid->baseVtable->inqArea(grid, area);
+}
 
-          default:
-            Error("Internal errror: Malformed dimension order encountered. Please report this bug.\n");
-        }
-    }
 
-  if ( skipdim == 2 ) addDimension(0, 1);
+static void
+cdfLazyLoadXYVals(struct xyValGet *valsGet, double **valsp)
+{
+  double *grid_vals
+    = (double *)Malloc(valsGet->size * sizeof (double));
+  *valsp = grid_vals;
+  if ( valsGet->ndims == 3 )
+    cdf_get_vara_double(valsGet->datasetNCId, valsGet->varNCId,
+                        valsGet->start, valsGet->count, grid_vals);
+  else
+    cdf_get_var_double(valsGet->datasetNCId, valsGet->varNCId, grid_vals);
+  scale_add(valsGet->size, grid_vals, valsGet->addoffset, valsGet->scalefactor);
+}
 
-  assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
-  assert(ndims <= (int)(sizeof(*count)/sizeof(**count)));
+static const double *
+cdfLazyGridInqXValsPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->xvals == cdfPendingLoad)
+    cdfLazyLoadXYVals(&lazyGrid->xValsGet, &grid->xvals);
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqXValsPtr(grid);
+}
 
-#undef addDimension
+static const double *
+cdfLazyGridInqYValsPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->yvals == cdfPendingLoad)
+    cdfLazyLoadXYVals(&lazyGrid->yValsGet, &grid->yvals);
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqYValsPtr(grid);
+}
 
-  if ( CDI_Debug )
-    for (int idim = 0; idim < ndims; idim++)
-      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
+static double
+cdfLazyGridInqXYVal(grid_t *grid, size_t index,
+                    const struct xyValGet *valsGet, double *vals,
+                    const double *(*inqValsPtr)(grid_t *gridptr))
+{
+  size_t size = valsGet->size;
+  double v;
+  if ( vals == cdfPendingLoad )
+    {
+      /* prevent full load if only first/last values get inspected */
+      if ( index == 0 || index == size - 1 )
+        {
+          size_t indexND[3];
+          if ( valsGet->ndims == 3 )
+            {
+              indexND[0] = 0;
+              indexND[1] = index / valsGet->count[2];
+              indexND[2] = index % valsGet->count[2];
+            }
+          else if ( valsGet->ndims == 2)
+            {
+              indexND[0] = index / (size_t)grid->xsize;
+              indexND[1] = index % (size_t)grid->xsize;
+            }
+          else
+            indexND[0] = index;
+          cdf_get_var1_double(valsGet->datasetNCId, valsGet->varNCId,
+                              indexND, &v);
+        }
+      else
+        {
+          const double *grid_vals = inqValsPtr(grid);
+          v = grid_vals[index];
+        }
+    }
+  else if ( vals )
+    v = vals[index];
+  else
+    v = 0.0;
+  return v;
+}
 
-  int nvdims;
-  cdf_inq_varndims(fileId, ncvarid, &nvdims);
+static void
+cdfLazyGridDefXVals(grid_t *grid, const double *vals)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->xvals == cdfPendingLoad)
+    grid->xvals = NULL;
+  cdfGrid->xValsGet.datasetNCId = -1;
+  cdfGrid->xValsGet.varNCId = -1;
+  cdfGrid->baseVtable->defXVals(grid, vals);
+  unlock_lazy_load(cdfGrid);
+}
 
-  if ( nvdims != ndims )
-    Error("Internal error, variable %s has an unsupported array structure!", vlistInqVarNamePtr(vlistId, varId));
+static void
+cdfLazyGridDefYVals(grid_t *grid, const double *vals)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->yvals == cdfPendingLoad)
+    grid->yvals = NULL;
+  cdfGrid->yValsGet.datasetNCId = -1;
+  cdfGrid->yValsGet.varNCId = -1;
+  cdfGrid->baseVtable->defYVals(grid, vals);
+  unlock_lazy_load(cdfGrid);
 }
 
+static double
+cdfLazyGridInqXVal(grid_t *grid, int index)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  double rv = cdfLazyGridInqXYVal(grid, (size_t)index, &lazyGrid->xValsGet,
+                                  grid->xvals, grid->vtable->inqXValsPtr);
+  unlock_lazy_load(lazyGrid);
+  return rv;
+}
 
-void cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+static double
+cdfLazyGridInqYVal(grid_t *grid, int index)
 {
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  double rv = cdfLazyGridInqXYVal(grid, (size_t)index, &lazyGrid->yValsGet,
+                                  grid->yvals, grid->vtable->inqYValsPtr);
+  unlock_lazy_load(lazyGrid);
+  return rv;
+}
 
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
+static int
+cdfLazyXYValGetCompare(struct cdfLazyGrid *lazyGridRef,
+                       struct cdfLazyGrid *lazyGridTest)
+{
+  struct xyValGet *valsGetXRef = &lazyGridRef->xValsGet,
+    *valsGetYRef = &lazyGridRef->yValsGet,
+    *valsGetXTest = &lazyGridTest->xValsGet,
+    *valsGetYTest = &lazyGridTest->yValsGet;
+  if (valsGetXRef->datasetNCId == -1
+      || valsGetXTest->datasetNCId == -1
+      || valsGetYRef->datasetNCId == -1
+      || valsGetYTest->datasetNCId == -1)
+    return lazyGridRef->baseVtable->compareXYFull(&lazyGridRef->base,
+                                                  &lazyGridTest->base);
+  return valsGetXRef->datasetNCId != valsGetXTest->datasetNCId
+    ||   valsGetXRef->varNCId     != valsGetXTest->varNCId
+    ||   valsGetYRef->datasetNCId != valsGetYTest->datasetNCId
+    ||   valsGetYRef->varNCId     != valsGetYTest->varNCId;
+}
 
-  int ncvarid = streamptr->vars[varID].ncvarid;
+static int
+cdfLazyCompareXYFull(grid_t *gridRef, grid_t *gridTest)
+{
+  int diff;
+  struct cdfLazyGrid *lazyGridRef = (struct cdfLazyGrid *)gridRef;
+  if (gridTest->vtable == &cdfLazyGridVtable)
+    diff = cdfLazyXYValGetCompare(lazyGridRef, (struct cdfLazyGrid *)gridTest);
+  else
+    diff = lazyGridRef->baseVtable->compareXYFull(gridRef, gridTest);
+  return diff;
+}
 
-  int gridID  = vlistInqVarGrid(vlistID, varID);
-  int zaxisID = vlistInqVarZaxis(vlistID, varID);
+static int
+cdfLazyCompareXYAO(grid_t *gridRef, grid_t *gridTest)
+{
+  int diff;
+  struct cdfLazyGrid *lazyGridRef = (struct cdfLazyGrid *)gridRef;
+  if (gridTest->vtable == &cdfLazyGridVtable)
+    diff = cdfLazyXYValGetCompare(lazyGridRef, (struct cdfLazyGrid *)gridTest);
+  else
+    diff = lazyGridRef->baseVtable->compareXYAO(gridRef, gridTest);
+  return diff;
+}
 
-  size_t start[4];
-  size_t count[4];
-  cdfGetSlapDescription(streamptr, varID, &start, &count);
 
-  cdf_get_vara_double(fileID, ncvarid, start, count, data);
+static const double *
+cdfLazyGridInqXBoundsPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->xbounds == cdfPendingLoad)
+    {
+      grid->xbounds = (double *)Malloc((size_t)grid->nvertex
+                                       * (size_t)grid->size * sizeof(double));
+      cdf_get_var_double(lazyGrid->xBoundsGet.datasetNCId,
+                         lazyGrid->xBoundsGet.varNCId, grid->xbounds);
+    }
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqXBoundsPtr(grid);
+}
 
-  size_t size = (size_t)gridInqSize(gridID)*(size_t)zaxisInqSize(zaxisID);
-  double missval = vlistInqVarMissval(vlistID, varID);
-  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
-  double validRange[2];
-  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
-    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
-  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
-  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
-  size_t nmiss_ = cdfDoInputDataTransformationDP(size, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
-  assert(nmiss_ <= INT_MAX);
-  *nmiss = (int)nmiss_;
+static void
+cdfLazyGridDefXBounds(grid_t *grid, const double *xbounds)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->xbounds == cdfPendingLoad)
+    grid->xbounds = NULL;
+  cdfGrid->xBoundsGet.datasetNCId = -1;
+  cdfGrid->xBoundsGet.varNCId = -1;
+  cdfGrid->baseVtable->defXBounds(grid, xbounds);
+  unlock_lazy_load(cdfGrid);
 }
 
+static void
+cdfLazyGridDefYBounds(grid_t *grid, const double *ybounds)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->ybounds == cdfPendingLoad)
+    grid->ybounds = NULL;
+  cdfGrid->yBoundsGet.datasetNCId = -1;
+  cdfGrid->yBoundsGet.varNCId = -1;
+  cdfGrid->baseVtable->defYBounds(grid, ybounds);
+  unlock_lazy_load(cdfGrid);
+}
 
-void cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss)
+static const double *
+cdfLazyGridInqYBoundsPtr(grid_t *grid)
 {
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->ybounds == cdfPendingLoad)
+    {
+      grid->ybounds = (double *)Malloc((size_t)grid->nvertex
+                                       * (size_t)grid->size * sizeof(double));
+      cdf_get_var_double(lazyGrid->yBoundsGet.datasetNCId,
+                         lazyGrid->yBoundsGet.varNCId, grid->ybounds);
+    }
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqYBoundsPtr(grid);
+}
 
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
+static void
+cdfLazyGridCopyScalarFields(grid_t *gridptrOrig, grid_t *gridptrDup)
+{
+  struct cdfLazyGrid *lazyGridDup = (struct cdfLazyGrid *)gridptrDup,
+    *lazyGridOrig = (struct cdfLazyGrid *)gridptrOrig;
+  lazyGridOrig->baseVtable->copyScalarFields(gridptrOrig, &lazyGridDup->base);
+  lazyGridDup->baseVtable = lazyGridOrig->baseVtable;
+  lazyGridDup->cellAreaGet = lazyGridOrig->cellAreaGet;
+  lazyGridDup->xBoundsGet = lazyGridOrig->xBoundsGet;
+  lazyGridDup->yBoundsGet = lazyGridOrig->yBoundsGet;
+  lazyGridDup->xValsGet = lazyGridOrig->xValsGet;
+  lazyGridDup->yValsGet = lazyGridOrig->yValsGet;
+  init_lazy_load_lock(lazyGridDup);
+}
 
-  int ncvarid = streamptr->vars[varID].ncvarid;
+static void
+cdfLazyGridCopyArrayFields(grid_t *gridptrOrig, grid_t *gridptrDup)
+{
+  size_t nrowlon = (size_t)gridptrOrig->nrowlon;
+  size_t gridsize = (size_t)gridptrOrig->size;
+  int gridtype = gridptrOrig->type;
+  int irregular = gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED;
+  if ( nrowlon )
+    {
+      gridptrDup->rowlon = (int *)Malloc(nrowlon * sizeof (int));
+      memcpy(gridptrDup->rowlon, gridptrOrig->rowlon, nrowlon * sizeof(int));
+    }
 
-  int gridID  = vlistInqVarGrid(vlistID, varID);
-  int zaxisID = vlistInqVarZaxis(vlistID, varID);
+  if ( gridptrOrig->xvals != NULL && gridptrOrig->xvals != cdfPendingLoad )
+    {
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->xsize;
 
-  size_t start[4];
-  size_t count[4];
-  cdfGetSlapDescription(streamptr, varID, &start, &count);
+      gridptrDup->xvals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->xvals, gridptrOrig->xvals, size * sizeof (double));
+    }
 
-  cdf_get_vara_float(fileID, ncvarid, start, count, data);
+  if ( gridptrOrig->yvals != NULL && gridptrOrig->yvals != cdfPendingLoad )
+    {
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->ysize;
 
-  size_t size = (size_t)gridInqSize(gridID) * (size_t)zaxisInqSize(zaxisID);
-  double missval = vlistInqVarMissval(vlistID, varID);
-  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
-  double validRange[2];
-  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
-    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
-  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
-  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
-  size_t nmiss_ = cdfDoInputDataTransformationSP(size, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
-  assert(nmiss_ <= INT_MAX);
-  *nmiss = (int)nmiss_;
-}
+      gridptrDup->yvals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->yvals, gridptrOrig->yvals, size * sizeof (double));
+    }
 
+  if ( gridptrOrig->xbounds != NULL && gridptrOrig->xbounds != cdfPendingLoad )
+    {
+      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->xsize)
+        * (size_t)gridptrOrig->nvertex;
 
-void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data, int *nmiss)
-{
-  size_t start[4];
-  size_t count[4];
+      gridptrDup->xbounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->xbounds, gridptrOrig->xbounds, size * sizeof (double));
+    }
 
-  if ( CDI_Debug )
-    Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
+  if ( gridptrOrig->ybounds != NULL && gridptrOrig->ybounds != cdfPendingLoad )
+    {
+      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->ysize)
+        * (size_t)gridptrOrig->nvertex;
 
-  int vlistID = streamptr->vlistID;
-  int fileID = streamptr->fileID;
+      gridptrDup->ybounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->ybounds, gridptrOrig->ybounds, size * sizeof (double));
+    }
 
-  bool swapxy;
-  cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
+  {
+    if ( gridptrOrig->area != NULL && gridptrOrig->area != cdfPendingLoad )
+      {
+        size_t size = gridsize;
 
-  int ncvarid = streamptr->vars[varID].ncvarid;
-  int gridId = vlistInqVarGrid(vlistID, varID);
-  size_t gridsize = (size_t)gridInqSize(gridId);
-  size_t xsize = (size_t)gridInqXsize(gridId);
-  size_t ysize = (size_t)gridInqYsize(gridId);
+        gridptrDup->area = (double *)Malloc(size * sizeof (double));
+        memcpy(gridptrDup->area, gridptrOrig->area, size * sizeof (double));
+      }
+  }
 
-  if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT32 )
-    {
-      float *data_fp = (float *) Malloc(gridsize*sizeof(*data_fp));
-      cdf_get_vara_float(fileID, ncvarid, start, count, data_fp);
-      for ( size_t i = 0; i < gridsize; i++ )
-        data[i] = (double) data_fp[i];
-      Free(data_fp);
-    }
-  else if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
+  if ( gridptrOrig->mask != NULL )
     {
-      nc_type xtype;
-      cdf_inq_vartype(fileID, ncvarid, &xtype);
-      if ( xtype == NC_BYTE )
-        {
-          for ( size_t i = 0; i < gridsize; i++ )
-            if ( data[i] < 0 ) data[i] += 256;
-        }
+      size_t size = gridsize;
+
+      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
+      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
     }
-  else
+
+  if ( gridptrOrig->mask_gme != NULL )
     {
-      cdf_get_vara_double(fileID, ncvarid, start, count, data);
+      size_t size = gridsize;
+
+      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
+      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
     }
+}
 
-  if ( swapxy ) transpose2dArrayDP(ysize, xsize, data);
+static grid_t *
+cdfLazyGridCopy(grid_t *gridptrOrig)
+{
+  struct cdfLazyGrid *lazyGridDup
+    = (struct cdfLazyGrid *)Malloc(sizeof (*lazyGridDup));
+  gridptrOrig->vtable->copyScalarFields(gridptrOrig, &lazyGridDup->base);
+  gridptrOrig->vtable->copyArrayFields(gridptrOrig, &lazyGridDup->base);
+  return &lazyGridDup->base;
+}
 
-  double missval = vlistInqVarMissval(vlistID, varID);
-  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
-  double validRange[2];
-  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
-    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
-  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
-  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
-  size_t nmiss_ = cdfDoInputDataTransformationDP(gridsize, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
-  assert(nmiss_ <= INT_MAX);
-  *nmiss = (int)nmiss_;
+static void
+cdfLazyGridInitOnce(void)
+{
+  cdfLazyGridVtable = cdiGridVtable;
+  cdfLazyGridVtable.destroy = cdfLazyGridDelete;
+  cdfLazyGridVtable.copy = cdfLazyGridCopy;
+  cdfLazyGridVtable.copyScalarFields = cdfLazyGridCopyScalarFields;
+  cdfLazyGridVtable.copyArrayFields = cdfLazyGridCopyArrayFields;
+  cdfLazyGridVtable.defArea = cdfLazyGridDefArea;
+  cdfLazyGridVtable.inqAreaPtr = cdfLazyGridInqAreaPtr;
+  cdfLazyGridVtable.inqArea = cdfLazyGridInqArea;
+  cdfLazyGridVtable.inqXValsPtr = cdfLazyGridInqXValsPtr;
+  cdfLazyGridVtable.inqYValsPtr = cdfLazyGridInqYValsPtr;
+  cdfLazyGridVtable.inqXVal = cdfLazyGridInqXVal;
+  cdfLazyGridVtable.inqYVal = cdfLazyGridInqYVal;
+  cdfLazyGridVtable.defXVals = cdfLazyGridDefXVals;
+  cdfLazyGridVtable.defYVals = cdfLazyGridDefYVals;
+  cdfLazyGridVtable.compareXYFull = cdfLazyCompareXYFull;
+  cdfLazyGridVtable.compareXYAO = cdfLazyCompareXYAO;
+  cdfLazyGridVtable.defXBounds = cdfLazyGridDefXBounds;
+  cdfLazyGridVtable.defYBounds = cdfLazyGridDefYBounds;
+  cdfLazyGridVtable.inqXBoundsPtr = cdfLazyGridInqXBoundsPtr;
+  cdfLazyGridVtable.inqYBoundsPtr = cdfLazyGridInqYBoundsPtr;
+  /* create inaccessible memory area, if possible, this serves as
+   * dummy value for pointers to data not yet loaded */
+  /*
+#ifdef HAVE_MMAP
+  {
+    size_t pgSize = cdiGetPageSize(false);
+    static const char devZero[] = "/dev/zero";
+    int fd = open(devZero, O_RDWR);
+    if (fd == -1)
+      SysError("Could not open %s to map anonymous memory", devZero);
+    void *cdfInvalid = mmap(NULL, pgSize, PROT_NONE, MAP_PRIVATE, fd, 0);
+    if (cdfInvalid == MAP_FAILED)
+      SysError("Could not mmap anonymous memory");
+    cdfPendingLoad = cdfInvalid;
+    int rc = close(fd);
+    if (rc == -1)
+      SysError("Could not close %s file handle %d after mapping anonymous"
+               " memory", devZero, fd);
+  }
+#else
+  */
+  cdfPendingLoad = (double *)&cdfPendingLoad;
+  //#endif
+  atexit(cdfLazyGridDestroyOnce);
+#ifndef HAVE_LIBPTHREAD
+  cdfLazyInitialized = true;
+#endif
 }
 
-
-void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data, int *nmiss)
+static void
+cdfBaseGridInit(grid_t *grid, int gridtype)
 {
-  size_t start[4];
-  size_t count[4];
-
-  if ( CDI_Debug )
-    Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
-
-  int vlistID = streamptr->vlistID;
-  int fileID = streamptr->fileID;
-
-  bool swapxy;
-  cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
-
-  int ncvarid = streamptr->vars[varID].ncvarid;
-  int gridId = vlistInqVarGrid(vlistID, varID);
-  size_t gridsize = (size_t)gridInqSize(gridId);
-  size_t xsize = (size_t)gridInqXsize(gridId);
-  size_t ysize = (size_t)gridInqYsize(gridId);
-
-  if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT64 )
-    {
-      double *data_dp = (double *) Malloc(gridsize*sizeof(*data_dp));
-      cdf_get_vara_double(fileID, ncvarid, start, count, data_dp);
-      for ( size_t i = 0; i < gridsize; i++ )
-        data[i] = (float) data_dp[i];
-      Free(data_dp);
-    }
-  else if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
-    {
-      nc_type xtype;
-      cdf_inq_vartype(fileID, ncvarid, &xtype);
-      if ( xtype == NC_BYTE )
-        {
-          for ( size_t i = 0; i < gridsize; i++ )
-            if ( data[i] < 0 ) data[i] += 256;
-        }
-    }
-  else
-    {
-      cdf_get_vara_float(fileID, ncvarid, start, count, data);
-    }
-
-  if ( swapxy ) transpose2dArraySP(ysize, xsize, data);
-
-  double missval = vlistInqVarMissval(vlistID, varID);
-  bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
-  double validRange[2];
-  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
-    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
-  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
-  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
-  size_t nmiss_ = cdfDoInputDataTransformationSP(gridsize, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
-  assert(nmiss_ <= INT_MAX);
-  *nmiss = (int)nmiss_;
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, 0);
 }
 
-
-void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
+static void
+cdfLazyGridInit(struct cdfLazyGrid *grid, int gridtype)
 {
-  size_t xsize = 0, ysize = 0;
-  size_t start[5];
-  size_t count[5];
-  int dimorder[3];
-  int xid = UNDEFID, yid = UNDEFID, zid = UNDEFID;
-
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  long ntsteps = streamptr->ntsteps;
-  if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
-
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
-
-  int ncvarid = cdfDefVar(streamptr, varID);
-
-  int gridID    = vlistInqVarGrid(vlistID, varID);
-  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
-  vlistInqVarDimorder(vlistID, varID, &dimorder);
-
-
-  if ( gridInqType(gridID) == GRID_TRAJECTORY )
-    {
-      cdfWriteGridTraj(streamptr, gridID);
-    }
-  else
-    {
-      int gridindex = vlistGridIndex(vlistID, gridID);
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
-    }
-  {
-    int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-    zid = streamptr->zaxisID[zaxisindex];
-  }
-
-  int swapxy = (dimorder[2] == 2 || dimorder[0] == 1) && xid != UNDEFID && yid != UNDEFID;
-  /*
-  printf("swapxy %d\n", swapxy);
-  printf("dimorder: %d %d %d\n", dimorder[0], dimorder[1], dimorder[2]);
-  */
-
-  size_t ndims = 0;
-  if ( tsteptype != TSTEP_CONSTANT )
-    {
-      start[ndims] = (size_t)ntsteps - 1;
-      count[ndims] = 1;
-      ndims++;
-    }
-
-  for ( int id = 0; id < 3; ++id )
-    {
-      if ( dimorder[id] == 3 && zid != UNDEFID )
-        {
-          start[ndims] = (size_t)levelID;
-          count[ndims] = 1;
-          ndims++;
-        }
-      else if ( dimorder[id] == 2 && yid != UNDEFID )
-        {
-          start[ndims] = 0;
-          cdf_inq_dimlen(fileID, yid, &ysize);
-          count[ndims] = ysize;
-          ndims++;
-        }
-      else if ( dimorder[id] == 1 && xid != UNDEFID )
-        {
-          start[ndims] = 0;
-          cdf_inq_dimlen(fileID, xid, &xsize);
-          count[ndims] = xsize;
-          ndims++;
-        }
-    }
-
-  if ( CDI_Debug )
-    for (size_t idim = 0; idim < ndims; idim++)
-      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
-
-  int dtype = vlistInqVarDatatype(vlistID, varID);
-
-  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
-
-  long nvals = gridInqSize(gridID);
+#ifdef HAVE_LIBPTHREAD
+  pthread_once(&cdfLazyInitialized, cdfLazyGridInitOnce);
+#else
+  if (cdfLazyInitialized) ; else cdfLazyGridInitOnce();
+#endif
+  cdfBaseGridInit(&grid->base, gridtype);
+  grid->baseVtable = grid->base.vtable;
+  grid->cellAreaGet.datasetNCId = -1;
+  grid->cellAreaGet.varNCId = -1;
+  grid->xValsGet.datasetNCId = -1;
+  grid->xValsGet.varNCId = -1;
+  grid->yValsGet.datasetNCId = -1;
+  grid->yValsGet.varNCId = -1;
+  grid->xBoundsGet.datasetNCId = -1;
+  grid->xBoundsGet.varNCId = -1;
+  grid->yBoundsGet.datasetNCId = -1;
+  grid->yBoundsGet.varNCId = -1;
+  grid->base.vtable = &cdfLazyGridVtable;
+  init_lazy_load_lock(grid);
+}
 
-  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
+static void
+cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
+{
+  struct cdfLazyGrid *restrict grid = *gridpptr;
+  if (!grid)
+    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (*grid));
+  cdfLazyGridInit(grid, gridtype);
+}
 
+static void
+cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
+{
+  struct cdfLazyGrid *restrict grid = *gridpptr;
+  if (!grid)
+    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (grid_t));
+  cdfBaseGridInit((grid_t*)grid, gridtype);
 }
 
 
+/* define all input grids */
 static
-void cdfCreateRecords(stream_t *streamptr, int tsID)
+void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars, int timedimid, unsigned char *uuidOfHGrid, char *gridfile, int number_of_grid_used)
 {
-  int varID, levelID, recID, vrecID, zaxisID;
-  int nlev, nvrecs;
-
-  int vlistID  = streamptr->vlistID;
+  int ltwarn = TRUE;
+  struct cdfLazyGrid *restrict lazyGrid = NULL, *restrict lazyProj = NULL;
+#define grid (&lazyGrid->base)
+#define proj (&lazyProj->base)
 
-  if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
+  for ( int ncvarid = 0; ncvarid < nvars; ++ncvarid )
+    {
+      if ( ncvars[ncvarid].isvar && ncvars[ncvarid].gridID == UNDEFID )
+	{
+          int xdimids[2] = {-1,-1}, ydimids[2] = {-1,-1};
+	  int xdimid = -1, ydimid = -1;
+	  int islon = 0, islat = 0;
+	  int nxdims = 0, nydims = 0;
+          size_t size = 0;
+          size_t xsize = 0, ysize = 0;
+	  double yinc = 0;
+          struct addIffNewRes projAdded = { .Id = CDI_UNDEFID, .isNew = 0 },
+            gridAdded  = { .Id = CDI_UNDEFID, .isNew = 0 };
 
-  if ( streamptr->tsteps[tsID].nallrecs > 0 ) return;
+	  int ndims = ncvars[ncvarid].ndims;
+	  for ( int i = 0; i < ndims; i++ )
+	    {
+	      if ( ncvars[ncvarid].dimtype[i] == X_AXIS && nxdims < 2 )
+		{
+		  xdimids[nxdims] = ncvars[ncvarid].dimids[i];
+		  nxdims++;
+		}
+	      else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS && nydims < 2 )
+		{
+		  ydimids[nydims] = ncvars[ncvarid].dimids[i];
+		  nydims++;
+		}
+	    }
 
-  tsteps_t* sourceTstep = streamptr->tsteps;
-  tsteps_t* destTstep = sourceTstep + tsID;
+	  if ( nxdims == 2 )
+	    {
+	      xdimid = xdimids[1];
+	      ydimid = xdimids[0];
+	    }
+	  else if ( nydims == 2 )
+	    {
+	      xdimid = ydimids[1];
+	      ydimid = ydimids[0];
+	    }
+	  else
+	    {
+	      xdimid = xdimids[0];
+	      ydimid = ydimids[0];
+	    }
 
-  int nvars = vlistNvars(vlistID);
-  int nrecs = vlistNrecs(vlistID);
+	  int xvarid = ncvars[ncvarid].xvarid != UNDEFID
+	    ? ncvars[ncvarid].xvarid
+            : (xdimid != UNDEFID ? ncdims[xdimid].ncvarid : -1);
+          int yvarid = ncvars[ncvarid].yvarid != UNDEFID
+            ? ncvars[ncvarid].yvarid
+            : (ydimid != UNDEFID ? ncdims[ydimid].ncvarid : -1);
 
-  if ( nrecs <= 0 ) return;
+	  /*
+	  if ( xdimid != UNDEFID )
+	    xvarid = ncdims[xdimid].ncvarid;
+	  if ( xvarid == UNDEFID && ncvars[ncvarid].xvarid != UNDEFID )
+	    xvarid = ncvars[ncvarid].xvarid;
 
-  if ( tsID == 0 )
-    {
-      nvrecs = nrecs; /* use all records at first timestep */
+	  if ( ydimid != UNDEFID )
+	    yvarid = ncdims[ydimid].ncvarid;
+	  if ( yvarid == UNDEFID && ncvars[ncvarid].yvarid != UNDEFID )
+	    yvarid = ncvars[ncvarid].yvarid;
+	  */
 
-      streamptr->nrecs += nrecs;
+	  if ( xdimid != UNDEFID ) xsize = ncdims[xdimid].len;
+	  if ( ydimid != UNDEFID ) ysize = ncdims[ydimid].len;
 
-      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
-      destTstep->nrecs      = nrecs;
-      destTstep->nallrecs   = nrecs;
-      destTstep->recordSize = nrecs;
-      destTstep->curRecID   = UNDEFID;
-      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs*sizeof (int));;
-      for ( recID = 0; recID < nvrecs; recID++ ) destTstep->recIDs[recID] = recID;
+	  if ( ydimid == UNDEFID && yvarid != UNDEFID )
+	    {
+	      if ( ncvars[yvarid].ndims == 1 )
+		{
+		  ydimid = ncvars[yvarid].dimids[0];
+		  ysize  = ncdims[ydimid].len;
+		}
+	    }
 
-      record_t *records = destTstep->records;
+	  if ( ncvars[ncvarid].gridtype == UNDEFID || ncvars[ncvarid].gridtype == GRID_GENERIC )
+	    if ( xdimid != UNDEFID && xdimid == ydimid && nydims == 0 ) ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
 
-      recID = 0;
-      for ( varID = 0; varID < nvars; varID++ )
-        {
-          zaxisID = vlistInqVarZaxis(vlistID, varID);
-          nlev    = zaxisInqSize(zaxisID);
-          for ( levelID = 0; levelID < nlev; levelID++ )
+          if (CDI_netcdf_lazy_grid_load)
             {
-              recordInitEntry(&records[recID]);
-              records[recID].varID   = (short)varID;
-              records[recID].levelID = (short)levelID;
-              recID++;
+              cdfLazyGridRenew(&lazyGrid, ncvars[ncvarid].gridtype);
+              cdfLazyGridRenew(&lazyProj, GRID_PROJECTION);
             }
-        }
-    }
-  else if ( tsID == 1 )
-    {
-      nvrecs = 0;
-      for ( varID = 0; varID < nvars; varID++ )
-        {
-          if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
+          else
             {
-              zaxisID = vlistInqVarZaxis(vlistID, varID);
-              nvrecs += zaxisInqSize(zaxisID);
+              cdfBaseGridRenew(&lazyGrid, ncvars[ncvarid].gridtype);
+              cdfBaseGridRenew(&lazyProj, GRID_PROJECTION);
             }
-        }
 
-      streamptr->nrecs += nvrecs;
+	  grid->prec  = DATATYPE_FLT64;
+	  grid->trunc = ncvars[ncvarid].truncation;
 
-      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
-      destTstep->nrecs      = nvrecs;
-      destTstep->nallrecs   = nrecs;
-      destTstep->recordSize = nrecs;
-      destTstep->curRecID   = UNDEFID;
+	  if ( ncvars[ncvarid].gridtype == GRID_TRAJECTORY )
+	    {
+	      if ( ncvars[ncvarid].xvarid == UNDEFID )
+		Error("Longitude coordinate undefined for %s!", ncvars[ncvarid].name);
+	      if ( ncvars[ncvarid].yvarid == UNDEFID )
+		Error("Latitude coordinate undefined for %s!", ncvars[ncvarid].name);
+	    }
+	  else
+	    {
+	      size_t start[3], count[3];
+	      int ltgrid = FALSE;
 
-      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
+	      if ( xvarid != UNDEFID && yvarid != UNDEFID )
+		{
+		  if ( ncvars[xvarid].ndims != ncvars[yvarid].ndims )
+		    {
+		      Warning("Inconsistent grid structure for variable %s!", ncvars[ncvarid].name);
+		      ncvars[ncvarid].xvarid = UNDEFID;
+		      ncvars[ncvarid].yvarid = UNDEFID;
+		      xvarid = UNDEFID;
+		      yvarid = UNDEFID;
+		    }
 
-      if ( nvrecs )
-        {
-          destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
-          vrecID = 0;
-          for ( recID = 0; recID < nrecs; recID++ )
-            {
-              varID = destTstep->records[recID].varID;
-              if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
+		  if ( ncvars[xvarid].ndims > 2 || ncvars[yvarid].ndims > 2 )
+		    {
+		      if ( ncvars[xvarid].ndims == 3 && ncvars[xvarid].dimids[0] == timedimid &&
+			   ncvars[yvarid].ndims == 3 && ncvars[yvarid].dimids[0] == timedimid )
+			{
+			  if ( ltwarn )
+			    Warning("Time varying grids unsupported, using grid at time step 1!");
+			  ltgrid = TRUE;
+			  ltwarn = FALSE;
+			  start[0] = start[1] = start[2] = 0;
+			  count[0] = 1; count[1] = ysize; count[2] = xsize;
+			}
+		      else
+			{
+			  Warning("Unsupported grid structure for variable %s (grid dims > 2)!", ncvars[ncvarid].name);
+			  ncvars[ncvarid].xvarid = UNDEFID;
+			  ncvars[ncvarid].yvarid = UNDEFID;
+			  xvarid = UNDEFID;
+			  yvarid = UNDEFID;
+			}
+		    }
+		}
+
+              if ( xvarid != UNDEFID )
                 {
-                  destTstep->recIDs[vrecID++] = recID;
+                  if ( ncvars[xvarid].ndims > 3 || (ncvars[xvarid].ndims == 3 && ltgrid == FALSE) )
+                    {
+                      Warning("Coordinate variable %s has to many dimensions (%d), skipped!", ncvars[xvarid].name, ncvars[xvarid].ndims);
+                      //ncvars[ncvarid].xvarid = UNDEFID;
+                      xvarid = UNDEFID;
+                    }
                 }
-            }
-        }
-    }
-  else
-    {
-      if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
 
-      nvrecs = streamptr->tsteps[1].nrecs;
+              if ( yvarid != UNDEFID )
+                {
+                  if ( ncvars[yvarid].ndims > 3 || (ncvars[yvarid].ndims == 3 && ltgrid == FALSE) )
+                    {
+                      Warning("Coordinate variable %s has to many dimensions (%d), skipped!", ncvars[yvarid].name, ncvars[yvarid].ndims);
+                      //ncvars[ncvarid].yvarid = UNDEFID;
+                      yvarid = UNDEFID;
+                    }
+                }
 
-      streamptr->nrecs += nvrecs;
+              if ( xvarid != UNDEFID )
+		{
+                  bool skipvar = true;
+		  islon = ncvars[xvarid].islon;
+		  ndims = ncvars[xvarid].ndims;
+		  if ( ndims == 2 || ndims == 3 )
+		    {
+		      ncvars[ncvarid].gridtype = GRID_CURVILINEAR;
+		      size = xsize*ysize;
+		      /* Check size of 2 dimensional coordinate variables */
+                      int dimid = ncvars[xvarid].dimids[ndims-2];
+                      size_t dimsize1 = ncdims[dimid].len;
+                      dimid = ncvars[xvarid].dimids[ndims-1];
+                      size_t dimsize2 = ncdims[dimid].len;
+                      skipvar = dimsize1*dimsize2 != size;
+		    }
+		  else if ( ndims == 1 )
+		    {
+		      size = xsize;
+		      /* Check size of 1 dimensional coordinate variables */
+                      int dimid = ncvars[xvarid].dimids[0];
+                      size_t dimsize = ncdims[dimid].len;
+                      skipvar = dimsize != size;
+		    }
+		  else if ( ndims == 0 && xsize == 0 )
+		    {
+                      size = xsize = 1;
+                      skipvar = false;
+		    }
 
-      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
-      destTstep->nrecs      = nvrecs;
-      destTstep->nallrecs   = nrecs;
-      destTstep->recordSize = nrecs;
-      destTstep->curRecID   = UNDEFID;
+                  if ( skipvar )
+                    {
+                      Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
+                      ncvars[ncvarid].isvar = -1;
+                      continue;
+                    }
 
-      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
+		  if ( ncvars[xvarid].xtype == NC_FLOAT ) grid->prec = DATATYPE_FLT32;
+                  if (CDI_netcdf_lazy_grid_load)
+                    {
+                      lazyGrid->xValsGet = (struct xyValGet){
+                        .scalefactor = ncvars[xvarid].scalefactor,
+                        .addoffset = ncvars[xvarid].addoffset,
+                        .start = { start[0], start[1], start[2] },
+                        .count = { count[0], count[1], count[2] },
+                        .size = size,
+                        .datasetNCId = ncvars[xvarid].ncid,
+                        .varNCId = xvarid,
+                        .ndims = (short)ndims,
+                      };
+                      grid->xvals = cdfPendingLoad;
+                    }
+                  else
+                    {
+                      grid->xvals = (double *) Malloc(size*sizeof(double));
+                      if ( ltgrid )
+                        cdf_get_vara_double(ncvars[xvarid].ncid, xvarid,
+                                            start, count, grid->xvals);
+                      else
+                        cdf_get_var_double(ncvars[xvarid].ncid, xvarid,
+                                           grid->xvals);
+                      scale_add(size, grid->xvals,
+                                ncvars[xvarid].addoffset,
+                                ncvars[xvarid].scalefactor);
+                    }
+		  strcpy(grid->xname, ncvars[xvarid].name);
+		  strcpy(grid->xlongname, ncvars[xvarid].longname);
+		  strcpy(grid->xunits, ncvars[xvarid].units);
+		  /* don't change the name !!! */
+		  /*
+		  if ( (len = strlen(grid->xname)) > 2 )
+		    if ( grid->xname[len-2] == '_' && isdigit((int) grid->xname[len-1]) )
+		      grid->xname[len-2] = 0;
+		  */
+		}
 
-      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs * sizeof(int));
+	      if ( yvarid != UNDEFID )
+		{
+                  bool skipvar = true;
+		  islat = ncvars[yvarid].islat;
+		  ndims = ncvars[yvarid].ndims;
+		  if ( ndims == 2 || ndims == 3 )
+		    {
+		      ncvars[ncvarid].gridtype = GRID_CURVILINEAR;
+		      size = xsize*ysize;
+		      /* Check size of 2 dimensional coordinate variables */
+		      {
+			int dimid;
+			size_t dimsize1, dimsize2;
+			dimid = ncvars[yvarid].dimids[ndims-2];
+			dimsize1 = ncdims[dimid].len;
+			dimid = ncvars[yvarid].dimids[ndims-1];
+			dimsize2 = ncdims[dimid].len;
+			skipvar = dimsize1*dimsize2 != size;
+		      }
+		    }
+		  else if ( ndims == 1 )
+		    {
+		      if ( (int) ysize == 0 ) size = xsize;
+		      else                    size = ysize;
 
-      memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
-    }
-}
+		      /* Check size of 1 dimensional coordinate variables */
+		      {
+			int dimid;
+			size_t dimsize;
+			dimid = ncvars[yvarid].dimids[0];
+			dimsize = ncdims[dimid].len;
+			skipvar = dimsize != size;
+		      }
+		    }
+		  else if ( ndims == 0 && ysize == 0 )
+		    {
+                      size = ysize = 1;
+                      skipvar = false;
+		    }
 
+                  if ( skipvar )
+                    {
+                      Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
+                      ncvars[ncvarid].isvar = -1;
+                      continue;
+                    }
 
-static
-int cdfTimeDimID(int fileID, int ndims, int nvars)
-{
-  int dimid = UNDEFID;
-  int timedimid = UNDEFID;
-  char dimname[80];
-  char timeunits[CDI_MAX_NAME];
-  char attname[CDI_MAX_NAME];
-  char name[CDI_MAX_NAME];
-  nc_type xtype;
-  int nvdims, nvatts;
-  int dimids[9];
-  int varid, iatt;
+		  if ( ncvars[yvarid].xtype == NC_FLOAT ) grid->prec = DATATYPE_FLT32;
+                  /* see below for when it's impossible to operate
+                   * without y values */
+                  if ( !CDI_netcdf_lazy_grid_load
+                       || ((ncvars[ncvarid].gridtype == UNDEFID ||
+                            ncvars[ncvarid].gridtype == GRID_GENERIC)
+                           && islat && (islon || xsize == 0)) )
+                    {
+                      grid->yvals = (double *) Malloc(size*sizeof(double));
 
-  for ( dimid = 0; dimid < ndims; dimid++ )
-    {
-      cdf_inq_dimname(fileID, dimid, dimname);
-      if ( memcmp(dimname, "time", 4) == 0 )
-        {
-          timedimid = dimid;
-          break;
-        }
-    }
+                      if ( ltgrid )
+                        cdf_get_vara_double(ncvars[yvarid].ncid, yvarid, start, count, grid->yvals);
+                      else
+                        cdf_get_var_double(ncvars[yvarid].ncid, yvarid, grid->yvals);
 
-  if ( timedimid == UNDEFID )
-    {
-      for ( varid = 0; varid < nvars; varid++ )
-        {
-          cdf_inq_var(fileID, varid, name, &xtype, &nvdims, dimids, &nvatts);
-          if ( nvdims == 1 )
-            {
-              for ( iatt = 0; iatt < nvatts; iatt++ )
-                {
-                  cdf_inq_attname(fileID, varid, iatt, attname);
-                  if ( strncmp(attname, "units", 5) == 0 )
-                    {
-                      cdfGetAttText(fileID, varid, "units", sizeof(timeunits), timeunits);
-                      strtolower(timeunits);
+                      scale_add(size, grid->yvals, ncvars[yvarid].addoffset, ncvars[yvarid].scalefactor);
 
-                      if ( isTimeUnits(timeunits) )
+                      /* don't change the name !!! */
+                      /*
+                        if ( (len = strlen(grid->yname)) > 2 )
+                        if ( grid->yname[len-2] == '_' && isdigit((int) grid->yname[len-1]) )
+                        grid->yname[len-2] = 0;
+                      */
+                      if ( islon && (int) ysize > 1 )
                         {
-                          timedimid = dimids[0];
-                          break;
+                          yinc = fabs(grid->yvals[0] - grid->yvals[1]);
+                          for ( size_t i = 2; i < ysize; i++ )
+                            if ( (fabs(grid->yvals[i-1] - grid->yvals[i]) - yinc) > (yinc/1000) )
+                              {
+                                yinc = 0;
+                                break;
+                              }
                         }
                     }
-                }
-            }
-        }
-    }
+                  else
+                    {
+                      lazyGrid->yValsGet = (struct xyValGet){
+                        .scalefactor = ncvars[yvarid].scalefactor,
+                        .addoffset = ncvars[yvarid].addoffset,
+                        .start = { start[0], start[1], start[2] },
+                        .count = { count[0], count[1], count[2] },
+                        .size = size,
+                        .datasetNCId = ncvars[yvarid].ncid,
+                        .varNCId = yvarid,
+                        .ndims = (short)ndims,
+                      };
+                      grid->yvals = cdfPendingLoad;
+                    }
+                  strcpy(grid->yname, ncvars[yvarid].name);
+                  strcpy(grid->ylongname, ncvars[yvarid].longname);
+                  strcpy(grid->yunits, ncvars[yvarid].units);
+		}
 
-  return (timedimid);
-}
+	      if      ( (int) ysize == 0 ) size = xsize;
+	      else if ( (int) xsize == 0 ) size = ysize;
+	      else if ( ncvars[ncvarid].gridtype == GRID_UNSTRUCTURED ) size = xsize;
+	      else                         size = xsize*ysize;
+	    }
 
-static
-void init_ncdims(long ndims, ncdim_t *ncdims)
-{
-  for ( long ncdimid = 0; ncdimid < ndims; ncdimid++ )
-    {
-      ncdims[ncdimid].ncvarid      = UNDEFID;
-      ncdims[ncdimid].dimtype      = UNDEFID;
-      ncdims[ncdimid].len          = 0;
-      ncdims[ncdimid].name[0]      = 0;
-    }
-}
+	  if ( ncvars[ncvarid].gridtype == UNDEFID ||
+	       ncvars[ncvarid].gridtype == GRID_GENERIC )
+	    {
+	      if ( islat && (islon || xsize == 0) )
+		{
+		  if ( isGaussGrid(ysize, yinc, grid->yvals) )
+                    {
+                      ncvars[ncvarid].gridtype = GRID_GAUSSIAN;
+                      grid->np = (int)(ysize/2);
+                    }
+                  else
+		    ncvars[ncvarid].gridtype = GRID_LONLAT;
+		}
+	      else if ( islon && !islat && ysize == 0 )
+		{
+		  ncvars[ncvarid].gridtype = GRID_LONLAT;
+		}
+	      else
+		ncvars[ncvarid].gridtype = GRID_GENERIC;
+	    }
 
-static
-void init_ncvars(long nvars, ncvar_t *ncvars)
-{
-  for ( long ncvarid = 0; ncvarid < nvars; ++ncvarid )
-    {
-      ncvars[ncvarid].ncid            = UNDEFID;
-      ncvars[ncvarid].ignore          = FALSE;
-      ncvars[ncvarid].isvar           = UNDEFID;
-      ncvars[ncvarid].islon           = FALSE;
-      ncvars[ncvarid].islat           = FALSE;
-      ncvars[ncvarid].islev           = FALSE;
-      ncvars[ncvarid].istime          = FALSE;
-      ncvars[ncvarid].warn            = FALSE;
-      ncvars[ncvarid].tsteptype       = TSTEP_CONSTANT;
-      ncvars[ncvarid].param           = UNDEFID;
-      ncvars[ncvarid].code            = UNDEFID;
-      ncvars[ncvarid].tabnum          = 0;
-      ncvars[ncvarid].calendar        = FALSE;
-      ncvars[ncvarid].climatology     = FALSE;
-      ncvars[ncvarid].bounds          = UNDEFID;
-      ncvars[ncvarid].lformula        = FALSE;
-      ncvars[ncvarid].lformulaterms   = FALSE;
-      ncvars[ncvarid].gridID          = UNDEFID;
-      ncvars[ncvarid].zaxisID         = UNDEFID;
-      ncvars[ncvarid].gridtype        = UNDEFID;
-      ncvars[ncvarid].zaxistype       = UNDEFID;
-      ncvars[ncvarid].xdim            = UNDEFID;
-      ncvars[ncvarid].ydim            = UNDEFID;
-      ncvars[ncvarid].zdim            = UNDEFID;
-      ncvars[ncvarid].xvarid          = UNDEFID;
-      ncvars[ncvarid].yvarid          = UNDEFID;
-      ncvars[ncvarid].zvarid          = UNDEFID;
-      ncvars[ncvarid].tvarid          = UNDEFID;
-      ncvars[ncvarid].psvarid         = UNDEFID;
-      ncvars[ncvarid].ncoordvars      = 0;
-      for ( int i = 0; i < MAX_COORDVARS; ++i )
-        ncvars[ncvarid].coordvarids[i]  = UNDEFID;
-      ncvars[ncvarid].nauxvars      = 0;
-      for ( int i = 0; i < MAX_AUXVARS; ++i )
-        ncvars[ncvarid].auxvarids[i]  = UNDEFID;
-      ncvars[ncvarid].cellarea        = UNDEFID;
-      ncvars[ncvarid].tableID         = UNDEFID;
-      ncvars[ncvarid].xtype           = 0;
-      ncvars[ncvarid].ndims           = 0;
-      ncvars[ncvarid].gmapid          = UNDEFID;
-      ncvars[ncvarid].vctsize         = 0;
-      ncvars[ncvarid].vct             = NULL;
-      ncvars[ncvarid].truncation      = 0;
-      ncvars[ncvarid].position        = 0;
-      ncvars[ncvarid].positive        = 0;
-      ncvars[ncvarid].chunked         = 0;
-      ncvars[ncvarid].chunktype       = UNDEFID;
-      ncvars[ncvarid].defmissval      = 0;
-      ncvars[ncvarid].deffillval      = 0;
-      ncvars[ncvarid].missval         = 0;
-      ncvars[ncvarid].fillval         = 0;
-      ncvars[ncvarid].addoffset       = 0;
-      ncvars[ncvarid].scalefactor     = 1;
-      ncvars[ncvarid].name[0]         = 0;
-      ncvars[ncvarid].longname[0]     = 0;
-      ncvars[ncvarid].stdname[0]      = 0;
-      ncvars[ncvarid].units[0]        = 0;
-      ncvars[ncvarid].extra[0]        = 0;
-      ncvars[ncvarid].natts           = 0;
-      ncvars[ncvarid].atts            = NULL;
-      ncvars[ncvarid].deflate         = 0;
-      ncvars[ncvarid].lunsigned       = 0;
-      ncvars[ncvarid].lvalidrange     = 0;
-      ncvars[ncvarid].validrange[0]   = VALIDMISS;
-      ncvars[ncvarid].validrange[1]   = VALIDMISS;
-      ncvars[ncvarid].ensdata         = NULL;
-    }
-}
-
-static
-void cdfSetVar(ncvar_t *ncvars, int ncvarid, short isvar)
-{
-  if ( ncvars[ncvarid].isvar != UNDEFID &&
-       ncvars[ncvarid].isvar != isvar   &&
-       ncvars[ncvarid].warn  == FALSE )
-    {
-      if ( ! ncvars[ncvarid].ignore )
-        Warning("Inconsistent variable definition for %s!", ncvars[ncvarid].name);
-
-      ncvars[ncvarid].warn = TRUE;
-      isvar = FALSE;
-    }
+	  switch (ncvars[ncvarid].gridtype)
+	    {
+	    case GRID_GENERIC:
+	    case GRID_LONLAT:
+	    case GRID_GAUSSIAN:
+	    case GRID_UNSTRUCTURED:
+	    case GRID_CURVILINEAR:
+	      {
+		grid->size  = (int)size;
+		grid->xsize = (int)xsize;
+		grid->ysize = (int)ysize;
+		if ( xvarid != UNDEFID )
+		  {
+		    grid->xdef  = 1;
+		    if ( ncvars[xvarid].bounds != UNDEFID )
+		      {
+			int nbdims = ncvars[ncvars[xvarid].bounds].ndims;
+			if ( nbdims == 2 || nbdims == 3 )
+			  {
+			    size_t nvertex = ncdims[ncvars[ncvars[xvarid].bounds].dimids[nbdims-1]].len;
+			    grid->nvertex = (int)nvertex;
+                            if (CDI_netcdf_lazy_grid_load)
+                              {
+                                lazyGrid->xBoundsGet.datasetNCId
+                                  = ncvars[xvarid].ncid;
+                                lazyGrid->xBoundsGet.varNCId
+                                  = ncvars[xvarid].bounds;
+                                grid->xbounds = cdfPendingLoad;
+                              }
+                            else
+                              {
+                                grid->xbounds
+                                  = (double *)Malloc(nvertex * size
+                                                     * sizeof(double));
+                                cdf_get_var_double(ncvars[xvarid].ncid,
+                                                   ncvars[xvarid].bounds,
+                                                   grid->xbounds);
+                              }
+			  }
+		      }
+		  }
+		if ( yvarid != UNDEFID )
+		  {
+		    grid->ydef  = 1;
+		    if ( ncvars[yvarid].bounds != UNDEFID )
+		      {
+			int nbdims = ncvars[ncvars[yvarid].bounds].ndims;
+			if ( nbdims == 2 || nbdims == 3 )
+			  {
+			    /* size_t nvertex = ncdims[ncvars[ncvars[yvarid].bounds].dimids[nbdims-1]].len;
+			    if ( nvertex != grid->nvertex )
+			      Warning("nvertex problem! nvertex x %d, nvertex y %d",
+				      grid->nvertex, (int) nvertex);
+			    */
+                            if (CDI_netcdf_lazy_grid_load)
+                              {
+                                lazyGrid->yBoundsGet.datasetNCId
+                                  = ncvars[yvarid].ncid;
+                                lazyGrid->yBoundsGet.varNCId
+                                  = ncvars[yvarid].bounds;
+                                grid->ybounds = cdfPendingLoad;
+                              }
+                            else
+                              {
+                                int vid
+                                  = ncvars[ncvars[yvarid].bounds].dimids[nbdims-1];
+                                size_t nvertex = ncdims[vid].len;
+                                /*
+                                  if ( nvertex != grid->nvertex )
+                                  Warning("nvertex problem! nvertex x %d, nvertex y %d",
+                                  grid->nvertex, (int) nvertex);
+                                */
+                                grid->ybounds
+                                  = (double *)Malloc(nvertex * size
+                                                     * sizeof(double));
+                                cdf_get_var_double(ncvars[yvarid].ncid,
+                                                   ncvars[yvarid].bounds,
+                                                   grid->ybounds);
+                              }
+			  }
+		      }
+		  }
 
-  ncvars[ncvarid].isvar = isvar;
-}
+		if ( ncvars[ncvarid].cellarea != UNDEFID )
+                  {
+                    if (CDI_netcdf_lazy_grid_load)
+                      {
+                        grid->area = cdfPendingLoad;
+                        lazyGrid->cellAreaGet.datasetNCId
+                          = ncvars[ncvarid].ncid;
+                        lazyGrid->cellAreaGet.varNCId
+                          = ncvars[ncvarid].cellarea;
+                      }
+                    else
+                      {
+                        grid->area = (double *) Malloc(size*sizeof(double));
+                        cdf_get_var_double(ncvars[ncvarid].ncid,
+                                           ncvars[ncvarid].cellarea,
+                                           grid->area);
+                      }
+                  }
 
-static
-void cdfSetDim(ncvar_t *ncvars, int ncvarid, int dimid, int dimtype)
-{
-  if ( ncvars[ncvarid].dimtype[dimid] != UNDEFID &&
-       ncvars[ncvarid].dimtype[dimid] != dimtype )
-    {
-      Warning("Inconsistent dimension definition for %s! dimid = %d;  type = %d;  newtype = %d",
-              ncvars[ncvarid].name, dimid, ncvars[ncvarid].dimtype[dimid], dimtype);
-    }
+		break;
+	      }
+	    case GRID_SPECTRAL:
+	      {
+		grid->size = (int)size;
+		grid->lcomplex = 1;
+		break;
+	      }
+	    case GRID_FOURIER:
+	      {
+		grid->size = (int)size;
+		break;
+	      }
+	    case GRID_TRAJECTORY:
+	      {
+		grid->size = 1;
+		break;
+	      }
+	    }
 
-  ncvars[ncvarid].dimtype[dimid] = dimtype;
-}
+          if (grid->type != ncvars[ncvarid].gridtype)
+            {
+              int gridtype = ncvars[ncvarid].gridtype;
+              grid->type = gridtype;
+              cdiGridTypeInit(grid, gridtype, grid->size);
+            }
 
-static
-int isLonAxis(const char *units, const char *stdname)
-{
-  int status = FALSE;
-  char lc_units[16];
+	  if ( grid->size == 0 )
+	    {
+	      if ( (ncvars[ncvarid].ndims == 1 && ncvars[ncvarid].dimtype[0] == T_AXIS) ||
+		   (ncvars[ncvarid].ndims == 1 && ncvars[ncvarid].dimtype[0] == Z_AXIS) ||
+		   (ncvars[ncvarid].ndims == 2 && ncvars[ncvarid].dimtype[0] == T_AXIS && ncvars[ncvarid].dimtype[1] == Z_AXIS) )
+		{
+		  grid->type  = GRID_GENERIC;
+		  grid->size  = 1;
+		  grid->xsize = 0;
+		  grid->ysize = 0;
+		}
+	      else
+		{
+		  Warning("Variable %s has an unsupported grid, skipped!", ncvars[ncvarid].name);
+		  ncvars[ncvarid].isvar = -1;
+		  continue;
+		}
+	    }
 
-  memcpy(lc_units, units, 15);
-  lc_units[15] = 0;
-  strtolower(lc_units);
+	  if ( number_of_grid_used != UNDEFID && (grid->type == UNDEFID || grid->type == GRID_GENERIC) )
+            grid->type   = GRID_UNSTRUCTURED;
 
-  if ( ((memcmp(lc_units, "degree", 6) == 0 || memcmp(lc_units, "radian", 6) == 0) &&
-        (memcmp(stdname, "grid_longitude", 14) == 0 || memcmp(stdname, "longitude", 9) == 0)) )
-    {
-      status = TRUE;
-    }
+	  if ( number_of_grid_used != UNDEFID && grid->type == GRID_UNSTRUCTURED )
+            grid->number = number_of_grid_used;
 
-  if ( status == FALSE &&
-       memcmp(stdname, "grid_latitude", 13) && memcmp(stdname, "latitude", 8) &&
-       memcmp(lc_units, "degree", 6) == 0 )
-    {
-      int ioff = 6;
-      if ( lc_units[ioff] == 's' ) ioff++;
-      if ( lc_units[ioff] == '_' ) ioff++;
-      if ( lc_units[ioff] == 'e' ) status = TRUE;
-    }
+	  if ( ncvars[ncvarid].gmapid >= 0 && ncvars[ncvarid].gridtype != GRID_CURVILINEAR )
+	    {
+              int nvatts;
+	      cdf_inq_varnatts(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, &nvatts);
 
-  return (status);
-}
+	      for ( int iatt = 0; iatt < nvatts; iatt++ )
+		{
+                  size_t attlen;
+                  char attname[CDI_MAX_NAME];
+		  cdf_inq_attname(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, iatt, attname);
+		  cdf_inq_attlen(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, &attlen);
 
-static
-int isLatAxis(const char *units, const char *stdname)
-{
-  int status = FALSE;
-  char lc_units[16];
+		  if ( strcmp(attname, "grid_mapping_name") == 0 )
+		    {
+                      enum {
+                        attstringlen = 8192,
+                      };
+                      char attstring[attstringlen];
 
-  memcpy(lc_units, units, 15);
-  lc_units[15] = 0;
-  strtolower(lc_units);
+		      cdfGetAttText(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, attstringlen, attstring);
+		      strtolower(attstring);
 
-  if ( ((memcmp(lc_units, "degree", 6) == 0 || memcmp(lc_units, "radian", 6) == 0) &&
-        (memcmp(stdname, "grid_latitude", 13) == 0 || memcmp(stdname, "latitude", 8) == 0)) )
-    {
-      status = TRUE;
-    }
+		      if ( strcmp(attstring, "rotated_latitude_longitude") == 0 )
+			grid->isRotated = TRUE;
+		      else if ( strcmp(attstring, "sinusoidal") == 0 )
+			grid->type = GRID_SINUSOIDAL;
+		      else if ( strcmp(attstring, "lambert_azimuthal_equal_area") == 0 )
+			grid->type = GRID_LAEA;
+		      else if ( strcmp(attstring, "lambert_conformal_conic") == 0 )
+			grid->type = GRID_LCC2;
+		      else if ( strcmp(attstring, "lambert_cylindrical_equal_area") == 0 )
+			{
+			  proj->type = GRID_PROJECTION;
+			  proj->name = strdup(attstring);
+			}
+		    }
+		  else if ( strcmp(attname, "earth_radius") == 0 )
+		    {
+                      double datt;
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
+		      grid->laea_a = datt;
+		      grid->lcc2_a = datt;
+		    }
+		  else if ( strcmp(attname, "longitude_of_projection_origin") == 0 )
+		    {
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->laea_lon_0);
+		    }
+		  else if ( strcmp(attname, "longitude_of_central_meridian") == 0 )
+		    {
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->lcc2_lon_0);
+		    }
+		  else if ( strcmp(attname, "latitude_of_projection_origin") == 0 )
+		    {
+                      double datt;
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
+		      grid->laea_lat_0 = datt;
+		      grid->lcc2_lat_0 = datt;
+		    }
+		  else if ( strcmp(attname, "standard_parallel") == 0 )
+		    {
+		      if ( attlen == 1 )
+			{
+                          double datt;
+			  cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
+			  grid->lcc2_lat_1 = datt;
+			  grid->lcc2_lat_2 = datt;
+			}
+		      else
+			{
+			  double datt2[2];
+			  cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 2, datt2);
+			  grid->lcc2_lat_1 = datt2[0];
+			  grid->lcc2_lat_2 = datt2[1];
+			}
+		    }
+		  else if ( strcmp(attname, "grid_north_pole_latitude") == 0 )
+		    {
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->ypole);
+		    }
+		  else if ( strcmp(attname, "grid_north_pole_longitude") == 0 )
+		    {
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->xpole);
+		    }
+		  else if ( strcmp(attname, "north_pole_grid_longitude") == 0 )
+		    {
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->angle);
+		    }
+		}
+	    }
 
-  if ( status == FALSE &&
-       memcmp(stdname, "grid_longitude", 14) && memcmp(stdname, "longitude", 9) &&
-       memcmp(lc_units, "degree", 6) == 0 )
-    {
-      int ioff = 6;
-      if ( lc_units[ioff] == 's' ) ioff++;
-      if ( lc_units[ioff] == '_' ) ioff++;
-      if ( lc_units[ioff] == 'n' || lc_units[ioff] == 's' ) status = TRUE;
-    }
+          if ( grid->type == GRID_UNSTRUCTURED )
+            {
+              int zdimid = UNDEFID;
+              int xdimidx = -1, ydimidx = -1;
 
-  return (status);
-}
+              for ( int i = 0; i < ndims; i++ )
+                {
+                  if      ( ncvars[ncvarid].dimtype[i] == X_AXIS ) xdimidx = i;
+                  else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) ydimidx = i;
+                  else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) zdimid = ncvars[ncvarid].dimids[i];
+                }
 
-static
-int isDBLAxis(/*const char *units,*/ const char *longname)
-{
-  int status = FALSE;
+              if ( xdimid != UNDEFID && ydimid != UNDEFID && zdimid == UNDEFID )
+                {
+                  if ( grid->xsize > grid->ysize && grid->ysize < 1000 )
+                    {
+                      ncvars[ncvarid].dimtype[ydimidx] = Z_AXIS;
+                      ydimid = UNDEFID;
+                      grid->size  = grid->xsize;
+                      grid->ysize = 0;
+                    }
+                  else if ( grid->ysize > grid->xsize && grid->xsize < 1000 )
+                    {
+                      ncvars[ncvarid].dimtype[xdimidx] = Z_AXIS;
+                      xdimid = ydimid;
+                      ydimid = UNDEFID;
+                      grid->size  = grid->ysize;
+                      grid->xsize = grid->ysize;
+                      grid->ysize = 0;
+                    }
+                }
 
-  if ( strcmp(longname, "depth below land")         == 0 ||
-       strcmp(longname, "depth_below_land")         == 0 ||
-       strcmp(longname, "levels below the surface") == 0 )
-    {
-      /*
-      if ( strcmp(ncvars[ncvarid].units, "cm") == 0 ||
-           strcmp(ncvars[ncvarid].units, "dm") == 0 ||
-           strcmp(ncvars[ncvarid].units, "m")  == 0 )
-      */
-        status = TRUE;
-    }
+              if ( grid->size != grid->xsize )
+                {
+                  Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
+                  ncvars[ncvarid].isvar = -1;
+                  continue;
+                }
 
-  return (status);
-}
+              if ( ncvars[ncvarid].position > 0 ) grid->position = ncvars[ncvarid].position;
+              if ( uuidOfHGrid[0] != 0 ) memcpy(grid->uuid, uuidOfHGrid, 16);
+            }
 
-static
-int unitsIsMeter(const char *units)
-{
-  return (units[0] == 'm' && (!units[1] || strncmp(units, "meter", 5) == 0));
-}
+#if defined (PROJECTION_TEST)
+	  if ( proj->type == GRID_PROJECTION )
+	    {
+	      if ( grid->type == GRID_GENERIC )
+		{
+		  grid->type = GRID_CURVILINEAR;
+		}
 
-static
-int isDepthAxis(const char *stdname, const char *longname)
-{
-  int status = FALSE;
+	      if ( grid->type == GRID_CURVILINEAR )
+		{
+                  proj->size  = grid->size;
+                  proj->xsize = grid->xsize;
+                  proj->ysize = grid->ysize;
+		}
 
-  if ( strcmp(stdname, "depth") == 0 ) status = TRUE;
+	      //  grid->proj = gridGenerate(proj);
+	    }
+#endif
 
-  if ( status == FALSE )
-    if ( strcmp(longname, "depth_below_sea") == 0 ||
-         strcmp(longname, "depth below sea") == 0 )
-      {
-        status = TRUE;
-      }
+	  if ( CDI_Debug )
+	    {
+	      Message("grid: type = %d, size = %d, nx = %d, ny %d",
+		      grid->type, grid->size, grid->xsize, grid->ysize);
+	      Message("proj: type = %d, size = %d, nx = %d, ny %d",
+		      proj->type, proj->size, proj->xsize, proj->ysize);
+	    }
 
-  return (status);
-}
+#if defined (PROJECTION_TEST)
+	  if ( proj->type == GRID_PROJECTION )
+	    {
+              projAdded = cdiVlistAddGridIfNew(vlistID, proj, 1);
+              ncvars[ncvarid].gridID = projAdded.Id;
+	      copy_numeric_projatts(ncvars[ncvarid].gridID, ncvars[ncvarid].gmapid, ncvars[ncvarid].ncid);
+	    }
+	  else
+#endif
+            {
+              gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 1);
+              ncvars[ncvarid].gridID = gridAdded.Id;
+            }
 
-static
-int isHeightAxis(const char *stdname, const char *longname)
-{
-  int status = FALSE;
+          if ( grid->type == GRID_UNSTRUCTURED )
+            {
+              if ( gridfile[0] != 0 ) gridDefReference(ncvars[ncvarid].gridID, gridfile);
+            }
 
-  if ( strcmp(stdname, "height") == 0 ) status = TRUE;
+          if ( ncvars[ncvarid].chunked ) grid_set_chunktype(grid, &ncvars[ncvarid]);
 
-  if ( status == FALSE )
-    if ( strcmp(longname, "height") == 0 ||
-         strcmp(longname, "height above the surface") == 0 )
-      {
-        status = TRUE;
-      }
+	  int gridindex = vlistGridIndex(vlistID, ncvars[ncvarid].gridID);
+	  streamptr->xdimID[gridindex] = xdimid;
+	  streamptr->ydimID[gridindex] = ydimid;
+          if ( xdimid == -1 && ydimid == -1 && grid->size == 1 )
+            gridDefHasDims(ncvars[ncvarid].gridID, FALSE);
 
-  return (status);
-}
+	  if ( CDI_Debug )
+	    Message("gridID %d %d %s", ncvars[ncvarid].gridID, ncvarid, ncvars[ncvarid].name);
 
-static
-int unitsIsPressure(const char *units)
-{
-  int status = FALSE;
+	  for ( int ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
+	    if ( ncvars[ncvarid2].isvar == TRUE && ncvars[ncvarid2].gridID == UNDEFID )
+	      {
+		int xdimid2 = UNDEFID, ydimid2 = UNDEFID, zdimid2 = UNDEFID;
+                int xdimidx = -1, ydimidx = -1;
+		int ndims2 = ncvars[ncvarid2].ndims;
 
-  if ( memcmp(units, "millibar", 8) == 0 ||
-       memcmp(units, "mb", 2)       == 0 ||
-       memcmp(units, "hectopas", 8) == 0 ||
-       memcmp(units, "hPa", 3)      == 0 ||
-       memcmp(units, "Pa", 2)       == 0 )
-    {
-      status = TRUE;
-    }
+		for ( int i = 0; i < ndims2; i++ )
+		  {
+		    if ( ncvars[ncvarid2].dimtype[i] == X_AXIS )
+		      { xdimid2 = ncvars[ncvarid2].dimids[i]; xdimidx = i; }
+		    else if ( ncvars[ncvarid2].dimtype[i] == Y_AXIS )
+		      { ydimid2 = ncvars[ncvarid2].dimids[i]; ydimidx = i; }
+		    else if ( ncvars[ncvarid2].dimtype[i] == Z_AXIS )
+		      { zdimid2 = ncvars[ncvarid2].dimids[i]; }
+		  }
 
-  return status;
-}
+                if ( ncvars[ncvarid2].gridtype == UNDEFID && grid->type == GRID_UNSTRUCTURED )
+                  {
+                    if ( xdimid == xdimid2 && ydimid2 != UNDEFID && zdimid2 == UNDEFID )
+                      {
+                        ncvars[ncvarid2].dimtype[ydimidx] = Z_AXIS;
+                        ydimid2 = UNDEFID;
+                      }
 
-static
-void scan_hybrid_formula(int ncid, int ncfvarid, int *apvarid, int *bvarid, int *psvarid)
-{
-  *apvarid = -1;
-  *bvarid  = -1;
-  *psvarid = -1;
-  const int attstringlen = 8192; char attstring[8192];
-  cdfGetAttText(ncid, ncfvarid, "formula", attstringlen, attstring);
-  if ( strcmp(attstring, "p = ap + b*ps") == 0 )
-    {
-      int lstop = FALSE;
-      int dimvarid;
-      cdfGetAttText(ncid, ncfvarid, "formula_terms", attstringlen, attstring);
-      char *pstring = attstring;
+                    if ( xdimid == ydimid2 && xdimid2 != UNDEFID && zdimid2 == UNDEFID )
+                      {
+                        ncvars[ncvarid2].dimtype[xdimidx] = Z_AXIS;
+                        xdimid2 = ydimid2;
+                        ydimid2 = UNDEFID;
+                      }
+                  }
 
-      for ( int i = 0; i < 3; i++ )
-        {
-          while ( isspace((int) *pstring) ) pstring++;
-          if ( *pstring == 0 ) break;
-          char *tagname = pstring;
-          while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
-          if ( *pstring == 0 ) lstop = TRUE;
-          *pstring++ = 0;
+                if ( xdimid == xdimid2 &&
+		    (ydimid == ydimid2 || (xdimid == ydimid && ydimid2 == UNDEFID)) )
+		  {
+		    int same_grid = ncvars[ncvarid].xvarid == ncvars[ncvarid2].xvarid
+                      && ncvars[ncvarid].yvarid == ncvars[ncvarid2].yvarid
+                      && ncvars[ncvarid].position == ncvars[ncvarid2].position;
+                    /*
+		    if ( xvarid != -1 && ncvars[ncvarid2].xvarid != UNDEFID &&
+			 xvarid != ncvars[ncvarid2].xvarid ) same_grid = FALSE;
 
-          while ( isspace((int) *pstring) ) pstring++;
-          if ( *pstring == 0 ) break;
-          char *varname = pstring;
-          while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
-          if ( *pstring == 0 ) lstop = TRUE;
-          *pstring++ = 0;
+		    if ( yvarid != -1 && ncvars[ncvarid2].yvarid != UNDEFID &&
+			 yvarid != ncvars[ncvarid2].yvarid ) same_grid = FALSE;
+                    */
 
-          int status = nc_inq_varid(ncid, varname, &dimvarid);
-          if ( status == NC_NOERR )
-            {
-              if      ( strcmp(tagname, "ap:") == 0 ) *apvarid = dimvarid;
-              else if ( strcmp(tagname, "b:")  == 0 ) *bvarid  = dimvarid;
-              else if ( strcmp(tagname, "ps:") == 0 ) *psvarid = dimvarid;
-            }
-          else if ( strcmp(tagname, "ps:") != 0 )
-            {
-              Warning("%s - %s", nc_strerror(status), varname);
-            }
+		    if ( same_grid )
+		      {
+			if ( CDI_Debug )
+			  Message("Same gridID %d %d %s", ncvars[ncvarid].gridID, ncvarid2, ncvars[ncvarid2].name);
+			ncvars[ncvarid2].gridID = ncvars[ncvarid].gridID;
+			ncvars[ncvarid2].chunktype = ncvars[ncvarid].chunktype;
+		      }
+		  }
+	      }
 
-          if ( lstop ) break;
-        }
+          if (gridAdded.isNew)
+            lazyGrid = NULL;
+          if (projAdded.isNew)
+            lazyProj = NULL;
+	}
+    }
+  if (lazyGrid)
+    {
+      if (CDI_netcdf_lazy_grid_load) cdfLazyGridDestroy(lazyGrid);
+      grid_free(grid);
+      Free(grid);
     }
+  if (lazyProj)
+    {
+      if (CDI_netcdf_lazy_grid_load) cdfLazyGridDestroy(lazyProj);
+      grid_free(proj);
+      Free(proj);
+    }
+#undef proj
+#undef grid
 }
 
+/* define all input zaxes */
 static
-int isHybridSigmaPressureCoordinate(int ncid, int ncvarid, ncvar_t *ncvars, const ncdim_t *ncdims)
+void define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars,
+		      size_t vctsize_echam, double *vct_echam, unsigned char *uuidOfVGrid)
 {
-  int status = FALSE;
-  int ncfvarid = ncvarid;
-  ncvar_t *ncvar = &ncvars[ncvarid];
+  int ncvarid, ncvarid2;
+  int i, ilev;
+  int zaxisindex;
+  int nbdims, nvertex, nlevel;
+  int psvarid = -1;
+  char *pname, *plongname, *punits;
+  size_t vctsize = vctsize_echam;
+  double *vct = vct_echam;
 
-  if ( strcmp(ncvar->stdname, "atmosphere_hybrid_sigma_pressure_coordinate") == 0 )
+  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-      cdiConvention = CDI_CONVENTION_CF;
-
-      status = TRUE;
-      ncvar->zaxistype = ZAXIS_HYBRID;
-      int dimid = ncvar->dimids[0];
-      size_t dimlen = ncdims[dimid].len;
+      if ( ncvars[ncvarid].isvar == TRUE && ncvars[ncvarid].zaxisID == UNDEFID )
+	{
+          int is_scalar = FALSE;
+	  int with_bounds = FALSE;
+	  int zdimid = UNDEFID;
+	  int zvarid = UNDEFID;
+	  int zsize = 1;
+	  double *lbounds = NULL;
+	  double *ubounds = NULL;
 
-      int apvarid1 = -1, bvarid1 = -1, psvarid1 = -1;
-      if ( ncvars[ncfvarid].lformula && ncvars[ncfvarid].lformulaterms )
-        scan_hybrid_formula(ncid, ncfvarid, &apvarid1, &bvarid1, &psvarid1);
-      if ( apvarid1 != -1 ) ncvars[apvarid1].isvar = FALSE;
-      if ( bvarid1  != -1 ) ncvars[bvarid1].isvar  = FALSE;
-      if ( psvarid1 != -1 ) ncvar->psvarid = psvarid1;
+          int positive = 0;
+	  int ndims = ncvars[ncvarid].ndims;
 
-      if ( ncvar->bounds != UNDEFID && ncvars[ncvar->bounds].lformula && ncvars[ncvar->bounds].lformulaterms )
-        {
-          ncfvarid = ncvar->bounds;
-          int apvarid2 = -1, bvarid2 = -1, psvarid2 = -1;
-          if ( ncvars[ncfvarid].lformula && ncvars[ncfvarid].lformulaterms )
-            scan_hybrid_formula(ncid, ncfvarid, &apvarid2, &bvarid2, &psvarid2);
-          if ( apvarid2 != -1 && bvarid2 != -1 )
+          if ( ncvars[ncvarid].zvarid != -1 && ncvars[ncvars[ncvarid].zvarid].ndims == 0 )
             {
-              ncvars[apvarid2].isvar = FALSE;
-              ncvars[bvarid2].isvar  = FALSE;
-
-              if ( dimid == ncvars[apvarid2].dimids[0] && ncdims[ncvars[apvarid2].dimids[1]].len == 2 )
+              zvarid = ncvars[ncvarid].zvarid;
+              is_scalar = TRUE;
+            }
+          else
+            {
+              for ( i = 0; i < ndims; i++ )
                 {
-                  double abuf[dimlen*2], bbuf[dimlen*2];
-                  cdf_get_var_double(ncid, apvarid2, abuf);
-                  cdf_get_var_double(ncid, bvarid2, bbuf);
-                  /*
-                  for ( int i = 0; i < dimlen; ++i )
-                    printf("%d  %g %g    %g %g\n", i, abuf[i*2], abuf[i*2+1], bbuf[i*2], bbuf[i*2+1]);
-                  */
-                  size_t vctsize = (dimlen+1)*2;
-                  double *vct = (double *) Malloc(vctsize * sizeof(double));
-                  for ( size_t i = 0; i < dimlen; ++i )
-                    {
-                      vct[i] = abuf[i*2];
-                      vct[i+dimlen+1] = bbuf[i*2];
-                    }
-                  vct[dimlen]     = abuf[dimlen*2-1];
-                  vct[dimlen*2+1] = bbuf[dimlen*2-1];
+                  if ( ncvars[ncvarid].dimtype[i] == Z_AXIS )
+                    zdimid = ncvars[ncvarid].dimids[i];
+                }
 
-                  ncvar->vct = vct;
-                  ncvar->vctsize = vctsize;
+              if ( zdimid != UNDEFID )
+                {
+                  zvarid = ncdims[zdimid].ncvarid;
+                  zsize  = (int)ncdims[zdimid].len;
                 }
             }
-        }
-    }
 
-  return status;
-}
+	  if ( CDI_Debug ) Message("nlevs = %d", zsize);
 
+	  double *zvar = (double *) Malloc((size_t)zsize * sizeof (double));
 
-static
-int isGaussGrid(size_t ysize, double yinc, const double *yvals)
-{
-  int lgauss = FALSE;
-  double *yv, *yw;
-
-  if ( IS_EQUAL(yinc, 0) && ysize > 2 ) /* check if gaussian */
-    {
-      size_t i;
-      yv = (double *) Malloc(ysize*sizeof(double));
-      yw = (double *) Malloc(ysize*sizeof(double));
-      gaussaw(yv, yw, ysize);
-      Free(yw);
-      for ( i = 0; i < ysize; i++ )
-        yv[i] = asin(yv[i])/M_PI*180.0;
+	  int zaxisType = UNDEFID;
+	  if ( zvarid != UNDEFID ) zaxisType = ncvars[zvarid].zaxistype;
+	  if ( zaxisType == UNDEFID )  zaxisType = ZAXIS_GENERIC;
 
-      for ( i = 0; i < ysize; i++ )
-        if ( fabs(yv[i] - yvals[i]) >
-             ((yv[0] - yv[1])/500) ) break;
+	  int zprec = DATATYPE_FLT64;
 
-      if ( i == ysize ) lgauss = TRUE;
+	  if ( zvarid != UNDEFID )
+	    {
+	      positive  = ncvars[zvarid].positive;
+	      pname     = ncvars[zvarid].name;
+	      plongname = ncvars[zvarid].longname;
+	      punits    = ncvars[zvarid].units;
+	      if ( ncvars[zvarid].xtype == NC_FLOAT ) zprec = DATATYPE_FLT32;
+	      /* don't change the name !!! */
+	      /*
+	      if ( (len = strlen(pname)) > 2 )
+		if ( pname[len-2] == '_' && isdigit((int) pname[len-1]) )
+		  pname[len-2] = 0;
+	      */
+              psvarid = -1;
+              if ( zaxisType == ZAXIS_HYBRID && ncvars[zvarid].vct )
+                {
+                  vct = ncvars[zvarid].vct;
+                  vctsize = ncvars[zvarid].vctsize;
 
-      /* check S->N */
-      if ( lgauss == FALSE )
-        {
-          for ( i = 0; i < ysize; i++ )
-            if ( fabs(yv[i] - yvals[ysize-i-1]) >
-                 ((yv[0] - yv[1])/500) ) break;
+                  if ( ncvars[zvarid].psvarid != -1 ) psvarid = ncvars[zvarid].psvarid;
+                }
 
-          if ( i == ysize ) lgauss = TRUE;
-        }
+	      cdf_get_var_double(ncvars[zvarid].ncid, zvarid, zvar);
 
-      Free(yv);
-    }
+	      if ( ncvars[zvarid].bounds != UNDEFID )
+		{
+		  nbdims = ncvars[ncvars[zvarid].bounds].ndims;
+		  if ( nbdims == 2 )
+		    {
+		      nlevel  = (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[0]].len;
+		      nvertex = (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[1]].len;
+		      if ( nlevel == zsize && nvertex == 2 )
+			{
+			  with_bounds = TRUE;
+			  lbounds = (double *) Malloc((size_t)nlevel*sizeof(double));
+			  ubounds = (double *) Malloc((size_t)nlevel*sizeof(double));
+			  double zbounds[2*nlevel];
+			  cdf_get_var_double(ncvars[zvarid].ncid, ncvars[zvarid].bounds, zbounds);
+			  for ( i = 0; i < nlevel; ++i )
+			    {
+			      lbounds[i] = zbounds[i*2];
+			      ubounds[i] = zbounds[i*2+1];
+			    }
+			}
+		    }
+		}
+	    }
+	  else
+	    {
+	      pname     = NULL;
+	      plongname = NULL;
+	      punits    = NULL;
 
-  return (lgauss);
-}
+	      if ( zsize == 1 )
+		{
+                  if ( ncvars[ncvarid].zaxistype != UNDEFID )
+                    zaxisType = ncvars[ncvarid].zaxistype;
+                  else
+                    zaxisType = ZAXIS_SURFACE;
 
-static
-void printNCvars(const ncvar_t *ncvars, int nvars, const char *oname)
-{
-  char axis[7];
-  int ncvarid, i;
-  int ndim;
-  static const char iaxis[] = {'t', 'z', 'y', 'x'};
+		  zvar[0] = 0;
+		  /*
+		  if ( zdimid == UNDEFID )
+		    zvar[0] = 9999;
+		  else
+		    zvar[0] = 0;
+		  */
+		}
+	      else
+		{
+		  for ( ilev = 0; ilev < zsize; ilev++ ) zvar[ilev] = ilev + 1;
+		}
+	    }
 
-  fprintf(stderr, "%s:\n", oname);
+      	  ncvars[ncvarid].zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, with_bounds, lbounds, ubounds,
+						(int)vctsize, vct, pname, plongname, punits, zprec, 1, 0);
 
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      ndim = 0;
-      if ( ncvars[ncvarid].isvar )
-        {
-          axis[ndim++] = 'v';
-          axis[ndim++] = ':';
-          for ( i = 0; i < ncvars[ncvarid].ndims; i++ )
-            {/*
-              if      ( ncvars[ncvarid].tvarid != -1 ) axis[ndim++] = iaxis[0];
-              else if ( ncvars[ncvarid].zvarid != -1 ) axis[ndim++] = iaxis[1];
-              else if ( ncvars[ncvarid].yvarid != -1 ) axis[ndim++] = iaxis[2];
-              else if ( ncvars[ncvarid].xvarid != -1 ) axis[ndim++] = iaxis[3];
-              else
-             */
-              if      ( ncvars[ncvarid].dimtype[i] == T_AXIS ) axis[ndim++] = iaxis[0];
-              else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) axis[ndim++] = iaxis[1];
-              else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) axis[ndim++] = iaxis[2];
-              else if ( ncvars[ncvarid].dimtype[i] == X_AXIS ) axis[ndim++] = iaxis[3];
-              else                                             axis[ndim++] = '?';
+	  if ( uuidOfVGrid[0] != 0 )
+            {
+              // printf("uuidOfVGrid: defined\n");
+              zaxisDefUUID(ncvars[ncvarid].zaxisID, uuidOfVGrid);
             }
-        }
-      else
-        {
-          axis[ndim++] = 'c';
-          axis[ndim++] = ':';
-          if      ( ncvars[ncvarid].istime ) axis[ndim++] = iaxis[0];
-          else if ( ncvars[ncvarid].islev  ) axis[ndim++] = iaxis[1];
-          else if ( ncvars[ncvarid].islat  ) axis[ndim++] = iaxis[2];
-          else if ( ncvars[ncvarid].islon  ) axis[ndim++] = iaxis[3];
-          else                               axis[ndim++] = '?';
-        }
 
-      axis[ndim++] = 0;
+          if ( zaxisType == ZAXIS_HYBRID && psvarid != -1 ) zaxisDefPsName(ncvars[ncvarid].zaxisID, ncvars[psvarid].name);
 
-      fprintf(stderr, "%3d %3d  %-6s %s\n", ncvarid, ndim-3, axis, ncvars[ncvarid].name);
+          if ( positive > 0 ) zaxisDefPositive(ncvars[ncvarid].zaxisID, positive);
+          if ( is_scalar ) zaxisDefScalar(ncvars[ncvarid].zaxisID);
+
+	  Free(zvar);
+	  Free(lbounds);
+	  Free(ubounds);
+
+	  zaxisindex = vlistZaxisIndex(vlistID, ncvars[ncvarid].zaxisID);
+	  streamptr->zaxisID[zaxisindex]  = zdimid;
+
+	  if ( CDI_Debug )
+	    Message("zaxisID %d %d %s", ncvars[ncvarid].zaxisID, ncvarid, ncvars[ncvarid].name);
+
+	  for ( ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
+	    if ( ncvars[ncvarid2].isvar == TRUE && ncvars[ncvarid2].zaxisID == UNDEFID /*&& ncvars[ncvarid2].zaxistype == UNDEFID*/ )
+	      {
+                int zvarid2 = UNDEFID;
+                if ( ncvars[ncvarid2].zvarid != UNDEFID && ncvars[ncvars[ncvarid2].zvarid].ndims == 0 )
+                  zvarid2 = ncvars[ncvarid2].zvarid;
+
+		int zdimid2 = UNDEFID;
+		ndims = ncvars[ncvarid2].ndims;
+		for ( i = 0; i < ndims; i++ )
+		  {
+		    if ( ncvars[ncvarid2].dimtype[i] == Z_AXIS )
+		      zdimid2 = ncvars[ncvarid2].dimids[i];
+		  }
+
+		if ( zdimid == zdimid2 /* && zvarid == zvarid2 */)
+		  {
+                    if ( (zdimid != UNDEFID && ncvars[ncvarid2].zaxistype == UNDEFID) ||
+                         (zdimid == UNDEFID && zvarid != UNDEFID && zvarid == zvarid2) ||
+                         (zdimid == UNDEFID && zaxisType == ncvars[ncvarid2].zaxistype) ||
+                         (zdimid == UNDEFID && zvarid2 == UNDEFID && ncvars[ncvarid2].zaxistype == UNDEFID) )
+                      {
+                        if ( CDI_Debug )
+                          Message("zaxisID %d %d %s", ncvars[ncvarid].zaxisID, ncvarid2, ncvars[ncvarid2].name);
+                        ncvars[ncvarid2].zaxisID = ncvars[ncvarid].zaxisID;
+                      }
+                  }
+	      }
+	}
     }
 }
 
-static
-void cdfScanVarAttributes(int nvars, ncvar_t *ncvars, ncdim_t *ncdims,
-                          int timedimid, int modelID, int format)
+struct varinfo
 {
-  int ncid;
-  int ncdimid;
-  int nvdims, nvatts;
-  int *dimidsp;
-  int iatt;
-  nc_type xtype, atttype;
-  size_t attlen;
-  char name[CDI_MAX_NAME];
-  char attname[CDI_MAX_NAME];
-  const int attstringlen = 8192; char attstring[8192];
+  int      ncvarid;
+  const char *name;
+};
 
-  int nchecked_vars = 0;
-  enum { max_check_vars = 9 };
-  char *checked_vars[max_check_vars];
-  for ( int i = 0; i < max_check_vars; ++i ) checked_vars[i] = NULL;
+static
+int cmpvarname(const void *s1, const void *s2)
+{
+  const struct varinfo *x = (const struct varinfo *)s1,
+    *y = (const struct varinfo *)s2;
+  return (strcmp(x->name, y->name));
+}
 
-  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+/* define all input data variables */
+static
+void define_all_vars(stream_t *streamptr, int vlistID, int instID, int modelID, int *varids, int nvars, int num_ncvars, ncvar_t *ncvars)
+{
+  if ( CDI_Debug )
     {
-      ncid    = ncvars[ncvarid].ncid;
-      dimidsp = ncvars[ncvarid].dimids;
+      for(int i = 0; i < nvars; i++) Message("varids[%d] = %d", i, varids[i]);
+    }
+  if ( streamptr->sortname )
+    {
+      struct varinfo *varInfo
+        = (struct varinfo *) Malloc((size_t)nvars * sizeof (struct varinfo));
 
-      cdf_inq_var(ncid, ncvarid, name, &xtype, &nvdims, dimidsp, &nvatts);
-      strcpy(ncvars[ncvarid].name, name);
+      for ( int varID = 0; varID < nvars; varID++ )
+	{
+	  int ncvarid = varids[varID];
+	  varInfo[varID].ncvarid = ncvarid;
+	  varInfo[varID].name = ncvars[ncvarid].name;
+	}
+      qsort(varInfo, (size_t)nvars, sizeof(varInfo[0]), cmpvarname);
+      for ( int varID = 0; varID < nvars; varID++ )
+	{
+	  varids[varID] = varInfo[varID].ncvarid;
+	}
+      Free(varInfo);
+      if ( CDI_Debug )
+        {
+          for(int i = 0; i < nvars; i++) Message("sorted varids[%d] = %d", i, varids[i]);
+        }
+    }
 
-      for ( ncdimid = 0; ncdimid < nvdims; ncdimid++ )
-        ncvars[ncvarid].dimtype[ncdimid] = -1;
+  for ( int varID1 = 0; varID1 < nvars; varID1++ )
+    {
+      int ncvarid = varids[varID1];
+      int gridID  = ncvars[ncvarid].gridID;
+      int zaxisID = ncvars[ncvarid].zaxisID;
 
-      ncvars[ncvarid].xtype = xtype;
-      ncvars[ncvarid].ndims = nvdims;
+      stream_new_var(streamptr, gridID, zaxisID, CDI_UNDEFID);
+      int varID = vlistDefVar(vlistID, gridID, zaxisID, ncvars[ncvarid].tsteptype);
 
 #if  defined  (HAVE_NETCDF4)
-      if ( format == NC_FORMAT_NETCDF4_CLASSIC || format == NC_FORMAT_NETCDF4 )
-        {
-          char buf[CDI_MAX_NAME];
-          int shuffle, deflate, deflate_level;
-          size_t chunks[nvdims];
-          int storage_in;
-          nc_inq_var_deflate(ncid, ncvarid, &shuffle, &deflate, &deflate_level);
-          if ( deflate > 0 ) ncvars[ncvarid].deflate = 1;
+      if ( ncvars[ncvarid].deflate )
+	vlistDefVarCompType(vlistID, varID, COMPRESS_ZIP);
 
-          if ( nc_inq_var_chunking(ncid, ncvarid, &storage_in, chunks) == NC_NOERR )
-            {
-              if ( storage_in == NC_CHUNKED )
-                {
-                  ncvars[ncvarid].chunked = 1;
-                  for ( int i = 0; i < nvdims; ++i ) ncvars[ncvarid].chunks[i] = (int)chunks[i];
-                  if ( CDI_Debug )
-                    {
-                      fprintf(stderr, "%s: chunking %d %d %d  chunks ", name, storage_in, NC_CONTIGUOUS, NC_CHUNKED);
-                      for ( int i = 0; i < nvdims; ++i ) fprintf(stderr, "%ld ", chunks[i]);
-                      fprintf(stderr, "\n");
-                    }
-                  strcat(ncvars[ncvarid].extra, "chunks=");
-                  for ( int i = nvdims-1; i >= 0; --i )
-                    {
-                      sprintf(buf, "%ld", (long) chunks[i]);
-                      strcat(ncvars[ncvarid].extra, buf);
-                      if ( i > 0 ) strcat(ncvars[ncvarid].extra, "x");
-                    }
-                  strcat(ncvars[ncvarid].extra, " ");
-                }
-            }
-        }
+      if ( ncvars[ncvarid].chunked && ncvars[ncvarid].chunktype != UNDEFID )
+        vlistDefVarChunkType(vlistID, varID, ncvars[ncvarid].chunktype);
 #endif
 
-      if ( nvdims > 0 )
+      streamptr->vars[varID1].defmiss = 0;
+      streamptr->vars[varID1].ncvarid = ncvarid;
+
+      vlistDefVarName(vlistID, varID, ncvars[ncvarid].name);
+      if ( ncvars[ncvarid].param != UNDEFID ) vlistDefVarParam(vlistID, varID, ncvars[ncvarid].param);
+      if ( ncvars[ncvarid].code != UNDEFID )  vlistDefVarCode(vlistID, varID, ncvars[ncvarid].code);
+      if ( ncvars[ncvarid].code != UNDEFID )
+	{
+	  int param = cdiEncodeParam(ncvars[ncvarid].code, ncvars[ncvarid].tabnum, 255);
+	  vlistDefVarParam(vlistID, varID, param);
+	}
+      if ( ncvars[ncvarid].longname[0] )  vlistDefVarLongname(vlistID, varID, ncvars[ncvarid].longname);
+      if ( ncvars[ncvarid].stdname[0] )   vlistDefVarStdname(vlistID, varID, ncvars[ncvarid].stdname);
+      if ( ncvars[ncvarid].units[0] )     vlistDefVarUnits(vlistID, varID, ncvars[ncvarid].units);
+
+      if ( ncvars[ncvarid].lvalidrange )
+        vlistDefVarValidrange(vlistID, varID, ncvars[ncvarid].validrange);
+
+      if ( IS_NOT_EQUAL(ncvars[ncvarid].addoffset, 0) )
+	vlistDefVarAddoffset(vlistID, varID, ncvars[ncvarid].addoffset);
+      if ( IS_NOT_EQUAL(ncvars[ncvarid].scalefactor, 1) )
+	vlistDefVarScalefactor(vlistID, varID, ncvars[ncvarid].scalefactor);
+
+      vlistDefVarDatatype(vlistID, varID, cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned));
+
+      vlistDefVarInstitut(vlistID, varID, instID);
+      vlistDefVarModel(vlistID, varID, modelID);
+      if ( ncvars[ncvarid].tableID != UNDEFID )
+	vlistDefVarTable(vlistID, varID, ncvars[ncvarid].tableID);
+
+      if ( ncvars[ncvarid].deffillval == FALSE && ncvars[ncvarid].defmissval == TRUE )
         {
-          if ( timedimid == dimidsp[0] )
-            {
-              ncvars[ncvarid].tsteptype = TSTEP_INSTANT;
-              cdfSetDim(ncvars, ncvarid, 0, T_AXIS);
-            }
-          else
-            {
-              for ( ncdimid = 1; ncdimid < nvdims; ncdimid++ )
-                {
-                  if ( timedimid == dimidsp[ncdimid] )
-                    {
-                      Warning("Time must be the first dimension! Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                      ncvars[ncvarid].isvar = FALSE;
-                    }
-                }
-            }
+          ncvars[ncvarid].deffillval = TRUE;
+          ncvars[ncvarid].fillval    = ncvars[ncvarid].missval;
         }
 
-      for ( iatt = 0; iatt < nvatts; iatt++ )
-        {
-          cdf_inq_attname(ncid, ncvarid, iatt, attname);
-          cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
-          cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
+      if ( ncvars[ncvarid].deffillval == TRUE )
+        vlistDefVarMissval(vlistID, varID, ncvars[ncvarid].fillval);
 
-          if ( strcmp(attname, "long_name") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, CDI_MAX_NAME, ncvars[ncvarid].longname);
-            }
-          else if ( strcmp(attname, "standard_name") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, CDI_MAX_NAME, ncvars[ncvarid].stdname);
-            }
-          else if ( strcmp(attname, "units") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, CDI_MAX_NAME, ncvars[ncvarid].units);
-            }
-          else if ( strcmp(attname, "calendar") == 0 )
-            {
-              ncvars[ncvarid].calendar = TRUE;
-            }
-          else if ( strcmp(attname, "param") == 0 && xtypeIsText(atttype) )
-            {
-	      char paramstr[32];
-	      int pnum = 0, pcat = 255, pdis = 255;
-              cdfGetAttText(ncid, ncvarid, attname, sizeof(paramstr), paramstr);
-	      sscanf(paramstr, "%d.%d.%d", &pnum, &pcat, &pdis);
-	      ncvars[ncvarid].param = cdiEncodeParam(pnum, pcat, pdis);
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "code") == 0 && !xtypeIsText(atttype) )
-            {
-              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].code);
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "table") == 0 && !xtypeIsText(atttype) )
-            {
-              int tablenum;
-              cdfGetAttInt(ncid, ncvarid, attname, 1, &tablenum);
-              if ( tablenum > 0 )
-                {
-                  ncvars[ncvarid].tabnum = tablenum;
-                  ncvars[ncvarid].tableID = tableInq(modelID, tablenum, NULL);
-                  if ( ncvars[ncvarid].tableID == CDI_UNDEFID )
-                    ncvars[ncvarid].tableID = tableDef(modelID, tablenum, NULL);
-                }
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "trunc_type") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              if ( memcmp(attstring, "Triangular", attlen) == 0 )
-                ncvars[ncvarid].gridtype = GRID_SPECTRAL;
-            }
-          else if ( strcmp(attname, "grid_type") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              strtolower(attstring);
+      if ( CDI_Debug )
+	Message("varID = %d  gridID = %d  zaxisID = %d", varID,
+		vlistInqVarGrid(vlistID, varID), vlistInqVarZaxis(vlistID, varID));
 
-              if      ( strcmp(attstring, "gaussian reduced") == 0 )
-                ncvars[ncvarid].gridtype = GRID_GAUSSIAN_REDUCED;
-              else if ( strcmp(attstring, "gaussian") == 0 )
-                ncvars[ncvarid].gridtype = GRID_GAUSSIAN;
-              else if ( strncmp(attstring, "spectral", 8) == 0 )
-                ncvars[ncvarid].gridtype = GRID_SPECTRAL;
-              else if ( strncmp(attstring, "fourier", 7) == 0 )
-                ncvars[ncvarid].gridtype = GRID_FOURIER;
-              else if ( strcmp(attstring, "trajectory") == 0 )
-                ncvars[ncvarid].gridtype = GRID_TRAJECTORY;
-              else if ( strcmp(attstring, "generic") == 0 )
-                ncvars[ncvarid].gridtype = GRID_GENERIC;
-              else if ( strcmp(attstring, "cell") == 0 )
-                ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
-              else if ( strcmp(attstring, "unstructured") == 0 )
-                ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
-              else if ( strcmp(attstring, "curvilinear") == 0 )
-                ncvars[ncvarid].gridtype = GRID_CURVILINEAR;
-              else if ( strcmp(attstring, "sinusoidal") == 0 )
-                ;
-              else if ( strcmp(attstring, "laea") == 0 )
-                ;
-              else if ( strcmp(attstring, "lcc2") == 0 )
-                ;
-              else if ( strcmp(attstring, "linear") == 0 ) // ignore grid type linear
-                ;
-              else
-                {
-                  static int warn = TRUE;
-                  if ( warn )
-                    {
-                      warn = FALSE;
-                      Warning("netCDF attribute grid_type='%s' unsupported!", attstring);
-                    }
-                }
+      int gridindex = vlistGridIndex(vlistID, gridID);
+      int xdimid = streamptr->xdimID[gridindex];
+      int ydimid = streamptr->ydimID[gridindex];
 
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "level_type") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              strtolower(attstring);
+      int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+      int zdimid = streamptr->zaxisID[zaxisindex];
 
-              if      ( strcmp(attstring, "toa") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_TOA;
-              else if ( strcmp(attstring, "cloudbase") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_CLOUD_BASE;
-              else if ( strcmp(attstring, "cloudtop") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_CLOUD_TOP;
-              else if ( strcmp(attstring, "isotherm0") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_ISOTHERM_ZERO;
-              else if ( strcmp(attstring, "seabottom") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_SEA_BOTTOM;
-              else if ( strcmp(attstring, "lakebottom") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_LAKE_BOTTOM;
-              else if ( strcmp(attstring, "sedimentbottom") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_SEDIMENT_BOTTOM;
-              else if ( strcmp(attstring, "sedimentbottomta") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;
-              else if ( strcmp(attstring, "sedimentbottomtw") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;
-              else if ( strcmp(attstring, "mixlayer") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_MIX_LAYER;
-              else if ( strcmp(attstring, "atmosphere") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_ATMOSPHERE;
-              else
-                {
-                  static int warn = TRUE;
-                  if ( warn )
-                    {
-                      warn = FALSE;
-                      Warning("netCDF attribute level_type='%s' unsupported!", attstring);
-                    }
-                }
+      int ndims = ncvars[ncvarid].ndims;
+      int iodim = 0;
+      int ixyz = 0;
+      int ipow10[4] = {1, 10, 100, 1000};
 
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "trunc_count") == 0 && !xtypeIsText(atttype) )
+      if ( ncvars[ncvarid].tsteptype != TSTEP_CONSTANT ) iodim++;
+
+      if ( gridInqType(gridID) == GRID_UNSTRUCTURED && ndims-iodim <= 2 && ydimid == xdimid )
+        {
+          if ( xdimid == ncvars[ncvarid].dimids[ndims-1] )
             {
-              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
+              ixyz = 321;
             }
-          else if ( strcmp(attname, "truncation") == 0 && !xtypeIsText(atttype) )
+          else
             {
-              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
+              ixyz = 213;
             }
-          else if ( strcmp(attname, "number_of_grid_in_reference") == 0 && !xtypeIsText(atttype) )
+        }
+      else
+        {
+          for ( int idim = iodim; idim < ndims; idim++ )
             {
-              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].position);
+              if      ( xdimid == ncvars[ncvarid].dimids[idim] )
+                ixyz += 1*ipow10[ndims-idim-1];
+              else if ( ydimid == ncvars[ncvarid].dimids[idim] )
+                ixyz += 2*ipow10[ndims-idim-1];
+              else if ( zdimid == ncvars[ncvarid].dimids[idim] )
+                ixyz += 3*ipow10[ndims-idim-1];
             }
-          else if ( strcmp(attname, "add_offset") == 0 && !xtypeIsText(atttype) )
-            {
-	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].addoffset);
-	      /*
-		if ( atttype != NC_BYTE && atttype != NC_SHORT && atttype != NC_INT )
-		if ( ncvars[ncvarid].addoffset != 0 )
-		Warning("attribute add_offset not supported for atttype %d", atttype);
-	      */
-	      /* (also used for lon/lat) cdfSetVar(ncvars, ncvarid, TRUE); */
-            }
-          else if ( strcmp(attname, "scale_factor") == 0 && !xtypeIsText(atttype) )
-            {
-	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].scalefactor);
+        }
+
+      vlistDefVarXYZ(vlistID, varID, ixyz);
+      /*
+      printf("ixyz %d\n", ixyz);
+      printf("ndims %d\n", ncvars[ncvarid].ndims);
+      for ( int i = 0; i < ncvars[ncvarid].ndims; ++i )
+        printf("dimids: %d %d\n", i, ncvars[ncvarid].dimids[i]);
+      printf("xdimid, ydimid %d %d\n", xdimid, ydimid);
+      */
+      if ( ncvars[ncvarid].ensdata != NULL )
+        {
+          vlistDefVarEnsemble( vlistID, varID, ncvars[ncvarid].ensdata->ens_index,
+                               ncvars[ncvarid].ensdata->ens_count,
+                               ncvars[ncvarid].ensdata->forecast_init_type );
+          Free(ncvars[ncvarid].ensdata);
+          ncvars[ncvarid].ensdata = NULL;
+        }
+
+      if ( ncvars[ncvarid].extra[0] != 0 )
+        {
+          vlistDefVarExtra(vlistID, varID, ncvars[ncvarid].extra);
+        }
+    }
+
+  for ( int varID = 0; varID < nvars; varID++ )
+    {
+      int ncvarid = varids[varID];
+      int ncid = ncvars[ncvarid].ncid;
+
+      if ( ncvars[ncvarid].natts )
+	{
+	  int attnum;
+	  int iatt;
+	  nc_type attrtype;
+	  size_t attlen;
+	  char attname[CDI_MAX_NAME];
+	  const int attstringlen = 8192; char attstring[8192];
+	  int nvatts = ncvars[ncvarid].natts;
+
+	  for ( iatt = 0; iatt < nvatts; iatt++ )
+	    {
+	      attnum = ncvars[ncvarid].atts[iatt];
+	      cdf_inq_attname(ncid, ncvarid, attnum, attname);
+	      cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
+	      cdf_inq_atttype(ncid, ncvarid, attname, &attrtype);
+
+	      if ( attrtype == NC_SHORT || attrtype == NC_INT )
+		{
+		  int attint[attlen];
+		  cdfGetAttInt(ncid, ncvarid, attname, (int)attlen, attint);
+		  if ( attrtype == NC_SHORT )
+		    vlistDefAttInt(vlistID, varID, attname, DATATYPE_INT16, (int)attlen, attint);
+		  else
+		    vlistDefAttInt(vlistID, varID, attname, DATATYPE_INT32, (int)attlen, attint);
+		}
+	      else if ( attrtype == NC_FLOAT || attrtype == NC_DOUBLE )
+		{
+		  double attflt[attlen];
+		  cdfGetAttDouble(ncid, ncvarid, attname, (int)attlen, attflt);
+		  if ( attrtype == NC_FLOAT )
+		    vlistDefAttFlt(vlistID, varID, attname, DATATYPE_FLT32, (int)attlen, attflt);
+		  else
+		    vlistDefAttFlt(vlistID, varID, attname, DATATYPE_FLT64, (int)attlen, attflt);
+		}
+	      else if ( xtypeIsText(attrtype) )
+		{
+		  cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
+		  vlistDefAttTxt(vlistID, varID, attname, (int)attlen, attstring);
+		}
+	      else
+		{
+		  if ( CDI_Debug ) printf("att: %s.%s = unknown\n", ncvars[ncvarid].name, attname);
+		}
+	    }
+
+	  if (ncvars[ncvarid].vct) Free(ncvars[ncvarid].vct);
+	  if (ncvars[ncvarid].atts) Free(ncvars[ncvarid].atts);
+          ncvars[ncvarid].vct = NULL;
+          ncvars[ncvarid].atts = NULL;
+	}
+    }
+
+  /* release mem of not freed attributes */
+  for ( int ncvarid = 0; ncvarid < num_ncvars; ncvarid++ )
+    if ( ncvars[ncvarid].atts ) Free(ncvars[ncvarid].atts);
+
+  if ( varids ) Free(varids);
+
+  for ( int varID = 0; varID < nvars; varID++ )
+    {
+      if ( vlistInqVarCode(vlistID, varID) == -varID-1 )
+	{
+	  const char *pname = vlistInqVarNamePtr(vlistID, varID);
+	  size_t len = strlen(pname);
+	  if ( len > 3 && isdigit((int) pname[3]) )
+	    {
+	      if ( memcmp("var", pname, 3) == 0 )
+		{
+		  vlistDefVarCode(vlistID, varID, atoi(pname+3));
+                  // vlistDestroyVarName(vlistID, varID);
+		}
+	    }
+	  else if ( len > 4 && isdigit((int) pname[4]) )
+	    {
+	      if ( memcmp("code", pname, 4) == 0 )
+		{
+		  vlistDefVarCode(vlistID, varID, atoi(pname+4));
+		  // vlistDestroyVarName(vlistID, varID);
+		}
+	    }
+	  else if ( len > 5 && isdigit((int) pname[5]) )
+	    {
+	      if ( memcmp("param", pname, 5) == 0 )
+		{
+		  int pnum = -1, pcat = 255, pdis = 255;
+		  sscanf(pname+5, "%d.%d.%d", &pnum, &pcat, &pdis);
+		  vlistDefVarParam(vlistID, varID, cdiEncodeParam(pnum, pcat, pdis));
+                  // vlistDestroyVarName(vlistID, varID);
+		}
+	    }
+	}
+    }
+
+  for ( int varID = 0; varID < nvars; varID++ )
+    {
+      int varInstID  = vlistInqVarInstitut(vlistID, varID);
+      int varModelID = vlistInqVarModel(vlistID, varID);
+      int varTableID = vlistInqVarTable(vlistID, varID);
+      int code = vlistInqVarCode(vlistID, varID);
+      if ( cdiDefaultTableID != UNDEFID )
+	{
+	  if ( tableInqParNamePtr(cdiDefaultTableID, code) )
+	    {
+	      vlistDestroyVarName(vlistID, varID);
+	      vlistDestroyVarLongname(vlistID, varID);
+	      vlistDestroyVarUnits(vlistID, varID);
+
+	      if ( varTableID != UNDEFID )
+		{
+		  vlistDefVarName(vlistID, varID, tableInqParNamePtr(cdiDefaultTableID, code));
+		  if ( tableInqParLongnamePtr(cdiDefaultTableID, code) )
+		    vlistDefVarLongname(vlistID, varID, tableInqParLongnamePtr(cdiDefaultTableID, code));
+		  if ( tableInqParUnitsPtr(cdiDefaultTableID, code) )
+		    vlistDefVarUnits(vlistID, varID, tableInqParUnitsPtr(cdiDefaultTableID, code));
+		}
+	      else
+		{
+		  varTableID = cdiDefaultTableID;
+		}
+	    }
+
+	  if ( cdiDefaultModelID != UNDEFID ) varModelID = cdiDefaultModelID;
+	  if ( cdiDefaultInstID  != UNDEFID ) varInstID  = cdiDefaultInstID;
+	}
+      if ( varInstID  != UNDEFID ) vlistDefVarInstitut(vlistID, varID, varInstID);
+      if ( varModelID != UNDEFID ) vlistDefVarModel(vlistID, varID, varModelID);
+      if ( varTableID != UNDEFID ) vlistDefVarTable(vlistID, varID, varTableID);
+    }
+}
+
+static
+void scan_global_attributes(int fileID, int vlistID, stream_t *streamptr, int ngatts, int *instID, int *modelID, int *ucla_les, unsigned char *uuidOfHGrid, unsigned char *uuidOfVGrid, char *gridfile, int *number_of_grid_used)
+{
+  nc_type xtype;
+  size_t attlen;
+  char attname[CDI_MAX_NAME];
+  enum { attstringlen = 65636 };
+  char attstring[attstringlen];
+  int iatt;
+
+  for ( iatt = 0; iatt < ngatts; iatt++ )
+    {
+      cdf_inq_attname(fileID, NC_GLOBAL, iatt, attname);
+      cdf_inq_atttype(fileID, NC_GLOBAL, attname, &xtype);
+      cdf_inq_attlen(fileID, NC_GLOBAL, attname, &attlen);
+
+      if ( xtypeIsText(xtype) )
+	{
+	  cdfGetAttText(fileID, NC_GLOBAL, attname, attstringlen, attstring);
+
+          size_t attstrlen = strlen(attstring);
+
+	  if ( attlen > 0 && attstring[0] != 0 )
+	    {
+	      if ( strcmp(attname, "history") == 0 )
+		{
+		  streamptr->historyID = iatt;
+		}
+	      else if ( strcmp(attname, "institution") == 0 )
+		{
+		  *instID = institutInq(0, 0, NULL, attstring);
+		  if ( *instID == UNDEFID )
+		    *instID = institutDef(0, 0, NULL, attstring);
+		}
+	      else if ( strcmp(attname, "source") == 0 )
+		{
+		  *modelID = modelInq(-1, 0, attstring);
+		  if ( *modelID == UNDEFID )
+		    *modelID = modelDef(-1, 0, attstring);
+		}
+	      else if ( strcmp(attname, "Source") == 0 )
+		{
+		  if ( strncmp(attstring, "UCLA-LES", 8) == 0 )
+		    *ucla_les = TRUE;
+		}
 	      /*
-		if ( atttype != NC_BYTE && atttype != NC_SHORT && atttype != NC_INT )
-		if ( ncvars[ncvarid].scalefactor != 1 )
-		Warning("attribute scale_factor not supported for atttype %d", atttype);
+	      else if ( strcmp(attname, "Conventions") == 0 )
+		{
+		}
 	      */
-	      /* (also used for lon/lat) cdfSetVar(ncvars, ncvarid, TRUE); */
-            }
-          else if ( strcmp(attname, "climatology") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              int ncboundsid;
-              int status = nc_inq_varid(ncid, attstring, &ncboundsid);
-              if ( status == NC_NOERR )
-                {
-                  ncvars[ncvarid].climatology = TRUE;
-                  ncvars[ncvarid].bounds = ncboundsid;
-                  cdfSetVar(ncvars, ncvars[ncvarid].bounds, FALSE);
-                  cdfSetVar(ncvars, ncvarid, FALSE);
-                }
-              else
-                Warning("%s - %s", nc_strerror(status), attstring);
-            }
-          else if ( xtypeIsText(atttype) && strcmp(attname, "bounds") == 0 )
+	      else if ( strcmp(attname, "CDI") == 0 )
+		{
+		}
+	      else if ( strcmp(attname, "CDO") == 0 )
+		{
+		}
+              /*
+	      else if ( strcmp(attname, "forecast_reference_time") == 0 )
+		{
+                  memcpy(fcreftime, attstring, attstrlen+1);
+		}
+              */
+	      else if ( strcmp(attname, "grid_file_uri") == 0 )
+		{
+                  memcpy(gridfile, attstring, attstrlen+1);
+		}
+	      else if ( strcmp(attname, "uuidOfHGrid") == 0 && attstrlen == 36 )
+		{
+                  attstring[36] = 0;
+                  cdiStr2UUID(attstring, uuidOfHGrid);
+                  //   printf("uuid: %d %s\n", attlen, attstring);
+		}
+	      else if ( strcmp(attname, "uuidOfVGrid") == 0 && attstrlen == 36 )
+		{
+                  attstring[36] = 0;
+                  cdiStr2UUID(attstring, uuidOfVGrid);
+		}
+	      else
+		{
+                  if ( strcmp(attname, "ICON_grid_file_uri") == 0 && gridfile[0] == 0 )
+                    {
+                      memcpy(gridfile, attstring, attstrlen+1);
+                    }
+
+		  vlistDefAttTxt(vlistID, CDI_GLOBAL, attname, (int)attstrlen, attstring);
+		}
+	    }
+	}
+      else if ( xtype == NC_SHORT || xtype == NC_INT )
+	{
+	  if ( strcmp(attname, "number_of_grid_used") == 0 )
+	    {
+	      (*number_of_grid_used) = UNDEFID;
+	      cdfGetAttInt(fileID, NC_GLOBAL, attname, 1, number_of_grid_used);
+	    }
+ 	  else
             {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              int ncboundsid;
-              int status = nc_inq_varid(ncid, attstring, &ncboundsid);
-              if ( status == NC_NOERR )
-                {
-                  ncvars[ncvarid].bounds = ncboundsid;
-                  cdfSetVar(ncvars, ncvars[ncvarid].bounds, FALSE);
-                  cdfSetVar(ncvars, ncvarid, FALSE);
-                }
+              int attint[attlen];
+              cdfGetAttInt(fileID, NC_GLOBAL, attname, (int)attlen, attint);
+              if ( xtype == NC_SHORT )
+                vlistDefAttInt(vlistID, CDI_GLOBAL, attname, DATATYPE_INT16, (int)attlen, attint);
               else
-                Warning("%s - %s", nc_strerror(status), attstring);
-            }
-          else if ( xtypeIsText(atttype) && strcmp(attname, "formula_terms") == 0 )
-            {
-              ncvars[ncvarid].lformulaterms = TRUE;
+                vlistDefAttInt(vlistID, CDI_GLOBAL, attname, DATATYPE_INT32, (int)attlen, attint);
             }
-          else if ( xtypeIsText(atttype) && strcmp(attname, "formula") == 0 )
+        }
+      else if ( xtype == NC_FLOAT || xtype == NC_DOUBLE )
+	{
+	  double attflt[attlen];
+	  cdfGetAttDouble(fileID, NC_GLOBAL, attname, (int)attlen, attflt);
+	  if ( xtype == NC_FLOAT )
+	    vlistDefAttFlt(vlistID, CDI_GLOBAL, attname, DATATYPE_FLT32, (int)attlen, attflt);
+	  else
+	    vlistDefAttFlt(vlistID, CDI_GLOBAL, attname, DATATYPE_FLT64, (int)attlen, attflt);
+	}
+    }
+}
+
+static
+int find_leadtime(int nvars, ncvar_t *ncvars)
+{
+  int leadtime_id = UNDEFID;
+
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].stdname[0] )
+        {
+          if ( strcmp(ncvars[ncvarid].stdname, "forecast_period") == 0 )
             {
-              ncvars[ncvarid].lformula = TRUE;
+              leadtime_id = ncvarid;
+              break;
             }
-          else if ( strcmp(attname, "cell_measures") == 0 && xtypeIsText(atttype) )
-            {
-              char *cell_measures = NULL, *cell_var = NULL;
+        }
+    }
 
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              char *pstring = attstring;
+  return (leadtime_id);
+}
 
-              while ( isspace((int) *pstring) ) pstring++;
-              cell_measures = pstring;
-              while ( isalnum((int) *pstring) ) pstring++;
-              *pstring++ = 0;
-              while ( isspace((int) *pstring) ) pstring++;
-              cell_var = pstring;
-              while ( ! isspace((int) *pstring) && *pstring != 0 ) pstring++;
-              *pstring++ = 0;
-              /*
-              printf("cell_measures >%s<\n", cell_measures);
-              printf("cell_var >%s<\n", cell_var);
-              */
-              if ( memcmp(cell_measures, "area", 4) == 0 )
+static
+void find_time_vars(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimid, stream_t *streamptr,
+                    int *time_has_units, int *time_has_bounds, int *time_climatology)
+{
+  int ncvarid;
+
+  if ( timedimid == UNDEFID )
+    {
+      char timeunits[CDI_MAX_NAME];
+
+      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+        {
+          if ( ncvars[ncvarid].ndims == 0 && strcmp(ncvars[ncvarid].name, "time") == 0 )
+            {
+              if ( ncvars[ncvarid].units[0] )
                 {
-                  int nc_cell_id;
-                  int status = nc_inq_varid(ncid, cell_var, &nc_cell_id);
-                  if ( status == NC_NOERR )
+                  strcpy(timeunits, ncvars[ncvarid].units);
+                  strtolower(timeunits);
+
+                  if ( isTimeUnits(timeunits) )
                     {
-                      ncvars[ncvarid].cellarea = nc_cell_id;
-                      /* ncvars[nc_cell_id].isvar = UNDEFID; */
-                      cdfSetVar(ncvars, nc_cell_id, FALSE);
+                      streamptr->basetime.ncvarid = ncvarid;
+                      break;
                     }
-                  else
-                    Warning("%s - %s", nc_strerror(status), cell_var);
                 }
-              else
-                {
-                  Warning("%s has an unexpected contents: %s", attname, cell_measures);
-                }
-              cdfSetVar(ncvars, ncvarid, TRUE);
             }
-          /*
-          else if ( strcmp(attname, "coordinates") == 0 )
-            {
-              char *pstring, *xvarname = NULL, *yvarname = NULL;
+        }
+    }
+  else
+    {
+      int ltimevar = FALSE;
 
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              pstring = attstring;
+      if ( ncdims[timedimid].ncvarid != UNDEFID )
+        {
+          streamptr->basetime.ncvarid = ncdims[timedimid].ncvarid;
+          ltimevar = TRUE;
+        }
 
-              while ( isspace((int) *pstring) ) pstring++;
-              xvarname = pstring;
-              while ( isgraph((int) *pstring) ) pstring++;
-              *pstring++ = 0;
-              while ( isspace((int) *pstring) ) pstring++;
-              yvarname = pstring;
-              while ( isgraph((int) *pstring) ) pstring++;
-              *pstring++ = 0;
+      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+        if ( ncvarid != streamptr->basetime.ncvarid &&
+             ncvars[ncvarid].ndims == 1 &&
+             timedimid == ncvars[ncvarid].dimids[0] &&
+             !xtypeIsText(ncvars[ncvarid].xtype) &&
+             isTimeAxisUnits(ncvars[ncvarid].units) )
+          {
+            ncvars[ncvarid].isvar = FALSE;
 
-              cdf_inq_varid(ncid, xvarname, &ncvars[ncvarid].xvarid);
-              cdf_inq_varid(ncid, yvarname, &ncvars[ncvarid].yvarid);
+            if ( !ltimevar )
+              {
+                streamptr->basetime.ncvarid = ncvarid;
+                ltimevar = TRUE;
+                if ( CDI_Debug )
+                  fprintf(stderr, "timevar %s\n", ncvars[ncvarid].name);
+              }
+            else
+              {
+                Warning("Found more than one time variable, skipped variable %s!", ncvars[ncvarid].name);
+              }
+          }
 
-              cdfSetVar(ncvars, ncvars[ncvarid].xvarid, FALSE);
-              cdfSetVar(ncvars, ncvars[ncvarid].yvarid, FALSE);
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          */
-          else if ( (strcmp(attname, "associate")  == 0 || strcmp(attname, "coordinates") == 0) && xtypeIsText(atttype) )
+      if ( ltimevar == FALSE ) /* search for WRF time description */
+        {
+          for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+            if ( ncvarid != streamptr->basetime.ncvarid &&
+                 ncvars[ncvarid].ndims == 2 &&
+                 timedimid == ncvars[ncvarid].dimids[0] &&
+                 xtypeIsText(ncvars[ncvarid].xtype) &&
+                 ncdims[ncvars[ncvarid].dimids[1]].len == 19 )
+              {
+                streamptr->basetime.ncvarid = ncvarid;
+                streamptr->basetime.lwrf    = TRUE;
+                break;
+              }
+        }
+
+      /* time varID */
+      ncvarid = streamptr->basetime.ncvarid;
+
+      if ( ncvarid == UNDEFID )
+        {
+          Warning("Time variable >%s< not found!", ncdims[timedimid].name);
+        }
+    }
+
+  /* time varID */
+  ncvarid = streamptr->basetime.ncvarid;
+
+  if ( ncvarid != UNDEFID && streamptr->basetime.lwrf == FALSE )
+    {
+      if ( ncvars[ncvarid].units[0] != 0 ) *time_has_units = TRUE;
+
+      if ( ncvars[ncvarid].bounds != UNDEFID )
+        {
+          int nbdims = ncvars[ncvars[ncvarid].bounds].ndims;
+          if ( nbdims == 2 )
             {
-              int status;
-              char *varname = NULL;
-              int lstop = FALSE;
-              int dimvarid;
+              int len = (int) ncdims[ncvars[ncvars[ncvarid].bounds].dimids[nbdims-1]].len;
+              if ( len == 2 && timedimid == ncvars[ncvars[ncvarid].bounds].dimids[0] )
+                {
+                  *time_has_bounds = TRUE;
+                  streamptr->basetime.ncvarboundsid = ncvars[ncvarid].bounds;
+                  if ( ncvars[ncvarid].climatology ) *time_climatology = TRUE;
+                }
+            }
+        }
+    }
+}
 
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              char *pstring = attstring;
+static
+void read_vct_echam(int fileID, int nvars, ncvar_t *ncvars, ncdim_t *ncdims, double **vct, size_t *pvctsize)
+{
+  /* find ECHAM VCT */
+  int nvcth_id = UNDEFID, vcta_id = UNDEFID, vctb_id = UNDEFID;
 
-              for ( int i = 0; i < MAX_COORDVARS; i++ )
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].ndims == 1 )
+        {
+          size_t len = strlen(ncvars[ncvarid].name);
+          if ( len == 4 && ncvars[ncvarid].name[0] == 'h' && ncvars[ncvarid].name[1] == 'y' )
+            {
+              if ( ncvars[ncvarid].name[2] == 'a' && ncvars[ncvarid].name[3] == 'i' ) // hyai
                 {
-                  while ( isspace((int) *pstring) ) pstring++;
-                  if ( *pstring == 0 ) break;
-                  varname = pstring;
-                  while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
-                  if ( *pstring == 0 ) lstop = TRUE;
-                  *pstring++ = 0;
+                  vcta_id = ncvarid;
+                  nvcth_id = ncvars[ncvarid].dimids[0];
+                  ncvars[ncvarid].isvar = FALSE;
+                }
+              else if ( ncvars[ncvarid].name[2] == 'b' && ncvars[ncvarid].name[3] == 'i' ) //hybi
+                {
+                  vctb_id = ncvarid;
+                  nvcth_id = ncvars[ncvarid].dimids[0];
+                  ncvars[ncvarid].isvar = FALSE;
+                }
+              else if ( (ncvars[ncvarid].name[2] == 'a' || ncvars[ncvarid].name[2] == 'b') && ncvars[ncvarid].name[3] == 'm' )
+                {
+                  ncvars[ncvarid].isvar = FALSE; // hyam or hybm
+                }
+            }
+	}
+    }
+
+  /* read VCT */
+  if ( nvcth_id != UNDEFID && vcta_id != UNDEFID && vctb_id != UNDEFID )
+    {
+      size_t vctsize = ncdims[nvcth_id].len;
+      vctsize *= 2;
+      *vct = (double *) Malloc(vctsize*sizeof(double));
+      cdf_get_var_double(fileID, vcta_id, *vct);
+      cdf_get_var_double(fileID, vctb_id, *vct+vctsize/2);
+      *pvctsize = vctsize;
+    }
+}
+
+
+int cdfInqContents(stream_t *streamptr)
+{
+  int ndims, nvars, ngatts, unlimdimid;
+  int ncvarid;
+  int ncdimid;
+  size_t ntsteps;
+  int timedimid = -1;
+  int *varids;
+  int nvarids;
+  int time_has_units = FALSE;
+  int time_has_bounds = FALSE;
+  int time_climatology = FALSE;
+  int leadtime_id = UNDEFID;
+  int nvars_data;
+  int instID  = UNDEFID;
+  int modelID = UNDEFID;
+  int taxisID;
+  int i;
+  int calendar = UNDEFID;
+  ncdim_t *ncdims;
+  ncvar_t *ncvars = NULL;
+  int format = 0;
+  int ucla_les = FALSE;
+  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
+  unsigned char uuidOfVGrid[CDI_UUID_SIZE];
+  char gridfile[8912];
+  char fcreftime[CDI_MAX_NAME];
+  int number_of_grid_used = UNDEFID;
+
+  memset(uuidOfHGrid, 0, CDI_UUID_SIZE);
+  memset(uuidOfVGrid, 0, CDI_UUID_SIZE);
+  gridfile[0] = 0;
+  fcreftime[0] = 0;
+
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+
+  if ( CDI_Debug ) Message("streamID = %d, fileID = %d", streamptr->self, fileID);
+
+#if  defined  (HAVE_NETCDF4)
+  nc_inq_format(fileID, &format);
+#endif
+
+  cdf_inq(fileID, &ndims , &nvars, &ngatts, &unlimdimid);
+
+  if ( CDI_Debug )
+    Message("root: ndims %d, nvars %d, ngatts %d", ndims, nvars, ngatts);
+
+  if ( ndims == 0 )
+    {
+      Warning("ndims = %d", ndims);
+      return (CDI_EUFSTRUCT);
+    }
+
+  /* alloc ncdims */
+  ncdims = (ncdim_t *) Malloc((size_t)ndims * sizeof (ncdim_t));
+  init_ncdims(ndims, ncdims);
+
+  if ( nvars > 0 )
+    {
+      /* alloc ncvars */
+      ncvars = (ncvar_t *) Malloc((size_t)nvars * sizeof (ncvar_t));
+      init_ncvars(nvars, ncvars);
+
+      for ( ncvarid = 0; ncvarid < nvars; ++ncvarid )
+        ncvars[ncvarid].ncid = fileID;
+    }
+
+#if  defined  (TEST_GROUPS)
+#if  defined  (HAVE_NETCDF4)
+  if ( format == NC_FORMAT_NETCDF4 )
+    {
+      int ncid;
+      int numgrps;
+      int ncids[NC_MAX_VARS];
+      char name1[CDI_MAX_NAME];
+      int gndims, gnvars, gngatts, gunlimdimid;
+      nc_inq_grps(fileID, &numgrps, ncids);
+      for ( int i = 0; i < numgrps; ++i )
+        {
+          ncid = ncids[i];
+          nc_inq_grpname (ncid, name1);
+          cdf_inq(ncid, &gndims , &gnvars, &gngatts, &gunlimdimid);
+
+          if ( CDI_Debug )
+            Message("%s: ndims %d, nvars %d, ngatts %d", name1, gndims, gnvars, gngatts);
+
+          if ( gndims == 0 )
+            {
+            }
+        }
+    }
+#endif
+#endif
+
+  if ( nvars == 0 )
+    {
+      Warning("nvars = %d", nvars);
+      return (CDI_EUFSTRUCT);
+    }
+
+  /* scan global attributes */
+  scan_global_attributes(fileID, vlistID, streamptr, ngatts, &instID, &modelID, &ucla_les,
+                         uuidOfHGrid, uuidOfVGrid, gridfile, &number_of_grid_used);
+
+  /* find time dim */
+  if ( unlimdimid >= 0 )
+    timedimid = unlimdimid;
+  else
+    timedimid = cdfTimeDimID(fileID, ndims, nvars);
+
+  streamptr->basetime.ncdimid = timedimid;
+
+  if ( timedimid != UNDEFID )
+    cdf_inq_dimlen(fileID, timedimid, &ntsteps);
+  else
+    ntsteps = 0;
+
+  if ( CDI_Debug ) Message("Number of timesteps = %d", ntsteps);
+  if ( CDI_Debug ) Message("Time dimid = %d", streamptr->basetime.ncdimid);
+
+  /* read ncdims */
+  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
+    {
+      cdf_inq_dimlen(fileID, ncdimid, &ncdims[ncdimid].len);
+      cdf_inq_dimname(fileID, ncdimid, ncdims[ncdimid].name);
+      if ( timedimid == ncdimid )
+	ncdims[ncdimid].dimtype = T_AXIS;
+    }
+
+  if ( CDI_Debug ) printNCvars(ncvars, nvars, "cdfScanVarAttributes");
+
+  /* scan attributes of all variables */
+  cdfScanVarAttributes(nvars, ncvars, ncdims, timedimid, modelID, format);
+
+
+  if ( CDI_Debug ) printNCvars(ncvars, nvars, "find coordinate vars");
+
+  /* find coordinate vars */
+  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
+    {
+      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+	{
+	  if ( ncvars[ncvarid].ndims == 1 )
+	    {
+	      if ( timedimid != UNDEFID && timedimid == ncvars[ncvarid].dimids[0] )
+		{
+		  if ( ncvars[ncvarid].isvar != FALSE ) cdfSetVar(ncvars, ncvarid, TRUE);
+		}
+	      else
+		{
+                  //  if ( ncvars[ncvarid].isvar != TRUE ) cdfSetVar(ncvars, ncvarid, FALSE);
+		}
+	      // if ( ncvars[ncvarid].isvar != TRUE ) cdfSetVar(ncvars, ncvarid, FALSE);
+
+	      if ( ncdimid == ncvars[ncvarid].dimids[0] && ncdims[ncdimid].ncvarid == UNDEFID )
+		if ( strcmp(ncvars[ncvarid].name, ncdims[ncdimid].name) == 0 )
+		  {
+		    ncdims[ncdimid].ncvarid = ncvarid;
+		    ncvars[ncvarid].isvar = FALSE;
+		  }
+	    }
+	}
+    }
+
+  /* find time vars */
+  find_time_vars(nvars, ncvars, ncdims, timedimid, streamptr, &time_has_units, &time_has_bounds, &time_climatology);
+
+  leadtime_id = find_leadtime(nvars, ncvars);
+  if ( leadtime_id != UNDEFID ) ncvars[leadtime_id].isvar = FALSE;
+
+  /* check ncvars */
+  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( timedimid != UNDEFID )
+	if ( ncvars[ncvarid].isvar == -1 &&
+	     ncvars[ncvarid].ndims > 1   &&
+	     timedimid == ncvars[ncvarid].dimids[0] )
+	  cdfSetVar(ncvars, ncvarid, TRUE);
+
+      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims == 0 )
+	cdfSetVar(ncvars, ncvarid, FALSE);
+
+      //if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims > 1 )
+      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims >= 1 )
+	cdfSetVar(ncvars, ncvarid, TRUE);
+
+      if ( ncvars[ncvarid].isvar == -1 )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  Warning("Variable %s has an unknown type, skipped!", ncvars[ncvarid].name);
+	  continue;
+	}
+
+      if ( ncvars[ncvarid].ndims > 4 )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  Warning("%d dimensional variables are not supported, skipped variable %s!",
+		ncvars[ncvarid].ndims, ncvars[ncvarid].name);
+	  continue;
+	}
+
+      if ( ncvars[ncvarid].ndims == 4 && timedimid == UNDEFID )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  Warning("%d dimensional variables without time dimension are not supported, skipped variable %s!",
+		ncvars[ncvarid].ndims, ncvars[ncvarid].name);
+	  continue;
+	}
+
+      if ( xtypeIsText(ncvars[ncvarid].xtype) )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  continue;
+	}
+
+      if ( cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned) == -1 )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  Warning("Variable %s has an unsupported data type, skipped!", ncvars[ncvarid].name);
+	  continue;
+	}
+
+      if ( timedimid != UNDEFID && ntsteps == 0 && ncvars[ncvarid].ndims > 0 )
+	{
+	  if ( timedimid == ncvars[ncvarid].dimids[0] )
+	    {
+	      ncvars[ncvarid].isvar = 0;
+	      Warning("Number of time steps undefined, skipped variable %s!", ncvars[ncvarid].name);
+	      continue;
+	    }
+	}
+    }
+
+  /* verify coordinate vars - first scan (dimname == varname) */
+  verify_coordinate_vars_1(fileID, ndims, ncdims, ncvars, timedimid);
+
+  /* verify coordinate vars - second scan (all other variables) */
+  verify_coordinate_vars_2(nvars, ncvars);
+
+  if ( CDI_Debug ) printNCvars(ncvars, nvars, "verify_coordinate_vars");
+
+  if ( ucla_les == TRUE )
+    {
+      for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
+	{
+	  ncvarid = ncdims[ncdimid].ncvarid;
+	  if ( ncvarid != -1 )
+	    {
+	      if ( ncdims[ncdimid].dimtype == UNDEFID && ncvars[ncvarid].units[0] == 'm' )
+		{
+		  if      ( ncvars[ncvarid].name[0] == 'x' ) ncdims[ncdimid].dimtype = X_AXIS;
+		  else if ( ncvars[ncvarid].name[0] == 'y' ) ncdims[ncdimid].dimtype = Y_AXIS;
+		  else if ( ncvars[ncvarid].name[0] == 'z' ) ncdims[ncdimid].dimtype = Z_AXIS;
+		}
+	    }
+	}
+    }
+  /*
+  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
+    {
+      ncvarid = ncdims[ncdimid].ncvarid;
+      if ( ncvarid != -1 )
+	{
+	  printf("coord var %d %s %s\n", ncvarid, ncvars[ncvarid].name, ncvars[ncvarid].units);
+	  if ( ncdims[ncdimid].dimtype == X_AXIS )
+	    printf("coord var %d %s is x dim\n", ncvarid, ncvars[ncvarid].name);
+	  if ( ncdims[ncdimid].dimtype == Y_AXIS )
+	    printf("coord var %d %s is y dim\n", ncvarid, ncvars[ncvarid].name);
+	  if ( ncdims[ncdimid].dimtype == Z_AXIS )
+	    printf("coord var %d %s is z dim\n", ncvarid, ncvars[ncvarid].name);
+	  if ( ncdims[ncdimid].dimtype == T_AXIS )
+	    printf("coord var %d %s is t dim\n", ncvarid, ncvars[ncvarid].name);
+
+	  if ( ncvars[ncvarid].islon )
+	    printf("coord var %d %s is lon\n", ncvarid, ncvars[ncvarid].name);
+	  if ( ncvars[ncvarid].islat )
+	    printf("coord var %d %s is lat\n", ncvarid, ncvars[ncvarid].name);
+	  if ( ncvars[ncvarid].islev )
+	    printf("coord var %d %s is lev\n", ncvarid, ncvars[ncvarid].name);
+	}
+    }
+  */
+
+  /* Set coordinate varids (att: associate)  */
+  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].isvar == TRUE && ncvars[ncvarid].ncoordvars )
+	{
+	  /* ndims = ncvars[ncvarid].ndims; */
+	  ndims = ncvars[ncvarid].ncoordvars;
+	  for ( i = 0; i < ndims; i++ )
+	    {
+	      if ( ncvars[ncvars[ncvarid].coordvarids[i]].islon )
+		ncvars[ncvarid].xvarid = ncvars[ncvarid].coordvarids[i];
+	      else if ( ncvars[ncvars[ncvarid].coordvarids[i]].islat )
+		ncvars[ncvarid].yvarid = ncvars[ncvarid].coordvarids[i];
+	      else if ( ncvars[ncvars[ncvarid].coordvarids[i]].islev )
+		ncvars[ncvarid].zvarid = ncvars[ncvarid].coordvarids[i];
+	    }
+	}
+    }
+
+  /* set dim type */
+  setDimType(nvars, ncvars, ncdims);
+
+  /* read ECHAM VCT if present */
+  size_t vctsize = 0;
+  double *vct = NULL;
+  read_vct_echam(fileID, nvars, ncvars, ncdims, &vct, &vctsize);
+
+
+  if ( CDI_Debug ) printNCvars(ncvars, nvars, "define_all_grids");
+
+  /* define all grids */
+  define_all_grids(streamptr, vlistID, ncdims, nvars, ncvars, timedimid, uuidOfHGrid, gridfile, number_of_grid_used);
+
+
+  /* define all zaxes */
+  define_all_zaxes(streamptr, vlistID, ncdims, nvars, ncvars, vctsize, vct, uuidOfVGrid);
+  if ( vct ) Free(vct);
+
+
+  /* select vars */
+  varids = (int *) Malloc((size_t)nvars * sizeof (int));
+  nvarids = 0;
+  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    if ( ncvars[ncvarid].isvar == TRUE ) varids[nvarids++] = ncvarid;
+
+  nvars_data = nvarids;
+
+  if ( CDI_Debug ) Message("time varid = %d", streamptr->basetime.ncvarid);
+  if ( CDI_Debug ) Message("ntsteps = %d", ntsteps);
+  if ( CDI_Debug ) Message("nvars_data = %d", nvars_data);
+
+
+  if ( nvars_data == 0 )
+    {
+      streamptr->ntsteps = 0;
+      return (CDI_EUFSTRUCT);
+    }
+
+  if ( ntsteps == 0 && streamptr->basetime.ncdimid == UNDEFID && streamptr->basetime.ncvarid != UNDEFID )
+    ntsteps = 1;
+
+  streamptr->ntsteps = (long)ntsteps;
+
+  /* define all data variables */
+  define_all_vars(streamptr, vlistID, instID, modelID, varids, nvars_data, nvars, ncvars);
+
+
+  cdiCreateTimesteps(streamptr);
+
+  /* time varID */
+  int nctimevarid = streamptr->basetime.ncvarid;
+
+  if ( time_has_units )
+    {
+      taxis_t *taxis = &streamptr->tsteps[0].taxis;
+
+      if ( setBaseTime(ncvars[nctimevarid].units, taxis) == 1 )
+        {
+          nctimevarid = UNDEFID;
+          streamptr->basetime.ncvarid = UNDEFID;
+        }
+
+      if ( leadtime_id != UNDEFID && taxis->type == TAXIS_RELATIVE )
+        {
+          streamptr->basetime.leadtimeid = leadtime_id;
+          taxis->type = TAXIS_FORECAST;
+
+          int timeunit = -1;
+          if ( ncvars[leadtime_id].units[0] != 0 ) timeunit = scanTimeUnit(ncvars[leadtime_id].units);
+          if ( timeunit == -1 ) timeunit = taxis->unit;
+          taxis->fc_unit = timeunit;
+
+          setForecastTime(fcreftime, taxis);
+        }
+    }
+
+  if ( time_has_bounds )
+    {
+      streamptr->tsteps[0].taxis.has_bounds = TRUE;
+      if ( time_climatology ) streamptr->tsteps[0].taxis.climatology = TRUE;
+    }
+
+  if ( nctimevarid != UNDEFID )
+    {
+      taxis_t *taxis = &streamptr->tsteps[0].taxis;
+      ptaxisDefName(taxis, ncvars[nctimevarid].name);
+      if ( ncvars[nctimevarid].longname[0] )
+        ptaxisDefLongname(taxis, ncvars[nctimevarid].longname);
+    }
+
+  if ( nctimevarid != UNDEFID )
+    if ( ncvars[nctimevarid].calendar == TRUE )
+      {
+        enum {attstringlen = 8192};
+        char attstring[attstringlen];
+
+	cdfGetAttText(fileID, nctimevarid, "calendar", attstringlen, attstring);
+	strtolower(attstring);
+
+	if ( memcmp(attstring, "standard", 8)  == 0 ||
+	     memcmp(attstring, "gregorian", 9) == 0 )
+	  calendar = CALENDAR_STANDARD;
+	else if ( memcmp(attstring, "none", 4) == 0 )
+	  calendar = CALENDAR_NONE;
+	else if ( memcmp(attstring, "proleptic", 9) == 0 )
+	  calendar = CALENDAR_PROLEPTIC;
+	else if ( memcmp(attstring, "360", 3) == 0 )
+	  calendar = CALENDAR_360DAYS;
+	else if ( memcmp(attstring, "365", 3) == 0 ||
+		  memcmp(attstring, "noleap", 6)  == 0 )
+	  calendar = CALENDAR_365DAYS;
+	else if ( memcmp(attstring, "366", 3)  == 0 ||
+		  memcmp(attstring, "all_leap", 8) == 0 )
+	  calendar = CALENDAR_366DAYS;
+	else
+	  Warning("calendar >%s< unsupported!", attstring);
+      }
+
+  if ( streamptr->tsteps[0].taxis.type == TAXIS_FORECAST )
+    {
+      taxisID = taxisCreate(TAXIS_FORECAST);
+    }
+  else if ( streamptr->tsteps[0].taxis.type == TAXIS_RELATIVE )
+    {
+      taxisID = taxisCreate(TAXIS_RELATIVE);
+    }
+  else
+    {
+      taxisID = taxisCreate(TAXIS_ABSOLUTE);
+      if ( !time_has_units )
+	{
+	  taxisDefTunit(taxisID, TUNIT_DAY);
+	  streamptr->tsteps[0].taxis.unit = TUNIT_DAY;
+	}
+    }
+
+
+  if ( calendar == UNDEFID && streamptr->tsteps[0].taxis.type != TAXIS_ABSOLUTE )
+    {
+      calendar = CALENDAR_STANDARD;
+    }
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-Wstrict-overflow"
+#endif
+  if ( calendar != UNDEFID )
+    {
+      taxis_t *taxis = &streamptr->tsteps[0].taxis;
+      taxis->calendar = calendar;
+      taxisDefCalendar(taxisID, calendar);
+    }
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
+#pragma GCC diagnostic pop
+#endif
+
+  vlistDefTaxis(vlistID, taxisID);
+
+  streamptr->curTsID = 0;
+  streamptr->rtsteps = 1;
+
+  (void) cdfInqTimestep(streamptr, 0);
+
+  cdfCreateRecords(streamptr, 0);
+
+  /* free ncdims */
+  Free(ncdims);
+
+  /* free ncvars */
+  Free(ncvars);
+
+  return (0);
+}
+
+static
+void wrf_read_timestep(int fileID, int nctimevarid, int tsID, taxis_t *taxis)
+{
+  size_t start[2], count[2];
+  char stvalue[32];
+  start[0] = (size_t) tsID; start[1] = 0;
+  count[0] = 1; count[1] = 19;
+  stvalue[0] = 0;
+  cdf_get_vara_text(fileID, nctimevarid, start, count, stvalue);
+  stvalue[19] = 0;
+  {
+    int year = 1, month = 1, day = 1 , hour = 0, minute = 0, second = 0;
+    if ( strlen(stvalue) == 19 )
+      sscanf(stvalue, "%d-%d-%d_%d:%d:%d", &year, &month, &day, &hour, &minute, &second);
+    taxis->vdate = cdiEncodeDate(year, month, day);
+    taxis->vtime = cdiEncodeTime(hour, minute, second);
+    taxis->type = TAXIS_ABSOLUTE;
+  }
+}
+
+static
+double get_timevalue(int fileID, int nctimevarid, int tsID, timecache_t *tcache)
+{
+  double timevalue = 0;
+  size_t index = (size_t) tsID;
+
+  if ( tcache )
+    {
+      if ( tcache->size == 0 || (tsID < tcache->startid || tsID > (tcache->startid+tcache->size-1)) )
+        {
+          int maxvals = MAX_TIMECACHE_SIZE;
+          tcache->startid = (tsID/MAX_TIMECACHE_SIZE)*MAX_TIMECACHE_SIZE;
+          if ( (tcache->startid + maxvals) > tcache->maxvals ) maxvals = (tcache->maxvals)%MAX_TIMECACHE_SIZE;
+          tcache->size = maxvals;
+          index = (size_t) tcache->startid;
+          // fprintf(stderr, "fill time cache: %d %d %d %d %d\n", tcache->maxvals, tsID, tcache->startid, tcache->startid+maxvals-1, maxvals);
+          for ( int ival = 0; ival < maxvals; ++ival )
+            {
+              cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
+              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+              tcache->cache[ival] = timevalue;
+              index++;
+            }
+        }
+
+      timevalue = tcache->cache[tsID%MAX_TIMECACHE_SIZE];
+    }
+  else
+    {
+      cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
+      if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+    }
+
+  return timevalue;
+}
 
-                  status = nc_inq_varid(ncid, varname, &dimvarid);
-                  if ( status == NC_NOERR )
-                    {
-                      cdfSetVar(ncvars, dimvarid, FALSE);
-                      if ( cdiIgnoreAttCoordinates == FALSE )
-                        {
-                          ncvars[ncvarid].coordvarids[i] = dimvarid;
-                          ncvars[ncvarid].ncoordvars++;
-                        }
-                    }
-                  else
-                    {
-                      int k;
-                      for ( k = 0; k < nchecked_vars; ++k )
-                        if ( strcmp(checked_vars[k], varname) == 0 ) break;
 
-                      if ( k == nchecked_vars )
-                        {
-                          if ( nchecked_vars < max_check_vars ) checked_vars[nchecked_vars++] = strdup(varname);
-                          Warning("%s - %s", nc_strerror(status), varname);
-                        }
-                    }
+int cdfInqTimestep(stream_t * streamptr, int tsID)
+{
+  long nrecs = 0;
+  double timevalue;
+  int fileID;
+  taxis_t *taxis;
 
-                  if ( lstop ) break;
-                }
+  if ( CDI_Debug ) Message("streamID = %d  tsID = %d", streamptr->self, tsID);
 
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( (strcmp(attname, "auxiliary_variable") == 0) && xtypeIsText(atttype) )
-            {
-              int status;
-              char *varname = NULL;
-              int lstop = FALSE;
-              int dimvarid;
+  if ( tsID < 0 ) Error("unexpected tsID = %d", tsID);
 
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              char *pstring = attstring;
+  if ( tsID < streamptr->ntsteps && streamptr->ntsteps > 0 )
+    {
+      cdfCreateRecords(streamptr, tsID);
 
-              for ( int i = 0; i < MAX_AUXVARS; i++ )
-                {
-                  while ( isspace((int) *pstring) ) pstring++;
-                  if ( *pstring == 0 ) break;
-                  varname = pstring;
-                  while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
-                  if ( *pstring == 0 ) lstop = TRUE;
-                  *pstring++ = 0;
+      taxis = &streamptr->tsteps[tsID].taxis;
+      if ( tsID > 0 )
+	ptaxisCopy(taxis, &streamptr->tsteps[0].taxis);
 
-                  status = nc_inq_varid(ncid, varname, &dimvarid);
-                  if ( status == NC_NOERR )
-                    {
-                      cdfSetVar(ncvars, dimvarid, FALSE);
-                      //  if ( cdiIgnoreAttCoordinates == FALSE )
-                        {
-                          ncvars[ncvarid].auxvarids[i] = dimvarid;
-                          ncvars[ncvarid].nauxvars++;
-                        }
-                    }
-                  else
-                    Warning("%s - %s", nc_strerror(status), varname);
+      timevalue = tsID;
 
-                  if ( lstop ) break;
-                }
+      int nctimevarid = streamptr->basetime.ncvarid;
+      if ( nctimevarid != UNDEFID )
+	{
+	  fileID = streamptr->fileID;
+	  size_t index  = (size_t)tsID;
 
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "grid_mapping") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              int nc_gmap_id;
-              int status = nc_inq_varid(ncid, attstring, &nc_gmap_id);
-              if ( status == NC_NOERR )
+	  if ( streamptr->basetime.lwrf )
+	    {
+              wrf_read_timestep(fileID, nctimevarid, tsID, taxis);
+	    }
+	  else
+	    {
+#if defined (USE_TIMECACHE)
+              if ( streamptr->basetime.timevar_cache == NULL )
                 {
-                  ncvars[ncvarid].gmapid = nc_gmap_id;
-                  cdfSetVar(ncvars, ncvars[ncvarid].gmapid, FALSE);
+                  streamptr->basetime.timevar_cache = (timecache_t *) Malloc(MAX_TIMECACHE_SIZE*sizeof(timecache_t));
+                  streamptr->basetime.timevar_cache->size = 0;
+                  streamptr->basetime.timevar_cache->maxvals = streamptr->ntsteps;
                 }
-              else
-                Warning("%s - %s", nc_strerror(status), attstring);
+#endif
+              timevalue = get_timevalue(fileID, nctimevarid, tsID, streamptr->basetime.timevar_cache);
+	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate, &taxis->vtime);
+	    }
 
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "positive") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              strtolower(attstring);
+	  int nctimeboundsid = streamptr->basetime.ncvarboundsid;
+	  if ( nctimeboundsid != UNDEFID )
+	    {
+	      size_t start[2], count[2];
+              start[0] = index; count[0] = 1; start[1] = 0; count[1] = 1;
+	      cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
+              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
 
-              if    ( memcmp(attstring, "down", 4) == 0 ) ncvars[ncvarid].positive = POSITIVE_DOWN;
-              else if ( memcmp(attstring, "up", 2) == 0 ) ncvars[ncvarid].positive = POSITIVE_UP;
+	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_lb, &taxis->vtime_lb);
 
-              if ( ncvars[ncvarid].ndims == 1 )
-                {
-                  cdfSetVar(ncvars, ncvarid, FALSE);
-                  cdfSetDim(ncvars, ncvarid, 0, Z_AXIS);
-                  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Z_AXIS;
-                }
-            }
-          else if ( strcmp(attname, "_FillValue") == 0 && !xtypeIsText(atttype) )
-            {
-	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].fillval);
-	      ncvars[ncvarid].deffillval = TRUE;
-	      /* cdfSetVar(ncvars, ncvarid, TRUE); */
-            }
-          else if ( strcmp(attname, "missing_value") == 0 && !xtypeIsText(atttype) )
-            {
-	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].missval);
-	      ncvars[ncvarid].defmissval = TRUE;
-	      /* cdfSetVar(ncvars, ncvarid, TRUE); */
-            }
-          else if ( strcmp(attname, "valid_range") == 0 && attlen == 2 )
-            {
-              if ( ncvars[ncvarid].lvalidrange == FALSE )
-                {
-                  extern int cdiIgnoreValidRange;
-                  int lignore = FALSE;
-                  if ( xtypeIsFloat(atttype) != xtypeIsFloat(xtype) ) lignore = TRUE;
-                  if ( cdiIgnoreValidRange == FALSE && lignore == FALSE )
-                    {
-                      cdfGetAttDouble(ncid, ncvarid, attname, 2, ncvars[ncvarid].validrange);
-                      ncvars[ncvarid].lvalidrange = TRUE;
-                      if ( ((int)ncvars[ncvarid].validrange[0]) == 0 && ((int)ncvars[ncvarid].validrange[1]) == 255 )
-                        ncvars[ncvarid].lunsigned = TRUE;
-                      /* cdfSetVar(ncvars, ncvarid, TRUE); */
-                    }
-                  else if ( lignore )
-                    {
-                      Warning("Inconsistent data type for attribute %s:valid_range, ignored!", name);
-                    }
-                }
-            }
-          else if ( strcmp(attname, "valid_min") == 0 && attlen == 1 )
-            {
-              if ( ncvars[ncvarid].lvalidrange == FALSE )
-                {
-                  extern int cdiIgnoreValidRange;
-                  int lignore = FALSE;
-                  if ( xtypeIsFloat(atttype) != xtypeIsFloat(xtype) ) lignore = TRUE;
-                  if ( cdiIgnoreValidRange == FALSE && lignore == FALSE )
-                    {
-                      cdfGetAttDouble(ncid, ncvarid, attname, 1, &(ncvars[ncvarid].validrange)[0]);
-                      ncvars[ncvarid].lvalidrange = TRUE;
-                    }
-                  else if ( lignore )
-                    {
-                      Warning("Inconsistent data type for attribute %s:valid_min, ignored!", name);
-                    }
-                }
-            }
-          else if ( strcmp(attname, "valid_max") == 0 && attlen == 1 )
+              start[0] = index; count[0] = 1; start[1] = 1; count[1] = 1;
+	      cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
+              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+
+	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_ub, &taxis->vtime_ub);
+	    }
+
+          int leadtimeid = streamptr->basetime.leadtimeid;
+          if ( leadtimeid != UNDEFID )
             {
-              if ( ncvars[ncvarid].lvalidrange == FALSE )
-                {
-                  extern int cdiIgnoreValidRange;
-                  int lignore = FALSE;
-                  if ( xtypeIsFloat(atttype) != xtypeIsFloat(xtype) ) lignore = TRUE;
-                  if ( cdiIgnoreValidRange == FALSE && lignore == FALSE )
-                    {
-                      cdfGetAttDouble(ncid, ncvarid, attname, 1, &(ncvars[ncvarid].validrange)[1]);
-                      ncvars[ncvarid].lvalidrange = TRUE;
-                    }
-                  else if ( lignore )
-                    {
-                      Warning("Inconsistent data type for attribute %s:valid_max, ignored!", name);
-                    }
-                }
+              timevalue = get_timevalue(fileID, leadtimeid, tsID, NULL);
+              cdiSetForecastPeriod(timevalue, taxis);
             }
-          else if ( strcmp(attname, "_Unsigned") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              strtolower(attstring);
+	}
+    }
 
-              if ( memcmp(attstring, "true", 4) == 0 )
-                {
-                  ncvars[ncvarid].lunsigned = TRUE;
-                  /*
-                  ncvars[ncvarid].lvalidrange = TRUE;
-                  ncvars[ncvarid].validrange[0] = 0;
-                  ncvars[ncvarid].validrange[1] = 255;
-                  */
-                }
-	      /* cdfSetVar(ncvars, ncvarid, TRUE); */
-            }
-          else if ( strcmp(attname, "cdi") == 0 && xtypeIsText(atttype) )
-            {
-	      cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-	      strtolower(attstring);
+  streamptr->curTsID = tsID;
+  nrecs = streamptr->tsteps[tsID].nrecs;
 
-	      if ( memcmp(attstring, "ignore", 6) == 0 )
-		{
-		  ncvars[ncvarid].ignore = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		}
-            }
-          else if ( strcmp(attname, "axis") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-	      attlen = strlen(attstring);
+  return ((int) nrecs);
+}
 
-	      if ( (int) attlen > nvdims && nvdims > 0 && attlen > 1 )
-		{
-		    Warning("Unexpected axis attribute length for %s, ignored!", name);
-		}
-              else if ( nvdims == 0 && attlen == 1 )
-                {
-                  if ( attstring[0] == 'z' || attstring[0] == 'Z' )
-                    {
-                      cdfSetVar(ncvars, ncvarid, FALSE);
-                      ncvars[ncvarid].islev = TRUE;
-                    }
-                }
-	      else
-		{
-		  strtolower(attstring);
-                  int i;
-		  for ( i = 0; i < (int)attlen; ++i )
-		    {
-		      if ( attstring[i] != '-' && attstring[i] != 't' && attstring[i] != 'z' &&
-			   attstring[i] != 'y' && attstring[i] != 'x' )
-			{
-			  Warning("Unexpected character in axis attribute for %s, ignored!", name);
-			  break;
-			}
-		    }
 
-		  if ( i == (int) attlen && (int) attlen == nvdims )
-		    {
-		      while ( attlen-- )
-			{
-			  if ( (int) attstring[attlen] == 't' )
-			    {
-			      if ( attlen != 0 ) Warning("axis attribute 't' not on first position");
-			      cdfSetDim(ncvars, ncvarid, (int)attlen, T_AXIS);
-			    }
-			  else if ( (int) attstring[attlen] == 'z' )
-			    {
-                              ncvars[ncvarid].zdim = dimidsp[attlen];
-                              cdfSetDim(ncvars, ncvarid, (int)attlen, Z_AXIS);
+void cdfDefHistory(stream_t *streamptr, int size, const char *history)
+{
+  int ncid = streamptr->fileID;
+  cdf_put_att_text(ncid, NC_GLOBAL, "history", (size_t) size, history);
+}
 
-                              if ( ncvars[ncvarid].ndims == 1 )
-                                {
-                                  cdfSetVar(ncvars, ncvarid, FALSE);
-                                  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Z_AXIS;
-                                }
-			    }
-			  else if ( (int) attstring[attlen] == 'y' )
-			    {
-			      ncvars[ncvarid].ydim = dimidsp[attlen];
-			      cdfSetDim(ncvars, ncvarid, (int)attlen, Y_AXIS);
 
-			      if ( ncvars[ncvarid].ndims == 1 )
-				{
-				  cdfSetVar(ncvars, ncvarid, FALSE);
-				  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Y_AXIS;
-				}
-			    }
-			  else if ( (int) attstring[attlen] == 'x' )
-			    {
-			      ncvars[ncvarid].xdim = dimidsp[attlen];
-			      cdfSetDim(ncvars, ncvarid, (int)attlen, X_AXIS);
+int cdfInqHistorySize(stream_t *streamptr)
+{
+  size_t size = 0;
+  int ncid = streamptr->fileID;
+  if ( streamptr->historyID != UNDEFID )
+    cdf_inq_attlen(ncid, NC_GLOBAL, "history", &size);
 
-			      if ( ncvars[ncvarid].ndims == 1 )
-				{
-				  cdfSetVar(ncvars, ncvarid, FALSE);
-				  ncdims[ncvars[ncvarid].dimids[0]].dimtype = X_AXIS;
-				}
-			    }
-			}
-		    }
-		}
-	    }
-	  else if ( ( strcmp(attname, "realization") == 0 )         ||
-	            ( strcmp(attname, "ensemble_members") == 0 )    ||
-	            ( strcmp(attname, "forecast_init_type") == 0 )    )
-	    {
-	      int temp;
+  return ((int) size);
+}
 
-	      if( ncvars[ncvarid].ensdata == NULL )
-		ncvars[ncvarid].ensdata = (ensinfo_t *) Malloc( sizeof( ensinfo_t ) );
 
-	      cdfGetAttInt(ncid, ncvarid, attname, 1, &temp);
+void cdfInqHistoryString(stream_t *streamptr, char *history)
+{
+  int ncid = streamptr->fileID;
+  if ( streamptr->historyID != UNDEFID )
+    {
+      nc_type atttype;
+      cdf_inq_atttype(ncid, NC_GLOBAL, "history", &atttype);
 
-	      if( strcmp(attname, "realization") == 0 )
-		ncvars[ncvarid].ensdata->ens_index = temp;
-	      else if( strcmp(attname, "ensemble_members") == 0 )
-		ncvars[ncvarid].ensdata->ens_count = temp;
-	      else if( strcmp(attname, "forecast_init_type") == 0 )
-		ncvars[ncvarid].ensdata->forecast_init_type = temp;
+      if ( atttype == NC_CHAR )
+        {
+          cdf_get_att_text(ncid, NC_GLOBAL, "history", history);
+        }
+#if  defined  (HAVE_NETCDF4)
+      else if ( atttype == NC_STRING )
+        {
+          // ToDo
+          Warning("History attribute with type NC_STRING unsupported!");
+        }
+#endif
+    }
+}
 
-	      cdfSetVar(ncvars, ncvarid, TRUE);
-	    }
-	  else
-	    {
-	      if ( ncvars[ncvarid].natts == 0 )
-		ncvars[ncvarid].atts
-                  = (int *) Malloc((size_t)nvatts * sizeof (int));
 
-	      ncvars[ncvarid].atts[ncvars[ncvarid].natts++] = iatt;
-	      /*
-	      int attrint;
-	      double attrflt;
-	      nc_type attrtype;
-	      cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
-	      cdf_inq_atttype(ncid, ncvarid, attname, &attrtype);
-	      if ( attlen == 1 && (attrtype == NC_INT || attrtype == NC_SHORT) )
-		{
-		  cdfGetAttInt(ncid, ncvarid, attname, 1, &attrint);
-		  printf("int: %s.%s = %d\n", ncvars[ncvarid].name, attname, attrint);
-		}
-	      else if ( attlen == 1 && (attrtype == NC_FLOAT || attrtype == NC_DOUBLE) )
-		{
-		  cdfGetAttDouble(ncid, ncvarid, attname, 1, &attrflt);
-		  printf("flt: %s.%s = %g\n", ncvars[ncvarid].name, attname, attrflt);
-		}
-	      else if ( attrtype == NC_CHAR )
-		{
-		  cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-		  attstring[attlen] = 0;
-		  printf("txt: %s.%s = %s\n", ncvars[ncvarid].name, attname, attstring);
-		}
-	      else
-		printf("att: %s.%s = unknown\n", ncvars[ncvarid].name, attname);
-	      */
-	    }
-	}
+void cdfDefVars(stream_t *streamptr)
+{
+  int vlistID = streamptr->vlistID;
+  if ( vlistID == UNDEFID )
+    Error("Internal problem! vlist undefined for streamptr %p", streamptr);
+
+  int ngrids = vlistNgrids(vlistID);
+  int nzaxis = vlistNzaxis(vlistID);
+  /*
+  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
+  */
+  if ( ngrids > 0 )
+    for ( int index = 0; index < ngrids; index++ )
+      {
+        int gridID = vlistGrid(vlistID, index);
+        cdfDefGrid(streamptr, gridID);
+      }
+
+  if ( nzaxis > 0 )
+    for ( int index = 0; index < nzaxis; index++ )
+      {
+        int zaxisID = vlistZaxis(vlistID, index);
+        if ( streamptr->zaxisID[index] == UNDEFID ) cdfDefZaxis(streamptr, zaxisID);
+      }
+
+  /* define time first!!!
+    int nvars  = vlistNvars(vlistID);
+  for ( int varID = 0; varID < nvars; varID++ )
+    {
+      int ncvarid = cdfDefVar(streamptr, varID);
     }
+  */
+}
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef CDI_DATETIME_H
+#define CDI_DATETIME_H
 
-  for ( int i = 0; i < max_check_vars; ++i ) if ( checked_vars[i] ) Free(checked_vars[i]);
+typedef struct
+{
+  long date;
+  long time;
 }
+DateTime;
 
-static
-void setDimType(int nvars, ncvar_t *ncvars, ncdim_t *ncdims)
+static inline int
+datetimeCmp(DateTime dt1, DateTime dt2)
 {
-  int ndims;
-  int ncvarid, ncdimid;
-  int i;
+  return 2 * ((dt1.date > dt2.date) - (dt1.date < dt2.date))
+    + (dt1.time > dt2.time) - (dt1.time < dt2.time);
+}
 
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      if ( ncvars[ncvarid].isvar == TRUE )
-	{
-	  int lxdim = 0, lydim = 0, lzdim = 0/* , ltdim = 0 */;
-	  ndims = ncvars[ncvarid].ndims;
-	  for ( i = 0; i < ndims; i++ )
-	    {
-	      ncdimid = ncvars[ncvarid].dimids[i];
-	      if      ( ncdims[ncdimid].dimtype == X_AXIS ) cdfSetDim(ncvars, ncvarid, i, X_AXIS);
-	      else if ( ncdims[ncdimid].dimtype == Y_AXIS ) cdfSetDim(ncvars, ncvarid, i, Y_AXIS);
-	      else if ( ncdims[ncdimid].dimtype == Z_AXIS ) cdfSetDim(ncvars, ncvarid, i, Z_AXIS);
-	      else if ( ncdims[ncdimid].dimtype == T_AXIS ) cdfSetDim(ncvars, ncvarid, i, T_AXIS);
-	    }
 
-	  if ( CDI_Debug )
-	    {
-	      Message("var %d %s", ncvarid, ncvars[ncvarid].name);
-	      for ( i = 0; i < ndims; i++ )
-		printf("  dim%d type=%d  ", i, ncvars[ncvarid].dimtype[i]);
-	      printf("\n");
-	    }
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef _STREAM_CGRIBEX_H
+#define _STREAM_CGRIBEX_H
 
-	  for ( i = 0; i < ndims; i++ )
-	    {
-	      if      ( ncvars[ncvarid].dimtype[i] == X_AXIS ) lxdim = TRUE;
-	      else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) lydim = TRUE;
-	      else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) lzdim = TRUE;
-	      /* else if ( ncvars[ncvarid].dimtype[i] == T_AXIS ) ltdim = TRUE; */
-	    }
+int cgribexScanTimestep1(stream_t * streamptr);
+int cgribexScanTimestep2(stream_t * streamptr);
+int cgribexScanTimestep(stream_t * streamptr);
 
-          if ( lxdim == FALSE && ncvars[ncvarid].xvarid != UNDEFID )
-            {
-              if (  ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = TRUE;
-            }
+int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long datasize,
+		  int unreduced, int *nmiss, double missval);
+
+size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
+		     int vdate, int vtime, int tsteptype, int numavg,
+		     long datasize, const void *data, int nmiss, void *gribbuffer, size_t gribbuffersize);
+
+#endif  /* _STREAM_CGRIBEX_H */
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
+
+#include <limits.h>
+#include <stdio.h>
+
+
+#if  defined  (HAVE_LIBCGRIBEX)
+#endif
 
-          if ( lydim == FALSE && ncvars[ncvarid].yvarid != UNDEFID )
-            {
-              if (  ncvars[ncvars[ncvarid].yvarid].ndims == 0 ) lydim = TRUE;
-            }
+typedef struct {
+  int param;
+  int level1;
+  int level2;
+  int ltype;
+  int tsteptype;
+} compvar_t;
 
-          //   if ( ndims > 1 )
-            for ( i = ndims-1; i >= 0; i-- )
-              {
-                if ( ncvars[ncvarid].dimtype[i] == -1 )
-                  {
-                    if ( lxdim == FALSE )
-                      {
-                        cdfSetDim(ncvars, ncvarid, i, X_AXIS);
-                        lxdim = TRUE;
-                      }
-                    else if ( lydim == FALSE && ncvars[ncvarid].gridtype != GRID_UNSTRUCTURED )
-                      {
-                        cdfSetDim(ncvars, ncvarid, i, Y_AXIS);
-                        lydim = TRUE;
-                      }
-                    else if ( lzdim == FALSE )
-                      {
-                        cdfSetDim(ncvars, ncvarid, i, Z_AXIS);
-                        lzdim = TRUE;
-                      }
-                  }
-              }
-	}
-    }
-}
 
-/* verify coordinate vars - first scan (dimname == varname) */
+#if  defined  (HAVE_LIBCGRIBEX)
 static
-void verify_coordinate_vars_1(int ncid, int ndims, ncdim_t *ncdims, ncvar_t *ncvars, int timedimid)
+int cgribexGetGridType(int *isec2)
 {
-  int ncdimid, ncvarid;
+  int gridtype = GRID_GENERIC;
 
-  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
+  switch (ISEC2_GridType)
     {
-      ncvarid = ncdims[ncdimid].ncvarid;
-      if ( ncvarid != -1 )
-	{
-	  if ( ncvars[ncvarid].dimids[0] == timedimid )
-	    {
-              ncvars[ncvarid].istime = TRUE;
-	      ncdims[ncdimid].dimtype = T_AXIS;
-	      continue;
-	    }
-
-          if ( isHybridSigmaPressureCoordinate(ncid, ncvarid, ncvars, ncdims) ) continue;
+    case  GRIB1_GTYPE_LATLON:     { if ( ISEC2_Reduced )      break; }
+    case  GRIB1_GTYPE_LATLON_ROT: { gridtype = GRID_LONLAT;   break; }
+    case  GRIB1_GTYPE_LCC:        { gridtype = GRID_LCC;      break; }
+    case  GRIB1_GTYPE_GAUSSIAN:   { if ( ISEC2_Reduced )
+	                              gridtype = GRID_GAUSSIAN_REDUCED;
+                         	    else
+				      gridtype = GRID_GAUSSIAN;
+          	                    break;
+                                  }
+    case  GRIB1_GTYPE_SPECTRAL:   { gridtype = GRID_SPECTRAL; break; }
+    case  GRIB1_GTYPE_GME:        { gridtype = GRID_GME;      break; }
+    }
 
-	  if ( ncvars[ncvarid].units[0] != 0 )
-	    {
-	      if ( isLonAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
-		{
-		  ncvars[ncvarid].islon = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		  cdfSetDim(ncvars, ncvarid, 0, X_AXIS);
-		  ncdims[ncdimid].dimtype = X_AXIS;
-		}
-	      else if ( isLatAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
-		{
-		  ncvars[ncvarid].islat = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		  cdfSetDim(ncvars, ncvarid, 0, Y_AXIS);
-		  ncdims[ncdimid].dimtype = Y_AXIS;
-		}
-	      else if ( unitsIsPressure(ncvars[ncvarid].units) )
-		{
-		  ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
-		}
-	      else if ( strcmp(ncvars[ncvarid].units, "level") == 0 || strcmp(ncvars[ncvarid].units, "1") == 0 )
-		{
-		  if      ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer midpoints") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
-		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at midpoints", 25) == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
-		  else if ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer interfaces") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
-		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at interfaces", 26) == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
-		  else if ( strcmp(ncvars[ncvarid].units, "level") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_GENERIC;
-		}
-	      else if ( isDBLAxis(ncvars[ncvarid].longname) )
-                {
-                  ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
-		}
-	      else if ( unitsIsMeter(ncvars[ncvarid].units) )
-		{
-		  if ( isDepthAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
-		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
-		  else if ( isHeightAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HEIGHT;
-		}
-	    }
-          else
-            {
-              if ( (strcmp(ncvars[ncvarid].longname, "generalized_height") == 0 ||
-                    strcmp(ncvars[ncvarid].longname, "generalized height") == 0) &&
-                   strcmp(ncvars[ncvarid].stdname, "height") == 0 )
-                  ncvars[ncvarid].zaxistype = ZAXIS_REFERENCE;
-            }
+  return (gridtype);
+}
 
-	  if ( ncvars[ncvarid].islon == FALSE && ncvars[ncvarid].longname[0] != 0 &&
-               ncvars[ncvarid].islat == FALSE && ncvars[ncvarid].longname[1] != 0 )
-	    {
-	      if ( memcmp(ncvars[ncvarid].longname+1, "ongitude", 8) == 0 )
-		{
-		  ncvars[ncvarid].islon = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		  cdfSetDim(ncvars, ncvarid, 0, X_AXIS);
-		  ncdims[ncdimid].dimtype = X_AXIS;
-		  continue;
-		}
-	      else if ( memcmp(ncvars[ncvarid].longname+1, "atitude", 7) == 0 )
-		{
-		  ncvars[ncvarid].islat = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		  cdfSetDim(ncvars, ncvarid, 0, Y_AXIS);
-		  ncdims[ncdimid].dimtype = Y_AXIS;
-		  continue;
-		}
-	    }
+static
+int cgribexGetIsRotated(int *isec2)
+{
+  int isRotated = 0;
 
-	  if ( ncvars[ncvarid].zaxistype != UNDEFID )
-	    {
-              ncvars[ncvarid].islev = TRUE;
-	      cdfSetVar(ncvars, ncvarid, FALSE);
-	      cdfSetDim(ncvars, ncvarid, 0, Z_AXIS);
-	      ncdims[ncdimid].dimtype = Z_AXIS;
-	    }
-	}
+  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
+    {
+      isRotated = 1;
     }
+
+  return (isRotated);
 }
 
-/* verify coordinate vars - second scan (all other variables) */
 static
-void verify_coordinate_vars_2(int nvars, ncvar_t *ncvars)
+int cgribexGetZaxisHasBounds(int grb_ltype)
 {
-  int ncvarid;
+  int lbounds = 0;
 
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  switch (grb_ltype)
     {
-      if ( ncvars[ncvarid].isvar == 0 )
-	{
-	  if ( ncvars[ncvarid].units[0] != 0 )
-	    {
-	      if ( isLonAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
-		{
-		  ncvars[ncvarid].islon = TRUE;
-		  continue;
-		}
-	      else if ( isLatAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
-		{
-		  ncvars[ncvarid].islat = TRUE;
-		  continue;
-		}
-	      else if ( unitsIsPressure(ncvars[ncvarid].units) )
-		{
-		  ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
-		  continue;
-		}
-	      else if ( strcmp(ncvars[ncvarid].units, "level") == 0 || strcmp(ncvars[ncvarid].units, "1") == 0 )
-		{
-		  if      ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer midpoints") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
-		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at midpoints", 25) == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
-		  else if ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer interfaces") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
-		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at interfaces", 26) == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
-		  else if ( strcmp(ncvars[ncvarid].units, "level") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_GENERIC;
-		  continue;
-		}
-	      else if ( isDBLAxis(ncvars[ncvarid].longname) )
-		{
-                  ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
-		  continue;
-		}
-	      else if ( unitsIsMeter(ncvars[ncvarid].units) )
-		{
-		  if ( isDepthAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
-		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
-		  else if ( isHeightAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HEIGHT;
-		  continue;
-		}
-            }
-
-	  /* not needed anymore for rotated grids */
-	  if ( ncvars[ncvarid].islon == FALSE && ncvars[ncvarid].longname[0] != 0 &&
-               ncvars[ncvarid].islat == FALSE && ncvars[ncvarid].longname[1] != 0 )
-	    {
-	      if ( memcmp(ncvars[ncvarid].longname+1, "ongitude", 8) == 0 )
-		{
-		  ncvars[ncvarid].islon = TRUE;
-		  continue;
-		}
-	      else if ( memcmp(ncvars[ncvarid].longname+1, "atitude", 7) == 0 )
-		{
-		  ncvars[ncvarid].islat = TRUE;
-		  continue;
-		}
-	    }
-	}
+    case GRIB1_LTYPE_SIGMA_LAYER:
+    case GRIB1_LTYPE_HYBRID_LAYER:
+    case GRIB1_LTYPE_LANDDEPTH_LAYER:
+      {
+	lbounds = 1;
+	break;
+      }
     }
+
+  return (lbounds);
 }
 
-#if defined (PROJECTION_TEST)
 static
-void copy_numeric_projatts(int gridID, int ncvarID, int ncfileID)
+int cgribexGetTimeUnit(int *isec1)
 {
-  int iatt, nvatts;
-  size_t attlen;
-  char attname[CDI_MAX_NAME];
-  nc_type xtype;
-
-  cdf_inq_varnatts(ncfileID, ncvarID, &nvatts);
+  int timeunit = TUNIT_HOUR;
+  static int lprint = TRUE;
 
-  for ( iatt = 0; iatt < nvatts; iatt++ )
+  switch ( ISEC1_TimeUnit )
     {
-      cdf_inq_attname(ncfileID, ncvarID, iatt, attname);
-      cdf_inq_atttype(ncfileID, ncvarID, attname, &xtype);
-      cdf_inq_attlen(ncfileID, ncvarID, attname, &attlen);
-
-      //  printf("%s %d\n", attname, (int)attlen);
+    case ISEC1_TABLE4_MINUTE:    timeunit = TUNIT_MINUTE;    break;
+    case ISEC1_TABLE4_QUARTER:   timeunit = TUNIT_QUARTER;   break;
+    case ISEC1_TABLE4_30MINUTES: timeunit = TUNIT_30MINUTES; break;
+    case ISEC1_TABLE4_HOUR:      timeunit = TUNIT_HOUR;      break;
+    case ISEC1_TABLE4_3HOURS:    timeunit = TUNIT_3HOURS;    break;
+    case ISEC1_TABLE4_6HOURS:    timeunit = TUNIT_6HOURS;    break;
+    case ISEC1_TABLE4_12HOURS:   timeunit = TUNIT_12HOURS;   break;
+    case ISEC1_TABLE4_DAY:       timeunit = TUNIT_DAY;       break;
+    default:
+      if ( lprint )
+	{
+	  Message("GRIB time unit %d unsupported!", ISEC1_TimeUnit);
+	  lprint = FALSE;
+	}
+      break;
     }
 
+  return (timeunit);
 }
-#endif
 
 static
-void grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
+int cgribexTimeIsFC(int *isec1)
 {
-  if ( ncvar->chunked )
-    {
-      int ndims = ncvar->ndims;
+  int isFC = TRUE;
 
-      if ( grid->type == GRID_UNSTRUCTURED )
-        {
-          if ( ncvar->chunks[ndims-1] == grid->size )
-            ncvar->chunktype = CHUNK_GRID;
-          else
-            ncvar->chunktype = CHUNK_AUTO;
-        }
-      else
-        {
-          if ( grid->xsize > 1 && grid->ysize > 1 && ndims > 1 &&
-               grid->xsize == ncvar->chunks[ndims-1] &&
-               grid->ysize == ncvar->chunks[ndims-2] )
-            ncvar->chunktype = CHUNK_GRID;
-          else if ( grid->xsize > 1 && grid->xsize == ncvar->chunks[ndims-1] )
-            ncvar->chunktype = CHUNK_LINES;
-          else
-            ncvar->chunktype = CHUNK_AUTO;
-        }
-    }
+  if ( ISEC1_TimeRange == 10 && ISEC1_TimePeriod1 == 0 && ISEC1_TimePeriod2 == 0 )
+    isFC = FALSE;
+
+  return (isFC);
 }
 
-/* define all input grids */
 static
-void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars, int timedimid, unsigned char *uuidOfHGrid, char *gridfile, int number_of_grid_used)
+int cgribexGetTsteptype(int timerange)
 {
-  int ncvarid, ncvarid2;
-  int nbdims;
-  int i;
-  int nvatts;
-  int skipvar;
-  size_t nvertex;
-  grid_t grid;
-  grid_t proj;
-  int gridindex;
-  char name[CDI_MAX_NAME];
-  int iatt;
-  int ltwarn = TRUE;
-  size_t attlen;
-  char attname[CDI_MAX_NAME];
-  double datt;
+  int tsteptype = TSTEP_INSTANT;
+  static int lprint = TRUE;
 
-  for ( ncvarid = 0; ncvarid < nvars; ++ncvarid )
+  switch ( timerange )
     {
-      if ( ncvars[ncvarid].isvar && ncvars[ncvarid].gridID == UNDEFID )
+    case  0:  tsteptype = TSTEP_INSTANT;  break;
+    case  1:  tsteptype = TSTEP_INSTANT2; break;
+    case  2:  tsteptype = TSTEP_RANGE;    break;
+    case  3:  tsteptype = TSTEP_AVG;      break;
+    case  4:  tsteptype = TSTEP_ACCUM;    break;
+    case  5:  tsteptype = TSTEP_DIFF;     break;
+    case 10:  tsteptype = TSTEP_INSTANT3; break;
+    default:
+      if ( lprint )
 	{
-	  int xdimids[2] = {-1,-1}, ydimids[2] = {-1,-1};
-	  int xdimid = -1, ydimid = -1;
-	  int xvarid = -1, yvarid = -1;
-	  int islon = 0, islat = 0;
-	  int nxdims = 0, nydims = 0;
-          size_t size = 0, np = 0;
-          size_t xsize = 0, ysize = 0;
-	  double xinc = 0, yinc = 0;
+	  Message("Time range indicator %d unsupported, set to 0!", timerange);
+	  lprint = FALSE;
+	}
+      break;
+    }
 
-	  int ndims = ncvars[ncvarid].ndims;
-	  for ( i = 0; i < ndims; i++ )
-	    {
-	      if ( ncvars[ncvarid].dimtype[i] == X_AXIS && nxdims < 2 )
-		{
-		  xdimids[nxdims] = ncvars[ncvarid].dimids[i];
-		  nxdims++;
-		}
-	      else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS && nydims < 2 )
-		{
-		  ydimids[nydims] = ncvars[ncvarid].dimids[i];
-		  nydims++;
-		}
-	    }
+  return (tsteptype);
+}
 
-	  if ( nxdims == 2 )
-	    {
-	      xdimid = xdimids[1];
-	      ydimid = xdimids[0];
-	    }
-	  else if ( nydims == 2 )
-	    {
-	      xdimid = ydimids[1];
-	      ydimid = ydimids[0];
-	    }
-	  else
-	    {
-	      xdimid = xdimids[0];
-	      ydimid = ydimids[0];
-	    }
+static
+void cgribexGetGrid(stream_t *streamptr, int *isec2, double *fsec2, int *isec4, grid_t *grid, int iret)
+{
+  int compyinc = TRUE;
+  int gridtype = cgribexGetGridType(isec2);
 
-	  if ( ncvars[ncvarid].xvarid != UNDEFID )
-	    xvarid = ncvars[ncvarid].xvarid;
-	  else if ( xdimid != UNDEFID )
-	    xvarid = ncdims[xdimid].ncvarid;
+  if ( streamptr->unreduced && gridtype == GRID_GAUSSIAN_REDUCED && iret != -801 )
+    {
+      int ilat, nlon = 0;
+      for ( ilat = 0; ilat < ISEC2_NumLat; ++ilat )
+        if ( ISEC2_RowLon(ilat) > nlon ) nlon = ISEC2_RowLon(ilat);
+      gridtype = GRID_GAUSSIAN;
+      ISEC2_NumLon = nlon;
+      ISEC4_NumValues = nlon*ISEC2_NumLat;
+      compyinc = FALSE;
+    }
 
-	  if ( ncvars[ncvarid].yvarid != UNDEFID )
-	    yvarid = ncvars[ncvarid].yvarid;
-	  else if ( ydimid != UNDEFID )
-	    yvarid = ncdims[ydimid].ncvarid;
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, 0);
+  switch (gridtype)
+    {
+    case GRID_LONLAT:
+    case GRID_GAUSSIAN:
+      {
+	if ( ISEC4_NumValues != ISEC2_NumLon*ISEC2_NumLat )
+	  Error("numberOfPoints (%d) and gridSize (%d) differ!", ISEC4_NumValues, ISEC2_NumLon*ISEC2_NumLat);
+	grid->size  = ISEC4_NumValues;
+	grid->xsize = ISEC2_NumLon;
+	grid->ysize = ISEC2_NumLat;
+        if ( gridtype == GRID_GAUSSIAN ) grid->np = ISEC2_NumPar;
+	grid->xinc  = 0;
+	grid->yinc  = 0;
+	grid->xdef  = 0;
+	/* if ( ISEC2_FirstLon != 0 || ISEC2_LastLon != 0 ) */
+	  {
+	    if ( grid->xsize > 1 )
+	      {
+                int recompinc = TRUE;
 
-	  /*
-	  if ( xdimid != UNDEFID )
-	    xvarid = ncdims[xdimid].ncvarid;
-	  if ( xvarid == UNDEFID && ncvars[ncvarid].xvarid != UNDEFID )
-	    xvarid = ncvars[ncvarid].xvarid;
+                if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
 
-	  if ( ydimid != UNDEFID )
-	    yvarid = ncdims[ydimid].ncvarid;
-	  if ( yvarid == UNDEFID && ncvars[ncvarid].yvarid != UNDEFID )
-	    yvarid = ncvars[ncvarid].yvarid;
-	  */
+		if ( ISEC2_ResFlag && ISEC2_LonIncr > 0 )
+                  {
+                    if ( abs(ISEC2_LastLon - (ISEC2_FirstLon+ISEC2_LonIncr*(grid->xsize-1))) <= 2 )
+                      {
+                        recompinc = FALSE;
+                        grid->xinc = ISEC2_LonIncr * 0.001;
+                      }
+                  }
 
-	  if ( xdimid != UNDEFID ) xsize = ncdims[xdimid].len;
-	  if ( ydimid != UNDEFID ) ysize = ncdims[ydimid].len;
+		/* recompute xinc if necessary */
+                if ( recompinc ) grid->xinc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->xsize-1);
 
-	  if ( ydimid == UNDEFID && yvarid != UNDEFID )
-	    {
-	      if ( ncvars[yvarid].ndims == 1 )
-		{
-		  ydimid = ncvars[yvarid].dimids[0];
-		  ysize  = ncdims[ydimid].len;
-		}
-	    }
+		/* correct xinc if necessary */
+		if ( ISEC2_FirstLon == 0 && ISEC2_LastLon > 354000 && ISEC2_LastLon < 360000 )
+		  {
+		    double xinc = 360. / grid->xsize;
 
-	  if ( ncvars[ncvarid].gridtype == UNDEFID || ncvars[ncvarid].gridtype == GRID_GENERIC )
-	    if ( xdimid != UNDEFID && xdimid == ydimid && nydims == 0 ) ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
+		    if ( fabs(grid->xinc-xinc) > 0.0 )
+		      {
+			grid->xinc = xinc;
+			if ( CDI_Debug ) Message("set xinc to %g", grid->xinc);
+		      }
+		  }
+	      }
+	    grid->xfirst = ISEC2_FirstLon * 0.001;
+	    grid->xlast  = ISEC2_LastLon  * 0.001;
+	    grid->xdef   = 2;
+	  }
+	grid->ydef  = 0;
+	/* if ( ISEC2_FirstLat != 0 || ISEC2_LastLat != 0 ) */
+	  {
+	    if ( grid->ysize > 1 && compyinc )
+	      {
+                int recompinc = TRUE;
+		if ( ISEC2_ResFlag && ISEC2_LatIncr > 0 )
+                  {
+                    if ( abs(ISEC2_LastLat - (ISEC2_FirstLat+ISEC2_LatIncr*(grid->ysize-1))) <= 2 )
+                      {
+                        recompinc = FALSE;
+                        grid->yinc = ISEC2_LatIncr * 0.001;
+                      }
+                  }
 
-	  grid_init(&grid);
-	  grid_init(&proj);
+		/* recompute yinc if necessary */
+                if ( recompinc ) grid->yinc = (ISEC2_LastLat - ISEC2_FirstLat) * 0.001 / (grid->ysize - 1);
+	      }
+	    grid->yfirst = ISEC2_FirstLat * 0.001;
+	    grid->ylast  = ISEC2_LastLat  * 0.001;
+	    grid->ydef   = 2;
+	  }
+	break;
+      }
+    case GRID_GAUSSIAN_REDUCED:
+      {
+        grid->np     = ISEC2_NumPar;
+	grid->size   = ISEC4_NumValues;
+        grid->rowlon = ISEC2_RowLonPtr;
+	grid->ysize  = ISEC2_NumLat;
+	grid->xinc   = 0;
+	grid->yinc   = 0;
+	grid->xdef   = 0;
+	/* if ( ISEC2_FirstLon != 0 || ISEC2_LastLon != 0 ) */
+	  {
+	    if ( grid->xsize > 1 )
+	      {
+                if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
 
-	  grid.prec  = DATATYPE_FLT64;
-	  grid.trunc = ncvars[ncvarid].truncation;
+		if ( ISEC2_ResFlag && ISEC2_LonIncr > 0 )
+		  grid->xinc = ISEC2_LonIncr * 0.001;
+		else
+		  grid->xinc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->xsize - 1);
+	      }
+	    grid->xfirst = ISEC2_FirstLon * 0.001;
+	    grid->xlast  = ISEC2_LastLon  * 0.001;
+	    grid->xdef   = 2;
+	  }
+	grid->ydef  = 0;
+	/* if ( ISEC2_FirstLat != 0 || ISEC2_LastLat != 0 ) */
+	  {
+	    if ( grid->ysize > 1 )
+	      {
+		if ( ISEC2_ResFlag && ISEC2_LatIncr > 0 )
+		  grid->yinc = ISEC2_LatIncr * 0.001;
+		else
+		  grid->yinc = (ISEC2_LastLat - ISEC2_FirstLat) * 0.001 / (grid->ysize - 1);
+	      }
+	    grid->yfirst = ISEC2_FirstLat * 0.001;
+	    grid->ylast  = ISEC2_LastLat  * 0.001;
+	    grid->ydef   = 2;
+	  }
+	break;
+      }
+    case GRID_LCC:
+      {
+	if ( ISEC4_NumValues != ISEC2_NumLon*ISEC2_NumLat )
+	  Error("numberOfPoints (%d) and gridSize (%d) differ!",
+		ISEC4_NumValues, ISEC2_NumLon*ISEC2_NumLat);
 
-	  if ( ncvars[ncvarid].gridtype == GRID_TRAJECTORY )
-	    {
-	      if ( ncvars[ncvarid].xvarid == UNDEFID )
-		Error("Longitude coordinate undefined for %s!", name);
-	      if ( ncvars[ncvarid].yvarid == UNDEFID )
-		Error("Latitude coordinate undefined for %s!", name);
-	    }
-	  else
-	    {
-	      size_t start[3], count[3];
-	      int ltgrid = FALSE;
+	grid->size  = ISEC4_NumValues;
+	grid->xsize = ISEC2_NumLon;
+	grid->ysize = ISEC2_NumLat;
 
-	      if ( xvarid != UNDEFID && yvarid != UNDEFID )
-		{
-		  if ( ncvars[xvarid].ndims != ncvars[yvarid].ndims )
-		    {
-		      Warning("Inconsistent grid structure for variable %s!", ncvars[ncvarid].name);
-		      ncvars[ncvarid].xvarid = UNDEFID;
-		      ncvars[ncvarid].yvarid = UNDEFID;
-		      xvarid = UNDEFID;
-		      yvarid = UNDEFID;
-		    }
+	grid->lcc_xinc      = ISEC2_Lambert_dx;
+	grid->lcc_yinc      = ISEC2_Lambert_dy;
+	grid->lcc_originLon = ISEC2_FirstLon * 0.001;
+	grid->lcc_originLat = ISEC2_FirstLat * 0.001;
+	grid->lcc_lonParY   = ISEC2_Lambert_Lov * 0.001;
+	grid->lcc_lat1      = ISEC2_Lambert_LatS1 * 0.001;
+	grid->lcc_lat2      = ISEC2_Lambert_LatS2 * 0.001;
+	grid->lcc_projflag  = ISEC2_Lambert_ProjFlag;
+	grid->lcc_scanflag  = ISEC2_ScanFlag;
 
-		  if ( ncvars[xvarid].ndims > 2 || ncvars[yvarid].ndims > 2 )
-		    {
-		      if ( ncvars[xvarid].ndims == 3 && ncvars[xvarid].dimids[0] == timedimid &&
-			   ncvars[yvarid].ndims == 3 && ncvars[yvarid].dimids[0] == timedimid )
-			{
-			  if ( ltwarn )
-			    Warning("Time varying grids unsupported, using grid at time step 1!");
-			  ltgrid = TRUE;
-			  ltwarn = FALSE;
-			  start[0] = start[1] = start[2] = 0;
-			  count[0] = 1; count[1] = ysize; count[2] = xsize;
-			}
-		      else
-			{
-			  Warning("Unsupported grid structure for variable %s (grid dims > 2)!", ncvars[ncvarid].name);
-			  ncvars[ncvarid].xvarid = UNDEFID;
-			  ncvars[ncvarid].yvarid = UNDEFID;
-			  xvarid = UNDEFID;
-			  yvarid = UNDEFID;
-			}
-		    }
-		}
+	grid->xdef   = 0;
+	grid->ydef   = 0;
 
-              if ( xvarid != UNDEFID )
-                {
-                  if ( ncvars[xvarid].ndims > 3 || (ncvars[xvarid].ndims == 3 && ltgrid == FALSE) )
-                    {
-                      Warning("Coordinate variable %s has to many dimensions (%d), skipped!", ncvars[xvarid].name, ncvars[xvarid].ndims);
-                      //ncvars[ncvarid].xvarid = UNDEFID;
-                      xvarid = UNDEFID;
-                    }
-                }
+	break;
+      }
+    case GRID_SPECTRAL:
+      {
+	grid->size  = ISEC4_NumValues;
+	grid->trunc = ISEC2_PentaJ;
+	if ( ISEC2_RepMode == 2 )
+	  grid->lcomplex = 1;
+	else
+	  grid->lcomplex = 0;
 
-              if ( yvarid != UNDEFID )
-                {
-                  if ( ncvars[yvarid].ndims > 3 || (ncvars[yvarid].ndims == 3 && ltgrid == FALSE) )
-                    {
-                      Warning("Coordinate variable %s has to many dimensions (%d), skipped!", ncvars[yvarid].name, ncvars[yvarid].ndims);
-                      //ncvars[ncvarid].yvarid = UNDEFID;
-                      yvarid = UNDEFID;
-                    }
-                }
+	break;
+      }
+    case GRID_GME:
+      {
+	grid->size  = ISEC4_NumValues;
+	grid->nd    = ISEC2_GME_ND;
+	grid->ni    = ISEC2_GME_NI;
+	grid->ni2   = ISEC2_GME_NI2;
+	grid->ni3   = ISEC2_GME_NI3;
+	break;
+      }
+    case GRID_GENERIC:
+      {
+	grid->size  = ISEC4_NumValues;
+	grid->xsize = 0;
+	grid->ysize = 0;
+	break;
+      }
+    default:
+      {
+	Error("Unsupported grid type: %s", gridNamePtr(gridtype));
+	break;
+      }
+    }
 
-              if ( xvarid != UNDEFID )
-		{
-                  skipvar = TRUE;
-		  islon = ncvars[xvarid].islon;
-		  ndims = ncvars[xvarid].ndims;
-		  if ( ndims == 2 || ndims == 3 )
-		    {
-		      ncvars[ncvarid].gridtype = GRID_CURVILINEAR;
-		      size = xsize*ysize;
-		      /* Check size of 2 dimensional coordinate variables */
-		      {
-			int dimid = ncvars[xvarid].dimids[ndims-2];
-			size_t dimsize1 = ncdims[dimid].len;
-			dimid = ncvars[xvarid].dimids[ndims-1];
-			size_t dimsize2 = ncdims[dimid].len;
-			if ( dimsize1*dimsize2 == size ) skipvar = FALSE;
-		      }
-		    }
-		  else if ( ndims == 1 )
-		    {
-		      size = xsize;
-		      /* Check size of 1 dimensional coordinate variables */
-		      {
-			int dimid = ncvars[xvarid].dimids[0];
-			size_t dimsize = ncdims[dimid].len;
-			if ( dimsize == size ) skipvar = FALSE;
-		      }
-		    }
-		  else if ( ndims == 0 && xsize == 0 )
-		    {
-                      xsize = 1;
-		      size = xsize;
-                      skipvar = FALSE;
-		    }
+  grid->isRotated = FALSE;
+  if ( cgribexGetIsRotated(isec2) )
+    {
+      grid->isRotated = TRUE;
+      grid->ypole     = - ISEC2_LatSP*0.001;
+      grid->xpole     =   ISEC2_LonSP*0.001 - 180;
+      grid->angle     = - FSEC2_RotAngle;
+    }
 
-                  if ( skipvar )
-                    {
-                      Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                      ncvars[ncvarid].isvar = -1;
-                      continue;
-                    }
+  grid->xvals = NULL;
+  grid->yvals = NULL;
+  grid->type  = gridtype;
+}
 
-		  if ( ncvars[xvarid].xtype == NC_FLOAT ) grid.prec = DATATYPE_FLT32;
-		  grid.xvals = (double *) Malloc(size*sizeof(double));
+static
+void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, double *fsec2, double *fsec3,
+		      int *isec4, long recsize, off_t position, int datatype, int comptype, int lmv, int iret)
+{
+  int varID;
+  int levelID = 0;
+  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
 
-		  if ( ltgrid )
-		    cdf_get_vara_double(ncvars[xvarid].ncid, xvarid, start, count, grid.xvals);
-		  else
-		    cdf_get_var_double(ncvars[xvarid].ncid, xvarid, grid.xvals);
+  int vlistID = streamptr->vlistID;
+  int tsID    = streamptr->curTsID;
+  int recID   = recordNewEntry(streamptr, tsID);
+  record_t *record  = &streamptr->tsteps[tsID].records[recID];
 
-                  scale_add(size, grid.xvals, ncvars[xvarid].addoffset, ncvars[xvarid].scalefactor);
+  int tsteptype = cgribexGetTsteptype(ISEC1_TimeRange);
+  int numavg    = ISEC1_AvgNum;
 
-		  strcpy(grid.xname, ncvars[xvarid].name);
-		  strcpy(grid.xlongname, ncvars[xvarid].longname);
-		  strcpy(grid.xunits, ncvars[xvarid].units);
-		  /* don't change the name !!! */
-		  /*
-		  if ( (len = strlen(grid.xname)) > 2 )
-		    if ( grid.xname[len-2] == '_' && isdigit((int) grid.xname[len-1]) )
-		      grid.xname[len-2] = 0;
-		  */
-		  if ( islon && xsize > 1 )
-		    {
-		      xinc = fabs(grid.xvals[0] - grid.xvals[1]);
-		      for ( i = 2; i < (int) xsize; i++ )
-			if ( (fabs(grid.xvals[i-1] - grid.xvals[i]) - xinc) > (xinc/1000) ) break;
+  int level1  = ISEC1_Level1;
+  int level2  = ISEC1_Level2;
 
-		      if ( i < (int) xsize ) xinc = 0;
-		    }
-		}
+  /* fprintf(stderr, "param %d %d %d %d\n", param, level1, level2, ISEC1_LevelType); */
 
-	      if ( yvarid != UNDEFID )
-		{
-                  skipvar = TRUE;
-		  islat = ncvars[yvarid].islat;
-		  ndims = ncvars[yvarid].ndims;
-		  if ( ndims == 2 || ndims == 3 )
-		    {
-		      ncvars[ncvarid].gridtype = GRID_CURVILINEAR;
-		      size = xsize*ysize;
-		      /* Check size of 2 dimensional coordinate variables */
-		      {
-			int dimid;
-			size_t dimsize1, dimsize2;
-			dimid = ncvars[yvarid].dimids[ndims-2];
-			dimsize1 = ncdims[dimid].len;
-			dimid = ncvars[yvarid].dimids[ndims-1];
-			dimsize2 = ncdims[dimid].len;
-			if ( dimsize1*dimsize2 == size ) skipvar = FALSE;
-		      }
-		    }
-		  else if ( ndims == 1 )
-		    {
-		      if ( (int) ysize == 0 ) size = xsize;
-		      else                    size = ysize;
+  record->size      = (size_t)recsize;
+  record->position  = position;
+  record->param     = param;
+  record->ilevel    = level1;
+  record->ilevel2   = level2;
+  record->ltype     = ISEC1_LevelType;
+  record->tsteptype = (short)tsteptype;
 
-		      /* Check size of 1 dimensional coordinate variables */
-		      {
-			int dimid;
-			size_t dimsize;
-			dimid = ncvars[yvarid].dimids[0];
-			dimsize = ncdims[dimid].len;
-			if ( dimsize == size ) skipvar = FALSE;
-		      }
-		    }
-		  else if ( ndims == 0 && ysize == 0 )
-		    {
-                      ysize = 1;
-		      size = ysize;
-                      skipvar = FALSE;
-		    }
+  cgribexGetGrid(streamptr, isec2, fsec2, isec4, grid, iret);
 
-                  if ( skipvar )
-                    {
-                      Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                      ncvars[ncvarid].isvar = -1;
-                      continue;
-                    }
+  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  int gridID = gridAdded.Id;
+  if (!gridAdded.isNew) Free(grid);
 
-		  if ( ncvars[yvarid].xtype == NC_FLOAT ) grid.prec = DATATYPE_FLT32;
-		  grid.yvals = (double *) Malloc(size*sizeof(double));
+  int zaxistype = grib1ltypeToZaxisType(ISEC1_LevelType);
 
-		  if ( ltgrid )
-		    cdf_get_vara_double(ncvars[yvarid].ncid, yvarid, start, count, grid.yvals);
-		  else
-		    cdf_get_var_double(ncvars[yvarid].ncid, yvarid, grid.yvals);
+  if ( zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF )
+    {
+      size_t vctsize = (size_t)ISEC2_NumVCP;
+      double *vctptr = &fsec2[10];
 
-                  scale_add(size, grid.yvals, ncvars[yvarid].addoffset, ncvars[yvarid].scalefactor);
+      varDefVCT(vctsize, vctptr);
+    }
 
-		  strcpy(grid.yname, ncvars[yvarid].name);
-		  strcpy(grid.ylongname, ncvars[yvarid].longname);
-		  strcpy(grid.yunits, ncvars[yvarid].units);
-		  /* don't change the name !!! */
-		  /*
-		  if ( (len = strlen(grid.yname)) > 2 )
-		    if ( grid.yname[len-2] == '_' && isdigit((int) grid.yname[len-1]) )
-		      grid.yname[len-2] = 0;
-		  */
-		  if ( islon && (int) ysize > 1 )
-		    {
-		      yinc = fabs(grid.yvals[0] - grid.yvals[1]);
-		      for ( i = 2; i < (int) ysize; i++ )
-			if ( (fabs(grid.yvals[i-1] - grid.yvals[i]) - yinc) > (yinc/1000) ) break;
+  int lbounds = cgribexGetZaxisHasBounds(ISEC1_LevelType);
 
-		      if ( i < (int) ysize ) yinc = 0;
-		    }
-		}
+  if ( datatype > 32 ) datatype = DATATYPE_PACK32;
+  if ( datatype <  0 ) datatype = DATATYPE_PACK;
 
-	      if      ( (int) ysize == 0 ) size = xsize;
-	      else if ( (int) xsize == 0 ) size = ysize;
-	      else if ( ncvars[ncvarid].gridtype == GRID_UNSTRUCTURED ) size = xsize;
-	      else                         size = xsize*ysize;
-	    }
+  varAddRecord(recID, param, gridID, zaxistype, lbounds, level1, level2, 0, 0,
+	       datatype, &varID, &levelID, tsteptype, numavg, ISEC1_LevelType, -1,
+               NULL, NULL, NULL, NULL, NULL, NULL);
 
-	  if ( ncvars[ncvarid].gridtype == UNDEFID ||
-	       ncvars[ncvarid].gridtype == GRID_GENERIC )
-	    {
-	      if ( islat && islon )
-		{
-		  if ( isGaussGrid(ysize, yinc, grid.yvals) )
-                    {
-                      ncvars[ncvarid].gridtype = GRID_GAUSSIAN;
-                      np = ysize/2;
-                    }
-                  else
-		    ncvars[ncvarid].gridtype = GRID_LONLAT;
-		}
-	      else if ( islat && !islon && xsize == 0 )
-		{
-		  if ( isGaussGrid(ysize, yinc, grid.yvals) )
-                    {
-                      ncvars[ncvarid].gridtype = GRID_GAUSSIAN;
-                      np = ysize/2;
-                    }
-                  else
-		    ncvars[ncvarid].gridtype = GRID_LONLAT;
-		}
-	      else if ( islon && !islat && ysize == 0 )
-		{
-		  ncvars[ncvarid].gridtype = GRID_LONLAT;
-		}
-	      else
-		ncvars[ncvarid].gridtype = GRID_GENERIC;
-	    }
+  record->varID   = (short)varID;
+  record->levelID = (short)levelID;
 
-	  switch (ncvars[ncvarid].gridtype)
-	    {
-	    case GRID_GENERIC:
-	    case GRID_LONLAT:
-	    case GRID_GAUSSIAN:
-	    case GRID_UNSTRUCTURED:
-	    case GRID_CURVILINEAR:
-	      {
-		grid.size  = (int)size;
-		grid.xsize = (int)xsize;
-		grid.ysize = (int)ysize;
-                grid.np    = (int)np;
-		if ( xvarid != UNDEFID )
-		  {
-		    grid.xdef  = 1;
-		    if ( ncvars[xvarid].bounds != UNDEFID )
-		      {
-			nbdims = ncvars[ncvars[xvarid].bounds].ndims;
-			if ( nbdims == 2 || nbdims == 3 )
-			  {
-			    nvertex = ncdims[ncvars[ncvars[xvarid].bounds].dimids[nbdims-1]].len;
-			    grid.nvertex = (int) nvertex;
-			    grid.xbounds = (double *) Malloc(nvertex*size*sizeof(double));
-			    cdf_get_var_double(ncvars[xvarid].ncid, ncvars[xvarid].bounds, grid.xbounds);
-			  }
-		      }
-		  }
-		if ( yvarid != UNDEFID )
-		  {
-		    grid.ydef  = 1;
-		    if ( ncvars[yvarid].bounds != UNDEFID )
-		      {
-			nbdims = ncvars[ncvars[yvarid].bounds].ndims;
-			if ( nbdims == 2 || nbdims == 3 )
-			  {
-			    nvertex = ncdims[ncvars[ncvars[yvarid].bounds].dimids[nbdims-1]].len;
-			    /*
-			    if ( nvertex != grid.nvertex )
-			      Warning("nvertex problem! nvertex x %d, nvertex y %d",
-				      grid.nvertex, (int) nvertex);
-			    */
-			    grid.ybounds = (double *) Malloc(nvertex*size*sizeof(double));
-			    cdf_get_var_double(ncvars[yvarid].ncid, ncvars[yvarid].bounds, grid.ybounds);
-			  }
-		      }
-		  }
+  varDefCompType(varID, comptype);
 
-		if ( ncvars[ncvarid].cellarea != UNDEFID )
-		  {
-		    grid.area = (double *) Malloc(size*sizeof(double));
-		    cdf_get_var_double(ncvars[ncvarid].ncid, ncvars[ncvarid].cellarea, grid.area);
-		  }
+  if ( ISEC1_LocalFLag )
+    {
+      if      ( ISEC1_CenterID == 78  && isec1[36] == 253 ) // DWD local extension
+        varDefEnsembleInfo(varID, isec1[54], isec1[53], isec1[52]);
+      else if ( ISEC1_CenterID == 252 && isec1[36] ==   1 ) // MPIM local extension
+        varDefEnsembleInfo(varID, isec1[38], isec1[39], isec1[37]);
+    }
 
-		break;
-	      }
-	    case GRID_SPECTRAL:
-	      {
-		grid.size = (int)size;
-		grid.lcomplex = 1;
-		break;
-	      }
-	    case GRID_FOURIER:
-	      {
-		grid.size = (int)size;
-		break;
-	      }
-	    case GRID_TRAJECTORY:
-	      {
-		grid.size = 1;
-		break;
-	      }
-	    }
+  if ( lmv ) varDefMissval(varID, FSEC3_MissVal);
 
-	  grid.type = ncvars[ncvarid].gridtype;
+  if ( varInqInst(varID) == CDI_UNDEFID )
+    {
+      int center, subcenter, instID;
+      center    = ISEC1_CenterID;
+      subcenter = ISEC1_SubCenterID;
+      instID    = institutInq(center, subcenter, NULL, NULL);
+      if ( instID == CDI_UNDEFID )
+	instID = institutDef(center, subcenter, NULL, NULL);
+      varDefInst(varID, instID);
+    }
 
-	  if ( grid.size == 0 )
-	    {
-	      if ( (ncvars[ncvarid].ndims == 1 && ncvars[ncvarid].dimtype[0] == T_AXIS) ||
-		   (ncvars[ncvarid].ndims == 1 && ncvars[ncvarid].dimtype[0] == Z_AXIS) ||
-		   (ncvars[ncvarid].ndims == 2 && ncvars[ncvarid].dimtype[0] == T_AXIS && ncvars[ncvarid].dimtype[1] == Z_AXIS) )
-		{
-		  grid.type  = GRID_GENERIC;
-		  grid.size  = 1;
-		  grid.xsize = 0;
-		  grid.ysize = 0;
-		}
-	      else
-		{
-		  Warning("Variable %s has an unsupported grid, skipped!", ncvars[ncvarid].name);
-		  ncvars[ncvarid].isvar = -1;
-		  continue;
-		}
-	    }
+  if ( varInqModel(varID) == CDI_UNDEFID )
+    {
+      int modelID;
+      modelID = modelInq(varInqInst(varID), ISEC1_ModelID, NULL);
+      if ( modelID == CDI_UNDEFID )
+	modelID = modelDef(varInqInst(varID), ISEC1_ModelID, NULL);
+      varDefModel(varID, modelID);
+    }
 
-	  if ( number_of_grid_used != UNDEFID && (grid.type == UNDEFID || grid.type == GRID_GENERIC) )
-            grid.type   = GRID_UNSTRUCTURED;
+  if ( varInqTable(varID) == CDI_UNDEFID )
+    {
+      int tableID;
 
-	  if ( number_of_grid_used != UNDEFID && grid.type == GRID_UNSTRUCTURED )
-            grid.number = number_of_grid_used;
+      tableID = tableInq(varInqModel(varID), ISEC1_CodeTable, NULL);
 
-	  if ( ncvars[ncvarid].gmapid >= 0 && ncvars[ncvarid].gridtype != GRID_CURVILINEAR )
-	    {
-	      cdf_inq_varnatts(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, &nvatts);
+      if ( tableID == CDI_UNDEFID )
+	tableID = tableDef(varInqModel(varID), ISEC1_CodeTable, NULL);
+      varDefTable(varID, tableID);
+    }
 
-	      for ( iatt = 0; iatt < nvatts; iatt++ )
-		{
-		  cdf_inq_attname(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, iatt, attname);
-		  cdf_inq_attlen(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, &attlen);
+  streamptr->tsteps[tsID].nallrecs++;
+  streamptr->nrecs++;
+}
 
-		  if ( strcmp(attname, "grid_mapping_name") == 0 )
-		    {
-                      enum {
-                        attstringlen = 8192,
-                      };
-                      char attstring[attstringlen];
+static
+void MCH_get_undef(int *isec1, double *undef_pds, double *undef_eps)
+{
+  /* 2010-01-13: Oliver Fuhrer */
+  if ( ISEC1_CenterID == 215 ) {
+    if (isec1[34] != 0 && isec1[34] != 255) {
+      if (isec1[34] & 2) {
+        if (isec1[34] & 1) {
+          *undef_pds = -0.99*pow(10.0,-isec1[35]);
+        } else {
+          *undef_pds = +0.99*pow(10.0,-isec1[35]);
+        }
+        *undef_eps = pow(10.0,-isec1[35]-1);
+      } else {
+        if (isec1[34] & 1) {
+          *undef_pds = -0.99*pow(10.0,+isec1[35]);
+        } else {
+          *undef_pds = +0.99*pow(10.0,+isec1[35]);
+        }
+        *undef_eps = pow(10.0,isec1[35]-1);
+      }
+    }
+  }
+}
 
-		      cdfGetAttText(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, attstringlen, attstring);
-		      strtolower(attstring);
+static
+void cgribexDecodeHeader(int *isec0, int *isec1, int *isec2, double *fsec2,
+			 int *isec3, double *fsec3, int *isec4, double *fsec4,
+			 int *gribbuffer, int recsize, int *lmv, int *iret)
+{
+  int ipunp = 0, iword = 0;
 
-		      if ( strcmp(attstring, "rotated_latitude_longitude") == 0 )
-			grid.isRotated = TRUE;
-		      else if ( strcmp(attstring, "sinusoidal") == 0 )
-			grid.type = GRID_SINUSOIDAL;
-		      else if ( strcmp(attstring, "lambert_azimuthal_equal_area") == 0 )
-			grid.type = GRID_LAEA;
-		      else if ( strcmp(attstring, "lambert_conformal_conic") == 0 )
-			grid.type = GRID_LCC2;
-		      else if ( strcmp(attstring, "lambert_cylindrical_equal_area") == 0 )
-			{
-			  proj.type = GRID_PROJECTION;
-			  proj.name = strdup(attstring);
-			}
-		    }
-		  else if ( strcmp(attname, "earth_radius") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
-		      grid.laea_a = datt;
-		      grid.lcc2_a = datt;
-		    }
-		  else if ( strcmp(attname, "longitude_of_projection_origin") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid.laea_lon_0);
-		    }
-		  else if ( strcmp(attname, "longitude_of_central_meridian") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid.lcc2_lon_0);
-		    }
-		  else if ( strcmp(attname, "latitude_of_projection_origin") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
-		      grid.laea_lat_0 = datt;
-		      grid.lcc2_lat_0 = datt;
-		    }
-		  else if ( strcmp(attname, "standard_parallel") == 0 )
-		    {
-		      if ( attlen == 1 )
-			{
-			  cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
-			  grid.lcc2_lat_1 = datt;
-			  grid.lcc2_lat_2 = datt;
-			}
-		      else
-			{
-			  double datt2[2];
-			  cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 2, datt2);
-			  grid.lcc2_lat_1 = datt2[0];
-			  grid.lcc2_lat_2 = datt2[1];
-			}
-		    }
-		  else if ( strcmp(attname, "grid_north_pole_latitude") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid.ypole);
-		    }
-		  else if ( strcmp(attname, "grid_north_pole_longitude") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid.xpole);
-		    }
-		  else if ( strcmp(attname, "north_pole_grid_longitude") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid.angle);
-		    }
-		}
-	    }
+  memset(isec1, 0, 256*sizeof(int));
 
-          if ( grid.type == GRID_UNSTRUCTURED )
-            {
-              int zdimid = UNDEFID;
-              int xdimidx = -1, ydimidx = -1;
+  gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, fsec4,
+	   ipunp, (int *) gribbuffer, recsize, &iword, "J", iret);
 
-              for ( i = 0; i < ndims; i++ )
-                {
-                  if      ( ncvars[ncvarid].dimtype[i] == X_AXIS ) xdimidx = i;
-                  else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) ydimidx = i;
-                  else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) zdimid = ncvars[ncvarid].dimids[i];
-                }
+  *lmv = 0;
 
-              if ( xdimid != UNDEFID && ydimid != UNDEFID && zdimid == UNDEFID )
-                {
-                  if ( grid.xsize > grid.ysize && grid.ysize < 1000 )
-                    {
-                      ncvars[ncvarid].dimtype[ydimidx] = Z_AXIS;
-                      ydimid = UNDEFID;
-                      grid.size  = grid.xsize;
-                      grid.ysize = 0;
-                    }
-                  else if ( grid.ysize > grid.xsize && grid.xsize < 1000 )
-                    {
-                      ncvars[ncvarid].dimtype[xdimidx] = Z_AXIS;
-                      xdimid = ydimid;
-                      ydimid = UNDEFID;
-                      grid.size  = grid.ysize;
-                      grid.xsize = grid.ysize;
-                      grid.ysize = 0;
-                    }
-                }
+  if ( ISEC1_CenterID == 215 && (isec1[34] != 0 && isec1[34] != 255) )
+    {
+      double undef_pds, undef_eps;
 
-              if ( grid.size != grid.xsize )
-                {
-                  Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                  ncvars[ncvarid].isvar = -1;
-                  continue;
-                }
+      MCH_get_undef(isec1, &undef_pds, &undef_eps);
+      FSEC3_MissVal = undef_pds;
+      *lmv = 1;
+    }
+}
 
-              if ( ncvars[ncvarid].position > 0 ) grid.position = ncvars[ncvarid].position;
-              if ( uuidOfHGrid[0] != 0 ) memcpy(grid.uuid, uuidOfHGrid, 16);
-            }
+static
+compvar_t cgribexVarSet(int param, int level1, int level2, int leveltype, int trange)
+{
+  compvar_t compVar;
+  int tsteptype = cgribexGetTsteptype(trange);
 
-#if defined (PROJECTION_TEST)
-	  if ( proj.type == GRID_PROJECTION )
-	    {
-	      if ( grid.type == GRID_GENERIC )
-		{
-		  grid.type = GRID_CURVILINEAR;
-		}
+  compVar.param     = param;
+  compVar.level1    = level1;
+  compVar.level2    = level2;
+  compVar.ltype     = leveltype;
+  compVar.tsteptype = tsteptype;
 
-	      if ( grid.type == GRID_CURVILINEAR )
-		{
-		  proj.size  = grid.size;
-		  proj.xsize = grid.xsize;
-                  proj.ysize = grid.ysize;
-		}
+  return (compVar);
+}
 
-	      //  grid.proj = gridGenerate(proj);
-	    }
+static inline int
+cgribexVarCompare(compvar_t compVar, record_t record, int flag)
+{
+  int tstepDiff = (!((flag == 0) & (((compVar.tsteptype == TSTEP_INSTANT)
+                                     & (record.tsteptype == TSTEP_INSTANT3))
+                                    |((compVar.tsteptype == TSTEP_INSTANT3)
+                                      & (record.tsteptype == TSTEP_INSTANT)))))
+    & (compVar.tsteptype != record.tsteptype);
+  int rstatus = (compVar.param != record.param)
+    |           (compVar.level1 != record.ilevel)
+    |           (compVar.level2 != record.ilevel2)
+    |           (compVar.ltype != record.ltype)
+    |           tstepDiff;
+  return (rstatus);
+}
 #endif
 
-	  if ( CDI_Debug )
-	    {
-	      Message("grid: type = %d, size = %d, nx = %d, ny %d",
-		      grid.type, grid.size, grid.xsize, grid.ysize);
-	      Message("proj: type = %d, size = %d, nx = %d, ny %d",
-		      proj.type, proj.size, proj.xsize, proj.ysize);
-	    }
-
-#if defined (PROJECTION_TEST)
-	  if ( proj.type == GRID_PROJECTION )
-	    {
-	      ncvars[ncvarid].gridID = varDefGrid(vlistID, &proj, 1);
-	      copy_numeric_projatts(ncvars[ncvarid].gridID, ncvars[ncvarid].gmapid, ncvars[ncvarid].ncid);
-	    }
-	  else
-#endif
-	    ncvars[ncvarid].gridID = varDefGrid(vlistID, &grid, 1);
+#define gribWarning(text, nrecs, timestep, paramstr, level1, level2) \
+            Warning("Record %2d (id=%s lev1=%d lev2=%d) timestep %d: %s", nrecs, paramstr, level1, level2, timestep, text)
 
-          if ( grid.type == GRID_UNSTRUCTURED )
-            {
-              if ( gridfile[0] != 0 ) gridDefReference(ncvars[ncvarid].gridID, gridfile);
-            }
+#if  defined  (HAVE_LIBCGRIBEX)
 
-          if ( ncvars[ncvarid].chunked ) grid_set_chunktype(&grid, &ncvars[ncvarid]);
+static inline void
+cgribexScanTsFixNtsteps(stream_t *streamptr, off_t recpos)
+{
+  if ( streamptr->ntsteps == -1 )
+    {
+      int tsID = tstepsNewEntry(streamptr);
+      if ( tsID != streamptr->rtsteps )
+	Error("Internal error. tsID = %d", tsID);
 
-	  gridindex = vlistGridIndex(vlistID, ncvars[ncvarid].gridID);
-	  streamptr->xdimID[gridindex] = xdimid;
-	  streamptr->ydimID[gridindex] = ydimid;
-          if ( xdimid == -1 && ydimid == -1 && grid.size == 1 )
-            gridDefHasDims(ncvars[ncvarid].gridID, FALSE);
+      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID].position = recpos;
+    }
+}
 
-	  if ( CDI_Debug )
-	    Message("gridID %d %d %s", ncvars[ncvarid].gridID, ncvarid, ncvars[ncvarid].name);
+static inline void
+cgribexScanTsConstAdjust(stream_t *streamptr, taxis_t *taxis)
+{
+  int vlistID = streamptr->vlistID;
+  if ( streamptr->ntsteps == 1 )
+    {
+      if ( taxis->vdate == 0 && taxis->vtime == 0 )
+	{
+	  streamptr->ntsteps = 0;
+	  for (int varID = 0; varID < streamptr->nvars; varID++ )
+	    {
+	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	    }
+	}
+    }
+}
 
-	  for ( ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
-	    if ( ncvars[ncvarid2].isvar == TRUE && ncvars[ncvarid2].gridID == UNDEFID )
-	      {
-		int xdimid2 = UNDEFID, ydimid2 = UNDEFID, zdimid2 = UNDEFID;
-                int xdimidx = -1, ydimidx = -1;
-		int ndims2 = ncvars[ncvarid2].ndims;
 
-		for ( i = 0; i < ndims2; i++ )
-		  {
-		    if ( ncvars[ncvarid2].dimtype[i] == X_AXIS )
-		      { xdimid2 = ncvars[ncvarid2].dimids[i]; xdimidx = i; }
-		    else if ( ncvars[ncvarid2].dimtype[i] == Y_AXIS )
-		      { ydimid2 = ncvars[ncvarid2].dimids[i]; ydimidx = i; }
-		    else if ( ncvars[ncvarid2].dimtype[i] == Z_AXIS )
-		      { zdimid2 = ncvars[ncvarid2].dimids[i]; }
-		  }
+int cgribexScanTimestep1(stream_t * streamptr)
+{
+  double fsec2[512], fsec3[2], *fsec4 = NULL;
+  int lmv = 0, iret = 0;
+  off_t recpos = 0;
+  void *gribbuffer = NULL;
+  size_t buffersize = 0;
+  int rstatus;
+  int param = 0;
+  int level1 = 0, level2 = 0, vdate = 0, vtime = 0;
+  DateTime datetime, datetime0 = { LONG_MIN, LONG_MIN };
+  size_t readsize;
+  unsigned nrecords, recID;
+  int nrecs_scanned = 0;
+  int datatype;
+  long recsize = 0;
+  int warn_time = TRUE;
+  int warn_numavg = TRUE;
+  int taxisID = -1;
+  int rdate = 0, rtime = 0, tunit = 0, fcast = 0;
+  int vlistID;
+  int comptype;
+  long unzipsize;
+  char paramstr[32];
+  int nskip = cdiSkipRecords;
 
-                if ( ncvars[ncvarid2].gridtype == UNDEFID && grid.type == GRID_UNSTRUCTURED )
-                  {
-                    if ( xdimid == xdimid2 && ydimid2 != UNDEFID && zdimid2 == UNDEFID )
-                      {
-                        ncvars[ncvarid2].dimtype[ydimidx] = Z_AXIS;
-                        ydimid2 = UNDEFID;
-                      }
+  streamptr->curTsID = 0;
 
-                    if ( xdimid == ydimid2 && xdimid2 != UNDEFID && zdimid2 == UNDEFID )
-                      {
-                        ncvars[ncvarid2].dimtype[xdimidx] = Z_AXIS;
-                        xdimid2 = ydimid2;
-                        ydimid2 = UNDEFID;
-                      }
-                  }
+  int *isec0 = streamptr->record->sec0;
+  int *isec1 = streamptr->record->sec1;
+  int *isec2 = streamptr->record->sec2;
+  int *isec3 = streamptr->record->sec3;
+  int *isec4 = streamptr->record->sec4;
 
-                if ( xdimid == xdimid2 &&
-		    (ydimid == ydimid2 || (xdimid == ydimid && ydimid2 == UNDEFID)) )
-		  {
-		    int same_grid = TRUE;
-                    /*
-		    if ( xvarid != -1 && ncvars[ncvarid2].xvarid != UNDEFID &&
-			 xvarid != ncvars[ncvarid2].xvarid ) same_grid = FALSE;
+  int tsID  = tstepsNewEntry(streamptr);
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
-		    if ( yvarid != -1 && ncvars[ncvarid2].yvarid != UNDEFID &&
-			 yvarid != ncvars[ncvarid2].yvarid ) same_grid = FALSE;
-                    */
-		    if ( ncvars[ncvarid].xvarid != ncvars[ncvarid2].xvarid ) same_grid = FALSE;
-		    if ( ncvars[ncvarid].yvarid != ncvars[ncvarid2].yvarid ) same_grid = FALSE;
+  if ( tsID != 0 )
+    Error("Internal problem! tstepsNewEntry returns %d", tsID);
 
-		    if ( ncvars[ncvarid].position != ncvars[ncvarid2].position ) same_grid = FALSE;
+  int fileID = streamptr->fileID;
 
-		    if ( same_grid )
-		      {
-			if ( CDI_Debug )
-			  Message("Same gridID %d %d %s", ncvars[ncvarid].gridID, ncvarid2, ncvars[ncvarid2].name);
-			ncvars[ncvarid2].gridID = ncvars[ncvarid].gridID;
-			ncvars[ncvarid2].chunktype = ncvars[ncvarid].chunktype;
-		      }
-		  }
-	      }
+  while ( nskip-- > 0 )
+    {
+      recsize = gribGetSize(fileID);
+      if ( recsize == 0 )
+	Error("Skipping of %d records failed!", cdiSkipRecords);
 
-	  grid_free(&grid);
-	  grid_free(&proj);
-	}
+      recpos  = fileGetPos(fileID);
+      fileSetPos(fileID, (off_t)recsize, SEEK_CUR);
     }
-}
-
-/* define all input zaxes */
-static
-void define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars,
-		      size_t vctsize_echam, double *vct_echam, unsigned char *uuidOfVGrid)
-{
-  int ncvarid, ncvarid2;
-  int i, ilev;
-  int zaxisindex;
-  int nbdims, nvertex, nlevel;
-  int psvarid = -1;
-  char *pname, *plongname, *punits;
-  size_t vctsize = vctsize_echam;
-  double *vct = vct_echam;
 
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  unsigned nrecs = 0;
+  while ( TRUE )
     {
-      if ( ncvars[ncvarid].isvar == TRUE && ncvars[ncvarid].zaxisID == UNDEFID )
-	{
-          int is_scalar = FALSE;
-	  int with_bounds = FALSE;
-	  int zdimid = UNDEFID;
-	  int zvarid = UNDEFID;
-	  int zsize = 1;
-	  double *lbounds = NULL;
-	  double *ubounds = NULL;
+      recsize = gribGetSize(fileID);
+      recpos  = fileGetPos(fileID);
 
-          int positive = 0;
-	  int ndims = ncvars[ncvarid].ndims;
+      if ( recsize == 0 )
+	{
+	  if ( nrecs == 0 )
+	    Error("No GRIB records found!");
 
-          if ( ncvars[ncvarid].zvarid != -1 && ncvars[ncvars[ncvarid].zvarid].ndims == 0 )
-            {
-              zvarid = ncvars[ncvarid].zvarid;
-              is_scalar = TRUE;
-            }
-          else
-            {
-              for ( i = 0; i < ndims; i++ )
-                {
-                  if ( ncvars[ncvarid].dimtype[i] == Z_AXIS )
-                    zdimid = ncvars[ncvarid].dimids[i];
-                }
+	  streamptr->ntsteps = 1;
+	  break;
+	}
+      if ( (size_t)recsize > buffersize )
+	{
+	  buffersize = (size_t)recsize;
+	  gribbuffer = Realloc(gribbuffer, buffersize);
+	}
 
-              if ( zdimid != UNDEFID )
-                {
-                  zvarid = ncdims[zdimid].ncvarid;
-                  zsize  = (int)ncdims[zdimid].len;
-                }
-            }
+      readsize = (size_t)recsize;
+      rstatus = gribRead(fileID, (unsigned char *)gribbuffer, &readsize);
+      if ( rstatus ) break;
 
-	  if ( CDI_Debug ) Message("nlevs = %d", zsize);
+      comptype = COMPRESS_NONE;
+      if ( gribGetZip(recsize, (unsigned char *)gribbuffer, &unzipsize) > 0 )
+	{
+	  comptype = COMPRESS_SZIP;
+	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
+	  if ( buffersize < (size_t)unzipsize )
+	    {
+	      buffersize = (size_t)unzipsize;
+	      gribbuffer = Realloc(gribbuffer, buffersize);
+	    }
+	}
 
-	  double *zvar = (double *) Malloc((size_t)zsize * sizeof (double));
+      nrecs_scanned++;
+      cgribexDecodeHeader(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, fsec4,
+			  (int *) gribbuffer, (int)recsize, &lmv, &iret);
 
-	  int zaxisType = UNDEFID;
-	  if ( zvarid != UNDEFID ) zaxisType = ncvars[zvarid].zaxistype;
-	  if ( zaxisType == UNDEFID )  zaxisType = ZAXIS_GENERIC;
+      param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
+      cdiParamToString(param, paramstr, sizeof(paramstr));
 
-	  int zprec = DATATYPE_FLT64;
+      if ( ISEC1_LevelType == 100 ) ISEC1_Level1 *= 100;
+      if ( ISEC1_LevelType ==  99 ) ISEC1_LevelType = 100;
+      level1   = ISEC1_Level1;
+      level2   = ISEC1_Level2;
 
-	  if ( zvarid != UNDEFID )
-	    {
-	      positive  = ncvars[zvarid].positive;
-	      pname     = ncvars[zvarid].name;
-	      plongname = ncvars[zvarid].longname;
-	      punits    = ncvars[zvarid].units;
-	      if ( ncvars[zvarid].xtype == NC_FLOAT ) zprec = DATATYPE_FLT32;
-	      /* don't change the name !!! */
-	      /*
-	      if ( (len = strlen(pname)) > 2 )
-		if ( pname[len-2] == '_' && isdigit((int) pname[len-1]) )
-		  pname[len-2] = 0;
-	      */
-              psvarid = -1;
-              if ( zaxisType == ZAXIS_HYBRID && ncvars[zvarid].vct )
-                {
-                  vct = ncvars[zvarid].vct;
-                  vctsize = ncvars[zvarid].vctsize;
+      gribDateTime(isec1, &vdate, &vtime);
 
-                  if ( ncvars[zvarid].psvarid != -1 ) psvarid = ncvars[zvarid].psvarid;
-                }
+      if ( ISEC4_NumBits > 0 && ISEC4_NumBits <= 32 )
+	datatype = ISEC4_NumBits;
+      else
+        datatype = DATATYPE_PACK;
 
-	      cdf_get_var_double(ncvars[zvarid].ncid, zvarid, zvar);
+      if ( nrecs == 0 )
+	{
+	  datetime0.date = vdate;
+	  datetime0.time = vtime;
+	  rdate = gribRefDate(isec1);
+	  rtime = gribRefTime(isec1);
+	  tunit = cgribexGetTimeUnit(isec1);
+	  fcast = cgribexTimeIsFC(isec1);
+	}
+      else
+	{
+	  datetime.date  = vdate;
+	  datetime.time  = vtime;
+	  compvar_t compVar = cgribexVarSet(param, level1, level2, ISEC1_LevelType, ISEC1_TimeRange);
+	  for ( recID = 0; recID < nrecs; recID++ )
+	    {
+	      if ( cgribexVarCompare(compVar, streamptr->tsteps[0].records[recID], 0) == 0 ) break;
+	    }
 
-	      if ( ncvars[zvarid].bounds != UNDEFID )
-		{
-		  nbdims = ncvars[ncvars[zvarid].bounds].ndims;
-		  if ( nbdims == 2 )
-		    {
-		      nlevel  = (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[0]].len;
-		      nvertex = (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[1]].len;
-		      if ( nlevel == zsize && nvertex == 2 )
-			{
-			  with_bounds = TRUE;
-			  lbounds = (double *) Malloc((size_t)nlevel*sizeof(double));
-			  ubounds = (double *) Malloc((size_t)nlevel*sizeof(double));
-			  double zbounds[2*nlevel];
-			  cdf_get_var_double(ncvars[zvarid].ncid, ncvars[zvarid].bounds, zbounds);
-			  for ( i = 0; i < nlevel; ++i )
-			    {
-			      lbounds[i] = zbounds[i*2];
-			      ubounds[i] = zbounds[i*2+1];
-			    }
-			}
-		    }
-		}
+	  if ( cdiInventoryMode == 1 )
+	    {
+	      if ( recID < nrecs ) break;
+	      if ( warn_time )
+		if ( datetimeCmp(datetime, datetime0) != 0 )
+		  {
+                    gribWarning("Inconsistent verification time!", nrecs_scanned, tsID+1, paramstr, level1, level2);
+		    warn_time = FALSE;
+		  }
 	    }
 	  else
 	    {
-	      pname     = NULL;
-	      plongname = NULL;
-	      punits    = NULL;
-
-	      if ( zsize == 1 )
-		{
-                  if ( ncvars[ncvarid].zaxistype != UNDEFID )
-                    zaxisType = ncvars[ncvarid].zaxistype;
-                  else
-                    zaxisType = ZAXIS_SURFACE;
+	      if ( datetimeCmp(datetime, datetime0) != 0 ) break;
 
-		  zvar[0] = 0;
-		  /*
-		  if ( zdimid == UNDEFID )
-		    zvar[0] = 9999;
-		  else
-		    zvar[0] = 0;
-		  */
-		}
-	      else
+	      if ( recID < nrecs )
 		{
-		  for ( ilev = 0; ilev < zsize; ilev++ ) zvar[ilev] = ilev + 1;
+		  gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, paramstr, level1, level2);
+		  continue;
 		}
 	    }
+	}
 
-      	  ncvars[ncvarid].zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, with_bounds, lbounds, ubounds,
-						(int)vctsize, vct, pname, plongname, punits, zprec, 1, 0);
+      if ( ISEC1_AvgNum )
+	{
+	  if (  taxis->numavg && warn_numavg && (taxis->numavg != ISEC1_AvgNum) )
+	    {
+	      Warning("Changing numavg from %d to %d not supported!", taxis->numavg, ISEC1_AvgNum);
+	      warn_numavg = FALSE;
+	    }
+	  else
+	    {
+	      taxis->numavg = ISEC1_AvgNum;
+	    }
+	}
 
-	  if ( uuidOfVGrid[0] != 0 )
-            {
-              // printf("uuidOfVGrid: defined\n");
-              zaxisDefUUID(ncvars[ncvarid].zaxisID, uuidOfVGrid);
-            }
+      nrecs++;
 
-          if ( zaxisType == ZAXIS_HYBRID && psvarid != -1 ) zaxisDefPsName(ncvars[ncvarid].zaxisID, ncvars[psvarid].name);
+      if ( CDI_Debug )
+	Message("Read record %2d (id=%s lev1=%d lev2=%d) %8d %6d", nrecs_scanned, paramstr, level1, level2, vdate, vtime);
 
-          if ( positive > 0 ) zaxisDefPositive(ncvars[ncvarid].zaxisID, positive);
-          if ( is_scalar ) zaxisDefScalar(ncvars[ncvarid].zaxisID);
+      cgribexAddRecord(streamptr, param, isec1, isec2, fsec2, fsec3,
+		       isec4, recsize, recpos, datatype, comptype, lmv, iret);
+    }
 
-	  Free(zvar);
-	  Free(lbounds);
-	  Free(ubounds);
+  streamptr->rtsteps = 1;
 
-	  zaxisindex = vlistZaxisIndex(vlistID, ncvars[ncvarid].zaxisID);
-	  streamptr->zaxisID[zaxisindex]  = zdimid;
+  if ( nrecs == 0 ) return (CDI_EUFSTRUCT);
 
-	  if ( CDI_Debug )
-	    Message("zaxisID %d %d %s", ncvars[ncvarid].zaxisID, ncvarid, ncvars[ncvarid].name);
+  cdi_generate_vars(streamptr);
 
-	  for ( ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
-	    if ( ncvars[ncvarid2].isvar == TRUE && ncvars[ncvarid2].zaxisID == UNDEFID /*&& ncvars[ncvarid2].zaxistype == UNDEFID*/ )
-	      {
-                int zvarid2 = UNDEFID;
-                if ( ncvars[ncvarid2].zvarid != UNDEFID && ncvars[ncvars[ncvarid2].zvarid].ndims == 0 )
-                  zvarid2 = ncvars[ncvarid2].zvarid;
+  if ( fcast )
+    {
+      taxisID = taxisCreate(TAXIS_RELATIVE);
+      taxis->type  = TAXIS_RELATIVE;
+      taxis->rdate = rdate;
+      taxis->rtime = rtime;
+      taxis->unit  = tunit;
+    }
+  else
+    {
+      taxisID = taxisCreate(TAXIS_ABSOLUTE);
+      taxis->type  = TAXIS_ABSOLUTE;
+      taxis->unit  = tunit;
+    }
 
-		int zdimid2 = UNDEFID;
-		ndims = ncvars[ncvarid2].ndims;
-		for ( i = 0; i < ndims; i++ )
-		  {
-		    if ( ncvars[ncvarid2].dimtype[i] == Z_AXIS )
-		      zdimid2 = ncvars[ncvarid2].dimids[i];
-		  }
+  taxis->vdate = (int)datetime0.date;
+  taxis->vtime = (int)datetime0.time;
 
-		if ( zdimid == zdimid2 /* && zvarid == zvarid2 */)
-		  {
-                    if ( (zdimid != UNDEFID && ncvars[ncvarid2].zaxistype == UNDEFID) ||
-                         (zdimid == UNDEFID && zvarid != UNDEFID && zvarid == zvarid2) ||
-                         (zdimid == UNDEFID && zaxisType == ncvars[ncvarid2].zaxistype) ||
-                         (zdimid == UNDEFID && zvarid2 == UNDEFID && ncvars[ncvarid2].zaxistype == UNDEFID) )
-                      {
-                        if ( CDI_Debug )
-                          Message("zaxisID %d %d %s", ncvars[ncvarid].zaxisID, ncvarid2, ncvars[ncvarid2].name);
-                        ncvars[ncvarid2].zaxisID = ncvars[ncvarid].zaxisID;
-                      }
-                  }
-	      }
-	}
+  vlistID = streamptr->vlistID;
+  vlistDefTaxis(vlistID, taxisID);
+
+  nrecords = (unsigned)streamptr->tsteps[0].nallrecs;
+  if ( nrecords < (unsigned)streamptr->tsteps[0].recordSize )
+    {
+      streamptr->tsteps[0].recordSize = (int)nrecords;
+      streamptr->tsteps[0].records =
+      (record_t *) Realloc(streamptr->tsteps[0].records, nrecords*sizeof(record_t));
     }
+
+  streamptr->tsteps[0].recIDs = (int *) Malloc(nrecords*sizeof(int));
+  streamptr->tsteps[0].nrecs = (int)nrecords;
+  for ( recID = 0; recID < nrecords; recID++ )
+    streamptr->tsteps[0].recIDs[recID] = (int)recID;
+
+  streamptr->record->buffer     = gribbuffer;
+  streamptr->record->buffersize = (size_t)buffersize;
+
+  cgribexScanTsFixNtsteps(streamptr, recpos);
+  cgribexScanTsConstAdjust(streamptr, taxis);
+
+  return (0);
 }
 
-struct varinfo
-{
-  int      ncvarid;
-  const char *name;
-};
 
-static
-int cmpvarname(const void *s1, const void *s2)
+int cgribexScanTimestep2(stream_t * streamptr)
 {
-  const struct varinfo *x = (const struct varinfo *)s1,
-    *y = (const struct varinfo *)s2;
-  return (strcmp(x->name, y->name));
-}
+  int rstatus = 0;
+  double fsec2[512], fsec3[2], *fsec4 = NULL;
+  int lmv = 0, iret = 0;
+  off_t recpos = 0;
+  int param = 0;
+  int level1 = 0, level2 = 0, vdate = 0, vtime = 0;
+  DateTime datetime, datetime0 = { LONG_MIN, LONG_MIN };
+  int varID, gridID;
+  size_t readsize;
+  int nrecs, recID;
+  long recsize = 0;
+  int warn_numavg = TRUE;
+  int tsteptype;
+  long unzipsize;
+  char paramstr[32];
+
+  streamptr->curTsID = 1;
+
+  int *isec0 = streamptr->record->sec0;
+  int *isec1 = streamptr->record->sec1;
+  int *isec2 = streamptr->record->sec2;
+  int *isec3 = streamptr->record->sec3;
+  int *isec4 = streamptr->record->sec4;
+
+  int fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int taxisID = vlistInqTaxis(vlistID);
+
+  void *gribbuffer = streamptr->record->buffer;
+  size_t buffersize = streamptr->record->buffersize;
+
+  int tsID = streamptr->rtsteps;
+  if ( tsID != 1 )
+    Error("Internal problem! unexpected timestep %d", tsID+1);
+
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+
+  fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+
+  cdi_create_records(streamptr, tsID);
+
+  int nrecords = streamptr->tsteps[tsID].nallrecs;
+  if ( nrecords ) streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords * sizeof(int));
+  streamptr->tsteps[1].nrecs = 0;
+  for ( recID = 0; recID < nrecords; recID++ )
+    streamptr->tsteps[1].recIDs[recID] = -1;
+
+  for ( recID = 0; recID < nrecords; recID++ )
+    {
+      varID = streamptr->tsteps[0].records[recID].varID;
+      streamptr->tsteps[tsID].records[recID].position =	streamptr->tsteps[0].records[recID].position;
+      streamptr->tsteps[tsID].records[recID].size     =	streamptr->tsteps[0].records[recID].size;
+    }
 
-/* define all input data variables */
-static
-void define_all_vars(stream_t *streamptr, int vlistID, int instID, int modelID, int *varids, int nvars, int num_ncvars, ncvar_t *ncvars)
-{
-  if ( streamptr->sortname )
+  int nrecs_scanned = nrecords;
+  int rindex = 0;
+  while ( TRUE )
     {
-      struct varinfo *varInfo
-        = (struct varinfo *) Malloc((size_t)nvars * sizeof (struct varinfo));
+      if ( rindex > nrecords ) break;
 
-      for ( int varID = 0; varID < nvars; varID++ )
+      recsize = gribGetSize(fileID);
+      recpos  = fileGetPos(fileID);
+      if ( recsize == 0 )
 	{
-	  int ncvarid = varids[varID];
-	  varInfo[varID].ncvarid = ncvarid;
-	  varInfo[varID].name = ncvars[ncvarid].name;
+	  streamptr->ntsteps = 2;
+	  break;
 	}
-      qsort(varInfo, (size_t)nvars, sizeof(varInfo[0]), cmpvarname);
-      for ( int varID = 0; varID < nvars; varID++ )
+      if ( (size_t)recsize > buffersize )
 	{
-	  varids[varID] = varInfo[varID].ncvarid;
+	  buffersize = (size_t)recsize;
+	  gribbuffer = Realloc(gribbuffer, buffersize);
 	}
-      Free(varInfo);
-    }
 
-  for ( int varID1 = 0; varID1 < nvars; varID1++ )
-    {
-      int ncvarid = varids[varID1];
-      int gridID  = ncvars[ncvarid].gridID;
-      int zaxisID = ncvars[ncvarid].zaxisID;
+      readsize = (size_t)recsize;
+      rstatus = gribRead(fileID, (unsigned char *)gribbuffer, &readsize);
+      if ( rstatus ) break;
 
-      stream_new_var(streamptr, gridID, zaxisID, CDI_UNDEFID);
-      int varID = vlistDefVar(vlistID, gridID, zaxisID, ncvars[ncvarid].tsteptype);
+      if ( gribGetZip(recsize, (unsigned char *)gribbuffer, &unzipsize) > 0 )
+	{
+	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
+	  if ( buffersize < (size_t)unzipsize )
+	    {
+	      buffersize = (size_t)unzipsize;
+	      gribbuffer = Realloc(gribbuffer, buffersize);
+	    }
+	}
 
-#if  defined  (HAVE_NETCDF4)
-      if ( ncvars[ncvarid].deflate )
-	vlistDefVarCompType(vlistID, varID, COMPRESS_ZIP);
+      cgribexDecodeHeader(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, fsec4,
+			  (int *) gribbuffer, (int)recsize, &lmv, &iret);
 
-      if ( ncvars[ncvarid].chunked && ncvars[ncvarid].chunktype != UNDEFID )
-        vlistDefVarChunkType(vlistID, varID, ncvars[ncvarid].chunktype);
-#endif
+      nrecs_scanned++;
 
-      streamptr->vars[varID1].defmiss = 0;
-      streamptr->vars[varID1].ncvarid = ncvarid;
+      param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
+      cdiParamToString(param, paramstr, sizeof(paramstr));
 
-      vlistDefVarName(vlistID, varID, ncvars[ncvarid].name);
-      if ( ncvars[ncvarid].param != UNDEFID ) vlistDefVarParam(vlistID, varID, ncvars[ncvarid].param);
-      if ( ncvars[ncvarid].code != UNDEFID )  vlistDefVarCode(vlistID, varID, ncvars[ncvarid].code);
-      if ( ncvars[ncvarid].code != UNDEFID )
+      if ( ISEC1_LevelType == 100 ) ISEC1_Level1 *= 100;
+      if ( ISEC1_LevelType ==  99 ) ISEC1_LevelType = 100;
+      level1    = ISEC1_Level1;
+      level2    = ISEC1_Level2;
+
+      gribDateTime(isec1, &vdate, &vtime);
+
+      if ( rindex == 0 )
 	{
-	  int param = cdiEncodeParam(ncvars[ncvarid].code, ncvars[ncvarid].tabnum, 255);
-	  vlistDefVarParam(vlistID, varID, param);
+	  if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
+	    {
+	      taxis->type  = TAXIS_RELATIVE;
+	      taxis->rdate = gribRefDate(isec1);
+	      taxis->rtime = gribRefTime(isec1);
+	    }
+	  else
+	    {
+	      taxis->type  = TAXIS_ABSOLUTE;
+	    }
+	  taxis->unit  = cgribexGetTimeUnit(isec1);
+	  taxis->vdate = vdate;
+	  taxis->vtime = vtime;
+
+	  datetime0.date = vdate;
+	  datetime0.time = vtime;
 	}
-      if ( ncvars[ncvarid].longname[0] )  vlistDefVarLongname(vlistID, varID, ncvars[ncvarid].longname);
-      if ( ncvars[ncvarid].stdname[0] )   vlistDefVarStdname(vlistID, varID, ncvars[ncvarid].stdname);
-      if ( ncvars[ncvarid].units[0] )     vlistDefVarUnits(vlistID, varID, ncvars[ncvarid].units);
 
-      if ( ncvars[ncvarid].lvalidrange )
-        vlistDefVarValidrange(vlistID, varID, ncvars[ncvarid].validrange);
+      tsteptype = cgribexGetTsteptype(ISEC1_TimeRange);
 
-      if ( IS_NOT_EQUAL(ncvars[ncvarid].addoffset, 0) )
-	vlistDefVarAddoffset(vlistID, varID, ncvars[ncvarid].addoffset);
-      if ( IS_NOT_EQUAL(ncvars[ncvarid].scalefactor, 1) )
-	vlistDefVarScalefactor(vlistID, varID, ncvars[ncvarid].scalefactor);
+      if ( ISEC1_AvgNum )
+	{
+	  if (  taxis->numavg && warn_numavg &&
+        	(taxis->numavg != ISEC1_AvgNum) )
+	    {
+	  /*
+	      Warning("Changing numavg from %d to %d not supported!", taxis->numavg, ISEC1_AvgNum);
+	  */
+	      warn_numavg = FALSE;
+	    }
+	  else
+	    {
+	      taxis->numavg = ISEC1_AvgNum;
+	    }
+	}
 
-      vlistDefVarDatatype(vlistID, varID, cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned));
+      datetime.date  = vdate;
+      datetime.time  = vtime;
 
-      vlistDefVarInstitut(vlistID, varID, instID);
-      vlistDefVarModel(vlistID, varID, modelID);
-      if ( ncvars[ncvarid].tableID != UNDEFID )
-	vlistDefVarTable(vlistID, varID, ncvars[ncvarid].tableID);
+      compvar_t compVar = cgribexVarSet(param, level1, level2, ISEC1_LevelType, ISEC1_TimeRange);
 
-      if ( ncvars[ncvarid].deffillval == FALSE && ncvars[ncvarid].defmissval == TRUE )
-        {
-          ncvars[ncvarid].deffillval = TRUE;
-          ncvars[ncvarid].fillval    = ncvars[ncvarid].missval;
-        }
+      for ( recID = 0; recID < nrecords; recID++ )
+	{
+	  if ( cgribexVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) == 0 ) break;
+	}
 
-      if ( ncvars[ncvarid].deffillval == TRUE )
-        vlistDefVarMissval(vlistID, varID, ncvars[ncvarid].fillval);
+      if ( recID == nrecords )
+	{
+	  gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, paramstr, level1, level2);
+	  return (CDI_EUFSTRUCT);
+	}
 
-      if ( CDI_Debug )
-	Message("varID = %d  gridID = %d  zaxisID = %d", varID,
-		vlistInqVarGrid(vlistID, varID), vlistInqVarZaxis(vlistID, varID));
+      if ( cdiInventoryMode == 1 )
+	{
+	  if ( streamptr->tsteps[tsID].records[recID].used )
+	    {
+	      break;
+	    }
+	  else
+	    {
+	      streamptr->tsteps[tsID].records[recID].used = TRUE;
+	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
+	    }
+	}
+      else
+	{
+	  if ( streamptr->tsteps[tsID].records[recID].used )
+	    {
+	      if ( datetimeCmp(datetime, datetime0) != 0 ) break;
 
-      int gridindex = vlistGridIndex(vlistID, gridID);
-      int xdimid = streamptr->xdimID[gridindex];
-      int ydimid = streamptr->ydimID[gridindex];
+              gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, paramstr, level1, level2);
+	      continue;
+	    }
+	  else
+	    {
+	      streamptr->tsteps[tsID].records[recID].used = TRUE;
+	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
+	    }
+	}
 
-      int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-      int zdimid = streamptr->zaxisID[zaxisindex];
+      if ( CDI_Debug )
+	Message("Read record %2d (id=%s lev1=%d lev2=%d) %8d %6d", nrecs_scanned, paramstr, level1, level2, vdate, vtime);
 
-      int ndims = ncvars[ncvarid].ndims;
-      int iodim = 0;
-      int ixyz = 0;
-      int ipow10[4] = {1, 10, 100, 1000};
+      streamptr->tsteps[tsID].records[recID].size = (size_t)recsize;
 
-      if ( ncvars[ncvarid].tsteptype != TSTEP_CONSTANT ) iodim++;
+      if ( cgribexVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) != 0 )
+	{
+	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
+		  tsID, recID,
+		  streamptr->tsteps[tsID].records[recID].param, param,
+		  streamptr->tsteps[tsID].records[recID].ilevel, level1);
+	  return (CDI_EUFSTRUCT);
+	}
 
-      if ( gridInqType(gridID) == GRID_UNSTRUCTURED && ndims-iodim <= 2 && ydimid == xdimid )
-        {
-          if ( xdimid == ncvars[ncvarid].dimids[ndims-1] )
-            {
-              ixyz = 321;
-            }
-          else
-            {
-              ixyz = 213;
-            }
-        }
-      else
-        {
-          for ( int idim = iodim; idim < ndims; idim++ )
-            {
-              if      ( xdimid == ncvars[ncvarid].dimids[idim] )
-                ixyz += 1*ipow10[ndims-idim-1];
-              else if ( ydimid == ncvars[ncvarid].dimids[idim] )
-                ixyz += 2*ipow10[ndims-idim-1];
-              else if ( zdimid == ncvars[ncvarid].dimids[idim] )
-                ixyz += 3*ipow10[ndims-idim-1];
-            }
-        }
+      streamptr->tsteps[1].records[recID].position = recpos;
+      varID = streamptr->tsteps[tsID].records[recID].varID;
+      gridID = vlistInqVarGrid(vlistID, varID);
+      if ( gridInqSize(gridID) == 1 && gridInqType(gridID) == GRID_LONLAT )
+	{
+	  if ( IS_NOT_EQUAL(gridInqXval(gridID, 0),ISEC2_FirstLon*0.001) ||
+	       IS_NOT_EQUAL(gridInqYval(gridID, 0),ISEC2_FirstLat*0.001) )
+	    gridChangeType(gridID, GRID_TRAJECTORY);
+	}
 
-      vlistDefVarXYZ(vlistID, varID, ixyz);
-      /*
-      printf("ixyz %d\n", ixyz);
-      printf("ndims %d\n", ncvars[ncvarid].ndims);
-      for ( int i = 0; i < ncvars[ncvarid].ndims; ++i )
-        printf("dimids: %d %d\n", i, ncvars[ncvarid].dimids[i]);
-      printf("xdimid, ydimid %d %d\n", xdimid, ydimid);
-      */
-      if ( ncvars[ncvarid].ensdata != NULL )
-        {
-          vlistDefVarEnsemble( vlistID, varID, ncvars[ncvarid].ensdata->ens_index,
-                               ncvars[ncvarid].ensdata->ens_count,
-                               ncvars[ncvarid].ensdata->forecast_init_type );
-          Free(ncvars[ncvarid].ensdata);
-          ncvars[ncvarid].ensdata = NULL;
-        }
+      if ( tsteptype != vlistInqVarTsteptype(vlistID, varID) )
+	vlistDefVarTsteptype(vlistID, varID, tsteptype);
 
-      if ( ncvars[ncvarid].extra[0] != 0 )
-        {
-          vlistDefVarExtra(vlistID, varID, ncvars[ncvarid].extra);
-        }
+      rindex++;
     }
 
-  for ( int varID = 0; varID < nvars; varID++ )
+  nrecs = 0;
+  for ( recID = 0; recID < nrecords; recID++ )
     {
-      int ncvarid = varids[varID];
-      int ncid = ncvars[ncvarid].ncid;
-
-      if ( ncvars[ncvarid].natts )
+      if ( ! streamptr->tsteps[tsID].records[recID].used )
 	{
-	  int attnum;
-	  int iatt;
-	  nc_type attrtype;
-	  size_t attlen;
-	  char attname[CDI_MAX_NAME];
-	  const int attstringlen = 8192; char attstring[8192];
-	  int nvatts = ncvars[ncvarid].natts;
+	  varID = streamptr->tsteps[tsID].records[recID].varID;
+          vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	}
+      else
+	{
+	  nrecs++;
+	}
+    }
+  streamptr->tsteps[tsID].nrecs = nrecs;
 
-	  for ( iatt = 0; iatt < nvatts; iatt++ )
-	    {
-	      attnum = ncvars[ncvarid].atts[iatt];
-	      cdf_inq_attname(ncid, ncvarid, attnum, attname);
-	      cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
-	      cdf_inq_atttype(ncid, ncvarid, attname, &attrtype);
+  streamptr->rtsteps = 2;
 
-	      if ( attrtype == NC_SHORT || attrtype == NC_INT )
-		{
-		  int attint[attlen];
-		  cdfGetAttInt(ncid, ncvarid, attname, (int)attlen, attint);
-		  if ( attrtype == NC_SHORT )
-		    vlistDefAttInt(vlistID, varID, attname, DATATYPE_INT16, (int)attlen, attint);
-		  else
-		    vlistDefAttInt(vlistID, varID, attname, DATATYPE_INT32, (int)attlen, attint);
-		}
-	      else if ( attrtype == NC_FLOAT || attrtype == NC_DOUBLE )
-		{
-		  double attflt[attlen];
-		  cdfGetAttDouble(ncid, ncvarid, attname, (int)attlen, attflt);
-		  if ( attrtype == NC_FLOAT )
-		    vlistDefAttFlt(vlistID, varID, attname, DATATYPE_FLT32, (int)attlen, attflt);
-		  else
-		    vlistDefAttFlt(vlistID, varID, attname, DATATYPE_FLT64, (int)attlen, attflt);
-		}
-	      else if ( xtypeIsText(attrtype) )
-		{
-		  cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-		  vlistDefAttTxt(vlistID, varID, attname, (int)attlen, attstring);
-		}
-	      else
-		{
-		  if ( CDI_Debug ) printf("att: %s.%s = unknown\n", ncvars[ncvarid].name, attname);
-		}
-	    }
+  cgribexScanTsFixNtsteps(streamptr, recpos);
 
-	  if (ncvars[ncvarid].vct) Free(ncvars[ncvarid].vct);
-	  if (ncvars[ncvarid].atts) Free(ncvars[ncvarid].atts);
-          ncvars[ncvarid].vct = NULL;
-          ncvars[ncvarid].atts = NULL;
-	}
-    }
+  streamptr->record->buffer     = gribbuffer;
+  streamptr->record->buffersize = buffersize;
 
-  /* release mem of not freed attributes */
-  for ( int ncvarid = 0; ncvarid < num_ncvars; ncvarid++ )
-    if ( ncvars[ncvarid].atts ) Free(ncvars[ncvarid].atts);
+  return (rstatus);
+}
+#endif
 
-  if ( varids ) Free(varids);
 
-  for ( int varID = 0; varID < nvars; varID++ )
+#if  defined  (HAVE_LIBCGRIBEX)
+int cgribexScanTimestep(stream_t * streamptr)
+{
+  int rstatus = 0;
+  double fsec2[512], fsec3[2], *fsec4 = NULL;
+  int lmv = 0, iret = 0;
+  long recsize = 0;
+  off_t recpos = 0;
+  void *gribbuffer;
+  size_t buffersize = 0;
+  int fileID;
+  int param = 0;
+  int level1 = 0, level2 = 0, vdate = 0, vtime = 0;
+  DateTime datetime, datetime0 = { LONG_MIN, LONG_MIN };
+  int vrecID, recID;
+  int warn_numavg = TRUE;
+  size_t readsize;
+  int taxisID = -1;
+  int rindex, nrecs = 0;
+  int nrecs_scanned;
+  long unzipsize;
+  char paramstr[32];
+
+  /*
+  if ( CDI_Debug )
     {
-      if ( vlistInqVarCode(vlistID, varID) == -varID-1 )
+      Message("streamID = %d", streamptr->self);
+      Message("cts = %d", streamptr->curTsID);
+      Message("rts = %d", streamptr->rtsteps);
+      Message("nts = %d", streamptr->ntsteps);
+    }
+  */
+  int *isec0 = streamptr->record->sec0;
+  int *isec1 = streamptr->record->sec1;
+  int *isec2 = streamptr->record->sec2;
+  int *isec3 = streamptr->record->sec3;
+  int *isec4 = streamptr->record->sec4;
+
+  int tsID  = streamptr->rtsteps;
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+
+  if ( streamptr->tsteps[tsID].recordSize == 0 )
+    {
+      gribbuffer = streamptr->record->buffer;
+      buffersize = streamptr->record->buffersize;
+
+      cdi_create_records(streamptr, tsID);
+
+      nrecs = streamptr->tsteps[1].nrecs;
+
+      streamptr->tsteps[tsID].nrecs = nrecs;
+      streamptr->tsteps[tsID].recIDs = (int *) Malloc((size_t)nrecs * sizeof (int));
+      for ( recID = 0; recID < nrecs; recID++ )
+	streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
+
+      fileID = streamptr->fileID;
+
+      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+
+      nrecs_scanned = streamptr->tsteps[0].nallrecs + streamptr->tsteps[1].nrecs*(tsID-1);
+      rindex = 0;
+      while ( TRUE )
 	{
-	  const char *pname = vlistInqVarNamePtr(vlistID, varID);
-	  size_t len = strlen(pname);
-	  if ( len > 3 && isdigit((int) pname[3]) )
+	  if ( rindex > nrecs ) break;
+
+	  recsize = gribGetSize(fileID);
+	  recpos  = fileGetPos(fileID);
+	  if ( recsize == 0 )
 	    {
-	      if ( memcmp("var", pname, 3) == 0 )
-		{
-		  vlistDefVarCode(vlistID, varID, atoi(pname+3));
-                  // vlistDestroyVarName(vlistID, varID);
-		}
+	      streamptr->ntsteps = streamptr->rtsteps + 1;
+	      break;
 	    }
-	  else if ( len > 4 && isdigit((int) pname[4]) )
+	  if ( recsize > 0 && (size_t)recsize > buffersize )
 	    {
-	      if ( memcmp("code", pname, 4) == 0 )
-		{
-		  vlistDefVarCode(vlistID, varID, atoi(pname+4));
-		  // vlistDestroyVarName(vlistID, varID);
-		}
+	      buffersize = (size_t)recsize;
+	      gribbuffer = Realloc(gribbuffer, buffersize);
 	    }
-	  else if ( len > 5 && isdigit((int) pname[5]) )
+
+	  if ( rindex >= nrecs ) break;
+
+	  readsize = (size_t)recsize;
+	  rstatus = gribRead(fileID, (unsigned char *)gribbuffer, &readsize);
+	  if ( rstatus )
 	    {
-	      if ( memcmp("param", pname, 5) == 0 )
-		{
-		  int pnum = -1, pcat = 255, pdis = 255;
-		  sscanf(pname+5, "%d.%d.%d", &pnum, &pcat, &pdis);
-		  vlistDefVarParam(vlistID, varID, cdiEncodeParam(pnum, pcat, pdis));
-                  // vlistDestroyVarName(vlistID, varID);
-		}
+	      Warning("Inconsistent timestep %d (GRIB record %d/%d)!", tsID+1, rindex+1,
+                      streamptr->tsteps[tsID].recordSize);
+	      break;
 	    }
-	}
-    }
 
-  for ( int varID = 0; varID < nvars; varID++ )
-    {
-      int varInstID  = vlistInqVarInstitut(vlistID, varID);
-      int varModelID = vlistInqVarModel(vlistID, varID);
-      int varTableID = vlistInqVarTable(vlistID, varID);
-      int code = vlistInqVarCode(vlistID, varID);
-      if ( cdiDefaultTableID != UNDEFID )
-	{
-	  if ( tableInqParNamePtr(cdiDefaultTableID, code) )
+	  if ( gribGetZip(recsize, (unsigned char *)gribbuffer, &unzipsize) > 0 )
 	    {
-	      vlistDestroyVarName(vlistID, varID);
-	      vlistDestroyVarLongname(vlistID, varID);
-	      vlistDestroyVarUnits(vlistID, varID);
-
-	      if ( varTableID != UNDEFID )
-		{
-		  vlistDefVarName(vlistID, varID, tableInqParNamePtr(cdiDefaultTableID, code));
-		  if ( tableInqParLongnamePtr(cdiDefaultTableID, code) )
-		    vlistDefVarLongname(vlistID, varID, tableInqParLongnamePtr(cdiDefaultTableID, code));
-		  if ( tableInqParUnitsPtr(cdiDefaultTableID, code) )
-		    vlistDefVarUnits(vlistID, varID, tableInqParUnitsPtr(cdiDefaultTableID, code));
-		}
-	      else
+	      unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
+	      if ( buffersize < (size_t)unzipsize )
 		{
-		  varTableID = cdiDefaultTableID;
+		  buffersize = (size_t)unzipsize;
+		  gribbuffer = Realloc(gribbuffer, buffersize);
 		}
 	    }
 
-	  if ( cdiDefaultModelID != UNDEFID ) varModelID = cdiDefaultModelID;
-	  if ( cdiDefaultInstID  != UNDEFID ) varInstID  = cdiDefaultInstID;
-	}
-      if ( varInstID  != UNDEFID ) vlistDefVarInstitut(vlistID, varID, varInstID);
-      if ( varModelID != UNDEFID ) vlistDefVarModel(vlistID, varID, varModelID);
-      if ( varTableID != UNDEFID ) vlistDefVarTable(vlistID, varID, varTableID);
-    }
-}
+	  cgribexDecodeHeader(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, fsec4,
+			      (int *) gribbuffer, (int)recsize, &lmv, &iret);
 
-static
-void scan_global_attributes(int fileID, int vlistID, stream_t *streamptr, int ngatts, int *instID, int *modelID, int *ucla_les, unsigned char *uuidOfHGrid, unsigned char *uuidOfVGrid, char *gridfile, int *number_of_grid_used)
-{
-  nc_type xtype;
-  size_t attlen;
-  char attname[CDI_MAX_NAME];
-  enum { attstringlen = 65636 };
-  char attstring[attstringlen];
-  int iatt;
+          nrecs_scanned++;
 
-  for ( iatt = 0; iatt < ngatts; iatt++ )
-    {
-      cdf_inq_attname(fileID, NC_GLOBAL, iatt, attname);
-      cdf_inq_atttype(fileID, NC_GLOBAL, attname, &xtype);
-      cdf_inq_attlen(fileID, NC_GLOBAL, attname, &attlen);
+	  param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
+          cdiParamToString(param, paramstr, sizeof(paramstr));
 
-      if ( xtypeIsText(xtype) )
-	{
-	  cdfGetAttText(fileID, NC_GLOBAL, attname, attstringlen, attstring);
+	  if ( ISEC1_LevelType == 100 ) ISEC1_Level1 *= 100;
+	  if ( ISEC1_LevelType ==  99 ) ISEC1_LevelType = 100;
+	  level1   = ISEC1_Level1;
+	  level2   = ISEC1_Level2;
 
-          size_t attstrlen = strlen(attstring);
+	  gribDateTime(isec1, &vdate, &vtime);
 
-	  if ( attlen > 0 && attstring[0] != 0 )
+	  if ( rindex == nrecs ) break;
+
+	  if ( rindex == 0 )
 	    {
-	      if ( strcmp(attname, "history") == 0 )
-		{
-		  streamptr->historyID = iatt;
-		}
-	      else if ( strcmp(attname, "institution") == 0 )
+              int vlistID = streamptr->vlistID;
+	      taxisID = vlistInqTaxis(vlistID);
+	      if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
 		{
-		  *instID = institutInq(0, 0, NULL, attstring);
-		  if ( *instID == UNDEFID )
-		    *instID = institutDef(0, 0, NULL, attstring);
+		  taxis->type  = TAXIS_RELATIVE;
+		  taxis->rdate = gribRefDate(isec1);
+		  taxis->rtime = gribRefTime(isec1);
 		}
-	      else if ( strcmp(attname, "source") == 0 )
+	      else
 		{
-		  *modelID = modelInq(-1, 0, attstring);
-		  if ( *modelID == UNDEFID )
-		    *modelID = modelDef(-1, 0, attstring);
+		  taxis->type  = TAXIS_ABSOLUTE;
 		}
-	      else if ( strcmp(attname, "Source") == 0 )
+	      taxis->unit  = cgribexGetTimeUnit(isec1);
+	      taxis->vdate = vdate;
+	      taxis->vtime = vtime;
+
+	      datetime0.date = vdate;
+	      datetime0.time = vtime;
+	    }
+
+	  if ( ISEC1_AvgNum )
+	    {
+	      if (  taxis->numavg && warn_numavg &&
+		   (taxis->numavg != ISEC1_AvgNum) )
 		{
-		  if ( strncmp(attstring, "UCLA-LES", 8) == 0 )
-		    *ucla_les = TRUE;
-		}
 	      /*
-	      else if ( strcmp(attname, "Conventions") == 0 )
-		{
-		}
+	          Warning("Changing numavg from %d to %d not supported!", streamptr->tsteps[tsID].taxis.numavg, ISEC1_AvgNum);
 	      */
-	      else if ( strcmp(attname, "CDI") == 0 )
-		{
-		}
-	      else if ( strcmp(attname, "CDO") == 0 )
-		{
-		}
-              /*
-	      else if ( strcmp(attname, "forecast_reference_time") == 0 )
-		{
-                  memcpy(fcreftime, attstring, attstrlen+1);
-		}
-              */
-	      else if ( strcmp(attname, "grid_file_uri") == 0 )
-		{
-                  memcpy(gridfile, attstring, attstrlen+1);
-		}
-	      else if ( strcmp(attname, "uuidOfHGrid") == 0 && attstrlen == 36 )
-		{
-                  attstring[36] = 0;
-                  str2uuid(attstring, uuidOfHGrid);
-                  //   printf("uuid: %d %s\n", attlen, attstring);
-		}
-	      else if ( strcmp(attname, "uuidOfVGrid") == 0 && attstrlen == 36 )
-		{
-                  attstring[36] = 0;
-                  str2uuid(attstring, uuidOfVGrid);
+		  warn_numavg = FALSE;
 		}
 	      else
 		{
-                  if ( strcmp(attname, "ICON_grid_file_uri") == 0 && gridfile[0] == 0 )
-                    {
-                      memcpy(gridfile, attstring, attstrlen+1);
-                    }
-
-		  vlistDefAttTxt(vlistID, CDI_GLOBAL, attname, (int)attstrlen, attstring);
+		  taxis->numavg = ISEC1_AvgNum;
 		}
 	    }
-	}
-      else if ( xtype == NC_SHORT || xtype == NC_INT )
-	{
-	  if ( strcmp(attname, "number_of_grid_used") == 0 )
-	    {
-	      (*number_of_grid_used) = UNDEFID;
-	      cdfGetAttInt(fileID, NC_GLOBAL, attname, 1, number_of_grid_used);
-	    }
- 	  else
-            {
-              int attint[attlen];
-              cdfGetAttInt(fileID, NC_GLOBAL, attname, (int)attlen, attint);
-              if ( xtype == NC_SHORT )
-                vlistDefAttInt(vlistID, CDI_GLOBAL, attname, DATATYPE_INT16, (int)attlen, attint);
-              else
-                vlistDefAttInt(vlistID, CDI_GLOBAL, attname, DATATYPE_INT32, (int)attlen, attint);
-            }
-        }
-      else if ( xtype == NC_FLOAT || xtype == NC_DOUBLE )
-	{
-	  double attflt[attlen];
-	  cdfGetAttDouble(fileID, NC_GLOBAL, attname, (int)attlen, attflt);
-	  if ( xtype == NC_FLOAT )
-	    vlistDefAttFlt(vlistID, CDI_GLOBAL, attname, DATATYPE_FLT32, (int)attlen, attflt);
-	  else
-	    vlistDefAttFlt(vlistID, CDI_GLOBAL, attname, DATATYPE_FLT64, (int)attlen, attflt);
-	}
-    }
-}
 
-static
-int find_leadtime(int nvars, ncvar_t *ncvars)
-{
-  int leadtime_id = UNDEFID;
+	  datetime.date  = vdate;
+	  datetime.time  = vtime;
 
-  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      if ( ncvars[ncvarid].stdname[0] )
-        {
-          if ( strcmp(ncvars[ncvarid].stdname, "forecast_period") == 0 )
-            {
-              leadtime_id = ncvarid;
-              break;
-            }
-        }
-    }
+	  compvar_t compVar = cgribexVarSet(param, level1, level2, ISEC1_LevelType, ISEC1_TimeRange);
 
-  return (leadtime_id);
-}
+	  for ( vrecID = 0; vrecID < nrecs; vrecID++ )
+	    {
+	      recID   = streamptr->tsteps[1].recIDs[vrecID];
+	      if ( cgribexVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) == 0 ) break;
+	    }
 
-static
-void find_time_vars(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimid, stream_t *streamptr,
-                    int *time_has_units, int *time_has_bounds, int *time_climatology)
-{
-  int ncvarid;
+	  if ( vrecID == nrecs )
+	    {
+	      gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, paramstr, level1, level2);
 
-  if ( timedimid == UNDEFID )
-    {
-      char timeunits[CDI_MAX_NAME];
+	      if ( cdiInventoryMode == 1 )
+		return (CDI_EUFSTRUCT);
+	      else
+		continue;
+	    }
 
-      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-        {
-          if ( ncvars[ncvarid].ndims == 0 && strcmp(ncvars[ncvarid].name, "time") == 0 )
-            {
-              if ( ncvars[ncvarid].units[0] )
-                {
-                  strcpy(timeunits, ncvars[ncvarid].units);
-                  strtolower(timeunits);
+	  if ( cdiInventoryMode == 1 )
+	    {
+	      streamptr->tsteps[tsID].records[recID].used = TRUE;
+	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
+	    }
+	  else
+	    {
+	      if ( streamptr->tsteps[tsID].records[recID].used )
+		{
+		  char paramstr_[32];
+		  cdiParamToString(param, paramstr_, sizeof(paramstr_));
 
-                  if ( isTimeUnits(timeunits) )
-                    {
-                      streamptr->basetime.ncvarid = ncvarid;
-                      break;
-                    }
-                }
-            }
-        }
-    }
-  else
-    {
-      int ltimevar = FALSE;
+		  if ( datetimeCmp(datetime, datetime0) != 0 ) break;
 
-      if ( ncdims[timedimid].ncvarid != UNDEFID )
-        {
-          streamptr->basetime.ncvarid = ncdims[timedimid].ncvarid;
-          ltimevar = TRUE;
-        }
+		  if ( CDI_Debug )
+                    gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, paramstr_, level1, level2);
 
-      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-        if ( ncvarid != streamptr->basetime.ncvarid &&
-             ncvars[ncvarid].ndims == 1 &&
-             timedimid == ncvars[ncvarid].dimids[0] &&
-             !xtypeIsText(ncvars[ncvarid].xtype) &&
-             isTimeAxisUnits(ncvars[ncvarid].units) )
-          {
-            ncvars[ncvarid].isvar = FALSE;
+		  continue;
+		}
+	      else
+		{
+		  streamptr->tsteps[tsID].records[recID].used = TRUE;
+		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
+		}
+	    }
 
-            if ( !ltimevar )
-              {
-                streamptr->basetime.ncvarid = ncvarid;
-                ltimevar = TRUE;
-                if ( CDI_Debug )
-                  fprintf(stderr, "timevar %s\n", ncvars[ncvarid].name);
-              }
-            else
-              {
-                Warning("Found more than one time variable, skipped variable %s!", ncvars[ncvarid].name);
-              }
-          }
+	  if ( CDI_Debug )
+            Message("Read record %2d (id=%s lev1=%d lev2=%d) %8d %6d", nrecs_scanned, paramstr, level1, level2, vdate, vtime);
 
-      if ( ltimevar == FALSE ) /* search for WRF time description */
-        {
-          for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-            if ( ncvarid != streamptr->basetime.ncvarid &&
-                 ncvars[ncvarid].ndims == 2 &&
-                 timedimid == ncvars[ncvarid].dimids[0] &&
-                 xtypeIsText(ncvars[ncvarid].xtype) &&
-                 ncdims[ncvars[ncvarid].dimids[1]].len == 19 )
-              {
-                streamptr->basetime.ncvarid = ncvarid;
-                streamptr->basetime.lwrf    = TRUE;
-                break;
-              }
-        }
+	  if ( cgribexVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) != 0 )
+	    {
+	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
+		      tsID, recID,
+		      streamptr->tsteps[tsID].records[recID].param, param,
+		      streamptr->tsteps[tsID].records[recID].ilevel, level1);
+	      Error("Invalid, unsupported or inconsistent record structure");
+	    }
 
-      /* time varID */
-      ncvarid = streamptr->basetime.ncvarid;
+	  streamptr->tsteps[tsID].records[recID].position = recpos;
+	  streamptr->tsteps[tsID].records[recID].size = (size_t)recsize;
 
-      if ( ncvarid == UNDEFID )
-        {
-          Warning("Time variable >%s< not found!", ncdims[timedimid].name);
-        }
-    }
+	  rindex++;
+	}
 
-  /* time varID */
-  ncvarid = streamptr->basetime.ncvarid;
+      for ( vrecID = 0; vrecID < nrecs; vrecID++ )
+	{
+	  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
+	  if ( ! streamptr->tsteps[tsID].records[recID].used ) break;
+	}
 
-  if ( ncvarid != UNDEFID && streamptr->basetime.lwrf == FALSE )
-    {
-      if ( ncvars[ncvarid].units[0] != 0 ) *time_has_units = TRUE;
+      if ( vrecID < nrecs )
+	{
+	  cdiParamToString(streamptr->tsteps[tsID].records[recID].param, paramstr, sizeof(paramstr));
+	  gribWarning("Paramameter not found!", nrecs_scanned, tsID+1, paramstr,
+                      streamptr->tsteps[tsID].records[recID].ilevel, streamptr->tsteps[tsID].records[recID].ilevel2);
+	  return (CDI_EUFSTRUCT);
+	}
 
-      if ( ncvars[ncvarid].bounds != UNDEFID )
-        {
-          int nbdims = ncvars[ncvars[ncvarid].bounds].ndims;
-          if ( nbdims == 2 )
-            {
-              int len = (int) ncdims[ncvars[ncvars[ncvarid].bounds].dimids[nbdims-1]].len;
-              if ( len == 2 && timedimid == ncvars[ncvars[ncvarid].bounds].dimids[0] )
-                {
-                  *time_has_bounds = TRUE;
-                  streamptr->basetime.ncvarboundsid = ncvars[ncvarid].bounds;
-                  if ( ncvars[ncvarid].climatology ) *time_climatology = TRUE;
-                }
-            }
-        }
-    }
-}
+      streamptr->rtsteps++;
 
-static
-void read_vct_echam(int fileID, int nvars, ncvar_t *ncvars, ncdim_t *ncdims, double **vct, size_t *pvctsize)
-{
-  /* find ECHAM VCT */
-  int nvcth_id = UNDEFID, vcta_id = UNDEFID, vctb_id = UNDEFID;
+      if ( streamptr->ntsteps != streamptr->rtsteps )
+	{
+	  tsID = tstepsNewEntry(streamptr);
+	  if ( tsID != streamptr->rtsteps )
+	    Error("Internal error. tsID = %d", tsID);
 
-  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      if ( ncvars[ncvarid].ndims == 1 )
-        {
-          size_t len = strlen(ncvars[ncvarid].name);
-          if ( len == 4 && ncvars[ncvarid].name[0] == 'h' && ncvars[ncvarid].name[1] == 'y' )
-            {
-              if ( ncvars[ncvarid].name[2] == 'a' && ncvars[ncvarid].name[3] == 'i' ) // hyai
-                {
-                  vcta_id = ncvarid;
-                  nvcth_id = ncvars[ncvarid].dimids[0];
-                  ncvars[ncvarid].isvar = FALSE;
-                }
-              else if ( ncvars[ncvarid].name[2] == 'b' && ncvars[ncvarid].name[3] == 'i' ) //hybi
-                {
-                  vctb_id = ncvarid;
-                  nvcth_id = ncvars[ncvarid].dimids[0];
-                  ncvars[ncvarid].isvar = FALSE;
-                }
-              else if ( (ncvars[ncvarid].name[2] == 'a' || ncvars[ncvarid].name[2] == 'b') && ncvars[ncvarid].name[3] == 'm' )
-                {
-                  ncvars[ncvarid].isvar = FALSE; // hyam or hybm
-                }
-            }
+	  streamptr->tsteps[tsID-1].next   = 1;
+	  streamptr->tsteps[tsID].position = recpos;
 	}
+
+      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+      streamptr->tsteps[tsID].position = recpos;
+
+      streamptr->record->buffer     = gribbuffer;
+      streamptr->record->buffersize = buffersize;
     }
 
-  /* read VCT */
-  if ( nvcth_id != UNDEFID && vcta_id != UNDEFID && vctb_id != UNDEFID )
+  if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
     {
-      size_t vctsize = ncdims[nvcth_id].len;
-      vctsize *= 2;
-      *vct = (double *) Malloc(vctsize*sizeof(double));
-      cdf_get_var_double(fileID, vcta_id, *vct);
-      cdf_get_var_double(fileID, vctb_id, *vct+vctsize/2);
-      *pvctsize = vctsize;
+      Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
+      streamptr->ntsteps = tsID;
     }
-}
-
 
-int cdfInqContents(stream_t *streamptr)
-{
-  int ndims, nvars, ngatts, unlimdimid;
-  int ncvarid;
-  int ncdimid;
-  size_t ntsteps;
-  int timedimid = -1;
-  int *varids;
-  int nvarids;
-  int time_has_units = FALSE;
-  int time_has_bounds = FALSE;
-  int time_climatology = FALSE;
-  int leadtime_id = UNDEFID;
-  int nvars_data;
-  int instID  = UNDEFID;
-  int modelID = UNDEFID;
-  int taxisID;
-  int i;
-  int calendar = UNDEFID;
-  ncdim_t *ncdims;
-  ncvar_t *ncvars = NULL;
-  int format = 0;
-  int ucla_les = FALSE;
-  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
-  unsigned char uuidOfVGrid[CDI_UUID_SIZE];
-  char gridfile[8912];
-  char fcreftime[CDI_MAX_NAME];
-  int number_of_grid_used = UNDEFID;
-
-  memset(uuidOfHGrid, 0, CDI_UUID_SIZE);
-  memset(uuidOfVGrid, 0, CDI_UUID_SIZE);
-  gridfile[0] = 0;
-  fcreftime[0] = 0;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  if ( CDI_Debug ) Message("streamID = %d, fileID = %d", streamptr->self, fileID);
+  rstatus = (int)streamptr->ntsteps;
 
-#if  defined  (HAVE_NETCDF4)
-  nc_inq_format(fileID, &format);
+  return (rstatus);
+}
 #endif
 
-  cdf_inq(fileID, &ndims , &nvars, &ngatts, &unlimdimid);
+#ifdef gribWarning
+#undef gribWarning
+#endif
 
-  if ( CDI_Debug )
-    Message("root: ndims %d, nvars %d, ngatts %d", ndims, nvars, ngatts);
+#if  defined  (HAVE_LIBCGRIBEX)
+int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long datasize,
+		  int unreduced, int *nmiss, double missval)
+{
+  int status = 0;
+  int iret = 0, iword = 0;
+  int isec0[2], isec1[4096], isec2[4096], isec3[2], isec4[512];
+  float fsec2f[512], fsec3f[2];
+  double fsec2[512], fsec3[2];
+  char hoper[2];
 
-  if ( ndims == 0 )
-    {
-      Warning("ndims = %d", ndims);
-      return (CDI_EUFSTRUCT);
-    }
+  if ( unreduced ) strcpy(hoper, "R");
+  else             strcpy(hoper, "D");
 
-  /* alloc ncdims */
-  ncdims = (ncdim_t *) Malloc((size_t)ndims * sizeof (ncdim_t));
-  init_ncdims(ndims, ncdims);
+  FSEC3_MissVal = missval;
 
-  if ( nvars > 0 )
-    {
-      /* alloc ncvars */
-      ncvars = (ncvar_t *) Malloc((size_t)nvars * sizeof (ncvar_t));
-      init_ncvars(nvars, ncvars);
+  if ( memtype == MEMTYPE_FLOAT )
+    gribExSP(isec0, isec1, isec2, fsec2f, isec3, fsec3f, isec4, (float*) data,
+             (int) datasize, (int*) gribbuffer, gribsize, &iword, hoper, &iret);
+  else
+    gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, (double*) data,
+             (int) datasize, (int*) gribbuffer, gribsize, &iword, hoper, &iret);
 
-      for ( ncvarid = 0; ncvarid < nvars; ++ncvarid )
-        ncvars[ncvarid].ncid = fileID;
-    }
+  if ( ISEC1_Sec2Or3Flag & 64 )
+    *nmiss = ISEC4_NumValues - ISEC4_NumNonMissValues;
+  else
+    *nmiss = 0;
 
-#if  defined  (TEST_GROUPS)
-#if  defined  (HAVE_NETCDF4)
-  if ( format == NC_FORMAT_NETCDF4 )
+  if ( ISEC1_CenterID == 215 && (isec1[34] != 0 && isec1[34] != 255) )
     {
-      int ncid;
-      int numgrps;
-      int ncids[NC_MAX_VARS];
-      char name1[CDI_MAX_NAME];
-      int gndims, gnvars, gngatts, gunlimdimid;
-      nc_inq_grps(fileID, &numgrps, ncids);
-      for ( int i = 0; i < numgrps; ++i )
-        {
-          ncid = ncids[i];
-          nc_inq_grpname (ncid, name1);
-          cdf_inq(ncid, &gndims , &gnvars, &gngatts, &gunlimdimid);
-
-          if ( CDI_Debug )
-            Message("%s: ndims %d, nvars %d, ngatts %d", name1, gndims, gnvars, gngatts);
+      double undef_pds, undef_eps;
+      MCH_get_undef(isec1, &undef_pds, &undef_eps);
 
-          if ( gndims == 0 )
-            {
+      *nmiss = 0;
+      if ( memtype == MEMTYPE_FLOAT )
+        {
+          float *restrict dataf = (float*) data;
+          for ( long i = 0; i < datasize; i++ )
+            if ( (fabs(dataf[i]-undef_pds) < undef_eps) || IS_EQUAL(dataf[i],FSEC3_MissVal) ) {
+              dataf[i] = (float)missval;
+              (*nmiss)++;
+            }
+        }
+      else
+        {
+          double *restrict datad = (double*) data;
+          for ( long i = 0; i < datasize; i++ )
+            if ( (fabs(datad[i]-undef_pds) < undef_eps) || IS_EQUAL(datad[i],FSEC3_MissVal) ) {
+              datad[i] = missval;
+              (*nmiss)++;
             }
         }
-    }
-#endif
-#endif
-
-  if ( nvars == 0 )
-    {
-      Warning("nvars = %d", nvars);
-      return (CDI_EUFSTRUCT);
     }
 
-  /* scan global attributes */
-  scan_global_attributes(fileID, vlistID, streamptr, ngatts, &instID, &modelID, &ucla_les,
-                         uuidOfHGrid, uuidOfVGrid, gridfile, &number_of_grid_used);
+  return status;
+}
+#endif
 
-  /* find time dim */
-  if ( unlimdimid >= 0 )
-    timedimid = unlimdimid;
-  else
-    timedimid = cdfTimeDimID(fileID, ndims, nvars);
 
-  streamptr->basetime.ncdimid = timedimid;
+#if  defined  (HAVE_LIBCGRIBEX)
+static
+void cgribexDefInstitut(int *isec1, int vlistID, int varID)
+{
+  int instID;
 
-  if ( timedimid != UNDEFID )
-    cdf_inq_dimlen(fileID, timedimid, &ntsteps);
+  if ( vlistInqInstitut(vlistID) != CDI_UNDEFID )
+    instID = vlistInqInstitut(vlistID);
   else
-    ntsteps = 0;
-
-  if ( CDI_Debug ) Message("Number of timesteps = %d", ntsteps);
-  if ( CDI_Debug ) Message("Time dimid = %d", streamptr->basetime.ncdimid);
+    instID = vlistInqVarInstitut(vlistID, varID);
 
-  /* read ncdims */
-  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
+  if ( instID != CDI_UNDEFID )
     {
-      cdf_inq_dimlen(fileID, ncdimid, &ncdims[ncdimid].len);
-      cdf_inq_dimname(fileID, ncdimid, ncdims[ncdimid].name);
-      if ( timedimid == ncdimid )
-	ncdims[ncdimid].dimtype = T_AXIS;
+      int center, subcenter;
+      center    = institutInqCenter(instID);
+      subcenter = institutInqSubcenter(instID);
+      ISEC1_CenterID    = center;
+      ISEC1_SubCenterID = subcenter;
     }
+}
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "cdfScanVarAttributes");
-
-  /* scan attributes of all variables */
-  cdfScanVarAttributes(nvars, ncvars, ncdims, timedimid, modelID, format);
-
+static
+void cgribexDefModel(int *isec1, int vlistID, int varID)
+{
+  int modelID;
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "find coordinate vars");
+  if ( vlistInqModel(vlistID) != CDI_UNDEFID )
+    modelID = vlistInqModel(vlistID);
+  else
+    modelID = vlistInqVarModel(vlistID, varID);
 
-  /* find coordinate vars */
-  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
-    {
-      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-	{
-	  if ( ncvars[ncvarid].ndims == 1 )
-	    {
-	      if ( timedimid != UNDEFID && timedimid == ncvars[ncvarid].dimids[0] )
-		{
-		  if ( ncvars[ncvarid].isvar != FALSE ) cdfSetVar(ncvars, ncvarid, TRUE);
-		}
-	      else
-		{
-                  //  if ( ncvars[ncvarid].isvar != TRUE ) cdfSetVar(ncvars, ncvarid, FALSE);
-		}
-	      // if ( ncvars[ncvarid].isvar != TRUE ) cdfSetVar(ncvars, ncvarid, FALSE);
+  if ( modelID != CDI_UNDEFID )
+    ISEC1_ModelID = modelInqGribID(modelID);
+}
 
-	      if ( ncdimid == ncvars[ncvarid].dimids[0] && ncdims[ncdimid].ncvarid == UNDEFID )
-		if ( strcmp(ncvars[ncvarid].name, ncdims[ncdimid].name) == 0 )
-		  {
-		    ncdims[ncdimid].ncvarid = ncvarid;
-		    ncvars[ncvarid].isvar = FALSE;
-		  }
-	    }
-	}
-    }
+static
+void cgribexDefParam(int *isec1, int param)
+{
+  int pdis, pcat, pnum;
 
-  /* find time vars */
-  find_time_vars(nvars, ncvars, ncdims, timedimid, streamptr, &time_has_units, &time_has_bounds, &time_climatology);
+  cdiDecodeParam(param, &pnum, &pcat, &pdis);
 
-  leadtime_id = find_leadtime(nvars, ncvars);
-  if ( leadtime_id != UNDEFID ) ncvars[leadtime_id].isvar = FALSE;
+  if ( pnum < 0 ) pnum = -pnum;
 
-  /* check ncvars */
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  static bool lwarn_pdis = true;
+  if ( pdis != 255 && lwarn_pdis )
     {
-      if ( timedimid != UNDEFID )
-	if ( ncvars[ncvarid].isvar == -1 &&
-	     ncvars[ncvarid].ndims > 1   &&
-	     timedimid == ncvars[ncvarid].dimids[0] )
-	  cdfSetVar(ncvars, ncvarid, TRUE);
+      char paramstr[32];
+      cdiParamToString(param, paramstr, sizeof(paramstr));
+      Warning("Can't convert GRIB2 parameter ID (%s) to GRIB1, set to %d.%d!", paramstr, pnum, pcat);
+      lwarn_pdis = false;
+    }
 
-      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims == 0 )
-	cdfSetVar(ncvars, ncvarid, FALSE);
+  static bool lwarn_pnum = true;
+  if ( pnum > 255 && lwarn_pnum )
+    {
+      Warning("Parameter number %d out of range (1-255), set to %d!", pnum, pnum%256);
+      lwarn_pnum = false;
+      pnum = pnum%256;
+    }
 
-      //if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims > 1 )
-      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims >= 1 )
-	cdfSetVar(ncvars, ncvarid, TRUE);
+  ISEC1_CodeTable = pcat;
+  ISEC1_Parameter = pnum;
+}
 
-      if ( ncvars[ncvarid].isvar == -1 )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  Warning("Variable %s has an unknown type, skipped!", ncvars[ncvarid].name);
-	  continue;
-	}
+static
+int cgribexDefTimerange(int tsteptype, int factor, int calendar,
+			int rdate, int rtime, int vdate, int vtime, int *pip1, int *pip2)
+{
+  int timerange = -1;
+  int year, month, day, hour, minute, second;
+  int julday1, secofday1, julday2, secofday2, days, secs;
+  int ip, ip1 = 0, ip2 = 0;
 
-      if ( ncvars[ncvarid].ndims > 4 )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  Warning("%d dimensional variables are not supported, skipped variable %s!",
-		ncvars[ncvarid].ndims, ncvars[ncvarid].name);
-	  continue;
-	}
+  cdiDecodeDate(rdate, &year, &month, &day);
+  cdiDecodeTime(rtime, &hour, &minute, &second);
+  encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday1, &secofday1);
 
-      if ( ncvars[ncvarid].ndims == 4 && timedimid == UNDEFID )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  Warning("%d dimensional variables without time dimension are not supported, skipped variable %s!",
-		ncvars[ncvarid].ndims, ncvars[ncvarid].name);
-	  continue;
-	}
+  cdiDecodeDate(vdate, &year, &month, &day);
+  cdiDecodeTime(vtime, &hour, &minute, &second);
+  encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday2, &secofday2);
 
-      if ( xtypeIsText(ncvars[ncvarid].xtype) )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  continue;
-	}
+  (void) julday_sub(julday1, secofday1, julday2, secofday2, &days, &secs);
 
-      if ( cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned) == -1 )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  Warning("Variable %s has an unsupported data type, skipped!", ncvars[ncvarid].name);
-	  continue;
-	}
+  if ( !(int)(fmod(days*86400.0 + secs, factor)) )
+    {
+      ip = (int) ((days*86400.0 + secs)/factor);
 
-      if ( timedimid != UNDEFID && ntsteps == 0 && ncvars[ncvarid].ndims > 0 )
+      switch ( tsteptype )
 	{
-	  if ( timedimid == ncvars[ncvarid].dimids[0] )
-	    {
-	      ncvars[ncvarid].isvar = 0;
-	      Warning("Number of time steps undefined, skipped variable %s!", ncvars[ncvarid].name);
-	      continue;
-	    }
+	case TSTEP_INSTANT:  timerange =  0; ip1 = ip; ip2 = 0;  break;
+	case TSTEP_INSTANT2: timerange =  1; ip1 = 0;  ip2 = 0;  break;
+	case TSTEP_RANGE:    timerange =  2; ip1 = 0;  ip2 = ip; break;
+	case TSTEP_AVG:      timerange =  3; ip1 = 0;  ip2 = ip; break;
+	case TSTEP_ACCUM:    timerange =  4; ip1 = 0;  ip2 = ip; break;
+	case TSTEP_DIFF:     timerange =  5; ip1 = 0;  ip2 = ip; break;
+	case TSTEP_INSTANT3:
+	default:             timerange = 10; ip1 = ip/256; ip2 = ip%256;  break;
 	}
     }
 
-  /* verify coordinate vars - first scan (dimname == varname) */
-  verify_coordinate_vars_1(fileID, ndims, ncdims, ncvars, timedimid);
+  *pip1 = ip1;
+  *pip2 = ip2;
 
-  /* verify coordinate vars - second scan (all other variables) */
-  verify_coordinate_vars_2(nvars, ncvars);
+  return (timerange);
+}
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "verify_coordinate_vars");
+static
+int cgribexDefDateTime(int *isec1, int timeunit, int date, int time)
+{
+  int year, month, day, hour, minute, second;
+  int century = 0;
+  int factor = 1;
 
-  if ( ucla_les == TRUE )
-    {
-      for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
-	{
-	  ncvarid = ncdims[ncdimid].ncvarid;
-	  if ( ncvarid != -1 )
-	    {
-	      if ( ncdims[ncdimid].dimtype == UNDEFID && ncvars[ncvarid].units[0] == 'm' )
-		{
-		  if      ( ncvars[ncvarid].name[0] == 'x' ) ncdims[ncdimid].dimtype = X_AXIS;
-		  else if ( ncvars[ncvarid].name[0] == 'y' ) ncdims[ncdimid].dimtype = Y_AXIS;
-		  else if ( ncvars[ncvarid].name[0] == 'z' ) ncdims[ncdimid].dimtype = Z_AXIS;
-		}
-	    }
-	}
-    }
-  /*
-  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
-    {
-      ncvarid = ncdims[ncdimid].ncvarid;
-      if ( ncvarid != -1 )
-	{
-	  printf("coord var %d %s %s\n", ncvarid, ncvars[ncvarid].name, ncvars[ncvarid].units);
-	  if ( ncdims[ncdimid].dimtype == X_AXIS )
-	    printf("coord var %d %s is x dim\n", ncvarid, ncvars[ncvarid].name);
-	  if ( ncdims[ncdimid].dimtype == Y_AXIS )
-	    printf("coord var %d %s is y dim\n", ncvarid, ncvars[ncvarid].name);
-	  if ( ncdims[ncdimid].dimtype == Z_AXIS )
-	    printf("coord var %d %s is z dim\n", ncvarid, ncvars[ncvarid].name);
-	  if ( ncdims[ncdimid].dimtype == T_AXIS )
-	    printf("coord var %d %s is t dim\n", ncvarid, ncvars[ncvarid].name);
+  cdiDecodeDate(date, &year, &month, &day);
+  cdiDecodeTime(time, &hour, &minute, &second);
 
-	  if ( ncvars[ncvarid].islon )
-	    printf("coord var %d %s is lon\n", ncvarid, ncvars[ncvarid].name);
-	  if ( ncvars[ncvarid].islat )
-	    printf("coord var %d %s is lat\n", ncvarid, ncvars[ncvarid].name);
-	  if ( ncvars[ncvarid].islev )
-	    printf("coord var %d %s is lev\n", ncvarid, ncvars[ncvarid].name);
-	}
+  century =  year / 100;
+
+  ISEC1_Year = year - century*100;
+
+  if ( year < 0 )
+    {
+      century = -century;
+      ISEC1_Year = -ISEC1_Year;
     }
-  */
 
-  /* Set coordinate varids (att: associate)  */
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  if ( ISEC1_Year == 0 )
     {
-      if ( ncvars[ncvarid].isvar == TRUE && ncvars[ncvarid].ncoordvars )
-	{
-	  /* ndims = ncvars[ncvarid].ndims; */
-	  ndims = ncvars[ncvarid].ncoordvars;
-	  for ( i = 0; i < ndims; i++ )
-	    {
-	      if ( ncvars[ncvars[ncvarid].coordvarids[i]].islon )
-		ncvars[ncvarid].xvarid = ncvars[ncvarid].coordvarids[i];
-	      else if ( ncvars[ncvars[ncvarid].coordvarids[i]].islat )
-		ncvars[ncvarid].yvarid = ncvars[ncvarid].coordvarids[i];
-	      else if ( ncvars[ncvars[ncvarid].coordvarids[i]].islev )
-		ncvars[ncvarid].zvarid = ncvars[ncvarid].coordvarids[i];
-	    }
-	}
+      century -= 1;
+      ISEC1_Year = 100;
     }
 
-  /* set dim type */
-  setDimType(nvars, ncvars, ncdims);
+  century += 1;
+  if ( year < 0 ) century = -century;
 
-  /* read ECHAM VCT if present */
-  size_t vctsize = 0;
-  double *vct = NULL;
-  read_vct_echam(fileID, nvars, ncvars, ncdims, &vct, &vctsize);
+  ISEC1_Month  = month;
+  ISEC1_Day    = day;
+  ISEC1_Hour   = hour;
+  ISEC1_Minute = minute;
 
+  ISEC1_Century = century;
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "define_all_grids");
+  switch (timeunit)
+    {
+    case TUNIT_MINUTE:    factor =    60; ISEC1_TimeUnit = ISEC1_TABLE4_MINUTE;    break;
+    case TUNIT_QUARTER:   factor =   900; ISEC1_TimeUnit = ISEC1_TABLE4_QUARTER;   break;
+    case TUNIT_30MINUTES: factor =  1800; ISEC1_TimeUnit = ISEC1_TABLE4_30MINUTES; break;
+    case TUNIT_HOUR:      factor =  3600; ISEC1_TimeUnit = ISEC1_TABLE4_HOUR;      break;
+    case TUNIT_3HOURS:    factor = 10800; ISEC1_TimeUnit = ISEC1_TABLE4_3HOURS;    break;
+    case TUNIT_6HOURS:    factor = 21600; ISEC1_TimeUnit = ISEC1_TABLE4_6HOURS;    break;
+    case TUNIT_12HOURS:   factor = 43200; ISEC1_TimeUnit = ISEC1_TABLE4_12HOURS;   break;
+    case TUNIT_DAY:       factor = 86400; ISEC1_TimeUnit = ISEC1_TABLE4_DAY;       break;
+    default:              factor =  3600; ISEC1_TimeUnit = ISEC1_TABLE4_HOUR;      break;
+    }
 
-  /* define all grids */
-  define_all_grids(streamptr, vlistID, ncdims, nvars, ncvars, timedimid, uuidOfHGrid, gridfile, number_of_grid_used);
+  return (factor);
+}
 
+static
+void cgribexDefTime(int *isec1, int vdate, int vtime, int tsteptype, int numavg, int taxisID)
+{
+  int timetype = TAXIS_ABSOLUTE;
+  int timerange = 0;
+  int timeunit = TUNIT_HOUR;
 
-  /* define all zaxes */
-  define_all_zaxes(streamptr, vlistID, ncdims, nvars, ncvars, vctsize, vct, uuidOfVGrid);
-  if ( vct ) Free(vct);
+  if ( taxisID != -1 )
+    {
+      timetype = taxisInqType(taxisID);
+      timeunit = taxisInqTunit(taxisID);
+    }
 
+  if ( timetype == TAXIS_RELATIVE )
+    {
+      int factor = 1;
+      int rdate, rtime;
+      int ip1 = 0, ip2 = 0;
+      int calendar;
 
-  /* select vars */
-  varids = (int *) Malloc((size_t)nvars * sizeof (int));
-  nvarids = 0;
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    if ( ncvars[ncvarid].isvar == TRUE ) varids[nvarids++] = ncvarid;
+      calendar = taxisInqCalendar(taxisID);
+      rdate    = taxisInqRdate(taxisID);
+      rtime    = taxisInqRtime(taxisID);
 
-  nvars_data = nvarids;
+      factor = cgribexDefDateTime(isec1, timeunit, rdate, rtime);
+      timerange = cgribexDefTimerange(tsteptype, factor, calendar,
+				      rdate, rtime, vdate, vtime, &ip1, &ip2);
 
-  if ( CDI_Debug ) Message("time varid = %d", streamptr->basetime.ncvarid);
-  if ( CDI_Debug ) Message("ntsteps = %d", ntsteps);
-  if ( CDI_Debug ) Message("nvars_data = %d", nvars_data);
+      if ( ip2 > 0xFF && timeunit < TUNIT_YEAR )
+        {
+          timeunit++;
+          factor = cgribexDefDateTime(isec1, timeunit, rdate, rtime);
+          timerange = cgribexDefTimerange(tsteptype, factor, calendar,
+                                          rdate, rtime, vdate, vtime, &ip1, &ip2);
+        }
 
+      if ( timerange == -1 || timerange == 3 )
+	{
+	  timetype = TAXIS_ABSOLUTE;
+	}
+      /*
+      else if ( timerange == 10 )
+	{
+	  if ( ip1 < 0 || ip1 > 0xFFFF ) timetype = TAXIS_ABSOLUTE;
+	  if ( ip2 < 0 || ip2 > 0xFFFF ) timetype = TAXIS_ABSOLUTE;
+	}
+      */
+      else
+	{
+	  if ( ip1 < 0 || ip1 > 0xFF   ) timetype = TAXIS_ABSOLUTE;
+	  if ( ip2 < 0 || ip2 > 0xFF   ) timetype = TAXIS_ABSOLUTE;
+	}
 
-  if ( nvars_data == 0 )
-    {
-      streamptr->ntsteps = 0;
-      return (CDI_EUFSTRUCT);
+      ISEC1_TimeRange   = timerange;
+      ISEC1_TimePeriod1 = ip1;
+      ISEC1_TimePeriod2 = ip2;
     }
 
-  if ( ntsteps == 0 && streamptr->basetime.ncdimid == UNDEFID && streamptr->basetime.ncvarid != UNDEFID )
-    ntsteps = 1;
+  if ( timetype == TAXIS_ABSOLUTE )
+    {
+      (void) cgribexDefDateTime(isec1, timeunit, vdate, vtime);
 
-  streamptr->ntsteps = (long)ntsteps;
+      /*
+      if ( numavg > 0 )
+	ISEC1_TimeRange = 0;
+      else
+      */
+      if ( ISEC1_TimeRange != 3 )
+	ISEC1_TimeRange   = 10;
 
-  /* define all data variables */
-  define_all_vars(streamptr, vlistID, instID, modelID, varids, nvars_data, nvars, ncvars);
+      ISEC1_TimePeriod1 = 0;
+      ISEC1_TimePeriod2 = 0;
+    }
 
+  ISEC1_AvgNum         = numavg;
+  ISEC1_AvgMiss        = 0;
+  ISEC1_DecScaleFactor = 0;
+}
 
-  cdiCreateTimesteps(streamptr);
+static
+void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridID)
+{
+  int gridtype;
+  bool lcurvi = false;
+  static bool lwarning = true;
 
-  /* time varID */
-  int nctimevarid = streamptr->basetime.ncvarid;
+  memset(isec2, 0, 16*sizeof(int));
 
-  if ( time_has_units )
-    {
-      taxis_t *taxis = &streamptr->tsteps[0].taxis;
+  ISEC1_Sec2Or3Flag = 128;
 
-      if ( setBaseTime(ncvars[nctimevarid].units, taxis) == 1 )
-        {
-          nctimevarid = UNDEFID;
-          streamptr->basetime.ncvarid = UNDEFID;
-        }
+  gridtype = gridInqType(gridID);
 
-      if ( leadtime_id != UNDEFID && taxis->type == TAXIS_RELATIVE )
-        {
-          streamptr->basetime.leadtimeid = leadtime_id;
-          taxis->type = TAXIS_FORECAST;
+  ISEC1_GridDefinition = 255;
 
-          int timeunit = -1;
-          if ( ncvars[leadtime_id].units[0] != 0 ) timeunit = scanTimeUnit(ncvars[leadtime_id].units);
-          if ( timeunit == -1 ) timeunit = taxis->unit;
-          taxis->fc_unit = timeunit;
+  if ( gridtype == GRID_GENERIC )
+    {
+      int xsize, ysize, gridsize;
 
-          setForecastTime(fcreftime, taxis);
-        }
-    }
+      gridsize = gridInqSize(gridID);
+      xsize = gridInqXsize(gridID);
+      ysize = gridInqYsize(gridID);
 
-  if ( time_has_bounds )
-    {
-      streamptr->tsteps[0].taxis.has_bounds = TRUE;
-      if ( time_climatology ) streamptr->tsteps[0].taxis.climatology = TRUE;
+      if ( (ysize ==  32 || ysize ==  48 || ysize ==  64 ||
+	    ysize ==  96 || ysize == 160 || ysize == 192 ||
+	    ysize == 240 || ysize == 320 || ysize == 384 ||
+	    ysize == 480 || ysize == 768 ) &&
+	   (xsize == 2*ysize || xsize == 1) )
+	{
+	  gridtype = GRID_GAUSSIAN;
+	  gridChangeType(gridID, gridtype);
+	}
+      else if ( gridsize == 1 )
+	{
+	  gridtype = GRID_LONLAT;
+	  gridChangeType(gridID, gridtype);
+	}
+      else if ( gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL) )
+	{
+	  gridtype = GRID_LONLAT;
+	  gridChangeType(gridID, gridtype);
+	}
     }
-
-  if ( nctimevarid != UNDEFID )
+  else if ( gridtype == GRID_CURVILINEAR )
     {
-      taxis_t *taxis = &streamptr->tsteps[0].taxis;
-      ptaxisDefName(taxis, ncvars[nctimevarid].name);
-      if ( ncvars[nctimevarid].longname[0] )
-        ptaxisDefLongname(taxis, ncvars[nctimevarid].longname);
+      if ( lwarning && gridInqSize(gridID) > 1 )
+	{
+	  lwarning = false;
+	  Warning("Curvilinear grids are unsupported in GRIB1! Created wrong GDS!");
+	}
+      gridtype = GRID_LONLAT;
+      lcurvi = true;
     }
 
-  if ( nctimevarid != UNDEFID )
-    if ( ncvars[nctimevarid].calendar == TRUE )
+  ISEC2_Reduced  = FALSE;
+  ISEC2_ScanFlag = 0;
+
+  switch (gridtype)
+    {
+    case GRID_LONLAT:
+    case GRID_GAUSSIAN:
+    case GRID_GAUSSIAN_REDUCED:
+    case GRID_TRAJECTORY:
       {
-        enum {attstringlen = 8192};
-        char attstring[attstringlen];
+	int nlon = 0, nlat;
+	double xfirst = 0, xlast = 0, xinc = 0;
+	double yfirst = 0, ylast = 0, yinc = 0;
 
-	cdfGetAttText(fileID, nctimevarid, "calendar", attstringlen, attstring);
-	strtolower(attstring);
+	if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
+          ISEC2_GridType = GRIB1_GTYPE_GAUSSIAN;
+        else if ( gridtype == GRID_LONLAT && gridIsRotated(gridID) )
+	  ISEC2_GridType = GRIB1_GTYPE_LATLON_ROT;
+	else
+	  ISEC2_GridType = GRIB1_GTYPE_LATLON;
 
-	if ( memcmp(attstring, "standard", 8)  == 0 ||
-	     memcmp(attstring, "gregorian", 9) == 0 )
-	  calendar = CALENDAR_STANDARD;
-	else if ( memcmp(attstring, "none", 4) == 0 )
-	  calendar = CALENDAR_NONE;
-	else if ( memcmp(attstring, "proleptic", 9) == 0 )
-	  calendar = CALENDAR_PROLEPTIC;
-	else if ( memcmp(attstring, "360", 3) == 0 )
-	  calendar = CALENDAR_360DAYS;
-	else if ( memcmp(attstring, "365", 3) == 0 ||
-		  memcmp(attstring, "noleap", 6)  == 0 )
-	  calendar = CALENDAR_365DAYS;
-	else if ( memcmp(attstring, "366", 3)  == 0 ||
-		  memcmp(attstring, "all_leap", 8) == 0 )
-	  calendar = CALENDAR_366DAYS;
+	nlon = gridInqXsize(gridID);
+	nlat = gridInqYsize(gridID);
+
+	if ( gridtype == GRID_GAUSSIAN_REDUCED )
+	  {
+	    ISEC2_Reduced = TRUE;
+	    nlon = 0;
+	    gridInqRowlon(gridID, ISEC2_RowLonPtr);
+	  }
 	else
-	  Warning("calendar >%s< unsupported!", attstring);
-      }
+	  {
+	    if ( nlon == 0 )
+	      {
+		nlon = 1;
+	      }
+	    else
+	      {
+		xfirst = gridInqXval(gridID,      0);
+		if ( lcurvi )
+		  xlast  = gridInqXval(gridID, nlon*nlat-1);
+		else
+		  xlast  = gridInqXval(gridID, nlon-1);
+		xinc   = gridInqXinc(gridID);
+	      }
+	  }
 
-  if ( streamptr->tsteps[0].taxis.type == TAXIS_FORECAST )
-    {
-      taxisID = taxisCreate(TAXIS_FORECAST);
-    }
-  else if ( streamptr->tsteps[0].taxis.type == TAXIS_RELATIVE )
-    {
-      taxisID = taxisCreate(TAXIS_RELATIVE);
-    }
-  else
-    {
-      taxisID = taxisCreate(TAXIS_ABSOLUTE);
-      if ( !time_has_units )
-	{
-	  taxisDefTunit(taxisID, TUNIT_DAY);
-	  streamptr->tsteps[0].taxis.unit = TUNIT_DAY;
-	}
-    }
+	if ( nlat == 0 )
+	  {
+	    nlat = 1;
+	  }
+	else
+	  {
+	    yfirst = gridInqYval(gridID,      0);
+	    if ( lcurvi )
+	      ylast  = gridInqYval(gridID, nlon*nlat-1);
+	    else
+	      ylast  = gridInqYval(gridID, nlat-1);
+	    yinc   = gridInqYinc(gridID);
+	    if ( yinc < 0 ) yinc = -yinc;
+	  }
+
+	ISEC2_NumLon   = nlon;
+	ISEC2_NumLat   = nlat;
+	ISEC2_FirstLat = (int)lround(yfirst*1000);
+	ISEC2_LastLat  = (int)lround(ylast*1000);
+	if ( gridtype == GRID_GAUSSIAN_REDUCED )
+	  {
+	    ISEC2_FirstLon = 0;
+	    ISEC2_LastLon  = (int)lround(1000*(360.-360./(nlat*2)));
+	    ISEC2_LonIncr  = (int)lround(1000*360./(nlat*2));
+	  }
+	else
+	  {
+	    ISEC2_FirstLon = (int)lround(xfirst*1000);
+	    ISEC2_LastLon  = (int)lround(xlast*1000);
+	    ISEC2_LonIncr  = (int)lround(xinc*1000);
+	  }
+
+	if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
+          {
+            int np = gridInqNP(gridID);
+            if ( np == 0 ) np = nlat/2;
+            ISEC2_NumPar = np;
+          }
+	else
+	  {
+	    ISEC2_LatIncr = (int)lround(yinc*1000);
+	    if ( ISEC2_LatIncr < 0 ) ISEC2_LatIncr = -ISEC2_LatIncr;
+	  }
 
+	if ( ISEC2_NumLon > 1 && ISEC2_NumLat == 1 )
+	  if ( ISEC2_LonIncr != 0 && ISEC2_LatIncr == 0 ) ISEC2_LatIncr = ISEC2_LonIncr;
 
-  if ( calendar == UNDEFID && streamptr->tsteps[0].taxis.type != TAXIS_ABSOLUTE )
-    {
-      calendar = CALENDAR_STANDARD;
-    }
+	if ( ISEC2_NumLon == 1 && ISEC2_NumLat > 1 )
+	  if ( ISEC2_LonIncr == 0 && ISEC2_LatIncr != 0 ) ISEC2_LonIncr = ISEC2_LatIncr;
 
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic warning "-Wstrict-overflow"
-#endif
-  if ( calendar != UNDEFID )
-    {
-      taxis_t *taxis = &streamptr->tsteps[0].taxis;
-      taxis->calendar = calendar;
-      taxisDefCalendar(taxisID, calendar);
-    }
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
-#pragma GCC diagnostic pop
-#endif
+	if ( ISEC2_LatIncr == 0 || ISEC2_LonIncr == 0 )
+	  ISEC2_ResFlag = 0;
+	else
+	  ISEC2_ResFlag = 128;
 
-  vlistDefTaxis(vlistID, taxisID);
+	if ( gridIsRotated(gridID) )
+	  {
+	    ISEC2_LatSP = - (int)lround(gridInqYpole(gridID) * 1000);
+	    ISEC2_LonSP =   (int)lround((gridInqXpole(gridID) + 180) * 1000);
+            double angle = gridInqAngle(gridID);
+            if ( fabs(angle) > 0 ) angle = -angle;
+            FSEC2_RotAngle = angle;
+	  }
 
-  streamptr->curTsID = 0;
-  streamptr->rtsteps = 1;
+	/* East -> West */
+	if ( ISEC2_LastLon < ISEC2_FirstLon ) ISEC2_ScanFlag += 128;
 
-  (void) cdfInqTimestep(streamptr, 0);
+	/* South -> North */
+	if ( ISEC2_LastLat > ISEC2_FirstLat ) ISEC2_ScanFlag += 64;
 
-  cdfCreateRecords(streamptr, 0);
+	break;
+      }
+    case GRID_LCC:
+      {
+	double originLon = 0.0, originLat = 0.0, lonParY = 0.0,
+          lat1 = 0.0, lat2 = 0.0, xincm = 0.0, yincm = 0.0;
+	int projflag = 0, scanflag = 0;
 
-  /* free ncdims */
-  Free(ncdims);
+	int xsize = gridInqXsize(gridID),
+          ysize = gridInqYsize(gridID);
 
-  /* free ncvars */
-  Free(ncvars);
+	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
+		   &projflag, &scanflag);
 
-  return (0);
-}
+	ISEC2_GridType = GRIB1_GTYPE_LCC;
+	ISEC2_NumLon   = xsize;
+	ISEC2_NumLat   = ysize;
+	ISEC2_FirstLon = (int)lround(originLon * 1000);
+	ISEC2_FirstLat = (int)lround(originLat * 1000);
+	ISEC2_Lambert_Lov    = (int)lround(lonParY * 1000);
+	ISEC2_Lambert_LatS1  = (int)lround(lat1 * 1000);
+	ISEC2_Lambert_LatS2  = (int)lround(lat2 * 1000);
+	ISEC2_Lambert_dx     = (int)lround(xincm);
+	ISEC2_Lambert_dy     = (int)lround(yincm);
+	ISEC2_Lambert_LatSP  = 0;
+	ISEC2_Lambert_LonSP  = 0;
+	ISEC2_Lambert_ProjFlag = projflag;
+	ISEC2_ScanFlag = scanflag;
 
-static
-void wrf_read_timestep(int fileID, int nctimevarid, int tsID, taxis_t *taxis)
-{
-  size_t start[2], count[2];
-  char stvalue[32];
-  start[0] = (size_t) tsID; start[1] = 0;
-  count[0] = 1; count[1] = 19;
-  stvalue[0] = 0;
-  cdf_get_vara_text(fileID, nctimevarid, start, count, stvalue);
-  stvalue[19] = 0;
-  {
-    int year = 1, month = 1, day = 1 , hour = 0, minute = 0, second = 0;
-    if ( strlen(stvalue) == 19 )
-      sscanf(stvalue, "%d-%d-%d_%d:%d:%d", &year, &month, &day, &hour, &minute, &second);
-    taxis->vdate = cdiEncodeDate(year, month, day);
-    taxis->vtime = cdiEncodeTime(hour, minute, second);
-    taxis->type = TAXIS_ABSOLUTE;
-  }
+	break;
+      }
+    case GRID_SPECTRAL:
+      {
+	ISEC2_GridType = GRIB1_GTYPE_SPECTRAL;
+	ISEC2_PentaJ   = gridInqTrunc(gridID);
+	ISEC2_PentaK   = ISEC2_PentaJ;
+	ISEC2_PentaM   = ISEC2_PentaJ;
+	ISEC2_RepType  = 1;
+	isec4[2]       = 128;
+	if ( gridInqComplexPacking(gridID) && ISEC2_PentaJ >= 21 )
+	  {
+	    ISEC2_RepMode  = 2;
+	    isec4[3]       = 64;
+	    isec4[16]      = 0;
+	    isec4[17]      = 20;
+	    isec4[18]      = 20;
+	    isec4[19]      = 20;
+	  }
+	else
+	  {
+	    ISEC2_RepMode  = 1;
+	    isec4[3]       = 0;
+	  }
+	break;
+      }
+    case GRID_GME:
+      {
+	ISEC2_GridType   = GRIB1_GTYPE_GME;
+	ISEC2_GME_ND     = gridInqGMEnd(gridID);
+	ISEC2_GME_NI     = gridInqGMEni(gridID);
+	ISEC2_GME_NI2    = gridInqGMEni2(gridID);
+	ISEC2_GME_NI3    = gridInqGMEni3(gridID);
+	ISEC2_GME_AFlag  = 0;
+	ISEC2_GME_LatPP  = 90000;
+	ISEC2_GME_LonPP  = 0;
+	ISEC2_GME_LonMPL = 0;
+	ISEC2_GME_BFlag  = 0;
+	break;
+      }
+    default:
+      {
+	Warning("The CGRIBEX library can not store fields on the used grid!");
+	Error("Unsupported grid type: %s", gridNamePtr(gridtype));
+	break;
+      }
+    }
 }
 
 static
-double get_timevalue(int fileID, int nctimevarid, int tsID, timecache_t *tcache)
+void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int levelID)
 {
-  double timevalue = 0;
-  size_t index = (size_t) tsID;
+  double level;
+  int ilevel, zaxistype, ltype;
+  static bool lwarning_vct = true;
 
-  if ( tcache )
-    {
-      if ( tcache->size == 0 || (tsID < tcache->startid || tsID > (tcache->startid+tcache->size-1)) )
-        {
-          int maxvals = MAX_TIMECACHE_SIZE;
-          tcache->startid = (tsID/MAX_TIMECACHE_SIZE)*MAX_TIMECACHE_SIZE;
-          if ( (tcache->startid + maxvals) > tcache->maxvals ) maxvals = (tcache->maxvals)%MAX_TIMECACHE_SIZE;
-          tcache->size = maxvals;
-          index = (size_t) tcache->startid;
-          // fprintf(stderr, "fill time cache: %d %d %d %d %d\n", tcache->maxvals, tsID, tcache->startid, tcache->startid+maxvals-1, maxvals);
-          for ( int ival = 0; ival < maxvals; ++ival )
-            {
-              cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
-              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
-              tcache->cache[ival] = timevalue;
-              index++;
-            }
-        }
+  zaxistype = zaxisInqType(zaxisID);
+  ltype = zaxisInqLtype(zaxisID);
 
-      timevalue = tcache->cache[tsID%MAX_TIMECACHE_SIZE];
-    }
-  else
+  if ( zaxistype == ZAXIS_GENERIC && ltype == 0 )
     {
-      cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
-      if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+      Message("Changed zaxis type from %s to %s",
+	      zaxisNamePtr(zaxistype),
+	      zaxisNamePtr(ZAXIS_PRESSURE));
+      zaxistype = ZAXIS_PRESSURE;
+      zaxisChangeType(zaxisID, zaxistype);
+      zaxisDefUnits(zaxisID, "Pa");
     }
 
-  return timevalue;
-}
-
-
-int cdfInqTimestep(stream_t * streamptr, int tsID)
-{
-  long nrecs = 0;
-  double timevalue;
-  int fileID;
-  taxis_t *taxis;
-
-  if ( CDI_Debug ) Message("streamID = %d  tsID = %d", streamptr->self, tsID);
-
-  if ( tsID < 0 ) Error("unexpected tsID = %d", tsID);
+  ISEC2_NumVCP = 0;
 
-  if ( tsID < streamptr->ntsteps && streamptr->ntsteps > 0 )
+  switch (zaxistype)
     {
-      cdfCreateRecords(streamptr, tsID);
-
-      taxis = &streamptr->tsteps[tsID].taxis;
-      if ( tsID > 0 )
-	ptaxisCopy(taxis, &streamptr->tsteps[0].taxis);
-
-      timevalue = tsID;
-
-      int nctimevarid = streamptr->basetime.ncvarid;
-      if ( nctimevarid != UNDEFID )
-	{
-	  fileID = streamptr->fileID;
-	  size_t index  = (size_t)tsID;
-
-	  if ( streamptr->basetime.lwrf )
-	    {
-              wrf_read_timestep(fileID, nctimevarid, tsID, taxis);
-	    }
-	  else
-	    {
-#if defined (USE_TIMECACHE)
-              if ( streamptr->basetime.timevar_cache == NULL )
-                {
-                  streamptr->basetime.timevar_cache = (timecache_t *) Malloc(MAX_TIMECACHE_SIZE*sizeof(timecache_t));
-                  streamptr->basetime.timevar_cache->size = 0;
-                  streamptr->basetime.timevar_cache->maxvals = streamptr->ntsteps;
-                }
-#endif
-              timevalue = get_timevalue(fileID, nctimevarid, tsID, streamptr->basetime.timevar_cache);
-	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate, &taxis->vtime);
-	    }
+    case ZAXIS_SURFACE:
+      {
+	ISEC1_LevelType = GRIB1_LTYPE_SURFACE;
+	ISEC1_Level1    = (int)(zaxisInqLevel(zaxisID, levelID));
+	ISEC1_Level2    = 0;
+	break;
+      }
+    case ZAXIS_CLOUD_BASE:
+      {
+	ISEC1_LevelType = GRIB1_LTYPE_CLOUD_BASE;
+	ISEC1_Level1    = 0;
+	ISEC1_Level2    = 0;
+	break;
+      }
+    case ZAXIS_CLOUD_TOP:
+      {
+	ISEC1_LevelType = GRIB1_LTYPE_CLOUD_TOP;
+	ISEC1_Level1    = 0;
+	ISEC1_Level2    = 0;
+	break;
+      }
+    case ZAXIS_ISOTHERM_ZERO:
+      {
+	ISEC1_LevelType = GRIB1_LTYPE_ISOTHERM0;
+	ISEC1_Level1    = 0;
+	ISEC1_Level2    = 0;
+	break;
+      }
+    case ZAXIS_TOA:
+      {
+	ISEC1_LevelType = GRIB1_LTYPE_TOA;
+	ISEC1_Level1    = 0;
+	ISEC1_Level2    = 0;
+	break;
+      }
+    case ZAXIS_SEA_BOTTOM:
+      {
+	ISEC1_LevelType = GRIB1_LTYPE_SEA_BOTTOM;
+	ISEC1_Level1    = 0;
+	ISEC1_Level2    = 0;
+	break;
+      }
+    case ZAXIS_ATMOSPHERE:
+      {
+	ISEC1_LevelType = GRIB1_LTYPE_ATMOSPHERE;
+	ISEC1_Level1    = 0;
+	ISEC1_Level2    = 0;
+	break;
+      }
+    case ZAXIS_MEANSEA:
+      {
+	ISEC1_LevelType = GRIB1_LTYPE_MEANSEA;
+	ISEC1_Level1    = (int)(zaxisInqLevel(zaxisID, levelID));
+	ISEC1_Level2    = 0;
+	break;
+      }
+    case ZAXIS_HYBRID:
+    case ZAXIS_HYBRID_HALF:
+      {
+	int vctsize;
 
-	  int nctimeboundsid = streamptr->basetime.ncvarboundsid;
-	  if ( nctimeboundsid != UNDEFID )
-	    {
-	      size_t start[2], count[2];
-              start[0] = index; count[0] = 1; start[1] = 0; count[1] = 1;
-	      cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
-              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
+	  {
+	    ISEC1_LevelType = GRIB1_LTYPE_HYBRID_LAYER;
+	    ISEC1_Level1    = (int)(zaxisInqLbound(zaxisID, levelID));
+	    ISEC1_Level2    = (int)(zaxisInqUbound(zaxisID, levelID));
+	  }
+	else
+	  {
+	    ISEC1_LevelType = GRIB1_LTYPE_HYBRID;
+	    ISEC1_Level1    = (int)(zaxisInqLevel(zaxisID, levelID));
+	    ISEC1_Level2    = 0;
+	  }
 
-	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_lb, &taxis->vtime_lb);
+	vctsize = zaxisInqVctSize(zaxisID);
+	if ( vctsize > 255 )
+	  {
+	    ISEC2_NumVCP = 0;
+	    if ( lwarning_vct )
+	      {
+		Warning("VCT size of %d is too large (maximum is 255). Set to 0!", vctsize);
+		lwarning_vct = false;
+	      }
+	  }
+	else
+	  {
+	    ISEC2_NumVCP = vctsize;
+	    zaxisInqVct(zaxisID, &fsec2[10]);
+	  }
+	break;
+      }
+    case ZAXIS_PRESSURE:
+      {
+	double dum;
+	char units[128];
 
-              start[0] = index; count[0] = 1; start[1] = 1; count[1] = 1;
-	      cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
-              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+	level = zaxisInqLevel(zaxisID, levelID);
+	if ( level < 0 )
+	  Warning("Pressure level of %f Pa is below zero!", level);
 
-	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_ub, &taxis->vtime_ub);
-	    }
+	zaxisInqUnits(zaxisID, units);
+	if ( (units[0] != 'P') | (units[1] != 'a') ) level *= 100;
 
-          int leadtimeid = streamptr->basetime.leadtimeid;
-          if ( leadtimeid != UNDEFID )
-            {
-              timevalue = get_timevalue(fileID, leadtimeid, tsID, NULL);
-              cdiSetForecastPeriod(timevalue, taxis);
-            }
-	}
-    }
+	ilevel = (int) level;
+	if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
+	  {
+	    ISEC1_LevelType = GRIB1_LTYPE_99;
+	    ISEC1_Level1    = ilevel;
+	    ISEC1_Level2    = 0;
+	  }
+	else
+	  {
+	    ISEC1_LevelType = GRIB1_LTYPE_ISOBARIC;
+	    ISEC1_Level1    = ilevel/100;
+	    ISEC1_Level2    = 0;
+	  }
+	break;
+      }
+    case ZAXIS_HEIGHT:
+      {
+	level = zaxisInqLevel(zaxisID, levelID);
 
-  streamptr->curTsID = tsID;
-  nrecs = streamptr->tsteps[tsID].nrecs;
+	char units[128];
+	zaxisInqUnits(zaxisID, units);
+        if ( units[1] == 'm' && !units[2] )
+          {
+            if      ( units[0] == 'c' ) level *= 0.01;
+            else if ( units[0] == 'd' ) level *= 0.1;
+            else if ( units[0] == 'k' ) level *= 1000;
+          }
 
-  return ((int) nrecs);
-}
+	ilevel = (int) level;
+	ISEC1_LevelType = GRIB1_LTYPE_HEIGHT;
+	ISEC1_Level1    = ilevel;
+	ISEC1_Level2    = 0;
 
+	break;
+      }
+    case ZAXIS_ALTITUDE:
+      {
+	level = zaxisInqLevel(zaxisID, levelID);
 
-void cdfEndDef(stream_t *streamptr)
-{
-  int varID;
-  int nvars;
-  int fileID;
+	ilevel = (int) level;
+	ISEC1_LevelType = GRIB1_LTYPE_ALTITUDE;
+	ISEC1_Level1    = ilevel;
+	ISEC1_Level2    = 0;
 
-  fileID  = streamptr->fileID;
+	break;
+      }
+    case ZAXIS_SIGMA:
+      {
+	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
+	  {
+	    ISEC1_LevelType = GRIB1_LTYPE_SIGMA_LAYER;
+	    ISEC1_Level1    = (int)(zaxisInqLbound(zaxisID, levelID));
+	    ISEC1_Level2    = (int)(zaxisInqUbound(zaxisID, levelID));
+	  }
+	else
+	  {
+            level = zaxisInqLevel(zaxisID, levelID);
 
-  cdfDefGlobalAtts(streamptr);
-  cdfDefLocalAtts(streamptr);
+            ilevel = (int) level;
+            ISEC1_LevelType = GRIB1_LTYPE_SIGMA;
+            ISEC1_Level1    = ilevel;
+            ISEC1_Level2    = 0;
+          }
 
-  if ( streamptr->accessmode == 0 )
-    {
-      nvars =  streamptr->nvars;
+	break;
+      }
+    case ZAXIS_DEPTH_BELOW_LAND:
+      {
+	char units[128];
+	double factor;
 
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+	zaxisInqUnits(zaxisID, units);
 
-      for ( varID = 0; varID < nvars; varID++ )
-	cdfDefVar(streamptr, varID);
+        if      ( units[0] == 'm' && units[1] == 'm' ) factor =   0.1;
+        else if ( units[0] == 'c' && units[1] == 'm' ) factor =   1;
+        else if ( units[0] == 'd' && units[1] == 'm' ) factor =  10;
+        else                                           factor = 100; // meter
 
-      if ( streamptr->ncmode == 2 )
-        {
-          if ( CDI_netcdf_hdr_pad == 0UL )
-            cdf_enddef(fileID);
-          else
-            cdf__enddef(fileID, CDI_netcdf_hdr_pad);
-        }
+	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
+	  {
+            double level1, level2;
+            level1 = zaxisInqLbound(zaxisID, levelID);
+            level2 = zaxisInqUbound(zaxisID, levelID);
+	    ISEC1_LevelType = GRIB1_LTYPE_LANDDEPTH_LAYER;
+	    ISEC1_Level1    = (int) (level1*factor);
+	    ISEC1_Level2    = (int) (level2*factor);
+	  }
+	else
+	  {
+	    level = zaxisInqLevel(zaxisID, levelID);
 
-      streamptr->accessmode = 1;
-    }
-}
+	    ilevel = (int) (level*factor);
+	    ISEC1_LevelType = GRIB1_LTYPE_LANDDEPTH;
+	    ISEC1_Level1    = ilevel;
+	    ISEC1_Level2    = 0;
+	  }
 
+	break;
+      }
+    case ZAXIS_DEPTH_BELOW_SEA:
+      {
+	level = zaxisInqLevel(zaxisID, levelID);
 
-static void cdfDefInstitut(stream_t *streamptr)
-{
-  int fileID, instID;
-  size_t len;
-  int vlistID;
+	ilevel = (int) level;
+	ISEC1_LevelType = GRIB1_LTYPE_SEADEPTH;
+	ISEC1_Level1    = ilevel;
+	ISEC1_Level2    = 0;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
-  instID  = vlistInqInstitut(vlistID);
+	break;
+      }
+    case ZAXIS_ISENTROPIC:
+      {
+	level = zaxisInqLevel(zaxisID, levelID);
 
-  if ( instID != UNDEFID )
-    {
-      const char *longname = institutInqLongnamePtr(instID);
-      if ( longname )
-	{
-	  len = strlen(longname);
-	  if ( len > 0 )
-	    {
-	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-	      cdf_put_att_text(fileID, NC_GLOBAL, "institution", len, longname);
-	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
-	    }
-	}
-    }
-}
+	ilevel = (int) level;
+	ISEC1_LevelType = GRIB1_LTYPE_ISENTROPIC;
+	ISEC1_Level1    = ilevel;
+	ISEC1_Level2    = 0;
 
+	break;
+      }
+    case ZAXIS_GENERIC:
+      {
+	level = zaxisInqLevel(zaxisID, levelID);
 
-static void cdfDefSource(stream_t *streamptr)
-{
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-  int modelID = vlistInqModel(vlistID);
+	ilevel = (int) level;
+	ISEC1_LevelType = ltype;
+	ISEC1_Level1    = ilevel;
+	ISEC1_Level2    = 0;
 
-  if ( modelID != UNDEFID )
-    {
-      const char *longname = modelInqNamePtr(modelID);
-      if ( longname )
-	{
-          size_t len = strlen(longname);
-	  if ( len > 0 )
-	    {
-	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-	      cdf_put_att_text(fileID, NC_GLOBAL, "source", len, longname);
-	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
-	    }
-	}
+	break;
+      }
+    default:
+      {
+	Error("Unsupported zaxis type: %s", zaxisNamePtr(zaxistype));
+	break;
+      }
     }
 }
 
-
-static void cdfDefGlobalAtts(stream_t *streamptr)
+static
+void cgribexDefaultSec0(int *isec0)
 {
-  int natts;
-
-  if ( streamptr->globalatts ) return;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  cdfDefSource(streamptr);
-  cdfDefInstitut(streamptr);
-
-  vlistInqNatts(vlistID, CDI_GLOBAL, &natts);
-
-  if ( natts > 0 && streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-  defineAttributes(vlistID, CDI_GLOBAL, fileID, NC_GLOBAL);
-
-  if ( natts > 0 && streamptr->ncmode == 2 ) cdf_enddef(fileID);
-
-  streamptr->globalatts = 1;
+  ISEC0_GRIB_Len     = 0;
+  ISEC0_GRIB_Version = 0;
 }
 
+static
+void cgribexDefaultSec1(int *isec1)
+{
+  ISEC1_CenterID    = 0;
+  ISEC1_SubCenterID = 0;
+  ISEC1_LocalFLag   = 0;
+}
 
-static void cdfDefLocalAtts(stream_t *streamptr)
+static
+void cgribexDefaultSec4(int *isec4)
 {
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
+  for ( int i = 2; i <= 10; ++i ) isec4[i] = 0;
+}
 
-  if ( streamptr->localatts ) return;
-  if ( vlistInqInstitut(vlistID) != UNDEFID ) return;
+static
+void cgribexDefEnsembleVar(int *isec1, int vlistID, int varID)
+{
+  int ensID, ensCount, forecast_type;
 
-  streamptr->localatts = 1;
+  /* For Ensemble info  */
 
-  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+  //Put1Byte(isec1[36]);        /* MPIM local GRIB use definition identifier  */
+                                /*    (extension identifier)                  */
+  //Put1Byte(isec1[37]);        /* type of ensemble forecast                  */
+  //Put2Byte(isec1[38]);        /* individual ensemble member                 */
+  //Put2Byte(isec1[39]);        /* number of forecasts in ensemble            */
 
-  for ( int varID = 0; varID < streamptr->nvars; varID++ )
+  if ( vlistInqVarEnsemble(vlistID, varID, &ensID, &ensCount, &forecast_type) )
     {
-      int instID = vlistInqVarInstitut(vlistID, varID);
-      if ( instID != UNDEFID )
-	{
-          int ncvarid = streamptr->vars[varID].ncvarid;
-  	  const char *name = institutInqNamePtr(instID);
-	  if ( name )
-	    {
-              size_t len = strlen(name);
-	      cdf_put_att_text(fileID, ncvarid, "institution", len, name);
-	    }
-	}
-      }
+      if ( ISEC1_CenterID == 252 )
+        {
+          ISEC1_LocalFLag = 1;
+          isec1[36] = 1;
 
-  if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
+          isec1[37] =  forecast_type;
+          isec1[38] =  ensID;
+          isec1[39] =  ensCount;
+        }
+    }
 }
+#endif
 
 
-void cdfDefHistory(stream_t *streamptr, int size, const char *history)
+#if  defined  (HAVE_LIBCGRIBEX)
+size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
+		     int vdate, int vtime, int tsteptype, int numavg,
+		     long datasize, const void *data, int nmiss, void *gribbuffer, size_t gribbuffersize)
 {
-  int ncid = streamptr->fileID;
-  cdf_put_att_text(ncid, NC_GLOBAL, "history", (size_t) size, history);
-}
+  size_t nbytes = 0;
+  int gribsize;
+  int iret = 0, iword = 0;
+  int isec0[2], isec1[4096], isec2[4096], isec3[2], isec4[512];
+  float fsec2f[512], fsec3f[2];
+  double fsec2[512], fsec3[2];
+  int datatype;
+  int param;
 
+  memset(isec1, 0, 256*sizeof(int));
+  fsec2[0] = 0; fsec2[1] = 0;
+  fsec2f[0] = 0; fsec2f[1] = 0;
 
-int cdfInqHistorySize(stream_t *streamptr)
-{
-  size_t size = 0;
-  int ncid = streamptr->fileID;
-  if ( streamptr->historyID != UNDEFID )
-    cdf_inq_attlen(ncid, NC_GLOBAL, "history", &size);
+  gribsize = (int)(gribbuffersize / sizeof(int));
+  param    = vlistInqVarParam(vlistID, varID);
 
-  return ((int) size);
-}
+  cgribexDefaultSec0(isec0);
+  cgribexDefaultSec1(isec1);
+  cgribexDefaultSec4(isec4);
 
+  cgribexDefInstitut(isec1, vlistID, varID);
+  cgribexDefModel(isec1, vlistID, varID);
 
-void cdfInqHistoryString(stream_t *streamptr, char *history)
-{
-  int ncid = streamptr->fileID;
-  if ( streamptr->historyID != UNDEFID )
-    cdf_get_att_text(ncid, NC_GLOBAL, "history", history);
-}
+  datatype = vlistInqVarDatatype(vlistID, varID);
 
+  cgribexDefParam(isec1, param);
+  cgribexDefTime(isec1, vdate, vtime, tsteptype, numavg, vlistInqTaxis(vlistID));
+  cgribexDefGrid(isec1, isec2, fsec2, isec4, gridID);
+  cgribexDefLevel(isec1, isec2, fsec2, zaxisID, levelID);
 
-void cdfDefVars(stream_t *streamptr)
-{
-  int vlistID = streamptr->vlistID;
-  if ( vlistID == UNDEFID )
-    Error("Internal problem! vlist undefined for streamptr %p", streamptr);
+  cgribexDefEnsembleVar(isec1, vlistID, varID);
 
-  int ngrids = vlistNgrids(vlistID);
-  int nzaxis = vlistNzaxis(vlistID);
-  /*
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
-  */
-  if ( ngrids > 0 )
-    for ( int index = 0; index < ngrids; index++ )
-      {
-        int gridID = vlistGrid(vlistID, index);
-        cdfDefGrid(streamptr, gridID);
-      }
+  ISEC4_NumValues = gridInqSize(gridID);
+  ISEC4_NumBits   = grbBitsPerValue(datatype);
 
-  if ( nzaxis > 0 )
-    for ( int index = 0; index < nzaxis; index++ )
-      {
-        int zaxisID = vlistZaxis(vlistID, index);
-        if ( streamptr->zaxisID[index] == UNDEFID ) cdfDefZaxis(streamptr, zaxisID);
-      }
+  if ( nmiss > 0 )
+    {
+      FSEC3_MissVal = vlistInqVarMissval(vlistID, varID);
+      ISEC1_Sec2Or3Flag |= 64;
+    }
 
-  /* define time first!!!
-    int nvars  = vlistNvars(vlistID);
-  for ( int varID = 0; varID < nvars; varID++ )
+  if ( isec4[2] == 128 && isec4[3] == 64 )
     {
-      int ncvarid = cdfDefVar(streamptr, varID);
+      if ( memtype == MEMTYPE_FLOAT )
+        isec4[16] = (int) (1000*calculate_pfactor_float((const float*) data, ISEC2_PentaJ, isec4[17]));
+      else
+        isec4[16] = (int) (1000*calculate_pfactor_double((const double*) data, ISEC2_PentaJ, isec4[17]));
+      if ( isec4[16] < -10000 ) isec4[16] = -10000;
+      if ( isec4[16] >  10000 ) isec4[16] =  10000;
     }
-  */
-}
-#endif
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef CDI_DATETIME_H
-#define CDI_DATETIME_H
+  //printf("isec4[16] %d\n", isec4[16]);
 
-typedef struct
-{
-  long date;
-  long time;
-}
-DateTime;
+  if ( memtype == MEMTYPE_FLOAT )
+    {
+      size_t numVCP = ISEC2_NumVCP > 0 ? (size_t)ISEC2_NumVCP : (size_t)0;
+      for ( size_t i = 0; i < numVCP; ++i ) fsec2f[10+i] = (float)fsec2[10+i];
+      fsec3f[ 1] = (float)fsec3[ 1];
+    }
 
-static inline int
-datetimeCmp(DateTime dt1, DateTime dt2)
-{
-  return 2 * ((dt1.date > dt2.date) - (dt1.date < dt2.date))
-    + (dt1.time > dt2.time) - (dt1.time < dt2.time);
-}
+  if ( memtype == MEMTYPE_FLOAT )
+    gribExSP(isec0, isec1, isec2, fsec2f, isec3, fsec3f, isec4, (float*) data,
+             (int) datasize, (int*) gribbuffer, gribsize, &iword, "C", &iret);
+  else
+    gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, (double*) data,
+             (int) datasize, (int*) gribbuffer, gribsize, &iword, "C", &iret);
 
+  if ( iret ) Error("Problem during GRIB encode (errno = %d)!", iret);
 
+  nbytes = (size_t)iword * sizeof (int);
+  return nbytes;
+}
 #endif
 /*
  * Local Variables:
@@ -45846,21 +47285,16 @@ datetimeCmp(DateTime dt1, DateTime dt2)
  * require-trailing-newline: t
  * End:
  */
-#ifndef _STREAM_CGRIBEX_H
-#define _STREAM_CGRIBEX_H
-
-int cgribexScanTimestep1(stream_t * streamptr);
-int cgribexScanTimestep2(stream_t * streamptr);
-int cgribexScanTimestep(stream_t * streamptr);
+#ifndef STREAM_FCOMMON_H
+#define STREAM_FCOMMON_H
 
-int cgribexDecode(unsigned char *gribbuffer, int gribsize, double *data, int gridsize,
-		  int unreduced, int *nmiss, double missval);
+#ifndef  _CDI_INT_H
+#endif
 
-size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
-		     int vdate, int vtime, int tsteptype, int numavg, 
-		     long datasize, const double *data, int nmiss, unsigned char *gribbuffer, size_t gribbuffersize);
+void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1,
+                       const char *container_name);
 
-#endif  /* _STREAM_CGRIBEX_H */
+#endif
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -45875,833 +47309,407 @@ size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridI
 
 #include <limits.h>
 #include <stdio.h>
-// #include <float.h>  /* FLT_EPSILON */
-
-
-#if  defined  (HAVE_LIBCGRIBEX)
-#endif
-
-typedef struct {
-  int param;
-  int level1;
-  int level2;
-  int ltype;
-  int tsteptype;
-} compvar_t;
-
-
-#if  defined  (HAVE_LIBCGRIBEX)
-static
-int cgribexGetGridType(int *isec2)
-{
-  int gridtype = GRID_GENERIC;
-
-  switch (ISEC2_GridType)
-    {
-    case  GRIB1_GTYPE_LATLON:     { if ( ISEC2_Reduced )      break; }
-    case  GRIB1_GTYPE_LATLON_ROT: { gridtype = GRID_LONLAT;   break; }
-    case  GRIB1_GTYPE_LCC:        { gridtype = GRID_LCC;      break; }
-    case  GRIB1_GTYPE_GAUSSIAN:   { if ( ISEC2_Reduced )
-	                              gridtype = GRID_GAUSSIAN_REDUCED;
-                         	    else
-				      gridtype = GRID_GAUSSIAN;
-          	                    break;
-                                  }
-    case  GRIB1_GTYPE_SPECTRAL:   { gridtype = GRID_SPECTRAL; break; }
-    case  GRIB1_GTYPE_GME:        { gridtype = GRID_GME;      break; }
-    }
-
-  return (gridtype);
-}
-
-static
-int cgribexGetIsRotated(int *isec2)
-{
-  int isRotated = 0;
-
-  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
-    {
-      isRotated = 1;
-    }
-
-  return (isRotated);
-}
-
-static
-int cgribexGetZaxisHasBounds(int grb_ltype)
-{
-  int lbounds = 0;
-
-  switch (grb_ltype)
-    {
-    case GRIB1_LTYPE_SIGMA_LAYER:
-    case GRIB1_LTYPE_HYBRID_LAYER:
-    case GRIB1_LTYPE_LANDDEPTH_LAYER:
-      {
-	lbounds = 1;
-	break;
-      }
-    }
-
-  return (lbounds);
-}
-
-static
-int cgribexGetTimeUnit(int *isec1)
-{
-  int timeunit = TUNIT_HOUR;
-  static int lprint = TRUE;
-
-  switch ( ISEC1_TimeUnit )
-    {
-    case ISEC1_TABLE4_MINUTE:    timeunit = TUNIT_MINUTE;    break;
-    case ISEC1_TABLE4_QUARTER:   timeunit = TUNIT_QUARTER;   break;
-    case ISEC1_TABLE4_30MINUTES: timeunit = TUNIT_30MINUTES; break;
-    case ISEC1_TABLE4_HOUR:      timeunit = TUNIT_HOUR;      break;
-    case ISEC1_TABLE4_3HOURS:    timeunit = TUNIT_3HOURS;    break;
-    case ISEC1_TABLE4_6HOURS:    timeunit = TUNIT_6HOURS;    break;
-    case ISEC1_TABLE4_12HOURS:   timeunit = TUNIT_12HOURS;   break;
-    case ISEC1_TABLE4_DAY:       timeunit = TUNIT_DAY;       break;
-    default:
-      if ( lprint )
-	{
-	  Message("GRIB time unit %d unsupported!", ISEC1_TimeUnit);
-	  lprint = FALSE;
-	}
-      break;
-    }
-
-  return (timeunit);
-}
-
-static
-int cgribexTimeIsFC(int *isec1)
-{
-  int isFC = TRUE;
-
-  if ( ISEC1_TimeRange == 10 && ISEC1_TimePeriod1 == 0 && ISEC1_TimePeriod2 == 0 )
-    isFC = FALSE;
-
-  return (isFC);
-}
-
-static
-int cgribexGetTsteptype(int timerange)
-{
-  int tsteptype = TSTEP_INSTANT;
-  static int lprint = TRUE;
-
-  switch ( timerange )
-    {
-    case  0:  tsteptype = TSTEP_INSTANT;  break;
-    case  1:  tsteptype = TSTEP_INSTANT2; break;
-    case  2:  tsteptype = TSTEP_RANGE;    break;
-    case  3:  tsteptype = TSTEP_AVG;      break;
-    case  4:  tsteptype = TSTEP_ACCUM;    break;
-    case  5:  tsteptype = TSTEP_DIFF;     break;
-    case 10:  tsteptype = TSTEP_INSTANT3; break;
-    default:
-      if ( lprint )
-	{
-	  Message("Time range indicator %d unsupported, set to 0!", timerange);
-	  lprint = FALSE;
-	}
-      break;
-    }
-
-  return (tsteptype);
-}
-
-static
-void cgribexGetGrid(stream_t *streamptr, int *isec2, double *fsec2, int *isec4, grid_t *grid, int iret)
-{
-  int compyinc = TRUE;
-  int gridtype = cgribexGetGridType(isec2);
-
-  if ( streamptr->unreduced && gridtype == GRID_GAUSSIAN_REDUCED && iret != -801 )
-    {
-      int ilat, nlon = 0;
-      for ( ilat = 0; ilat < ISEC2_NumLat; ++ilat )
-        if ( ISEC2_RowLon(ilat) > nlon ) nlon = ISEC2_RowLon(ilat);
-      gridtype = GRID_GAUSSIAN;
-      ISEC2_NumLon = nlon;
-      ISEC4_NumValues = nlon*ISEC2_NumLat;
-      compyinc = FALSE;
-    }
-
-  memset(grid, 0, sizeof(grid_t));
-  switch (gridtype)
-    {
-    case GRID_LONLAT:
-    case GRID_GAUSSIAN:
-      {
-	if ( ISEC4_NumValues != ISEC2_NumLon*ISEC2_NumLat )
-	  Error("numberOfPoints (%d) and gridSize (%d) differ!", ISEC4_NumValues, ISEC2_NumLon*ISEC2_NumLat);
-	grid->size  = ISEC4_NumValues;
-	grid->xsize = ISEC2_NumLon;
-	grid->ysize = ISEC2_NumLat;
-        if ( gridtype == GRID_GAUSSIAN ) grid->np = ISEC2_NumPar;
-	grid->xinc  = 0;
-	grid->yinc  = 0;
-	grid->xdef  = 0;
-	/* if ( ISEC2_FirstLon != 0 || ISEC2_LastLon != 0 ) */
-	  {
-	    if ( grid->xsize > 1 )
-	      {
-                int recompinc = TRUE;
-
-                if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
-
-		if ( ISEC2_ResFlag && ISEC2_LonIncr > 0 )
-                  {
-                    if ( abs(ISEC2_LastLon - (ISEC2_FirstLon+ISEC2_LonIncr*(grid->xsize-1))) <= 2 )
-                      {
-                        recompinc = FALSE;
-                        grid->xinc = ISEC2_LonIncr * 0.001;
-                      }
-                  }
-
-		/* recompute xinc if necessary */
-                if ( recompinc ) grid->xinc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->xsize-1);
-
-		/* correct xinc if necessary */
-		if ( ISEC2_FirstLon == 0 && ISEC2_LastLon > 354000 && ISEC2_LastLon < 360000 )
-		  {
-		    double xinc = 360. / grid->xsize;
+#include <string.h>
 
-		    if ( fabs(grid->xinc-xinc) > 0.0 )
-		      {
-			grid->xinc = xinc;
-			if ( CDI_Debug ) Message("set xinc to %g", grid->xinc);
-		      }
-		  }
-	      }
-	    grid->xfirst = ISEC2_FirstLon * 0.001;
-	    grid->xlast  = ISEC2_LastLon  * 0.001;
-	    grid->xdef   = 2;
-	  }
-	grid->ydef  = 0;
-	/* if ( ISEC2_FirstLat != 0 || ISEC2_LastLat != 0 ) */
-	  {
-	    if ( grid->ysize > 1 && compyinc )
-	      {
-                int recompinc = TRUE;
-		if ( ISEC2_ResFlag && ISEC2_LatIncr > 0 )
-                  {
-                    if ( abs(ISEC2_LastLat - (ISEC2_FirstLat+ISEC2_LatIncr*(grid->ysize-1))) <= 2 )
-                      {
-                        recompinc = FALSE;
-                        grid->yinc = ISEC2_LatIncr * 0.001;
-                      }
-                  }
 
-		/* recompute yinc if necessary */
-                if ( recompinc ) grid->yinc = (ISEC2_LastLat - ISEC2_FirstLat) * 0.001 / (grid->ysize - 1);
-	      }
-	    grid->yfirst = ISEC2_FirstLat * 0.001;
-	    grid->ylast  = ISEC2_LastLat  * 0.001;
-	    grid->ydef   = 2;
-	  }
-	break;
-      }
-    case GRID_GAUSSIAN_REDUCED:
-      {
-        grid->np     = ISEC2_NumPar;
-	grid->size   = ISEC4_NumValues;
-        grid->rowlon = ISEC2_RowLonPtr;
-	grid->ysize  = ISEC2_NumLat;
-	grid->xinc   = 0;
-	grid->yinc   = 0;
-	grid->xdef   = 0;
-	/* if ( ISEC2_FirstLon != 0 || ISEC2_LastLon != 0 ) */
-	  {
-	    if ( grid->xsize > 1 )
-	      {
-                if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
 
-		if ( ISEC2_ResFlag && ISEC2_LonIncr > 0 )
-		  grid->xinc = ISEC2_LonIncr * 0.001;
-		else
-		  grid->xinc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->xsize - 1);
-	      }
-	    grid->xfirst = ISEC2_FirstLon * 0.001;
-	    grid->xlast  = ISEC2_LastLon  * 0.001;
-	    grid->xdef   = 2;
-	  }
-	grid->ydef  = 0;
-	/* if ( ISEC2_FirstLat != 0 || ISEC2_LastLat != 0 ) */
-	  {
-	    if ( grid->ysize > 1 )
-	      {
-		if ( ISEC2_ResFlag && ISEC2_LatIncr > 0 )
-		  grid->yinc = ISEC2_LatIncr * 0.001;
-		else
-		  grid->yinc = (ISEC2_LastLat - ISEC2_FirstLat) * 0.001 / (grid->ysize - 1);
-	      }
-	    grid->yfirst = ISEC2_FirstLat * 0.001;
-	    grid->ylast  = ISEC2_LastLat  * 0.001;
-	    grid->ydef   = 2;
-	  }
-	break;
-      }
-    case GRID_LCC:
-      {
-	if ( ISEC4_NumValues != ISEC2_NumLon*ISEC2_NumLat )
-	  Error("numberOfPoints (%d) and gridSize (%d) differ!",
-		ISEC4_NumValues, ISEC2_NumLon*ISEC2_NumLat);
 
-	grid->size  = ISEC4_NumValues;
-	grid->xsize = ISEC2_NumLon;
-	grid->ysize = ISEC2_NumLat;
+#undef  UNDEFID
+#define UNDEFID  CDI_UNDEFID
 
-	grid->lcc_xinc      = ISEC2_Lambert_dx;
-	grid->lcc_yinc      = ISEC2_Lambert_dy;
-	grid->lcc_originLon = ISEC2_FirstLon * 0.001;
-	grid->lcc_originLat = ISEC2_FirstLat * 0.001;
-	grid->lcc_lonParY   = ISEC2_Lambert_Lov * 0.001;
-	grid->lcc_lat1      = ISEC2_Lambert_LatS1 * 0.001;
-	grid->lcc_lat2      = ISEC2_Lambert_LatS2 * 0.001;
-	grid->lcc_projflag  = ISEC2_Lambert_ProjFlag;
-	grid->lcc_scanflag  = ISEC2_ScanFlag;
+#define SINGLE_PRECISION  4
+#define DOUBLE_PRECISION  8
 
-	grid->xdef   = 0;
-	grid->ydef   = 0;
+#if defined (HAVE_LIBEXTRA)
 
-	break;
-      }
-    case GRID_SPECTRAL:
-      {
-	grid->size  = ISEC4_NumValues;
-	grid->trunc = ISEC2_PentaJ;
-	if ( ISEC2_RepMode == 2 )
-	  grid->lcomplex = 1;
-	else
-	  grid->lcomplex = 0;
 
-	break;
-      }
-    case GRID_GME:
-      {
-	grid->size  = ISEC4_NumValues;
-	grid->nd    = ISEC2_GME_ND;
-	grid->ni    = ISEC2_GME_NI;
-	grid->ni2   = ISEC2_GME_NI2;
-	grid->ni3   = ISEC2_GME_NI3;
-	break;
-      }
-    case GRID_GENERIC:
-      {
-	grid->size  = ISEC4_NumValues;
-	grid->xsize = 0;
-	grid->ysize = 0;
-	break;
-      }
-    default:
-      {
-	Error("Unsupported grid type: %s", gridNamePtr(gridtype));
-	break;
-      }
-    }
+typedef struct {
+  int param;
+  int level;
+} extcompvar_t;
 
-  grid->isRotated = FALSE;
-  if ( cgribexGetIsRotated(isec2) )
+static
+int extInqDatatype(int prec, int number)
+{
+  int datatype;
+
+  if ( number == 2 )
     {
-      grid->isRotated = TRUE;
-      grid->ypole     = - ISEC2_LatSP*0.001;
-      grid->xpole     =   ISEC2_LonSP*0.001 - 180;
-      grid->angle     = - FSEC2_RotAngle;
+      if ( prec == DOUBLE_PRECISION ) datatype = DATATYPE_CPX64;
+      else                            datatype = DATATYPE_CPX32;
+    }
+  else
+    {
+      if ( prec == DOUBLE_PRECISION ) datatype = DATATYPE_FLT64;
+      else                            datatype = DATATYPE_FLT32;
     }
 
-  grid->xvals = NULL;
-  grid->yvals = NULL;
-  grid->type  = gridtype;
+  return (datatype);
 }
 
 static
-void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, double *fsec2, double *fsec3,
-		      int *isec4, long recsize, off_t position, int datatype, int comptype, int lmv, int iret)
+void extDefDatatype(int datatype, int *prec, int *number)
 {
-  int varID;
-  int levelID = 0;
-  grid_t grid;
 
-  int vlistID = streamptr->vlistID;
-  int tsID    = streamptr->curTsID;
-  int recID   = recordNewEntry(streamptr, tsID);
-  record_t *record  = &streamptr->tsteps[tsID].records[recID];
+  if ( datatype != DATATYPE_FLT32 && datatype != DATATYPE_FLT64 &&
+       datatype != DATATYPE_CPX32 && datatype != DATATYPE_CPX64 )
+    datatype = DATATYPE_FLT32;
 
-  int tsteptype = cgribexGetTsteptype(ISEC1_TimeRange);
-  int numavg    = ISEC1_AvgNum;
+  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
+    *number = 2;
+  else
+    *number = 1;
 
-  int level1  = ISEC1_Level1;
-  int level2  = ISEC1_Level2;
+  if ( datatype == DATATYPE_FLT64 || datatype == DATATYPE_CPX64 )
+    *prec = DOUBLE_PRECISION;
+  else 
+    *prec = SINGLE_PRECISION;
+}
 
-  /* fprintf(stderr, "param %d %d %d %d\n", param, level1, level2, ISEC1_LevelType); */
+/* not used
+int extInqRecord(stream_t *streamptr, int *varID, int *levelID)
+{
+  int status;
+  int fileID;
+  int icode, ilevel;
+  int zaxisID = -1;
+  int header[4];
+  int vlistID;
+  void *extp = streamptr->record->exsep;
 
-  record->size      = (size_t)recsize;
-  record->position  = position;
-  record->param     = param;
-  record->ilevel    = level1;
-  record->ilevel2   = level2;
-  record->ltype     = ISEC1_LevelType;
-  record->tsteptype = tsteptype;
+  vlistID = streamptr->vlistID;
+  fileID  = streamptr->fileID;
 
-  cgribexGetGrid(streamptr, isec2, fsec2, isec4, &grid, iret);
+  *varID   = -1;
+  *levelID = -1;
 
-  int gridID = varDefGrid(vlistID, &grid, 0);
+  status = extRead(fileID, extp);
+  if ( status != 0 ) return (0);
 
-  int zaxistype = grib1ltypeToZaxisType(ISEC1_LevelType);
+  extInqHeader(extp, header);
 
-  if ( zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF )
-    {
-      size_t vctsize = (size_t)ISEC2_NumVCP;
-      double *vctptr = &fsec2[10];
+  icode  = header[1];
+  ilevel = header[2];
 
-      varDefVCT(vctsize, vctptr);
-    }
+  *varID = vlistInqVarID(vlistID, icode);
 
-  int lbounds = cgribexGetZaxisHasBounds(ISEC1_LevelType);
+  if ( *varID == UNDEFID ) Error("Code %d undefined", icode);
 
-  if ( datatype > 32 ) datatype = DATATYPE_PACK32;
-  if ( datatype <  0 ) datatype = DATATYPE_PACK;
+  zaxisID = vlistInqVarZaxis(vlistID, *varID);
 
-  varAddRecord(recID, param, gridID, zaxistype, lbounds, level1, level2, 0, 0,
-	       datatype, &varID, &levelID, tsteptype, numavg, ISEC1_LevelType, -1,
-               NULL, NULL, NULL, NULL, NULL, NULL);
+  *levelID = zaxisInqLevelID(zaxisID, (double) ilevel);
 
-  record->varID   = (short)varID;
-  record->levelID = (short)levelID;
+  return (1);
+}
+*/
 
-  varDefCompType(varID, comptype);
+void extReadRecord(stream_t *streamptr, double *data, int *nmiss)
+{
+  int vlistID, fileID;
+  int status;
+  int recID, vrecID, tsID;
+  off_t recpos;
+  int header[4];
+  int varID, gridID;
+  int i, size;
+  double missval;
+  void *extp = streamptr->record->exsep;
 
-  if ( ISEC1_LocalFLag )
-    {
-      if      ( ISEC1_CenterID == 78  && isec1[36] == 253 ) // DWD local extension
-        varDefEnsembleInfo(varID, isec1[54], isec1[53], isec1[52]);
-      else if ( ISEC1_CenterID == 252 && isec1[36] ==   1 ) // MPIM local extension
-        varDefEnsembleInfo(varID, isec1[38], isec1[39], isec1[37]);
-    }
+  vlistID = streamptr->vlistID;
+  fileID  = streamptr->fileID;
+  tsID    = streamptr->curTsID;
+  vrecID  = streamptr->tsteps[tsID].curRecID;
+  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
+  recpos  = streamptr->tsteps[tsID].records[recID].position;
+  varID   = streamptr->tsteps[tsID].records[recID].varID;
 
-  if ( lmv ) varDefMissval(varID, FSEC3_MissVal);
+  fileSetPos(fileID, recpos, SEEK_SET);
 
-  if ( varInqInst(varID) == CDI_UNDEFID )
-    {
-      int center, subcenter, instID;
-      center    = ISEC1_CenterID;
-      subcenter = ISEC1_SubCenterID;
-      instID    = institutInq(center, subcenter, NULL, NULL);
-      if ( instID == CDI_UNDEFID )
-	instID = institutDef(center, subcenter, NULL, NULL);
-      varDefInst(varID, instID);
-    }
+  status = extRead(fileID, extp);
+  if ( status != 0 )
+    Error("Failed to read EXTRA record");
 
-  if ( varInqModel(varID) == CDI_UNDEFID )
-    {
-      int modelID;
-      modelID = modelInq(varInqInst(varID), ISEC1_ModelID, NULL);
-      if ( modelID == CDI_UNDEFID )
-	modelID = modelDef(varInqInst(varID), ISEC1_ModelID, NULL);
-      varDefModel(varID, modelID);
-    }
+  extInqHeader(extp, header);
+  extInqDataDP(extp, data);
 
-  if ( varInqTable(varID) == CDI_UNDEFID )
-    {
-      int tableID;
+  missval = vlistInqVarMissval(vlistID, varID);
+  gridID  = vlistInqVarGrid(vlistID, varID);
+  size    = gridInqSize(gridID);
 
-      tableID = tableInq(varInqModel(varID), ISEC1_CodeTable, NULL);
+  streamptr->numvals += size;
 
-      if ( tableID == CDI_UNDEFID )
-	tableID = tableDef(varInqModel(varID), ISEC1_CodeTable, NULL);
-      varDefTable(varID, tableID);
+  *nmiss = 0;
+  if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
+    {
+      for ( i = 0; i < size; i++ )
+	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
+	  {
+	    data[i] = missval;
+	    (*nmiss)++;
+	  }
+    }
+  else
+    {
+      for ( i = 0; i < 2*size; i+=2 )
+	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
+	  {
+	    data[i] = missval;
+	    (*nmiss)++;
+	  }
     }
-
-  streamptr->tsteps[tsID].nallrecs++;
-  streamptr->nrecs++;
 }
 
-static
-void MCH_get_undef(int *isec1, double *undef_pds, double *undef_eps)
+
+void extCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
 {
-  /* 2010-01-13: Oliver Fuhrer */
-  if ( ISEC1_CenterID == 215 ) {
-    if (isec1[34] != 0 && isec1[34] != 255) {
-      if (isec1[34] & 2) {
-        if (isec1[34] & 1) {
-          *undef_pds = -0.99*pow(10.0,-isec1[35]);
-        } else {
-          *undef_pds = +0.99*pow(10.0,-isec1[35]);
-        }
-        *undef_eps = pow(10.0,-isec1[35]-1);
-      } else {
-        if (isec1[34] & 1) {
-          *undef_pds = -0.99*pow(10.0,+isec1[35]);
-        } else {
-          *undef_pds = +0.99*pow(10.0,+isec1[35]);
-        }
-        *undef_eps = pow(10.0,isec1[35]-1);
-      }
-    }
-  }
+  streamFCopyRecord(streamptr2, streamptr1, "EXTRA");
 }
 
-static
-void cgribexDecodeHeader(int *isec0, int *isec1, int *isec2, double *fsec2,
-			 int *isec3, double *fsec3, int *isec4, double *fsec4,
-			 int *gribbuffer, int recsize, int *lmv, int *iret)
-{
-  int ipunp = 0, iword = 0;
 
-  memset(isec1, 0, 256*sizeof(int));
+void extDefRecord(stream_t *streamptr)
+{
+  int gridID;
+  int header[4];
+  int pdis, pcat, pnum;
+  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
 
-  gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, fsec4,
-	   ipunp, (int *) gribbuffer, recsize, &iword, "J", iret);
+  gridID   = streamptr->record->gridID;
 
-  *lmv = 0;
+  cdiDecodeParam(streamptr->record->param, &pnum, &pcat, &pdis);
+  header[0] = streamptr->record->date;
+  header[1] = pnum;
+  header[2] = streamptr->record->level;
+  header[3] = gridInqSize(gridID);
 
-  if ( ISEC1_CenterID == 215 && (isec1[34] != 0 && isec1[34] != 255) )
-    {
-      double undef_pds, undef_eps;
+  extDefDatatype(streamptr->record->prec, &extp->prec, &extp->number);
 
-      MCH_get_undef(isec1, &undef_pds, &undef_eps);
-      FSEC3_MissVal = undef_pds;
-      *lmv = 1;
-    }
+  extDefHeader(extp, header);
 }
 
-static
-compvar_t cgribexVarSet(int param, int level1, int level2, int leveltype, int trange)
-{
-  compvar_t compVar;
-  int tsteptype = cgribexGetTsteptype(trange);
 
-  compVar.param     = param;
-  compVar.level1    = level1;
-  compVar.level2    = level2;
-  compVar.ltype     = leveltype;
-  compVar.tsteptype = tsteptype;
+void extWriteRecord(stream_t *streamptr, const double *data)
+{
+  int fileID = streamptr->fileID;
+  void *extp = streamptr->record->exsep;
 
-  return (compVar);
+  extDefDataDP(extp, data);
+  extWrite(fileID, extp);
 }
 
-static inline int
-cgribexVarCompare(compvar_t compVar, record_t record, int flag)
+static
+void extAddRecord(stream_t *streamptr, int param, int level, int xysize,
+		  size_t recsize, off_t position, int prec, int number)
 {
-  int tstepDiff = (!((flag == 0) & (((compVar.tsteptype == TSTEP_INSTANT)
-                                     & (record.tsteptype == TSTEP_INSTANT3))
-                                    |((compVar.tsteptype == TSTEP_INSTANT3)
-                                      & (record.tsteptype == TSTEP_INSTANT)))))
-    & (compVar.tsteptype != record.tsteptype);
-  int rstatus = (compVar.param != record.param)
-    |           (compVar.level1 != record.ilevel)
-    |           (compVar.level2 != record.ilevel2)
-    |           (compVar.ltype != record.ltype)
-    |           tstepDiff;
-  return (rstatus);
-}
-#endif
+  int vlistID = streamptr->vlistID;
+  int tsID    = streamptr->curTsID;
+  int recID   = recordNewEntry(streamptr, tsID);
+  record_t *record  = &streamptr->tsteps[tsID].records[recID];
 
-#define gribWarning(text, nrecs, timestep, paramstr, level1, level2) \
-            Warning("Record %2d (id=%s lev1=%d lev2=%d) timestep %d: %s", nrecs, paramstr, level1, level2, timestep, text)
+  record->size     = recsize;
+  record->position = position;
+  record->param    = param;
+  record->ilevel   = level;
 
-#if  defined  (HAVE_LIBCGRIBEX)
+  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
+  grid_init(grid);
+  cdiGridTypeInit(grid, GRID_GENERIC, xysize);
+  grid->xsize = xysize;
+  grid->ysize = 0;
+  grid->xvals = NULL;
+  grid->yvals = NULL;
+  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  int gridID = gridAdded.Id;
+  if (!gridAdded.isNew) Free(grid);
+  /*
+  if ( level == 0 ) leveltype = ZAXIS_SURFACE;
+  else              leveltype = ZAXIS_GENERIC;
+  */
+  int leveltype = ZAXIS_GENERIC;
 
-static inline void
-cgribexScanTsFixNtsteps(stream_t *streamptr, off_t recpos)
-{
-  if ( streamptr->ntsteps == -1 )
-    {
-      int tsID = tstepsNewEntry(streamptr);
-      if ( tsID != streamptr->rtsteps )
-	Error("Internal error. tsID = %d", tsID);
+  int varID, levelID = 0;
+  varAddRecord(recID, param, gridID, leveltype, 0, level, 0, 0, 0,
+               extInqDatatype(prec, number), &varID, &levelID, TSTEP_INSTANT, 0, 0, -1,
+               NULL, NULL, NULL, NULL, NULL, NULL);
+  record->varID   = (short)varID;
+  record->levelID = (short)levelID;
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
-      streamptr->tsteps[tsID].position = recpos;
-    }
-}
+  streamptr->tsteps[tsID].nallrecs++;
+  streamptr->nrecs++;
 
-static inline void
-cgribexScanTsConstAdjust(stream_t *streamptr, taxis_t *taxis)
-{
-  int vlistID = streamptr->vlistID;
-  if ( streamptr->ntsteps == 1 )
-    {
-      if ( taxis->vdate == 0 && taxis->vtime == 0 )
-	{
-	  streamptr->ntsteps = 0;
-	  for (int varID = 0; varID < streamptr->nvars; varID++ )
-	    {
-	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-	    }
-	}
-    }
+  if ( CDI_Debug )
+    Message("varID = %d gridID = %d levelID = %d",
+	    varID, gridID, levelID);
 }
 
-
-int cgribexScanTimestep1(stream_t * streamptr)
+static
+void extScanTimestep1(stream_t *streamptr)
 {
-  double fsec2[512], fsec3[2], *fsec4 = NULL;
-  int lmv = 0, iret = 0;
-  off_t recpos = 0;
-  void *gribbuffer = NULL;
-  size_t buffersize = 0;
-  int rstatus;
+  int header[4];
+  int status;
+  int fileID;
+  int rxysize = 0;
   int param = 0;
-  int level1 = 0, level2 = 0, vdate = 0, vtime = 0;
-  DateTime datetime, datetime0 = { LONG_MIN, LONG_MIN };
-  size_t readsize;
-  unsigned nrecords, recID;
-  int nrecs_scanned = 0;
-  int datatype;
-  long recsize = 0;
-  int warn_time = TRUE;
-  int warn_numavg = TRUE;
+  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
+  DateTime datetime0 = { LONG_MIN, LONG_MIN };
+  int tsID;
+  int varID;
+  long recsize;
+  off_t recpos;
+  int nrecords, nrecs, recID;
   int taxisID = -1;
-  int rdate = 0, rtime = 0, tunit = 0, fcast = 0;
+  taxis_t *taxis;
   int vlistID;
-  int comptype;
-  long unzipsize;
-  char paramstr[32];
-  int nskip = cdiSkipRecords;
+  extcompvar_t compVar, compVar0;
+  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
 
   streamptr->curTsID = 0;
 
-  int *isec0 = streamptr->record->sec0;
-  int *isec1 = streamptr->record->sec1;
-  int *isec2 = streamptr->record->sec2;
-  int *isec3 = streamptr->record->sec3;
-  int *isec4 = streamptr->record->sec4;
-
-  int tsID  = tstepsNewEntry(streamptr);
-  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+  tsID  = tstepsNewEntry(streamptr);
+  taxis = &streamptr->tsteps[tsID].taxis;
 
   if ( tsID != 0 )
     Error("Internal problem! tstepsNewEntry returns %d", tsID);
 
-  int fileID = streamptr->fileID;
-
-  while ( nskip-- > 0 )
-    {
-      recsize = gribGetSize(fileID);
-      if ( recsize == 0 )
-	Error("Skipping of %d records failed!", cdiSkipRecords);
-
-      recpos  = fileGetPos(fileID);
-      fileSetPos(fileID, (off_t)recsize, SEEK_CUR);
-    }
+  fileID = streamptr->fileID;
 
-  unsigned nrecs = 0;
+  nrecs = 0;
   while ( TRUE )
     {
-      recsize = gribGetSize(fileID);
-      recpos  = fileGetPos(fileID);
-
-      if ( recsize == 0 )
+      recpos = fileGetPos(fileID);
+      status = extRead(fileID, extp);
+      if ( status != 0 )
 	{
-	  if ( nrecs == 0 )
-	    Error("No GRIB records found!");
-
 	  streamptr->ntsteps = 1;
 	  break;
 	}
-      if ( (size_t)recsize > buffersize )
-	{
-	  buffersize = (size_t)recsize;
-	  gribbuffer = Realloc(gribbuffer, buffersize);
-	}
-
-      readsize = (size_t)recsize;
-      rstatus = gribRead(fileID, (unsigned char *)gribbuffer, &readsize);
-      if ( rstatus ) break;
-
-      comptype = COMPRESS_NONE;
-      if ( gribGetZip(recsize, (unsigned char *)gribbuffer, &unzipsize) > 0 )
-	{
-	  comptype = COMPRESS_SZIP;
-	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
-	  if ( buffersize < (size_t)unzipsize )
-	    {
-	      buffersize = (size_t)unzipsize;
-	      gribbuffer = Realloc(gribbuffer, buffersize);
-	    }
-	}
-
-      nrecs_scanned++;
-      cgribexDecodeHeader(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, fsec4,
-			  (int *) gribbuffer, (int)recsize, &lmv, &iret);
-
-      param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
-      cdiParamToString(param, paramstr, sizeof(paramstr));
+      recsize = fileGetPos(fileID) - recpos;
 
-      if ( ISEC1_LevelType == 100 ) ISEC1_Level1 *= 100;
-      if ( ISEC1_LevelType ==  99 ) ISEC1_LevelType = 100;
-      level1   = ISEC1_Level1;
-      level2   = ISEC1_Level2;
+      extInqHeader(extp, header);
 
-      gribDateTime(isec1, &vdate, &vtime);
+      vdate   = header[0];
+      vtime   = 0;
+      rcode   = header[1];
+      rlevel  = header[2];
+      rxysize = header[3];
 
-      if ( ISEC4_NumBits > 0 && ISEC4_NumBits <= 32 )
-	datatype = ISEC4_NumBits;
-      else
-        datatype = DATATYPE_PACK;
+      param = cdiEncodeParam(rcode, 255, 255);
 
       if ( nrecs == 0 )
 	{
 	  datetime0.date = vdate;
 	  datetime0.time = vtime;
-	  rdate = gribRefDate(isec1);
-	  rtime = gribRefTime(isec1);
-	  tunit = cgribexGetTimeUnit(isec1);
-	  fcast = cgribexTimeIsFC(isec1);
 	}
       else
 	{
-	  datetime.date  = vdate;
-	  datetime.time  = vtime;
-	  compvar_t compVar = cgribexVarSet(param, level1, level2, ISEC1_LevelType, ISEC1_TimeRange);
-	  for ( recID = 0; recID < nrecs; recID++ )
-	    {
-	      if ( cgribexVarCompare(compVar, streamptr->tsteps[0].records[recID], 0) == 0 ) break;
-	    }
-
-	  if ( cdiInventoryMode == 1 )
-	    {
-	      if ( recID < nrecs ) break;
-	      if ( warn_time )
-		if ( datetimeCmp(datetime, datetime0) != 0 )
-		  {
-                    gribWarning("Inconsistent verification time!", nrecs_scanned, tsID+1, paramstr, level1, level2);
-		    warn_time = FALSE;
-		  }
-	    }
-	  else
-	    {
-	      if ( datetimeCmp(datetime, datetime0) != 0 ) break;
-
-	      if ( recID < nrecs )
-		{
-		  gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, paramstr, level1, level2);
-		  continue;
-		}
-	    }
-	}
-
-      if ( ISEC1_AvgNum )
-	{
-	  if (  taxis->numavg && warn_numavg && (taxis->numavg != ISEC1_AvgNum) )
-	    {
-	      Warning("Changing numavg from %d to %d not supported!", taxis->numavg, ISEC1_AvgNum);
-	      warn_numavg = FALSE;
-	    }
-	  else
+	  compVar.param = param;
+          compVar.level = rlevel;
+	  for ( recID = 0; recID < nrecs; recID++ )
 	    {
-	      taxis->numavg = ISEC1_AvgNum;
+	      compVar0.param  = streamptr->tsteps[0].records[recID].param;
+	      compVar0.level = streamptr->tsteps[0].records[recID].ilevel;
+
+	      if ( memcmp(&compVar0, &compVar, sizeof(extcompvar_t)) == 0 ) break;
 	    }
+	  if ( recID < nrecs ) break;
+	  DateTime datetime = { .date = vdate, .time = vtime};
+	  if ( datetimeCmp(datetime, datetime0) )
+	    Warning("Inconsistent verification time for code %d level %d", rcode, rlevel);
 	}
 
       nrecs++;
 
       if ( CDI_Debug )
-	Message("Read record %2d (id=%s lev1=%d lev2=%d) %8d %6d", nrecs_scanned, paramstr, level1, level2, vdate, vtime);
+	Message("%4d%8d%4d%8d%8d%6d", nrecs, (int)recpos, rcode, rlevel, vdate, vtime);
 
-      cgribexAddRecord(streamptr, param, isec1, isec2, fsec2, fsec3,
-		       isec4, recsize, recpos, datatype, comptype, lmv, iret);
+      extAddRecord(streamptr, param, rlevel, rxysize, (size_t)recsize, recpos, extp->prec, extp->number);
     }
 
   streamptr->rtsteps = 1;
 
-  if ( nrecs == 0 ) return (CDI_EUFSTRUCT);
-
   cdi_generate_vars(streamptr);
 
-  if ( fcast )
-    {
-      taxisID = taxisCreate(TAXIS_RELATIVE);
-      taxis->type  = TAXIS_RELATIVE;
-      taxis->rdate = rdate;
-      taxis->rtime = rtime;
-      taxis->unit  = tunit;
-    }
-  else
-    {
-      taxisID = taxisCreate(TAXIS_ABSOLUTE);
-      taxis->type  = TAXIS_ABSOLUTE;
-      taxis->unit  = tunit;
-    }
-
+  taxisID = taxisCreate(TAXIS_ABSOLUTE);
+  taxis->type  = TAXIS_ABSOLUTE;
   taxis->vdate = (int)datetime0.date;
   taxis->vtime = (int)datetime0.time;
 
   vlistID = streamptr->vlistID;
   vlistDefTaxis(vlistID, taxisID);
 
-  nrecords = (unsigned)streamptr->tsteps[0].nallrecs;
-  if ( nrecords < (unsigned)streamptr->tsteps[0].recordSize )
+  vlist_check_contents(vlistID);
+
+  nrecords = streamptr->tsteps[0].nallrecs;
+  if ( nrecords < streamptr->tsteps[0].recordSize )
     {
-      streamptr->tsteps[0].recordSize = (int)nrecords;
+      streamptr->tsteps[0].recordSize = nrecords;
       streamptr->tsteps[0].records =
-      (record_t *) Realloc(streamptr->tsteps[0].records, nrecords*sizeof(record_t));
+        (record_t *) Realloc(streamptr->tsteps[0].records, (size_t)nrecords * sizeof (record_t));
     }
 
-  streamptr->tsteps[0].recIDs = (int *) Malloc(nrecords*sizeof(int));
-  streamptr->tsteps[0].nrecs = (int)nrecords;
+  streamptr->tsteps[0].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
+  streamptr->tsteps[0].nrecs = nrecords;
   for ( recID = 0; recID < nrecords; recID++ )
-    streamptr->tsteps[0].recIDs[recID] = (int)recID;
+    streamptr->tsteps[0].recIDs[recID] = recID;
 
-  streamptr->record->buffer     = gribbuffer;
-  streamptr->record->buffersize = (size_t)buffersize;
+  if ( streamptr->ntsteps == -1 )
+    {
+      tsID = tstepsNewEntry(streamptr);
+      if ( tsID != streamptr->rtsteps )
+	Error("Internal error. tsID = %d", tsID);
 
-  cgribexScanTsFixNtsteps(streamptr, recpos);
-  cgribexScanTsConstAdjust(streamptr, taxis);
+      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID].position = recpos;
+    }
 
-  return (0);
+  if ( streamptr->ntsteps == 1 )
+    {
+      if ( taxis->vdate == 0 && taxis->vtime == 0 )
+	{
+	  streamptr->ntsteps = 0;
+	  for ( varID = 0; varID < streamptr->nvars; varID++ )
+	    {
+	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	    }
+	}
+    }
 }
 
-
-int cgribexScanTimestep2(stream_t * streamptr)
+static
+int extScanTimestep2(stream_t *streamptr)
 {
-  int rstatus = 0;
-  double fsec2[512], fsec3[2], *fsec4 = NULL;
-  int lmv = 0, iret = 0;
-  off_t recpos = 0;
+  int header[4];
+  int status;
+  int fileID;
+  // int rxysize = 0;
   int param = 0;
-  int level1 = 0, level2 = 0, vdate = 0, vtime = 0;
-  DateTime datetime, datetime0 = { LONG_MIN, LONG_MIN };
-  int varID, gridID;
-  size_t readsize;
-  int nrecs, recID;
-  long recsize = 0;
-  int warn_numavg = TRUE;
-  int tsteptype;
-  long unzipsize;
-  char paramstr[32];
+  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
+  int tsID;
+  int varID;
+  off_t recpos = 0;
+  int nrecords, nrecs, recID, rindex;
+  int nextstep;
+  taxis_t *taxis;
+  int vlistID;
+  extcompvar_t compVar, compVar0;
+  void *extp = streamptr->record->exsep;
 
   streamptr->curTsID = 1;
 
-  int *isec0 = streamptr->record->sec0;
-  int *isec1 = streamptr->record->sec1;
-  int *isec2 = streamptr->record->sec2;
-  int *isec3 = streamptr->record->sec3;
-  int *isec4 = streamptr->record->sec4;
-
-  int fileID  = streamptr->fileID;
-  int vlistID = streamptr->vlistID;
-  int taxisID = vlistInqTaxis(vlistID);
-
-  void *gribbuffer = streamptr->record->buffer;
-  size_t buffersize = streamptr->record->buffersize;
+  fileID  = streamptr->fileID;
+  vlistID = streamptr->vlistID;
 
-  int tsID = streamptr->rtsteps;
+  tsID = streamptr->rtsteps;
   if ( tsID != 1 )
     Error("Internal problem! unexpected timestep %d", tsID+1);
 
-  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+  taxis = &streamptr->tsteps[tsID].taxis;
 
   fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
   cdi_create_records(streamptr, tsID);
 
-  int nrecords = streamptr->tsteps[tsID].nallrecs;
-  if ( nrecords ) streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords * sizeof(int));
+  nrecords = streamptr->tsteps[0].nallrecs;
+  streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
   streamptr->tsteps[1].nrecs = 0;
   for ( recID = 0; recID < nrecords; recID++ )
     streamptr->tsteps[1].recIDs[recID] = -1;
@@ -46709,168 +47717,88 @@ int cgribexScanTimestep2(stream_t * streamptr)
   for ( recID = 0; recID < nrecords; recID++ )
     {
       varID = streamptr->tsteps[0].records[recID].varID;
-      streamptr->tsteps[tsID].records[recID].position =	streamptr->tsteps[0].records[recID].position;
-      streamptr->tsteps[tsID].records[recID].size     =	streamptr->tsteps[0].records[recID].size;
+      streamptr->tsteps[tsID].records[recID].position =
+	streamptr->tsteps[0].records[recID].position;
+      streamptr->tsteps[tsID].records[recID].size     =
+	streamptr->tsteps[0].records[recID].size;
     }
 
-  int nrecs_scanned = nrecords;
-  int rindex = 0;
-  while ( TRUE )
+  for ( rindex = 0; rindex <= nrecords; rindex++ )
     {
-      if ( rindex > nrecords ) break;
-
-      recsize = gribGetSize(fileID);
-      recpos  = fileGetPos(fileID);
-      if ( recsize == 0 )
+      recpos = fileGetPos(fileID);
+      status = extRead(fileID, extp);
+      if ( status != 0 )
 	{
 	  streamptr->ntsteps = 2;
 	  break;
 	}
-      if ( (size_t)recsize > buffersize )
-	{
-	  buffersize = (size_t)recsize;
-	  gribbuffer = Realloc(gribbuffer, buffersize);
-	}
-
-      readsize = (size_t)recsize;
-      rstatus = gribRead(fileID, (unsigned char *)gribbuffer, &readsize);
-      if ( rstatus ) break;
-
-      if ( gribGetZip(recsize, (unsigned char *)gribbuffer, &unzipsize) > 0 )
-	{
-	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
-	  if ( buffersize < (size_t)unzipsize )
-	    {
-	      buffersize = (size_t)unzipsize;
-	      gribbuffer = Realloc(gribbuffer, buffersize);
-	    }
-	}
-
-      cgribexDecodeHeader(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, fsec4,
-			  (int *) gribbuffer, (int)recsize, &lmv, &iret);
-
-      nrecs_scanned++;
+      size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
 
-      param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
-      cdiParamToString(param, paramstr, sizeof(paramstr));
+      extInqHeader(extp, header);
 
-      if ( ISEC1_LevelType == 100 ) ISEC1_Level1 *= 100;
-      if ( ISEC1_LevelType ==  99 ) ISEC1_LevelType = 100;
-      level1    = ISEC1_Level1;
-      level2    = ISEC1_Level2;
+      vdate  = header[0];
+      vtime  = 0;
+      rcode  = header[1];
+      rlevel = header[2];
+      // rxysize = header[3];
 
-      gribDateTime(isec1, &vdate, &vtime);
+      param = cdiEncodeParam(rcode, 255, 255);
 
       if ( rindex == 0 )
 	{
-	  if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
-	    {
-	      taxis->type  = TAXIS_RELATIVE;
-	      taxis->rdate = gribRefDate(isec1);
-	      taxis->rtime = gribRefTime(isec1);
-	    }
-	  else
-	    {
-	      taxis->type  = TAXIS_ABSOLUTE;
-	    }
-	  taxis->unit  = cgribexGetTimeUnit(isec1);
+	  taxis->type  = TAXIS_ABSOLUTE;
 	  taxis->vdate = vdate;
 	  taxis->vtime = vtime;
-
-	  datetime0.date = vdate;
-	  datetime0.time = vtime;
-	}
-
-      tsteptype = cgribexGetTsteptype(ISEC1_TimeRange);
-
-      if ( ISEC1_AvgNum )
-	{
-	  if (  taxis->numavg && warn_numavg &&
-        	(taxis->numavg != ISEC1_AvgNum) )
-	    {
-	  /*
-	      Warning("Changing numavg from %d to %d not supported!", taxis->numavg, ISEC1_AvgNum);
-	  */
-	      warn_numavg = FALSE;
-	    }
-	  else
-	    {
-	      taxis->numavg = ISEC1_AvgNum;
-	    }
 	}
 
-      datetime.date  = vdate;
-      datetime.time  = vtime;
-
-      compvar_t compVar = cgribexVarSet(param, level1, level2, ISEC1_LevelType, ISEC1_TimeRange);
-
+      compVar.param = param;
+      compVar.level = rlevel;
+      nextstep = FALSE;
       for ( recID = 0; recID < nrecords; recID++ )
 	{
-	  if ( cgribexVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) == 0 ) break;
-	}
-
-      if ( recID == nrecords )
-	{
-	  gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, paramstr, level1, level2);
-	  return (CDI_EUFSTRUCT);
-	}
+	  compVar0.param = streamptr->tsteps[tsID].records[recID].param;
+	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
 
-      if ( cdiInventoryMode == 1 )
-	{
-	  if ( streamptr->tsteps[tsID].records[recID].used )
+	  if ( memcmp(&compVar0, &compVar, sizeof(extcompvar_t)) == 0 )
 	    {
+	      if ( streamptr->tsteps[tsID].records[recID].used )
+		{
+		  nextstep = TRUE;
+		}
+	      else
+		{
+		  streamptr->tsteps[tsID].records[recID].used = TRUE;
+		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
+		}
 	      break;
 	    }
-	  else
-	    {
-	      streamptr->tsteps[tsID].records[recID].used = TRUE;
-	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
-	    }
 	}
-      else
+      if ( recID == nrecords )
 	{
-	  if ( streamptr->tsteps[tsID].records[recID].used )
-	    {
-	      if ( datetimeCmp(datetime, datetime0) != 0 ) break;
-
-              gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, paramstr, level1, level2);
-	      continue;
-	    }
-	  else
-	    {
-	      streamptr->tsteps[tsID].records[recID].used = TRUE;
-	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
-	    }
+	  Warning("Code %d level %d not found at timestep %d", rcode, rlevel, tsID+1);
+	  return (CDI_EUFSTRUCT);
 	}
 
+      if ( nextstep ) break;
+
       if ( CDI_Debug )
-	Message("Read record %2d (id=%s lev1=%d lev2=%d) %8d %6d", nrecs_scanned, paramstr, level1, level2, vdate, vtime);
+	Message("%4d%8d%4d%8d%8d%6d", rindex+1, (int)recpos, rcode, rlevel, vdate, vtime);
 
-      streamptr->tsteps[tsID].records[recID].size = (size_t)recsize;
+      streamptr->tsteps[tsID].records[recID].size = recsize;
 
-      if ( cgribexVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) != 0 )
+      compVar0.param  = streamptr->tsteps[tsID].records[recID].param;
+      compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+
+      if ( memcmp(&compVar0, &compVar, sizeof(extcompvar_t)) != 0 )
 	{
 	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
 		  tsID, recID,
 		  streamptr->tsteps[tsID].records[recID].param, param,
-		  streamptr->tsteps[tsID].records[recID].ilevel, level1);
+		  streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
 	  return (CDI_EUFSTRUCT);
 	}
 
       streamptr->tsteps[1].records[recID].position = recpos;
-      varID = streamptr->tsteps[tsID].records[recID].varID;
-      gridID = vlistInqVarGrid(vlistID, varID);
-      if ( gridInqSize(gridID) == 1 && gridInqType(gridID) == GRID_LONLAT )
-	{
-	  if ( IS_NOT_EQUAL(gridInqXval(gridID, 0),ISEC2_FirstLon*0.001) ||
-	       IS_NOT_EQUAL(gridInqYval(gridID, 0),ISEC2_FirstLat*0.001) )
-	    gridChangeType(gridID, GRID_TRAJECTORY);
-	}
-
-      if ( tsteptype != vlistInqVarTsteptype(vlistID, varID) )
-	vlistDefVarTsteptype(vlistID, varID, tsteptype);
-
-      rindex++;
     }
 
   nrecs = 0;
@@ -46890,39 +47818,52 @@ int cgribexScanTimestep2(stream_t * streamptr)
 
   streamptr->rtsteps = 2;
 
-  cgribexScanTsFixNtsteps(streamptr, recpos);
+  if ( streamptr->ntsteps == -1 )
+    {
+      tsID = tstepsNewEntry(streamptr);
+      if ( tsID != streamptr->rtsteps )
+	Error("Internal error. tsID = %d", tsID);
 
-  streamptr->record->buffer     = gribbuffer;
-  streamptr->record->buffersize = buffersize;
+      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID].position = recpos;
+    }
 
-  return (rstatus);
+  return (0);
 }
-#endif
 
 
-#if  defined  (HAVE_LIBCGRIBEX)
-int cgribexScanTimestep(stream_t * streamptr)
+int extInqContents(stream_t *streamptr)
 {
-  int rstatus = 0;
-  double fsec2[512], fsec3[2], *fsec4 = NULL;
-  int lmv = 0, iret = 0;
-  long recsize = 0;
-  off_t recpos = 0;
-  void *gribbuffer;
-  size_t buffersize = 0;
   int fileID;
+  int status = 0;
+
+  fileID = streamptr->fileID;
+
+  streamptr->curTsID = 0;
+
+  extScanTimestep1(streamptr);
+
+  if ( streamptr->ntsteps == -1 ) status = extScanTimestep2(streamptr);
+
+  fileSetPos(fileID, 0, SEEK_SET);
+
+  return (status);
+}
+
+static
+long extScanTimestep(stream_t *streamptr)
+{
+  int header[4];
+  int status;
+  int fileID;
+  // int rxysize = 0;
   int param = 0;
-  int level1 = 0, level2 = 0, vdate = 0, vtime = 0;
-  DateTime datetime, datetime0 = { LONG_MIN, LONG_MIN };
-  int vrecID, recID;
-  int warn_numavg = TRUE;
-  size_t readsize;
-  int taxisID = -1;
+  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
+  off_t recpos = 0;
+  int recID;
   int rindex, nrecs = 0;
-  int nrecs_scanned;
-  long unzipsize;
-  char paramstr[32];
-
+  extcompvar_t compVar, compVar0;
+  void *extp = streamptr->record->exsep;
   /*
   if ( CDI_Debug )
     {
@@ -46932,20 +47873,12 @@ int cgribexScanTimestep(stream_t * streamptr)
       Message("nts = %d", streamptr->ntsteps);
     }
   */
-  int *isec0 = streamptr->record->sec0;
-  int *isec1 = streamptr->record->sec1;
-  int *isec2 = streamptr->record->sec2;
-  int *isec3 = streamptr->record->sec3;
-  int *isec4 = streamptr->record->sec4;
 
   int tsID  = streamptr->rtsteps;
   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
   if ( streamptr->tsteps[tsID].recordSize == 0 )
     {
-      gribbuffer = streamptr->record->buffer;
-      buffersize = streamptr->record->buffersize;
-
       cdi_create_records(streamptr, tsID);
 
       nrecs = streamptr->tsteps[1].nrecs;
@@ -46959,178 +47892,57 @@ int cgribexScanTimestep(stream_t * streamptr)
 
       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
-      nrecs_scanned = streamptr->tsteps[0].nallrecs + streamptr->tsteps[1].nrecs*(tsID-1);
-      rindex = 0;
-      while ( TRUE )
+      for ( rindex = 0; rindex <= nrecs; rindex++ )
 	{
-	  if ( rindex > nrecs ) break;
-
-	  recsize = gribGetSize(fileID);
-	  recpos  = fileGetPos(fileID);
-	  if ( recsize == 0 )
+	  recpos = fileGetPos(fileID);
+	  status = extRead(fileID, extp);
+	  if ( status != 0 )
 	    {
 	      streamptr->ntsteps = streamptr->rtsteps + 1;
 	      break;
 	    }
-	  if ( recsize > 0 && (size_t)recsize > buffersize )
-	    {
-	      buffersize = (size_t)recsize;
-	      gribbuffer = Realloc(gribbuffer, buffersize);
-	    }
-
-	  if ( rindex >= nrecs ) break;
-
-	  readsize = (size_t)recsize;
-	  rstatus = gribRead(fileID, (unsigned char *)gribbuffer, &readsize);
-	  if ( rstatus )
-	    {
-	      Warning("Inconsistent timestep %d (GRIB record %d/%d)!", tsID+1, rindex+1,
-                      streamptr->tsteps[tsID].recordSize);
-	      break;
-	    }
-
-	  if ( gribGetZip(recsize, (unsigned char *)gribbuffer, &unzipsize) > 0 )
-	    {
-	      unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
-	      if ( buffersize < (size_t)unzipsize )
-		{
-		  buffersize = (size_t)unzipsize;
-		  gribbuffer = Realloc(gribbuffer, buffersize);
-		}
-	    }
-
-	  cgribexDecodeHeader(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, fsec4,
-			      (int *) gribbuffer, (int)recsize, &lmv, &iret);
-
-          nrecs_scanned++;
+	  size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
 
-	  param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
-          cdiParamToString(param, paramstr, sizeof(paramstr));
+	  extInqHeader(extp, header);
 
-	  if ( ISEC1_LevelType == 100 ) ISEC1_Level1 *= 100;
-	  if ( ISEC1_LevelType ==  99 ) ISEC1_LevelType = 100;
-	  level1   = ISEC1_Level1;
-	  level2   = ISEC1_Level2;
+	  vdate  = header[0];
+	  vtime  = 0;
+	  rcode  = header[1];
+	  rlevel = header[2];
+	  // rxysize = header[3];
 
-	  gribDateTime(isec1, &vdate, &vtime);
+	  param = cdiEncodeParam(rcode, 255, 255);
 
-	  if ( rindex == nrecs ) break;
+	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
+	  if ( rindex == nrecs ) continue;
+	  recID = streamptr->tsteps[tsID].recIDs[rindex];
 
 	  if ( rindex == 0 )
 	    {
-              int vlistID = streamptr->vlistID;
-	      taxisID = vlistInqTaxis(vlistID);
-	      if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
-		{
-		  taxis->type  = TAXIS_RELATIVE;
-		  taxis->rdate = gribRefDate(isec1);
-		  taxis->rtime = gribRefTime(isec1);
-		}
-	      else
-		{
-		  taxis->type  = TAXIS_ABSOLUTE;
-		}
-	      taxis->unit  = cgribexGetTimeUnit(isec1);
+	      taxis->type  = TAXIS_ABSOLUTE;
 	      taxis->vdate = vdate;
 	      taxis->vtime = vtime;
-
-	      datetime0.date = vdate;
-	      datetime0.time = vtime;
-	    }
-
-	  if ( ISEC1_AvgNum )
-	    {
-	      if (  taxis->numavg && warn_numavg &&
-		   (taxis->numavg != ISEC1_AvgNum) )
-		{
-	      /*
-	          Warning("Changing numavg from %d to %d not supported!", streamptr->tsteps[tsID].taxis.numavg, ISEC1_AvgNum);
-	      */
-		  warn_numavg = FALSE;
-		}
-	      else
-		{
-		  taxis->numavg = ISEC1_AvgNum;
-		}
-	    }
-
-	  datetime.date  = vdate;
-	  datetime.time  = vtime;
-
-	  compvar_t compVar = cgribexVarSet(param, level1, level2, ISEC1_LevelType, ISEC1_TimeRange);
-
-	  for ( vrecID = 0; vrecID < nrecs; vrecID++ )
-	    {
-	      recID   = streamptr->tsteps[1].recIDs[vrecID];
-	      if ( cgribexVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) == 0 ) break;
-	    }
-
-	  if ( vrecID == nrecs )
-	    {
-	      gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, paramstr, level1, level2);
-
-	      if ( cdiInventoryMode == 1 )
-		return (CDI_EUFSTRUCT);
-	      else
-		continue;
-	    }
-
-	  if ( cdiInventoryMode == 1 )
-	    {
-	      streamptr->tsteps[tsID].records[recID].used = TRUE;
-	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
-	    }
-	  else
-	    {
-	      if ( streamptr->tsteps[tsID].records[recID].used )
-		{
-		  char paramstr_[32];
-		  cdiParamToString(param, paramstr_, sizeof(paramstr_));
-
-		  if ( datetimeCmp(datetime, datetime0) != 0 ) break;
-
-		  if ( CDI_Debug )
-                    gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, paramstr_, level1, level2);
-
-		  continue;
-		}
-	      else
-		{
-		  streamptr->tsteps[tsID].records[recID].used = TRUE;
-		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
-		}
 	    }
 
-	  if ( CDI_Debug )
-            Message("Read record %2d (id=%s lev1=%d lev2=%d) %8d %6d", nrecs_scanned, paramstr, level1, level2, vdate, vtime);
-
-	  if ( cgribexVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) != 0 )
+	  compVar.param  = param;
+          compVar.level  = rlevel;
+	  compVar0.param = streamptr->tsteps[tsID].records[recID].param;
+	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+
+	  if ( memcmp(&compVar0, &compVar, sizeof(extcompvar_t)) != 0 )
 	    {
 	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
 		      tsID, recID,
 		      streamptr->tsteps[tsID].records[recID].param, param,
-		      streamptr->tsteps[tsID].records[recID].ilevel, level1);
-	      Error("Invalid, unsupported or inconsistent record structure");
+		      streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
+	      Error("Invalid, unsupported or inconsistent record structure!");
 	    }
 
 	  streamptr->tsteps[tsID].records[recID].position = recpos;
-	  streamptr->tsteps[tsID].records[recID].size = (size_t)recsize;
-
-	  rindex++;
-	}
-
-      for ( vrecID = 0; vrecID < nrecs; vrecID++ )
-	{
-	  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-	  if ( ! streamptr->tsteps[tsID].records[recID].used ) break;
-	}
+	  streamptr->tsteps[tsID].records[recID].size = recsize;
 
-      if ( vrecID < nrecs )
-	{
-	  cdiParamToString(streamptr->tsteps[tsID].records[recID].param, paramstr, sizeof(paramstr));
-	  gribWarning("Paramameter not found!", nrecs_scanned, tsID+1, paramstr,
-                      streamptr->tsteps[tsID].records[recID].ilevel, streamptr->tsteps[tsID].records[recID].ilevel2);
-	  return (CDI_EUFSTRUCT);
+	  if ( CDI_Debug )
+	    Message("%4d%8d%4d%8d%8d%6d", rindex, (int)recpos, rcode, rlevel, vdate, vtime);
 	}
 
       streamptr->rtsteps++;
@@ -47147,9 +47959,6 @@ int cgribexScanTimestep(stream_t * streamptr)
 
       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
       streamptr->tsteps[tsID].position = recpos;
-
-      streamptr->record->buffer     = gribbuffer;
-      streamptr->record->buffersize = buffersize;
     }
 
   if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
@@ -47158,933 +47967,635 @@ int cgribexScanTimestep(stream_t * streamptr)
       streamptr->ntsteps = tsID;
     }
 
-  rstatus = (int)streamptr->ntsteps;
-
-  return (rstatus);
+  return (streamptr->ntsteps);
 }
-#endif
 
-#ifdef gribWarning
-#undef gribWarning
-#endif
 
-#if  defined  (HAVE_LIBCGRIBEX)
-int cgribexDecode(unsigned char *gribbuffer, int gribsize, double *data, int gridsize,
-		  int unreduced, int *nmiss, double missval)
+int extInqTimestep(stream_t *streamptr, int tsID)
 {
-  int status = 0;
-  int iret = 0, iword = 0;
-  int isec0[2], isec1[4096], isec2[4096], isec3[2], isec4[512];
-  double fsec2[512], fsec3[2];
-  char hoper[2];
-
-  if ( unreduced ) strcpy(hoper, "R");
-  else             strcpy(hoper, "D");
-
-  FSEC3_MissVal = missval;
-
-  gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, data,
-	   gridsize, (int *)(void *)gribbuffer, gribsize, &iword, hoper, &iret);
-
-  if ( ISEC1_Sec2Or3Flag & 64 )
-    *nmiss = ISEC4_NumValues - ISEC4_NumNonMissValues;
-  else
-    *nmiss = 0;
-
-  if ( ISEC1_CenterID == 215 && (isec1[34] != 0 && isec1[34] != 255) )
-    {
-      double undef_pds, undef_eps;
-      int i;
-
-      MCH_get_undef(isec1, &undef_pds, &undef_eps);
-
-      *nmiss = 0;
-      for ( i = 0; i < gridsize; i++ )
-        if ( (fabs(data[i]-undef_pds) < undef_eps) || IS_EQUAL(data[i],FSEC3_MissVal) ) {
-          data[i] = missval;
-          (*nmiss)++;
-        }
-    }
-
-  return (status);
-}
-#endif
+  int nrecs;
+  long ntsteps;
 
+  if ( tsID == 0 && streamptr->rtsteps == 0 )
+    Error("Call to cdiInqContents missing!");
 
-#if  defined  (HAVE_LIBCGRIBEX)
-static
-void cgribexDefInstitut(int *isec1, int vlistID, int varID)
-{
-  int instID;
+  if ( CDI_Debug )
+    Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
 
-  if ( vlistInqInstitut(vlistID) != CDI_UNDEFID )
-    instID = vlistInqInstitut(vlistID);
-  else
-    instID = vlistInqVarInstitut(vlistID, varID);
+  ntsteps = UNDEFID;
+  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == UNDEFID )
+    ntsteps = extScanTimestep(streamptr);
 
-  if ( instID != CDI_UNDEFID )
+  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
     {
-      int center, subcenter;
-      center    = institutInqCenter(instID);
-      subcenter = institutInqSubcenter(instID);
-      ISEC1_CenterID    = center;
-      ISEC1_SubCenterID = subcenter;
+      nrecs = 0;
     }
-}
-
-static
-void cgribexDefModel(int *isec1, int vlistID, int varID)
-{
-  int modelID;
-
-  if ( vlistInqModel(vlistID) != CDI_UNDEFID )
-    modelID = vlistInqModel(vlistID);
   else
-    modelID = vlistInqVarModel(vlistID, varID);
-
-  if ( modelID != CDI_UNDEFID )
-    ISEC1_ModelID = modelInqGribID(modelID);
-}
-
-static
-void cgribexDefParam(int *isec1, int param)
-{
-  int pdis, pcat, pnum;
-
-  cdiDecodeParam(param, &pnum, &pcat, &pdis);
-
-  if ( pnum < 0 ) pnum = -pnum;
-
-  static bool lwarn_pdis = true;
-  if ( pdis != 255 && lwarn_pdis )
     {
-      char paramstr[32];
-      cdiParamToString(param, paramstr, sizeof(paramstr));
-      Warning("Can't convert GRIB2 parameter ID (%s) to GRIB1, set to %d.%d!", paramstr, pnum, pcat);
-      lwarn_pdis = false;
-    }
-
-  static bool lwarn_pnum = true;
-  if ( pnum > 255 && lwarn_pnum )
-    {
-      Warning("Parameter number %d out of range (1-255), set to %d!", pnum, pnum%256);
-      lwarn_pnum = false;
-      pnum = pnum%256;
+      streamptr->curTsID = tsID;
+      nrecs = streamptr->tsteps[tsID].nrecs;
     }
 
-  ISEC1_CodeTable = pcat;
-  ISEC1_Parameter = pnum;
+  return (nrecs);
 }
 
-static
-int cgribexDefTimerange(int tsteptype, int factor, int calendar,
-			int rdate, int rtime, int vdate, int vtime, int *pip1, int *pip2)
-{
-  int timerange = -1;
-  int year, month, day, hour, minute, second;
-  int julday1, secofday1, julday2, secofday2, days, secs;
-  int ip, ip1 = 0, ip2 = 0;
-
-  cdiDecodeDate(rdate, &year, &month, &day);
-  cdiDecodeTime(rtime, &hour, &minute, &second);
-  encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday1, &secofday1);
-
-  cdiDecodeDate(vdate, &year, &month, &day);
-  cdiDecodeTime(vtime, &hour, &minute, &second);
-  encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday2, &secofday2);
-
-  (void) julday_sub(julday1, secofday1, julday2, secofday2, &days, &secs);
-
-  if ( !(int)(fmod(days*86400.0 + secs, factor)) )
-    {
-      ip = (int) ((days*86400.0 + secs)/factor);
-
-      switch ( tsteptype )
-	{
-	case TSTEP_INSTANT:  timerange =  0; ip1 = ip; ip2 = 0;  break;
-	case TSTEP_INSTANT2: timerange =  1; ip1 = 0;  ip2 = 0;  break;
-	case TSTEP_RANGE:    timerange =  2; ip1 = 0;  ip2 = ip; break;
-	case TSTEP_AVG:      timerange =  3; ip1 = 0;  ip2 = ip; break;
-	case TSTEP_ACCUM:    timerange =  4; ip1 = 0;  ip2 = ip; break;
-	case TSTEP_DIFF:     timerange =  5; ip1 = 0;  ip2 = ip; break;
-	case TSTEP_INSTANT3:
-	default:             timerange = 10; ip1 = ip/256; ip2 = ip%256;  break;
-	}
-    }
-
-  *pip1 = ip1;
-  *pip2 = ip2;
-
-  return (timerange);
-}
 
-static
-int cgribexDefDateTime(int *isec1, int timeunit, int date, int time)
+void extReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
 {
-  int year, month, day, hour, minute, second;
-  int century = 0;
-  int factor = 1;
+  int vlistID, fileID;
+  int levID, nlevs, gridID, gridsize;
+  off_t recpos, currentfilepos;
+  int header[4];
+  int tsid;
+  int recID;
+  int i;
+  double missval;
+  void *extp = streamptr->record->exsep;
 
-  cdiDecodeDate(date, &year, &month, &day);
-  cdiDecodeTime(time, &hour, &minute, &second);
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  /* NOTE: tiles are not supported here! */
+  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
+  missval  = vlistInqVarMissval(vlistID, varID);
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  gridsize = gridInqSize(gridID);
+  tsid     = streamptr->curTsID;
 
-  century =  year / 100;
+  if ( CDI_Debug )
+    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
 
-  ISEC1_Year = year - century*100;
+  currentfilepos = fileGetPos(fileID);
 
-  if ( year < 0 )
+  for (levID = 0; levID < nlevs; levID++)
     {
-      century = -century;
-      ISEC1_Year = -ISEC1_Year;
+      /* NOTE: tiles are not supported here! */
+      recID = streamptr->vars[varID].recordTable[0].recordID[levID];
+      recpos = streamptr->tsteps[tsid].records[recID].position;
+      fileSetPos(fileID, recpos, SEEK_SET);
+      extRead(fileID, extp);
+      extInqHeader(extp, header);
+      extInqDataDP(extp, &data[levID*gridsize]);
     }
+  fileSetPos(fileID, currentfilepos, SEEK_SET);
 
-  if ( ISEC1_Year == 0 )
+  *nmiss = 0;
+  if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
     {
-      century -= 1;
-      ISEC1_Year = 100;
+      for ( i = 0; i < nlevs*gridsize; i++ )
+	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
+	  {
+	    data[i] = missval;
+	    (*nmiss)++;
+	  }
     }
-
-  century += 1;
-  if ( year < 0 ) century = -century;
-
-  ISEC1_Month  = month;
-  ISEC1_Day    = day;
-  ISEC1_Hour   = hour;
-  ISEC1_Minute = minute;
-
-  ISEC1_Century = century;
-
-  switch (timeunit)
+  else
     {
-    case TUNIT_MINUTE:    factor =    60; ISEC1_TimeUnit = ISEC1_TABLE4_MINUTE;    break;
-    case TUNIT_QUARTER:   factor =   900; ISEC1_TimeUnit = ISEC1_TABLE4_QUARTER;   break;
-    case TUNIT_30MINUTES: factor =  1800; ISEC1_TimeUnit = ISEC1_TABLE4_30MINUTES; break;
-    case TUNIT_HOUR:      factor =  3600; ISEC1_TimeUnit = ISEC1_TABLE4_HOUR;      break;
-    case TUNIT_3HOURS:    factor = 10800; ISEC1_TimeUnit = ISEC1_TABLE4_3HOURS;    break;
-    case TUNIT_6HOURS:    factor = 21600; ISEC1_TimeUnit = ISEC1_TABLE4_6HOURS;    break;
-    case TUNIT_12HOURS:   factor = 43200; ISEC1_TimeUnit = ISEC1_TABLE4_12HOURS;   break;
-    case TUNIT_DAY:       factor = 86400; ISEC1_TimeUnit = ISEC1_TABLE4_DAY;       break;
-    default:              factor =  3600; ISEC1_TimeUnit = ISEC1_TABLE4_HOUR;      break;
+      for ( i = 0; i < 2*nlevs*gridsize; i+=2 )
+	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
+	  {
+	    data[i] = missval;
+	    (*nmiss)++;
+	  }
     }
-
-  return (factor);
 }
 
-static
-void cgribexDefTime(int *isec1, int vdate, int vtime, int tsteptype, int numavg, int taxisID)
-{
-  int timetype = TAXIS_ABSOLUTE;
-  int timerange = 0;
-  int timeunit = TUNIT_HOUR;
-
-  if ( taxisID != -1 )
-    {
-      timetype = taxisInqType(taxisID);
-      timeunit = taxisInqTunit(taxisID);
-    }
-
-  if ( timetype == TAXIS_RELATIVE )
-    {
-      int factor = 1;
-      int rdate, rtime;
-      int ip1 = 0, ip2 = 0;
-      int calendar;
-
-      calendar = taxisInqCalendar(taxisID);
-      rdate    = taxisInqRdate(taxisID);
-      rtime    = taxisInqRtime(taxisID);
-
-      factor = cgribexDefDateTime(isec1, timeunit, rdate, rtime);
-
-      timerange = cgribexDefTimerange(tsteptype, factor, calendar,
-				      rdate, rtime, vdate, vtime, &ip1, &ip2);
-
-      if ( timerange == -1 || timerange == 3 )
-	{
-	  timetype = TAXIS_ABSOLUTE;
-	}
-      /*
-      else if ( timerange == 10 )
-	{
-	  if ( ip1 < 0 || ip1 > 0xFFFF ) timetype = TAXIS_ABSOLUTE;
-	  if ( ip2 < 0 || ip2 > 0xFFFF ) timetype = TAXIS_ABSOLUTE;
-	}
-      */
-      else
-	{
-	  if ( ip1 < 0 || ip1 > 0xFF   ) timetype = TAXIS_ABSOLUTE;
-	  if ( ip2 < 0 || ip2 > 0xFF   ) timetype = TAXIS_ABSOLUTE;
-	}
-
-      ISEC1_TimeRange   = timerange;
-      ISEC1_TimePeriod1 = ip1;
-      ISEC1_TimePeriod2 = ip2;
-    }
-
-  if ( timetype == TAXIS_ABSOLUTE )
-    {
-      (void) cgribexDefDateTime(isec1, timeunit, vdate, vtime);
-
-      /*
-      if ( numavg > 0 )
-	ISEC1_TimeRange = 0;
-      else
-      */
-      if ( ISEC1_TimeRange != 3 )
-	ISEC1_TimeRange   = 10;
-
-      ISEC1_TimePeriod1 = 0;
-      ISEC1_TimePeriod2 = 0;
-    }
-
-  ISEC1_AvgNum         = numavg;
-  ISEC1_AvgMiss        = 0;
-  ISEC1_DecScaleFactor = 0;
-}
 
-static
-void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridID)
+void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
 {
-  int gridtype;
-  bool lcurvi = false;
-  static bool lwarning = true;
-
-  memset(isec2, 0, 16*sizeof(int));
-
-  ISEC1_Sec2Or3Flag = 128;
-
-  gridtype = gridInqType(gridID);
+  int vlistID, fileID;
+  int nlevs, gridID, gridsize;
+  off_t recpos, currentfilepos;
+  int header[4];
+  int tsid;
+  int recID;
+  int i;
+  double missval;
+  void *extp = streamptr->record->exsep;
 
-  ISEC1_GridDefinition = 255;
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  /* NOTE: tiles are not supported here! */
+  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
+  missval  = vlistInqVarMissval(vlistID, varID);
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  gridsize = gridInqSize(gridID);
+  tsid     = streamptr->curTsID;
 
-  if ( gridtype == GRID_GENERIC )
-    {
-      int xsize, ysize, gridsize;
+  if ( CDI_Debug )
+    Message("nlevs = %d gridID = %d gridsize = %d",
+	     nlevs, gridID, gridsize);
 
-      gridsize = gridInqSize(gridID);
-      xsize = gridInqXsize(gridID);
-      ysize = gridInqYsize(gridID);
+  currentfilepos = fileGetPos(fileID);
 
-      if ( (ysize ==  32 || ysize ==  48 || ysize ==  64 ||
-	    ysize ==  96 || ysize == 160 || ysize == 192 ||
-	    ysize == 240 || ysize == 320 || ysize == 384 ||
-	    ysize == 480 || ysize == 768 ) &&
-	   (xsize == 2*ysize || xsize == 1) )
-	{
-	  gridtype = GRID_GAUSSIAN;
-	  gridChangeType(gridID, gridtype);
-	}
-      else if ( gridsize == 1 )
-	{
-	  gridtype = GRID_LONLAT;
-	  gridChangeType(gridID, gridtype);
-	}
-      else if ( gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL) )
-	{
-	  gridtype = GRID_LONLAT;
-	  gridChangeType(gridID, gridtype);
-	}
-    }
-  else if ( gridtype == GRID_CURVILINEAR )
-    {
-      if ( lwarning && gridInqSize(gridID) > 1 )
-	{
-	  lwarning = false;
-	  Warning("Curvilinear grids are unsupported in GRIB1! Created wrong GDS!");
-	}
-      gridtype = GRID_LONLAT;
-      lcurvi = true;
-    }
+  /* NOTE: tiles are not supported here! */
+  recID = streamptr->vars[varID].recordTable[0].recordID[levID];
+  recpos = streamptr->tsteps[tsid].records[recID].position;
+  fileSetPos(fileID, recpos, SEEK_SET);
+  extRead(fileID, extp);
+  extInqHeader(extp, header);
+  extInqDataDP(extp, data);
 
-  ISEC2_Reduced  = FALSE;
-  ISEC2_ScanFlag = 0;
+  fileSetPos(fileID, currentfilepos, SEEK_SET);
 
-  switch (gridtype)
+  *nmiss = 0;
+  if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
     {
-    case GRID_LONLAT:
-    case GRID_GAUSSIAN:
-    case GRID_GAUSSIAN_REDUCED:
-    case GRID_TRAJECTORY:
-      {
-	int nlon = 0, nlat;
-	double xfirst = 0, xlast = 0, xinc = 0;
-	double yfirst = 0, ylast = 0, yinc = 0;
-
-	if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
-          ISEC2_GridType = GRIB1_GTYPE_GAUSSIAN;
-        else if ( gridtype == GRID_LONLAT && gridIsRotated(gridID) )
-	  ISEC2_GridType = GRIB1_GTYPE_LATLON_ROT;
-	else
-	  ISEC2_GridType = GRIB1_GTYPE_LATLON;
-
-	nlon = gridInqXsize(gridID);
-	nlat = gridInqYsize(gridID);
-
-	if ( gridtype == GRID_GAUSSIAN_REDUCED )
-	  {
-	    ISEC2_Reduced = TRUE;
-	    nlon = 0;
-	    gridInqRowlon(gridID, ISEC2_RowLonPtr);
-	  }
-	else
-	  {
-	    if ( nlon == 0 )
-	      {
-		nlon = 1;
-	      }
-	    else
-	      {
-		xfirst = gridInqXval(gridID,      0);
-		if ( lcurvi )
-		  xlast  = gridInqXval(gridID, nlon*nlat-1);
-		else
-		  xlast  = gridInqXval(gridID, nlon-1);
-		xinc   = gridInqXinc(gridID);
-	      }
-	  }
-
-	if ( nlat == 0 )
-	  {
-	    nlat = 1;
-	  }
-	else
-	  {
-	    yfirst = gridInqYval(gridID,      0);
-	    if ( lcurvi )
-	      ylast  = gridInqYval(gridID, nlon*nlat-1);
-	    else
-	      ylast  = gridInqYval(gridID, nlat-1);
-	    yinc   = gridInqYinc(gridID);
-	    if ( yinc < 0 ) yinc = -yinc;
-	  }
-
-	ISEC2_NumLon   = nlon;
-	ISEC2_NumLat   = nlat;
-	ISEC2_FirstLat = (int)lround(yfirst*1000);
-	ISEC2_LastLat  = (int)lround(ylast*1000);
-	if ( gridtype == GRID_GAUSSIAN_REDUCED )
-	  {
-	    ISEC2_FirstLon = 0;
-	    ISEC2_LastLon  = (int)lround(1000*(360.-360./(nlat*2)));
-	    ISEC2_LonIncr  = (int)lround(1000*360./(nlat*2));
-	  }
-	else
+      for ( i = 0; i < gridsize; i++ )
+	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
-	    ISEC2_FirstLon = (int)lround(xfirst*1000);
-	    ISEC2_LastLon  = (int)lround(xlast*1000);
-	    ISEC2_LonIncr  = (int)lround(xinc*1000);
+	    data[i] = missval;
+	    (*nmiss)++;
 	  }
-
-	// if ( fabs(xinc*1000 - ISEC2_LonIncr) > FLT_EPSILON ) ISEC2_LonIncr = 0;
-
-	if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
-          {
-            int np = gridInqNP(gridID);
-            if ( np == 0 ) np = nlat/2;
-            ISEC2_NumPar = np;
-          }
-	else
+    }
+  else
+    {
+      for ( i = 0; i < 2*gridsize; i+=2 )
+	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
-	    ISEC2_LatIncr = (int)lround(yinc*1000);
-	    // if ( fabs(yinc*1000 - ISEC2_LatIncr) > FLT_EPSILON ) ISEC2_LatIncr = 0;
-
-	    if ( ISEC2_LatIncr < 0 ) ISEC2_LatIncr = -ISEC2_LatIncr;
+	    data[i] = missval;
+	    (*nmiss)++;
 	  }
+    }
+}
 
-	if ( ISEC2_NumLon > 1 && ISEC2_NumLat == 1 )
-	  if ( ISEC2_LonIncr != 0 && ISEC2_LatIncr == 0 ) ISEC2_LatIncr = ISEC2_LonIncr;
-
-	if ( ISEC2_NumLon == 1 && ISEC2_NumLat > 1 )
-	  if ( ISEC2_LonIncr == 0 && ISEC2_LatIncr != 0 ) ISEC2_LonIncr = ISEC2_LatIncr;
 
-	if ( ISEC2_LatIncr == 0 || ISEC2_LonIncr == 0 )
-	  ISEC2_ResFlag = 0;
-	else
-	  ISEC2_ResFlag = 128;
+void extWriteVarDP(stream_t *streamptr, int varID, const double *data)
+{
+  int fileID;
+  int levID, nlevs, gridID, gridsize;
+  int zaxisID;
+  double level;
+  int header[4];
+  int tsID;
+  int vlistID;
+  int pdis, pcat, pnum;
+  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
 
-	if ( gridIsRotated(gridID) )
-	  {
-	    ISEC2_LatSP = - (int)lround(gridInqYpole(gridID) * 1000);
-	    ISEC2_LonSP =   (int)lround((gridInqXpole(gridID) + 180) * 1000);
-            double angle = gridInqAngle(gridID);
-            if ( fabs(angle) > 0 ) angle = -angle;
-            FSEC2_RotAngle = angle;
-	  }
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-	/* East -> West */
-	if ( ISEC2_LastLon < ISEC2_FirstLon ) ISEC2_ScanFlag += 128;
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  tsID     = streamptr->curTsID;
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  gridsize = gridInqSize(gridID);
+  zaxisID  = vlistInqVarZaxis(vlistID, varID);
+  nlevs    = zaxisInqSize(zaxisID);
 
-	/* South -> North */
-	if ( ISEC2_LastLat > ISEC2_FirstLat ) ISEC2_ScanFlag += 64;
+  if ( CDI_Debug )
+    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
 
-	break;
-      }
-    case GRID_LCC:
-      {
-	double originLon, originLat, lonParY, lat1, lat2, xincm, yincm;
-	int xsize, ysize;
-	int projflag, scanflag;
+  cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
 
-	xsize = gridInqXsize(gridID);
-	ysize = gridInqYsize(gridID);
+  header[0] = streamptr->tsteps[tsID].taxis.vdate;
+  header[1] = pnum;
+  header[3] = gridInqSize(gridID);
 
-	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
-		   &projflag, &scanflag);
+  extDefDatatype(vlistInqVarDatatype(vlistID, varID), &extp->prec, &extp->number);
 
-	ISEC2_GridType = GRIB1_GTYPE_LCC;
-	ISEC2_NumLon   = xsize;
-	ISEC2_NumLat   = ysize;
-	ISEC2_FirstLon = (int)lround(originLon * 1000);
-	ISEC2_FirstLat = (int)lround(originLat * 1000);
-	ISEC2_Lambert_Lov    = (int)lround(lonParY * 1000);
-	ISEC2_Lambert_LatS1  = (int)lround(lat1 * 1000);
-	ISEC2_Lambert_LatS2  = (int)lround(lat2 * 1000);
-	ISEC2_Lambert_dx     = (int)lround(xincm);
-	ISEC2_Lambert_dy     = (int)lround(yincm);
-	ISEC2_Lambert_LatSP  = 0;
-	ISEC2_Lambert_LatSP  = 0;
-	ISEC2_Lambert_ProjFlag = projflag;
-	ISEC2_ScanFlag = scanflag;
+  for ( levID = 0;  levID < nlevs; levID++ )
+    {
+      level = zaxisInqLevel(zaxisID, levID);
 
-	break;
-      }
-    case GRID_SPECTRAL:
-      {
-	ISEC2_GridType = GRIB1_GTYPE_SPECTRAL;
-	ISEC2_PentaJ   = gridInqTrunc(gridID);
-	ISEC2_PentaK   = ISEC2_PentaJ;
-	ISEC2_PentaM   = ISEC2_PentaJ;
-	ISEC2_RepType  = 1;
-	isec4[2]       = 128;
-	if ( gridInqComplexPacking(gridID) && ISEC2_PentaJ >= 21 )
-	  {
-	    ISEC2_RepMode  = 2;
-	    isec4[3]       = 64;
-	    isec4[16]      = 0;
-	    isec4[17]      = 20;
-	    isec4[18]      = 20;
-	    isec4[19]      = 20;
-	  }
-	else
-	  {
-	    ISEC2_RepMode  = 1;
-	    isec4[3]       = 0;
-	  }
-	break;
-      }
-    case GRID_GME:
-      {
-	ISEC2_GridType   = GRIB1_GTYPE_GME;
-	ISEC2_GME_ND     = gridInqGMEnd(gridID);
-	ISEC2_GME_NI     = gridInqGMEni(gridID);
-	ISEC2_GME_NI2    = gridInqGMEni2(gridID);
-	ISEC2_GME_NI3    = gridInqGMEni3(gridID);
-	ISEC2_GME_AFlag  = 0;
-	ISEC2_GME_LatPP  = 90000;
-	ISEC2_GME_LonPP  = 0;
-	ISEC2_GME_LonMPL = 0;
-	ISEC2_GME_BFlag  = 0;
-	break;
-      }
-    default:
-      {
-	Warning("The CGRIBEX library can not store fields on the used grid!");
-	Error("Unsupported grid type: %s", gridNamePtr(gridtype));
-	break;
-      }
+      header[2] = (int) level;
+      extDefHeader(extp, header);
+      extDefDataDP(extp, &data[levID*gridsize]);
+      extWrite(fileID, extp);
     }
 }
 
-static
-void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int levelID)
+
+void extWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
 {
+  int fileID;
+  int gridID;
+  int zaxisID;
   double level;
-  int ilevel, zaxistype, ltype;
-  static bool lwarning = true;
-  static bool lwarning_vct = true;
+  int header[4];
+  int tsID;
+  int vlistID;
+  int pdis, pcat, pnum;
+  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
 
-  zaxistype = zaxisInqType(zaxisID);
-  ltype = zaxisInqLtype(zaxisID);
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  tsID     = streamptr->curTsID;
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  zaxisID  = vlistInqVarZaxis(vlistID, varID);
+  level    = zaxisInqLevel(zaxisID, levID);
 
-  if ( zaxistype == ZAXIS_GENERIC && ltype == 0 )
-    {
-      Message("Changed zaxis type from %s to %s",
-	      zaxisNamePtr(zaxistype),
-	      zaxisNamePtr(ZAXIS_PRESSURE));
-      zaxistype = ZAXIS_PRESSURE;
-      zaxisChangeType(zaxisID, zaxistype);
-      zaxisDefUnits(zaxisID, "Pa");
-    }
+  if ( CDI_Debug )
+    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
 
-  ISEC2_NumVCP = 0;
+  cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
 
-  switch (zaxistype)
-    {
-    case ZAXIS_SURFACE:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_SURFACE;
-	ISEC1_Level1    = (int)(zaxisInqLevel(zaxisID, levelID));
-	ISEC1_Level2    = 0;
-	break;
-      }
-    case ZAXIS_CLOUD_BASE:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_CLOUD_BASE;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
-    case ZAXIS_CLOUD_TOP:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_CLOUD_TOP;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
-    case ZAXIS_ISOTHERM_ZERO:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_ISOTHERM0;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
-    case ZAXIS_TOA:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_TOA;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
-    case ZAXIS_SEA_BOTTOM:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_SEA_BOTTOM;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
-    case ZAXIS_ATMOSPHERE:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_ATMOSPHERE;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
-    case ZAXIS_MEANSEA:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_MEANSEA;
-	ISEC1_Level1    = (int)(zaxisInqLevel(zaxisID, levelID));
-	ISEC1_Level2    = 0;
-	break;
-      }
-    case ZAXIS_HYBRID:
-    case ZAXIS_HYBRID_HALF:
-      {
-	int vctsize;
+  header[0] = streamptr->tsteps[tsID].taxis.vdate;
+  header[1] = pnum;
+  header[2] = (int) level;
+  header[3] = gridInqSize(gridID);
 
-	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_HYBRID_LAYER;
-	    ISEC1_Level1    = (int)(zaxisInqLbound(zaxisID, levelID));
-	    ISEC1_Level2    = (int)(zaxisInqUbound(zaxisID, levelID));
-	  }
-	else
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_HYBRID;
-	    ISEC1_Level1    = (int)(zaxisInqLevel(zaxisID, levelID));
-	    ISEC1_Level2    = 0;
-	  }
+  extDefDatatype(vlistInqVarDatatype(vlistID, varID), &extp->prec, &extp->number);
 
-	vctsize = zaxisInqVctSize(zaxisID);
-	if ( vctsize == 0 && lwarning )
-	  {
-	    Warning("VCT missing. ( param = %d, zaxisID = %d )", ISEC1_Parameter, zaxisID);
-	    lwarning = false;
-	  }
-	if ( vctsize > 255 )
-	  {
-	    ISEC2_NumVCP = 0;
-	    if ( lwarning_vct )
-	      {
-		Warning("VCT size of %d is too large (maximum is 255). Set to 0!", vctsize);
-		lwarning_vct = false;
-	      }
-	  }
-	else
-	  {
-	    ISEC2_NumVCP = vctsize;
-	    zaxisInqVct(zaxisID, &fsec2[10]);
-	  }
-	break;
-      }
-    case ZAXIS_PRESSURE:
-      {
-	double dum;
-	char units[128];
+  extDefHeader(extp, header);
+  extDefDataDP(extp, data);
+  extWrite(fileID, extp);
+}
 
-	level = zaxisInqLevel(zaxisID, levelID);
-	if ( level < 0 )
-	  Warning("Pressure level of %f Pa is below zero!", level);
+#endif /* HAVE_LIBEXTRA */
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#include <stdlib.h>
 
-	zaxisInqUnits(zaxisID, units);
-	if ( (units[0] != 'P') | (units[1] != 'a') ) level *= 100;
 
-	ilevel = (int) level;
-	if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_99;
-	    ISEC1_Level1    = ilevel;
-	    ISEC1_Level2    = 0;
-	  }
-	else
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_ISOBARIC;
-	    ISEC1_Level1    = ilevel/100;
-	    ISEC1_Level2    = 0;
-	  }
-	break;
-      }
-    case ZAXIS_HEIGHT:
-      {
-	level = zaxisInqLevel(zaxisID, levelID);
 
-	ilevel = (int) level;
-	ISEC1_LevelType = GRIB1_LTYPE_HEIGHT;
-	ISEC1_Level1    = ilevel;
-	ISEC1_Level2    = 0;
+void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1, const char *container_name)
+{
+  int fileID1 = streamptr1->fileID;
+  int fileID2 = streamptr2->fileID;
 
-	break;
-      }
-    case ZAXIS_ALTITUDE:
-      {
-	level = zaxisInqLevel(zaxisID, levelID);
+  int tsID    = streamptr1->curTsID;
+  int vrecID  = streamptr1->tsteps[tsID].curRecID;
+  int recID   = streamptr1->tsteps[tsID].recIDs[vrecID];
+  off_t recpos  = streamptr1->tsteps[tsID].records[recID].position;
+  size_t recsize = streamptr1->tsteps[tsID].records[recID].size;
 
-	ilevel = (int) level;
-	ISEC1_LevelType = GRIB1_LTYPE_ALTITUDE;
-	ISEC1_Level1    = ilevel;
-	ISEC1_Level2    = 0;
+  if (fileSetPos(fileID1, recpos, SEEK_SET) != 0)
+    Error("Cannot seek input file for %s record copy!", container_name);
 
-	break;
-      }
-    case ZAXIS_SIGMA:
-      {
-	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_SIGMA_LAYER;
-	    ISEC1_Level1    = (int)(zaxisInqLbound(zaxisID, levelID));
-	    ISEC1_Level2    = (int)(zaxisInqUbound(zaxisID, levelID));
-	  }
-	else
-	  {
-            level = zaxisInqLevel(zaxisID, levelID);
+  char *buffer = (char *) Malloc(recsize);
 
-            ilevel = (int) level;
-            ISEC1_LevelType = GRIB1_LTYPE_SIGMA;
-            ISEC1_Level1    = ilevel;
-            ISEC1_Level2    = 0;
-          }
+  if (fileRead(fileID1, buffer, recsize) != recsize)
+    Error("Failed to read record from %s file for copying!", container_name);
 
-	break;
-      }
-    case ZAXIS_DEPTH_BELOW_LAND:
-      {
-	char units[128];
-	double factor;
+  if (fileWrite(fileID2, buffer, recsize) != recsize)
+    Error("Failed to write record to %s file when copying!", container_name);
 
-	zaxisInqUnits(zaxisID, units);
+  Free(buffer);
+}
 
-        if      ( units[0] == 'm' && units[1] == 'm' ) factor =   0.1;
-        else if ( units[0] == 'c' && units[1] == 'm' ) factor =   1;
-        else if ( units[0] == 'd' && units[1] == 'm' ) factor =  10;
-        else                                           factor = 100; // meter
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef _STREAM_GRIBAPI_H
+#define _STREAM_GRIBAPI_H
 
-	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-	  {
-            double level1, level2;
-            level1 = zaxisInqLbound(zaxisID, levelID);
-            level2 = zaxisInqUbound(zaxisID, levelID);
-	    ISEC1_LevelType = GRIB1_LTYPE_LANDDEPTH_LAYER;
-	    ISEC1_Level1    = (int) (level1*factor);
-	    ISEC1_Level2    = (int) (level2*factor);
-	  }
-	else
-	  {
-	    level = zaxisInqLevel(zaxisID, levelID);
+int gribapiScanTimestep1(stream_t * streamptr);
+int gribapiScanTimestep2(stream_t * streamptr);
+int gribapiScanTimestep(stream_t * streamptr);
 
-	    ilevel = (int) (level*factor);
-	    ISEC1_LevelType = GRIB1_LTYPE_LANDDEPTH;
-	    ISEC1_Level1    = ilevel;
-	    ISEC1_Level2    = 0;
-	  }
+int gribapiDecode(void *gribbuffer, int gribsize, double *data, long datasize,
+		  int unreduced, int *nmiss, double missval, int vlistID, int varID);
 
-	break;
-      }
-    case ZAXIS_DEPTH_BELOW_SEA:
-      {
-	level = zaxisInqLevel(zaxisID, levelID);
+size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
+		     int vdate, int vtime, int tsteptype, int numavg,
+		     long datasize, const double *data, int nmiss, void **gribbuffer, size_t *gribbuffersize,
+		     int ljpeg, void *gribContainer);
 
-	ilevel = (int) level;
-	ISEC1_LevelType = GRIB1_LTYPE_SEADEPTH;
-	ISEC1_Level1    = ilevel;
-	ISEC1_Level2    = 0;
+#endif  /* _STREAM_GRIBAPI_H */
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifdef HAVE_CONFIG_H
+#endif
 
-	break;
-      }
-    case ZAXIS_ISENTROPIC:
-      {
-	level = zaxisInqLevel(zaxisID, levelID);
 
-	ilevel = (int) level;
-	ISEC1_LevelType = GRIB1_LTYPE_ISENTROPIC;
-	ISEC1_Level1    = ilevel;
-	ISEC1_Level2    = 0;
 
-	break;
-      }
-    case ZAXIS_GENERIC:
-      {
-	level = zaxisInqLevel(zaxisID, levelID);
+int grib1ltypeToZaxisType(int grib_ltype)
+{
+  int zaxistype = ZAXIS_GENERIC;
 
-	ilevel = (int) level;
-	ISEC1_LevelType = ltype;
-	ISEC1_Level1    = ilevel;
-	ISEC1_Level2    = 0;
+  switch ( grib_ltype )
+    {
+    case GRIB1_LTYPE_SURFACE:            zaxistype = ZAXIS_SURFACE;                break;
+    case GRIB1_LTYPE_CLOUD_BASE:         zaxistype = ZAXIS_CLOUD_BASE;             break;
+    case GRIB1_LTYPE_CLOUD_TOP:          zaxistype = ZAXIS_CLOUD_TOP;              break;
+    case GRIB1_LTYPE_ISOTHERM0:          zaxistype = ZAXIS_ISOTHERM_ZERO;          break;
+    case GRIB1_LTYPE_TOA:                zaxistype = ZAXIS_TOA;                    break;
+    case GRIB1_LTYPE_SEA_BOTTOM:         zaxistype = ZAXIS_SEA_BOTTOM;             break;
+    case GRIB1_LTYPE_ATMOSPHERE:         zaxistype = ZAXIS_ATMOSPHERE;             break;
+    case GRIB1_LTYPE_MEANSEA:            zaxistype = ZAXIS_MEANSEA;                break;
+    case GRIB1_LTYPE_99:
+    case GRIB1_LTYPE_ISOBARIC:           zaxistype = ZAXIS_PRESSURE;               break;
+    case GRIB1_LTYPE_HEIGHT:             zaxistype = ZAXIS_HEIGHT;                 break;
+    case GRIB1_LTYPE_ALTITUDE:           zaxistype = ZAXIS_ALTITUDE;	           break;
+    case GRIB1_LTYPE_SIGMA:
+    case GRIB1_LTYPE_SIGMA_LAYER:        zaxistype = ZAXIS_SIGMA;	           break;
+    case GRIB1_LTYPE_HYBRID:
+    case GRIB1_LTYPE_HYBRID_LAYER:       zaxistype = ZAXIS_HYBRID;	           break;
+    case GRIB1_LTYPE_LANDDEPTH:
+    case GRIB1_LTYPE_LANDDEPTH_LAYER:    zaxistype = ZAXIS_DEPTH_BELOW_LAND;       break;
+    case GRIB1_LTYPE_ISENTROPIC:         zaxistype = ZAXIS_ISENTROPIC;             break;
+    case GRIB1_LTYPE_SEADEPTH:           zaxistype = ZAXIS_DEPTH_BELOW_SEA;        break;
+    case GRIB1_LTYPE_LAKE_BOTTOM:        zaxistype = ZAXIS_LAKE_BOTTOM;            break;
+    case GRIB1_LTYPE_SEDIMENT_BOTTOM:    zaxistype = ZAXIS_SEDIMENT_BOTTOM;        break;
+    case GRIB1_LTYPE_SEDIMENT_BOTTOM_TA: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;     break;
+    case GRIB1_LTYPE_SEDIMENT_BOTTOM_TW: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;     break;
+    case GRIB1_LTYPE_MIX_LAYER:          zaxistype = ZAXIS_MIX_LAYER;              break;
+    }
 
-	break;
-      }
-    default:
-      {
-	Error("Unsupported zaxis type: %s", zaxisNamePtr(zaxistype));
-	break;
-      }
+  return zaxistype;
+}
+
+
+int grib2ltypeToZaxisType(int grib_ltype)
+{
+  int zaxistype = ZAXIS_GENERIC;
+
+  switch ( grib_ltype )
+    {
+    case GRIB2_LTYPE_SURFACE:            zaxistype = ZAXIS_SURFACE;                break;
+    case GRIB2_LTYPE_CLOUD_BASE:         zaxistype = ZAXIS_CLOUD_BASE;             break;
+    case GRIB2_LTYPE_CLOUD_TOP:          zaxistype = ZAXIS_CLOUD_TOP;              break;
+    case GRIB2_LTYPE_ISOTHERM0:          zaxistype = ZAXIS_ISOTHERM_ZERO;          break;
+    case GRIB2_LTYPE_TOA:                zaxistype = ZAXIS_TOA;                    break;
+    case GRIB2_LTYPE_SEA_BOTTOM:         zaxistype = ZAXIS_SEA_BOTTOM;             break;
+    case GRIB2_LTYPE_ATMOSPHERE:         zaxistype = ZAXIS_ATMOSPHERE;             break;
+    case GRIB2_LTYPE_MEANSEA:            zaxistype = ZAXIS_MEANSEA;                break;
+    case GRIB2_LTYPE_ISOBARIC:           zaxistype = ZAXIS_PRESSURE;               break;
+    case GRIB2_LTYPE_HEIGHT:             zaxistype = ZAXIS_HEIGHT;                 break;
+    case GRIB2_LTYPE_ALTITUDE:           zaxistype = ZAXIS_ALTITUDE;               break;
+    case GRIB2_LTYPE_SIGMA:              zaxistype = ZAXIS_SIGMA;                  break;
+    case GRIB2_LTYPE_HYBRID:
+ /* case GRIB2_LTYPE_HYBRID_LAYER: */    zaxistype = ZAXIS_HYBRID;                 break;
+    case GRIB2_LTYPE_LANDDEPTH:
+ /* case GRIB2_LTYPE_LANDDEPTH_LAYER: */ zaxistype = ZAXIS_DEPTH_BELOW_LAND;       break;
+    case GRIB2_LTYPE_ISENTROPIC:         zaxistype = ZAXIS_ISENTROPIC;             break;
+    case GRIB2_LTYPE_SNOW:               zaxistype = ZAXIS_SNOW;                   break;
+    case GRIB2_LTYPE_SEADEPTH:           zaxistype = ZAXIS_DEPTH_BELOW_SEA;        break;
+    case GRIB2_LTYPE_LAKE_BOTTOM:        zaxistype = ZAXIS_LAKE_BOTTOM;            break;
+    case GRIB2_LTYPE_SEDIMENT_BOTTOM:    zaxistype = ZAXIS_SEDIMENT_BOTTOM;        break;
+    case GRIB2_LTYPE_SEDIMENT_BOTTOM_TA: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;     break;
+    case GRIB2_LTYPE_SEDIMENT_BOTTOM_TW: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;     break;
+    case GRIB2_LTYPE_MIX_LAYER:          zaxistype = ZAXIS_MIX_LAYER;              break;
+    case GRIB2_LTYPE_REFERENCE:          zaxistype = ZAXIS_REFERENCE;              break;
+    }
+
+  return zaxistype;
+}
+
+
+int zaxisTypeToGrib1ltype(int zaxistype)
+{
+  int grib_ltype = -1;
+
+  switch (zaxistype)
+    {
+    case ZAXIS_SURFACE:               grib_ltype = GRIB1_LTYPE_SURFACE;            break;
+    case ZAXIS_MEANSEA:               grib_ltype = GRIB1_LTYPE_MEANSEA;            break;
+    case ZAXIS_HEIGHT:                grib_ltype = GRIB1_LTYPE_HEIGHT;             break;
+    case ZAXIS_ALTITUDE:              grib_ltype = GRIB1_LTYPE_ALTITUDE;           break;
+    case ZAXIS_SIGMA:                 grib_ltype = GRIB1_LTYPE_SIGMA;              break;
+    case ZAXIS_DEPTH_BELOW_SEA:       grib_ltype = GRIB1_LTYPE_SEADEPTH;           break;
+    case ZAXIS_ISENTROPIC:            grib_ltype = GRIB1_LTYPE_ISENTROPIC;         break;
+    case ZAXIS_CLOUD_BASE:            grib_ltype = GRIB1_LTYPE_CLOUD_BASE;         break;
+    case ZAXIS_CLOUD_TOP:             grib_ltype = GRIB1_LTYPE_CLOUD_TOP;          break;
+    case ZAXIS_ISOTHERM_ZERO:         grib_ltype = GRIB1_LTYPE_ISOTHERM0;          break;
+    case ZAXIS_TOA:                   grib_ltype = GRIB1_LTYPE_TOA;                break;
+    case ZAXIS_SEA_BOTTOM:            grib_ltype = GRIB1_LTYPE_SEA_BOTTOM;         break;
+    case ZAXIS_LAKE_BOTTOM:           grib_ltype = GRIB1_LTYPE_LAKE_BOTTOM;        break;
+    case ZAXIS_SEDIMENT_BOTTOM:       grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM;    break;
+    case ZAXIS_SEDIMENT_BOTTOM_TA:    grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TA; break;
+    case ZAXIS_SEDIMENT_BOTTOM_TW:    grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TW; break;
+    case ZAXIS_MIX_LAYER:             grib_ltype = GRIB1_LTYPE_MIX_LAYER;          break;
+    case ZAXIS_ATMOSPHERE:            grib_ltype = GRIB1_LTYPE_ATMOSPHERE;         break;
+    }
+
+  return grib_ltype;
+}
+
+
+int zaxisTypeToGrib2ltype(int zaxistype)
+{
+  int grib_ltype = -1;
+
+  switch (zaxistype)
+    {
+    case ZAXIS_SURFACE:               grib_ltype = GRIB2_LTYPE_SURFACE;            break;
+    case ZAXIS_MEANSEA:               grib_ltype = GRIB2_LTYPE_MEANSEA;            break;
+    case ZAXIS_HEIGHT:                grib_ltype = GRIB2_LTYPE_HEIGHT;             break;
+    case ZAXIS_ALTITUDE:              grib_ltype = GRIB2_LTYPE_ALTITUDE;           break;
+    case ZAXIS_SIGMA:                 grib_ltype = GRIB2_LTYPE_SIGMA;              break;
+    case ZAXIS_DEPTH_BELOW_SEA:       grib_ltype = GRIB2_LTYPE_SEADEPTH;           break;
+    case ZAXIS_ISENTROPIC:            grib_ltype = GRIB2_LTYPE_ISENTROPIC;         break;
+    case ZAXIS_CLOUD_BASE:            grib_ltype = GRIB2_LTYPE_CLOUD_BASE;         break;
+    case ZAXIS_CLOUD_TOP:             grib_ltype = GRIB2_LTYPE_CLOUD_TOP;          break;
+    case ZAXIS_ISOTHERM_ZERO:         grib_ltype = GRIB2_LTYPE_ISOTHERM0;          break;
+    case ZAXIS_TOA:                   grib_ltype = GRIB2_LTYPE_TOA;                break;
+    case ZAXIS_SEA_BOTTOM:            grib_ltype = GRIB2_LTYPE_SEA_BOTTOM;         break;
+    case ZAXIS_LAKE_BOTTOM:           grib_ltype = GRIB2_LTYPE_LAKE_BOTTOM;        break;
+    case ZAXIS_SEDIMENT_BOTTOM:       grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM;    break;
+    case ZAXIS_SEDIMENT_BOTTOM_TA:    grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TA; break;
+    case ZAXIS_SEDIMENT_BOTTOM_TW:    grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TW; break;
+    case ZAXIS_MIX_LAYER:             grib_ltype = GRIB2_LTYPE_MIX_LAYER;          break;
+    case ZAXIS_ATMOSPHERE:            grib_ltype = GRIB2_LTYPE_ATMOSPHERE;         break;
+    }
+
+  return grib_ltype;
+}
+
+
+int grbBitsPerValue(int datatype)
+{
+  int bitsPerValue = 16;
+
+  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
+    Error("CDI/GRIB library does not support complex numbers!");
+
+  if ( datatype != CDI_UNDEFID )
+    {
+      if ( datatype > 0 && datatype <= 32 )
+	bitsPerValue = datatype;
+      else if ( datatype == DATATYPE_FLT64 )
+	bitsPerValue = 24;
+      else
+	bitsPerValue = 16;
     }
+
+  return bitsPerValue;
+}
+
+
+/*
+int grbInqRecord(stream_t * streamptr, int *varID, int *levelID)
+{
+  int status;
+
+  status = cgribexInqRecord(streamptr, varID, levelID);
+
+  return (status);
 }
+*/
 
-static
-void cgribexDefaultSec0(int *isec0)
+void grbDefRecord(stream_t * streamptr)
 {
-  ISEC0_GRIB_Len     = 0;
-  ISEC0_GRIB_Version = 0;
+  UNUSED(streamptr);
 }
 
 static
-void cgribexDefaultSec1(int *isec1)
+int grbScanTimestep1(stream_t * streamptr)
 {
-  ISEC1_CenterID    = 0;
-  ISEC1_SubCenterID = 0;
-  ISEC1_LocalFLag   = 0;
+  int status = CDI_EUFTYPE;
+
+#if  defined  (HAVE_LIBCGRIBEX)
+  int filetype  = streamptr->filetype;
+
+  if ( filetype == FILETYPE_GRB )
+    status = cgribexScanTimestep1(streamptr);
+#endif
+#if defined(HAVE_LIBCGRIBEX) && defined (HAVE_LIBGRIB_API)
+  else
+#endif
+#ifdef HAVE_LIBGRIB_API
+    status = gribapiScanTimestep1(streamptr);
+#endif
+
+  return status;
 }
 
 static
-void cgribexDefaultSec4(int *isec4)
+int grbScanTimestep2(stream_t * streamptr)
 {
-  long i;
+  int status = CDI_EUFTYPE;
+
+#if  defined  (HAVE_LIBCGRIBEX)
+  int filetype = streamptr->filetype;
+
+  if ( filetype == FILETYPE_GRB )
+    {
+      status = cgribexScanTimestep2(streamptr);
+    }
+#endif
+#if defined(HAVE_LIBCGRIBEX) && defined (HAVE_LIBGRIB_API)
+  else
+#endif
+#ifdef HAVE_LIBGRIB_API
+    status = gribapiScanTimestep2(streamptr);
+#endif
 
-  for ( i = 2; i <= 10; ++i ) isec4[i] = 0;
+  return status;
 }
 
 static
-void cgribexDefEnsembleVar(int *isec1, int vlistID, int varID)
+int grbScanTimestep(stream_t * streamptr)
 {
-  int ensID, ensCount, forecast_type;
-
-  /* For Ensemble info  */
+  int status = CDI_EUFTYPE;
+  int filetype;
 
-  //Put1Byte(isec1[36]);        /* MPIM local GRIB use definition identifier  */
-                                /*    (extension identifier)                  */
-  //Put1Byte(isec1[37]);        /* type of ensemble forecast                  */
-  //Put2Byte(isec1[38]);        /* individual ensemble member                 */
-  //Put2Byte(isec1[39]);        /* number of forecasts in ensemble            */
+  filetype  = streamptr->filetype;
 
-  if ( vlistInqVarEnsemble(vlistID, varID, &ensID, &ensCount, &forecast_type) )
+#if  defined  (HAVE_LIBCGRIBEX)
+  if ( filetype == FILETYPE_GRB )
     {
-      if ( ISEC1_CenterID == 252 )
-        {
-          ISEC1_LocalFLag = 1;
-          isec1[36] = 1;
-
-          isec1[37] =  forecast_type;
-          isec1[38] =  ensID;
-          isec1[39] =  ensCount;
-        }
+      status = cgribexScanTimestep(streamptr);
     }
-}
+  else
+#endif
+#ifdef HAVE_LIBGRIB_API
+    status = gribapiScanTimestep(streamptr);
+#else
+    Error("Sufficient GRIB support unavailable!");
 #endif
 
+  return status;
+}
 
-#if  defined  (HAVE_LIBCGRIBEX)
-size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
-		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const double *data, int nmiss, unsigned char *gribbuffer, size_t gribbuffersize)
+
+#if  defined  (HAVE_LIBGRIB)
+int grbInqContents(stream_t * streamptr)
 {
-  size_t nbytes = 0;
-  int gribsize;
-  int iret = 0, iword = 0;
-  int isec0[2], isec1[4096], isec2[4096], isec3[2], isec4[512];
-  float fsec2f[512], fsec3f[2];
-  double fsec2[512], fsec3[2];
-  int datatype;
-  int param;
+  int fileID;
+  int status = 0;
 
-  memset(isec1, 0, 256*sizeof(int));
-  fsec2[0] = 0; fsec2[1] = 0;
-  fsec2f[0] = 0; fsec2f[1] = 0;
+  fileID = streamptr->fileID;
 
-  gribsize = (int)(gribbuffersize / sizeof(int));
-  param    = vlistInqVarParam(vlistID, varID);
+  streamptr->curTsID = 0;
 
-  cgribexDefaultSec0(isec0);
-  cgribexDefaultSec1(isec1);
-  cgribexDefaultSec4(isec4);
+  status = grbScanTimestep1(streamptr);
 
-  cgribexDefInstitut(isec1, vlistID, varID);
-  cgribexDefModel(isec1, vlistID, varID);
+  if ( status == 0 && streamptr->ntsteps == -1 ) status = grbScanTimestep2(streamptr);
 
-  datatype = vlistInqVarDatatype(vlistID, varID);
+  fileSetPos(fileID, 0, SEEK_SET);
 
-  cgribexDefParam(isec1, param);
-  cgribexDefTime(isec1, vdate, vtime, tsteptype, numavg, vlistInqTaxis(vlistID));
-  cgribexDefGrid(isec1, isec2, fsec2, isec4, gridID);
-  cgribexDefLevel(isec1, isec2, fsec2, zaxisID, levelID);
+  return status;
+}
+#endif
 
-  cgribexDefEnsembleVar(isec1, vlistID, varID);
+int grbInqTimestep(stream_t * streamptr, int tsID)
+{
+  int ntsteps, nrecs;
 
-  ISEC4_NumValues = gridInqSize(gridID);
-  ISEC4_NumBits   = grbBitsPerValue(datatype);
+  if ( tsID == 0 && streamptr->rtsteps == 0 )
+    Error("Call to cdiInqContents missing!");
 
-  if ( nmiss > 0 )
+  if ( CDI_Debug )
+    Message("tsid = %d rtsteps = %d", tsID, streamptr->rtsteps);
+
+  ntsteps = CDI_UNDEFID;
+  while ( (tsID + 1) > streamptr->rtsteps && ntsteps == CDI_UNDEFID )
     {
-      FSEC3_MissVal = vlistInqVarMissval(vlistID, varID);
-      ISEC1_Sec2Or3Flag |= 64;
+      ntsteps = grbScanTimestep(streamptr);
+      if ( ntsteps == CDI_EUFSTRUCT )
+	{
+	  streamptr->ntsteps = streamptr->rtsteps;
+	  break;
+	}
     }
 
-  if ( isec4[2] == 128 && isec4[3] == 64 )
+  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
     {
-      isec4[16] = (int) (1000*calculate_pfactor(data, ISEC2_PentaJ, isec4[17]));
-      if ( isec4[16] < -10000 ) isec4[16] = -10000;
-      if ( isec4[16] >  10000 ) isec4[16] =  10000;
+      nrecs = 0;
     }
-  //printf("isec4[16] %d\n", isec4[16]);
-
-  if ( memtype == MEMTYPE_FLOAT )
+  else
     {
-      size_t numVCP = ISEC2_NumVCP > 0 ? (size_t)ISEC2_NumVCP : (size_t)0;
-      for ( size_t i = 0; i < numVCP; ++i ) fsec2f[10+i] = (float)fsec2[10+i];
-      fsec3f[ 1] = (float)fsec3[ 1];
+      streamptr->curTsID = tsID;
+      nrecs = streamptr->tsteps[tsID].nrecs;
     }
 
-  if ( memtype == MEMTYPE_FLOAT )
-    gribExSP(isec0, isec1, isec2, fsec2f, isec3, fsec3f, isec4, (float*) data,
-             (int)datasize, (int *)(void *)gribbuffer, gribsize, &iword, "C", &iret);
-  else
-    gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, (double*) data,
-             (int)datasize, (int *)(void *)gribbuffer, gribsize, &iword, "C", &iret);
+  return nrecs;
+}
 
-  if ( iret ) Error("Problem during GRIB encode (errno = %d)!", iret);
 
-  nbytes = (size_t)iword * sizeof (int);
-  return (nbytes);
+void streamInqGRIBinfo(int streamID, int *intnum, float *fltnum, off_t *bignum)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+
+  int filetype = streamptr->filetype;
+
+  if ( filetype == FILETYPE_GRB )
+    {
+      int tsID     = streamptr->curTsID;
+      int vrecID   = streamptr->tsteps[tsID].curRecID;
+      int recID    = streamptr->tsteps[tsID].recIDs[vrecID];
+      off_t recpos = streamptr->tsteps[tsID].records[recID].position;
+      int zip      = streamptr->tsteps[tsID].records[recID].zip;
+
+      void *gribbuffer = streamptr->record->buffer;
+      size_t gribbuffersize = streamptr->record->buffersize;
+
+      if ( zip > 0 )
+	Error("Compressed GRIB records unsupported!");
+      else
+        grib_info_for_grads(recpos, (long)gribbuffersize, (unsigned char *) gribbuffer, intnum, fltnum, bignum);
+    }
 }
-#endif
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -48094,16 +48605,102 @@ size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridI
  * require-trailing-newline: t
  * End:
  */
-#ifndef STREAM_FCOMMON_H
-#define STREAM_FCOMMON_H
+#ifndef _SUBTYPE_H
+#define _SUBTYPE_H
 
-#ifndef  _CDI_INT_H
-#endif
 
-void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1,
-                       const char *container_name);
+enum {
+  /* subtype attributes wrt. TILES */
+  SUBTYPE_ATT_TILEINDEX                 = 0,
+  SUBTYPE_ATT_TOTALNO_OF_TILEATTR_PAIRS = 1,
+  SUBTYPE_ATT_TILE_CLASSIFICATION       = 2,
+  SUBTYPE_ATT_NUMBER_OF_TILES           = 3,
+  SUBTYPE_ATT_NUMBER_OF_ATTR            = 4,
+  SUBTYPE_ATT_TILEATTRIBUTE             = 5,
+/* No. of different constants in the enumeration
+   "subtype_attributes" */
+  nSubtypeAttributes
+};
+
+
+/* Literal constants corresponding to the different constants of the
+   enumeration "subtype_attributes". */
+extern const char * const cdiSubtypeAttributeName[];
+
+/* Data type specifying an attribute of a subtype (for example an
+   attribute of a set of TILES) or an attribute of a subtype entry
+   (for example an attribute of a single TILE). This data type is part
+   of a linked list. */
+struct subtype_attr_t {
+  int   key, val;                                /* key/value pair */
+  struct subtype_attr_t* next;                   /* next element in linked list */
+};
+
+
+/* Data type specifying a single entry of a subtype, for example a
+   single TILE in a set of TILES. */
+struct subtype_entry_t {
+  int                     self;                  /* list entry index (0,...,nentries-1) */
+  struct subtype_entry_t *next;                  /* next node in linked list */
+
+  /* linked list with attributes for this subtype entry, ordered by its key values*/
+  struct subtype_attr_t  *atts;
+};
+
+
+/* Data type specifying a variable subtype, for example a list of
+   TILES. This can be interpreted as an additional axis like the
+   vertical axis. */
+typedef struct  {
+  int                     self;                  /* resource handler ID */
+  int                     subtype;               /* subtype kind: TILES, ... */
+  int                     nentries;              /* counter: total no. of entries in list */
+
+  struct subtype_entry_t  globals;               /* global attributes */
+
+  /* list of subtype entries, e.g. the list of tiles, ordered by entry->self. */
+  struct subtype_entry_t *entries;
+  /* currently active subtype, e.g. GRIB2 tile index (for example for
+     stream/vlist accesses): */
+  int                     active_subtype_index;
+} subtype_t;
+
+
+
+
+/* prototypes: allocation and destruction */
+void  subtypeAllocate(subtype_t **subtype_ptr2, int subtype);
+int   subtypePush(subtype_t *subtype_ptr);
+void  subtypeDestroyPtr(void *ptr);
+void  subtypeDuplicate(subtype_t *subtype_ptr, subtype_t **dst);
+struct subtype_entry_t* subtypeEntryInsert(subtype_t* head);
+
+/* prototypes: accessing global attributes */
+void  subtypePrint(int subtypeID);
+void  subtypePrintPtr(subtype_t* subtype_ptr);
+void  subtypeDefGlobalDataP(subtype_t *subtype_ptr, int key, int val);
+void  subtypeDefGlobalData(int subtypeID, int key, int val);
+int   subtypeGetGlobalData(int subtypeID, int key);
+int   subtypeGetGlobalDataP(subtype_t *subtype_ptr, int key);
+int   subtypeComparePtr(int s1_ID, subtype_t *s2);
+
+/* prototypes: accessing subtype entries */
+void  subtypeDefEntryDataP(struct subtype_entry_t *subtype_entry_ptr, int key, int val);
+
+
+/* prototypes: tile implementations */
+void  tilesetInsertP(subtype_t *s1, subtype_t *s2);
+
+/* Construct a new subtype for a tile set. If a corresponding subtype
+ * already exists, then we return this subtype ID instead. */
+int vlistDefTileSubtype(int vlistID, subtype_t *tiles);
+
+/* Insert a trivial one-tile-subtype */
+int vlistInsertTrivialTileSubtype(int vlistID);
+
 
 #endif
+
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -48116,4647 +48713,4615 @@ void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1,
 #if defined (HAVE_CONFIG_H)
 #endif
 
+#if  defined  (HAVE_LIBGRIB_API)
 #include <limits.h>
 #include <stdio.h>
-#include <string.h>
 
 
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
-
-#define SINGLE_PRECISION  4
-#define DOUBLE_PRECISION  8
+#  include <grib_api.h>
 
-#if defined (HAVE_LIBEXTRA)
+extern int cdiInventoryMode;
 
+static const var_tile_t dummy_tiles = { 0, -1, -1, -1, -1, -1 };
 
 typedef struct {
   int param;
-  int level;
-} extcompvar_t;
+  int level1;
+  int level2;
+  int ltype;
+  int tsteptype;
+  char name[32];
+
+  var_tile_t tiles;
+
+} compvar2_t;
+
 
 static
-int extInqDatatype(int prec, int number)
+int gribapiGetZaxisType(long editionNumber, int grib_ltype)
 {
-  int datatype;
+  int zaxistype = ZAXIS_GENERIC;
 
-  if ( number == 2 )
+  if ( editionNumber <= 1 )
     {
-      if ( prec == DOUBLE_PRECISION ) datatype = DATATYPE_CPX64;
-      else                            datatype = DATATYPE_CPX32;
+      zaxistype = grib1ltypeToZaxisType(grib_ltype);
     }
   else
     {
-      if ( prec == DOUBLE_PRECISION ) datatype = DATATYPE_FLT64;
-      else                            datatype = DATATYPE_FLT32;
+      zaxistype = grib2ltypeToZaxisType(grib_ltype);
     }
 
-  return (datatype);
+  return (zaxistype);
 }
 
 static
-void extDefDatatype(int datatype, int *prec, int *number)
+int getTimeunits(long unitsOfTime)
 {
+  int timeunits = -1;
 
-  if ( datatype != DATATYPE_FLT32 && datatype != DATATYPE_FLT64 &&
-       datatype != DATATYPE_CPX32 && datatype != DATATYPE_CPX64 )
-    datatype = DATATYPE_FLT32;
-
-  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
-    *number = 2;
-  else
-    *number = 1;
+  switch (unitsOfTime)
+    {
+    case 13:  timeunits = TUNIT_SECOND;  break;
+    case  0:  timeunits = TUNIT_MINUTE;  break;
+    case  1:  timeunits = TUNIT_HOUR;    break;
+    case 10:  timeunits = TUNIT_3HOURS;  break;
+    case 11:  timeunits = TUNIT_6HOURS;  break;
+    case 12:  timeunits = TUNIT_12HOURS; break;
+    case  2:  timeunits = TUNIT_DAY;     break;
+    default:  timeunits = TUNIT_HOUR;    break;
+    }
 
-  if ( datatype == DATATYPE_FLT64 || datatype == DATATYPE_CPX64 )
-    *prec = DOUBLE_PRECISION;
-  else 
-    *prec = SINGLE_PRECISION;
+  return (timeunits);
 }
 
-/* not used
-int extInqRecord(stream_t *streamptr, int *varID, int *levelID)
+static
+double timeunit_factor(int tu1, int tu2)
 {
-  int status;
-  int fileID;
-  int icode, ilevel;
-  int zaxisID = -1;
-  int header[4];
-  int vlistID;
-  void *extp = streamptr->record->exsep;
-
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
-
-  *varID   = -1;
-  *levelID = -1;
-
-  status = extRead(fileID, extp);
-  if ( status != 0 ) return (0);
+  double factor = 1;
 
-  extInqHeader(extp, header);
+  if ( tu2 == TUNIT_HOUR )
+    {
+      switch (tu1)
+        {
+        case TUNIT_SECOND:  factor = 3600;   break;
+        case TUNIT_MINUTE:  factor = 60;     break;
+        case TUNIT_HOUR:    factor = 1;      break;
+        case TUNIT_3HOURS:  factor = 1./3;   break;
+        case TUNIT_6HOURS:  factor = 1./6;   break;
+        case TUNIT_12HOURS: factor = 1./12;  break;
+        case TUNIT_DAY:     factor = 1./24;  break;
+        }
+    }
 
-  icode  = header[1];
-  ilevel = header[2];
+  return (factor);
+}
 
-  *varID = vlistInqVarID(vlistID, icode);
+static
+int gribapiGetTimeUnits(grib_handle *gh)
+{
+  int timeunits = -1;
+  long unitsOfTime = -1;
 
-  if ( *varID == UNDEFID ) Error("Code %d undefined", icode);
+  grib_get_long(gh, "indicatorOfUnitOfTimeRange", &unitsOfTime);
 
-  zaxisID = vlistInqVarZaxis(vlistID, *varID);
+  GRIB_CHECK(my_grib_set_long(gh, "stepUnits", unitsOfTime), 0);
 
-  *levelID = zaxisInqLevelID(zaxisID, (double) ilevel);
+  timeunits = getTimeunits(unitsOfTime);
 
-  return (1);
+  return (timeunits);
 }
-*/
 
-void extReadRecord(stream_t *streamptr, double *data, int *nmiss)
+static
+void gribapiGetSteps(grib_handle *gh, int timeunits, int *startStep, int *endStep)
 {
-  int vlistID, fileID;
-  int status;
-  int recID, vrecID, tsID;
-  off_t recpos;
-  int header[4];
-  int varID, gridID;
-  int i, size;
-  double missval;
-  void *extp = streamptr->record->exsep;
+  int timeunits2 = timeunits;
+  long unitsOfTime;
+  int status = grib_get_long(gh, "stepUnits", &unitsOfTime);
+  if ( status == 0 ) timeunits2 = getTimeunits(unitsOfTime);
+  //timeunits2 = gribapiGetTimeUnits(gh);
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
-  tsID    = streamptr->curTsID;
-  vrecID  = streamptr->tsteps[tsID].curRecID;
-  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-  recpos  = streamptr->tsteps[tsID].records[recID].position;
-  varID   = streamptr->tsteps[tsID].records[recID].varID;
+  long lpar;
+  status = grib_get_long(gh, "forecastTime", &lpar);
+  if ( status == 0 ) *startStep = (int) lpar;
+  else
+    {
+      status = grib_get_long(gh, "startStep", &lpar);
+      if ( status == 0 )
+        *startStep = (int) (((double)lpar * timeunit_factor(timeunits, timeunits2)) + 0.5);
+    }
 
-  fileSetPos(fileID, recpos, SEEK_SET);
+  *endStep = *startStep;
+  status = grib_get_long(gh, "endStep", &lpar);
+  if ( status == 0 )
+    *endStep = (int) (((double)lpar * timeunit_factor(timeunits, timeunits2)) + 0.5);
+  // printf("%d %d %d %d %d %g\n", *startStep, *endStep, lpar, timeunits, timeunits2, timeunit_factor(timeunits, timeunits2));
+}
 
-  status = extRead(fileID, extp);
-  if ( status != 0 )
-    Error("Failed to read EXTRA record");
+static
+void gribapiGetDataDateTime(grib_handle *gh, int *datadate, int *datatime)
+{
+  long lpar;
 
-  extInqHeader(extp, header);
-  extInqDataDP(extp, data);
+  GRIB_CHECK(grib_get_long(gh, "dataDate", &lpar), 0);
+  *datadate = (int) lpar;
+  GRIB_CHECK(grib_get_long(gh, "dataTime", &lpar), 0);  //FIXME: This looses the seconds in GRIB2 files.
+  *datatime = (int) lpar*100;
+}
 
-  missval = vlistInqVarMissval(vlistID, varID);
-  gridID  = vlistInqVarGrid(vlistID, varID);
-  size    = gridInqSize(gridID);
+static
+void gribapiSetDataDateTime(grib_handle *gh, int datadate, int datatime)
+{
+  GRIB_CHECK(my_grib_set_long(gh, "dataDate", datadate), 0);
+  GRIB_CHECK(my_grib_set_long(gh, "dataTime", datatime/100), 0);
+}
 
-  streamptr->numvals += size;
+static
+int gribapiGetValidityDateTime(grib_handle *gh, int *vdate, int *vtime)
+{
+  int rdate, rtime;
+  int timeUnits, startStep = 0, endStep;
+  int tstepRange = 0;
+  int range;
+  long sigofrtime = 3;
 
-  *nmiss = 0;
-  if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
+  if ( gribEditionNumber(gh) > 1 )
     {
-      for ( i = 0; i < size; i++ )
-	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-	  {
-	    data[i] = missval;
-	    (*nmiss)++;
-	  }
+      GRIB_CHECK(grib_get_long(gh, "significanceOfReferenceTime", &sigofrtime), 0);
     }
   else
     {
-      for ( i = 0; i < 2*size; i+=2 )
-	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-	  {
-	    data[i] = missval;
-	    (*nmiss)++;
-	  }
+      GRIB_CHECK(grib_get_long(gh, "timeRangeIndicator", &sigofrtime), 0);
     }
-}
 
+  if ( sigofrtime == 3 )        //XXX: This looks like a bug to me, because timeRangeIndicator == 3 does not seem to have the same meaning as significanceOfReferenceTime == 3. I would recommend replacing this condition with `if(!gribapiTimeIsFC())`.
+    {
+      gribapiGetDataDateTime(gh, vdate, vtime);
+    }
+  else
+    {
+      gribapiGetDataDateTime(gh, &rdate, &rtime);
 
-void extCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
-{
-  streamFCopyRecord(streamptr2, streamptr1, "EXTRA");
-}
+      timeUnits = gribapiGetTimeUnits(gh);
+      gribapiGetSteps(gh, timeUnits, &startStep, &endStep);
 
+      range = endStep - startStep;
 
-void extDefRecord(stream_t *streamptr)
-{
-  int gridID;
-  int header[4];
-  int pdis, pcat, pnum;
-  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
+      if ( range > 0 )
+	{
+	  if ( startStep == 0 ) tstepRange = -1;
+	  else                  tstepRange =  1;
+	}
 
-  gridID   = streamptr->record->gridID;
+      {
+	static int lprint = TRUE;
+	extern int grib_calendar;
+	int ryear, rmonth, rday, rhour, rminute, rsecond;
+	int julday, secofday;
+	int64_t time_period = endStep;
+        int64_t addsec;
 
-  cdiDecodeParam(streamptr->record->param, &pnum, &pcat, &pdis);
-  header[0] = streamptr->record->date;
-  header[1] = pnum;
-  header[2] = streamptr->record->level;
-  header[3] = gridInqSize(gridID);
+	cdiDecodeDate(rdate, &ryear, &rmonth, &rday);
+	cdiDecodeTime(rtime, &rhour, &rminute, &rsecond);
 
-  extDefDatatype(streamptr->record->prec, &extp->prec, &extp->number);
+        if ( rday > 0 )
+          {
+            encode_caldaysec(grib_calendar, ryear, rmonth, rday, rhour, rminute, rsecond, &julday, &secofday);
 
-  extDefHeader(extp, header);
-}
+            addsec = 0;
+            switch ( timeUnits )
+              {
+              case TUNIT_SECOND:  addsec =         time_period; break;
+              case TUNIT_MINUTE:  addsec =    60 * time_period; break;
+              case TUNIT_HOUR:    addsec =  3600 * time_period; break;
+              case TUNIT_3HOURS:  addsec = 10800 * time_period; break;
+              case TUNIT_6HOURS:  addsec = 21600 * time_period; break;
+              case TUNIT_12HOURS: addsec = 43200 * time_period; break;
+              case TUNIT_DAY:     addsec = 86400 * time_period; break;
+              default:
+                if ( lprint )
+                  {
+                    Warning("Time unit %d unsupported", timeUnits);
+                    lprint = FALSE;
+                  }
+                break;
+              }
 
+            julday_add_seconds(addsec, &julday, &secofday);
 
-void extWriteRecord(stream_t *streamptr, const double *data)
-{
-  int fileID = streamptr->fileID;
-  void *extp = streamptr->record->exsep;
+            decode_caldaysec(grib_calendar, julday, secofday, &ryear, &rmonth, &rday, &rhour, &rminute, &rsecond);
+          }
 
-  extDefDataDP(extp, data);
-  extWrite(fileID, extp);
+	*vdate = cdiEncodeDate(ryear, rmonth, rday);
+	*vtime = cdiEncodeTime(rhour, rminute, rsecond);
+      }
+    }
+
+  return (tstepRange);
 }
 
 static
-void extAddRecord(stream_t *streamptr, int param, int level, int xysize,
-		  size_t recsize, off_t position, int prec, int number)
+void grib1GetLevel(grib_handle *gh, int *leveltype, int *lbounds, int *level1, int *level2)
 {
-  int leveltype;
-  int gridID = CDI_UNDEFID;
-  int levelID = 0;
-  int tsID, recID, varID;
-  record_t *record;
-  grid_t grid;
-  int vlistID;
+  *leveltype = 0;
+  *lbounds   = 0;
+  *level1    = 0;
+  *level2    = 0;
 
-  vlistID = streamptr->vlistID;
-  tsID    = streamptr->curTsID;
-  recID   = recordNewEntry(streamptr, tsID);
-  record  = &streamptr->tsteps[tsID].records[recID];
+  long lpar;
+  if(!grib_get_long(gh, "indicatorOfTypeOfLevel", &lpar))       //1 byte
+    {
+      *leveltype = (int) lpar;
 
-  (*record).size     = recsize;
-  (*record).position = position;
-  (*record).param     = param;
-  (*record).ilevel   = level;
-
-  memset(&grid, 0, sizeof(grid_t));
-  grid.type  = GRID_GENERIC;
-  grid.size  = xysize;
-  grid.xsize = xysize;
-  grid.ysize = 0;
-  grid.xvals = NULL;
-  grid.yvals = NULL;
-  gridID = varDefGrid(vlistID, &grid, 0);
-  /*
-  if ( level == 0 ) leveltype = ZAXIS_SURFACE;
-  else              leveltype = ZAXIS_GENERIC;
-  */
-  leveltype = ZAXIS_GENERIC;
+      switch (*leveltype)
+	{
+	case GRIB1_LTYPE_SIGMA_LAYER:
+	case GRIB1_LTYPE_HYBRID_LAYER:
+	case GRIB1_LTYPE_LANDDEPTH_LAYER:
+	  { *lbounds = 1; break; }
+	}
 
-  varAddRecord(recID, param, gridID, leveltype, 0, level, 0, 0, 0,
-	       extInqDatatype(prec, number), &varID, &levelID, TSTEP_INSTANT, 0, 0, -1,
-               NULL, NULL, NULL, NULL, NULL, NULL);
+      if ( *lbounds )
+	{
+	  GRIB_CHECK(grib_get_long(gh, "topLevel", &lpar), 0);  //1 byte
+	  *level1 = (int)lpar;
+	  GRIB_CHECK(grib_get_long(gh, "bottomLevel", &lpar), 0);       //1 byte
+	  *level2 = (int)lpar;
+	}
+      else
+	{
+          double dlevel;
+	  GRIB_CHECK(grib_get_double(gh, "level", &dlevel), 0); //2 byte
+	  if ( *leveltype == 100 ) dlevel *= 100;
+	  if ( dlevel < -2.e9 || dlevel > 2.e9 ) dlevel = 0;
+	  if ( *leveltype == GRIB1_LTYPE_99 ) *leveltype = 100;
 
-  (*record).varID   = (short)varID;
-  (*record).levelID = (short)levelID;
+	  *level1 = (int) dlevel;
+	  *level2 = 0;
+	}
+    }
+}
 
-  streamptr->tsteps[tsID].nallrecs++;
-  streamptr->nrecs++;
+static
+double grib2ScaleFactor(long factor)
+{
+  switch(factor)
+    {
+      case GRIB_MISSING_LONG: return 1;
+      case 0: return 1;
+      case 1: return 0.1;
+      case 2: return 0.01;
+      case 3: return 0.001;
+      case 4: return 0.0001;
+      case 5: return 0.00001;
+      case 6: return 0.000001;
+      case 7: return 0.0000001;
+      case 8: return 0.00000001;
+      case 9: return 0.000000001;
+      default: return 0;
+    }
+}
 
-  if ( CDI_Debug )
-    Message("varID = %d gridID = %d levelID = %d",
-	    varID, gridID, levelID);
+static
+int calcLevel(int level_sf, long factor, long level)
+{
+  double result = 0;
+  if(level != GRIB_MISSING_LONG) result = (double)level*grib2ScaleFactor(factor);
+  if(level_sf) result *= level_sf;
+  return (int)result;
 }
 
 static
-void extScanTimestep1(stream_t *streamptr)
+void grib2GetLevel(grib_handle *gh, int *leveltype1, int *leveltype2, int *lbounds, int *level1,
+                   int *level2, int *level_sf, int *level_unit)
 {
-  int header[4];
   int status;
-  int fileID;
-  int rxysize = 0;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  DateTime datetime0 = { LONG_MIN, LONG_MIN };
-  int tsID;
-  int varID;
-  long recsize;
-  off_t recpos;
-  int nrecords, nrecs, recID;
-  int taxisID = -1;
-  taxis_t *taxis;
-  int vlistID;
-  extcompvar_t compVar, compVar0;
-  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
-
-  streamptr->curTsID = 0;
-
-  tsID  = tstepsNewEntry(streamptr);
-  taxis = &streamptr->tsteps[tsID].taxis;
-
-  if ( tsID != 0 )
-    Error("Internal problem! tstepsNewEntry returns %d", tsID);
+  long lpar;
+  long factor;
 
-  fileID = streamptr->fileID;
+  *leveltype1 = 0;
+  *leveltype2 = -1;
+  *lbounds    = 0;
+  *level1     = 0;
+  *level2     = 0;
+  *level_sf   = 0;
+  *level_unit = 0;
 
-  nrecs = 0;
-  while ( TRUE )
+  status = grib_get_long(gh, "typeOfFirstFixedSurface", &lpar); //1 byte
+  if ( status == 0 )
     {
-      recpos = fileGetPos(fileID);
-      status = extRead(fileID, extp);
-      if ( status != 0 )
-	{
-	  streamptr->ntsteps = 1;
-	  break;
-	}
-      recsize = fileGetPos(fileID) - recpos;
+      long llevel;
 
-      extInqHeader(extp, header);
+      *leveltype1 = (int) lpar;
 
-      vdate   = header[0];
-      vtime   = 0;
-      rcode   = header[1];
-      rlevel  = header[2];
-      rxysize = header[3];
+      status = grib_get_long(gh, "typeOfSecondFixedSurface", &lpar); //1 byte
+      /* FIXME: assert(lpar >= INT_MIN && lpar <= INT_MAX) */
+      if ( status == 0 ) *leveltype2 = (int)lpar;
 
-      param = cdiEncodeParam(rcode, 255, 255);
+      if ( *leveltype1 != 255 && *leveltype2 != 255 && *leveltype2 > 0 ) *lbounds = 1;
+      switch(*leveltype1)
+        {
+          case GRIB2_LTYPE_REFERENCE:
+            if(*leveltype2 == 1) *lbounds = 0;
+            break;
 
-      if ( nrecs == 0 )
-	{
-	  datetime0.date = vdate;
-	  datetime0.time = vtime;
-	}
-      else
-	{
-	  compVar.param = param;
-          compVar.level = rlevel;
-	  for ( recID = 0; recID < nrecs; recID++ )
-	    {
-	      compVar0.param  = streamptr->tsteps[0].records[recID].param;
-	      compVar0.level = streamptr->tsteps[0].records[recID].ilevel;
+          case GRIB2_LTYPE_LANDDEPTH:
+            *level_sf = 1000;
+            *level_unit = CDI_UNIT_M;
+            break;
 
-	      if ( memcmp(&compVar0, &compVar, sizeof(extcompvar_t)) == 0 ) break;
-	    }
-	  if ( recID < nrecs ) break;
-	  DateTime datetime = { .date = vdate, .time = vtime};
-	  if ( datetimeCmp(datetime, datetime0) )
-	    Warning("Inconsistent verification time for code %d level %d", rcode, rlevel);
-	}
+          case GRIB2_LTYPE_ISOBARIC:
+            *level_sf = 1000;
+            *level_unit = CDI_UNIT_PA;
+            break;
 
-      nrecs++;
+          case GRIB2_LTYPE_SIGMA:
+            *level_sf = 1000;
+            *level_unit = 0;
+            break;
+        }
 
-      if ( CDI_Debug )
-	Message("%4d%8d%4d%8d%8d%6d", nrecs, (int)recpos, rcode, rlevel, vdate, vtime);
+      GRIB_CHECK(grib_get_long(gh, "scaleFactorOfFirstFixedSurface", &factor), 0);      //1 byte
+      GRIB_CHECK(grib_get_long(gh, "scaledValueOfFirstFixedSurface", &llevel), 0);      //4 byte
+      *level1 = calcLevel(*level_sf, factor, llevel);
 
-      extAddRecord(streamptr, param, rlevel, rxysize, (size_t)recsize, recpos, extp->prec, extp->number);
+      if ( *lbounds )
+        {
+          GRIB_CHECK(grib_get_long(gh, "scaleFactorOfSecondFixedSurface", &factor), 0); //1 byte
+          GRIB_CHECK(grib_get_long(gh, "scaledValueOfSecondFixedSurface", &llevel), 0); //4 byte
+          *level2 = calcLevel(*level_sf, factor, llevel);
+        }
     }
+}
 
-  streamptr->rtsteps = 1;
-
-  cdi_generate_vars(streamptr);
-
-  taxisID = taxisCreate(TAXIS_ABSOLUTE);
-  taxis->type  = TAXIS_ABSOLUTE;
-  taxis->vdate = (int)datetime0.date;
-  taxis->vtime = (int)datetime0.time;
-
-  vlistID = streamptr->vlistID;
-  vlistDefTaxis(vlistID, taxisID);
-
-  vlist_check_contents(vlistID);
-
-  nrecords = streamptr->tsteps[0].nallrecs;
-  if ( nrecords < streamptr->tsteps[0].recordSize )
+static
+void gribGetLevel(grib_handle *gh, int* leveltype1, int* leveltype2, int* lbounds, int* level1, int* level2, int* level_sf, int* level_unit, var_tile_t* tiles)
+{
+  if ( gribEditionNumber(gh) <= 1 )
     {
-      streamptr->tsteps[0].recordSize = nrecords;
-      streamptr->tsteps[0].records =
-        (record_t *) Realloc(streamptr->tsteps[0].records, (size_t)nrecords * sizeof (record_t));
+      grib1GetLevel(gh, leveltype1, lbounds, level1, level2);
+      *leveltype2 = -1;
+      *level_sf = 0;
+      *level_unit = 0;
     }
-
-  streamptr->tsteps[0].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
-  streamptr->tsteps[0].nrecs = nrecords;
-  for ( recID = 0; recID < nrecords; recID++ )
-    streamptr->tsteps[0].recIDs[recID] = recID;
-
-  if ( streamptr->ntsteps == -1 )
+  else
     {
-      tsID = tstepsNewEntry(streamptr);
-      if ( tsID != streamptr->rtsteps )
-	Error("Internal error. tsID = %d", tsID);
+      grib2GetLevel(gh, leveltype1, leveltype2, lbounds, level1, level2, level_sf, level_unit);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
-      streamptr->tsteps[tsID].position = recpos;
+      /* read in tiles attributes (if there are any) */
+      tiles->tileindex = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TILEINDEX], -1);
+      tiles->totalno_of_tileattr_pairs = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TOTALNO_OF_TILEATTR_PAIRS], -1);
+      tiles->tileClassification = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TILE_CLASSIFICATION], -1);
+      tiles->numberOfTiles = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_NUMBER_OF_TILES], -1);
+      tiles->numberOfAttributes = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_NUMBER_OF_ATTR], -1);
+      tiles->attribute = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TILEATTRIBUTE], -1);
     }
+}
 
-  if ( streamptr->ntsteps == 1 )
+static
+void gribapiGetString(grib_handle *gh, const char *key, char *string, size_t length)
+{
+  string[0] = 0;
+
+  int ret = grib_get_string(gh, key, string, &length);
+  if (ret != 0)
     {
-      if ( taxis->vdate == 0 && taxis->vtime == 0 )
-	{
-	  streamptr->ntsteps = 0;
-	  for ( varID = 0; varID < streamptr->nvars; varID++ )
-	    {
-	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-	    }
-	}
+      fprintf(stderr, "grib_get_string(gh, \"%s\", ...) failed!\n", key);
+      GRIB_CHECK(ret, 0);
     }
+  if      ( length == 8 && memcmp(string, "unknown", length) == 0 ) string[0] = 0;
+  else if ( length == 2 && memcmp(string, "~", length)       == 0 ) string[0] = 0;
 }
 
 static
-int extScanTimestep2(stream_t *streamptr)
+void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
+                      size_t recsize, off_t position, int datatype, int comptype, const char *varname,
+                      int leveltype1, int leveltype2, int lbounds, int level1, int level2, int level_sf, int level_unit,
+                      const var_tile_t *tiles, int lread_additional_keys)
 {
-  int header[4];
-  int status;
-  int fileID;
-  // int rxysize = 0;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  int tsID;
-  int varID;
-  off_t recpos = 0;
-  int nrecords, nrecs, recID, rindex;
-  int nextstep;
-  taxis_t *taxis;
-  int vlistID;
-  extcompvar_t compVar, compVar0;
-  void *extp = streamptr->record->exsep;
+  int levelID = 0;
+  char stdname[CDI_MAX_NAME], longname[CDI_MAX_NAME], units[CDI_MAX_NAME];
+  long ens_index = 0, ens_count = 0, ens_forecast_type = 0;
 
-  streamptr->curTsID = 1;
+  int vlistID = streamptr->vlistID;
+  int tsID    = streamptr->curTsID;
+  int recID   = recordNewEntry(streamptr, tsID);
+  record_t *record  = &streamptr->tsteps[tsID].records[recID];
 
-  fileID  = streamptr->fileID;
-  vlistID = streamptr->vlistID;
+  int tsteptype = gribapiGetTsteptype(gh);
+  // numavg  = ISEC1_AvgNum;
+  int numavg  = 0;
 
-  tsID = streamptr->rtsteps;
-  if ( tsID != 1 )
-    Error("Internal problem! unexpected timestep %d", tsID+1);
+  // fprintf(stderr, "param %d %d %d %d\n", param, level1, level2, leveltype1);
 
-  taxis = &streamptr->tsteps[tsID].taxis;
+  record->size      = recsize;
+  record->position  = position;
+  record->param     = param;
+  record->ilevel    = level1;
+  record->ilevel2   = level2;
+  record->ltype     = leveltype1;
+  record->tsteptype = (short)tsteptype;
+  record->tiles = tiles ? *tiles : dummy_tiles;
 
-  fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+  //FIXME: This may leave the variable name unterminated (which is the behavior that I found in the code).
+  //       I don't know precisely how this field is used, so I did not change this behavior to avoid regressions,
+  //       but I think that it would be better to at least add a line
+  //
+  //           record->varname[sizeof(record->varname) - 1] = 0;`
+  //
+  //       after the `strncpy()` call.
+  //
+  //       I would consider using strdup() (that requires POSIX-2008 compliance, though), or a similar homebrew approach.
+  //       I. e. kick the fixed size array and allocate enough space, whatever that may be.
+  strncpy(record->varname, varname, sizeof(record->varname));
 
-  cdi_create_records(streamptr, tsID);
+  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
+  gribapiGetGrid(gh, grid);
 
-  nrecords = streamptr->tsteps[0].nallrecs;
-  streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
-  streamptr->tsteps[1].nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
-    streamptr->tsteps[1].recIDs[recID] = -1;
+  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  int gridID = gridAdded.Id;
+  if (!gridAdded.isNew) Free(grid);
 
-  for ( recID = 0; recID < nrecords; recID++ )
+  int zaxistype = gribapiGetZaxisType(gribEditionNumber(gh), leveltype1);
+
+  switch (zaxistype)
     {
-      varID = streamptr->tsteps[0].records[recID].varID;
-      streamptr->tsteps[tsID].records[recID].position =
-	streamptr->tsteps[0].records[recID].position;
-      streamptr->tsteps[tsID].records[recID].size     =
-	streamptr->tsteps[0].records[recID].size;
+    case ZAXIS_HYBRID:
+    case ZAXIS_HYBRID_HALF:
+      {
+        long lpar;
+        GRIB_CHECK(grib_get_long(gh, "NV", &lpar), 0);
+        /* FIXME: assert(lpar >= 0) */
+        size_t vctsize = (size_t)lpar;
+        if ( vctsize > 0 )
+          {
+            double *vctptr = (double *) Malloc(vctsize*sizeof(double));
+            size_t dummy = vctsize;
+            GRIB_CHECK(grib_get_double_array(gh, "pv", vctptr, &dummy), 0);
+            varDefVCT(vctsize, vctptr);
+            Free(vctptr);
+          }
+        break;
+      }
+    case ZAXIS_REFERENCE:
+      {
+        unsigned char uuid[CDI_UUID_SIZE];
+        long lpar;
+        GRIB_CHECK(grib_get_long(gh, "NV", &lpar), 0);
+        if ( lpar != 6 )
+          {
+            fprintf(stderr, "Warning ...\n");
+          }
+        GRIB_CHECK(grib_get_long(gh, "nlev", &lpar), 0);
+        int nhlev = (int)lpar;
+        GRIB_CHECK(grib_get_long(gh, "numberOfVGridUsed", &lpar), 0);
+        int nvgrid = (int)lpar;
+        size_t len = (size_t)CDI_UUID_SIZE;
+        memset(uuid, 0, CDI_UUID_SIZE);
+        GRIB_CHECK(grib_get_bytes(gh, "uuidOfVGrid", uuid, &len), 0);
+        varDefZAxisReference(nhlev, nvgrid, uuid);
+        break;
+      }
     }
 
-  for ( rindex = 0; rindex <= nrecords; rindex++ )
-    {
-      recpos = fileGetPos(fileID);
-      status = extRead(fileID, extp);
-      if ( status != 0 )
-	{
-	  streamptr->ntsteps = 2;
-	  break;
-	}
-      size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
+  // if ( datatype > 32 ) datatype = DATATYPE_PACK32;
+  if ( datatype <  0 ) datatype = DATATYPE_PACK;
 
-      extInqHeader(extp, header);
+  stdname[0] = 0;
+  longname[0] = 0;
+  units[0] = 0;
 
-      vdate  = header[0];
-      vtime  = 0;
-      rcode  = header[1];
-      rlevel = header[2];
-      // rxysize = header[3];
+  if ( varname[0] != 0 )
+    {
+      size_t vlen = CDI_MAX_NAME;
+      gribapiGetString(gh, "name", longname, vlen);
+      vlen = CDI_MAX_NAME;
+      gribapiGetString(gh, "units", units, vlen);
+      vlen = CDI_MAX_NAME;
+      int status = grib_get_string(gh, "cfName", stdname, &vlen);
+      if ( status != 0 || vlen <= 1 || strncmp(stdname, "unknown", 7) == 0 )
+        stdname[0] = 0;
+    }
+  // fprintf(stderr, "param %d name %s %s %s\n", param, name, longname, units);
 
-      param = cdiEncodeParam(rcode, 255, 255);
+  /* add the previously read record data to the (intermediate) list of records */
+  int tile_index = 0, varID;
+  varAddRecord(recID, param, gridID, zaxistype, lbounds, level1, level2, level_sf, level_unit,
+	       datatype, &varID, &levelID, tsteptype, numavg, leveltype1, leveltype2,
+	       varname, stdname, longname, units, tiles, &tile_index);
 
-      if ( rindex == 0 )
-	{
-	  taxis->type  = TAXIS_ABSOLUTE;
-	  taxis->vdate = vdate;
-	  taxis->vtime = vtime;
-	}
+  record->varID   = (short)varID;
+  record->levelID = (short)levelID;
 
-      compVar.param = param;
-      compVar.level = rlevel;
-      nextstep = FALSE;
-      for ( recID = 0; recID < nrecords; recID++ )
-	{
-	  compVar0.param = streamptr->tsteps[tsID].records[recID].param;
-	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+  varDefCompType(varID, comptype);
 
-	  if ( memcmp(&compVar0, &compVar, sizeof(extcompvar_t)) == 0 )
-	    {
-	      if ( streamptr->tsteps[tsID].records[recID].used )
-		{
-		  nextstep = TRUE;
-		}
-	      else
-		{
-		  streamptr->tsteps[tsID].records[recID].used = TRUE;
-		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
-		}
-	      break;
-	    }
-	}
-      if ( recID == nrecords )
-	{
-	  Warning("Code %d level %d not found at timestep %d", rcode, rlevel, tsID+1);
-	  return (CDI_EUFSTRUCT);
-	}
+  /*
+    Get the ensemble Info from the grib-2 Tables and update the intermediate datastructure.
+    Further update to the "vlist" is handled in the same way as for GRIB-1 by "cdi_generate_vars"
+  */
+  if ( grib_get_long(gh, "typeOfEnsembleForecast", &ens_forecast_type) == 0 )
+    {
+      GRIB_CHECK(grib_get_long(gh, "numberOfForecastsInEnsemble", &ens_count ), 0);
+      GRIB_CHECK(grib_get_long(gh, "perturbationNumber", &ens_index ), 0);
+    }
 
-      if ( nextstep ) break;
+  if ( ens_index > 0 )
+    varDefEnsembleInfo(varID, (int)ens_index, (int)ens_count, (int)ens_forecast_type);
 
-      if ( CDI_Debug )
-	Message("%4d%8d%4d%8d%8d%6d", rindex+1, (int)recpos, rcode, rlevel, vdate, vtime);
+  long typeOfGeneratingProcess = 0;
+  if ( grib_get_long(gh, "typeOfGeneratingProcess", &typeOfGeneratingProcess) == 0 )
+    varDefTypeOfGeneratingProcess(varID, (int) typeOfGeneratingProcess);
 
-      streamptr->tsteps[tsID].records[recID].size = recsize;
+  long productDefinitionTemplate = 0;
+  if ( grib_get_long(gh, "productDefinitionTemplateNumber", &productDefinitionTemplate) == 0 )
+    varDefProductDefinitionTemplate(varID, (int) productDefinitionTemplate);
 
-      compVar0.param  = streamptr->tsteps[tsID].records[recID].param;
-      compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+  int    i;
+  long   lval;
+  double dval;
 
-      if ( memcmp(&compVar0, &compVar, sizeof(extcompvar_t)) != 0 )
-	{
-	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
-		  tsID, recID,
-		  streamptr->tsteps[tsID].records[recID].param, param,
-		  streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
-	  return (CDI_EUFSTRUCT);
-	}
+  if (lread_additional_keys)
+    for ( i = 0; i < cdiNAdditionalGRIBKeys; i++ )
+      {
+        /* note: if the key is not defined, we do not throw an error! */
+        if ( grib_get_long(gh, cdiAdditionalGRIBKeys[i], &lval) == 0 )
+          varDefOptGribInt(varID, tile_index, lval, cdiAdditionalGRIBKeys[i]);
+        if ( grib_get_double(gh, cdiAdditionalGRIBKeys[i], &dval) == 0 )
+          varDefOptGribDbl(varID, tile_index, dval, cdiAdditionalGRIBKeys[i]);
+      }
 
-      streamptr->tsteps[1].records[recID].position = recpos;
+  if ( varInqInst(varID) == CDI_UNDEFID )
+    {
+      long center, subcenter;
+      int instID;
+      GRIB_CHECK(grib_get_long(gh, "centre", &center), 0);
+      GRIB_CHECK(grib_get_long(gh, "subCentre", &subcenter), 0);
+      instID    = institutInq((int)center, (int)subcenter, NULL, NULL);
+      if ( instID == CDI_UNDEFID )
+	instID = institutDef((int)center, (int)subcenter, NULL, NULL);
+      varDefInst(varID, instID);
     }
 
-  nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
+  if ( varInqModel(varID) == CDI_UNDEFID )
     {
-      if ( ! streamptr->tsteps[tsID].records[recID].used )
-	{
-	  varID = streamptr->tsteps[tsID].records[recID].varID;
-          vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-	}
-      else
+      int modelID;
+      long processID;
+      if ( grib_get_long(gh, "generatingProcessIdentifier", &processID) == 0 )
 	{
-	  nrecs++;
+          /* FIXME: assert(processID >= INT_MIN && processID <= INT_MAX) */
+	  modelID = modelInq(varInqInst(varID), (int)processID, NULL);
+	  if ( modelID == CDI_UNDEFID )
+	    modelID = modelDef(varInqInst(varID), (int)processID, NULL);
+	  varDefModel(varID, modelID);
 	}
     }
-  streamptr->tsteps[tsID].nrecs = nrecs;
 
-  streamptr->rtsteps = 2;
-
-  if ( streamptr->ntsteps == -1 )
+  if ( varInqTable(varID) == CDI_UNDEFID )
     {
-      tsID = tstepsNewEntry(streamptr);
-      if ( tsID != streamptr->rtsteps )
-	Error("Internal error. tsID = %d", tsID);
+      int pdis, pcat, pnum;
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
-      streamptr->tsteps[tsID].position = recpos;
+      cdiDecodeParam(param, &pnum, &pcat, &pdis);
+
+      if ( pdis == 255 )
+	{
+	  int tableID;
+	  int tabnum = pcat;
+
+	  tableID = tableInq(varInqModel(varID), tabnum, NULL);
+
+	  if ( tableID == CDI_UNDEFID )
+	    tableID = tableDef(varInqModel(varID), tabnum, NULL);
+	  varDefTable(varID, tableID);
+	}
     }
 
-  return (0);
-}
+  streamptr->tsteps[tsID].nallrecs++;
+  streamptr->nrecs++;
 
+  if ( CDI_Debug )
+    Message("varID = %d  param = %d  zaxistype = %d  gridID = %d  levelID = %d",
+	    varID, param, zaxistype, gridID, levelID);
+}
 
-int extInqContents(stream_t *streamptr)
+static compvar2_t gribapiVarSet(int param, int level1, int level2, int leveltype, 
+                                int tsteptype, char *name, var_tile_t tiles_data)
 {
-  int fileID;
-  int status = 0;
+  compvar2_t compVar;
+  size_t maxlen = sizeof(compVar.name);
+  size_t len = strlen(name);
+  if ( len > maxlen ) len = maxlen;
 
-  fileID = streamptr->fileID;
+  compVar.param     = param;
+  compVar.level1    = level1;
+  compVar.level2    = level2;
+  compVar.ltype     = leveltype;
+  compVar.tsteptype = tsteptype;
+  memset(compVar.name, 0, maxlen);
+  memcpy(compVar.name, name, len);
+  compVar.tiles = tiles_data;
 
-  streamptr->curTsID = 0;
+  return (compVar);
+}
 
-  extScanTimestep1(streamptr);
+static
+int gribapiVarCompare(compvar2_t compVar, record_t record, int flag)
+{
+  compvar2_t compVar0;
+  compVar0.param     = record.param;
+  compVar0.level1    = record.ilevel;
+  compVar0.level2    = record.ilevel2;
+  compVar0.ltype     = record.ltype;
+  compVar0.tsteptype = record.tsteptype;
+  memcpy(compVar0.name, record.varname, sizeof(compVar.name));
 
-  if ( streamptr->ntsteps == -1 ) status = extScanTimestep2(streamptr);
+  if ( flag == 0 )
+    {
+      if ( compVar0.tsteptype == TSTEP_INSTANT  && compVar.tsteptype == TSTEP_INSTANT3 ) compVar0.tsteptype = TSTEP_INSTANT3;
+      if ( compVar0.tsteptype == TSTEP_INSTANT3 && compVar.tsteptype == TSTEP_INSTANT  ) compVar0.tsteptype = TSTEP_INSTANT;
+    }
 
-  fileSetPos(fileID, 0, SEEK_SET);
+  compVar0.tiles = record.tiles;
 
-  return (status);
+  return memcmp(&compVar0, &compVar, sizeof(compvar2_t));
 }
 
 static
-long extScanTimestep(stream_t *streamptr)
+void ensureBufferSize(size_t requiredSize, size_t *curSize, void **buffer)
 {
-  int header[4];
-  int status;
-  int fileID;
-  // int rxysize = 0;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  off_t recpos = 0;
-  int recID;
-  int rindex, nrecs = 0;
-  extcompvar_t compVar, compVar0;
-  void *extp = streamptr->record->exsep;
-  /*
-  if ( CDI_Debug )
+  if ( *curSize < requiredSize )
     {
-      Message("streamID = %d", streamptr->self);
-      Message("cts = %d", streamptr->curTsID);
-      Message("rts = %d", streamptr->rtsteps);
-      Message("nts = %d", streamptr->ntsteps);
+      *curSize = requiredSize;
+      *buffer = Realloc(*buffer, *curSize);
     }
-  */
+}
 
-  int tsID  = streamptr->rtsteps;
-  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+static
+grib_handle *gribapiGetDiskRepresentation(size_t recsize, size_t *buffersize, void **gribbuffer, int *outDatatype, int *outCompressionType, long *outUnzipsize)
+{
+  int lieee = FALSE;
 
-  if ( streamptr->tsteps[tsID].recordSize == 0 )
+  grib_handle *gh = grib_handle_new_from_message(NULL, *gribbuffer, recsize);
+  if(gribEditionNumber(gh) > 1)
     {
-      cdi_create_records(streamptr, tsID);
-
-      nrecs = streamptr->tsteps[1].nrecs;
-
-      streamptr->tsteps[tsID].nrecs = nrecs;
-      streamptr->tsteps[tsID].recIDs = (int *) Malloc((size_t)nrecs * sizeof (int));
-      for ( recID = 0; recID < nrecs; recID++ )
-	streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
-
-      fileID = streamptr->fileID;
-
-      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
-
-      for ( rindex = 0; rindex <= nrecs; rindex++ )
-	{
-	  recpos = fileGetPos(fileID);
-	  status = extRead(fileID, extp);
-	  if ( status != 0 )
-	    {
-	      streamptr->ntsteps = streamptr->rtsteps + 1;
-	      break;
-	    }
-	  size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
-
-	  extInqHeader(extp, header);
+      size_t len = 256;
+      char typeOfPacking[256];
 
-	  vdate  = header[0];
-	  vtime  = 0;
-	  rcode  = header[1];
-	  rlevel = header[2];
-	  // rxysize = header[3];
+      if ( grib_get_string(gh, "packingType", typeOfPacking, &len) == 0 )
+        {
+          // fprintf(stderr, "packingType %d %s\n", len, typeOfPacking);
+          if      ( strncmp(typeOfPacking, "grid_jpeg", len) == 0 ) *outCompressionType = COMPRESS_JPEG;
+          else if ( strncmp(typeOfPacking, "grid_ccsds", len) == 0 ) *outCompressionType = COMPRESS_SZIP;
+          else if ( strncmp(typeOfPacking, "grid_ieee", len) == 0 ) lieee = TRUE;
+        }
+    }
+  else
+    {
+      if( gribGetZip((long)recsize, *gribbuffer, outUnzipsize) > 0 )
+        {
+          *outCompressionType = COMPRESS_SZIP;
+          ensureBufferSize((size_t)*outUnzipsize + 100, buffersize, gribbuffer);
+        }
+      else
+        {
+          *outCompressionType = COMPRESS_NONE;
+        }
+    }
 
-	  param = cdiEncodeParam(rcode, 255, 255);
+  if ( lieee )
+    {
+      *outDatatype = DATATYPE_FLT64;
+      long precision;
+      int status = grib_get_long(gh, "precision", &precision);
+      if ( status == 0 && precision == 1 ) *outDatatype = DATATYPE_FLT32;
+    }
+  else
+    {
+      *outDatatype = DATATYPE_PACK;
+      long bitsPerValue;
+      if ( grib_get_long(gh, "bitsPerValue", &bitsPerValue) == 0 )
+        {
+          if ( bitsPerValue > 0 && bitsPerValue <= 32 ) *outDatatype = (int)bitsPerValue;
+        }
+    }
+  return gh;
+}
 
-	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
-	  if ( rindex == nrecs ) continue;
-	  recID = streamptr->tsteps[tsID].recIDs[rindex];
+typedef enum { CHECKTIME_OK, CHECKTIME_SKIP, CHECKTIME_STOP, CHECKTIME_INCONSISTENT } checkTimeResult;
+static checkTimeResult checkTime(stream_t* streamptr, compvar2_t compVar, const DateTime* verificationTime, const DateTime* expectedVTime) {
+  // First determine whether the current record exists already.
+  int recID = 0;
+  for ( ; recID < streamptr->nrecs; recID++ )
+    {
+      if ( gribapiVarCompare(compVar, streamptr->tsteps[0].records[recID], 1) == 0 ) break;
+    }
+  int recordExists = recID < streamptr->nrecs;
 
-	  if ( rindex == 0 )
-	    {
-	      taxis->type  = TAXIS_ABSOLUTE;
-	      taxis->vdate = vdate;
-	      taxis->vtime = vtime;
-	    }
+  // Then we need to know whether the verification time is consistent.
+  int consistentTime = !memcmp(verificationTime, expectedVTime, sizeof(*verificationTime));
 
-	  compVar.param  = param;
-          compVar.level  = rlevel;
-	  compVar0.param = streamptr->tsteps[tsID].records[recID].param;
-	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+  // Finally, we make a decision.
+  if ( cdiInventoryMode == 1 )
+    {
+      if ( recordExists ) return CHECKTIME_STOP;
+      if ( !consistentTime ) return CHECKTIME_INCONSISTENT;
+    }
+  else
+    {
+      if ( !consistentTime ) return CHECKTIME_STOP;
+      if ( recordExists ) return CHECKTIME_SKIP;
+    }
 
-	  if ( memcmp(&compVar0, &compVar, sizeof(extcompvar_t)) != 0 )
-	    {
-	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
-		      tsID, recID,
-		      streamptr->tsteps[tsID].records[recID].param, param,
-		      streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
-	      Error("Invalid, unsupported or inconsistent record structure!");
-	    }
+  return CHECKTIME_OK;
+}
 
-	  streamptr->tsteps[tsID].records[recID].position = recpos;
-	  streamptr->tsteps[tsID].records[recID].size = recsize;
+#define gribWarning(text, nrecs, timestep, varname, param, level1, level2) do \
+  { \
+    char paramstr[32]; \
+    cdiParamToString(param, paramstr, sizeof(paramstr)); \
+    Warning("Record %2d (name=%s id=%s lev1=%d lev2=%d) timestep %d: %s", nrecs, varname, paramstr, level1, level2, timestep, text); \
+  } \
+while(0)
 
-	  if ( CDI_Debug )
-	    Message("%4d%8d%4d%8d%8d%6d", rindex, (int)recpos, rcode, rlevel, vdate, vtime);
-	}
+int gribapiScanTimestep1(stream_t * streamptr)
+{
+  off_t recpos = 0;
+  void *gribbuffer = NULL;
+  size_t buffersize = 0;
+  DateTime datetime0 = { .date = 10101, .time = 0 };
+  int nrecs_scanned = 0;        //Only used for debug output.
+  int warn_time = TRUE;
+  // int warn_numavg = TRUE;
+  int rdate = 0, rtime = 0, tunit = 0, fcast = 0;
+  grib_handle *gh = NULL;
 
-      streamptr->rtsteps++;
+  streamptr->curTsID = 0;
 
-      if ( streamptr->ntsteps != streamptr->rtsteps )
-	{
-	  tsID = tstepsNewEntry(streamptr);
-	  if ( tsID != streamptr->rtsteps )
-	    Error("Internal error. tsID = %d", tsID);
+  int tsID  = tstepsNewEntry(streamptr);
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
-	  streamptr->tsteps[tsID-1].next   = 1;
-	  streamptr->tsteps[tsID].position = recpos;
-	}
+  if ( tsID != 0 )
+    Error("Internal problem! tstepsNewEntry returns %d", tsID);
 
-      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
-      streamptr->tsteps[tsID].position = recpos;
-    }
+  int fileID = streamptr->fileID;
 
-  if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
+  unsigned nrecs = 0;
+  while ( TRUE )
     {
-      Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
-      streamptr->ntsteps = tsID;
-    }
+      int level1 = 0, level2 = 0;
+      size_t recsize = (size_t)gribGetSize(fileID);
+      recpos  = fileGetPos(fileID);
 
-  return (streamptr->ntsteps);
-}
+      if ( recsize == 0 )
+        {
+          streamptr->ntsteps = 1;
+          break;
+        }
+      ensureBufferSize(recsize, &buffersize, &gribbuffer);
 
+      size_t readsize = recsize;
+      int rstatus = gribRead(fileID, gribbuffer, &readsize); //Search for next 'GRIB', read the following record, and position file offset after it.
+      if ( rstatus ) break;
 
-int extInqTimestep(stream_t *streamptr, int tsID)
-{
-  int nrecs;
-  long ntsteps;
+      int datatype, comptype = 0;
+      long unzipsize;
+      gh = gribapiGetDiskRepresentation(recsize, &buffersize, &gribbuffer, &datatype, &comptype, &unzipsize);
 
-  if ( tsID == 0 && streamptr->rtsteps == 0 )
-    Error("Call to cdiInqContents missing!");
+      nrecs_scanned++;
+      GRIB_CHECK(my_grib_set_double(gh, "missingValue", cdiDefaultMissval), 0);
 
-  if ( CDI_Debug )
-    Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
+      int param = gribapiGetParam(gh);
+      int leveltype1 = -1, leveltype2 = -1, lbounds, level_sf, level_unit;
+      var_tile_t tiles = dummy_tiles;
+      gribGetLevel(gh, &leveltype1, &leveltype2, &lbounds, &level1, &level2, &level_sf, &level_unit, &tiles);
 
-  ntsteps = UNDEFID;
-  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == UNDEFID )
-    ntsteps = extScanTimestep(streamptr);
+      char varname[256];
+      varname[0] = 0;
+      gribapiGetString(gh, "shortName", varname, sizeof(varname));
 
-  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
-    {
-      nrecs = 0;
-    }
-  else
-    {
-      streamptr->curTsID = tsID;
-      nrecs = streamptr->tsteps[tsID].nrecs;
-    }
+      int tsteptype = gribapiGetTsteptype(gh);
 
-  return (nrecs);
-}
+      int vdate = 0, vtime = 0;
+      gribapiGetValidityDateTime(gh, &vdate, &vtime);
+      DateTime datetime = { .date = vdate, .time = vtime };
+      /*
+      printf("%d %d %d\n", vdate, vtime, leveltype1);
+      */
 
+      if ( datetime0.date == 10101 && datetime0.time == 0 )
+        {
+          if( datetimeCmp(datetime, datetime0) || !nrecs )       //Do we really need this condition? I have included it in order not to change the number of times gribapiGetDataDateTime() etc. get called. But if those are sideeffect-free, this condition should be removed.
+            {
+              datetime0 = datetime;
 
-void extReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
-{
-  int vlistID, fileID;
-  int levID, nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int header[4];
-  int tsid;
-  int recID;
-  int i;
-  double missval;
-  void *extp = streamptr->record->exsep;
+              gribapiGetDataDateTime(gh, &rdate, &rtime);
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
+              fcast = gribapiTimeIsFC(gh);
+              if ( fcast ) tunit = gribapiGetTimeUnits(gh);
+            }
+        }
 
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+      if ( nrecs )
+        {
+          checkTimeResult result = checkTime(streamptr, gribapiVarSet(param, level1, level2, leveltype1, tsteptype, varname, tiles), &datetime, &datetime0);
+          if ( result == CHECKTIME_STOP )
+            {
+              break;
+            }
+          else if ( result == CHECKTIME_SKIP )
+            {
+              gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, varname, param, level1, level2);
+              continue;
+            }
+          else if ( result == CHECKTIME_INCONSISTENT && warn_time )
+            {
+              gribWarning("Inconsistent verification time!", nrecs_scanned, tsID+1, varname, param, level1, level2);
+              warn_time = FALSE;
+            }
+          assert(result == CHECKTIME_OK || result == CHECKTIME_INCONSISTENT);
+        }
+      /*
+      if ( ISEC1_AvgNum )
+        {
+          if (  taxis->numavg && warn_numavg && (taxis->numavg != ISEC1_AvgNum) )
+            {
+              Message("Change numavg from %d to %d not allowed!",
+                      taxis->numavg, ISEC1_AvgNum);
+              warn_numavg = FALSE;
+            }
+          else
+            {
+              taxis->numavg = ISEC1_AvgNum;
+            }
+        }
+      */
+      nrecs++;
 
-  currentfilepos = fileGetPos(fileID);
+      if ( CDI_Debug )
+        {
+          char paramstr[32];
+          cdiParamToString(param, paramstr, sizeof(paramstr));
+          Message("%4u %8d name=%s id=%s ltype=%d lev1=%d lev2=%d vdate=%d vtime=%d",
+                nrecs, (int)recpos, varname, paramstr, leveltype1, level1, level2, vdate, vtime);
+        }
 
-  for (levID = 0; levID < nlevs; levID++)
-    {
-      /* NOTE: tiles are not supported here! */
-      recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-      recpos = streamptr->tsteps[tsid].records[recID].position;
-      fileSetPos(fileID, recpos, SEEK_SET);
-      extRead(fileID, extp);
-      extInqHeader(extp, header);
-      extInqDataDP(extp, &data[levID*gridsize]);
-    }
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
+      var_tile_t *ptiles = NULL;
+      if ( memcmp(&tiles, &dummy_tiles, sizeof(var_tile_t)) != 0 ) ptiles = &tiles;
+      gribapiAddRecord(streamptr, param, gh, recsize, recpos, datatype, comptype, varname,
+                       leveltype1, leveltype2, lbounds, level1, level2, level_sf, level_unit, ptiles, 1);
 
-  *nmiss = 0;
-  if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
-    {
-      for ( i = 0; i < nlevs*gridsize; i++ )
-	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-	  {
-	    data[i] = missval;
-	    (*nmiss)++;
-	  }
-    }
-  else
-    {
-      for ( i = 0; i < 2*nlevs*gridsize; i+=2 )
-	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-	  {
-	    data[i] = missval;
-	    (*nmiss)++;
-	  }
+      grib_handle_delete(gh);
+      gh = NULL;
     }
-}
-
-
-void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
-{
-  int vlistID, fileID;
-  int nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int header[4];
-  int tsid;
-  int recID;
-  int i;
-  double missval;
-  void *extp = streamptr->record->exsep;
-
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
 
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d",
-	     nlevs, gridID, gridsize);
+  if ( gh ) grib_handle_delete(gh);
 
-  currentfilepos = fileGetPos(fileID);
+  streamptr->rtsteps = 1;
 
-  /* NOTE: tiles are not supported here! */
-  recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-  recpos = streamptr->tsteps[tsid].records[recID].position;
-  fileSetPos(fileID, recpos, SEEK_SET);
-  extRead(fileID, extp);
-  extInqHeader(extp, header);
-  extInqDataDP(extp, data);
+  if ( nrecs == 0 ) return (CDI_EUFSTRUCT);
 
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
+  cdi_generate_vars(streamptr);
 
-  *nmiss = 0;
-  if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
+  int taxisID = -1;
+  if ( fcast )
     {
-      for ( i = 0; i < gridsize; i++ )
-	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-	  {
-	    data[i] = missval;
-	    (*nmiss)++;
-	  }
+      taxisID = taxisCreate(TAXIS_RELATIVE);
+      taxis->type  = TAXIS_RELATIVE;
+      taxis->rdate = rdate;
+      taxis->rtime = rtime;
+      taxis->unit  = tunit;
     }
   else
     {
-      for ( i = 0; i < 2*gridsize; i+=2 )
-	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-	  {
-	    data[i] = missval;
-	    (*nmiss)++;
-	  }
+      taxisID = taxisCreate(TAXIS_ABSOLUTE);
+      taxis->type  = TAXIS_ABSOLUTE;
     }
-}
-
 
-void extWriteVarDP(stream_t *streamptr, int varID, const double *data)
-{
-  int fileID;
-  int levID, nlevs, gridID, gridsize;
-  int zaxisID;
-  double level;
-  int header[4];
-  int tsID;
-  int vlistID;
-  int pdis, pcat, pnum;
-  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
+  taxis->vdate = (int)datetime0.date;
+  taxis->vtime = (int)datetime0.time;
 
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
+  int vlistID = streamptr->vlistID;
+  vlistDefTaxis(vlistID, taxisID);
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  tsID     = streamptr->curTsID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  nlevs    = zaxisInqSize(zaxisID);
+  int nrecords = streamptr->tsteps[0].nallrecs;
+  if ( nrecords < streamptr->tsteps[0].recordSize )
+    {
+      streamptr->tsteps[0].recordSize = nrecords;
+      streamptr->tsteps[0].records =
+        (record_t *) Realloc(streamptr->tsteps[0].records, (size_t)nrecords*sizeof(record_t));
+    }
 
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+  streamptr->tsteps[0].recIDs = (int *) Malloc((size_t)nrecords*sizeof(int));
+  streamptr->tsteps[0].nrecs = nrecords;
+  for ( int recID = 0; recID < nrecords; recID++ )
+    streamptr->tsteps[0].recIDs[recID] = recID;
 
-  cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
+  streamptr->record->buffer     = gribbuffer;
+  streamptr->record->buffersize = buffersize;
 
-  header[0] = streamptr->tsteps[tsID].taxis.vdate;
-  header[1] = pnum;
-  header[3] = gridInqSize(gridID);
+  if ( streamptr->ntsteps == -1 )
+    {
+      tsID = tstepsNewEntry(streamptr);
+      if ( tsID != streamptr->rtsteps )
+        Error("Internal error. tsID = %d", tsID);
 
-  extDefDatatype(vlistInqVarDatatype(vlistID, varID), &extp->prec, &extp->number);
+      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID].position = recpos;
+    }
 
-  for ( levID = 0;  levID < nlevs; levID++ )
+  if ( streamptr->ntsteps == 1 )
     {
-      level = zaxisInqLevel(zaxisID, levID);
-
-      header[2] = (int) level;
-      extDefHeader(extp, header);
-      extDefDataDP(extp, &data[levID*gridsize]);
-      extWrite(fileID, extp);
+      if ( taxis->vdate == 0 && taxis->vtime == 0 )
+        {
+          streamptr->ntsteps = 0;
+          for ( int varID = 0; varID < streamptr->nvars; varID++ )
+            {
+              vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+            }
+        }
     }
+
+  return (0);
 }
 
 
-void extWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
+int gribapiScanTimestep2(stream_t * streamptr)
 {
-  int fileID;
-  int gridID;
-  int zaxisID;
-  double level;
-  int header[4];
-  int tsID;
-  int vlistID;
-  int pdis, pcat, pnum;
-  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
+  int rstatus = 0;
+  off_t recpos = 0;
+  DateTime datetime0 = { LONG_MIN, LONG_MIN };
+  // int gridID;
+  int recID;
+  //  int warn_numavg = TRUE;
+  grib_handle *gh = NULL;
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  tsID     = streamptr->curTsID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  level    = zaxisInqLevel(zaxisID, levID);
+  streamptr->curTsID = 1;
 
-  if ( CDI_Debug )
-    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
+  int fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int taxisID = vlistInqTaxis(vlistID);
 
-  cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
+  void *gribbuffer = streamptr->record->buffer;
+  size_t buffersize = streamptr->record->buffersize;
 
-  header[0] = streamptr->tsteps[tsID].taxis.vdate;
-  header[1] = pnum;
-  header[2] = (int) level;
-  header[3] = gridInqSize(gridID);
+  int tsID = streamptr->rtsteps;
+  if ( tsID != 1 )
+    Error("Internal problem! unexpected timestep %d", tsID+1);
 
-  extDefDatatype(vlistInqVarDatatype(vlistID, varID), &extp->prec, &extp->number);
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
-  extDefHeader(extp, header);
-  extDefDataDP(extp, data);
-  extWrite(fileID, extp);
-}
+  fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
-#endif /* HAVE_LIBEXTRA */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#include <stdlib.h>
+  cdi_create_records(streamptr, tsID);
 
+  int nrecords = streamptr->tsteps[tsID].nallrecs;
+  streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords*sizeof(int));
+  streamptr->tsteps[1].nrecs = 0;
+  for ( recID = 0; recID < nrecords; recID++ )
+    streamptr->tsteps[1].recIDs[recID] = -1;
 
-void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1,
-                       const char *container_name)
-{
+  for ( recID = 0; recID < nrecords; recID++ )
+    {
+      streamptr->tsteps[tsID].records[recID].position = streamptr->tsteps[0].records[recID].position;
+      streamptr->tsteps[tsID].records[recID].size     = streamptr->tsteps[0].records[recID].size;
+    }
 
-  int fileID1 = streamptr1->fileID;
-  int fileID2 = streamptr2->fileID;
+  int nrecs_scanned = nrecords; //Only used for debug output
+  int rindex = 0;
+  while ( TRUE )
+    {
+      if ( rindex > nrecords ) break;
 
-  int tsID    = streamptr1->curTsID;
-  int vrecID  = streamptr1->tsteps[tsID].curRecID;
-  int recID   = streamptr1->tsteps[tsID].recIDs[vrecID];
-  off_t recpos  = streamptr1->tsteps[tsID].records[recID].position;
-  size_t recsize = streamptr1->tsteps[tsID].records[recID].size;
+      size_t recsize = (size_t)gribGetSize(fileID);
+      recpos  = fileGetPos(fileID);
+      if ( recsize == 0 )
+	{
+	  streamptr->ntsteps = 2;
+	  break;
+	}
+      ensureBufferSize(recsize, &buffersize, &gribbuffer);
 
-  if (fileSetPos(fileID1, recpos, SEEK_SET) != 0)
-    Error("Cannot seek input file for %s record copy!", container_name);
+      size_t readsize = recsize;
+      rstatus = gribRead(fileID, gribbuffer, &readsize);
+      if ( rstatus ) break;
 
-  char *buffer = (char *) Malloc(recsize);
+      long unzipsize;
+      if ( gribGetZip((long)recsize, gribbuffer, &unzipsize) > 0 )
+        ensureBufferSize((size_t)unzipsize + 100, &buffersize, &gribbuffer);
 
-  if (fileRead(fileID1, buffer, recsize) != recsize)
-    Error("Failed to read record from %s file for copying!", container_name);
+      nrecs_scanned++;
+      gh = grib_handle_new_from_message(NULL, gribbuffer, recsize);
+      GRIB_CHECK(my_grib_set_double(gh, "missingValue", cdiDefaultMissval), 0);
 
-  if (fileWrite(fileID2, buffer, recsize) != recsize)
-    Error("Failed to write record to %s file when copying!", container_name);
+      int param = gribapiGetParam(gh);
+      int level1 = 0, level2 = 0, leveltype1, leveltype2, lbounds, level_sf, level_unit;
+      var_tile_t tiles = dummy_tiles;
+      gribGetLevel(gh, &leveltype1, &leveltype2, &lbounds, &level1, &level2, &level_sf, &level_unit, &tiles);
 
-  Free(buffer);
-}
+      char varname[256];
+      varname[0] = 0;
+      gribapiGetString(gh, "shortName", varname, sizeof(varname));
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef _STREAM_GRIBAPI_H
-#define _STREAM_GRIBAPI_H
+      int vdate = 0, vtime = 0;
+      gribapiGetValidityDateTime(gh, &vdate, &vtime);
 
-int gribapiScanTimestep1(stream_t * streamptr);
-int gribapiScanTimestep2(stream_t * streamptr);
-int gribapiScanTimestep(stream_t * streamptr);
+      if ( rindex == 0 )
+	{
+	  if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
+	    {
+	      taxis->type  = TAXIS_RELATIVE;
 
-int gribapiDecode(unsigned char *gribbuffer, int gribsize, double *data, int gridsize,
-		  int unreduced, int *nmiss, double missval, int vlistID, int varID);
+              gribapiGetDataDateTime(gh, &(taxis->rdate), &(taxis->rtime));
 
-size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
-		     int vdate, int vtime, int tsteptype, int numavg, 
-		     long datasize, const double *data, int nmiss, unsigned char **gribbuffer, size_t *gribbuffersize,
-		     int ljpeg, void *gribContainer);
+	      taxis->unit  = gribapiGetTimeUnits(gh);
+	    }
+	  else
+	    {
+	      taxis->type  = TAXIS_ABSOLUTE;
+	    }
+	  taxis->vdate = vdate;
+	  taxis->vtime = vtime;
 
-#endif  /* _STREAM_GRIBAPI_H */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
+	  datetime0.date = vdate;
+	  datetime0.time = vtime;
+	}
 
-#include <stdio.h>
-#include <string.h>
+      int tsteptype = gribapiGetTsteptype(gh);
+      /*
+      if ( ISEC1_AvgNum )
+	{
+	  if (  taxis->numavg && warn_numavg &&
+		(taxis->numavg != ISEC1_AvgNum) )
+	    {
+	      warn_numavg = FALSE;
+	    }
+	  else
+	    {
+	      taxis->numavg = ISEC1_AvgNum;
+	    }
+	}
+      */
+      DateTime datetime = {
+        .date = vdate,
+        .time = vtime
+      };
 
+      compvar2_t compVar = gribapiVarSet(param, level1, level2, leveltype1, tsteptype, varname, tiles);
 
+      for ( recID = 0; recID < nrecords; recID++ )
+        if ( gribapiVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) == 0 ) break;
 
+      if ( recID == nrecords )
+	{
+	  gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, varname, param, level1, level2);
+	  return (CDI_EUFSTRUCT);
+	}
 
-int grib1ltypeToZaxisType(int grib_ltype)
-{
-  int zaxistype = ZAXIS_GENERIC;
+      if ( streamptr->tsteps[tsID].records[recID].used )
+        {
+          if ( cdiInventoryMode == 1 ) break;
+          else
+	    {
+	      if ( datetimeCmp(datetime, datetime0) != 0 ) break;
 
-  switch ( grib_ltype )
-    {
-    case GRIB1_LTYPE_SURFACE:            { zaxistype = ZAXIS_SURFACE;                break; }
-    case GRIB1_LTYPE_CLOUD_BASE:         { zaxistype = ZAXIS_CLOUD_BASE;             break; }
-    case GRIB1_LTYPE_CLOUD_TOP:          { zaxistype = ZAXIS_CLOUD_TOP;              break; }
-    case GRIB1_LTYPE_ISOTHERM0:          { zaxistype = ZAXIS_ISOTHERM_ZERO;          break; }
-    case GRIB1_LTYPE_TOA:                { zaxistype = ZAXIS_TOA;                    break; }
-    case GRIB1_LTYPE_SEA_BOTTOM:         { zaxistype = ZAXIS_SEA_BOTTOM;             break; }
-    case GRIB1_LTYPE_ATMOSPHERE:         { zaxistype = ZAXIS_ATMOSPHERE;             break; }
-    case GRIB1_LTYPE_MEANSEA:            { zaxistype = ZAXIS_MEANSEA;                break; }
-    case GRIB1_LTYPE_99:
-    case GRIB1_LTYPE_ISOBARIC:           { zaxistype = ZAXIS_PRESSURE;               break; }
-    case GRIB1_LTYPE_HEIGHT:             { zaxistype = ZAXIS_HEIGHT;                 break; }
-    case GRIB1_LTYPE_ALTITUDE:           { zaxistype = ZAXIS_ALTITUDE;	             break; }
-    case GRIB1_LTYPE_SIGMA:
-    case GRIB1_LTYPE_SIGMA_LAYER:        { zaxistype = ZAXIS_SIGMA;	             break; }
-    case GRIB1_LTYPE_HYBRID:
-    case GRIB1_LTYPE_HYBRID_LAYER:       { zaxistype = ZAXIS_HYBRID;	             break; }
-    case GRIB1_LTYPE_LANDDEPTH:
-    case GRIB1_LTYPE_LANDDEPTH_LAYER:    { zaxistype = ZAXIS_DEPTH_BELOW_LAND;       break; }
-    case GRIB1_LTYPE_ISENTROPIC:         { zaxistype = ZAXIS_ISENTROPIC;             break; }
-    case GRIB1_LTYPE_SEADEPTH:           { zaxistype = ZAXIS_DEPTH_BELOW_SEA;        break; }
-    case GRIB1_LTYPE_LAKE_BOTTOM:        { zaxistype = ZAXIS_LAKE_BOTTOM;            break; }
-    case GRIB1_LTYPE_SEDIMENT_BOTTOM:    { zaxistype = ZAXIS_SEDIMENT_BOTTOM;        break; }
-    case GRIB1_LTYPE_SEDIMENT_BOTTOM_TA: { zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;     break; }
-    case GRIB1_LTYPE_SEDIMENT_BOTTOM_TW: { zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;     break; }
-    case GRIB1_LTYPE_MIX_LAYER:          { zaxistype = ZAXIS_MIX_LAYER;              break; }
-    }
+              gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, varname, param, level1, level2);
+	      continue;
+	    }
+	}
 
-  return (zaxistype);
-}
+      streamptr->tsteps[tsID].records[recID].used = TRUE;
+      streamptr->tsteps[tsID].recIDs[rindex] = recID;
 
+      if ( CDI_Debug )
+        {
+          char paramstr[32];
+          cdiParamToString(param, paramstr, sizeof(paramstr));
+          Message("%4d %8d name=%s id=%s ltype=%d lev1=%d lev2=%d vdate=%d vtime=%d",
+                  nrecs_scanned, (int)recpos, varname, paramstr, leveltype1, level1, level2, vdate, vtime);
+        }
 
-int grib2ltypeToZaxisType(int grib_ltype)
-{
-  int zaxistype = ZAXIS_GENERIC;
+      streamptr->tsteps[tsID].records[recID].size = recsize;
 
-  switch ( grib_ltype )
-    {
-    case GRIB2_LTYPE_SURFACE:            { zaxistype = ZAXIS_SURFACE;                break; }
-    case GRIB2_LTYPE_CLOUD_BASE:         { zaxistype = ZAXIS_CLOUD_BASE;             break; }
-    case GRIB2_LTYPE_CLOUD_TOP:          { zaxistype = ZAXIS_CLOUD_TOP;              break; }
-    case GRIB2_LTYPE_ISOTHERM0:          { zaxistype = ZAXIS_ISOTHERM_ZERO;          break; }
-    case GRIB2_LTYPE_TOA:                { zaxistype = ZAXIS_TOA;                    break; }
-    case GRIB2_LTYPE_SEA_BOTTOM:         { zaxistype = ZAXIS_SEA_BOTTOM;             break; }
-    case GRIB2_LTYPE_ATMOSPHERE:         { zaxistype = ZAXIS_ATMOSPHERE;             break; }
-    case GRIB2_LTYPE_MEANSEA:            { zaxistype = ZAXIS_MEANSEA;                break; }
-    case GRIB2_LTYPE_ISOBARIC:           { zaxistype = ZAXIS_PRESSURE;               break; }
-    case GRIB2_LTYPE_HEIGHT:             { zaxistype = ZAXIS_HEIGHT;                 break; }
-    case GRIB2_LTYPE_ALTITUDE:           { zaxistype = ZAXIS_ALTITUDE;               break; }
-    case GRIB2_LTYPE_SIGMA:              { zaxistype = ZAXIS_SIGMA;                  break; }
-    case GRIB2_LTYPE_HYBRID:
- /* case GRIB2_LTYPE_HYBRID_LAYER: */    { zaxistype = ZAXIS_HYBRID;                 break; }
-    case GRIB2_LTYPE_LANDDEPTH:
- /* case GRIB2_LTYPE_LANDDEPTH_LAYER: */ { zaxistype = ZAXIS_DEPTH_BELOW_LAND;       break; }
-    case GRIB2_LTYPE_ISENTROPIC:         { zaxistype = ZAXIS_ISENTROPIC;             break; }
-    case GRIB2_LTYPE_SNOW:               { zaxistype = ZAXIS_SNOW;                   break; }
-    case GRIB2_LTYPE_SEADEPTH:           { zaxistype = ZAXIS_DEPTH_BELOW_SEA;        break; }
-    case GRIB2_LTYPE_LAKE_BOTTOM:        { zaxistype = ZAXIS_LAKE_BOTTOM;            break; }
-    case GRIB2_LTYPE_SEDIMENT_BOTTOM:    { zaxistype = ZAXIS_SEDIMENT_BOTTOM;        break; }
-    case GRIB2_LTYPE_SEDIMENT_BOTTOM_TA: { zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;     break; }
-    case GRIB2_LTYPE_SEDIMENT_BOTTOM_TW: { zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;     break; }
-    case GRIB2_LTYPE_MIX_LAYER:          { zaxistype = ZAXIS_MIX_LAYER;              break; }
-    case GRIB2_LTYPE_REFERENCE:          { zaxistype = ZAXIS_REFERENCE;              break; }
+      if ( gribapiVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) != 0 )
+	{
+	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
+		  tsID, recID,
+		  streamptr->tsteps[tsID].records[recID].param, param,
+		  streamptr->tsteps[tsID].records[recID].ilevel, level1);
+	  return (CDI_EUFSTRUCT);
+	}
+
+      streamptr->tsteps[1].records[recID].position = recpos;
+      int varID = streamptr->tsteps[tsID].records[recID].varID;
+      /*
+      gridID = vlistInqVarGrid(vlistID, varID);
+      if ( gridInqSize(gridID) == 1 && gridInqType(gridID) == GRID_LONLAT )
+	{
+	  if ( IS_NOT_EQUAL(gridInqXval(gridID, 0),ISEC2_FirstLon*0.001) ||
+	       IS_NOT_EQUAL(gridInqYval(gridID, 0),ISEC2_FirstLat*0.001) )
+	    gridChangeType(gridID, GRID_TRAJECTORY);
+	}
+      */
+      if ( tsteptype != vlistInqVarTsteptype(vlistID, varID) )
+	vlistDefVarTsteptype(vlistID, varID, tsteptype);
+
+      grib_handle_delete(gh);
+      gh = NULL;
+
+      rindex++;
     }
 
-  return (zaxistype);
-}
+  if ( gh ) grib_handle_delete(gh);
 
+  int nrecs = 0;
+  for ( recID = 0; recID < nrecords; recID++ )
+    {
+      if ( ! streamptr->tsteps[tsID].records[recID].used )
+	{
+	  int varID = streamptr->tsteps[tsID].records[recID].varID;
+	  vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	}
+      else
+	{
+	  nrecs++;
+	}
+    }
+  streamptr->tsteps[tsID].nrecs = nrecs;
 
-int zaxisTypeToGrib1ltype(int zaxistype)
-{
-  int grib_ltype = -1;
+  streamptr->rtsteps = 2;
 
-  switch (zaxistype)
+  if ( streamptr->ntsteps == -1 )
     {
-    case ZAXIS_SURFACE:               { grib_ltype = GRIB1_LTYPE_SURFACE;            break; }
-    case ZAXIS_MEANSEA:               { grib_ltype = GRIB1_LTYPE_MEANSEA;            break; }
-    case ZAXIS_HEIGHT:                { grib_ltype = GRIB1_LTYPE_HEIGHT;             break; }
-    case ZAXIS_ALTITUDE:              { grib_ltype = GRIB1_LTYPE_ALTITUDE;           break; }
-    case ZAXIS_SIGMA:                 { grib_ltype = GRIB1_LTYPE_SIGMA;              break; }
-    case ZAXIS_DEPTH_BELOW_SEA:       { grib_ltype = GRIB1_LTYPE_SEADEPTH;           break; }
-    case ZAXIS_ISENTROPIC:            { grib_ltype = GRIB1_LTYPE_ISENTROPIC;         break; }
-    case ZAXIS_CLOUD_BASE:            { grib_ltype = GRIB1_LTYPE_CLOUD_BASE;         break; }
-    case ZAXIS_CLOUD_TOP:             { grib_ltype = GRIB1_LTYPE_CLOUD_TOP;          break; }
-    case ZAXIS_ISOTHERM_ZERO:         { grib_ltype = GRIB1_LTYPE_ISOTHERM0;          break; }
-    case ZAXIS_TOA:                   { grib_ltype = GRIB1_LTYPE_TOA;                break; }
-    case ZAXIS_SEA_BOTTOM:            { grib_ltype = GRIB1_LTYPE_SEA_BOTTOM;         break; }
-    case ZAXIS_LAKE_BOTTOM:           { grib_ltype = GRIB1_LTYPE_LAKE_BOTTOM;        break; }
-    case ZAXIS_SEDIMENT_BOTTOM:       { grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM;    break; }
-    case ZAXIS_SEDIMENT_BOTTOM_TA:    { grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TA; break; }
-    case ZAXIS_SEDIMENT_BOTTOM_TW:    { grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TW; break; }
-    case ZAXIS_MIX_LAYER:             { grib_ltype = GRIB1_LTYPE_MIX_LAYER;          break; }
-    case ZAXIS_ATMOSPHERE:            { grib_ltype = GRIB1_LTYPE_ATMOSPHERE;         break; }
+      tsID = tstepsNewEntry(streamptr);
+      if ( tsID != streamptr->rtsteps )
+	Error("Internal error. tsID = %d", tsID);
+
+      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID].position = recpos;
     }
 
-  return (grib_ltype);
+  streamptr->record->buffer     = gribbuffer;
+  streamptr->record->buffersize = buffersize;
+
+  return (rstatus);
 }
 
 
-int zaxisTypeToGrib2ltype(int zaxistype)
+int gribapiScanTimestep(stream_t * streamptr)
 {
-  int grib_ltype = -1;
+  int vrecID, recID;
+  //int warn_numavg = TRUE;
+  int nrecs = 0;
+  int vlistID = streamptr->vlistID;
 
-  switch (zaxistype)
+  if ( CDI_Debug )
     {
-    case ZAXIS_SURFACE:               { grib_ltype = GRIB2_LTYPE_SURFACE;            break; }
-    case ZAXIS_MEANSEA:               { grib_ltype = GRIB2_LTYPE_MEANSEA;            break; }
-    case ZAXIS_HEIGHT:                { grib_ltype = GRIB2_LTYPE_HEIGHT;             break; }
-    case ZAXIS_ALTITUDE:              { grib_ltype = GRIB2_LTYPE_ALTITUDE;           break; }
-    case ZAXIS_SIGMA:                 { grib_ltype = GRIB2_LTYPE_SIGMA;              break; }
-    case ZAXIS_DEPTH_BELOW_SEA:       { grib_ltype = GRIB2_LTYPE_SEADEPTH;           break; }
-    case ZAXIS_ISENTROPIC:            { grib_ltype = GRIB2_LTYPE_ISENTROPIC;         break; }
-    case ZAXIS_CLOUD_BASE:            { grib_ltype = GRIB2_LTYPE_CLOUD_BASE;         break; }
-    case ZAXIS_CLOUD_TOP:             { grib_ltype = GRIB2_LTYPE_CLOUD_TOP;          break; }
-    case ZAXIS_ISOTHERM_ZERO:         { grib_ltype = GRIB2_LTYPE_ISOTHERM0;          break; }
-    case ZAXIS_TOA:                   { grib_ltype = GRIB2_LTYPE_TOA;                break; }
-    case ZAXIS_SEA_BOTTOM:            { grib_ltype = GRIB2_LTYPE_SEA_BOTTOM;         break; }
-    case ZAXIS_LAKE_BOTTOM:           { grib_ltype = GRIB2_LTYPE_LAKE_BOTTOM;        break; }
-    case ZAXIS_SEDIMENT_BOTTOM:       { grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM;    break; }
-    case ZAXIS_SEDIMENT_BOTTOM_TA:    { grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TA; break; }
-    case ZAXIS_SEDIMENT_BOTTOM_TW:    { grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TW; break; }
-    case ZAXIS_MIX_LAYER:             { grib_ltype = GRIB2_LTYPE_MIX_LAYER;          break; }
-    case ZAXIS_ATMOSPHERE:            { grib_ltype = GRIB2_LTYPE_ATMOSPHERE;         break; }
+      Message("streamID = %d", streamptr->self);
+      Message("cts = %d", streamptr->curTsID);
+      Message("rts = %d", streamptr->rtsteps);
+      Message("nts = %d", streamptr->ntsteps);
     }
 
-  return (grib_ltype);
-}
+  int tsID  = streamptr->rtsteps;
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
+  if ( streamptr->tsteps[tsID].recordSize == 0 )
+    {
+      void *gribbuffer = streamptr->record->buffer;
+      size_t buffersize = streamptr->record->buffersize;
 
-int grbBitsPerValue(int datatype)
-{
-  int bitsPerValue = 16;
+      cdi_create_records(streamptr, tsID);
 
-  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
-    Error("CDI/GRIB library does not support complex numbers!");
+      nrecs = streamptr->tsteps[1].nrecs;
 
-  if ( datatype != CDI_UNDEFID )
-    {
-      if ( datatype > 0 && datatype <= 32 )
-	bitsPerValue = datatype;
-      else if ( datatype == DATATYPE_FLT64 )
-	bitsPerValue = 24;
-      else
-	bitsPerValue = 16;
-    }
+      streamptr->tsteps[tsID].nrecs = nrecs;
+      streamptr->tsteps[tsID].recIDs = (int *) Malloc((size_t)nrecs*sizeof(int));
+      for ( recID = 0; recID < nrecs; recID++ )
+	streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
 
-  return (bitsPerValue);
-}
+      int fileID = streamptr->fileID;
 
+      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
-/*
-int grbInqRecord(stream_t * streamptr, int *varID, int *levelID)
-{
-  int status;
+      int nrecs_scanned = streamptr->tsteps[0].nallrecs + streamptr->tsteps[1].nrecs*(tsID-1);    //Only used for debug output.
+      int rindex = 0;
+      off_t recpos = 0;
+      DateTime datetime0 = { LONG_MIN, LONG_MIN };
+      grib_handle *gh = NULL;
+      char varname[256];
+      while ( TRUE )
+	{
+	  if ( rindex > nrecs ) break;
 
-  status = cgribexInqRecord(streamptr, varID, levelID);
+	  size_t recsize = (size_t)gribGetSize(fileID);
+	  recpos  = fileGetPos(fileID);
+	  if ( recsize == 0 )
+	    {
+	      streamptr->ntsteps = streamptr->rtsteps + 1;
+	      break;
+	    }
 
-  return (status);
-}
-*/
+	  if ( rindex >= nrecs ) break;
 
-void grbDefRecord(stream_t * streamptr)
-{
-  UNUSED(streamptr);
-}
+          ensureBufferSize(recsize, &buffersize, &gribbuffer);
 
-static
-int grbDecode(int filetype, unsigned char *gribbuffer, int gribsize, double *data, int gridsize,
-	      int unreduced, int *nmiss, double missval, int vlistID, int varID)
-{
-  int status = 0;
+	  size_t readsize = recsize;
+	  if (gribRead(fileID, gribbuffer, &readsize))
+	    {
+	      Warning("Inconsistent timestep %d (GRIB record %d/%d)!", tsID+1, rindex+1,
+		      streamptr->tsteps[tsID].recordSize);
+	      break;
+	    }
 
-#if  defined  (HAVE_LIBCGRIBEX)
-  if ( filetype == FILETYPE_GRB )
-    {
-#if  defined  (HAVE_LIBGRIB_API)
-      extern int cdiNAdditionalGRIBKeys;
-      if ( cdiNAdditionalGRIBKeys > 0 )
-	Error("CGRIBEX decode does not support reading of additional GRIB keys!");
-#endif
-      status = cgribexDecode(gribbuffer, gribsize, data, gridsize, unreduced, nmiss, missval);
-    }
-  else
-#endif
-#ifdef HAVE_LIBGRIB_API
-    status = gribapiDecode(gribbuffer, gribsize, data, gridsize, unreduced, nmiss, missval, vlistID, varID);
-#else
-    {
-      (void)vlistID; (void)varID;
-      Error("GRIB_API support not compiled in!");
-    }
-#endif
+          long unzipsize;
+	  if ( gribGetZip((long)recsize, gribbuffer, &unzipsize) > 0 )
+            ensureBufferSize((size_t)unzipsize + 100, &buffersize, &gribbuffer);
+
+          nrecs_scanned++;
+	  gh = grib_handle_new_from_message(NULL, gribbuffer, recsize);
+	  GRIB_CHECK(my_grib_set_double(gh, "missingValue", cdiDefaultMissval), 0);
+
+          int param = gribapiGetParam(gh);
+          int level1 = 0, level2 = 0, leveltype1, leveltype2 = -1, lbounds, level_sf, level_unit;
+          var_tile_t tiles = dummy_tiles;
+          gribGetLevel(gh, &leveltype1, &leveltype2, &lbounds, &level1, &level2, &level_sf, &level_unit, &tiles);
+
+          varname[0] = 0;
+	  gribapiGetString(gh, "shortName", varname, sizeof(varname));
 
-  return (status);
-}
+          int vdate = 0, vtime = 0;
+	  gribapiGetValidityDateTime(gh, &vdate, &vtime);
 
+	  if ( rindex == nrecs ) break;
 
-static int grbUnzipRecord(unsigned char *gribbuffer, size_t *gribsize)
-{
-  int zip = 0;
-  int izip;
-  size_t igribsize;
-  size_t ogribsize;
-  long unzipsize;
+	  if ( rindex == 0 )
+	    {
+              int taxisID = vlistInqTaxis(vlistID);
+	      if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
+		{
+		  taxis->type  = TAXIS_RELATIVE;
 
-  igribsize = *gribsize;
-  ogribsize = *gribsize;
+                  gribapiGetDataDateTime(gh, &(taxis->rdate), &(taxis->rtime));
 
-  if ( (izip = gribGetZip((long)igribsize, gribbuffer, &unzipsize)) > 0 )
-    {
-      zip = izip;
-      if ( izip == 128 ) /* szip */
-	{
-	  unsigned char *itmpbuffer = NULL;
-	  size_t itmpbuffersize = 0;
+		  taxis->unit  = gribapiGetTimeUnits(gh);
+		}
+	      else
+		{
+		  taxis->type  = TAXIS_ABSOLUTE;
+		}
+	      taxis->vdate = vdate;
+	      taxis->vtime = vtime;
 
-	  if ( unzipsize < (long) igribsize )
-	    {
-	      fprintf(stderr, "Decompressed size smaller than compressed size (in %ld; out %ld)!\n", (long)igribsize, unzipsize);
-	      return (0);
+	      datetime0.date = vdate;
+	      datetime0.time = vtime;
 	    }
-
-	  if ( itmpbuffersize < igribsize )
+	  /*
+	  if ( ISEC1_AvgNum )
 	    {
-	      itmpbuffersize = igribsize;
-	      itmpbuffer = (unsigned char *) Realloc(itmpbuffer, itmpbuffersize);
+	      if (  taxis->numavg && warn_numavg &&
+		   (taxis->numavg != ISEC1_AvgNum) )
+		{
+		  warn_numavg = FALSE;
+		}
+	      else
+		{
+		  taxis->numavg = ISEC1_AvgNum;
+		}
 	    }
+	  */
+          DateTime datetime = {
+            .date  = vdate,
+            .time  = vtime
+          };
 
-	  memcpy(itmpbuffer, gribbuffer, itmpbuffersize);
-
-	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
-
-	  ogribsize = (size_t)gribUnzip(gribbuffer, unzipsize, itmpbuffer, (long)igribsize);
+          int tsteptype = gribapiGetTsteptype(gh);
 
-	  Free(itmpbuffer);
+          compvar2_t compVar = gribapiVarSet(param, level1, level2, leveltype1, tsteptype, varname, tiles);
 
-	  if ( ogribsize <= 0 ) Error("Decompression problem!");
-	}
-      else
-	{
-	  Error("Decompression for %d not implemented!", izip);
-	}
-    }
+	  for ( vrecID = 0; vrecID < nrecs; vrecID++ )
+	    {
+	      recID   = streamptr->tsteps[1].recIDs[vrecID];
+	      if ( gribapiVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) == 0 ) break;
+	    }
 
-  *gribsize = ogribsize;
+	  if ( vrecID == nrecs )
+	    {
+	      gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, varname, param, level1, level2);
 
-  return zip;
-}
+	      if ( cdiInventoryMode == 1 )
+		return (CDI_EUFSTRUCT);
+	      else
+		continue;
+	    }
 
+	  if ( cdiInventoryMode != 1 )
+	    {
+	      if ( streamptr->tsteps[tsID].records[recID].used )
+		{
+		  if ( datetimeCmp(datetime, datetime0) != 0 ) break;
 
-void grbReadRecord(stream_t * streamptr, double *data, int *nmiss)
-{
-  int filetype = streamptr->filetype;
+		  if ( CDI_Debug )
+                    gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, varname, param, level1, level2);
 
-  unsigned char *gribbuffer = (unsigned char *) streamptr->record->buffer;
+		  continue;
+		}
+	    }
 
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-  int tsID    = streamptr->curTsID;
-  int vrecID  = streamptr->tsteps[tsID].curRecID;
-  int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-  off_t recpos  = streamptr->tsteps[tsID].records[recID].position;
-  size_t recsize = streamptr->tsteps[tsID].records[recID].size;
-  int varID   = streamptr->tsteps[tsID].records[recID].varID;
+          streamptr->tsteps[tsID].records[recID].used = TRUE;
+          streamptr->tsteps[tsID].recIDs[rindex] = recID;
 
-  int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
+	  if ( CDI_Debug )
+	    Message("%4d %8d %4d %8d %8d %6d", rindex+1, (int)recpos, param, level1, vdate, vtime);
 
-  streamptr->numvals += gridsize;
+	  if ( gribapiVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) != 0 )
+	    {
+	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
+		      tsID, recID,
+		      streamptr->tsteps[tsID].records[recID].param, param,
+		      streamptr->tsteps[tsID].records[recID].ilevel, level1);
+	      Error("Invalid, unsupported or inconsistent record structure");
+	    }
 
-  fileSetPos(fileID, recpos, SEEK_SET);
+	  streamptr->tsteps[tsID].records[recID].position = recpos;
+	  streamptr->tsteps[tsID].records[recID].size = recsize;
 
-  if (fileRead(fileID, gribbuffer, recsize) != recsize)
-    Error("Failed to read GRIB record");
+	  if ( CDI_Debug )
+	    Message("%4d %8d %4d %8d %8d %6d", rindex, (int)recpos, param, level1, vdate, vtime);
 
-  double missval = vlistInqVarMissval(vlistID, varID);
+	  grib_handle_delete(gh);
+	  gh = NULL;
 
-  streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
+	  rindex++;
+	}
 
-  grbDecode(filetype, gribbuffer, (int)recsize, data, gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
-}
+      if ( gh ) grib_handle_delete(gh);
 
-static
-int grbScanTimestep1(stream_t * streamptr)
-{
-  int status = CDI_EUFTYPE;
+      for ( vrecID = 0; vrecID < nrecs; vrecID++ )
+	{
+	  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
+	  if ( ! streamptr->tsteps[tsID].records[recID].used ) break;
+	}
 
-#if  defined  (HAVE_LIBCGRIBEX)
-  int filetype  = streamptr->filetype;
+      if ( vrecID < nrecs )
+	{
+	  gribWarning("Paramameter not found!", nrecs_scanned, tsID+1, varname, streamptr->tsteps[tsID].records[recID].param,
+                      streamptr->tsteps[tsID].records[recID].ilevel, streamptr->tsteps[tsID].records[recID].ilevel2);
+	  return (CDI_EUFSTRUCT);
+	}
 
-  if ( filetype == FILETYPE_GRB )
-    status = cgribexScanTimestep1(streamptr);
-#endif
-#if defined(HAVE_LIBCGRIBEX) && defined (HAVE_LIBGRIB_API)
-  else
-#endif
-#ifdef HAVE_LIBGRIB_API
-    status = gribapiScanTimestep1(streamptr);
-#endif
+      streamptr->rtsteps++;
 
-  return (status);
-}
+      if ( streamptr->ntsteps != streamptr->rtsteps )
+	{
+	  tsID = tstepsNewEntry(streamptr);
+	  if ( tsID != streamptr->rtsteps )
+	    Error("Internal error. tsID = %d", tsID);
 
-static
-int grbScanTimestep2(stream_t * streamptr)
-{
-  int status = CDI_EUFTYPE;
+	  streamptr->tsteps[tsID-1].next   = 1;
+	  streamptr->tsteps[tsID].position = recpos;
+	}
 
-#if  defined  (HAVE_LIBCGRIBEX)
-  int filetype = streamptr->filetype;
+      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+      streamptr->tsteps[tsID].position = recpos;
 
-  if ( filetype == FILETYPE_GRB )
-    {
-      status = cgribexScanTimestep2(streamptr);
+      streamptr->record->buffer     = gribbuffer;
+      streamptr->record->buffersize = buffersize;
     }
-#endif
-#if defined(HAVE_LIBCGRIBEX) && defined (HAVE_LIBGRIB_API)
-  else
-#endif
-#ifdef HAVE_LIBGRIB_API
-    status = gribapiScanTimestep2(streamptr);
-#endif
-
-  return (status);
-}
-
-static
-int grbScanTimestep(stream_t * streamptr)
-{
-  int status = CDI_EUFTYPE;
-  int filetype;
-
-  filetype  = streamptr->filetype;
 
-#if  defined  (HAVE_LIBCGRIBEX)
-  if ( filetype == FILETYPE_GRB )
+  if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
     {
-      status = cgribexScanTimestep(streamptr);
+      Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
+      streamptr->ntsteps = tsID;
     }
-  else
-#endif
-#ifdef HAVE_LIBGRIB_API
-    status = gribapiScanTimestep(streamptr);
-#else
-    Error("Sufficient GRIB support unavailable!");
-#endif
 
-  return (status);
+  return (int)streamptr->ntsteps;
 }
 
+#ifdef gribWarning
+#undef gribWarning
+#endif
 
-#if  defined  (HAVE_LIBGRIB)
-int grbInqContents(stream_t * streamptr)
+int gribapiDecode(void *gribbuffer, int gribsize, double *data, long gridsize,
+		  int unreduced, int *nmiss, double missval, int vlistID, int varID)
 {
-  int fileID;
   int status = 0;
+  long lpar;
+  long numberOfPoints;
+  size_t datasize;
 
-  fileID = streamptr->fileID;
-
-  streamptr->curTsID = 0;
+  UNUSED(vlistID);
+  UNUSED(varID);
 
-  status = grbScanTimestep1(streamptr);
+  if ( unreduced )
+    {
+      static int lwarn = 1;
 
-  if ( status == 0 && streamptr->ntsteps == -1 ) status = grbScanTimestep2(streamptr);
+      if ( lwarn )
+	{
+	  lwarn = 0;
+	  Warning("Conversion of gaussian reduced grids unsupported!");
+	}
+    }
 
-  fileSetPos(fileID, 0, SEEK_SET);
+  size_t recsize = (size_t)gribsize;
+  grib_handle *gh = grib_handle_new_from_message(NULL, gribbuffer, recsize);
+  GRIB_CHECK(my_grib_set_double(gh, "missingValue", missval), 0);
 
-  return (status);
-}
-#endif
+  /* get the size of the values array*/
+  GRIB_CHECK(grib_get_size(gh, "values", &datasize), 0);
+  GRIB_CHECK(grib_get_long(gh, "numberOfPoints", &numberOfPoints), 0);
 
-int grbInqTimestep(stream_t * streamptr, int tsID)
-{
-  int ntsteps, nrecs;
+  // printf("values_size = %d  numberOfPoints = %ld\n", datasize, numberOfPoints);
 
-  if ( tsID == 0 && streamptr->rtsteps == 0 )
-    Error("Call to cdiInqContents missing!");
+  if ( gridsize != (long) datasize )
+    Error("Internal problem: gridsize(%ld) != datasize(%zu)!", gridsize, datasize);
+  size_t dummy = datasize;
+  GRIB_CHECK(grib_get_double_array(gh, "values", data, &dummy), 0);
 
-  if ( CDI_Debug )
-    Message("tsid = %d rtsteps = %d", tsID, streamptr->rtsteps);
+  GRIB_CHECK(grib_get_long(gh, "gridDefinitionTemplateNumber", &lpar), 0);
+  int gridtype = (int) lpar;
 
-  ntsteps = CDI_UNDEFID;
-  while ( (tsID + 1) > streamptr->rtsteps && ntsteps == CDI_UNDEFID )
+  *nmiss = 0;
+  if ( gridtype < 50 || gridtype > 53 )
     {
-      ntsteps = grbScanTimestep(streamptr);
-      if ( ntsteps == CDI_EUFSTRUCT )
-	{
-	  streamptr->ntsteps = streamptr->rtsteps;
-	  break;
-	}
+      GRIB_CHECK(grib_get_long(gh, "numberOfMissing", &lpar), 0);
+      *nmiss = (int) lpar;
+      // printf("gridtype %d, nmiss %d\n", gridtype, nmiss);
     }
 
-  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
-    {
-      nrecs = 0;
-    }
-  else
-    {
-      streamptr->curTsID = tsID;
-      nrecs = streamptr->tsteps[tsID].nrecs;
-    }
+  grib_handle_delete(gh);
 
-  return (nrecs);
+  return status;
 }
 
 
-void grbReadVarDP(stream_t * streamptr, int varID, double *data, int *nmiss)
+static
+void gribapiDefInstitut(grib_handle *gh, int vlistID, int varID)
 {
-  int filetype = streamptr->filetype;
-
-  unsigned char *gribbuffer = (unsigned char *) streamptr->record->buffer;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-  int tsID    = streamptr->curTsID;
-
-  int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
-
-  off_t currentfilepos = fileGetPos(fileID);
+  int instID;
 
+  if ( vlistInqInstitut(vlistID) != CDI_UNDEFID )
+    instID = vlistInqInstitut(vlistID);
+  else
+    instID = vlistInqVarInstitut(vlistID, varID);
 
-  int isub     = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
-  int nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
-  *nmiss = 0;
-  for (int levelID = 0; levelID < nlevs; levelID++ )
+  if ( instID != CDI_UNDEFID )
     {
-      int    recID   = streamptr->vars[varID].recordTable[isub].recordID[levelID];
-      off_t  recpos  = streamptr->tsteps[tsID].records[recID].position;
-      size_t recsize = streamptr->tsteps[tsID].records[recID].size;
-
-      fileSetPos(fileID, recpos, SEEK_SET);
-
-      fileRead(fileID, gribbuffer, recsize);
+      long center, subcenter;
+      long center0, subcenter0;
 
-      double missval = vlistInqVarMissval(vlistID, varID);
+      center    = institutInqCenter(instID);
+      subcenter = institutInqSubcenter(instID);
 
-      int imiss;
+      GRIB_CHECK(grib_get_long(gh, "centre", &center0), 0);
+      GRIB_CHECK(grib_get_long(gh, "subCentre", &subcenter0), 0);
 
-      streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
+      if ( center != center0 )
+	GRIB_CHECK(my_grib_set_long(gh, "centre", center), 0);
+      if ( subcenter != subcenter0 )
+	GRIB_CHECK(my_grib_set_long(gh, "subCentre", subcenter), 0);
+    }
+}
 
-      grbDecode(filetype, gribbuffer, (int)recsize, &data[levelID*gridsize], gridsize,
-                streamptr->unreduced, &imiss, missval, vlistID, varID);
+static
+void gribapiDefModel(grib_handle *gh, int vlistID, int varID)
+{
+  int modelID;
 
-      *nmiss += imiss;
-    }
+  if ( vlistInqModel(vlistID) != CDI_UNDEFID )
+    modelID = vlistInqModel(vlistID);
+  else
+    modelID = vlistInqVarModel(vlistID, varID);
 
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
+  if ( modelID != CDI_UNDEFID )
+    GRIB_CHECK(my_grib_set_long(gh, "generatingProcessIdentifier", modelInqGribID(modelID)), 0);
 }
 
-
-void grbReadVarSliceDP(stream_t * streamptr, int varID, int levelID, double *data, int *nmiss)
+static
+void gribapiDefParam(int editionNumber, grib_handle *gh, int param, const char *name, const char *stdname)
 {
-  int filetype = streamptr->filetype;
-
-  unsigned char *gribbuffer = (unsigned char *) streamptr->record->buffer;
+  bool ldefined = false;
 
-  int vlistID = streamptr->vlistID;
-  int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
-  int tsID = streamptr->curTsID;
+  int pdis, pcat, pnum;
+  cdiDecodeParam(param, &pnum, &pcat, &pdis);
 
-  if ( CDI_Debug )
-    Message("gridID = %d gridsize = %d", gridID, gridsize);
+  if ( pnum < 0 )
+    {
+      size_t len;
+      len = strlen(stdname);
+      if ( len )
+        {
+          int status = my_grib_set_string(gh, "cfName", stdname, &len);
+          if ( status == 0 ) ldefined = true;
+          else Warning("grib_api: No match for cfName=%s", stdname);
+        }
 
-  int fileID = streamptr->fileID;
+      if ( ldefined == false )
+        {
+          len = strlen(name);
+          int status = my_grib_set_string(gh, "shortName", name, &len);
+          if ( status == 0 ) ldefined = true;
+          else Warning("grib_api: No match for shortName=%s", name);
+        }
+    }
 
-  off_t currentfilepos = fileGetPos(fileID);
+  if ( ldefined == false )
+    {
+      if ( pnum < 0 ) pnum = -pnum;
 
-  int    isub    = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
+      static bool lwarn_pnum = true;
+      if ( pnum > 255 && lwarn_pnum )
+        {
+          Warning("Parameter number %d out of range (1-255), set to %d!", pnum, pnum%256);
+          lwarn_pnum = false;
+          pnum = pnum%256;
+        }
 
+      if ( editionNumber <= 1 )
+	{
+          static bool lwarn_pdis = true;
+	  if ( pdis != 255 && lwarn_pdis )
+	    {
+	      char paramstr[32];
+	      cdiParamToString(param, paramstr, sizeof(paramstr));
+	      Warning("Can't convert GRIB2 parameter ID (%s) to GRIB1, set to %d.%d!", paramstr, pnum, pcat);
+              lwarn_pdis = false;
+	    }
 
-  int    recID   = streamptr->vars[varID].recordTable[isub].recordID[levelID];
-  off_t  recpos  = streamptr->tsteps[tsID].records[recID].position;
-  size_t recsize = streamptr->tsteps[tsID].records[recID].size;
+	  GRIB_CHECK(my_grib_set_long(gh, "table2Version",        pcat), 0);
+	  GRIB_CHECK(my_grib_set_long(gh, "indicatorOfParameter", pnum), 0);
+	}
+      else
+	{
+	  GRIB_CHECK(my_grib_set_long(gh, "discipline",        pdis), 0);
+	  GRIB_CHECK(my_grib_set_long(gh, "parameterCategory", pcat), 0);
+	  GRIB_CHECK(my_grib_set_long(gh, "parameterNumber",   pnum), 0);
+	}
+    }
 
-  if ( recsize == 0 )
-    Error("Internal problem! Recordsize is zero for record %d at timestep %d",
-	  recID+1, tsID+1);
+  // printf("param: %d.%d.%d %s\n", pnum, pcat, pdis, name);
+}
 
-  fileSetPos(fileID, recpos, SEEK_SET);
+static
+int getTimeunitFactor(int timeunit)
+{
+  int factor = 1;
 
-  fileRead(fileID, gribbuffer, recsize);
+  switch (timeunit)
+    {
+    case TUNIT_SECOND:  factor =     1;  break;
+    case TUNIT_MINUTE:  factor =    60;  break;
+    case TUNIT_HOUR:    factor =  3600;  break;
+    case TUNIT_3HOURS:  factor = 10800;  break;
+    case TUNIT_6HOURS:  factor = 21600;  break;
+    case TUNIT_12HOURS: factor = 43200;  break;
+    case TUNIT_DAY:     factor = 86400;  break;
+    default:            factor =  3600;  break;
+    }
 
-  double missval = vlistInqVarMissval(vlistID, varID);
+  return (factor);
+}
 
-  streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
+static
+void gribapiDefStepUnits(grib_handle *gh, int timeunit, int proDefTempNum, int gcinit)
+{
+  long unitsOfTime;
 
-  grbDecode(filetype, gribbuffer, (int)recsize, data, gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
+  switch (timeunit)
+    {
+    case TUNIT_SECOND:  unitsOfTime = 13;  break;
+    case TUNIT_MINUTE:  unitsOfTime =  0;  break;
+    case TUNIT_HOUR:    unitsOfTime =  1;  break;
+    case TUNIT_3HOURS:  unitsOfTime = 10;  break;
+    case TUNIT_6HOURS:  unitsOfTime = 11;  break;
+    case TUNIT_12HOURS: unitsOfTime = 12;  break;
+    case TUNIT_DAY:     unitsOfTime =  2;  break;
+    default:            unitsOfTime =  1;  break;
+    }
 
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
+  if ( !gcinit )
+    {
+      GRIB_CHECK(my_grib_set_long(gh, "stepUnits", unitsOfTime), 0);
+      if ( proDefTempNum == 8 || proDefTempNum == 11 )
+        GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitForTimeRange", unitsOfTime), 0);
+      GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime), 0);
+    }
 }
 
 static
-size_t grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
-		 int date, int time, int tsteptype, int numavg,
-		 size_t datasize, const double *data, int nmiss, unsigned char **gribbuffer,
-		 int comptype, void *gribContainer)
+int gribapiDefSteptype(int editionNumber, grib_handle *gh, int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int gcinit)
 {
-  size_t nbytes = 0;
+  long proDefTempNum = 0;
+  size_t len = 64;
+  const char *stepType;
 
-#if  defined  (HAVE_LIBCGRIBEX)
-  if ( filetype == FILETYPE_GRB )
+  static struct {
+    long productionTemplate;
+    const char sname[8];
+  } ts_tab[] = {
+    [TSTEP_INSTANT] = {  0, "instant" },
+    [TSTEP_AVG] = { 8, "avg" },
+    [TSTEP_ACCUM] = {  8, "accum" },
+    [TSTEP_MAX] = {  8, "max" },
+    [TSTEP_MIN] = {  8, "min" },
+    [TSTEP_DIFF] = {  8, "diff" },
+    [TSTEP_RMS] = {  8, "rms" },
+    [TSTEP_SD] = {  8, "sd" },
+    [TSTEP_COV] = { 8, "cov" },
+    [TSTEP_RATIO] = {  8, "ratio" }
+  };
+  if (tsteptype >= TSTEP_INSTANT && tsteptype <= TSTEP_RATIO)
     {
-      size_t gribbuffersize = datasize*4+3000;
-      *gribbuffer = (unsigned char *) Malloc(gribbuffersize);
-
-      nbytes = cgribexEncode(memtype, varID, levelID, vlistID, gridID, zaxisID,
-			     date, time, tsteptype, numavg,
-			     (long)datasize, data, nmiss, *gribbuffer, gribbuffersize);
+      stepType = ts_tab[tsteptype].sname;
+      proDefTempNum = ts_tab[tsteptype].productionTemplate;
     }
   else
-#endif
-#ifdef HAVE_LIBGRIB_API
     {
-      if ( memtype == MEMTYPE_FLOAT ) Error("gribapiEncode() not implemented for memtype float!");
+      stepType = "instant";
+      proDefTempNum = 0;
+    }
 
-      size_t gribbuffersize;
-      nbytes = gribapiEncode(varID, levelID, vlistID, gridID, zaxisID,
-			     date, time, tsteptype, numavg,
-			     (long)datasize, data, nmiss, gribbuffer, &gribbuffersize,
-			     comptype, gribContainer);
+  if ( typeOfGeneratingProcess == 4 )
+    {
+      if ( proDefTempNum == 8 ) proDefTempNum = 11;
+      else                      proDefTempNum = 1;
     }
-#else
-    Error("GRIB_API support not compiled in!");
-    (void)gribContainer;
-    (void)comptype;
-#endif
 
+  if ( productDefinitionTemplate != -1 ) proDefTempNum = productDefinitionTemplate;
+
+  if ( !gcinit )
+    {
+      if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "productDefinitionTemplateNumber", proDefTempNum), 0);
+      len = strlen(stepType);
+      GRIB_CHECK(my_grib_set_string(gh, "stepType", stepType, &len), 0);
+    }
 
-  return (nbytes);
+  return ((int)proDefTempNum);
 }
 
 static
-size_t grbSzip(int filetype, unsigned char *gribbuffer, size_t gribbuffersize)
+void gribapiDefDateTimeAbs(int editionNumber, grib_handle *gh, int date, int time, int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int gcinit)
 {
-  size_t nbytes = 0;
-  unsigned char *buffer;
-  size_t buffersize;
-  static int lszip_warn = 1;
-
-  buffersize = gribbuffersize + 1000; /* compressed record can be greater than source record */
-  buffer = (unsigned char *) Malloc(buffersize);
-
-  /*  memcpy(buffer, gribbuffer, gribbuffersize); */
-
-  if ( filetype == FILETYPE_GRB )
-    {
-      nbytes = (size_t)gribZip(gribbuffer, (long) gribbuffersize, buffer, (long) buffersize);
-    }
-  else
-    {
-      if ( lszip_warn ) Warning("Szip compression of GRIB2 records not implemented!");
-      lszip_warn = 0;
-      nbytes = gribbuffersize;
-    }
+  (void ) gribapiDefSteptype(editionNumber, gh, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
 
-  Free(buffer);
+  if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "significanceOfReferenceTime", 0), 0);
+  if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "stepRange", 0), 0);
 
-  return (nbytes);
+  if ( date == 0 ) date = 10101;
+  gribapiSetDataDateTime(gh, date, time);
 }
 
-
-void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
+static
+int gribapiDefDateTimeRel(int editionNumber, grib_handle *gh, int rdate, int rtime, int vdate, int vtime,
+                          int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int timeunit, int calendar, int gcinit)
 {
-  size_t nwrite;
-  int fileID;
-  int gridID;
-  int zaxisID;
-  unsigned char *gribbuffer = NULL;
-  int tsID;
-  int vlistID;
-  int date, time;
-  int tsteptype;
-  int numavg = 0;
-  size_t nbytes;
-  int filetype;
-  void *gc = NULL;
-
-  filetype  = streamptr->filetype;
-  fileID    = streamptr->fileID;
-  vlistID   = streamptr->vlistID;
-  gridID    = vlistInqVarGrid(vlistID, varID);
-  zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  int status = -1;
+  int year, month, day, hour, minute, second;
+  int julday1, secofday1, julday2, secofday2, days, secs;
+  long startStep = 0, endStep;
 
-  int comptype  = streamptr->comptype;
+  cdiDecodeDate(rdate, &year, &month, &day);
+  cdiDecodeTime(rtime, &hour, &minute, &second);
+  encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday1, &secofday1);
 
-  tsID      = streamptr->curTsID;
-  date      = streamptr->tsteps[tsID].taxis.vdate;
-  time      = streamptr->tsteps[tsID].taxis.vtime;
-  if ( vlistInqVarTimave(vlistID, varID) )
-    numavg = streamptr->tsteps[tsID].taxis.numavg;
+  if ( vdate == 0 && vtime == 0 ) { vdate = rdate; vtime = rtime; }
 
-  if ( CDI_Debug )
-    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
+  cdiDecodeDate(vdate, &year, &month, &day);
+  cdiDecodeTime(vtime, &hour, &minute, &second);
+  encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday2, &secofday2);
 
-  size_t datasize = (size_t)gridInqSize(gridID);
-  /*
-  gribbuffersize = datasize*4+3000;
-  gribbuffer = (unsigned char *) Malloc(gribbuffersize);
-  */
-#if  defined  (HAVE_LIBCGRIBEX)
-  if ( filetype == FILETYPE_GRB )
-    {
-    }
-  else
-#endif
-    {
-#if defined (GRIBCONTAINER2D)
-      gribContainer_t **gribContainers =  (gribContainer_t **) streamptr->gribContainers;
-      gc = (void *) &gribContainers[varID][levelID];
-#else
-      gribContainer_t *gribContainers =  (gribContainer_t *) streamptr->gribContainers;
-      gc = (void *) &gribContainers[varID];
-#endif
-    }
+  (void) julday_sub(julday1, secofday1, julday2, secofday2, &days, &secs);
 
-  if ( comptype != COMPRESS_JPEG && comptype != COMPRESS_SZIP ) comptype = COMPRESS_NONE;
+  int factor = getTimeunitFactor(timeunit);
 
-  if ( filetype == FILETYPE_GRB && comptype == COMPRESS_JPEG )
+  if ( !(int) fmod(days*86400.0 + secs, factor) )
     {
-      static int ljpeg_warn = 1;
-      if ( ljpeg_warn ) Warning("JPEG compression of GRIB1 records not available!");
-      ljpeg_warn = 0;
-    }
-
-  nbytes = grbEncode(filetype, memtype, varID, levelID, vlistID, gridID, zaxisID, date, time, tsteptype, numavg,
-		     datasize, (const double*) data, nmiss, &gribbuffer, comptype, gc);
+      int proDefTempNum = gribapiDefSteptype(editionNumber, gh, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
 
-  if ( filetype == FILETYPE_GRB && streamptr->comptype == COMPRESS_SZIP )
-    nbytes = grbSzip(filetype, gribbuffer, nbytes);
+      gribapiDefStepUnits(gh, timeunit, proDefTempNum, gcinit);
 
-  {
-    size_t (*myFileWrite)(int fileID, const void *restrict buffer,
-                          size_t len, int tsID)
-      = (size_t (*)(int, const void *restrict, size_t, int))
-      namespaceSwitchGet(NSSWITCH_FILE_WRITE).func;
-    nwrite = myFileWrite(fileID, gribbuffer, nbytes, tsID);
-  }
+      endStep = (int) ((days*86400.0 + secs)/factor);
 
-  if ( nwrite != nbytes )
-    {
-      perror(__func__);
-      Error("Failed to write GRIB slice!");
-    }
+      if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "significanceOfReferenceTime", 1), 0);
+      if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "stepRange", 0), 0);
 
-  if ( gribbuffer ) Free(gribbuffer);
-}
+      if ( rdate == 0 ) rdate = 10101;
+      gribapiSetDataDateTime(gh, rdate, rtime);
 
+      // printf(">>>>> tsteptype %d  startStep %ld  endStep %ld\n", tsteptype, startStep, endStep);
 
-void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
-{
-  int vlistID, gridID, zaxisID, levelID, nlevs;
-  int gridsize;
+      // Product Definition Template Number: defined in GRIB_API file 4.0.table
+      // point in time products:
+      if ( (proDefTempNum >= 0 && proDefTempNum <=  7) || 
+           proDefTempNum == 55 || proDefTempNum == 40055 ) // Tile
+        startStep = endStep;
 
-  vlistID  = streamptr->vlistID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  nlevs    = zaxisInqSize(zaxisID);
+      if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "forecastTime", startStep), 0);
+      GRIB_CHECK(my_grib_set_long(gh, "endStep", endStep), 0);
 
-  for ( levelID = 0; levelID < nlevs; levelID++ )
-    {
-      if ( memtype == MEMTYPE_FLOAT )
-        grb_write_var_slice(streamptr, varID, levelID, memtype, ((float*)data)+levelID*gridsize, nmiss);
-      else
-        grb_write_var_slice(streamptr, varID, levelID, memtype, ((double*)data)+levelID*gridsize, nmiss);
+      status = 0;
     }
-}
 
+  return (status);
+}
 
-void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
+static
+void gribapiDefTime(int editionNumber, int productDefinitionTemplate, int typeOfGeneratingProcess, grib_handle *gh,
+                    int vdate, int vtime, int tsteptype, int numavg, int taxisID, int gcinit)
 {
-  int filetype = streamptr1->filetype;
-
-  int fileID1 = streamptr1->fileID;
-  int fileID2 = streamptr2->fileID;
-
-  int tsID    = streamptr1->curTsID;
-  int vrecID  = streamptr1->tsteps[tsID].curRecID;
-  int recID   = streamptr1->tsteps[tsID].recIDs[vrecID];
-  off_t recpos  = streamptr1->tsteps[tsID].records[recID].position;
-  size_t recsize = streamptr1->tsteps[tsID].records[recID].size;
-
-  fileSetPos(fileID1, recpos, SEEK_SET);
-
-  /* round up recsize to next multiple of 8 */
-  size_t gribbuffersize = ((recsize + 7U) & ~7U);
+  int taxistype = -1;
 
-  unsigned char *gribbuffer = (unsigned char *) Malloc(gribbuffersize);
+  UNUSED(numavg);
 
-  if (fileRead(fileID1, gribbuffer, recsize) != recsize)
-    Error("Could not read GRIB record for copying!");
+  if ( taxisID != -1 ) taxistype = taxisInqType(taxisID);
 
-  size_t nbytes = recsize;
+  if ( typeOfGeneratingProcess == 196 )
+    {
+      vdate = 10101;
+      vtime = 0;
+      taxistype = TAXIS_ABSOLUTE;
+    }
+  /*
+  else if ( typeOfGeneratingProcess == 9 )
+    {
+    }
+  */
 
-  if ( filetype == FILETYPE_GRB )
+  if ( taxistype == TAXIS_RELATIVE )
     {
-      long unzipsize;
-      int izip = gribGetZip((long)recsize, gribbuffer, &unzipsize);
+      int status;
+      int calendar = taxisInqCalendar(taxisID);
+      int rdate    = taxisInqRdate(taxisID);
+      int rtime    = taxisInqRtime(taxisID);
+      int timeunit = taxisInqTunit(taxisID);
 
-      if ( izip == 0 )
-        if ( streamptr2->comptype == COMPRESS_SZIP )
-          nbytes = grbSzip(filetype, gribbuffer, nbytes);
-    }
+      status = gribapiDefDateTimeRel(editionNumber, gh, rdate, rtime, vdate, vtime,
+                                     productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, timeunit, calendar, gcinit);
 
-  while ( nbytes & 7 ) gribbuffer[nbytes++] = 0;
+      if ( status != 0 ) taxistype = TAXIS_ABSOLUTE;
+    }
 
-  size_t nwrite = fileWrite(fileID2, gribbuffer, nbytes);
-  if ( nwrite != nbytes )
+  if ( taxistype == TAXIS_ABSOLUTE )
     {
-      perror(__func__);
-      Error("Could not write record for copying!");
+      gribapiDefDateTimeAbs(editionNumber, gh, vdate, vtime, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
     }
-
-  Free(gribbuffer);
 }
 
-
-void grb_write_record(stream_t * streamptr, int memtype, const void *data, int nmiss)
+static
+void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype, int lieee, int datatype, int nmiss, int gcinit)
 {
-  int varID, levelID;
-
-  varID   = streamptr->record->varID;
-  levelID = streamptr->record->levelID;
-
-  grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
-}
+  int status;
+  static short lwarn = TRUE;
 
+  UNUSED(nmiss);
 
-void streamInqGRIBinfo(int streamID, int *intnum, float *fltnum, off_t *bignum)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
+  int gridtype = gridInqType(gridID);
+  int gridsize = gridInqSize(gridID);
 
-  stream_check_ptr(__func__, streamptr);
+  if ( editionNumber <= 1 )
+    if ( gridtype == GRID_GME || gridtype == GRID_UNSTRUCTURED )
+      gridtype = -1;
 
-  int filetype = streamptr->filetype;
+  if ( gridtype == GRID_GENERIC )
+    {
+      int xsize = gridInqXsize(gridID);
+      int ysize = gridInqYsize(gridID);
 
-  if ( filetype == FILETYPE_GRB )
+      if ( (ysize ==  32 || ysize ==  48 || ysize ==  64 ||
+	    ysize ==  96 || ysize == 160 || ysize == 192 ||
+	    ysize == 240 || ysize == 320 || ysize == 384 ||
+	    ysize == 480 || ysize == 768 ) &&
+	   (xsize == 2*ysize || xsize == 1) )
+	{
+	  gridtype = GRID_GAUSSIAN;
+	  gridChangeType(gridID, gridtype);
+	}
+      else if ( gridsize == 1 )
+	{
+	  gridtype = GRID_LONLAT;
+	  gridChangeType(gridID, gridtype);
+	}
+      else if ( gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL) )
+	{
+	  gridtype = GRID_LONLAT;
+	  gridChangeType(gridID, gridtype);
+	}
+    }
+  else if ( gridtype == GRID_CURVILINEAR )
     {
-      int tsID     = streamptr->curTsID;
-      int vrecID   = streamptr->tsteps[tsID].curRecID;
-      int recID    = streamptr->tsteps[tsID].recIDs[vrecID];
-      off_t recpos = streamptr->tsteps[tsID].records[recID].position;
-      int zip      = streamptr->tsteps[tsID].records[recID].zip;
+      if ( lwarn && gridsize > 1 )
+	{
+	  lwarn = FALSE;
+	  Warning("Curvilinear grids are unsupported in GRIB format! Created wrong GDS!");
+	}
+      gridtype = GRID_LONLAT;
+    }
 
-      void *gribbuffer = streamptr->record->buffer;
-      size_t gribbuffersize = streamptr->record->buffersize;
+  if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN )
+    {
+      if ( editionNumber != 2 || lieee ) { comptype = 0; }
 
-      if ( zip > 0 )
-	Error("Compressed GRIB records unsupported!");
-      else
-        grib_info_for_grads(recpos, (long)gribbuffersize, (unsigned char *) gribbuffer, intnum, fltnum, bignum);
+      if ( comptype )
+        {
+          if ( comptype == COMPRESS_JPEG && gridsize > 1 )
+            {
+              static const char mesg[] = "grid_jpeg";
+              size_t len = sizeof (mesg) - 1;
+              GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+            }
+          else if ( comptype == COMPRESS_SZIP && gridsize > 1 )
+            {
+              static const char mesg[] = "grid_ccsds";
+              size_t len = sizeof (mesg) - 1;
+              GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+            }
+          else
+            {
+              static const char mesg[] = "grid_simple";
+              size_t len = sizeof (mesg) - 1;
+              GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+            }
+        }
     }
-}
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef _SUBTYPE_H
-#define _SUBTYPE_H
 
+  if ( gcinit ) return;
 
-enum {
-  /* subtype attributes wrt. TILES */
-  SUBTYPE_ATT_TILEINDEX                 = 0,
-  SUBTYPE_ATT_TOTALNO_OF_TILEATTR_PAIRS = 1,
-  SUBTYPE_ATT_TILE_CLASSIFICATION       = 2,
-  SUBTYPE_ATT_NUMBER_OF_TILES           = 3,
-  SUBTYPE_ATT_NUMBER_OF_ATTR            = 4,
-  SUBTYPE_ATT_TILEATTRIBUTE             = 5,
-/* No. of different constants in the enumeration
-   "subtype_attributes" */
-  nSubtypeAttributes
-};
+  switch (gridtype)
+    {
+    case GRID_LONLAT:
+    case GRID_GAUSSIAN:
+    case GRID_GAUSSIAN_REDUCED:
+    case GRID_TRAJECTORY:
+      {
+	double xfirst = 0, xlast = 0, xinc = 0;
+	double yfirst = 0, ylast = 0, yinc = 0;
+	double latIncr;
+
+	if ( gridtype == GRID_GAUSSIAN )
+	  {
+            static const char mesg[] = "regular_gg";
+            size_t len = sizeof (mesg) -1;
+	    GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
+	  }
+	else if ( gridtype == GRID_GAUSSIAN_REDUCED )
+	  {
+            static const char mesg[] = "reduced_gg";
+            size_t len = sizeof (mesg) -1;
+	    GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
+	  }
+	else if ( gridtype == GRID_LONLAT && gridIsRotated(gridID) )
+	  {
+            static const char mesg[] = "rotated_ll";
+            size_t len = sizeof (mesg) -1;
+	    GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
+	  }
+	else
+	  {
+            static const char mesg[] = "regular_ll";
+            size_t len = sizeof (mesg) -1;
+	    GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
+	  }
 
+	int nlon = gridInqXsize(gridID);
+	int nlat = gridInqYsize(gridID);
 
-/* Literal constants corresponding to the different constants of the
-   enumeration "subtype_attributes". */
-extern const char * const cdiSubtypeAttributeName[];
+	if ( gridtype == GRID_GAUSSIAN_REDUCED )
+	  {
+	    int *rowlon, i;
+	    long *pl = NULL;
 
-/* Data type specifying an attribute of a subtype (for example an
-   attribute of a set of TILES) or an attribute of a subtype entry
-   (for example an attribute of a single TILE). This data type is part
-   of a linked list. */
-struct subtype_attr_t {
-  int   key, val;                                /* key/value pair */
-  struct subtype_attr_t* next;                   /* next element in linked list */
-};
+	    nlon = 0;
 
+	    rowlon = (int *) Malloc((size_t)nlat*sizeof(int));
+	    pl     = (long *) Malloc((size_t)nlat*sizeof(long));
+	    gridInqRowlon(gridID, rowlon);
+	    for ( i = 0; i < nlat; ++i ) pl[i] = rowlon[i];
 
-/* Data type specifying a single entry of a subtype, for example a
-   single TILE in a set of TILES. */
-struct subtype_entry_t {
-  int                     self;                  /* list entry index (0,...,nentries-1) */
-  struct subtype_entry_t *next;                  /* next node in linked list */
+	    // GRIB_CHECK(my_grib_set_long_array(gh, "pl", pl, nlat), 0);
 
-  /* linked list with attributes for this subtype entry, ordered by its key values*/
-  struct subtype_attr_t  *atts;
-};
+	    Free(pl);
+	    Free(rowlon);
+	  }
+	else
+	  {
+	    if ( nlon == 0 )
+	      {
+		nlon = 1;
+	      }
+	    else
+	      {
+		xfirst = gridInqXval(gridID,      0);
+		xlast  = gridInqXval(gridID, nlon-1);
+		xinc   = gridInqXinc(gridID);
+	      }
+	  }
 
+	if ( nlat == 0 )
+	  {
+	    nlat = 1;
+	  }
+	else
+	  {
+	    yfirst = gridInqYval(gridID,      0);
+	    ylast  = gridInqYval(gridID, nlat-1);
+	    yinc   = gridInqYinc(gridID);
+	  }
 
-/* Data type specifying a variable subtype, for example a list of
-   TILES. This can be interpreted as an additional axis like the
-   vertical axis. */
-typedef struct  {
-  int                     self;                  /* resource handler ID */
-  int                     subtype;               /* subtype kind: TILES, ... */
-  int                     nentries;              /* counter: total no. of entries in list */
+	GRIB_CHECK(my_grib_set_long(gh, "Ni", nlon), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "Nj", nlat), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "longitudeOfFirstGridPointInDegrees", xfirst), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "longitudeOfLastGridPointInDegrees",  xlast), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees",  yfirst), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "latitudeOfLastGridPointInDegrees",   ylast), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "iDirectionIncrementInDegrees", xinc), 0);
 
-  struct subtype_entry_t  globals;               /* global attributes */
+        {
+          long jscan = 0;
+          if ( yfirst < ylast ) jscan = 1;
+          GRIB_CHECK(my_grib_set_long(gh, "jScansPositively", jscan), 0);
+        }
+	/*
+	if ( fabs(xinc*1000 - ISEC2_LonIncr) > FLT_EPSILON )
+	  ISEC2_LonIncr = 0;
+	*/
+	if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
+          {
+            int np = gridInqNP(gridID);
+            if ( np == 0 ) np = nlat/2;
+            GRIB_CHECK(my_grib_set_long(gh, "numberOfParallelsBetweenAPoleAndTheEquator", np), 0);
+          }
+	else
+	  {
+	    latIncr = yinc;
+	    if ( latIncr < 0 ) latIncr = -latIncr;
+	    GRIB_CHECK(my_grib_set_double(gh, "jDirectionIncrementInDegrees", latIncr), 0);
+	    /*
+	    if ( fabs(yinc*1000 - ISEC2_LatIncr) > FLT_EPSILON )
+	      ISEC2_LatIncr = 0;
+	    */
+	  }
+	/*
+	if ( ISEC2_NumLon > 1 && ISEC2_NumLat == 1 )
+	  if ( ISEC2_LonIncr != 0 && ISEC2_LatIncr == 0 ) ISEC2_LatIncr = ISEC2_LonIncr;
 
-  /* list of subtype entries, e.g. the list of tiles, ordered by entry->self. */
-  struct subtype_entry_t *entries;
-  /* currently active subtype, e.g. GRIB2 tile index (for example for
-     stream/vlist accesses): */
-  int                     active_subtype_index;
-} subtype_t;
+	if ( ISEC2_NumLon == 1 && ISEC2_NumLat > 1 )
+	  if ( ISEC2_LonIncr == 0 && ISEC2_LatIncr != 0 ) ISEC2_LonIncr = ISEC2_LatIncr;
 
+	if ( ISEC2_LatIncr == 0 || ISEC2_LonIncr == 0 )
+	  ISEC2_ResFlag = 0;
+	else
+	  ISEC2_ResFlag = 128;
+	*/
+	if ( gridIsRotated(gridID) )
+	  {
+	    double xpole = gridInqXpole(gridID);
+	    double ypole = gridInqYpole(gridID);
+	    double angle = gridInqAngle(gridID);
+	    /* change from north to south pole */
+	    if ( fabs(ypole) > 0 ) ypole = -ypole;
+	    xpole =  xpole + 180;
+            if ( fabs(angle) > 0 ) angle = -angle;
+	    GRIB_CHECK(my_grib_set_double(gh, "latitudeOfSouthernPoleInDegrees",  ypole), 0);
+	    GRIB_CHECK(my_grib_set_double(gh, "longitudeOfSouthernPoleInDegrees", xpole), 0);
+	    GRIB_CHECK(my_grib_set_double(gh, "angleOfRotation", angle), 0);
+	  }
 
+	/* East -> West */
+	//if ( ISEC2_LastLon < ISEC2_FirstLon ) ISEC2_ScanFlag += 128;
 
+	/* South -> North */
+	//if ( ISEC2_LastLat > ISEC2_FirstLat ) ISEC2_ScanFlag += 64;
 
-/* prototypes: allocation and destruction */
-void  subtypeAllocate(subtype_t **subtype_ptr2, int subtype);
-int   subtypePush(subtype_t *subtype_ptr);
-void  subtypeDestroyPtr(void *ptr);
-void  subtypeDuplicate(subtype_t *subtype_ptr, subtype_t **dst);
-struct subtype_entry_t* subtypeEntryInsert(subtype_t* head);
+        if ( editionNumber != 2 ) { lieee = 0; comptype = 0; }
 
-/* prototypes: accessing global attributes */
-void  subtypePrint(int subtypeID);
-void  subtypePrintPtr(subtype_t* subtype_ptr);
-void  subtypeDefGlobalDataP(subtype_t *subtype_ptr, int key, int val);
-void  subtypeDefGlobalData(int subtypeID, int key, int val);
-int   subtypeGetGlobalData(int subtypeID, int key);
-int   subtypeGetGlobalDataP(subtype_t *subtype_ptr, int key);
-int   subtypeComparePtr(int s1_ID, subtype_t *s2);
+        if ( lieee )
+          {
+            static const char mesg[] = "grid_ieee";
+            size_t len = sizeof (mesg) -1;
+            GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
 
-/* prototypes: accessing subtype entries */
-void  subtypeDefEntryDataP(struct subtype_entry_t *subtype_entry_ptr, int key, int val);
+	    if ( datatype == DATATYPE_FLT64 )
+	      GRIB_CHECK(my_grib_set_long(gh, "precision", 2), 0);
+	    else
+	      GRIB_CHECK(my_grib_set_long(gh, "precision", 1), 0);
+          }
+        else
+	  {
+            if ( comptype == COMPRESS_JPEG && gridsize > 1 )
+              {
+                static const char mesg[] = "grid_jpeg";
+                size_t len = sizeof (mesg) -1;
+                GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+              }
+            else if ( comptype == COMPRESS_SZIP && gridsize > 1 )
+              {
+                static const char mesg[] = "grid_ccsds";
+                size_t len = sizeof (mesg) -1;
+                GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+              }
+            else
+              {
+                static const char mesg[] = "grid_simple";
+                size_t len = sizeof (mesg) -1;
+                GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+              }
+	  }
 
+	break;
+      }
+    case GRID_LCC:
+      {
+	double originLon, originLat, lonParY, lat1, lat2, xincm, yincm;
+	int projflag, scanflag;
 
-/* prototypes: tile implementations */
-void  tilesetInsertP(subtype_t *s1, subtype_t *s2);
+	int xsize = gridInqXsize(gridID);
+	int ysize = gridInqYsize(gridID);
 
-/* Construct a new subtype for a tile set. If a corresponding subtype
- * already exists, then we return this subtype ID instead. */
-int vlistDefTileSubtype(int vlistID, subtype_t *tiles);
+	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
+		   &projflag, &scanflag);
 
-/* Insert a trivial one-tile-subtype */
-int vlistInsertTrivialTileSubtype(int vlistID);
+        static const char mesg[] = "lambert";
+        size_t len = sizeof (mesg) -1;
+        GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
 
+	GRIB_CHECK(my_grib_set_long(gh, "Nx", xsize), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "Ny", ysize), 0);
 
-#endif
+        /* FIXME: lround should probably be round here */
+	GRIB_CHECK(my_grib_set_double(gh, "DxInMetres", (double)lround(xincm)), 0);
+        /* FIXME: lround should probably be round here */
+	GRIB_CHECK(my_grib_set_double(gh, "DyInMetres", (double)lround(yincm)), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "longitudeOfFirstGridPointInDegrees", originLon), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees", originLat), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "LoVInDegrees", lonParY), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "Latin1InDegrees", lat1), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "Latin2InDegrees", lat2), 0);
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
+        if ( editionNumber <= 1 )
+          {
+            GRIB_CHECK(my_grib_set_long(gh, "projectionCenterFlag", projflag), 0);
+            GRIB_CHECK(my_grib_set_long(gh, "scanningMode", scanflag), 0);
+          }
 
-#include <limits.h>
-#include <stdio.h>
+	break;
+      }
+    case GRID_SPECTRAL:
+      {
+	int trunc = gridInqTrunc(gridID);
 
+        static const char mesg[] = "sh";
+        size_t len = sizeof (mesg) -1;
+	GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
 
+	GRIB_CHECK(my_grib_set_long(gh, "J", trunc), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "K", trunc), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "M", trunc), 0);
 
-#if  defined  (HAVE_LIBGRIB_API)
+	// GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridsize), 0);
+        /*
+        if ( lieee )
+          {
+            printf("spectral_ieee\n");
+            if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridsize, 0);
+            static const char mesg[] = "spectral_ieee";
+            size_t len = sizeof (mesg) -1;
+            GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+          }
+        else */ if ( gridInqComplexPacking(gridID) )
+	  {
+	    if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridsize), 0);
+            static const char mesg[] = "spectral_complex";
+            size_t len = sizeof (mesg) -1;
+	    GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
 
-#  include <grib_api.h>
-#endif
+	    GRIB_CHECK(my_grib_set_long(gh, "JS", 20), 0);
+	    GRIB_CHECK(my_grib_set_long(gh, "KS", 20), 0);
+	    GRIB_CHECK(my_grib_set_long(gh, "MS", 20), 0);
+	  }
+	else
+	  {
+            static const char mesg[] = "spectral_simple";
+            size_t len = sizeof (mesg) -1;
+	    GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+	  }
 
-extern int cdiInventoryMode;
+	break;
+      }
+    case GRID_GME:
+      {
+	GRIB_CHECK(my_grib_set_long(gh, "gridDefinitionTemplateNumber", GRIB2_GTYPE_GME), 0);
 
-#if  defined  (HAVE_LIBGRIB_API)
-static const var_tile_t dummy_tiles = { -1, -1, -1, -1, -1, -1 };
-#endif
+	GRIB_CHECK(my_grib_set_long(gh, "nd", gridInqGMEnd(gridID)), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "Ni", gridInqGMEni(gridID)), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "n2", gridInqGMEni2(gridID)), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "n3", gridInqGMEni3(gridID)), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "latitudeOfThePolePoint", 90000000), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "longitudeOfThePolePoint", 0), 0);
 
-typedef struct {
-  int param;
-  int level1;
-  int level2;
-  int ltype;
-  int tsteptype;
-  char name[32];
+	GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridsize), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "totalNumberOfGridPoints", gridsize), 0);
 
-  var_tile_t tiles;
+        if ( comptype == COMPRESS_SZIP )
+          {
+            static const char mesg[] = "grid_ccsds";
+            size_t len = sizeof (mesg) -1;
+            GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+          }
 
-} compvar2_t;
+	break;
+      }
+    case GRID_UNSTRUCTURED:
+      {
+	static int warning = 1;
 
+	status = my_grib_set_long(gh, "gridDefinitionTemplateNumber", GRIB2_GTYPE_UNSTRUCTURED);
+	if ( status != 0 && warning )
+	  {
+	    warning = 0;
+	    Warning("Can't write reference grid!");
+	    Warning("gridDefinitionTemplateNumber %d not found (grib2/template.3.%d.def)!",
+		    GRIB2_GTYPE_UNSTRUCTURED, GRIB2_GTYPE_UNSTRUCTURED);
+	  }
+	else
+	  {
+            unsigned char uuid[CDI_UUID_SIZE];
+            int position = gridInqPosition(gridID);
+            int number = gridInqNumber(gridID);
+            if ( position < 0 ) position = 0;
+            if ( number < 0 ) number = 0;
+	    GRIB_CHECK(my_grib_set_long(gh, "numberOfGridUsed", number), 0);
+	    GRIB_CHECK(my_grib_set_long(gh, "numberOfGridInReference", position), 0);
+            size_t len = CDI_UUID_SIZE;
+            gridInqUUID(gridID, uuid);
+	    if (grib_set_bytes(gh, "uuidOfHGrid", uuid, &len) != 0)
+	      Warning("Can't write UUID!");
+	  }
 
-#if  defined  (HAVE_LIBGRIB_API)
-static
-int gribapiGetZaxisType(long editionNumber, int grib_ltype)
-{
-  int zaxistype = ZAXIS_GENERIC;
+        if ( comptype == COMPRESS_SZIP )
+          {
+            static const char mesg[] = "grid_ccsds";
+            size_t len = sizeof (mesg) -1;
+            GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+          }
 
-  if ( editionNumber <= 1 )
-    {
-      zaxistype = grib1ltypeToZaxisType(grib_ltype);
-    }
-  else
-    {
-      zaxistype = grib2ltypeToZaxisType(grib_ltype);
+	break;
+      }
+    default:
+      {
+	Error("Unsupported grid type: %s", gridNamePtr(gridtype));
+	break;
+      }
     }
-
-  return (zaxistype);
 }
 
 static
-int getTimeunits(long unitsOfTime)
+void getLevelFactor(double level, long *factor, long *out_scaled_value)
 {
-  int timeunits = -1;
+  double scaled_value  = level;
+  /* FIXME: lround might be better here */
+  long   iscaled_value = (long) round(scaled_value);
+  long   i;
 
-  switch (unitsOfTime)
+  const double eps = 1.e-8;
+  for ( i=0; (fabs(scaled_value - (double) iscaled_value) >= eps) && i < 7; i++ )
     {
-    case 13:  timeunits = TUNIT_SECOND;  break;
-    case  0:  timeunits = TUNIT_MINUTE;  break;
-    case  1:  timeunits = TUNIT_HOUR;    break;
-    case 10:  timeunits = TUNIT_3HOURS;  break;
-    case 11:  timeunits = TUNIT_6HOURS;  break;
-    case 12:  timeunits = TUNIT_12HOURS; break;
-    case  2:  timeunits = TUNIT_DAY;     break;
-    default:  timeunits = TUNIT_HOUR;    break;
+      scaled_value *= 10.;
+      /* FIXME: lround might be better here */
+      iscaled_value = (long)round(scaled_value);
     }
 
-  return (timeunits);
+  (*factor)           = i;
+  (*out_scaled_value) = iscaled_value;
 }
 
 static
-double timeunit_factor(int tu1, int tu2)
+void gribapiDefLevelType(grib_handle *gh, int gcinit, const char *keyname, long leveltype)
 {
-  double factor = 1;
-
-  if ( tu2 == TUNIT_HOUR )
-    {
-      switch (tu1)
-        {
-        case TUNIT_SECOND:  factor = 3600;   break;
-        case TUNIT_MINUTE:  factor = 60;     break;
-        case TUNIT_HOUR:    factor = 1;      break;
-        case TUNIT_3HOURS:  factor = 1./3;   break;
-        case TUNIT_6HOURS:  factor = 1./6;   break;
-        case TUNIT_12HOURS: factor = 1./12;  break;
-        case TUNIT_DAY:     factor = 1./24;  break;
-        }
-    }
-
-  return (factor);
+  if ( !gcinit ) GRIB_CHECK(my_grib_set_long(gh, keyname, leveltype), 0);
 }
 
 static
-int gribapiGetTimeUnits(grib_handle *gh)
+void grib2DefLevel(grib_handle *gh, int gcinit, long leveltype1, long leveltype2, int lbounds, double level, double dlevel1, double dlevel2)
 {
-  int timeunits = -1;
-  long unitsOfTime = -1;
-
-  grib_get_long(gh, "indicatorOfUnitOfTimeRange", &unitsOfTime);
-
-  GRIB_CHECK(my_grib_set_long(gh, "stepUnits", unitsOfTime), 0);
+  long scaled_level;
+  long factor;
 
-  timeunits = getTimeunits(unitsOfTime);
+  gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", leveltype1);
+  if ( lbounds ) gribapiDefLevelType(gh, gcinit, "typeOfSecondFixedSurface", leveltype2);
 
-  return (timeunits);
-}
+  if ( !lbounds ) dlevel1 = level;
 
-static
-void gribapiGetSteps(grib_handle *gh, int timeunits, int *startStep, int *endStep)
-{
-  int timeunits2 = timeunits;
-  long unitsOfTime;
-  int status = grib_get_long(gh, "stepUnits", &unitsOfTime);
-  if ( status == 0 ) timeunits2 = getTimeunits(unitsOfTime);
-  //timeunits2 = gribapiGetTimeUnits(gh);
+  getLevelFactor(dlevel1, &factor, &scaled_level);
+  GRIB_CHECK(my_grib_set_long(gh, "scaleFactorOfFirstFixedSurface", factor), 0);
+  GRIB_CHECK(my_grib_set_long(gh, "scaledValueOfFirstFixedSurface", scaled_level), 0);
 
-  long lpar;
-  status = grib_get_long(gh, "forecastTime", &lpar);
-  if ( status == 0 ) *startStep = (int) lpar;
-  else
+  if ( lbounds )
     {
-      status = grib_get_long(gh, "startStep", &lpar);
-      if ( status == 0 )
-        *startStep = (int) (((double)lpar * timeunit_factor(timeunits, timeunits2)) + 0.5);
+      getLevelFactor(dlevel2, &factor, &scaled_level);
+      GRIB_CHECK(my_grib_set_long(gh, "scaleFactorOfSecondFixedSurface", factor), 0);
+      GRIB_CHECK(my_grib_set_long(gh, "scaledValueOfSecondFixedSurface", scaled_level), 0);
     }
-
-  *endStep = *startStep;
-  status = grib_get_long(gh, "endStep", &lpar);
-  if ( status == 0 )
-    *endStep = (int) (((double)lpar * timeunit_factor(timeunits, timeunits2)) + 0.5);
-  // printf("%d %d %d %d %d %g\n", *startStep, *endStep, lpar, timeunits, timeunits2, timeunit_factor(timeunits, timeunits2));
 }
 
 static
-void gribapiGetDataDateTime(grib_handle *gh, int *datadate, int *datatime)
-{
-  long lpar;
-
-  GRIB_CHECK(grib_get_long(gh, "dataDate", &lpar), 0);
-  *datadate = (int) lpar;
-  GRIB_CHECK(grib_get_long(gh, "dataTime", &lpar), 0);  //FIXME: This looses the seconds in GRIB2 files.
-  *datatime = (int) lpar*100;
-}
-
-static
-void gribapiSetDataDateTime(grib_handle *gh, int datadate, int datatime)
+void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID, int levelID, int gcinit, int proddef_template_num)
 {
-  GRIB_CHECK(my_grib_set_long(gh, "dataDate", datadate), 0);
-  GRIB_CHECK(my_grib_set_long(gh, "dataTime", datatime/100), 0);
-}
+  int lbounds = 0;
+  double dlevel1 = 0, dlevel2 = 0;
 
-static
-int gribapiGetValidityDateTime(grib_handle *gh, int *vdate, int *vtime)
-{
-  int rdate, rtime;
-  int timeUnits, startStep = 0, endStep;
-  int tstepRange = 0;
-  int range;
-  long sigofrtime = 3;
+  int zaxistype = zaxisInqType(zaxisID);
+  int ltype = zaxisInqLtype(zaxisID);
+  int ltype2 = zaxisInqLtype2(zaxisID);
+  double level = zaxisInqLevel(zaxisID, levelID);
 
-  if ( gribEditionNumber(gh) > 1 )
+  if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
     {
-      GRIB_CHECK(grib_get_long(gh, "significanceOfReferenceTime", &sigofrtime), 0);
+      lbounds = 1;
+      dlevel1 = zaxisInqLbound(zaxisID, levelID);
+      dlevel2 = zaxisInqUbound(zaxisID, levelID);
     }
   else
     {
-      GRIB_CHECK(grib_get_long(gh, "timeRangeIndicator", &sigofrtime), 0);
+      dlevel1 = level;
+      dlevel2 = 0;
     }
 
-  if ( sigofrtime == 3 )        //XXX: This looks like a bug to me, because timeRangeIndicator == 3 does not seem to have the same meaning as significanceOfReferenceTime == 3. I would recommend replacing this condition with `if(!gribapiTimeIsFC())`.
+  if ( zaxistype == ZAXIS_GENERIC && ltype == 0 )
     {
-      gribapiGetDataDateTime(gh, vdate, vtime);
+      Message("Changed zaxis type from %s to %s", zaxisNamePtr(zaxistype), zaxisNamePtr(ZAXIS_PRESSURE));
+      zaxistype = ZAXIS_PRESSURE;
+      zaxisChangeType(zaxisID, zaxistype);
+      zaxisDefUnits(zaxisID, "Pa");
     }
-  else
-    {
-      gribapiGetDataDateTime(gh, &rdate, &rtime);
-
-      timeUnits = gribapiGetTimeUnits(gh);
-      gribapiGetSteps(gh, timeUnits, &startStep, &endStep);
 
-      range = endStep - startStep;
-
-      if ( range > 0 )
-	{
-	  if ( startStep == 0 ) tstepRange = -1;
-	  else                  tstepRange =  1;
-	}
+  int grib2ltype = zaxisTypeToGrib2ltype(zaxistype);
 
+  switch (zaxistype)
+    {
+    case ZAXIS_SURFACE:
+    case ZAXIS_MEANSEA:
+    case ZAXIS_HEIGHT:
+    case ZAXIS_ALTITUDE:
+    case ZAXIS_SIGMA:
+    case ZAXIS_DEPTH_BELOW_SEA:
+    case ZAXIS_ISENTROPIC:
       {
-	static int lprint = TRUE;
-	extern int grib_calendar;
-	int ryear, rmonth, rday, rhour, rminute, rsecond;
-	int julday, secofday;
-	int64_t time_period = endStep;
-        int64_t addsec;
-
-	cdiDecodeDate(rdate, &ryear, &rmonth, &rday);
-	cdiDecodeTime(rtime, &rhour, &rminute, &rsecond);
-
-        if ( rday > 0 )
+        if ( zaxistype == ZAXIS_HEIGHT )
           {
-            encode_caldaysec(grib_calendar, ryear, rmonth, rday, rhour, rminute, rsecond, &julday, &secofday);
-
-            addsec = 0;
-            switch ( timeUnits )
+            double sf = 1;
+            char units[128];
+            zaxisInqUnits(zaxisID, units);
+            if ( units[1] == 'm' && !units[2] )
               {
-              case TUNIT_SECOND:  addsec =         time_period; break;
-              case TUNIT_MINUTE:  addsec =    60 * time_period; break;
-              case TUNIT_HOUR:    addsec =  3600 * time_period; break;
-              case TUNIT_3HOURS:  addsec = 10800 * time_period; break;
-              case TUNIT_6HOURS:  addsec = 21600 * time_period; break;
-              case TUNIT_12HOURS: addsec = 43200 * time_period; break;
-              case TUNIT_DAY:     addsec = 86400 * time_period; break;
-              default:
-                if ( lprint )
-                  {
-                    Warning("Time unit %d unsupported", timeUnits);
-                    lprint = FALSE;
-                  }
-                break;
+                if      ( units[0] == 'c' ) sf = 0.01;
+                else if ( units[0] == 'd' ) sf = 0.1;
+                else if ( units[0] == 'k' ) sf = 1000;
+              }
+            if ( IS_NOT_EQUAL(sf, 1) )
+              {
+                level   *= sf;
+                dlevel1 *= sf;
+                dlevel2 *= sf;
               }
-
-            julday_add_seconds(addsec, &julday, &secofday);
-
-            decode_caldaysec(grib_calendar, julday, secofday, &ryear, &rmonth, &rday, &rhour, &rminute, &rsecond);
           }
 
-	*vdate = cdiEncodeDate(ryear, rmonth, rday);
-	*vtime = cdiEncodeTime(rhour, rminute, rsecond);
-      }
-    }
-
-  return (tstepRange);
-}
-
-static
-void grib1GetLevel(grib_handle *gh, int *leveltype, int *lbounds, int *level1, int *level2)
-{
-  *leveltype = 0;
-  *lbounds   = 0;
-  *level1    = 0;
-  *level2    = 0;
-
-  long lpar;
-  if(!grib_get_long(gh, "indicatorOfTypeOfLevel", &lpar))       //1 byte
-    {
-      *leveltype = (int) lpar;
-
-      switch (*leveltype)
-	{
-	case GRIB1_LTYPE_SIGMA_LAYER:
-	case GRIB1_LTYPE_HYBRID_LAYER:
-	case GRIB1_LTYPE_LANDDEPTH_LAYER:
-	  { *lbounds = 1; break; }
-	}
-
-      if ( *lbounds )
-	{
-	  GRIB_CHECK(grib_get_long(gh, "topLevel", &lpar), 0);  //1 byte
-	  *level1 = (int)lpar;
-	  GRIB_CHECK(grib_get_long(gh, "bottomLevel", &lpar), 0);       //1 byte
-	  *level2 = (int)lpar;
-	}
-      else
-	{
-          double dlevel;
-	  GRIB_CHECK(grib_get_double(gh, "level", &dlevel), 0); //2 byte
-	  if ( *leveltype == 100 ) dlevel *= 100;
-	  if ( dlevel < -2.e9 || dlevel > 2.e9 ) dlevel = 0;
-	  if ( *leveltype == GRIB1_LTYPE_99 ) *leveltype = 100;
-
-	  *level1 = (int) dlevel;
-	  *level2 = 0;
-	}
-    }
-}
-
-static
-double grib2ScaleFactor(long factor)
-{
-  switch(factor)
-    {
-      case GRIB_MISSING_LONG: return 1;
-      case 0: return 1;
-      case 1: return 0.1;
-      case 2: return 0.01;
-      case 3: return 0.001;
-      case 4: return 0.0001;
-      case 5: return 0.00001;
-      case 6: return 0.000001;
-      case 7: return 0.0000001;
-      case 8: return 0.00000001;
-      case 9: return 0.000000001;
-      default: return 0;
-    }
-}
-
-static
-int calcLevel(int level_sf, long factor, long level)
-{
-  double result = 0;
-  if(level != GRIB_MISSING_LONG) result = (double)level*grib2ScaleFactor(factor);
-  if(level_sf) result *= level_sf;
-  return (int)result;
-}
-
-static
-void grib2GetLevel(grib_handle *gh, int *leveltype1, int *leveltype2, int *lbounds, int *level1, 
-                   int *level2, int *level_sf, int *level_unit)
-{
-  int status;
-  long lpar;
-  long factor;
-
-  *leveltype1 = 0;
-  *leveltype2 = -1;
-  *lbounds    = 0;
-  *level1     = 0;
-  *level2     = 0;
-  *level_sf   = 0;
-  *level_unit = 0;
-
-  status = grib_get_long(gh, "typeOfFirstFixedSurface", &lpar); //1 byte
-  if ( status == 0 )
-    {
-      long llevel;
-
-      *leveltype1 = (int) lpar;
-
-      status = grib_get_long(gh, "typeOfSecondFixedSurface", &lpar); //1 byte
-      /* FIXME: assert(lpar >= INT_MIN && lpar <= INT_MAX) */
-      if ( status == 0 ) *leveltype2 = (int)lpar;
-
-      if ( *leveltype1 != 255 && *leveltype2 != 255 && *leveltype2 > 0 ) *lbounds = 1;
-      switch(*leveltype1)
-        {
-          case GRIB2_LTYPE_REFERENCE:
-            if(*leveltype2 == 1) *lbounds = 0;
-            break;
-
-          case GRIB2_LTYPE_LANDDEPTH:
-            *level_sf = 1000;
-            *level_unit = CDI_UNIT_M;
-            break;
+        if ( editionNumber <= 1 )
+          {
+            gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", zaxisTypeToGrib1ltype(zaxistype));
+            GRIB_CHECK(my_grib_set_long(gh, "level", (long)level), 0);
+          }
+        else
+          {
+            /* PRODUCT DEFINITION TEMPLATE NUMBER 32:
 
-          case GRIB2_LTYPE_ISOBARIC:
-            *level_sf = 1000;
-            *level_unit = CDI_UNIT_PA;
-            break;
+               "Analysis or forecast at a horizontal level or in a horizontal layer at a point
+                in time for simulate (synthetic) satellite data"
 
-          case GRIB2_LTYPE_SIGMA:
-            *level_sf = 1000;
-            *level_unit = 0;
-            break;
-        }
+               The key/value pairs that are set in "grib2DefLevel" do not exist for this template.
+            */
+            if ( proddef_template_num != 32 )
+              grib2DefLevel(gh, gcinit, grib2ltype, grib2ltype, lbounds, level, dlevel1, dlevel2);
+          }
 
-      GRIB_CHECK(grib_get_long(gh, "scaleFactorOfFirstFixedSurface", &factor), 0);      //1 byte
-      GRIB_CHECK(grib_get_long(gh, "scaledValueOfFirstFixedSurface", &llevel), 0);      //4 byte
-      *level1 = calcLevel(*level_sf, factor, llevel);
+	break;
+      }
+    case ZAXIS_CLOUD_BASE:
+    case ZAXIS_CLOUD_TOP:
+    case ZAXIS_ISOTHERM_ZERO:
+    case ZAXIS_TOA:
+    case ZAXIS_SEA_BOTTOM:
+    case ZAXIS_LAKE_BOTTOM:
+    case ZAXIS_SEDIMENT_BOTTOM:
+    case ZAXIS_SEDIMENT_BOTTOM_TA:
+    case ZAXIS_SEDIMENT_BOTTOM_TW:
+    case ZAXIS_MIX_LAYER:
+    case ZAXIS_ATMOSPHERE:
+      {
+        if ( editionNumber <= 1 )
+          {
+            gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", zaxisTypeToGrib1ltype(zaxistype));
+            if ( lbounds )
+              {
+                GRIB_CHECK(my_grib_set_long(gh, "topLevel", (long) dlevel1), 0);
+                GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", (long) dlevel2), 0);
+              }
+            else
+              {
+                GRIB_CHECK(my_grib_set_long(gh, "level", (long) level), 0);
+              }
+          }
+        else
+          {
+            grib2DefLevel(gh, gcinit, grib2ltype, grib2ltype, lbounds, level, dlevel1, dlevel2);
+          }
 
-      if ( *lbounds )
-        {
-          GRIB_CHECK(grib_get_long(gh, "scaleFactorOfSecondFixedSurface", &factor), 0); //1 byte
-          GRIB_CHECK(grib_get_long(gh, "scaledValueOfSecondFixedSurface", &llevel), 0); //4 byte
-          *level2 = calcLevel(*level_sf, factor, llevel);
-        }
-    }
-}
+        break;
+      }
+    case ZAXIS_HYBRID:
+    case ZAXIS_HYBRID_HALF:
+      {
+        if ( editionNumber <= 1 )
+          {
+            if ( lbounds )
+              {
+                gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", GRIB1_LTYPE_HYBRID_LAYER);
+                GRIB_CHECK(my_grib_set_long(gh, "topLevel", (long) dlevel1), 0);
+                GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", (long) dlevel2), 0);
+              }
+            else
+              {
+                gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", GRIB1_LTYPE_HYBRID);
+                GRIB_CHECK(my_grib_set_long(gh, "level", (long) level), 0);
+              }
+          }
+        else
+          {
+            grib2DefLevel(gh, gcinit, GRIB2_LTYPE_HYBRID, GRIB2_LTYPE_HYBRID, lbounds, level, dlevel1, dlevel2);
+          }
 
-static
-void gribGetLevel(grib_handle *gh, int* leveltype1, int* leveltype2, int* lbounds, int* level1, int* level2, int* level_sf, int* level_unit, var_tile_t* tiles)
-{
-  if ( gribEditionNumber(gh) <= 1 )
-    {
-      grib1GetLevel(gh, leveltype1, lbounds, level1, level2);
-      *leveltype2 = -1;
-      *level_sf = 0;
-      *level_unit = 0;
-    }
-  else
-    {
-      grib2GetLevel(gh, leveltype1, leveltype2, lbounds, level1, level2, level_sf, level_unit);
+        if ( !gcinit )
+          {
+            int vctsize = zaxisInqVctSize(zaxisID);
+            if ( vctsize > 0 )
+              {
+                GRIB_CHECK(my_grib_set_long(gh, "PVPresent", 1), 0);
+                GRIB_CHECK(grib_set_double_array(gh, "pv", zaxisInqVctPtr(zaxisID), (size_t)vctsize), 0);
+              }
+          }
 
-      /* read in tiles attributes (if there are any) */
-      tiles->tileindex = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TILEINDEX], -1);
-      tiles->totalno_of_tileattr_pairs = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TOTALNO_OF_TILEATTR_PAIRS], -1);
-      tiles->tileClassification = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TILE_CLASSIFICATION], -1);
-      tiles->numberOfTiles = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_NUMBER_OF_TILES], -1);
-      tiles->numberOfAttributes = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_NUMBER_OF_ATTR], -1);
-      tiles->attribute = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TILEATTRIBUTE], -1);
-    }
-}
+	break;
+      }
+    case ZAXIS_PRESSURE:
+      {
+	double dum;
+	char units[128];
 
-static
-void gribapiGetString(grib_handle *gh, const char *key, char *string, size_t length)
-{
-  string[0] = 0;
+	if ( level < 0 ) Warning("Pressure level of %f Pa is below zero!", level);
 
-  int ret = grib_get_string(gh, key, string, &length);
-  if (ret != 0)
-    {
-      fprintf(stderr, "grib_get_string(gh, \"%s\", ...) failed!\n", key);
-      GRIB_CHECK(ret, 0);
-    }
-  if      ( length == 8 && memcmp(string, "unknown", length) == 0 ) string[0] = 0;
-  else if ( length == 2 && memcmp(string, "~", length)       == 0 ) string[0] = 0;
-}
+	zaxisInqUnits(zaxisID, units);
+	if ( memcmp(units, "Pa", 2) != 0 )
+          {
+            level   *= 100;
+            dlevel1 *= 100;
+            dlevel2 *= 100;
+          }
 
-#if  defined  (HAVE_LIBGRIB_API)
-static
-void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
-                      size_t recsize, off_t position, int datatype, int comptype, const char *varname,
-                      int leveltype1, int leveltype2, int lbounds, int level1, int level2, int level_sf, int level_unit,
-                      const var_tile_t *tiles, int lread_additional_keys)
-{
-  int varID;
-  int levelID = 0;
-  grid_t grid;
-  long lpar;
-  int status;
-  char stdname[CDI_MAX_NAME], longname[CDI_MAX_NAME], units[CDI_MAX_NAME];
-  size_t vlen;
-  long ens_index = 0, ens_count = 0, ens_forecast_type = 0;
+        if ( editionNumber <= 1 )
+          {
+            long leveltype = GRIB1_LTYPE_ISOBARIC;
 
-  int vlistID = streamptr->vlistID;
-  int tsID    = streamptr->curTsID;
-  int recID   = recordNewEntry(streamptr, tsID);
-  record_t *record  = &streamptr->tsteps[tsID].records[recID];
+            if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
+              leveltype = GRIB1_LTYPE_99;
+            else
+              level /= 100;
 
-  int tsteptype = gribapiGetTsteptype(gh);
-  // numavg  = ISEC1_AvgNum;
-  int numavg  = 0;
+            gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", leveltype);
+            GRIB_CHECK(my_grib_set_double(gh, "level", level), 0);
+	  }
+	else
+	  {
+            if ( ltype2 == -1 ) ltype2 = GRIB2_LTYPE_ISOBARIC;
+            grib2DefLevel(gh, gcinit, GRIB2_LTYPE_ISOBARIC, ltype2, lbounds, level, dlevel1, dlevel2);
+	  }
 
-  // fprintf(stderr, "param %d %d %d %d\n", param, level1, level2, leveltype1);
+	break;
+      }
+    case ZAXIS_SNOW:
+      {
+        if ( editionNumber <= 1 )
+          ; // not available
+	else
+          {
+            grib2DefLevel(gh, gcinit, GRIB2_LTYPE_SNOW, GRIB2_LTYPE_SNOW, lbounds, level, dlevel1, dlevel2);
+          }
 
-  (*record).size      = recsize;
-  (*record).position  = position;
-  (*record).param     = param;
-  (*record).ilevel    = level1;
-  (*record).ilevel2   = level2;
-  (*record).ltype     = leveltype1;
-  (*record).tsteptype = tsteptype;
-  if ( tiles ) (*record).tiles = *tiles;
-  else         (*record).tiles = dummy_tiles;
+	break;
+      }
+    case ZAXIS_DEPTH_BELOW_LAND:
+      {
+	char units[128];
 
-  //FIXME: This may leave the variable name unterminated (which is the behavior that I found in the code).
-  //       I don't know precisely how this field is used, so I did not change this behavior to avoid regressions,
-  //       but I think that it would be better to at least add a line
-  //
-  //           record->varname[sizeof(record->varname) - 1] = 0;`
-  //
-  //       after the `strncpy()` call.
-  //
-  //       I would consider using strdup() (that requires POSIX-2008 compliance, though), or a similar homebrew approach.
-  //       I. e. kick the fixed size array and allocate enough space, whatever that may be.
-  strncpy(record->varname, varname, sizeof(record->varname));
+	zaxisInqUnits(zaxisID, units);
 
-  gribapiGetGrid(gh, &grid);
+	if ( editionNumber <= 1 )
+	  {
+            double scalefactor;
+	    if      ( memcmp(units, "mm", 2) == 0 ) scalefactor =   0.1;
+	    else if ( memcmp(units, "cm", 2) == 0 ) scalefactor =   1; // cm
+	    else if ( memcmp(units, "dm", 2) == 0 ) scalefactor =  10;
+	    else                                    scalefactor = 100;
 
-  int gridID = varDefGrid(vlistID, &grid, 0);
+	    gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", GRIB1_LTYPE_LANDDEPTH);
+	    GRIB_CHECK(my_grib_set_double(gh, "level", level*scalefactor), 0);
+	  }
+	else
+	  {
+            double scalefactor;
+	    if      ( memcmp(units, "mm", 2) == 0 ) scalefactor = 0.001;
+	    else if ( memcmp(units, "cm", 2) == 0 ) scalefactor = 0.01;
+	    else if ( memcmp(units, "dm", 2) == 0 ) scalefactor = 0.1;
+	    else                                    scalefactor = 1; // meter
 
-  int zaxistype = gribapiGetZaxisType(gribEditionNumber(gh), leveltype1);
+            level   *= scalefactor;
+            dlevel1 *= scalefactor;
+            dlevel2 *= scalefactor;
 
-  switch (zaxistype)
-    {
-    case ZAXIS_HYBRID:
-    case ZAXIS_HYBRID_HALF:
-      {
-        size_t vctsize;
-        size_t dummy;
-        double *vctptr;
+            grib2DefLevel(gh, gcinit, GRIB2_LTYPE_LANDDEPTH, GRIB2_LTYPE_LANDDEPTH, lbounds, level, dlevel1, dlevel2);
+	  }
 
-        GRIB_CHECK(grib_get_long(gh, "NV", &lpar), 0);
-        /* FIXME: assert(lpar >= 0) */
-        vctsize = (size_t)lpar;
-        if ( vctsize > 0 )
-          {
-            vctptr = (double *) Malloc(vctsize*sizeof(double));
-            dummy = vctsize;
-            GRIB_CHECK(grib_get_double_array(gh, "pv", vctptr, &dummy), 0);
-            varDefVCT(vctsize, vctptr);
-            Free(vctptr);
-          }
-        break;
+	break;
       }
     case ZAXIS_REFERENCE:
       {
         unsigned char uuid[CDI_UUID_SIZE];
-        long ltmp;
-        long nhlev, nvgrid;
 
-        GRIB_CHECK(grib_get_long(gh, "NV", &lpar), 0);
-        if ( lpar != 6 )
+        if ( !gcinit )
           {
-            fprintf(stderr, "Warning ...\n");
+            GRIB_CHECK(my_grib_set_long(gh, "genVertHeightCoords", 1), 0);
           }
-        GRIB_CHECK(grib_get_long(gh, "nlev", &ltmp), 0);
-        nhlev = ltmp;
-        GRIB_CHECK(grib_get_long(gh, "numberOfVGridUsed", &ltmp), 0);
-        nvgrid = ltmp;
-        size_t len = (size_t)CDI_UUID_SIZE;
-        memset(uuid, 0, CDI_UUID_SIZE);
-        GRIB_CHECK(grib_get_bytes(gh, "uuidOfVGrid", uuid, &len), 0);
-        varDefZAxisReference((int) nhlev, (int) nvgrid, uuid);
-        break;
-      }
-    }
 
-  // if ( datatype > 32 ) datatype = DATATYPE_PACK32;
-  if ( datatype <  0 ) datatype = DATATYPE_PACK;
+        if ( lbounds )
+          {
+            if ( editionNumber <= 1 )
+              ; // not available
+            else
+              {
+                int number = zaxisInqNumber(zaxisID);
+                gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", GRIB2_LTYPE_REFERENCE);
+                gribapiDefLevelType(gh, gcinit, "typeOfSecondFixedSurface", GRIB2_LTYPE_REFERENCE);
+                GRIB_CHECK(my_grib_set_long(gh, "NV", 6), 0);
+                GRIB_CHECK(my_grib_set_long(gh, "nlev", zaxisInqNlevRef(zaxisID)), 0);
+                GRIB_CHECK(my_grib_set_long(gh, "numberOfVGridUsed", number), 0);
+                size_t len = CDI_UUID_SIZE;
+                zaxisInqUUID(zaxisID, uuid);
+                if (grib_set_bytes(gh, "uuidOfVGrid", uuid, &len) != 0)
+                  {
+                    Warning("Can't write UUID!");
+                  }
+                GRIB_CHECK(my_grib_set_long(gh, "topLevel", (long) dlevel1), 0);
+                GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", (long) dlevel2), 0);
+              }
+          }
+        else
+          {
+            if ( editionNumber <= 1 )
+              ; // not available
+            else
+              {
+                int number = zaxisInqNumber(zaxisID);
+                gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", GRIB2_LTYPE_REFERENCE);
+                GRIB_CHECK(my_grib_set_long(gh, "NV", 6), 0);
+                GRIB_CHECK(my_grib_set_long(gh, "nlev", zaxisInqNlevRef(zaxisID)), 0);
+                GRIB_CHECK(my_grib_set_long(gh, "numberOfVGridUsed", number), 0);
+                size_t len = CDI_UUID_SIZE;
+                zaxisInqUUID(zaxisID, uuid);
+                if (grib_set_bytes(gh, "uuidOfVGrid", uuid, &len) != 0)
+                  {
+                    Warning("Can't write UUID!");
+                  }
+                GRIB_CHECK(my_grib_set_double(gh, "level", level), 0);
+              }
+          }
 
-  stdname[0] = 0;
-  longname[0] = 0;
-  units[0] = 0;
+        break;
+      }
+    case ZAXIS_GENERIC:
+      {
+	if ( editionNumber <= 1 )
+          gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", ltype);
+        else
+          gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", ltype);
 
-  if ( varname[0] != 0 )
-    {
-      vlen = CDI_MAX_NAME;
-      gribapiGetString(gh, "name", longname, vlen);
-      vlen = CDI_MAX_NAME;
-      gribapiGetString(gh, "units", units, vlen);
+	GRIB_CHECK(my_grib_set_double(gh, "level", level), 0);
 
+	break;
+      }
+    default:
       {
-        vlen = CDI_MAX_NAME;
-        status = grib_get_string(gh, "cfName", stdname, &vlen);
-        if ( status != 0 || vlen <= 1 ) stdname[0] = 0;
-        else if ( strncmp(stdname, "unknown", 7) == 0 ) stdname[0] = 0;
+	Error("Unsupported zaxis type: %s", zaxisNamePtr(zaxistype));
+	break;
       }
     }
-  // fprintf(stderr, "param %d name %s %s %s\n", param, name, longname, units);
+}
 
-  /* add the previously read record data to the (intermediate) list of records */
-  int tile_index = -1;
-  varAddRecord(recID, param, gridID, zaxistype, lbounds, level1, level2, level_sf, level_unit,
-	       datatype, &varID, &levelID, tsteptype, numavg, leveltype1, leveltype2,
-	       varname, stdname, longname, units, tiles, &tile_index);
+/* #define GRIBAPIENCODETEST 1 */
 
-  record->varID   = (short)varID;
-  record->levelID = (short)levelID;
+size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
+		     int vdate, int vtime, int tsteptype, int numavg,
+		     long datasize, const double *data, int nmiss, void **gribbuffer, size_t *gribbuffersize,
+		     int comptype, void *gribContainer)
+{
+  size_t recsize = 0;
+  void *dummy = NULL;
+  int lieee = FALSE;
+  /*  int ensID, ensCount, forecast_type; *//* Ensemble Data */
+  int typeOfGeneratingProcess;
+  int productDefinitionTemplate;
+  long bitsPerValue;
+  long editionNumber = 2;
+  char name[256];
+  char stdname[256];
+  gribContainer_t *gc = (gribContainer_t *) gribContainer;
+  // extern unsigned char _grib_template_GRIB2[];
 
-  varDefCompType(varID, comptype);
+  int param    = vlistInqVarParam(vlistID, varID);
+  int datatype = vlistInqVarDatatype(vlistID, varID);
+  typeOfGeneratingProcess = vlistInqVarTypeOfGeneratingProcess(vlistID, varID);
+  productDefinitionTemplate = vlistInqVarProductDefinitionTemplate(vlistID, varID);
 
-  /*
-    Get the ensemble Info from the grib-2 Tables and update the intermediate datastructure.
-    Further update to the "vlist" is handled in the same way as for GRIB-1 by "cdi_generate_vars"
-  */
-  status = grib_get_long(gh, "typeOfEnsembleForecast", &ens_forecast_type );
-  if ( status == 0 )
+  vlistInqVarName(vlistID, varID, name);
+  vlistInqVarStdname(vlistID, varID, stdname);
+
+#if defined(GRIBAPIENCODETEST)
+  grib_handle *gh = (grib_handle *) gribHandleNew(editionNumber);
+#else
+  grib_handle *gh = (struct grib_handle *)gc->gribHandle;
+#endif
+  GRIB_CHECK(grib_get_long(gh, "editionNumber", &editionNumber), 0);
+
+  if ( editionNumber == 2 )
     {
-      GRIB_CHECK(grib_get_long(gh, "numberOfForecastsInEnsemble", &ens_count ), 0);
-      GRIB_CHECK(grib_get_long(gh, "perturbationNumber", &ens_index ), 0);
+      if ( typeOfGeneratingProcess == -1 ) typeOfGeneratingProcess = 0;
+      if ( ! gc->init ) GRIB_CHECK(my_grib_set_long(gh, "typeOfGeneratingProcess", typeOfGeneratingProcess), 0);
     }
 
-  if ( ens_index > 0 )
-    varDefEnsembleInfo(varID, (int)ens_index, (int)ens_count, (int)ens_forecast_type);
+  /*
+  if( vlistInqVarEnsemble( vlistID,  varID, &ensID, &ensCount, &forecast_type ) )
+    {
+      GRIB_CHECK(my_grib_set_long(gh, "typeOfEnsembleForecast", forecast_type ), 0);
+      GRIB_CHECK(my_grib_set_long(gh, "numberOfForecastsInEnsemble", ensCount ), 0);
+      GRIB_CHECK(my_grib_set_long(gh, "perturbationNumber", ensID ), 0);
+    }
+  */
 
-  long typeOfGeneratingProcess = 0;
-  status = grib_get_long(gh, "typeOfGeneratingProcess", &typeOfGeneratingProcess);
-  if ( status == 0 )
-    varDefTypeOfGeneratingProcess(varID, (int) typeOfGeneratingProcess);
+  gribapiDefTime((int)editionNumber, productDefinitionTemplate, typeOfGeneratingProcess, gh, vdate, vtime, tsteptype, numavg, vlistInqTaxis(vlistID), gc->init);
 
-  long productDefinitionTemplate = 0;
-  status = grib_get_long(gh, "productDefinitionTemplateNumber", &productDefinitionTemplate);
-  if ( status == 0 )
-    varDefProductDefinitionTemplate(varID, (int) productDefinitionTemplate);
+  if ( ! gc->init ) gribapiDefInstitut(gh, vlistID, varID);
+  if ( ! gc->init ) gribapiDefModel(gh, vlistID, varID);
 
-  int    i;
-  long   lval;
-  double dval;
+  if ( ! gc->init ) gribapiDefParam((int)editionNumber, gh, param, name, stdname);
 
-  if (lread_additional_keys)
-    for ( i = 0; i < cdiNAdditionalGRIBKeys; i++ )
-      {
-        /* note: if the key is not defined, we do not throw an error! */
-        if ( grib_get_long(gh, cdiAdditionalGRIBKeys[i], &lval) == 0 )
-          varDefOptGribInt(varID, tile_index, lval, cdiAdditionalGRIBKeys[i]);
-        if ( grib_get_double(gh, cdiAdditionalGRIBKeys[i], &dval) == 0 )
-          varDefOptGribDbl(varID, tile_index, dval, cdiAdditionalGRIBKeys[i]);
-      }
+  if ( editionNumber == 2 && (datatype == DATATYPE_FLT32 || datatype == DATATYPE_FLT64) ) lieee = TRUE;
 
-  if ( varInqInst(varID) == CDI_UNDEFID )
+  /* bitsPerValue have to be defined before call to DefGrid (complex packing) */
+  //  if ( lieee == FALSE )
     {
-      long center, subcenter;
-      int instID;
-      GRIB_CHECK(grib_get_long(gh, "centre", &center), 0);
-      GRIB_CHECK(grib_get_long(gh, "subCentre", &subcenter), 0);
-      instID    = institutInq((int)center, (int)subcenter, NULL, NULL);
-      if ( instID == CDI_UNDEFID )
-	instID = institutDef((int)center, (int)subcenter, NULL, NULL);
-      varDefInst(varID, instID);
+      bitsPerValue = grbBitsPerValue(datatype);
+      GRIB_CHECK(my_grib_set_long(gh, "bitsPerValue", bitsPerValue), 0);
     }
 
-  if ( varInqModel(varID) == CDI_UNDEFID )
-    {
-      int modelID;
-      long processID;
-      status = grib_get_long(gh, "generatingProcessIdentifier", &processID);
-      if ( status == 0 )
-	{
-          /* FIXME: assert(processID >= INT_MIN && processID <= INT_MAX) */
-	  modelID = modelInq(varInqInst(varID), (int)processID, NULL);
-	  if ( modelID == CDI_UNDEFID )
-	    modelID = modelDef(varInqInst(varID), (int)processID, NULL);
-	  varDefModel(varID, modelID);
-	}
-    }
+  gribapiDefGrid((int)editionNumber, gh, gridID, comptype, lieee, datatype, nmiss, gc->init);
 
-  if ( varInqTable(varID) == CDI_UNDEFID )
-    {
-      int pdis, pcat, pnum;
+  gribapiDefLevel((int)editionNumber, gh, param, zaxisID, levelID, gc->init, productDefinitionTemplate);
 
-      cdiDecodeParam(param, &pnum, &pcat, &pdis);
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
+  //if (!gc->init)
+  {
+    int ret = 0;
 
-      if ( pdis == 255 )
-	{
-	  int tableID;
-	  int tabnum = pcat;
+    /* NOTE: Optional key/value pairs: Note that we do not distinguish
+     *       between tiles here! */
 
-	  tableID = tableInq(varInqModel(varID), tabnum, NULL);
+    for ( int i=0; i<vlistptr->vars[varID].opt_grib_nentries; i++ )
+      {
+        if ( vlistptr->vars[varID].opt_grib_kvpair[i].update )
+          {
+            //DR: Fix for multi-level fields (otherwise only the 1st level is correct)
+            if ( zaxisInqSize(zaxisID)==(levelID+1) )
+              vlistptr->vars[varID].opt_grib_kvpair[i].update = FALSE;
 
-	  if ( tableID == CDI_UNDEFID )
-	    tableID = tableDef(varInqModel(varID), tabnum, NULL);
-	  varDefTable(varID, tableID);
-	}
+            if (vlistptr->vars[varID].opt_grib_kvpair[i].data_type == t_double)
+              {
+                if ( CDI_Debug )
+                  Message("key \"%s\"  :   double value = %g\n",
+                          vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
+                          vlistptr->vars[varID].opt_grib_kvpair[i].dbl_val);
+                my_grib_set_double(gh, vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
+                                   vlistptr->vars[varID].opt_grib_kvpair[i].dbl_val);
+                GRIB_CHECK(ret, 0);
+                }
+            if (vlistptr->vars[varID].opt_grib_kvpair[i].data_type == t_int)
+              {
+                if ( CDI_Debug )
+                  Message("key \"%s\"  :   integer value = %d\n",
+                          vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
+                          vlistptr->vars[varID].opt_grib_kvpair[i].int_val);
+                my_grib_set_long(gh, vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
+                                 (long) vlistptr->vars[varID].opt_grib_kvpair[i].int_val);
+                GRIB_CHECK(ret, 0);
+              }
+          }
+      }
+  }
+
+  if ( nmiss > 0 )
+    {
+      GRIB_CHECK(my_grib_set_long(gh, "bitmapPresent", 1), 0);
+      GRIB_CHECK(my_grib_set_double(gh, "missingValue", vlistInqVarMissval(vlistID, varID)), 0);
     }
 
-  streamptr->tsteps[tsID].nallrecs++;
-  streamptr->nrecs++;
+  GRIB_CHECK(grib_set_double_array(gh, "values", data, (size_t)datasize), 0);
 
-  if ( CDI_Debug )
-    Message("varID = %d  param = %d  zaxistype = %d  gridID = %d  levelID = %d",
-	    varID, param, zaxistype, gridID, levelID);
-}
-#endif
+  /* get the size of coded message  */
+  GRIB_CHECK(grib_get_message(gh, (const void **)&dummy, &recsize), 0);
+  recsize += 512; /* add some space for possible filling */
+  *gribbuffersize = recsize;
+  *gribbuffer = Malloc(*gribbuffersize);
 
-static compvar2_t gribapiVarSet(int param, int level1, int level2, int leveltype, 
-                                int tsteptype, char *name, var_tile_t tiles_data)
-{
-  compvar2_t compVar;
-  size_t maxlen = sizeof(compVar.name);
-  size_t len = strlen(name);
-  if ( len > maxlen ) len = maxlen;
+  /* get a copy of the coded message */
+  GRIB_CHECK(grib_get_message_copy(gh, *gribbuffer, &recsize), 0);
 
-  compVar.param     = param;
-  compVar.level1    = level1;
-  compVar.level2    = level2;
-  compVar.ltype     = leveltype;
-  compVar.tsteptype = tsteptype;
-  memset(compVar.name, 0, maxlen);
-  memcpy(compVar.name, name, len);
-  compVar.tiles = tiles_data;
+#if defined(GRIBAPIENCODETEST)
+  gribHandleDelete(gh);
+#endif
 
-  return (compVar);
+  gc->init = TRUE;
+
+  return recsize;
 }
 #endif
 
-#ifdef HAVE_LIBGRIB_API
-static
-int gribapiVarCompare(compvar2_t compVar, record_t record, int flag)
-{
-  compvar2_t compVar0;
-  compVar0.param     = record.param;
-  compVar0.level1    = record.ilevel;
-  compVar0.level2    = record.ilevel2;
-  compVar0.ltype     = record.ltype;
-  compVar0.tsteptype = record.tsteptype;
-  memcpy(compVar0.name, record.varname, sizeof(compVar.name));
-
-  if ( flag == 0 )
-    {
-      if ( compVar0.tsteptype == TSTEP_INSTANT  && compVar.tsteptype == TSTEP_INSTANT3 ) compVar0.tsteptype = TSTEP_INSTANT3;
-      if ( compVar0.tsteptype == TSTEP_INSTANT3 && compVar.tsteptype == TSTEP_INSTANT  ) compVar0.tsteptype = TSTEP_INSTANT;
-    }
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-  compVar0.tiles = record.tiles;
 
-  int rstatus = memcmp(&compVar0, &compVar, sizeof(compvar2_t));
 
-  return (rstatus);
-}
+void streamDefHistory(int streamID, int length, const char *history)
+{
+#ifdef HAVE_LIBNETCDF
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-static void ensureBufferSize(size_t requiredSize, size_t* curSize, unsigned char **buffer) {
-  if ( *curSize < requiredSize )
+  if ( streamptr->filetype == FILETYPE_NC  ||
+       streamptr->filetype == FILETYPE_NC2 ||
+       streamptr->filetype == FILETYPE_NC4 ||
+       streamptr->filetype == FILETYPE_NC4C )
     {
-      *curSize = requiredSize;
-      *buffer = (unsigned char *) Realloc(*buffer, *curSize);
+      char *histstring;
+      size_t len;
+      if ( history )
+	{
+	  len = strlen(history);
+	  if ( len )
+	    {
+              /* FIXME: what's the point of strdupx? Why not use
+               * history argument directly? */
+	      histstring = strdupx(history);
+	      cdfDefHistory(streamptr, length, histstring);
+	      Free(histstring);
+	    }
+	}
     }
+#else
+  (void)streamID; (void)length; (void)history;
+#endif
 }
 
-static
-grib_handle* gribapiGetDiskRepresentation(size_t recsize, size_t* buffersize, unsigned char** gribbuffer, int* outDatatype, int* outCompressionType, long* outUnzipsize)
-{
-  int lieee = FALSE;
-
-  grib_handle* gh = grib_handle_new_from_message(NULL, (void *) *gribbuffer, recsize);
-  if(gribEditionNumber(gh) > 1)
-    {
-      size_t len = 256;
-      char typeOfPacking[256];
 
-      if ( grib_get_string(gh, "packingType", typeOfPacking, &len) == 0 )
-        {
-          // fprintf(stderr, "packingType %d %s\n", len, typeOfPacking);
-          if      ( strncmp(typeOfPacking, "grid_jpeg", len) == 0 ) *outCompressionType = COMPRESS_JPEG;
-          else if ( strncmp(typeOfPacking, "grid_ccsds", len) == 0 ) *outCompressionType = COMPRESS_SZIP;
-          else if ( strncmp(typeOfPacking, "grid_ieee", len) == 0 ) lieee = TRUE;
-        }
-    }
-  else
-    {
-      if( gribGetZip((long)recsize, *gribbuffer, outUnzipsize) > 0 )
-        {
-          *outCompressionType = COMPRESS_SZIP;
-          ensureBufferSize((size_t)*outUnzipsize + 100, buffersize, gribbuffer);
-        }
-      else
-        {
-          *outCompressionType = COMPRESS_NONE;
-        }
-    }
+int streamInqHistorySize(int streamID)
+{
+  int size = 0;
+#ifdef HAVE_LIBNETCDF
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-  if ( lieee )
-    {
-      *outDatatype = DATATYPE_FLT64;
-      long precision;
-      int status = grib_get_long(gh, "precision", &precision);
-      if ( status == 0 && precision == 1 ) *outDatatype = DATATYPE_FLT32;
-    }
-  else
+  if ( streamptr->filetype == FILETYPE_NC  ||
+       streamptr->filetype == FILETYPE_NC2 ||
+       streamptr->filetype == FILETYPE_NC4 ||
+       streamptr->filetype == FILETYPE_NC4C )
     {
-      *outDatatype = DATATYPE_PACK;
-      long bitsPerValue;
-      if ( grib_get_long(gh, "bitsPerValue", &bitsPerValue) == 0 )
-        {
-          if ( bitsPerValue > 0 && bitsPerValue <= 32 ) *outDatatype = (int)bitsPerValue;
-        }
+      size = cdfInqHistorySize(streamptr);
     }
-  return gh;
-}
+#else
+  (void)streamID;
 #endif
+  return (size);
+}
 
-#if  defined  (HAVE_LIBGRIB_API)
-typedef enum { CHECKTIME_OK, CHECKTIME_SKIP, CHECKTIME_STOP, CHECKTIME_INCONSISTENT } checkTimeResult;
-static checkTimeResult checkTime(stream_t* streamptr, compvar2_t compVar, const DateTime* verificationTime, const DateTime* expectedVTime) {
-  // First determine whether the current record exists already.
-  int recID = 0;
-  for ( ; recID < streamptr->nrecs; recID++ )
-    {
-      if ( gribapiVarCompare(compVar, streamptr->tsteps[0].records[recID], 1) == 0 ) break;
-    }
-  int recordExists = recID < streamptr->nrecs;
 
-  // Then we need to know whether the verification time is consistent.
-  int consistentTime = !memcmp(verificationTime, expectedVTime, sizeof(*verificationTime));
+void streamInqHistoryString(int streamID, char *history)
+{
+#ifdef HAVE_LIBNETCDF
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-  // Finally, we make a decision.
-  if ( cdiInventoryMode == 1 )
-    {
-      if ( recordExists ) return CHECKTIME_STOP;
-      if ( !consistentTime ) return CHECKTIME_INCONSISTENT;
-    }
-  else
+  if ( streamptr->filetype == FILETYPE_NC  ||
+       streamptr->filetype == FILETYPE_NC2 ||
+       streamptr->filetype == FILETYPE_NC4 ||
+       streamptr->filetype == FILETYPE_NC4C )
     {
-      if ( !consistentTime ) return CHECKTIME_STOP;
-      if ( recordExists ) return CHECKTIME_SKIP;
+      cdfInqHistoryString(streamptr, history);
     }
-
-  return CHECKTIME_OK;
+#else
+  (void)streamID; (void)history;
+#endif
 }
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
 #endif
 
-#define gribWarning(text, nrecs, timestep, varname, param, level1, level2) do \
-  { \
-    char paramstr[32]; \
-    cdiParamToString(param, paramstr, sizeof(paramstr)); \
-    Warning("Record %2d (name=%s id=%s lev1=%d lev2=%d) timestep %d: %s", nrecs, varname, paramstr, level1, level2, timestep, text); \
-  } \
-while(0)
-
-#if  defined  (HAVE_LIBGRIB_API)
-int gribapiScanTimestep1(stream_t * streamptr)
-{
-  off_t recpos = 0;
-  unsigned char *gribbuffer = NULL;
-  size_t buffersize = 0;
-  DateTime datetime0 = { .date = 10101, .time = 0 };
-  int nrecs_scanned = 0;        //Only used for debug output.
-  int warn_time = TRUE;
-  // int warn_numavg = TRUE;
-  int rdate = 0, rtime = 0, tunit = 0, fcast = 0;
-  grib_handle *gh = NULL;
-
-  streamptr->curTsID = 0;
-
-  int tsID  = tstepsNewEntry(streamptr);
-  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+#include <math.h>
 
-  if ( tsID != 0 )
-    Error("Internal problem! tstepsNewEntry returns %d", tsID);
 
-  int fileID = streamptr->fileID;
 
-  unsigned nrecs = 0;
-  while ( TRUE )
-    {
-      int level1 = 0, level2 = 0;
-      size_t recsize = (size_t)gribGetSize(fileID);
-      recpos  = fileGetPos(fileID);
 
-      if ( recsize == 0 )
-        {
-          streamptr->ntsteps = 1;
-          break;
-        }
-      ensureBufferSize(recsize, &buffersize, &gribbuffer);
+#undef  UNDEFID
+#define UNDEFID  CDI_UNDEFID
 
-      size_t readsize = recsize;
-      int rstatus = gribRead(fileID, gribbuffer, &readsize); //Search for next 'GRIB', read the following record, and position file offset after it.
-      if ( rstatus ) break;
+#define SINGLE_PRECISION  4
+#define DOUBLE_PRECISION  8
 
-      int datatype, comptype = 0;
-      long unzipsize;
-      gh = gribapiGetDiskRepresentation(recsize, &buffersize, &gribbuffer, &datatype, &comptype, &unzipsize);
+#if defined (HAVE_LIBIEG)
 
-      nrecs_scanned++;
-      GRIB_CHECK(my_grib_set_double(gh, "missingValue", cdiDefaultMissval), 0);
 
-      int param = gribapiGetParam(gh);
-      int leveltype1 = -1, leveltype2 = -1, lbounds, level_sf, level_unit;
-      var_tile_t tiles = dummy_tiles;
-      gribGetLevel(gh, &leveltype1, &leveltype2, &lbounds, &level1, &level2, &level_sf, &level_unit, &tiles);
+typedef struct {
+  int param;
+  int level;
+} IEGCOMPVAR;
 
-      char varname[256];
-      varname[0] = 0;
-      gribapiGetString(gh, "shortName", varname, sizeof(varname));
 
-      int tsteptype = gribapiGetTsteptype(gh);
+static int iegInqDatatype(int prec)
+{
+  int datatype;
 
-      int vdate = 0, vtime = 0;
-      gribapiGetValidityDateTime(gh, &vdate, &vtime);
-      DateTime datetime = { .date = vdate, .time = vtime };
-      /*
-      printf("%d %d %d\n", vdate, vtime, leveltype1);
-      */
+  if ( prec == DOUBLE_PRECISION ) datatype = DATATYPE_FLT64;
+  else                            datatype = DATATYPE_FLT32;
 
-      if ( datetime0.date == 10101 && datetime0.time == 0 )
-        {
-          if( datetimeCmp(datetime, datetime0) || !nrecs )       //Do we really need this condition? I have included it in order not to change the number of times gribapiGetDataDateTime() etc. get called. But if those are sideeffect-free, this condition should be removed.
-            {
-              datetime0 = datetime;
+  return (datatype);
+}
 
-              gribapiGetDataDateTime(gh, &rdate, &rtime);
 
-              fcast = gribapiTimeIsFC(gh);
-              if ( fcast ) tunit = gribapiGetTimeUnits(gh);
-            }
-        }
+static int iegDefDatatype(int datatype)
+{
+  int prec;
 
-      if ( nrecs )
-        {
-          checkTimeResult result = checkTime(streamptr, gribapiVarSet(param, level1, level2, leveltype1, tsteptype, varname, tiles), &datetime, &datetime0);
-          if ( result == CHECKTIME_STOP )
-            {
-              break;
-            }
-          else if ( result == CHECKTIME_SKIP )
-            {
-              gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, varname, param, level1, level2);
-              continue;
-            }
-          else if ( result == CHECKTIME_INCONSISTENT && warn_time )
-            {
-              gribWarning("Inconsistent verification time!", nrecs_scanned, tsID+1, varname, param, level1, level2);
-              warn_time = FALSE;
-            }
-          assert(result == CHECKTIME_OK || result == CHECKTIME_INCONSISTENT);
-        }
-      /*
-      if ( ISEC1_AvgNum )
-        {
-          if (  taxis->numavg && warn_numavg && (taxis->numavg != ISEC1_AvgNum) )
-            {
-              Message("Change numavg from %d to %d not allowed!",
-                      taxis->numavg, ISEC1_AvgNum);
-              warn_numavg = FALSE;
-            }
-          else
-            {
-              taxis->numavg = ISEC1_AvgNum;
-            }
-        }
-      */
-      nrecs++;
+  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
+    Error("CDI/IEG library does not support complex numbers!");
 
-      if ( CDI_Debug )
-        {
-          char paramstr[32];
-          cdiParamToString(param, paramstr, sizeof(paramstr));
-          Message("%4u %8d name=%s id=%s ltype=%d lev1=%d lev2=%d vdate=%d vtime=%d",
-                nrecs, (int)recpos, varname, paramstr, leveltype1, level1, level2, vdate, vtime);
-        }
+  if ( datatype != DATATYPE_FLT32 && datatype != DATATYPE_FLT64 )
+    datatype = DATATYPE_FLT32;
 
-      var_tile_t *ptiles = NULL;
-      if ( memcmp(&tiles, &dummy_tiles, sizeof(var_tile_t)) != 0 ) ptiles = &tiles;
-      gribapiAddRecord(streamptr, param, gh, recsize, recpos, datatype, comptype, varname,
-                       leveltype1, leveltype2, lbounds, level1, level2, level_sf, level_unit, ptiles, 1);
+  if ( datatype == DATATYPE_FLT64 ) prec = DOUBLE_PRECISION;
+  else                              prec = SINGLE_PRECISION;
 
-      grib_handle_delete(gh);
-      gh = NULL;
-    }
+  return (prec);
+}
 
-  if ( gh ) grib_handle_delete(gh);
+/* not used
+int iegInqRecord(stream_t *streamptr, int *varID, int *levelID)
+{
+  int status;
+  int fileID;
+  int icode, ilevel;
+  int zaxisID = -1;
+  int vlistID;
+  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
 
-  streamptr->rtsteps = 1;
+  vlistID = streamptr->vlistID;
+  fileID  = streamptr->fileID;
 
-  if ( nrecs == 0 ) return (CDI_EUFSTRUCT);
+  *varID   = -1;
+  *levelID = -1;
 
-  cdi_generate_vars(streamptr);
+  status = iegRead(fileID, iegp);
+  if ( status != 0 ) return (0);
 
-  int taxisID = -1;
-  if ( fcast )
-    {
-      taxisID = taxisCreate(TAXIS_RELATIVE);
-      taxis->type  = TAXIS_RELATIVE;
-      taxis->rdate = rdate;
-      taxis->rtime = rtime;
-      taxis->unit  = tunit;
-    }
+  icode  = IEG_P_Parameter(iegp->ipdb);
+  if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
+    ilevel = IEG_P_Level1(iegp->ipdb);
   else
-    {
-      taxisID = taxisCreate(TAXIS_ABSOLUTE);
-      taxis->type  = TAXIS_ABSOLUTE;
-    }
-
-  taxis->vdate = (int)datetime0.date;
-  taxis->vtime = (int)datetime0.time;
-
-  int vlistID = streamptr->vlistID;
-  vlistDefTaxis(vlistID, taxisID);
-
-  int nrecords = streamptr->tsteps[0].nallrecs;
-  if ( nrecords < streamptr->tsteps[0].recordSize )
-    {
-      streamptr->tsteps[0].recordSize = nrecords;
-      streamptr->tsteps[0].records =
-        (record_t *) Realloc(streamptr->tsteps[0].records, (size_t)nrecords*sizeof(record_t));
-    }
-
-  streamptr->tsteps[0].recIDs = (int *) Malloc((size_t)nrecords*sizeof(int));
-  streamptr->tsteps[0].nrecs = nrecords;
-  for ( int recID = 0; recID < nrecords; recID++ )
-    streamptr->tsteps[0].recIDs[recID] = recID;
+    ilevel = IEG_P_Level2(iegp->ipdb);
 
-  streamptr->record->buffer     = gribbuffer;
-  streamptr->record->buffersize = buffersize;
+  *varID = vlistInqVarID(vlistID, icode);
 
-  if ( streamptr->ntsteps == -1 )
-    {
-      tsID = tstepsNewEntry(streamptr);
-      if ( tsID != streamptr->rtsteps )
-        Error("Internal error. tsID = %d", tsID);
+  if ( *varID == UNDEFID ) Error("Code %d undefined", icode);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
-      streamptr->tsteps[tsID].position = recpos;
-    }
+  zaxisID = vlistInqVarZaxis(vlistID, *varID);
 
-  if ( streamptr->ntsteps == 1 )
-    {
-      if ( taxis->vdate == 0 && taxis->vtime == 0 )
-        {
-          streamptr->ntsteps = 0;
-          for ( int varID = 0; varID < streamptr->nvars; varID++ )
-            {
-              vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-            }
-        }
-    }
+  *levelID = zaxisInqLevelID(zaxisID, (double) ilevel);
 
-  return (0);
+  return (1);
 }
-#endif
-
+*/
 
-#ifdef HAVE_LIBGRIB_API
-int gribapiScanTimestep2(stream_t * streamptr)
+void iegReadRecord(stream_t *streamptr, double *data, int *nmiss)
 {
-  int rstatus = 0;
-  off_t recpos = 0;
-  DateTime datetime0 = { LONG_MIN, LONG_MIN };
-  // int gridID;
-  int recID;
-  //  int warn_numavg = TRUE;
-  grib_handle *gh = NULL;
+  int vlistID, fileID;
+  int status;
+  int recID, vrecID, tsID;
+  off_t recpos;
+  int varID, gridID;
+  int i, size;
+  double missval;
+  void *iegp = streamptr->record->exsep;
 
-  streamptr->curTsID = 1;
+  vlistID = streamptr->vlistID;
+  fileID  = streamptr->fileID;
+  tsID    = streamptr->curTsID;
+  vrecID  = streamptr->tsteps[tsID].curRecID;
+  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
+  recpos  = streamptr->tsteps[tsID].records[recID].position;
+  varID   = streamptr->tsteps[tsID].records[recID].varID;
 
-  int fileID  = streamptr->fileID;
-  int vlistID = streamptr->vlistID;
-  int taxisID = vlistInqTaxis(vlistID);
+  fileSetPos(fileID, recpos, SEEK_SET);
 
-  unsigned char *gribbuffer = (unsigned char *) streamptr->record->buffer;
-  size_t buffersize = streamptr->record->buffersize;
+  status = iegRead(fileID, iegp);
+  if ( status != 0 )
+    Error("Could not read IEG record!");
 
-  int tsID = streamptr->rtsteps;
-  if ( tsID != 1 )
-    Error("Internal problem! unexpected timestep %d", tsID+1);
+  iegInqDataDP(iegp, data);
 
-  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+  missval = vlistInqVarMissval(vlistID, varID);
+  gridID  = vlistInqVarGrid(vlistID, varID);
+  size    = gridInqSize(gridID);
 
-  fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+  streamptr->numvals += size;
 
-  cdi_create_records(streamptr, tsID);
+  *nmiss = 0;
+  for ( i = 0; i < size; i++ )
+    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
+      {
+	data[i] = missval;
+	(*nmiss)++;
+      }
+}
 
-  int nrecords = streamptr->tsteps[tsID].nallrecs;
-  streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords*sizeof(int));
-  streamptr->tsteps[1].nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
-    streamptr->tsteps[1].recIDs[recID] = -1;
+static
+int iegGetZaxisType(int iegleveltype)
+{
+  int leveltype = 0;
 
-  for ( recID = 0; recID < nrecords; recID++ )
+  switch ( iegleveltype )
     {
-      streamptr->tsteps[tsID].records[recID].position = streamptr->tsteps[0].records[recID].position;
-      streamptr->tsteps[tsID].records[recID].size     = streamptr->tsteps[0].records[recID].size;
+    case IEG_LTYPE_SURFACE:
+      {
+	leveltype = ZAXIS_SURFACE;
+	break;
+      }
+    case IEG_LTYPE_99:
+    case IEG_LTYPE_ISOBARIC:
+      {
+	leveltype = ZAXIS_PRESSURE;
+	break;
+      }
+    case IEG_LTYPE_HEIGHT:
+      {
+	leveltype = ZAXIS_HEIGHT;
+	break;
+      }
+    case IEG_LTYPE_ALTITUDE:
+      {
+	leveltype = ZAXIS_ALTITUDE;
+	break;
+      }
+    case IEG_LTYPE_HYBRID:
+    case IEG_LTYPE_HYBRID_LAYER:
+      {
+	leveltype = ZAXIS_HYBRID;
+	break;
+      }
+    case IEG_LTYPE_LANDDEPTH:
+    case IEG_LTYPE_LANDDEPTH_LAYER:
+      {
+	leveltype = ZAXIS_DEPTH_BELOW_LAND;
+	break;
+      }
+    case IEG_LTYPE_SEADEPTH:
+      {
+	leveltype = ZAXIS_DEPTH_BELOW_SEA;
+	break;
+      }
+    default:
+      {
+	leveltype = ZAXIS_GENERIC;
+	break;
+      }
     }
 
-  int nrecs_scanned = nrecords; //Only used for debug output
-  int rindex = 0;
-  while ( TRUE )
-    {
-      if ( rindex > nrecords ) break;
+  return (leveltype);
+}
 
-      size_t recsize = (size_t)gribGetSize(fileID);
-      recpos  = fileGetPos(fileID);
-      if ( recsize == 0 )
-	{
-	  streamptr->ntsteps = 2;
-	  break;
-	}
-      ensureBufferSize(recsize, &buffersize, &gribbuffer);
 
-      size_t readsize = recsize;
-      rstatus = gribRead(fileID, gribbuffer, &readsize);
-      if ( rstatus ) break;
+static void iegDefTime(int *pdb, int date, int time, int taxisID)
+{
+  int year, month, day, hour, minute, second;
+  int timetype = -1;
+
+  if ( taxisID != -1 ) timetype = taxisInqType(taxisID);
+
+  if ( timetype == TAXIS_ABSOLUTE || timetype == TAXIS_RELATIVE )
+    {
+      cdiDecodeDate(date, &year, &month, &day);
+      cdiDecodeTime(time, &hour, &minute, &second);
+
+      IEG_P_Year(pdb)     = year;
+      IEG_P_Month(pdb)    = month;
+      IEG_P_Day(pdb)      = day;
+      IEG_P_Hour(pdb)     = hour;
+      IEG_P_Minute(pdb)   = minute;
 
-      long unzipsize;
-      if ( gribGetZip((long)recsize, gribbuffer, &unzipsize) > 0 )
-        ensureBufferSize((size_t)unzipsize + 100, &buffersize, &gribbuffer);
+      pdb[15] = 1;
+      pdb[16] = 0;
+      pdb[17] = 0;
+      pdb[18] = 10;
+      pdb[36] = 1;
+    }
 
-      nrecs_scanned++;
-      gh = grib_handle_new_from_message(NULL, (void *) gribbuffer, recsize);
-      GRIB_CHECK(my_grib_set_double(gh, "missingValue", cdiDefaultMissval), 0);
+  pdb[5] = 128;
+}
 
-      int param = gribapiGetParam(gh);
-      int level1 = 0, level2 = 0, leveltype1, leveltype2, lbounds, level_sf, level_unit;
-      var_tile_t tiles = dummy_tiles;
-      gribGetLevel(gh, &leveltype1, &leveltype2, &lbounds, &level1, &level2, &level_sf, &level_unit, &tiles);
+/* find smallest power of 10 in [1000,10000000] that upon
+ * multiplication results in fractional part close to zero for all
+ * arguments */
+static double
+calc_resfac(double xfirst, double xlast, double xinc, double yfirst, double ylast, double yinc)
+{
+  double resfac = 1000.0;
+  enum {
+    nPwrOf10 = 5,
+    nMultTests = 6,
+  };
+  static const double scaleFactors[nPwrOf10]
+    = { 1000, 10000, 100000, 1000000, 10000000 };
+  double vals[nMultTests] = { xfirst, xlast, xinc, yfirst, ylast, yinc };
 
-      char varname[256];
-      varname[0] = 0;
-      gribapiGetString(gh, "shortName", varname, sizeof(varname));
+  for (size_t j = 0; j < nPwrOf10; ++j )
+    {
+      double scaleBy = scaleFactors[j];
+      bool fractionalScale = false;
+      for (size_t i = 0; i < nMultTests; ++i )
+        {
+          fractionalScale = fractionalScale
+            || fabs(vals[i]*scaleBy - round(vals[i]*scaleBy)) > FLT_EPSILON;
+        }
+      if ( !fractionalScale )
+        {
+          resfac = scaleBy;
+          break;
+        }
+    }
 
-      int vdate = 0, vtime = 0;
-      gribapiGetValidityDateTime(gh, &vdate, &vtime);
+  return (resfac);
+}
 
-      if ( rindex == 0 )
-	{
-	  if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
-	    {
-	      taxis->type  = TAXIS_RELATIVE;
+static
+void iegDefGrid(int *gdb, int gridID)
+{
+  int gridtype = gridInqType(gridID);
 
-              gribapiGetDataDateTime(gh, &(taxis->rdate), &(taxis->rtime));
+  if ( gridtype == GRID_GENERIC )
+    {
+      int xsize, ysize;
 
-	      taxis->unit  = gribapiGetTimeUnits(gh);
-	    }
-	  else
-	    {
-	      taxis->type  = TAXIS_ABSOLUTE;
-	    }
-	  taxis->vdate = vdate;
-	  taxis->vtime = vtime;
+      xsize = gridInqXsize(gridID);
+      ysize = gridInqYsize(gridID);
 
-	  datetime0.date = vdate;
-	  datetime0.time = vtime;
+      if ( (ysize == 32  || ysize == 48 || ysize == 64 ||
+	    ysize == 96  || ysize == 160) &&
+	   (xsize == 2*ysize || xsize == 1) )
+	{
+	  gridtype = GRID_GAUSSIAN;
+	  gridChangeType(gridID, gridtype);
 	}
-
-      int tsteptype = gribapiGetTsteptype(gh);
-      /*
-      if ( ISEC1_AvgNum )
+      else if ( (xsize == 1 && ysize == 1) || (xsize == 0 && ysize == 0) )
 	{
-	  if (  taxis->numavg && warn_numavg &&
-		(taxis->numavg != ISEC1_AvgNum) )
-	    {
-	      warn_numavg = FALSE;
-	    }
-	  else
-	    {
-	      taxis->numavg = ISEC1_AvgNum;
-	    }
+	  gridtype = GRID_LONLAT;
+	  gridChangeType(gridID, gridtype);
 	}
-      */
-      DateTime datetime = {
-        .date = vdate,
-        .time = vtime
-      };
+      else if ( gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL) )
+	{
+	  gridtype = GRID_LONLAT;
+	  gridChangeType(gridID, gridtype);
+	}
+    }
+  else if ( gridtype == GRID_CURVILINEAR )
+    {
+      gridtype = GRID_LONLAT;
+    }
 
-      compvar2_t compVar = gribapiVarSet(param, level1, level2, leveltype1, tsteptype, varname, tiles);
+  if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN )
+    {
+      double xfirst = 0, xlast = 0, xinc = 0;
+      double yfirst = 0, ylast = 0, yinc = 0;
 
-      for ( recID = 0; recID < nrecords; recID++ )
-        if ( gribapiVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) == 0 ) break;
+      int nlon = gridInqXsize(gridID),
+        nlat = gridInqYsize(gridID);
 
-      if ( recID == nrecords )
+      if ( nlon == 0 )
 	{
-	  gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, varname, param, level1, level2);
-	  return (CDI_EUFSTRUCT);
+	  nlon = 1;
+	}
+      else
+	{
+	  xfirst = gridInqXval(gridID,      0);
+	  xlast  = gridInqXval(gridID, nlon-1);
+	  xinc   = gridInqXinc(gridID);
 	}
 
-      if ( streamptr->tsteps[tsID].records[recID].used )
-        {
-          if ( cdiInventoryMode == 1 ) break;
-          else
-	    {
-	      if ( datetimeCmp(datetime, datetime0) != 0 ) break;
-
-              gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, varname, param, level1, level2);
-	      continue;
-	    }
+      if ( nlat == 0 )
+	{
+	  nlat = 1;
+	}
+      else
+	{
+	  yfirst = gridInqYval(gridID,      0);
+	  ylast  = gridInqYval(gridID, nlat-1);
+	  yinc   = gridInqYinc(gridID);
 	}
 
-      streamptr->tsteps[tsID].records[recID].used = TRUE;
-      streamptr->tsteps[tsID].recIDs[rindex] = recID;
+      if ( gridtype == GRID_GAUSSIAN )
+	IEG_G_GridType(gdb) = 4;
+      else if ( gridtype == GRID_LONLAT && gridIsRotated(gridID) )
+	IEG_G_GridType(gdb) = 10;
+      else
+	IEG_G_GridType(gdb) = 0;
 
-      if ( CDI_Debug )
-        {
-          char paramstr[32];
-          cdiParamToString(param, paramstr, sizeof(paramstr));
-          Message("%4d %8d name=%s id=%s ltype=%d lev1=%d lev2=%d vdate=%d vtime=%d",
-                  nrecs_scanned, (int)recpos, varname, paramstr, leveltype1, level1, level2, vdate, vtime);
-        }
+      double resfac = calc_resfac(xfirst, xlast, xinc, yfirst, ylast, yinc);
+      int iresfac = (int)resfac;
+      if ( iresfac == 1000 ) iresfac = 0;
 
-      streamptr->tsteps[tsID].records[recID].size = recsize;
+      IEG_G_ResFac(gdb)   = iresfac;
 
-      if ( gribapiVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) != 0 )
-	{
-	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
-		  tsID, recID,
-		  streamptr->tsteps[tsID].records[recID].param, param,
-		  streamptr->tsteps[tsID].records[recID].ilevel, level1);
-	  return (CDI_EUFSTRUCT);
-	}
+      IEG_G_NumLon(gdb)   = nlon;
+      IEG_G_NumLat(gdb)   = nlat;
+      IEG_G_FirstLat(gdb) = (int)lround(yfirst*resfac);
+      IEG_G_LastLat(gdb)  = (int)lround(ylast*resfac);
+      IEG_G_FirstLon(gdb) = (int)lround(xfirst*resfac);
+      IEG_G_LastLon(gdb)  = (int)lround(xlast*resfac);
+      IEG_G_LonIncr(gdb)  = (int)lround(xinc*resfac);
+      if ( fabs(xinc*resfac - IEG_G_LonIncr(gdb)) > FLT_EPSILON )
+	IEG_G_LonIncr(gdb) = 0;
 
-      streamptr->tsteps[1].records[recID].position = recpos;
-      int varID = streamptr->tsteps[tsID].records[recID].varID;
-      /*
-      gridID = vlistInqVarGrid(vlistID, varID);
-      if ( gridInqSize(gridID) == 1 && gridInqType(gridID) == GRID_LONLAT )
+      if ( gridtype == GRID_GAUSSIAN )
+	IEG_G_LatIncr(gdb) = nlat/2;
+      else
 	{
-	  if ( IS_NOT_EQUAL(gridInqXval(gridID, 0),ISEC2_FirstLon*0.001) ||
-	       IS_NOT_EQUAL(gridInqYval(gridID, 0),ISEC2_FirstLat*0.001) )
-	    gridChangeType(gridID, GRID_TRAJECTORY);
+	  IEG_G_LatIncr(gdb) = (int)lround(yinc*resfac);
+	  if ( fabs(yinc*resfac - IEG_G_LatIncr(gdb)) > FLT_EPSILON )
+	    IEG_G_LatIncr(gdb) = 0;
+
+	  if ( IEG_G_LatIncr(gdb) < 0 ) IEG_G_LatIncr(gdb) = -IEG_G_LatIncr(gdb);
 	}
-      */
-      if ( tsteptype != vlistInqVarTsteptype(vlistID, varID) )
-	vlistDefVarTsteptype(vlistID, varID, tsteptype);
 
-      grib_handle_delete(gh);
-      gh = NULL;
+      if ( IEG_G_NumLon(gdb) > 1 && IEG_G_NumLat(gdb) == 1 )
+	if ( IEG_G_LonIncr(gdb) != 0 && IEG_G_LatIncr(gdb) == 0 ) IEG_G_LatIncr(gdb) = IEG_G_LonIncr(gdb);
 
-      rindex++;
-    }
+      if ( IEG_G_NumLon(gdb) == 1 && IEG_G_NumLat(gdb) > 1 )
+	if ( IEG_G_LonIncr(gdb) == 0 && IEG_G_LatIncr(gdb) != 0 ) IEG_G_LonIncr(gdb) = IEG_G_LatIncr(gdb);
 
-  if ( gh ) grib_handle_delete(gh);
+      if ( IEG_G_LatIncr(gdb) == 0 || IEG_G_LonIncr(gdb) == 0 )
+	IEG_G_ResFlag(gdb) = 0;
+      else
+	IEG_G_ResFlag(gdb) = 128;
 
-  int nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
-    {
-      if ( ! streamptr->tsteps[tsID].records[recID].used )
+      if ( gridIsRotated(gridID) )
 	{
-	  int varID = streamptr->tsteps[tsID].records[recID].varID;
-	  vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	  IEG_G_LatSP(gdb) = - (int)lround(gridInqYpole(gridID) * resfac);
+	  IEG_G_LonSP(gdb) =   (int)lround((gridInqXpole(gridID) + 180) * resfac);
+	  IEG_G_Size(gdb)  = 42;
 	}
       else
 	{
-	  nrecs++;
+	  IEG_G_Size(gdb)  = 32;
 	}
     }
-  streamptr->tsteps[tsID].nrecs = nrecs;
-
-  streamptr->rtsteps = 2;
-
-  if ( streamptr->ntsteps == -1 )
+  else
     {
-      tsID = tstepsNewEntry(streamptr);
-      if ( tsID != streamptr->rtsteps )
-	Error("Internal error. tsID = %d", tsID);
-
-      streamptr->tsteps[tsID-1].next   = TRUE;
-      streamptr->tsteps[tsID].position = recpos;
+      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
     }
 
-  streamptr->record->buffer     = gribbuffer;
-  streamptr->record->buffersize = buffersize;
-
-  return (rstatus);
+  IEG_G_ScanFlag(gdb) = 64;
 }
-#endif
-
 
-#if  defined  (HAVE_LIBGRIB_API)
-int gribapiScanTimestep(stream_t * streamptr)
+static
+void iegDefLevel(int *pdb, int *gdb, double *vct, int zaxisID, int levelID)
 {
-  int vrecID, recID;
-  //int warn_numavg = TRUE;
-  int nrecs = 0;
-  int vlistID = streamptr->vlistID;
+  double level;
+  int ilevel, leveltype;
+  static int vct_warning = 1;
 
-  if ( CDI_Debug )
+  leveltype = zaxisInqType(zaxisID);
+
+  if ( leveltype == ZAXIS_GENERIC )
     {
-      Message("streamID = %d", streamptr->self);
-      Message("cts = %d", streamptr->curTsID);
-      Message("rts = %d", streamptr->rtsteps);
-      Message("nts = %d", streamptr->ntsteps);
+      Message("Changed zaxis type from %s to %s",
+	      zaxisNamePtr(leveltype),
+	      zaxisNamePtr(ZAXIS_PRESSURE));
+      leveltype = ZAXIS_PRESSURE;
+      zaxisChangeType(zaxisID, leveltype);
+      zaxisDefUnits(zaxisID, "Pa");
     }
 
-  int tsID  = streamptr->rtsteps;
-  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+  /*  IEG_G_NumVCP(gdb) = 0; */
 
-  if ( streamptr->tsteps[tsID].recordSize == 0 )
+  switch (leveltype)
     {
-      unsigned char* gribbuffer = (unsigned char *) streamptr->record->buffer;
-      size_t buffersize = streamptr->record->buffersize;
-
-      cdi_create_records(streamptr, tsID);
-
-      nrecs = streamptr->tsteps[1].nrecs;
-
-      streamptr->tsteps[tsID].nrecs = nrecs;
-      streamptr->tsteps[tsID].recIDs = (int *) Malloc((size_t)nrecs*sizeof(int));
-      for ( recID = 0; recID < nrecs; recID++ )
-	streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
-
-      int fileID = streamptr->fileID;
-
-      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
-
-      int nrecs_scanned = streamptr->tsteps[0].nallrecs + streamptr->tsteps[1].nrecs*(tsID-1);    //Only used for debug output.
-      int rindex = 0;
-      off_t recpos = 0;
-      DateTime datetime0 = { LONG_MIN, LONG_MIN };
-      grib_handle *gh = NULL;
-      char varname[256];
-      while ( TRUE )
-	{
-	  if ( rindex > nrecs ) break;
-
-	  size_t recsize = (size_t)gribGetSize(fileID);
-	  recpos  = fileGetPos(fileID);
-	  if ( recsize == 0 )
-	    {
-	      streamptr->ntsteps = streamptr->rtsteps + 1;
-	      break;
-	    }
-
-	  if ( rindex >= nrecs ) break;
-
-          ensureBufferSize(recsize, &buffersize, &gribbuffer);
-
-	  size_t readsize = recsize;
-	  if (gribRead(fileID, gribbuffer, &readsize))
-	    {
-	      Warning("Inconsistent timestep %d (GRIB record %d/%d)!", tsID+1, rindex+1,
-		      streamptr->tsteps[tsID].recordSize);
-	      break;
-	    }
-
-          long unzipsize;
-	  if ( gribGetZip((long)recsize, gribbuffer, &unzipsize) > 0 )
-            ensureBufferSize((size_t)unzipsize + 100, &buffersize, &gribbuffer);
-
-          nrecs_scanned++;
-	  gh = grib_handle_new_from_message(NULL, (void *) gribbuffer, recsize);
-	  GRIB_CHECK(my_grib_set_double(gh, "missingValue", cdiDefaultMissval), 0);
-
-          int param = gribapiGetParam(gh);
-          int level1 = 0, level2 = 0, leveltype1, leveltype2 = -1, lbounds, level_sf, level_unit;
-          var_tile_t tiles = dummy_tiles;
-          gribGetLevel(gh, &leveltype1, &leveltype2, &lbounds, &level1, &level2, &level_sf, &level_unit, &tiles);
-
-          varname[0] = 0;
-	  gribapiGetString(gh, "shortName", varname, sizeof(varname));
-
-          int vdate = 0, vtime = 0;
-	  gribapiGetValidityDateTime(gh, &vdate, &vtime);
-
-	  if ( rindex == nrecs ) break;
-
-	  if ( rindex == 0 )
-	    {
-              int taxisID = vlistInqTaxis(vlistID);
-	      if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
-		{
-		  taxis->type  = TAXIS_RELATIVE;
-
-                  gribapiGetDataDateTime(gh, &(taxis->rdate), &(taxis->rtime));
-
-		  taxis->unit  = gribapiGetTimeUnits(gh);
-		}
-	      else
-		{
-		  taxis->type  = TAXIS_ABSOLUTE;
-		}
-	      taxis->vdate = vdate;
-	      taxis->vtime = vtime;
-
-	      datetime0.date = vdate;
-	      datetime0.time = vtime;
-	    }
-	  /*
-	  if ( ISEC1_AvgNum )
-	    {
-	      if (  taxis->numavg && warn_numavg &&
-		   (taxis->numavg != ISEC1_AvgNum) )
-		{
-		  warn_numavg = FALSE;
-		}
-	      else
-		{
-		  taxis->numavg = ISEC1_AvgNum;
-		}
-	    }
-	  */
-          DateTime datetime = {
-            .date  = vdate,
-            .time  = vtime
-          };
-
-          int tsteptype = gribapiGetTsteptype(gh);
-
-          compvar2_t compVar = gribapiVarSet(param, level1, level2, leveltype1, tsteptype, varname, tiles);
-
-	  for ( vrecID = 0; vrecID < nrecs; vrecID++ )
-	    {
-	      recID   = streamptr->tsteps[1].recIDs[vrecID];
-	      if ( gribapiVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) == 0 ) break;
-	    }
-
-	  if ( vrecID == nrecs )
-	    {
-	      gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, varname, param, level1, level2);
-
-	      if ( cdiInventoryMode == 1 )
-		return (CDI_EUFSTRUCT);
-	      else
-		continue;
-	    }
-
-	  if ( cdiInventoryMode != 1 )
-	    {
-	      if ( streamptr->tsteps[tsID].records[recID].used )
-		{
-		  if ( datetimeCmp(datetime, datetime0) != 0 ) break;
-
-		  if ( CDI_Debug )
-                    gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, varname, param, level1, level2);
-
-		  continue;
-		}
-	    }
-
-          streamptr->tsteps[tsID].records[recID].used = TRUE;
-          streamptr->tsteps[tsID].recIDs[rindex] = recID;
+    case ZAXIS_SURFACE:
+      {
+	IEG_P_LevelType(pdb) = IEG_LTYPE_SURFACE;
+	IEG_P_Level1(pdb)    = 0;
+	IEG_P_Level2(pdb)    = (int)(zaxisInqLevel(zaxisID, levelID));
+	break;
+      }
+    case ZAXIS_HYBRID:
+      {
+	int vctsize;
 
-	  if ( CDI_Debug )
-	    Message("%4d %8d %4d %8d %8d %6d", rindex+1, (int)recpos, param, level1, vdate, vtime);
+	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
+	  {
+	    IEG_P_LevelType(pdb) = IEG_LTYPE_HYBRID_LAYER;
+	    IEG_P_Level1(pdb)    = (int)(zaxisInqLbound(zaxisID, levelID));
+	    IEG_P_Level2(pdb)    = (int)(zaxisInqUbound(zaxisID, levelID));
+	  }
+	else
+	  {
+	    IEG_P_LevelType(pdb) = IEG_LTYPE_HYBRID;
+	    IEG_P_Level1(pdb)    = 0;
+	    IEG_P_Level2(pdb)    = (int)(zaxisInqLevel(zaxisID, levelID));
+	  }
 
-	  if ( gribapiVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) != 0 )
-	    {
-	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
-		      tsID, recID,
-		      streamptr->tsteps[tsID].records[recID].param, param,
-		      streamptr->tsteps[tsID].records[recID].ilevel, level1);
-	      Error("Invalid, unsupported or inconsistent record structure");
-	    }
+	vctsize = zaxisInqVctSize(zaxisID);
+	if ( vctsize > 100 )
+	  {
+	    /*	    IEG_G_NumVCP(gdb) = 0; */
+	    if ( vct_warning )
+	      {
+		Warning("VCT size of %d is too large (maximum is 100). Set to 0!", vctsize);
+		vct_warning = 0;
+	      }
+	  }
+	else
+	  {
+	    IEG_G_Size(gdb) += (vctsize*4);
+	    memcpy(vct, zaxisInqVctPtr(zaxisID), (size_t)vctsize/2*sizeof(double));
+	    memcpy(vct+50, zaxisInqVctPtr(zaxisID)+vctsize/2, (size_t)vctsize/2*sizeof(double));
+	  }
+	break;
+      }
+    case ZAXIS_PRESSURE:
+      {
+	double dum;
+	char units[128];
 
-	  streamptr->tsteps[tsID].records[recID].position = recpos;
-	  streamptr->tsteps[tsID].records[recID].size = recsize;
+	level = zaxisInqLevel(zaxisID, levelID);
+	if ( level < 0 )
+	  Warning("pressure level of %f Pa is below 0.", level);
 
-	  if ( CDI_Debug )
-	    Message("%4d %8d %4d %8d %8d %6d", rindex, (int)recpos, param, level1, vdate, vtime);
+	zaxisInqUnits(zaxisID, units);
+	if ( memcmp(units, "hPa", 3) == 0 || memcmp(units, "mb",2 ) == 0 )
+	  level = level*100;
 
-	  grib_handle_delete(gh);
-	  gh = NULL;
+	ilevel = (int) level;
+	if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
+	  {
+	    IEG_P_LevelType(pdb) = IEG_LTYPE_99;
+	    IEG_P_Level1(pdb)    = 0;
+	    IEG_P_Level2(pdb)    = ilevel;
+	  }
+	else
+	  {
+	    IEG_P_LevelType(pdb) = IEG_LTYPE_ISOBARIC;
+	    IEG_P_Level1(pdb)    = 0;
+	    IEG_P_Level2(pdb)    = ilevel/100;
+	  }
+	break;
+      }
+    case ZAXIS_HEIGHT:
+      {
+	level = zaxisInqLevel(zaxisID, levelID);
 
-	  rindex++;
-	}
+	ilevel = (int) level;
+	IEG_P_LevelType(pdb) = IEG_LTYPE_HEIGHT;
+	IEG_P_Level1(pdb)    = 0;
+	IEG_P_Level2(pdb)    = ilevel;
 
-      if ( gh ) grib_handle_delete(gh);
+	break;
+      }
+    case ZAXIS_ALTITUDE:
+      {
+	level = zaxisInqLevel(zaxisID, levelID);
 
-      for ( vrecID = 0; vrecID < nrecs; vrecID++ )
-	{
-	  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-	  if ( ! streamptr->tsteps[tsID].records[recID].used ) break;
-	}
+	ilevel = (int) level;
+	IEG_P_LevelType(pdb) = IEG_LTYPE_ALTITUDE;
+	IEG_P_Level1(pdb)    = 0;
+	IEG_P_Level2(pdb)    = ilevel;
 
-      if ( vrecID < nrecs )
-	{
-	  gribWarning("Paramameter not found!", nrecs_scanned, tsID+1, varname, streamptr->tsteps[tsID].records[recID].param,
-                      streamptr->tsteps[tsID].records[recID].ilevel, streamptr->tsteps[tsID].records[recID].ilevel2);
-	  return (CDI_EUFSTRUCT);
-	}
+	break;
+      }
+    case ZAXIS_DEPTH_BELOW_LAND:
+      {
+	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
+	  {
+	    IEG_P_LevelType(pdb) = IEG_LTYPE_LANDDEPTH_LAYER;
+	    IEG_P_Level1(pdb)    = (int)(zaxisInqLbound(zaxisID, levelID));
+	    IEG_P_Level2(pdb)    = (int)(zaxisInqUbound(zaxisID, levelID));
+	  }
+	else
+	  {
+	    level = zaxisInqLevel(zaxisID, levelID);
 
-      streamptr->rtsteps++;
+	    ilevel = (int) level;
+	    IEG_P_LevelType(pdb) = IEG_LTYPE_LANDDEPTH;
+	    IEG_P_Level1(pdb)    = 0;
+	    IEG_P_Level2(pdb)    = ilevel;
+	  }
 
-      if ( streamptr->ntsteps != streamptr->rtsteps )
-	{
-	  tsID = tstepsNewEntry(streamptr);
-	  if ( tsID != streamptr->rtsteps )
-	    Error("Internal error. tsID = %d", tsID);
+	break;
+      }
+    case ZAXIS_DEPTH_BELOW_SEA:
+      {
+	level = zaxisInqLevel(zaxisID, levelID);
 
-	  streamptr->tsteps[tsID-1].next   = 1;
-	  streamptr->tsteps[tsID].position = recpos;
-	}
+	ilevel = (int) level;
+	IEG_P_LevelType(pdb) = IEG_LTYPE_SEADEPTH;
+	IEG_P_Level1(pdb)    = 0;
+	IEG_P_Level2(pdb)    = ilevel;
 
-      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
-      streamptr->tsteps[tsID].position = recpos;
+	break;
+      }
+    case ZAXIS_ISENTROPIC:
+      {
+	level = zaxisInqLevel(zaxisID, levelID);
 
-      streamptr->record->buffer     = gribbuffer;
-      streamptr->record->buffersize = buffersize;
-    }
+	ilevel = (int) level;
+	IEG_P_LevelType(pdb) = 113;
+	IEG_P_Level1(pdb)    = 0;
+	IEG_P_Level2(pdb)    = ilevel;
 
-  if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
-    {
-      Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
-      streamptr->ntsteps = tsID;
+	break;
+      }
+    default:
+      {
+	Error("Unsupported zaxis type: %s", zaxisNamePtr(leveltype));
+	break;
+      }
     }
-
-  return (int)streamptr->ntsteps;
 }
-#endif
 
-#ifdef gribWarning
-#undef gribWarning
-#endif
 
-#ifdef HAVE_LIBGRIB_API
-int gribapiDecode(unsigned char *gribbuffer, int gribsize, double *data, int gridsize,
-		  int unreduced, int *nmiss, double missval, int vlistID, int varID)
+void iegCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
 {
-  int status = 0;
-  long lpar;
-  long numberOfPoints;
-  size_t datasize;
+  streamFCopyRecord(streamptr2, streamptr1, "IEG");
+}
 
-  UNUSED(vlistID);
-  UNUSED(varID);
 
-  if ( unreduced )
-    {
-      static int lwarn = 1;
+void iegDefRecord(stream_t *streamptr)
+{
+  int vlistID;
+  int gridID;
+  int date, time;
+  int datatype;
+  int i;
+  int param, pdis, pcat, pnum;
+  int varID, levelID, tsID, zaxisID;
+  int byteorder;
+  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
 
-      if ( lwarn )
-	{
-	  lwarn = 0;
-	  Warning("Conversion of gaussian reduced grids unsupported!");
-	}
-    }
+  vlistID = streamptr->vlistID;
+  byteorder = streamptr->byteorder;
 
-  size_t recsize = (size_t)gribsize;
-  grib_handle *gh = grib_handle_new_from_message(NULL, (void *) gribbuffer, recsize);
-  GRIB_CHECK(my_grib_set_double(gh, "missingValue", missval), 0);
+  varID   = streamptr->record->varID;
+  levelID = streamptr->record->levelID;
+  tsID    = streamptr->curTsID;
 
-  /* get the size of the values array*/
-  GRIB_CHECK(grib_get_size(gh, "values", &datasize), 0);
-  GRIB_CHECK(grib_get_long(gh, "numberOfPoints", &numberOfPoints), 0);
+  gridID  = vlistInqVarGrid(vlistID, varID);
+  zaxisID = vlistInqVarZaxis(vlistID, varID);
 
-  // printf("values_size = %d  numberOfPoints = %ld\n", datasize, numberOfPoints);
+  iegInitMem(iegp);
+  for ( i = 0; i < 37; i++ ) iegp->ipdb[i] = -1;
 
-  if ( gridsize != (int) datasize )
-    Error("Internal problem: gridsize(%d) != datasize(%d)!", gridsize, datasize);
-  size_t dummy = datasize;
-  GRIB_CHECK(grib_get_double_array(gh, "values", data, &dummy), 0);
+  iegp->byteswap = getByteswap(byteorder);
 
-  GRIB_CHECK(grib_get_long(gh, "gridDefinitionTemplateNumber", &lpar), 0);
-  int gridtype = (int) lpar;
+  param =  vlistInqVarParam(vlistID, varID);
+  cdiDecodeParam(param, &pnum, &pcat, &pdis);
+  IEG_P_Parameter(iegp->ipdb) = pnum;
+  if ( pdis == 255 ) IEG_P_CodeTable(iegp->ipdb) = pcat;
+  date     = streamptr->tsteps[tsID].taxis.vdate;
+  time     = streamptr->tsteps[tsID].taxis.vtime;
 
-  *nmiss = 0;
-  if ( gridtype < 50 || gridtype > 53 )
-    {
-      GRIB_CHECK(grib_get_long(gh, "numberOfMissing", &lpar), 0);
-      *nmiss = (int) lpar;
-      // printf("gridtype %d, nmiss %d\n", gridtype, nmiss);
-    }
+  iegDefTime(iegp->ipdb, date, time, vlistInqTaxis(vlistID));
+  iegDefGrid(iegp->igdb, gridID);
+  iegDefLevel(iegp->ipdb, iegp->igdb, iegp->vct, zaxisID, levelID);
 
-  grib_handle_delete(gh);
+  datatype = streamptr->record->prec;
 
-  return (status);
+  iegp->dprec = iegDefDatatype(datatype);
 }
-#endif
 
 
-#if  defined  (HAVE_LIBGRIB_API)
-static
-void gribapiDefInstitut(grib_handle *gh, int vlistID, int varID)
+void iegWriteRecord(stream_t *streamptr, const double *data)
 {
-  int instID;
-
-  if ( vlistInqInstitut(vlistID) != CDI_UNDEFID )
-    instID = vlistInqInstitut(vlistID);
-  else
-    instID = vlistInqVarInstitut(vlistID, varID);
-
-  if ( instID != CDI_UNDEFID )
-    {
-      long center, subcenter;
-      long center0, subcenter0;
+  int fileID;
+  int i, gridsize, gridID;
+  double refval;
+  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
 
-      center    = institutInqCenter(instID);
-      subcenter = institutInqSubcenter(instID);
+  fileID = streamptr->fileID;
+  gridID = streamptr->record->gridID;
 
-      GRIB_CHECK(grib_get_long(gh, "centre", &center0), 0);
-      GRIB_CHECK(grib_get_long(gh, "subCentre", &subcenter0), 0);
+  gridsize = gridInqSize(gridID);
 
-      if ( center != center0 )
-	GRIB_CHECK(my_grib_set_long(gh, "centre", center), 0);
-      if ( subcenter != subcenter0 )
-	GRIB_CHECK(my_grib_set_long(gh, "subCentre", subcenter), 0);
-    }
-}
+  refval = data[0];
+  for ( i = 1; i < gridsize; i++ )
+    if ( data[i] < refval ) refval = data[i];
 
-static
-void gribapiDefModel(grib_handle *gh, int vlistID, int varID)
-{
-  int modelID;
+  iegp->refval = refval;
 
-  if ( vlistInqModel(vlistID) != CDI_UNDEFID )
-    modelID = vlistInqModel(vlistID);
-  else
-    modelID = vlistInqVarModel(vlistID, varID);
+  iegDefDataDP(iegp, data);
 
-  if ( modelID != CDI_UNDEFID )
-    GRIB_CHECK(my_grib_set_long(gh, "generatingProcessIdentifier", modelInqGribID(modelID)), 0);
+  iegWrite(fileID, iegp);
 }
 
 static
-void gribapiDefParam(int editionNumber, grib_handle *gh, int param, const char *name, const char *stdname)
+void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vct,
+		  size_t recsize, off_t position, int prec)
 {
-  bool ldefined = false;
-
-  int pdis, pcat, pnum;
-  cdiDecodeParam(param, &pnum, &pcat, &pdis);
+  int levelID = 0;
+  int vlistID = streamptr->vlistID;
+  int tsID    = streamptr->curTsID;
+  int recID   = recordNewEntry(streamptr, tsID);
+  record_t *record = &streamptr->tsteps[tsID].records[recID];
 
-  if ( pnum < 0 )
+  int level1, level2;
+  if ( IEG_P_LevelType(pdb) == IEG_LTYPE_HYBRID_LAYER )
     {
-      size_t len;
-      len = strlen(stdname);
-      if ( len )
-        {
-          int status = my_grib_set_string(gh, "cfName", stdname, &len);
-          if ( status == 0 ) ldefined = true;
-          else Warning("grib_api: No match for cfName=%s", stdname);
-        }
-
-      if ( ldefined == false )
-        {
-          len = strlen(name);
-          int status = my_grib_set_string(gh, "shortName", name, &len);
-          if ( status == 0 ) ldefined = true;
-          else Warning("grib_api: No match for shortName=%s", name);
-        }
+      level1 = IEG_P_Level1(pdb);
+      level2 = IEG_P_Level2(pdb);
     }
-
-  if ( ldefined == false )
+  else
     {
-      if ( pnum < 0 ) pnum = -pnum;
+      level1 = IEG_P_Level2(pdb);
+      level2 = 0;
+      if ( IEG_P_LevelType(pdb) == 100 ) level1 *= 100;
+    }
 
-      static bool lwarn_pnum = true;
-      if ( pnum > 255 && lwarn_pnum )
-        {
-          Warning("Parameter number %d out of range (1-255), set to %d!", pnum, pnum%256);
-          lwarn_pnum = false;
-          pnum = pnum%256;
-        }
+  record->size     = recsize;
+  record->position = position;
+  record->param    = param;
+  record->ilevel   = level1;
+  record->ilevel2  = level2;
+  record->ltype    = IEG_P_LevelType(pdb);
 
-      if ( editionNumber <= 1 )
-	{
-          static bool lwarn_pdis = true;
-	  if ( pdis != 255 && lwarn_pdis )
-	    {
-	      char paramstr[32];
-	      cdiParamToString(param, paramstr, sizeof(paramstr));
-	      Warning("Can't convert GRIB2 parameter ID (%s) to GRIB1, set to %d.%d!", paramstr, pnum, pcat);
-              lwarn_pdis = false;
-	    }
+  int gridtype =
+   ( IEG_G_GridType(gdb) == 0 || IEG_G_GridType(gdb) == 10 ) ? GRID_LONLAT :
+    ( IEG_G_GridType(gdb) == 4 ) ? GRID_GAUSSIAN : GRID_GENERIC;
 
-	  GRIB_CHECK(my_grib_set_long(gh, "table2Version",        pcat), 0);
-	  GRIB_CHECK(my_grib_set_long(gh, "indicatorOfParameter", pnum), 0);
-	}
-      else
-	{
-	  GRIB_CHECK(my_grib_set_long(gh, "discipline",        pdis), 0);
-	  GRIB_CHECK(my_grib_set_long(gh, "parameterCategory", pcat), 0);
-	  GRIB_CHECK(my_grib_set_long(gh, "parameterNumber",   pnum), 0);
-	}
-    }
+  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, IEG_G_NumLon(gdb)*IEG_G_NumLat(gdb));
+  grid->xsize = IEG_G_NumLon(gdb);
+  grid->ysize = IEG_G_NumLat(gdb);
+  grid->xinc  = 0;
+  grid->yinc  = 0;
+  grid->xdef  = 0;
 
-  // printf("param: %d.%d.%d %s\n", pnum, pcat, pdis, name);
-}
+  int iresfac = IEG_G_ResFac(gdb);
+  if ( iresfac == 0 ) iresfac = 1000;
+  double resfac = 1./(double) iresfac;
 
-static
-int getTimeunitFactor(int timeunit)
-{
-  int factor = 1;
+  /* if ( IEG_G_FirstLon != 0 || IEG_G_LastLon != 0 ) */
+  {
+    if ( grid->xsize > 1 )
+      {
+	if ( IEG_G_ResFlag(gdb) && IEG_G_LonIncr(gdb) > 0 )
+	  grid->xinc = IEG_G_LonIncr(gdb) * resfac;
+	else
+	  grid->xinc = (IEG_G_LastLon(gdb) - IEG_G_FirstLon(gdb)) * resfac / (grid->xsize - 1);
 
-  switch (timeunit)
+	/* correct xinc if necessary */
+	if ( IEG_G_FirstLon(gdb) == 0 && IEG_G_LastLon(gdb) > 354000 )
+	  {
+	    double xinc = 360. / grid->xsize;
+            /* FIXME: why not use grid->xinc != xinc as condition? */
+	    if ( fabs(grid->xinc-xinc) > 0.0 )
+	      {
+		grid->xinc = xinc;
+		if ( CDI_Debug ) Message("set xinc to %g", grid->xinc);
+	      }
+	  }
+      }
+    grid->xfirst = IEG_G_FirstLon(gdb) * resfac;
+    grid->xlast  = IEG_G_LastLon(gdb)  * resfac;
+    grid->xdef   = 2;
+  }
+  grid->ydef  = 0;
+  /* if ( IEG_G_FirstLat != 0 || IEG_G_LastLat != 0 ) */
+  {
+    if ( grid->ysize > 1 )
+      {
+	if ( IEG_G_ResFlag(gdb) && IEG_G_LatIncr(gdb) > 0 )
+	  grid->yinc = IEG_G_LatIncr(gdb) * resfac;
+	else
+	  grid->yinc = (IEG_G_LastLat(gdb) - IEG_G_FirstLat(gdb)) * resfac / (grid->ysize - 1);
+      }
+    grid->yfirst = IEG_G_FirstLat(gdb) * resfac;
+    grid->ylast  = IEG_G_LastLat(gdb)  * resfac;
+    grid->ydef   = 2;
+  }
+  /*
+  grid->xfirst= IEG_G_FirstLon(gdb) * resfac;
+  grid->xlast = IEG_G_LastLon(gdb) * resfac;
+  grid->xinc  = IEG_G_LonIncr(gdb) * resfac;
+  grid->xdef  = 2;
+  grid->yfirst= IEG_G_FirstLat(gdb) * resfac;
+  grid->ylast = IEG_G_LastLat(gdb) * resfac;
+  grid->yinc  = IEG_G_LatIncr(gdb) * resfac;
+  grid->ydef  = 2;
+  */
+  grid->xvals = NULL;
+  grid->yvals = NULL;
+
+  grid->isRotated = FALSE;
+  if ( IEG_G_GridType(gdb) == 10 )
     {
-    case TUNIT_SECOND:  factor =     1;  break;
-    case TUNIT_MINUTE:  factor =    60;  break;
-    case TUNIT_HOUR:    factor =  3600;  break;
-    case TUNIT_3HOURS:  factor = 10800;  break;
-    case TUNIT_6HOURS:  factor = 21600;  break;
-    case TUNIT_12HOURS: factor = 43200;  break;
-    case TUNIT_DAY:     factor = 86400;  break;
-    default:            factor =  3600;  break;
+      grid->isRotated = TRUE;
+      grid->ypole     = - IEG_G_LatSP(gdb) * resfac;
+      grid->xpole     =   IEG_G_LonSP(gdb) * resfac - 180;
+      grid->angle     = 0;
     }
 
-  return (factor);
-}
+  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  int gridID = gridAdded.Id;
+  if (!gridAdded.isNew) Free(grid);
 
-static
-void gribapiDefStepUnits(grib_handle *gh, int timeunit, int proDefTempNum, int gcinit)
-{
-  long unitsOfTime;
+  int leveltype = iegGetZaxisType(IEG_P_LevelType(pdb));
 
-  switch (timeunit)
+  if ( leveltype == ZAXIS_HYBRID )
     {
-    case TUNIT_SECOND:  unitsOfTime = 13;  break;
-    case TUNIT_MINUTE:  unitsOfTime =  0;  break;
-    case TUNIT_HOUR:    unitsOfTime =  1;  break;
-    case TUNIT_3HOURS:  unitsOfTime = 10;  break;
-    case TUNIT_6HOURS:  unitsOfTime = 11;  break;
-    case TUNIT_12HOURS: unitsOfTime = 12;  break;
-    case TUNIT_DAY:     unitsOfTime =  2;  break;
-    default:            unitsOfTime =  1;  break;
-    }
+      double tmpvct[100];
+      size_t vctsize = (size_t)IEG_G_NumVCP(gdb);
 
-  if ( !gcinit )
-    {
-      GRIB_CHECK(my_grib_set_long(gh, "stepUnits", unitsOfTime), 0);
-      if ( proDefTempNum == 8 || proDefTempNum == 11 )
-        GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime), 0);
-      GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime), 0);
+      for (size_t i = 0; i < vctsize/2; i++ ) tmpvct[i] = vct[i];
+      for (size_t i = 0; i < vctsize/2; i++ ) tmpvct[i+vctsize/2] = vct[i+50];
+
+      varDefVCT(vctsize, tmpvct);
     }
+
+  int lbounds = IEG_P_LevelType(pdb) == IEG_LTYPE_HYBRID_LAYER ? 1 : 0;
+
+  int datatype = iegInqDatatype(prec);
+
+  int varID;
+  varAddRecord(recID, param, gridID, leveltype, lbounds, level1, level2, 0, 0,
+	       datatype, &varID, &levelID, TSTEP_INSTANT, 0, 0, -1,
+               NULL, NULL, NULL, NULL, NULL, NULL);
+
+  record->varID   = (short)varID;
+  record->levelID = (short)levelID;
+
+  streamptr->tsteps[tsID].nallrecs++;
+  streamptr->nrecs++;
+
+  if ( CDI_Debug )
+    Message("varID = %d gridID = %d levelID = %d",
+	    varID, gridID, levelID);
 }
 
+#if 0
 static
-int gribapiDefSteptype(int editionNumber, grib_handle *gh, int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int gcinit)
+void iegCmpRecord(stream_t *streamptr, int tsID, int recID, off_t position, int param,
+		  int level, int xsize, int ysize)
 {
-  long proDefTempNum = 0;
-  size_t len = 64;
-  const char *stepType;
+  int varID = 0;
+  int levelID = 0;
+  record_t *record;
 
-  static struct {
-    long productionTemplate;
-    const char sname[8];
-  } ts_tab[] = {
-    [TSTEP_INSTANT] = {  0, "instant" },
-    [TSTEP_AVG] = { 8, "avg" },
-    [TSTEP_ACCUM] = {  8, "accum" },
-    [TSTEP_MAX] = {  8, "max" },
-    [TSTEP_MIN] = {  8, "min" },
-    [TSTEP_DIFF] = {  8, "diff" },
-    [TSTEP_RMS] = {  8, "rms" },
-    [TSTEP_SD] = {  8, "sd" },
-    [TSTEP_COV] = { 8, "cov" },
-    [TSTEP_RATIO] = {  8, "ratio" }
-  };
-  if (tsteptype >= TSTEP_INSTANT && tsteptype <= TSTEP_RATIO)
-    {
-      stepType = ts_tab[tsteptype].sname;
-      proDefTempNum = ts_tab[tsteptype].productionTemplate;
-    }
-  else
-    {
-      stepType = "instant";
-      proDefTempNum = 0;
-    }
+  record  = &streamptr->tsteps[tsID].records[recID];
 
-  if ( typeOfGeneratingProcess == 4 )
-    {
-      if ( proDefTempNum == 8 ) proDefTempNum = 11;
-      else                      proDefTempNum = 1;
-    }
+  if ( param != (*record).param || level != (*record).ilevel )
+    Error("inconsistent timestep");
 
-  if ( productDefinitionTemplate != -1 ) proDefTempNum = productDefinitionTemplate;
+  (*record).position = position;
+  /*
+  varID   = (*record).varID;
+  levelID = (*record).levelID;
 
-  if ( !gcinit )
-    {
-      if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "productDefinitionTemplateNumber", proDefTempNum), 0);
-      len = strlen(stepType);
-      GRIB_CHECK(my_grib_set_string(gh, "stepType", stepType, &len), 0);
-    }
+  streamptr->vars[varID].level[levelID] = recID;
 
-  return ((int)proDefTempNum);
+  streamptr->tsteps[tsID].nallrecs++;
+  streamptr->nrecs++;
+  */
+  if ( CDI_Debug )
+    Message("varID = %d levelID = %d", varID, levelID);
 }
+#endif
 
-static
-void gribapiDefDateTimeAbs(int editionNumber, grib_handle *gh, int date, int time, int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int gcinit)
+static void iegDateTime(int *pdb, int *date, int *time)
 {
-  (void ) gribapiDefSteptype(editionNumber, gh, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
+  int ryear, rmonth, rday, rhour, rminute;
 
-  if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "significanceOfReferenceTime", 0), 0);
-  if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "stepRange", 0), 0);
+  ryear   = IEG_P_Year(pdb);
 
-  if ( date == 0 ) date = 10101;
-  gribapiSetDataDateTime(gh, date, time);
+  rmonth  = IEG_P_Month(pdb);
+  rday    = IEG_P_Day(pdb);
+
+  rhour   = IEG_P_Hour(pdb);
+  rminute = IEG_P_Minute(pdb);
+
+  if ( rminute == -1 ) rminute = 0;
+
+  *date = cdiEncodeDate(ryear, rmonth, rday);
+  *time = cdiEncodeTime(rhour, rminute, 0);
 }
 
 static
-int gribapiDefDateTimeRel(int editionNumber, grib_handle *gh, int rdate, int rtime, int vdate, int vtime,
-                          int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int timeunit, int calendar, int gcinit)
+void iegScanTimestep1(stream_t *streamptr)
 {
-  int status = -1;
-  int year, month, day, hour, minute, second;
-  int julday1, secofday1, julday2, secofday2, days, secs;
-  long startStep = 0, endStep;
+  int prec = 0;
+  int status;
+  int fileID;
+  int tabnum;
+  int param = 0;
+  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
+  DateTime datetime0 = { LONG_MIN, LONG_MIN };
+  int tsID;
+  int varID;
+  size_t recsize;
+  off_t recpos;
+  int nrecords, nrecs, recID;
+  int taxisID = -1;
+  taxis_t *taxis;
+  int vlistID;
+  IEGCOMPVAR compVar, compVar0;
+  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
 
-  cdiDecodeDate(rdate, &year, &month, &day);
-  cdiDecodeTime(rtime, &hour, &minute, &second);
-  encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday1, &secofday1);
+  streamptr->curTsID = 0;
 
-  if ( vdate == 0 && vtime == 0 ) { vdate = rdate; vtime = rtime; }
+  tsID  = tstepsNewEntry(streamptr);
+  taxis = &streamptr->tsteps[tsID].taxis;
 
-  cdiDecodeDate(vdate, &year, &month, &day);
-  cdiDecodeTime(vtime, &hour, &minute, &second);
-  encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday2, &secofday2);
+  if ( tsID != 0 )
+    Error("Internal problem! tstepsNewEntry returns %d", tsID);
 
-  (void) julday_sub(julday1, secofday1, julday2, secofday2, &days, &secs);
+  fileID = streamptr->fileID;
 
-  int factor = getTimeunitFactor(timeunit);
+  nrecs = 0;
+  while ( TRUE )
+    {
+      recpos = fileGetPos(fileID);
+      status = iegRead(fileID, iegp);
+      if ( status != 0 )
+	{
+	  streamptr->ntsteps = 1;
+	  break;
+	}
+      recsize = (size_t)(fileGetPos(fileID) - recpos);
 
-  if ( !(int) fmod(days*86400.0 + secs, factor) )
-    {
-      int proDefTempNum = gribapiDefSteptype(editionNumber, gh, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
+      prec   = iegp->dprec;
+      rcode  = IEG_P_Parameter(iegp->ipdb);
+      tabnum = IEG_P_CodeTable(iegp->ipdb);
+      param  = cdiEncodeParam(rcode, tabnum, 255);
 
-      gribapiDefStepUnits(gh, timeunit, proDefTempNum, gcinit);
+      if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
+	rlevel = IEG_P_Level1(iegp->ipdb);
+      else
+	rlevel = IEG_P_Level2(iegp->ipdb);
 
-      endStep = (int) ((days*86400.0 + secs)/factor);
+      if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
 
-      if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "significanceOfReferenceTime", 1), 0);
-      if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "stepRange", 0), 0);
+      iegDateTime(iegp->ipdb, &vdate, &vtime);
 
-      if ( rdate == 0 ) rdate = 10101;
-      gribapiSetDataDateTime(gh, rdate, rtime);
+      if ( nrecs == 0 )
+	{
+	  datetime0.date = vdate;
+	  datetime0.time = vtime;
+	}
+      else
+	{
+	  compVar.param = param;
+          compVar.level = rlevel;
+	  for ( recID = 0; recID < nrecs; recID++ )
+	    {
+	      compVar0.param = streamptr->tsteps[0].records[recID].param;
+	      compVar0.level = streamptr->tsteps[0].records[recID].ilevel;
 
-      // printf(">>>>> tsteptype %d  startStep %ld  endStep %ld\n", tsteptype, startStep, endStep);
+	      if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) == 0 ) break;
+	    }
+	  if ( recID < nrecs ) break;
+	  DateTime datetime = { .date = vdate, .time = vtime};
+	  if ( datetimeCmp(datetime, datetime0) )
+	    Warning("Inconsistent verification time for param %d level %d", param, rlevel);
+	}
 
-      // Product Definition Template Number: defined in GRIB_API file 4.0.table
-      // point in time products:
-      if ( (proDefTempNum >= 0 && proDefTempNum <=  7) || 
-           proDefTempNum == 55 || proDefTempNum == 40055 ) // Tile
-        startStep = endStep;
+      nrecs++;
 
-      if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "forecastTime", startStep), 0);
-      GRIB_CHECK(my_grib_set_long(gh, "endStep", endStep), 0);
+      if ( CDI_Debug )
+	Message("%4d%8d%4d%8d%8d%6d", nrecs, (int)recpos, param, rlevel, vdate, vtime);
 
-      status = 0;
+      iegAddRecord(streamptr, param, iegp->ipdb, iegp->igdb, iegp->vct, recsize, recpos, prec);
     }
 
-  return (status);
-}
+  streamptr->rtsteps = 1;
 
-static
-void gribapiDefTime(int editionNumber, int productDefinitionTemplate, int typeOfGeneratingProcess, grib_handle *gh,
-                    int vdate, int vtime, int tsteptype, int numavg, int taxisID, int gcinit)
-{
-  int taxistype = -1;
+  cdi_generate_vars(streamptr);
 
-  UNUSED(numavg);
+  taxisID = taxisCreate(TAXIS_ABSOLUTE);
+  taxis->type  = TAXIS_ABSOLUTE;
+  taxis->vdate = (int)datetime0.date;
+  taxis->vtime = (int)datetime0.time;
 
-  if ( taxisID != -1 ) taxistype = taxisInqType(taxisID);
+  vlistID = streamptr->vlistID;
+  vlistDefTaxis(vlistID, taxisID);
 
-  if ( typeOfGeneratingProcess == 196 )
-    {
-      vdate = 10101;
-      vtime = 0;
-      taxistype = TAXIS_ABSOLUTE;
-    }
-  /*
-  else if ( typeOfGeneratingProcess == 9 )
+  vlist_check_contents(vlistID);
+
+  nrecords = streamptr->tsteps[0].nallrecs;
+  if ( nrecords < streamptr->tsteps[0].recordSize )
     {
+      streamptr->tsteps[0].recordSize = nrecords;
+      streamptr->tsteps[0].records =
+	(record_t *) Realloc(streamptr->tsteps[0].records,
+                             (size_t)nrecords * sizeof (record_t));
     }
-  */
 
-  if ( taxistype == TAXIS_RELATIVE )
-    {
-      int status;
-      int calendar = taxisInqCalendar(taxisID);
-      int rdate    = taxisInqRdate(taxisID);
-      int rtime    = taxisInqRtime(taxisID);
-      int timeunit = taxisInqTunit(taxisID);
+  streamptr->tsteps[0].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
+  streamptr->tsteps[0].nrecs = nrecords;
+  for ( recID = 0; recID < nrecords; recID++ )
+    streamptr->tsteps[0].recIDs[recID] = recID;
 
-      status = gribapiDefDateTimeRel(editionNumber, gh, rdate, rtime, vdate, vtime,
-                                     productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, timeunit, calendar, gcinit);
+  if ( streamptr->ntsteps == -1 )
+    {
+      tsID = tstepsNewEntry(streamptr);
+      if ( tsID != streamptr->rtsteps )
+	Error("Internal error. tsID = %d", tsID);
 
-      if ( status != 0 ) taxistype = TAXIS_ABSOLUTE;
+      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID].position = recpos;
     }
 
-  if ( taxistype == TAXIS_ABSOLUTE )
+  if ( streamptr->ntsteps == 1 )
     {
-      gribapiDefDateTimeAbs(editionNumber, gh, vdate, vtime, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
+      if ( taxis->vdate == 0 && taxis->vtime == 0 )
+	{
+	  streamptr->ntsteps = 0;
+	  for ( varID = 0; varID < streamptr->nvars; varID++ )
+	    {
+	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	    }
+	}
     }
 }
 
 static
-void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype, int lieee, int datatype, int nmiss, int gcinit)
+int iegScanTimestep2(stream_t *streamptr)
 {
   int status;
-  static short lwarn = TRUE;
+  int fileID;
+  int tabnum;
+  int param = 0;
+  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
+  int tsID;
+  int varID;
+  size_t recsize;
+  off_t recpos = 0;
+  int nrecords, nrecs, recID, rindex;
+  int nextstep;
+  taxis_t *taxis;
+  int vlistID;
+  IEGCOMPVAR compVar, compVar0;
+  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
 
-  UNUSED(nmiss);
+  streamptr->curTsID = 1;
 
-  int gridtype = gridInqType(gridID);
+  vlistID = streamptr->vlistID;
+  fileID  = streamptr->fileID;
 
-  if ( editionNumber <= 1 )
-    if ( gridtype == GRID_GME || gridtype == GRID_UNSTRUCTURED )
-      gridtype = -1;
+  tsID = streamptr->rtsteps;
+  if ( tsID != 1 )
+    Error("Internal problem! unexpected timestep %d", tsID+1);
 
-  if ( gridtype == GRID_GENERIC )
+  taxis = &streamptr->tsteps[tsID].taxis;
+
+  fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+
+  cdi_create_records(streamptr, tsID);
+
+  nrecords = streamptr->tsteps[0].nallrecs;
+  streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords * sizeof(int));
+  streamptr->tsteps[1].nrecs = 0;
+  for ( recID = 0; recID < nrecords; recID++ )
+    streamptr->tsteps[1].recIDs[recID] = -1;
+
+  for ( recID = 0; recID < nrecords; recID++ )
     {
-      int xsize, ysize, gridsize;
+      varID = streamptr->tsteps[0].records[recID].varID;
+      streamptr->tsteps[tsID].records[recID].position =
+	streamptr->tsteps[0].records[recID].position;
+      streamptr->tsteps[tsID].records[recID].size     =
+	streamptr->tsteps[0].records[recID].size;
+    }
 
-      gridsize = gridInqSize(gridID);
-      xsize = gridInqXsize(gridID);
-      ysize = gridInqYsize(gridID);
+  for ( rindex = 0; rindex <= nrecords; rindex++ )
+    {
+      recpos = fileGetPos(fileID);
+      status = iegRead(fileID, iegp);
+      if ( status != 0 )
+	{
+	  streamptr->ntsteps = 2;
+	  break;
+	}
+      recsize = (size_t)(fileGetPos(fileID) - recpos);
 
-      if ( (ysize ==  32 || ysize ==  48 || ysize ==  64 ||
-	    ysize ==  96 || ysize == 160 || ysize == 192 ||
-	    ysize == 240 || ysize == 320 || ysize == 384 ||
-	    ysize == 480 || ysize == 768 ) &&
-	   (xsize == 2*ysize || xsize == 1) )
+      rcode  = IEG_P_Parameter(iegp->ipdb);
+      tabnum = IEG_P_CodeTable(iegp->ipdb);
+      param  = cdiEncodeParam(rcode, tabnum, 255);
+
+      if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
+	rlevel = IEG_P_Level1(iegp->ipdb);
+      else
+	rlevel = IEG_P_Level2(iegp->ipdb);
+
+      if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
+
+      iegDateTime(iegp->ipdb, &vdate, &vtime);
+
+      if ( rindex == 0 )
 	{
-	  gridtype = GRID_GAUSSIAN;
-	  gridChangeType(gridID, gridtype);
+	  taxis->type  = TAXIS_ABSOLUTE;
+	  taxis->vdate = vdate;
+	  taxis->vtime = vtime;
 	}
-      else if ( gridsize == 1 )
+
+      compVar.param = param;
+      compVar.level = rlevel;
+      nextstep = FALSE;
+      for ( recID = 0; recID < nrecords; recID++ )
 	{
-	  gridtype = GRID_LONLAT;
-	  gridChangeType(gridID, gridtype);
+	  compVar0.param = streamptr->tsteps[tsID].records[recID].param;
+	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+
+	  if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) == 0 )
+	    {
+	      if ( streamptr->tsteps[tsID].records[recID].used )
+		{
+		  nextstep = TRUE;
+		}
+	      else
+		{
+		  streamptr->tsteps[tsID].records[recID].used = TRUE;
+		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
+		}
+	      break;
+	    }
 	}
-      else if ( gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL) )
+      if ( recID == nrecords )
 	{
-	  gridtype = GRID_LONLAT;
-	  gridChangeType(gridID, gridtype);
+	  char paramstr[32];
+	  cdiParamToString(param, paramstr, sizeof(paramstr));
+	  Warning("param %s level %d not defined at timestep 1", paramstr, rlevel);
+	  return (CDI_EUFSTRUCT);
 	}
-    }
-  else if ( gridtype == GRID_CURVILINEAR )
-    {
-      if ( lwarn && gridInqSize(gridID) > 1 )
+
+      if ( nextstep ) break;
+
+      if ( CDI_Debug )
+	Message("%4d%8d%4d%8d%8d%6d", rindex+1, (int)recpos, param, rlevel, vdate, vtime);
+
+      streamptr->tsteps[tsID].records[recID].size = recsize;
+
+      compVar0.param = streamptr->tsteps[tsID].records[recID].param;
+      compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+
+      if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) != 0 )
 	{
-	  lwarn = FALSE;
-	  Warning("Curvilinear grids are unsupported in GRIB format! Created wrong GDS!");
+	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
+		  tsID, recID,
+		  streamptr->tsteps[tsID].records[recID].param, param,
+		  streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
+	  return (CDI_EUFSTRUCT);
 	}
-      gridtype = GRID_LONLAT;
+
+      streamptr->tsteps[1].records[recID].position = recpos;
     }
 
-  if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN )
+  nrecs = 0;
+  for ( recID = 0; recID < nrecords; recID++ )
     {
-      if ( editionNumber != 2 || lieee ) { comptype = 0; }
-
-      if ( comptype )
-        {
-          if ( comptype == COMPRESS_JPEG )
-            {
-              static const char mesg[] = "grid_jpeg";
-              size_t len = sizeof (mesg) - 1;
-              GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-            }
-          else if ( comptype == COMPRESS_SZIP )
-            {
-              static const char mesg[] = "grid_ccsds";
-              size_t len = sizeof (mesg) - 1;
-              GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-            }
-          else
-            {
-              static const char mesg[] = "grid_simple";
-              size_t len = sizeof (mesg) - 1;
-              GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-            }
-        }
+      if ( ! streamptr->tsteps[tsID].records[recID].used )
+	{
+	  varID = streamptr->tsteps[tsID].records[recID].varID;
+          vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	}
+      else
+	{
+	  nrecs++;
+	}
     }
+  streamptr->tsteps[tsID].nrecs = nrecs;
 
-  if ( gcinit ) return;
+  streamptr->rtsteps = 2;
 
-  switch (gridtype)
+  if ( streamptr->ntsteps == -1 )
     {
-    case GRID_LONLAT:
-    case GRID_GAUSSIAN:
-    case GRID_GAUSSIAN_REDUCED:
-    case GRID_TRAJECTORY:
-      {
-	int nlon = 0, nlat;
-	double xfirst = 0, xlast = 0, xinc = 0;
-	double yfirst = 0, ylast = 0, yinc = 0;
-	double latIncr;
-
-	if ( gridtype == GRID_GAUSSIAN )
-	  {
-            static const char mesg[] = "regular_gg";
-            size_t len = sizeof (mesg) -1;
-	    GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
-	  }
-	else if ( gridtype == GRID_GAUSSIAN_REDUCED )
-	  {
-            static const char mesg[] = "reduced_gg";
-            size_t len = sizeof (mesg) -1;
-	    GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
-	  }
-	else if ( gridtype == GRID_LONLAT && gridIsRotated(gridID) )
-	  {
-            static const char mesg[] = "rotated_ll";
-            size_t len = sizeof (mesg) -1;
-	    GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
-	  }
-	else
-	  {
-            static const char mesg[] = "regular_ll";
-            size_t len = sizeof (mesg) -1;
-	    GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
-	  }
-
-	nlon = gridInqXsize(gridID);
-	nlat = gridInqYsize(gridID);
+      tsID = tstepsNewEntry(streamptr);
+      if ( tsID != streamptr->rtsteps )
+	Error("Internal error. tsID = %d", tsID);
 
-	if ( gridtype == GRID_GAUSSIAN_REDUCED )
-	  {
-	    int *rowlon, i;
-	    long *pl = NULL;
+      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID].position = recpos;
+    }
 
-	    nlon = 0;
+  return (0);
+}
 
-	    rowlon = (int *) Malloc((size_t)nlat*sizeof(int));
-	    pl     = (long *) Malloc((size_t)nlat*sizeof(long));
-	    gridInqRowlon(gridID, rowlon);
-	    for ( i = 0; i < nlat; ++i ) pl[i] = rowlon[i];
 
-	    // GRIB_CHECK(my_grib_set_long_array(gh, "pl", pl, nlat), 0);
+int iegInqContents(stream_t *streamptr)
+{
+  int fileID;
+  int status = 0;
 
-	    Free(pl);
-	    Free(rowlon);
-	  }
-	else
-	  {
-	    if ( nlon == 0 )
-	      {
-		nlon = 1;
-	      }
-	    else
-	      {
-		xfirst = gridInqXval(gridID,      0);
-		xlast  = gridInqXval(gridID, nlon-1);
-		xinc   = gridInqXinc(gridID);
-	      }
-	  }
+  fileID = streamptr->fileID;
 
-	if ( nlat == 0 )
-	  {
-	    nlat = 1;
-	  }
-	else
-	  {
-	    yfirst = gridInqYval(gridID,      0);
-	    ylast  = gridInqYval(gridID, nlat-1);
-	    yinc   = gridInqYinc(gridID);
-	  }
+  streamptr->curTsID = 0;
 
-	GRIB_CHECK(my_grib_set_long(gh, "Ni", nlon), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "Nj", nlat), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "longitudeOfFirstGridPointInDegrees", xfirst), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "longitudeOfLastGridPointInDegrees",  xlast), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees",  yfirst), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "latitudeOfLastGridPointInDegrees",   ylast), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "iDirectionIncrementInDegrees", xinc), 0);
+  iegScanTimestep1(streamptr);
 
-        {
-          long jscan = 0;
-          if ( yfirst < ylast ) jscan = 1;
-          GRIB_CHECK(my_grib_set_long(gh, "jScansPositively", jscan), 0);
-        }
-	/*
-	if ( fabs(xinc*1000 - ISEC2_LonIncr) > FLT_EPSILON )
-	  ISEC2_LonIncr = 0;
-	*/
-	if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
-          {
-            int np = gridInqNP(gridID);
-            if ( np == 0 ) np = nlat/2;
-            GRIB_CHECK(my_grib_set_long(gh, "numberOfParallelsBetweenAPoleAndTheEquator", np), 0);
-          }
-	else
-	  {
-	    latIncr = yinc;
-	    if ( latIncr < 0 ) latIncr = -latIncr;
-	    GRIB_CHECK(my_grib_set_double(gh, "jDirectionIncrementInDegrees", latIncr), 0);
-	    /*
-	    if ( fabs(yinc*1000 - ISEC2_LatIncr) > FLT_EPSILON )
-	      ISEC2_LatIncr = 0;
-	    */
-	  }
-	/*
-	if ( ISEC2_NumLon > 1 && ISEC2_NumLat == 1 )
-	  if ( ISEC2_LonIncr != 0 && ISEC2_LatIncr == 0 ) ISEC2_LatIncr = ISEC2_LonIncr;
+  if ( streamptr->ntsteps == -1 ) status = iegScanTimestep2(streamptr);
 
-	if ( ISEC2_NumLon == 1 && ISEC2_NumLat > 1 )
-	  if ( ISEC2_LonIncr == 0 && ISEC2_LatIncr != 0 ) ISEC2_LonIncr = ISEC2_LatIncr;
+  fileSetPos(fileID, 0, SEEK_SET);
 
-	if ( ISEC2_LatIncr == 0 || ISEC2_LonIncr == 0 )
-	  ISEC2_ResFlag = 0;
-	else
-	  ISEC2_ResFlag = 128;
-	*/
-	if ( gridIsRotated(gridID) )
-	  {
-	    double xpole, ypole, angle;
-	    xpole = gridInqXpole(gridID);
-	    ypole = gridInqYpole(gridID);
-	    angle = gridInqAngle(gridID);
-	    /* change from north to south pole */
-	    if ( fabs(ypole) > 0 ) ypole = -ypole;
-	    xpole =  xpole + 180;
-            if ( fabs(angle) > 0 ) angle = -angle;
-	    GRIB_CHECK(my_grib_set_double(gh, "latitudeOfSouthernPoleInDegrees",  ypole), 0);
-	    GRIB_CHECK(my_grib_set_double(gh, "longitudeOfSouthernPoleInDegrees", xpole), 0);
-	    GRIB_CHECK(my_grib_set_double(gh, "angleOfRotation", angle), 0);
-	  }
+  return (status);
+}
 
-	/* East -> West */
-	//if ( ISEC2_LastLon < ISEC2_FirstLon ) ISEC2_ScanFlag += 128;
+static
+long iegScanTimestep(stream_t *streamptr)
+{
+  int status;
+  int fileID;
+  int tsID;
+  int tabnum;
+  int param = 0;
+  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
+  size_t recsize = 0;
+  off_t recpos = 0;
+  int recID;
+  taxis_t *taxis;
+  int rindex, nrecs = 0;
+  IEGCOMPVAR compVar, compVar0;
+  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
 
-	/* South -> North */
-	//if ( ISEC2_LastLat > ISEC2_FirstLat ) ISEC2_ScanFlag += 64;
+  if ( CDI_Debug )
+    {
+      Message("streamID = %d", streamptr->self);
+      Message("cts = %d", streamptr->curTsID);
+      Message("rts = %d", streamptr->rtsteps);
+      Message("nts = %d", streamptr->ntsteps);
+    }
 
-        if ( editionNumber != 2 ) { lieee = 0; comptype = 0; }
+  if ( streamptr->rtsteps == 0 )
+    Error("Internal problem! Missing contents.");
 
-        if ( lieee )
-          {
-            static const char mesg[] = "grid_ieee";
-            size_t len = sizeof (mesg) -1;
-            GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+  tsID  = streamptr->rtsteps;
+  taxis = &streamptr->tsteps[tsID].taxis;
 
-	    if ( datatype == DATATYPE_FLT64 )
-	      GRIB_CHECK(my_grib_set_long(gh, "precision", 2), 0);
-	    else
-	      GRIB_CHECK(my_grib_set_long(gh, "precision", 1), 0);
-          }
-        else
-	  {
-            if ( comptype == COMPRESS_JPEG )
-              {
-                static const char mesg[] = "grid_jpeg";
-                size_t len = sizeof (mesg) -1;
-                GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-              }
-            else if ( comptype == COMPRESS_SZIP )
-              {
-                static const char mesg[] = "grid_ccsds";
-                size_t len = sizeof (mesg) -1;
-                GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-              }
-            else
-              {
-                static const char mesg[] = "grid_simple";
-                size_t len = sizeof (mesg) -1;
-                GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-              }
-	  }
+  if ( streamptr->tsteps[tsID].recordSize == 0 )
+    {
+      cdi_create_records(streamptr, tsID);
 
-	break;
-      }
-    case GRID_LCC:
-      {
-	double originLon, originLat, lonParY, lat1, lat2, xincm, yincm;
-	int xsize, ysize;
-	int projflag, scanflag;
+      nrecs = streamptr->tsteps[1].nrecs;
 
-	xsize = gridInqXsize(gridID);
-	ysize = gridInqYsize(gridID);
+      streamptr->tsteps[tsID].nrecs = nrecs;
+      streamptr->tsteps[tsID].recIDs
+        = (int *) Malloc((size_t)nrecs * sizeof (int));
+      for ( recID = 0; recID < nrecs; recID++ )
+	streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
 
-	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
-		   &projflag, &scanflag);
+      fileID = streamptr->fileID;
 
-        static const char mesg[] = "lambert";
-        size_t len = sizeof (mesg) -1;
-        GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
+      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
-	GRIB_CHECK(my_grib_set_long(gh, "Nx", xsize), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "Ny", ysize), 0);
+      for ( rindex = 0; rindex <= nrecs; rindex++ )
+	{
+	  recpos = fileGetPos(fileID);
+	  status = iegRead(fileID, iegp);
+	  if ( status != 0 )
+	    {
+	      streamptr->ntsteps = streamptr->rtsteps + 1;
+	      break;
+	    }
+	  recsize = (size_t)(fileGetPos(fileID) - recpos);
 
-        /* FIXME: lround should probably be round here */
-	GRIB_CHECK(my_grib_set_double(gh, "DxInMetres", (double)lround(xincm)), 0);
-        /* FIXME: lround should probably be round here */
-	GRIB_CHECK(my_grib_set_double(gh, "DyInMetres", (double)lround(yincm)), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "longitudeOfFirstGridPointInDegrees", originLon), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees", originLat), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "LoVInDegrees", lonParY), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "Latin1InDegrees", lat1), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "Latin2InDegrees", lat2), 0);
+	  rcode  = IEG_P_Parameter(iegp->ipdb);
+	  tabnum = IEG_P_CodeTable(iegp->ipdb);
+	  param  = cdiEncodeParam(rcode, tabnum, 255);
 
-        if ( editionNumber <= 1 )
-          {
-            GRIB_CHECK(my_grib_set_long(gh, "projectionCenterFlag", projflag), 0);
-            GRIB_CHECK(my_grib_set_long(gh, "scanningMode", scanflag), 0);
-          }
-        /*
-	ISEC2_Lambert_LatSP  = 0;
-	ISEC2_Lambert_LatSP  = 0;
-        */
-	break;
-      }
-    case GRID_SPECTRAL:
-      {
-	int trunc = gridInqTrunc(gridID);
+	  if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
+	    rlevel = IEG_P_Level1(iegp->ipdb);
+	  else
+	    rlevel = IEG_P_Level2(iegp->ipdb);
 
-        static const char mesg[] = "sh";
-        size_t len = sizeof (mesg) -1;
-	GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
+	  if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
 
-	GRIB_CHECK(my_grib_set_long(gh, "J", trunc), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "K", trunc), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "M", trunc), 0);
+	  iegDateTime(iegp->ipdb, &vdate, &vtime);
 
-	// GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridInqSize(gridID)), 0);
-        /*
-        if ( lieee )
-          {
-            printf("spectral_ieee\n");
-            if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridInqSize(gridID)), 0);
-            static const char mesg[] = "spectral_ieee";
-            size_t len = sizeof (mesg) -1;
-            GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-          }
-        else */ if ( gridInqComplexPacking(gridID) )
-	  {
-	    if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridInqSize(gridID)), 0);
-            static const char mesg[] = "spectral_complex";
-            size_t len = sizeof (mesg) -1;
-	    GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
+	  if ( rindex == nrecs ) continue;
+	  recID = streamptr->tsteps[tsID].recIDs[rindex];
 
-	    GRIB_CHECK(my_grib_set_long(gh, "JS", 20), 0);
-	    GRIB_CHECK(my_grib_set_long(gh, "KS", 20), 0);
-	    GRIB_CHECK(my_grib_set_long(gh, "MS", 20), 0);
-	  }
-	else
-	  {
-            static const char mesg[] = "spectral_simple";
-            size_t len = sizeof (mesg) -1;
-	    GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-	  }
+	  if ( rindex == 0 )
+	    {
+	      taxis->type  = TAXIS_ABSOLUTE;
+	      taxis->vdate = vdate;
+	      taxis->vtime = vtime;
+	    }
 
-	break;
-      }
-    case GRID_GME:
-      {
-	GRIB_CHECK(my_grib_set_long(gh, "gridDefinitionTemplateNumber", GRIB2_GTYPE_GME), 0);
+	  compVar.param = param;
+          compVar.level = rlevel;
+	  compVar0.param = streamptr->tsteps[tsID].records[recID].param;
+	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
 
-	GRIB_CHECK(my_grib_set_long(gh, "nd", gridInqGMEnd(gridID)), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "Ni", gridInqGMEni(gridID)), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "n2", gridInqGMEni2(gridID)), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "n3", gridInqGMEni3(gridID)), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "latitudeOfThePolePoint", 90000000), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "longitudeOfThePolePoint", 0), 0);
+	  if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) != 0 )
+	    {
+	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
+		      tsID, recID,
+		      streamptr->tsteps[tsID].records[recID].param, param,
+		      streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
+	      Error("Invalid, unsupported or inconsistent record structure");
+	    }
 
-	GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridInqSize(gridID)), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "totalNumberOfGridPoints", gridInqSize(gridID)), 0);
+	  streamptr->tsteps[tsID].records[recID].position = recpos;
+	  streamptr->tsteps[tsID].records[recID].size = recsize;
 
-        if ( comptype == COMPRESS_SZIP )
-          {
-            static const char mesg[] = "grid_ccsds";
-            size_t len = sizeof (mesg) -1;
-            GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-          }
+	  if ( CDI_Debug )
+	    Message("%4d%8d%4d%8d%8d%6d", rindex, (int)recpos, param, rlevel, vdate, vtime);
+	}
 
-	break;
-      }
-    case GRID_UNSTRUCTURED:
-      {
-	static int warning = 1;
+      streamptr->rtsteps++;
 
-	status = my_grib_set_long(gh, "gridDefinitionTemplateNumber", GRIB2_GTYPE_UNSTRUCTURED);
-	if ( status != 0 && warning )
-	  {
-	    warning = 0;
-	    Warning("Can't write reference grid!");
-	    Warning("gridDefinitionTemplateNumber %d not found (grib2/template.3.%d.def)!",
-		    GRIB2_GTYPE_UNSTRUCTURED, GRIB2_GTYPE_UNSTRUCTURED);
-	  }
-	else
-	  {
-            unsigned char uuid[CDI_UUID_SIZE];
-            int position = gridInqPosition(gridID);
-            int number = gridInqNumber(gridID);
-            if ( position < 0 ) position = 0;
-            if ( number < 0 ) number = 0;
-	    GRIB_CHECK(my_grib_set_long(gh, "numberOfGridUsed", number), 0);
-	    GRIB_CHECK(my_grib_set_long(gh, "numberOfGridInReference", position), 0);
-            size_t len = CDI_UUID_SIZE;
-            gridInqUUID(gridID, uuid);
-	    if (grib_set_bytes(gh, "uuidOfHGrid", uuid, &len) != 0)
-	      Warning("Can't write UUID!");
-	  }
+      if ( streamptr->ntsteps != streamptr->rtsteps )
+	{
+	  tsID = tstepsNewEntry(streamptr);
+	  if ( tsID != streamptr->rtsteps )
+	    Error("Internal error. tsID = %d", tsID);
 
-        if ( comptype == COMPRESS_SZIP )
-          {
-            static const char mesg[] = "grid_ccsds";
-            size_t len = sizeof (mesg) -1;
-            GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-          }
+	  streamptr->tsteps[tsID-1].next   = 1;
+	  streamptr->tsteps[tsID].position = recpos;
+	}
 
-	break;
-      }
-    default:
-      {
-	Error("Unsupported grid type: %s", gridNamePtr(gridtype));
-	break;
-      }
+      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+      streamptr->tsteps[tsID].position = recpos;
+    }
+
+  if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
+    {
+      Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
+      streamptr->ntsteps = tsID;
     }
+
+  return (streamptr->ntsteps);
 }
 
-static
-void getLevelFactor(double level, long *factor, long *out_scaled_value)
+
+int iegInqTimestep(stream_t *streamptr, int tsID)
 {
-  double scaled_value  = level;
-  /* FIXME: lround might be better here */
-  long   iscaled_value = (long) round(scaled_value);
-  long   i;
+  int nrecs;
 
-  const double eps = 1.e-8;
-  for ( i=0; (fabs(scaled_value - (double) iscaled_value) >= eps) && i < 7; i++ )
+  if ( tsID == 0 && streamptr->rtsteps == 0 )
+    Error("Call to cdiInqContents missing!");
+
+  if ( CDI_Debug )
+    Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
+
+  long ntsteps = UNDEFID;
+  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == UNDEFID )
+    ntsteps = iegScanTimestep(streamptr);
+
+  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
     {
-      scaled_value *= 10.;
-      /* FIXME: lround might be better here */
-      iscaled_value = (long)round(scaled_value);
+      nrecs = 0;
+    }
+  else
+    {
+      streamptr->curTsID = tsID;
+      nrecs = streamptr->tsteps[tsID].nrecs;
     }
 
-  (*factor)           = i;
-  (*out_scaled_value) = iscaled_value;
+  return (nrecs);
 }
 
-static
-void gribapiDefLevelType(grib_handle *gh, int gcinit, const char *keyname, long leveltype)
-{
-  if ( !gcinit ) GRIB_CHECK(my_grib_set_long(gh, keyname, leveltype), 0);
-}
 
-static
-void grib2DefLevel(grib_handle *gh, int gcinit, long leveltype1, long leveltype2, int lbounds, double level, double dlevel1, double dlevel2)
+void iegReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
 {
-  long scaled_level;
-  long factor;
+  int vlistID, fileID;
+  int levID, nlevs, gridID, gridsize;
+  off_t recpos, currentfilepos;
+  int tsid;
+  int recID;
+  int i;
+  double missval;
+  void *iegp = streamptr->record->exsep;
 
-  gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", leveltype1);
-  if ( lbounds ) gribapiDefLevelType(gh, gcinit, "typeOfSecondFixedSurface", leveltype2);
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  /* NOTE: tiles are not supported here! */
+  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
+  missval  = vlistInqVarMissval(vlistID, varID);
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  gridsize = gridInqSize(gridID);
+  tsid     = streamptr->curTsID;
 
-  if ( !lbounds ) dlevel1 = level;
+  if ( CDI_Debug )
+    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
 
-  getLevelFactor(dlevel1, &factor, &scaled_level);
-  GRIB_CHECK(my_grib_set_long(gh, "scaleFactorOfFirstFixedSurface", factor), 0);
-  GRIB_CHECK(my_grib_set_long(gh, "scaledValueOfFirstFixedSurface", scaled_level), 0);
+  currentfilepos = fileGetPos(fileID);
 
-  if ( lbounds )
+  for (levID = 0; levID < nlevs; levID++)
     {
-      getLevelFactor(dlevel2, &factor, &scaled_level);
-      GRIB_CHECK(my_grib_set_long(gh, "scaleFactorOfSecondFixedSurface", factor), 0);
-      GRIB_CHECK(my_grib_set_long(gh, "scaledValueOfSecondFixedSurface", scaled_level), 0);
+      /* NOTE: tiles are not supported here! */
+      recID = streamptr->vars[varID].recordTable[0].recordID[levID];
+      recpos = streamptr->tsteps[tsid].records[recID].position;
+      fileSetPos(fileID, recpos, SEEK_SET);
+      iegRead(fileID, iegp);
+      iegInqDataDP(iegp, &data[levID*gridsize]);
     }
+  fileSetPos(fileID, currentfilepos, SEEK_SET);
+
+  *nmiss = 0;
+  for ( i = 0; i < nlevs*gridsize; i++ )
+    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
+      {
+	data[i] = missval;
+	(*nmiss)++;
+      }
 }
 
-static
-void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID, int levelID, int gcinit, int proddef_template_num)
+
+void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
 {
-  int lbounds = 0;
-  static int warning = 1;
-  double dlevel1 = 0, dlevel2 = 0;
+  int vlistID, fileID;
+  int nlevs, gridID, gridsize;
+  off_t recpos, currentfilepos;
+  int tsid;
+  int recID;
+  int i;
+  double missval;
+  void *iegp = streamptr->record->exsep;
 
-  int zaxistype = zaxisInqType(zaxisID);
-  int ltype = zaxisInqLtype(zaxisID);
-  int ltype2 = zaxisInqLtype2(zaxisID);
-  double level = zaxisInqLevel(zaxisID, levelID);
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  /* NOTE: tiles are not supported here! */
+  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
+  missval  = vlistInqVarMissval(vlistID, varID);
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  gridsize = gridInqSize(gridID);
+  tsid     = streamptr->curTsID;
 
-  if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-    {
-      lbounds = 1;
-      dlevel1 = zaxisInqLbound(zaxisID, levelID);
-      dlevel2 = zaxisInqUbound(zaxisID, levelID);
-    }
-  else
-    {
-      dlevel1 = level;
-      dlevel2 = 0;
-    }
+  if ( CDI_Debug )
+    Message("nlevs = %d gridID = %d gridsize = %d",
+	     nlevs, gridID, gridsize);
 
-  if ( zaxistype == ZAXIS_GENERIC && ltype == 0 )
-    {
-      Message("Changed zaxis type from %s to %s", zaxisNamePtr(zaxistype), zaxisNamePtr(ZAXIS_PRESSURE));
-      zaxistype = ZAXIS_PRESSURE;
-      zaxisChangeType(zaxisID, zaxistype);
-      zaxisDefUnits(zaxisID, "Pa");
-    }
+  currentfilepos = fileGetPos(fileID);
 
-  int grib2ltype = zaxisTypeToGrib2ltype(zaxistype);
+  /* NOTE: tiles are not supported here! */
+  recID = streamptr->vars[varID].recordTable[0].recordID[levID];
+  recpos = streamptr->tsteps[tsid].records[recID].position;
+  fileSetPos(fileID, recpos, SEEK_SET);
+  iegRead(fileID, iegp);
+  iegInqDataDP(iegp, data);
 
-  switch (zaxistype)
-    {
-    case ZAXIS_SURFACE:
-    case ZAXIS_MEANSEA:
-    case ZAXIS_HEIGHT:
-    case ZAXIS_ALTITUDE:
-    case ZAXIS_SIGMA:
-    case ZAXIS_DEPTH_BELOW_SEA:
-    case ZAXIS_ISENTROPIC:
+  fileSetPos(fileID, currentfilepos, SEEK_SET);
+
+  *nmiss = 0;
+  for ( i = 0; i < gridsize; i++ )
+    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
-	if ( editionNumber <= 1 )
-          {
-            gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", zaxisTypeToGrib1ltype(zaxistype));
-            GRIB_CHECK(my_grib_set_long(gh, "level", (long)level), 0);
-          }
-        else
-          {
-            /* PRODUCT DEFINITION TEMPLATE NUMBER 32:
+	data[i] = missval;
+	(*nmiss)++;
+      }
+}
 
-               "Analysis or forecast at a horizontal level or in a horizontal layer at a point
-                in time for simulate (synthetic) satellite data"
 
-               The key/value pairs that are set in "grib2DefLevel" do not exist for this template.
-            */
-            if ( proddef_template_num != 32 )
-              grib2DefLevel(gh, gcinit, grib2ltype, grib2ltype, lbounds, level, dlevel1, dlevel2);
-          }
+void iegWriteVarDP(stream_t *streamptr, int varID, const double *data)
+{
+  int fileID;
+  int levID, nlevs, gridID, gridsize;
+  int zaxisID;
+  int datatype;
+  int tsID;
+  int vlistID;
+  int i;
+  int date, time;
+  int param, pdis, pcat, pnum;
+  double refval;
+  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
 
-	break;
-      }
-    case ZAXIS_CLOUD_BASE:
-    case ZAXIS_CLOUD_TOP:
-    case ZAXIS_ISOTHERM_ZERO:
-    case ZAXIS_TOA:
-    case ZAXIS_SEA_BOTTOM:
-    case ZAXIS_LAKE_BOTTOM:
-    case ZAXIS_SEDIMENT_BOTTOM:
-    case ZAXIS_SEDIMENT_BOTTOM_TA:
-    case ZAXIS_SEDIMENT_BOTTOM_TW:
-    case ZAXIS_MIX_LAYER:
-    case ZAXIS_ATMOSPHERE:
-      {
-        if ( editionNumber <= 1 )
-          {
-            gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", zaxisTypeToGrib1ltype(zaxistype));
-            if ( lbounds )
-              {
-                GRIB_CHECK(my_grib_set_long(gh, "topLevel", (long) dlevel1), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", (long) dlevel2), 0);
-              }
-            else
-              {
-                GRIB_CHECK(my_grib_set_long(gh, "level", (long) level), 0);
-              }
-          }
-        else
-          {
-            grib2DefLevel(gh, gcinit, grib2ltype, grib2ltype, lbounds, level, dlevel1, dlevel2);
-          }
+  if ( CDI_Debug )
+    Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-        break;
-      }
-    case ZAXIS_HYBRID:
-    case ZAXIS_HYBRID_HALF:
-      {
-        if ( editionNumber <= 1 )
-          {
-            if ( lbounds )
-              {
-                gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", GRIB1_LTYPE_HYBRID_LAYER);
-                GRIB_CHECK(my_grib_set_long(gh, "topLevel", (long) dlevel1), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", (long) dlevel2), 0);
-              }
-            else
-              {
-                gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", GRIB1_LTYPE_HYBRID);
-                GRIB_CHECK(my_grib_set_long(gh, "level", (long) level), 0);
-              }
-          }
-        else
-          {
-            grib2DefLevel(gh, gcinit, GRIB2_LTYPE_HYBRID, GRIB2_LTYPE_HYBRID, lbounds, level, dlevel1, dlevel2);
-          }
+  iegInitMem(iegp);
+  for ( i = 0; i < 37; i++ ) iegp->ipdb[i] = -1;
 
-        if ( !gcinit )
-          {
-            int vctsize = zaxisInqVctSize(zaxisID);
-            if ( vctsize == 0 && warning )
-              {
-                char paramstr[32];
-                cdiParamToString(param, paramstr, sizeof(paramstr));
-                Warning("VCT missing ( param = %s, zaxisID = %d )", paramstr, zaxisID);
-                warning = 0;
-              }
-            GRIB_CHECK(my_grib_set_long(gh, "PVPresent", 1), 0);
-            GRIB_CHECK(grib_set_double_array(gh, "pv", zaxisInqVctPtr(zaxisID), (size_t)vctsize), 0);
-          }
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  tsID     = streamptr->curTsID;
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  gridsize = gridInqSize(gridID);
+  zaxisID  = vlistInqVarZaxis(vlistID, varID);
+  nlevs    = zaxisInqSize(zaxisID);
+
+  if ( CDI_Debug )
+    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+
+  param    = vlistInqVarParam(vlistID, varID);
+  cdiDecodeParam(param, &pnum, &pcat, &pdis);
+  IEG_P_Parameter(iegp->ipdb) = pnum;
+  if ( pdis == 255 ) IEG_P_CodeTable(iegp->ipdb) = pcat;
+  date     = streamptr->tsteps[tsID].taxis.vdate;
+  time     = streamptr->tsteps[tsID].taxis.vtime;
+
+  iegDefTime(iegp->ipdb, date, time, vlistInqTaxis(vlistID));
+  iegDefGrid(iegp->igdb, gridID);
+
+  datatype = vlistInqVarDatatype(vlistID, varID);
+
+  iegp->dprec = iegDefDatatype(datatype);
+
+  for ( levID = 0;  levID < nlevs; levID++ )
+    {
+      iegDefLevel(iegp->ipdb, iegp->igdb, iegp->vct, zaxisID, levID);
+
+      refval = data[0];
+      for ( i = 1; i < gridsize; i++ )
+	if ( data[levID*gridsize+i] < refval ) refval = data[levID*gridsize+i];
+
+      iegp->refval = refval;
+
+      iegDefDataDP(iegp, &data[levID*gridsize]);
+      iegWrite(fileID, iegp);
+    }
+}
+
+
+void iegWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
+{
+  int fileID;
+  int gridID;
+  int zaxisID;
+  /* double level; */
+  int datatype;
+  /* int tsID; */
+  int vlistID;
+  /* int param, date, time, datasize; */
+  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  /* tsID     = streamptr->curTsID; */
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  zaxisID  = vlistInqVarZaxis(vlistID, varID);
+  (void)levID;
+  /* level    = zaxisInqLevel(zaxisID, levID); */
+
+  if ( CDI_Debug )
+    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
+
+  /* param = vlistInqVarParam(vlistID, varID); */
+  /* date = streamptr->tsteps[tsID].taxis.vdate; */
+  /* time = streamptr->tsteps[tsID].taxis.vtime; */
+  /* datasize = gridInqSize(gridID); */
 
-	break;
-      }
-    case ZAXIS_PRESSURE:
-      {
-	double dum;
-	char units[128];
+  datatype = vlistInqVarDatatype(vlistID, varID);
 
-	if ( level < 0 ) Warning("Pressure level of %f Pa is below zero!", level);
+  iegp->dprec = iegDefDatatype(datatype);
 
-	zaxisInqUnits(zaxisID, units);
-	if ( memcmp(units, "Pa", 2) != 0 )
-          {
-            level   *= 100;
-            dlevel1 *= 100;
-            dlevel2 *= 100;
-          }
+  iegDefDataDP(iegp, data);
+  iegWrite(fileID, iegp);
+}
 
-        if ( editionNumber <= 1 )
-          {
-            long leveltype = GRIB1_LTYPE_ISOBARIC;
+#endif /* HAVE_LIBIEG */
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-            if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
-              leveltype = GRIB1_LTYPE_99;
-            else
-              level /= 100;
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
 
-            gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", leveltype);
-            GRIB_CHECK(my_grib_set_double(gh, "level", level), 0);
-	  }
-	else
-	  {
-            if ( ltype2 == -1 ) ltype2 = GRIB2_LTYPE_ISOBARIC;
-            grib2DefLevel(gh, gcinit, GRIB2_LTYPE_ISOBARIC, ltype2, lbounds, level, dlevel1, dlevel2);
-	  }
 
-	break;
-      }
-    case ZAXIS_SNOW:
-      {
-        if ( editionNumber <= 1 )
-          ; // not available
-	else
-          {
-            grib2DefLevel(gh, gcinit, GRIB2_LTYPE_SNOW, GRIB2_LTYPE_SNOW, lbounds, level, dlevel1, dlevel2);
-          }
 
-	break;
-      }
-    case ZAXIS_DEPTH_BELOW_LAND:
-      {
-	char units[128];
 
-	zaxisInqUnits(zaxisID, units);
+void recordInitEntry(record_t *record)
+{
+  record->position = CDI_UNDEFID;
+  record->size     = 0;
+  record->param    = 0;
+  record->ilevel   = CDI_UNDEFID;
+  record->used     = FALSE;
+  record->varID    = CDI_UNDEFID;
+  record->levelID  = CDI_UNDEFID;
+  memset(record->varname, 0, sizeof(record->varname));
+  memset(&record->tiles, 0, sizeof(record->tiles));
+}
 
-	if ( editionNumber <= 1 )
-	  {
-            double scalefactor;
-	    if      ( memcmp(units, "mm", 2) == 0 ) scalefactor =   0.1;
-	    else if ( memcmp(units, "cm", 2) == 0 ) scalefactor =   1; // cm
-	    else if ( memcmp(units, "dm", 2) == 0 ) scalefactor =  10;
-	    else                                    scalefactor = 100;
 
-	    gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", GRIB1_LTYPE_LANDDEPTH);
-	    GRIB_CHECK(my_grib_set_double(gh, "level", level*scalefactor), 0);
-	  }
-	else
-	  {
-            double scalefactor;
-	    if      ( memcmp(units, "mm", 2) == 0 ) scalefactor = 0.001;
-	    else if ( memcmp(units, "cm", 2) == 0 ) scalefactor = 0.01;
-	    else if ( memcmp(units, "dm", 2) == 0 ) scalefactor = 0.1;
-	    else                                    scalefactor = 1; // meter
+int recordNewEntry(stream_t *streamptr, int tsID)
+{
+  size_t recordID = 0;
+  size_t recordSize = (size_t)streamptr->tsteps[tsID].recordSize;
+  record_t *records = streamptr->tsteps[tsID].records;
+  /*
+    Look for a free slot in record.
+    (Create the table the first time through).
+  */
+  if ( ! recordSize )
+    {
+      recordSize = 1;   /*  <<<<----  */
+      records = (record_t *) Malloc(recordSize * sizeof (record_t));
 
-            level   *= scalefactor;
-            dlevel1 *= scalefactor;
-            dlevel2 *= scalefactor;
+      for ( size_t i = 0; i < recordSize; i++ )
+	records[i].used = CDI_UNDEFID;
+    }
+  else
+    {
+      while ( recordID < recordSize
+              && records[recordID].used != CDI_UNDEFID )
+        ++recordID;
+    }
+  /*
+    If the table overflows, double its size.
+  */
+  if ( recordID == recordSize )
+    {
+      if (recordSize <= INT_MAX / 2)
+        recordSize *= 2;
+      else if (recordSize < INT_MAX)
+        recordSize = INT_MAX;
+      else
+        Error("Cannot handle this many records!\n");
+      records = (record_t *) Realloc(records,
+                                     recordSize * sizeof (record_t));
 
-            grib2DefLevel(gh, gcinit, GRIB2_LTYPE_LANDDEPTH, GRIB2_LTYPE_LANDDEPTH, lbounds, level, dlevel1, dlevel2);
-	  }
+      for ( size_t i = recordID; i < recordSize; i++ )
+	records[i].used = CDI_UNDEFID;
+    }
 
-	break;
-      }
-    case ZAXIS_REFERENCE:
-      {
-        unsigned char uuid[CDI_UUID_SIZE];
+  recordInitEntry(&records[recordID]);
 
-        if ( !gcinit )
-          {
-            GRIB_CHECK(my_grib_set_long(gh, "genVertHeightCoords", 1), 0);
-          }
+  records[recordID].used = 1;
 
-        if ( lbounds )
-          {
-            if ( editionNumber <= 1 )
-              ; // not available
-            else
-              {
-                int number = zaxisInqNumber(zaxisID);
-                gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", GRIB2_LTYPE_REFERENCE);
-                gribapiDefLevelType(gh, gcinit, "typeOfSecondFixedSurface", GRIB2_LTYPE_REFERENCE);
-                GRIB_CHECK(my_grib_set_long(gh, "NV", 6), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "nlev", zaxisInqNlevRef(zaxisID)), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "numberOfVGridUsed", number), 0);
-                size_t len = CDI_UUID_SIZE;
-                zaxisInqUUID(zaxisID, uuid);
-                if (grib_set_bytes(gh, "uuidOfVGrid", uuid, &len) != 0)
-                  {
-                    Warning("Can't write UUID!");
-                  }
-                GRIB_CHECK(my_grib_set_long(gh, "topLevel", (long) dlevel1), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", (long) dlevel2), 0);
-              }
-          }
-        else
-          {
-            if ( editionNumber <= 1 )
-              ; // not available
-            else
-              {
-                int number = zaxisInqNumber(zaxisID);
-                gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", GRIB2_LTYPE_REFERENCE);
-                GRIB_CHECK(my_grib_set_long(gh, "NV", 6), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "nlev", zaxisInqNlevRef(zaxisID)), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "numberOfVGridUsed", number), 0);
-                size_t len = CDI_UUID_SIZE;
-                zaxisInqUUID(zaxisID, uuid);
-                if (grib_set_bytes(gh, "uuidOfVGrid", uuid, &len) != 0)
-                  {
-                    Warning("Can't write UUID!");
-                  }
-                GRIB_CHECK(my_grib_set_double(gh, "level", level), 0);
-              }
-          }
+  streamptr->tsteps[tsID].recordSize = (int)recordSize;
+  streamptr->tsteps[tsID].records    = records;
 
-        break;
-      }
-    case ZAXIS_GENERIC:
-      {
-	if ( editionNumber <= 1 )
-          gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", ltype);
-        else
-          gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", ltype);
+  return (int)recordID;
+}
 
-	GRIB_CHECK(my_grib_set_double(gh, "level", level), 0);
+static
+void cdiInitRecord(stream_t *streamptr)
+{
+  streamptr->record = (Record *) Malloc(sizeof(Record));
 
-	break;
-      }
-    default:
-      {
-	Error("Unsupported zaxis type: %s", zaxisNamePtr(zaxistype));
-	break;
-      }
-    }
+  streamptr->record->param      = 0;
+  streamptr->record->level      = 0;
+  streamptr->record->date       = 0;
+  streamptr->record->time       = 0;
+  streamptr->record->gridID     = 0;
+  streamptr->record->buffer     = NULL;
+  streamptr->record->buffersize = 0;
+  streamptr->record->position   = 0;
+  streamptr->record->varID      = 0;
+  streamptr->record->levelID    = CDI_UNDEFID;
 }
-#endif
 
-/* #define GRIBAPIENCODETEST 1 */
 
-#ifdef HAVE_LIBGRIB_API
-size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
-		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const double *data, int nmiss, unsigned char **gribbuffer, size_t *gribbuffersize,
-		     int comptype, void *gribContainer)
+void streamInqRecord(int streamID, int *varID, int *levelID)
 {
-  size_t recsize = 0;
-  void *dummy = NULL;
-  int lieee = FALSE;
-  /*  int ensID, ensCount, forecast_type; *//* Ensemble Data */
-  int typeOfGeneratingProcess;
-  int productDefinitionTemplate;
-  long bitsPerValue;
-  long editionNumber = 2;
-  char name[256];
-  char stdname[256];
-  gribContainer_t *gc = (gribContainer_t *) gribContainer;
-  // extern unsigned char _grib_template_GRIB2[];
-
-  int param    = vlistInqVarParam(vlistID, varID);
-  int datatype = vlistInqVarDatatype(vlistID, varID);
-  typeOfGeneratingProcess = vlistInqVarTypeOfGeneratingProcess(vlistID, varID);
-  productDefinitionTemplate = vlistInqVarProductDefinitionTemplate(vlistID, varID);
+  check_parg(varID);
+  check_parg(levelID);
 
-  vlistInqVarName(vlistID, varID, name);
-  vlistInqVarStdname(vlistID, varID, stdname);
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-#if defined(GRIBAPIENCODETEST)
-  grib_handle *gh = (grib_handle *) gribHandleNew(editionNumber);
-#else
-  grib_handle *gh = (struct grib_handle *)gc->gribHandle;
-#endif
-  GRIB_CHECK(grib_get_long(gh, "editionNumber", &editionNumber), 0);
+  cdiDefAccesstype(streamID, TYPE_REC);
 
-  if ( editionNumber == 2 )
-    {
-      if ( typeOfGeneratingProcess == -1 ) typeOfGeneratingProcess = 0;
-      if ( ! gc->init ) GRIB_CHECK(my_grib_set_long(gh, "typeOfGeneratingProcess", typeOfGeneratingProcess), 0);
-    }
+  if ( ! streamptr->record ) cdiInitRecord(streamptr);
 
-  /*
-  if( vlistInqVarEnsemble( vlistID,  varID, &ensID, &ensCount, &forecast_type ) )
-    {
-      GRIB_CHECK(my_grib_set_long(gh, "typeOfEnsembleForecast", forecast_type ), 0);
-      GRIB_CHECK(my_grib_set_long(gh, "numberOfForecastsInEnsemble", ensCount ), 0);
-      GRIB_CHECK(my_grib_set_long(gh, "perturbationNumber", ensID ), 0);
-    }
-  */
+  int tsID   = streamptr->curTsID;
+  int rindex = streamptr->tsteps[tsID].curRecID + 1;
 
-  gribapiDefTime((int)editionNumber, productDefinitionTemplate, typeOfGeneratingProcess, gh, vdate, vtime, tsteptype, numavg, vlistInqTaxis(vlistID), gc->init);
+  if ( rindex >= streamptr->tsteps[tsID].nrecs )
+    Error("record %d not available at timestep %d", rindex+1, tsID+1);
 
-  if ( ! gc->init ) gribapiDefInstitut(gh, vlistID, varID);
-  if ( ! gc->init ) gribapiDefModel(gh, vlistID, varID);
+  int recID  = streamptr->tsteps[tsID].recIDs[rindex];
 
-  if ( ! gc->init ) gribapiDefParam((int)editionNumber, gh, param, name, stdname);
+  if ( recID == -1 || recID >= streamptr->tsteps[tsID].nallrecs )
+    Error("Internal problem! tsID = %d recID = %d", tsID, recID);
 
-  if ( editionNumber == 2 && (datatype == DATATYPE_FLT32 || datatype == DATATYPE_FLT64) ) lieee = TRUE;
+  *varID   = streamptr->tsteps[tsID].records[recID].varID;
+  int lindex = streamptr->tsteps[tsID].records[recID].levelID;
 
-  /* bitsPerValue have to be defined before call to DefGrid (complex packing) */
-  //  if ( lieee == FALSE )
-    {
-      bitsPerValue = grbBitsPerValue(datatype);
-      GRIB_CHECK(my_grib_set_long(gh, "bitsPerValue", bitsPerValue), 0);
-    }
+  int isub = subtypeInqActiveIndex(streamptr->vars[*varID].subtypeID);
+  *levelID = streamptr->vars[*varID].recordTable[isub].lindex[lindex];
 
-  gribapiDefGrid((int)editionNumber, gh, gridID, comptype, lieee, datatype, nmiss, gc->init);
+  if ( CDI_Debug )
+    Message("tsID = %d, recID = %d, varID = %d, levelID = %d\n", tsID, recID, *varID, *levelID);
 
-  gribapiDefLevel((int)editionNumber, gh, param, zaxisID, levelID, gc->init, productDefinitionTemplate);
+  streamptr->curTsID = tsID;
+  streamptr->tsteps[tsID].curRecID = rindex;
+}
 
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  //if (!gc->init)
-  {
-    int ret = 0;
+/*
+ at Function  streamDefRecord
+ at Title     Define the next record
 
-    /* NOTE: Optional key/value pairs: Note that we do not distinguish
-     *       between tiles here! */
+ at Prototype void streamDefRecord(int streamID, int varID, int levelID)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
 
-    for ( int i=0; i<vlistptr->vars[varID].opt_grib_nentries; i++ )
-      {
-        if ( vlistptr->vars[varID].opt_grib_kvpair[i].update )
-          {
-            //DR: Fix for multi-level fields (otherwise only the 1st level is correct)
-            if ( zaxisInqSize(zaxisID)==(levelID+1) )
-              vlistptr->vars[varID].opt_grib_kvpair[i].update = FALSE;
+ at Description
+The function streamDefRecord defines the meta-data of the next record.
+ at EndFunction
+*/
+void streamDefRecord(int streamID, int varID, int levelID)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-            if (vlistptr->vars[varID].opt_grib_kvpair[i].data_type == t_double)
-              {
-                if ( CDI_Debug )
-                  Message("key \"%s\"  :   double value = %g\n",
-                          vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
-                          vlistptr->vars[varID].opt_grib_kvpair[i].dbl_val);
-                my_grib_set_double(gh, vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
-                                   vlistptr->vars[varID].opt_grib_kvpair[i].dbl_val);
-                GRIB_CHECK(ret, 0);
-                }
-            if (vlistptr->vars[varID].opt_grib_kvpair[i].data_type == t_int)
-              {
-                if ( CDI_Debug )
-                  Message("key \"%s\"  :   integer value = %d\n",
-                          vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
-                          vlistptr->vars[varID].opt_grib_kvpair[i].int_val);
-                my_grib_set_long(gh, vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
-                                 (long) vlistptr->vars[varID].opt_grib_kvpair[i].int_val);
-                GRIB_CHECK(ret, 0);
-              }
-          }
-      }
-  }
+  int tsID = streamptr->curTsID;
 
-  if ( nmiss > 0 )
+  if ( tsID == CDI_UNDEFID )
     {
-      GRIB_CHECK(my_grib_set_long(gh, "bitmapPresent", 1), 0);
-      GRIB_CHECK(my_grib_set_double(gh, "missingValue", vlistInqVarMissval(vlistID, varID)), 0);
+      tsID++;
+      streamDefTimestep(streamID, tsID);
     }
 
-  GRIB_CHECK(grib_set_double_array(gh, "values", data, (size_t)datasize), 0);
+  if ( ! streamptr->record ) cdiInitRecord(streamptr);
 
-  /* get the size of coded message  */
-  GRIB_CHECK(grib_get_message(gh, (const void **)&dummy, &recsize), 0);
-  recsize += 512; /* add some space for possible filling */
-  *gribbuffersize = recsize;
-  *gribbuffer = (unsigned char *) Malloc(*gribbuffersize);
+  int vlistID = streamptr->vlistID;
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  int zaxisID = vlistInqVarZaxis(vlistID, varID);
+  int param   = vlistInqVarParam(vlistID, varID);
+  int level   = (int)(zaxisInqLevel(zaxisID, levelID));
 
-  /* get a copy of the coded message */
-  GRIB_CHECK(grib_get_message_copy(gh, *gribbuffer, &recsize), 0);
+  streamptr->record->varID    = varID;
+  streamptr->record->levelID  = levelID;
+  streamptr->record->param    = param;
+  streamptr->record->level    = level;
+  streamptr->record->date     = streamptr->tsteps[tsID].taxis.vdate;
+  streamptr->record->time     = streamptr->tsteps[tsID].taxis.vtime;
+  streamptr->record->gridID   = gridID;
+  streamptr->record->prec     = vlistInqVarDatatype(vlistID, varID);
 
-#if defined(GRIBAPIENCODETEST)
-  gribHandleDelete(gh);
+  switch (streamptr->filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      grbDefRecord(streamptr);
+      break;
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      srvDefRecord(streamptr);
+      break;
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      extDefRecord(streamptr);
+      break;
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      iegDefRecord(streamptr);
+      break;
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
+      cdfDefRecord(streamptr);
+      break;
 #endif
+    default:
+      Error("%s support not compiled in!", strfiletype(streamptr->filetype));
+      break;
+    }
+}
 
-  gc->init = TRUE;
 
-  return (recsize);
-}
-#endif
+void streamCopyRecord(int streamID2, int streamID1)
+{
+  stream_t *streamptr1 = stream_to_pointer(streamID1),
+    *streamptr2 = stream_to_pointer(streamID2);
+  int filetype1 = streamptr1->filetype,
+    filetype2 = streamptr2->filetype,
+    filetype  = FILETYPE_UNDEF;
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
+  if ( filetype1 == filetype2 ) filetype = filetype2;
+  else
+    {
+      switch (filetype1)
+        {
+        case FILETYPE_NC:
+        case FILETYPE_NC2:
+        case FILETYPE_NC4:
+        case FILETYPE_NC4C:
+          switch (filetype2)
+            {
+            case FILETYPE_NC:
+            case FILETYPE_NC2:
+            case FILETYPE_NC4:
+            case FILETYPE_NC4C:
+              Warning("Streams have different file types (%s -> %s)!", strfiletype(filetype1), strfiletype(filetype2));
+              filetype = filetype2;
+              break;
+            }
+          break;
+        }
+    }
+
+  if ( filetype == FILETYPE_UNDEF )
+    Error("Streams have different file types (%s -> %s)!", strfiletype(filetype1), strfiletype(filetype2));
+
+  switch (filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      grbCopyRecord(streamptr2, streamptr1);
+      break;
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      srvCopyRecord(streamptr2, streamptr1);
+      break;
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      extCopyRecord(streamptr2, streamptr1);
+      break;
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      iegCopyRecord(streamptr2, streamptr1);
+      break;
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      cdfCopyRecord(streamptr2, streamptr1);
+      break;
 #endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
+      }
+    }
+}
+
+
+void cdi_create_records(stream_t *streamptr, int tsID)
+{
+  unsigned nrecords, maxrecords;
+  record_t *records;
+
+  tsteps_t *sourceTstep = streamptr->tsteps;
+  tsteps_t *destTstep = sourceTstep + tsID;
 
+  if ( destTstep->records ) return;
 
+  int vlistID = streamptr->vlistID;
 
-void streamDefHistory(int streamID, int length, const char *history)
-{
-#ifdef HAVE_LIBNETCDF
-  stream_t *streamptr = stream_to_pointer(streamID);
+  if ( tsID == 0 )
+    {
+      maxrecords = 0;
+      int nvars = streamptr->nvars;
+      for ( int varID = 0; varID < nvars; varID++)
+        for (int isub=0; isub<streamptr->vars[varID].subtypeSize; isub++)
+          maxrecords += (unsigned)streamptr->vars[varID].recordTable[isub].nlevs;
+    }
+  else
+    {
+      maxrecords = (unsigned)sourceTstep->recordSize;
+    }
 
-  if ( streamptr->filetype == FILETYPE_NC  ||
-       streamptr->filetype == FILETYPE_NC2 ||
-       streamptr->filetype == FILETYPE_NC4 ||
-       streamptr->filetype == FILETYPE_NC4C )
+  if ( tsID == 0 )
     {
-      char *histstring;
-      size_t len;
-      if ( history )
+      nrecords = maxrecords;
+    }
+  else if ( tsID == 1 )
+    {
+      nrecords = 0;
+      maxrecords = (unsigned)sourceTstep->recordSize;
+      for ( unsigned recID = 0; recID < maxrecords; recID++ )
 	{
-	  len = strlen(history);
-	  if ( len )
-	    {
-              /* FIXME: what's the point of strdupx? Why not use
-               * history argument directly? */
-	      histstring = strdupx(history);
-	      cdfDefHistory(streamptr, length, histstring);
-	      Free(histstring);
-	    }
+	  int varID = sourceTstep->records[recID].varID;
+	  nrecords += (varID == CDI_UNDEFID /* varID = CDI_UNDEFID for write mode !!! */
+                       || vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT);
+          //    printf("varID nrecords %d %d %d \n", varID, nrecords, vlistInqVarTsteptype(vlistID, varID));
 	}
     }
-#else
-  (void)streamID; (void)length; (void)history;
-#endif
-}
-
-
-int streamInqHistorySize(int streamID)
-{
-  int size = 0;
-#ifdef HAVE_LIBNETCDF
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  if ( streamptr->filetype == FILETYPE_NC  ||
-       streamptr->filetype == FILETYPE_NC2 ||
-       streamptr->filetype == FILETYPE_NC4 ||
-       streamptr->filetype == FILETYPE_NC4C )
+  else
     {
-      size = cdfInqHistorySize(streamptr);
+      nrecords = (unsigned)streamptr->tsteps[1].nallrecs;
     }
-#else
-  (void)streamID;
-#endif
-  return (size);
-}
+  //  printf("tsID, nrecords %d %d\n", tsID, nrecords);
 
+  if ( maxrecords > 0 )
+    records = (record_t *) Malloc(maxrecords*sizeof(record_t));
+  else
+    records = NULL;
 
-void streamInqHistoryString(int streamID, char *history)
-{
-#ifdef HAVE_LIBNETCDF
-  stream_t *streamptr = stream_to_pointer(streamID);
+  destTstep->records    = records;
+  destTstep->recordSize = (int)maxrecords;
+  destTstep->nallrecs   = (int)nrecords;
 
-  if ( streamptr->filetype == FILETYPE_NC  ||
-       streamptr->filetype == FILETYPE_NC2 ||
-       streamptr->filetype == FILETYPE_NC4 ||
-       streamptr->filetype == FILETYPE_NC4C )
+  if ( tsID == 0 )
     {
-      cdfInqHistoryString(streamptr, history);
+      for ( unsigned recID = 0; recID < maxrecords; recID++ )
+        recordInitEntry(&destTstep->records[recID]);
+    }
+  else
+    {
+      memcpy(destTstep->records, sourceTstep->records, (size_t)maxrecords*sizeof(record_t));
+
+      for ( unsigned recID = 0; recID < maxrecords; recID++ )
+	{
+          record_t *curRecord = &sourceTstep->records[recID];
+          destTstep->records[recID].used = curRecord->used;
+          if ( curRecord->used != CDI_UNDEFID && curRecord->varID != -1 ) /* curRecord->varID = -1 for write mode !!! */
+            {
+              if ( vlistInqVarTsteptype(vlistID, curRecord->varID) != TSTEP_CONSTANT )
+                {
+                  destTstep->records[recID].position = CDI_UNDEFID;
+                  destTstep->records[recID].size     = 0;
+                  destTstep->records[recID].used     = FALSE;
+                }
+            }
+	}
     }
-#else
-  (void)streamID; (void)history;
-#endif
 }
 /*
  * Local Variables:
@@ -52771,12 +53336,9 @@ void streamInqHistoryString(int streamID, char *history)
 #endif
 
 #include <limits.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <float.h>
-#include <math.h>
 
 
 
@@ -52787,16 +53349,16 @@ void streamInqHistoryString(int streamID, char *history)
 #define SINGLE_PRECISION  4
 #define DOUBLE_PRECISION  8
 
-#if defined (HAVE_LIBIEG)
+#if defined (HAVE_LIBSERVICE)
 
 
 typedef struct {
   int param;
   int level;
-} IEGCOMPVAR;
+} SRVCOMPVAR;
 
 
-static int iegInqDatatype(int prec)
+static int srvInqDatatype(int prec)
 {
   int datatype;
 
@@ -52807,12 +53369,12 @@ static int iegInqDatatype(int prec)
 }
 
 
-static int iegDefDatatype(int datatype)
+static int srvDefDatatype(int datatype)
 {
   int prec;
 
   if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
-    Error("CDI/IEG library does not support complex numbers!");
+    Error("CDI/SERVICE library does not support complex numbers!");
 
   if ( datatype != DATATYPE_FLT32 && datatype != DATATYPE_FLT64 )
     datatype = DATATYPE_FLT32;
@@ -52824,14 +53386,15 @@ static int iegDefDatatype(int datatype)
 }
 
 /* not used
-int iegInqRecord(stream_t *streamptr, int *varID, int *levelID)
+int srvInqRecord(stream_t *streamptr, int *varID, int *levelID)
 {
   int status;
   int fileID;
   int icode, ilevel;
   int zaxisID = -1;
+  int header[8];
   int vlistID;
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+  void *srvp = streamptr->record->exsep;
 
   vlistID = streamptr->vlistID;
   fileID  = streamptr->fileID;
@@ -52839,14 +53402,13 @@ int iegInqRecord(stream_t *streamptr, int *varID, int *levelID)
   *varID   = -1;
   *levelID = -1;
 
-  status = iegRead(fileID, iegp);
+  status = srvRead(fileID, srvp);
   if ( status != 0 ) return (0);
 
-  icode  = IEG_P_Parameter(iegp->ipdb);
-  if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
-    ilevel = IEG_P_Level1(iegp->ipdb);
-  else
-    ilevel = IEG_P_Level2(iegp->ipdb);
+  srvInqHeader(srvp, header);
+
+  icode  = header[0];
+  ilevel = header[1];
 
   *varID = vlistInqVarID(vlistID, icode);
 
@@ -52860,32 +53422,31 @@ int iegInqRecord(stream_t *streamptr, int *varID, int *levelID)
 }
 */
 
-void iegReadRecord(stream_t *streamptr, double *data, int *nmiss)
+void srvReadRecord(stream_t *streamptr, double *data, int *nmiss)
 {
-  int vlistID, fileID;
   int status;
-  int recID, vrecID, tsID;
-  off_t recpos;
-  int varID, gridID;
+  int header[8];
+  int gridID;
   int i, size;
   double missval;
-  void *iegp = streamptr->record->exsep;
+  void *srvp = streamptr->record->exsep;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
-  tsID    = streamptr->curTsID;
-  vrecID  = streamptr->tsteps[tsID].curRecID;
-  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-  recpos  = streamptr->tsteps[tsID].records[recID].position;
-  varID   = streamptr->tsteps[tsID].records[recID].varID;
+  int vlistID  = streamptr->vlistID;
+  int fileID   = streamptr->fileID;
+  int tsID     = streamptr->curTsID;
+  int vrecID   = streamptr->tsteps[tsID].curRecID;
+  int recID    = streamptr->tsteps[tsID].recIDs[vrecID];
+  int varID    = streamptr->tsteps[tsID].records[recID].varID;
+  off_t recpos = streamptr->tsteps[tsID].records[recID].position;
 
   fileSetPos(fileID, recpos, SEEK_SET);
 
-  status = iegRead(fileID, iegp);
+  status = srvRead(fileID, srvp);
   if ( status != 0 )
-    Error("Could not read IEG record!");
+    Error("Failed to read record from SRV file");
 
-  iegInqDataDP(iegp, data);
+  srvInqHeader(srvp, header);
+  srvInqDataDP(srvp, data);
 
   missval = vlistInqVarMissval(vlistID, varID);
   gridID  = vlistInqVarGrid(vlistID, varID);
@@ -52902,2965 +53463,3390 @@ void iegReadRecord(stream_t *streamptr, double *data, int *nmiss)
       }
 }
 
+
+void srvCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
+{
+  streamFCopyRecord(streamptr2, streamptr1, "SRV");
+}
+
+
+void srvDefRecord(stream_t *streamptr)
+{
+  int header[8];
+  Record *restrict record = streamptr->record;
+  srvrec_t *restrict srvp = (srvrec_t*) record->exsep;
+  int gridID = record->gridID;
+
+  int pdis, pcat, pnum;
+  cdiDecodeParam(record->param, &pnum, &pcat, &pdis);
+  header[0] = pnum;
+  header[1] = record->level;
+  header[2] = record->date;
+  header[3] = record->time;
+
+  int xsize = gridInqXsize(gridID),
+    ysize = gridInqYsize(gridID);
+  if ( xsize == 0 || ysize == 0 )
+    {
+      xsize = gridInqSize(gridID);
+      ysize = 1;
+    }
+  if ( gridInqType(gridID) == GRID_UNSTRUCTURED ) ysize = 1;
+  if ( gridInqSize(gridID) != xsize*ysize )
+    Error("Internal problem with gridsize!");
+
+  header[4] = xsize;
+  header[5] = ysize;
+  header[6] = 0;
+  header[7] = 0;
+
+  int datatype = record->prec;
+
+  srvp->dprec = srvDefDatatype(datatype);
+
+  srvDefHeader(srvp, header);
+}
+
+
+void srvWriteRecord(stream_t *streamptr, const double *data)
+{
+  int fileID = streamptr->fileID;
+  void *srvp = streamptr->record->exsep;
+
+  srvDefDataDP(srvp, data);
+  srvWrite(fileID, srvp);
+}
+
 static
-int iegGetZaxisType(int iegleveltype)
+void srv_add_record(stream_t *streamptr, int param, int level, int xsize, int ysize,
+                    size_t recsize, off_t position, int prec)
 {
-  int leveltype = 0;
+  int vlistID = streamptr->vlistID;
+  int tsID    = streamptr->curTsID;
+  int recID   = recordNewEntry(streamptr, tsID);
+  record_t *record = &streamptr->tsteps[tsID].records[recID];
 
-  switch ( iegleveltype )
+  record->size     = recsize;
+  record->position = position;
+  record->param    = param;
+  record->ilevel   = level;
+
+  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
+  grid_init(grid);
+  cdiGridTypeInit(grid, GRID_GENERIC, xsize*ysize);
+  grid->xsize = xsize;
+  grid->ysize = ysize;
+  grid->xvals = NULL;
+  grid->yvals = NULL;
+  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  int gridID = gridAdded.Id;
+  if (!gridAdded.isNew) Free(grid);
+  /*
+  if ( level == 0 ) leveltype = ZAXIS_SURFACE;
+  else              leveltype = ZAXIS_GENERIC;
+  */
+  int leveltype = ZAXIS_GENERIC;
+
+  int datatype = srvInqDatatype(prec);
+
+  int levelID = 0;
+  int varID;
+  varAddRecord(recID, param, gridID, leveltype, 0, level, 0, 0, 0,
+	       datatype, &varID, &levelID, TSTEP_INSTANT, 0, 0, -1,
+               NULL, NULL, NULL, NULL, NULL, NULL);
+
+  xassert(varID <= SHRT_MAX && levelID <= SHRT_MAX);
+  record->varID   = (short)varID;
+  record->levelID = (short)levelID;
+
+  streamptr->tsteps[tsID].nallrecs++;
+  streamptr->nrecs++;
+
+  if ( CDI_Debug )
+    Message("varID = %d gridID = %d levelID = %d",
+	    varID, gridID, levelID);
+}
+
+static
+void srvScanTimestep1(stream_t *streamptr)
+{
+  DateTime datetime0 = { LONG_MIN, LONG_MIN };
+  off_t recpos;
+  taxis_t *taxis;
+  srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
+
+  streamptr->curTsID = 0;
+
+  {
+    int tsID  = tstepsNewEntry(streamptr);
+    if ( tsID != 0 )
+      Error("Internal problem! tstepsNewEntry returns %d", tsID);
+    taxis = &streamptr->tsteps[tsID].taxis;
+  }
+
+
+  int fileID = streamptr->fileID;
+
+  int nrecs = 0;
+  while ( TRUE )
     {
-    case IEG_LTYPE_SURFACE:
-      {
-	leveltype = ZAXIS_SURFACE;
-	break;
-      }
-    case IEG_LTYPE_99:
-    case IEG_LTYPE_ISOBARIC:
-      {
-	leveltype = ZAXIS_PRESSURE;
-	break;
-      }
-    case IEG_LTYPE_HEIGHT:
-      {
-	leveltype = ZAXIS_HEIGHT;
-	break;
-      }
-    case IEG_LTYPE_ALTITUDE:
-      {
-	leveltype = ZAXIS_ALTITUDE;
-	break;
-      }
-    case IEG_LTYPE_HYBRID:
-    case IEG_LTYPE_HYBRID_LAYER:
-      {
-	leveltype = ZAXIS_HYBRID;
-	break;
-      }
-    case IEG_LTYPE_LANDDEPTH:
-    case IEG_LTYPE_LANDDEPTH_LAYER:
-      {
-	leveltype = ZAXIS_DEPTH_BELOW_LAND;
-	break;
-      }
-    case IEG_LTYPE_SEADEPTH:
-      {
-	leveltype = ZAXIS_DEPTH_BELOW_SEA;
-	break;
-      }
-    default:
-      {
-	leveltype = ZAXIS_GENERIC;
-	break;
-      }
+      int header[8];
+      recpos = fileGetPos(fileID);
+      int status = srvRead(fileID, srvp);
+      if ( status != 0 )
+	{
+	  streamptr->ntsteps = 1;
+	  break;
+	}
+      size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
+
+      srvInqHeader(srvp, header);
+
+      int prec   = srvp->dprec;
+      int rcode  = header[0];
+      int rlevel = header[1];
+      int vdate  = header[2];
+      int vtime  = header[3];
+      int rxsize = header[4];
+      int rysize = header[5];
+
+      int param = cdiEncodeParam(rcode, 255, 255);
+
+      if ( nrecs == 0 )
+	{
+	  datetime0.date = vdate;
+	  datetime0.time = vtime;
+	}
+      else
+	{
+	  for ( int recID = 0; recID < nrecs; recID++ )
+            if (    streamptr->tsteps[0].records[recID].param  == param
+                 && streamptr->tsteps[0].records[recID].ilevel == rlevel )
+              goto tstepScanLoopFinished;
+	  DateTime datetime = { .date = vdate, .time = vtime };
+	  if ( datetimeCmp(datetime, datetime0) )
+	    Warning("Inconsistent verification time for code %d level %d", rcode, rlevel);
+	}
+
+      nrecs++;
+
+      if ( CDI_Debug )
+	Message("%4d%8d%4d%8d%8d%6d", nrecs, (int)recpos, rcode, rlevel, vdate, vtime);
+
+      srv_add_record(streamptr, param, rlevel, rxsize, rysize, recsize, recpos, prec);
     }
 
-  return (leveltype);
+  tstepScanLoopFinished:
+  streamptr->rtsteps = 1;
+
+  cdi_generate_vars(streamptr);
+
+  int taxisID = taxisCreate(TAXIS_ABSOLUTE);
+  taxis->type  = TAXIS_ABSOLUTE;
+  taxis->vdate = (int)datetime0.date;
+  taxis->vtime = (int)datetime0.time;
+
+  int vlistID = streamptr->vlistID;
+  vlistDefTaxis(vlistID, taxisID);
+
+  vlist_check_contents(vlistID);
+
+  int nrecords = streamptr->tsteps[0].nallrecs;
+  if ( nrecords < streamptr->tsteps[0].recordSize )
+    {
+      streamptr->tsteps[0].recordSize = nrecords;
+      streamptr->tsteps[0].records =
+	(record_t *) Realloc(streamptr->tsteps[0].records,
+                             (size_t)nrecords * sizeof(record_t));
+    }
+
+  streamptr->tsteps[0].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
+  streamptr->tsteps[0].nrecs = nrecords;
+  for ( int recID = 0; recID < nrecords; recID++ )
+    streamptr->tsteps[0].recIDs[recID] = recID;
+
+  if ( streamptr->ntsteps == -1 )
+    {
+      int tsID = tstepsNewEntry(streamptr);
+      if ( tsID != streamptr->rtsteps )
+	Error("Internal error. tsID = %d", tsID);
+
+      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID].position = recpos;
+    }
+
+  if ( streamptr->ntsteps == 1 )
+    {
+      if ( taxis->vdate == 0 && taxis->vtime == 0 )
+	{
+	  streamptr->ntsteps = 0;
+	  for ( int varID = 0; varID < streamptr->nvars; varID++ )
+            vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	}
+    }
 }
 
+static
+int srvScanTimestep2(stream_t *streamptr)
+{
+  int header[8];
+  int status;
+  int fileID;
+  int param = 0;
+  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
+  int tsID;
+  int varID;
+  off_t recpos = 0;
+  int nrecords, nrecs, recID, rindex;
+  int nextstep;
+  taxis_t *taxis;
+  int vlistID;
+  SRVCOMPVAR compVar, compVar0;
+  void *srvp = streamptr->record->exsep;
+
+  streamptr->curTsID = 1;
+
+  vlistID = streamptr->vlistID;
+  fileID  = streamptr->fileID;
+
+  tsID = streamptr->rtsteps;
+  if ( tsID != 1 )
+    Error("Internal problem! unexpected timestep %d", tsID+1);
+
+  taxis = &streamptr->tsteps[tsID].taxis;
+
+  fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+
+  cdi_create_records(streamptr, tsID);
+
+  nrecords = streamptr->tsteps[0].nallrecs;
+  streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
+  streamptr->tsteps[1].nrecs = 0;
+  for ( recID = 0; recID < nrecords; recID++ )
+    streamptr->tsteps[1].recIDs[recID] = -1;
+
+  for ( recID = 0; recID < nrecords; recID++ )
+    {
+      varID = streamptr->tsteps[0].records[recID].varID;
+      streamptr->tsteps[tsID].records[recID].position =
+	streamptr->tsteps[0].records[recID].position;
+      streamptr->tsteps[tsID].records[recID].size     =
+	streamptr->tsteps[0].records[recID].size;
+    }
+
+  for ( rindex = 0; rindex <= nrecords; rindex++ )
+    {
+      recpos = fileGetPos(fileID);
+      status = srvRead(fileID, srvp);
+      if ( status != 0 )
+	{
+	  streamptr->ntsteps = 2;
+	  break;
+	}
+      size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
+
+      srvInqHeader(srvp, header);
+
+      rcode  = header[0];
+      rlevel = header[1];
+      vdate  = header[2];
+      vtime  = header[3];
+
+      param = cdiEncodeParam(rcode, 255, 255);
+
+      if ( rindex == 0 )
+	{
+	  taxis->type  = TAXIS_ABSOLUTE;
+	  taxis->vdate = vdate;
+	  taxis->vtime = vtime;
+	}
+
+      compVar.param = param;
+      compVar.level = rlevel;
+      nextstep = FALSE;
+      for ( recID = 0; recID < nrecords; recID++ )
+	{
+	  compVar0.param  = streamptr->tsteps[tsID].records[recID].param;
+	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+
+	  if ( memcmp(&compVar0, &compVar, sizeof(SRVCOMPVAR)) == 0 )
+	    {
+	      if ( streamptr->tsteps[tsID].records[recID].used )
+		{
+		  nextstep = TRUE;
+		}
+	      else
+		{
+		  streamptr->tsteps[tsID].records[recID].used = TRUE;
+		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
+		}
+	      break;
+	    }
+	}
+      if ( recID == nrecords )
+	{
+	  Warning("Code %d level %d not found at timestep %d", rcode, rlevel, tsID+1);
+	  return (CDI_EUFSTRUCT);
+	}
+
+      if ( nextstep ) break;
+
+      if ( CDI_Debug )
+	Message("%4d%8d%4d%8d%8d%6d", rindex+1, (int)recpos, rcode, rlevel, vdate, vtime);
+
+      streamptr->tsteps[tsID].records[recID].size = recsize;
+
+      compVar0.param  = streamptr->tsteps[tsID].records[recID].param;
+      compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+
+      if ( memcmp(&compVar0, &compVar, sizeof(SRVCOMPVAR)) != 0 )
+	{
+	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
+		  tsID, recID,
+		  streamptr->tsteps[tsID].records[recID].param, param,
+		  streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
+	  return (CDI_EUFSTRUCT);
+	}
+
+      streamptr->tsteps[1].records[recID].position = recpos;
+    }
 
-static void iegDefTime(int *pdb, int date, int time, int taxisID)
-{
-  int year, month, day, hour, minute, second;
-  int timetype = -1;
+  nrecs = 0;
+  for ( recID = 0; recID < nrecords; recID++ )
+    {
+      if ( ! streamptr->tsteps[tsID].records[recID].used )
+	{
+	  varID = streamptr->tsteps[tsID].records[recID].varID;
+          vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	}
+      else
+	{
+	  nrecs++;
+	}
+    }
+  streamptr->tsteps[tsID].nrecs = nrecs;
 
-  if ( taxisID != -1 ) timetype = taxisInqType(taxisID);
+  streamptr->rtsteps = 2;
 
-  if ( timetype == TAXIS_ABSOLUTE || timetype == TAXIS_RELATIVE )
+  if ( streamptr->ntsteps == -1 )
     {
-      cdiDecodeDate(date, &year, &month, &day);
-      cdiDecodeTime(time, &hour, &minute, &second);
-
-      IEG_P_Year(pdb)     = year;
-      IEG_P_Month(pdb)    = month;
-      IEG_P_Day(pdb)      = day;
-      IEG_P_Hour(pdb)     = hour;
-      IEG_P_Minute(pdb)   = minute;
+      tsID = tstepsNewEntry(streamptr);
+      if ( tsID != streamptr->rtsteps )
+	Error("Internal error. tsID = %d", tsID);
 
-      pdb[15] = 1;
-      pdb[16] = 0;
-      pdb[17] = 0;
-      pdb[18] = 10;
-      pdb[36] = 1;
+      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID].position = recpos;
     }
 
-  pdb[5] = 128;
+  return (0);
 }
 
-/* find smallest power of 10 in [1000,10000000] that upon
- * multiplication results in fractional part close to zero for all
- * arguments */
-static double
-calc_resfac(double xfirst, double xlast, double xinc, double yfirst, double ylast, double yinc)
+
+int srvInqContents(stream_t *streamptr)
 {
-  double resfac = 1000.0;
-  enum {
-    nPwrOf10 = 5,
-    nMultTests = 6,
-  };
-  static const double scaleFactors[nPwrOf10]
-    = { 1000, 10000, 100000, 1000000, 10000000 };
-  double vals[nMultTests] = { xfirst, xlast, xinc, yfirst, ylast, yinc };
+  int fileID;
+  int status = 0;
 
-  for (size_t j = 0; j < nPwrOf10; ++j )
-    {
-      double scaleBy = scaleFactors[j];
-      bool fractionalScale = false;
-      for (size_t i = 0; i < nMultTests; ++i )
-        {
-          fractionalScale = fractionalScale
-            || fabs(vals[i]*scaleBy - round(vals[i]*scaleBy)) > FLT_EPSILON;
-        }
-      if ( !fractionalScale )
-        {
-          resfac = scaleBy;
-          break;
-        }
-    }
+  fileID = streamptr->fileID;
 
-  return (resfac);
-}
+  streamptr->curTsID = 0;
 
-static
-void iegDefGrid(int *gdb, int gridID)
-{
-  int gridtype;
+  srvScanTimestep1(streamptr);
 
-  gridtype = gridInqType(gridID);
+  if ( streamptr->ntsteps == -1 ) status = srvScanTimestep2(streamptr);
 
-  if ( gridtype == GRID_GENERIC )
-    {
-      int xsize, ysize;
+  fileSetPos(fileID, 0, SEEK_SET);
 
-      xsize = gridInqXsize(gridID);
-      ysize = gridInqYsize(gridID);
+  return (status);
+}
 
-      if ( (ysize == 32  || ysize == 48 || ysize == 64 ||
-	    ysize == 96  || ysize == 160) &&
-	   (xsize == 2*ysize || xsize == 1) )
-	{
-	  gridtype = GRID_GAUSSIAN;
-	  gridChangeType(gridID, gridtype);
-	}
-      else if ( (xsize == 1 && ysize == 1) || (xsize == 0 && ysize == 0) )
-	{
-	  gridtype = GRID_LONLAT;
-	  gridChangeType(gridID, gridtype);
-	}
-      else if ( gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL) )
-	{
-	  gridtype = GRID_LONLAT;
-	  gridChangeType(gridID, gridtype);
-	}
-    }
-  else if ( gridtype == GRID_CURVILINEAR )
+static
+long srvScanTimestep(stream_t *streamptr)
+{
+  int header[8];
+  int status;
+  int fileID;
+  /* int rxsize = 0, rysize = 0; */
+  int param = 0;
+  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
+  off_t recpos = 0;
+  int recID;
+  int rindex, nrecs = 0;
+  void *srvp = streamptr->record->exsep;
+  /*
+  if ( CDI_Debug )
     {
-      gridtype = GRID_LONLAT;
+      Message("streamID = %d", streamptr->self);
+      Message("cts = %d", streamptr->curTsID);
+      Message("rts = %d", streamptr->rtsteps);
+      Message("nts = %d", streamptr->ntsteps);
     }
+  */
 
-  if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN )
+  int tsID  = streamptr->rtsteps;
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+
+  if ( streamptr->tsteps[tsID].recordSize == 0 )
     {
-      double xfirst = 0, xlast = 0, xinc = 0;
-      double yfirst = 0, ylast = 0, yinc = 0;
+      cdi_create_records(streamptr, tsID);
 
-      int nlon = gridInqXsize(gridID),
-        nlat = gridInqYsize(gridID);
+      nrecs = streamptr->tsteps[1].nrecs;
 
-      if ( nlon == 0 )
-	{
-	  nlon = 1;
-	}
-      else
-	{
-	  xfirst = gridInqXval(gridID,      0);
-	  xlast  = gridInqXval(gridID, nlon-1);
-	  xinc   = gridInqXinc(gridID);
-	}
+      streamptr->tsteps[tsID].nrecs = nrecs;
+      streamptr->tsteps[tsID].recIDs = (int *) Malloc((size_t)nrecs * sizeof (int));
+      for ( recID = 0; recID < nrecs; recID++ )
+	streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
 
-      if ( nlat == 0 )
-	{
-	  nlat = 1;
-	}
-      else
-	{
-	  yfirst = gridInqYval(gridID,      0);
-	  ylast  = gridInqYval(gridID, nlat-1);
-	  yinc   = gridInqYinc(gridID);
-	}
+      fileID = streamptr->fileID;
 
-      if ( gridtype == GRID_GAUSSIAN )
-	IEG_G_GridType(gdb) = 4;
-      else if ( gridtype == GRID_LONLAT && gridIsRotated(gridID) )
-	IEG_G_GridType(gdb) = 10;
-      else
-	IEG_G_GridType(gdb) = 0;
+      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
-      double resfac = calc_resfac(xfirst, xlast, xinc, yfirst, ylast, yinc);
-      int iresfac = (int)resfac;
-      if ( iresfac == 1000 ) iresfac = 0;
+      for ( rindex = 0; rindex <= nrecs; rindex++ )
+	{
+	  recpos = fileGetPos(fileID);
+	  status = srvRead(fileID, srvp);
+	  if ( status != 0 )
+	    {
+	      streamptr->ntsteps = streamptr->rtsteps + 1;
+	      break;
+	    }
+	  size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
 
-      IEG_G_ResFac(gdb)   = iresfac;
+	  srvInqHeader(srvp, header);
 
-      IEG_G_NumLon(gdb)   = nlon;
-      IEG_G_NumLat(gdb)   = nlat;
-      IEG_G_FirstLat(gdb) = (int)lround(yfirst*resfac);
-      IEG_G_LastLat(gdb)  = (int)lround(ylast*resfac);
-      IEG_G_FirstLon(gdb) = (int)lround(xfirst*resfac);
-      IEG_G_LastLon(gdb)  = (int)lround(xlast*resfac);
-      IEG_G_LonIncr(gdb)  = (int)lround(xinc*resfac);
-      if ( fabs(xinc*resfac - IEG_G_LonIncr(gdb)) > FLT_EPSILON )
-	IEG_G_LonIncr(gdb) = 0;
+	  rcode  = header[0];
+	  rlevel = header[1];
+	  vdate  = header[2];
+	  vtime  = header[3];
+          /* rxsize = header[4]; */
+          /* rysize = header[5]; */
 
-      if ( gridtype == GRID_GAUSSIAN )
-	IEG_G_LatIncr(gdb) = nlat/2;
-      else
-	{
-	  IEG_G_LatIncr(gdb) = (int)lround(yinc*resfac);
-	  if ( fabs(yinc*resfac - IEG_G_LatIncr(gdb)) > FLT_EPSILON )
-	    IEG_G_LatIncr(gdb) = 0;
+	  param = cdiEncodeParam(rcode, 255, 255);
 
-	  if ( IEG_G_LatIncr(gdb) < 0 ) IEG_G_LatIncr(gdb) = -IEG_G_LatIncr(gdb);
-	}
+	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
+	  if ( rindex == nrecs ) continue;
+	  recID = streamptr->tsteps[tsID].recIDs[rindex];
 
-      if ( IEG_G_NumLon(gdb) > 1 && IEG_G_NumLat(gdb) == 1 )
-	if ( IEG_G_LonIncr(gdb) != 0 && IEG_G_LatIncr(gdb) == 0 ) IEG_G_LatIncr(gdb) = IEG_G_LonIncr(gdb);
+	  if ( rindex == 0 )
+	    {
+	      taxis->type  = TAXIS_ABSOLUTE;
+	      taxis->vdate = vdate;
+	      taxis->vtime = vtime;
+	    }
 
-      if ( IEG_G_NumLon(gdb) == 1 && IEG_G_NumLat(gdb) > 1 )
-	if ( IEG_G_LonIncr(gdb) == 0 && IEG_G_LatIncr(gdb) != 0 ) IEG_G_LonIncr(gdb) = IEG_G_LatIncr(gdb);
+          if (    param  != streamptr->tsteps[tsID].records[recID].param
+               || rlevel != streamptr->tsteps[tsID].records[recID].ilevel )
+	    {
+	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
+		      tsID, recID,
+		      streamptr->tsteps[tsID].records[recID].param, param,
+		      streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
+	      Error("Invalid, unsupported or inconsistent record structure!");
+	    }
 
-      if ( IEG_G_LatIncr(gdb) == 0 || IEG_G_LonIncr(gdb) == 0 )
-	IEG_G_ResFlag(gdb) = 0;
-      else
-	IEG_G_ResFlag(gdb) = 128;
+	  streamptr->tsteps[tsID].records[recID].position = recpos;
+	  streamptr->tsteps[tsID].records[recID].size = recsize;
 
-      if ( gridIsRotated(gridID) )
-	{
-	  IEG_G_LatSP(gdb) = - (int)lround(gridInqYpole(gridID) * resfac);
-	  IEG_G_LonSP(gdb) =   (int)lround((gridInqXpole(gridID) + 180) * resfac);
-	  IEG_G_Size(gdb)  = 42;
+	  if ( CDI_Debug )
+	    Message("%4d%8d%4d%8d%8d%6d", rindex, (int)recpos, rcode, rlevel, vdate, vtime);
 	}
-      else
+
+      streamptr->rtsteps++;
+
+      if ( streamptr->ntsteps != streamptr->rtsteps )
 	{
-	  IEG_G_Size(gdb)  = 32;
+	  tsID = tstepsNewEntry(streamptr);
+	  if ( tsID != streamptr->rtsteps )
+	    Error("Internal error. tsID = %d", tsID);
+
+	  streamptr->tsteps[tsID-1].next   = 1;
+	  streamptr->tsteps[tsID].position = recpos;
 	}
+
+      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+      streamptr->tsteps[tsID].position = recpos;
     }
-  else
+
+  if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
     {
-      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
+      Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
+      streamptr->ntsteps = tsID;
     }
 
-  IEG_G_ScanFlag(gdb) = 64;
+  return (streamptr->ntsteps);
 }
 
-static
-void iegDefLevel(int *pdb, int *gdb, double *vct, int zaxisID, int levelID)
+
+int srvInqTimestep(stream_t *streamptr, int tsID)
 {
-  double level;
-  int ilevel, leveltype;
-  static int warning = 1;
-  static int vct_warning = 1;
+  long ntsteps;
+  int nrecs;
 
-  leveltype = zaxisInqType(zaxisID);
+  if ( tsID == 0 && streamptr->rtsteps == 0 )
+    Error("Call to cdiInqContents missing!");
 
-  if ( leveltype == ZAXIS_GENERIC )
+  if ( CDI_Debug )
+    Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
+
+  ntsteps = UNDEFID;
+  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == UNDEFID )
+    ntsteps = srvScanTimestep(streamptr);
+
+  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != UNDEFID )
     {
-      Message("Changed zaxis type from %s to %s",
-	      zaxisNamePtr(leveltype),
-	      zaxisNamePtr(ZAXIS_PRESSURE));
-      leveltype = ZAXIS_PRESSURE;
-      zaxisChangeType(zaxisID, leveltype);
-      zaxisDefUnits(zaxisID, "Pa");
+      nrecs = 0;
+    }
+  else
+    {
+      streamptr->curTsID = tsID;
+      nrecs = streamptr->tsteps[tsID].nrecs;
     }
 
-  /*  IEG_G_NumVCP(gdb) = 0; */
+  return (nrecs);
+}
 
-  switch (leveltype)
+
+void srvReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+{
+  int vlistID, fileID;
+  int levID, nlevs, gridID, gridsize;
+  off_t recpos, currentfilepos;
+  int header[8];
+  int tsid;
+  int recID;
+  int i;
+  double missval;
+  void *srvp = streamptr->record->exsep;
+
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  /* NOTE: tiles are not supported here! */
+  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
+  missval  = vlistInqVarMissval(vlistID, varID);
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  gridsize = gridInqSize(gridID);
+  tsid     = streamptr->curTsID;
+
+  if ( CDI_Debug )
+    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+
+  currentfilepos = fileGetPos(fileID);
+
+  for (levID = 0; levID < nlevs; levID++)
     {
-    case ZAXIS_SURFACE:
+      /* NOTE: tiles are not supported here! */
+      recID = streamptr->vars[varID].recordTable[0].recordID[levID];
+      recpos = streamptr->tsteps[tsid].records[recID].position;
+      fileSetPos(fileID, recpos, SEEK_SET);
+      if (srvRead(fileID, srvp) < 0)
+        abort();
+      srvInqHeader(srvp, header);
+      srvInqDataDP(srvp, &data[levID*gridsize]);
+    }
+  fileSetPos(fileID, currentfilepos, SEEK_SET);
+
+  *nmiss = 0;
+  for ( i = 0; i < nlevs*gridsize; i++ )
+    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
-	IEG_P_LevelType(pdb) = IEG_LTYPE_SURFACE;
-	IEG_P_Level1(pdb)    = 0;
-	IEG_P_Level2(pdb)    = (int)(zaxisInqLevel(zaxisID, levelID));
-	break;
+	data[i] = missval;
+	(*nmiss)++;
       }
-    case ZAXIS_HYBRID:
-      {
-	int vctsize;
+}
 
-	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-	  {
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_HYBRID_LAYER;
-	    IEG_P_Level1(pdb)    = (int)(zaxisInqLbound(zaxisID, levelID));
-	    IEG_P_Level2(pdb)    = (int)(zaxisInqUbound(zaxisID, levelID));
-	  }
-	else
-	  {
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_HYBRID;
-	    IEG_P_Level1(pdb)    = 0;
-	    IEG_P_Level2(pdb)    = (int)(zaxisInqLevel(zaxisID, levelID));
-	  }
 
-	vctsize = zaxisInqVctSize(zaxisID);
-	if ( vctsize == 0 && warning )
-	  {
-	    Warning("VCT missing. ( code = %d, zaxisID = %d )",
-		    IEG_P_Parameter(pdb), zaxisID);
-	    warning = 0;
-	  }
-	if ( vctsize > 100 )
-	  {
-	    /*	    IEG_G_NumVCP(gdb) = 0; */
-	    if ( vct_warning )
-	      {
-		Warning("VCT size of %d is too large (maximum is 100). Set to 0!", vctsize);
-		vct_warning = 0;
-	      }
-	  }
-	else
-	  {
-	    IEG_G_Size(gdb) += (vctsize*4);
-	    memcpy(vct, zaxisInqVctPtr(zaxisID), (size_t)vctsize/2*sizeof(double));
-	    memcpy(vct+50, zaxisInqVctPtr(zaxisID)+vctsize/2, (size_t)vctsize/2*sizeof(double));
-	  }
-	break;
-      }
-    case ZAXIS_PRESSURE:
-      {
-	double dum;
-	char units[128];
+void srvReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
+{
+  int vlistID, fileID;
+  int nlevs, gridID, gridsize;
+  off_t recpos, currentfilepos;
+  int header[8];
+  int tsid;
+  int recID;
+  int i;
+  double missval;
+  void *srvp = streamptr->record->exsep;
 
-	level = zaxisInqLevel(zaxisID, levelID);
-	if ( level < 0 )
-	  Warning("pressure level of %f Pa is below 0.", level);
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  /* NOTE: tiles are not supported here! */
+  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
+  missval  = vlistInqVarMissval(vlistID, varID);
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  gridsize = gridInqSize(gridID);
+  tsid     = streamptr->curTsID;
 
-	zaxisInqUnits(zaxisID, units);
-	if ( memcmp(units, "hPa", 3) == 0 || memcmp(units, "mb",2 ) == 0 )
-	  level = level*100;
+  if ( CDI_Debug )
+    Message("nlevs = %d gridID = %d gridsize = %d",
+	     nlevs, gridID, gridsize);
 
-	ilevel = (int) level;
-	if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
-	  {
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_99;
-	    IEG_P_Level1(pdb)    = 0;
-	    IEG_P_Level2(pdb)    = ilevel;
-	  }
-	else
-	  {
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_ISOBARIC;
-	    IEG_P_Level1(pdb)    = 0;
-	    IEG_P_Level2(pdb)    = ilevel/100;
-	  }
-	break;
-      }
-    case ZAXIS_HEIGHT:
-      {
-	level = zaxisInqLevel(zaxisID, levelID);
+  currentfilepos = fileGetPos(fileID);
 
-	ilevel = (int) level;
-	IEG_P_LevelType(pdb) = IEG_LTYPE_HEIGHT;
-	IEG_P_Level1(pdb)    = 0;
-	IEG_P_Level2(pdb)    = ilevel;
+  /* NOTE: tiles are not supported here! */
+  recID = streamptr->vars[varID].recordTable[0].recordID[levID];
+  recpos = streamptr->tsteps[tsid].records[recID].position;
+  fileSetPos(fileID, recpos, SEEK_SET);
+  if (srvRead(fileID, srvp) < 0)
+    abort();
+  srvInqHeader(srvp, header);
+  srvInqDataDP(srvp, data);
 
-	break;
-      }
-    case ZAXIS_ALTITUDE:
+  fileSetPos(fileID, currentfilepos, SEEK_SET);
+
+  *nmiss = 0;
+  for ( i = 0; i < gridsize; i++ )
+    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
-	level = zaxisInqLevel(zaxisID, levelID);
+	data[i] = missval;
+	(*nmiss)++;
+      }
+}
 
-	ilevel = (int) level;
-	IEG_P_LevelType(pdb) = IEG_LTYPE_ALTITUDE;
-	IEG_P_Level1(pdb)    = 0;
-	IEG_P_Level2(pdb)    = ilevel;
 
-	break;
-      }
-    case ZAXIS_DEPTH_BELOW_LAND:
-      {
-	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-	  {
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_LANDDEPTH_LAYER;
-	    IEG_P_Level1(pdb)    = (int)(zaxisInqLbound(zaxisID, levelID));
-	    IEG_P_Level2(pdb)    = (int)(zaxisInqUbound(zaxisID, levelID));
-	  }
-	else
-	  {
-	    level = zaxisInqLevel(zaxisID, levelID);
+void srvWriteVarDP(stream_t *streamptr, int varID, const double *data)
+{
+  int fileID;
+  int levID, nlevs, gridID, gridsize;
+  int zaxisID;
+  double level;
+  int header[8];
+  int xsize, ysize;
+  int datatype;
+  int tsID;
+  int vlistID;
+  int pdis, pcat, pnum;
+  srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
 
-	    ilevel = (int) level;
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_LANDDEPTH;
-	    IEG_P_Level1(pdb)    = 0;
-	    IEG_P_Level2(pdb)    = ilevel;
-	  }
+  if ( CDI_Debug )
+    Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-	break;
-      }
-    case ZAXIS_DEPTH_BELOW_SEA:
-      {
-	level = zaxisInqLevel(zaxisID, levelID);
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  tsID     = streamptr->curTsID;
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  gridsize = gridInqSize(gridID);
+  zaxisID  = vlistInqVarZaxis(vlistID, varID);
+  nlevs    = zaxisInqSize(zaxisID);
 
-	ilevel = (int) level;
-	IEG_P_LevelType(pdb) = IEG_LTYPE_SEADEPTH;
-	IEG_P_Level1(pdb)    = 0;
-	IEG_P_Level2(pdb)    = ilevel;
+  if ( CDI_Debug )
+    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
 
-	break;
-      }
-    case ZAXIS_ISENTROPIC:
-      {
-	level = zaxisInqLevel(zaxisID, levelID);
+  cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
 
-	ilevel = (int) level;
-	IEG_P_LevelType(pdb) = 113;
-	IEG_P_Level1(pdb)    = 0;
-	IEG_P_Level2(pdb)    = ilevel;
+  header[0] = pnum;
+  header[2] = streamptr->tsteps[tsID].taxis.vdate;
+  header[3] = streamptr->tsteps[tsID].taxis.vtime;
 
-	break;
-      }
-    default:
-      {
-	Error("Unsupported zaxis type: %s", zaxisNamePtr(leveltype));
-	break;
-      }
+  xsize = gridInqXsize(gridID);
+  ysize = gridInqYsize(gridID);
+  if ( xsize == 0 || ysize == 0 )
+    {
+      xsize = gridInqSize(gridID);
+      ysize = 1;
     }
-}
+  if ( gridInqType(gridID) == GRID_UNSTRUCTURED ) ysize = 1;
+  if ( gridInqSize(gridID) != xsize*ysize )
+    Error("Internal problem with gridsize!");
 
+  header[4] = xsize;
+  header[5] = ysize;
+  header[6] = 0;
+  header[7] = 0;
 
-void iegCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
-{
-  streamFCopyRecord(streamptr2, streamptr1, "IEG");
+  datatype = vlistInqVarDatatype(vlistID, varID);
+
+  srvp->dprec = srvDefDatatype(datatype);
+
+  for ( levID = 0; levID < nlevs; levID++ )
+    {
+      level = zaxisInqLevel(zaxisID, levID);
+
+      header[1] = (int) level;
+      srvDefHeader(srvp, header);
+      srvDefDataDP(srvp, &data[levID*gridsize]);
+      srvWrite(fileID, srvp);
+    }
 }
 
 
-void iegDefRecord(stream_t *streamptr)
+void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
 {
-  int vlistID;
+  int fileID;
   int gridID;
-  int date, time;
+  int zaxisID;
+  double level;
+  int header[8];
+  int xsize, ysize;
   int datatype;
-  int i;
-  int param, pdis, pcat, pnum;
-  int varID, levelID, tsID, zaxisID;
-  int byteorder;
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+  int tsID;
+  int vlistID;
+  int pdis, pcat, pnum;
+  srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
 
-  vlistID = streamptr->vlistID;
-  byteorder = streamptr->byteorder;
+  vlistID  = streamptr->vlistID;
+  fileID   = streamptr->fileID;
+  tsID     = streamptr->curTsID;
+  gridID   = vlistInqVarGrid(vlistID, varID);
+  zaxisID  = vlistInqVarZaxis(vlistID, varID);
+  level    = zaxisInqLevel(zaxisID, levID);
 
-  varID   = streamptr->record->varID;
-  levelID = streamptr->record->levelID;
-  tsID    = streamptr->curTsID;
+  if ( CDI_Debug )
+    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
 
-  gridID  = vlistInqVarGrid(vlistID, varID);
-  zaxisID = vlistInqVarZaxis(vlistID, varID);
+  cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
 
-  iegInitMem(iegp);
-  for ( i = 0; i < 37; i++ ) iegp->ipdb[i] = -1;
+  header[0] = pnum;
+  header[1] = (int) level;
+  header[2] = streamptr->tsteps[tsID].taxis.vdate;
+  header[3] = streamptr->tsteps[tsID].taxis.vtime;
 
-  iegp->byteswap = getByteswap(byteorder);
+  xsize = gridInqXsize(gridID);
+  ysize = gridInqYsize(gridID);
+  if ( xsize == 0 || ysize == 0 )
+    {
+      xsize = gridInqSize(gridID);
+      ysize = 1;
+    }
+  if ( gridInqType(gridID) == GRID_UNSTRUCTURED ) ysize = 1;
+  if ( gridInqSize(gridID) != xsize*ysize )
+    Error("Internal problem with gridsize!");
 
-  param =  vlistInqVarParam(vlistID, varID);
-  cdiDecodeParam(param, &pnum, &pcat, &pdis);
-  IEG_P_Parameter(iegp->ipdb) = pnum;
-  if ( pdis == 255 ) IEG_P_CodeTable(iegp->ipdb) = pcat;
-  date     = streamptr->tsteps[tsID].taxis.vdate;
-  time     = streamptr->tsteps[tsID].taxis.vtime;
+  header[4] = xsize;
+  header[5] = ysize;
+  header[6] = 0;
+  header[7] = 0;
 
-  iegDefTime(iegp->ipdb, date, time, vlistInqTaxis(vlistID));
-  iegDefGrid(iegp->igdb, gridID);
-  iegDefLevel(iegp->ipdb, iegp->igdb, iegp->vct, zaxisID, levelID);
+  datatype = vlistInqVarDatatype(vlistID, varID);
 
-  datatype = streamptr->record->prec;
+  srvp->dprec = srvDefDatatype(datatype);
 
-  iegp->dprec = iegDefDatatype(datatype);
+  srvDefHeader(srvp, header);
+  srvDefDataDP(srvp, data);
+  srvWrite(fileID, srvp);
 }
 
+#endif /* HAVE_LIBSERVICE */
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-void iegWriteRecord(stream_t *streamptr, const double *data)
-{
-  int fileID;
-  int i, gridsize, gridID;
-  double refval;
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+#include <string.h>
 
-  fileID = streamptr->fileID;
-  gridID = streamptr->record->gridID;
 
-  gridsize = gridInqSize(gridID);
 
-  refval = data[0];
-  for ( i = 1; i < gridsize; i++ )
-    if ( data[i] < refval ) refval = data[i];
 
-  iegp->refval = refval;
+static void streamvar_init_recordtable(stream_t *streamptr, int varID, int isub)
+{
+  streamptr->vars[varID].recordTable[isub].nlevs    = 0;
+  streamptr->vars[varID].recordTable[isub].recordID = NULL;
+  streamptr->vars[varID].recordTable[isub].lindex   = NULL;
+}
 
-  iegDefDataDP(iegp, data);
 
-  iegWrite(fileID, iegp);
+static
+void streamvar_init_entry(stream_t *streamptr, int varID)
+{
+  streamptr->vars[varID].ncvarid      = CDI_UNDEFID;
+  streamptr->vars[varID].defmiss      = 0;
+
+  streamptr->vars[varID].subtypeSize  = 0;
+  streamptr->vars[varID].recordTable  = NULL;
+
+  streamptr->vars[varID].gridID       = CDI_UNDEFID;
+  streamptr->vars[varID].zaxisID      = CDI_UNDEFID;
+  streamptr->vars[varID].tsteptype    = CDI_UNDEFID;
+  streamptr->vars[varID].subtypeID    = CDI_UNDEFID;
 }
 
 static
-void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vct,
-		  size_t recsize, off_t position, int prec)
+int streamvar_new_entry(stream_t *streamptr)
 {
-  int leveltype;
-  int gridID = UNDEFID;
-  int levelID = 0;
-  int tsID, recID, varID;
-  int datatype;
-  int level1, level2;
-  int gridtype;
-  int lbounds = 0;
-  record_t *record;
-  grid_t grid;
-  int vlistID;
-
-  vlistID = streamptr->vlistID;
-  tsID    = streamptr->curTsID;
-  recID   = recordNewEntry(streamptr, tsID);
-  record  = &streamptr->tsteps[tsID].records[recID];
+  int varID = 0;
+  int streamvarSize;
+  svarinfo_t *streamvar;
 
-  if ( IEG_P_LevelType(pdb) == IEG_LTYPE_HYBRID_LAYER )
+  streamvarSize = streamptr->varsAllocated;
+  streamvar     = streamptr->vars;
+  /*
+    Look for a free slot in streamvar.
+    (Create the table the first time through).
+  */
+  if ( ! streamvarSize )
     {
-      level1 = IEG_P_Level1(pdb);
-      level2 = IEG_P_Level2(pdb);
+      int i;
+
+      streamvarSize = 2;
+      streamvar
+        = (svarinfo_t *) Malloc((size_t)streamvarSize * sizeof(svarinfo_t));
+      if ( streamvar == NULL )
+	{
+          Message("streamvarSize = %d", streamvarSize);
+	  SysError("Allocation of svarinfo_t failed");
+	}
+
+      for ( i = 0; i < streamvarSize; i++ )
+	streamvar[i].isUsed = FALSE;
     }
   else
     {
-      level1 = IEG_P_Level2(pdb);
-      level2 = 0;
-      if ( IEG_P_LevelType(pdb) == 100 ) level1 *= 100;
+      while ( varID < streamvarSize )
+	{
+	  if ( ! streamvar[varID].isUsed ) break;
+	  varID++;
+	}
     }
-
-  record->size     = recsize;
-  record->position = position;
-  record->param    = param;
-  record->ilevel   = level1;
-  record->ilevel2  = level2;
-  record->ltype    = IEG_P_LevelType(pdb);
-
-  if ( IEG_G_GridType(gdb) == 0 || IEG_G_GridType(gdb) == 10 )
-    gridtype = GRID_LONLAT;
-  else if ( IEG_G_GridType(gdb) == 4 )
-    gridtype = GRID_GAUSSIAN;
-  else
-    gridtype = GRID_GENERIC;
-
-  memset(&grid, 0, sizeof(grid_t));
-  grid.type  = gridtype;
-  grid.size  = IEG_G_NumLon(gdb)*IEG_G_NumLat(gdb);
-  grid.xsize = IEG_G_NumLon(gdb);
-  grid.ysize = IEG_G_NumLat(gdb);
-  grid.xinc  = 0;
-  grid.yinc  = 0;
-  grid.xdef  = 0;
-
-  int iresfac = IEG_G_ResFac(gdb);
-  if ( iresfac == 0 ) iresfac = 1000;
-  double resfac = 1./(double) iresfac;
-
-  /* if ( IEG_G_FirstLon != 0 || IEG_G_LastLon != 0 ) */
-  {
-    if ( grid.xsize > 1 )
-      {
-	if ( IEG_G_ResFlag(gdb) && IEG_G_LonIncr(gdb) > 0 )
-	  grid.xinc = IEG_G_LonIncr(gdb) * resfac;
-	else
-	  grid.xinc = (IEG_G_LastLon(gdb) - IEG_G_FirstLon(gdb)) * resfac / (grid.xsize - 1);
-
-	/* correct xinc if necessary */
-	if ( IEG_G_FirstLon(gdb) == 0 && IEG_G_LastLon(gdb) > 354000 )
-	  {
-	    double xinc = 360. / grid.xsize;
-            /* FIXME: why not use grid.xinc != xinc as condition? */
-	    if ( fabs(grid.xinc-xinc) > 0.0 )
-	      {
-		grid.xinc = xinc;
-		if ( CDI_Debug ) Message("set xinc to %g", grid.xinc);
-	      }
-	  }
-      }
-    grid.xfirst = IEG_G_FirstLon(gdb) * resfac;
-    grid.xlast  = IEG_G_LastLon(gdb)  * resfac;
-    grid.xdef   = 2;
-  }
-  grid.ydef  = 0;
-  /* if ( IEG_G_FirstLat != 0 || IEG_G_LastLat != 0 ) */
-  {
-    if ( grid.ysize > 1 )
-      {
-	if ( IEG_G_ResFlag(gdb) && IEG_G_LatIncr(gdb) > 0 )
-	  grid.yinc = IEG_G_LatIncr(gdb) * resfac;
-	else
-	  grid.yinc = (IEG_G_LastLat(gdb) - IEG_G_FirstLat(gdb)) * resfac / (grid.ysize - 1);
-      }
-    grid.yfirst = IEG_G_FirstLat(gdb) * resfac;
-    grid.ylast  = IEG_G_LastLat(gdb)  * resfac;
-    grid.ydef   = 2;
-  }
   /*
-  grid.xfirst= IEG_G_FirstLon(gdb) * resfac;
-  grid.xlast = IEG_G_LastLon(gdb) * resfac;
-  grid.xinc  = IEG_G_LonIncr(gdb) * resfac;
-  grid.xdef  = 2;
-  grid.yfirst= IEG_G_FirstLat(gdb) * resfac;
-  grid.ylast = IEG_G_LastLat(gdb) * resfac;
-  grid.yinc  = IEG_G_LatIncr(gdb) * resfac;
-  grid.ydef  = 2;
+    If the table overflows, double its size.
   */
-  grid.xvals = NULL;
-  grid.yvals = NULL;
-
-  grid.isRotated = FALSE;
-  if ( IEG_G_GridType(gdb) == 10 )
+  if ( varID == streamvarSize )
     {
-      grid.isRotated = TRUE;
-      grid.ypole     = - IEG_G_LatSP(gdb) * resfac;
-      grid.xpole     =   IEG_G_LonSP(gdb) * resfac - 180;
-      grid.angle     = 0;
-    }
+      int i;
 
-  gridID = varDefGrid(vlistID, &grid, 0);
+      streamvarSize = 2*streamvarSize;
+      streamvar
+        = (svarinfo_t *) Realloc(streamvar,
+                                 (size_t)streamvarSize * sizeof (svarinfo_t));
+      if ( streamvar == NULL )
+	{
+          Message("streamvarSize = %d", streamvarSize);
+	  SysError("Reallocation of svarinfo_t failed");
+	}
+      varID = streamvarSize/2;
 
-  leveltype = iegGetZaxisType(IEG_P_LevelType(pdb));
+      for ( i = varID; i < streamvarSize; i++ )
+	streamvar[i].isUsed = FALSE;
+    }
 
-  if ( leveltype == ZAXIS_HYBRID )
-    {
-      double tmpvct[100];
-      size_t vctsize = (size_t)IEG_G_NumVCP(gdb);
+  streamptr->varsAllocated = streamvarSize;
+  streamptr->vars          = streamvar;
 
-      for (size_t i = 0; i < vctsize/2; i++ ) tmpvct[i] = vct[i];
-      for (size_t i = 0; i < vctsize/2; i++ ) tmpvct[i+vctsize/2] = vct[i+50];
+  streamvar_init_entry(streamptr, varID);
 
-      varDefVCT(vctsize, tmpvct);
-    }
+  streamptr->vars[varID].isUsed = TRUE;
+  return (varID);
+}
 
-  if ( IEG_P_LevelType(pdb) == IEG_LTYPE_HYBRID_LAYER ) lbounds = 1;
 
-  datatype = iegInqDatatype(prec);
+static void
+allocate_record_table_entry(stream_t *streamptr, int varID, int subID, int nlevs)
+{
+  int *level    = (int *) Malloc((size_t)nlevs * sizeof (int));
+  int *lindex   = (int *) Malloc((size_t)nlevs * sizeof (int));
 
-  varAddRecord(recID, param, gridID, leveltype, lbounds, level1, level2, 0, 0,
-	       datatype, &varID, &levelID, TSTEP_INSTANT, 0, 0, -1,
-               NULL, NULL, NULL, NULL, NULL, NULL);
+  for (int levID = 0; levID < nlevs; levID++ )
+    {
+      level[levID]    = CDI_UNDEFID;
+      lindex[levID]   = levID;
+    }
 
-  record->varID   = (short)varID;
-  record->levelID = (short)levelID;
+  streamptr->vars[varID].recordTable[subID].nlevs    = nlevs;
+  streamptr->vars[varID].recordTable[subID].recordID = level;
+  streamptr->vars[varID].recordTable[subID].lindex   = lindex;
+}
 
-  streamptr->tsteps[tsID].nallrecs++;
-  streamptr->nrecs++;
 
+int stream_new_var(stream_t *streamptr, int gridID, int zaxisID, int tilesetID)
+{
   if ( CDI_Debug )
-    Message("varID = %d gridID = %d levelID = %d",
-	    varID, gridID, levelID);
-}
+    Message("gridID = %d  zaxisID = %d", gridID, zaxisID);
 
-#if 0
-static
-void iegCmpRecord(stream_t *streamptr, int tsID, int recID, off_t position, int param,
-		  int level, int xsize, int ysize)
-{
-  int varID = 0;
-  int levelID = 0;
-  record_t *record;
+  int varID = streamvar_new_entry(streamptr);
+  int nlevs = zaxisInqSize(zaxisID);
 
-  record  = &streamptr->tsteps[tsID].records[recID];
+  streamptr->nvars++;
 
-  if ( param != (*record).param || level != (*record).ilevel )
-    Error("inconsistent timestep");
+  streamptr->vars[varID].gridID  = gridID;
+  streamptr->vars[varID].zaxisID = zaxisID;
 
-  (*record).position = position;
-  /*
-  varID   = (*record).varID;
-  levelID = (*record).levelID;
+  int nsub = 1;
+  if (tilesetID != CDI_UNDEFID)
+    nsub = subtypeInqSize(tilesetID); /* e.g. no of tiles */
+  if ( CDI_Debug )
+    Message("varID %d: create %d tiles with %d level(s), zaxisID=%d", varID, nsub, nlevs,zaxisID);
+  streamptr->vars[varID].recordTable = (sleveltable_t *) Malloc((size_t)nsub * sizeof (sleveltable_t));
+  if( streamptr->vars[varID].recordTable == NULL )
+    SysError("Allocation of leveltable failed!");
+  streamptr->vars[varID].subtypeSize = nsub;
 
-  streamptr->vars[varID].level[levelID] = recID;
+  for (int isub=0; isub<nsub; isub++) {
+    streamvar_init_recordtable(streamptr, varID, isub);
+    allocate_record_table_entry(streamptr, varID, isub, nlevs);
+    if ( CDI_Debug )
+      Message("streamptr->vars[varID].recordTable[isub].recordID[0]=%d",
+              streamptr->vars[varID].recordTable[isub].recordID[0]);
+  }
 
-  streamptr->tsteps[tsID].nallrecs++;
-  streamptr->nrecs++;
-  */
-  if ( CDI_Debug )
-    Message("varID = %d levelID = %d", varID, levelID);
+  streamptr->vars[varID].subtypeID = tilesetID;
+
+  return (varID);
 }
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifdef HAVE_CONFIG_H
 #endif
 
-static void iegDateTime(int *pdb, int *date, int *time)
-{
-  int ryear, rmonth, rday, rhour, rminute;
+#ifdef HAVE_LIBGRIB
 
-  ryear   = IEG_P_Year(pdb);
 
-  rmonth  = IEG_P_Month(pdb);
-  rday    = IEG_P_Day(pdb);
 
-  rhour   = IEG_P_Hour(pdb);
-  rminute = IEG_P_Minute(pdb);
+static
+size_t grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
+		 int date, int time, int tsteptype, int numavg,
+		 size_t datasize, const void *data, int nmiss, void **gribbuffer,
+		 int comptype, void *gribContainer)
+{
+  size_t nbytes = 0;
 
-  if ( rminute == -1 ) rminute = 0;
+#ifdef HAVE_LIBCGRIBEX
+  if ( filetype == FILETYPE_GRB )
+    {
+      size_t gribbuffersize = datasize*4+3000;
+      *gribbuffer = Malloc(gribbuffersize);
 
-  *date = cdiEncodeDate(ryear, rmonth, rday);
-  *time = cdiEncodeTime(rhour, rminute, 0);
+      nbytes = cgribexEncode(memtype, varID, levelID, vlistID, gridID, zaxisID,
+			     date, time, tsteptype, numavg,
+			     (long) datasize, data, nmiss, *gribbuffer, gribbuffersize);
+    }
+  else
+#endif
+#ifdef HAVE_LIBGRIB_API
+    {
+      const void *datap = data;
+      if ( memtype == MEMTYPE_FLOAT )
+        {
+          const float *dataf = (const float*) data;
+          double *datad = (double*) Malloc(datasize*sizeof(double));
+          for ( size_t i = 0; i < datasize; ++i ) datad[i] = (double) dataf[i];
+          datap = (const void*) datad;
+        }
+
+      size_t gribbuffersize;
+      nbytes = gribapiEncode(varID, levelID, vlistID, gridID, zaxisID,
+			     date, time, tsteptype, numavg,
+			     (long) datasize, datap, nmiss, gribbuffer, &gribbuffersize,
+			     comptype, gribContainer);
+      
+      if ( memtype == MEMTYPE_FLOAT ) free((void*)datap);
+    }
+#else
+    {
+      Error("GRIB_API support not compiled in!");
+      (void)gribContainer;
+      (void)comptype;
+    }
+#endif
+
+  return nbytes;
 }
 
 static
-void iegScanTimestep1(stream_t *streamptr)
+size_t grbSzip(int filetype, void *gribbuffer, size_t gribbuffersize)
 {
-  int prec = 0;
-  int status;
-  int fileID;
-  int tabnum;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  DateTime datetime0 = { LONG_MIN, LONG_MIN };
-  int tsID;
-  int varID;
-  size_t recsize;
-  off_t recpos;
-  int nrecords, nrecs, recID;
-  int taxisID = -1;
-  taxis_t *taxis;
-  int vlistID;
-  IEGCOMPVAR compVar, compVar0;
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+  size_t buffersize = gribbuffersize + 1000; /* compressed record can be greater than source record */
+  void *buffer = Malloc(buffersize);
 
-  streamptr->curTsID = 0;
-
-  tsID  = tstepsNewEntry(streamptr);
-  taxis = &streamptr->tsteps[tsID].taxis;
-
-  if ( tsID != 0 )
-    Error("Internal problem! tstepsNewEntry returns %d", tsID);
-
-  fileID = streamptr->fileID;
+  /*  memcpy(buffer, gribbuffer, gribbuffersize); */
 
-  nrecs = 0;
-  while ( TRUE )
+  size_t nbytes = 0;
+  if ( filetype == FILETYPE_GRB )
     {
-      recpos = fileGetPos(fileID);
-      status = iegRead(fileID, iegp);
-      if ( status != 0 )
-	{
-	  streamptr->ntsteps = 1;
-	  break;
-	}
-      recsize = (size_t)(fileGetPos(fileID) - recpos);
+      nbytes = (size_t)gribZip((unsigned char *)gribbuffer, (long) gribbuffersize, (unsigned char *)buffer, (long) buffersize);
+    }
+  else
+    {
+      static int lszip_warn = 1;
+      if ( lszip_warn ) Warning("Szip compression of GRIB2 records not implemented!");
+      lszip_warn = 0;
+      nbytes = gribbuffersize;
+    }
 
-      prec   = iegp->dprec;
-      rcode  = IEG_P_Parameter(iegp->ipdb);
-      tabnum = IEG_P_CodeTable(iegp->ipdb);
-      param  = cdiEncodeParam(rcode, tabnum, 255);
+  Free(buffer);
 
-      if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
-	rlevel = IEG_P_Level1(iegp->ipdb);
-      else
-	rlevel = IEG_P_Level2(iegp->ipdb);
+  return nbytes;
+}
 
-      if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
 
-      iegDateTime(iegp->ipdb, &vdate, &vtime);
+void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
+{
+  int filetype = streamptr1->filetype;
+  int fileID1 = streamptr1->fileID;
+  int fileID2 = streamptr2->fileID;
+  int tsID    = streamptr1->curTsID;
+  int vrecID  = streamptr1->tsteps[tsID].curRecID;
+  int recID   = streamptr1->tsteps[tsID].recIDs[vrecID];
+  off_t recpos  = streamptr1->tsteps[tsID].records[recID].position;
+  size_t recsize = streamptr1->tsteps[tsID].records[recID].size;
 
-      if ( nrecs == 0 )
-	{
-	  datetime0.date = vdate;
-	  datetime0.time = vtime;
-	}
-      else
-	{
-	  compVar.param = param;
-          compVar.level = rlevel;
-	  for ( recID = 0; recID < nrecs; recID++ )
-	    {
-	      compVar0.param = streamptr->tsteps[0].records[recID].param;
-	      compVar0.level = streamptr->tsteps[0].records[recID].ilevel;
+  fileSetPos(fileID1, recpos, SEEK_SET);
 
-	      if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) == 0 ) break;
-	    }
-	  if ( recID < nrecs ) break;
-	  DateTime datetime = { .date = vdate, .time = vtime};
-	  if ( datetimeCmp(datetime, datetime0) )
-	    Warning("Inconsistent verification time for param %d level %d", param, rlevel);
-	}
+  /* round up recsize to next multiple of 8 */
+  size_t gribbuffersize = ((recsize + 7U) & ~7U);
 
-      nrecs++;
+  unsigned char *gribbuffer = (unsigned char *) Malloc(gribbuffersize);
 
-      if ( CDI_Debug )
-	Message("%4d%8d%4d%8d%8d%6d", nrecs, (int)recpos, param, rlevel, vdate, vtime);
+  if (fileRead(fileID1, gribbuffer, recsize) != recsize)
+    Error("Could not read GRIB record for copying!");
 
-      iegAddRecord(streamptr, param, iegp->ipdb, iegp->igdb, iegp->vct, recsize, recpos, prec);
+  size_t nbytes = recsize;
+
+  if ( filetype == FILETYPE_GRB )
+    {
+      long unzipsize;
+      int izip = gribGetZip((long)recsize, gribbuffer, &unzipsize);
+
+      if ( izip == 0 && streamptr2->comptype == COMPRESS_SZIP )
+          nbytes = grbSzip(filetype, gribbuffer, nbytes);
     }
 
-  streamptr->rtsteps = 1;
+  while ( nbytes & 7 ) gribbuffer[nbytes++] = 0;
 
-  cdi_generate_vars(streamptr);
+  size_t nwrite = fileWrite(fileID2, gribbuffer, nbytes);
+  if ( nwrite != nbytes )
+    {
+      perror(__func__);
+      Error("Could not write record for copying!");
+    }
 
-  taxisID = taxisCreate(TAXIS_ABSOLUTE);
-  taxis->type  = TAXIS_ABSOLUTE;
-  taxis->vdate = (int)datetime0.date;
-  taxis->vtime = (int)datetime0.time;
+  Free(gribbuffer);
+}
 
-  vlistID = streamptr->vlistID;
-  vlistDefTaxis(vlistID, taxisID);
 
-  vlist_check_contents(vlistID);
+void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
+{
+  void *gribbuffer = NULL;
+  void *gc = NULL;
 
-  nrecords = streamptr->tsteps[0].nallrecs;
-  if ( nrecords < streamptr->tsteps[0].recordSize )
+  int filetype  = streamptr->filetype;
+  int fileID    = streamptr->fileID;
+  int vlistID   = streamptr->vlistID;
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  int comptype  = streamptr->comptype;
+  int tsID      = streamptr->curTsID;
+  int date      = streamptr->tsteps[tsID].taxis.vdate;
+  int time      = streamptr->tsteps[tsID].taxis.vtime;
+  int numavg    = 0;
+  if ( vlistInqVarTimave(vlistID, varID) )
+    numavg = streamptr->tsteps[tsID].taxis.numavg;
+
+  if ( CDI_Debug )
+    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
+
+  size_t datasize = (size_t)gridInqSize(gridID);
+
+#ifdef HAVE_LIBCGRIBEX
+  if ( filetype == FILETYPE_GRB )
     {
-      streamptr->tsteps[0].recordSize = nrecords;
-      streamptr->tsteps[0].records =
-	(record_t *) Realloc(streamptr->tsteps[0].records,
-                             (size_t)nrecords * sizeof (record_t));
+    }
+  else
+#endif
+    {
+#ifdef GRIBCONTAINER2D
+      gribContainer_t **gribContainers =  (gribContainer_t **) streamptr->gribContainers;
+      gc = (void *) &gribContainers[varID][levelID];
+#else
+      gribContainer_t *gribContainers =  (gribContainer_t *) streamptr->gribContainers;
+      gc = (void *) &gribContainers[varID];
+#endif
     }
 
-  streamptr->tsteps[0].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
-  streamptr->tsteps[0].nrecs = nrecords;
-  for ( recID = 0; recID < nrecords; recID++ )
-    streamptr->tsteps[0].recIDs[recID] = recID;
+  if ( comptype != COMPRESS_JPEG && comptype != COMPRESS_SZIP ) comptype = COMPRESS_NONE;
 
-  if ( streamptr->ntsteps == -1 )
+  if ( filetype == FILETYPE_GRB && comptype == COMPRESS_JPEG )
     {
-      tsID = tstepsNewEntry(streamptr);
-      if ( tsID != streamptr->rtsteps )
-	Error("Internal error. tsID = %d", tsID);
-
-      streamptr->tsteps[tsID-1].next   = TRUE;
-      streamptr->tsteps[tsID].position = recpos;
+      static int ljpeg_warn = 1;
+      if ( ljpeg_warn ) Warning("JPEG compression of GRIB1 records not available!");
+      ljpeg_warn = 0;
     }
 
-  if ( streamptr->ntsteps == 1 )
+  size_t nbytes = grbEncode(filetype, memtype, varID, levelID, vlistID, gridID, zaxisID, date, time, tsteptype, numavg,
+                            datasize, data, nmiss, &gribbuffer, comptype, gc);
+
+  if ( filetype == FILETYPE_GRB && streamptr->comptype == COMPRESS_SZIP )
+    nbytes = grbSzip(filetype, gribbuffer, nbytes);
+
+  size_t (*myFileWrite)(int fileID, const void *restrict buffer,
+                        size_t len, int tsID)
+    = (size_t (*)(int, const void *restrict, size_t, int))
+    namespaceSwitchGet(NSSWITCH_FILE_WRITE).func;
+  size_t nwrite = myFileWrite(fileID, gribbuffer, nbytes, tsID);
+
+  if ( nwrite != nbytes )
     {
-      if ( taxis->vdate == 0 && taxis->vtime == 0 )
-	{
-	  streamptr->ntsteps = 0;
-	  for ( varID = 0; varID < streamptr->nvars; varID++ )
-	    {
-	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-	    }
-	}
+      perror(__func__);
+      Error("Failed to write GRIB slice!");
     }
+
+  if ( gribbuffer ) Free(gribbuffer);
 }
 
-static
-int iegScanTimestep2(stream_t *streamptr)
+
+void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
 {
-  int status;
-  int fileID;
-  int tabnum;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  int tsID;
-  int varID;
-  size_t recsize;
-  off_t recpos = 0;
-  int nrecords, nrecs, recID, rindex;
-  int nextstep;
-  taxis_t *taxis;
-  int vlistID;
-  IEGCOMPVAR compVar, compVar0;
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+  int vlistID  = streamptr->vlistID,
+    gridID   = vlistInqVarGrid(vlistID, varID),
+    gridsize = gridInqSize(gridID),
+    zaxisID  = vlistInqVarZaxis(vlistID, varID),
+    nlevs    = zaxisInqSize(zaxisID);
+  double missval = vlistInqVarMissval(vlistID, varID);
 
-  streamptr->curTsID = 1;
+  size_t chunkLen = (size_t)gridsize;
+  if ( memtype == MEMTYPE_FLOAT )
+    for ( int levelID = 0; levelID < nlevs; levelID++ )
+      {
+        const float *restrict fdata = ((const float *)data)+levelID*gridsize;
+        
+        int nmiss_slice = 0;
+        if ( nmiss )
+          for ( size_t i = 0; i < chunkLen; ++i )
+            nmiss_slice += DBL_IS_EQUAL(fdata[i], missval);
+
+        grb_write_var_slice(streamptr, varID, levelID, memtype, fdata, nmiss_slice);
+      }
+  else
+    for ( int levelID = 0; levelID < nlevs; levelID++ )
+      {
+        const double *restrict ddata = ((const double *)data)+levelID*gridsize;
+        
+        int nmiss_slice = 0;
+        if ( nmiss )
+          for ( size_t i = 0; i < chunkLen; ++i )
+            nmiss_slice += DBL_IS_EQUAL(ddata[i], missval);
+
+        grb_write_var_slice(streamptr, varID, levelID, memtype, ddata, nmiss_slice);
+      }
+}
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
 
-  tsID = streamptr->rtsteps;
-  if ( tsID != 1 )
-    Error("Internal problem! unexpected timestep %d", tsID+1);
+void grb_write_record(stream_t * streamptr, int memtype, const void *data, int nmiss)
+{
+  int varID   = streamptr->record->varID;
+  int levelID = streamptr->record->levelID;
 
-  taxis = &streamptr->tsteps[tsID].taxis;
+  grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+}
 
-  fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+#endif
+#ifdef HAVE_CONFIG_H
+#endif
 
-  cdi_create_records(streamptr, tsID);
+#ifdef HAVE_LIBGRIB
 
-  nrecords = streamptr->tsteps[0].nallrecs;
-  streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords * sizeof(int));
-  streamptr->tsteps[1].nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
-    streamptr->tsteps[1].recIDs[recID] = -1;
 
-  for ( recID = 0; recID < nrecords; recID++ )
+
+static
+int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *data, size_t datasize,
+	      int unreduced, int *nmiss, double missval, int vlistID, int varID)
+{
+  int status = 0;
+
+#if  defined  (HAVE_LIBCGRIBEX)
+  if ( filetype == FILETYPE_GRB )
     {
-      varID = streamptr->tsteps[0].records[recID].varID;
-      streamptr->tsteps[tsID].records[recID].position =
-	streamptr->tsteps[0].records[recID].position;
-      streamptr->tsteps[tsID].records[recID].size     =
-	streamptr->tsteps[0].records[recID].size;
+#if  defined  (HAVE_LIBGRIB_API)
+      extern int cdiNAdditionalGRIBKeys;
+      if ( cdiNAdditionalGRIBKeys > 0 )
+	Error("CGRIBEX decode does not support reading of additional GRIB keys!");
+#endif
+      status = cgribexDecode(memtype, gribbuffer, gribsize, data, (long) datasize, unreduced, nmiss, missval);
     }
-
-  for ( rindex = 0; rindex <= nrecords; rindex++ )
+  else
+#endif
+#ifdef HAVE_LIBGRIB_API
     {
-      recpos = fileGetPos(fileID);
-      status = iegRead(fileID, iegp);
-      if ( status != 0 )
-	{
-	  streamptr->ntsteps = 2;
-	  break;
-	}
-      recsize = (size_t)(fileGetPos(fileID) - recpos);
+      void *datap = data;
+      if ( memtype == MEMTYPE_FLOAT )
+        datap = Malloc(datasize*sizeof(double));
 
-      rcode  = IEG_P_Parameter(iegp->ipdb);
-      tabnum = IEG_P_CodeTable(iegp->ipdb);
-      param  = cdiEncodeParam(rcode, tabnum, 255);
+      status = gribapiDecode(gribbuffer, gribsize, datap, (long) datasize, unreduced, nmiss, missval, vlistID, varID);
 
-      if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
-	rlevel = IEG_P_Level1(iegp->ipdb);
-      else
-	rlevel = IEG_P_Level2(iegp->ipdb);
+      if ( memtype == MEMTYPE_FLOAT )
+        {
+          float *dataf = (float*) data;
+          double *datad = (double*) datap;
+          for ( size_t i = 0; i < datasize; ++i ) dataf[i] = (float) datad[i];
+          free((void*)datap);
+        }
+    }
+#else
+    {
+      (void)vlistID; (void)varID;
+      Error("GRIB_API support not compiled in!");
+    }
+#endif
 
-      if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
+  return status;
+}
 
-      iegDateTime(iegp->ipdb, &vdate, &vtime);
+static
+int grbUnzipRecord(void *gribbuffer, size_t *gribsize)
+{
+  int zip = 0;
+  int izip;
+  long unzipsize;
 
-      if ( rindex == 0 )
-	{
-	  taxis->type  = TAXIS_ABSOLUTE;
-	  taxis->vdate = vdate;
-	  taxis->vtime = vtime;
-	}
+  size_t igribsize = *gribsize;
+  size_t ogribsize = *gribsize;
 
-      compVar.param = param;
-      compVar.level = rlevel;
-      nextstep = FALSE;
-      for ( recID = 0; recID < nrecords; recID++ )
+  if ( (izip = gribGetZip((long)igribsize, (unsigned char *)gribbuffer, &unzipsize)) > 0 )
+    {
+      zip = izip;
+      if ( izip == 128 ) /* szip */
 	{
-	  compVar0.param = streamptr->tsteps[tsID].records[recID].param;
-	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+	  unsigned char *itmpbuffer = NULL;
+	  size_t itmpbuffersize = 0;
 
-	  if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) == 0 )
+	  if ( unzipsize < (long) igribsize )
 	    {
-	      if ( streamptr->tsteps[tsID].records[recID].used )
-		{
-		  nextstep = TRUE;
-		}
-	      else
-		{
-		  streamptr->tsteps[tsID].records[recID].used = TRUE;
-		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
-		}
-	      break;
+	      fprintf(stderr, "Decompressed size smaller than compressed size (in %ld; out %ld)!\n", (long)igribsize, unzipsize);
+	      return (0);
 	    }
-	}
-      if ( recID == nrecords )
-	{
-	  char paramstr[32];
-	  cdiParamToString(param, paramstr, sizeof(paramstr));
-	  Warning("param %s level %d not defined at timestep 1", paramstr, rlevel);
-	  return (CDI_EUFSTRUCT);
-	}
-
-      if ( nextstep ) break;
 
-      if ( CDI_Debug )
-	Message("%4d%8d%4d%8d%8d%6d", rindex+1, (int)recpos, param, rlevel, vdate, vtime);
+	  if ( itmpbuffersize < igribsize )
+	    {
+	      itmpbuffersize = igribsize;
+	      itmpbuffer = (unsigned char *) Realloc(itmpbuffer, itmpbuffersize);
+	    }
 
-      streamptr->tsteps[tsID].records[recID].size = recsize;
+	  memcpy(itmpbuffer, gribbuffer, itmpbuffersize);
 
-      compVar0.param = streamptr->tsteps[tsID].records[recID].param;
-      compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
 
-      if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) != 0 )
-	{
-	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
-		  tsID, recID,
-		  streamptr->tsteps[tsID].records[recID].param, param,
-		  streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
-	  return (CDI_EUFSTRUCT);
-	}
+	  ogribsize = (size_t)gribUnzip((unsigned char *)gribbuffer, unzipsize, itmpbuffer, (long)igribsize);
 
-      streamptr->tsteps[1].records[recID].position = recpos;
-    }
+	  Free(itmpbuffer);
 
-  nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
-    {
-      if ( ! streamptr->tsteps[tsID].records[recID].used )
-	{
-	  varID = streamptr->tsteps[tsID].records[recID].varID;
-          vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	  if ( ogribsize <= 0 ) Error("Decompression problem!");
 	}
       else
 	{
-	  nrecs++;
+	  Error("Decompression for %d not implemented!", izip);
 	}
     }
-  streamptr->tsteps[tsID].nrecs = nrecs;
-
-  streamptr->rtsteps = 2;
-
-  if ( streamptr->ntsteps == -1 )
-    {
-      tsID = tstepsNewEntry(streamptr);
-      if ( tsID != streamptr->rtsteps )
-	Error("Internal error. tsID = %d", tsID);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
-      streamptr->tsteps[tsID].position = recpos;
-    }
+  *gribsize = ogribsize;
 
-  return (0);
+  return zip;
 }
 
 
-int iegInqContents(stream_t *streamptr)
+void grb_read_record(stream_t * streamptr, int memtype, void *data, int *nmiss)
 {
-  int fileID;
-  int status = 0;
+  int filetype = streamptr->filetype;
 
-  fileID = streamptr->fileID;
+  void *gribbuffer = streamptr->record->buffer;
 
-  streamptr->curTsID = 0;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+  int tsID    = streamptr->curTsID;
+  int vrecID  = streamptr->tsteps[tsID].curRecID;
+  int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
+  off_t recpos  = streamptr->tsteps[tsID].records[recID].position;
+  size_t recsize = streamptr->tsteps[tsID].records[recID].size;
+  int varID   = streamptr->tsteps[tsID].records[recID].varID;
 
-  iegScanTimestep1(streamptr);
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int gridsize = gridInqSize(gridID);
 
-  if ( streamptr->ntsteps == -1 ) status = iegScanTimestep2(streamptr);
+  streamptr->numvals += gridsize;
 
-  fileSetPos(fileID, 0, SEEK_SET);
+  fileSetPos(fileID, recpos, SEEK_SET);
 
-  return (status);
+  if (fileRead(fileID, gribbuffer, recsize) != recsize)
+    Error("Failed to read GRIB record");
+
+  double missval = vlistInqVarMissval(vlistID, varID);
+
+  streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
+
+  grbDecode(filetype, memtype, gribbuffer, (int)recsize, data, (size_t)gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
 }
 
-static
-long iegScanTimestep(stream_t *streamptr)
+
+void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int *nmiss)
 {
-  int status;
-  int fileID;
-  int tsID;
-  int tabnum;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  size_t recsize = 0;
-  off_t recpos = 0;
-  int recID;
-  taxis_t *taxis;
-  int rindex, nrecs = 0;
-  IEGCOMPVAR compVar, compVar0;
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+  int filetype = streamptr->filetype;
+
+  void *gribbuffer = streamptr->record->buffer;
+
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+  int tsID    = streamptr->curTsID;
+
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int gridsize = gridInqSize(gridID);
+
+  off_t currentfilepos = fileGetPos(fileID);
 
+  int isub     = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
+  int nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
   if ( CDI_Debug )
+    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+  *nmiss = 0;
+  for (int levelID = 0; levelID < nlevs; levelID++ )
     {
-      Message("streamID = %d", streamptr->self);
-      Message("cts = %d", streamptr->curTsID);
-      Message("rts = %d", streamptr->rtsteps);
-      Message("nts = %d", streamptr->ntsteps);
+      int    recID   = streamptr->vars[varID].recordTable[isub].recordID[levelID];
+      off_t  recpos  = streamptr->tsteps[tsID].records[recID].position;
+      size_t recsize = streamptr->tsteps[tsID].records[recID].size;
+
+      fileSetPos(fileID, recpos, SEEK_SET);
+
+      fileRead(fileID, gribbuffer, recsize);
+
+      double missval = vlistInqVarMissval(vlistID, varID);
+
+      int imiss;
+
+      streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
+
+      void *datap = NULL;
+      if ( memtype == MEMTYPE_FLOAT )
+        datap = (float*)data + levelID*gridsize;
+      else
+        datap = (double*)data + levelID*gridsize;
+
+      grbDecode(filetype, memtype, gribbuffer, (int)recsize, datap, (size_t)gridsize,
+                streamptr->unreduced, &imiss, missval, vlistID, varID);
+
+      *nmiss += imiss;
     }
 
-  if ( streamptr->rtsteps == 0 )
-    Error("Internal problem! Missing contents.");
+  fileSetPos(fileID, currentfilepos, SEEK_SET);
+}
 
-  tsID  = streamptr->rtsteps;
-  taxis = &streamptr->tsteps[tsID].taxis;
 
-  if ( streamptr->tsteps[tsID].recordSize == 0 )
-    {
-      cdi_create_records(streamptr, tsID);
+void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss)
+{
+  int filetype = streamptr->filetype;
 
-      nrecs = streamptr->tsteps[1].nrecs;
+  void *gribbuffer = streamptr->record->buffer;
 
-      streamptr->tsteps[tsID].nrecs = nrecs;
-      streamptr->tsteps[tsID].recIDs
-        = (int *) Malloc((size_t)nrecs * sizeof (int));
-      for ( recID = 0; recID < nrecs; recID++ )
-	streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
+  int vlistID = streamptr->vlistID;
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int gridsize = gridInqSize(gridID);
+  int tsID = streamptr->curTsID;
 
-      fileID = streamptr->fileID;
+  if ( CDI_Debug )
+    Message("gridID = %d gridsize = %d", gridID, gridsize);
 
-      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
+  int fileID = streamptr->fileID;
 
-      for ( rindex = 0; rindex <= nrecs; rindex++ )
-	{
-	  recpos = fileGetPos(fileID);
-	  status = iegRead(fileID, iegp);
-	  if ( status != 0 )
-	    {
-	      streamptr->ntsteps = streamptr->rtsteps + 1;
-	      break;
-	    }
-	  recsize = (size_t)(fileGetPos(fileID) - recpos);
+  off_t currentfilepos = fileGetPos(fileID);
 
-	  rcode  = IEG_P_Parameter(iegp->ipdb);
-	  tabnum = IEG_P_CodeTable(iegp->ipdb);
-	  param  = cdiEncodeParam(rcode, tabnum, 255);
+  int    isub    = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
 
-	  if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
-	    rlevel = IEG_P_Level1(iegp->ipdb);
-	  else
-	    rlevel = IEG_P_Level2(iegp->ipdb);
+  int    recID   = streamptr->vars[varID].recordTable[isub].recordID[levelID];
+  off_t  recpos  = streamptr->tsteps[tsID].records[recID].position;
+  size_t recsize = streamptr->tsteps[tsID].records[recID].size;
 
-	  if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
+  if ( recsize == 0 )
+    Error("Internal problem! Recordsize is zero for record %d at timestep %d",
+	  recID+1, tsID+1);
 
-	  iegDateTime(iegp->ipdb, &vdate, &vtime);
+  fileSetPos(fileID, recpos, SEEK_SET);
+  fileRead(fileID, gribbuffer, recsize);
 
-	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
-	  if ( rindex == nrecs ) continue;
-	  recID = streamptr->tsteps[tsID].recIDs[rindex];
+  streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
 
-	  if ( rindex == 0 )
-	    {
-	      taxis->type  = TAXIS_ABSOLUTE;
-	      taxis->vdate = vdate;
-	      taxis->vtime = vtime;
-	    }
+  double missval = vlistInqVarMissval(vlistID, varID);
+  grbDecode(filetype, memtype, gribbuffer, (int)recsize, data, (size_t)gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
 
-	  compVar.param = param;
-          compVar.level = rlevel;
-	  compVar0.param = streamptr->tsteps[tsID].records[recID].param;
-	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+  fileSetPos(fileID, currentfilepos, SEEK_SET);
+}
 
-	  if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) != 0 )
-	    {
-	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
-		      tsID, recID,
-		      streamptr->tsteps[tsID].records[recID].param, param,
-		      streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
-	      Error("Invalid, unsupported or inconsistent record structure");
-	    }
+#endif
+#ifdef HAVE_CONFIG_H
+#endif
 
-	  streamptr->tsteps[tsID].records[recID].position = recpos;
-	  streamptr->tsteps[tsID].records[recID].size = recsize;
+#ifdef HAVE_LIBNETCDF
 
-	  if ( CDI_Debug )
-	    Message("%4d%8d%4d%8d%8d%6d", rindex, (int)recpos, param, rlevel, vdate, vtime);
-	}
 
-      streamptr->rtsteps++;
 
-      if ( streamptr->ntsteps != streamptr->rtsteps )
-	{
-	  tsID = tstepsNewEntry(streamptr);
-	  if ( tsID != streamptr->rtsteps )
-	    Error("Internal error. tsID = %d", tsID);
+#undef  UNDEFID
+#define UNDEFID  CDI_UNDEFID
 
-	  streamptr->tsteps[tsID-1].next   = 1;
-	  streamptr->tsteps[tsID].position = recpos;
-	}
 
-      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
-      streamptr->tsteps[tsID].position = recpos;
+void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level)
+{
+#if  defined  (HAVE_NETCDF4)
+  int retval;
+  /* Set chunking, shuffle, and deflate. */
+  int shuffle = 1;
+  int deflate = 1;
+
+  if ( deflate_level < 1 || deflate_level > 9 ) deflate_level = 1;
+
+  if ((retval = nc_def_var_deflate(ncid, ncvarid, shuffle, deflate, deflate_level)))
+    {
+      Error("nc_def_var_deflate failed, status = %d", retval);
     }
-
-  if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
+#else
+  
+  static int lwarn = TRUE;
+  if ( lwarn )
     {
-      Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
-      streamptr->ntsteps = tsID;
+      lwarn = FALSE;
+      Warning("Deflate compression failed, NetCDF4 not available!");
     }
-
-  return (streamptr->ntsteps);
+#endif
 }
 
-
-int iegInqTimestep(stream_t *streamptr, int tsID)
+static
+int cdfDefDatatype(int datatype, int filetype)
 {
-  int nrecs;
-
-  if ( tsID == 0 && streamptr->rtsteps == 0 )
-    Error("Call to cdiInqContents missing!");
+  int xtype = NC_FLOAT;
 
-  if ( CDI_Debug )
-    Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
-
-  long ntsteps = UNDEFID;
-  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == UNDEFID )
-    ntsteps = iegScanTimestep(streamptr);
+  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
+    Error("CDI/NetCDF library does not support complex numbers!");
 
-  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
+  if ( filetype == FILETYPE_NC4 )
     {
-      nrecs = 0;
+      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
+      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
+      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
+#if  defined  (HAVE_NETCDF4)
+      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_UBYTE;
+      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_USHORT;
+      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_UINT;
+#else
+      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
+      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
+      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
+#endif
+      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
+      else                                    xtype = NC_FLOAT;
     }
   else
     {
-      streamptr->curTsID = tsID;
-      nrecs = streamptr->tsteps[tsID].nrecs;
+      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
+      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
+      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
+      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
+      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
+      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
+      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
+      else                                    xtype = NC_FLOAT;
     }
 
-  return (nrecs);
+  return xtype;
 }
 
-
-void iegReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+static
+void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
 {
-  int vlistID, fileID;
-  int levID, nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int tsid;
-  int recID;
-  int i;
-  double missval;
-  void *iegp = streamptr->record->exsep;
+  if ( streamptr->vars[varID].defmiss == FALSE )
+    {
+      int vlistID = streamptr->vlistID;
+      int fileID  = streamptr->fileID;
+      int ncvarid = streamptr->vars[varID].ncvarid;
+      double missval = vlistInqVarMissval(vlistID, varID);
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
+      if ( lcheck && streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+      int xtype = cdfDefDatatype(dtype, streamptr->filetype);
 
-  currentfilepos = fileGetPos(fileID);
+      if ( xtype == NC_BYTE && missval > 127 && missval < 256 ) xtype = NC_INT;
 
-  for (levID = 0; levID < nlevs; levID++)
-    {
-      /* NOTE: tiles are not supported here! */
-      recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-      recpos = streamptr->tsteps[tsid].records[recID].position;
-      fileSetPos(fileID, recpos, SEEK_SET);
-      iegRead(fileID, iegp);
-      iegInqDataDP(iegp, &data[levID*gridsize]);
-    }
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
+      cdf_put_att_double(fileID, ncvarid, "_FillValue", (nc_type) xtype, 1, &missval);
+      cdf_put_att_double(fileID, ncvarid, "missing_value", (nc_type) xtype, 1, &missval);
 
-  *nmiss = 0;
-  for ( i = 0; i < nlevs*gridsize; i++ )
-    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-      {
-	data[i] = missval;
-	(*nmiss)++;
-      }
-}
+      if ( lcheck && streamptr->ncmode == 2 ) cdf_enddef(fileID);
 
+      streamptr->vars[varID].defmiss = TRUE;
+    }
+}
 
-void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
+static
+void cdfDefInstitut(stream_t *streamptr)
 {
-  int vlistID, fileID;
-  int nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int tsid;
-  int recID;
-  int i;
-  double missval;
-  void *iegp = streamptr->record->exsep;
-
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
-
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d",
-	     nlevs, gridID, gridsize);
-
-  currentfilepos = fileGetPos(fileID);
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+  int instID  = vlistInqInstitut(vlistID);
 
-  /* NOTE: tiles are not supported here! */
-  recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-  recpos = streamptr->tsteps[tsid].records[recID].position;
-  fileSetPos(fileID, recpos, SEEK_SET);
-  iegRead(fileID, iegp);
-  iegInqDataDP(iegp, data);
+  if ( instID != UNDEFID )
+    {
+      const char *longname = institutInqLongnamePtr(instID);
+      if ( longname )
+	{
+	  size_t len = strlen(longname);
+	  if ( len > 0 )
+	    {
+	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+	      cdf_put_att_text(fileID, NC_GLOBAL, "institution", len, longname);
+	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
+	    }
+	}
+    }
+}
 
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
+static
+void cdfDefSource(stream_t *streamptr)
+{
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+  int modelID = vlistInqModel(vlistID);
 
-  *nmiss = 0;
-  for ( i = 0; i < gridsize; i++ )
-    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-      {
-	data[i] = missval;
-	(*nmiss)++;
-      }
+  if ( modelID != UNDEFID )
+    {
+      const char *longname = modelInqNamePtr(modelID);
+      if ( longname )
+	{
+          size_t len = strlen(longname);
+	  if ( len > 0 )
+	    {
+	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+	      cdf_put_att_text(fileID, NC_GLOBAL, "source", len, longname);
+	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
+	    }
+	}
+    }
 }
 
+static inline
+void *resizeBuf(void **buf, size_t *bufSize, size_t reqSize)
+{
+  if (reqSize > *bufSize)
+    {
+      *buf = Realloc(*buf, reqSize);
+      *bufSize = reqSize;
+    }
+  return *buf;
+}
 
-void iegWriteVarDP(stream_t *streamptr, int varID, const double *data)
+static
+void cdfDefineAttributes(int vlistID, int varID, int fileID, int ncvarID)
 {
-  int fileID;
-  int levID, nlevs, gridID, gridsize;
-  int zaxisID;
-  int datatype;
-  int tsID;
-  int vlistID;
-  int i;
-  int date, time;
-  int param, pdis, pcat, pnum;
-  double refval;
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+  int atttype, attlen;
+  size_t len;
+  char attname[CDI_MAX_NAME+1];
+  void *attBuf = NULL;
+  size_t attBufSize = 0;
 
-  if ( CDI_Debug )
-    Message("streamID = %d  varID = %d", streamptr->self, varID);
+  int natts;
+  vlistInqNatts(vlistID, varID, &natts);
 
-  iegInitMem(iegp);
-  for ( i = 0; i < 37; i++ ) iegp->ipdb[i] = -1;
+  for ( int iatt = 0; iatt < natts; iatt++ )
+    {
+      vlistInqAtt(vlistID, varID, iatt, attname, &atttype, &attlen);
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  tsID     = streamptr->curTsID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  nlevs    = zaxisInqSize(zaxisID);
+      if ( attlen == 0 ) continue;
 
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+      if ( atttype == DATATYPE_TXT )
+        {
+          size_t attSize = (size_t)attlen*sizeof(char);
+          char *atttxt = (char *)resizeBuf(&attBuf, &attBufSize, attSize);
+          vlistInqAttTxt(vlistID, varID, attname, attlen, atttxt);
+          len = (size_t)attlen;
+          cdf_put_att_text(fileID, ncvarID, attname, len, atttxt);
+        }
+      else if ( atttype == DATATYPE_INT16 || atttype == DATATYPE_INT32 )
+        {
+          size_t attSize = (size_t)attlen*sizeof(int);
+          int *attint = (int *)resizeBuf(&attBuf, &attBufSize, attSize);
+          vlistInqAttInt(vlistID, varID, attname, attlen, &attint[0]);
+          len = (size_t)attlen;
+          cdf_put_att_int(fileID, ncvarID, attname, atttype == DATATYPE_INT16 ? NC_SHORT : NC_INT, len, attint);
+        }
+      else if ( atttype == DATATYPE_FLT32 || atttype == DATATYPE_FLT64 )
+        {
+          size_t attSize = (size_t)attlen * sizeof(double);
+          double *attflt = (double *)resizeBuf(&attBuf, &attBufSize, attSize);
+          vlistInqAttFlt(vlistID, varID, attname, attlen, attflt);
+          len = (size_t)attlen;
+          if ( atttype == DATATYPE_FLT32 )
+            {
+              float attflt_sp[len];
+              for ( size_t i = 0; i < len; ++i ) attflt_sp[i] = (float)attflt[i];
+              cdf_put_att_float(fileID, ncvarID, attname, NC_FLOAT, len, attflt_sp);
+            }
+          else
+            cdf_put_att_double(fileID, ncvarID, attname, NC_DOUBLE, len, attflt);
+        }
+    }
+  
+  Free(attBuf);
+}
 
-  param    = vlistInqVarParam(vlistID, varID);
-  cdiDecodeParam(param, &pnum, &pcat, &pdis);
-  IEG_P_Parameter(iegp->ipdb) = pnum;
-  if ( pdis == 255 ) IEG_P_CodeTable(iegp->ipdb) = pcat;
-  date     = streamptr->tsteps[tsID].taxis.vdate;
-  time     = streamptr->tsteps[tsID].taxis.vtime;
+static
+void cdfDefGlobalAtts(stream_t *streamptr)
+{
+  if ( streamptr->globalatts ) return;
 
-  iegDefTime(iegp->ipdb, date, time, vlistInqTaxis(vlistID));
-  iegDefGrid(iegp->igdb, gridID);
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  datatype = vlistInqVarDatatype(vlistID, varID);
+  cdfDefSource(streamptr);
+  cdfDefInstitut(streamptr);
 
-  iegp->dprec = iegDefDatatype(datatype);
+  int natts;
+  vlistInqNatts(vlistID, CDI_GLOBAL, &natts);
 
-  for ( levID = 0;  levID < nlevs; levID++ )
-    {
-      iegDefLevel(iegp->ipdb, iegp->igdb, iegp->vct, zaxisID, levID);
+  if ( natts > 0 && streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-      refval = data[0];
-      for ( i = 1; i < gridsize; i++ )
-	if ( data[levID*gridsize+i] < refval ) refval = data[levID*gridsize+i];
+  cdfDefineAttributes(vlistID, CDI_GLOBAL, fileID, NC_GLOBAL);
 
-      iegp->refval = refval;
+  if ( natts > 0 && streamptr->ncmode == 2 ) cdf_enddef(fileID);
 
-      iegDefDataDP(iegp, &data[levID*gridsize]);
-      iegWrite(fileID, iegp);
-    }
+  streamptr->globalatts = 1;
 }
 
-
-void iegWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
+static
+void cdfDefLocalAtts(stream_t *streamptr)
 {
-  int fileID;
-  int gridID;
-  int zaxisID;
-  /* double level; */
-  int datatype;
-  /* int tsID; */
-  int vlistID;
-  /* int param, date, time, datasize; */
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
-
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  /* tsID     = streamptr->curTsID; */
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  (void)levID;
-  /* level    = zaxisInqLevel(zaxisID, levID); */
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  if ( CDI_Debug )
-    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
+  if ( streamptr->localatts ) return;
+  if ( vlistInqInstitut(vlistID) != UNDEFID ) return;
 
-  /* param = vlistInqVarParam(vlistID, varID); */
-  /* date = streamptr->tsteps[tsID].taxis.vdate; */
-  /* time = streamptr->tsteps[tsID].taxis.vtime; */
-  /* datasize = gridInqSize(gridID); */
+  streamptr->localatts = 1;
 
-  datatype = vlistInqVarDatatype(vlistID, varID);
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-  iegp->dprec = iegDefDatatype(datatype);
+  for ( int varID = 0; varID < streamptr->nvars; varID++ )
+    {
+      int instID = vlistInqVarInstitut(vlistID, varID);
+      if ( instID != UNDEFID )
+	{
+          int ncvarid = streamptr->vars[varID].ncvarid;
+  	  const char *name = institutInqNamePtr(instID);
+	  if ( name )
+	    {
+              size_t len = strlen(name);
+	      cdf_put_att_text(fileID, ncvarid, "institution", len, name);
+	    }
+	}
+      }
 
-  iegDefDataDP(iegp, data);
-  iegWrite(fileID, iegp);
+  if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
 }
 
-#endif /* HAVE_LIBIEG */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
-
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
+static
+int cdfDefVar(stream_t *streamptr, int varID)
+{
+  int ncvarid = -1;
+  int xid = UNDEFID, yid = UNDEFID;
+  size_t xsize = 0, ysize = 0;
+  char varname[CDI_MAX_NAME];
+  int dims[4];
+  int lchunk = FALSE;
+  size_t chunks[4] = {0,0,0,0};
+  int ndims = 0;
+  int tablenum;
+  int dimorder[3];
+  size_t iax = 0;
+  char axis[5];
+  int ensID, ensCount, forecast_type;
+  int retval;
 
+  int fileID  = streamptr->fileID;
 
+  if ( CDI_Debug )
+    Message("streamID = %d, fileID = %d, varID = %d", streamptr->self, fileID, varID);
 
+  if ( streamptr->vars[varID].ncvarid != UNDEFID )
+    return streamptr->vars[varID].ncvarid;
 
-void recordInitEntry(record_t *record)
-{
-  record->position = CDI_UNDEFID;
-  record->size     = 0;
-  record->param    = 0;
-  record->ilevel   = CDI_UNDEFID;
-  record->used     = FALSE;
-  record->varID    = CDI_UNDEFID;
-  record->levelID  = CDI_UNDEFID;
-  memset(record->varname, 0, sizeof(record->varname));
-  memset(&record->tiles, 0, sizeof(record->tiles));
-}
+  int vlistID   = streamptr->vlistID;
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  int code      = vlistInqVarCode(vlistID, varID);
+  int param     = vlistInqVarParam(vlistID, varID);
+  int pnum, pcat, pdis;
+  cdiDecodeParam(param, &pnum, &pcat, &pdis);
 
+  int chunktype = vlistInqVarChunkType(vlistID, varID);
 
-int recordNewEntry(stream_t *streamptr, int tsID)
-{
-  size_t recordID = 0;
-  size_t recordSize = (size_t)streamptr->tsteps[tsID].recordSize;
-  record_t *records = streamptr->tsteps[tsID].records;
-  /*
-    Look for a free slot in record.
-    (Create the table the first time through).
-  */
-  if ( ! recordSize )
-    {
-      recordSize = 1;   /*  <<<<----  */
-      records = (record_t *) Malloc(recordSize * sizeof (record_t));
+  vlistInqVarDimorder(vlistID, varID, &dimorder);
 
-      for ( size_t i = 0; i < recordSize; i++ )
-	records[i].used = CDI_UNDEFID;
-    }
-  else
-    {
-      while ( recordID < recordSize
-              && records[recordID].used != CDI_UNDEFID )
-        ++recordID;
-    }
-  /*
-    If the table overflows, double its size.
-  */
-  if ( recordID == recordSize )
+  int gridsize  = gridInqSize(gridID);
+  if ( gridsize > 1 ) lchunk = TRUE;
+  int gridtype  = gridInqType(gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
+  if ( gridtype != GRID_TRAJECTORY )
     {
-      if (recordSize <= INT_MAX / 2)
-        recordSize *= 2;
-      else if (recordSize < INT_MAX)
-        recordSize = INT_MAX;
-      else
-        Error("Cannot handle this many records!\n");
-      records = (record_t *) Realloc(records,
-                                     recordSize * sizeof (record_t));
-
-      for ( size_t i = recordID; i < recordSize; i++ )
-	records[i].used = CDI_UNDEFID;
+      xid = streamptr->xdimID[gridindex];
+      yid = streamptr->ydimID[gridindex];
+      if ( xid != UNDEFID ) cdf_inq_dimlen(fileID, xid, &xsize);
+      if ( yid != UNDEFID ) cdf_inq_dimlen(fileID, yid, &ysize);
     }
 
-  recordInitEntry(&records[recordID]);
-
-  records[recordID].used = 1;
+  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+  int zid = streamptr->zaxisID[zaxisindex];
+  int zaxis_is_scalar = FALSE;
+  if ( zid == UNDEFID ) zaxis_is_scalar = zaxisInqScalar(zaxisID);
 
-  streamptr->tsteps[tsID].recordSize = (int)recordSize;
-  streamptr->tsteps[tsID].records    = records;
+  if ( dimorder[0] != 3 ) lchunk = FALSE; /* ZYX and ZXY */
 
-  return (int)recordID;
-}
+  if ( ((dimorder[0]>0)+(dimorder[1]>0)+(dimorder[2]>0)) < ((xid!=UNDEFID)+(yid!=UNDEFID)+(zid!=UNDEFID)) )
+    {
+      printf("zid=%d  yid=%d  xid=%d\n", zid, yid, xid);
+      Error("Internal problem, dimension order missing!");
+    }
 
-static
-void cdiInitRecord(stream_t *streamptr)
-{
-  streamptr->record = (Record *) Malloc(sizeof(Record));
+  int tid = streamptr->basetime.ncdimid;
 
-  streamptr->record->param      = 0;
-  streamptr->record->level      = 0;
-  streamptr->record->date       = 0;
-  streamptr->record->time       = 0;
-  streamptr->record->gridID     = 0;
-  streamptr->record->buffer     = NULL;
-  streamptr->record->buffersize = 0;
-  streamptr->record->position   = 0;
-  streamptr->record->varID      = 0;
-  streamptr->record->levelID    = CDI_UNDEFID;
-}
+  if ( tsteptype != TSTEP_CONSTANT )
+    {
+      if ( tid == UNDEFID ) Error("Internal problem, time undefined!");
+      chunks[ndims] = 1;
+      dims[ndims++] = tid;
+      axis[iax++] = 'T';
+    }
+  /*
+  if ( zid != UNDEFID ) axis[iax++] = 'Z';
+  if ( zid != UNDEFID ) chunks[ndims] = 1;
+  if ( zid != UNDEFID ) dims[ndims++] = zid;
 
+  if ( yid != UNDEFID ) chunks[ndims] = ysize;
+  if ( yid != UNDEFID ) dims[ndims++] = yid;
 
-void streamInqRecord(int streamID, int *varID, int *levelID)
-{
-  check_parg(varID);
-  check_parg(levelID);
+  if ( xid != UNDEFID ) chunks[ndims] = xsize;
+  if ( xid != UNDEFID ) dims[ndims++] = xid;
+  */
+  for ( int id = 0; id < 3; ++id )
+    {
+      if ( dimorder[id] == 3 && zid != UNDEFID )
+        {
+          axis[iax++] = 'Z';
+          chunks[ndims] = 1;
+          dims[ndims] = zid;
+          ndims++;
+        }
+      else if ( dimorder[id] == 2 && yid != UNDEFID )
+        {
+          if ( chunktype == CHUNK_LINES )
+            chunks[ndims] = 1;
+          else
+            chunks[ndims] = ysize;
+          dims[ndims] = yid;
+          ndims++;
+        }
+      else if ( dimorder[id] == 1 && xid != UNDEFID )
+        {
+          chunks[ndims] = xsize;
+          dims[ndims] = xid;
+          ndims++;
+        }
+    }
 
-  stream_t *streamptr = stream_to_pointer(streamID);
-  stream_check_ptr(__func__, streamptr);
+  if ( CDI_Debug )
+    fprintf(stderr, "chunktype %d  chunks %d %d %d %d\n", chunktype, (int)chunks[0], (int)chunks[1], (int)chunks[2], (int)chunks[3]);
 
-  cdiDefAccesstype(streamID, TYPE_REC);
+  int tableID  = vlistInqVarTable(vlistID, varID);
 
-  if ( ! streamptr->record ) cdiInitRecord(streamptr);
+  const char *name     = vlistInqVarNamePtr(vlistID, varID);
+  const char *longname = vlistInqVarLongnamePtr(vlistID, varID);
+  const char *stdname  = vlistInqVarStdnamePtr(vlistID, varID);
+  const char *units    = vlistInqVarUnitsPtr(vlistID, varID);
 
-  int tsID   = streamptr->curTsID;
-  int rindex = streamptr->tsteps[tsID].curRecID + 1;
+  if ( name     == NULL )     name = tableInqParNamePtr(tableID, code);
+  if ( longname == NULL ) longname = tableInqParLongnamePtr(tableID, code);
+  if ( units    == NULL )    units = tableInqParUnitsPtr(tableID, code);
+  if ( name )
+    {
+      int checkname;
+      int iz;
+      int status;
 
-  if ( rindex >= streamptr->tsteps[tsID].nrecs )
-    Error("record %d not available at timestep %d", rindex+1, tsID+1);
+      sprintf(varname, "%s", name);
 
-  int recID  = streamptr->tsteps[tsID].recIDs[rindex];
+      checkname = TRUE;
+      iz = 0;
 
-  if ( recID == -1 || recID >= streamptr->tsteps[tsID].nallrecs )
-    Error("Internal problem! tsID = %d recID = %d", tsID, recID);
+      while ( checkname )
+        {
+          if ( iz ) sprintf(varname, "%s_%d", name, iz+1);
 
-  *varID   = streamptr->tsteps[tsID].records[recID].varID;
-  int lindex = streamptr->tsteps[tsID].records[recID].levelID;
+          status = nc_inq_varid(fileID, varname, &ncvarid);
+          if ( status != NC_NOERR )
+            {
+              checkname = FALSE;
+            }
 
-  int isub = subtypeInqActiveIndex(streamptr->vars[*varID].subtypeID);
-  *levelID = streamptr->vars[*varID].recordTable[isub].lindex[lindex];
+          if ( checkname ) iz++;
 
-  if ( CDI_Debug )
-    Message("tsID = %d, recID = %d, varID = %d, levelID = %d\n", tsID, recID, *varID, *levelID);
+          if ( iz >= CDI_MAX_NAME ) Error("Double entry of variable name '%s'!", name);
+        }
 
-  streamptr->curTsID = tsID;
-  streamptr->tsteps[tsID].curRecID = rindex;
-}
+      if ( strcmp(name, varname) != 0 )
+        {
+          if ( iz == 1 )
+            Warning("Changed double entry of variable name '%s' to '%s'!", name, varname);
+          else
+            Warning("Changed multiple entry of variable name '%s' to '%s'!", name, varname);
+        }
 
-/*
- at Function  streamDefRecord
- at Title     Define the next record
+      name = varname;
+    }
+  else
+    {
+      if ( code < 0 ) code = -code;
+      if ( pnum < 0 ) pnum = -pnum;
 
- at Prototype void streamDefRecord(int streamID, int varID, int levelID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
+      if ( pdis == 255 )
+	sprintf(varname, "var%d", code);
+      else
+	sprintf(varname, "param%d.%d.%d", pnum, pcat, pdis);
 
- at Description
-The function streamDefRecord defines the meta-data of the next record.
- at EndFunction
-*/
-void streamDefRecord(int streamID, int varID, int levelID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-  stream_check_ptr(__func__, streamptr);
+      char *varname2 = varname+strlen(varname);
 
-  int tsID = streamptr->curTsID;
+      int checkname = TRUE;
+      int iz = 0;
 
-  if ( tsID == CDI_UNDEFID )
-    {
-      tsID++;
-      streamDefTimestep(streamID, tsID);
-    }
+      while ( checkname )
+        {
+          if ( iz ) sprintf(varname2, "_%d", iz+1);
 
-  if ( ! streamptr->record ) cdiInitRecord(streamptr);
+          int status = nc_inq_varid(fileID, varname, &ncvarid);
+          if ( status != NC_NOERR ) checkname = FALSE;
 
-  int vlistID = streamptr->vlistID;
-  int gridID  = vlistInqVarGrid(vlistID, varID);
-  int zaxisID = vlistInqVarZaxis(vlistID, varID);
-  int param   = vlistInqVarParam(vlistID, varID);
-  int level   = (int)(zaxisInqLevel(zaxisID, levelID));
+          if ( checkname ) iz++;
 
-  streamptr->record->varID    = varID;
-  streamptr->record->levelID  = levelID;
-  streamptr->record->param    = param;
-  streamptr->record->level    = level;
-  streamptr->record->date     = streamptr->tsteps[tsID].taxis.vdate;
-  streamptr->record->time     = streamptr->tsteps[tsID].taxis.vtime;
-  streamptr->record->gridID   = gridID;
-  streamptr->record->prec     = vlistInqVarDatatype(vlistID, varID);
+          if ( iz >= CDI_MAX_NAME ) break;
+        }
 
-  switch (streamptr->filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      grbDefRecord(streamptr);
-      break;
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      srvDefRecord(streamptr);
-      break;
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      extDefRecord(streamptr);
-      break;
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      iegDefRecord(streamptr);
-      break;
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
-      cdfDefRecord(streamptr);
-      break;
-#endif
-    default:
-      Error("%s support not compiled in!", strfiletype(streamptr->filetype));
-      break;
+      name = varname;
+      code = 0;
+      pdis = 255;
     }
-}
 
+  /* if ( streamptr->ncmode == 2 ) cdf_redef(fileID); */
 
-void streamReadRecord(int streamID, double *data, int *nmiss)
-{
-  check_parg(data);
-  check_parg(nmiss);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
-  stream_check_ptr(__func__, streamptr);
+  int dtype = vlistInqVarDatatype(vlistID, varID);
+  int xtype = cdfDefDatatype(dtype, streamptr->filetype);
 
-  *nmiss = 0;
+  cdf_def_var(fileID, name, (nc_type) xtype, ndims, dims, &ncvarid);
 
-  switch (streamptr->filetype)
+#if  defined  (HAVE_NETCDF4)
+  if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      grbReadRecord(streamptr, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      srvReadRecord(streamptr, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      extReadRecord(streamptr, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      iegReadRecord(streamptr, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      cdfReadRecord(streamptr, data, nmiss);
-      break;
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
-	break;
-      }
+      if ( chunktype == CHUNK_AUTO )
+        retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
+      else
+        retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, chunks);
+
+      if ( retval ) Error("nc_def_var_chunking failed, status = %d", retval);
     }
-}
+#endif
 
-static void
-stream_write_record(int streamID, int memtype, const void *data, int nmiss)
-{
-  check_parg(data);
+  if ( streamptr->comptype == COMPRESS_ZIP )
+    {
+      if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
+        {
+          cdfDefVarDeflate(fileID, ncvarid, streamptr->complevel);
+        }
+      else
+        {
+          if ( lchunk )
+            {
+              static int lwarn = TRUE;
 
-  stream_t *streamptr = stream_to_pointer(streamID);
-  stream_check_ptr(__func__, streamptr);
+              if ( lwarn )
+                {
+                  lwarn = FALSE;
+                  Warning("Deflate compression is only available for NetCDF4!");
+                }
+            }
+        }
+    }
 
-  switch (streamptr->filetype)
+  if ( streamptr->comptype == COMPRESS_SZIP )
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      grb_write_record(streamptr, memtype, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      if ( memtype == MEMTYPE_FLOAT ) Error("srvWriteRecord not implemented for memtype float!");
-      srvWriteRecord(streamptr, (const double *)data);
-      break;
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      if ( memtype == MEMTYPE_FLOAT ) Error("extWriteRecord not implemented for memtype float!");
-      extWriteRecord(streamptr, (const double *)data);
-      break;
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      if ( memtype == MEMTYPE_FLOAT ) Error("iegWriteRecord not implemented for memtype float!");
-      iegWriteRecord(streamptr, (const double *)data);
-      break;
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-	cdf_write_record(streamptr, memtype, data, nmiss);
-	break;
-      }
+      if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
+        {
+#if defined (NC_SZIP_NN_OPTION_MASK)
+          cdfDefVarSzip(fileID, ncvarid);
+#else
+          static int lwarn = TRUE;
+
+          if ( lwarn )
+            {
+              lwarn = FALSE;
+              Warning("NetCDF4/SZIP compression not available!");
+            }
 #endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
-	break;
-      }
-    }
-}
+        }
+      else
+        {
+          static int lwarn = TRUE;
 
-/*
- at Function  streamWriteRecord
- at Title     Write a horizontal slice of a variable
+          if ( lwarn )
+            {
+              lwarn = FALSE;
+              Warning("SZIP compression is only available for NetCDF4!");
+            }
+        }
+    }
 
- at Prototype void streamWriteRecord(int streamID, const double *data, int nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  data      Pointer to a block of double precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
+  if ( stdname && *stdname )
+    cdf_put_att_text(fileID, ncvarid, "standard_name", strlen(stdname), stdname);
 
- at Description
-The function streamWriteRecord writes the values of a horizontal slice (record) of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
- at EndFunction
-*/
-void streamWriteRecord(int streamID, const double *data, int nmiss)
-{
-  stream_write_record(streamID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
-}
+  if ( longname && *longname )
+    cdf_put_att_text(fileID, ncvarid, "long_name", strlen(longname), longname);
 
-void streamWriteRecordF(int streamID, const float *data, int nmiss)
-{
-  stream_write_record(streamID, MEMTYPE_FLOAT, (const void *) data, nmiss);
-}
+  if ( units && *units )
+    cdf_put_att_text(fileID, ncvarid, "units", strlen(units), units);
 
+  if ( code > 0 && pdis == 255 )
+    cdf_put_att_int(fileID, ncvarid, "code", NC_INT, 1, &code);
 
-void streamCopyRecord(int streamID2, int streamID1)
-{
-  stream_t *streamptr1 = stream_to_pointer(streamID1);
-  stream_t *streamptr2 = stream_to_pointer(streamID2);
+  if ( pdis != 255 )
+    {
+      char paramstr[32];
+      cdiParamToString(param, paramstr, sizeof(paramstr));
+      cdf_put_att_text(fileID, ncvarid, "param", strlen(paramstr), paramstr);
+    }
 
-  stream_check_ptr(__func__, streamptr1);
-  stream_check_ptr(__func__, streamptr2);
+  if ( tableID != UNDEFID )
+    {
+      tablenum = tableInqNum(tableID);
+      if ( tablenum > 0 )
+        cdf_put_att_int(fileID, ncvarid, "table", NC_INT, 1, &tablenum);
+    }
 
-  int filetype1 = streamptr1->filetype;
-  int filetype2 = streamptr2->filetype;
-  int filetype  = FILETYPE_UNDEF;
+  char coordinates[CDI_MAX_NAME];
+  coordinates[0] = 0;
 
-  if ( filetype1 == filetype2 ) filetype = filetype2;
-  else
+  if ( zaxis_is_scalar )
     {
-      switch (filetype1)
+      int nczvarID = streamptr->nczvarID[zaxisindex];
+      if ( nczvarID != CDI_UNDEFID )
         {
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-          switch (filetype2)
-            {
-            case FILETYPE_NC:
-            case FILETYPE_NC2:
-            case FILETYPE_NC4:
-            case FILETYPE_NC4C:
-              Warning("Streams have different file types (%s -> %s)!", strfiletype(filetype1), strfiletype(filetype2));
-              filetype = filetype2;
-              break;
-            }
-          break;
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, nczvarID, coordinates+len);
         }
     }
 
-  if ( filetype == FILETYPE_UNDEF )
-    Error("Streams have different file types (%s -> %s)!", strfiletype(filetype1), strfiletype(filetype2));
-
-  switch (filetype)
+  if ( gridtype != GRID_GENERIC && gridtype != GRID_LONLAT  && gridtype != GRID_CURVILINEAR )
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      grbCopyRecord(streamptr2, streamptr1);
-      break;
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      srvCopyRecord(streamptr2, streamptr1);
-      break;
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      extCopyRecord(streamptr2, streamptr1);
-      break;
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      iegCopyRecord(streamptr2, streamptr1);
-      break;
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      cdfCopyRecord(streamptr2, streamptr1);
-      break;
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
-      }
+      size_t len = strlen(gridNamePtr(gridtype));
+      if ( len > 0 )
+        cdf_put_att_text(fileID, ncvarid, "grid_type", len, gridNamePtr(gridtype));
     }
-}
-
-
-void cdi_create_records(stream_t *streamptr, int tsID)
-{
-  unsigned nrecords, maxrecords;
-  record_t *records;
-
-  tsteps_t *sourceTstep = streamptr->tsteps;
-  tsteps_t *destTstep = sourceTstep + tsID;
-
-  if ( destTstep->records ) return;
 
-  int vlistID = streamptr->vlistID;
+  if ( gridIsRotated(gridID) )
+    {
+      char mapping[] = "rotated_pole";
+      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
+    }
 
-  if ( tsID == 0 )
+  if ( gridtype == GRID_SINUSOIDAL )
     {
-      maxrecords = 0;
-      int nvars = streamptr->nvars;
-      for ( int varID = 0; varID < nvars; varID++)
-        for (int isub=0; isub<streamptr->vars[varID].subtypeSize; isub++)
-          maxrecords += (unsigned)streamptr->vars[varID].recordTable[isub].nlevs;
+      char mapping[] = "sinusoidal";
+      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
     }
-  else
+  else if ( gridtype == GRID_LAEA )
     {
-      maxrecords = (unsigned)sourceTstep->recordSize;
+      char mapping[] = "laea";
+      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
     }
-
-  if ( tsID == 0 )
+  else if ( gridtype == GRID_LCC2 )
     {
-      nrecords = maxrecords;
+      char mapping[] = "Lambert_Conformal";
+      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
     }
-  else if ( tsID == 1 )
+  else if ( gridtype == GRID_TRAJECTORY )
     {
-      nrecords = 0;
-      maxrecords = (unsigned)sourceTstep->recordSize;
-      for ( unsigned recID = 0; recID < maxrecords; recID++ )
-	{
-	  int varID = sourceTstep->records[recID].varID;
-	  nrecords += (varID == CDI_UNDEFID /* varID = CDI_UNDEFID for write mode !!! */
-                       || vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT);
-          //    printf("varID nrecords %d %d %d \n", varID, nrecords, vlistInqVarTsteptype(vlistID, varID));
-	}
+      cdf_put_att_text(fileID, ncvarid, "coordinates", 9, "tlon tlat" );
+    }
+  else if ( gridtype == GRID_LONLAT && xid == UNDEFID && yid == UNDEFID && gridsize == 1 )
+    {
+      int ncxvarID = streamptr->ncxvarID[gridindex];
+      int ncyvarID = streamptr->ncyvarID[gridindex];
+      if ( ncyvarID != CDI_UNDEFID )
+        {
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, ncyvarID, coordinates+len);
+        }
+      if ( ncxvarID != CDI_UNDEFID )
+        {
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, ncxvarID, coordinates+len);
+        }
+    }
+  else if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
+    {
+      char cellarea[CDI_MAX_NAME] = "area: ";
+      int ncxvarID = streamptr->ncxvarID[gridindex];
+      int ncyvarID = streamptr->ncyvarID[gridindex];
+      int ncavarID = streamptr->ncavarID[gridindex];
+      if ( ncyvarID != CDI_UNDEFID )
+        {
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, ncyvarID, coordinates+len);
+        }
+      if ( ncxvarID != CDI_UNDEFID )
+        {
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, ncxvarID, coordinates+len);
+        }
+
+      if ( ncavarID != CDI_UNDEFID )
+        {
+          size_t len = strlen(cellarea);
+          cdf_inq_varname(fileID, ncavarID, cellarea+len);
+          len = strlen(cellarea);
+          cdf_put_att_text(fileID, ncvarid, "cell_measures", len, cellarea);
+        }
+
+      if ( gridtype == GRID_UNSTRUCTURED )
+        {
+          int position = gridInqPosition(gridID);
+          if ( position > 0 )
+            cdf_put_att_int(fileID, ncvarid, "number_of_grid_in_reference", NC_INT, 1, &position);
+        }
     }
-  else
+  else if ( gridtype == GRID_SPECTRAL || gridtype == GRID_FOURIER )
     {
-      nrecords = (unsigned)streamptr->tsteps[1].nallrecs;
+      int gridTruncation = gridInqTrunc(gridID);
+      axis[iax++] = '-';
+      axis[iax++] = '-';
+      cdf_put_att_text(fileID, ncvarid, "axis", iax, axis);
+      cdf_put_att_int(fileID, ncvarid, "truncation", NC_INT, 1, &gridTruncation);
     }
-  //  printf("tsID, nrecords %d %d\n", tsID, nrecords);
-
-  if ( maxrecords > 0 )
-    records = (record_t *) Malloc(maxrecords*sizeof(record_t));
-  else
-    records = NULL;
 
-  destTstep->records    = records;
-  destTstep->recordSize = (int)maxrecords;
-  destTstep->nallrecs   = (int)nrecords;
+  size_t len = strlen(coordinates);
+  if ( len ) cdf_put_att_text(fileID, ncvarid, "coordinates", len, coordinates);
 
-  if ( tsID == 0 )
-    {
-      for ( unsigned recID = 0; recID < maxrecords; recID++ )
-        recordInitEntry(&destTstep->records[recID]);
-    }
-  else
+  /*  if ( xtype == NC_BYTE || xtype == NC_SHORT || xtype == NC_INT ) */
     {
-      memcpy(destTstep->records, sourceTstep->records, (size_t)maxrecords*sizeof(record_t));
+      int laddoffset, lscalefactor;
+      double addoffset, scalefactor;
+      int astype = NC_DOUBLE;
 
-      for ( unsigned recID = 0; recID < maxrecords; recID++ )
-	{
-          record_t *curRecord = &sourceTstep->records[recID];
-          destTstep->records[recID].used = curRecord->used;
-          if ( curRecord->used != CDI_UNDEFID && curRecord->varID != -1 ) /* curRecord->varID = -1 for write mode !!! */
+      addoffset    = vlistInqVarAddoffset(vlistID, varID);
+      scalefactor  = vlistInqVarScalefactor(vlistID, varID);
+      laddoffset   = IS_NOT_EQUAL(addoffset, 0);
+      lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+
+      if ( laddoffset || lscalefactor )
+        {
+          if ( IS_EQUAL(addoffset,   (double) ((float) addoffset)) &&
+               IS_EQUAL(scalefactor, (double) ((float) scalefactor)) )
             {
-              if ( vlistInqVarTsteptype(vlistID, curRecord->varID) != TSTEP_CONSTANT )
-                {
-                  destTstep->records[recID].position = CDI_UNDEFID;
-                  destTstep->records[recID].size     = 0;
-                  destTstep->records[recID].used     = FALSE;
-                }
+              astype = NC_FLOAT;
             }
-	}
+
+          if ( xtype == (int) NC_FLOAT ) astype = NC_FLOAT;
+
+          cdf_put_att_double(fileID, ncvarid, "add_offset",   (nc_type) astype, 1, &addoffset);
+          cdf_put_att_double(fileID, ncvarid, "scale_factor", (nc_type) astype, 1, &scalefactor);
+        }
     }
-}
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
 
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+  if ( dtype == DATATYPE_UINT8 && xtype == NC_BYTE )
+    {
+      int validrange[2] = {0, 255};
+      cdf_put_att_int(fileID, ncvarid, "valid_range", NC_SHORT, 2, validrange);
+      cdf_put_att_text(fileID, ncvarid, "_Unsigned", 4, "true");
+    }
 
+  streamptr->vars[varID].ncvarid = ncvarid;
 
+  if ( vlistInqVarMissvalUsed(vlistID, varID) )
+    cdfDefVarMissval(streamptr, varID, vlistInqVarDatatype(vlistID, varID), 0);
 
+  if ( zid == -1 )
+    {
+      if ( zaxisInqType(zaxisID) == ZAXIS_CLOUD_BASE          ||
+           zaxisInqType(zaxisID) == ZAXIS_CLOUD_TOP           ||
+           zaxisInqType(zaxisID) == ZAXIS_ISOTHERM_ZERO       ||
+           zaxisInqType(zaxisID) == ZAXIS_TOA                 ||
+           zaxisInqType(zaxisID) == ZAXIS_SEA_BOTTOM          ||
+           zaxisInqType(zaxisID) == ZAXIS_LAKE_BOTTOM         ||
+           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM     ||
+           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM_TA  ||
+           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM_TW  ||
+           zaxisInqType(zaxisID) == ZAXIS_MIX_LAYER           ||
+           zaxisInqType(zaxisID) == ZAXIS_ATMOSPHERE )
+        {
+          zaxisInqName(zaxisID, varname);
+          cdf_put_att_text(fileID, ncvarid, "level_type", strlen(varname), varname);
+        }
+    }
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
+  if ( vlistInqVarEnsemble( vlistID,  varID, &ensID, &ensCount, &forecast_type ) )
+    {
+      /* void cdf_put_att_int(  int ncid, int varid, const char *name, nc_type xtype,
+	                        size_t len, const int *ip )
+       */
+	cdf_put_att_int(fileID, ncvarid, "realization", NC_INT, 1, &ensID);
+	cdf_put_att_int(fileID, ncvarid, "ensemble_members", NC_INT, 1, &ensCount);
+	cdf_put_att_int(fileID, ncvarid, "forecast_init_type", NC_INT, 1, &forecast_type);
 
-#define SINGLE_PRECISION  4
-#define DOUBLE_PRECISION  8
+#ifdef DBG
+	if( DBG )
+	  {
+	    fprintf( stderr, "cdfDefVar :\n EnsID  %d\n Enscount %d\n Forecast init type %d\n",  ensID,
+		     ensCount,  forecast_type );
+	  }
+#endif
+    }
 
-#if defined (HAVE_LIBSERVICE)
+  /* Attributes */
+  cdfDefineAttributes(vlistID, varID, fileID, ncvarid);
 
+  /* if ( streamptr->ncmode == 2 ) cdf_enddef(fileID); */
 
-typedef struct {
-  int param;
-  int level;
-} SRVCOMPVAR;
+  return ncvarid;
+}
 
 
-static int srvInqDatatype(int prec)
+void cdfEndDef(stream_t *streamptr)
 {
-  int datatype;
+  cdfDefGlobalAtts(streamptr);
+  cdfDefLocalAtts(streamptr);
 
-  if ( prec == DOUBLE_PRECISION ) datatype = DATATYPE_FLT64;
-  else                            datatype = DATATYPE_FLT32;
+  if ( streamptr->accessmode == 0 )
+    {
+      int fileID  = streamptr->fileID;
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-  return (datatype);
-}
+      int nvars =  streamptr->nvars;
+      for ( int varID = 0; varID < nvars; varID++ )
+	cdfDefVar(streamptr, varID);
 
+      if ( streamptr->ncmode == 2 )
+        {
+          if ( CDI_netcdf_hdr_pad == 0UL )
+            cdf_enddef(fileID);
+          else
+            cdf__enddef(fileID, CDI_netcdf_hdr_pad);
+        }
 
-static int srvDefDatatype(int datatype)
-{
-  int prec;
+      streamptr->accessmode = 1;
+    }
+}
 
-  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
-    Error("CDI/SERVICE library does not support complex numbers!");
+static
+void cdfWriteGridTraj(stream_t *streamptr, int gridID)
+{
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  if ( datatype != DATATYPE_FLT32 && datatype != DATATYPE_FLT64 )
-    datatype = DATATYPE_FLT32;
+  int gridindex = vlistGridIndex(vlistID, gridID);
+  int lonID = streamptr->xdimID[gridindex];
+  int latID = streamptr->ydimID[gridindex];
 
-  if ( datatype == DATATYPE_FLT64 ) prec = DOUBLE_PRECISION;
-  else                              prec = SINGLE_PRECISION;
+  double xlon = gridInqXval(gridID, 0);
+  double xlat = gridInqYval(gridID, 0);
+  int tsID = streamptr->curTsID;
+  size_t index = (size_t)tsID;
 
-  return (prec);
+  cdf_put_var1_double(fileID, lonID, &index, &xlon);
+  cdf_put_var1_double(fileID, latID, &index, &xlat);
 }
 
-/* not used
-int srvInqRecord(stream_t *streamptr, int *varID, int *levelID)
+static
+void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dtype, size_t nvals, size_t xsize, size_t ysize,
+                        int swapxy, size_t *start, size_t *count, int memtype, const void *data, int nmiss)
 {
-  int status;
-  int fileID;
-  int icode, ilevel;
-  int zaxisID = -1;
-  int header[8];
-  int vlistID;
-  void *srvp = streamptr->record->exsep;
+  const double *pdata_dp = (const double *) data;
+  double *mdata_dp = NULL;
+  double *sdata_dp = NULL;
+  const float *pdata_sp = (const float *) data;
+  float *mdata_sp = NULL;
+  float *sdata_sp = NULL;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  /*  if ( dtype == DATATYPE_INT8 || dtype == DATATYPE_INT16 || dtype == DATATYPE_INT32 ) */
+    {
+      double missval      = vlistInqVarMissval(vlistID, varID);
+      double addoffset    = vlistInqVarAddoffset(vlistID, varID);
+      double scalefactor  = vlistInqVarScalefactor(vlistID, varID);
+      bool laddoffset     = IS_NOT_EQUAL(addoffset, 0);
+      bool lscalefactor   = IS_NOT_EQUAL(scalefactor, 1);
 
-  *varID   = -1;
-  *levelID = -1;
+      if ( laddoffset || lscalefactor )
+        {
+          if ( memtype == MEMTYPE_FLOAT )
+            {
+              mdata_sp = (float *) Malloc(nvals*sizeof(float));
+              memcpy(mdata_sp, pdata_sp, nvals*sizeof(float));
+              pdata_sp = mdata_sp;
 
-  status = srvRead(fileID, srvp);
-  if ( status != 0 ) return (0);
+              if ( nmiss > 0 )
+                {
+                  for ( size_t i = 0; i < nvals; i++ )
+                    {
+                      double temp = mdata_sp[i];
+                      if ( !DBL_IS_EQUAL(temp, missval) )
+                        {
+                          if ( laddoffset )   temp -= addoffset;
+                          if ( lscalefactor ) temp /= scalefactor;
+                          mdata_sp[i] = (float)temp;
+                        }
+                    }
+                }
+              else
+                {
+                  for ( size_t i = 0; i < nvals; i++ )
+                    {
+                      double temp = mdata_sp[i];
+                      if ( laddoffset )   temp -= addoffset;
+                      if ( lscalefactor ) temp /= scalefactor;
+                      mdata_sp[i] = (float)temp;
+                    }
+                }
+            }
+          else
+            {
+              mdata_dp = (double *) Malloc(nvals*sizeof(double));
+              memcpy(mdata_dp, pdata_dp, nvals*sizeof(double));
+              pdata_dp = mdata_dp;
 
-  srvInqHeader(srvp, header);
+              if ( nmiss > 0 )
+                {
+                  for ( size_t i = 0; i < nvals; i++ )
+                    {
+                      if ( !DBL_IS_EQUAL(mdata_dp[i], missval) )
+                        {
+                          if ( laddoffset )   mdata_dp[i] -= addoffset;
+                          if ( lscalefactor ) mdata_dp[i] /= scalefactor;
+                        }
+                    }
+                }
+              else
+                {
+                  for ( size_t i = 0; i < nvals; i++ )
+                    {
+                      if ( laddoffset )   mdata_dp[i] -= addoffset;
+                      if ( lscalefactor ) mdata_dp[i] /= scalefactor;
+                    }
+                }
+            }
+        }
 
-  icode  = header[0];
-  ilevel = header[1];
+      if ( dtype == DATATYPE_UINT8 || dtype == DATATYPE_INT8 ||
+           dtype == DATATYPE_INT16 || dtype == DATATYPE_INT32 )
+        {
+          if ( memtype == MEMTYPE_FLOAT )
+            {
+              if ( mdata_sp == NULL )
+                {
+                  mdata_sp = (float *) Malloc(nvals*sizeof(float));
+                  memcpy(mdata_sp, pdata_sp, nvals*sizeof(float));
+                  pdata_sp = mdata_sp;
+                }
 
-  *varID = vlistInqVarID(vlistID, icode);
+              for ( size_t i = 0; i < nvals; i++ ) mdata_sp[i] = roundf(mdata_sp[i]);
 
-  if ( *varID == UNDEFID ) Error("Code %d undefined", icode);
+              if ( dtype == DATATYPE_UINT8 )
+                {
+                  nc_type xtype;
+                  cdf_inq_vartype(fileID, ncvarid, &xtype);
+                  if ( xtype == NC_BYTE )
+                    {
+                      for ( size_t i = 0; i < nvals; ++i )
+                        if ( mdata_sp[i] > 127 ) mdata_sp[i] -= 256;
+                    }
+                }
+            }
+          else
+            {
+              if ( mdata_dp == NULL )
+                {
+                  mdata_dp = (double *) Malloc(nvals*sizeof(double));
+                  memcpy(mdata_dp, pdata_dp, nvals*sizeof(double));
+                  pdata_dp = mdata_dp;
+                }
 
-  zaxisID = vlistInqVarZaxis(vlistID, *varID);
+              for ( size_t i = 0; i < nvals; i++ ) mdata_dp[i] = round(mdata_dp[i]);
 
-  *levelID = zaxisInqLevelID(zaxisID, (double) ilevel);
+              if ( dtype == DATATYPE_UINT8 )
+                {
+                  nc_type xtype;
+                  cdf_inq_vartype(fileID, ncvarid, &xtype);
+                  if ( xtype == NC_BYTE )
+                    {
+                      for ( size_t i = 0; i < nvals; ++i )
+                        if ( mdata_dp[i] > 127 ) mdata_dp[i] -= 256;
+                    }
+                }
+            }
+        }
 
-  return (1);
-}
-*/
+      if ( CDF_Debug && memtype != MEMTYPE_FLOAT )
+        {
+          double fmin, fmax;
+          fmin =  1.0e200;
+          fmax = -1.0e200;
+          for ( size_t i = 0; i < nvals; ++i )
+            {
+              if ( !DBL_IS_EQUAL(pdata_dp[i], missval) )
+                {
+                  if ( pdata_dp[i] < fmin ) fmin = pdata_dp[i];
+                  if ( pdata_dp[i] > fmax ) fmax = pdata_dp[i];
+                }
+            }
+          Message("nvals = %zu, nmiss = %d, missval = %g, minval = %g, maxval = %g",
+                  nvals, nmiss, missval, fmin, fmax);
+        }
+    }
 
-void srvReadRecord(stream_t *streamptr, double *data, int *nmiss)
-{
-  int vlistID, fileID;
-  int status;
-  int recID, vrecID, tsID;
-  off_t recpos;
-  int header[8];
-  int varID, gridID;
-  int i, size;
-  double missval;
-  void *srvp = streamptr->record->exsep;
+  if ( swapxy ) // implemented only for cdf_write_var_slice() 
+    {
+      size_t gridsize = xsize*ysize;
+      if ( memtype == MEMTYPE_FLOAT )
+        {
+          sdata_sp = (float *) Malloc(gridsize*sizeof(float));
+          for ( size_t j = 0; j < ysize; ++j )
+            for ( size_t i = 0; i < xsize; ++i )
+              sdata_sp[i*ysize+j] = pdata_sp[j*xsize+i];
+          pdata_sp = sdata_sp;
+        }
+      else
+        {
+          sdata_dp = (double *) Malloc(gridsize*sizeof (double));
+          for ( size_t j = 0; j < ysize; ++j )
+            for ( size_t i = 0; i < xsize; ++i )
+              sdata_dp[i*ysize+j] = pdata_dp[j*xsize+i];
+          pdata_dp = sdata_dp;
+        }
+    }
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
-  tsID    = streamptr->curTsID;
-  vrecID  = streamptr->tsteps[tsID].curRecID;
-  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-  recpos  = streamptr->tsteps[tsID].records[recID].position;
-  varID   = streamptr->tsteps[tsID].records[recID].varID;
+  if ( memtype == MEMTYPE_FLOAT )
+    cdf_put_vara_float(fileID, ncvarid, start, count, pdata_sp);
+  else
+    cdf_put_vara_double(fileID, ncvarid, start, count, pdata_dp);
 
-  fileSetPos(fileID, recpos, SEEK_SET);
+  if ( mdata_dp ) Free(mdata_dp);
+  if ( sdata_dp ) Free(sdata_dp);
+  if ( mdata_sp ) Free(mdata_sp);
+  if ( sdata_sp ) Free(sdata_sp);
+}
 
-  status = srvRead(fileID, srvp);
-  if ( status != 0 )
-    Error("Failed to read record from SRV file");
 
-  srvInqHeader(srvp, header);
-  srvInqDataDP(srvp, data);
+void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
+{
+  if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
 
-  missval = vlistInqVarMissval(vlistID, varID);
-  gridID  = vlistInqVarGrid(vlistID, varID);
-  size    = gridInqSize(gridID);
+  size_t xsize = 0, ysize = 0;
+  size_t size;
+  size_t start[5];
+  size_t count[5];
+  int swapxy = FALSE;
+  int ndims = 0;
+  int idim;
 
-  streamptr->numvals += size;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-  *nmiss = 0;
-  for ( i = 0; i < size; i++ )
-    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-      {
-	data[i] = missval;
-	(*nmiss)++;
-      }
-}
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
+  long ntsteps = streamptr->ntsteps;
+  if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
 
-void srvCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
-{
-  streamFCopyRecord(streamptr2, streamptr1, "SRV");
-}
+  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
 
+  int ncvarid = cdfDefVar(streamptr, varID);
 
-void srvDefRecord(stream_t *streamptr)
-{
-  int gridID;
-  int header[8];
-  int xsize, ysize;
-  int datatype;
-  int pdis, pcat, pnum;
-  srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
 
-  gridID = streamptr->record->gridID;
+  int xid = UNDEFID, yid = UNDEFID;
+  if ( gridInqType(gridID) == GRID_TRAJECTORY )
+    {
+      cdfWriteGridTraj(streamptr, gridID);
+    }
+  else
+    {
+      int gridindex = vlistGridIndex(vlistID, gridID);
+      xid = streamptr->xdimID[gridindex];
+      yid = streamptr->ydimID[gridindex];
+    }
 
-  cdiDecodeParam(streamptr->record->param, &pnum, &pcat, &pdis);
-  header[0] = pnum;
-  header[1] = streamptr->record->level;
-  header[2] = streamptr->record->date;
-  header[3] = streamptr->record->time;
+  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+  int zid = streamptr->zaxisID[zaxisindex];
 
-  xsize = gridInqXsize(gridID);
-  ysize = gridInqYsize(gridID);
-  if ( xsize == 0 || ysize == 0 )
+  if ( tsteptype != TSTEP_CONSTANT )
     {
-      xsize = gridInqSize(gridID);
-      ysize = 1;
+      start[ndims] = (size_t)ntsteps - 1;
+      count[ndims] = 1;
+      ndims++;
     }
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED ) ysize = 1;
-  if ( gridInqSize(gridID) != xsize*ysize )
-    Error("Internal problem with gridsize!");
 
-  header[4] = xsize;
-  header[5] = ysize;
-  header[6] = 0;
-  header[7] = 0;
+  if ( zid != UNDEFID )
+    {
+      start[ndims] = 0;
+      count[ndims] = (size_t)zaxisInqSize(zaxisID);
+      ndims++;
+    }
 
-  datatype = streamptr->record->prec;
+  if ( yid != UNDEFID )
+    {
+      start[ndims] = 0;
+      cdf_inq_dimlen(fileID, yid, &size);
+      /*      count[ndims] = gridInqYsize(gridID); */
+      count[ndims] = size;
+      ndims++;
+    }
 
-  srvp->dprec = srvDefDatatype(datatype);
+  if ( xid != UNDEFID )
+    {
+      start[ndims] = 0;
+      cdf_inq_dimlen(fileID, xid, &size);
+      /*      count[ndims] = gridInqXsize(gridID); */
+      count[ndims] = size;
+      ndims++;
+    }
 
-  srvDefHeader(srvp, header);
-}
+  if ( CDI_Debug )
+    for (idim = 0; idim < ndims; idim++)
+      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
 
+  if ( streamptr->ncmode == 1 )
+    {
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+    }
 
-void srvWriteRecord(stream_t *streamptr, const double *data)
-{
-  int fileID = streamptr->fileID;
-  void *srvp = streamptr->record->exsep;
+  int dtype = vlistInqVarDatatype(vlistID, varID);
 
-  srvDefDataDP(srvp, data);
-  srvWrite(fileID, srvp);
-}
+  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
 
-static
-void srv_add_record(stream_t *streamptr, int param, int level, int xsize, int ysize,
-                    size_t recsize, off_t position, int prec)
-{
-  int vlistID = streamptr->vlistID;
-  int tsID    = streamptr->curTsID;
-  int recID   = recordNewEntry(streamptr, tsID);
-  record_t *record = &streamptr->tsteps[tsID].records[recID];
+  size_t nvals = (size_t)(gridInqSize(gridID)) * (size_t)(zaxisInqSize(zaxisID));
 
-  record->size     = recsize;
-  record->position = position;
-  record->param    = param;
-  record->ilevel   = level;
+  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
+}
 
-  grid_t grid;
-  memset(&grid, 0, sizeof(grid_t));
-  grid.type  = GRID_GENERIC;
-  grid.size  = xsize*ysize;
-  grid.xsize = xsize;
-  grid.ysize = ysize;
-  grid.xvals = NULL;
-  grid.yvals = NULL;
-  int gridID = varDefGrid(vlistID, &grid, 0);
-  /*
-  if ( level == 0 ) leveltype = ZAXIS_SURFACE;
-  else              leveltype = ZAXIS_GENERIC;
-  */
-  int leveltype = ZAXIS_GENERIC;
 
-  int datatype = srvInqDatatype(prec);
+void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
+                         const int rect[][2], const void *data, int nmiss)
+{
+  if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
 
-  int levelID = 0;
-  int varID;
-  varAddRecord(recID, param, gridID, leveltype, 0, level, 0, 0, 0,
-	       datatype, &varID, &levelID, TSTEP_INSTANT, 0, 0, -1,
-               NULL, NULL, NULL, NULL, NULL, NULL);
+  int xid = UNDEFID, yid = UNDEFID;
+  size_t xsize = 0, ysize = 0;
+  size_t start[5];
+  size_t count[5];
+  int swapxy = FALSE;
+  int ndims = 0;
+  int idim;
+  int streamID = streamptr->self;
 
-  xassert(varID <= SHRT_MAX && levelID <= SHRT_MAX);
-  record->varID   = (short)varID;
-  record->levelID = (short)levelID;
+  if ( CDI_Debug )
+    Message("streamID = %d  varID = %d", streamID, varID);
 
-  streamptr->tsteps[tsID].nallrecs++;
-  streamptr->nrecs++;
+  int vlistID = streamInqVlist(streamID);
+  int fileID  = streamInqFileID(streamID);
 
+  long ntsteps = streamptr->ntsteps;
   if ( CDI_Debug )
-    Message("varID = %d gridID = %d levelID = %d",
-	    varID, gridID, levelID);
-}
+    Message("ntsteps = %ld", ntsteps);
 
-static
-void srvScanTimestep1(stream_t *streamptr)
-{
-  int header[8];
-  int prec = 0;
-  int status;
-  int fileID;
-  int rxsize = 0, rysize = 0;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  DateTime datetime0 = { LONG_MIN, LONG_MIN };
-  int tsID;
-  int varID;
-  off_t recpos;
-  int nrecords, nrecs, recID;
-  int taxisID = -1;
-  taxis_t *taxis;
-  int vlistID;
-  srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
+  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
 
-  streamptr->curTsID = 0;
+  int ncvarid = cdfDefVar(streamptr, varID);
 
-  tsID  = tstepsNewEntry(streamptr);
-  taxis = &streamptr->tsteps[tsID].taxis;
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
 
-  if ( tsID != 0 )
-    Error("Internal problem! tstepsNewEntry returns %d", tsID);
+  if ( gridInqType(gridID) == GRID_TRAJECTORY )
+    {
+      cdfWriteGridTraj(streamptr, gridID);
+    }
+  else
+    {
+      int gridindex = vlistGridIndex(vlistID, gridID);
+      xid = streamptr->xdimID[gridindex];
+      yid = streamptr->ydimID[gridindex];
+    }
 
-  fileID = streamptr->fileID;
+  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+  int zid = streamptr->zaxisID[zaxisindex];
 
-  nrecs = 0;
-  while ( TRUE )
+  if ( tsteptype != TSTEP_CONSTANT )
     {
-      recpos = fileGetPos(fileID);
-      status = srvRead(fileID, srvp);
-      if ( status != 0 )
-	{
-	  streamptr->ntsteps = 1;
-	  break;
-	}
-      size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
+      start[ndims] = (size_t)ntsteps - 1;
+      count[ndims] = 1;
+      ndims++;
+    }
+  if ( zid != UNDEFID )
+    {
+      int size = zaxisInqSize(zaxisID);
+      xassert(rect[2][0] >= 0 && rect[2][0] <= rect[2][1]
+              && rect[2][1] <= size);
+      start[ndims] = (size_t)rect[2][0];
+      count[ndims] = (size_t)rect[2][1] - (size_t)rect[2][0] + 1;
+      ndims++;
+    }
+  if ( yid != UNDEFID )
+    {
+      size_t size;
+      cdf_inq_dimlen(fileID, yid, &size);
+      xassert(rect[1][0] >= 0 && rect[1][0] <= rect[1][1]
+              && (size_t)rect[1][1] <= size);
+      start[ndims] = (size_t)rect[1][0];
+      count[ndims] = (size_t)rect[1][1] - (size_t)rect[1][0] + 1;
+      ndims++;
+    }
+  if ( xid != UNDEFID )
+    {
+      size_t size;
+      cdf_inq_dimlen(fileID, xid, &size);
+      xassert(rect[0][0] >= 0 && rect[0][0] <= rect[0][1]
+              && (size_t)rect[0][1] <= size);
+      start[ndims] = (size_t)rect[0][0];
+      count[ndims] = (size_t)rect[0][1] - (size_t)rect[0][0] + 1;
+      ndims++;
+    }
 
-      srvInqHeader(srvp, header);
+  if ( CDI_Debug )
+    for (idim = 0; idim < ndims; idim++)
+      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
 
-      prec   = srvp->dprec;
-      rcode  = header[0];
-      rlevel = header[1];
-      vdate  = header[2];
-      vtime  = header[3];
-      rxsize = header[4];
-      rysize = header[5];
+  if ( streamptr->ncmode == 1 )
+    {
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+    }
 
-      param = cdiEncodeParam(rcode, 255, 255);
+  int dtype = vlistInqVarDatatype(vlistID, varID);
 
-      if ( nrecs == 0 )
-	{
-	  datetime0.date = vdate;
-	  datetime0.time = vtime;
-	}
-      else
-	{
-	  for ( recID = 0; recID < nrecs; recID++ )
-            if (    streamptr->tsteps[0].records[recID].param  == param
-                 && streamptr->tsteps[0].records[recID].ilevel == rlevel )
-              break;
-	  if ( recID < nrecs ) break;
-	  DateTime datetime = { .date = vdate, .time = vtime };
-	  if ( datetimeCmp(datetime, datetime0) )
-	    Warning("Inconsistent verification time for code %d level %d", rcode, rlevel);
-	}
+  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
 
-      nrecs++;
+  size_t nvals = (size_t)(gridInqSize(gridID)) * (size_t)(zaxisInqSize(zaxisID));
 
-      if ( CDI_Debug )
-	Message("%4d%8d%4d%8d%8d%6d", nrecs, (int)recpos, rcode, rlevel, vdate, vtime);
+  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals,
+                     xsize, ysize, swapxy, start, count, memtype, data, nmiss);
+}
 
-      srv_add_record(streamptr, param, rlevel, rxsize, rysize, recsize, recpos, prec);
-    }
 
-  streamptr->rtsteps = 1;
+void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
+{
+  if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
 
-  cdi_generate_vars(streamptr);
+  size_t xsize = 0, ysize = 0;
+  size_t start[5];
+  size_t count[5];
+  int dimorder[3];
+  int xid = UNDEFID, yid = UNDEFID;
 
-  taxisID = taxisCreate(TAXIS_ABSOLUTE);
-  taxis->type  = TAXIS_ABSOLUTE;
-  taxis->vdate = (int)datetime0.date;
-  taxis->vtime = (int)datetime0.time;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-  vlistID = streamptr->vlistID;
-  vlistDefTaxis(vlistID, taxisID);
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  vlist_check_contents(vlistID);
+  long ntsteps = streamptr->ntsteps;
+  if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
 
-  nrecords = streamptr->tsteps[0].nallrecs;
-  if ( nrecords < streamptr->tsteps[0].recordSize )
+  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
+
+  int ncvarid = cdfDefVar(streamptr, varID);
+
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  vlistInqVarDimorder(vlistID, varID, &dimorder);
+
+  if ( gridInqType(gridID) == GRID_TRAJECTORY )
     {
-      streamptr->tsteps[0].recordSize = nrecords;
-      streamptr->tsteps[0].records =
-	(record_t *) Realloc(streamptr->tsteps[0].records,
-                             (size_t)nrecords * sizeof(record_t));
+      cdfWriteGridTraj(streamptr, gridID);
+    }
+  else
+    {
+      int gridindex = vlistGridIndex(vlistID, gridID);
+      xid = streamptr->xdimID[gridindex];
+      yid = streamptr->ydimID[gridindex];
     }
 
-  streamptr->tsteps[0].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
-  streamptr->tsteps[0].nrecs = nrecords;
-  for ( recID = 0; recID < nrecords; recID++ )
-    streamptr->tsteps[0].recIDs[recID] = recID;
+  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+  int zid = streamptr->zaxisID[zaxisindex];
 
-  if ( streamptr->ntsteps == -1 )
-    {
-      tsID = tstepsNewEntry(streamptr);
-      if ( tsID != streamptr->rtsteps )
-	Error("Internal error. tsID = %d", tsID);
+  int swapxy = (dimorder[2] == 2 || dimorder[0] == 1) && xid != UNDEFID && yid != UNDEFID;
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
-      streamptr->tsteps[tsID].position = recpos;
+  size_t ndims = 0;
+  if ( tsteptype != TSTEP_CONSTANT )
+    {
+      start[ndims] = (size_t)ntsteps - 1;
+      count[ndims] = 1;
+      ndims++;
     }
 
-  if ( streamptr->ntsteps == 1 )
+  for ( int id = 0; id < 3; ++id )
     {
-      if ( taxis->vdate == 0 && taxis->vtime == 0 )
-	{
-	  streamptr->ntsteps = 0;
-	  for ( varID = 0; varID < streamptr->nvars; varID++ )
-	    {
-	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-	    }
-	}
+      if ( dimorder[id] == 3 && zid != UNDEFID )
+        {
+          start[ndims] = (size_t)levelID;
+          count[ndims] = 1;
+          ndims++;
+        }
+      else if ( dimorder[id] == 2 && yid != UNDEFID )
+        {
+          start[ndims] = 0;
+          cdf_inq_dimlen(fileID, yid, &ysize);
+          count[ndims] = ysize;
+          ndims++;
+        }
+      else if ( dimorder[id] == 1 && xid != UNDEFID )
+        {
+          start[ndims] = 0;
+          cdf_inq_dimlen(fileID, xid, &xsize);
+          count[ndims] = xsize;
+          ndims++;
+        }
     }
-}
 
-static
-int srvScanTimestep2(stream_t *streamptr)
-{
-  int header[8];
-  int status;
-  int fileID;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  int tsID;
-  int varID;
-  off_t recpos = 0;
-  int nrecords, nrecs, recID, rindex;
-  int nextstep;
-  taxis_t *taxis;
-  int vlistID;
-  SRVCOMPVAR compVar, compVar0;
-  void *srvp = streamptr->record->exsep;
+  if ( CDI_Debug )
+    for (size_t idim = 0; idim < ndims; idim++)
+      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
 
-  streamptr->curTsID = 1;
+  int dtype = vlistInqVarDatatype(vlistID, varID);
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
 
-  tsID = streamptr->rtsteps;
-  if ( tsID != 1 )
-    Error("Internal problem! unexpected timestep %d", tsID+1);
+  size_t nvals = (size_t)(gridInqSize(gridID));
 
-  taxis = &streamptr->tsteps[tsID].taxis;
+  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
+}
 
-  fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
-  cdi_create_records(streamptr, tsID);
+void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss)
+{
+  int varID   = streamptr->record->varID;
+  int levelID = streamptr->record->levelID;
 
-  nrecords = streamptr->tsteps[0].nallrecs;
-  streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
-  streamptr->tsteps[1].nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
-    streamptr->tsteps[1].recIDs[recID] = -1;
+  cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+}
 
-  for ( recID = 0; recID < nrecords; recID++ )
-    {
-      varID = streamptr->tsteps[0].records[recID].varID;
-      streamptr->tsteps[tsID].records[recID].position =
-	streamptr->tsteps[0].records[recID].position;
-      streamptr->tsteps[tsID].records[recID].size     =
-	streamptr->tsteps[0].records[recID].size;
-    }
+#endif
+#ifdef HAVE_CONFIG_H
+#endif
 
-  for ( rindex = 0; rindex <= nrecords; rindex++ )
-    {
-      recpos = fileGetPos(fileID);
-      status = srvRead(fileID, srvp);
-      if ( status != 0 )
-	{
-	  streamptr->ntsteps = 2;
-	  break;
-	}
-      size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
+#ifdef HAVE_LIBNETCDF
 
-      srvInqHeader(srvp, header);
+#include <limits.h>
+#include <float.h>
 
-      rcode  = header[0];
-      rlevel = header[1];
-      vdate  = header[2];
-      vtime  = header[3];
 
-      param = cdiEncodeParam(rcode, 255, 255);
 
-      if ( rindex == 0 )
-	{
-	  taxis->type  = TAXIS_ABSOLUTE;
-	  taxis->vdate = vdate;
-	  taxis->vtime = vtime;
-	}
+#undef  UNDEFID
+#define UNDEFID  CDI_UNDEFID
 
-      compVar.param = param;
-      compVar.level = rlevel;
-      nextstep = FALSE;
-      for ( recID = 0; recID < nrecords; recID++ )
-	{
-	  compVar0.param  = streamptr->tsteps[tsID].records[recID].param;
-	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
 
-	  if ( memcmp(&compVar0, &compVar, sizeof(SRVCOMPVAR)) == 0 )
-	    {
-	      if ( streamptr->tsteps[tsID].records[recID].used )
-		{
-		  nextstep = TRUE;
-		}
-	      else
-		{
-		  streamptr->tsteps[tsID].records[recID].used = TRUE;
-		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
-		}
-	      break;
-	    }
-	}
-      if ( recID == nrecords )
-	{
-	  Warning("Code %d level %d not found at timestep %d", rcode, rlevel, tsID+1);
-	  return (CDI_EUFSTRUCT);
-	}
+static
+void cdfReadGridTraj(stream_t *streamptr, int gridID)
+{
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-      if ( nextstep ) break;
+  int gridindex = vlistGridIndex(vlistID, gridID);
+  int lonID = streamptr->xdimID[gridindex];
+  int latID = streamptr->ydimID[gridindex];
 
-      if ( CDI_Debug )
-	Message("%4d%8d%4d%8d%8d%6d", rindex+1, (int)recpos, rcode, rlevel, vdate, vtime);
+  int tsID = streamptr->curTsID;
+  size_t index = (size_t)tsID;
 
-      streamptr->tsteps[tsID].records[recID].size = recsize;
+  double xlon, xlat;
+  cdf_get_var1_double(fileID, lonID, &index, &xlon);
+  cdf_get_var1_double(fileID, latID, &index, &xlat);
 
-      compVar0.param  = streamptr->tsteps[tsID].records[recID].param;
-      compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
+  gridDefXvals(gridID, &xlon);
+  gridDefYvals(gridID, &xlat);
+}
 
-      if ( memcmp(&compVar0, &compVar, sizeof(SRVCOMPVAR)) != 0 )
-	{
-	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
-		  tsID, recID,
-		  streamptr->tsteps[tsID].records[recID].param, param,
-		  streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
-	  return (CDI_EUFSTRUCT);
-	}
+static
+void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], size_t (*count)[4])
+{
+  int vlistID = streamptr->vlistID;
+  int tsID = streamptr->curTsID;
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
 
-      streamptr->tsteps[1].records[recID].position = recpos;
-    }
+  if ( CDI_Debug ) Message("tsID = %d", tsID);
 
-  nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
+  int xid = UNDEFID, yid = UNDEFID;
+  if ( gridInqType(gridID) == GRID_TRAJECTORY )
     {
-      if ( ! streamptr->tsteps[tsID].records[recID].used )
-	{
-	  varID = streamptr->tsteps[tsID].records[recID].varID;
-          vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-	}
-      else
-	{
-	  nrecs++;
-	}
+      cdfReadGridTraj(streamptr, gridID);
     }
-  streamptr->tsteps[tsID].nrecs = nrecs;
+  else
+    {
+      xid = streamptr->xdimID[gridindex];
+      yid = streamptr->ydimID[gridindex];
+    }
+  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+  int zid = streamptr->zaxisID[zaxisindex];
 
-  streamptr->rtsteps = 2;
+  int ndims = 0;
+#define addDimension(startCoord, length) do \
+    { \
+      (*start)[ndims] = startCoord; \
+      (*count)[ndims] = length; \
+      ndims++; \
+    } while(0)
+  if ( tsteptype != TSTEP_CONSTANT ) addDimension((size_t)tsID, 1);
+  if ( zid != UNDEFID ) addDimension(0, (size_t)zaxisInqSize(zaxisID));
+  if ( yid != UNDEFID ) addDimension(0, (size_t)gridInqYsize(gridID));
+  if ( xid != UNDEFID ) addDimension(0, (size_t)gridInqXsize(gridID));
+#undef addDimension
 
-  if ( streamptr->ntsteps == -1 )
-    {
-      tsID = tstepsNewEntry(streamptr);
-      if ( tsID != streamptr->rtsteps )
-	Error("Internal error. tsID = %d", tsID);
+  assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
+  assert(ndims <= (int)(sizeof(*count)/sizeof(**count)));
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
-      streamptr->tsteps[tsID].position = recpos;
+  if ( CDI_Debug )
+    for (int idim = 0; idim < ndims; idim++)
+      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
+}
+
+//Scans the data array for missVals, optionally applying first a scale factor and then an offset.
+//Returns the number of missing + out-of-range values encountered.
+static
+size_t cdfDoInputDataTransformationDP(size_t valueCount, double *data, bool haveMissVal, double missVal, double scaleFactor, double offset, double validMin, double validMax)
+ {
+  const bool haveOffset   = IS_NOT_EQUAL(offset, 0);
+  const bool haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1);
+  size_t missValCount = 0;
+
+  if ( IS_EQUAL(validMin, VALIDMISS) ) validMin = DBL_MIN;
+  if ( IS_EQUAL(validMax, VALIDMISS) ) validMax = DBL_MAX;
+
+  bool haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin,DBL_MIN));
+  assert(!haveRangeCheck || haveMissVal);
+
+  switch ((int)haveMissVal | ((int)haveScaleFactor << 1)
+          | ((int)haveOffset << 2) | ((int)haveRangeCheck << 3))
+    {
+    case 15: /* haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset */
+      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;
+        }
+      break;
+    case 13: /* haveRangeCheck & haveMissVal & haveOffset */
+      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;
+        }
+      break;
+    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;
+        }
+      break;
+    case 9: /* haveRangeCheck & haveMissVal */
+      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 : data[i];
+        }
+      break;
+    case 7: /* haveMissVal & haveScaleFactor & haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        if ( DBL_IS_EQUAL(data[i], missVal) )
+          missValCount++;
+        else
+          data[i] = data[i] * scaleFactor + offset;
+      break;
+    case 6: /* haveOffset & haveScaleFactor */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] = data[i] * scaleFactor + offset;
+      break;
+    case 5: /* haveMissVal & haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        if ( DBL_IS_EQUAL(data[i], missVal) )
+          missValCount++;
+        else
+          data[i] += offset;
+      break;
+    case 4: /* haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] += offset;
+      break;
+    case 3: /* haveMissVal & haveScaleFactor */
+      for ( size_t i = 0; i < valueCount; i++ )
+        if ( DBL_IS_EQUAL(data[i], missVal) )
+          missValCount++;
+        else
+          data[i] *= scaleFactor;
+      break;
+    case 2: /* haveScaleFactor */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] *= scaleFactor;
+      break;
+    case 1: /* haveMissVal */
+      for ( size_t i = 0; i < valueCount; i++ )
+        missValCount += (unsigned)DBL_IS_EQUAL(data[i], missVal);
+      break;
     }
 
-  return (0);
+  return missValCount;
 }
 
+static
+size_t cdfDoInputDataTransformationSP(size_t valueCount, float *data, bool haveMissVal, double missVal, double scaleFactor, double offset, double validMin, double validMax)
+ {
+  const bool haveOffset   = IS_NOT_EQUAL(offset, 0);
+  const bool haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1);
+  size_t missValCount = 0;
 
-int srvInqContents(stream_t *streamptr)
-{
-  int fileID;
-  int status = 0;
-
-  fileID = streamptr->fileID;
-
-  streamptr->curTsID = 0;
+  if ( IS_EQUAL(validMin, VALIDMISS) ) validMin = DBL_MIN;
+  if ( IS_EQUAL(validMax, VALIDMISS) ) validMax = DBL_MAX;
 
-  srvScanTimestep1(streamptr);
+  bool haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin,DBL_MIN));
+  assert(!haveRangeCheck || haveMissVal);
 
-  if ( streamptr->ntsteps == -1 ) status = srvScanTimestep2(streamptr);
+  switch ((int)haveMissVal | ((int)haveScaleFactor << 1)
+          | ((int)haveOffset << 2) | ((int)haveRangeCheck << 3))
+    {
+    case 15: /* haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset */
+      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);
+        }
+      break;
+    case 13: /* haveRangeCheck & haveMissVal & haveOffset */
+      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);
+        }
+      break;
+    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);
+        }
+      break;
+    case 9: /* haveRangeCheck & haveMissVal */
+      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 : data[i];
+        }
+      break;
+    case 7: /* haveMissVal & haveScaleFactor & haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        if ( DBL_IS_EQUAL(data[i], missVal) )
+          missValCount++;
+        else
+          data[i] = (float)(data[i] * scaleFactor + offset);
+      break;
+    case 6: /* haveOffset & haveScaleFactor */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] = (float)(data[i] * scaleFactor + offset);
+      break;
+    case 5: /* haveMissVal & haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        if ( DBL_IS_EQUAL(data[i], missVal) )
+          missValCount++;
+        else
+          data[i] = (float)(data[i] + offset);
+      break;
+    case 4: /* haveOffset */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] = (float)(data[i] + offset);
+      break;
+    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);
+      break;
+    case 2: /* haveScaleFactor */
+      for ( size_t i = 0; i < valueCount; i++ )
+        data[i] = (float)(data[i] * scaleFactor);
+      break;
+    case 1: /* haveMissVal */
+      for ( size_t i = 0; i < valueCount; i++ )
+        missValCount += (unsigned)DBL_IS_EQUAL(data[i], missVal);
+      break;
+    }
 
-  fileSetPos(fileID, 0, SEEK_SET);
+  return missValCount;
+}
 
-  return (status);
+static
+size_t min_size(size_t a, size_t b)
+{
+  return a < b ? a : b;
 }
 
 static
-long srvScanTimestep(stream_t *streamptr)
+void transpose2dArrayDP(size_t inWidth, size_t inHeight, double *data)
 {
-  int header[8];
-  int status;
-  int fileID;
-  /* int rxsize = 0, rysize = 0; */
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  off_t recpos = 0;
-  int recID;
-  int rindex, nrecs = 0;
-  void *srvp = streamptr->record->exsep;
+  const size_t cacheBlockSize = 256;   // Purely an optimization parameter. Current value of 32 means we are handling 8kB blocks,
+                                       // which should be a decent compromise on many architectures.
+#ifdef __cplusplus
+  double *out[inHeight];
+  double *temp[inWidth];
+  temp[0] = (double *) Malloc(inHeight*inWidth*sizeof(double));
+  memcpy(temp[0], data, inHeight*inWidth*sizeof(double));
+  for(int i = 0; i < inHeight; i++) out[i] = data + (inWidth*i);
+  for(int i = 1; i < inWidth; i++) temp[i] = temp[0] + (inHeight*i);
+#else
+  double (*out)[inHeight] = (double (*)[inHeight])data;
+  double (*temp)[inWidth] = (double (*)[inWidth]) Malloc(inHeight*sizeof(*temp));
+  memcpy(temp, data, inHeight*sizeof(*temp));
+#endif
+
   /*
-  if ( CDI_Debug )
-    {
-      Message("streamID = %d", streamptr->self);
-      Message("cts = %d", streamptr->curTsID);
-      Message("rts = %d", streamptr->rtsteps);
-      Message("nts = %d", streamptr->ntsteps);
-    }
+  for ( size_t y = 0; y < inHeight; ++y )
+    for ( size_t x = 0; x < inWidth; ++x )
+      out[x][y] = temp[y][x];
   */
 
-  int tsID  = streamptr->rtsteps;
-  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
-
-  if ( streamptr->tsteps[tsID].recordSize == 0 )
+  for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
     {
-      cdi_create_records(streamptr, tsID);
-
-      nrecs = streamptr->tsteps[1].nrecs;
-
-      streamptr->tsteps[tsID].nrecs = nrecs;
-      streamptr->tsteps[tsID].recIDs = (int *) Malloc((size_t)nrecs * sizeof (int));
-      for ( recID = 0; recID < nrecs; recID++ )
-	streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
-
-      fileID = streamptr->fileID;
-
-      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
-
-      for ( rindex = 0; rindex <= nrecs; rindex++ )
-	{
-	  recpos = fileGetPos(fileID);
-	  status = srvRead(fileID, srvp);
-	  if ( status != 0 )
-	    {
-	      streamptr->ntsteps = streamptr->rtsteps + 1;
-	      break;
-	    }
-	  size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
-
-	  srvInqHeader(srvp, header);
-
-	  rcode  = header[0];
-	  rlevel = header[1];
-	  vdate  = header[2];
-	  vtime  = header[3];
-          /* rxsize = header[4]; */
-          /* rysize = header[5]; */
-
-	  param = cdiEncodeParam(rcode, 255, 255);
-
-	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
-	  if ( rindex == nrecs ) continue;
-	  recID = streamptr->tsteps[tsID].recIDs[rindex];
-
-	  if ( rindex == 0 )
-	    {
-	      taxis->type  = TAXIS_ABSOLUTE;
-	      taxis->vdate = vdate;
-	      taxis->vtime = vtime;
-	    }
-
-          if (    param  != streamptr->tsteps[tsID].records[recID].param
-               || rlevel != streamptr->tsteps[tsID].records[recID].ilevel )
-	    {
-	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
-		      tsID, recID,
-		      streamptr->tsteps[tsID].records[recID].param, param,
-		      streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
-	      Error("Invalid, unsupported or inconsistent record structure!");
-	    }
-
-	  streamptr->tsteps[tsID].records[recID].position = recpos;
-	  streamptr->tsteps[tsID].records[recID].size = recsize;
-
-	  if ( CDI_Debug )
-	    Message("%4d%8d%4d%8d%8d%6d", rindex, (int)recpos, rcode, rlevel, vdate, vtime);
-	}
-
-      streamptr->rtsteps++;
+      for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
+        {
+          for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
+            {
+              for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
+                {
+                  out[x][y] = temp[y][x];
+                }
+            }
+        }
+    }
 
-      if ( streamptr->ntsteps != streamptr->rtsteps )
-	{
-	  tsID = tstepsNewEntry(streamptr);
-	  if ( tsID != streamptr->rtsteps )
-	    Error("Internal error. tsID = %d", tsID);
+  Free(temp[0]);
+}
 
-	  streamptr->tsteps[tsID-1].next   = 1;
-	  streamptr->tsteps[tsID].position = recpos;
-	}
+static
+void transpose2dArraySP(size_t inWidth, size_t inHeight, float *data)
+{
+  const size_t cacheBlockSize = 256;   // Purely an optimization parameter. Current value of 32 means we are handling 8kB blocks,
+                                       // which should be a decent compromise on many architectures.
+#ifdef __cplusplus
+  float *out[inHeight];
+  float *temp[inWidth];
+  temp[0] = (float *) Malloc(inHeight*inWidth*sizeof(float));
+  memcpy(temp[0], data, inHeight*inWidth*sizeof(float));
+  for(int i = 0; i < inHeight; i++) out[i] = data + (inWidth*i);
+  for(int i = 1; i < inWidth; i++) temp[i] = temp[0] + (inHeight*i);
+#else
+  float (*out)[inHeight] = (float (*)[inHeight])data;
+  float (*temp)[inWidth] = (float (*)[inWidth]) Malloc(inHeight*sizeof(*temp));
+  memcpy(temp, data, inHeight*sizeof(*temp));
+#endif
 
-      fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
-      streamptr->tsteps[tsID].position = recpos;
-    }
+  /*
+  for ( size_t y = 0; y < inHeight; ++y )
+    for ( size_t x = 0; x < inWidth; ++x )
+      out[x][y] = temp[y][x];
+  */
 
-  if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
+  for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
     {
-      Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
-      streamptr->ntsteps = tsID;
+      for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
+        {
+          for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
+            {
+              for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
+                {
+                  out[x][y] = temp[y][x];
+                }
+            }
+        }
     }
 
-  return (streamptr->ntsteps);
+  Free(temp);
 }
 
-
-int srvInqTimestep(stream_t *streamptr, int tsID)
+static
+void cdfInqDimIds(stream_t *streamptr, int varId, int (*outDimIds)[3])
 {
-  long ntsteps;
-  int nrecs;
-
-  if ( tsID == 0 && streamptr->rtsteps == 0 )
-    Error("Call to cdiInqContents missing!");
+  int gridId = vlistInqVarGrid(streamptr->vlistID, varId);
+  int gridindex = vlistGridIndex(streamptr->vlistID, gridId);
 
-  if ( CDI_Debug )
-    Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
+  (*outDimIds)[0] = (*outDimIds)[1] = (*outDimIds)[2] = UNDEFID;
+  switch ( gridInqType(gridId) )
+    {
+      case GRID_TRAJECTORY:
+        cdfReadGridTraj(streamptr, gridId);
+        break;
 
-  ntsteps = UNDEFID;
-  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == UNDEFID )
-    ntsteps = srvScanTimestep(streamptr);
+      case GRID_UNSTRUCTURED:
+        (*outDimIds)[0] = streamptr->xdimID[gridindex];
+        break;
 
-  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != UNDEFID )
-    {
-      nrecs = 0;
-    }
-  else
-    {
-      streamptr->curTsID = tsID;
-      nrecs = streamptr->tsteps[tsID].nrecs;
+      default:
+        (*outDimIds)[0] = streamptr->xdimID[gridindex];
+        (*outDimIds)[1] = streamptr->ydimID[gridindex];
+        break;
     }
 
-  return (nrecs);
+  int zaxisID = vlistInqVarZaxis(streamptr->vlistID, varId);
+  int zaxisindex = vlistZaxisIndex(streamptr->vlistID, zaxisID);
+  (*outDimIds)[2] = streamptr->zaxisID[zaxisindex];
 }
 
-
-void srvReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+static
+int cdfGetSkipDim(int fileId, int ncvarid, int (*dimIds)[3])
 {
-  int vlistID, fileID;
-  int levID, nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int header[8];
-  int tsid;
-  int recID;
-  int i;
-  double missval;
-  void *srvp = streamptr->record->exsep;
-
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
-
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
-
-  currentfilepos = fileGetPos(fileID);
+  if((*dimIds)[0] != UNDEFID) return 0;
+  if((*dimIds)[1] != UNDEFID) return 0;
+  int nvdims;
+  cdf_inq_varndims(fileId, ncvarid, &nvdims);
+  if(nvdims != 3) return 0;
 
-  for (levID = 0; levID < nlevs; levID++)
+  int varDimIds[3];
+  cdf_inq_vardimid(fileId, ncvarid, varDimIds);
+  size_t size = 0;
+  if ( (*dimIds)[2] == varDimIds[2] )
     {
-      /* NOTE: tiles are not supported here! */
-      recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-      recpos = streamptr->tsteps[tsid].records[recID].position;
-      fileSetPos(fileID, recpos, SEEK_SET);
-      if (srvRead(fileID, srvp) < 0)
-        abort();
-      srvInqHeader(srvp, header);
-      srvInqDataDP(srvp, &data[levID*gridsize]);
+      cdf_inq_dimlen(fileId, varDimIds[1], &size);
+      if ( size == 1 ) return 1;
     }
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
-
-  *nmiss = 0;
-  for ( i = 0; i < nlevs*gridsize; i++ )
-    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-      {
-	data[i] = missval;
-	(*nmiss)++;
-      }
+  else if ( (*dimIds)[2] == varDimIds[1] )
+    {
+      cdf_inq_dimlen(fileId, varDimIds[2], &size);
+      if ( size == 1 ) return 2;
+    }
+  return 0;
 }
 
-
-void srvReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
+static
+void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, bool *outSwapXY, size_t (*start)[4], size_t (*count)[4])
 {
-  int vlistID, fileID;
-  int nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int header[8];
-  int tsid;
-  int recID;
-  int i;
-  double missval;
-  void *srvp = streamptr->record->exsep;
-
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
-
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d",
-	     nlevs, gridID, gridsize);
-
-  currentfilepos = fileGetPos(fileID);
+  int tsID = streamptr->curTsID;
+  if ( CDI_Debug ) Message("tsID = %d", tsID);
 
-  /* NOTE: tiles are not supported here! */
-  recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-  recpos = streamptr->tsteps[tsid].records[recID].position;
-  fileSetPos(fileID, recpos, SEEK_SET);
-  if (srvRead(fileID, srvp) < 0)
-    abort();
-  srvInqHeader(srvp, header);
-  srvInqDataDP(srvp, data);
+  int fileId = streamptr->fileID;
+  int vlistId = streamptr->vlistID;
+  int ncvarid = streamptr->vars[varId].ncvarid;
 
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
+  int gridId = vlistInqVarGrid(vlistId, varId);
+  int tsteptype = vlistInqVarTsteptype(vlistId, varId);
+  int gridsize = gridInqSize(gridId);
 
-  *nmiss = 0;
-  for ( i = 0; i < gridsize; i++ )
-    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-      {
-	data[i] = missval;
-	(*nmiss)++;
-      }
-}
+  streamptr->numvals += gridsize;
 
+  int dimIds[3];    //this array joins the old variables xid, yid, and zid
+  cdfInqDimIds(streamptr, varId, &dimIds);
 
-void srvWriteVarDP(stream_t *streamptr, int varID, const double *data)
-{
-  int fileID;
-  int levID, nlevs, gridID, gridsize;
-  int zaxisID;
-  double level;
-  int header[8];
-  int xsize, ysize;
-  int datatype;
-  int tsID;
-  int vlistID;
-  int pdis, pcat, pnum;
-  srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
+  int skipdim = cdfGetSkipDim(fileId, ncvarid, &dimIds);
 
-  if ( CDI_Debug )
-    Message("streamID = %d  varID = %d", streamptr->self, varID);
+  int dimorder[3];
+  vlistInqVarDimorder(vlistId, varId, &dimorder);
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  tsID     = streamptr->curTsID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  nlevs    = zaxisInqSize(zaxisID);
+  *outSwapXY = (dimorder[2] == 2 || dimorder[0] == 1) && dimIds[0] != UNDEFID && dimIds[1] != UNDEFID ;
 
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+  int ndims = 0;
 
-  cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
+#define addDimension(startIndex, extent) do {   \
+      (*start)[ndims] = startIndex; \
+      (*count)[ndims] = extent; \
+      ndims++; \
+  } while(0)
 
-  header[0] = pnum;
-  header[2] = streamptr->tsteps[tsID].taxis.vdate;
-  header[3] = streamptr->tsteps[tsID].taxis.vtime;
+  if ( tsteptype != TSTEP_CONSTANT ) addDimension((size_t)tsID, 1);
+  if ( skipdim == 1 ) addDimension(0, 1);
 
-  xsize = gridInqXsize(gridID);
-  ysize = gridInqYsize(gridID);
-  if ( xsize == 0 || ysize == 0 )
+  for ( int id = 0; id < 3; ++id )
     {
-      xsize = gridInqSize(gridID);
-      ysize = 1;
-    }
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED ) ysize = 1;
-  if ( gridInqSize(gridID) != xsize*ysize )
-    Error("Internal problem with gridsize!");
-
-  header[4] = xsize;
-  header[5] = ysize;
-  header[6] = 0;
-  header[7] = 0;
-
-  datatype = vlistInqVarDatatype(vlistID, varID);
-
-  srvp->dprec = srvDefDatatype(datatype);
+      size_t size;
+      int curDimId = dimIds[dimorder[id]-1];
+      if ( curDimId == UNDEFID ) continue;
+      switch ( dimorder[id] )
+        {
+          Error("Internal errror: Malformed dimension order encountered. Please report this bug.\n");
+          case 1:
+          case 2:
+            cdf_inq_dimlen(fileId, curDimId, &size);
+            addDimension(0, size);
+            break;
 
-  for ( levID = 0; levID < nlevs; levID++ )
-    {
-      level = zaxisInqLevel(zaxisID, levID);
+          case 3:
+            addDimension((size_t)levelId, 1);
+            break;
 
-      header[1] = (int) level;
-      srvDefHeader(srvp, header);
-      srvDefDataDP(srvp, &data[levID*gridsize]);
-      srvWrite(fileID, srvp);
+          default:
+            Error("Internal errror: Malformed dimension order encountered. Please report this bug.\n");
+        }
     }
-}
 
+  if ( skipdim == 2 ) addDimension(0, 1);
 
-void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
-{
-  int fileID;
-  int gridID;
-  int zaxisID;
-  double level;
-  int header[8];
-  int xsize, ysize;
-  int datatype;
-  int tsID;
-  int vlistID;
-  int pdis, pcat, pnum;
-  srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
+  assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
+  assert(ndims <= (int)(sizeof(*count)/sizeof(**count)));
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  tsID     = streamptr->curTsID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  level    = zaxisInqLevel(zaxisID, levID);
+#undef addDimension
 
   if ( CDI_Debug )
-    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
+    for (int idim = 0; idim < ndims; idim++)
+      Message("dim = %d  start = %d  count = %d", idim, (*start)[idim], (*count)[idim]);
 
-  cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
+  int nvdims;
+  cdf_inq_varndims(fileId, ncvarid, &nvdims);
 
-  header[0] = pnum;
-  header[1] = (int) level;
-  header[2] = streamptr->tsteps[tsID].taxis.vdate;
-  header[3] = streamptr->tsteps[tsID].taxis.vtime;
+  if ( nvdims != ndims )
+    Error("Internal error, variable %s has an unsupported array structure!", vlistInqVarNamePtr(vlistId, varId));
+}
 
-  xsize = gridInqXsize(gridID);
-  ysize = gridInqYsize(gridID);
-  if ( xsize == 0 || ysize == 0 )
-    {
-      xsize = gridInqSize(gridID);
-      ysize = 1;
-    }
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED ) ysize = 1;
-  if ( gridInqSize(gridID) != xsize*ysize )
-    Error("Internal problem with gridsize!");
+static
+void cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+{
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-  header[4] = xsize;
-  header[5] = ysize;
-  header[6] = 0;
-  header[7] = 0;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  datatype = vlistInqVarDatatype(vlistID, varID);
+  int ncvarid = streamptr->vars[varID].ncvarid;
 
-  srvp->dprec = srvDefDatatype(datatype);
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  int zaxisID = vlistInqVarZaxis(vlistID, varID);
 
-  srvDefHeader(srvp, header);
-  srvDefDataDP(srvp, data);
-  srvWrite(fileID, srvp);
+  size_t start[4];
+  size_t count[4];
+  cdfGetSlapDescription(streamptr, varID, &start, &count);
+
+  cdf_get_vara_double(fileID, ncvarid, start, count, data);
+
+  size_t size = (size_t)gridInqSize(gridID)*(size_t)zaxisInqSize(zaxisID);
+  double missval = vlistInqVarMissval(vlistID, varID);
+  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
+  double validRange[2];
+  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
+    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
+  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
+  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
+  size_t nmiss_ = cdfDoInputDataTransformationDP(size, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
+  assert(nmiss_ <= INT_MAX);
+  *nmiss = (int)nmiss_;
 }
 
-#endif /* HAVE_LIBSERVICE */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
+static
+void cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss)
+{
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-#include <string.h>
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
+  int ncvarid = streamptr->vars[varID].ncvarid;
+
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  int zaxisID = vlistInqVarZaxis(vlistID, varID);
 
+  size_t start[4];
+  size_t count[4];
+  cdfGetSlapDescription(streamptr, varID, &start, &count);
 
+  cdf_get_vara_float(fileID, ncvarid, start, count, data);
 
-static void streamvar_init_recordtable(stream_t *streamptr, int varID, int isub)
-{
-  streamptr->vars[varID].recordTable[isub].nlevs    = 0;
-  streamptr->vars[varID].recordTable[isub].recordID = NULL;
-  streamptr->vars[varID].recordTable[isub].lindex   = NULL;
+  size_t size = (size_t)gridInqSize(gridID) * (size_t)zaxisInqSize(zaxisID);
+  double missval = vlistInqVarMissval(vlistID, varID);
+  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
+  double validRange[2];
+  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
+    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
+  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
+  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
+  size_t nmiss_ = cdfDoInputDataTransformationSP(size, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
+  assert(nmiss_ <= INT_MAX);
+  *nmiss = (int)nmiss_;
 }
 
 
-static
-void streamvar_init_entry(stream_t *streamptr, int varID)
+void cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss)
 {
-  streamptr->vars[varID].ncvarid      = CDI_UNDEFID;
-  streamptr->vars[varID].defmiss      = 0;
-
-  streamptr->vars[varID].subtypeSize  = 0;
-  streamptr->vars[varID].recordTable  = NULL;
-
-  streamptr->vars[varID].gridID       = CDI_UNDEFID;
-  streamptr->vars[varID].zaxisID      = CDI_UNDEFID;
-  streamptr->vars[varID].tsteptype    = CDI_UNDEFID;
-  streamptr->vars[varID].subtypeID    = CDI_UNDEFID;
+  if ( memtype == MEMTYPE_DOUBLE )
+    cdfReadVarDP(streamptr, varID, (double*) data, nmiss);
+  else
+    cdfReadVarSP(streamptr, varID, (float*) data, nmiss);
 }
 
 static
-int streamvar_new_entry(stream_t *streamptr)
+void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data, int *nmiss)
 {
-  int varID = 0;
-  int streamvarSize;
-  svarinfo_t *streamvar;
+  size_t start[4];
+  size_t count[4];
 
-  streamvarSize = streamptr->varsAllocated;
-  streamvar     = streamptr->vars;
-  /*
-    Look for a free slot in streamvar.
-    (Create the table the first time through).
-  */
-  if ( ! streamvarSize )
-    {
-      int i;
+  if ( CDI_Debug )
+    Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
 
-      streamvarSize = 2;
-      streamvar
-        = (svarinfo_t *) Malloc((size_t)streamvarSize * sizeof(svarinfo_t));
-      if ( streamvar == NULL )
-	{
-          Message("streamvarSize = %d", streamvarSize);
-	  SysError("Allocation of svarinfo_t failed");
-	}
+  int vlistID = streamptr->vlistID;
+  int fileID = streamptr->fileID;
 
-      for ( i = 0; i < streamvarSize; i++ )
-	streamvar[i].isUsed = FALSE;
+  bool swapxy;
+  cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
+
+  int ncvarid = streamptr->vars[varID].ncvarid;
+  int gridId = vlistInqVarGrid(vlistID, varID);
+  size_t gridsize = (size_t)gridInqSize(gridId);
+  size_t xsize = (size_t)gridInqXsize(gridId);
+  size_t ysize = (size_t)gridInqYsize(gridId);
+
+  if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT32 )
+    {
+      float *data_fp = (float *) Malloc(gridsize*sizeof(*data_fp));
+      cdf_get_vara_float(fileID, ncvarid, start, count, data_fp);
+      for ( size_t i = 0; i < gridsize; i++ )
+        data[i] = (double) data_fp[i];
+      Free(data_fp);
     }
-  else
+  else if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
     {
-      while ( varID < streamvarSize )
-	{
-	  if ( ! streamvar[varID].isUsed ) break;
-	  varID++;
-	}
+      nc_type xtype;
+      cdf_inq_vartype(fileID, ncvarid, &xtype);
+      if ( xtype == NC_BYTE )
+        {
+          for ( size_t i = 0; i < gridsize; i++ )
+            if ( data[i] < 0 ) data[i] += 256;
+        }
     }
-  /*
-    If the table overflows, double its size.
-  */
-  if ( varID == streamvarSize )
+  else
     {
-      int i;
+      cdf_get_vara_double(fileID, ncvarid, start, count, data);
+    }
 
-      streamvarSize = 2*streamvarSize;
-      streamvar
-        = (svarinfo_t *) Realloc(streamvar,
-                                 (size_t)streamvarSize * sizeof (svarinfo_t));
-      if ( streamvar == NULL )
-	{
-          Message("streamvarSize = %d", streamvarSize);
-	  SysError("Reallocation of svarinfo_t failed");
-	}
-      varID = streamvarSize/2;
+  if ( swapxy ) transpose2dArrayDP(ysize, xsize, data);
 
-      for ( i = varID; i < streamvarSize; i++ )
-	streamvar[i].isUsed = FALSE;
-    }
+  double missval = vlistInqVarMissval(vlistID, varID);
+  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
+  double validRange[2];
+  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
+    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
+  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
+  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
+  size_t nmiss_ = cdfDoInputDataTransformationDP(gridsize, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
+  assert(nmiss_ <= INT_MAX);
+  *nmiss = (int)nmiss_;
+}
 
-  streamptr->varsAllocated = streamvarSize;
-  streamptr->vars          = streamvar;
+static
+void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data, int *nmiss)
+{
+  size_t start[4];
+  size_t count[4];
 
-  streamvar_init_entry(streamptr, varID);
+  if ( CDI_Debug )
+    Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
 
-  streamptr->vars[varID].isUsed = TRUE;
-  return (varID);
-}
+  int vlistID = streamptr->vlistID;
+  int fileID = streamptr->fileID;
 
+  bool swapxy;
+  cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
 
-static void
-allocate_record_table_entry(stream_t *streamptr, int varID, int subID, int nlevs)
-{
-  int *level    = (int *) Malloc((size_t)nlevs * sizeof (int));
-  int *lindex   = (int *) Malloc((size_t)nlevs * sizeof (int));
+  int ncvarid = streamptr->vars[varID].ncvarid;
+  int gridId = vlistInqVarGrid(vlistID, varID);
+  size_t gridsize = (size_t)gridInqSize(gridId);
+  size_t xsize = (size_t)gridInqXsize(gridId);
+  size_t ysize = (size_t)gridInqYsize(gridId);
 
-  for (int levID = 0; levID < nlevs; levID++ )
+  if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT64 )
     {
-      level[levID]    = CDI_UNDEFID;
-      lindex[levID]   = levID;
+      double *data_dp = (double *) Malloc(gridsize*sizeof(*data_dp));
+      cdf_get_vara_double(fileID, ncvarid, start, count, data_dp);
+      for ( size_t i = 0; i < gridsize; i++ )
+        data[i] = (float) data_dp[i];
+      Free(data_dp);
+    }
+  else if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
+    {
+      nc_type xtype;
+      cdf_inq_vartype(fileID, ncvarid, &xtype);
+      if ( xtype == NC_BYTE )
+        {
+          for ( size_t i = 0; i < gridsize; i++ )
+            if ( data[i] < 0 ) data[i] += 256;
+        }
+    }
+  else
+    {
+      cdf_get_vara_float(fileID, ncvarid, start, count, data);
     }
 
-  streamptr->vars[varID].recordTable[subID].nlevs    = nlevs;
-  streamptr->vars[varID].recordTable[subID].recordID = level;
-  streamptr->vars[varID].recordTable[subID].lindex   = lindex;
+  if ( swapxy ) transpose2dArraySP(ysize, xsize, data);
+
+  double missval = vlistInqVarMissval(vlistID, varID);
+  bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
+  double validRange[2];
+  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
+    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
+  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
+  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
+  size_t nmiss_ = cdfDoInputDataTransformationSP(gridsize, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
+  assert(nmiss_ <= INT_MAX);
+  *nmiss = (int)nmiss_;
 }
 
 
-int stream_new_var(stream_t *streamptr, int gridID, int zaxisID, int tilesetID)
+void cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss)
 {
-  if ( CDI_Debug )
-    Message("gridID = %d  zaxisID = %d", gridID, zaxisID);
-
-  int varID = streamvar_new_entry(streamptr);
-  int nlevs = zaxisInqSize(zaxisID);
-
-  streamptr->nvars++;
-
-  streamptr->vars[varID].gridID  = gridID;
-  streamptr->vars[varID].zaxisID = zaxisID;
+  if ( memtype == MEMTYPE_DOUBLE )
+    cdfReadVarSliceDP(streamptr, varID, levelID, (double*) data, nmiss);
+  else
+    cdfReadVarSliceSP(streamptr, varID, levelID, (float*) data, nmiss);
+}
 
-  int nsub = 1;
-  if (tilesetID != CDI_UNDEFID)
-    nsub = subtypeInqSize(tilesetID); /* e.g. no of tiles */
-  if ( CDI_Debug )
-    Message("varID %d: create %d tiles with %d level(s), zaxisID=%d", varID, nsub, nlevs,zaxisID);
-  streamptr->vars[varID].recordTable = (sleveltable_t *) Malloc((size_t)nsub * sizeof (sleveltable_t));
-  if( streamptr->vars[varID].recordTable == NULL )
-    SysError("Allocation of leveltable failed!");
-  streamptr->vars[varID].subtypeSize = nsub;
 
-  for (int isub=0; isub<nsub; isub++) {
-    streamvar_init_recordtable(streamptr, varID, isub);
-    allocate_record_table_entry(streamptr, varID, isub, nlevs);
-    if ( CDI_Debug )
-      Message("streamptr->vars[varID].recordTable[isub].recordID[0]=%d",
-              streamptr->vars[varID].recordTable[isub].recordID[0]);
-  }
+void cdf_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss)
+{
+  if ( CDI_Debug ) Message("streamID = %d", streamptr->self);
 
-  streamptr->vars[varID].subtypeID = tilesetID;
+  int tsID    = streamptr->curTsID;
+  int vrecID  = streamptr->tsteps[tsID].curRecID;
+  int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
+  int varID   = streamptr->tsteps[tsID].records[recID].varID;
+  int levelID = streamptr->tsteps[tsID].records[recID].levelID;
 
-  return (varID);
+  if ( memtype == MEMTYPE_DOUBLE )
+    cdfReadVarSliceDP(streamptr, varID, levelID, (double*) data, nmiss);
+  else
+    cdfReadVarSliceSP(streamptr, varID, levelID, (float*) data, nmiss);
 }
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
+
+#endif
 /* Subroutines and data structures for storing "subtypes".             */
 /*                                                                     */
 /* A subtype is, for example, a list of TILES. This can be interpreted */
@@ -55936,7 +56922,7 @@ enum {
 
 
 /* ------------------------------------------------------------------- */
-/* SUBROUTINES FOR ATTRIBUTE LISTS				       */
+/* SUBROUTINES FOR ATTRIBUTE LISTS                                     */
 /* ------------------------------------------------------------------- */
 
 
@@ -56068,7 +57054,7 @@ static void subtypeAttsDuplicate(struct subtype_attr_t *a1, struct subtype_entry
 
 
 /* ------------------------------------------------------------------- */
-/* SUBROUTINES FOR LIST OF ENTRIES				       */
+/* SUBROUTINES FOR LIST OF ENTRIES                                     */
 /* ------------------------------------------------------------------- */
 
 
@@ -56192,7 +57178,7 @@ static void subtypeEntryDuplicate(struct subtype_entry_t *a1, subtype_t* dst)
 
 
 /* ------------------------------------------------------------------- */
-/* SUBROUTINES FOR THE SUBTYPE ITSELF				       */
+/* SUBROUTINES FOR THE SUBTYPE ITSELF                                  */
 /* ------------------------------------------------------------------- */
 
 /* Print-out subtype data structure together with its attributes. */
@@ -56403,7 +57389,7 @@ void subtypeDefEntryDataP(struct subtype_entry_t *subtype_entry_ptr, int key, in
 
 
 /* ------------------------------------------------------------------- */
-/* IMPLEMENTATIONS FOR KEY-VALUE-PAIR QUERIES			       */
+/* IMPLEMENTATIONS FOR KEY-VALUE-PAIR QUERIES                          */
 /* ------------------------------------------------------------------- */
 
 
@@ -56452,7 +57438,7 @@ subtype_query_t matchAND(subtype_query_t q1, subtype_query_t q2)
 
 
 /* ------------------------------------------------------------------- */
-/* SPECIFIC IMPLEMENTATIONS FOR TILE SETS			       */
+/* SPECIFIC IMPLEMENTATIONS FOR TILE SETS                              */
 /* ------------------------------------------------------------------- */
 
 
@@ -56464,39 +57450,39 @@ void tilesetInsertP(subtype_t *s1, subtype_t *s2)
 {
   if (s1 == NULL)  Error("Internal error!");
   if (s2 == NULL)  Error("Internal error!");
-  struct subtype_entry_t 
+  struct subtype_entry_t
     *entry1 = s1->entries,
     *entry2 = s2->entries;
   struct subtype_attr_t *att_ptr2;
 
   /* test all entries of set 2 against set 1, to check if entry
      already exists: */
-  if (subtypeAttsCompare(s1->globals.atts, s2->globals.atts) != differ) 
+  if (subtypeAttsCompare(s1->globals.atts, s2->globals.atts) != differ)
     {
       while (entry1 != NULL) {
-	int found = 1;
-	entry2 = s2->entries;
-	while (entry2 != NULL) {
-	  found &= (subtypeAttsCompare(entry1->atts, entry2->atts) != differ);
-	  entry2 = entry2->next;
-	}
-	if (found) 
-	  {
-	    return;
-	  }
-	entry1 = entry1->next;
+        int found = 1;
+        entry2 = s2->entries;
+        while (entry2 != NULL) {
+          found &= (subtypeAttsCompare(entry1->atts, entry2->atts) != differ);
+          entry2 = entry2->next;
+        }
+        if (found)
+          {
+            return;
+          }
+        entry1 = entry1->next;
       }
-    
+
       entry2 = s2->entries;
       while (entry2 != NULL) {
-	entry1 = subtypeEntryInsert(s1);
-	
-	att_ptr2 = entry2->atts;
-	while (att_ptr2 != NULL) {
-	  (void) subtypeAttrInsert(entry1, att_ptr2->key, att_ptr2->val);
-	  att_ptr2 = att_ptr2->next;
-	}
-	entry2 = entry2->next;
+        entry1 = subtypeEntryInsert(s1);
+
+        att_ptr2 = entry2->atts;
+        while (att_ptr2 != NULL) {
+          (void) subtypeAttrInsert(entry1, att_ptr2->key, att_ptr2->val);
+          att_ptr2 = att_ptr2->next;
+        }
+        entry2 = entry2->next;
       }
     }
   else
@@ -56512,7 +57498,7 @@ void tilesetInsertP(subtype_t *s1, subtype_t *s2)
 
 
 /* ------------------------------------------------------------------- */
-/* IMPLEMENTATIONS FOR ROUTINES VISIBLE THROUGH CDI.H		       */
+/* IMPLEMENTATIONS FOR ROUTINES VISIBLE THROUGH CDI.H                  */
 /* ------------------------------------------------------------------- */
 
 
@@ -56607,22 +57593,22 @@ int subtypeInqSubEntry(int subtypeID, subtype_query_t criterion)
       int match = 1;
       /* test if this entry matches ALL criteria. */
       for (int j=0; (j<criterion.nAND) && (match); j++)
-	{
-	  if (CDI_Debug)  Message("check criterion %d :  %d --?-- %d", j,
-				  criterion.key_value_pairs[0][j], criterion.key_value_pairs[1][j]);
-	  struct subtype_attr_t* att_ptr = 
-	    subtypeAttrFind(entry->atts, criterion.key_value_pairs[0][j]);
-	  if (att_ptr == NULL)
-	    {
-	      match = 0;
-	      if (CDI_Debug)  Message("did not find %d", criterion.key_value_pairs[0][j]);
-	    }
-	  else
-	    {
-	      if (CDI_Debug)  Message("found %d", criterion.key_value_pairs[0][j]);
-	      match &= (att_ptr->val == criterion.key_value_pairs[1][j]);
-	    }
-	}
+        {
+          if (CDI_Debug)  Message("check criterion %d :  %d --?-- %d", j,
+                                  criterion.key_value_pairs[0][j], criterion.key_value_pairs[1][j]);
+          struct subtype_attr_t* att_ptr =
+            subtypeAttrFind(entry->atts, criterion.key_value_pairs[0][j]);
+          if (att_ptr == NULL)
+            {
+              match = 0;
+              if (CDI_Debug)  Message("did not find %d", criterion.key_value_pairs[0][j]);
+            }
+          else
+            {
+              if (CDI_Debug)  Message("found %d", criterion.key_value_pairs[0][j]);
+              match &= (att_ptr->val == criterion.key_value_pairs[1][j]);
+            }
+        }
       if (match) return entry->self;
     }
     entry = entry->next;
@@ -56634,10 +57620,50 @@ int subtypeInqSubEntry(int subtypeID, subtype_query_t criterion)
 int subtypeInqTile(int subtypeID, int tileindex, int attribute)
 {
   return subtypeInqSubEntry(subtypeID, 
-			    matchAND(keyValuePair(cdiSubtypeAttributeName[SUBTYPE_ATT_TILEINDEX], tileindex),
-				     keyValuePair(cdiSubtypeAttributeName[SUBTYPE_ATT_TILEATTRIBUTE], attribute)));
+                            matchAND(keyValuePair(cdiSubtypeAttributeName[SUBTYPE_ATT_TILEINDEX], tileindex),
+                                     keyValuePair(cdiSubtypeAttributeName[SUBTYPE_ATT_TILEATTRIBUTE], attribute)));
 }
 
+int subtypeInqAttribute(int subtypeID, int index, const char* key, int* outValue)
+{
+  //Validate input params.
+  if(subtypeID == CDI_UNDEFID) xabort("CDI_UNDEFID was passed to %s() as a subtypeID. Please check the origin of that ID.", __func__);
+  subtype_t *subtype_ptr = (subtype_t *)reshGetVal(subtypeID, &subtypeOps);
+  if(!subtype_ptr) xabort("Internal error: subtypeID %d resolved to NULL.", subtypeID);
+
+  if((unsigned)index >= (unsigned)subtype_ptr->nentries)
+    {
+      xabort("index argument of %s() is out of range. Expected 0 <= index < %d, but got index = %d.", __func__, subtype_ptr->nentries, index);
+    }
+
+#ifndef __cplusplus
+  if(!outValue) outValue = &(int){0};
+#else
+  int dummy = 0;
+  if(!outValue) outValue = &dummy;
+#endif
+
+  if(!key) return CDI_EINVAL;
+  int iKey = attribute_to_index(key);
+  if(iKey < 0) return CDI_EINVAL;
+
+  //Find the entry.
+  struct subtype_entry_t* entry = subtype_ptr->entries;
+  for(; index--; entry = entry->next) if(!entry) xabort("internal error: preliminary end of subtype entry list");
+
+  //Find the attribute.
+  for(struct subtype_attr_t* attribute = entry->atts; attribute; attribute = attribute->next)
+    {
+      if(attribute->key == iKey)
+        {
+          *outValue = attribute->val;
+          return CDI_NOERR;
+        }
+    }
+
+  //Failed to find the attribute if this point is reached.
+  return CDI_EINVAL;
+}
 
 /* Construct a new subtype for a tile set. If a corresponding subtype
  * already exists, then we return this subtype ID instead. 
@@ -56694,7 +57720,7 @@ int vlistInsertTrivialTileSubtype(int vlistID)
 
 
 /* ------------------------------------------------------------------- */
-/* NOT YET IMPLEMENTED						       */
+/* NOT YET IMPLEMENTED                                                 */
 /* ------------------------------------------------------------------- */
 
 static int subtypeGetPackSize( void * subtype_ptr, void *context)
@@ -56791,6 +57817,7 @@ int tableDef(int modelID, int tablegribID, const char *tablename);
  * require-trailing-newline: t
  * End:
  */
+/* Automatically generated, do not edit! */
 #ifndef _TABLE_H
 #define _TABLE_H
 
@@ -57345,177 +58372,177 @@ static const PAR mpiom1[] = {
 };
 
 static const PAR ecmwf[] = {
-  {   1, 0, "STRF",   "Stream function",                                            "m**2 s**-1"            },
-  {   2, 0, "VPOT",   "Velocity potential",                                         "m**2 s**-1"            },
-  {   3, 0, "PT",     "Potential temperature",                                      "K"                     },
-  {   4, 0, "EQPT",   "Equivalent potential temperature",                           "K"                     },
-  {   5, 0, "SEPT",   "Saturated equivalent potential temperature",                 "K"                     },
-  {  11, 0, "UDVW",   "U component of divergent wind",                              "m s**-1"               },
-  {  12, 0, "VDVW",   "V component of divergent wind",                              "m s**-1"               },
-  {  13, 0, "URTW",   "U component of rotational wind",                             "m s**-1"               },
-  {  14, 0, "VRTW",   "V component of rotational wind",                             "m s**-1"               },
-  {  21, 0, "UCTP",   "Unbalanced component of temperature",                        "K"                     },
-  {  22, 0, "UCLN",   "Unbalanced component of logarithm of surface pressure",       NULL                   },
-  {  23, 0, "UCDV",   "Unbalanced component of divergence",                         "s**-1"                 },
-  {  26, 0, "CL",     "Lake cover",                                                  NULL                   },
-  {  27, 0, "CVL",    "Low vegetation cover",                                        NULL                   },
-  {  28, 0, "CVH",    "High vegetation cover",                                       NULL                   },
-  {  29, 0, "TVL",    "Type of low vegetation",                                      NULL                   },
-  {  30, 0, "TVH",    "Type of high vegetation",                                     NULL                   },
-  {  31, 0, "CI",     "Sea-ice cover",                                               NULL                   },
-  {  32, 0, "ASN",    "Snow albedo",                                                 NULL                   },
-  {  33, 0, "RSN",    "Snow density kg",                                            "m**-3"                 },
-  {  34, 0, "SSTK",   "Sea surface temperature",                                    "K"                     },
-  {  35, 0, "ISTL1",  "Ice surface temperature layer 1",                            "K"                     },
-  {  36, 0, "ISTL2",  "Ice surface temperature layer 2",                            "K"                     },
-  {  37, 0, "ISTL3",  "Ice surface temperature layer 3",                            "K"                     },
-  {  38, 0, "ISTL4",  "Ice surface temperature layer 4",                            "K"                     },
-  {  39, 0, "SWVL1",  "Volumetric soil water layer 1",                              "m**3 m**-3"            },
-  {  40, 0, "SWVL2",  "Volumetric soil water layer 2",                              "m**3 m**-3"            },
-  {  41, 0, "SWVL3",  "Volumetric soil water layer 3",                              "m**3 m**-3"            },
-  {  42, 0, "SWVL4",  "Volumetric soil water layer 4",                              "m**3 m**-3"            },
-  {  43, 0, "SLT",    "Soil type",                                                   NULL                   },
-  {  44, 0, "ES",     "Snow evaporation m of water",                                 NULL                   },
-  {  45, 0, "SMLT",   "Snowmelt m of water",                                         NULL                   },
-  {  46, 0, "SDUR",   "Solar duration",                                             "s"                     },
-  {  47, 0, "DSRP",   "Direct solar radiation",                                     "w m**-2"               },
-  {  48, 0, "MAGSS",  "Magnitude of surface stress",                                "N m**-2 s"             },
-  {  49, 0, "WG10",   "Wind gust at 10 metres",                                     "m s**-1"               },
-  {  50, 0, "LSPF",   "Large-scale precipitation fraction",                         "s"                     },
-  {  51, 0, "MX2T24", "Maximum 2 metre temperature",                                "K"                     },
-  {  52, 0, "MN2T24", "Minimum 2 metre temperature",                                "K"                     },
-  {  53, 0, "MONT",   "Montgomery potential",                                       "m**2 s**-2"            },
-  {  54, 0, "PRES",   "Pressure",                                                   "Pa"                    },
-  {  55, 0, "MN2T24", "Mean 2 metre temperature past 24 hours",                     "K"                     },
-  {  56, 0, "MN2D24", "Mean 2 metre dewpoint temperature past 24 hours",            "K"                     },
-  {  60, 0, "PV",     "Potential vorticity",                                        "K m**2 kg**-1 s**-1"   },
-  { 127, 0, "AT",     "Atmospheric tide",                                            NULL                   },
-  { 128, 0, "BV",     "Budget values",                                               NULL                   },
-  { 129, 0, "Z",      "Geopotential",                                               "m**2 s**-2"            },
-  { 130, 0, "T",      "Temperature",                                                "K"                     },
-  { 131, 0, "U",      "U velocity",                                                 "m s**-1"               },
-  { 132, 0, "V",      "V velocity",                                                 "m s**-1"               },
-  { 133, 0, "Q",      "Specific humidity",                                          "kg kg**-1"             },
-  { 134, 0, "SP",     "Surface pressure",                                           "Pa"                    },
-  { 135, 0, "W",      "Vertical velocity",                                          "Pa s**-1"              },
-  { 136, 0, "TCW",    "Total column water",                                         "kg m**-2"              },
-  { 137, 0, "TCWV",   "Total column water vapour",                                  "kg m**-2"              },
-  { 138, 0, "VO",     "Vorticity (relative)",                                       "s**-1"                 },
-  { 139, 0, "STL1",   "Soil temperature level 1",                                   "K"                     },
-  { 140, 0, "SWL1",   "Soil wetness level 1 m of water",                             NULL                   },
-  { 141, 0, "SD",     "Snow depth         1 m of water equivalent",                  NULL                   },
-  { 142, 0, "LSP",    "Stratiform precipitation (Large scale precipitation)",       "m"                     },
-  { 143, 0, "CP",     "Convective precipitation",                                   "m"                     },
-  { 144, 0, "SF",     "Snowfall (convective + stratiform)",                         "m"                     },
-  { 145, 0, "BLD",    "Boundary layer dissipation",                                 "W m**-2 s"             },
-  { 146, 0, "SSHF",   "Surface sensible heat flux",                                 "W m**-2 s"             },
-  { 147, 0, "SLHF",   "Surface latent heat flux",                                   "W m**-2 s"             },
-  { 148, 0, "CHNK",   "Charnock",                                                    NULL                   },
-  { 149, 0, "SNR",    "Surface net radiation",                                      "W m**-2 s"             },
-  { 150, 0, "TNR",    "Top net radiation",                                           NULL                   },
-  { 151, 0, "MSL",    "Mean sea-level pressure",                                    "Pa"                    },
-  { 152, 0, "LNSP",   "Logarithm of surface pressure",                               NULL                   },
-  { 153, 0, "SWHR",   "Short-wave heating rate",                                    "K"                     },
-  { 154, 0, "LWHR",   "Long-wave heating rate",                                     "K"                     },
-  { 155, 0, "D",      "Divergence",                                                 "s**-1"                 },
-  { 156, 0, "GH",     "Height m Geopotential height",                                NULL                   },
-  { 157, 0, "R",      "Relative humidity",                                          "%"                     },
-  { 158, 0, "TSP",    "Tendency of surface pressure",                               "Pa s**-1"              },
-  { 159, 0, "BLH",    "Boundary layer height",                                      "m"                     },
-  { 160, 0, "SDOR",   "Standard deviation of orography",                             NULL                   },
-  { 161, 0, "ISOR",   "Anisotropy of sub-gridscale orography",                       NULL                   },
-  { 162, 0, "ANOR",   "Angle of sub-gridscale orography",                           "rad"                   },
-  { 163, 0, "SLOR",   "Slope of sub-gridscale orography",                            NULL                   },
-  { 164, 0, "TCC",    "Total cloud cover",                                           NULL                   },
-  { 165, 0, "U10M",   "10 metre U wind component",                                  "m s**-1"               },
-  { 166, 0, "V10M",   "10 metre V wind component",                                  "m s**-1"               },
-  { 167, 0, "T2M",    "2 metre temperature",                                        "K"                     },
-  { 168, 0, "D2M",    "2 metre dewpoint temperature",                               "K"                     },
-  { 169, 0, "SSRD",   "Surface solar radiation downwards",                          "W m**-2 s"             },
-  { 170, 0, "STL2",   "Soil temperature level 2",                                   "K"                     },
-  { 171, 0, "SWL2",   "Soil wetness level 2",                                       "m of water"            },
-  { 172, 0, "LSM",    "Land/sea mask",                                               NULL                   },
-  { 173, 0, "SR",     "Surface roughness",                                          "m"                     },
-  { 174, 0, "AL",     "Albedo",                                                      NULL                   },
-  { 175, 0, "STRD",   "Surface thermal radiation downwards",                        "W m**-2 s"             },
-  { 176, 0, "SSR",    "Surface solar radiation",                                    "W m**-2 s"             },
-  { 177, 0, "STR",    "Surface thermal radiation",                                  "W m**-2 s"             },
-  { 178, 0, "TSR",    "Top solar radiation",                                        "W m**-2 s"             },
-  { 179, 0, "TTR",    "Top thermal radiation",                                      "W m**-2 s"             },
-  { 180, 0, "EWSS",   "East/West surface stress",                                   "N m**-2 s"             },
-  { 181, 0, "NSSS",   "North/South surface stress",                                 "N m**-2 s"             },
-  { 182, 0, "E",      "Evaporation",                                                "m of water"            },
-  { 183, 0, "STL3",   "Soil temperature level 3",                                   "K"                     },
-  { 184, 0, "SWL3",   "Soil wetness level 3",                                       "m of water"            },
-  { 185, 0, "CCC",    "Convective cloud cover",                                      NULL                   },
-  { 186, 0, "LCC",    "Low cloud cover",                                             NULL                   },
-  { 187, 0, "MCC",    "Medium cloud cover",                                          NULL                   },
-  { 188, 0, "HCC",    "High cloud cover",                                            NULL                   },
-  { 189, 0, "SUND",   "Sunshine duration",                                          "s"                     },
-  { 190, 0, "EWOV",   "EW component of subgrid orographic variance",                "m**2"                  },
-  { 191, 0, "NSOV",   "NS component of subgrid orographic variance",                "m**2"                  },
-  { 192, 0, "NWOV",   "NWSE component of subgrid orographic variance",              "m**2"                  },
-  { 193, 0, "NEOV",   "NESW component of subgrid orographic variance",              "m**2"                  },
-  { 194, 0, "BTMP",   "Brightness temperature",                                     "K"                     },
-  { 195, 0, "LGWS",   "Lat. component of gravity wave stress",                      "N m**-2 s"             },
-  { 196, 0, "MGWS",   "Meridional component of gravity wave stress",                "N m**-2 s"             },
-  { 197, 0, "GWD",    "Gravity wave dissipation",                                   "W m**-2 s"             },
-  { 198, 0, "SRC",    "Skin reservoir content",                                     "m of water"            },
-  { 199, 0, "VEG",    "Vegetation fraction",                                         NULL                   },
-  { 200, 0, "VSO",    "Variance of sub-gridscale orography",                        "m**2"                  },
-  { 201, 0, "MX2T",   "Maximum 2 metre temperature since previous post-processing", "K"                     },
-  { 202, 0, "MN2T",   "Minimum 2 metre temperature since previous post-processing", "K"                     },
-  { 203, 0, "O3",     "Ozone mass mixing ratio",                                    "kg kg**-1"             },
-  { 204, 0, "PAW",    "Precipiation analysis weights",                               NULL                   },
-  { 205, 0, "RO",     "Runoff",                                                     "m"                     },
-  { 206, 0, "TCO3",   "Total column ozone",                                         "kg m**-2"              },
-  { 207, 0, "WS10",   "10 meter windspeed",                                         "m s**-1"               },
-  { 208, 0, "TSRC",   "Top net solar radiation, clear sky",                         "W m**-2"               },
-  { 209, 0, "TTRC",   "Top net thermal radiation, clear sky",                       "W m**-2"               },
-  { 210, 0, "SSRC",   "Surface net solar radiation, clear sky",                     "W m**-2"               },
-  { 211, 0, "STRC",   "Surface net thermal radiation, clear sky",                   "W m**-2"               },
-  { 212, 0, "SI",     "Solar insolation",                                           "W m**-2"               },
-  { 214, 0, "DHR",    "Diabatic heating by radiation",                              "K"                     },
-  { 215, 0, "DHVD",   "Diabatic heating by vertical diffusion",                     "K"                     },
-  { 216, 0, "DHCC",   "Diabatic heating by cumulus convection",                     "K"                     },
-  { 217, 0, "DHLC",   "Diabatic heating large-scale condensation",                  "K"                     },
-  { 218, 0, "VDZW",   "Vertical diffusion of zonal wind",                           "m s**-1"               },
-  { 219, 0, "VDMW",   "Vertical diffusion of meridional wind",                      "m s**-1"               },
-  { 220, 0, "EWGD",   "EW gravity wave drag tendency",                              "m s**-1"               },
-  { 221, 0, "NSGD",   "NS gravity wave drag tendency",                              "m s**-1"               },
-  { 222, 0, "CTZW",   "Convective tendency of zonal wind",                          "m s**-1"               },
-  { 223, 0, "CTMW",   "Convective tendency of meridional wind",                     "m s**-1"               },
-  { 224, 0, "VDH",    "Vertical diffusion of humidity",                             "kg kg**-1"             },
-  { 225, 0, "HTCC",   "Humidity tendency by cumulus convection",                    "kg kg**-1"             },
-  { 226, 0, "HTLC",   "Humidity tendency large-scale condensation",                 "kg kg**-1"             },
-  { 227, 0, "CRNH",   "Change from removing negative humidity",                     "kg kg**-1"             },
-  { 228, 0, "TP",     "Total precipitation",                                        "m"                     },
-  { 229, 0, "IEWS",   "Instantaneous X surface stress",                             "N m**-2"               },
-  { 230, 0, "INSS",   "Instantaneous Y surface stress",                             "N m**-2"               },
-  { 231, 0, "ISHF",   "Instantaneous surface heat flux",                            "W m**-2"               },
-  { 232, 0, "IE",     "Instantaneous moisture flux",                                "kg m**-2 s"            },
-  { 233, 0, "ASQ",    "Apparent surface humidity",                                  "kg kg**-1"             },
-  { 234, 0, "LSRH",   "Logarithm of surface roughness length for heat",              NULL                   },
-  { 235, 0, "SKT",    "Skin temperature",                                           "K"                     },
-  { 236, 0, "STL4",   "Soil temperature level 4",                                   "K"                     },
-  { 237, 0, "SWL4",   "Soil wetness level 4",                                       "m"                     },
-  { 238, 0, "TSN",    "Temperature of snow layer",                                  "K"                     },
-  { 239, 0, "CSF",    "Convective snowfall",                                        "m of water equivalent" },
-  { 240, 0, "LSF",    "Large-scale snowfall",                                       "m of water equivalent" },
-  { 241, 0, "ACF",    "Accumulated cloud fraction tendency",                         NULL                   },
-  { 242, 0, "ALW",    "Accumulated liquid water tendency",                           NULL                   },
-  { 243, 0, "FAL",    "Forecast albedo",                                             NULL                   },
-  { 244, 0, "FSR",    "Forecast surface roughness",                                 "m"                     },
-  { 245, 0, "FLSR",   "Forecast log of surface roughness for heat",                  NULL                   },
-  { 246, 0, "CLWC",   "Cloud liquid water content",                                 "kg kg**-1"             },
-  { 247, 0, "CIWC",   "Cloud ice water content",                                    "kg kg**-1"             },
-  { 248, 0, "CC",     "Cloud cover",                                                 NULL                   },
-  { 249, 0, "AIW",    "Accumulated ice water tendency",                              NULL                   },
-  { 250, 0, "ICE",    "Ice age",                                                     NULL                   },
-  { 251, 0, "ATTE",   "Adiabatic tendency of temperature",                          "K"                     },
-  { 252, 0, "ATHE",   "Adiabatic tendency of humidity",                             "kg kg**-1"             },
-  { 253, 0, "ATZE",   "Adiabatic tendency of zonal wind",                           "m s**-1"               },
-  { 254, 0, "ATMW",   "Adiabatic tendency of meridional wind",                      "m s**-1"               },
+  {   1, 0, "STRF",     "Stream function",                                            "m**2 s**-1"            },
+  {   2, 0, "VPOT",     "Velocity potential",                                         "m**2 s**-1"            },
+  {   3, 0, "PT",       "Potential temperature",                                      "K"                     },
+  {   4, 0, "EQPT",     "Equivalent potential temperature",                           "K"                     },
+  {   5, 0, "SEPT",     "Saturated equivalent potential temperature",                 "K"                     },
+  {  11, 0, "UDVW",     "U component of divergent wind",                              "m s**-1"               },
+  {  12, 0, "VDVW",     "V component of divergent wind",                              "m s**-1"               },
+  {  13, 0, "URTW",     "U component of rotational wind",                             "m s**-1"               },
+  {  14, 0, "VRTW",     "V component of rotational wind",                             "m s**-1"               },
+  {  21, 0, "UCTP",     "Unbalanced component of temperature",                        "K"                     },
+  {  22, 0, "UCLN",     "Unbalanced component of logarithm of surface pressure",       NULL                   },
+  {  23, 0, "UCDV",     "Unbalanced component of divergence",                         "s**-1"                 },
+  {  26, 0, "CL",       "Lake cover",                                                  NULL                   },
+  {  27, 0, "CVL",      "Low vegetation cover",                                        NULL                   },
+  {  28, 0, "CVH",      "High vegetation cover",                                       NULL                   },
+  {  29, 0, "TVL",      "Type of low vegetation",                                      NULL                   },
+  {  30, 0, "TVH",      "Type of high vegetation",                                     NULL                   },
+  {  31, 0, "CI",       "Sea-ice cover",                                               NULL                   },
+  {  32, 0, "ASN",      "Snow albedo",                                                 NULL                   },
+  {  33, 0, "RSN",      "Snow density kg",                                            "m**-3"                 },
+  {  34, 0, "SSTK",     "Sea surface temperature",                                    "K"                     },
+  {  35, 0, "ISTL1",    "Ice surface temperature layer 1",                            "K"                     },
+  {  36, 0, "ISTL2",    "Ice surface temperature layer 2",                            "K"                     },
+  {  37, 0, "ISTL3",    "Ice surface temperature layer 3",                            "K"                     },
+  {  38, 0, "ISTL4",    "Ice surface temperature layer 4",                            "K"                     },
+  {  39, 0, "SWVL1",    "Volumetric soil water layer 1",                              "m**3 m**-3"            },
+  {  40, 0, "SWVL2",    "Volumetric soil water layer 2",                              "m**3 m**-3"            },
+  {  41, 0, "SWVL3",    "Volumetric soil water layer 3",                              "m**3 m**-3"            },
+  {  42, 0, "SWVL4",    "Volumetric soil water layer 4",                              "m**3 m**-3"            },
+  {  43, 0, "SLT",      "Soil type",                                                   NULL                   },
+  {  44, 0, "ES",       "Snow evaporation m of water",                                 NULL                   },
+  {  45, 0, "SMLT",     "Snowmelt m of water",                                         NULL                   },
+  {  46, 0, "SDUR",     "Solar duration",                                             "s"                     },
+  {  47, 0, "DSRP",     "Direct solar radiation",                                     "w m**-2"               },
+  {  48, 0, "MAGSS",    "Magnitude of surface stress",                                "N m**-2 s"             },
+  {  49, 0, "WG10",     "Wind gust at 10 metres",                                     "m s**-1"               },
+  {  50, 0, "LSPF",     "Large-scale precipitation fraction",                         "s"                     },
+  {  51, 0, "MX2T24",   "Maximum 2 metre temperature",                                "K"                     },
+  {  52, 0, "MN2T24",   "Minimum 2 metre temperature",                                "K"                     },
+  {  53, 0, "MONT",     "Montgomery potential",                                       "m**2 s**-2"            },
+  {  54, 0, "PRES",     "Pressure",                                                   "Pa"                    },
+  {  55, 0, "MEAN2T24", "Mean 2 metre temperature past 24 hours",                     "K"                     },
+  {  56, 0, "MEAN2D24", "Mean 2 metre dewpoint temperature past 24 hours",            "K"                     },
+  {  60, 0, "PV",       "Potential vorticity",                                        "K m**2 kg**-1 s**-1"   },
+  { 127, 0, "AT",       "Atmospheric tide",                                            NULL                   },
+  { 128, 0, "BV",       "Budget values",                                               NULL                   },
+  { 129, 0, "Z",        "Geopotential",                                               "m**2 s**-2"            },
+  { 130, 0, "T",        "Temperature",                                                "K"                     },
+  { 131, 0, "U",        "U velocity",                                                 "m s**-1"               },
+  { 132, 0, "V",        "V velocity",                                                 "m s**-1"               },
+  { 133, 0, "Q",        "Specific humidity",                                          "kg kg**-1"             },
+  { 134, 0, "SP",       "Surface pressure",                                           "Pa"                    },
+  { 135, 0, "W",        "Vertical velocity",                                          "Pa s**-1"              },
+  { 136, 0, "TCW",      "Total column water",                                         "kg m**-2"              },
+  { 137, 0, "TCWV",     "Total column water vapour",                                  "kg m**-2"              },
+  { 138, 0, "VO",       "Vorticity (relative)",                                       "s**-1"                 },
+  { 139, 0, "STL1",     "Soil temperature level 1",                                   "K"                     },
+  { 140, 0, "SWL1",     "Soil wetness level 1 m of water",                             NULL                   },
+  { 141, 0, "SD",       "Snow depth         1 m of water equivalent",                  NULL                   },
+  { 142, 0, "LSP",      "Stratiform precipitation (Large scale precipitation)",       "m"                     },
+  { 143, 0, "CP",       "Convective precipitation",                                   "m"                     },
+  { 144, 0, "SF",       "Snowfall (convective + stratiform)",                         "m"                     },
+  { 145, 0, "BLD",      "Boundary layer dissipation",                                 "W m**-2 s"             },
+  { 146, 0, "SSHF",     "Surface sensible heat flux",                                 "W m**-2 s"             },
+  { 147, 0, "SLHF",     "Surface latent heat flux",                                   "W m**-2 s"             },
+  { 148, 0, "CHNK",     "Charnock",                                                    NULL                   },
+  { 149, 0, "SNR",      "Surface net radiation",                                      "W m**-2 s"             },
+  { 150, 0, "TNR",      "Top net radiation",                                           NULL                   },
+  { 151, 0, "MSL",      "Mean sea-level pressure",                                    "Pa"                    },
+  { 152, 0, "LNSP",     "Logarithm of surface pressure",                               NULL                   },
+  { 153, 0, "SWHR",     "Short-wave heating rate",                                    "K"                     },
+  { 154, 0, "LWHR",     "Long-wave heating rate",                                     "K"                     },
+  { 155, 0, "D",        "Divergence",                                                 "s**-1"                 },
+  { 156, 0, "GH",       "Height m Geopotential height",                                NULL                   },
+  { 157, 0, "R",        "Relative humidity",                                          "%"                     },
+  { 158, 0, "TSP",      "Tendency of surface pressure",                               "Pa s**-1"              },
+  { 159, 0, "BLH",      "Boundary layer height",                                      "m"                     },
+  { 160, 0, "SDOR",     "Standard deviation of orography",                             NULL                   },
+  { 161, 0, "ISOR",     "Anisotropy of sub-gridscale orography",                       NULL                   },
+  { 162, 0, "ANOR",     "Angle of sub-gridscale orography",                           "rad"                   },
+  { 163, 0, "SLOR",     "Slope of sub-gridscale orography",                            NULL                   },
+  { 164, 0, "TCC",      "Total cloud cover",                                           NULL                   },
+  { 165, 0, "U10M",     "10 metre U wind component",                                  "m s**-1"               },
+  { 166, 0, "V10M",     "10 metre V wind component",                                  "m s**-1"               },
+  { 167, 0, "T2M",      "2 metre temperature",                                        "K"                     },
+  { 168, 0, "D2M",      "2 metre dewpoint temperature",                               "K"                     },
+  { 169, 0, "SSRD",     "Surface solar radiation downwards",                          "W m**-2 s"             },
+  { 170, 0, "STL2",     "Soil temperature level 2",                                   "K"                     },
+  { 171, 0, "SWL2",     "Soil wetness level 2",                                       "m of water"            },
+  { 172, 0, "LSM",      "Land/sea mask",                                               NULL                   },
+  { 173, 0, "SR",       "Surface roughness",                                          "m"                     },
+  { 174, 0, "AL",       "Albedo",                                                      NULL                   },
+  { 175, 0, "STRD",     "Surface thermal radiation downwards",                        "W m**-2 s"             },
+  { 176, 0, "SSR",      "Surface solar radiation",                                    "W m**-2 s"             },
+  { 177, 0, "STR",      "Surface thermal radiation",                                  "W m**-2 s"             },
+  { 178, 0, "TSR",      "Top solar radiation",                                        "W m**-2 s"             },
+  { 179, 0, "TTR",      "Top thermal radiation",                                      "W m**-2 s"             },
+  { 180, 0, "EWSS",     "East/West surface stress",                                   "N m**-2 s"             },
+  { 181, 0, "NSSS",     "North/South surface stress",                                 "N m**-2 s"             },
+  { 182, 0, "E",        "Evaporation",                                                "m of water"            },
+  { 183, 0, "STL3",     "Soil temperature level 3",                                   "K"                     },
+  { 184, 0, "SWL3",     "Soil wetness level 3",                                       "m of water"            },
+  { 185, 0, "CCC",      "Convective cloud cover",                                      NULL                   },
+  { 186, 0, "LCC",      "Low cloud cover",                                             NULL                   },
+  { 187, 0, "MCC",      "Medium cloud cover",                                          NULL                   },
+  { 188, 0, "HCC",      "High cloud cover",                                            NULL                   },
+  { 189, 0, "SUND",     "Sunshine duration",                                          "s"                     },
+  { 190, 0, "EWOV",     "EW component of subgrid orographic variance",                "m**2"                  },
+  { 191, 0, "NSOV",     "NS component of subgrid orographic variance",                "m**2"                  },
+  { 192, 0, "NWOV",     "NWSE component of subgrid orographic variance",              "m**2"                  },
+  { 193, 0, "NEOV",     "NESW component of subgrid orographic variance",              "m**2"                  },
+  { 194, 0, "BTMP",     "Brightness temperature",                                     "K"                     },
+  { 195, 0, "LGWS",     "Lat. component of gravity wave stress",                      "N m**-2 s"             },
+  { 196, 0, "MGWS",     "Meridional component of gravity wave stress",                "N m**-2 s"             },
+  { 197, 0, "GWD",      "Gravity wave dissipation",                                   "W m**-2 s"             },
+  { 198, 0, "SRC",      "Skin reservoir content",                                     "m of water"            },
+  { 199, 0, "VEG",      "Vegetation fraction",                                         NULL                   },
+  { 200, 0, "VSO",      "Variance of sub-gridscale orography",                        "m**2"                  },
+  { 201, 0, "MX2T",     "Maximum 2 metre temperature since previous post-processing", "K"                     },
+  { 202, 0, "MN2T",     "Minimum 2 metre temperature since previous post-processing", "K"                     },
+  { 203, 0, "O3",       "Ozone mass mixing ratio",                                    "kg kg**-1"             },
+  { 204, 0, "PAW",      "Precipiation analysis weights",                               NULL                   },
+  { 205, 0, "RO",       "Runoff",                                                     "m"                     },
+  { 206, 0, "TCO3",     "Total column ozone",                                         "kg m**-2"              },
+  { 207, 0, "WS10",     "10 meter windspeed",                                         "m s**-1"               },
+  { 208, 0, "TSRC",     "Top net solar radiation, clear sky",                         "W m**-2"               },
+  { 209, 0, "TTRC",     "Top net thermal radiation, clear sky",                       "W m**-2"               },
+  { 210, 0, "SSRC",     "Surface net solar radiation, clear sky",                     "W m**-2"               },
+  { 211, 0, "STRC",     "Surface net thermal radiation, clear sky",                   "W m**-2"               },
+  { 212, 0, "SI",       "Solar insolation",                                           "W m**-2"               },
+  { 214, 0, "DHR",      "Diabatic heating by radiation",                              "K"                     },
+  { 215, 0, "DHVD",     "Diabatic heating by vertical diffusion",                     "K"                     },
+  { 216, 0, "DHCC",     "Diabatic heating by cumulus convection",                     "K"                     },
+  { 217, 0, "DHLC",     "Diabatic heating large-scale condensation",                  "K"                     },
+  { 218, 0, "VDZW",     "Vertical diffusion of zonal wind",                           "m s**-1"               },
+  { 219, 0, "VDMW",     "Vertical diffusion of meridional wind",                      "m s**-1"               },
+  { 220, 0, "EWGD",     "EW gravity wave drag tendency",                              "m s**-1"               },
+  { 221, 0, "NSGD",     "NS gravity wave drag tendency",                              "m s**-1"               },
+  { 222, 0, "CTZW",     "Convective tendency of zonal wind",                          "m s**-1"               },
+  { 223, 0, "CTMW",     "Convective tendency of meridional wind",                     "m s**-1"               },
+  { 224, 0, "VDH",      "Vertical diffusion of humidity",                             "kg kg**-1"             },
+  { 225, 0, "HTCC",     "Humidity tendency by cumulus convection",                    "kg kg**-1"             },
+  { 226, 0, "HTLC",     "Humidity tendency large-scale condensation",                 "kg kg**-1"             },
+  { 227, 0, "CRNH",     "Change from removing negative humidity",                     "kg kg**-1"             },
+  { 228, 0, "TP",       "Total precipitation",                                        "m"                     },
+  { 229, 0, "IEWS",     "Instantaneous X surface stress",                             "N m**-2"               },
+  { 230, 0, "INSS",     "Instantaneous Y surface stress",                             "N m**-2"               },
+  { 231, 0, "ISHF",     "Instantaneous surface heat flux",                            "W m**-2"               },
+  { 232, 0, "IE",       "Instantaneous moisture flux",                                "kg m**-2 s"            },
+  { 233, 0, "ASQ",      "Apparent surface humidity",                                  "kg kg**-1"             },
+  { 234, 0, "LSRH",     "Logarithm of surface roughness length for heat",              NULL                   },
+  { 235, 0, "SKT",      "Skin temperature",                                           "K"                     },
+  { 236, 0, "STL4",     "Soil temperature level 4",                                   "K"                     },
+  { 237, 0, "SWL4",     "Soil wetness level 4",                                       "m"                     },
+  { 238, 0, "TSN",      "Temperature of snow layer",                                  "K"                     },
+  { 239, 0, "CSF",      "Convective snowfall",                                        "m of water equivalent" },
+  { 240, 0, "LSF",      "Large-scale snowfall",                                       "m of water equivalent" },
+  { 241, 0, "ACF",      "Accumulated cloud fraction tendency",                         NULL                   },
+  { 242, 0, "ALW",      "Accumulated liquid water tendency",                           NULL                   },
+  { 243, 0, "FAL",      "Forecast albedo",                                             NULL                   },
+  { 244, 0, "FSR",      "Forecast surface roughness",                                 "m"                     },
+  { 245, 0, "FLSR",     "Forecast log of surface roughness for heat",                  NULL                   },
+  { 246, 0, "CLWC",     "Cloud liquid water content",                                 "kg kg**-1"             },
+  { 247, 0, "CIWC",     "Cloud ice water content",                                    "kg kg**-1"             },
+  { 248, 0, "CC",       "Cloud cover",                                                 NULL                   },
+  { 249, 0, "AIW",      "Accumulated ice water tendency",                              NULL                   },
+  { 250, 0, "ICE",      "Ice age",                                                     NULL                   },
+  { 251, 0, "ATTE",     "Adiabatic tendency of temperature",                          "K"                     },
+  { 252, 0, "ATHE",     "Adiabatic tendency of humidity",                             "kg kg**-1"             },
+  { 253, 0, "ATZE",     "Adiabatic tendency of zonal wind",                           "m s**-1"               },
+  { 254, 0, "ATMW",     "Adiabatic tendency of meridional wind",                      "m s**-1"               },
 };
 
 static const PAR remo[] = {
@@ -58017,7 +59044,8 @@ static const PAR cosmo250[] = {
 };
 
 
-static void tableDefault(void)
+static
+void tableDefault(void)
 {
   int tableID, instID, modelID;
 
@@ -58216,15 +59244,6 @@ static void tableDefault(void)
 }
 
 #endif  /* _TABLE_H */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
 #if defined (HAVE_CONFIG_H)
 #endif
 
@@ -58581,7 +59600,7 @@ int tableRead(const char *tablefile)
       */
       if ( id == 0 ) continue;
 
-      while ( isdigit((int) *pline) ) pline++; 
+      while ( isdigit((int) *pline) ) pline++;
 
       if ( strchr(pline, '|') )
 	err = decodeForm2(pline, name, longname, units);
@@ -58590,7 +59609,7 @@ int tableRead(const char *tablefile)
 
       if ( err ) continue;
 
-      if ( name[0] ) sprintf(name, "var%d", id);
+      if ( name[0] == 0 ) sprintf(name, "var%d", id);
 
       tableDefEntry(tableID, id, name, longname, units);
     }
@@ -60216,28 +61235,26 @@ void cdiEncodeTimevalue(int days, int secs, int timeunit, double *timevalue)
     }
 }
 
+
 void timeval2vtime(double timevalue, taxis_t *taxis, int *vdate, int *vtime)
 {
-  int year, month, day, hour, minute, second;
-  int rdate, rtime;
-  int timeunit;
-  int calendar;
-  int julday, secofday, days, secs;
-
-  *vdate = 0;
-  *vtime = 0;
-
-  timeunit = (*taxis).unit;
-  calendar = (*taxis).calendar;
-
-  rdate  = (*taxis).rdate;
-  rtime  = (*taxis).rtime;
+  int rdate = taxis->rdate;
+  int rtime = taxis->rtime;
 
-  if ( rdate == 0 && rtime == 0 && DBL_IS_EQUAL(timevalue, 0.) ) return;
+  if ( DBL_IS_EQUAL(timevalue, 0.) )
+    {
+      *vdate = rdate;
+      *vtime = rtime;
+      return;
+    }
 
+  int year, month, day, hour, minute, second;
   cdiDecodeDate(rdate, &year, &month, &day);
   cdiDecodeTime(rtime, &hour, &minute, &second);
 
+  int timeunit = taxis->unit;
+  int calendar = taxis->calendar;
+
   if ( timeunit == TUNIT_MONTH && calendar == CALENDAR_360DAYS )
     {
       timeunit = TUNIT_DAY;
@@ -60246,24 +61263,22 @@ void timeval2vtime(double timevalue, taxis_t *taxis, int *vdate, int *vtime)
 
   if ( timeunit == TUNIT_MONTH || timeunit == TUNIT_YEAR )
     {
-      int nmon, dpm;
-      double fmon;
-
       if ( timeunit == TUNIT_YEAR ) timevalue *= 12;
 
-      nmon = (int) timevalue;
-      fmon = timevalue - nmon;
+      int nmon = (int) timevalue;
+      double fmon = timevalue - nmon;
 
       month += nmon;
 
       while ( month > 12 ) { month -= 12; year++; }
       while ( month <  1 ) { month += 12; year--; }
 
-      dpm = days_per_month(calendar, year, month);
+      int dpm = days_per_month(calendar, year, month);
       timeunit = TUNIT_DAY;
       timevalue = fmon*dpm;
     }
 
+  int julday, secofday, days, secs;
   encode_caldaysec(calendar, year, month, day, hour, minute, second, &julday, &secofday);
 
   cdiDecodeTimevalue(timeunit, timevalue, &days, &secs);
@@ -60622,50 +61637,49 @@ taxisPrintKernel(taxis_t * taxisptr, FILE * fp)
   taxisInqVdateBounds ( taxisptr->self, &vdate_lb, &vdate_ub);
   taxisInqVtimeBounds ( taxisptr->self, &vtime_lb, &vtime_ub);
 
-  fprintf ( fp, "#\n");
-  fprintf ( fp, "# taxisID %d\n", taxisptr->self);
-  fprintf ( fp, "#\n");
-  fprintf ( fp, "self        = %d\n", taxisptr->self );
-  fprintf ( fp, "used        = %d\n", taxisptr->used );
-  fprintf ( fp, "type        = %d\n", taxisptr->type );
-  fprintf ( fp, "vdate       = %d\n", taxisptr->vdate );
-  fprintf ( fp, "vtime       = %d\n", taxisptr->vtime );
-  fprintf ( fp, "rdate       = %d\n", taxisptr->rdate );
-  fprintf ( fp, "rtime       = %d\n", taxisptr->rtime );
-  fprintf ( fp, "fdate       = %d\n", taxisptr->fdate );
-  fprintf ( fp, "ftime       = %d\n", taxisptr->ftime );
-  fprintf ( fp, "calendar    = %d\n", taxisptr->calendar );
-  fprintf ( fp, "unit        = %d\n", taxisptr->unit );
-  fprintf ( fp, "numavg      = %d\n", taxisptr->numavg );
-  fprintf ( fp, "climatology = %d\n", taxisptr->climatology );
-  fprintf ( fp, "has_bounds  = %d\n", taxisptr->has_bounds );
-  fprintf ( fp, "vdate_lb    = %d\n", vdate_lb );
-  fprintf ( fp, "vtime_lb    = %d\n", vtime_lb );
-  fprintf ( fp, "vdate_ub    = %d\n", vdate_ub );
-  fprintf ( fp, "vtime_ub    = %d\n", vtime_ub );
-  fprintf ( fp, "fc_unit     = %d\n", taxisptr->fc_unit );
-  fprintf ( fp, "fc_period   = %g\n", taxisptr->fc_period );
-  fprintf ( fp, "\n");
-}
-
-static void taxisPrint ( int taxisID )
-{
-  taxis_t * taxisptr;
-
-  taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
-  taxisPrintKernel ( taxisptr, stdout );
+  fprintf(fp,
+          "#\n"
+          "# taxisID %d\n"
+          "#\n"
+          "self        = %d\n"
+          "used        = %d\n"
+          "type        = %d\n"
+          "vdate       = %d\n"
+          "vtime       = %d\n"
+          "rdate       = %d\n"
+          "rtime       = %d\n"
+          "fdate       = %d\n"
+          "ftime       = %d\n"
+          "calendar    = %d\n"
+          "unit        = %d\n"
+          "numavg      = %d\n"
+          "climatology = %d\n"
+          "has_bounds  = %d\n"
+          "vdate_lb    = %d\n"
+          "vtime_lb    = %d\n"
+          "vdate_ub    = %d\n"
+          "vtime_ub    = %d\n"
+          "fc_unit     = %d\n"
+          "fc_period   = %g\n"
+          "\n", taxisptr->self, taxisptr->self,
+          taxisptr->used, taxisptr->type,
+          taxisptr->vdate, taxisptr->vtime,
+          taxisptr->rdate, taxisptr->rtime,
+          taxisptr->fdate, taxisptr->ftime,
+          taxisptr->calendar, taxisptr->unit,
+          taxisptr->numavg, taxisptr->climatology,
+          taxisptr->has_bounds,
+          vdate_lb, vtime_lb, vdate_ub, vtime_ub,
+          taxisptr->fc_unit, taxisptr->fc_period );
 }
 
 static int
 taxisCompareP(void *taxisptr1, void *taxisptr2)
 {
-  taxis_t * t1, * t2;
+  const taxis_t *t1 = ( const taxis_t * ) taxisptr1,
+    *t2 = ( const taxis_t * ) taxisptr2;
 
-  t1 = ( taxis_t * ) taxisptr1;
-  t2 = ( taxis_t * ) taxisptr2;
-
-  xassert ( t1 );
-  xassert ( t2 );
+  xassert ( t1 && t2 );
 
   return ! ( t1->used        == t2->used        &&
 	     t1->type        == t2->type        &&
@@ -61274,27 +62288,6 @@ void cdiCreateTimesteps(stream_t *streamptr)
  * require-trailing-newline: t
  * End:
  */
-#ifndef CREATE_UUID_H
-#define CREATE_UUID_H
-
-#if defined (HAVE_CONFIG_H)
-#endif
-
-
-void
-create_uuid(unsigned char uuid[CDI_UUID_SIZE]);
-
-#endif
-
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
 #if defined (HAVE_CONFIG_H)
 #endif
 
@@ -61358,7 +62351,8 @@ enum {
   uuidNumHexChars = 36,
 };
 
-void uuid2str(const unsigned char *uuid, char *uuidstr)
+
+void cdiUUID2Str(const unsigned char *uuid, char *uuidstr)
 {
 
   if ( uuid == NULL || uuidstr == NULL ) return;
@@ -61373,7 +62367,7 @@ void uuid2str(const unsigned char *uuid, char *uuidstr)
 }
 
 
-int str2uuid(const char *uuidstr, unsigned char *uuid)
+int cdiStr2UUID(const char *uuidstr, unsigned char *uuid)
 {
   if ( uuid == NULL || uuidstr == NULL || strlen(uuidstr) != uuidNumHexChars)
     return -1;
@@ -61442,8 +62436,7 @@ char* cdiUnescapeSpaces(const char* string, const char** outStringEnd)
 #ifdef HAVE_DECL_UUID_GENERATE
 #include <sys/time.h>
 #include <uuid/uuid.h>
-void
-create_uuid(unsigned char *uuid)
+void cdiCreateUUID(unsigned char *uuid)
 {
   static int uuid_seeded = 0;
   static char uuid_rand_state[31 * sizeof (long)];
@@ -61472,8 +62465,7 @@ typedef uint8_t u_int8_t;
 typedef uint16_t u_int16_t;
 typedef uint32_t u_int32_t;
 #include <uuid.h>
-void
-create_uuid(unsigned char *uuid)
+void cdiCreateUUID(unsigned char *uuid)
 {
   uint32_t status;
   uuid_create((uuid_t *)(void *)uuid, &status);
@@ -61485,8 +62477,7 @@ create_uuid(unsigned char *uuid)
 }
 #else
 #include <sys/time.h>
-void
-create_uuid(unsigned char *uuid)
+void cdiCreateUUID(unsigned char *uuid)
 {
   static int uuid_seeded = 0;
   static char uuid_rand_state[31 * sizeof (long)];
@@ -61913,39 +62904,22 @@ int varInsertTileSubtype(vartable_t *vptr, const var_tile_t *tiles)
 {
   if ( tiles == NULL ) return -1;
 
-  int totalno_of_tileattr_pairs = -1;
-  int tileClassification = -1;
-  int numberOfTiles = -1;
-  int numberOfAttributes = -1;
-  int tileindex = -1;
-  int attribute = -1;
-
-  if ( tiles )
-    {
-      totalno_of_tileattr_pairs = tiles->totalno_of_tileattr_pairs;
-      tileClassification =  tiles->tileClassification;
-      numberOfTiles = tiles->numberOfTiles;
-      numberOfAttributes = tiles->numberOfAttributes;
-      tileindex = tiles->tileindex;
-      attribute = tiles->attribute;
-    }
-
   /* first, generate a subtype based on the info in "tiles". */
 
   subtype_t *subtype_ptr;
   subtypeAllocate(&subtype_ptr, SUBTYPE_TILES);
-  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_TOTALNO_OF_TILEATTR_PAIRS, totalno_of_tileattr_pairs);
-  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_TILE_CLASSIFICATION      , tileClassification);
-  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_NUMBER_OF_TILES          , numberOfTiles);
+  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_TOTALNO_OF_TILEATTR_PAIRS, tiles->totalno_of_tileattr_pairs);
+  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_TILE_CLASSIFICATION      , tiles->tileClassification);
+  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_NUMBER_OF_TILES          , tiles->numberOfTiles);
 
   /*
    * Here, we create a tile set for comparison that contains only one
    * tile/attribute pair (based on "tiles").
    */
   struct subtype_entry_t *entry = subtypeEntryInsert(subtype_ptr);
-  subtypeDefEntryDataP(entry, SUBTYPE_ATT_NUMBER_OF_ATTR,            numberOfAttributes);
-  subtypeDefEntryDataP(entry, SUBTYPE_ATT_TILEINDEX,                 tileindex);
-  subtypeDefEntryDataP(entry, SUBTYPE_ATT_TILEATTRIBUTE,             attribute);
+  subtypeDefEntryDataP(entry, SUBTYPE_ATT_NUMBER_OF_ATTR,            tiles->numberOfAttributes);
+  subtypeDefEntryDataP(entry, SUBTYPE_ATT_TILEINDEX,                 tiles->tileindex);
+  subtypeDefEntryDataP(entry, SUBTYPE_ATT_TILEATTRIBUTE,             tiles->attribute);
 
   if (vptr->tiles == NULL) {
     vptr->tiles = subtype_ptr;
@@ -62475,7 +63449,7 @@ struct varDefZAxisSearchState
   int zaxistype;
   int nlevels;
   int lbounds;
-  double *levels;
+  const double *levels;
   const char *longname;
   const char *units;
   int ltype;
@@ -62498,23 +63472,19 @@ varDefZAxisSearch(int id, void *res, void *data)
 }
 
 
-int varDefZaxis(int vlistID, int zaxistype, int nlevels, double *levels, int lbounds,
-		double *levels1, double *levels2, int vctsize, double *vct, char *name,
-		char *longname, const char *units, int prec, int mode, int ltype1)
+int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, int lbounds,
+		const double *levels1, const double *levels2, int vctsize, const double *vct, char *name,
+		const char *longname, const char *units, int prec, int mode, int ltype1)
 {
   /*
     mode: 0 search in vlist and zaxis table
           1 search in zaxis table
    */
   int zaxisdefined = 0;
-  int nzaxis;
   int zaxisID = UNDEFID;
   int zaxisglobdefined = 0;
-  vlist_t *vlistptr;
-
-  vlistptr = vlist_to_pointer(vlistID);
-
-  nzaxis = vlistptr->nzaxis;
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
+  int nzaxis = vlistptr->nzaxis;
 
   if ( mode == 0 )
     for ( int index = 0; index < nzaxis; index++ )
@@ -62565,15 +63535,8 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, double *levels, int lbo
 	      zaxisDefUbounds(zaxisID, levels2);
 	    }
 
-	  if ( zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF )
-	    {
-	      /* if ( vctsize > 0 && vctsize >= 2*(nlevels+1)) */
-	      /* if ( vctsize > 0 && vctsize >= 2*(nlevels)) */
-	      if ( vctsize > 0 )
-		zaxisDefVct(zaxisID, vctsize, vct);
-	      else
-		Warning("VCT missing");
-	    }
+	  if ( (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF) && vctsize > 0 )
+            zaxisDefVct(zaxisID, vctsize, vct);
 
 	  zaxisDefName(zaxisID, name);
 	  zaxisDefLongname(zaxisID, longname);
@@ -62923,7 +63886,8 @@ vlist_t *vlist_to_pointer(int vlistID)
 static
 void vlist_init_entry(vlist_t *vlistptr)
 {
-  vlistptr->locked         = 0;
+  vlistptr->immutable      = 0;
+  vlistptr->internal       = 0;
   vlistptr->self           = CDI_UNDEFID;
   vlistptr->nvars          = 0;
   vlistptr->vars           = NULL;
@@ -62988,32 +63952,22 @@ static
 void vlist_copy(vlist_t *vlistptr2, vlist_t *vlistptr1)
 {
   int vlistID2 = vlistptr2->self;
+  int vlist2internal = vlistptr2->internal;
   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->atts.nelems = 0;
   vlistptr2->self = vlistID2;
 }
 
-void vlist_lock(int vlistID)
+void cdiVlistMakeInternal(int vlistID)
 {
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-
-  if ( !vlistptr->locked )
-    {
-      vlistptr->locked += 1;
-      reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
-    }
+  vlist_to_pointer(vlistID)->internal = 1;
 }
 
-
-void vlist_unlock(int vlistID)
+void cdiVlistMakeImmutable(int vlistID)
 {
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-
-  if ( vlistptr->locked )
-    {
-      vlistptr->locked -= 1;
-      reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
-    }
+  vlist_to_pointer(vlistID)->immutable = 1;
 }
 
 /*
@@ -63106,12 +64060,25 @@ void vlistDestroy(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  if ( vlistptr->locked != 0 )
-    Warning("Destroying of a locked object (vlistID=%d) failed!", vlistID);
+  if ( vlistptr->internal )
+    Warning("Attempt to destroy an internal vlist object by the user (vlistID=%d).", vlistID);
   else
     vlist_delete(vlistptr);
 }
 
+// destroy an internal vlist object
+void cdiVlistDestroy_(int vlistID)
+{
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
+
+  if(!vlistptr->internal)
+    Warning("Destroying a vlist object that is owned by the user.\n"
+            "This is most likely because of a missing vlistDestroy() in the application code.\n"
+            "If that's not the case, and you are absolutely certain about it, please report the bug.");
+
+  vlist_delete(vlistptr);
+}
+
 static
 void var_copy_entries(var_t *var2, var_t *var1)
 {
@@ -63322,13 +64289,8 @@ int vlist_generate_zaxis(int vlistID, int zaxistype, int nlevels, const double *
 	      zaxisDefUbounds(zaxisID, ubounds);
 	    }
 
-	  if ( zaxistype == ZAXIS_HYBRID )
-	    {
-	      if ( vctsize > 0 )
-		zaxisDefVct(zaxisID, vctsize, vct);
-	      else
-		Warning("VCT missing");
-	    }
+	  if ( zaxistype == ZAXIS_HYBRID && vctsize > 0 )
+            zaxisDefVct(zaxisID, vctsize, vct);
 	}
 
       nzaxis = vlistptr->nzaxis;
@@ -63559,12 +64521,12 @@ void vlistCat(int vlistID2, int vlistID1)
 
       var_copy_entries(&vars2[varID2], &vars1[varID]);
 
-      int nlevs = zaxisInqSize(vars1[varID].zaxisID);
       if ( vars1[varID].levinfo )
         {
-          vars2[varID2].levinfo = (levinfo_t *) Malloc((size_t)nlevs * sizeof(levinfo_t));
+          size_t nlevs = (size_t)zaxisInqSize(vars1[varID].zaxisID);
+          vars2[varID2].levinfo = (levinfo_t *) Malloc(nlevs * sizeof(levinfo_t));
           memcpy(vars2[varID2].levinfo, vars1[varID].levinfo,
-                 (size_t)nlevs * sizeof(levinfo_t));
+                 nlevs * sizeof(levinfo_t));
         }
 
       vars2[varID2].atts.nelems = 0;
@@ -64266,12 +65228,10 @@ int vlistSubtypeIndex(int vlistID, int subtypeID)
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
   int index;
-  for ( index = 0 ; index < vlistptr->nsubtypes ; index++ )
+  for(index = vlistptr->nsubtypes; index--; )
     if ( subtypeID == vlistptr->subtypeIDs[index] ) break;
 
-  if ( index == vlistptr->nsubtypes ) index = -1;
-
-  return (index);
+  return index;
 }
 
 
@@ -64348,6 +65308,7 @@ void vlistUnpack(char * buf, int size, int *position, int originNamespace,
   xassert(!force_id || p->self == targetID);
   if (!force_id)
     targetID = p->self;
+  cdiVlistMakeInternal(p->self);
   p->taxisID = namespaceAdaptKey(tempbuf[2], originNamespace);
   p->tableID = tempbuf[3];
   p->instID = namespaceAdaptKey(tempbuf[4], originNamespace);
@@ -65659,7 +66620,7 @@ The function @func{vlistInqVarStdname} returns the standard name of a variable i
 otherwise the result is an empty string.
 
 @Result
- at func{vlistInqVarName} returns the standard name of the variable to the parameter stdname.
+ at func{vlistInqVarStdname} returns the standard name of the variable to the parameter stdname.
 
 @EndFunction
 */
@@ -66790,9 +67751,10 @@ void vlistDefVarIntKey(int vlistID, int varID, const char *name, int value)
   if (vlistptr == NULL)  Error("Internal error!");
   int idx;
 
-  if ( vlistptr->locked != 0 )
-    Error("User defined vlist object (vlistID=%d) isn't allowed!\n"
-          "Need a CDI internal vlist object from streamInqVlist(streamID).", vlistID);
+  if ( vlistptr->immutable )
+    Error("vlistDefVarIntKey() was called on an immutable vlist object (vlistID = %d)\n"
+          "Either call vlistDefVarIntKey() before passing the vlist object to streamDefVlist(),\n"
+          "or use the stream-internal vlist by calling streamInqVlist().", vlistID);
 
   for ( idx=0; idx<vlistptr->vars[varID].opt_grib_nentries; idx++)
     if ( (strcmp(name, vlistptr->vars[varID].opt_grib_kvpair[idx].keyword) == 0 ) &&
@@ -66852,9 +67814,10 @@ void vlistDefVarDblKey(int vlistID, int varID, const char *name, double value)
   if (vlistptr == NULL)  Error("Internal error!");
   int idx;
 
-  if ( vlistptr->locked != 0 )
-    Error("User defined vlist object (vlistID=%d) isn't allowed!\n"
-          "Need a CDI internal vlist object from streamInqVlist(streamID).", vlistID);
+  if ( vlistptr->immutable )
+    Error("vlistDefVarDblKey() was called on an immutable vlist object (vlistID = %d)\n"
+          "Either call vlistDefVarIntKey() before passing the vlist object to streamDefVlist(),\n"
+          "or use the stream-internal vlist by calling streamInqVlist().", vlistID);
 
   for ( idx=0; idx<vlistptr->vars[varID].opt_grib_nentries; idx++)
     if ( (strcmp(name, vlistptr->vars[varID].opt_grib_kvpair[idx].keyword) == 0 ) &&
@@ -67048,6 +68011,7 @@ int vlistVarCompare(vlist_t *a, int varIDA, vlist_t *b, int varIDB)
     | FCMPFLT(validrange[0]) | FCMPFLT(validrange[1]);
 #undef FCMP
 #undef FCMPFLT
+#undef FCMPSTR
 #undef FCMP2
   if ((diff |= ((pva->levinfo == NULL) ^ (pvb->levinfo == NULL))))
     return 1;
@@ -68470,7 +69434,6 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
   unsigned char uuid[CDI_UUID_SIZE];
   int levelID;
   int nbyte;
-  double level;
 
   xassert ( zaxisptr );
 
@@ -68499,16 +69462,28 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
 	  fprintf(fp, "%*s", nbyte0, "");
 	  nbyte = nbyte0;
 	}
-      level = zaxisInqLevel(zaxisID, levelID);
-      nbyte += fprintf(fp, "%.9g ", level);
+      nbyte += fprintf(fp, "%.9g ", zaxisptr->vals[levelID]);
     }
   fprintf(fp, "\n");
 
   if ( zaxisptr->lbounds && zaxisptr->ubounds )
     {
-      double level1, level2;
+      nbyte0 = fprintf(fp, "lbounds   = ");
+      nbyte = nbyte0;
+      for ( levelID = 0; levelID < nlevels; levelID++ )
+	{
+	  if ( nbyte > 80 )
+	    {
+	      fprintf(fp, "\n");
+	      fprintf(fp, "%*s", nbyte0, "");
+	      nbyte = nbyte0;
+	    }
+	  nbyte += fprintf(fp, "%.9g ", zaxisptr->lbounds[levelID]);
+	}
+      fprintf(fp, "\n");
+
+      nbyte0 = fprintf(fp, "ubounds   = ");
       nbyte = nbyte0;
-      nbyte0 = fprintf(fp, "bounds    = ");
       for ( levelID = 0; levelID < nlevels; levelID++ )
 	{
 	  if ( nbyte > 80 )
@@ -68517,27 +69492,21 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
 	      fprintf(fp, "%*s", nbyte0, "");
 	      nbyte = nbyte0;
 	    }
-	  level1 = zaxisInqLbound(zaxisID, levelID);
-	  level2 = zaxisInqUbound(zaxisID, levelID);
-	  nbyte += fprintf(fp, "%.9g-%.9g ", level1, level2);
+	  nbyte += fprintf(fp, "%.9g ", zaxisptr->ubounds[levelID]);
 	}
       fprintf(fp, "\n");
     }
 
   if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
     {
-      int i;
-      int vctsize;
-      const double *vct;
-
-      vctsize = zaxisptr->vctsize;
-      vct     = zaxisptr->vct;
+      int vctsize = zaxisptr->vctsize;
+      const double *vct = zaxisptr->vct;
       fprintf(fp, "vctsize   = %d\n", vctsize);
       if ( vctsize )
         {
           nbyte0 = fprintf(fp, "vct       = ");
           nbyte = nbyte0;
-          for ( i = 0; i < vctsize; i++ )
+          for ( int i = 0; i < vctsize; i++ )
             {
               if ( nbyte > 70 || i == vctsize/2 )
                 {
@@ -68985,7 +69954,7 @@ void cdiZaxisGetIndexList(unsigned nzaxis, int *zaxisResHs)
  * require-trailing-newline: t
  * End:
  */
-   static const char cdi_libvers[] = "1.7.0" " of " "Oct 25 2015"" " "12:56:26";
+   static const char cdi_libvers[] = "1.7.1" " of " "Feb 19 2016"" " "11:18:00";
 const char *cdiLibraryVersion(void)
 {
   return (cdi_libvers);
@@ -71712,6 +72681,7 @@ FCALLSCSUB3 (streamInqRecord, STREAMINQRECORD, streaminqrecord, INT, PINT, PINT)
 FCALLSCSUB3 (streamWriteRecord, STREAMWRITERECORD, streamwriterecord, INT, DOUBLEV, INT)
 FCALLSCSUB3 (streamWriteRecordF, STREAMWRITERECORDF, streamwriterecordf, INT, FLOATV, INT)
 FCALLSCSUB3 (streamReadRecord, STREAMREADRECORD, streamreadrecord, INT, DOUBLEV, PINT)
+FCALLSCSUB3 (streamReadRecordF, STREAMREADRECORDF, streamreadrecordf, INT, FLOATV, PINT)
 FCALLSCSUB2 (streamCopyRecord, STREAMCOPYRECORD, streamcopyrecord, INT, INT)
 
 /*  File driven I/O (may yield better performance than using the streamXXX functions)  */
@@ -71839,6 +72809,12 @@ FCALLSCFUN3 (INT, vlistHasVarKey, VLISTHASVARKEY, vlisthasvarkey, INT, INT, STRI
 FCALLSCFUN3 (DOUBLE, vlistInqVarDblKey, VLISTINQVARDBLKEY, vlistinqvardblkey, INT, INT, STRING)
 FCALLSCFUN3 (INT, vlistInqVarIntKey, VLISTINQVARINTKEY, vlistinqvarintkey, INT, INT, STRING)
 
+/*  needed only for CDO operator after  */
+
+FCALLSCFUN2 (STRING, vlistInqVarNamePtr, VLISTINQVARNAMEPTR, vlistinqvarnameptr, INT, INT)
+FCALLSCFUN2 (STRING, vlistInqVarLongnamePtr, VLISTINQVARLONGNAMEPTR, vlistinqvarlongnameptr, INT, INT)
+FCALLSCFUN2 (STRING, vlistInqVarUnitsPtr, VLISTINQVARUNITSPTR, vlistinqvarunitsptr, INT, INT)
+
 /*  VLIST attributes  */
 
 FCALLSCFUN3 (INT, vlistInqNatts, VLISTINQNATTS, vlistinqnatts, INT, INT, PINT)
@@ -72081,6 +73057,9 @@ FCALLSCFUN3 (INT, tableInqParCode, TABLEINQPARCODE, tableinqparcode, INT, PSTRIN
 FCALLSCFUN3 (INT, tableInqParName, TABLEINQPARNAME, tableinqparname, INT, INT, PSTRING)
 FCALLSCFUN3 (INT, tableInqParLongname, TABLEINQPARLONGNAME, tableinqparlongname, INT, INT, PSTRING)
 FCALLSCFUN3 (INT, tableInqParUnits, TABLEINQPARUNITS, tableinqparunits, INT, INT, PSTRING)
+
+/*  needed only for CDO operator after  */
+
 FCALLSCFUN2 (STRING, tableInqParNamePtr, TABLEINQPARNAMEPTR, tableinqparnameptr, INT, INT)
 FCALLSCFUN2 (STRING, tableInqParLongnamePtr, TABLEINQPARLONGNAMEPTR, tableinqparlongnameptr, INT, INT)
 FCALLSCFUN2 (STRING, tableInqParUnitsPtr, TABLEINQPARUNITSPTR, tableinqparunitsptr, INT, INT)
@@ -72113,6 +73092,7 @@ FCALLSCSUB2 (subtypeDefActiveIndex, SUBTYPEDEFACTIVEINDEX, subtypedefactiveindex
          query objects.  */
 
 FCALLSCFUN3 (INT, subtypeInqTile, SUBTYPEINQTILE, subtypeinqtile, INT, INT, INT)
+FCALLSCFUN4 (INT, subtypeInqAttribute, SUBTYPEINQATTRIBUTE, subtypeinqattribute, INT, INT, STRING, PINT)
 FCALLSCFUN2 (INT, vlistInqVarSubtype, VLISTINQVARSUBTYPE, vlistinqvarsubtype, INT, INT)
 FCALLSCSUB3 (gribapiLibraryVersion, GRIBAPILIBRARYVERSION, gribapilibraryversion, PINT, PINT, PINT)
 
diff --git a/libcdi/src/cdipio.inc b/libcdi/src/cdipio.inc
index d6afa53..ab4eba3 100644
--- a/libcdi/src/cdipio.inc
+++ b/libcdi/src/cdipio.inc
@@ -4,7 +4,7 @@
 !
 ! Author:
 ! -------
-! Uwe Schulzweida, MPI-MET, Hamburg,   October 2015
+! Uwe Schulzweida, MPI-MET, Hamburg,   February 2016
 !
 
 !
diff --git a/libcdi/src/cgribex.h b/libcdi/src/cgribex.h
index 43385aa..0f0f713 100644
--- a/libcdi/src/cgribex.h
+++ b/libcdi/src/cgribex.h
@@ -175,6 +175,9 @@
 #define  ISEC4_NumNonMissValues     (isec4[20])  /* Number of non-missing values                  */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 
 void  gribFixZSE(int flag);     /* 1: Fix ZeroShiftError of simple packed spherical harmonics */
@@ -188,11 +191,11 @@ void  gribSetValueCheck(int vcheck);
 
 void  gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
                float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
-               int kleng, int *kword, char *hoper, int *kret);
+               int kleng, int *kword, const char *hoper, int *kret);
 
 void  gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
                double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
-               int kleng, int *kword, char *hoper, int *kret);
+               int kleng, int *kword, const char *hoper, int *kret);
 
 
 const char *cgribexLibraryVersion(void);
@@ -243,7 +246,13 @@ int   gribVersion(unsigned char *buffer, size_t buffersize);
 
 int   grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer, int *intnum, float *fltnum, off_t *bignum);
 
-double calculate_pfactor(const double* spectralField, long fieldTruncation, long subsetTruncation);
+double calculate_pfactor_float(const float* spectralField, long fieldTruncation, long subsetTruncation);
+double calculate_pfactor_double(const double* spectralField, long fieldTruncation, long subsetTruncation);
+
+
+#if defined (__cplusplus)
+}
+#endif
 
 #endif  /* _CGRIBEX_H */ 
 
diff --git a/libcdi/src/cgribexlib.c b/libcdi/src/cgribexlib.c
index 62a26c5..e824767 100644
--- a/libcdi/src/cgribexlib.c
+++ b/libcdi/src/cgribexlib.c
@@ -1,7 +1,7 @@
 
-/* Automatically generated by m214003 at 2015-09-14, do not edit */
+/* Automatically generated by m214003 at 2016-02-19, do not edit */
 
-/* CGRIBEXLIB_VERSION="1.7.3" */
+/* CGRIBEXLIB_VERSION="1.7.4" */
 
 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) || defined (__clang__)
 #pragma GCC diagnostic push
@@ -38,8 +38,8 @@
 #define TEMPLATE(X,Y) CAT(X,Y)
 
 #endif 
-#ifndef _GRIB_INT_H
-#define _GRIB_INT_H
+#ifndef GRIB_INT_H
+#define GRIB_INT_H
 
 #if defined (HAVE_CONFIG_H)
 #  include "config.h"
@@ -112,24 +112,25 @@
 #endif
 #endif
 
-#ifndef DBL_IS_EQUAL
-/*#define DBL_IS_EQUAL(x,y) (!(x < y || y < x)) */
-#  define DBL_IS_EQUAL(x,y) (DBL_IS_NAN(x)||DBL_IS_NAN(y)?(DBL_IS_NAN(x)&&DBL_IS_NAN(y)?1:0):!(x < y || y < x))
-#endif
-
 #ifndef IS_EQUAL
 #  define IS_NOT_EQUAL(x,y) (x < y || y < x)
 #  define IS_EQUAL(x,y)     (!IS_NOT_EQUAL(x,y))
 #endif
 
 /* dummy use of unused parameters to silence compiler warnings */
-#define  UNUSED(x) (void)x
+#ifndef UNUSED
+#  define  UNUSED(x) (void)(x)
+#endif
 
 #define  JP23SET    0x7FFFFF  /* 2**23 - 1 (---> 8388607)  */
 
 #define  POW_2_M24  0.000000059604644775390625  /*  pow(2.0, -24.0) */
 
-double intpow2(int x);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define intpow2(x) (ldexp(1.0, (x)))
 
 int gribrec_len(unsigned b1, unsigned b2, unsigned b3);
 int correct_bdslen(int bdslen, long recsize, long gribpos);
@@ -176,8 +177,8 @@ void   scale_complex_double(double *fpdata, int pcStart, int pcScale, int trunc,
 void   scale_complex_float(float *fpdata, int pcStart, int pcScale, int trunc, int inv);
 void   scatter_complex_double(double *fpdata, int pcStart, int trunc, int nsp);
 void   scatter_complex_float(float *fpdata, int pcStart, int trunc, int nsp);
-void   gather_complex_double(double *fpdata, int pcStart, int trunc, int nsp);
-void   gather_complex_float(float *fpdata, int pcStart, int trunc, int nsp);
+void   gather_complex_double(double *fpdata, size_t pcStart, size_t trunc, size_t nsp);
+void   gather_complex_float(float *fpdata, size_t pcStart, size_t trunc, size_t nsp);
 
 void   scm0_double(double *pdl, double *pdr, double *pfl, double *pfr, int klg);
 int    qu2reg2(double *pfield, int *kpoint, int klat, int klon,
@@ -217,7 +218,11 @@ int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **i
 		  unsigned char **lusp, unsigned char **gdsp, unsigned char **pdsp,
 		  unsigned char **drsp, unsigned char **bmsp, unsigned char **bdsp);
 
-#endif  /* _GRIB_INT_H */
+#if defined (__cplusplus)
+}
+#endif
+
+#endif  /* GRIB_INT_H */
 #ifndef _GRIBDECODE_H
 #define _GRIBDECODE_H
 
@@ -319,7 +324,7 @@ int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **i
 #define  GDS_ScanFlag        GET_UINT1(gds[27])
 #define  GDS_LatSP           GET_INT3(gds[32], gds[33], gds[34])
 #define  GDS_LonSP           GET_INT3(gds[35], gds[36], gds[37])
-#define  GDS_RotAngle        GET_Real(&(gds[38]))
+#define  GDS_RotAngle        (GET_Real(&(gds[38])))
 
 /* GRIB1 Lambert */
 #define  GDS_Lambert_Lov     GET_INT3(gds[17], gds[18], gds[19])
@@ -344,9 +349,9 @@ int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **i
 #define  BDS_Len	    ((int) ((bds[0]<<16)+(bds[1]<<8)+bds[2]))
 #define  BDS_Flag	    (bds[3])
 #define  BDS_BinScale       GET_INT2(bds[ 4], bds[ 5])
-#define  BDS_RefValue       decfp2((int)bds[ 6], GET_UINT3(bds[ 7], bds[ 8], bds[ 9]))
+#define  BDS_RefValue       (decfp2((int)bds[ 6], GET_UINT3(bds[ 7], bds[ 8], bds[ 9])))
 #define  BDS_NumBits        ((int) bds[10])
-#define  BDS_RealCoef       decfp2((int)bds[zoff+11], GET_UINT3(bds[zoff+12], bds[zoff+13], bds[zoff+14]))
+#define  BDS_RealCoef       (decfp2((int)bds[zoff+11], GET_UINT3(bds[zoff+12], bds[zoff+13], bds[zoff+14])))
 #define  BDS_PackData       ((int) ((bds[zoff+11]<<8) + bds[zoff+12]))
 #define  BDS_Power          GET_INT2(bds[zoff+13], bds[zoff+14])
 #define  BDS_Z              (bds[13])
@@ -365,21 +370,20 @@ int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **i
 
 #define PutnZero(n) \
 { \
-  int i; \
-  for ( i = z; i < z+n; i++ ) lGrib[i] = 0; \
+  for ( size_t i = z >= 0 ? (size_t)z : 0; i < (size_t)(z+n); i++ ) lGrib[i] = 0; \
   z += n; \
 }
 
-#define Put1Byte(Value)  (lGrib[z++] = (Value))
-#define Put2Byte(Value) ((lGrib[z++] = (Value) >>  8), \
-                         (lGrib[z++] = (Value)))
-#define Put3Byte(Value) ((lGrib[z++] = (Value) >> 16), \
-                         (lGrib[z++] = (Value) >>  8), \
-                         (lGrib[z++] = (Value)))
-#define Put4Byte(Value) ((lGrib[z++] = (Value) >> 24), \
-                         (lGrib[z++] = (Value) >> 16), \
-                         (lGrib[z++] = (Value) >>  8), \
-                         (lGrib[z++] = (Value)))
+#define Put1Byte(Value)  (lGrib[z++] = (GRIBPACK)(Value))
+#define Put2Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
+                         (lGrib[z++] = (GRIBPACK)(Value)))
+#define Put3Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >> 16)),      \
+                         (lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
+                         (lGrib[z++] = (GRIBPACK)(Value)))
+#define Put4Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >> 24)),      \
+                         (lGrib[z++] = (GRIBPACK)((Value) >> 16)),      \
+                         (lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
+                         (lGrib[z++] = (GRIBPACK)(Value)))
 
 #define Put1Int(Value)  {ival = Value; if ( ival < 0 ) ival =     0x80 - ival; Put1Byte(ival);}
 #define Put2Int(Value)  {ival = Value; if ( ival < 0 ) ival =   0x8000 - ival; Put2Byte(ival);}
@@ -393,278 +397,21 @@ int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **i
 }
 
 #endif  /* _GRIB_ENCODE_H */
-#include <stdio.h>
-#include <math.h>
-
-
-const double _pow2tab[158] = {
- /* pow(2.0,  0.0) */  1.0,
- /* pow(2.0,  1.0) */  2.0,
- /* pow(2.0,  2.0) */  4.0,
- /* pow(2.0,  3.0) */  8.0,
- /* pow(2.0,  4.0) */  16.0,
- /* pow(2.0,  5.0) */  32.0,
- /* pow(2.0,  6.0) */  64.0,
- /* pow(2.0,  7.0) */  128.0,
- /* pow(2.0,  8.0) */  256.0,
- /* pow(2.0,  9.0) */  512.0,
- /* pow(2.0, 10.0) */  1024.0,
- /* pow(2.0, 11.0) */  2048.0,
- /* pow(2.0, 12.0) */  4096.0,
- /* pow(2.0, 13.0) */  8192.0,
- /* pow(2.0, 14.0) */  16384.0,
- /* pow(2.0, 15.0) */  32768.0,
- /* pow(2.0, 16.0) */  65536.0,
- /* pow(2.0, 17.0) */  131072.0,
- /* pow(2.0, 18.0) */  262144.0,
- /* pow(2.0, 19.0) */  524288.0,
- /* pow(2.0, 20.0) */  1048576.0,
- /* pow(2.0, 21.0) */  2097152.0,
- /* pow(2.0, 22.0) */  4194304.0,
- /* pow(2.0, 23.0) */  8388608.0,
- /* pow(2.0, 24.0) */  16777216.0,
- /* pow(2.0, 25.0) */  33554432.0,
- /* pow(2.0, 26.0) */  67108864.0,
- /* pow(2.0, 27.0) */  134217728.0,
- /* pow(2.0, 28.0) */  268435456.0,
- /* pow(2.0, 29.0) */  536870912.0,
- /* pow(2.0, 30.0) */  1073741824.0,
- /* pow(2.0, 31.0) */  2147483648.0,
- /* pow(2.0, 32.0) */  4294967296.0,
- /* pow(2.0, 33.0) */  8589934592.0,
- /* pow(2.0, 34.0) */  17179869184.0,
- /* pow(2.0, 35.0) */  34359738368.0,
- /* pow(2.0, 36.0) */  68719476736.0,
- /* pow(2.0, 37.0) */  137438953472.0,
- /* pow(2.0, 38.0) */  274877906944.0,
- /* pow(2.0, 39.0) */  549755813888.0,
- /* pow(2.0, 40.0) */  1099511627776.0,
- /* pow(2.0, 41.0) */  2199023255552.0,
- /* pow(2.0, 42.0) */  4398046511104.0,
- /* pow(2.0, 43.0) */  8796093022208.0,
- /* pow(2.0, 44.0) */  17592186044416.0,
- /* pow(2.0, 45.0) */  35184372088832.0,
- /* pow(2.0, 46.0) */  70368744177664.0,
- /* pow(2.0, 47.0) */  140737488355328.0,
- /* pow(2.0, 48.0) */  281474976710656.0,
- /* pow(2.0, 49.0) */  562949953421312.0,
- /* pow(2.0, 50.0) */  1125899906842624.0,
- /* pow(2.0, 51.0) */  2251799813685248.0,
- /* pow(2.0, 52.0) */  4503599627370496.0,
- /* pow(2.0, 53.0) */  9007199254740992.0,
- /* pow(2.0, 54.0) */  18014398509481984.0,
- /* pow(2.0, 55.0) */  36028797018963968.0,
- /* pow(2.0, 56.0) */  72057594037927936.0,
- /* pow(2.0, 57.0) */  144115188075855872.0,
- /* pow(2.0, 58.0) */  288230376151711744.0,
- /* pow(2.0, 59.0) */  576460752303423488.0,
- /* pow(2.0, 60.0) */  1152921504606846976.0,
- /* pow(2.0, 61.0) */  2305843009213693952.0,
- /* pow(2.0, 62.0) */  4611686018427387904.0,
- /* pow(2.0, 63.0) */  9223372036854775808.0,
- /* pow(2.0, 64.0) */  18446744073709551616.0,
- /* pow(2.0, 65.0) */  36893488147419103232.0,
- /* pow(2.0, 66.0) */  73786976294838206464.0,
- /* pow(2.0, 67.0) */  147573952589676412928.0,
- /* pow(2.0, 68.0) */  295147905179352825856.0,
- /* pow(2.0, 69.0) */  590295810358705651712.0,
- /* pow(2.0, 70.0) */  1180591620717411303424.0,
- /* pow(2.0, 71.0) */  2361183241434822606848.0,
- /* pow(2.0, 72.0) */  4722366482869645213696.0,
- /* pow(2.0, 73.0) */  9444732965739290427392.0,
- /* pow(2.0, 74.0) */  18889465931478580854784.0,
- /* pow(2.0, 75.0) */  37778931862957161709568.0,
- /* pow(2.0, 76.0) */  75557863725914323419136.0,
- /* pow(2.0, 77.0) */  151115727451828646838272.0,
- /* pow(2.0, 78.0) */  302231454903657293676544.0,
- /* pow(2.0, 79.0) */  604462909807314587353088.0,
- /* pow(2.0, 80.0) */  1208925819614629174706176.0,
- /* pow(2.0, 81.0) */  2417851639229258349412352.0,
- /* pow(2.0, 82.0) */  4835703278458516698824704.0,
- /* pow(2.0, 83.0) */  9671406556917033397649408.0,
- /* pow(2.0, 84.0) */  19342813113834066795298816.0,
- /* pow(2.0, 85.0) */  38685626227668133590597632.0,
- /* pow(2.0, 86.0) */  77371252455336267181195264.0,
- /* pow(2.0, 87.0) */  154742504910672534362390528.0,
- /* pow(2.0, 88.0) */  309485009821345068724781056.0,
- /* pow(2.0, 89.0) */  618970019642690137449562112.0,
- /* pow(2.0, 90.0) */  1237940039285380274899124224.0,
- /* pow(2.0, 91.0) */  2475880078570760549798248448.0,
- /* pow(2.0, 92.0) */  4951760157141521099596496896.0,
- /* pow(2.0, 93.0) */  9903520314283042199192993792.0,
- /* pow(2.0, 94.0) */  19807040628566084398385987584.0,
- /* pow(2.0, 95.0) */  39614081257132168796771975168.0,
- /* pow(2.0, 96.0) */  79228162514264337593543950336.0,
- /* pow(2.0, 97.0) */  158456325028528675187087900672.0,
- /* pow(2.0, 98.0) */  316912650057057350374175801344.0,
- /* pow(2.0, 99.0) */  633825300114114700748351602688.0,
- /* pow(2.0, 100.0) */  1267650600228229401496703205376.0,
- /* pow(2.0, 101.0) */  2535301200456458802993406410752.0,
- /* pow(2.0, 102.0) */  5070602400912917605986812821504.0,
- /* pow(2.0, 103.0) */  10141204801825835211973625643008.0,
- /* pow(2.0, 104.0) */  20282409603651670423947251286016.0,
- /* pow(2.0, 105.0) */  40564819207303340847894502572032.0,
- /* pow(2.0, 106.0) */  81129638414606681695789005144064.0,
- /* pow(2.0, 107.0) */  162259276829213363391578010288128.0,
- /* pow(2.0, 108.0) */  324518553658426726783156020576256.0,
- /* pow(2.0, 109.0) */  649037107316853453566312041152512.0,
- /* pow(2.0, 110.0) */  1298074214633706907132624082305024.0,
- /* pow(2.0, 111.0) */  2596148429267413814265248164610048.0,
- /* pow(2.0, 112.0) */  5192296858534827628530496329220096.0,
- /* pow(2.0, 113.0) */  10384593717069655257060992658440192.0,
- /* pow(2.0, 114.0) */  20769187434139310514121985316880384.0,
- /* pow(2.0, 115.0) */  41538374868278621028243970633760768.0,
- /* pow(2.0, 116.0) */  83076749736557242056487941267521536.0,
- /* pow(2.0, 117.0) */  166153499473114484112975882535043072.0,
- /* pow(2.0, 118.0) */  332306998946228968225951765070086144.0,
- /* pow(2.0, 119.0) */  664613997892457936451903530140172288.0,
- /* pow(2.0, 120.0) */  1329227995784915872903807060280344576.0,
- /* pow(2.0, 121.0) */  2658455991569831745807614120560689152.0,
- /* pow(2.0, 122.0) */  5316911983139663491615228241121378304.0,
- /* pow(2.0, 123.0) */  10633823966279326983230456482242756608.0,
- /* pow(2.0, 124.0) */  21267647932558653966460912964485513216.0,
- /* pow(2.0, 125.0) */  42535295865117307932921825928971026432.0,
- /* pow(2.0, 126.0) */  85070591730234615865843651857942052864.0,
- /* pow(2.0, 127.0) */  170141183460469231731687303715884105728.0,
- /* pow(2.0, 128.0) */  340282366920938463463374607431768211456.0,
- /* pow(2.0, 129.0) */  680564733841876926926749214863536422912.0,
- /* pow(2.0, 130.0) */  1361129467683753853853498429727072845824.0,
- /* pow(2.0, 131.0) */  2722258935367507707706996859454145691648.0,
- /* pow(2.0, 132.0) */  5444517870735015415413993718908291383296.0,
- /* pow(2.0, 133.0) */  10889035741470030830827987437816582766592.0,
- /* pow(2.0, 134.0) */  21778071482940061661655974875633165533184.0,
- /* pow(2.0, 135.0) */  43556142965880123323311949751266331066368.0,
- /* pow(2.0, 136.0) */  87112285931760246646623899502532662132736.0,
- /* pow(2.0, 137.0) */  174224571863520493293247799005065324265472.0,
- /* pow(2.0, 138.0) */  348449143727040986586495598010130648530944.0,
- /* pow(2.0, 139.0) */  696898287454081973172991196020261297061888.0,
- /* pow(2.0, 140.0) */  1393796574908163946345982392040522594123776.0,
- /* pow(2.0, 141.0) */  2787593149816327892691964784081045188247552.0,
- /* pow(2.0, 142.0) */  5575186299632655785383929568162090376495104.0,
- /* pow(2.0, 143.0) */  11150372599265311570767859136324180752990208.0,
- /* pow(2.0, 144.0) */  22300745198530623141535718272648361505980416.0,
- /* pow(2.0, 145.0) */  44601490397061246283071436545296723011960832.0,
- /* pow(2.0, 146.0) */  89202980794122492566142873090593446023921664.0,
- /* pow(2.0, 147.0) */  178405961588244985132285746181186892047843328.0,
- /* pow(2.0, 148.0) */  356811923176489970264571492362373784095686656.0,
- /* pow(2.0, 149.0) */  713623846352979940529142984724747568191373312.0,
- /* pow(2.0, 150.0) */  1427247692705959881058285969449495136382746624.0,
- /* pow(2.0, 151.0) */  2854495385411919762116571938898990272765493248.0,
- /* pow(2.0, 152.0) */  5708990770823839524233143877797980545530986496.0,
- /* pow(2.0, 153.0) */  11417981541647679048466287755595961091061972992.0,
- /* pow(2.0, 154.0) */  22835963083295358096932575511191922182123945984.0,
- /* pow(2.0, 155.0) */  45671926166590716193865151022383844364247891968.0,
- /* pow(2.0, 156.0) */  91343852333181432387730302044767688728495783936.0,
- /* pow(2.0, 157.0) */  182687704666362864775460604089535377456991567872.0,
-};
-
-
-const double _pow16tab[71] = {
- /* pow(16.0,  0.0) */  1.0,
- /* pow(16.0,  1.0) */  16.0,
- /* pow(16.0,  2.0) */  256.0,
- /* pow(16.0,  3.0) */  4096.0,
- /* pow(16.0,  4.0) */  65536.0,
- /* pow(16.0,  5.0) */  1048576.0,
- /* pow(16.0,  6.0) */  16777216.0,
- /* pow(16.0,  7.0) */  268435456.0,
- /* pow(16.0,  8.0) */  4294967296.0,
- /* pow(16.0,  9.0) */  68719476736.0,
- /* pow(16.0, 10.0) */  1099511627776.0,
- /* pow(16.0, 11.0) */  17592186044416.0,
- /* pow(16.0, 12.0) */  281474976710656.0,
- /* pow(16.0, 13.0) */  4503599627370496.0,
- /* pow(16.0, 14.0) */  72057594037927936.0,
- /* pow(16.0, 15.0) */  1152921504606846976.0,
- /* pow(16.0, 16.0) */  18446744073709551616.0,
- /* pow(16.0, 17.0) */  295147905179352825856.0,
- /* pow(16.0, 18.0) */  4722366482869645213696.0,
- /* pow(16.0, 19.0) */  75557863725914323419136.0,
- /* pow(16.0, 20.0) */  1208925819614629174706176.0,
- /* pow(16.0, 21.0) */  19342813113834066795298816.0,
- /* pow(16.0, 22.0) */  309485009821345068724781056.0,
- /* pow(16.0, 23.0) */  4951760157141521099596496896.0,
- /* pow(16.0, 24.0) */  79228162514264337593543950336.0,
- /* pow(16.0, 25.0) */  1267650600228229401496703205376.0,
- /* pow(16.0, 26.0) */  20282409603651670423947251286016.0,
- /* pow(16.0, 27.0) */  324518553658426726783156020576256.0,
- /* pow(16.0, 28.0) */  5192296858534827628530496329220096.0,
- /* pow(16.0, 29.0) */  83076749736557242056487941267521536.0,
- /* pow(16.0, 30.0) */  1329227995784915872903807060280344576.0,
- /* pow(16.0, 31.0) */  21267647932558653966460912964485513216.0,
- /* pow(16.0, 32.0) */  340282366920938463463374607431768211456.0,
- /* pow(16.0, 33.0) */  5444517870735015415413993718908291383296.0,
- /* pow(16.0, 34.0) */  87112285931760246646623899502532662132736.0,
- /* pow(16.0, 35.0) */  1393796574908163946345982392040522594123776.0,
- /* pow(16.0, 36.0) */  22300745198530623141535718272648361505980416.0,
- /* pow(16.0, 37.0) */  356811923176489970264571492362373784095686656.0,
- /* pow(16.0, 38.0) */  5708990770823839524233143877797980545530986496.0,
- /* pow(16.0, 39.0) */  91343852333181432387730302044767688728495783936.0,
- /* pow(16.0, 40.0) */  1461501637330902918203684832716283019655932542976.0,
- /* pow(16.0, 41.0) */  23384026197294446691258957323460528314494920687616.0,
- /* pow(16.0, 42.0) */  374144419156711147060143317175368453031918731001856.0,
- /* pow(16.0, 43.0) */  5986310706507378352962293074805895248510699696029696.0,
- /* pow(16.0, 44.0) */  95780971304118053647396689196894323976171195136475136.0,
- /* pow(16.0, 45.0) */  1532495540865888858358347027150309183618739122183602176.0,
- /* pow(16.0, 46.0) */  24519928653854221733733552434404946937899825954937634816.0,
- /* pow(16.0, 47.0) */  392318858461667547739736838950479151006397215279002157056.0,
- /* pow(16.0, 48.0) */  6277101735386680763835789423207666416102355444464034512896.0,
- /* pow(16.0, 49.0) */  100433627766186892221372630771322662657637687111424552206336.0,
- /* pow(16.0, 50.0) */  1606938044258990275541962092341162602522202993782792835301376.0,
- /* pow(16.0, 51.0) */  25711008708143844408671393477458601640355247900524685364822016.0,
- /* pow(16.0, 52.0) */  411376139330301510538742295639337626245683966408394965837152256.0,
- /* pow(16.0, 53.0) */  6582018229284824168619876730229402019930943462534319453394436096.0,
- /* pow(16.0, 54.0) */  105312291668557186697918027683670432318895095400549111254310977536.0,
- /* pow(16.0, 55.0) */  1684996666696914987166688442938726917102321526408785780068975640576.0,
- /* pow(16.0, 56.0) */  26959946667150639794667015087019630673637144422540572481103610249216.0,
- /* pow(16.0, 57.0) */  431359146674410236714672241392314090778194310760649159697657763987456.0,
- /* pow(16.0, 58.0) */  6901746346790563787434755862277025452451108972170386555162524223799296.0,
- /* pow(16.0, 59.0) */  110427941548649020598956093796432407239217743554726184882600387580788736.0,
- /* pow(16.0, 60.0) */  1766847064778384329583297500742918515827483896875618958121606201292619776.0,
- /* pow(16.0, 61.0) */  28269553036454149273332760011886696253239742350009903329945699220681916416.0,
- /* pow(16.0, 62.0) */  452312848583266388373324160190187140051835877600158453279131187530910662656.0,
- /* pow(16.0, 63.0) */  7237005577332262213973186563042994240829374041602535252466099000494570602496.0,
- /* pow(16.0, 64.0) */  115792089237316195423570985008687907853269984665640564039457584007913129639936.0,
- /* pow(16.0, 65.0) */  1852673427797059126777135760139006525652319754650249024631321344126610074238976.0,
- /* pow(16.0, 66.0) */  29642774844752946028434172162224104410437116074403984394101141506025761187823616.0,
- /* pow(16.0, 67.0) */  474284397516047136454946754595585670566993857190463750305618264096412179005177856.0,
- /* pow(16.0, 68.0) */  7588550360256754183279148073529370729071901715047420004889892225542594864082845696.0,
- /* pow(16.0, 69.0) */  121416805764108066932466369176469931665150427440758720078238275608681517825325531136.0,
- /* pow(16.0, 70.0) */  1942668892225729070919461906823518906642406839052139521251812409738904285205208498176.0,
-};
-
-static int _pow2tab_size = sizeof(_pow2tab)/sizeof(double);
-
-void gen_pow2tab(void)
-{
-  int jloop;
-
-  for ( jloop = 0; jloop < 158; jloop++ )
-    printf(" /* pow(2.0, %2d.0) */  %.1f,\n", jloop,  pow(2.0, (double) jloop));
-}
-
-
-void gen_pow16tab(void)
-{
-  double pval;
-  int iexp;
-
-  for ( iexp = 0; iexp < 71; iexp++ )
-    {
-      pval = pow(16.0, (double)(iexp));
-      printf(" /* pow(16.0, %2d.0) */  %.1f,\n", iexp, pval);
-    }
-}
-
-
-double intpow2(int x)
-{
-  if ( x < _pow2tab_size )
-    return (_pow2tab[x]);
-  else
-    return (pow(2.0, (double) x));
-}
+#ifndef CODEC_COMMON_H
+#define CODEC_COMMON_H
+#define gribSwapByteOrder_uint16(ui16)  ((uint16_t)((ui16<<8) | (ui16>>8)))
+#endif  /* CODEC_COMMON_H */
 /* 
+icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -openmp -DOMP_SIMD minmax_val.c
+ result on hama2 (icc 16.0.0):
+     float:
+minmax_val: fmin: -500000  fmax: 499999  time:   0.63s
+    double:
+minmax_val: fmin: -500000  fmax: 499999  time:   2.98s
+orig      : fmin: -500000  fmax: 499999  time:   2.83s
+simd      : fmin: -500000  fmax: 499999  time:   2.82s
+avx       : fmin: -500000  fmax: 499999  time:   3.17s
+
 gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL minmax_val.c
  result on bailung (gcc 4.8.2):
   orig    : fmin: -500000  fmax: 499999  time:   4.82s
@@ -682,16 +429,6 @@ icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -openmp
   simd    : fmin: -500000  fmax: 499999  time:   2.83s
   avx     : fmin: -500000  fmax: 499999  time:   2.92s
 
-icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -openmp -DOMP_SIMD minmax_val.c
- result on hama (icc 15.0.1):
- float:
-  minmax_val: fmin: -500000  fmax: 499999  time:   0.60s
- double:
-  minmax_val: fmin: -500000  fmax: 499999  time:   3.06s
-  orig      : fmin: -500000  fmax: 499999  time:   2.66s
-  simd      : fmin: -500000  fmax: 499999  time:   6.65s
-  avx       : fmin: -500000  fmax: 499999  time:   3.11s
-
 xlc_r -g -O3 -qhot -q64 -qarch=auto -qtune=auto -qreport -DTEST_MINMAXVAL minmax_val.c
  result on blizzard (xlc 12):
   orig    : fmin: -500000  fmax: 499999  time:   7.26s
@@ -937,10 +674,9 @@ void sse2_minmax_val_double(const double *restrict buf, size_t nframes, double *
 
 #if defined(_ARCH_PWR6)
 static
-void pwr6_minmax_val_double_unrolled6(const double *restrict data, long idatasize, double *fmin, double *fmax)
+void pwr6_minmax_val_double_unrolled6(const double *restrict data, size_t datasize, double *fmin, double *fmax)
 {
 #define __UNROLL_DEPTH_1 6
-  size_t datasize = idatasize;
 
   // to allow pipelining we have to unroll 
 
@@ -984,9 +720,9 @@ void pwr6_minmax_val_double_unrolled6(const double *restrict data, long idatasiz
 
 #if defined(TEST_MINMAXVAL) && defined(__GNUC__)
 static
-void minmax_val_double_orig(const double *restrict data, long idatasize, double *fmin, double *fmax) __attribute__ ((noinline));
+void minmax_val_double_orig(const double *restrict data, size_t datasize, double *fmin, double *fmax) __attribute__ ((noinline));
 static
-void minmax_val_double_simd(const double *restrict data, long idatasize, double *fmin, double *fmax) __attribute__ ((noinline));
+void minmax_val_double_simd(const double *restrict data, size_t datasize, double *fmin, double *fmax) __attribute__ ((noinline));
 #endif
 
 #if defined(GNUC_PUSH_POP)
@@ -994,10 +730,8 @@ void minmax_val_double_simd(const double *restrict data, long idatasize, double
 #pragma GCC optimize ("O3", "fast-math")
 #endif
 static
-void minmax_val_double_orig(const double *restrict data, long idatasize, double *fmin, double *fmax)
+void minmax_val_double_orig(const double *restrict data, size_t datasize, double *fmin, double *fmax)
 {
-  size_t i;
-  size_t datasize = idatasize;
   double dmin = *fmin, dmax = *fmax;
 
 #if   defined(CRAY)
@@ -1009,7 +743,7 @@ void minmax_val_double_orig(const double *restrict data, long idatasize, double
 #elif defined (__ICC)
 #pragma ivdep
 #endif
-  for ( i = 0; i < datasize; ++i )
+  for ( size_t i = 0; i < datasize; ++i )
     {
       dmin = dmin < data[i] ? dmin : data[i];
       dmax = dmax > data[i] ? dmax : data[i];
@@ -1022,8 +756,7 @@ void minmax_val_double_orig(const double *restrict data, long idatasize, double
 static
 void minmax_val_float(const float *restrict data, long idatasize, float *fmin, float *fmax)
 {
-  size_t i;
-  size_t datasize = idatasize;
+  size_t datasize = (size_t)idatasize;
   float dmin = *fmin, dmax = *fmax;
 
 #if   defined(CRAY)
@@ -1035,7 +768,7 @@ void minmax_val_float(const float *restrict data, long idatasize, float *fmin, f
 #elif defined (__ICC)
 #pragma ivdep
 #endif
-  for ( i = 0; i < datasize; ++i )
+  for ( size_t i = 0; i < datasize; ++i )
     {
       dmin = dmin < data[i] ? dmin : data[i];
       dmax = dmax > data[i] ? dmax : data[i];
@@ -1051,25 +784,19 @@ void minmax_val_float(const float *restrict data, long idatasize, float *fmin, f
 // TEST
 #if defined(OMP_SIMD)
 
-//#pragma omp declare reduction(xmin : double : omp_out = omp_in > omp_out ? omp_out : omp_in) initializer( omp_priv = { 1.e300 })
-//#pragma omp declare reduction(xmax : double : omp_out = omp_in < omp_out ? omp_out : omp_in) initializer( omp_priv = { -1.e300 })
-
 #if defined(GNUC_PUSH_POP)
 #pragma GCC push_options
 #pragma GCC optimize ("O3", "fast-math")
 #endif
 static
-void minmax_val_double_simd(const double *restrict data, long idatasize, double *fmin, double *fmax)
+void minmax_val_double_simd(const double *restrict data, size_t datasize, double *fmin, double *fmax)
 {
-  size_t i;
-  size_t datasize = idatasize;
   double dmin = *fmin, dmax = *fmax;
 
 #if defined(_OPENMP)
-  //#pragma omp simd reduction(xmin:dmin) reduction(xmax:dmax)
-#pragma omp simd
+#pragma omp simd reduction(min:dmin) reduction(max:dmax)
 #endif
-  for ( i = 0; i < datasize; ++i )
+  for ( size_t i = 0; i < datasize; ++i )
     {
       dmin = dmin < data[i] ? dmin : data[i];
       dmax = dmax > data[i] ? dmax : data[i];
@@ -1089,9 +816,9 @@ void minmax_val_double(const double *restrict data, long idatasize, double *fmin
 #if defined(_GET_X86_COUNTER) || defined(_GET_MACH_COUNTER) 
   uint64_t start_minmax, end_minmax;
 #endif
-  size_t datasize = idatasize;
+  size_t datasize = (size_t)idatasize;
 
-  if ( idatasize < 1 ) return;
+  if ( idatasize >= 1 ) ; else return;
 
 #if defined(_GET_X86_COUNTER) 
   start_minmax = _rdtsc();
@@ -1200,7 +927,7 @@ int main(void)
 
   {
     float fmin, fmax;
-    float *data_sp = (float*) Malloc(datasize*sizeof(float));
+    float *data_sp = (float*) malloc(datasize*sizeof(float));
 
     for ( long i = 0; i < datasize/2; i++ )        data_sp[i] = (float) (i);
     for ( long i = datasize/2; i < datasize; i++ ) data_sp[i] = (float) (-datasize + i);
@@ -1215,12 +942,12 @@ int main(void)
       }
     t_end = dtime();
     printf("minmax_val: fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
-    Free(data_sp);
+    free(data_sp);
   }
 
   {
     double fmin, fmax;
-    double *data_dp = (double*) Malloc(datasize*sizeof(double));
+    double *data_dp = (double*) malloc(datasize*sizeof(double));
 
     // for ( long i = datasize-1; i >= 0; i-- ) data[i] = (double) (-datasize/2 + i);
     for ( long i = 0; i < datasize/2; i++ )        data_dp[i] = (double) (i);
@@ -1286,7 +1013,7 @@ int main(void)
     t_end = dtime();
     printf("pwr6u6  : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
 #endif
-    Free(data_dp);
+    free(data_dp);
   }
 
   return (0);
@@ -1297,20 +1024,48 @@ int main(void)
 #undef _ENABLE_AVX
 #undef _ENABLE_SSE2
 #undef GNUC_PUSH_POP
-/* 
+/*
+### new version with gribSwapByteOrder_uint16()
 icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_ENCODE encode_array.c
- result on hama (icc 15.0.1):
-  float:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 8.7936s
+ result on hama2 (icc 16.0.0):
+   float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 1.8731s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 2.0898s
   double:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 13.6093s
-     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.90009s
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.68089s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.30798s
+     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.23864s
+
+gcc -g -Wall -O3 -std=c99 -DTEST_ENCODE encode_array.c
+ result on hama2 (gcc 5.2.0):
+   float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.96739s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.30871s
+  double:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 6.24448s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 8.66679s
 
-gcc -g -Wall -O3 -march=native -std=c99 -DTEST_ENCODE encode_array.c
- result on hama (gcc 4.8.2):
-  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 16.0471s
-  sse41   : val1: 1  val2: 1  val3: 2  valn: 66  time: 15.4391s
+###
+icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_ENCODE encode_array.c
+ result on hama2 (icc 16.0.0):
+   float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 9.10691s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 8.63584s
+  double:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 13.5768s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 9.17742s
+     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.9488s
+
+gcc -g -Wall -O3 -std=c99 -DTEST_ENCODE encode_array.c
+ result on hama2 (gcc 5.2.0):
+   float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 5.32775s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 7.87125s
+  double:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 7.85873s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 12.9979s
 
+###
 gcc -g -Wall -O3 -march=native -std=c99 -DTEST_ENCODE encode_array.c
  result on bailung (gcc 4.7):
   orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 8.4166s
@@ -1675,14 +1430,11 @@ void pout(char *name, int s, unsigned char *lgrib, long datasize, double tt)
 int main(void)
 {
   long datasize = 1000000;
-  float *dataf = NULL;
-  double *data = NULL;
   double t_begin, t_end;
-  unsigned char *lgrib;
 
-  dataf = (float*) Malloc(datasize*sizeof(float));
-  data  = (double*) Malloc(datasize*sizeof(double));
-  lgrib = (unsigned char*) Malloc(2*datasize*sizeof(unsigned char));
+  float *dataf = (float*) malloc(datasize*sizeof(float));
+  double *data = (double*) malloc(datasize*sizeof(double));
+  unsigned char *lgrib = (unsigned char*) malloc(2*datasize*sizeof(unsigned char));
 
   for ( long i = 0; i < datasize; ++i ) dataf[i] = (float) (-datasize/2 + i);
   for ( long i = 0; i < datasize; ++i ) data[i] = (double) (-datasize/2 + i);
@@ -1700,7 +1452,6 @@ int main(void)
       encode_array_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
     }
 
-
 #if   defined(__ICC)
   printf("icc\n");
 #elif defined(__clang__)
@@ -1776,240 +1527,6 @@ int main(void)
 #undef DISABLE_SIMD
 #undef _ENABLE_AVX
 #undef _ENABLE_SSE4_1
-//#undef _GET_X86_COUNTER
-//#undef _GET_MACH_COUNTER
-//#undef _GET_IBM_COUNTER
-//#undef _ARCH_PWR6
-
-#if defined _GET_IBM_COUNTER
-#include <libhpc.h>
-#elif defined _GET_X86_COUNTER
-#include <x86intrin.h>
-#elif defined _GET_MACH_COUNTER
-#include <mach/mach_time.h>
-#endif
-
-#ifdef __cplusplus
-#define __STDC_FORMAT_MACROS
-#endif
-#include <inttypes.h>
-
-#if   defined(__GNUC__) && (__GNUC__ >= 4)
-#elif defined(__ICC)    && (__ICC >= 1100)
-#elif defined(__clang__)
-#else
-#define DISABLE_SIMD
-#endif
-
-#define DISABLE_SIMD
-
-#ifdef DISABLE_SIMD
-# ifdef ENABLE_AVX
-#  define _ENABLE_AVX
-# endif
-# ifdef ENABLE_SSE4_1
-#  define _ENABLE_SSE4_1
-# endif
-#endif
-
-#ifndef DISABLE_SIMD
-# ifdef __AVX__
-#  define _ENABLE_AVX
-# endif
-# ifdef __SSE4_1__
-#  define _ENABLE_SSE4_1
-# endif
-#endif
-
-#if defined _ENABLE_AVX
-#include <immintrin.h>
-#elif defined _ENABLE_SSE4_1
-#include <smmintrin.h>
-#endif
-
-#if defined _ENABLE_AVX
-
-static
-void avx_decode_array_2byte_double(size_t datasize, const unsigned char * restrict igrib,
-				     double * restrict fpdata, double fmin, double zscale)
-{
-  size_t i, j;
-  size_t nframes = datasize;
-  size_t residual;
-  size_t ofs;
-
-  double dval;
-
-  double *data = fpdata;
-  __m128i *sgrib;
-  
-  __m128i mask = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
-
-  __m256d ymm0 = _mm256_set1_pd(fmin);
-  __m256d ymm1 = _mm256_set1_pd(zscale);
-  
-  __m128i xmm0, xmm1, xmm2, xmm3;
-  __m256d ymm2, ymm3;
-
-  i = -1;
-  while ( ((unsigned long) data) % 32 != 0 && datasize > 0)
-    {
-      i++;
-      dval = (((int)igrib[2*i] <<  8) | (int)igrib[2*i+1]);
-      fpdata[i] = fmin + zscale * dval;
-      data++;
-      nframes--;
-    }
-  
-  if (i == -1) i = 0;
-  sgrib = (__m128i *) (igrib+i);
-
-  while (nframes >= 16)
-    { 
-      xmm0 = _mm_loadu_si128((__m128i *) sgrib);
-      xmm0 = _mm_shuffle_epi8(xmm0, mask);
-      xmm1 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(1, 0, 3, 2));
-      xmm2 = _mm_cvtepu16_epi32(xmm0);
-      xmm3 = _mm_cvtepu16_epi32(xmm1);
-
-      ymm2 = _mm256_cvtepi32_pd(xmm2);
-      ymm2 = _mm256_add_pd(_mm256_mul_pd(ymm2, ymm1), ymm0);
-      (void) _mm256_stream_pd(data, ymm2);
-      ymm3 = _mm256_cvtepi32_pd(xmm3);
-      ymm3 = _mm256_add_pd(_mm256_mul_pd(ymm3, ymm1), ymm0);
-      (void) _mm256_stream_pd(data+4, ymm3);  
-      
-      xmm0 = _mm_loadu_si128((__m128i *) sgrib + 1);
-      xmm0 = _mm_shuffle_epi8(xmm0, mask);
-      xmm1 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(1, 0, 3, 2));
-      xmm2 = _mm_cvtepu16_epi32(xmm0);
-      xmm3 = _mm_cvtepu16_epi32(xmm1);
-      
-      ymm2 = _mm256_cvtepi32_pd(xmm2);
-      ymm2 = _mm256_add_pd(_mm256_mul_pd(ymm2, ymm1), ymm0);
-      (void) _mm256_stream_pd(data+8, ymm2);
-      ymm3 = _mm256_cvtepi32_pd(xmm3);
-      ymm3 = _mm256_add_pd(_mm256_mul_pd(ymm3, ymm1), ymm0);
-      (void) _mm256_stream_pd(data+12, ymm3);  
-      
-      data += 16;
-      sgrib += 2;
-      nframes -= 16;
-    }
-
-  residual = nframes;
-  ofs = datasize - residual;
-  for ( j = 0; j < residual; j++ )
-    {
-      dval = (((int)igrib[2*(ofs+j)] <<  8) | (int)igrib[2*(ofs+j)+1]);
-      fpdata[ofs+j] = fmin + zscale * dval;
-    }
-
-  return;
-}
-
-#elif defined _ENABLE_SSE4_1
-
-static
-void sse41_decode_array_2byte_double(size_t datasize, const unsigned char * restrict igrib,
-				     double * restrict fpdata, double fmin, double zscale)
-{
-  size_t i, j;
-  size_t nframes = datasize;
-  size_t residual;
-  size_t ofs;
-
-  double dval;
-
-  double *data = fpdata;
-  __m128i *sgrib;
-  
-  __m128i mask = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
-  __m128d dmm8 = _mm_set1_pd(fmin);
-  __m128d dmm9 = _mm_set1_pd(zscale);
-  
-  __m128i xmm4, xmm5;
-  __m128i xmm6, xmm7;
-  
-  __m128d dmm0, dmm1, dmm2, dmm3;
-  __m128d dmm4, dmm5, dmm6, dmm7;
-
-  i = -1;
-  while ( ((unsigned long) data) % 32 != 0 && datasize > 0)
-    {
-      i++;
-      dval = (((int)igrib[2*i] <<  8) | (int)igrib[2*i+1]);
-      fpdata[i] = fmin + zscale * dval;
-      data++;
-      nframes--;
-    }
-  
-  if (i == -1) i = 0;
-  sgrib = (__m128i *) (igrib+i);
-  
-  while (nframes >= 16)
-    {
-      xmm5 = _mm_loadu_si128((__m128i *) sgrib);
-      xmm5 = _mm_shuffle_epi8(xmm5, mask);
-      xmm4 = _mm_srli_si128(xmm5, 8);
-      xmm6 = _mm_cvtepu16_epi32(xmm5);
-      dmm0 = _mm_cvtepi32_pd(xmm6);
-      dmm0 = _mm_add_pd(_mm_mul_pd(dmm0, dmm9), dmm8);
-      (void) _mm_stream_pd(data, dmm0);
-      xmm7 = _mm_srli_si128(xmm6, 8);
-      dmm1 = _mm_cvtepi32_pd(xmm7);
-      dmm1 = _mm_add_pd(_mm_mul_pd(dmm1, dmm9), dmm8);
-      (void) _mm_stream_pd(data+2, dmm1);
-      xmm6 = _mm_cvtepu16_epi32(xmm4);
-      dmm2 = _mm_cvtepi32_pd(xmm6);
-      dmm2 = _mm_add_pd(_mm_mul_pd(dmm2, dmm9), dmm8);
-      (void) _mm_stream_pd(data+4, dmm2);
-      xmm7 = _mm_srli_si128(xmm6, 8);
-      dmm3 = _mm_cvtepi32_pd(xmm7);
-      dmm3 = _mm_add_pd(_mm_mul_pd(dmm3, dmm9), dmm8);
-      (void) _mm_stream_pd(data+6, dmm3);
-      
-      xmm5 = _mm_loadu_si128((__m128i *) sgrib+1);
-      xmm5 = _mm_shuffle_epi8(xmm5, mask);
-      xmm4 = _mm_srli_si128(xmm5, 8);
-      xmm6 = _mm_cvtepu16_epi32(xmm5);
-      dmm4 = _mm_cvtepi32_pd(xmm6);
-      dmm4 = _mm_add_pd(_mm_mul_pd(dmm4, dmm9), dmm8);
-      (void) _mm_stream_pd(data+8, dmm4);
-      xmm7 = _mm_srli_si128(xmm6, 8);
-      dmm5 = _mm_cvtepi32_pd(xmm7);
-      dmm5 = _mm_add_pd(_mm_mul_pd(dmm5, dmm9), dmm8);
-      (void) _mm_stream_pd(data+10, dmm5);
-      xmm6 = _mm_cvtepu16_epi32(xmm4);
-      dmm6 = _mm_cvtepi32_pd(xmm6);
-      dmm6 = _mm_add_pd(_mm_mul_pd(dmm6, dmm9), dmm8);
-      (void) _mm_stream_pd(data+12, dmm6);
-      xmm7 = _mm_srli_si128(xmm6, 8);
-      dmm7 = _mm_cvtepi32_pd(xmm7);
-      dmm7 = _mm_add_pd(_mm_mul_pd(dmm7, dmm9), dmm8);
-      (void) _mm_stream_pd(data+14, dmm7);
-
-      data += 16;
-      sgrib += 2;
-      nframes -= 16;
-    }
-
-  residual = nframes;
-  ofs = datasize - residual;
-  for ( j = 0; j < residual; j++ )
-    {
-      dval = (((int)igrib[2*(ofs+j)] <<  8) | (int)igrib[2*(ofs+j)+1]);
-      fpdata[ofs+j] = fmin + zscale * dval;
-    }
-
-  return;
-}
-
-#endif
-
-#undef DISABLE_SIMD
-#undef _ENABLE_AVX
-#undef _ENABLE_SSE4_1
 
 
 void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
@@ -2080,12 +1597,7 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
         - replace 1.0 / pow(16.0, (double)(iexp - 70)) by rpow16m70tab[iexp]
   */
 
-  double rpowref;
-  double zref, zeps;
-  int iexp, isign;
-  int iround;
   // extern int CGRIBEX_Debug;
-  extern const double _pow16tab[71];
 
   /* ----------------------------------------------------------------- */
   /*   Section 1 . Initialise                                          */
@@ -2093,7 +1605,7 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
 
   /*  Check conversion type parameter. */
 
-  iround = kround;
+  int iround = kround;
   if ( iround != 0 && iround != 1 )
     {
       Error("Invalid conversion type = %d", iround);
@@ -2118,42 +1630,35 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
   /* ----------------------------------------------------------------- */
   /*   Section 3 . Convert other values.                               */
   /* ----------------------------------------------------------------- */
+  {
+    double zeps = kbits != 32 ? 1.0e-12 : 1.0e-8;
+    double zref = pval;
 
-  zeps = 1.0e-12;
-  if ( kbits == 32 ) zeps = 1.0e-8;
-  zref = pval;
-
-  /*  Sign of value. */
+    /*  Sign of value. */
 
-  isign = 0;
-  if ( zref < 0.0 )
-    {
-      isign = 128;
-      zref  = - zref;
-    }
+    int isign = zref >= 0.0 ? 0 : 128;
+    zref = fabs(zref);
 
-  /*  Exponent. */
+    /*  Exponent. */
 
-  iexp = (int) (log(zref)/log(16.0) + 65.0 + zeps);
+    int iexp = (int) (log(zref)/log(16.0) + 65.0 + zeps);
 
-  /* only ANSI C99 has log2 */
-  /* iexp = (int) (log2(zref) * 0.25 + 65.0 + zeps); */
+    /* only ANSI C99 has log2 */
+    /* iexp = (int) (log2(zref) * 0.25 + 65.0 + zeps); */
 
-  if ( iexp < 0   ) iexp = 0;
-  if ( iexp > 127 ) iexp = 127;
+    if ( iexp < 0   ) iexp = 0;
+    if ( iexp > 127 ) iexp = 127;
 
-  /*
-  rpowref = zref / pow(16.0, (double)(iexp - 70));
-  */
+    double rpowref;
+    /*
+      rpowref = zref / pow(16.0, (double)(iexp - 70));
+    */
 
-  if ( (iexp - 70) < 0 )
-    rpowref = zref * _pow16tab[-(iexp - 70)];
-  else
-    rpowref = zref / _pow16tab[(iexp - 70)];
+    rpowref = ldexp(zref, 4 * -(iexp - 70));
 
-  /*  Mantissa. */
+    /*  Mantissa. */
 
-  if ( iround == 0 )
+    if ( iround == 0 )
     {
       /*  Closest number in GRIB format less than original number. */
       /*  Truncate for positive numbers. */
@@ -2164,7 +1669,7 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
       else
 	*kmant = (int)lround(rpowref + 0.5);
     }
-  else
+    else
     {
       /*  Closest number in GRIB format to the original number   */
       /*  (equal to, greater than or less than original number). */
@@ -2172,12 +1677,12 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
       *kmant = (int)lround(rpowref);
     }
 
-  /*  Check that mantissa value does not exceed 24 bits. */
-  /*  If it does, adjust the exponent upwards and recalculate */
-  /*  the mantissa. */
-  /*  16777215 = 2**24 - 1 */
+    /*  Check that mantissa value does not exceed 24 bits. */
+    /*  If it does, adjust the exponent upwards and recalculate */
+    /*  the mantissa. */
+    /*  16777215 = 2**24 - 1 */
 
-  if ( *kmant > 16777215 )
+    if ( *kmant > 16777215 )
     {
 
     LABEL350:
@@ -2187,47 +1692,44 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
       /*  Check for exponent overflow during adjustment  */
 
       if ( iexp > 127 )
-	{
-          Message("Exponent overflow");
-          Message("Original number = %30.20f", pval);
-          Message("Sign = %3d, Exponent = %3d, Mantissa = %12d",
-		  isign, iexp, *kmant);
+      {
+        Message("Exponent overflow");
+        Message("Original number = %30.20f", pval);
+        Message("Sign = %3d, Exponent = %3d, Mantissa = %12d",
+                isign, iexp, *kmant);
 
-	  Error("Exponent overflow");
+        Error("Exponent overflow");
 
-	  /*  If not aborting, arbitrarily set value to zero  */
+        /*  If not aborting, arbitrarily set value to zero  */
 
-          Message("Value arbitrarily set to zero.");
-          *kexp  = 0;
-          *kmant = 0;
-          // iexp  = 0;
-          // isign = 0;
-          goto LABEL900;
-	}
+        Message("Value arbitrarily set to zero.");
+        *kexp  = 0;
+        *kmant = 0;
+        // iexp  = 0;
+        // isign = 0;
+        goto LABEL900;
+      }
 
-      if ( (iexp - 70) < 0 )
-	rpowref = zref * _pow16tab[-(iexp - 70)];
-      else
-	rpowref = zref / _pow16tab[(iexp - 70)];
+      rpowref = ldexp(zref, 4 * -(iexp - 70));
 
       if ( iround == 0 )
-	{
-	  /*  Closest number in GRIB format less than original number. */
-	  /*  Truncate for positive numbers. */
-	  /*  Round up for negative numbers. */
+      {
+        /*  Closest number in GRIB format less than original number. */
+        /*  Truncate for positive numbers. */
+        /*  Round up for negative numbers. */
 
-	  if ( isign == 0 )
-	    *kmant = (int)rpowref;
-	  else
-	    *kmant = (int)lround(rpowref + 0.5);
-	}
+        if ( isign == 0 )
+          *kmant = (int)rpowref;
+        else
+          *kmant = (int)lround(rpowref + 0.5);
+      }
       else
-	{
-	  /*  Closest number in GRIB format to the original number */
-	  /*  (equal to, greater or less than original number). */
+      {
+        /*  Closest number in GRIB format to the original number */
+        /*  (equal to, greater or less than original number). */
 
-	  *kmant = (int)lround(rpowref);
-	}
+        *kmant = (int)lround(rpowref);
+      }
 
       /*  Repeat calculation (with modified exponent) if still have */
       /*  mantissa overflow. */
@@ -2235,9 +1737,10 @@ void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
       if ( *kmant > 16777215 ) goto LABEL350;
     }
 
-  /*  Add sign bit to exponent. */
+    /*  Add sign bit to exponent. */
 
-  *kexp = iexp + isign;
+    *kexp = iexp + isign;
+  }
 
   /* ----------------------------------------------------------------- */
   /*   Section 9. Return                                               */
@@ -2260,6 +1763,7 @@ LABEL900:
   */
   return;
 } /* confp3 */
+#include <math.h>
 
 
 double decfp2(int kexp, int kmant)
@@ -2321,7 +1825,7 @@ double decfp2(int kexp, int kmant)
     Uwe Schulzweida   MPIfM   01/04/2001
 
      - Convert to C from EMOS library version 130
-     
+
     Uwe Schulzweida   MPIfM   02/08/2002
 
      - speed up by factor 2 on NEC SX6
@@ -2330,10 +1834,7 @@ double decfp2(int kexp, int kmant)
   */
 
   double pval;
-  int iexp, isign;
   //extern int CGRIBEX_Debug;
-  extern const double _pow16tab[71];
-  
   /* ----------------------------------------------------------------- */
   /*   Section 1 . Convert value of 0.0. Ignore sign bit.              */
   /* ----------------------------------------------------------------- */
@@ -2354,14 +1855,10 @@ double decfp2(int kexp, int kmant)
 
   /*  Sign of value. */
 
-  iexp  = kexp;
-  isign = 1;
+  int iexp  = kexp,
+    isign = (iexp < 128) * 2 - 1;
 
-  if ( iexp >= 128 )
-    {
-      iexp -= 128;
-      isign = -1;
-    }
+  iexp -= iexp < 128 ? 0 : 128;
 
   /*  Decode value. */
 
@@ -2369,12 +1866,7 @@ double decfp2(int kexp, int kmant)
 
   iexp -= 64;
 
-  if ( iexp < 0 )
-    pval = 1./_pow16tab[-iexp];
-  else
-    pval = _pow16tab[iexp];
-
-  pval *= isign * POW_2_M24 * kmant;
+  pval = ldexp(1.0, 4 * iexp) * isign * POW_2_M24 * kmant;
 
   /* ----------------------------------------------------------------- */
   /*   Section 9. Return to calling routine.                           */
@@ -2574,7 +2066,7 @@ void gprintf(const char *caller, const char *fmt, ...)
 void
 gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
 	 double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
-	 int kleng, int *kword, char *hoper, int *kret)
+	 int kleng, int *kword, const char *hoper, int *kret)
 {
   int yfunc = *hoper;
 
@@ -2605,7 +2097,7 @@ gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
 void
 gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
 	 float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
-	 int kleng, int *kword, char *hoper, int *kret)
+	 int kleng, int *kword, const char *hoper, int *kret)
 {
   int yfunc = *hoper;
 
@@ -2632,86 +2124,6 @@ gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
     }
 }
 
-
-void
-gribExSP_old(int *isec0, int *isec1, int *isec2, float *fsec2sp, int *isec3,
-	     float *fsec3sp, int *isec4, float *fsec4sp, int klenp, int *kgrib,
-	     int kleng, int *kword, char *hoper, int *kret)
-{
-  int inum, j;
-  double fsec2dp[1024];
-  double fsec3dp[2];
-  double *fsec4dp = NULL;
-  int yfunc = *hoper;
-
-  if ( yfunc == 'C' )
-    {
-      inum = 10 + isec2[11];
-      for ( j = 0; j < inum; j++ ) fsec2dp[j] = fsec2sp[j];
-
-      fsec3dp[0] = fsec3sp[0];
-      fsec3dp[1] = fsec3sp[1];
-
-      inum = isec4[0];
-      fsec4dp = (double*) Malloc(inum*sizeof(double));
-      if ( fsec4dp == NULL ) SysError("No Memory!");
-
-      for ( j = 0; j < inum; j++ ) fsec4dp[j] = fsec4sp[j];
-
-      gribExDP(isec0, isec1, isec2, fsec2dp, isec3,
-	       fsec3dp, isec4, fsec4dp, klenp, kgrib,
-	       kleng, kword, hoper, kret);
-
-      Free(fsec4dp);
-    }
-  else if ( yfunc == 'D' || yfunc == 'J' || yfunc == 'R' )
-    {
-      if ( yfunc == 'D' || yfunc == 'R' )
-	{
-	  fsec4dp = (double*) Malloc(klenp*sizeof(double));
-	  if ( fsec4dp == NULL ) SysError("No Memory!");
-	}
-
-      for ( j = 0; j < 10; j++ ) fsec2dp[j] = 0.0;
-      for ( j = 0; j <  2; j++ ) fsec3dp[j] = 0.0;
-
-      gribExDP(isec0, isec1, isec2, fsec2dp, isec3,
-	       fsec3dp, isec4, fsec4dp, klenp, kgrib,
-	       kleng, kword, hoper, kret);
-
-      inum = 10 + isec2[11];
-      for ( j = 0; j < inum; j++ ) fsec2sp[j] = fsec2dp[j];
-
-      fsec3sp[0] = fsec3dp[0];
-      fsec3sp[1] = fsec3dp[1];
-
-      if ( yfunc == 'D' || yfunc == 'R' )
-	{
-	  inum = isec4[0];
-	  for ( j = 0; j < inum; j++ )
-	    {
-	      if ( fsec4dp[j] > -FLT_MIN && fsec4dp[j] < FLT_MIN )
-		fsec4sp[j] = 0;
-	      else if ( fsec4dp[j] > FLT_MAX )
-		fsec4sp[j] = FLT_MAX;
-	      else if ( fsec4dp[j] < -FLT_MAX )
-		fsec4sp[j] = -FLT_MAX;
-	      else
-		fsec4sp[j] = fsec4dp[j];
-	    }
-
-	  Free(fsec4dp);
-	}
-    }
-  else if ( yfunc == 'V' )
-    fprintf(stderr, " c-gribex: Version is %s\n", cgribexLibraryVersion());
-  else
-    {
-      Error("oper %c unsupported!", yfunc);
-      *kret=-9;
-    }
-}
-
 int CGRIBEX_Fix_ZSE  = 0;    /* 1: Fix ZeroShiftError of simple packed spherical harmonics */
 int CGRIBEX_Const    = 0;    /* 1: Don't pack constant fields on regular grids */
 int CGRIBEX_Debug    = 0;    /* 1: Debugging */
@@ -3992,7 +3404,7 @@ void gribPrintSec2SP(int *isec0, int *isec2, float  *fsec2sp)
 
   inum = 10 + isec2[11];
 
-  fsec2 = (double*) Malloc(inum*sizeof(double));
+  fsec2 = (double*) Malloc((size_t)inum*sizeof(double));
   if ( fsec2 == NULL ) SysError("No Memory!");
 
   for ( j = 0; j < inum; j++ )
@@ -4340,29 +3752,30 @@ int gribCheckSeek(int fileID, long *offset, int *version)
 int gribFileSeekOld(int fileID, long *offset)
 {
   /* position file pointer after GRIB */
-  int ch;
-  int buffersize = 4096;
-  unsigned char buffer[4096];
+  enum { buffersize = 4096 };
+  unsigned char buffer[buffersize];
   int retry = 4096;
-  int i;
 
   *offset = 0;
 
   void *fileptr = filePtr(fileID);
 
-  ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[0] = ch;
-  ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[1] = ch;
-  ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[2] = ch;
-  ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[3] = ch;
+  for ( size_t i = 0; i < 4; ++i)
+    {
+      int ch = filePtrGetc(fileptr);
+      if ( ch == EOF ) return (-1);
+      buffer[i] = (unsigned char)ch;
+    }
   /*
   fileRead(fileID, buffer, 4);
   */
 
   while ( retry-- )
     {
+      size_t i;
       for ( i = 0; i < buffersize-4; ++i )
 	{
-	  if (buffer[i  ] == 'G' && 
+	  if (buffer[i  ] == 'G' &&
 	      buffer[i+1] == 'R' &&
 	      buffer[i+2] == 'I' &&
 	      buffer[i+3] == 'B')
@@ -4373,7 +3786,7 @@ int gribFileSeekOld(int fileID, long *offset)
 	    }
 	  else
 	    {
-	      ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[i+4] = ch;
+	      int ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[i+4] = (unsigned char)ch;
 	      (*offset)++;
 	    }
 	}
@@ -4427,13 +3840,13 @@ int gribFileSeek(int fileID, long *offset)
 int gribFileSeekTest(int fileID, long *offset)
 {
   /* position file pointer after GRIB */
-  const long GRIB = 0x47524942;
+  const long GRIB = 0x47524942L;
   long code = 0;
   int ch;
   int i = 0;
-  const int buffersize = 8;
-  unsigned char buffer[8];
-  int retry = 4096*4096;
+  enum { buffersize = 8 };
+  unsigned char buffer[buffersize];
+  unsigned long retry = 4096L*4096L;
   int nread = 0;
 
   *offset = 0;
@@ -4450,7 +3863,7 @@ int gribFileSeekTest(int fileID, long *offset)
 	}
 
       ch = buffer[i++];
-      code = ( (code << 8) + ch ) & 0xFFFFFFFF;
+      code = ( (code << 8) + ch ) & 0xFFFFFFFFL;
 
       if ( code == GRIB )
 	{
@@ -4471,6 +3884,14 @@ int gribFileSeekTest(int fileID, long *offset)
   return 1;
 }
 
+static inline int
+read3ByteMSBFirst(void *fileptr)
+{
+  unsigned b1 = (unsigned)(filePtrGetc(fileptr));
+  unsigned b2 = (unsigned)(filePtrGetc(fileptr));
+  unsigned b3 = (unsigned)(filePtrGetc(fileptr));
+  return (int)((b1 << 16) + (b2 << 8) + b3);
+}
 
 int gribReadSize(int fileID)
 {
@@ -4496,7 +3917,7 @@ int gribReadSize(int fileID)
     {
       int pdssize = 0, gdssize = 0, bmssize = 0, bdssize = 0;
       int issize = 4, essize = 4;
-      int flag;
+      int flag = 0;
 
       pdssize = gribsize;
       fileSetPos(fileID, (off_t) 3, SEEK_CUR);
@@ -4508,22 +3929,19 @@ int gribReadSize(int fileID)
 
       if ( flag & 128 )
 	{
-	  b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	  gdssize = (b1 << 16) + (b2 << 8) + b3;
+	  gdssize = read3ByteMSBFirst(fileptr);
 	  fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
 	  if ( CGRIBEX_Debug ) Message("gdssize     = %d", gdssize);
 	}
 
       if ( flag & 64 )
 	{
-	  b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	  bmssize = (b1 << 16) + (b2 << 8) + b3;
+	  bmssize = read3ByteMSBFirst(fileptr);
 	  fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
 	  if ( CGRIBEX_Debug ) Message("bmssize     = %d", bmssize);
 	}
 
-      b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-      bdssize = (b1 << 16) + (b2 << 8) + b3;
+      bdssize = read3ByteMSBFirst(fileptr);
       if ( CGRIBEX_Debug ) Message("bdssize     = %d", bdssize);
 
       gribsize = issize + pdssize + gdssize + bmssize + bdssize + essize;
@@ -4536,8 +3954,7 @@ int gribReadSize(int fileID)
 	  int issize = 4, essize = 4;
 	  int flag;
 
-	  b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	  pdssize = (b1 << 16) + (b2 << 8) + b3;
+	  pdssize = read3ByteMSBFirst(fileptr);
 	  if ( CGRIBEX_Debug ) Message("pdssize     = %d", pdssize);
 
 	  for ( int i = 0; i < 5; ++i ) flag = filePtrGetc(fileptr);
@@ -4547,22 +3964,19 @@ int gribReadSize(int fileID)
 
 	  if ( flag & 128 )
 	    {
-	      b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	      gdssize = (b1 << 16) + (b2 << 8) + b3;
+	      gdssize = read3ByteMSBFirst(fileptr);
 	      fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
 	      if ( CGRIBEX_Debug ) Message("gdssize     = %d", gdssize);
 	    }
 	  
 	  if ( flag & 64 )
 	    {
-	      b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	      bmssize = (b1 << 16) + (b2 << 8) + b3;
+	      bmssize = read3ByteMSBFirst(fileptr);
 	      fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
 	      if ( CGRIBEX_Debug ) Message("bmssize     = %d", bmssize);
 	    }
 
-	  b1 = filePtrGetc(fileptr); b2 = filePtrGetc(fileptr); b3 = filePtrGetc(fileptr);
-	  bdssize = (b1 << 16) + (b2 << 8) + b3;
+	  bdssize = read3ByteMSBFirst(fileptr);
 	  bdssize = correct_bdslen(bdssize, gribsize, issize+pdssize+gdssize+bmssize);
 	  if ( CGRIBEX_Debug ) Message("bdssize     = %d", bdssize);
 
@@ -4631,7 +4045,7 @@ int gribRead(int fileID, unsigned char *buffer, size_t *buffersize)
   if      ( ierr == -1 ) { *buffersize = 0; return -1; }
   else if ( ierr ==  1 ) { *buffersize = 0; return -2; }
 
-  size_t recSize  = gribReadSize(fileID);
+  size_t recSize  = (size_t)gribReadSize(fileID);
   size_t readSize = recSize;
 
   if ( readSize > *buffersize )
@@ -4662,7 +4076,7 @@ int gribWrite(int fileID, unsigned char *buffer, size_t buffersize)
 {
   int  nwrite = 0;
 
-  if ( (nwrite = fileWrite(fileID, buffer, buffersize)) != (int) buffersize )
+  if ( (nwrite = (int)(fileWrite(fileID, buffer, buffersize))) != (int) buffersize )
     {
       perror(__func__);
       nwrite = -1;
@@ -4682,7 +4096,7 @@ int gribrec_len(unsigned b1, unsigned b2, unsigned b3)
   */
   int needRescaling = b1 & (1 << 7);
   
-  int gribsize = (((b1&127) << 16)+(b2<<8) + b3);
+  int gribsize = (int)((((b1&127) << 16)+(b2<<8) + b3));
 
   if ( needRescaling ) gribsize *= 120;
 
@@ -5547,6 +4961,7 @@ void ref2ibm(double *pref, int kbits)
 
   return;
 } /* ref2ibm */
+#include <math.h>
 #include <string.h>
 
 
@@ -5560,7 +4975,7 @@ int correct_bdslen(int bdslen, long recsize, long gribpos)
     due to the count being only 24 bits. It is only possible because
     the (default) rounding for GRIB products is 120 bytes.
   */
-  if ( recsize > JP23SET ) bdslen = recsize - gribpos - bdslen;
+  if ( recsize > JP23SET ) bdslen = (int)(recsize - gribpos - bdslen);
   return (bdslen);
 }
 
@@ -5924,19 +5339,20 @@ int grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer,
 	      bufpointer[0], bufpointer[1], bufpointer[2], bufpointer[3]);
     }
 
-  bsf = BDS_BinScale;
-  if ( bsf > 32767 ) bsf = 32768-bsf;
-  bsf = pow(2.0,(double)bsf);
+  {
+    int bs = BDS_BinScale;
+    if ( bs > 32767 ) bs = 32768-bs;
+    bsf = ldexpf(1.0f, bs);
+  }
 
   bignum[0] = dpos;
-  if ( bms ) bignum[1] = bpos;
-  else       bignum[1] = -999;
+  bignum[1] = bms ? bpos : -999;
   intnum[0] = BDS_NumBits;
 
   /*  fltnum[0] = 1.0; */
-  fltnum[0] = pow(10.0, (double)PDS_DecimalScale);
+  fltnum[0] = powf(10.0f, (float)PDS_DecimalScale);
   fltnum[1] = bsf;
-  fltnum[2] = BDS_RefValue;
+  fltnum[2] = (float)BDS_RefValue;
   /*
   printf("intnum %d %d %d\n", intnum[0], intnum[1], intnum[2]);
   printf("fltnum %g %g %g\n", fltnum[0], fltnum[1], fltnum[2]);
@@ -6077,7 +5493,7 @@ void gribPrintALL(int nrec, long offset, long recpos, long recsize, unsigned cha
 {
   int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 0 || gribversion == 1 )
     grib1PrintALL(nrec, offset, recpos, recsize, gribbuffer);
@@ -6169,7 +5585,7 @@ void gribPrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer
 {
   int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 0 || gribversion == 1 )
     grib1PrintPDS(nrec, recpos, recsize, gribbuffer);
@@ -6230,7 +5646,7 @@ void gribPrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer
 {
   int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 0 || gribversion == 1 )
     grib1PrintGDS(nrec, recpos, recsize, gribbuffer);
@@ -6295,7 +5711,7 @@ void gribPrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer
 {
   int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 0 || gribversion == 1 )
     grib1PrintBMS(nrec, recpos, recsize, gribbuffer);
@@ -6385,7 +5801,7 @@ void gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer
 {
   int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 0 || gribversion == 1 )
     grib1PrintBDS(nrec, recpos, recsize, gribbuffer);
@@ -6448,7 +5864,6 @@ void gribCheck1(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
 static
 void repair1(unsigned char *gbuf, long gbufsize)
 {
-  long i;
   int nerr;
   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
   /* int recLen; */
@@ -6504,15 +5919,13 @@ void repair1(unsigned char *gbuf, long gbufsize)
 
   source = bds + datstart;
 
-  sourceLen = ((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8;
+  sourceLen = (size_t)(((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8);
 
   if ( bds_nbits == 24 )
     {
-      long nelem;
-      unsigned char *pbuf;
-      nelem = sourceLen/3;
-      pbuf = (unsigned char*) Malloc(sourceLen);
-      for ( i = 0; i < nelem; i++ )
+      unsigned char *pbuf = (unsigned char*) Malloc(sourceLen);;
+      size_t nelem = sourceLen/3;
+      for ( size_t i = 0; i < nelem; i++ )
 	{
 	  pbuf[3*i  ] = source[        i];
 	  pbuf[3*i+1] = source[  nelem+i];
@@ -6620,9 +6033,8 @@ int gribGetZip(long recsize, unsigned char *gribbuffer, long *urecsize)
   int bds_flag, lcompress;
   long gribsize = 0;
   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  int gribversion;
 
-  gribversion = gribVersion(gribbuffer, recsize);
+  int gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
   if ( gribversion == 2 ) return (compress);
 
@@ -6977,22 +6389,20 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 #if ! (defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC))
   static int libszwarn = 1;
 #endif
-  int nerr;
   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  int bdsLen, recLen, gribLen = 0;
+  size_t gribLen = 0;
   unsigned char *dest, *source;
   size_t destLen, sourceLen;
   int /* bds_len, */ bds_nbits, bds_flag, lspherc, lcomplex /*, lcompress*/;
-  int bds_head = 11;
+  enum { bds_head = 11 };
   int bds_ext = 0;
   int bds_zoffset, bds_zstart;
-  int datstart = 0;
   int llarge = FALSE;
 
   UNUSED(dbufsize);
 
   long gribrecsize;
-  nerr = grib1Sections(sbuf, sbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  int nerr = grib1Sections(sbuf, sbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
   if ( nerr < 0 )
     {
       fprintf(stdout, "GRIB message error\n");
@@ -7007,7 +6417,7 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 
   bds_zstart = 14;
 
-  recLen = gribrec_len(bds[bds_zstart], bds[bds_zstart+1], bds[bds_zstart+2]);
+  int recLen = gribrec_len(bds[bds_zstart], bds[bds_zstart+1], bds[bds_zstart+2]);
   if ( recLen > JP23SET ) llarge = TRUE;
 
   bds_zoffset = 12;
@@ -7035,7 +6445,7 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 	}
     }
 
-  datstart = bds_head + bds_ext;
+  size_t datstart = bds_head + (size_t)bds_ext;
 
   source = bds + datstart + bds_zoffset;
   if ( llarge )
@@ -7057,14 +6467,14 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
     }
 
   dest = bds + datstart;
-   if ( llarge )
+  if ( llarge )
     destLen = ((size_t) ((bds[17]<<24)+(bds[18]<<16)+(bds[19]<<8)+bds[20]));
   else
     destLen = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
 
-  BDS_Flag -= 16;
+  BDS_Flag = (unsigned char)(BDS_Flag - 16);
 
-  bdsLen = datstart + destLen;
+  size_t bdsLen = datstart + destLen;
 
 #if  defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC)
   {
@@ -7159,7 +6569,7 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 	    pbuf[3*i+2] = dest[2*nelem+i];
 	  }
 	memcpy(dest, pbuf, tmpLen);
-        Free(pbuf);
+	Free(pbuf);
       }
 #endif
 
@@ -7195,7 +6605,7 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 	*/
 	while ( gribLen%120 ) dbuf[gribLen++] = 0;
 
-	if ( gribLen != recLen )
+	if ( gribLen != (size_t)recLen )
 	  fprintf(stderr, "Internal problem, recLen and gribLen differ!\n");
 	
 	itemp = gribLen / (-120);
@@ -7236,126 +6646,19 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
     }
 #endif
 
-  return (gribLen);
+  return (int)gribLen;
 }
 #include <stdio.h>
 #include <math.h>
 
 
-/* calculate_pfactor: source code from grib_api-1.8.0 */
-double calculate_pfactor(const double* spectralField, long fieldTruncation, long subsetTruncation)
+
+static
+int rowina2(double *p, int ko, int ki, double *pw,
+	    int kcode, double msval, int *kret)
 {
-  /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
-  long loop, index, m, n = 0;
-  double pFactor, zeps = 1.0e-15;
-  long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
-  double* weights, range, * norms;
-  double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0, x, y;
-  double numerator = 0.0, denominator = 0.0, slope;
-
-  /*
-  // Setup the weights
-   */
-
-  range = (double) (ismax - ismin +1);
-
-  weights = (double*) Malloc((ismax+1)*sizeof(double));
-  for( loop = ismin; loop <= ismax; loop++ )
-    weights[loop] = range / (double) (loop-ismin+1);
-  /*
-  // Compute norms
-  // Handle values 2 at a time (real and imaginary parts).
-   */
-  norms = (double*) Malloc((ismax+1)*sizeof(double));
-
-  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
-  /*
-  // Form norms for the rows which contain part of the unscaled subset.
-   */
-
-  index = -2;
-  for( m = 0; m < subsetTruncation; m++ )
-    for( n = m; n <= fieldTruncation; n++ ) {
-      index += 2;
-      if( n >= subsetTruncation ) {
-        double tval = spectralField[index];
-        tval=tval<0?-tval:tval;
-        norms[n] = norms[n] > tval ? norms[n] : tval;
-        tval = spectralField[index+1];
-        tval=tval<0?-tval:tval;
-        norms[n] = norms[n] > tval ? norms[n] : tval;
-      }
-    }
-  /*
-  // Form norms for the rows which do not contain part of the unscaled subset.
-   */
-
-  for( m = subsetTruncation; m <= fieldTruncation; m++ )
-    for( n = m; n <= fieldTruncation; n++ ) {
-      double tval = spectralField[index];
-      index += 2;
-      tval=tval<0?-tval:tval;
-      norms[n] = norms[n] > tval ? norms[n] : tval;
-      tval = spectralField[index+1];
-      tval=tval<0?-tval:tval;
-      norms[n] = norms[n] > tval ? norms[n] : tval;
-    }
-
-  /*
-  // Ensure the norms have a value which is not too small in case of
-  // problems with math functions (e.g. LOG).
-   */
-
-  for( loop = ismin; loop <= ismax; loop++ ) {
-    norms[n] = norms[n] > zeps ? norms[n] : zeps;
-    if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
-  }
-
-  /*
-  // Do linear fit to find the slope
-   */
-
-  for( loop = ismin; loop <= ismax; loop++ ) {
-    x = log( (double) (loop*(loop+1)) );
-    y = log( norms[loop] );
-    weightedSumOverX = weightedSumOverX + x * weights[loop];
-    weightedSumOverY = weightedSumOverY + y * weights[loop];
-    sumOfWeights = sumOfWeights + weights[loop];
-  }
-  weightedSumOverX = weightedSumOverX / sumOfWeights;
-  weightedSumOverY = weightedSumOverY / sumOfWeights;
-
-  /*
-  // Perform a least square fit for the equation
-   */
-
-  for( loop = ismin; loop <= ismax; loop++ ) {
-
-    x = log( (double)(loop*(loop+1)) );
-    y = log( norms[loop] );
-    numerator =
-      numerator + weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
-    denominator =
-      denominator + weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
-  }
-  slope = numerator / denominator;
-
-  Free(weights);
-  Free(norms);
-
-  pFactor = -slope;
-  if( pFactor < -9999.9 ) pFactor = -9999.9;
-  if( pFactor > 9999.9 )  pFactor = 9999.9;
-
-  return pFactor;
-}
-
-static
-int rowina2(double *p, int ko, int ki, double *pw,
-	    int kcode, double msval, int *kret)
-{
-  /* System generated locals */
-  int pw_dim1, pw_offset, i_1;
+  /* System generated locals */
+  int pw_dim1, pw_offset, i_1;
 
   /* Local variables */
   double zwt1, zrdi, zpos;
@@ -7535,10 +6838,10 @@ int qu2reg2(double *pfield, int *kpoint, int klat, int klon,
    int iregno, iquano, j210, j220, j230, j240, j225;
 
 
-   zline = (double*) Malloc(2*klon*sizeof(double));
+   zline = (double*) Malloc(2*(size_t)klon*sizeof(double));
    if ( zline == NULL ) SysError("No Memory!");
 
-   zwork = (double*) Malloc(3*(2*klon+3)*sizeof(double));
+   zwork = (double*) Malloc(3*(2*(size_t)klon+3)*sizeof(double));
    if ( zwork == NULL ) SysError("No Memory!");
 
    /* Parameter adjustments */
@@ -7689,12 +6992,118 @@ L900:
 #define T double
 #ifdef T
 
+/* calculate_pfactor: source code from grib_api-1.8.0 */
+double TEMPLATE(calculate_pfactor,T)(const T *spectralField, long fieldTruncation, long subsetTruncation)
+{
+  /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
+  long loop, index, m, n = 0;
+  double pFactor, zeps = 1.0e-15;
+  long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
+  double* weights, range, * norms;
+  double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0, x, y;
+  double numerator = 0.0, denominator = 0.0, slope;
+
+  /*
+  // Setup the weights
+   */
+
+  range = (double) (ismax - ismin +1);
+
+  weights = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+  for( loop = ismin; loop <= ismax; loop++ )
+    weights[loop] = range / (double) (loop-ismin+1);
+  /*
+  // Compute norms
+  // Handle values 2 at a time (real and imaginary parts).
+   */
+  norms = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+
+  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
+  /*
+  // Form norms for the rows which contain part of the unscaled subset.
+   */
+
+  index = -2;
+  for( m = 0; m < subsetTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      index += 2;
+      if( n >= subsetTruncation ) {
+        double tval = spectralField[index];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+        tval = spectralField[index+1];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+      }
+    }
+  /*
+  // Form norms for the rows which do not contain part of the unscaled subset.
+   */
+
+  for( m = subsetTruncation; m <= fieldTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      double tval = spectralField[index];
+      index += 2;
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
+      tval = spectralField[index+1];
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
+    }
+
+  /*
+  // Ensure the norms have a value which is not too small in case of
+  // problems with math functions (e.g. LOG).
+   */
+
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    norms[n] = norms[n] > zeps ? norms[n] : zeps;
+    if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
+  }
+
+  /*
+  // Do linear fit to find the slope
+   */
+
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    x = log( (double) (loop*(loop+1)) );
+    y = log( norms[loop] );
+    weightedSumOverX = weightedSumOverX + x * weights[loop];
+    weightedSumOverY = weightedSumOverY + y * weights[loop];
+    sumOfWeights = sumOfWeights + weights[loop];
+  }
+  weightedSumOverX = weightedSumOverX / sumOfWeights;
+  weightedSumOverY = weightedSumOverY / sumOfWeights;
+
+  /*
+  // Perform a least square fit for the equation
+   */
+
+  for( loop = ismin; loop <= ismax; loop++ ) {
+
+    x = log( (double)(loop*(loop+1)) );
+    y = log( norms[loop] );
+    numerator =
+      numerator + weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
+    denominator =
+      denominator + weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
+  }
+  slope = numerator / denominator;
+
+  Free(weights);
+  Free(norms);
+
+  pFactor = -slope;
+  if( pFactor < -9999.9 ) pFactor = -9999.9;
+  if( pFactor > 9999.9 )  pFactor = 9999.9;
+
+  return pFactor;
+}
+
 void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, int inv)
 {
   double power;
-  double *scale = (double*) Malloc((trunc+1)*sizeof(double));
-  int  n, m;
-  int  index;
+  double *scale = (double*) Malloc(((size_t)trunc+1)*sizeof(double));
 
   if ( scale == NULL ) SysError("No Memory!");
 
@@ -7711,38 +7120,33 @@ void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, i
   power = (double) pcScale / 1000.;
   scale[0] = 1.0;
 
-  for ( n = 1; n <= trunc; n++ )
-    {
-      if (pcScale != 1000)
-         scale[n] = pow((double) (n*(n+1)), power);
-      else
-         scale[n] =     (double) (n*(n+1));
-    }
+  if (pcScale != 1000)
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] = pow((double) (n*(n+1)), power);
+  else
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] =     (double) (n*(n+1));
 
   if ( inv )
-    for ( n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
+    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
 
   /* Scale the values */
 
-  index = 0;
+  size_t index = 0;
 
-  for ( m = 0;   m < pcStart; m++ )
-    for ( n = m; n <= trunc; n++ )
-      {
-	if ( n >= pcStart )
-	  {
-	    fpdata[index  ] *= scale[n];
-	    fpdata[index+1] *= scale[n];
-	  }
-	index += 2;
-      }
+  for ( int m = 0;   m < pcStart; m++ )
+    for ( int n = m; n <= trunc; n++, index += 2 )
+      if ( n >= pcStart )
+        {
+          fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+          fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
+        }
 
-  for ( m = pcStart; m <= trunc; m++ )
-    for ( n = m;     n <= trunc; n++ )
+  for ( int m = pcStart; m <= trunc; m++ )
+    for ( int n = m;     n <= trunc; n++, index += 2 )
       {
-	fpdata[index  ] *= scale[n];
-	fpdata[index+1] *= scale[n];
-	index += 2;
+	fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+	fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
       }
 
   Free(scale);
@@ -7751,7 +7155,7 @@ void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, i
 
 void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 {
-  T *fphelp = (T*) Malloc(nsp*sizeof(T));
+  T *fphelp = (T*) Malloc((size_t)nsp*sizeof(T));
   int  m, n;
   int  index, inext;
 
@@ -7788,18 +7192,13 @@ void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 }
 
 
-void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
+void TEMPLATE(gather_complex,T)(T *fpdata, size_t pcStart, size_t trunc, size_t nsp)
 {
-  T *fphelp = (T*) Malloc(nsp*sizeof(T));
-  int  m, n;
-  int  index, inext;
-
-  if ( fphelp == NULL ) SysError("No Memory!");
+  T *restrict fphelp = (T*) Malloc(nsp*sizeof(T));
+  size_t inext = 0;
 
-  index = inext = 0;
-
-  for ( m = 0;   m <= pcStart; m++ )
-    for ( n = m; n <= trunc; n++ )
+  for ( size_t m = 0, index = 0;   m <= pcStart; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
       {
 	if ( pcStart >= n )
 	  {
@@ -7809,9 +7208,8 @@ void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 	index += 2;
       }
 
-  index = 0;
-  for ( m = 0;   m <= trunc; m++ )
-    for ( n = m; n <= trunc; n++ )
+  for ( size_t m = 0, index = 0; m <= trunc; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
       {
 	if ( n > pcStart )
 	  {
@@ -7821,7 +7219,7 @@ void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 	index += 2;
       }
 
-  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
   Free(fphelp);
 }
@@ -8042,8 +7440,8 @@ C     -----------------------------------------------------------------
 		{
 		  /*  Interpolate using the weighted values on either side */
 		  /*  of the output point position */
-		  p[jl] = (1.0 - zwt) * pw[ip+1 + pw_dim1] +
-		                  zwt * pw[ip+2 + pw_dim1];
+		  p[jl] = (T)((1.0 - zwt) * pw[ip+1 + pw_dim1]
+                              + zwt * pw[ip+2 + pw_dim1]);
 		}
 	    }
 	}
@@ -8073,14 +7471,14 @@ C     -----------------------------------------------------------------
       for ( jl = 1; jl <= i_1; ++jl )
 	{
           pw[jl + (pw_dim1 << 1)] =
-	        - pw[jl - 1 + pw_dim1] / 3.0 -
-	          pw[jl     + pw_dim1] * 0.5 +
-	          pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0;
+            (T)(- pw[jl - 1 + pw_dim1] / 3.0 -
+                pw[jl     + pw_dim1] * 0.5 +
+                pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0);
           pw[jl + 1 + pw_dim1 * 3] =
-                  pw[jl - 1 + pw_dim1] / 6.0 -
-                  pw[jl     + pw_dim1] +
-                  pw[jl + 1 + pw_dim1] * 0.5 +
-                  pw[jl + 2 + pw_dim1] / 3.0;
+            (T)(pw[jl - 1 + pw_dim1] / 6.0 -
+                pw[jl     + pw_dim1] +
+                pw[jl + 1 + pw_dim1] * 0.5 +
+                pw[jl + 2 + pw_dim1] / 3.0);
 	}
 
       TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
@@ -8095,10 +7493,10 @@ C     -----------------------------------------------------------------
           ip = (int) zwt + 1;
           zwt = zwt + 1.0 - ip;
           zwt1 = 1.0 - zwt;
-          p[jl] = ((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
-                  zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
-                  ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
-                  zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt;
+          p[jl] = (T)(((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
+                       zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
+                      ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
+                       zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt);
 	}
 
     }
@@ -8227,14 +7625,11 @@ C
    T *zline = NULL;
    T *zwork = NULL;
 
-   ztemp = (T*) Malloc(klon*klat*sizeof(T));
-   if ( ztemp == NULL ) SysError("No Memory!");
+   ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
 
-   zline = (T*) Malloc(2*klon*sizeof(T));
-   if ( zline == NULL ) SysError("No Memory!");
+   zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
 
-   zwork = (T*) Malloc(3*(2*klon+3)*sizeof(T));
-   if ( zwork == NULL ) SysError("No Memory!");
+   zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
 
    /* Parameter adjustments */
    --pfield;
@@ -8310,54 +7705,166 @@ C
             ztemp[ilio - 1] = zline[j220 - 1];
          }
 
-      } else {
+      } else {
+
+/*       Line contains the required number of values, so add */
+/*       this line to the temporary array. */
+
+         i_2 = iregno;
+         for (j225 = 1; j225 <= i_2; ++j225) {
+            ++ilio;
+            ++ilii;
+            ztemp[ilio - 1] = pfield[ilii];
+         }
+      }
+   }
+
+/* Copy temporary array to user array. */
+
+   i_1 = klon * klat;
+   for (j240 = 1; j240 <= i_1; ++j240) {
+      pfield[j240] = ztemp[j240 - 1];
+   }
+
+/* -------------------------------------------------------- */
+/* Section 9. Return to calling routine. Format statements. */
+/* -------------------------------------------------------- */
+
+L900:
+
+   Free(zwork);
+   Free(zline);
+   Free(ztemp);
+
+   return 0;
+} /* qu2reg3 */
+
+#endif /* T */
+
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
+#ifdef T
+#undef T
+#endif
+#define T float
+#ifdef T
+
+/* calculate_pfactor: source code from grib_api-1.8.0 */
+double TEMPLATE(calculate_pfactor,T)(const T *spectralField, long fieldTruncation, long subsetTruncation)
+{
+  /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
+  long loop, index, m, n = 0;
+  double pFactor, zeps = 1.0e-15;
+  long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
+  double* weights, range, * norms;
+  double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0, x, y;
+  double numerator = 0.0, denominator = 0.0, slope;
+
+  /*
+  // Setup the weights
+   */
+
+  range = (double) (ismax - ismin +1);
+
+  weights = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+  for( loop = ismin; loop <= ismax; loop++ )
+    weights[loop] = range / (double) (loop-ismin+1);
+  /*
+  // Compute norms
+  // Handle values 2 at a time (real and imaginary parts).
+   */
+  norms = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+
+  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
+  /*
+  // Form norms for the rows which contain part of the unscaled subset.
+   */
+
+  index = -2;
+  for( m = 0; m < subsetTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      index += 2;
+      if( n >= subsetTruncation ) {
+        double tval = spectralField[index];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+        tval = spectralField[index+1];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+      }
+    }
+  /*
+  // Form norms for the rows which do not contain part of the unscaled subset.
+   */
+
+  for( m = subsetTruncation; m <= fieldTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      double tval = spectralField[index];
+      index += 2;
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
+      tval = spectralField[index+1];
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
+    }
 
-/*       Line contains the required number of values, so add */
-/*       this line to the temporary array. */
+  /*
+  // Ensure the norms have a value which is not too small in case of
+  // problems with math functions (e.g. LOG).
+   */
 
-         i_2 = iregno;
-         for (j225 = 1; j225 <= i_2; ++j225) {
-            ++ilio;
-            ++ilii;
-            ztemp[ilio - 1] = pfield[ilii];
-         }
-      }
-   }
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    norms[n] = norms[n] > zeps ? norms[n] : zeps;
+    if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
+  }
 
-/* Copy temporary array to user array. */
+  /*
+  // Do linear fit to find the slope
+   */
 
-   i_1 = klon * klat;
-   for (j240 = 1; j240 <= i_1; ++j240) {
-      pfield[j240] = ztemp[j240 - 1];
-   }
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    x = log( (double) (loop*(loop+1)) );
+    y = log( norms[loop] );
+    weightedSumOverX = weightedSumOverX + x * weights[loop];
+    weightedSumOverY = weightedSumOverY + y * weights[loop];
+    sumOfWeights = sumOfWeights + weights[loop];
+  }
+  weightedSumOverX = weightedSumOverX / sumOfWeights;
+  weightedSumOverY = weightedSumOverY / sumOfWeights;
 
-/* -------------------------------------------------------- */
-/* Section 9. Return to calling routine. Format statements. */
-/* -------------------------------------------------------- */
+  /*
+  // Perform a least square fit for the equation
+   */
 
-L900:
+  for( loop = ismin; loop <= ismax; loop++ ) {
 
-   Free(zwork);
-   Free(zline);
-   Free(ztemp);
+    x = log( (double)(loop*(loop+1)) );
+    y = log( norms[loop] );
+    numerator =
+      numerator + weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
+    denominator =
+      denominator + weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
+  }
+  slope = numerator / denominator;
 
-   return 0;
-} /* qu2reg3 */
+  Free(weights);
+  Free(norms);
 
-#endif /* T */
+  pFactor = -slope;
+  if( pFactor < -9999.9 ) pFactor = -9999.9;
+  if( pFactor > 9999.9 )  pFactor = 9999.9;
 
-#ifdef T
-#undef T
-#endif
-#define T float
-#ifdef T
+  return pFactor;
+}
 
 void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, int inv)
 {
   double power;
-  double *scale = (double*) Malloc((trunc+1)*sizeof(double));
-  int  n, m;
-  int  index;
+  double *scale = (double*) Malloc(((size_t)trunc+1)*sizeof(double));
 
   if ( scale == NULL ) SysError("No Memory!");
 
@@ -8374,38 +7881,33 @@ void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, i
   power = (double) pcScale / 1000.;
   scale[0] = 1.0;
 
-  for ( n = 1; n <= trunc; n++ )
-    {
-      if (pcScale != 1000)
-         scale[n] = pow((double) (n*(n+1)), power);
-      else
-         scale[n] =     (double) (n*(n+1));
-    }
+  if (pcScale != 1000)
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] = pow((double) (n*(n+1)), power);
+  else
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] =     (double) (n*(n+1));
 
   if ( inv )
-    for ( n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
+    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
 
   /* Scale the values */
 
-  index = 0;
+  size_t index = 0;
 
-  for ( m = 0;   m < pcStart; m++ )
-    for ( n = m; n <= trunc; n++ )
-      {
-	if ( n >= pcStart )
-	  {
-	    fpdata[index  ] *= scale[n];
-	    fpdata[index+1] *= scale[n];
-	  }
-	index += 2;
-      }
+  for ( int m = 0;   m < pcStart; m++ )
+    for ( int n = m; n <= trunc; n++, index += 2 )
+      if ( n >= pcStart )
+        {
+          fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+          fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
+        }
 
-  for ( m = pcStart; m <= trunc; m++ )
-    for ( n = m;     n <= trunc; n++ )
+  for ( int m = pcStart; m <= trunc; m++ )
+    for ( int n = m;     n <= trunc; n++, index += 2 )
       {
-	fpdata[index  ] *= scale[n];
-	fpdata[index+1] *= scale[n];
-	index += 2;
+	fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+	fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
       }
 
   Free(scale);
@@ -8414,7 +7916,7 @@ void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, i
 
 void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 {
-  T *fphelp = (T*) Malloc(nsp*sizeof(T));
+  T *fphelp = (T*) Malloc((size_t)nsp*sizeof(T));
   int  m, n;
   int  index, inext;
 
@@ -8451,18 +7953,13 @@ void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 }
 
 
-void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
+void TEMPLATE(gather_complex,T)(T *fpdata, size_t pcStart, size_t trunc, size_t nsp)
 {
-  T *fphelp = (T*) Malloc(nsp*sizeof(T));
-  int  m, n;
-  int  index, inext;
-
-  if ( fphelp == NULL ) SysError("No Memory!");
-
-  index = inext = 0;
+  T *restrict fphelp = (T*) Malloc(nsp*sizeof(T));
+  size_t inext = 0;
 
-  for ( m = 0;   m <= pcStart; m++ )
-    for ( n = m; n <= trunc; n++ )
+  for ( size_t m = 0, index = 0;   m <= pcStart; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
       {
 	if ( pcStart >= n )
 	  {
@@ -8472,9 +7969,8 @@ void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 	index += 2;
       }
 
-  index = 0;
-  for ( m = 0;   m <= trunc; m++ )
-    for ( n = m; n <= trunc; n++ )
+  for ( size_t m = 0, index = 0; m <= trunc; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
       {
 	if ( n > pcStart )
 	  {
@@ -8484,7 +7980,7 @@ void TEMPLATE(gather_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
 	index += 2;
       }
 
-  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
   Free(fphelp);
 }
@@ -8705,8 +8201,8 @@ C     -----------------------------------------------------------------
 		{
 		  /*  Interpolate using the weighted values on either side */
 		  /*  of the output point position */
-		  p[jl] = (1.0 - zwt) * pw[ip+1 + pw_dim1] +
-		                  zwt * pw[ip+2 + pw_dim1];
+		  p[jl] = (T)((1.0 - zwt) * pw[ip+1 + pw_dim1]
+                              + zwt * pw[ip+2 + pw_dim1]);
 		}
 	    }
 	}
@@ -8736,14 +8232,14 @@ C     -----------------------------------------------------------------
       for ( jl = 1; jl <= i_1; ++jl )
 	{
           pw[jl + (pw_dim1 << 1)] =
-	        - pw[jl - 1 + pw_dim1] / 3.0 -
-	          pw[jl     + pw_dim1] * 0.5 +
-	          pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0;
+            (T)(- pw[jl - 1 + pw_dim1] / 3.0 -
+                pw[jl     + pw_dim1] * 0.5 +
+                pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0);
           pw[jl + 1 + pw_dim1 * 3] =
-                  pw[jl - 1 + pw_dim1] / 6.0 -
-                  pw[jl     + pw_dim1] +
-                  pw[jl + 1 + pw_dim1] * 0.5 +
-                  pw[jl + 2 + pw_dim1] / 3.0;
+            (T)(pw[jl - 1 + pw_dim1] / 6.0 -
+                pw[jl     + pw_dim1] +
+                pw[jl + 1 + pw_dim1] * 0.5 +
+                pw[jl + 2 + pw_dim1] / 3.0);
 	}
 
       TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
@@ -8758,10 +8254,10 @@ C     -----------------------------------------------------------------
           ip = (int) zwt + 1;
           zwt = zwt + 1.0 - ip;
           zwt1 = 1.0 - zwt;
-          p[jl] = ((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
-                  zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
-                  ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
-                  zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt;
+          p[jl] = (T)(((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
+                       zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
+                      ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
+                       zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt);
 	}
 
     }
@@ -8890,14 +8386,11 @@ C
    T *zline = NULL;
    T *zwork = NULL;
 
-   ztemp = (T*) Malloc(klon*klat*sizeof(T));
-   if ( ztemp == NULL ) SysError("No Memory!");
+   ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
 
-   zline = (T*) Malloc(2*klon*sizeof(T));
-   if ( zline == NULL ) SysError("No Memory!");
+   zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
 
-   zwork = (T*) Malloc(3*(2*klon+3)*sizeof(T));
-   if ( zwork == NULL ) SysError("No Memory!");
+   zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
 
    /* Parameter adjustments */
    --pfield;
@@ -9008,6 +8501,12 @@ L900:
 } /* qu2reg3 */
 
 #endif /* T */
+
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 #include <string.h>
 
 
@@ -9301,31 +8800,31 @@ void gribPrintSec3_float(int *isec0, int *isec3, float *fsec3) {gribPrintSec3SP(
 void gribPrintSec4_float(int *isec0, int *isec4, float *fsec4) {gribPrintSec4SP(isec0, isec4, fsec4);}
 
 
-
 #ifdef T
 #undef T
 #endif
 #define T double
 #ifdef T
 
+#include <inttypes.h>
+
 static 
-void TEMPLATE(decode_array_common,T)(const unsigned char * restrict igrib, long jlend, int NumBits, 
-				     T fmin, T zscale, T * restrict fpdata)
+void TEMPLATE(decode_array_common,T)(const unsigned char *restrict igrib, long jlend, int NumBits, 
+				     T fmin, T zscale, T *restrict fpdata)
 {
   /* code from wgrib routine BDS_unpack */
   const unsigned char *bits = igrib;
-  unsigned int jmask;
   long i;
   unsigned int tbits = 0;
   int n_bits = NumBits;
   int t_bits = 0;
-      
-  jmask = (1 << n_bits) - 1;
+
+  unsigned jmask = (1U << n_bits) - 1U;
   for ( i = 0; i < jlend; i++ )
     {
       if (n_bits - t_bits > 8)
 	{
-	  tbits = (tbits << 16) | (bits[0] << 8) | (bits[1]);
+	  tbits = (tbits << 16) | ((unsigned)bits[0] << 8) | ((unsigned)bits[1]);
 	  bits += 2;
 	  t_bits += 16;
 	}
@@ -9336,35 +8835,32 @@ void TEMPLATE(decode_array_common,T)(const unsigned char * restrict igrib, long
 	  t_bits += 8;
 	}
       t_bits -= n_bits;
-      fpdata[i] = (tbits >> t_bits) & jmask;
+      fpdata[i] = (float)((tbits >> t_bits) & jmask);
     }
   /* at least this vectorizes :) */
   for ( i = 0; i < jlend; i++ )
     fpdata[i] = fmin + zscale*fpdata[i];
 }
 
-#if !defined(_MASK_AND_SHIFT_)
-#define _MASK_AND_SHIFT_
-static unsigned int mask[] = {0,1,3,7,15,31,63,127,255};
-static double shift[9] = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
-#endif
-
-static 
-void TEMPLATE(decode_array_common2,T)(const unsigned char * restrict igrib, long jlend, int NumBits, 
-				      T fmin, T zscale, T * restrict fpdata)
+static
+void TEMPLATE(decode_array_common2,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
+				      T fmin, T zscale, T *restrict fpdata)
 {
+  static const unsigned mask[] = {0,1,3,7,15,31,63,127,255};
+  static const double shift[9]
+    = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
+
   /* code from wgrib routine BDS_unpack */
   const unsigned char *bits = igrib;
   long i;
   int n_bits = NumBits;
   int c_bits, j_bits;
-  double jj;
 
   /* older unoptimized code, not often used */
   c_bits = 8;
   for ( i = 0; i < jlend; i++ )
     {
-      jj = 0.0;
+      double jj = 0.0;
       j_bits = n_bits;
       while (c_bits <= j_bits)
 	{
@@ -9385,12 +8881,36 @@ void TEMPLATE(decode_array_common2,T)(const unsigned char * restrict igrib, long
       if (j_bits)
 	{
 	  c_bits -= j_bits;
-	  jj = (jj * shift[j_bits]) + (double) ((*bits >> c_bits) & mask[j_bits]);
+	  jj = (jj * shift[j_bits]) + (double) (((unsigned)*bits >> c_bits) & mask[j_bits]);
 	}
-      
-      fpdata[i] = fmin + zscale*jj;
+      fpdata[i] = (T)(fmin + zscale*jj);
+    }
+}
+
+static
+void TEMPLATE(decode_array_2byte,T)(size_t jlend, const unsigned char *restrict igrib,
+                                    T *fpdata, T fmin, T zscale)
+{
+  U_BYTEORDER;
+  const uint16_t *restrict sgrib = (uint16_t *) (igrib);
+
+  if ( IS_BIGENDIAN() )
+    {
+      for ( size_t i = 0; i < jlend; i++ )
+        {
+          fpdata[i] = fmin + zscale * sgrib[i];
+        }
+    }
+  else
+    {
+      uint16_t ui16;
+      for ( size_t i = 0; i < jlend; i++ )
+        {
+          ui16 = gribSwapByteOrder_uint16(sgrib[i]);
+          fpdata[i] = fmin + zscale * ui16;
+        }
     }
-} 
+}
 
 static 
 void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, int numBits, 
@@ -9401,7 +8921,6 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
 #endif
 
   long i;
-  T dval;
 #if defined (VECTORCODE)
   GRIBPACK *lgrib = NULL;
 
@@ -9425,26 +8944,26 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
   else if ( numBits ==  8 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (int)lgrib[i];
+	T dval = (int)lgrib[i];
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 16 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
+	T dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 24 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
+	T dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
 	  	 (int)lgrib[3*i+2]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 32 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
+	T dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
 		((unsigned int)lgrib[4*i+2] <<  8) +  (unsigned int)lgrib[4*i+3]);
 	fpdata[i] = fmin + zscale * dval;
       }
@@ -9472,75 +8991,25 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
   else if ( numBits ==  8 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (int)igrib[i];
+	T dval = (int)igrib[i];
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 16 )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(6, "unpack 16 bit base");
-#elif defined _GET_X86_COUNTER 
-      start_decode = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      start_decode = mach_absolute_time();
-#endif
-      
-      if ( sizeof(T) == sizeof(double) )
-      	{ 
-#if defined _ENABLE_AVX
-	  printf("AVX selected ...\n");
-	  avx_decode_array_2byte_double((size_t) jlend, igrib, fpdata, fmin, zscale);
-#elif defined _ENABLE_SSE4_1
-	  printf("SSE4 selected ...\n");
-	  sse41_decode_array_2byte_double((size_t) jlend, igrib, fpdata, fmin, zscale);
-#else
-	  for ( i = 0; i < jlend; i++ )
-	    {
-	      dval = (((int)igrib[2*i  ] <<  8) |  (int)igrib[2*i+1]);
-	      fpdata[i] = fmin + zscale * dval;
-	    }
-#endif
-	}
-      else
-	{
-	  for ( i = 0; i < jlend; i++ )
-	    {
-	      dval = (((int)igrib[2*i  ] <<  8) |  (int)igrib[2*i+1]);
-	      fpdata[i] = fmin + zscale * dval;
-	    }
-	}
-
-#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
-#if defined _GET_X86_COUNTER 
-      end_decode = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      end_decode = mach_absolute_time();
-#endif
-#if defined _ENABLE_AVX
-      printf("AVX encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#elif defined _ENABLE_SSE4_1
-      printf("SSE 4.1 encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#else
-      printf("loop encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#endif  
-#endif
-      
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(6);
-#endif
+      TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
     }
   else if ( numBits == 24 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
-		 (int)igrib[3*i+2]);
+	T dval = (T)(((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
+                     (int)igrib[3*i+2]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 32 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
-		((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
+	T dval = (T)(((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
+                     ((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits <= 25 )
@@ -9560,30 +9029,37 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 #ifdef T
 #undef T
 #endif
 #define T float
 #ifdef T
 
+#include <inttypes.h>
+
 static 
-void TEMPLATE(decode_array_common,T)(const unsigned char * restrict igrib, long jlend, int NumBits, 
-				     T fmin, T zscale, T * restrict fpdata)
+void TEMPLATE(decode_array_common,T)(const unsigned char *restrict igrib, long jlend, int NumBits, 
+				     T fmin, T zscale, T *restrict fpdata)
 {
   /* code from wgrib routine BDS_unpack */
   const unsigned char *bits = igrib;
-  unsigned int jmask;
   long i;
   unsigned int tbits = 0;
   int n_bits = NumBits;
   int t_bits = 0;
-      
-  jmask = (1 << n_bits) - 1;
+
+  unsigned jmask = (1U << n_bits) - 1U;
   for ( i = 0; i < jlend; i++ )
     {
       if (n_bits - t_bits > 8)
 	{
-	  tbits = (tbits << 16) | (bits[0] << 8) | (bits[1]);
+	  tbits = (tbits << 16) | ((unsigned)bits[0] << 8) | ((unsigned)bits[1]);
 	  bits += 2;
 	  t_bits += 16;
 	}
@@ -9594,35 +9070,32 @@ void TEMPLATE(decode_array_common,T)(const unsigned char * restrict igrib, long
 	  t_bits += 8;
 	}
       t_bits -= n_bits;
-      fpdata[i] = (tbits >> t_bits) & jmask;
+      fpdata[i] = (float)((tbits >> t_bits) & jmask);
     }
   /* at least this vectorizes :) */
   for ( i = 0; i < jlend; i++ )
     fpdata[i] = fmin + zscale*fpdata[i];
 }
 
-#if !defined(_MASK_AND_SHIFT_)
-#define _MASK_AND_SHIFT_
-static unsigned int mask[] = {0,1,3,7,15,31,63,127,255};
-static double shift[9] = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
-#endif
-
-static 
-void TEMPLATE(decode_array_common2,T)(const unsigned char * restrict igrib, long jlend, int NumBits, 
-				      T fmin, T zscale, T * restrict fpdata)
+static
+void TEMPLATE(decode_array_common2,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
+				      T fmin, T zscale, T *restrict fpdata)
 {
+  static const unsigned mask[] = {0,1,3,7,15,31,63,127,255};
+  static const double shift[9]
+    = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
+
   /* code from wgrib routine BDS_unpack */
   const unsigned char *bits = igrib;
   long i;
   int n_bits = NumBits;
   int c_bits, j_bits;
-  double jj;
 
   /* older unoptimized code, not often used */
   c_bits = 8;
   for ( i = 0; i < jlend; i++ )
     {
-      jj = 0.0;
+      double jj = 0.0;
       j_bits = n_bits;
       while (c_bits <= j_bits)
 	{
@@ -9643,12 +9116,36 @@ void TEMPLATE(decode_array_common2,T)(const unsigned char * restrict igrib, long
       if (j_bits)
 	{
 	  c_bits -= j_bits;
-	  jj = (jj * shift[j_bits]) + (double) ((*bits >> c_bits) & mask[j_bits]);
+	  jj = (jj * shift[j_bits]) + (double) (((unsigned)*bits >> c_bits) & mask[j_bits]);
 	}
-      
-      fpdata[i] = fmin + zscale*jj;
+      fpdata[i] = (T)(fmin + zscale*jj);
+    }
+}
+
+static
+void TEMPLATE(decode_array_2byte,T)(size_t jlend, const unsigned char *restrict igrib,
+                                    T *fpdata, T fmin, T zscale)
+{
+  U_BYTEORDER;
+  const uint16_t *restrict sgrib = (uint16_t *) (igrib);
+
+  if ( IS_BIGENDIAN() )
+    {
+      for ( size_t i = 0; i < jlend; i++ )
+        {
+          fpdata[i] = fmin + zscale * sgrib[i];
+        }
+    }
+  else
+    {
+      uint16_t ui16;
+      for ( size_t i = 0; i < jlend; i++ )
+        {
+          ui16 = gribSwapByteOrder_uint16(sgrib[i]);
+          fpdata[i] = fmin + zscale * ui16;
+        }
     }
-} 
+}
 
 static 
 void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, int numBits, 
@@ -9659,7 +9156,6 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
 #endif
 
   long i;
-  T dval;
 #if defined (VECTORCODE)
   GRIBPACK *lgrib = NULL;
 
@@ -9683,26 +9179,26 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
   else if ( numBits ==  8 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (int)lgrib[i];
+	T dval = (int)lgrib[i];
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 16 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
+	T dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 24 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
+	T dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
 	  	 (int)lgrib[3*i+2]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 32 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
+	T dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
 		((unsigned int)lgrib[4*i+2] <<  8) +  (unsigned int)lgrib[4*i+3]);
 	fpdata[i] = fmin + zscale * dval;
       }
@@ -9722,83 +9218,33 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
   if ( lgrib ) Free(lgrib);
 
 #else
-  if ( numBits ==  0 )
-    {
-      for ( i = 0; i < jlend; i++ )
-	fpdata[i] = fmin;
-    }
-  else if ( numBits ==  8 )
-    for ( i = 0; i < jlend; i++ )
-      {
-	dval = (int)igrib[i];
-	fpdata[i] = fmin + zscale * dval;
-      }
-  else if ( numBits == 16 )
-    {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(6, "unpack 16 bit base");
-#elif defined _GET_X86_COUNTER 
-      start_decode = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      start_decode = mach_absolute_time();
-#endif
-      
-      if ( sizeof(T) == sizeof(double) )
-      	{ 
-#if defined _ENABLE_AVX
-	  printf("AVX selected ...\n");
-	  avx_decode_array_2byte_double((size_t) jlend, igrib, fpdata, fmin, zscale);
-#elif defined _ENABLE_SSE4_1
-	  printf("SSE4 selected ...\n");
-	  sse41_decode_array_2byte_double((size_t) jlend, igrib, fpdata, fmin, zscale);
-#else
-	  for ( i = 0; i < jlend; i++ )
-	    {
-	      dval = (((int)igrib[2*i  ] <<  8) |  (int)igrib[2*i+1]);
-	      fpdata[i] = fmin + zscale * dval;
-	    }
-#endif
-	}
-      else
-	{
-	  for ( i = 0; i < jlend; i++ )
-	    {
-	      dval = (((int)igrib[2*i  ] <<  8) |  (int)igrib[2*i+1]);
-	      fpdata[i] = fmin + zscale * dval;
-	    }
-	}
-
-#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
-#if defined _GET_X86_COUNTER 
-      end_decode = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      end_decode = mach_absolute_time();
-#endif
-#if defined _ENABLE_AVX
-      printf("AVX encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#elif defined _ENABLE_SSE4_1
-      printf("SSE 4.1 encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#else
-      printf("loop encoding cycles:: %" PRIu64 "\n", end_decode-start_decode);
-#endif  
-#endif
-      
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(6);
-#endif
+  if ( numBits ==  0 )
+    {
+      for ( i = 0; i < jlend; i++ )
+	fpdata[i] = fmin;
+    }
+  else if ( numBits ==  8 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (int)igrib[i];
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits == 16 )
+    {
+      TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
     }
   else if ( numBits == 24 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
-		 (int)igrib[3*i+2]);
+	T dval = (T)(((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
+                     (int)igrib[3*i+2]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits == 32 )
     for ( i = 0; i < jlend; i++ )
       {
-	dval = (((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
-		((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
+	T dval = (T)(((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
+                     ((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
 	fpdata[i] = fmin + zscale * dval;
       }
   else if ( numBits <= 25 )
@@ -9818,6 +9264,12 @@ void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, i
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 
 #ifdef T
 #undef T
@@ -9832,7 +9284,6 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
   int  ReducedGrid = FALSE, VertCoorTab = FALSE;
   int  locnv = 0, locnl;
   int  jlenl;
-  long i;
   int iexp, imant;
   int ipvpl, ipl;
   int gdsLen = 0;
@@ -9884,7 +9335,7 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 	{
 	  *numGridVals = 0;
 	  ISEC2_Reduced = TRUE;
-	  for ( i = 0; i < jlenl; i++ )
+	  for ( int i = 0; i < jlenl; i++ )
 	    {
 	      ISEC2_RowLon(i) = GET_UINT2(gds[locnl+2*i], gds[locnl+2*i+1]);
 	      *numGridVals += ISEC2_RowLon(i);
@@ -9924,7 +9375,7 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 	{
 	  ISEC2_LatSP     = GDS_LatSP;
 	  ISEC2_LonSP     = GDS_LonSP;
-	  FSEC2_RotAngle  = GDS_RotAngle;
+	  FSEC2_RotAngle  = (T)GDS_RotAngle;
 	}
       /*
 	if ( Lons != Longitudes || Lats != Latitudes )
@@ -10034,31 +9485,34 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 
       igrib = &gds[locnv];
       if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
-      for ( i = 0; i < ISEC2_NumVCP; i++ )
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
 	{
 	  iexp   = (lgrib[4*i  ]);
 	  imant  =((lgrib[4*i+1]) << 16) +
 	          ((lgrib[4*i+2]) <<  8) +
 	           (lgrib[4*i+3]);
-	  fsec2[10+i] = POW_2_M24 * imant * pow(16.0, (double)(iexp - 64));
+	  fsec2[10+i] = POW_2_M24 * imant * ldexp(1.0, 4 * (iexp - 64));
 	}
 
       Free(lgrib);
 #else
-      for ( i = 0; i < ISEC2_NumVCP; i++ )
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
 	{
 	  iexp   = (gds[locnv+4*i  ]);
 	  imant  =((gds[locnv+4*i+1]) << 16) +
 	          ((gds[locnv+4*i+2]) <<  8) +
 	           (gds[locnv+4*i+3]);
-	  fsec2[10+i] = decfp2(iexp,imant);
+	  fsec2[10+i] = (T)decfp2(iexp,imant);
 	}
 #endif
     }
 
-  return (gdsLen);
+  return gdsLen;
 }
 
+#define ldexp_double ldexp
+#define ldexp_float ldexpf
+
 static
 int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *isec4, 
 			  T *fsec4, int fsec4len, int dfunc, int bdsLenIn, int numGridVals, int llarge, int *iret)
@@ -10068,15 +9522,13 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
   int lcompress;
   int jup, kup, mup;
   int locnd;
-  long jlend;
-  long i;
   int bds_flag, jscale, imiss;
   int bds_ubits;
   int ioff = 0;
   int iexp, imant;
   int zoff;
   int bds_head = 11;
-  double zscale = 0.;
+  T zscale = 0.;
   T fmin = 0.;
   T *fpdata = fsec4;
   int bdsLen;
@@ -10147,16 +9599,11 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 
   /* convert reference value and scale factor. */
 
-  if ( ! (dfunc == 'J') )
-    if ( imiss == 0 )
-      {
-	fmin = BDS_RefValue;
-	
-	if ( jscale < 0 )
-	  zscale = 1.0/intpow2(-jscale);
-	else
-	  zscale = intpow2(jscale);
-      }
+  if ( ! (dfunc == 'J') && imiss == 0 )
+    {
+      fmin = BDS_RefValue;
+      zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
+    }
 
   /* get number of bits in each data value. */
 
@@ -10190,7 +9637,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  if ( dfunc != 'J' )
 	    {
 	      if ( imiss ) *fpdata++ = 0.0;
-	      else         *fpdata++ = BDS_RealCoef;
+	      else         *fpdata++ = (T)BDS_RealCoef;
 	    }
 	}
       else /* complex packed spherical harmonics */
@@ -10217,7 +9664,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  ioff   = (jup+1)*(jup+2);
 
 	  if ( dfunc != 'J' )
-	    for ( i = 0; i < ioff; i++ )
+	    for ( int i = 0; i < ioff; i++ )
 	      {
 		if ( imiss )
 		  *fpdata++ = 0.0;
@@ -10228,7 +9675,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 		            ((bds[locnd+4*i+2]) <<  8) +
 		             (bds[locnd+4*i+3]);
 
-		    *fpdata++ = decfp2(iexp,imant);
+		    *fpdata++ = (T)decfp2(iexp,imant);
 		  }
 	      }
 	  
@@ -10242,7 +9689,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 1999;
 	  gprintf(__func__, " Second order packed grids unsupported!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
     }
 
@@ -10251,7 +9698,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
   /* Take into account that spherical harmonics can be packed  */
   /* simple (lcomplex = 0) or complex (lcomplex = 1)           */
 
-  jlend = bdsLen - locnd;
+  int jlend = bdsLen - locnd;
 
   if ( ISEC4_NumBits == 0 )
     {
@@ -10260,7 +9707,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 2001;
 	  gprintf(__func__, " Number of bits per data value = 0!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
 
       if ( numGridVals == 0 )
@@ -10268,7 +9715,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 2002;
 	  gprintf(__func__, " Constant field unsupported for this grid type!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
 
       jlend = numGridVals;
@@ -10291,7 +9738,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
       else
         len = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
 
-      ISEC4_NumValues = len*8/ISEC4_NumBits;
+      ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
 
       if ( lspherc )
 	{
@@ -10302,7 +9749,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	}
     }
 
-  if ( dfunc == 'J' ) return (bdsLen);
+  if ( dfunc == 'J' ) return bdsLen;
 
   /* check length of output array. */
   
@@ -10312,10 +9759,10 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
       gprintf(__func__, " Output array too small. Length = %d", fsec4len);
       gprintf(__func__, " Number of values = %d", ISEC4_NumValues);
       gprintf(__func__, " Return code =  %d", *iret);
-      return (0);
+      return 0;
     }
 
-  if ( imiss ) memset((char *)fpdata, 0, jlend*sizeof(T));
+  if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
   else
     {
       igrib += locnd;
@@ -10325,9 +9772,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 
   if ( lspherc && lcomplex )
     {
-      int pcStart, pcScale;
-      pcStart = isec4[19];
-      pcScale = isec4[16];
+      int pcStart = isec4[19], pcScale = isec4[16];
       TEMPLATE(scatter_complex,T)(fsec4, pcStart, ISEC2_PentaJ, ISEC4_NumValues);
       TEMPLATE(scale_complex,T)(fsec4, pcStart, pcScale, ISEC2_PentaJ, 1);
     }
@@ -10339,17 +9784,17 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	if ( IS_NOT_EQUAL(fsec4[1], 0.0) )
 	  {
 	    T zserr = fsec4[1];
-	    for ( i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
+	    for ( int i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
 	  }
       }
 
   if ( decscale )
     {
       T scale = (T) pow(10.0, (double)-decscale);
-      for ( i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
+      for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
     }
 
-  return (bdsLen);
+  return bdsLen;
 }
 
 
@@ -10359,7 +9804,6 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 {
   UCHAR *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
   int isLen = 0, pdsLen = 0, gdsLen = 0, bmsLen = 0, bdsLen = 0, esLen = 0;
-  int gribLen = 0;
   int gdsIncluded = FALSE;
   int bmsIncluded = FALSE;
   int bitmapSize = 0;
@@ -10550,7 +9994,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
 	  {
 	    lmissvalinfo = 0;
-	    FSEC3_MissVal = GRIB_MISSVAL;
+	    FSEC3_MissVal = (T)GRIB_MISSVAL;
 	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
 	  }
 
@@ -10559,16 +10003,12 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
       if ( dfunc != 'J' || bitmapSize == ISEC4_NumNonMissValues )
 	{
-	  long i, j;
-	  GRIBPACK *pbitmap;
 	  GRIBPACK bitmap;
-	  GRIBPACK *imask;
-
 	  /*
 	  unsigned char *bitmap;
 	  bitmap = BMS_Bitmap;
-	  j = ISEC4_NumNonMissValues;
-	  for ( i = ISEC4_NumValues-1; i >= 0; i-- )
+	  int j = ISEC4_NumNonMissValues;
+	  for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
 	    {
 	      if ( (bitmap[i/8]>>(7-(i&7)))&1 )
 		fsec4[i] = fsec4[--j];
@@ -10577,13 +10017,13 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	    }
 	  */
 
-	  imask = (GRIBPACK*) Malloc(imaskSize*sizeof(GRIBPACK));
+	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
 
 #if defined (VECTORCODE)
 	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
-	  pbitmap = imask;
+	  GRIBPACK *pbitmap = imask;
 #else
-	  pbitmap = BMS_Bitmap;
+	  GRIBPACK *pbitmap = BMS_Bitmap;
 #endif
 
 #if defined (CRAY)
@@ -10595,7 +10035,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 #ifdef __uxpch__
 #pragma loop novrec
 #endif
-	  for ( i = imaskSize/8-1; i >= 0; i-- )
+	  for ( int i = imaskSize/8-1; i >= 0; i-- )
 	    {
 	      bitmap = pbitmap[i];
 	      imask[i*8+0] = 1 & (bitmap >> 7);
@@ -10608,8 +10048,8 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	      imask[i*8+7] = 1 & (bitmap);
 	    }
 
-	  j = 0;
-	  for ( i = 0; i < ISEC4_NumValues; i++ )
+	  int j = 0;
+	  for ( int i = 0; i < ISEC4_NumValues; i++ )
 	    if ( imask[i] ) j++;
 
 	  if ( ISEC4_NumNonMissValues != j )
@@ -10632,7 +10072,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 #ifdef __uxpch__
 #pragma loop novrec
 #endif
-	      for ( i = ISEC4_NumValues-1; i >= 0; i-- )
+	      for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
 		fsec4[i] = imask[i] ? fsec4[--j] : FSEC3_MissVal;
 	    }
 
@@ -10642,24 +10082,18 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   if ( ISEC2_Reduced )
     {
-      int nlon, nlat;
-      int lperio = 1, lveggy;
-      int ilat;
       int nvalues = 0;
-
-      nlat = ISEC2_NumLat;
-      nlon = ISEC2_RowLonPtr[0];
-      for ( ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
-      for ( ilat = 1; ilat < nlat; ++ilat )
+      int nlat = ISEC2_NumLat;
+      int nlon = ISEC2_RowLonPtr[0];
+      for ( int ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
+      for ( int ilat = 1; ilat < nlat; ++ilat )
 	if ( ISEC2_RowLon(ilat) > nlon ) nlon = ISEC2_RowLon(ilat);
 
       // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
       // if ( dlon < 0 ) dlon += 360000;
 	  
-      if ( nvalues != ISEC4_NumValues )
-	{
-	  *iret = -801;
-	}
+      if ( nvalues != ISEC4_NumValues ) *iret = -801;
+
       //printf("nlat %d  nlon %d \n", nlat, nlon);
       //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
 
@@ -10674,18 +10108,20 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	  ISEC4_NumValues = nlon*nlat;
 
 	  lsect3 = bitmapSize > 0;
-	  lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
-	          ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
-	           (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30));
+          int lperio = 1;
+	  int lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
+                      ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
+                       (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30) ||
+                       (ISEC1_Parameter == 39) || (ISEC1_Parameter == 40) ||
+                       (ISEC1_Parameter == 41) || (ISEC1_Parameter == 42) ||
+                       (ISEC1_Parameter == 43));
 	
 	  (void) TEMPLATE(qu2reg3,T)(fsec4, ISEC2_RowLonPtr, nlat, nlon, FSEC3_MissVal, iret, lsect3, lperio, lveggy);
 	      
 	  if ( bitmapSize > 0 )
 	    {
-	      long i;
-	      int j = 0;
-	      
-	      for ( i = 0; i < ISEC4_NumValues; i++ )
+	      int j = 0;	      
+	      for ( int i = 0; i < ISEC4_NumValues; i++ )
 		if ( IS_NOT_EQUAL(fsec4[i], FSEC3_MissVal) ) j++;
 		  
 	      ISEC4_NumNonMissValues = j;
@@ -10697,7 +10133,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
   esLen = 4;
 
-  gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
+  int gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
 
   if ( ISEC0_GRIB_Len )
     if ( ISEC0_GRIB_Len < gribLen )
@@ -10705,8 +10141,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   ISEC0_GRIB_Len = gribLen;
 
-  *kword = gribLen / sizeof(int);
-  if ( (size_t) gribLen != *kword * sizeof(int) ) *kword += 1;
+  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
 
   /*
     ----------------------------------------------------------------
@@ -10751,6 +10186,12 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 #ifdef T
 #undef T
 #endif
@@ -10764,7 +10205,6 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
   int  ReducedGrid = FALSE, VertCoorTab = FALSE;
   int  locnv = 0, locnl;
   int  jlenl;
-  long i;
   int iexp, imant;
   int ipvpl, ipl;
   int gdsLen = 0;
@@ -10816,7 +10256,7 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 	{
 	  *numGridVals = 0;
 	  ISEC2_Reduced = TRUE;
-	  for ( i = 0; i < jlenl; i++ )
+	  for ( int i = 0; i < jlenl; i++ )
 	    {
 	      ISEC2_RowLon(i) = GET_UINT2(gds[locnl+2*i], gds[locnl+2*i+1]);
 	      *numGridVals += ISEC2_RowLon(i);
@@ -10856,7 +10296,7 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 	{
 	  ISEC2_LatSP     = GDS_LatSP;
 	  ISEC2_LonSP     = GDS_LonSP;
-	  FSEC2_RotAngle  = GDS_RotAngle;
+	  FSEC2_RotAngle  = (T)GDS_RotAngle;
 	}
       /*
 	if ( Lons != Longitudes || Lats != Latitudes )
@@ -10966,31 +10406,34 @@ int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2,
 
       igrib = &gds[locnv];
       if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
-      for ( i = 0; i < ISEC2_NumVCP; i++ )
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
 	{
 	  iexp   = (lgrib[4*i  ]);
 	  imant  =((lgrib[4*i+1]) << 16) +
 	          ((lgrib[4*i+2]) <<  8) +
 	           (lgrib[4*i+3]);
-	  fsec2[10+i] = POW_2_M24 * imant * pow(16.0, (double)(iexp - 64));
+	  fsec2[10+i] = POW_2_M24 * imant * ldexp(1.0, 4 * (iexp - 64));
 	}
 
       Free(lgrib);
 #else
-      for ( i = 0; i < ISEC2_NumVCP; i++ )
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
 	{
 	  iexp   = (gds[locnv+4*i  ]);
 	  imant  =((gds[locnv+4*i+1]) << 16) +
 	          ((gds[locnv+4*i+2]) <<  8) +
 	           (gds[locnv+4*i+3]);
-	  fsec2[10+i] = decfp2(iexp,imant);
+	  fsec2[10+i] = (T)decfp2(iexp,imant);
 	}
 #endif
     }
 
-  return (gdsLen);
+  return gdsLen;
 }
 
+#define ldexp_double ldexp
+#define ldexp_float ldexpf
+
 static
 int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *isec4, 
 			  T *fsec4, int fsec4len, int dfunc, int bdsLenIn, int numGridVals, int llarge, int *iret)
@@ -11000,15 +10443,13 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
   int lcompress;
   int jup, kup, mup;
   int locnd;
-  long jlend;
-  long i;
   int bds_flag, jscale, imiss;
   int bds_ubits;
   int ioff = 0;
   int iexp, imant;
   int zoff;
   int bds_head = 11;
-  double zscale = 0.;
+  T zscale = 0.;
   T fmin = 0.;
   T *fpdata = fsec4;
   int bdsLen;
@@ -11079,16 +10520,11 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 
   /* convert reference value and scale factor. */
 
-  if ( ! (dfunc == 'J') )
-    if ( imiss == 0 )
-      {
-	fmin = BDS_RefValue;
-	
-	if ( jscale < 0 )
-	  zscale = 1.0/intpow2(-jscale);
-	else
-	  zscale = intpow2(jscale);
-      }
+  if ( ! (dfunc == 'J') && imiss == 0 )
+    {
+      fmin = BDS_RefValue;
+      zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
+    }
 
   /* get number of bits in each data value. */
 
@@ -11122,7 +10558,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  if ( dfunc != 'J' )
 	    {
 	      if ( imiss ) *fpdata++ = 0.0;
-	      else         *fpdata++ = BDS_RealCoef;
+	      else         *fpdata++ = (T)BDS_RealCoef;
 	    }
 	}
       else /* complex packed spherical harmonics */
@@ -11149,7 +10585,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  ioff   = (jup+1)*(jup+2);
 
 	  if ( dfunc != 'J' )
-	    for ( i = 0; i < ioff; i++ )
+	    for ( int i = 0; i < ioff; i++ )
 	      {
 		if ( imiss )
 		  *fpdata++ = 0.0;
@@ -11160,7 +10596,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 		            ((bds[locnd+4*i+2]) <<  8) +
 		             (bds[locnd+4*i+3]);
 
-		    *fpdata++ = decfp2(iexp,imant);
+		    *fpdata++ = (T)decfp2(iexp,imant);
 		  }
 	      }
 	  
@@ -11174,7 +10610,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 1999;
 	  gprintf(__func__, " Second order packed grids unsupported!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
     }
 
@@ -11183,7 +10619,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
   /* Take into account that spherical harmonics can be packed  */
   /* simple (lcomplex = 0) or complex (lcomplex = 1)           */
 
-  jlend = bdsLen - locnd;
+  int jlend = bdsLen - locnd;
 
   if ( ISEC4_NumBits == 0 )
     {
@@ -11192,7 +10628,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 2001;
 	  gprintf(__func__, " Number of bits per data value = 0!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
 
       if ( numGridVals == 0 )
@@ -11200,7 +10636,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	  *iret = 2002;
 	  gprintf(__func__, " Constant field unsupported for this grid type!");
 	  gprintf(__func__, " Return code =  %d", *iret);
-	  return (0);
+	  return 0;
 	}
 
       jlend = numGridVals;
@@ -11223,7 +10659,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
       else
         len = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
 
-      ISEC4_NumValues = len*8/ISEC4_NumBits;
+      ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
 
       if ( lspherc )
 	{
@@ -11234,7 +10670,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	}
     }
 
-  if ( dfunc == 'J' ) return (bdsLen);
+  if ( dfunc == 'J' ) return bdsLen;
 
   /* check length of output array. */
   
@@ -11244,10 +10680,10 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
       gprintf(__func__, " Output array too small. Length = %d", fsec4len);
       gprintf(__func__, " Number of values = %d", ISEC4_NumValues);
       gprintf(__func__, " Return code =  %d", *iret);
-      return (0);
+      return 0;
     }
 
-  if ( imiss ) memset((char *)fpdata, 0, jlend*sizeof(T));
+  if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
   else
     {
       igrib += locnd;
@@ -11257,9 +10693,7 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 
   if ( lspherc && lcomplex )
     {
-      int pcStart, pcScale;
-      pcStart = isec4[19];
-      pcScale = isec4[16];
+      int pcStart = isec4[19], pcScale = isec4[16];
       TEMPLATE(scatter_complex,T)(fsec4, pcStart, ISEC2_PentaJ, ISEC4_NumValues);
       TEMPLATE(scale_complex,T)(fsec4, pcStart, pcScale, ISEC2_PentaJ, 1);
     }
@@ -11271,17 +10705,17 @@ int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *ise
 	if ( IS_NOT_EQUAL(fsec4[1], 0.0) )
 	  {
 	    T zserr = fsec4[1];
-	    for ( i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
+	    for ( int i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
 	  }
       }
 
   if ( decscale )
     {
       T scale = (T) pow(10.0, (double)-decscale);
-      for ( i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
+      for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
     }
 
-  return (bdsLen);
+  return bdsLen;
 }
 
 
@@ -11291,7 +10725,6 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 {
   UCHAR *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
   int isLen = 0, pdsLen = 0, gdsLen = 0, bmsLen = 0, bdsLen = 0, esLen = 0;
-  int gribLen = 0;
   int gdsIncluded = FALSE;
   int bmsIncluded = FALSE;
   int bitmapSize = 0;
@@ -11482,7 +10915,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
 	  {
 	    lmissvalinfo = 0;
-	    FSEC3_MissVal = GRIB_MISSVAL;
+	    FSEC3_MissVal = (T)GRIB_MISSVAL;
 	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
 	  }
 
@@ -11491,16 +10924,12 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
       if ( dfunc != 'J' || bitmapSize == ISEC4_NumNonMissValues )
 	{
-	  long i, j;
-	  GRIBPACK *pbitmap;
 	  GRIBPACK bitmap;
-	  GRIBPACK *imask;
-
 	  /*
 	  unsigned char *bitmap;
 	  bitmap = BMS_Bitmap;
-	  j = ISEC4_NumNonMissValues;
-	  for ( i = ISEC4_NumValues-1; i >= 0; i-- )
+	  int j = ISEC4_NumNonMissValues;
+	  for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
 	    {
 	      if ( (bitmap[i/8]>>(7-(i&7)))&1 )
 		fsec4[i] = fsec4[--j];
@@ -11509,13 +10938,13 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	    }
 	  */
 
-	  imask = (GRIBPACK*) Malloc(imaskSize*sizeof(GRIBPACK));
+	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
 
 #if defined (VECTORCODE)
 	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
-	  pbitmap = imask;
+	  GRIBPACK *pbitmap = imask;
 #else
-	  pbitmap = BMS_Bitmap;
+	  GRIBPACK *pbitmap = BMS_Bitmap;
 #endif
 
 #if defined (CRAY)
@@ -11527,7 +10956,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 #ifdef __uxpch__
 #pragma loop novrec
 #endif
-	  for ( i = imaskSize/8-1; i >= 0; i-- )
+	  for ( int i = imaskSize/8-1; i >= 0; i-- )
 	    {
 	      bitmap = pbitmap[i];
 	      imask[i*8+0] = 1 & (bitmap >> 7);
@@ -11540,8 +10969,8 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	      imask[i*8+7] = 1 & (bitmap);
 	    }
 
-	  j = 0;
-	  for ( i = 0; i < ISEC4_NumValues; i++ )
+	  int j = 0;
+	  for ( int i = 0; i < ISEC4_NumValues; i++ )
 	    if ( imask[i] ) j++;
 
 	  if ( ISEC4_NumNonMissValues != j )
@@ -11564,7 +10993,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 #ifdef __uxpch__
 #pragma loop novrec
 #endif
-	      for ( i = ISEC4_NumValues-1; i >= 0; i-- )
+	      for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
 		fsec4[i] = imask[i] ? fsec4[--j] : FSEC3_MissVal;
 	    }
 
@@ -11574,24 +11003,18 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   if ( ISEC2_Reduced )
     {
-      int nlon, nlat;
-      int lperio = 1, lveggy;
-      int ilat;
       int nvalues = 0;
-
-      nlat = ISEC2_NumLat;
-      nlon = ISEC2_RowLonPtr[0];
-      for ( ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
-      for ( ilat = 1; ilat < nlat; ++ilat )
+      int nlat = ISEC2_NumLat;
+      int nlon = ISEC2_RowLonPtr[0];
+      for ( int ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
+      for ( int ilat = 1; ilat < nlat; ++ilat )
 	if ( ISEC2_RowLon(ilat) > nlon ) nlon = ISEC2_RowLon(ilat);
 
       // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
       // if ( dlon < 0 ) dlon += 360000;
 	  
-      if ( nvalues != ISEC4_NumValues )
-	{
-	  *iret = -801;
-	}
+      if ( nvalues != ISEC4_NumValues ) *iret = -801;
+
       //printf("nlat %d  nlon %d \n", nlat, nlon);
       //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
 
@@ -11606,18 +11029,20 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 	  ISEC4_NumValues = nlon*nlat;
 
 	  lsect3 = bitmapSize > 0;
-	  lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
-	          ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
-	           (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30));
+          int lperio = 1;
+	  int lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
+                      ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
+                       (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30) ||
+                       (ISEC1_Parameter == 39) || (ISEC1_Parameter == 40) ||
+                       (ISEC1_Parameter == 41) || (ISEC1_Parameter == 42) ||
+                       (ISEC1_Parameter == 43));
 	
 	  (void) TEMPLATE(qu2reg3,T)(fsec4, ISEC2_RowLonPtr, nlat, nlon, FSEC3_MissVal, iret, lsect3, lperio, lveggy);
 	      
 	  if ( bitmapSize > 0 )
 	    {
-	      long i;
-	      int j = 0;
-	      
-	      for ( i = 0; i < ISEC4_NumValues; i++ )
+	      int j = 0;	      
+	      for ( int i = 0; i < ISEC4_NumValues; i++ )
 		if ( IS_NOT_EQUAL(fsec4[i], FSEC3_MissVal) ) j++;
 		  
 	      ISEC4_NumNonMissValues = j;
@@ -11629,7 +11054,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
   esLen = 4;
 
-  gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
+  int gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
 
   if ( ISEC0_GRIB_Len )
     if ( ISEC0_GRIB_Len < gribLen )
@@ -11637,8 +11062,7 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   ISEC0_GRIB_Len = gribLen;
 
-  *kword = gribLen / sizeof(int);
-  if ( (size_t) gribLen != *kword * sizeof(int) ) *kword += 1;
+  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
 
   /*
     ----------------------------------------------------------------
@@ -11683,6 +11107,12 @@ void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 /* GRIB block 0 - indicator block */
 static
 void encodeIS(GRIBPACK *lGrib, long *gribLen)
@@ -11745,20 +11175,20 @@ void encodeES(GRIBPACK *lGrib, long *gribLen, long bdsstart)
       itemp = z / (-120);
       itemp = JP23SET - itemp + 1;
 
-      lGrib[4] = itemp >> 16;
-      lGrib[5] = itemp >>  8;
-      lGrib[6] = itemp;
+      lGrib[4] = (GRIBPACK)(itemp >> 16);
+      lGrib[5] = (GRIBPACK)(itemp >>  8);
+      lGrib[6] = (GRIBPACK)itemp;
 
       bdslen = z - bdslen;
-      lGrib[bdsstart  ] = bdslen >> 16;
-      lGrib[bdsstart+1] = bdslen >>  8;
-      lGrib[bdsstart+2] = bdslen;
+      lGrib[bdsstart  ] = (GRIBPACK)(bdslen >> 16);
+      lGrib[bdsstart+1] = (GRIBPACK)(bdslen >>  8);
+      lGrib[bdsstart+2] = (GRIBPACK)bdslen;
     }
   else
     {
-      lGrib[4] = z >> 16;
-      lGrib[5] = z >>  8;
-      lGrib[6] = z;
+      lGrib[4] = (GRIBPACK)(z >> 16);
+      lGrib[5] = (GRIBPACK)(z >>  8);
+      lGrib[6] = (GRIBPACK)z;
 
       while ( z%8 ) lGrib[z++] = 0;
     }
@@ -12030,6 +11460,7 @@ int  BitsPerInt = (int) (sizeof(int) * 8);
 #define T double
 #ifdef T
 
+
 static
 void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datasize, GRIBPACK *lGrib,
 				     const T *data, T zref, T factor, size_t *gz)
@@ -12047,7 +11478,7 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
   for ( i = packStart; i < datasize; i++ )
     {
       /* note float -> unsigned int .. truncate */
-      ival = (unsigned int) ((data[i] - zref) * factor + 0.5);
+      ival = (unsigned int) ((data[i] - zref) * factor + (T)0.5);
       /*
 	if ( ival > max_nbpv_pow2 ) ival = max_nbpv_pow2;
 	if ( ival < 0 ) ival = 0;
@@ -12063,7 +11494,7 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
 	  else
 	    {
 	      jbits -= cbits;
-	      lGrib[z++] = (c << cbits) + ((ival >> jbits) & mask[cbits]);
+	      lGrib[z++] = (GRIBPACK)((c << cbits) + ((ival >> jbits) & mask[cbits]));
 	      cbits = 8;
 	      c = 0;
 	    }
@@ -12075,11 +11506,39 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
 	  cbits -= jbits;
 	}
     }
-  if ( cbits != 8 ) lGrib[z++] = c << cbits;
+  if ( cbits != 8 ) lGrib[z++] = (GRIBPACK)(c << cbits);
 
   *gz = z;
 }
 
+
+static
+void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
+				    const T *restrict data, T zref, T factor, size_t *gz)
+{
+  U_BYTEORDER;
+  uint16_t *restrict sgrib = (uint16_t *) (lGrib+*gz);
+
+  if ( IS_BIGENDIAN() )
+    {
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          sgrib[i] = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+        }
+    }
+  else
+    {
+      uint16_t ui16;
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          ui16 = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+          sgrib[i] = gribSwapByteOrder_uint16(ui16);
+        }
+    }
+
+  *gz += 2*datasize;
+}
+/*
 static
 void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 				    const T *restrict data, T zref, T factor, size_t *gz)
@@ -12099,7 +11558,7 @@ void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 #endif
   for ( i = 0; i < datasize; i++ )
     {
-      tmp = ((data[i] - zref) * factor + 0.5);
+      tmp = ((data[i] - zref) * factor + (T)0.5);
       ui16 = (uint16_t) tmp;
       lGrib[z  ] = ui16 >>  8;
       lGrib[z+1] = ui16;
@@ -12108,7 +11567,7 @@ void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 
   *gz = z;
 }
-
+*/
 static
 void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize, 
 			      GRIBPACK *restrict lGrib,
@@ -12118,7 +11577,6 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER 
   uint64_t start_minmax, end_minmax;
 #endif
-
   uint32_t ui32;
   size_t i, z = *gz;
   T tmp;
@@ -12143,8 +11601,8 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
-	  lGrib[z  ] = (uint16_t) tmp;
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
+	  lGrib[z  ] = (GRIBPACK)tmp;
           z++;
 	}
 
@@ -12161,10 +11619,9 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #elif defined _GET_MACH_COUNTER 
       start_minmax = mach_absolute_time();
 #endif
-
       if ( sizeof(T) == sizeof(double) )
       	{
-          grib_encode_array_2byte_double(datasize, lGrib, (const double * restrict) data, zref, factor, &z);
+          grib_encode_array_2byte_double(datasize, lGrib, (const double *) data, zref, factor, &z);
         }
       else
         {
@@ -12207,11 +11664,11 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
           ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  ui32 >> 16;
-          lGrib[z+1] =  ui32 >>  8;
-          lGrib[z+2] =  ui32;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+2] =  (GRIBPACK)ui32;
           z += 3;
 	}
 
@@ -12236,12 +11693,12 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
           ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  ui32 >> 24;
-          lGrib[z+1] =  ui32 >> 16;
-          lGrib[z+2] =  ui32 >>  8;
-          lGrib[z+3] =  ui32;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 24);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+2] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+3] =  (GRIBPACK)ui32;
           z += 4;
 	}
 
@@ -12275,12 +11732,11 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _ARCH_PWR6
 #define __UNROLL_DEPTH_2 8
 #else
-#define __UNROLL_DEPTH_2 8
+#define __UNROLL_DEPTH_2 128
 #endif
   size_t residual;
   size_t ofs;
   T dval[__UNROLL_DEPTH_2];
-  unsigned long ival;
 
   data += packStart;
   datasize -= packStart;
@@ -12291,29 +11747,37 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 
   if      ( numBits ==  8 )
     {
-      unsigned char *cgrib = (unsigned char *) (lGrib + z);
 #ifdef _GET_IBM_COUNTER 
       hpmStart(2, "pack 8 bit unrolled");
 #endif
+      unsigned char *cgrib = (unsigned char *) (lGrib + z);
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *cgrib++ =  (unsigned long) dval[j];
+#else
+	      *cgrib++ =  (unsigned char) dval[j];
+#endif
 	    }
 	  z += __UNROLL_DEPTH_2;
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       for (j = 0; j < residual; j++) 
 	{
+#ifdef _ARCH_PWR6
 	  *cgrib++ = (unsigned long) dval[j];
+#else
+	  *cgrib++ = (unsigned char) dval[j];
+#endif
 	}
       z += residual;
 
@@ -12323,21 +11787,31 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
     }
   else if ( numBits == 16 )
     {
-      unsigned short *sgrib = (unsigned short *) (lGrib + z);
 #ifdef _GET_IBM_COUNTER 
       hpmStart(3, "pack 16 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint16_t ival;
+#endif
+      uint16_t *sgrib = (uint16_t *) (lGrib+z);
+
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  if ( IS_BIGENDIAN() )
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
+#ifdef _ARCH_PWR6
 		  *sgrib++ = (unsigned long) dval[j];
+#else
+		  *sgrib++ = (uint16_t) dval[j];
+#endif
 		}
 	      z += 2*__UNROLL_DEPTH_2;
 	    }
@@ -12345,22 +11819,25 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
-		  ival = (unsigned long) dval[j];
-		  lGrib[z  ] = ival >>  8;
-		  lGrib[z+1] = ival;
-		  z += 2;
+		  ival = (uint16_t) dval[j];
+                  *sgrib++ = gribSwapByteOrder_uint16(ival);
 		}
+	      z += 2*__UNROLL_DEPTH_2;
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       if ( IS_BIGENDIAN() )
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *sgrib++ = (unsigned long) dval[j];
+#else
+              *sgrib++ = (uint16_t) dval[j];
+#endif
 	    }
 	  z += 2*residual;
 	}
@@ -12368,9 +11845,9 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
-	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] = ival >>  8;
-	      lGrib[z+1] = ival;
+              ival = (uint16_t) dval[j];
+	      lGrib[z  ] = (GRIBPACK)(ival >>  8);
+	      lGrib[z+1] = (GRIBPACK)ival;
 	      z += 2;
 	    }
 	}
@@ -12383,31 +11860,40 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _GET_IBM_COUNTER 
       hpmStart(4, "pack 24 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] =  ival >> 16;
-	      lGrib[z+1] =  ival >>  8;
-	      lGrib[z+2] =  ival;
+#else
+	      ival = (uint32_t) dval[j];
+#endif
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+2] =  (GRIBPACK)ival;
 	      z += 3;
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  ival = (unsigned long) dval[j];
-	  lGrib[z  ] =  ival >> 16;
-	  lGrib[z+1] =  ival >>  8;
-	  lGrib[z+2] =  ival;
+	  ival = (uint32_t) dval[j];
+	  lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	  lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	  lGrib[z+2] =  (GRIBPACK)ival;
 	  z += 3;
 	}
 #ifdef _GET_IBM_COUNTER 
@@ -12419,18 +11905,27 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _GET_IBM_COUNTER 
       hpmStart(5, "pack 32 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
       unsigned int *igrib = (unsigned int *) (lGrib + z);
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
-	{
+ {
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  if ( IS_BIGENDIAN() )
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
+#ifdef _ARCH_PWR6
 		  *igrib = (unsigned long) dval[j];
+#else
+		  *igrib = (uint32_t) dval[j];
+#endif
 		  igrib++;
 		  z += 4;
 		}
@@ -12439,37 +11934,41 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
-		  ival = (unsigned long) dval[j];
-		  lGrib[z  ] =  ival >> 24;
-		  lGrib[z+1] =  ival >> 16;
-		  lGrib[z+2] =  ival >>  8;
-		  lGrib[z+3] =  ival;
+                  ival = (uint32_t) dval[j];
+		  lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+		  lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+		  lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+		  lGrib[z+3] =  (GRIBPACK)ival;
 		  z += 4;
 		}
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       if ( IS_BIGENDIAN() )
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *igrib = (unsigned long) dval[j];
+#else
+	      *igrib = (uint32_t) dval[j];
+#endif
 	      igrib++;
 	      z += 4;
 	    }
 	}
       else
 	{
-	  for (j = 0; j < residual; j++) 
+          for (j = 0; j < residual; j++) 
 	    {
-	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] =  ival >> 24;
-	      lGrib[z+1] =  ival >> 16;
-	      lGrib[z+2] =  ival >>  8;
-	      lGrib[z+3] =  ival;
+	      ival = (uint32_t) dval[j];
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+	      lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+3] =  (GRIBPACK)ival;
 	      z += 4;
 	    }
 	}
@@ -12495,12 +11994,19 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 #ifdef T
 #undef T
 #endif
 #define T float
 #ifdef T
 
+
 static
 void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datasize, GRIBPACK *lGrib,
 				     const T *data, T zref, T factor, size_t *gz)
@@ -12518,7 +12024,7 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
   for ( i = packStart; i < datasize; i++ )
     {
       /* note float -> unsigned int .. truncate */
-      ival = (unsigned int) ((data[i] - zref) * factor + 0.5);
+      ival = (unsigned int) ((data[i] - zref) * factor + (T)0.5);
       /*
 	if ( ival > max_nbpv_pow2 ) ival = max_nbpv_pow2;
 	if ( ival < 0 ) ival = 0;
@@ -12534,7 +12040,7 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
 	  else
 	    {
 	      jbits -= cbits;
-	      lGrib[z++] = (c << cbits) + ((ival >> jbits) & mask[cbits]);
+	      lGrib[z++] = (GRIBPACK)((c << cbits) + ((ival >> jbits) & mask[cbits]));
 	      cbits = 8;
 	      c = 0;
 	    }
@@ -12546,11 +12052,39 @@ void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datas
 	  cbits -= jbits;
 	}
     }
-  if ( cbits != 8 ) lGrib[z++] = c << cbits;
+  if ( cbits != 8 ) lGrib[z++] = (GRIBPACK)(c << cbits);
 
   *gz = z;
 }
 
+
+static
+void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
+				    const T *restrict data, T zref, T factor, size_t *gz)
+{
+  U_BYTEORDER;
+  uint16_t *restrict sgrib = (uint16_t *) (lGrib+*gz);
+
+  if ( IS_BIGENDIAN() )
+    {
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          sgrib[i] = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+        }
+    }
+  else
+    {
+      uint16_t ui16;
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          ui16 = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+          sgrib[i] = gribSwapByteOrder_uint16(ui16);
+        }
+    }
+
+  *gz += 2*datasize;
+}
+/*
 static
 void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 				    const T *restrict data, T zref, T factor, size_t *gz)
@@ -12570,7 +12104,7 @@ void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 #endif
   for ( i = 0; i < datasize; i++ )
     {
-      tmp = ((data[i] - zref) * factor + 0.5);
+      tmp = ((data[i] - zref) * factor + (T)0.5);
       ui16 = (uint16_t) tmp;
       lGrib[z  ] = ui16 >>  8;
       lGrib[z+1] = ui16;
@@ -12579,7 +12113,7 @@ void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
 
   *gz = z;
 }
-
+*/
 static
 void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize, 
 			      GRIBPACK *restrict lGrib,
@@ -12589,7 +12123,6 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER 
   uint64_t start_minmax, end_minmax;
 #endif
-
   uint32_t ui32;
   size_t i, z = *gz;
   T tmp;
@@ -12614,8 +12147,8 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
-	  lGrib[z  ] = (uint16_t) tmp;
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
+	  lGrib[z  ] = (GRIBPACK)tmp;
           z++;
 	}
 
@@ -12632,10 +12165,9 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #elif defined _GET_MACH_COUNTER 
       start_minmax = mach_absolute_time();
 #endif
-
       if ( sizeof(T) == sizeof(double) )
       	{
-          grib_encode_array_2byte_double(datasize, lGrib, (const double * restrict) data, zref, factor, &z);
+          grib_encode_array_2byte_double(datasize, lGrib, (const double *) data, zref, factor, &z);
         }
       else
         {
@@ -12678,11 +12210,11 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
           ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  ui32 >> 16;
-          lGrib[z+1] =  ui32 >>  8;
-          lGrib[z+2] =  ui32;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+2] =  (GRIBPACK)ui32;
           z += 3;
 	}
 
@@ -12707,12 +12239,12 @@ void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
 #endif
       for ( i = 0; i < datasize; i++ )
 	{
-	  tmp = ((data[i] - zref) * factor + 0.5);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
           ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  ui32 >> 24;
-          lGrib[z+1] =  ui32 >> 16;
-          lGrib[z+2] =  ui32 >>  8;
-          lGrib[z+3] =  ui32;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 24);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+2] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+3] =  (GRIBPACK)ui32;
           z += 4;
 	}
 
@@ -12746,12 +12278,11 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _ARCH_PWR6
 #define __UNROLL_DEPTH_2 8
 #else
-#define __UNROLL_DEPTH_2 8
+#define __UNROLL_DEPTH_2 128
 #endif
   size_t residual;
   size_t ofs;
   T dval[__UNROLL_DEPTH_2];
-  unsigned long ival;
 
   data += packStart;
   datasize -= packStart;
@@ -12762,29 +12293,37 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 
   if      ( numBits ==  8 )
     {
-      unsigned char *cgrib = (unsigned char *) (lGrib + z);
 #ifdef _GET_IBM_COUNTER 
       hpmStart(2, "pack 8 bit unrolled");
 #endif
+      unsigned char *cgrib = (unsigned char *) (lGrib + z);
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *cgrib++ =  (unsigned long) dval[j];
+#else
+	      *cgrib++ =  (unsigned char) dval[j];
+#endif
 	    }
 	  z += __UNROLL_DEPTH_2;
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       for (j = 0; j < residual; j++) 
 	{
+#ifdef _ARCH_PWR6
 	  *cgrib++ = (unsigned long) dval[j];
+#else
+	  *cgrib++ = (unsigned char) dval[j];
+#endif
 	}
       z += residual;
 
@@ -12794,21 +12333,31 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
     }
   else if ( numBits == 16 )
     {
-      unsigned short *sgrib = (unsigned short *) (lGrib + z);
 #ifdef _GET_IBM_COUNTER 
       hpmStart(3, "pack 16 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint16_t ival;
+#endif
+      uint16_t *sgrib = (uint16_t *) (lGrib+z);
+
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  if ( IS_BIGENDIAN() )
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
+#ifdef _ARCH_PWR6
 		  *sgrib++ = (unsigned long) dval[j];
+#else
+		  *sgrib++ = (uint16_t) dval[j];
+#endif
 		}
 	      z += 2*__UNROLL_DEPTH_2;
 	    }
@@ -12816,22 +12365,25 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
-		  ival = (unsigned long) dval[j];
-		  lGrib[z  ] = ival >>  8;
-		  lGrib[z+1] = ival;
-		  z += 2;
+		  ival = (uint16_t) dval[j];
+                  *sgrib++ = gribSwapByteOrder_uint16(ival);
 		}
+	      z += 2*__UNROLL_DEPTH_2;
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       if ( IS_BIGENDIAN() )
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *sgrib++ = (unsigned long) dval[j];
+#else
+              *sgrib++ = (uint16_t) dval[j];
+#endif
 	    }
 	  z += 2*residual;
 	}
@@ -12839,9 +12391,9 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
-	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] = ival >>  8;
-	      lGrib[z+1] = ival;
+              ival = (uint16_t) dval[j];
+	      lGrib[z  ] = (GRIBPACK)(ival >>  8);
+	      lGrib[z+1] = (GRIBPACK)ival;
 	      z += 2;
 	    }
 	}
@@ -12854,31 +12406,40 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _GET_IBM_COUNTER 
       hpmStart(4, "pack 24 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
 	{
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] =  ival >> 16;
-	      lGrib[z+1] =  ival >>  8;
-	      lGrib[z+2] =  ival;
+#else
+	      ival = (uint32_t) dval[j];
+#endif
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+2] =  (GRIBPACK)ival;
 	      z += 3;
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  ival = (unsigned long) dval[j];
-	  lGrib[z  ] =  ival >> 16;
-	  lGrib[z+1] =  ival >>  8;
-	  lGrib[z+2] =  ival;
+	  ival = (uint32_t) dval[j];
+	  lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	  lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	  lGrib[z+2] =  (GRIBPACK)ival;
 	  z += 3;
 	}
 #ifdef _GET_IBM_COUNTER 
@@ -12890,18 +12451,27 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #ifdef _GET_IBM_COUNTER 
       hpmStart(5, "pack 32 bit unrolled");
 #endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
       unsigned int *igrib = (unsigned int *) (lGrib + z);
       for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
-	{
+ {
 	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + 0.5);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
 	    }
 	  if ( IS_BIGENDIAN() )
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
+#ifdef _ARCH_PWR6
 		  *igrib = (unsigned long) dval[j];
+#else
+		  *igrib = (uint32_t) dval[j];
+#endif
 		  igrib++;
 		  z += 4;
 		}
@@ -12910,37 +12480,41 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 	    {
 	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
 		{
-		  ival = (unsigned long) dval[j];
-		  lGrib[z  ] =  ival >> 24;
-		  lGrib[z+1] =  ival >> 16;
-		  lGrib[z+2] =  ival >>  8;
-		  lGrib[z+3] =  ival;
+                  ival = (uint32_t) dval[j];
+		  lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+		  lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+		  lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+		  lGrib[z+3] =  (GRIBPACK)ival;
 		  z += 4;
 		}
 	    }
 	}
       for (j = 0; j < residual; j++) 
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + 0.5);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
       if ( IS_BIGENDIAN() )
 	{
 	  for (j = 0; j < residual; j++) 
 	    {
+#ifdef _ARCH_PWR6
 	      *igrib = (unsigned long) dval[j];
+#else
+	      *igrib = (uint32_t) dval[j];
+#endif
 	      igrib++;
 	      z += 4;
 	    }
 	}
       else
 	{
-	  for (j = 0; j < residual; j++) 
+          for (j = 0; j < residual; j++) 
 	    {
-	      ival = (unsigned long) dval[j];
-	      lGrib[z  ] =  ival >> 24;
-	      lGrib[z+1] =  ival >> 16;
-	      lGrib[z+2] =  ival >>  8;
-	      lGrib[z+3] =  ival;
+	      ival = (uint32_t) dval[j];
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+	      lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+3] =  (GRIBPACK)ival;
 	      z += 4;
 	    }
 	}
@@ -12966,6 +12540,12 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 
 #ifdef T
 #undef T
@@ -13066,8 +12646,8 @@ void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
 	}
       else
 	{
-	  lonIncr = ISEC2_LonIncr;
-	  latIncr = ISEC2_LatIncr;
+	  lonIncr = (unsigned)ISEC2_LonIncr;
+	  latIncr = (unsigned)ISEC2_LatIncr;
 	}
       Put2Byte(lonIncr);               /* 23-24 i - direction increment  */
       if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN )
@@ -13180,7 +12760,7 @@ void TEMPLATE(encodeBMS,T)(GRIBPACK *lGrib, long *gribLen, T *fsec3, int *isec4,
       if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
 	{
 	  data[fsec4size++] = data[i];
-	  bitmap[i/8] |= 1<<(7-(i&7));
+	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
 	}
     }
 #endif
@@ -13206,36 +12786,33 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
   /* Uwe Schulzweida, 11/04/2003 : Check that number of bits per value is not exceeded */
   /* Uwe Schulzweida,  6/05/2003 : Copy result to fpval to prevent integer overflow */
 
-  size_t z = *gribLen;
-  long i, jloop;
+  size_t z = (size_t)*gribLen;
+  long i;
   int numBits;
   int ival;
-  int blockLength, PackStart = 0, Flag = 0;
+  long PackStart = 0, Flag = 0;
   int binscale = 0;
   int nbpv;
   int bds_head = 11;
   int bds_ext = 0;
   /* ibits = BitsPerInt; */
-  unsigned int max_nbpv_pow2;
   int exponent, mantissa;
-  int unused_bits = 0;
   int lspherc = FALSE, lcomplex = FALSE;
   int isubset = 0, itemp = 0, itrunc = 0;
   T factor = 1, fmin, fmax;
   double zref;
-  double range, rangec;
+  double range;
   double jpepsln = 1.0e-12;     /* -----> tolerance used to check equality     */
                                 /*        of floating point numbers - needed   */
 		                /*        on some platforms (eg vpp700, linux) */
-  extern const double _pow2tab[158];
   extern int CGRIBEX_Const;         /* 1: Don't pack constant fields on regular grids */
 
   if ( isec2 )
     {
       /* If section 2 is present, it says if data is spherical harmonic */
 
-      if ( isec2[0] == 50 || isec2[0] == 60 || 
-	   isec2[0] == 70 || isec2[0] == 80 ) lspherc = TRUE;
+      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
+                   isec2[0] == 70 || isec2[0] == 80 );
 
       if ( lspherc )
 	isec4[2] = 128;
@@ -13318,7 +12895,7 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
       pcStart = isubset;
       pcScale = isec4[16];
       TEMPLATE(scale_complex,T)(data, pcStart, pcScale, itrunc, 0);
-      TEMPLATE(gather_complex,T)(data, pcStart, itrunc, datasize);
+      TEMPLATE(gather_complex,T)(data, (size_t)pcStart, (size_t)itrunc, (size_t)datasize);
     }
 
   fmin = fmax = data[PackStart];
@@ -13334,10 +12911,10 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
     }
 
 
-  blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
-  if ( (blockLength%2) == 1 ) blockLength++;
+  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
+  blockLength += blockLength & 1;
 
-  unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
+  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
 
   Flag += unused_bits;
 
@@ -13375,57 +12952,54 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
     }
   else if ( range > 1.0 )
     {
-      rangec = range + jpepsln;
-      for ( jloop = 1; jloop < 128; jloop++ )
-	{
-	  if ( _pow2tab[jloop] > rangec ) break;
-	}
-      if ( jloop == 128 )
-	{
-	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-	  gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-	  return (707);
-	}
+      double rangec = range + jpepsln,
+        p2 = 2.0;
+      long jloop = 1;
+      while ( jloop < 128 && p2 <= rangec )
+        {
+          p2 *= 2.0;
+          ++jloop;
+        }
+      if (jloop < 128)
+        binscale = jloop - nbpv;
       else
-	{
-	  binscale = jloop - nbpv;
-	}
+        {
+          gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+          gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+          return (707);
+        }
     }
   else
     {
-      rangec = range - jpepsln;
-      for ( jloop = 1; jloop < 127; jloop++ )
+      double rangec = range - jpepsln, p05 = 0.5;
+      long jloop = 1;
+      while ( jloop < 127 && p05 >= rangec )
 	{
-	  if ( 1.0/_pow2tab[jloop] < rangec ) break;
+          p05 *= 0.5;
+          jloop++;
 	}
-      if ( jloop == 127 )
+      if ( jloop < 127 )
 	{
-	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-	  return (707);
+	  binscale = 1 - jloop - nbpv;
 	}
       else
 	{
-	  binscale = 1 - jloop - nbpv;
+	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+	  return (707);
 	}
     }
 
-  //max_nbpv_pow2 = (unsigned) (intpow2(nbpv) - 1);
-  max_nbpv_pow2 = (unsigned) ((1ULL << nbpv) - 1);
+  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
 
   if ( binscale != 0 )
     {
       if ( binscale < 0 )
-	{
-	  if ( (unsigned)(range*intpow2(-binscale)+0.5) > max_nbpv_pow2 ) binscale++;
-	}
+        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
       else
-	{
-	  if ( (unsigned)(range/intpow2(binscale)+0.5) > max_nbpv_pow2 ) binscale--;
-	}
+        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale--;
 
-      if ( binscale < 0 ) factor =     intpow2(-binscale);
-      else                factor = 1.0/intpow2( binscale);
+      factor = intpow2(-binscale);
     }
 
   ref2ibm(&zref, BitsPerInt);
@@ -13442,7 +13016,7 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
       if ( lcomplex )
 	{
 	  int jup = isubset;
-	  int ioff = z + bds_ext;
+	  int ioff = (int)z + bds_ext;
 	  if ( ioff > 0xFFFF ) ioff = 0;
 	  Put2Byte(ioff);
 	  Put2Int(isec4[16]);
@@ -13460,14 +13034,14 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
   *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
 
 #if  defined  (_ARCH_PWR6)
-  TEMPLATE(encode_array_unrolled,T)(nbpv, PackStart, datasize, lGrib, data, (T)zref, factor, &z);
+  TEMPLATE(encode_array_unrolled,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
 #else
-  TEMPLATE(encode_array,T)(nbpv, PackStart, datasize, lGrib, data, (T)zref, factor, &z);
+  TEMPLATE(encode_array,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
 #endif
 
   if ( unused_bits >= 8 ) Put1Byte(0);  /*  Fillbyte                     */
 
-  *gribLen = z;
+  *gribLen = (long)z;
 
   return (0);
 }
@@ -13482,9 +13056,7 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   GRIBPACK *lpds;
   unsigned char *CGrib;
   long fsec4size = 0;
-  int numBytes;
   int bmsIncluded;
-  size_t len;
   GRIBPACK *lGrib;
   long datstart, datsize, bdsstart;
   int status = 0;
@@ -13499,15 +13071,15 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   bmsIncluded = ISEC1_Sec2Or3Flag & 64;
 
   /* set max header len */
-  len = 16384;
+  size_t len = 16384;
 
   /* add data len */
-  numBytes = (ISEC4_NumBits+7)>>3;
+  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
 
-  len += numBytes*klenp;
+  len += numBytes*(size_t)klenp;
 
   /* add bitmap len */
-  if ( bmsIncluded ) len += (klenp+7)>>3;
+  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
 
 #if defined (VECTORCODE)
   lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
@@ -13563,7 +13135,7 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   encodeES(lGrib, &gribLen, bdsstart);
 
-  if ( (size_t) gribLen > kleng*sizeof(int) )
+  if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
     Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
 
 #if defined (VECTORCODE)
@@ -13575,17 +13147,22 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   Free(lGrib);
 #endif
 
-  ISEC0_GRIB_Len     = gribLen;
+  ISEC0_GRIB_Len     = (int)gribLen;
   ISEC0_GRIB_Version = 1;
 
-  *kword = gribLen / sizeof(int);
-  if ( (size_t) gribLen != *kword * sizeof(int) ) *kword += 1;
+  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
 
   *kret = status;
 }
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 #ifdef T
 #undef T
 #endif
@@ -13685,8 +13262,8 @@ void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
 	}
       else
 	{
-	  lonIncr = ISEC2_LonIncr;
-	  latIncr = ISEC2_LatIncr;
+	  lonIncr = (unsigned)ISEC2_LonIncr;
+	  latIncr = (unsigned)ISEC2_LatIncr;
 	}
       Put2Byte(lonIncr);               /* 23-24 i - direction increment  */
       if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN )
@@ -13799,7 +13376,7 @@ void TEMPLATE(encodeBMS,T)(GRIBPACK *lGrib, long *gribLen, T *fsec3, int *isec4,
       if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
 	{
 	  data[fsec4size++] = data[i];
-	  bitmap[i/8] |= 1<<(7-(i&7));
+	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
 	}
     }
 #endif
@@ -13825,36 +13402,33 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
   /* Uwe Schulzweida, 11/04/2003 : Check that number of bits per value is not exceeded */
   /* Uwe Schulzweida,  6/05/2003 : Copy result to fpval to prevent integer overflow */
 
-  size_t z = *gribLen;
-  long i, jloop;
+  size_t z = (size_t)*gribLen;
+  long i;
   int numBits;
   int ival;
-  int blockLength, PackStart = 0, Flag = 0;
+  long PackStart = 0, Flag = 0;
   int binscale = 0;
   int nbpv;
   int bds_head = 11;
   int bds_ext = 0;
   /* ibits = BitsPerInt; */
-  unsigned int max_nbpv_pow2;
   int exponent, mantissa;
-  int unused_bits = 0;
   int lspherc = FALSE, lcomplex = FALSE;
   int isubset = 0, itemp = 0, itrunc = 0;
   T factor = 1, fmin, fmax;
   double zref;
-  double range, rangec;
+  double range;
   double jpepsln = 1.0e-12;     /* -----> tolerance used to check equality     */
                                 /*        of floating point numbers - needed   */
 		                /*        on some platforms (eg vpp700, linux) */
-  extern const double _pow2tab[158];
   extern int CGRIBEX_Const;         /* 1: Don't pack constant fields on regular grids */
 
   if ( isec2 )
     {
       /* If section 2 is present, it says if data is spherical harmonic */
 
-      if ( isec2[0] == 50 || isec2[0] == 60 || 
-	   isec2[0] == 70 || isec2[0] == 80 ) lspherc = TRUE;
+      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
+                   isec2[0] == 70 || isec2[0] == 80 );
 
       if ( lspherc )
 	isec4[2] = 128;
@@ -13937,7 +13511,7 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
       pcStart = isubset;
       pcScale = isec4[16];
       TEMPLATE(scale_complex,T)(data, pcStart, pcScale, itrunc, 0);
-      TEMPLATE(gather_complex,T)(data, pcStart, itrunc, datasize);
+      TEMPLATE(gather_complex,T)(data, (size_t)pcStart, (size_t)itrunc, (size_t)datasize);
     }
 
   fmin = fmax = data[PackStart];
@@ -13953,10 +13527,10 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
     }
 
 
-  blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
-  if ( (blockLength%2) == 1 ) blockLength++;
+  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
+  blockLength += blockLength & 1;
 
-  unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
+  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
 
   Flag += unused_bits;
 
@@ -13994,57 +13568,54 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
     }
   else if ( range > 1.0 )
     {
-      rangec = range + jpepsln;
-      for ( jloop = 1; jloop < 128; jloop++ )
-	{
-	  if ( _pow2tab[jloop] > rangec ) break;
-	}
-      if ( jloop == 128 )
-	{
-	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-	  gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-	  return (707);
-	}
+      double rangec = range + jpepsln,
+        p2 = 2.0;
+      long jloop = 1;
+      while ( jloop < 128 && p2 <= rangec )
+        {
+          p2 *= 2.0;
+          ++jloop;
+        }
+      if (jloop < 128)
+        binscale = jloop - nbpv;
       else
-	{
-	  binscale = jloop - nbpv;
-	}
+        {
+          gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+          gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+          return (707);
+        }
     }
   else
     {
-      rangec = range - jpepsln;
-      for ( jloop = 1; jloop < 127; jloop++ )
+      double rangec = range - jpepsln, p05 = 0.5;
+      long jloop = 1;
+      while ( jloop < 127 && p05 >= rangec )
 	{
-	  if ( 1.0/_pow2tab[jloop] < rangec ) break;
+          p05 *= 0.5;
+          jloop++;
 	}
-      if ( jloop == 127 )
+      if ( jloop < 127 )
 	{
-	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-	  return (707);
+	  binscale = 1 - jloop - nbpv;
 	}
       else
 	{
-	  binscale = 1 - jloop - nbpv;
+	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+	  return (707);
 	}
     }
 
-  //max_nbpv_pow2 = (unsigned) (intpow2(nbpv) - 1);
-  max_nbpv_pow2 = (unsigned) ((1ULL << nbpv) - 1);
+  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
 
   if ( binscale != 0 )
     {
       if ( binscale < 0 )
-	{
-	  if ( (unsigned)(range*intpow2(-binscale)+0.5) > max_nbpv_pow2 ) binscale++;
-	}
+        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
       else
-	{
-	  if ( (unsigned)(range/intpow2(binscale)+0.5) > max_nbpv_pow2 ) binscale--;
-	}
+        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale--;
 
-      if ( binscale < 0 ) factor =     intpow2(-binscale);
-      else                factor = 1.0/intpow2( binscale);
+      factor = intpow2(-binscale);
     }
 
   ref2ibm(&zref, BitsPerInt);
@@ -14061,7 +13632,7 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
       if ( lcomplex )
 	{
 	  int jup = isubset;
-	  int ioff = z + bds_ext;
+	  int ioff = (int)z + bds_ext;
 	  if ( ioff > 0xFFFF ) ioff = 0;
 	  Put2Byte(ioff);
 	  Put2Int(isec4[16]);
@@ -14079,14 +13650,14 @@ int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *ise
   *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
 
 #if  defined  (_ARCH_PWR6)
-  TEMPLATE(encode_array_unrolled,T)(nbpv, PackStart, datasize, lGrib, data, (T)zref, factor, &z);
+  TEMPLATE(encode_array_unrolled,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
 #else
-  TEMPLATE(encode_array,T)(nbpv, PackStart, datasize, lGrib, data, (T)zref, factor, &z);
+  TEMPLATE(encode_array,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
 #endif
 
   if ( unused_bits >= 8 ) Put1Byte(0);  /*  Fillbyte                     */
 
-  *gribLen = z;
+  *gribLen = (long)z;
 
   return (0);
 }
@@ -14101,9 +13672,7 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   GRIBPACK *lpds;
   unsigned char *CGrib;
   long fsec4size = 0;
-  int numBytes;
   int bmsIncluded;
-  size_t len;
   GRIBPACK *lGrib;
   long datstart, datsize, bdsstart;
   int status = 0;
@@ -14118,15 +13687,15 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   bmsIncluded = ISEC1_Sec2Or3Flag & 64;
 
   /* set max header len */
-  len = 16384;
+  size_t len = 16384;
 
   /* add data len */
-  numBytes = (ISEC4_NumBits+7)>>3;
+  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
 
-  len += numBytes*klenp;
+  len += numBytes*(size_t)klenp;
 
   /* add bitmap len */
-  if ( bmsIncluded ) len += (klenp+7)>>3;
+  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
 
 #if defined (VECTORCODE)
   lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
@@ -14182,7 +13751,7 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 
   encodeES(lGrib, &gribLen, bdsstart);
 
-  if ( (size_t) gribLen > kleng*sizeof(int) )
+  if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
     Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
 
 #if defined (VECTORCODE)
@@ -14194,23 +13763,28 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
   Free(lGrib);
 #endif
 
-  ISEC0_GRIB_Len     = gribLen;
+  ISEC0_GRIB_Len     = (int)gribLen;
   ISEC0_GRIB_Version = 1;
 
-  *kword = gribLen / sizeof(int);
-  if ( (size_t) gribLen != *kword * sizeof(int) ) *kword += 1;
+  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
 
   *kret = status;
 }
 
 #endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
 void encode_dummy(void)
 {
   (void) encode_array_unrolled_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
   (void) encode_array_unrolled_float(0, 0, 0, NULL, NULL, 0, 0, NULL);
 }
-static const char grb_libvers[] = "1.7.3" " of ""Sep 14 2015"" ""10:58:44";
+static const char grb_libvers[] = "1.7.4" " of ""Feb 19 2016"" ""11:03:41";
 const char *
 cgribexLibraryVersion(void)
 {
diff --git a/libcdi/src/config.h.in b/libcdi/src/config.h.in
index 230bf53..f7ceef6 100644
--- a/libcdi/src/config.h.in
+++ b/libcdi/src/config.h.in
@@ -58,8 +58,7 @@
    don't. */
 #undef HAVE_DECL__SC_PAGE_SIZE
 
-/* Define to 1 if you have the declaration of `__builtin_ctz', and to 0 if you
-   don't. */
+/* Define to 1 if __builtin_ctz is available, 0 if not */
 #undef HAVE_DECL___BUILTIN_CTZ
 
 /* Define to 1 if you have the <dlfcn.h> header file. */
diff --git a/libcdi/src/create_uuid.h b/libcdi/src/create_uuid.h
deleted file mode 100644
index 30566d2..0000000
--- a/libcdi/src/create_uuid.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef CREATE_UUID_H
-#define CREATE_UUID_H
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#include "cdi.h"
-
-void
-create_uuid(unsigned char uuid[CDI_UUID_SIZE]);
-
-#endif
-
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
diff --git a/libcdi/src/dmemory.h b/libcdi/src/dmemory.h
index d5f60a9..90ec1f0 100644
--- a/libcdi/src/dmemory.h
+++ b/libcdi/src/dmemory.h
@@ -10,6 +10,10 @@
 #define  WITH_FUNCTION_NAME
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern size_t  memTotal(void);
 extern void    memDebug(int debug);
 extern void    memExitOnError(void);
@@ -21,6 +25,10 @@ extern void   *memCalloc (size_t nmemb, size_t size, const char *file, const cha
 extern void   *memMalloc (size_t size, const char *file, const char *functionname, int line);
 extern void    memFree   (void *ptr, const char *file, const char *functionname, int line);
 
+#if defined (__cplusplus)
+}
+#endif
+
 #if  defined  WITH_FUNCTION_NAME
 #  define  Realloc(p, s)  memRealloc((p), (s), __FILE__, __func__, __LINE__)
 #  define   Calloc(n, s)   memCalloc((n), (s), __FILE__, __func__, __LINE__)
diff --git a/libcdi/src/error.c b/libcdi/src/error.c
index 7d488a9..5d1c345 100644
--- a/libcdi/src/error.c
+++ b/libcdi/src/error.c
@@ -27,6 +27,7 @@ void SysError_(const char *caller, const char *fmt, ...)
 void SysError_(const char *caller, const char *fmt, ...)
 {
   va_list args;
+  int saved_errno = errno;
 
   va_start(args, fmt);
 
@@ -37,8 +38,11 @@ void SysError_(const char *caller, const char *fmt, ...)
 
   va_end(args);
 
-  if ( errno )
-    perror("System error message ");
+  if ( saved_errno )
+    {
+      errno = saved_errno;
+      perror("System error message");
+    }
 
   exit(EXIT_FAILURE);
 }
diff --git a/libcdi/src/error.h b/libcdi/src/error.h
index 77ea2b5..58b7288 100644
--- a/libcdi/src/error.h
+++ b/libcdi/src/error.h
@@ -8,9 +8,9 @@
 #define  WITH_CALLER_NAME
 #endif
 
-#define  _FATAL     1     /* Error flag: exit on error  */
-#define  _VERBOSE   2     /* Error flag: report errors  */
-#define  _DEBUG     4     /* Error flag: debug          */
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 extern int _ExitOnError;  /* If set to 1, exit on error (default 1)       */
 extern int _Verbose;      /* If set to 1, errors are reported (default 1) */
@@ -66,6 +66,10 @@ cdiAbortC_serial(const char *caller, const char *filename,
                  const char *errorString, va_list ap)
   __attribute__((noreturn));
 
+#if defined (__cplusplus)
+}
+#endif
+
 #endif  /* _ERROR_H */
 /*
  * Local Variables:
diff --git a/libcdi/src/gaussgrid.h b/libcdi/src/gaussgrid.h
index c431324..e33df5e 100644
--- a/libcdi/src/gaussgrid.h
+++ b/libcdi/src/gaussgrid.h
@@ -1,7 +1,15 @@
 #ifndef _GAUSSGRID_H
 #define _GAUSSGRID_H
 
-void   gaussaw(double *restrict pa, double *restrict pw, size_t nlat);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gaussaw(double *restrict pa, double *restrict pw, size_t nlat);
+
+#if defined (__cplusplus)
+}
+#endif
 
 #endif  /* _GAUSSGRID_H */
 /*
diff --git a/libcdi/src/grb_read.c b/libcdi/src/grb_read.c
new file mode 100644
index 0000000..4e52232
--- /dev/null
+++ b/libcdi/src/grb_read.c
@@ -0,0 +1,239 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_LIBGRIB
+
+#include "dmemory.h"
+#include "cdi.h"
+#include "cdi_int.h"
+#include "stream_cgribex.h"
+#include "stream_grb.h"
+#include "stream_gribapi.h"
+#include "file.h"
+#include "cgribex.h"  /* gribZip gribGetZip gribGinfo */
+#include "gribapi.h"
+#include "namespace.h"
+
+
+static
+int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *data, size_t datasize,
+	      int unreduced, int *nmiss, double missval, int vlistID, int varID)
+{
+  int status = 0;
+
+#if  defined  (HAVE_LIBCGRIBEX)
+  if ( filetype == FILETYPE_GRB )
+    {
+#if  defined  (HAVE_LIBGRIB_API)
+      extern int cdiNAdditionalGRIBKeys;
+      if ( cdiNAdditionalGRIBKeys > 0 )
+	Error("CGRIBEX decode does not support reading of additional GRIB keys!");
+#endif
+      status = cgribexDecode(memtype, gribbuffer, gribsize, data, (long) datasize, unreduced, nmiss, missval);
+    }
+  else
+#endif
+#ifdef HAVE_LIBGRIB_API
+    {
+      void *datap = data;
+      if ( memtype == MEMTYPE_FLOAT )
+        datap = Malloc(datasize*sizeof(double));
+
+      status = gribapiDecode(gribbuffer, gribsize, datap, (long) datasize, unreduced, nmiss, missval, vlistID, varID);
+
+      if ( memtype == MEMTYPE_FLOAT )
+        {
+          float *dataf = (float*) data;
+          double *datad = (double*) datap;
+          for ( size_t i = 0; i < datasize; ++i ) dataf[i] = (float) datad[i];
+          free((void*)datap);
+        }
+    }
+#else
+    {
+      (void)vlistID; (void)varID;
+      Error("GRIB_API support not compiled in!");
+    }
+#endif
+
+  return status;
+}
+
+static
+int grbUnzipRecord(void *gribbuffer, size_t *gribsize)
+{
+  int zip = 0;
+  int izip;
+  long unzipsize;
+
+  size_t igribsize = *gribsize;
+  size_t ogribsize = *gribsize;
+
+  if ( (izip = gribGetZip((long)igribsize, (unsigned char *)gribbuffer, &unzipsize)) > 0 )
+    {
+      zip = izip;
+      if ( izip == 128 ) /* szip */
+	{
+	  unsigned char *itmpbuffer = NULL;
+	  size_t itmpbuffersize = 0;
+
+	  if ( unzipsize < (long) igribsize )
+	    {
+	      fprintf(stderr, "Decompressed size smaller than compressed size (in %ld; out %ld)!\n", (long)igribsize, unzipsize);
+	      return (0);
+	    }
+
+	  if ( itmpbuffersize < igribsize )
+	    {
+	      itmpbuffersize = igribsize;
+	      itmpbuffer = (unsigned char *) Realloc(itmpbuffer, itmpbuffersize);
+	    }
+
+	  memcpy(itmpbuffer, gribbuffer, itmpbuffersize);
+
+	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
+
+	  ogribsize = (size_t)gribUnzip((unsigned char *)gribbuffer, unzipsize, itmpbuffer, (long)igribsize);
+
+	  Free(itmpbuffer);
+
+	  if ( ogribsize <= 0 ) Error("Decompression problem!");
+	}
+      else
+	{
+	  Error("Decompression for %d not implemented!", izip);
+	}
+    }
+
+  *gribsize = ogribsize;
+
+  return zip;
+}
+
+
+void grb_read_record(stream_t * streamptr, int memtype, void *data, int *nmiss)
+{
+  int filetype = streamptr->filetype;
+
+  void *gribbuffer = streamptr->record->buffer;
+
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+  int tsID    = streamptr->curTsID;
+  int vrecID  = streamptr->tsteps[tsID].curRecID;
+  int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
+  off_t recpos  = streamptr->tsteps[tsID].records[recID].position;
+  size_t recsize = streamptr->tsteps[tsID].records[recID].size;
+  int varID   = streamptr->tsteps[tsID].records[recID].varID;
+
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int gridsize = gridInqSize(gridID);
+
+  streamptr->numvals += gridsize;
+
+  fileSetPos(fileID, recpos, SEEK_SET);
+
+  if (fileRead(fileID, gribbuffer, recsize) != recsize)
+    Error("Failed to read GRIB record");
+
+  double missval = vlistInqVarMissval(vlistID, varID);
+
+  streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
+
+  grbDecode(filetype, memtype, gribbuffer, (int)recsize, data, (size_t)gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
+}
+
+
+void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int *nmiss)
+{
+  int filetype = streamptr->filetype;
+
+  void *gribbuffer = streamptr->record->buffer;
+
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+  int tsID    = streamptr->curTsID;
+
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int gridsize = gridInqSize(gridID);
+
+  off_t currentfilepos = fileGetPos(fileID);
+
+  int isub     = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
+  int nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
+  if ( CDI_Debug )
+    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+  *nmiss = 0;
+  for (int levelID = 0; levelID < nlevs; levelID++ )
+    {
+      int    recID   = streamptr->vars[varID].recordTable[isub].recordID[levelID];
+      off_t  recpos  = streamptr->tsteps[tsID].records[recID].position;
+      size_t recsize = streamptr->tsteps[tsID].records[recID].size;
+
+      fileSetPos(fileID, recpos, SEEK_SET);
+
+      fileRead(fileID, gribbuffer, recsize);
+
+      double missval = vlistInqVarMissval(vlistID, varID);
+
+      int imiss;
+
+      streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
+
+      void *datap = NULL;
+      if ( memtype == MEMTYPE_FLOAT )
+        datap = (float*)data + levelID*gridsize;
+      else
+        datap = (double*)data + levelID*gridsize;
+
+      grbDecode(filetype, memtype, gribbuffer, (int)recsize, datap, (size_t)gridsize,
+                streamptr->unreduced, &imiss, missval, vlistID, varID);
+
+      *nmiss += imiss;
+    }
+
+  fileSetPos(fileID, currentfilepos, SEEK_SET);
+}
+
+
+void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss)
+{
+  int filetype = streamptr->filetype;
+
+  void *gribbuffer = streamptr->record->buffer;
+
+  int vlistID = streamptr->vlistID;
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int gridsize = gridInqSize(gridID);
+  int tsID = streamptr->curTsID;
+
+  if ( CDI_Debug )
+    Message("gridID = %d gridsize = %d", gridID, gridsize);
+
+  int fileID = streamptr->fileID;
+
+  off_t currentfilepos = fileGetPos(fileID);
+
+  int    isub    = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
+
+  int    recID   = streamptr->vars[varID].recordTable[isub].recordID[levelID];
+  off_t  recpos  = streamptr->tsteps[tsID].records[recID].position;
+  size_t recsize = streamptr->tsteps[tsID].records[recID].size;
+
+  if ( recsize == 0 )
+    Error("Internal problem! Recordsize is zero for record %d at timestep %d",
+	  recID+1, tsID+1);
+
+  fileSetPos(fileID, recpos, SEEK_SET);
+  fileRead(fileID, gribbuffer, recsize);
+
+  streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
+
+  double missval = vlistInqVarMissval(vlistID, varID);
+  grbDecode(filetype, memtype, gribbuffer, (int)recsize, data, (size_t)gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
+
+  fileSetPos(fileID, currentfilepos, SEEK_SET);
+}
+
+#endif
diff --git a/libcdi/src/grb_write.c b/libcdi/src/grb_write.c
new file mode 100644
index 0000000..dd8cc9f
--- /dev/null
+++ b/libcdi/src/grb_write.c
@@ -0,0 +1,257 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_LIBGRIB
+
+#include "dmemory.h"
+#include "cdi.h"
+#include "cdi_int.h"
+#include "stream_cgribex.h"
+#include "stream_grb.h"
+#include "stream_gribapi.h"
+#include "file.h"
+#include "cgribex.h"  /* gribZip gribGetZip gribGinfo */
+#include "gribapi.h"
+#include "namespace.h"
+
+
+static
+size_t grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
+		 int date, int time, int tsteptype, int numavg,
+		 size_t datasize, const void *data, int nmiss, void **gribbuffer,
+		 int comptype, void *gribContainer)
+{
+  size_t nbytes = 0;
+
+#ifdef HAVE_LIBCGRIBEX
+  if ( filetype == FILETYPE_GRB )
+    {
+      size_t gribbuffersize = datasize*4+3000;
+      *gribbuffer = Malloc(gribbuffersize);
+
+      nbytes = cgribexEncode(memtype, varID, levelID, vlistID, gridID, zaxisID,
+			     date, time, tsteptype, numavg,
+			     (long) datasize, data, nmiss, *gribbuffer, gribbuffersize);
+    }
+  else
+#endif
+#ifdef HAVE_LIBGRIB_API
+    {
+      const void *datap = data;
+      if ( memtype == MEMTYPE_FLOAT )
+        {
+          const float *dataf = (const float*) data;
+          double *datad = (double*) Malloc(datasize*sizeof(double));
+          for ( size_t i = 0; i < datasize; ++i ) datad[i] = (double) dataf[i];
+          datap = (const void*) datad;
+        }
+
+      size_t gribbuffersize;
+      nbytes = gribapiEncode(varID, levelID, vlistID, gridID, zaxisID,
+			     date, time, tsteptype, numavg,
+			     (long) datasize, datap, nmiss, gribbuffer, &gribbuffersize,
+			     comptype, gribContainer);
+      
+      if ( memtype == MEMTYPE_FLOAT ) free((void*)datap);
+    }
+#else
+    {
+      Error("GRIB_API support not compiled in!");
+      (void)gribContainer;
+      (void)comptype;
+    }
+#endif
+
+  return nbytes;
+}
+
+static
+size_t grbSzip(int filetype, void *gribbuffer, size_t gribbuffersize)
+{
+  size_t buffersize = gribbuffersize + 1000; /* compressed record can be greater than source record */
+  void *buffer = Malloc(buffersize);
+
+  /*  memcpy(buffer, gribbuffer, gribbuffersize); */
+
+  size_t nbytes = 0;
+  if ( filetype == FILETYPE_GRB )
+    {
+      nbytes = (size_t)gribZip((unsigned char *)gribbuffer, (long) gribbuffersize, (unsigned char *)buffer, (long) buffersize);
+    }
+  else
+    {
+      static int lszip_warn = 1;
+      if ( lszip_warn ) Warning("Szip compression of GRIB2 records not implemented!");
+      lszip_warn = 0;
+      nbytes = gribbuffersize;
+    }
+
+  Free(buffer);
+
+  return nbytes;
+}
+
+
+void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
+{
+  int filetype = streamptr1->filetype;
+  int fileID1 = streamptr1->fileID;
+  int fileID2 = streamptr2->fileID;
+  int tsID    = streamptr1->curTsID;
+  int vrecID  = streamptr1->tsteps[tsID].curRecID;
+  int recID   = streamptr1->tsteps[tsID].recIDs[vrecID];
+  off_t recpos  = streamptr1->tsteps[tsID].records[recID].position;
+  size_t recsize = streamptr1->tsteps[tsID].records[recID].size;
+
+  fileSetPos(fileID1, recpos, SEEK_SET);
+
+  /* round up recsize to next multiple of 8 */
+  size_t gribbuffersize = ((recsize + 7U) & ~7U);
+
+  unsigned char *gribbuffer = (unsigned char *) Malloc(gribbuffersize);
+
+  if (fileRead(fileID1, gribbuffer, recsize) != recsize)
+    Error("Could not read GRIB record for copying!");
+
+  size_t nbytes = recsize;
+
+  if ( filetype == FILETYPE_GRB )
+    {
+      long unzipsize;
+      int izip = gribGetZip((long)recsize, gribbuffer, &unzipsize);
+
+      if ( izip == 0 && streamptr2->comptype == COMPRESS_SZIP )
+          nbytes = grbSzip(filetype, gribbuffer, nbytes);
+    }
+
+  while ( nbytes & 7 ) gribbuffer[nbytes++] = 0;
+
+  size_t nwrite = fileWrite(fileID2, gribbuffer, nbytes);
+  if ( nwrite != nbytes )
+    {
+      perror(__func__);
+      Error("Could not write record for copying!");
+    }
+
+  Free(gribbuffer);
+}
+
+
+void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
+{
+  void *gribbuffer = NULL;
+  void *gc = NULL;
+
+  int filetype  = streamptr->filetype;
+  int fileID    = streamptr->fileID;
+  int vlistID   = streamptr->vlistID;
+  int gridID    = vlistInqVarGrid(vlistID, varID);
+  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  int comptype  = streamptr->comptype;
+  int tsID      = streamptr->curTsID;
+  int date      = streamptr->tsteps[tsID].taxis.vdate;
+  int time      = streamptr->tsteps[tsID].taxis.vtime;
+  int numavg    = 0;
+  if ( vlistInqVarTimave(vlistID, varID) )
+    numavg = streamptr->tsteps[tsID].taxis.numavg;
+
+  if ( CDI_Debug )
+    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
+
+  size_t datasize = (size_t)gridInqSize(gridID);
+
+#ifdef HAVE_LIBCGRIBEX
+  if ( filetype == FILETYPE_GRB )
+    {
+    }
+  else
+#endif
+    {
+#ifdef GRIBCONTAINER2D
+      gribContainer_t **gribContainers =  (gribContainer_t **) streamptr->gribContainers;
+      gc = (void *) &gribContainers[varID][levelID];
+#else
+      gribContainer_t *gribContainers =  (gribContainer_t *) streamptr->gribContainers;
+      gc = (void *) &gribContainers[varID];
+#endif
+    }
+
+  if ( comptype != COMPRESS_JPEG && comptype != COMPRESS_SZIP ) comptype = COMPRESS_NONE;
+
+  if ( filetype == FILETYPE_GRB && comptype == COMPRESS_JPEG )
+    {
+      static int ljpeg_warn = 1;
+      if ( ljpeg_warn ) Warning("JPEG compression of GRIB1 records not available!");
+      ljpeg_warn = 0;
+    }
+
+  size_t nbytes = grbEncode(filetype, memtype, varID, levelID, vlistID, gridID, zaxisID, date, time, tsteptype, numavg,
+                            datasize, data, nmiss, &gribbuffer, comptype, gc);
+
+  if ( filetype == FILETYPE_GRB && streamptr->comptype == COMPRESS_SZIP )
+    nbytes = grbSzip(filetype, gribbuffer, nbytes);
+
+  size_t (*myFileWrite)(int fileID, const void *restrict buffer,
+                        size_t len, int tsID)
+    = (size_t (*)(int, const void *restrict, size_t, int))
+    namespaceSwitchGet(NSSWITCH_FILE_WRITE).func;
+  size_t nwrite = myFileWrite(fileID, gribbuffer, nbytes, tsID);
+
+  if ( nwrite != nbytes )
+    {
+      perror(__func__);
+      Error("Failed to write GRIB slice!");
+    }
+
+  if ( gribbuffer ) Free(gribbuffer);
+}
+
+
+void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
+{
+  int vlistID  = streamptr->vlistID,
+    gridID   = vlistInqVarGrid(vlistID, varID),
+    gridsize = gridInqSize(gridID),
+    zaxisID  = vlistInqVarZaxis(vlistID, varID),
+    nlevs    = zaxisInqSize(zaxisID);
+  double missval = vlistInqVarMissval(vlistID, varID);
+
+  size_t chunkLen = (size_t)gridsize;
+  if ( memtype == MEMTYPE_FLOAT )
+    for ( int levelID = 0; levelID < nlevs; levelID++ )
+      {
+        const float *restrict fdata = ((const float *)data)+levelID*gridsize;
+        
+        int nmiss_slice = 0;
+        if ( nmiss )
+          for ( size_t i = 0; i < chunkLen; ++i )
+            nmiss_slice += DBL_IS_EQUAL(fdata[i], missval);
+
+        grb_write_var_slice(streamptr, varID, levelID, memtype, fdata, nmiss_slice);
+      }
+  else
+    for ( int levelID = 0; levelID < nlevs; levelID++ )
+      {
+        const double *restrict ddata = ((const double *)data)+levelID*gridsize;
+        
+        int nmiss_slice = 0;
+        if ( nmiss )
+          for ( size_t i = 0; i < chunkLen; ++i )
+            nmiss_slice += DBL_IS_EQUAL(ddata[i], missval);
+
+        grb_write_var_slice(streamptr, varID, levelID, memtype, ddata, nmiss_slice);
+      }
+}
+
+
+void grb_write_record(stream_t * streamptr, int memtype, const void *data, int nmiss)
+{
+  int varID   = streamptr->record->varID;
+  int levelID = streamptr->record->levelID;
+
+  grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+}
+
+#endif
diff --git a/libcdi/src/gribapi_utilities.c b/libcdi/src/gribapi_utilities.c
index a8907ec..90a2a98 100644
--- a/libcdi/src/gribapi_utilities.c
+++ b/libcdi/src/gribapi_utilities.c
@@ -10,6 +10,7 @@
 #include "dmemory.h"
 #include "error.h"
 #include "gribapi.h"
+#include "grid.h"
 
 #include <assert.h>
 #include <time.h>
@@ -274,7 +275,8 @@ static int getAvailabilityOfRelativeTimes(grib_handle* gh, bool* outHaveForecast
         *outHaveForecastTime = false, *outHaveTimeRange = false;
         return 0;
 
-      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 15: case 32: case 33: case 40: case 41: case 44: case 45: case 48: case 51: case 53: case 54: case 60: case 1000: case 1002: case 1100: case 40033:
+      //case 55 and case 40455 are the same: 55 is the proposed standard value, 40455 is the value in the local use range that is used by the dwd until the standard is updated.
+      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 15: case 32: case 33: case 40: case 41: case 44: case 45: case 48: case 51: case 53: case 54: case 55: case 60: case 1000: case 1002: case 1100: case 40033: case 40455:
         *outHaveForecastTime = true, *outHaveTimeRange = false;
         return 0;
 
@@ -287,24 +289,15 @@ static int getAvailabilityOfRelativeTimes(grib_handle* gh, bool* outHaveForecast
     }
 }
 
-char* gribMakeTimeString(grib_handle* gh, bool getEndTime)
+char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType)
 {
   //Get the parts of the reference date.
-#ifdef __cplusplus
-    struct tm date;
-    date.tm_mon = (int) gribGetLong(gh, "month") - 1;   //months are zero based in struct tm and one based in GRIBy
+  struct tm date;
+  date.tm_mon = (int)gribGetLong(gh, "month") - 1;   //months are zero based in struct tm and one based in GRIB
+  date.tm_mday = (int)gribGetLong(gh, "day");
+  date.tm_hour = (int)gribGetLong(gh, "hour");
+  date.tm_min = (int)gribGetLong(gh, "minute");
 
-    date.tm_mday = (int)gribGetLong(gh, "day");
-    date.tm_hour = (int)gribGetLong(gh, "hour");
-    date.tm_min = (int)gribGetLong(gh, "minute");
-#else
-  struct tm date = {
-    .tm_mon = (int)gribGetLong(gh, "month") - 1,   //months are zero based in struct tm and one based in GRIBy
-    .tm_mday = (int)gribGetLong(gh, "day"),
-    .tm_hour = (int)gribGetLong(gh, "hour"),
-    .tm_min = (int)gribGetLong(gh, "minute")
-  };
-#endif
   if(gribEditionNumber(gh) == 1)
     {
       date.tm_year = (int)gribGetLong(gh, "yearOfCentury");  //years are -1900 based both in struct tm and GRIB1
@@ -314,23 +307,27 @@ char* gribMakeTimeString(grib_handle* gh, bool getEndTime)
       date.tm_year = (int)gribGetLong(gh, "year") - 1900;   //years are -1900 based in struct tm and zero based in GRIB2
       date.tm_sec = (int)gribGetLong(gh, "second");
 
-      //Determine whether we have a forecast time and a time range.
-      bool haveForecastTime, haveTimeRange;
-      if(getAvailabilityOfRelativeTimes(gh, &haveForecastTime, &haveTimeRange)) return NULL;
-      if(getEndTime && !haveTimeRange) return NULL;     //tell the caller that the requested time does not exist
-
-      //If we have relative times, apply them to the date
-      if(haveForecastTime)
+      //If the start or end time are requested, we need to take the relative times into account.
+      if(timeType != kCdiTimeType_referenceTime)
         {
-          long offset = gribGetLongDefault(gh, "forecastTime", 0);  //if(stepUnits == indicatorOfUnitOfTimeRange) assert(startStep == forecastTime)
-          long offsetUnit = gribGetLongDefault(gh, "indicatorOfUnitOfTimeRange", 255);
-          if(addToDate(&date, offset, offsetUnit)) return NULL;
-          if(getEndTime)
+          //Determine whether we have a forecast time and a time range.
+          bool haveForecastTime, haveTimeRange;
+          if(getAvailabilityOfRelativeTimes(gh, &haveForecastTime, &haveTimeRange)) return NULL;
+          if(timeType == kCdiTimeType_endTime && !haveTimeRange) return NULL;     //tell the caller that the requested time does not exist
+
+          //If we have relative times, apply the relative times to the date
+          if(haveForecastTime)
             {
-              assert(haveTimeRange);
-              long range = gribGetLongDefault(gh, "lengthOfTimeRange", 0);       //if(stepUnits == indicatorOfUnitForTimeRange) assert(endStep == startStep + lengthOfTimeRange)
-              long rangeUnit = gribGetLongDefault(gh, "indicatorOfUnitForTimeRange", 255);
-              if(addToDate(&date, range, rangeUnit)) return NULL;
+              long offset = gribGetLongDefault(gh, "forecastTime", 0);  //if(stepUnits == indicatorOfUnitOfTimeRange) assert(startStep == forecastTime)
+              long offsetUnit = gribGetLongDefault(gh, "indicatorOfUnitOfTimeRange", 255);
+              if(addToDate(&date, offset, offsetUnit)) return NULL;
+              if(timeType == kCdiTimeType_endTime)
+                {
+                  assert(haveTimeRange);
+                  long range = gribGetLongDefault(gh, "lengthOfTimeRange", 0);       //if(stepUnits == indicatorOfUnitForTimeRange) assert(endStep == startStep + lengthOfTimeRange)
+                  long rangeUnit = gribGetLongDefault(gh, "indicatorOfUnitForTimeRange", 255);
+                  if(addToDate(&date, range, rangeUnit)) return NULL;
+                }
             }
         }
     }
@@ -461,7 +458,8 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
       ISEC4_NumValues = ISEC2_NumLon*ISEC2_NumLat;
     }
   */
-  memset(grid, 0, sizeof(grid_t));
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, 0);
 
   size_t datasize;
   FAIL_ON_GRIB_ERROR(grib_get_size, gh, "values", &datasize);
diff --git a/libcdi/src/gribapi_utilities.h b/libcdi/src/gribapi_utilities.h
index 0f8a12c..b9f2084 100644
--- a/libcdi/src/gribapi_utilities.h
+++ b/libcdi/src/gribapi_utilities.h
@@ -3,6 +3,7 @@
 
 #ifdef HAVE_LIBGRIB_API
 
+#include "cdi_int.h"
 #include "grid.h"
 
 #include <grib_api.h>
@@ -24,7 +25,7 @@ void gribGetDoubleArray(grib_handle* gribHandle, const char* key, double* array)
 void gribGetLongArray(grib_handle* gribHandle, const char* key, long* array);   //The caller is responsible to ensure a sufficiently large buffer.
 
 long gribEditionNumber(grib_handle* gh);
-char* gribMakeTimeString(grib_handle* gh, bool getEndTime);     //For statistical fields, setting getEndTime produces the time of the end of the integration period, otherwise the time of the start of the integration period is returned. Returns NULL if getEndTime is set and the field does not have an integration period.
+char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType);     //Returns NULL if timeType is kCdiTimeType_endTime and the field does not have an integration period (statistical data).
 int gribapiTimeIsFC(grib_handle *gh);
 int gribapiGetTsteptype(grib_handle *gh);
 int gribGetDatatype(grib_handle* gribHandle);
diff --git a/libcdi/src/grid.c b/libcdi/src/grid.c
index a2ff574..64cc1df 100644
--- a/libcdi/src/grid.c
+++ b/libcdi/src/grid.c
@@ -2,6 +2,7 @@
 #  include "config.h"
 #endif
 
+#include <assert.h>
 #include <string.h>
 #include <float.h>  /* FLT_EPSILON */
 #include <limits.h> /* INT_MAX     */
@@ -10,6 +11,7 @@
 #include "cdi.h"
 #include "cdi_cksum.h"
 #include "cdi_int.h"
+#include "cdi_uuid.h"
 #include "grid.h"
 #include "gaussgrid.h"
 #include "resource_handle.h"
@@ -42,6 +44,23 @@ static const char Grids[][17] = {
   /* 15 */  "projection",
 };
 
+/* must match table below */
+enum xystdname_idx {
+  grid_xystdname_grid_latlon,
+  grid_xystdname_latlon,
+  grid_xystdname_projection,
+};
+static const char xystdname_tab[][2][24] = {
+  [grid_xystdname_grid_latlon] = { "grid_longitude",
+                                   "grid_latitude" },
+  [grid_xystdname_latlon] = { "longitude",
+                              "latitude" },
+  [grid_xystdname_projection] = { "projection_x_coordinate",
+                                  "projection_y_coordinate" },
+
+};
+
+
 
 static int    gridCompareP    ( void * gridptr1, void * gridptr2 );
 static void   gridDestroyP    ( void * gridptr );
@@ -62,7 +81,13 @@ static const resOps gridOps = {
 
 static int  GRID_Debug = 0;   /* If set to 1, debugging */
 
+grid_t *gridID2Ptr(int gridID)
+{
+  return (grid_t *)reshGetVal(gridID, &gridOps);
+}
 #define gridID2Ptr(gridID) (grid_t *)reshGetVal(gridID, &gridOps)
+#define gridMark4Update(gridID) reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE)
+
 
 void grid_init(grid_t *gridptr)
 {
@@ -125,7 +150,6 @@ void grid_init(grid_t *gridptr)
   gridptr->xpole        = 0.0;
   gridptr->ypole        = 0.0;
   gridptr->angle        = 0.0;
-  gridptr->locked       = FALSE;
   gridptr->lcomplex     = 0;
   gridptr->hasdims      = TRUE;
   gridptr->xname[0]     = 0;
@@ -134,26 +158,30 @@ void grid_init(grid_t *gridptr)
   gridptr->ylongname[0] = 0;
   gridptr->xunits[0]    = 0;
   gridptr->yunits[0]    = 0;
-  gridptr->xstdname[0]  = 0;
-  gridptr->ystdname[0]  = 0;
+  gridptr->xstdname  = NULL;
+  gridptr->ystdname  = NULL;
   memset(gridptr->uuid, 0, CDI_UUID_SIZE);
   gridptr->name         = NULL;
+  gridptr->vtable       = &cdiGridVtable;
+  gridptr->extraData    = NULL;
 }
 
 
-void grid_free(grid_t *gridptr)
+static void
+grid_free_components(grid_t *gridptr)
 {
-  if ( gridptr->mask      ) Free(gridptr->mask);
-  if ( gridptr->mask_gme  ) Free(gridptr->mask_gme);
-  if ( gridptr->xvals     ) Free(gridptr->xvals);
-  if ( gridptr->yvals     ) Free(gridptr->yvals);
-  if ( gridptr->area      ) Free(gridptr->area);
-  if ( gridptr->xbounds   ) Free(gridptr->xbounds);
-  if ( gridptr->ybounds   ) Free(gridptr->ybounds);
-  if ( gridptr->rowlon    ) Free(gridptr->rowlon);
-  if ( gridptr->reference ) Free(gridptr->reference);
-  if ( gridptr->name      ) Free(gridptr->name);
+  void *p2free[] = { gridptr->mask, gridptr->mask_gme,
+                   gridptr->xvals, gridptr->yvals,
+                   gridptr->xbounds, gridptr->ybounds,
+                   gridptr->rowlon, gridptr->area,
+                   gridptr->reference, gridptr->name };
+  for (size_t i = 0; i < sizeof (p2free) / sizeof (p2free[0]); ++i)
+    if (p2free[i]) Free(p2free[i]);
+}
 
+void grid_free(grid_t *gridptr)
+{
+  grid_free_components(gridptr);
   grid_init(gridptr);
 }
 
@@ -186,14 +214,23 @@ void gridInit (void)
   if ( env ) GRID_Debug = atoi(env);
 }
 
-static
-void grid_copy(grid_t *gridptr2, grid_t *gridptr1)
+static void
+grid_copy_base_scalar_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
 {
-  int gridID2;
+  memcpy(gridptrDup, gridptrOrig, sizeof(grid_t));
+  gridptrDup->self = CDI_UNDEFID;
+  if (gridptrOrig->reference)
+    gridptrDup->reference = strdupx(gridptrOrig->reference);
+}
 
-  gridID2 = gridptr2->self;
-  memcpy(gridptr2, gridptr1, sizeof(grid_t));
-  gridptr2->self = gridID2;
+
+static grid_t *
+grid_copy_base(grid_t *gridptrOrig)
+{
+  grid_t *gridptrDup = (grid_t *)Malloc(sizeof (*gridptrDup));
+  gridptrOrig->vtable->copyScalarFields(gridptrOrig, gridptrDup);
+  gridptrOrig->vtable->copyArrayFields(gridptrOrig, gridptrDup);
+  return gridptrDup;
 }
 
 unsigned cdiGridCount(void)
@@ -201,8 +238,145 @@ unsigned cdiGridCount(void)
   return reshCountType(&gridOps);
 }
 
+static inline void
+gridSetXname(grid_t *gridptr, const char *xname)
+{
+  strncpy(gridptr->xname, xname, CDI_MAX_NAME);
+  gridptr->xname[CDI_MAX_NAME - 1] = 0;
+}
+
+static inline void
+gridSetXlongname(grid_t *gridptr, const char *xlongname)
+{
+  strncpy(gridptr->xlongname, xlongname, CDI_MAX_NAME);
+  gridptr->xlongname[CDI_MAX_NAME - 1] = 0;
+}
+
+static inline void
+gridSetXunits(grid_t *gridptr, const char *xunits)
+{
+  strncpy(gridptr->xunits, xunits, CDI_MAX_NAME);
+  gridptr->xunits[CDI_MAX_NAME - 1] = 0;
+}
+
+static inline void
+gridSetYname(grid_t *gridptr, const char *yname)
+{
+  strncpy(gridptr->yname, yname, CDI_MAX_NAME);
+  gridptr->yname[CDI_MAX_NAME - 1] = 0;
+}
+
+static inline void
+gridSetYlongname(grid_t *gridptr, const char *ylongname)
+{
+  strncpy(gridptr->ylongname, ylongname, CDI_MAX_NAME);
+  gridptr->ylongname[CDI_MAX_NAME - 1] = 0;
+}
+
+static inline void
+gridSetYunits(grid_t *gridptr, const char *yunits)
+{
+  strncpy(gridptr->yunits, yunits, CDI_MAX_NAME);
+  gridptr->yunits[CDI_MAX_NAME - 1] = 0;
+}
+
+void
+cdiGridTypeInit(grid_t *gridptr, int gridtype, int size)
+{
+
+  gridptr->type = gridtype;
+  gridptr->size = size;
+
+  switch (gridtype)
+    {
+    case GRID_CURVILINEAR:
+      gridptr->nvertex = 4;
+      /* Fall through */
+    case GRID_LONLAT:
+    case GRID_GAUSSIAN:
+    case GRID_GAUSSIAN_REDUCED:
+    case GRID_TRAJECTORY:
+      {
+        if ( gridtype == GRID_TRAJECTORY )
+          {
+            gridSetXname(gridptr, "tlon");
+            gridSetYname(gridptr, "tlat");
+          }
+        else
+          {
+            gridSetXname(gridptr, "lon");
+            gridSetYname(gridptr, "lat");
+          }
+        gridSetXlongname(gridptr, "longitude");
+        gridSetYlongname(gridptr, "latitude");
+
+        /*
+        if ( gridtype == GRID_CURVILINEAR )
+          {
+            gridptr->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
+            gridptr->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
+            gridDefXunits(gridID, "degrees");
+            gridDefYunits(gridID, "degrees");
+          }
+        else
+        */
+          {
+            gridptr->xstdname = xystdname_tab[grid_xystdname_latlon][0];
+            gridptr->ystdname = xystdname_tab[grid_xystdname_latlon][1];
+            gridSetXunits(gridptr, "degrees_east");
+            gridSetYunits(gridptr, "degrees_north");
+          }
+
+        break;
+      }
+    case GRID_UNSTRUCTURED:
+      gridptr->xsize = size;
+      /* Fall through */
+    case GRID_GME:
+      {
+        gridSetXname(gridptr, "lon");
+        gridSetYname(gridptr, "lat");
+        gridptr->xstdname = xystdname_tab[grid_xystdname_latlon][0];
+        gridptr->ystdname = xystdname_tab[grid_xystdname_latlon][1];
+        gridSetXunits(gridptr, "degrees_east");
+        gridSetYunits(gridptr, "degrees_north");
+        break;
+      }
+    case GRID_GENERIC:
+      {
+
+        /* gridptr->xsize = size; */
+        gridSetXname(gridptr, "x");
+        gridSetYname(gridptr, "y");
+        /*
+        strcpy(gridptr->xstdname, "grid_longitude");
+        strcpy(gridptr->ystdname, "grid_latitude");
+        gridptr->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
+        gridptr->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
+        gridDefXunits(gridID, "degrees");
+        gridDefYunits(gridID, "degrees");
+        */
+        break;
+      }
+    case GRID_LCC2:
+    case GRID_SINUSOIDAL:
+    case GRID_LAEA:
+      {
+        gridSetXname(gridptr, "x");
+        gridSetYname(gridptr, "y");
+        gridptr->xstdname = xystdname_tab[grid_xystdname_projection][0];
+        gridptr->ystdname = xystdname_tab[grid_xystdname_projection][1];
+        gridSetXunits(gridptr, "m");
+        gridSetYunits(gridptr, "m");
+        break;
+      }
+    }
+
+}
+
+
 // used also in CDO
-void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *xvals)
+void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *restrict xvals)
 {
   if ( (! (fabs(xinc) > 0)) && xsize > 1 )
     {
@@ -222,7 +396,7 @@ void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *x
 }
 
 static
-void calc_gaussgrid(double *yvals, int ysize, double yfirst, double ylast)
+void calc_gaussgrid(double *restrict yvals, int ysize, double yfirst, double ylast)
 {
   double *restrict yw = (double *) Malloc((size_t)ysize * sizeof(double));
   gaussaw(yvals, yw, (size_t)ysize);
@@ -243,7 +417,7 @@ void calc_gaussgrid(double *yvals, int ysize, double yfirst, double ylast)
 }
 
 // used also in CDO
-void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *yvals)
+void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
 {
   const double deleps = 0.002;
 
@@ -258,7 +432,7 @@ void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double y
 	      {
 		double *restrict ytmp = NULL;
 		int nstart, lfound = 0;
-		int ny = (int) (180./fabs(ylast-yfirst)/(ysize-1) + 0.5);
+		int ny = (int) (180./(fabs(ylast-yfirst)/(ysize-1)) + 0.5);
 		ny -= ny%2;
 		if ( ny > ysize && ny < 4096 )
 		  {
@@ -388,89 +562,7 @@ int gridCreate(int gridtype, int size)
 
   if ( CDI_Debug ) Message("gridID: %d", gridID);
 
-  gridptr->type = gridtype;
-  gridptr->size = size;
-
-  /*  if ( gridtype == GRID_GENERIC )     gridptr->xsize = size; */
-  if ( gridtype == GRID_UNSTRUCTURED )  gridptr->xsize = size;
-  if ( gridtype == GRID_CURVILINEAR  )  gridptr->nvertex = 4;
-
-  switch (gridtype)
-    {
-    case GRID_LONLAT:
-    case GRID_GAUSSIAN:
-    case GRID_GAUSSIAN_REDUCED:
-    case GRID_CURVILINEAR:
-    case GRID_TRAJECTORY:
-      {
-        if ( gridtype == GRID_TRAJECTORY )
-          {
-            gridDefXname(gridID, "tlon");
-            gridDefYname(gridID, "tlat");
-          }
-        else
-          {
-            gridDefXname(gridID, "lon");
-            gridDefYname(gridID, "lat");
-          }
-        gridDefXlongname(gridID, "longitude");
-        gridDefYlongname(gridID, "latitude");
-
-        /*
-        if ( gridtype == GRID_CURVILINEAR )
-          {
-            strcpy(gridptr->xstdname, "grid_longitude");
-            strcpy(gridptr->ystdname, "grid_latitude");
-            gridDefXunits(gridID, "degrees");
-            gridDefYunits(gridID, "degrees");
-          }
-        else
-        */
-          {
-            strcpy(gridptr->xstdname, "longitude");
-            strcpy(gridptr->ystdname, "latitude");
-            gridDefXunits(gridID, "degrees_east");
-            gridDefYunits(gridID, "degrees_north");
-          }
-
-        break;
-      }
-    case GRID_GME:
-    case GRID_UNSTRUCTURED:
-      {
-        gridDefXname(gridID, "lon");
-        gridDefYname(gridID, "lat");
-        strcpy(gridptr->xstdname, "longitude");
-        strcpy(gridptr->ystdname, "latitude");
-        gridDefXunits(gridID, "degrees_east");
-        gridDefYunits(gridID, "degrees_north");
-        break;
-      }
-    case GRID_GENERIC:
-      {
-        gridDefXname(gridID, "x");
-        gridDefYname(gridID, "y");
-        /*
-        strcpy(gridptr->xstdname, "grid_longitude");
-        strcpy(gridptr->ystdname, "grid_latitude");
-        gridDefXunits(gridID, "degrees");
-        gridDefYunits(gridID, "degrees");
-        */
-        break;
-      }
-    case GRID_LCC2:
-    case GRID_SINUSOIDAL:
-    case GRID_LAEA:
-      {
-        gridDefXname(gridID, "x");
-        gridDefYname(gridID, "y");
-        strcpy(gridptr->xstdname, "projection_x_coordinate");
-        strcpy(gridptr->ystdname, "projection_y_coordinate");
-        gridDefXunits(gridID, "m");
-        gridDefYunits(gridID, "m");
-        break;
-      }
-    }
+  cdiGridTypeInit(gridptr, gridtype, size);
 
   return (gridID);
 }
@@ -484,16 +576,7 @@ void gridDestroyKernel( grid_t * gridptr )
 
   id = gridptr->self;
 
-  if ( gridptr->mask      ) Free(gridptr->mask);
-  if ( gridptr->mask_gme  ) Free(gridptr->mask_gme);
-  if ( gridptr->xvals     ) Free(gridptr->xvals);
-  if ( gridptr->yvals     ) Free(gridptr->yvals);
-  if ( gridptr->area      ) Free(gridptr->area);
-  if ( gridptr->xbounds   ) Free(gridptr->xbounds);
-  if ( gridptr->ybounds   ) Free(gridptr->ybounds);
-  if ( gridptr->rowlon    ) Free(gridptr->rowlon);
-  if ( gridptr->reference ) Free(gridptr->reference);
-
+  grid_free_components(gridptr);
   Free( gridptr );
 
   reshRemove ( id, &gridOps );
@@ -512,13 +595,12 @@ void gridDestroyKernel( grid_t * gridptr )
 void gridDestroy(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  gridDestroyKernel ( gridptr );
+  gridptr->vtable->destroy(gridptr);
 }
 
 void gridDestroyP ( void * gridptr )
 {
-  gridDestroyKernel (( grid_t * ) gridptr );
+  ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
 }
 
 
@@ -553,16 +635,15 @@ The function @func{gridDefXname} defines the name of a X-axis.
 */
 void gridDefXname(int gridID, const char *xname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( xname )
+  if ( xname && *xname )
     {
-      strncpy(gridptr->xname, xname, CDI_MAX_NAME);
-      gridptr->xname[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetXname(gridptr, xname);
+      gridMark4Update(gridID);
     }
 }
 
+
 /*
 @Function  gridDefXlongname
 @Title     Define the longname of a X-axis
@@ -579,12 +660,11 @@ The function @func{gridDefXlongname} defines the longname of a X-axis.
 */
 void gridDefXlongname(int gridID, const char *xlongname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
   if ( xlongname )
     {
-      strncpy(gridptr->xlongname, xlongname, CDI_MAX_NAME);
-      gridptr->xlongname[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetXlongname(gridptr, xlongname);
+      gridMark4Update(gridID);
     }
 }
 
@@ -604,13 +684,11 @@ The function @func{gridDefXunits} defines the units of a X-axis.
 */
 void gridDefXunits(int gridID, const char *xunits)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
   if ( xunits )
     {
-      strncpy(gridptr->xunits, xunits, CDI_MAX_NAME);
-      gridptr->xunits[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetXunits(gridptr, xunits);
+      gridMark4Update(gridID);
     }
 }
 
@@ -630,13 +708,11 @@ The function @func{gridDefYname} defines the name of a Y-axis.
 */
 void gridDefYname(int gridID, const char *yname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( yname )
+  if ( yname && *yname )
     {
-      strncpy(gridptr->yname, yname, CDI_MAX_NAME);
-      gridptr->yname[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetYname(gridptr, yname);
+      gridMark4Update(gridID);
     }
 }
 
@@ -656,13 +732,11 @@ The function @func{gridDefYlongname} defines the longname of a Y-axis.
 */
 void gridDefYlongname(int gridID, const char *ylongname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
   if ( ylongname )
     {
-      strncpy(gridptr->ylongname, ylongname, CDI_MAX_NAME);
-      gridptr->ylongname[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetYlongname(gridptr, ylongname);
+      gridMark4Update(gridID);
     }
 }
 
@@ -682,13 +756,11 @@ The function @func{gridDefYunits} defines the units of a Y-axis.
 */
 void gridDefYunits(int gridID, const char *yunits)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
   if ( yunits )
     {
-      strncpy(gridptr->yunits, yunits, CDI_MAX_NAME);
-      gridptr->yunits[CDI_MAX_NAME - 1] = 0;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      grid_t *gridptr = gridID2Ptr(gridID);
+      gridSetYunits(gridptr, yunits);
+      gridMark4Update(gridID);
     }
 }
 
@@ -774,8 +846,10 @@ void gridInqXunits(int gridID, char *xunits)
 void gridInqXstdname(int gridID, char *xstdname)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  strcpy(xstdname, gridptr->xstdname);
+  if ( gridptr->xstdname )
+    strcpy(xstdname, gridptr->xstdname);
+  else
+    xstdname[0] = 0;
 }
 
 /*
@@ -859,8 +933,10 @@ void gridInqYunits(int gridID, char *yunits)
 void gridInqYstdname(int gridID, char *ystdname)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  strcpy(ystdname, gridptr->ystdname);
+  if ( gridptr->ystdname )
+    strcpy(ystdname, gridptr->ystdname);
+  else
+    ystdname[0] = 0;
 }
 
 /*
@@ -921,7 +997,7 @@ int gridInqSize(int gridID)
       ysize = gridptr->ysize;
 
       if ( ysize )
-        size = xsize *ysize;
+        size = xsize * ysize;
       else
         size = xsize;
 
@@ -969,7 +1045,7 @@ void gridDefTrunc(int gridID, int trunc)
 
   if (gridptr->trunc != trunc)
     {
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
       gridptr->trunc = trunc;
     }
 }
@@ -996,16 +1072,17 @@ void gridDefXsize(int gridID, int xsize)
   if ( xsize > gridSize )
     Error("xsize %d is greater then gridsize %d", xsize, gridSize);
 
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED && xsize != gridSize )
+  int gridType = gridInqType(gridID);
+  if ( gridType == GRID_UNSTRUCTURED && xsize != gridSize )
     Error("xsize %d must be equal to gridsize %d for gridtype: UNSTRUCTURED", xsize, gridSize);
 
   if (gridptr->xsize != xsize)
     {
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
       gridptr->xsize = xsize;
     }
 
-  if ( gridInqType(gridID) != GRID_UNSTRUCTURED )
+  if ( gridType != GRID_UNSTRUCTURED )
     {
       long axisproduct = gridptr->xsize*gridptr->ysize;
       if ( axisproduct > 0 && axisproduct != gridSize )
@@ -1030,7 +1107,7 @@ void gridDefPrec(int gridID, int prec)
 
   if (gridptr->prec != prec)
     {
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
       gridptr->prec = prec;
     }
 }
@@ -1103,7 +1180,7 @@ void gridDefYsize(int gridID, int ysize)
 
   if (gridptr->ysize != ysize)
     {
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
       gridptr->ysize = ysize;
     }
 
@@ -1160,7 +1237,7 @@ void gridDefNP(int gridID, int np)
 
   if (gridptr->np != np)
     {
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
       gridptr->np = np;
     }
 }
@@ -1206,7 +1283,7 @@ void gridDefRowlon(int gridID, int nrowlon, const int rowlon[])
   gridptr->rowlon = (int *) Malloc((size_t)nrowlon * sizeof(int));
   gridptr->nrowlon = nrowlon;
   memcpy(gridptr->rowlon, rowlon, (size_t)nrowlon * sizeof(int));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+  gridMark4Update(gridID);
 }
 
 /*
@@ -1228,34 +1305,48 @@ void gridInqRowlon(int gridID, int *rowlon)
   memcpy(rowlon, gridptr->rowlon, (size_t)gridptr->nrowlon * sizeof(int));
 }
 
-
-int gridInqMask(int gridID, int *mask)
+static int
+gridInqMaskSerialGeneric(grid_t *gridptr, mask_t **internalMask,
+                        int *restrict mask)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
   long size = gridptr->size;
 
   if ( CDI_Debug && size == 0 )
-    Warning("Size undefined for gridID = %d", gridID);
+    Warning("Size undefined for gridID = %d", gridptr->self);
 
-  if (mask && gridptr->mask)
-    for (long i = 0; i < size; ++i)
-      mask[i] = (int)gridptr->mask[i];
-
-  if ( gridptr->mask == NULL ) size = 0;
+  const mask_t *restrict mask_src = *internalMask;
+  if (mask_src)
+    {
+      if (mask && size > 0)
+        for (size_t i = 0; i < (size_t)size; ++i)
+          mask[i] = (int)mask_src[i];
+    }
+  else
+    size = 0;
 
   return (int)size;
 }
 
+static int
+gridInqMaskSerial(grid_t *gridptr, int *mask)
+{
+  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask, mask);
+}
+
 
-void gridDefMask(int gridID, const int *mask)
+int gridInqMask(int gridID, int *mask)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqMask(gridptr, mask);
+}
 
+static void
+gridDefMaskSerial(grid_t *gridptr, const int *mask)
+{
   long size = gridptr->size;
 
   if ( size == 0 )
-    Error("Size undefined for gridID = %d", gridID);
+    Error("Size undefined for gridID = %d", gridptr->self);
 
   if ( mask == NULL )
     {
@@ -1277,34 +1368,32 @@ void gridDefMask(int gridID, const int *mask)
     }
 }
 
-
-int gridInqMaskGME(int gridID, int *mask)
+void gridDefMask(int gridID, const int *mask)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  long size = gridptr->size;
-
-  if ( CDI_Debug && size == 0 )
-    Warning("Size undefined for gridID = %d", gridID);
-
-  if ( mask && gridptr->mask_gme )
-    for (long i = 0; i < size; ++i)
-      mask[i] = (int)gridptr->mask_gme[i];
-
-  if ( gridptr->mask_gme == NULL ) size = 0;
-
-  return (int)size;
+  gridptr->vtable->defMask(gridptr, mask);
+  gridMark4Update(gridID);
 }
 
+static int
+gridInqMaskGMESerial(grid_t *gridptr, int *mask_gme)
+{
+  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask_gme, mask_gme);
+}
 
-void gridDefMaskGME(int gridID, const int *mask)
+int gridInqMaskGME(int gridID, int *mask)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqMaskGME(gridptr, mask);
+}
 
+static void
+gridDefMaskGMESerial(grid_t *gridptr, const int *mask)
+{
   long size = gridptr->size;
 
   if ( size == 0 )
-    Error("Size undefined for gridID = %d", gridID);
+    Error("Size undefined for gridID = %d", gridptr->self);
 
   if ( gridptr->mask_gme == NULL )
     gridptr->mask_gme = (mask_t *) Malloc((size_t)size * sizeof (mask_t));
@@ -1315,6 +1404,41 @@ void gridDefMaskGME(int gridID, const int *mask)
     gridptr->mask_gme[i] = (mask_t)(mask[i] != 0);
 }
 
+void gridDefMaskGME(int gridID, const int *mask)
+{
+  grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defMaskGME(gridptr, mask);
+  gridMark4Update(gridID);
+}
+
+
+static int
+gridInqXValsSerial(grid_t *gridptr, double *xvals)
+{
+  long size;
+  if ( gridptr->type == GRID_CURVILINEAR || gridptr->type == GRID_UNSTRUCTURED )
+    size = gridptr->size;
+  else if ( gridptr->type == GRID_GAUSSIAN_REDUCED )
+    size = 2;
+  else
+    size = gridptr->xsize;
+
+  if ( CDI_Debug && size == 0 )
+    Warning("size undefined for gridID = %d", gridptr->self);
+
+  if ( gridptr->xvals )
+    {
+      if ( size && xvals )
+        {
+          const double *gridptr_xvals = gridptr->vtable->inqXValsPtr(gridptr);
+          memcpy(xvals, gridptr_xvals, (size_t)size * sizeof (double));
+        }
+    }
+  else
+    size = 0;
+  return (int)size;
+}
+
 /*
 @Function  gridInqXvals
 @Title     Get all values of a X-axis
@@ -1338,24 +1462,31 @@ Otherwise, 0 is returned and @func{xvals} is empty.
 int gridInqXvals(int gridID, double *xvals)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqXVals(gridptr, xvals);
+}
+
+
+static void
+gridDefXValsSerial(grid_t *gridptr, const double *xvals)
+{
+  int gridtype = gridptr->type;
 
   long size;
-  if ( gridptr->type == GRID_CURVILINEAR || gridptr->type == GRID_UNSTRUCTURED )
+  if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
     size = gridptr->size;
-  else if ( gridptr->type == GRID_GAUSSIAN_REDUCED )
+  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
     size = 2;
   else
     size = gridptr->xsize;
 
-  if ( CDI_Debug && size == 0 )
-    Warning("size undefined for gridID = %d", gridID);
-
-  if ( size && xvals && gridptr->xvals )
-    memcpy(xvals, gridptr->xvals, (size_t)size * sizeof (double));
-
-  if ( gridptr->xvals == NULL ) size = 0;
+  if ( size == 0 )
+    Error("Size undefined for gridID = %d", gridptr->self);
 
-  return (int)size;
+  if (gridptr->xvals && CDI_Debug)
+    Warning("values already defined!");
+  gridptr->xvals = (double *)Realloc(gridptr->xvals,
+                                      (size_t)size * sizeof(double));
+  memcpy(gridptr->xvals, xvals, (size_t)size * sizeof (double));
 }
 
 /*
@@ -1375,26 +1506,33 @@ The function @func{gridDefXvals} defines all values of the X-axis.
 void gridDefXvals(int gridID, const double *xvals)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defXVals(gridptr, xvals);
+  gridMark4Update(gridID);
+}
+
+static int
+gridInqYValsSerial(grid_t *gridptr, double *yvals)
+{
   int gridtype = gridptr->type;
+  long size
+    = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
+    ? gridptr->size : gridptr->ysize;
 
-  long size;
+  if ( CDI_Debug && size == 0 )
+    Warning("size undefined for gridID = %d!", gridptr->self);
 
-  if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
-    size = gridptr->size;
-  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
-    size = 2;
+  if ( gridptr->yvals )
+    {
+      if ( size && yvals )
+        {
+          const double *gridptr_yvals = gridptr->vtable->inqYValsPtr(gridptr);
+          memcpy(yvals, gridptr_yvals, (size_t)size * sizeof (double));
+        }
+    }
   else
-    size = gridptr->xsize;
-
-  if ( size == 0 )
-    Error("Size undefined for gridID = %d", gridID);
+    size = 0;
 
-  if (gridptr->xvals && CDI_Debug)
-    Warning("values already defined!");
-  gridptr->xvals = (double *) Realloc(gridptr->xvals,
-                                      (size_t)size * sizeof(double));
-  memcpy(gridptr->xvals, xvals, (size_t)size * sizeof (double));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+  return (int)size;
 }
 
 /*
@@ -1420,23 +1558,28 @@ Otherwise, 0 is returned and @func{yvals} is empty.
 int gridInqYvals(int gridID, double *yvals)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqYVals(gridptr, yvals);
+}
 
+static void
+gridDefYValsSerial(grid_t *gridptr, const double *yvals)
+{
   int gridtype = gridptr->type;
   long size
     = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
     ? gridptr->size : gridptr->ysize;
 
-  if ( CDI_Debug && size == 0 )
-    Warning("size undefined for gridID = %d!", gridID);
-
-  if ( size && yvals && gridptr->yvals )
-    memcpy(yvals, gridptr->yvals, (size_t)size * sizeof (double));
+  if ( size == 0 )
+    Error("Size undefined for gridID = %d!", gridptr->self);
 
-  if ( gridptr->yvals == NULL ) size = 0;
+  if (gridptr->yvals && CDI_Debug)
+    Warning("Values already defined!");
 
-  return (int)size;
+  gridptr->yvals = (double *)Realloc(gridptr->yvals, (size_t)size * sizeof (double));
+  memcpy(gridptr->yvals, yvals, (size_t)size * sizeof (double));
 }
 
+
 /*
 @Function  gridDefYvals
 @Title     Define the values of a Y-axis
@@ -1454,32 +1597,29 @@ The function @func{gridDefYvals} defines all values of the Y-axis.
 void gridDefYvals(int gridID, const double *yvals)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defYVals(gridptr, yvals);
+  gridMark4Update(gridID);
+}
 
-  int gridtype = gridptr->type;
-  long size
-    = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
-    ? gridptr->size : gridptr->ysize;
-
-  if ( size == 0 )
-    Error("Size undefined for gridID = %d!", gridID);
-
-  if (gridptr->yvals && CDI_Debug)
-    Warning("Values already defined!");
-
-  gridptr->yvals = (double *) Realloc(gridptr->yvals, (size_t)size * sizeof (double));
-  memcpy(gridptr->yvals, yvals, (size_t)size * sizeof (double));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+static double
+gridInqXValSerial(grid_t *gridptr, int index)
+{
+  double xval = gridptr->xvals ? gridptr->xvals[index] : 0;
+  return xval;
 }
 
 
 double gridInqXval(int gridID, int index)
 {
-  double xval = 0;
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqXVal(gridptr, index);
+}
 
-  if ( gridptr->xvals ) xval = gridptr->xvals[index];
-
-  return xval;
+static double
+gridInqYValSerial(grid_t *gridptr, int index)
+{
+  double yval = gridptr->yvals ? gridptr->yvals[index] : 0;
+  return yval;
 }
 
 /*
@@ -1494,12 +1634,8 @@ double gridInqXval(int gridID, int index)
 */
 double gridInqYval(int gridID, int index)
 {
-  double yval = 0;
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( gridptr->yvals ) yval = gridptr->yvals[index];
-
-  return yval;
+  return gridptr->vtable->inqYVal(gridptr, index);
 }
 
 /*
@@ -1516,7 +1652,7 @@ double gridInqXinc(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
   double xinc = gridptr->xinc;
-  const double *restrict xvals = gridptr->xvals;
+  const double *restrict xvals = gridptr->vtable->inqXValsPtr(gridptr);
 
   if ( (! (fabs(xinc) > 0)) && xvals )
     {
@@ -1524,7 +1660,7 @@ double gridInqXinc(int gridID)
       if ( xsize > 1 )
         {
           xinc = fabs(xvals[xsize-1] - xvals[0])/(xsize-1);
-          for ( size_t i = 2; i < (size_t)xsize; i++ )
+          for (size_t i = 2; i < (size_t)xsize; i++ )
             if ( fabs(fabs(xvals[i-1] - xvals[i]) - xinc) > 0.01*xinc )
               {
                 xinc = 0;
@@ -1552,7 +1688,7 @@ double gridInqYinc(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
   double yinc = gridptr->yinc;
-  const double *yvals = gridptr->yvals;
+  const double *yvals = gridptr->vtable->inqYValsPtr(gridptr);
 
   if ( (! (fabs(yinc) > 0)) && yvals )
     {
@@ -1561,8 +1697,8 @@ double gridInqYinc(int gridID)
         {
           yinc = yvals[1] - yvals[0];
           double abs_yinc = fabs(yinc);
-          for ( size_t i = 2; i < (size_t)ysize; i++ )
-            if ( fabs(fabs(yvals[i] - yvals[i-1]) - abs_yinc) > (0.01*abs_yinc))
+          for (size_t i = 2; i < (size_t)ysize; i++ )
+            if ( fabs(fabs(yvals[i] - yvals[i-1]) - abs_yinc) > (0.01*abs_yinc) )
               {
                 yinc = 0;
                 break;
@@ -1608,14 +1744,14 @@ void gridDefXpole(int gridID, double xpole)
   // Xpole -> grid_north_pole_longitude
   grid_t *gridptr = gridID2Ptr(gridID);
 
-  if ( memcmp(gridptr->xstdname, "grid", 4) != 0 )
-    strcpy(gridptr->xstdname, "grid_longitude");
+  if ( gridptr->xstdname && memcmp(gridptr->xstdname, "grid", 4) != 0 )
+    gridptr->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
 
   if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->xpole, xpole) )
     {
       gridptr->isRotated = TRUE;
       gridptr->xpole = xpole;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -1652,14 +1788,14 @@ void gridDefYpole(int gridID, double ypole)
   // Ypole -> grid_north_pole_latitude
   grid_t *gridptr = gridID2Ptr(gridID);
 
-  if ( memcmp(gridptr->ystdname, "grid", 4) != 0 )
-    strcpy(gridptr->ystdname, "grid_latitude");
+  if ( gridptr->ystdname && memcmp(gridptr->ystdname, "grid", 4) != 0 )
+    gridptr->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
 
   if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->ypole, ypole) )
     {
       gridptr->isRotated = TRUE;
       gridptr->ypole = ypole;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -1700,7 +1836,7 @@ void gridDefAngle(int gridID, double angle)
     {
       gridptr->isRotated = TRUE;
       gridptr->angle = angle;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -1738,7 +1874,7 @@ void gridDefGMEnd(int gridID, int nd)
   if (gridptr->nd != nd)
     {
       gridptr->nd = nd;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -1776,7 +1912,7 @@ void gridDefGMEni(int gridID, int ni)
   if (gridptr->ni != ni)
     {
       gridptr->ni = ni;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -1814,7 +1950,7 @@ void gridDefGMEni2(int gridID, int ni2)
   if (gridptr->ni2 != ni2)
     {
       gridptr->ni2 = ni2;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -1842,7 +1978,7 @@ void gridDefGMEni3(int gridID, int ni3)
   if (gridptr->ni3 != ni3)
     {
       gridptr->ni3 = ni3;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -1866,7 +2002,7 @@ void gridChangeType(int gridID, int gridtype)
   if (gridptr->type != gridtype)
     {
       gridptr->type = gridtype;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -1874,18 +2010,20 @@ static
 void grid_check_cyclic(grid_t *gridptr)
 {
   gridptr->isCyclic = FALSE;
-
-  int xsize = gridptr->xsize,
-    ysize = gridptr->ysize;
-  const double *xvals = gridptr->xvals,
-    *xbounds = gridptr->xbounds;
+  enum { numVertices = 4 };
+  size_t xsize = gridptr->xsize >= 0 ? (size_t)gridptr->xsize : 0,
+    ysize = gridptr->ysize >= 0 ? (size_t)gridptr->ysize : 0;
+  const double *xvals = gridptr->vtable->inqXValsPtr(gridptr),
+    (*xbounds)[numVertices]
+    = (const double (*)[numVertices])gridptr->vtable->inqXBoundsPtr(gridptr);
 
   if ( gridptr->type == GRID_GAUSSIAN || gridptr->type == GRID_LONLAT )
     {
       if ( xvals && xsize > 1 )
         {
           double xinc = xvals[1] - xvals[0];
-          if ( IS_EQUAL(xinc, 0) ) xinc = (xvals[xsize-1] - xvals[0])/(xsize-1);
+          if ( IS_EQUAL(xinc, 0) )
+            xinc = (xvals[xsize-1] - xvals[0])/(double)(xsize-1);
 
           double x0 = 2*xvals[xsize-1]-xvals[xsize-2]-360;
 
@@ -1897,10 +2035,10 @@ void grid_check_cyclic(grid_t *gridptr)
     {
       if ( xvals && xsize > 1 )
         {
-          long nc = 0;
-          for ( int j = 0; j < ysize; ++j )
+          size_t nc = 0;
+          for ( size_t j = 0; j < ysize; ++j )
             {
-              long i1 = j*xsize,
+              size_t i1 = j*xsize,
                 i2 = j*xsize+1,
                 in = j*xsize+(xsize-1);
               double val1 = xvals[i1],
@@ -1919,23 +2057,22 @@ void grid_check_cyclic(grid_t *gridptr)
 
               nc += fabs(x0-val1) < 0.5*xinc;
             }
-          gridptr->isCyclic = nc > 0.5*ysize ? TRUE : FALSE;
+          gridptr->isCyclic = nc > ysize/2 ? TRUE : FALSE;
         }
 
       if ( xbounds && xsize > 1 )
 	{
-          gridptr->isCyclic = TRUE;
-	  for ( int j = 0; j < ysize; ++j )
+          short isCyclic = TRUE;
+	  for ( size_t j = 0; j < ysize; ++j )
 	    {
-	      long i1 = j*xsize*4,
-                i2 = j*xsize*4+(xsize-1)*4;
-	      long nc = 0;
-	      for (unsigned k1 = 0; k1 < 4; ++k1 )
+	      size_t i1 = j*xsize,
+                i2 = j*xsize+(xsize-1);
+	      for (size_t k1 = 0; k1 < numVertices; ++k1 )
 		{
-		  double val1 = xbounds[i1+k1];
-		  for (unsigned k2 = 0; k2 < 4; ++k2 )
+		  double val1 = xbounds[i1][k1];
+		  for (size_t k2 = 0; k2 < numVertices; ++k2 )
 		    {
-		      double val2 = xbounds[i2+k2];
+		      double val2 = xbounds[i2][k2];
 
 		      if ( val1 <    1 && val2 > 300 ) val1 += 360;
 		      if ( val2 <    1 && val1 > 300 ) val2 += 360;
@@ -1944,19 +2081,16 @@ void grid_check_cyclic(grid_t *gridptr)
                       if ( fabs(val2-val1) > 180 ) val1 += 360;
 
 		      if ( fabs(val1-val2) < 0.001 )
-			{
-			  nc++;
-			  break;
-			}
+                        goto foundCloseVertices;
 		    }
 		}
-
-	      if ( nc < 1 )
-		{
-		  gridptr->isCyclic = FALSE;
-		  break;
-		}
+              /* all vertices more than 0.001 degrees apart */
+              isCyclic = FALSE;
+              break;
+              foundCloseVertices:
+              ;
 	    }
+          gridptr->isCyclic = isCyclic;
 	}
     }
 }
@@ -1980,67 +2114,60 @@ int gridIsRotated(int gridID)
 }
 
 static
-int compareXYvals(int gridID, long xsize, long ysize, double *xvals0, double *yvals0)
+int compareXYvals(grid_t *gridRef, grid_t *gridTest)
 {
-  long i;
   int differ = 0;
 
-  if ( !differ && xsize == gridInqXvals(gridID, NULL) )
+  int xsizeTest = gridTest->xsize, ysizeTest = gridTest->ysize;
+  if ( !differ && xsizeTest > 0 && xsizeTest == gridRef->vtable->inqXVals(gridRef, NULL) )
     {
-      double *xvals = (double *) Malloc((size_t)xsize * sizeof (double));
-
-      gridInqXvals(gridID, xvals);
+      const double *restrict xvalsRef = gridRef->vtable->inqXValsPtr(gridRef),
+        *restrict xvalsTest = gridTest->vtable->inqXValsPtr(gridTest);
 
-      for ( i = 0; i < xsize; ++i )
-	if ( fabs(xvals0[i] - xvals[i]) > 1.e-10 )
+      for ( size_t i = 0; i < (size_t)xsizeTest; ++i )
+	if ( fabs(xvalsTest[i] - xvalsRef[i]) > 1.e-10 )
 	  {
 	    differ = 1;
 	    break;
 	  }
-
-      Free(xvals);
     }
 
-  if ( !differ && ysize == gridInqYvals(gridID, NULL) )
+  if ( !differ && ysizeTest > 0 && ysizeTest == gridRef->vtable->inqYVals(gridRef, NULL) )
     {
-      double *yvals = (double *) Malloc((size_t)ysize * sizeof (double));
-
-      gridInqYvals(gridID, yvals);
-
-      for ( i = 0; i < ysize; ++i )
-	if ( fabs(yvals0[i] - yvals[i]) > 1.e-10 )
+      const double *restrict yvalsRef = gridRef->vtable->inqYValsPtr(gridRef),
+        *restrict yvalsTest = gridTest->vtable->inqYValsPtr(gridTest);
+      for ( size_t i = 0; i < (size_t)ysizeTest; ++i )
+	if ( fabs(yvalsTest[i] - yvalsRef[i]) > 1.e-10 )
 	  {
 	    differ = 1;
 	    break;
 	  }
-
-      Free(yvals);
     }
 
   return (differ);
 }
 
 static
-int compareXYvals2(int gridID, int gridsize, double *xvals, double *yvals)
+int compareXYvals2(grid_t *gridRef, grid_t *gridTest)
 {
-  int differ = 0;
+  int gridsize = gridTest->size;
+  int differ
+    = ((gridTest->xvals == NULL) ^ (gridRef->xvals == NULL))
+    || ((gridTest->yvals == NULL) ^ (gridRef->yvals == NULL));
 
-  if ( !differ && ((xvals == NULL && gridInqXvalsPtr(gridID) != NULL) || (xvals != NULL && gridInqXvalsPtr(gridID) == NULL)) ) differ = 1;
-  if ( !differ && ((yvals == NULL && gridInqYvalsPtr(gridID) != NULL) || (yvals != NULL && gridInqYvalsPtr(gridID) == NULL)) ) differ = 1;
+  typedef double (*inqVal)(grid_t *grid, int index);
+  inqVal inqXValRef = gridRef->vtable->inqXVal,
+    inqYValRef = gridRef->vtable->inqXVal,
+    inqXValTest = gridTest->vtable->inqXVal,
+    inqYValTest = gridTest->vtable->inqYVal;
 
-  if ( !differ && xvals && gridInqXvalsPtr(gridID) )
-    {
-      if ( fabs(xvals[0] - gridInqXval(gridID, 0)) > 1.e-9 ||
-	   fabs(xvals[gridsize-1] - gridInqXval(gridID, gridsize-1)) > 1.e-9 )
-	differ = 1;
-    }
+  if ( !differ && gridTest->xvals )
+    differ = fabs(inqXValTest(gridTest, 0) - inqXValRef(gridRef, 0)) > 1.e-9
+      || fabs(inqXValTest(gridTest, gridsize-1) - inqXValRef(gridRef, gridsize-1)) > 1.e-9;
 
-  if ( !differ && yvals && gridInqYvalsPtr(gridID) )
-    {
-      if ( fabs(yvals[0] - gridInqYval(gridID, 0)) > 1.e-9 ||
-	   fabs(yvals[gridsize-1] - gridInqYval(gridID, gridsize-1)) > 1.e-9 )
-	differ = 1;
-    }
+  if ( !differ && gridTest->yvals )
+    differ = fabs(inqYValTest(gridTest, 0) - inqYValRef(gridRef, 0)) > 1.e-9
+      || fabs(inqYValTest(gridTest, gridsize-1) - inqYValRef(gridRef, gridsize-1)) > 1.e-9;
 
   return differ;
 }
@@ -2049,10 +2176,11 @@ int compareXYvals2(int gridID, int gridsize, double *xvals, double *yvals)
 int gridCompare(int gridID, const grid_t *grid)
 {
   int differ = 1;
+  grid_t *gridRef = gridID2Ptr(gridID);
 
-  if ( grid->type == gridInqType(gridID) || grid->type == GRID_GENERIC )
+  if ( grid->type == gridRef->type || grid->type == GRID_GENERIC )
     {
-      if ( grid->size == gridInqSize(gridID) )
+      if ( grid->size == gridRef->size )
 	{
 	  differ = 0;
 	  if ( grid->type == GRID_LONLAT )
@@ -2072,7 +2200,7 @@ int gridCompare(int gridID, const grid_t *grid)
 	      printf("grid.xinc   %f\n", gridInqXinc(gridID));
 	      printf("grid.yinc   %f\n", gridInqYinc(gridID));
 	      */
-	      if ( grid->xsize == gridInqXsize(gridID) && grid->ysize == gridInqYsize(gridID) )
+	      if ( grid->xsize == gridRef->xsize && grid->ysize == grid->ysize )
 		{
 		  if ( grid->xdef == 2 && grid->ydef == 2 )
 		    {
@@ -2086,38 +2214,33 @@ int gridCompare(int gridID, const grid_t *grid)
 			      differ = 1;
 			    }
 			  if ( !differ && fabs(grid->xinc) > 0 &&
-			       fabs(fabs(grid->xinc) - fabs(gridInqXinc(gridID))) > fabs(grid->xinc/1000))
+			       fabs(fabs(grid->xinc) - fabs(gridRef->xinc)) > fabs(grid->xinc/1000))
 			    {
 			      differ = 1;
 			    }
 			  if ( !differ && fabs(grid->yinc) > 0 &&
-			       fabs(fabs(grid->yinc) - fabs(gridInqYinc(gridID))) > fabs(grid->yinc/1000))
+			       fabs(fabs(grid->yinc) - fabs(gridRef->yinc)) > fabs(grid->yinc/1000))
 			    {
 			      differ = 1;
 			    }
 			}
 		    }
-		  else
-		    {
-		      if ( grid->xvals && grid->yvals )
-			differ = compareXYvals(gridID, grid->xsize, grid->ysize, grid->xvals, grid->yvals);
-		    }
+		  else if ( grid->xvals && grid->yvals )
+                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
 		}
 	      else
 		differ = 1;
 	    }
 	  else if ( grid->type == GRID_GENERIC )
 	    {
-	      if ( grid->xsize == gridInqXsize(gridID) && grid->ysize == gridInqYsize(gridID) )
+	      if ( grid->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
 		{
-		  if ( grid->xdef == 1 && grid->ydef == 1 )
-		    {
-		      if ( grid->xvals && grid->yvals )
-			differ = compareXYvals(gridID, grid->xsize, grid->ysize, grid->xvals, grid->yvals);
-		    }
+		  if ( grid->xdef == 1 && grid->ydef == 1
+                       && grid->xvals && grid->yvals )
+                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
 		}
 	      else if ( (grid->ysize == 0 || grid->ysize == 1) &&
-			grid->xsize == gridInqXsize(gridID)*gridInqYsize(gridID) )
+			grid->xsize == gridRef->xsize*gridRef->ysize )
 		{
 		}
 	      else
@@ -2125,7 +2248,7 @@ int gridCompare(int gridID, const grid_t *grid)
 	    }
 	  else if ( grid->type == GRID_GAUSSIAN )
 	    {
-	      if ( grid->xsize == gridInqXsize(gridID) && grid->ysize == gridInqYsize(gridID) )
+	      if ( grid->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
 		{
 		  if ( grid->xdef == 2 && grid->ydef == 2 )
 		    {
@@ -2133,16 +2256,13 @@ int gridCompare(int gridID, const grid_t *grid)
 			   ! (IS_EQUAL(grid->yfirst, 0) && IS_EQUAL(grid->ylast, 0)) )
 			if ( fabs(grid->xfirst - gridInqXval(gridID, 0)) > 0.0015 ||
 			     fabs(grid->yfirst - gridInqYval(gridID, 0)) > 0.0015 ||
-			     (fabs(grid->xinc)>0 && fabs(fabs(grid->xinc) - fabs(gridInqXinc(gridID))) > fabs(grid->xinc/1000)) )
+			     (fabs(grid->xinc)>0 && fabs(fabs(grid->xinc) - fabs(gridRef->xinc)) > fabs(grid->xinc/1000)) )
 			  {
 			    differ = 1;
 			  }
 		    }
-		  else
-		    {
-		      if ( grid->xvals && grid->yvals )
-			differ = compareXYvals(gridID, grid->xsize, grid->ysize, grid->xvals, grid->yvals);
-		    }
+		  else if ( grid->xvals && grid->yvals )
+                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
 		}
 	      else
 		differ = 1;
@@ -2164,31 +2284,36 @@ int gridCompare(int gridID, const grid_t *grid)
 	      printf("grid.nv     %d\n", grid->nvertex);
 	      printf("grid nv     %d\n", gridInqNvertex(gridID));
 	      */
-	      if ( grid->xsize == gridInqXsize(gridID) && grid->ysize == gridInqYsize(gridID) )
-		differ = compareXYvals2(gridID, grid->size, grid->xvals, grid->yvals);
+	      if ( grid->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
+                differ = gridRef->vtable->compareXYAO(gridRef, (grid_t *)grid);
 	    }
 	  else if ( grid->type == GRID_UNSTRUCTURED )
 	    {
-              unsigned char uuidOfHGrid[CDI_UUID_SIZE];
-              gridInqUUID(gridID, uuidOfHGrid);
-
-              if ( !differ && uuidOfHGrid[0] && grid->uuid[0] && memcmp(uuidOfHGrid, grid->uuid, CDI_UUID_SIZE) != 0 ) differ = 1;
+              /* FIXME: not octet 0 but octet 7 is guaranteed  non-zero
+               * for any non-NULL UUID */
+              differ = differ || ( gridRef->uuid[0] && grid->uuid[0] && memcmp(gridRef->uuid, grid->uuid, CDI_UUID_SIZE) != 0 );
 
               if ( !differ &&
-                   ((grid->xvals == NULL && gridInqXvalsPtr(gridID) != NULL) || (grid->xvals != NULL && gridInqXvalsPtr(gridID) == NULL)) &&
-                   ((grid->yvals == NULL && gridInqYvalsPtr(gridID) != NULL) || (grid->yvals != NULL && gridInqYvalsPtr(gridID) == NULL)) )
+                   ((grid->xvals == NULL) ^ (gridRef->xvals == NULL)) &&
+                   ((grid->yvals == NULL) ^ (gridRef->yvals == NULL)) )
                 {
-                  if ( !differ && grid->nvertex && gridInqNvertex(gridID) && grid->nvertex != gridInqNvertex(gridID) ) differ = 1;
-                  if ( !differ && grid->number && gridInqNumber(gridID) && grid->number != gridInqNumber(gridID) ) differ = 1;
-                  if ( !differ && grid->number && gridInqNumber(gridID) && grid->position != gridInqPosition(gridID) ) differ = 1;
+                  int nvertexA, nvertexB, numberA, numberB;
+                  differ = ( (nvertexA = grid->nvertex)
+                             && (nvertexB = gridRef->nvertex)
+                             && (nvertexA != nvertexB) )
+                    || (numberA = grid->number, numberB = gridRef->number,
+                        ( (numberA)
+                          && numberB
+                          && (numberA != numberB) )
+                        || ( (numberA && numberB)
+                             && (grid->position) != (gridRef->position) ) );
                 }
-              else
+              else if ( !differ )
                 {
-                  if ( !differ && grid->nvertex != gridInqNvertex(gridID) ) differ = 1;
-                  if ( !differ && grid->number != gridInqNumber(gridID) ) differ = 1;
-                  if ( !differ && grid->number > 0 && grid->position != gridInqPosition(gridID) ) differ = 1;
-                  if ( !differ )
-                    differ = compareXYvals2(gridID, grid->size, grid->xvals, grid->yvals);
+                  differ = grid->nvertex != gridRef->nvertex
+                    || grid->number != gridRef->number
+                    || (grid->number > 0 && grid->position != gridRef->position)
+                    || gridRef->vtable->compareXYAO(gridRef, (grid_t *)grid);
                 }
               }
 	}
@@ -2232,7 +2357,6 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
   if ( g1->size          != g2->size         ) return differ;
   if ( g1->xsize         != g2->xsize        ) return differ;
   if ( g1->ysize         != g2->ysize        ) return differ;
-  if ( g1->locked        != g2->locked       ) return differ;
   if ( g1->lcomplex      != g2->lcomplex     ) return differ;
 
   if ( g1->rowlon )
@@ -2268,23 +2392,27 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
   if ( IS_NOT_EQUAL(g1->ypole         , g2->ypole)         ) return differ;
   if ( IS_NOT_EQUAL(g1->angle         , g2->angle)         ) return differ;
 
-  if ( g1->xvals )
+  const double *restrict g1_xvals = g1->vtable->inqXValsPtr(g1),
+    *restrict g2_xvals = g2->vtable->inqXValsPtr(g2);
+  if ( g1_xvals )
     {
       if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
-	size = g1->size;
+        size = g1->size;
       else
-	size = g1->xsize;
+        size = g1->xsize;
       xassert ( size );
 
-      if ( !g2->xvals ) return differ;
+      if ( !g2_xvals ) return differ;
 
       for ( i = 0; i < size; i++ )
-	if ( IS_NOT_EQUAL(g1->xvals[i], g2->xvals[i]) ) return differ;
+        if ( IS_NOT_EQUAL(g1_xvals[i], g2_xvals[i]) ) return differ;
     }
-  else if ( g2->xvals )
+  else if ( g2_xvals )
     return differ;
 
-  if ( g1->yvals )
+  const double *restrict g1_yvals = g1->vtable->inqXValsPtr(g1),
+    *restrict g2_yvals = g2->vtable->inqXValsPtr(g2);
+  if ( g1_yvals )
     {
       if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
 	size = g1->size;
@@ -2292,66 +2420,74 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
 	size = g1->ysize;
       xassert ( size );
 
-      if ( !g2->yvals ) return differ;
+      if ( !g2_yvals ) return differ;
 
       for ( i = 0; i < size; i++ )
-        if ( IS_NOT_EQUAL(g1->yvals[i], g2->yvals[i]) ) return differ;
+        if ( IS_NOT_EQUAL(g1_yvals[i], g2_yvals[i]) ) return differ;
     }
-  else if ( g2->yvals )
+  else if ( g2_yvals )
     return differ;
 
-  if ( g1->area )
+  const double *restrict g1_area = g1->vtable->inqAreaPtr(g1),
+    *restrict g2_area = g2->vtable->inqAreaPtr(g2);
+  if ( g1_area )
     {
       xassert ( g1->size );
 
-      if ( !g2->area ) return differ;
+      if ( !g2_area ) return differ;
 
       for ( i = 0; i < g1->size; i++ )
-	if ( IS_NOT_EQUAL(g1->area[i], g2->area[i]) ) return differ;
+	if ( IS_NOT_EQUAL(g1_area[i], g2_area[i]) ) return differ;
     }
-  else if ( g2->area )
+  else if ( g2_area )
     return differ;
 
-  if ( g1->xbounds )
-    {
-      xassert ( g1->nvertex );
-      if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
-	size = g1->nvertex * g1->size;
-      else
-	size = g1->nvertex * g1->xsize;
-      xassert ( size );
+  {
+    const double *restrict g1_xbounds, *restrict g2_xbounds;
+    if ( (g1_xbounds = g1->vtable->inqXBoundsPtr(g1)) )
+      {
+        xassert ( g1->nvertex );
+        if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
+          size = g1->nvertex * g1->size;
+        else
+          size = g1->nvertex * g1->xsize;
+        xassert ( size );
 
-      if ( !g2->xbounds ) return differ;
+        if ( !(g2_xbounds = g2->vtable->inqXBoundsPtr(g2)) ) return differ;
 
-      for ( i = 0; i < size; i++ )
-	if ( IS_NOT_EQUAL(g1->xbounds[i], g2->xbounds[i]) ) return differ;
-    }
-  else if ( g2->xbounds )
-    return differ;
+        for ( i = 0; i < size; i++ )
+          if ( IS_NOT_EQUAL(g1_xbounds[i], g2_xbounds[i]) ) return differ;
+      }
+    else if ( g2->vtable->inqXBoundsPtr(g2) )
+      return differ;
+  }
 
-  if ( g1->ybounds )
-    {
-      xassert ( g1->nvertex );
-      if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
-	size = g1->nvertex * g1->size;
-      else
-	size = g1->nvertex * g1->ysize;
-      xassert ( size );
+  {
+    const double *restrict g1_ybounds, *restrict g2_ybounds;
+    if ( (g1_ybounds = g1->vtable->inqYBoundsPtr(g1)) )
+      {
+        xassert ( g1->nvertex );
+        if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
+          size = g1->nvertex * g1->size;
+        else
+          size = g1->nvertex * g1->ysize;
+        xassert ( size );
 
-      if ( !g2->ybounds ) return differ;
+        if ( ! (g2_ybounds = g2->vtable->inqYBoundsPtr(g2)) ) return differ;
 
-      for ( i = 0; i < size; i++ )
-	if ( IS_NOT_EQUAL(g1->ybounds[i], g2->ybounds[i]) ) return differ;
-    }
-  else if ( g2->ybounds )
-    return differ;
+        for ( i = 0; i < size; i++ )
+          if ( IS_NOT_EQUAL(g1->ybounds[i], g2->ybounds[i]) ) return differ;
+      }
+    else if ( g2->vtable->inqYBoundsPtr(g2) )
+      return differ;
+  }
 
   if (strcmp(g1->xname, g2->xname)) return differ;
   if (strcmp(g1->yname, g2->yname)) return differ;
   if (strcmp(g1->xlongname, g2->xlongname)) return differ;
   if (strcmp(g1->ylongname, g2->ylongname)) return differ;
-  if (strcmp(g1->xstdname, g2->xstdname)) return differ;
-  if (strcmp(g1->ystdname, g2->ystdname)) return differ;
+  if (g1->xstdname != g2->xstdname) return differ;
+  if (g1->ystdname != g2->ystdname) return differ;
   if (strcmp(g1->xunits, g2->xunits)) return differ;
   if (strcmp(g1->yunits, g2->yunits)) return differ;
 
@@ -2387,16 +2523,13 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
   return equal;
 }
 
-
-int gridGenerate(const grid_t *grid)
+static void gridComplete(grid_t *grid)
 {
-  int gridID = gridCreate(grid->type, grid->size);
-
-  grid_t *gridptr = gridID2Ptr(gridID);
-
+  int gridID = grid->self;
   gridDefPrec(gridID, grid->prec);
 
-  switch (grid->type)
+  int gridtype = grid->type;
+  switch (gridtype)
     {
     case GRID_LONLAT:
     case GRID_GAUSSIAN:
@@ -2412,42 +2545,32 @@ int gridGenerate(const grid_t *grid)
 	if ( grid->xsize > 0 ) gridDefXsize(gridID, grid->xsize);
 	if ( grid->ysize > 0 ) gridDefYsize(gridID, grid->ysize);
 
-        if ( grid->type == GRID_GAUSSIAN ) gridDefNP(gridID, grid->np);
+        if ( gridtype == GRID_GAUSSIAN ) gridDefNP(gridID, grid->np);
 
 	if ( grid->nvertex > 0 )
 	  gridDefNvertex(gridID, grid->nvertex);
 
-	if ( grid->xdef == 1 )
-	  {
-	    gridDefXvals(gridID, grid->xvals);
-	    if ( grid->xbounds )
-	      gridDefXbounds(gridID, grid->xbounds);
-	  }
-	else if ( grid->xdef == 2 )
+	if ( grid->xdef == 2 )
 	  {
+            assert(gridtype != GRID_UNSTRUCTURED
+                   && gridtype != GRID_CURVILINEAR);
 	    double *xvals
               = (double *) Malloc((size_t)grid->xsize * sizeof (double));
 	    gridGenXvals(grid->xsize, grid->xfirst, grid->xlast, grid->xinc, xvals);
-	    gridDefXvals(gridID, xvals);
-	    Free(xvals);
+	    grid->xvals = xvals;
 	    /*
 	    gridDefXinc(gridID, grid->xinc);
 	    */
 	  }
 
-	if ( grid->ydef == 1 )
-	  {
-	    gridDefYvals(gridID, grid->yvals);
-	    if ( grid->ybounds && grid->nvertex )
-	      gridDefYbounds(gridID, grid->ybounds);
-	  }
-	else if ( grid->ydef == 2 )
+	if ( grid->ydef == 2 )
 	  {
+            assert(gridtype != GRID_UNSTRUCTURED
+                   && gridtype != GRID_CURVILINEAR);
 	    double *yvals
               = (double *) Malloc((size_t)grid->ysize * sizeof (double));
-	    gridGenYvals(grid->type, grid->ysize, grid->yfirst, grid->ylast, grid->yinc, yvals);
-	    gridDefYvals(gridID, yvals);
-	    Free(yvals);
+	    gridGenYvals(gridtype, grid->ysize, grid->yfirst, grid->ylast, grid->yinc, yvals);
+	    grid->yvals = yvals;
 	    /*
 	    gridDefYinc(gridID, grid->yinc);
 	    */
@@ -2459,8 +2582,8 @@ int gridGenerate(const grid_t *grid)
 	    gridDefYname(gridID, "rlat");
 	    gridDefXlongname(gridID, "longitude in rotated pole grid");
 	    gridDefYlongname(gridID, "latitude in rotated pole grid");
-	    strcpy(gridptr->xstdname, "grid_longitude");
-	    strcpy(gridptr->ystdname, "grid_latitude");
+            grid->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
+            grid->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
 	    gridDefXunits(gridID, "degrees");
 	    gridDefYunits(gridID, "degrees");
 
@@ -2469,39 +2592,30 @@ int gridGenerate(const grid_t *grid)
 	    gridDefAngle(gridID, grid->angle);
 	  }
 
-	if ( grid->area )
-	  {
-	    gridDefArea(gridID, grid->area);
-	  }
-
-	if ( grid->type == GRID_LAEA )
-	  gridDefLaea(gridID, grid->laea_a, grid->laea_lon_0, grid->laea_lat_0);
-
-	if ( grid->type == GRID_LCC2 )
-	  gridDefLcc2(gridID, grid->lcc2_a, grid->lcc2_lon_0, grid->lcc2_lat_0, grid->lcc2_lat_1, grid->lcc2_lat_2);
-
-	if ( grid->type == GRID_LCC )
-	  gridDefLCC(gridID, grid->lcc_originLon, grid->lcc_originLat, grid->lcc_lonParY,
-		     grid->lcc_lat1, grid->lcc_lat2, grid->lcc_xinc, grid->lcc_yinc,
-		     grid->lcc_projflag, grid->lcc_scanflag);
-
-	if ( grid->type == GRID_UNSTRUCTURED )
+        switch (gridtype)
           {
-            int number = grid->number;
-            int position = grid->position;
-            if ( position < 0 ) position = 0;
-            if ( number > 0 )
-              {
-                gridDefNumber(gridID, number);
-                gridDefPosition(gridID, position);
-              }
-            gridDefUUID(gridID, grid->uuid);
-            if ( grid->reference ) gridDefReference(gridID, grid->reference);
-          }
-
-	if ( grid->type == GRID_PROJECTION )
-	  {
-	    gridptr->name = strdup(grid->name);
+          case GRID_LAEA:
+            gridDefLaea(gridID, grid->laea_a, grid->laea_lon_0, grid->laea_lat_0);
+            break;
+          case GRID_LCC2:
+            gridDefLcc2(gridID, grid->lcc2_a, grid->lcc2_lon_0, grid->lcc2_lat_0, grid->lcc2_lat_1, grid->lcc2_lat_2);
+            break;
+          case GRID_LCC:
+            gridDefLCC(gridID, grid->lcc_originLon, grid->lcc_originLat, grid->lcc_lonParY,
+                       grid->lcc_lat1, grid->lcc_lat2, grid->lcc_xinc, grid->lcc_yinc,
+                       grid->lcc_projflag, grid->lcc_scanflag);
+            break;
+          case GRID_UNSTRUCTURED:
+            {
+              int number = grid->number;
+              int position = grid->position >= 0 ? grid->position : 0;
+              if ( number > 0 )
+                {
+                  gridDefNumber(gridID, number);
+                  gridDefPosition(gridID, position);
+                }
+            }
+            break;
 	  }
 
 	break;
@@ -2510,29 +2624,19 @@ int gridGenerate(const grid_t *grid)
       {
 	gridDefNP(gridID, grid->np);
 	gridDefYsize(gridID, grid->ysize);
-	gridDefRowlon(gridID, grid->ysize, grid->rowlon);
 
         if ( grid->xdef == 2 )
           {
-            double xvals[2];
-            xvals[0] = grid->xfirst;
-            xvals[1] = grid->xlast;
+            double xvals[2] = { grid->xfirst, grid->xlast };
             gridDefXvals(gridID, xvals);
           }
 
-	if ( grid->ydef == 1 )
-	  {
-	    gridDefYvals(gridID, grid->yvals);
-	    if ( grid->ybounds && grid->nvertex )
-	      gridDefYbounds(gridID, grid->ybounds);
-	  }
-	else if ( grid->ydef == 2 )
+        if ( grid->ydef == 2 )
 	  {
 	    double *yvals
               = (double *) Malloc((size_t)grid->ysize * sizeof (double));
-	    gridGenYvals(grid->type, grid->ysize, grid->yfirst, grid->ylast, grid->yinc, yvals);
-	    gridDefYvals(gridID, yvals);
-	    Free(yvals);
+	    gridGenYvals(gridtype, grid->ysize, grid->yfirst, grid->ylast, grid->yinc, yvals);
+            grid->yvals = yvals;
 	    /*
 	    gridDefYinc(gridID, grid->yinc);
 	    */
@@ -2579,127 +2683,209 @@ int gridGenerate(const grid_t *grid)
       }
     default:
       {
-	Error("Gridtype %s unsupported!", gridNamePtr(grid->type));
+	Error("Gridtype %s unsupported!", gridNamePtr(gridtype));
 	break;
       }
     }
 
-  if ( grid->xname[0]     ) gridDefXname(gridID, grid->xname);
-  if ( grid->xlongname[0] ) gridDefXlongname(gridID, grid->xlongname);
-  if ( grid->xunits[0]    ) gridDefXunits(gridID, grid->xunits);
-  if ( grid->yname[0]     ) gridDefYname(gridID, grid->yname);
-  if ( grid->ylongname[0] ) gridDefYlongname(gridID, grid->ylongname);
-  if ( grid->yunits[0]    ) gridDefYunits(gridID, grid->yunits);
+  grid->xname[CDI_MAX_NAME - 1] = 0;
+  grid->xlongname[CDI_MAX_NAME - 1] = 0;
+  grid->xunits[CDI_MAX_NAME - 1] = 0;
+  grid->yname[CDI_MAX_NAME - 1] = 0;
+  grid->ylongname[CDI_MAX_NAME - 1] = 0;
+  grid->yunits[CDI_MAX_NAME - 1] = 0;
 
-  return (gridID);
 }
 
-/*
- at Function  gridDuplicate
- at Title     Duplicate a horizontal Grid
-
- at Prototype int gridDuplicate(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-
- at Description
-The function @func{gridDuplicate} duplicates a horizontal Grid.
-
- at Result
- at func{gridDuplicate} returns an identifier to the duplicated Grid.
+#define GRID_STR_SERIALIZE(gridP) { gridP->xname, gridP->yname, \
+    gridP->xlongname, gridP->ylongname, \
+    gridP->xunits, gridP->yunits }
 
- at EndFunction
-*/
-int gridDuplicate(int gridID)
+int gridGenerate(const grid_t *grid)
 {
-  grid_t *gridptr = (grid_t *)reshGetVal(gridID, &gridOps);
-
-  int gridtype = gridInqType(gridID);
-  int gridsize = gridInqSize(gridID);
-
-  int gridIDnew = gridCreate(gridtype, gridsize);
-  grid_t *gridptrnew = (grid_t *)reshGetVal(gridIDnew, &gridOps);
-
-  grid_copy(gridptrnew, gridptr);
-
-  strcpy(gridptrnew->xname, gridptr->xname);
-  strcpy(gridptrnew->yname, gridptr->yname);
-  strcpy(gridptrnew->xlongname, gridptr->xlongname);
-  strcpy(gridptrnew->ylongname, gridptr->ylongname);
-  strcpy(gridptrnew->xunits, gridptr->xunits);
-  strcpy(gridptrnew->yunits, gridptr->yunits);
-  strcpy(gridptrnew->xstdname, gridptr->xstdname);
-  strcpy(gridptrnew->ystdname, gridptr->ystdname);
-
-  if (gridptr->reference)
-    gridptrnew->reference = strdupx(gridptr->reference);
+  int gridtype = grid->type;
+  int gridID = gridCreate(gridtype, grid->size);
+  grid_t *restrict gridptr = gridID2Ptr(gridID);
+  gridptr->prec = grid->prec;
+  gridptr->xsize = grid->xsize;
+  gridptr->ysize = grid->ysize;
+  gridptr->np = grid->np;
+  gridptr->nvertex = grid->nvertex;
+  gridptr->xdef = grid->xdef;
+  int valdef_group1 = 0;
+  static const int valdef_group1_tab[] = {
+    GRID_LONLAT, GRID_GAUSSIAN, GRID_UNSTRUCTURED, GRID_CURVILINEAR,
+    GRID_GENERIC, GRID_LCC, GRID_LCC2, GRID_SINUSOIDAL, GRID_LAEA,
+    GRID_PROJECTION
+  };
+  for ( size_t i = 0; i < sizeof (valdef_group1_tab) / sizeof (valdef_group1_tab[0]); ++i)
+    valdef_group1 |= (gridtype == valdef_group1_tab[i]);
+  if ( valdef_group1 && grid->xdef == 1 )
+    {
+      gridDefXvals(gridID, grid->xvals);
+      if ( grid->xbounds )
+        gridDefXbounds(gridID, grid->xbounds);
+    }
+  gridptr->xfirst = grid->xfirst;
+  gridptr->xlast = grid->xlast;
+  gridptr->xinc = grid->xinc;
+  gridptr->ydef = grid->ydef;
+  if ( (valdef_group1 || gridtype == GRID_GAUSSIAN_REDUCED) && grid->ydef == 1)
+    {
+      gridDefYvals(gridID, grid->yvals);
+      if ( grid->ybounds )
+        gridDefYbounds(gridID, grid->ybounds);
+    }
+  gridptr->yfirst = grid->yfirst;
+  gridptr->ylast = grid->ylast;
+  gridptr->yinc = grid->yinc;
+  gridptr->isRotated = grid->isRotated;
+  gridptr->xpole = grid->xpole;
+  gridptr->ypole = grid->ypole;
+  gridptr->angle = grid->angle;
+  if ( valdef_group1 && grid->area)
+    gridDefArea(gridID, grid->area);
+  gridptr->laea_a = grid->laea_a;
+  gridptr->laea_lon_0 = grid->laea_lon_0;
+  gridptr->laea_lat_0 = grid->laea_lat_0;
+  gridptr->lcc2_a = grid->lcc2_a;
+  gridptr->lcc2_lon_0 = grid->lcc2_lon_0;
+  gridptr->lcc2_lat_0 = grid->lcc2_lat_0;
+  gridptr->lcc2_lat_1 = grid->lcc2_lat_1;
+  gridptr->lcc2_lat_2 = grid->lcc2_lat_2;
+  gridptr->lcc_originLon = grid->lcc_originLon;
+  gridptr->lcc_originLat = grid->lcc_originLat;
+  gridptr->lcc_lonParY = grid->lcc_lonParY;
+  gridptr->lcc_lat1 = grid->lcc_lat1;
+  gridptr->lcc_lat2 = grid->lcc_lat2;
+  gridptr->lcc_xinc = grid->lcc_xinc;
+  gridptr->lcc_yinc = grid->lcc_yinc;
+  gridptr->lcc_projflag = grid->lcc_projflag;
+  gridptr->lcc_scanflag = grid->lcc_scanflag;
+  gridptr->number = grid->number;
+  gridptr->position = grid->position;
+  memcpy(gridptr->uuid, grid->uuid, CDI_UUID_SIZE);
+  if ( gridtype == GRID_UNSTRUCTURED && grid->reference )
+    gridDefReference(gridID, grid->reference);
+  if ( gridtype == GRID_PROJECTION )
+    gridptr->name = strdup(grid->name);
+  if ( gridtype == GRID_GAUSSIAN_REDUCED )
+    gridDefRowlon(gridID, grid->ysize, grid->rowlon);
+  gridptr->trunc = grid->trunc;
+  gridptr->lcomplex = grid->lcomplex;
+  gridptr->nd = grid->nd;
+  gridptr->ni = grid->ni;
+  gridptr->ni2 = grid->ni2;
+  gridptr->ni3 = grid->ni3;
+  const char *grid_str_tab[] = GRID_STR_SERIALIZE(grid);
+  char *gridptr_str_tab[] = GRID_STR_SERIALIZE(gridptr);
+  for (size_t i = 0; i < sizeof (grid_str_tab) / sizeof (grid_str_tab[0]); ++i)
+    if ( grid_str_tab[i][0] )
+      memcpy(gridptr_str_tab[i], grid_str_tab[i], CDI_MAX_NAME);
+  gridComplete(gridptr);
+  return (gridID);
+}
 
-  size_t nrowlon = (size_t)gridptr->nrowlon;
+static void
+grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
+{
+  size_t nrowlon = (size_t)gridptrOrig->nrowlon;
+  size_t gridsize = (size_t)gridptrOrig->size;
+  int gridtype = gridptrOrig->type;
   int irregular = gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED;
   if ( nrowlon )
     {
-      gridptrnew->rowlon = (int *) Malloc(nrowlon * sizeof (int));
-      memcpy(gridptrnew->rowlon, gridptr->rowlon, nrowlon * sizeof(int));
+      gridptrDup->rowlon = (int *)Malloc(nrowlon * sizeof (int));
+      memcpy(gridptrDup->rowlon, gridptrOrig->rowlon, nrowlon * sizeof(int));
     }
 
-  if ( gridptr->xvals != NULL )
+  if ( gridptrOrig->xvals != NULL )
     {
-      size_t size  = (size_t)(irregular ? gridsize : gridptr->xsize);
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->xsize;
 
-      gridptrnew->xvals = (double *) Malloc(size * sizeof (double));
-      memcpy(gridptrnew->xvals, gridptr->xvals, size * sizeof (double));
+      gridptrDup->xvals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->xvals, gridptrOrig->xvals, size * sizeof (double));
     }
 
-  if ( gridptr->yvals != NULL )
+  if ( gridptrOrig->yvals != NULL )
     {
-      size_t size  = (size_t)(irregular ? gridsize : gridptr->ysize);
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->ysize;
 
-      gridptrnew->yvals = (double *) Malloc(size * sizeof (double));
-      memcpy(gridptrnew->yvals, gridptr->yvals, size * sizeof (double));
+      gridptrDup->yvals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->yvals, gridptrOrig->yvals, size * sizeof (double));
     }
 
-  if ( gridptr->xbounds != NULL )
+  if ( gridptrOrig->xbounds != NULL )
     {
-      size_t size  = (size_t)(irregular ? gridsize : gridptr->xsize)
-        * (size_t)gridptr->nvertex;
+      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->xsize)
+        * (size_t)gridptrOrig->nvertex;
 
-      gridptrnew->xbounds = (double *) Malloc(size * sizeof (double));
-      memcpy(gridptrnew->xbounds, gridptr->xbounds, size * sizeof (double));
+      gridptrDup->xbounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->xbounds, gridptrOrig->xbounds, size * sizeof (double));
     }
 
-  if ( gridptr->ybounds != NULL )
+  if ( gridptrOrig->ybounds != NULL )
     {
-      size_t size = (size_t)(irregular ? gridsize : gridptr->ysize)
-        * (size_t)gridptr->nvertex;
+      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->ysize)
+        * (size_t)gridptrOrig->nvertex;
 
-      gridptrnew->ybounds = (double *) Malloc(size * sizeof (double));
-      memcpy(gridptrnew->ybounds, gridptr->ybounds, size * sizeof (double));
+      gridptrDup->ybounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->ybounds, gridptrOrig->ybounds, size * sizeof (double));
     }
 
-  if ( gridptr->area != NULL )
-    {
-      size_t size = (size_t)gridsize;
+  {
+    const double *gridptrOrig_area
+      = gridptrOrig->vtable->inqAreaPtr(gridptrOrig);
+    if ( gridptrOrig_area != NULL )
+      {
+        size_t size = gridsize;
 
-      gridptrnew->area = (double *) Malloc(size * sizeof (double));
-      memcpy(gridptrnew->area, gridptr->area, size * sizeof (double));
-    }
+        gridptrDup->area = (double *)Malloc(size * sizeof (double));
+        memcpy(gridptrDup->area, gridptrOrig_area, size * sizeof (double));
+      }
+  }
 
-  if ( gridptr->mask != NULL )
+  if ( gridptrOrig->mask != NULL )
     {
-      size_t size = (size_t)gridsize;
+      size_t size = gridsize;
 
-      gridptrnew->mask = (mask_t *) Malloc(size * sizeof(mask_t));
-      memcpy(gridptrnew->mask, gridptr->mask, size * sizeof (mask_t));
+      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
+      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
     }
 
-  if ( gridptr->mask_gme != NULL )
+  if ( gridptrOrig->mask_gme != NULL )
     {
-      size_t size = (size_t)gridsize;
+      size_t size = gridsize;
 
-      gridptrnew->mask_gme = (mask_t *) Malloc(size * sizeof (mask_t));
-      memcpy(gridptrnew->mask_gme, gridptr->mask_gme, size * sizeof(mask_t));
+      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
+      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
     }
 
+}
+
+
+/*
+ at Function  gridDuplicate
+ at Title     Duplicate a horizontal Grid
+
+ at Prototype int gridDuplicate(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+
+ at Description
+The function @func{gridDuplicate} duplicates a horizontal Grid.
+
+ at Result
+ at func{gridDuplicate} returns an identifier to the duplicated Grid.
+
+ at EndFunction
+*/
+int gridDuplicate(int gridID)
+{
+  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptrnew = gridptr->vtable->copy(gridptr);
+  int gridIDnew = reshPut(gridptrnew, &gridOps);
+  gridptrnew->self = gridIDnew;
   return (gridIDnew);
 }
 
@@ -2715,71 +2901,72 @@ void gridCompress(int gridID)
 	{
           size_t gridsize = (size_t)gridInqSize(gridID);
 	  size_t nv = (size_t)gridptr->nvertex;
-
-	  size_t j = 0;
-          double *area = gridptr->area,
-            *xvals = gridptr->xvals,
-            *yvals = gridptr->yvals,
-            *xbounds = gridptr->xbounds,
-            *ybounds = gridptr->ybounds;
-          mask_t *mask_gme = gridptr->mask_gme;
-	  for (size_t i = 0; i < gridsize; i++ )
-	    {
-	      if (mask_gme[i])
-		{
-		  if (xvals) xvals[j] = xvals[i];
-		  if (yvals) yvals[j] = yvals[i];
-		  if (area) area[j]  = area[i];
-		  if (xbounds != NULL)
-		    for (size_t iv = 0; iv < nv; iv++)
-		      xbounds[j * nv + iv] = xbounds[i * nv + iv];
-		  if (ybounds != NULL)
-		    for (size_t iv = 0; iv < nv; iv++)
-		      ybounds[j * nv + iv] = ybounds[i * nv + iv];
-
-		  j++;
-		}
-	    }
+          double *restrict area
+            = (double *)gridptr->vtable->inqAreaPtr(gridptr),
+            *restrict xvals = (double *)gridptr->vtable->inqXValsPtr((grid_t *)gridptr),
+            *restrict yvals = (double *)gridptr->vtable->inqYValsPtr((grid_t *)gridptr),
+            *restrict xbounds = (double *)gridptr->vtable->inqXBoundsPtr(gridptr),
+            *restrict ybounds = (double *)gridptr->vtable->inqYBoundsPtr(gridptr);
+          mask_t *restrict mask_gme = gridptr->mask_gme;
+          size_t *restrict selection = (size_t *)Malloc(gridsize * sizeof (selection[0]));
+          size_t nselect;
+          {
+            size_t j = 0;
+            for (size_t i = 0; i < gridsize; i++ )
+              selection[j] = i, j += (mask_gme[i] != 0);
+            nselect = j;
+          }
+          selection = (size_t *)Realloc(selection, nselect * sizeof (selection[0]));
+          if (xvals)
+            for (size_t i = 0; i < nselect; i++ )
+	      xvals[i] = xvals[selection[i]];
+          if (yvals)
+            for (size_t i = 0; i < nselect; i++ )
+              yvals[i] = yvals[selection[i]];
+          if (area)
+            for (size_t i = 0; i < nselect; i++ )
+              area[i] = area[selection[i]];
+          if (xbounds)
+            for (size_t i = 0; i < nselect; i++ )
+              for (size_t iv = 0; iv < nv; iv++)
+                xbounds[i * nv + iv] = xbounds[selection[i] * nv + iv];
+          if (ybounds)
+            for (size_t i = 0; i < nselect; i++ )
+              for (size_t iv = 0; iv < nv; iv++)
+                ybounds[i * nv + iv] = ybounds[selection[i] * nv + iv];
+          Free(selection);
 
 	  /* fprintf(stderr, "grid compress %d %d %d\n", i, j, gridsize); */
-	  gridsize = j;
+	  gridsize = nselect;
 	  gridptr->size  = (int)gridsize;
 	  gridptr->xsize = (int)gridsize;
 	  gridptr->ysize = (int)gridsize;
 
-	  if ( gridptr->xvals )
-	    gridptr->xvals = (double *) Realloc(gridptr->xvals, gridsize*sizeof(double));
-
-	  if ( gridptr->yvals )
-	    gridptr->yvals = (double *) Realloc(gridptr->yvals, gridsize*sizeof(double));
-
-	  if ( gridptr->area )
-	    gridptr->area  = (double *) Realloc(gridptr->area, gridsize*sizeof(double));
-
-	  if ( gridptr->xbounds )
-	    gridptr->xbounds = (double *) Realloc(gridptr->xbounds, nv*gridsize*sizeof(double));
-
-	  if ( gridptr->ybounds )
-	    gridptr->ybounds = (double *) Realloc(gridptr->ybounds, nv*gridsize*sizeof(double));
+          double **resizeP[] = { &gridptr->xvals, &gridptr->yvals,
+                                 &gridptr->area,
+                                 &gridptr->xbounds, &gridptr->ybounds };
+          size_t newSize[] = { gridsize, gridsize, gridsize, nv*gridsize,
+                               nv*gridsize };
+          for ( size_t i = 0; i < sizeof (resizeP) / sizeof (resizeP[0]); ++i)
+            if ( *(resizeP[i]) )
+              *(resizeP[i]) = (double *)Realloc(*(resizeP[i]), newSize[i]*sizeof(double));
 
 	  Free(gridptr->mask_gme);
 	  gridptr->mask_gme = NULL;
-          reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+          gridMark4Update(gridID);
 	}
     }
   else
     Warning("Unsupported grid type: %s", gridNamePtr(gridtype));
 }
 
-
-void gridDefArea(int gridID, const double *area)
+static void
+gridDefAreaSerial(grid_t *gridptr, const double *area)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
   size_t size = (size_t)gridptr->size;
 
   if ( size == 0 )
-    Error("size undefined for gridID = %d", gridID);
+    Error("size undefined for gridID = %d", gridptr->self);
 
   if ( gridptr->area == NULL )
     gridptr->area = (double *) Malloc(size*sizeof(double));
@@ -2787,34 +2974,52 @@ void gridDefArea(int gridID, const double *area)
     Warning("values already defined!");
 
   memcpy(gridptr->area, area, size * sizeof(double));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
 }
 
 
-void gridInqArea(int gridID, double *area)
+void gridDefArea(int gridID, const double *area)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defArea(gridptr, area);
+  gridMark4Update(gridID);
+}
 
+static void
+gridInqAreaSerial(grid_t *gridptr, double *area)
+{
   if (gridptr->area)
     memcpy(area, gridptr->area, (size_t)gridptr->size * sizeof (double));
 }
 
 
-int gridHasArea(int gridID)
+void gridInqArea(int gridID, double *area)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->inqArea(gridptr, area);
+}
 
-  int hasArea = (gridptr->area != NULL);
+static int
+gridHasAreaBase(grid_t *gridptr)
+{
+  return gridptr->area != NULL;
+}
 
-  return (hasArea);
+int gridHasArea(int gridID)
+{
+  grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->hasArea(gridptr);
 }
 
 
+static const double *gridInqAreaPtrBase(grid_t *gridptr)
+{
+  return gridptr->area;
+}
+
 const double *gridInqAreaPtr(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  return (gridptr->area);
+  return gridptr->vtable->inqAreaPtr(gridptr);
 }
 
 
@@ -2825,7 +3030,7 @@ void gridDefNvertex(int gridID, int nvertex)
   if (gridptr->nvertex != nvertex)
     {
       gridptr->nvertex = nvertex;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -2837,6 +3042,38 @@ int gridInqNvertex(int gridID)
   return (gridptr->nvertex);
 }
 
+static void
+gridDefBoundsGeneric(grid_t *gridptr, const double *bounds, int regularSize,
+                     double **field)
+{
+  int irregular = gridptr->type == GRID_CURVILINEAR
+    || gridptr->type == GRID_UNSTRUCTURED;
+  size_t nvertex = (size_t)gridptr->nvertex;
+  if ( nvertex == 0 )
+    {
+      Warning("nvertex undefined for gridID = %d. Cannot define bounds!",
+              gridptr->self);
+      return;
+    }
+  size_t size = nvertex * (size_t)(irregular ? gridptr->size : regularSize);
+  if ( size == 0 )
+    Error("size undefined for gridID = %d", gridptr->self);
+
+  if (*field == NULL)
+    *field = (double *)Malloc(size * sizeof (double));
+  else if ( CDI_Debug )
+    Warning("values already defined!");
+
+  memcpy(*field, bounds, size * sizeof (double));
+}
+
+
+static void
+gridDefXBoundsSerial(grid_t *gridptr, const double *xbounds)
+{
+  gridDefBoundsGeneric(gridptr, xbounds, gridptr->xsize, &gridptr->xbounds);
+}
+
 /*
 @Function  gridDefXbounds
 @Title     Define the bounds of a X-axis
@@ -2854,28 +3091,29 @@ The function @func{gridDefXbounds} defines all bounds of the X-axis.
 void gridDefXbounds(int gridID, const double *xbounds)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defXBounds(gridptr, xbounds);
+  gridMark4Update(gridID);
+}
 
+static int
+gridInqXBoundsSerial(grid_t *gridptr, double *xbounds)
+{
   size_t nvertex = (size_t)gridptr->nvertex;
-  if ( nvertex == 0 )
-    {
-      Warning("nvertex undefined for gridID = %d. Cannot define bounds!", gridID);
-      return;
-    }
 
   int irregular = gridptr->type == GRID_CURVILINEAR
     || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex
-    * (size_t)(irregular ? gridptr->size : gridptr->xsize);
-  if ( size == 0 )
-    Error("size undefined for gridID = %d", gridID);
+  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->xsize);
 
-  if (gridptr->xbounds == NULL)
-    gridptr->xbounds = (double *) Malloc(size * sizeof (double));
-  else if ( CDI_Debug )
-    Warning("values already defined!");
+  const double *gridptr_xbounds = gridptr->vtable->inqXBoundsPtr(gridptr);
+  if ( gridptr_xbounds )
+    {
+      if ( size && xbounds )
+        memcpy(xbounds, gridptr_xbounds, size * sizeof (double));
+    }
+  else
+    size = 0;
 
-  memcpy(gridptr->xbounds, xbounds, size * sizeof (double));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+  return ((int)size);
 }
 
 /*
@@ -2901,27 +3139,26 @@ Otherwise, 0 is returned and @func{xbounds} is empty.
 int gridInqXbounds(int gridID, double *xbounds)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqXBounds(gridptr, xbounds);
+}
 
-  size_t nvertex = (size_t)gridptr->nvertex;
-
-  int irregular = gridptr->type == GRID_CURVILINEAR
-    || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->xsize);
-
-  if ( size && xbounds && gridptr->xbounds )
-    memcpy(xbounds, gridptr->xbounds, size * sizeof (double));
-
-  if ( gridptr->xbounds == NULL ) size = 0;
-
-  return ((int)size);
+static const double *
+gridInqXBoundsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->xbounds;
 }
 
 
 const double *gridInqXboundsPtr(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqXBoundsPtr(gridptr);
+}
 
-  return (gridptr->xbounds);
+static void
+gridDefYBoundsSerial(grid_t *gridptr, const double *ybounds)
+{
+  gridDefBoundsGeneric(gridptr, ybounds, gridptr->ysize, &gridptr->ybounds);
 }
 
 /*
@@ -2941,30 +3178,32 @@ The function @func{gridDefYbounds} defines all bounds of the Y-axis.
 void gridDefYbounds(int gridID, const double *ybounds)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->vtable->defYBounds(gridptr, ybounds);
+  gridMark4Update(gridID);
+}
 
+static int
+gridInqYBoundsSerial(grid_t *gridptr, double *ybounds)
+{
   size_t nvertex = (size_t)gridptr->nvertex;
-  if ( nvertex == 0 )
-    {
-      Warning("nvertex undefined for gridID = %d. Cannot define bounds!", gridID);
-      return;
-    }
 
   int irregular = gridptr->type == GRID_CURVILINEAR
     || gridptr->type == GRID_UNSTRUCTURED;
   size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->ysize);
 
-  if ( size == 0 )
-    Error("size undefined for gridID = %d", gridID);
-
-  if ( gridptr->ybounds == NULL )
-    gridptr->ybounds = (double *) Malloc(size * sizeof (double));
-  else if ( CDI_Debug )
-    Warning("values already defined!");
+  const double *gridptr_ybounds = gridptr->vtable->inqYBoundsPtr(gridptr);
+  if ( gridptr_ybounds )
+    {
+      if ( size && ybounds )
+        memcpy(ybounds, gridptr_ybounds, size * sizeof (double));
+    }
+  else
+    size = 0;
 
-  memcpy(gridptr->ybounds, ybounds, size * sizeof (double));
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+  return ((int)size);
 }
 
+
 /*
 @Function  gridInqYbounds
 @Title     Get the bounds of a Y-axis
@@ -2988,35 +3227,98 @@ Otherwise, 0 is returned and @func{ybounds} is empty.
 int gridInqYbounds(int gridID, double *ybounds)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqYBounds(gridptr, ybounds);
+}
 
-  size_t nvertex = (size_t)gridptr->nvertex;
-
-  int irregular = gridptr->type == GRID_CURVILINEAR
-    || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->ysize);
-
-  if ( size && ybounds && gridptr->ybounds )
-    memcpy(ybounds, gridptr->ybounds, size * sizeof (double));
-
-  if ( gridptr->ybounds == NULL ) size = 0;
-
-  return ((int)size);
+static const double *
+gridInqYBoundsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->ybounds;
 }
 
 
 const double *gridInqYboundsPtr(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
+  return gridptr->vtable->inqYBoundsPtr(gridptr);
+}
+
+static void
+printDblsPrefixAutoBrk(FILE *fp, const char prefix[], size_t nbyte0,
+                       size_t n, const double vals[])
+{
+  fputs(prefix, fp);
+  size_t nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
+    {
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%.9g ", vals[i]);
+    }
+  fputs("\n", fp);
+}
+
+static void
+printIntsPrefixAutoBrk(FILE *fp, const char prefix[], size_t nbyte0,
+                       size_t n, const int vals[])
+{
+  fputs(prefix, fp);
+  size_t nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
+    {
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%d ", vals[i]);
+    }
+  fputs("\n", fp);
+}
 
-  return (gridptr->ybounds);
+static void
+printBounds(FILE *fp, const char prefix[], size_t nbyte0,
+            size_t n, size_t nvertex, const double bounds[])
+{
+  fputs(prefix, fp);
+  if ( n > 0 )
+    {
+      for ( size_t iv = 0; iv < nvertex; iv++ )
+        fprintf(fp, "%.9g ", bounds[iv]);
+      for ( size_t i = 1; i < (size_t)n; i++ )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          for ( size_t iv = 0; iv < nvertex; iv++ )
+            fprintf(fp, "%.9g ", bounds[i*nvertex+iv]);
+        }
+      fputs("\n", fp);
+    }
 }
 
+static void
+printMask(FILE *fp, const char prefix[], size_t nbyte0,
+          size_t n, const mask_t mask[])
+{
+  fputs(prefix, fp);
+  size_t nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
+    {
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%d ", (int)mask[i]);
+    }
+  fputs("\n", fp);
+}
 
 static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 {
   int xdim, ydim;
-  int nbyte;
-  int i, iv;
   unsigned char uuidOfHGrid[CDI_UUID_SIZE];
   int gridID = gridptr->self;
   const double *area    = gridInqAreaPtr(gridID);
@@ -3032,12 +3334,11 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
   int ysize    = gridInqYsize(gridID);
   int nvertex  = gridInqNvertex(gridID);
 
-  int nbyte0 = 0;
-  fprintf(fp, "#\n");
-  fprintf(fp, "# gridID %d\n", index);
-  fprintf(fp, "#\n");
-  fprintf(fp, "gridtype  = %s\n", gridNamePtr(type));
-  fprintf(fp, "gridsize  = %d\n", gridsize);
+  fprintf(fp, "#\n"
+          "# gridID %d\n"
+          "#\n"
+          "gridtype  = %s\n"
+          "gridsize  = %d\n", index, gridNamePtr(type), gridsize);
 
   if ( type != GRID_GME )
     {
@@ -3121,20 +3422,21 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 	  {
 	    double a = 0, lon_0 = 0, lat_0 = 0;
 	    gridInqLaea(gridID, &a, &lon_0, &lat_0);
-	    fprintf(fp, "a         = %g\n", a);
-	    fprintf(fp, "lon_0     = %g\n", lon_0);
-	    fprintf(fp, "lat_0     = %g\n", lat_0);
+	    fprintf(fp, "a         = %g\n"
+                    "lon_0     = %g\n"
+                    "lat_0     = %g\n", a, lon_0, lat_0);
 	  }
 
 	if ( type == GRID_LCC2 )
 	  {
 	    double a = 0, lon_0 = 0, lat_0 = 0, lat_1 = 0, lat_2 = 0;
 	    gridInqLcc2(gridID, &a, &lon_0, &lat_0, &lat_1, &lat_2);
-	    fprintf(fp, "a         = %g\n", a);
-	    fprintf(fp, "lon_0     = %g\n", lon_0);
-	    fprintf(fp, "lat_0     = %g\n", lat_0);
-	    fprintf(fp, "lat_1     = %g\n", lat_1);
-	    fprintf(fp, "lat_2     = %g\n", lat_2);
+	    fprintf(fp, "a         = %g\n"
+                    "lon_0     = %g\n"
+                    "lat_0     = %g\n"
+                    "lat_1     = %g\n"
+                    "lat_2     = %g\n",
+                    a, lon_0, lat_0, lat_1, lat_2);
 	  }
 
 	if ( gridptr->isRotated )
@@ -3158,38 +3460,23 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 
 	    if ( IS_NOT_EQUAL(xinc, 0) && opt )
 	      {
-	  	fprintf(fp, "xfirst    = %g\n", xfirst);
-		fprintf(fp, "xinc      = %g\n", xinc);
+                fprintf(fp, "xfirst    = %g\n"
+                        "xinc      = %g\n", xfirst, xinc);
 	      }
 	    else
 	      {
-		nbyte0 = fprintf(fp, "xvals     = ");
-		nbyte = nbyte0;
-		for ( i = 0; i < xdim; i++ )
-		  {
-		    if ( nbyte > 80 )
-		      {
-			fprintf(fp, "\n");
-			fprintf(fp, "%*s", nbyte0, "");
-			nbyte = nbyte0;
-		      }
-		    nbyte += fprintf(fp, "%.9g ", xvals[i]);
-		  }
-		fprintf(fp, "\n");
+                static const char prefix[] = "xvals     = ";
+                printDblsPrefixAutoBrk(fp, prefix, sizeof (prefix),
+                                       (size_t)(xdim > 0 ? xdim : 0), xvals);
 	      }
 	  }
 
 	if ( xbounds )
 	  {
-	    nbyte0 = fprintf(fp, "xbounds   = ");
-	    for ( i = 0; i < xdim; i++ )
-	      {
-		if ( i ) fprintf(fp, "%*s", nbyte0, "");
-
-		for ( iv = 0; iv < nvertex; iv++ )
-		  fprintf(fp, "%.9g ", xbounds[i*nvertex+iv]);
-		fprintf(fp, "\n");
-	      }
+            static const char prefix[] = "xbounds   = ";
+            printBounds(fp, prefix, sizeof (prefix),
+                        (size_t)(xdim > 0 ? xdim : 0),
+                        (size_t)(nvertex > 0 ? nvertex : 0), xbounds);
 	  }
 
 	if ( yvals )
@@ -3205,75 +3492,39 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 
 	    if ( IS_NOT_EQUAL(yinc, 0) && opt )
 	      {
-	  	fprintf(fp, "yfirst    = %g\n", yfirst);
-		fprintf(fp, "yinc      = %g\n", yinc);
+	  	fprintf(fp, "yfirst    = %g\n"
+                        "yinc      = %g\n", yfirst, yinc);
 	      }
 	    else
 	      {
-		nbyte0 = fprintf(fp, "yvals     = ");
-		nbyte = nbyte0;
-		for ( i = 0; i < ydim; i++ )
-		  {
-		    if ( nbyte > 80 )
-		      {
-			fprintf(fp, "\n");
-			fprintf(fp, "%*s", nbyte0, "");
-			nbyte = nbyte0;
-		      }
-		    nbyte += fprintf(fp, "%.9g ", yvals[i]);
-		  }
-		fprintf(fp, "\n");
+                static const char prefix[] = "yvals     = ";
+                printDblsPrefixAutoBrk(fp, prefix, sizeof (prefix),
+                                       (size_t)(ydim > 0 ? ydim : 0), yvals);
 	      }
 	  }
 
 	if ( ybounds )
 	  {
-	    nbyte0 = fprintf(fp, "ybounds   = ");
-	    for ( i = 0; i < ydim; i++ )
-	      {
-		if ( i ) fprintf(fp, "%*s", nbyte0, "");
-
-		for ( iv = 0; iv < nvertex; iv++ )
-		  fprintf(fp, "%.9g ", ybounds[i*nvertex+iv]);
-		fprintf(fp, "\n");
-	      }
+            static const char prefix[] = "ybounds   = ";
+            printBounds(fp, prefix, sizeof (prefix),
+                        (size_t)(ydim > 0 ? ydim : 0),
+                        (size_t)(nvertex > 0 ? nvertex : 0), ybounds);
 	  }
 
 	if ( area )
 	  {
-	    nbyte0 = fprintf(fp, "area      = ");
-	    nbyte  = nbyte0;
-	    for ( i = 0; i < gridsize; i++ )
-	      {
-		if ( nbyte > 80 )
-		  {
-		    fprintf(fp, "\n");
-		    fprintf(fp, "%*s", nbyte0, "");
-		    nbyte = nbyte0;
-		  }
-		nbyte += fprintf(fp, "%.9g ", area[i]);
-	      }
-	    fprintf(fp, "\n");
+            static const char prefix[] = "area      = ";
+            printDblsPrefixAutoBrk(fp, prefix, sizeof (prefix),
+                                   (size_t)(gridsize > 0 ? gridsize : 0), area);
 	  }
 
         if ( type == GRID_GAUSSIAN_REDUCED )
           {
-            int *rowlon;
-            nbyte0 = fprintf(fp, "rowlon    = ");
-            nbyte  = nbyte0;
-            rowlon = (int *) Malloc((size_t)ysize*sizeof(int));
+            static const char prefix[] = "rowlon    = ";
+            int *rowlon = (int *)Malloc((size_t)ysize*sizeof(int));
             gridInqRowlon(gridID, rowlon);
-            for ( i = 0; i < ysize; i++ )
-              {
-                if ( nbyte > 80 )
-                  {
-                    fprintf(fp, "\n");
-                    fprintf(fp, "%*s", nbyte0, "");
-                    nbyte = nbyte0;
-                  }
-                nbyte += fprintf(fp, "%d ", rowlon[i]);
-              }
-            fprintf(fp, "\n");
+            printIntsPrefixAutoBrk(fp, prefix, sizeof (prefix),
+                                   (size_t)(ysize > 0 ? ysize : 0), rowlon);
             Free(rowlon);
           }
 
@@ -3286,27 +3537,26 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
 		   &projflag, &scanflag);
 
-	fprintf(fp, "xsize     = %d\n", xsize);
-	fprintf(fp, "ysize     = %d\n", ysize);
-
-	fprintf(fp, "originLon = %g\n", originLon);
-	fprintf(fp, "originLat = %g\n", originLat);
-	fprintf(fp, "lonParY   = %g\n", lonParY);
-	fprintf(fp, "lat1      = %g\n", lat1);
-	fprintf(fp, "lat2      = %g\n", lat2);
-	fprintf(fp, "xinc      = %g\n", xincm);
-	fprintf(fp, "yinc      = %g\n", yincm);
-	if ( (projflag & 128) == 0 )
-	  fprintf(fp, "projection = northpole\n");
-	else
-	  fprintf(fp, "projection = southpole\n");
-
+	fprintf(fp,
+                "xsize     = %d\n"
+                "ysize     = %d\n"
+                "originLon = %g\n"
+                "originLat = %g\n"
+                "lonParY   = %g\n"
+                "lat1      = %g\n"
+                "lat2      = %g\n"
+                "xinc      = %g\n"
+                "yinc      = %g\n"
+                "projection = %s\n"
+                , xsize, ysize, originLon, originLat, lonParY, lat1, lat2,
+                xincm, yincm,
+                (projflag & 128) == 0 ? "northpole" : "southpole");
 	break;
       }
     case GRID_SPECTRAL:
       {
-        fprintf(fp, "truncation = %d\n", trunc);
-        fprintf(fp, "complexpacking = %d\n", gridptr->lcomplex );
+        fprintf(fp, "truncation = %d\n"
+                "complexpacking = %d\n", trunc, gridptr->lcomplex );
         break;
       }
     case GRID_FOURIER:
@@ -3330,26 +3580,16 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
   if ( !cdiUUIDIsNull(uuidOfHGrid) )
     {
       char uuidOfHGridStr[37];
-      uuid2str(uuidOfHGrid, uuidOfHGridStr);
+      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
       if ( uuidOfHGridStr[0] != 0 && strlen(uuidOfHGridStr) == 36 )
         fprintf(fp, "uuid      = %s\n", uuidOfHGridStr);
     }
 
   if ( gridptr->mask )
     {
-      nbyte0 = fprintf(fp, "mask      = ");
-      nbyte  = nbyte0;
-      for ( i = 0; i < gridsize; i++ )
-        {
-          if ( nbyte > 80 )
-            {
-              fprintf(fp, "\n");
-              fprintf(fp, "%*s", nbyte0, "");
-              nbyte = nbyte0;
-            }
-          nbyte += fprintf(fp, "%d ", (int) gridptr->mask[i]);
-        }
-      fprintf(fp, "\n");
+      static const char prefix[] = "mask      = ";
+      printMask(fp, prefix, sizeof (prefix),
+                (size_t)(gridsize > 0 ? gridsize : 0), gridptr->mask);
     }
 }
 
@@ -3365,72 +3605,64 @@ void gridPrint ( int gridID, int index, int opt )
 void gridPrintP ( void * voidptr, FILE * fp )
 {
   grid_t * gridptr = ( grid_t * ) voidptr;
-  int nbyte0, nbyte, i;
 
   xassert ( gridptr );
 
   gridPrintKernel ( gridptr , gridptr->self, 0, fp );
 
-  fprintf ( fp, "precision = %d\n", gridptr->prec);
-  fprintf ( fp, "nd        = %d\n", gridptr->nd );
-  fprintf ( fp, "ni        = %d\n", gridptr->ni );
-  fprintf ( fp, "ni2       = %d\n", gridptr->ni2 );
-  fprintf ( fp, "ni3       = %d\n", gridptr->ni3 ); 
-  fprintf ( fp, "number    = %d\n", gridptr->number );
-  fprintf ( fp, "position  = %d\n", gridptr->position );
-  fprintf ( fp, "trunc     = %d\n", gridptr->trunc );
-  fprintf ( fp, "lcomplex  = %d\n", gridptr->lcomplex );
-  fprintf ( fp, "nrowlon   = %d\n", gridptr->nrowlon );
+  fprintf(fp,
+          "precision = %d\n"
+          "nd        = %d\n"
+          "ni        = %d\n"
+          "ni2       = %d\n"
+          "ni3       = %d\n"
+          "number    = %d\n"
+          "position  = %d\n"
+          "trunc     = %d\n"
+          "lcomplex  = %d\n"
+          "nrowlon   = %d\n",
+          gridptr->prec, gridptr->nd, gridptr->ni, gridptr->ni2,
+          gridptr->ni3, gridptr->number, gridptr->position, gridptr->trunc,
+          gridptr->lcomplex, gridptr->nrowlon );
 
   if ( gridptr->rowlon )
     {
-      nbyte0 = fprintf(fp, "rowlon    = ");
-      nbyte  = nbyte0;
-      for ( i = 0; i < gridptr->nrowlon; i++ )
-        {
-          if ( nbyte > 80 )
-            {
-              fprintf(fp, "\n");
-              fprintf(fp, "%*s", nbyte0, "");
-              nbyte = nbyte0;
-            }
-          nbyte += fprintf(fp, "%d ", gridptr->rowlon[i]);
-        }
-      fprintf(fp, "\n");
+      static const char prefix[] = "rowlon    = ";
+      printIntsPrefixAutoBrk(fp, prefix, sizeof (prefix),
+                             (size_t)(gridptr->nrowlon > 0
+                                      ? gridptr->nrowlon : 0), gridptr->rowlon);
     }
 
   if ( gridptr->mask_gme )
     {
-      nbyte0 = fprintf(fp, "mask_gme  = ");
-      nbyte  = nbyte0;
-      for ( i = 0; i < gridptr->size; i++ )
-        {
-          if ( nbyte > 80 )
-            {
-              fprintf(fp, "\n");
-              fprintf(fp, "%*s", nbyte0, "");
-              nbyte = nbyte0;
-            }
-          nbyte += fprintf(fp, "%d ", (int) gridptr->mask_gme[i]);
-        }
-      fprintf(fp, "\n");
+      static const char prefix[] = "mask_gme  = ";
+      printMask(fp, prefix, sizeof (prefix),
+                (size_t)(gridptr->size > 0 ? gridptr->size : 0),
+                gridptr->mask_gme);
     }
 }
 
+static const double *gridInqXValsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->xvals;
+}
 
 const double *gridInqXvalsPtr(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  return ( gridptr->xvals );
+  return gridptr->vtable->inqXValsPtr(gridptr);
 }
 
 
+static const double *gridInqYValsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->yvals;
+}
+
 const double *gridInqYvalsPtr(int gridID)
 {
   grid_t *gridptr = gridID2Ptr(gridID);
-
-  return ( gridptr->yvals );
+  return gridptr->vtable->inqYValsPtr(gridptr);
 }
 
 /*
@@ -3476,7 +3708,7 @@ void gridDefLCC(int gridID, double originLon, double originLat, double lonParY,
       gridptr->lcc_projflag  = projflag;
       gridptr->lcc_scanflag  = scanflag;
       gridptr->lcc_defined   = TRUE;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -3545,7 +3777,7 @@ void gridDefLcc2(int gridID, double earth_radius, double lon_0, double lat_0, do
       gridptr->lcc2_lat_1   = lat_1;
       gridptr->lcc2_lat_2   = lat_2;
       gridptr->lcc2_defined = TRUE;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -3585,7 +3817,7 @@ void gridDefLaea(int gridID, double earth_radius, double lon_0, double lat_0)
       gridptr->laea_lon_0   = lon_0;
       gridptr->laea_lat_0   = lat_0;
       gridptr->laea_defined = TRUE;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -3618,8 +3850,8 @@ void gridDefComplexPacking(int gridID, int lcomplex)
 
   if (gridptr->lcomplex != lcomplex)
     {
-      gridptr->lcomplex = lcomplex;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridptr->lcomplex = (short)(lcomplex != 0);
+      gridMark4Update(gridID);
     }
 }
 
@@ -3636,10 +3868,10 @@ void gridDefHasDims(int gridID, int hasdims)
 {
   grid_t* gridptr = gridID2Ptr(gridID);
 
-  if (gridptr->hasdims != hasdims)
+  if (gridptr->hasdims != (hasdims != 0))
     {
-      gridptr->hasdims = hasdims;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridptr->hasdims = hasdims != 0;
+      gridMark4Update(gridID);
     }
 }
 
@@ -3672,7 +3904,7 @@ void gridDefNumber(int gridID, const int number)
   if (gridptr->number != number)
     {
       gridptr->number = number;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -3694,8 +3926,7 @@ The function @func{gridInqNumber} returns the reference number to an unstructure
 int gridInqNumber(int gridID)
 {
   grid_t* gridptr = gridID2Ptr(gridID);
-
-  return (gridptr->number);
+  return gridptr->number;
 }
 
 /*
@@ -3719,7 +3950,7 @@ void gridDefPosition(int gridID, int position)
   if (gridptr->position != position)
     {
       gridptr->position = position;
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -3772,7 +4003,7 @@ void gridDefReference(int gridID, const char *reference)
         }
 
       gridptr->reference = strdupx(reference);
-      reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+      gridMark4Update(gridID);
     }
 }
 
@@ -3823,7 +4054,7 @@ void gridDefUUID(int gridID, const unsigned char uuid[CDI_UUID_SIZE])
   grid_t* gridptr = gridID2Ptr(gridID);
 
   memcpy(gridptr->uuid, uuid, CDI_UUID_SIZE);
-  reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE);
+  gridMark4Update(gridID);
 }
 
 /*
@@ -3861,7 +4092,7 @@ gridTxCode ()
   return GRID;
 }
 
-enum { gridNint    = 27,
+enum { gridNint    = 28,
        gridNdouble = 24,
        gridHasMaskFlag = 1 << 0,
        gridHasGMEMaskFlag = 1 << 1,
@@ -3880,9 +4111,13 @@ static int gridGetComponentFlags(const grid_t * gridP)
 {
   int flags = (gridHasMaskFlag & (int)((unsigned)(gridP->mask == NULL) - 1U))
     | (gridHasGMEMaskFlag & (int)((unsigned)(gridP->mask_gme == NULL) - 1U))
-    | (gridHasXValsFlag & (int)((unsigned)(gridP->xvals == NULL) - 1U))
-    | (gridHasYValsFlag & (int)((unsigned)(gridP->yvals == NULL) - 1U))
-    | (gridHasAreaFlag & (int)((unsigned)(gridP->area == NULL) - 1U))
+    | (gridHasXValsFlag
+       & (int)((unsigned)(gridP->vtable->inqXValsPtr((grid_t *)gridP) == NULL) - 1U))
+    | (gridHasYValsFlag
+       & (int)((unsigned)(gridP->vtable->inqYValsPtr((grid_t *)gridP) == NULL) - 1U))
+    | (gridHasAreaFlag
+       & (int)((unsigned)(gridP->vtable->inqAreaPtr((grid_t *)gridP) == NULL)
+               - 1U))
     | (gridHasXBoundsFlag & (int)((unsigned)(gridP->xbounds == NULL) - 1U))
     | (gridHasYBoundsFlag & (int)((unsigned)(gridP->ybounds == NULL) - 1U))
     | (gridHasReferenceFlag & (int)((unsigned)(gridP->reference == NULL) - 1U))
@@ -3892,9 +4127,8 @@ static int gridGetComponentFlags(const grid_t * gridP)
 }
 
 
-#define GRID_STR_SERIALIZE { gridP->xname, gridP->yname, \
+#define GRID_STR_SERIALIZE(gridP) { gridP->xname, gridP->yname, \
     gridP->xlongname, gridP->ylongname, \
-    gridP->xstdname, gridP->ystdname, \
     gridP->xunits, gridP->yunits }
 
 static int
@@ -3915,7 +4149,7 @@ gridGetPackSize(void * voidP, void *context)
 
   packBuffSize += serializeGetSize(gridNdouble, DATATYPE_FLT64, context);
 
-  if (gridP->xvals)
+  if (gridP->vtable->inqXValsPtr(gridP))
     {
       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
 	count = gridP->size;
@@ -3926,7 +4160,7 @@ gridGetPackSize(void * voidP, void *context)
         + serializeGetSize(1, DATATYPE_UINT32, context);
     }
 
-  if (gridP->yvals)
+  if (gridP->vtable->inqYValsPtr(gridP))
     {
       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
 	count = gridP->size;
@@ -3937,7 +4171,7 @@ gridGetPackSize(void * voidP, void *context)
         + serializeGetSize(1, DATATYPE_UINT32, context);
     }
 
-  if (gridP->area)
+  if (gridP->vtable->inqAreaPtr(gridP))
     {
       xassert(gridP->size);
       packBuffSize +=
@@ -3972,7 +4206,7 @@ gridGetPackSize(void * voidP, void *context)
     }
 
   {
-    const char *strTab[] = GRID_STR_SERIALIZE;
+    const char *strTab[] = GRID_STR_SERIALIZE(gridP);
     int numStr = (int)(sizeof (strTab) / sizeof (strTab[0]));
     packBuffSize
       += serializeStrTabGetPackSize(strTab, numStr, context);
@@ -4054,9 +4288,10 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
     gridP->size          =   intBuffer[21];
     gridP->xsize         =   intBuffer[22];
     gridP->ysize         =   intBuffer[23];
-    gridP->locked        =   intBuffer[24];
-    gridP->lcomplex      =   intBuffer[25];
-    memberMask           =   intBuffer[26];
+    gridP->lcomplex      =   (short)intBuffer[24];
+    memberMask           =   intBuffer[25];
+    gridP->xstdname      =   xystdname_tab[intBuffer[26]][0];
+    gridP->ystdname      =   xystdname_tab[intBuffer[27]][1];
   }
 
   if (memberMask & gridHasRowLonFlag)
@@ -4169,7 +4404,7 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
     }
 
   {
-    char *strTab[] = GRID_STR_SERIALIZE;
+    char *strTab[] = GRID_STR_SERIALIZE(gridP);
     int numStr = sizeof (strTab) / sizeof (strTab[0]);
     serializeStrTabUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
                           strTab, numStr, context);
@@ -4256,9 +4491,12 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
     intBuffer[21] = gridP->size;
     intBuffer[22] = gridP->xsize;
     intBuffer[23] = gridP->ysize;
-    intBuffer[24] = gridP->locked;
-    intBuffer[25] = gridP->lcomplex;
-    intBuffer[26] = memberMask = gridGetComponentFlags(gridP);
+    intBuffer[24] = gridP->lcomplex;
+    intBuffer[25] = memberMask = gridGetComponentFlags(gridP);
+    intBuffer[26] = (int)((const char (*)[2][24])gridP->xstdname
+                          - xystdname_tab);
+    intBuffer[27] = (int)((const char (*)[2][24])gridP->ystdname
+                          - (const char (*)[2][24])xystdname_tab[0][1]);
 
     serializePack(intBuffer, gridNint, DATATYPE_INT,
                   packBuffer, packBufferSize, packBufferPos, context);
@@ -4321,9 +4559,10 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
 	size = gridP->xsize;
       xassert(size);
 
-      serializePack(gridP->xvals, size, DATATYPE_FLT64,
+      const double *gridP_xvals = gridP->vtable->inqXValsPtr(gridP);
+      serializePack(gridP_xvals, size, DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP->xvals);
+      d = cdiCheckSum(DATATYPE_FLT, size, gridP_xvals);
       serializePack(&d, 1, DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
@@ -4335,9 +4574,10 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
       else
 	size = gridP->ysize;
       xassert(size);
-      serializePack(gridP->yvals, size, DATATYPE_FLT64,
+      const double *gridP_yvals = gridP->vtable->inqYValsPtr(gridP);
+      serializePack(gridP_yvals, size, DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP->yvals);
+      d = cdiCheckSum(DATATYPE_FLT, size, gridP_yvals);
       serializePack(&d, 1, DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
@@ -4386,7 +4626,7 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
     }
 
   {
-    const char *strTab[] = GRID_STR_SERIALIZE;
+    const char *strTab[] = GRID_STR_SERIALIZE(gridP);
     int numStr = sizeof (strTab) / sizeof (strTab[0]);
     serializeStrTabPack(strTab, numStr,
                         packBuffer, packBufferSize, packBufferPos, context);
@@ -4433,16 +4673,16 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
 #undef GRID_STR_SERIALIZE
 
 
-struct varDefGridSearchState
+struct gridCompareSearchState
 {
   int resIDValue;
   const grid_t *queryKey;
 };
 
 static enum cdiApplyRet
-varDefGridSearch(int id, void *res, void *data)
+gridCompareSearch(int id, void *res, void *data)
 {
-  struct varDefGridSearchState *state = (struct varDefGridSearchState*)data;
+  struct gridCompareSearchState *state = (struct gridCompareSearchState*)data;
   (void)res;
   if (gridCompare(id, state->queryKey) == 0)
     {
@@ -4453,40 +4693,43 @@ varDefGridSearch(int id, void *res, void *data)
     return CDI_APPLY_GO_ON;
 }
 
-int varDefGrid(int vlistID, const grid_t *grid, int mode)
+/* Add grid (which must be Malloc'ed to vlist if not already found */
+struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
 {
   /*
     mode: 0 search in vlist and grid table
           1 search in grid table
    */
   int gridglobdefined = FALSE;
-  int griddefined;
+  int griddefined = FALSE;
   int gridID = CDI_UNDEFID;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  griddefined = FALSE;
   unsigned ngrids = (unsigned)vlistptr->ngrids;
 
   if ( mode == 0 )
     for (unsigned index = 0; index < ngrids; index++ )
       {
-	gridID = vlistptr->gridIDs[index];
-	if ( gridID == UNDEFID )
-	  Error("Internal problem: undefined gridID %d!", gridID);
+	if ( (gridID = vlistptr->gridIDs[index]) != UNDEFID )
+          {
+            if ( gridCompare(gridID, grid) == 0 )
+              {
+                griddefined = TRUE;
+                break;
+              }
+          }
+        else
+          Error("Internal problem: undefined gridID in vlist "
+                "%d, position %u!", vlistID, index);
 
-	if ( gridCompare(gridID, grid) == 0 )
-	  {
-	    griddefined = TRUE;
-	    break;
-	  }
       }
 
   if ( ! griddefined )
     {
-      struct varDefGridSearchState query;
+      struct gridCompareSearchState query;
       query.queryKey = grid;// = { .queryKey = grid };
       if ((gridglobdefined
-           = (cdiResHFilterApply(&gridOps, varDefGridSearch, &query)
+           = (cdiResHFilterApply(&gridOps, gridCompareSearch, &query)
               == CDI_APPLY_STOP)))
         gridID = query.resIDValue;
 
@@ -4501,15 +4744,51 @@ int varDefGrid(int vlistID, const grid_t *grid, int mode)
 
   if ( ! griddefined )
     {
-      if ( ! gridglobdefined ) gridID = gridGenerate(grid);
-      ngrids = (unsigned)vlistptr->ngrids;
+      if ( ! gridglobdefined )
+        {
+          grid->self = gridID = reshPut(grid, &gridOps);
+          gridComplete(grid);
+        }
       vlistptr->gridIDs[ngrids] = gridID;
       vlistptr->ngrids++;
     }
 
-  return (gridID);
+  return (struct addIffNewRes){ .Id = gridID,
+      .isNew = !griddefined && !gridglobdefined };
 }
 
+const struct gridVirtTable cdiGridVtable
+  = {
+  .destroy = gridDestroyKernel,
+  .copy = grid_copy_base,
+  .copyScalarFields = grid_copy_base_scalar_fields,
+  .copyArrayFields = grid_copy_base_array_fields,
+  .defXVals = gridDefXValsSerial,
+  .defYVals = gridDefYValsSerial,
+  .defMask = gridDefMaskSerial,
+  .defMaskGME = gridDefMaskGMESerial,
+  .defXBounds = gridDefXBoundsSerial,
+  .defYBounds = gridDefYBoundsSerial,
+  .defArea = gridDefAreaSerial,
+  .inqXVal = gridInqXValSerial,
+  .inqYVal = gridInqYValSerial,
+  .inqXVals = gridInqXValsSerial,
+  .inqYVals = gridInqYValsSerial,
+  .inqXValsPtr = gridInqXValsPtrSerial,
+  .inqYValsPtr = gridInqYValsPtrSerial,
+  .compareXYFull = compareXYvals,
+  .compareXYAO = compareXYvals2,
+  .inqArea = gridInqAreaSerial,
+  .inqAreaPtr = gridInqAreaPtrBase,
+  .hasArea = gridHasAreaBase,
+  .inqMask = gridInqMaskSerial,
+  .inqMaskGME = gridInqMaskGMESerial,
+  .inqXBounds = gridInqXBoundsSerial,
+  .inqYBounds = gridInqYBoundsSerial,
+  .inqXBoundsPtr = gridInqXBoundsPtrSerial,
+  .inqYBoundsPtr = gridInqYBoundsPtrSerial,
+};
+
 /*
  * Local Variables:
  * c-file-style: "Java"
diff --git a/libcdi/src/grid.h b/libcdi/src/grid.h
index a248f59..fea99d7 100644
--- a/libcdi/src/grid.h
+++ b/libcdi/src/grid.h
@@ -5,7 +5,44 @@
 
 typedef unsigned char mask_t;
 
-typedef struct {
+typedef struct grid_t grid_t;
+
+struct gridVirtTable
+{
+  void (*destroy)(grid_t *gridptr);
+  grid_t *(*copy)(grid_t *gridptr);
+  void (*copyScalarFields)(grid_t *gridptrOrig, grid_t *gridptrDup);
+  void (*copyArrayFields)(grid_t *gridptrOrig, grid_t *gridptrDup);
+  void (*defXVals)(grid_t *gridptr, const double *xvals);
+  void (*defYVals)(grid_t *gridptr, const double *yvals);
+  void (*defMask)(grid_t *gridptr, const int *mask);
+  void (*defMaskGME)(grid_t *gridptr, const int *mask);
+  void (*defXBounds)(grid_t *gridptr, const double *xbounds);
+  void (*defYBounds)(grid_t *gridptr, const double *ybounds);
+  void (*defArea)(grid_t *gridptr, const double *area);
+  double (*inqXVal)(grid_t *gridptr, int index);
+  double (*inqYVal)(grid_t *gridptr, int index);
+  int (*inqXVals)(grid_t *gridptr, double *xvals);
+  int (*inqYVals)(grid_t *gridptr, double *yvals);
+  const double *(*inqXValsPtr)(grid_t *gridptr);
+  const double *(*inqYValsPtr)(grid_t *gridptr);
+  /* return if for both grids, all xval and all yval are equal */
+  int (*compareXYFull)(grid_t *gridRef, grid_t *gridTest);
+  /* return if for both grids, x[0], y[0], x[size-1] and y[size-1] are
+   * respectively equal */
+  int (*compareXYAO)(grid_t *gridRef, grid_t *gridTest);
+  void (*inqArea)(grid_t *gridptr, double *area);
+  const double *(*inqAreaPtr)(grid_t *gridptr);
+  int (*hasArea)(grid_t *gridptr);
+  int (*inqMask)(grid_t *gridptr, int *mask);
+  int (*inqMaskGME)(grid_t *gridptr, int *mask_gme);
+  int (*inqXBounds)(grid_t *gridptr, double *xbounds);
+  int (*inqYBounds)(grid_t *gridptr, double *ybounds);
+  const double *(*inqXBoundsPtr)(grid_t *gridptr);
+  const double *(*inqYBoundsPtr)(grid_t *gridptr);
+};
+
+struct grid_t {
   int     self;
   int     type;                   /* grid type                      */
   int     prec;                   /* grid precision                 */
@@ -57,24 +94,28 @@ typedef struct {
   int     xsize;                  /* number of values along X */
   int     ysize;                  /* number of values along Y */
   int     np;                     /* number of parallels between a pole and the equator */
-  int     locked;
-  int     lcomplex;
-  int     hasdims;
+  short   lcomplex;
+  short   hasdims;
+  const char *xstdname;
+  const char *ystdname;
   char    xname[CDI_MAX_NAME];
   char    yname[CDI_MAX_NAME];
   char    xlongname[CDI_MAX_NAME];
   char    ylongname[CDI_MAX_NAME];
-  char    xstdname[CDI_MAX_NAME];
-  char    ystdname[CDI_MAX_NAME];
   char    xunits[CDI_MAX_NAME];
   char    yunits[CDI_MAX_NAME];
   char   *name;
-}
-grid_t;
+  const struct gridVirtTable *vtable;
+  void *extraData;
+};
 
 
 void grid_init(grid_t *gridptr);
+void
+cdiGridTypeInit(grid_t *gridptr, int gridtype, int size);
 void grid_free(grid_t *gridptr);
+grid_t *gridID2Ptr(int gridID);
+extern const struct gridVirtTable cdiGridVtable;
 
 unsigned cdiGridCount(void);
 
@@ -95,16 +136,13 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
            int * unpackBufferPos, int originNamespace, void *context,
            int force_id);
 
-int  varDefGrid(int vlistID, const grid_t *grid, int mode);
-
-/* These are used by CDO. */
-void gridGenXvals(int xsize, double xfirst, double xlast,
-                  double xinc, double *xvals);
-void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast,
-                  double yinc, double *yvals);
-
-
+struct addIffNewRes
+{
+  int Id;
+  int isNew;
+};
 
+struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode);
 
 #endif
 /*
diff --git a/libcdi/src/ieglib.c b/libcdi/src/ieglib.c
index 2e0d494..cbae283 100644
--- a/libcdi/src/ieglib.c
+++ b/libcdi/src/ieglib.c
@@ -297,15 +297,9 @@ int iegInqDataDP(void *ieg, double *data)
 static int
 iegDefData(iegrec_t *iegp, int prec, const void *data)
 {
-  int dprec;
-  void *buffer;
+  int dprec = iegDefaultDprec ? iegDefaultDprec : iegp->dprec;
 
-  if ( iegDefaultDprec ) dprec = iegDefaultDprec;
-  else                   dprec = iegp->dprec;
-
-  if ( ! dprec ) dprec = prec;
-
-  iegp->dprec = dprec;
+  iegp->dprec = dprec = dprec ? dprec : prec;
 
   size_t datasize = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
   size_t blocklen = datasize * (size_t)dprec;
@@ -314,16 +308,14 @@ iegDefData(iegrec_t *iegp, int prec, const void *data)
 
   size_t buffersize = iegp->buffersize;
 
+  void *buffer = iegp->buffer;
   if ( buffersize != blocklen )
     {
       buffersize = blocklen;
-      buffer = iegp->buffer;
       buffer = Realloc(buffer, buffersize);
       iegp->buffer = buffer;
       iegp->buffersize = buffersize;
     }
-  else
-    buffer = iegp->buffer;
 
   switch ( dprec )
     {
diff --git a/libcdi/src/institution.c b/libcdi/src/institution.c
index 10ea652..69c1cff 100644
--- a/libcdi/src/institution.c
+++ b/libcdi/src/institution.c
@@ -67,7 +67,7 @@ void instituteDefaultEntries ( void )
     = { ECMWF   = institutDef( 98,   0, "ECMWF",     "European Centre for Medium-Range Weather Forecasts"),
         MPIMET  = institutDef( 98, 232, "MPIMET",    "Max-Planck-Institute for Meteorology"),
         institutDef( 98, 255, "MPIMET",    "Max-Planck-Institute for Meteorology"),
-        institutDef( 98, 232, "MPIMET",    "Max-Planck Institute for Meteorology"),
+        institutDef( 98, 232, "MPIMET",    "Max Planck Institute for Meteorology"),
         institutDef( 78,   0, "DWD",       "Deutscher Wetterdienst"),
         institutDef( 78, 255, "DWD",       "Deutscher Wetterdienst"),
         MCH     = institutDef(215, 255, "MCH",       "MeteoSwiss"),
diff --git a/libcdi/src/iterator.c b/libcdi/src/iterator.c
index 2ed5933..eb63a23 100644
--- a/libcdi/src/iterator.c
+++ b/libcdi/src/iterator.c
@@ -433,7 +433,7 @@ int cdiIterator_nextField(CdiIterator* me)
     }
 }
 
-static char* cdiIterator_inqTime(CdiIterator* me, bool getEndTime)
+static char* cdiIterator_inqTime(CdiIterator* me, CdiTimeType timeType)
 {
   sanityCheck(me);
   switch(me->filetype)
@@ -441,7 +441,7 @@ static char* cdiIterator_inqTime(CdiIterator* me, bool getEndTime)
 #ifdef HAVE_LIBGRIB_API
         case FILETYPE_GRB:
         case FILETYPE_GRB2:
-          return cdiGribIterator_inqTime(me, getEndTime);
+          return cdiGribIterator_inqTime(me, timeType);
 #endif
 
 #ifdef HAVE_LIBNETCDF
@@ -459,7 +459,7 @@ static char* cdiIterator_inqTime(CdiIterator* me, bool getEndTime)
 #ifdef HAVE_LIBIEG
         case FILETYPE_IEG:
 #endif
-          return cdiFallbackIterator_inqTime(me, getEndTime);
+          return cdiFallbackIterator_inqTime(me, timeType);
 
       default:
         Error(kUnexpectedFileTypeMessage);
@@ -490,7 +490,7 @@ This is due to the fact that GRIB-API version 1.12.3 still does not implement th
 */
 char* cdiIterator_inqStartTime(CdiIterator* me)
 {
-  return cdiIterator_inqTime(me, false);
+  return cdiIterator_inqTime(me, kCdiTimeType_startTime);
 }
 
 /*
@@ -516,7 +516,34 @@ This is due to the fact that GRIB-API version 1.12.3 still does not implement th
 */
 char* cdiIterator_inqEndTime(CdiIterator* me)
 {
-  return cdiIterator_inqTime(me, true);
+  return cdiIterator_inqTime(me, kCdiTimeType_endTime);
+}
+
+/*
+ at Function cdiIterator_inqRTime
+ at Title Get the validity time of the current field
+
+ at Prototype char* cdiIterator_inqRTime(CdiIterator* me)
+ at Parameter
+    @item iterator The iterator to operate on.
+
+ at Result A malloc'ed string containing the validity time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
+
+ at Description
+The returned time is the validity time as it is returned by taxisInqVtime(), only more precise.
+That is, if the field is a time point, its time is returned,
+if it is a statistical field with an integration period, the end time of the integration period is returned.
+
+Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
+The caller is responsible to Free() the resulting string.
+
+If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
+as it is implemented by the standard C mktime() function.
+This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
+*/
+char* cdiIterator_inqRTime(CdiIterator* me)
+{
+  return cdiIterator_inqTime(me, kCdiTimeType_referenceTime);
 }
 
 /*
@@ -701,6 +728,105 @@ int cdiIterator_inqLevelUuid(CdiIterator* me, int* outVgridNumber, int* outLevel
 }
 
 /*
+ at Function cdiIterator_inqTile
+ at Title Inquire the tile information for the current field
+
+ at Prototype int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute)
+ at Parameter
+    @item iterator The iterator to operate on.
+    @item outTileIndex The index of the current tile, -1 if no tile information is available.
+    @item outTileAttribute The attribute of the current tile, -1 if no tile information is available.
+
+ at Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
+
+ at Description
+Inquire the tile index and attribute for the current field.
+*/
+int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute)
+{
+  sanityCheck(me);
+  switch(me->filetype)
+    {
+      #ifdef HAVE_LIBGRIB_API
+        case FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_inqTile(me, outTileIndex, outTileAttribute);
+      #endif
+
+      #ifdef HAVE_LIBNETCDF
+        case FILETYPE_NC:
+        case FILETYPE_NC2:
+        case FILETYPE_NC4:
+        case FILETYPE_NC4C:
+      #endif
+      #ifdef HAVE_LIBSERVICE
+        case FILETYPE_SRV:
+      #endif
+      #ifdef HAVE_LIBEXTRA
+        case FILETYPE_EXT:
+      #endif
+      #ifdef HAVE_LIBIEG
+        case FILETYPE_IEG:
+      #endif
+          return cdiFallbackIterator_inqTile(me, outTileIndex, outTileAttribute);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_ELIBNAVAIL;
+    }
+}
+
+/**
+ at Function cdiIterator_inqTileCount
+ at Title Inquire the tile count and tile attribute counts for the current field
+
+ at Prototype int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount)
+ at Parameter
+    @item iterator The iterator to operate on.
+    @item outTileCount The number of tiles used for this variable, zero if no tile information is available.
+    @item outTileAttributeCount The number of attributes available for the tile of this field, zero if no tile information is available.
+          Note: This is not the global attribute count, which would be impossible to infer without reading the entire file if it's a GRIB file.
+
+ at Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
+
+ at Description
+Inquire the tile count and tile attribute counts for the current field.
+*/
+int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount)
+{
+  sanityCheck(me);
+  switch(me->filetype)
+    {
+      #ifdef HAVE_LIBGRIB_API
+        case FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
+      #endif
+
+      #ifdef HAVE_LIBNETCDF
+        case FILETYPE_NC:
+        case FILETYPE_NC2:
+        case FILETYPE_NC4:
+        case FILETYPE_NC4C:
+      #endif
+      #ifdef HAVE_LIBSERVICE
+        case FILETYPE_SRV:
+      #endif
+      #ifdef HAVE_LIBEXTRA
+        case FILETYPE_EXT:
+      #endif
+      #ifdef HAVE_LIBIEG
+        case FILETYPE_IEG:
+      #endif
+          return cdiFallbackIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_ELIBNAVAIL;
+    }
+}
+
+/*
 @Function cdiIterator_inqParam
 @Title Get discipline, category, and number
 
@@ -720,6 +846,31 @@ CdiParam cdiIterator_inqParam(CdiIterator* me)
 }
 
 /*
+ at Function cdiIterator_inqParamParts
+ at Title Get discipline, category, and number
+
+ at Prototype void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber)
+ at Parameter
+    @item iterator The iterator to operate on.
+    @item outDiscipline This is used to return the discipline.
+    @item outCategory This is used to return the category.
+    @item outNumber This is used to return the number.
+
+ at Description
+    Simple metadata inspection function.
+
+    Some FORTRAN compilers produce wrong code for the cdiIterator_inqParam()-wrapper,
+    rendering it unusable from FORTRAN. This function is the workaround.
+*/
+void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber)
+{
+  CdiParam result = cdiIterator_inqParam(me);
+  if(outDiscipline) *outDiscipline = result.discipline;
+  if(outCategory) *outCategory = result.category;
+  if(outNumber) *outNumber = result.number;
+}
+
+/*
 @Function cdiIterator_inqDatatype
 @Title Get the datatype of the current field
 
diff --git a/libcdi/src/iterator_fallback.c b/libcdi/src/iterator_fallback.c
index 74177ba..213f85d 100644
--- a/libcdi/src/iterator_fallback.c
+++ b/libcdi/src/iterator_fallback.c
@@ -11,11 +11,12 @@
 
 struct CdiFallbackIterator {
   CdiIterator super;
-  int streamId, vlistId;
+  int streamId, vlistId, subtypeId;
   char *path;   //needed for clone() & serialize()
 
   int variableCount, curVariable;
   int curLevelCount, curLevel;
+  int curSubtypeCount, curSubtype;
   int curTimestep;
 };
 
@@ -39,12 +40,15 @@ static CdiFallbackIterator *cdiFallbackIterator_condestruct(CdiFallbackIterator
   if(me->vlistId == CDI_UNDEFID) goto closeStream;
   me->variableCount = vlistNvars(me->vlistId);
   if(me->variableCount <= 0) goto closeStream;
+  me->subtypeId = CDI_UNDEFID;   //Will be set in cdiFallbackIterator_nextField()
+  me->curSubtypeCount = -1;      //Will be set in cdiFallbackIterator_nextField()
   me->curLevelCount = -1;        //Will be set in cdiFallbackIterator_nextField()
 
   //These values are chosen so that the natural increment at the start of cdiFallbackIterator_nextField() will correctly position us at the first slice.
   me->curTimestep = 0;
   if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
-  me->curVariable = 0;
+  me->curVariable = -1;
+  me->curSubtype = -1;
   me->curLevel = -1;
   me->path = strdup(path);
   if(!me->path) goto closeStream;
@@ -70,14 +74,20 @@ CdiIterator *cdiFallbackIterator_new(const char *path, int filetype)
   return &cdiFallbackIterator_condestruct(NULL, path, filetype)->super;
 }
 
-//Fetches the info that is published by the variables in the base class from the current field.
-static void fetchSuperInfo(CdiFallbackIterator *me)
+//Fetches the info that is derived from the current variable. Most of this is published by the data members in the base class.
+static void fetchVariableInfo(CdiFallbackIterator *me)
 {
+  //Fetch data that's published via base class data members.
   me->super.datatype = vlistInqVarDatatype(me->vlistId, me->curVariable);
   me->super.timesteptype = vlistInqVarTsteptype(me->vlistId, me->curVariable);
   me->super.gridId = vlistInqVarGrid(me->vlistId, me->curVariable);
   int param = vlistInqVarParam(me->vlistId, me->curVariable);
   cdiDecodeParam(param, &me->super.param.number, &me->super.param.category, &me->super.param.discipline);
+
+  //Fetch the current level and subtype counts.
+  me->curLevelCount = zaxisInqSize(vlistInqVarZaxis(me->vlistId, me->curVariable));
+  me->subtypeId = vlistInqVarSubtype(me->vlistId, me->curVariable);
+  me->curSubtypeCount = (me->subtypeId == CDI_UNDEFID) ? 1 : subtypeInqSize(me->subtypeId);
 }
 
 CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *super)
@@ -93,10 +103,12 @@ CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *super)
   clone->curVariable = me->curVariable;
   clone->curLevelCount = me->curLevelCount;
   clone->curLevel = me->curLevel;
+  clone->curSubtypeCount = me->curSubtypeCount;
+  clone->curSubtype = me->curSubtype;
   clone->curTimestep = me->curTimestep;
 
   clone->super.isAdvanced = super->isAdvanced;
-  if(super->isAdvanced) fetchSuperInfo(clone);
+  if(super->isAdvanced) fetchVariableInfo(clone);
 
   return clone;
 }
@@ -107,8 +119,8 @@ char *cdiFallbackIterator_serialize(CdiIterator *super)
 
   char *escapedPath = cdiEscapeSpaces(me->path);
   char *result = (char *) Malloc(strlen(escapedPath)
-                         + 5 * (3 * sizeof (int) * CHAR_BIT / 8 + 1) + 1);
-  sprintf(result, "%s %d %d %d %d %d", escapedPath, me->variableCount, me->curVariable, me->curLevelCount, me->curLevel, me->curTimestep);
+                         + 7 * (3 * sizeof (int) * CHAR_BIT / 8 + 1) + 1);
+  sprintf(result, "%s %d %d %d %d %d %d %d", escapedPath, me->variableCount, me->curVariable, me->curLevelCount, me->curLevel, me->curSubtypeCount, me->curSubtype, me->curTimestep);
   Free(escapedPath);
   return result;
 }
@@ -142,11 +154,13 @@ CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *description)
   decodeValue(me->curVariable, description);
   decodeValue(me->curLevelCount, description);
   decodeValue(me->curLevel, description);
+  decodeValue(me->curSubtypeCount, description);
+  decodeValue(me->curSubtype, description);
   decodeValue(me->curTimestep, description);
 #undef decodeValue
 
   if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
-  if(me->super.isAdvanced) fetchSuperInfo(me);
+  if(me->super.isAdvanced) fetchVariableInfo(me);
 
   return me;
 
@@ -164,15 +178,20 @@ fail:
 static int advance(CdiFallbackIterator *me)
 {
   me->curLevel++;
-  if(me->curLevel == me->curLevelCount)
+  if(me->curLevel >= me->curLevelCount)
     {
       me->curLevel = 0;
-      me->curVariable++;
-      if(me->curVariable == me->variableCount)
+      me->curSubtype++;
+      if(me->curSubtype >= me->curSubtypeCount)
         {
-          me->curVariable = 0;
-          me->curTimestep++;
-          if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) return CDI_EEOF;
+          me->curSubtype = 0;
+          me->curVariable++;
+          if(me->curVariable >= me->variableCount)
+            {
+              me->curVariable = 0;
+              me->curTimestep++;
+              if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) return CDI_EEOF;
+            }
         }
     }
   return CDI_NOERR;
@@ -184,21 +203,37 @@ int cdiFallbackIterator_nextField(CdiIterator *super)
   int result = advance(me);
   if(result) return result;
 
-  if(!me->curLevel)
-    { //Fetch the information that may have changed (we are processing a new variable/timestep if this point is reached).
-      fetchSuperInfo(me);
-      me->curLevelCount = zaxisInqSize(vlistInqVarZaxis(me->vlistId, me->curVariable));
-    }
+  if(!me->curLevel && !me->curSubtype) fetchVariableInfo(me);   //Check whether we are processing a new variable/timestep and fetch the information that may have changed in this case.
   return CDI_NOERR;
 }
 
-char *cdiFallbackIterator_inqTime(CdiIterator *super, bool getEndTime)
+char *cdiFallbackIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
 {
   CdiFallbackIterator *me = (CdiFallbackIterator *)(void *)super;
-  if(getEndTime) return NULL;   //The stream interface does not export the start/end times of statistical fields, so we treat all data as point of time data, returning the validity time as the start time.
+
+  //retrieve the time information
   int taxisId = vlistInqTaxis(me->vlistId);
-  int date = taxisInqVdate(taxisId);
-  int time = taxisInqVtime(taxisId);
+  int date = 0, time = 0;
+  switch(timeType)
+    {
+      case kCdiTimeType_referenceTime:
+        date = taxisInqRdate(taxisId);
+        time = taxisInqRtime(taxisId);
+        break;
+
+      case kCdiTimeType_startTime:
+        date = taxisInqVdate(taxisId);
+        time = taxisInqVtime(taxisId);
+        break;
+
+      case kCdiTimeType_endTime:
+        return NULL;   //The stream interface does not export the start/end times of statistical fields, so we treat all data as point of time data, returning the validity time as the start time.
+
+      default:
+        assert(0 && "internal error, please report this bug");
+    }
+
+  //decode the time information and reencode it into an ISO-compliant string
   int year, month, day, hour, minute, second;
   cdiDecodeDate(date, &year, &month, &day);
   cdiDecodeTime(time, &hour, &minute, &second);
@@ -278,6 +313,58 @@ int cdiFallbackIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *
   return CDI_NOERR;
 }
 
+int cdiFallbackIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
+{
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+#ifndef __cplusplus
+  if(!outTileIndex) outTileIndex = &(int){0};
+  if(!outTileAttribute) outTileAttribute = &(int){0};
+#else
+  int dummy = 0;
+  if(!outTileIndex) outTileIndex = &dummy;
+  if(!outTileAttribute) outTileAttribute = &dummy;
+#endif
+
+  int error = CDI_NOERR;
+  if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
+    {
+      error = CDI_EINVAL;
+    }
+  else
+    {
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileIndex", outTileIndex)) error = CDI_EINVAL;
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileAttribute", outTileAttribute)) error = CDI_EINVAL;
+    }
+  if(error) *outTileIndex = *outTileAttribute = -1; //Guarantee defined values in case of an error.
+  return error;
+}
+
+int cdiFallbackIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
+{
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+#ifndef __cplusplus
+  if(!outTileCount) outTileCount = &(int){0};
+  if(!outTileAttributeCount) outTileAttributeCount = &(int){0};
+#else
+  int temp = 0;
+  if(!outTileCount) outTileCount = &temp;
+  if(!outTileAttributeCount) outTileAttributeCount = &temp;
+#endif
+
+  int error = CDI_NOERR;
+  if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
+    {
+      error = CDI_EINVAL;
+    }
+  else
+    {
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTiles", outTileCount)) error = CDI_EINVAL;
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTileAttributes", outTileAttributeCount)) error = CDI_EINVAL;
+    }
+  if(error) *outTileCount = *outTileAttributeCount = -1; //Guarantee defined values in case of an error.
+  return CDI_NOERR;
+}
+
 char *cdiFallbackIterator_copyVariableName(CdiIterator *super)
 {
   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
diff --git a/libcdi/src/iterator_fallback.h b/libcdi/src/iterator_fallback.h
index aee5ae9..6c7170f 100644
--- a/libcdi/src/iterator_fallback.h
+++ b/libcdi/src/iterator_fallback.h
@@ -9,6 +9,7 @@
 #define INCLUDE_GUARD_CDI_ITERATOR_FALLBACK_H
 
 #include "cdi.h"
+#include "cdi_int.h"
 #include "iterator.h"
 
 typedef struct CdiFallbackIterator CdiFallbackIterator;
@@ -21,11 +22,13 @@ CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *me);
 
 int cdiFallbackIterator_nextField(CdiIterator *me);
 
-char *cdiFallbackIterator_inqTime(CdiIterator *me, bool getEndTime);
+char *cdiFallbackIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
 int cdiFallbackIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
 int cdiFallbackIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
 int cdiFallbackIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
 char *cdiFallbackIterator_copyVariableName(CdiIterator *me);
+int cdiFallbackIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute);
+int cdiFallbackIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount);
 
 void cdiFallbackIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
 void cdiFallbackIterator_readFieldF(CdiIterator *me, float *buffer, size_t *nmiss);
diff --git a/libcdi/src/iterator_grib.c b/libcdi/src/iterator_grib.c
index 7dd6ba1..fc8ef71 100644
--- a/libcdi/src/iterator_grib.c
+++ b/libcdi/src/iterator_grib.c
@@ -21,14 +21,14 @@
 struct CdiGribIterator {
   CdiIterator super;
 
-  CdiInputFile* file;
+  CdiInputFile *file;
   off_t fileOffset;
-  unsigned char* gribBuffer;
+  unsigned char *gribBuffer;
   size_t bufferSize, curRecordSize;
 #ifdef HAVE_LIBGRIB_API
-  grib_handle* gribHandle;
+  grib_handle *gribHandle;
 #else
-  void* gribHandle;
+  void *gribHandle;
 #endif
 };
 
@@ -88,7 +88,7 @@ CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *super)
   CdiGribIterator *me = (CdiGribIterator*)super;
 
   //Allocate memory and copy data. (operations that may fail)
-  CdiGribIterator* result = (struct CdiGribIterator *) Malloc(sizeof(*result));
+  CdiGribIterator *result = (struct CdiGribIterator *) Malloc(sizeof(*result));
   if(!result) goto fail;
 
   result->file = me->file;
@@ -139,9 +139,9 @@ char *cdiGribIterator_serialize(CdiIterator *super)
 {
   CdiGribIterator *me = (CdiGribIterator*)super;
 
-  const char* path = cdiInputFile_getPath(me->file);
-  char* escapedPath = cdiEscapeSpaces(path);
-  char* result = (char *) Malloc(strlen(escapedPath) + 3 * sizeof(int) * CHAR_BIT/8);
+  const char *path = cdiInputFile_getPath(me->file);
+  char *escapedPath = cdiEscapeSpaces(path);
+  char *result = (char *) Malloc(strlen(escapedPath) + 3 * sizeof(int) * CHAR_BIT/8);
   sprintf(result, "%s %zu", escapedPath, me->fileOffset);
   Free(escapedPath);
   return result;
@@ -150,8 +150,8 @@ char *cdiGribIterator_serialize(CdiIterator *super)
 
 CdiGribIterator *cdiGribIterator_deserialize(const char *description)
 {
-  char* path;
-  CdiGribIterator* me = (CdiGribIterator *) Malloc(sizeof(*me));
+  char *path;
+  CdiGribIterator *me = (CdiGribIterator *) Malloc(sizeof(*me));
   if(!me) goto fail;
 
   description = baseIter_constructFromString(&me->super, description);
@@ -236,7 +236,7 @@ static ssize_t scanToGribMarker(CdiGribIterator *me)
       if(scannedBytes + scanSize > kMaxScanSize) scanSize = kMaxScanSize - scannedBytes;
       assert(scanSize <= me->bufferSize);
       int status = cdiInputFile_read(me->file, me->fileOffset + (off_t)scannedBytes, scanSize, &scanSize, me->gribBuffer);
-      if(status != CDI_NOERR && status != CDI_EEOF) return status;
+      if(status != CDI_NOERR && status != CDI_EEOF) return -1;
 
       const unsigned char *startPosition = positionOfGribMarker(me->gribBuffer, scanSize);
       if(startPosition)
@@ -246,21 +246,21 @@ static ssize_t scanToGribMarker(CdiGribIterator *me)
 
       //Get the offset for the next iteration if there is a next iteration.
       scanSize -= 3;        //so that we won't miss a 'GRIB' sequence that happens to be cut off
-      scannedBytes += scanSize;
-      scannedBytes &= ~(size_t)0xf; //make 16 bytes aligned
+      scanSize &= ~(size_t)0xf; //make 16 bytes aligned
+      if((ssize_t)scanSize <= 0) return -1; //ensure that we make progress
     }
   return -1;
 }
 
 static unsigned decode24(void *beData)
 {
-  unsigned char* bytes = (unsigned char *)beData;
+  unsigned char *bytes = (unsigned char *)beData;
   return ((unsigned)bytes[0] << 16) + ((unsigned)bytes[1] << 8) + (unsigned)bytes[2];
 }
 
 static uint64_t decode64(void *beData)
 {
-  unsigned char* bytes = (unsigned char *)beData;
+  unsigned char *bytes = (unsigned char *)beData;
   uint64_t result = 0;
   for(size_t i = 0; i < 8; i++) result = (result << 8) + bytes[i];
   return result;
@@ -367,10 +367,10 @@ int cdiGribIterator_nextField(CdiIterator *super)
   return CDI_NOERR;
 }
 
-char *cdiGribIterator_inqTime(CdiIterator *super, bool getEndTime)
+char *cdiGribIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
 {
   CdiGribIterator *me = (CdiGribIterator*)super;
-  return gribMakeTimeString(me->gribHandle, getEndTime);
+  return gribMakeTimeString(me->gribHandle, timeType);
 }
 
 int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
@@ -381,13 +381,13 @@ int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outN
   int zaxisType = ZAXIS_GENERIC;
   if(gribEditionNumber(me->gribHandle) <= 1)
     {
-      int levelType = gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", 255);
+      int levelType = (int)gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", 255);
       if(levelSelector && !isGrib1DualLevel(levelType)) levelType = 255;
       zaxisType = grib1ltypeToZaxisType(levelType);
     }
   else
     {
-      int levelType = gribGetLongDefault(me->gribHandle, levelSelector ? "typeOfSecondFixedSurface" : "typeOfFirstFixedSurface", 255);
+      int levelType = (int)gribGetLongDefault(me->gribHandle, levelSelector ? "typeOfSecondFixedSurface" : "typeOfFirstFixedSurface", 255);
       zaxisType = grib2ltypeToZaxisType(levelType);
     }
 
@@ -405,6 +405,7 @@ int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outN
 static double logicalLevelValue2(long gribType, long storedValue, long power)
 {
   double factor = 1;
+  assert(power >= 0);
   while(power--) factor *= 10;      //this is precise up to factor == 22.
   switch(gribType)
     {
@@ -450,7 +451,7 @@ static int readLevel2(grib_handle *gribHandle, const char *levelTypeKey, const c
 
       default:
         {
-          long power = gribGetLongDefault(gribHandle, powerKey, 0);  //1 byte
+          long power = 255 & gribGetLongDefault(gribHandle, powerKey, 0);  //1 byte
           if(power == 255) power = 0;
           long value = gribGetLongDefault(gribHandle, valueKey, 0);   //4 bytes
           *outValue1 = logicalLevelValue2(levelType, value, power);
@@ -525,6 +526,46 @@ int cdiGribIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *outL
   return CDI_NOERR;
 }
 
+int cdiGribIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
+{
+  CdiGribIterator *me = (CdiGribIterator*)super;
+  int trash;
+  if(!outTileIndex) outTileIndex = &trash;
+  if(!outTileAttribute) outTileAttribute = &trash;
+
+  //Get the values if possible.
+  int error = CDI_NOERR;
+  long value;
+  if(grib_get_long(me->gribHandle, "tileIndex", &value)) error = CDI_EINVAL;
+  *outTileIndex = (int)value;
+  if(grib_get_long(me->gribHandle, "tileAttribute", &value)) error = CDI_EINVAL;
+  *outTileAttribute = (int)value;
+
+  //Ensure defined return values in case of failure.
+  if(error) *outTileIndex = *outTileAttribute = -1;
+  return error;
+}
+
+int cdiGribIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
+{
+  CdiGribIterator *me = (CdiGribIterator*)super;
+  int trash;
+  if(!outTileCount) outTileCount = &trash;
+  if(!outTileAttributeCount) outTileAttributeCount = &trash;
+
+  //Get the values if possible.
+  int error = CDI_NOERR;
+  long value;
+  if(grib_get_long(me->gribHandle, "numberOfTiles", &value)) error = CDI_EINVAL;
+  *outTileCount = (int)value;
+  if(grib_get_long(me->gribHandle, "numberOfTileAttributes", &value)) error = CDI_EINVAL;
+  *outTileAttributeCount = (int)value;
+
+  //Ensure defined return values in case of failure.
+  if(error) *outTileCount = *outTileAttributeCount = 0;
+  return error;
+}
+
 char *cdiGribIterator_copyVariableName(CdiIterator *super)
 {
   CdiGribIterator *me = (CdiGribIterator*)super;
@@ -549,7 +590,7 @@ void cdiGribIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss
   CdiGribIterator *me = (CdiGribIterator*)super;
 
   size_t valueCount = gribGetArraySize(me->gribHandle, "values");
-  double* temp = (double *) Malloc(valueCount*sizeof(*temp));
+  double *temp = (double *) Malloc(valueCount*sizeof(*temp));
   cdiGribIterator_readField(super, temp, nmiss);
   for(size_t i = valueCount; i--; ) buffer[i] = (float)temp[i];
   Free(temp);
@@ -572,8 +613,8 @@ void cdiGribIterator_delete(CdiGribIterator *me)
 #ifdef HAVE_LIBGRIB_API
   if(me) cdiGribIterator_condestruct(me, NULL, 0);
 #else
-  (void)me;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  if (me)
+    xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
 #endif
 }
 
diff --git a/libcdi/src/iterator_grib.h b/libcdi/src/iterator_grib.h
index 2b19110..65b9962 100644
--- a/libcdi/src/iterator_grib.h
+++ b/libcdi/src/iterator_grib.h
@@ -8,6 +8,7 @@
 #define INCLUDE_GUARD_CDI_ITERATOR_GRIB_H
 
 #include "cdi.h"
+#include "cdi_int.h"
 #include "iterator.h"
 #include "input_file.h"
 
@@ -25,10 +26,12 @@ CdiGribIterator *cdiGribIterator_deserialize(const char *me);
 
 int cdiGribIterator_nextField(CdiIterator *me);
 
-char *cdiGribIterator_inqTime(CdiIterator *me, bool getEndTime);
+char *cdiGribIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
 int cdiGribIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
 int cdiGribIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
 int cdiGribIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
+int cdiGribIterator_inqTile(CdiIterator *me, int *outTileIndex, int *outTileAttribute);
+int cdiGribIterator_inqTileCount(CdiIterator *me, int *outTileCount, int *outTileAttributeCount);
 char *cdiGribIterator_copyVariableName(CdiIterator *me);
 
 void cdiGribIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
diff --git a/libcdi/src/mo_cdi.f90 b/libcdi/src/mo_cdi.f90
index 02a4b7f..1221ad0 100644
--- a/libcdi/src/mo_cdi.f90
+++ b/libcdi/src/mo_cdi.f90
@@ -1,6 +1,6 @@
 ! >>> Warning: This is a generated file. If you modify it, you get what you deserve. <<<
 !
-! Generated by "../../../../libcdi/interfaces/f2003/bindGen.rb" from input file "../../../../libcdi/src/cdi.h".
+! Generated by "../interfaces/f2003/bindGen.rb" from input file "../src/cdi.h".
 
 module mo_cdi
   use iso_c_binding
@@ -259,6 +259,7 @@ module mo_cdi
   public :: streamWriteRecord
   public :: streamWriteRecordF
   public :: streamReadRecord
+  public :: streamReadRecordF
   public :: streamCopyRecord
   public :: cdiIterator_new
   public :: cdiIterator_clone
@@ -268,11 +269,15 @@ module mo_cdi
   public :: cdiIterator_nextField
   public :: cdiIterator_inqStartTime
   public :: cdiIterator_inqEndTime
+  public :: cdiIterator_inqRTime
   public :: cdiIterator_inqVTime
   public :: cdiIterator_inqLevelType
   public :: cdiIterator_inqLevel
   public :: cdiIterator_inqLevelUuid
+  public :: cdiIterator_inqTile
+  public :: cdiIterator_inqTileCount
   public :: cdiIterator_inqParam
+  public :: cdiIterator_inqParamParts
   public :: cdiIterator_inqDatatype
   public :: cdiIterator_inqTsteptype
   public :: cdiIterator_inqVariableName
@@ -404,6 +409,9 @@ module mo_cdi
   public :: vlistHasVarKey
   public :: vlistInqVarDblKey
   public :: vlistInqVarIntKey
+  public :: vlistInqVarNamePtr
+  public :: vlistInqVarLongnamePtr
+  public :: vlistInqVarUnitsPtr
   public :: vlistInqNatts
   public :: vlistInqAtt
   public :: vlistDelAtt
@@ -626,6 +634,7 @@ module mo_cdi
   public :: subtypeInqActiveIndex
   public :: subtypeDefActiveIndex
   public :: subtypeInqTile
+  public :: subtypeInqAttribute
   public :: vlistInqVarSubtype
   public :: gribapiLibraryVersion
 
@@ -964,6 +973,14 @@ module mo_cdi
       integer(c_int), intent(inout) :: nmiss_dummy
     end subroutine streamReadRecord
 
+    subroutine streamReadRecordF(streamID_dummy, data_dummy, nmiss_dummy)&
+    & bind(c, name = 'streamReadRecordF')
+      import c_float, c_int
+      integer(c_int), value :: streamID_dummy
+      real(c_float), intent(inout) :: data_dummy(*)
+      integer(c_int), intent(inout) :: nmiss_dummy
+    end subroutine streamReadRecordF
+
     subroutine streamCopyRecord(streamIDdest_dummy, streamIDsrc_dummy) bind(c,&
     & name = 'streamCopyRecord')
       import c_int
@@ -3265,6 +3282,32 @@ contains
     end if
   end function cdiIterator_inqEndTime
 
+  function cdiIterator_inqRTime(me_dummy) result(f_result)
+    character(kind = c_char), dimension(:), pointer :: f_result
+    type(t_CdiIterator), intent(in) :: me_dummy
+    type(c_ptr) :: cString
+    integer :: rv_shape(1)
+    character(kind = c_char), dimension(:), pointer :: temp
+    interface
+      function lib_cdiIterator_inqRTime(me_dummy) bind(c, name =&
+      & 'cdiIterator_inqRTime') result(c_result)
+        import c_ptr
+        type(c_ptr) :: c_result
+        type(c_ptr), value :: me_dummy
+      end function lib_cdiIterator_inqRTime
+    end interface
+    cString = lib_cdiIterator_inqRTime(me_dummy%ptr)
+    if(c_associated(cString)) then
+      rv_shape(1) = int(lib_strlen(cString))
+      call c_f_pointer(cString, temp, rv_shape)
+      allocate(f_result(rv_shape(1)))
+      f_result = temp
+      call lib_free(cString)
+    else
+      f_result => null()
+    end if
+  end function cdiIterator_inqRTime
+
   function cdiIterator_inqVTime(me_dummy) result(f_result)
     character(kind = c_char), dimension(:), pointer :: f_result
     type(t_CdiIterator), intent(in) :: me_dummy
@@ -3449,6 +3492,48 @@ contains
     & outLevelCount_cptr, outUuid_cptr)
   end function cdiIterator_inqLevelUuid
 
+  function cdiIterator_inqTile(me_dummy, outTileIndex_dummy,&
+  & outTileAttribute_dummy) result(f_result)
+    integer(c_int) :: f_result
+    type(t_CdiIterator), intent(in) :: me_dummy
+    integer(c_int), intent(inout) :: outTileIndex_dummy
+    integer(c_int), intent(inout) :: outTileAttribute_dummy
+    interface
+      function lib_cdiIterator_inqTile(me_dummy, outTileIndex_dummy,&
+      & outTileAttribute_dummy) bind(c, name = 'cdiIterator_inqTile')&
+      & result(c_result)
+        import c_int, c_ptr
+        integer(c_int) :: c_result
+        type(c_ptr), value :: me_dummy
+        integer(c_int), intent(inout) :: outTileIndex_dummy
+        integer(c_int), intent(inout) :: outTileAttribute_dummy
+      end function lib_cdiIterator_inqTile
+    end interface
+    f_result = lib_cdiIterator_inqTile(me_dummy%ptr, outTileIndex_dummy,&
+    & outTileAttribute_dummy)
+  end function cdiIterator_inqTile
+
+  function cdiIterator_inqTileCount(me_dummy, outTileCount_dummy,&
+  & outTileAttributeCount_dummy) result(f_result)
+    integer(c_int) :: f_result
+    type(t_CdiIterator), intent(in) :: me_dummy
+    integer(c_int), intent(inout) :: outTileCount_dummy
+    integer(c_int), intent(inout) :: outTileAttributeCount_dummy
+    interface
+      function lib_cdiIterator_inqTileCount(me_dummy, outTileCount_dummy,&
+      & outTileAttributeCount_dummy) bind(c, name = 'cdiIterator_inqTileCount')&
+      & result(c_result)
+        import c_int, c_ptr
+        integer(c_int) :: c_result
+        type(c_ptr), value :: me_dummy
+        integer(c_int), intent(inout) :: outTileCount_dummy
+        integer(c_int), intent(inout) :: outTileAttributeCount_dummy
+      end function lib_cdiIterator_inqTileCount
+    end interface
+    f_result = lib_cdiIterator_inqTileCount(me_dummy%ptr, outTileCount_dummy,&
+    & outTileAttributeCount_dummy)
+  end function cdiIterator_inqTileCount
+
   function cdiIterator_inqParam(me_dummy) result(f_result)
     type(t_CdiParam) :: f_result
     type(t_CdiIterator), intent(in) :: me_dummy
@@ -3463,6 +3548,27 @@ contains
     f_result = lib_cdiIterator_inqParam(me_dummy%ptr)
   end function cdiIterator_inqParam
 
+  subroutine cdiIterator_inqParamParts(me_dummy, outDiscipline_dummy,&
+  & outCategory_dummy, outNumber_dummy)
+    type(t_CdiIterator), intent(in) :: me_dummy
+    integer(c_int), intent(inout) :: outDiscipline_dummy
+    integer(c_int), intent(inout) :: outCategory_dummy
+    integer(c_int), intent(inout) :: outNumber_dummy
+    interface
+      subroutine lib_cdiIterator_inqParamParts(me_dummy, outDiscipline_dummy,&
+      & outCategory_dummy, outNumber_dummy) bind(c, name =&
+      & 'cdiIterator_inqParamParts')
+        import c_int, c_ptr
+        type(c_ptr), value :: me_dummy
+        integer(c_int), intent(inout) :: outDiscipline_dummy
+        integer(c_int), intent(inout) :: outCategory_dummy
+        integer(c_int), intent(inout) :: outNumber_dummy
+      end subroutine lib_cdiIterator_inqParamParts
+    end interface
+    call lib_cdiIterator_inqParamParts(me_dummy%ptr, outDiscipline_dummy,&
+    & outCategory_dummy, outNumber_dummy)
+  end subroutine cdiIterator_inqParamParts
+
   function cdiIterator_inqDatatype(me_dummy) result(f_result)
     integer(c_int) :: f_result
     type(t_CdiIterator), intent(in) :: me_dummy
@@ -4395,6 +4501,75 @@ contains
     f_result = lib_vlistInqVarIntKey(vlistID_dummy, varID_dummy, name_temp)
   end function vlistInqVarIntKey
 
+  function vlistInqVarNamePtr(vlistID_dummy, varID_dummy) result(f_result)
+    character(kind = c_char), dimension(:), pointer :: f_result
+    integer(c_int), value :: vlistID_dummy
+    integer(c_int), value :: varID_dummy
+    type(c_ptr) :: ptr
+    integer :: rv_shape(1)
+    interface
+      function lib_vlistInqVarNamePtr(vlistID_dummy, varID_dummy) bind(c, name&
+      & = 'vlistInqVarNamePtr') result(c_result)
+        import c_int, c_ptr
+        type(c_ptr) :: c_result
+        integer(c_int), value :: vlistID_dummy
+        integer(c_int), value :: varID_dummy
+      end function lib_vlistInqVarNamePtr
+    end interface
+    f_result => null()
+    ptr = lib_vlistInqVarNamePtr(vlistID_dummy, varID_dummy)
+    if(c_associated(ptr)) then
+      rv_shape(1) = int(lib_strlen(ptr))
+      call c_f_pointer(ptr, f_result, rv_shape)
+    end if
+  end function vlistInqVarNamePtr
+
+  function vlistInqVarLongnamePtr(vlistID_dummy, varID_dummy) result(f_result)
+    character(kind = c_char), dimension(:), pointer :: f_result
+    integer(c_int), value :: vlistID_dummy
+    integer(c_int), value :: varID_dummy
+    type(c_ptr) :: ptr
+    integer :: rv_shape(1)
+    interface
+      function lib_vlistInqVarLongnamePtr(vlistID_dummy, varID_dummy) bind(c,&
+      & name = 'vlistInqVarLongnamePtr') result(c_result)
+        import c_int, c_ptr
+        type(c_ptr) :: c_result
+        integer(c_int), value :: vlistID_dummy
+        integer(c_int), value :: varID_dummy
+      end function lib_vlistInqVarLongnamePtr
+    end interface
+    f_result => null()
+    ptr = lib_vlistInqVarLongnamePtr(vlistID_dummy, varID_dummy)
+    if(c_associated(ptr)) then
+      rv_shape(1) = int(lib_strlen(ptr))
+      call c_f_pointer(ptr, f_result, rv_shape)
+    end if
+  end function vlistInqVarLongnamePtr
+
+  function vlistInqVarUnitsPtr(vlistID_dummy, varID_dummy) result(f_result)
+    character(kind = c_char), dimension(:), pointer :: f_result
+    integer(c_int), value :: vlistID_dummy
+    integer(c_int), value :: varID_dummy
+    type(c_ptr) :: ptr
+    integer :: rv_shape(1)
+    interface
+      function lib_vlistInqVarUnitsPtr(vlistID_dummy, varID_dummy) bind(c, name&
+      & = 'vlistInqVarUnitsPtr') result(c_result)
+        import c_int, c_ptr
+        type(c_ptr) :: c_result
+        integer(c_int), value :: vlistID_dummy
+        integer(c_int), value :: varID_dummy
+      end function lib_vlistInqVarUnitsPtr
+    end interface
+    f_result => null()
+    ptr = lib_vlistInqVarUnitsPtr(vlistID_dummy, varID_dummy)
+    if(c_associated(ptr)) then
+      rv_shape(1) = int(lib_strlen(ptr))
+      call c_f_pointer(ptr, f_result, rv_shape)
+    end if
+  end function vlistInqVarUnitsPtr
+
   function vlistInqAtt(vlistID_dummy, varID_dummy, attrnum_dummy, name_dummy,&
   & typep_dummy, lenp_dummy) result(f_result)
     integer(c_int) :: f_result
@@ -6227,4 +6402,32 @@ contains
     end do
   end subroutine streamInqHistoryString
 
+  function subtypeInqAttribute(subtypeID_dummy, index_dummy, key_dummy,&
+  & outValue_dummy) result(f_result)
+    integer(c_int) :: f_result
+    integer(c_int), value :: subtypeID_dummy
+    integer(c_int), value :: index_dummy
+    character(kind = c_char, len = *), intent(in) :: key_dummy
+    integer(c_int), intent(inout) :: outValue_dummy
+    character(kind = c_char) :: key_temp(len(key_dummy) + 1)
+    integer :: key_i
+    interface
+      function lib_subtypeInqAttribute(subtypeID_dummy, index_dummy, key_dummy,&
+      & outValue_dummy) bind(c, name = 'subtypeInqAttribute') result(c_result)
+        import c_char, c_int
+        integer(c_int) :: c_result
+        integer(c_int), value :: subtypeID_dummy
+        integer(c_int), value :: index_dummy
+        character(kind = c_char) :: key_dummy(*)
+        integer(c_int), intent(inout) :: outValue_dummy
+      end function lib_subtypeInqAttribute
+    end interface
+    do key_i = 1, len(key_dummy)
+      key_temp(key_i) = key_dummy(key_i:key_i)
+    end do
+    key_temp(len(key_dummy) + 1) = c_null_char
+    f_result = lib_subtypeInqAttribute(subtypeID_dummy, index_dummy, key_temp,&
+    & outValue_dummy)
+  end function subtypeInqAttribute
+
 end module mo_cdi
diff --git a/libcdi/src/namespace.h b/libcdi/src/namespace.h
index 436a759..3609562 100644
--- a/libcdi/src/namespace.h
+++ b/libcdi/src/namespace.h
@@ -55,7 +55,7 @@ union namespaceSwitchValue
 void             namespaceCleanup      ( void );
 int              namespaceGetNumber    ( void );
 //void             namespaceSetActive(int namespaceID);
-int              namespaceGetActive    ( void );
+//int              namespaceGetActive    ( void );
 int              namespaceIdxEncode    ( namespaceTuple_t );
 int              namespaceIdxEncode2   ( int, int );
 namespaceTuple_t namespaceResHDecode   ( int );
diff --git a/libcdi/src/pio_client.c b/libcdi/src/pio_client.c
index a8249d7..100e25d 100644
--- a/libcdi/src/pio_client.c
+++ b/libcdi/src/pio_client.c
@@ -122,6 +122,16 @@ cdiPioClientStreamDefVlist_(int streamID, int vlistID)
   cdiPioClientStreamWinCreate(streamID, &cspec);
 }
 
+/* If we're not using GNU C, elide __attribute__ */
+#if ! defined __GNUC__ && ! defined __attribute__
+#  define  __attribute__(x)  /*NOTHING*/
+#endif
+
+static void
+cdiPioClientStreamWriteVar_(int streamID, int varID, int memtype,
+                            const void *data, int nmiss)
+  __attribute__((noreturn));
+
 static void
 cdiPioClientStreamWriteVar_(int streamID, int varID, int memtype,
                             const void *data, int nmiss)
diff --git a/libcdi/src/pio_mpi_fw_at_reblock.c b/libcdi/src/pio_mpi_fw_at_reblock.c
index 57c1901..961ef34 100644
--- a/libcdi/src/pio_mpi_fw_at_reblock.c
+++ b/libcdi/src/pio_mpi_fw_at_reblock.c
@@ -17,6 +17,7 @@
 #include <mpi.h>
 
 #include "cdi.h"
+#include "cdi_int.h"
 #include "dmemory.h"
 #include "error.h"
 #include "namespace.h"
@@ -172,7 +173,7 @@ initAFiledataFileWriteAtReblock(const char *filename, size_t bufSize)
 #undef MINBLOCKSIZE
     /* ensure block size also meets page and direct I/O buffer
      * alignment requirements */
-    size_t pageSize = cdiPioGetPageSize(largePageAlign),
+    size_t pageSize = cdiGetPageSize(largePageAlign),
       IOAlign = getXferBufAlign(filename);
     bufBlockAlign = lcm(pageSize, IOAlign);
     blockSize = lcm(blockSize, bufBlockAlign);
diff --git a/libcdi/src/pio_server.c b/libcdi/src/pio_server.c
index e203a74..050a6ec 100644
--- a/libcdi/src/pio_server.c
+++ b/libcdi/src/pio_server.c
@@ -278,32 +278,11 @@ buildVarRedist(int headerIdx, size_t streamIdx,
 }
 
 
-static void
-gatherArray(int headerIdx, size_t streamIdx,
-            double *gatherBuf,
-            /* index list representing the data elements gathered on
-             * this rank */
-            Xt_idxlist dstList,
-            const struct cdiPioConf *conf)
-{
-  Xt_redist gatherRedist = buildVarRedist(headerIdx, streamIdx,
-                                          dstList, conf);
-  xt_redist_s_exchange1(gatherRedist,
-                        rxWin[streamIdx].clientBuf[0].mem, gatherBuf);
-  xt_redist_delete(gatherRedist);
-}
-
 struct xyzDims
 {
   int sizes[3];
 };
 
-static inline int
-xyzGridSize(struct xyzDims dims)
-{
-  return dims.sizes[0] * dims.sizes[1] * dims.sizes[2];
-}
-
 static Xt_idxlist
 buildVarSlicesIdxList(int vlistID, int varID, int startLvl, int numLvl)
 {
@@ -336,6 +315,23 @@ countVarChunkMissingVals(int vlistID, int varID,
   return nmiss;
 }
 
+#ifdef HAVE_LIBNETCDF
+static void
+gatherArray(int headerIdx, size_t streamIdx,
+            double *gatherBuf,
+            /* index list representing the data elements gathered on
+             * this rank */
+            Xt_idxlist dstList,
+            const struct cdiPioConf *conf)
+{
+  Xt_redist gatherRedist = buildVarRedist(headerIdx, streamIdx,
+                                          dstList, conf);
+  xt_redist_s_exchange1(gatherRedist,
+                        rxWin[streamIdx].clientBuf[0].mem, gatherBuf);
+  xt_redist_delete(gatherRedist);
+}
+#endif
+
 #ifdef HAVE_PARALLEL_NC4
 static void
 queryVarBounds(struct PPM_extent varShape[3], int vlistID, int varID)
@@ -1052,7 +1048,7 @@ writeGribStream(size_t streamIdx,
                                     * (size_t)1024 * (size_t)1024,
                                     sizeof (double) * myAggSize);
           if (posix_memalign(&rxWin[streamIdx].aggBuf,
-                             cdiPioGetPageSize(conf->largePageAlign),
+                             cdiGetPageSize(conf->largePageAlign),
                              aggBufSize) == 0) ;
           else
             rxWin[streamIdx].aggBuf = Malloc(aggBufSize);
diff --git a/libcdi/src/pio_util.c b/libcdi/src/pio_util.c
index c1dd898..811e321 100644
--- a/libcdi/src/pio_util.c
+++ b/libcdi/src/pio_util.c
@@ -189,56 +189,12 @@ cdiPioQueryVarDims(int varShape[3], int vlistID, int varID)
     case GRID_CURVILINEAR:
     case GRID_UNSTRUCTURED:
       xabort("unimplemented grid type: %d", gridType);
-      break;
     }
   varShape[2] = zaxisInqSize(zaxisID);
   /* FIXME: other grids have different dimensionality */
   return (varShape[2] == 1)?2:3;
 }
 
-size_t
-cdiPioGetPageSize(bool largePageAlign)
-{
-  long pagesize = -1L;
-  bool nameAssigned = false;
-#if HAVE_DECL__SC_LARGE_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE || HAVE_DECL__SC_PAGESIZE
-  int name;
-#if HAVE_DECL__SC_LARGE_PAGESIZE
-  if (largePageAlign)
-    {
-      name = _SC_LARGE_PAGESIZE;
-      nameAssigned = true;
-    }
-  else
-#endif
-    {
-#if HAVE_DECL__SC_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE
-      name =
-#if HAVE_DECL__SC_PAGESIZE
-        _SC_PAGESIZE
-#elif HAVE_DECL__SC_PAGE_SIZE
-        _SC_PAGE_SIZE
-#endif
-        ;
-      nameAssigned = true;
-#endif
-    }
-  if (nameAssigned)
-    pagesize = sysconf(name);
-#endif
-  if (pagesize == -1L)
-    pagesize =
-#if HAVE_DECL_PAGESIZE
-      PAGESIZE
-#elif HAVE_DECL_PAGE_SIZE
-      PAGE_SIZE
-#else
-      commonPageSize
-#endif
-      ;
-  return (size_t)pagesize;
-}
-
 
 
 void
diff --git a/libcdi/src/pio_util.h b/libcdi/src/pio_util.h
index 20d887a..6be66af 100644
--- a/libcdi/src/pio_util.h
+++ b/libcdi/src/pio_util.h
@@ -94,7 +94,7 @@ void printArray ( const char *, const char *, const void *, int, int, const char
 #define xprintArray(ps,array,n,datatype)                                \
   if ( ddebug )                                                         \
       printArray ( debugString, ps, array, n, datatype,  __func__, __FILE__, __LINE__ )
- 
+
 #define xprintArray3(ps,array,n,datatype)                                \
   if ( ddebug == MAXDEBUG )                                                         \
       printArray ( debugString, ps, array, n, datatype,  __func__, __FILE__, __LINE__ )
@@ -105,15 +105,6 @@ void printArray ( const char *, const char *, const void *, int, int, const char
 int
 cdiPioQueryVarDims(int varShape[3], int vlistID, int varID);
 
-enum {
-  /* 8192 is known to work on most systems (4096 isn't on Alpha) */
-  commonPageSize = 8192,
-};
-
-size_t
-cdiPioGetPageSize(bool largePageAlign);
-
-
 #endif
 /*
  * Local Variables:
diff --git a/libcdi/src/stream.c b/libcdi/src/stream.c
index 068fb55..79e5ecc 100644
--- a/libcdi/src/stream.c
+++ b/libcdi/src/stream.c
@@ -7,8 +7,6 @@
 #endif
 
 #include <ctype.h>
-#include <stdio.h>
-#include <string.h>
 
 #include "binary.h"
 #include "cdi.h"
@@ -25,15 +23,10 @@
 #include "file.h"
 #include "cgribex.h"
 #include "gribapi.h"
-#include "cdf.h"
-#include "service.h"
-#include "extra.h"
-#include "ieg.h"
 #include "vlist.h"
 #include "serialize.h"
 #include "resource_handle.h"
 #include "resource_unpack.h"
-
 #include "namespace.h"
 
 
@@ -151,6 +144,7 @@ int cdiGetFiletype(const char *filename, int *byteorder)
       if ( CDI_Debug ) Message("found IEG file = %s", filename);
     }
 #endif
+#if  defined  (HAVE_LIBCGRIBEX)
   else if ( gribCheckSeek(fileID, &recpos, &version) == 0 )
     {
       if ( version <= 1 )
@@ -164,6 +158,7 @@ int cdiGetFiletype(const char *filename, int *byteorder)
 	  if ( CDI_Debug ) Message("found seeked GRIB2 file = %s", filename);
 	}
     }
+#endif
 
   fileClose(fileID);
 
@@ -194,9 +189,6 @@ The valid CDI file format types are @func{FILETYPE_GRB}, @func{FILETYPE_GRB2}, @
 int streamInqFiletype(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->filetype);
 }
 
@@ -240,9 +232,6 @@ with the file format type @func{FILETYPE_SRV}, @func{FILETYPE_EXT} or @func{FILE
 void streamDefByteorder(int streamID, int byteorder)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   streamptr->byteorder = byteorder;
   int filetype = streamptr->filetype;
 
@@ -300,9 +289,6 @@ The valid CDI byte order types are @func{CDI_BIGENDIAN} and @func{CDI_LITTLEENDI
 int streamInqByteorder(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->byteorder);
 }
 
@@ -326,9 +312,6 @@ const char *streamFilesuffix(int filetype)
 const char *streamFilename(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->filename);
 }
 
@@ -337,9 +320,6 @@ long cdiInqTimeSize(int streamID)
 {
   int tsID = 0, nrecs;
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   long ntsteps = streamptr->ntsteps;
 
   if ( ntsteps == (long)CDI_UNDEFID )
@@ -433,7 +413,12 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
     case FILETYPE_GRB:
     case FILETYPE_GRB2:
       {
+#ifndef __cplusplus
         fileID = gribOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = gribOpen(filename, temp);
+#endif
         if ( fileID < 0 ) fileID = CDI_ESYSTEM;
         if (recordBufIsToBeCreated)
           {
@@ -446,7 +431,12 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 #if  defined  (HAVE_LIBSERVICE)
     case FILETYPE_SRV:
       {
+#ifndef __cplusplus
         fileID = fileOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = fileOpen(filename, temp);
+#endif
         if ( fileID < 0 ) fileID = CDI_ESYSTEM;
         if (recordBufIsToBeCreated)
           {
@@ -460,7 +450,13 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 #if  defined  (HAVE_LIBEXTRA)
     case FILETYPE_EXT:
       {
+#ifndef __cplusplus
         fileID = fileOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = fileOpen(filename, temp);
+#endif
+
         if ( fileID < 0 ) fileID = CDI_ESYSTEM;
         if (recordBufIsToBeCreated)
           {
@@ -474,7 +470,12 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 #if  defined  (HAVE_LIBIEG)
     case FILETYPE_IEG:
       {
+#ifndef __cplusplus
         fileID = fileOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = fileOpen(filename, temp);
+#endif
         if ( fileID < 0 ) fileID = CDI_ESYSTEM;
         if (recordBufIsToBeCreated)
           {
@@ -488,18 +489,33 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 #if  defined  (HAVE_LIBNETCDF)
     case FILETYPE_NC:
       {
+#ifndef __cplusplus
         fileID = cdfOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = cdfOpen(filename, temp);
+#endif
         break;
       }
     case FILETYPE_NC2:
       {
+#ifndef __cplusplus
         fileID = cdfOpen64(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = cdfOpen64(filename, temp);
+#endif
         break;
       }
     case FILETYPE_NC4:
     case FILETYPE_NC4C:
       {
+#ifndef __cplusplus
         fileID = cdf4Open(filename, (char [2]){filemode, 0}, &filetype);
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = cdf4Open(filename, temp, &filetype);
+#endif
         break;
       }
 #endif
@@ -516,9 +532,7 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 }
 
 
-int
-streamOpenID(const char *filename, char filemode, int filetype,
-             int resH)
+int streamOpenID(const char *filename, char filemode, int filetype, int resH)
 {
   int fileID = CDI_UNDEFID;
   int status;
@@ -541,37 +555,49 @@ streamOpenID(const char *filename, char filemode, int filetype,
     fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
   }
 
-  if (fileID < 0)
+  if ( fileID < 0 )
     {
-      Free(streamptr->record);
-      stream_delete_entry(streamptr);
       streamID = fileID;
     }
   else
     {
-      streamID  = streamptr->self;
+      streamID = streamptr->self;
 
-      if ( streamID < 0 ) return (CDI_ELIMIT);
+      if ( streamID < 0 ) return CDI_ELIMIT;
 
       streamptr->filemode = filemode;
       streamptr->filename = strdupx(filename);
       streamptr->fileID   = fileID;
 
       if ( filemode == 'r' )
-	{
-	  int vlistID = vlistCreate();
-	  if ( vlistID < 0 ) return(CDI_ELIMIT);
-
-	  streamptr->vlistID = vlistID;
-	  /* cdiReadByteorder(streamID); */
-	  status = cdiInqContents(streamptr);
-	  if ( status < 0 ) return (status);
-	  vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
-	  vlistptr->ntsteps = streamptr->ntsteps;
-	}
+        {
+          int vlistID = vlistCreate();
+          if ( vlistID < 0 ) return(CDI_ELIMIT);
+
+          cdiVlistMakeInternal(vlistID);
+          streamptr->vlistID = vlistID;
+          /* cdiReadByteorder(streamID); */
+          status = cdiInqContents(streamptr);
+          if ( status < 0 )
+            {
+              streamID = status;
+            }
+          else
+            {
+              vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
+              vlistptr->ntsteps = streamptr->ntsteps;
+              cdiVlistMakeImmutable(vlistID);
+            }
+        }
     }
 
-  return (streamID);
+  if ( streamID < 0 )
+    {
+      Free(streamptr->record);
+      stream_delete_entry(streamptr);
+    }
+
+  return streamID;
 }
 
 static int streamOpen(const char *filename, const char *filemode, int filetype)
@@ -613,11 +639,13 @@ static int streamOpenA(const char *filename, const char *filemode, int filetype)
   streamptr->fileID   = fileID;
 
   streamptr->vlistID = vlistCreate();
+  cdiVlistMakeInternal(streamptr->vlistID);
   /* cdiReadByteorder(streamID); */
   status = cdiInqContents(streamptr);
   if ( status < 0 ) return (status);
   vlistptr = vlist_to_pointer(streamptr->vlistID);
   vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
+  if(!strcmp(filemode, "r")) cdiVlistMakeImmutable(streamptr->vlistID);
 
   {
     void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
@@ -718,7 +746,7 @@ open stream. Otherwise, a negative number with the error status is returned.
 @EndList
 
 @Example
-Here is an example using @func{streamOpenRead} to open an existing netCDF
+Here is an example using @func{streamOpenRead} to open an existing NetCDF
 file named @func{foo.nc} for reading:
 
 @Source
@@ -800,7 +828,7 @@ open stream. Otherwise, a negative number with the error status is returned.
 @EndList
 
 @Example
-Here is an example using @func{streamOpenWrite} to create a new netCDF file named @func{foo.nc} for writing:
+Here is an example using @func{streamOpenWrite} to create a new NetCDF file named @func{foo.nc} for writing:
 
 @Source
 #include "cdi.h"
@@ -986,8 +1014,6 @@ void streamClose(int streamID)
   int index;
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  stream_check_ptr(__func__, streamptr);
-
   if ( CDI_Debug )
     Message("streamID = %d filename = %s", streamID, streamptr->filename);
 
@@ -1045,8 +1071,7 @@ void streamClose(int streamID)
 	    taxisDestroy(vlistInqTaxis(vlistID));
 	  }
 
-      vlist_unlock(vlistID);
-      vlistDestroy(vlistID);
+      cdiVlistDestroy_(vlistID);
     }
 
   stream_delete_entry(streamptr);
@@ -1124,8 +1149,6 @@ void streamSync(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  stream_check_ptr(__func__, streamptr);
-
   void (*myStreamSync_)(stream_t *streamptr)
     = (void (*)(stream_t *))namespaceSwitchGet(NSSWITCH_STREAM_SYNC).func;
   myStreamSync_(streamptr);
@@ -1136,11 +1159,11 @@ int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
 {
   int taxisID = 0;
 
+  stream_check_ptr(__func__, streamptr);
+
   if ( CDI_Debug )
     Message("streamID = %d  tsID = %d", streamptr->self, tsID);
 
-  stream_check_ptr(__func__, streamptr);
-
   int vlistID = streamptr->vlistID;
 
   int time_is_varying = vlistHasTime(vlistID);
@@ -1177,7 +1200,7 @@ int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
        streamptr->filetype == FILETYPE_NC2 ||
        streamptr->filetype == FILETYPE_NC4 ||
        streamptr->filetype == FILETYPE_NC4C)
-      && vlistHasTime(vlistID))
+      && time_is_varying)
     {
       void (*myCdfDefTimestep)(stream_t *streamptr, int tsID)
         = (void (*)(stream_t *, int))
@@ -1246,9 +1269,6 @@ int streamInqTimestep(int streamID, int tsID)
   int nrecs = 0;
   int taxisID;
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   int vlistID = streamptr->vlistID;
 
   if ( tsID < streamptr->rtsteps )
@@ -1331,570 +1351,11 @@ int streamInqTimestep(int streamID, int tsID)
   return (nrecs);
 }
 
-/* the single image implementation */
-static
-void cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmiss)
-{
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
-
-  check_parg(data);
-  check_parg(nmiss);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
-  int filetype = streamptr->filetype;
-
-  *nmiss = 0;
-
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("grbReadVar not implemented for memtype float!");
-        grbReadVarDP(streamptr, varID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("srvReadVar not implemented for memtype float!");
-        srvReadVarDP(streamptr, varID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("extReadVar not implemented for memtype float!");
-        extReadVarDP(streamptr, varID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("iegReadVar not implemented for memtype float!");
-        iegReadVarDP(streamptr, varID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-        if ( memtype == MEMTYPE_FLOAT )
-          cdfReadVarSP(streamptr, varID, (float *)data, nmiss);
-        else
-          cdfReadVarDP(streamptr, varID, (double *)data, nmiss);
-
-	break;
-      }
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
-      }
-    }
-}
-
-/*
- at Function  streamReadVar
- at Title     Read a variable
-
- at Prototype void streamReadVar(int streamID, int varID, double *data, int *nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamReadVar reads all the values of one time step of a variable
-from an open dataset.
- at EndFunction
-*/
-void streamReadVar(int streamID, int varID, double *data, int *nmiss)
-{
-  cdiStreamReadVar(streamID, varID, MEMTYPE_DOUBLE, data, nmiss);
-}
-
-/*
- at Function  streamReadVarF
- at Title     Read a variable
-
- at Prototype void streamReadVar(int streamID, int varID, float *data, int *nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamReadVar reads all the values of one time step of a variable
-from an open dataset.
- at EndFunction
-*/
-void streamReadVarF(int streamID, int varID, float *data, int *nmiss)
-{
-  cdiStreamReadVar(streamID, varID, MEMTYPE_FLOAT, data, nmiss);
-}
-
-/* the single image implementation */
-void cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, int nmiss)
-{
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
-
-  check_parg(data);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
-  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
-    Error("Writing of non-trivial subtypes not yet implemented!");
-
-  stream_check_ptr(__func__, streamptr);
-
-  // check taxis
-  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
-
-  int filetype = streamptr->filetype;
-
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        grb_write_var(streamptr, varID, memtype, data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("srvWriteVar not implemented for memtype float!");
-        srvWriteVarDP(streamptr, varID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("extWriteVar not implemented for memtype float!");
-        extWriteVarDP(streamptr, varID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("iegWriteVar not implemented for memtype float!");
-        iegWriteVarDP(streamptr, varID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-	if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
-        cdf_write_var(streamptr, varID, memtype, (double *)data, nmiss);
-	break;
-      }
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
-      }
-    }
-}
-
-/*
- at Function  streamWriteVar
- at Title     Write a variable
-
- at Prototype void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to a block of double precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamWriteVar writes the values of one time step of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
- at EndFunction
-*/
-void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
-{
-  void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype,
-                               const void *data, int nmiss)
-    = (void (*)(int, int, int, const void *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
-  myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, data, nmiss);
-}
-
-/*
- at Function  streamWriteVarF
- at Title     Write a variable
-
- at Prototype void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to a block of single precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamWriteVarF writes the values of one time step of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
-Only support for netCDF was implemented in this function.
- at EndFunction
-*/
-void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
-{
-  void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype,
-                               const void *data, int nmiss)
-    = (void (*)(int, int, int, const void *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
-  myCdiStreamWriteVar_(streamID, varID, MEMTYPE_FLOAT, data, nmiss);
-}
-
-static
-int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, void *data, int *nmiss)
-{
-  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
-  // A value > 0 is returned in this case, otherwise it returns zero.
-  int status = 0;
-
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
-
-  check_parg(data);
-  check_parg(nmiss);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
-  int filetype = streamptr->filetype;
-
-  *nmiss = 0;
-
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        grbReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        srvReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        extReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        iegReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-        if ( memtype == MEMTYPE_FLOAT )
-          cdfReadVarSliceSP(streamptr, varID, levelID, (float *)data, nmiss);
-        else
-          cdfReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
-        break;
-      }
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(filetype));
-        status = 2;
-	break;
-      }
-    }
-
-  return status;
-}
-
-/*
- at Function  streamReadVarSlice
- at Title     Read a horizontal slice of a variable
-
- at Prototype void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamReadVarSlice reads all the values of a horizontal slice of a variable
-from an open dataset.
- at EndFunction
-*/
-void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
-{
-  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, data, nmiss) )
-    {
-      Warning("Unexpected error returned from cdiStreamReadVarSlice()!");
-      size_t elementCount = (size_t)gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      memset(data, 0, elementCount * sizeof(*data));
-    }
-}
-
-/*
- at Function  streamReadVarSliceF
- at Title     Read a horizontal slice of a variable
-
- at Prototype void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamReadVarSliceF reads all the values of a horizontal slice of a variable
-from an open dataset.
- at EndFunction
-*/
-void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
-{
-  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, data, nmiss) )
-    {
-      // In case the file format does not support single precision reading,
-      // we fall back to double precision reading, converting the data on the fly.
-      size_t elementCount = (size_t)gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      double *conversionBuffer = (double *) Malloc(elementCount * sizeof(*conversionBuffer));
-      streamReadVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
-      for (size_t i = elementCount; i--; ) data[i] = (float)conversionBuffer[i];
-      Free(conversionBuffer);
-    }
-}
-
-static
-void cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, int nmiss)
-{
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
-
-  check_parg(data);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
-  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
-    Error("Writing of non-trivial subtypes not yet implemented!");
-
-  stream_check_ptr(__func__, streamptr);
-
-  // check taxis
-  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
-
-  int filetype = streamptr->filetype;
-
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("srvWriteVarSlice not implemented for memtype float!");
-        srvWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("extWriteVarSlice not implemented for memtype float!");
-        extWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) Error("iegWriteVarSlice not implemented for memtype float!");
-        iegWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
-      cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
-      break;
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
-      }
-    }
-}
-
-/*
- at Function  streamWriteVarSlice
- at Title     Write a horizontal slice of a variable
-
- at Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to a block of double precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamWriteVarSlice writes the values of a horizontal slice of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
- at EndFunction
-*/
-void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
-{
-  cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, data, nmiss);
-}
-
-/*
- at Function  streamWriteVarSliceF
- at Title     Write a horizontal slice of a variable
-
- at Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to a block of single precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamWriteVarSliceF writes the values of a horizontal slice of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
-Only support for netCDF was implemented in this function.
- at EndFunction
-*/
-void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
-{
-  cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, data, nmiss);
-}
-
-
-void
-streamWriteVarChunk(int streamID, int varID,
-                    const int rect[][2], const double *data, int nmiss)
-{
-  void (*myCdiStreamWriteVarChunk_)(int streamID, int varID, int memtype,
-                                    const int rect[][2], const void *data,
-                                    int nmiss)
-    = (void (*)(int, int, int, const int [][2], const void *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_CHUNK_).func;
-  myCdiStreamWriteVarChunk_(streamID, varID, MEMTYPE_DOUBLE, rect, data, nmiss);
-}
-
-/* single image implementation */
-void
-cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
-                        const int rect[][2], const void *data, int nmiss)
-{
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
-  // streamDefineTaxis(streamID);
-
-  int filetype = streamptr->filetype;
-
-  switch (filetype)
-    {
-#if defined (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-#endif
-#if defined (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-#endif
-#if defined (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-#endif
-#if defined (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-#endif
-#if  defined (HAVE_LIBGRIB) || defined (HAVE_LIBSERVICE)      \
-  || defined (HAVE_LIBEXTRA) || defined (HAVE_LIBIEG)
-      xabort("streamWriteVarChunk not implemented for filetype %s!",
-             strfiletype(filetype));
-      break;
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
-      cdf_write_var_chunk(streamptr, varID, memtype, rect, data, nmiss);
-      break;
-#endif
-    default:
-      Error("%s support not compiled in!", strfiletype(filetype));
-      break;
-    }
-}
-
 #if 0
 void streamWriteContents(int streamID, char *cname)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  stream_check_ptr(__func__, streamptr);
-
   int vlistID = streamptr->vlistID;
 
   FILE *cnp = fopen(cname, "w");
@@ -1991,8 +1452,6 @@ off_t streamNvals(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->numvals);
 }
 
@@ -2008,6 +1467,10 @@ off_t streamNvals(int streamID)
 @Description
 The function @func{streamDefVlist} defines the variable list of a stream.
 
+To safeguard against errors by modifying the wrong vlist object,
+this function makes the passed vlist object immutable.
+All further vlist changes have to use the vlist object returned by streamInqVlist().
+
 @EndFunction
 */
 void streamDefVlist(int streamID, int vlistID)
@@ -2023,10 +1486,13 @@ cdiStreamDefVlist_(int streamID, int vlistID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  stream_check_ptr(__func__, streamptr);
-
   if ( streamptr->vlistID == CDI_UNDEFID )
-    cdiStreamSetupVlist(streamptr, vlistDuplicate(vlistID));
+    {
+      int vlistCopy = vlistDuplicate(vlistID);
+      cdiVlistMakeInternal(vlistCopy);
+      cdiVlistMakeImmutable(vlistID);
+      cdiStreamSetupVlist(streamptr, vlistCopy);
+    }
   else
     Warning("vlist already defined for %s!", streamptr->filename);
 }
@@ -2050,9 +1516,6 @@ The function @func{streamInqVlist} returns the variable list of a stream.
 int streamInqVlist(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->vlistID);
 }
 
@@ -2060,9 +1523,6 @@ int streamInqVlist(int streamID)
 void streamDefCompType(int streamID, int comptype)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   if (streamptr->comptype != comptype)
     {
       streamptr->comptype = comptype;
@@ -2074,9 +1534,6 @@ void streamDefCompType(int streamID, int comptype)
 void streamDefCompLevel(int streamID, int complevel)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   if (streamptr->complevel != complevel)
     {
       streamptr->complevel = complevel;
@@ -2088,9 +1545,6 @@ void streamDefCompLevel(int streamID, int complevel)
 int streamInqCompType(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->comptype);
 }
 
@@ -2098,9 +1552,6 @@ int streamInqCompType(int streamID)
 int streamInqCompLevel(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
-  stream_check_ptr(__func__, streamptr);
-
   return (streamptr->complevel);
 }
 
@@ -2153,7 +1604,6 @@ cdiStreamSetupVlist(stream_t *streamptr, int vlistID)
 void
 cdiStreamSetupVlist_(stream_t *streamptr, int vlistID)
 {
-  vlist_lock(vlistID);
   int nvars = vlistNvars(vlistID);
   streamptr->vlistID = vlistID;
   for (int varID = 0; varID < nvars; varID++ )
@@ -2183,10 +1633,14 @@ cdiStreamSetupVlist_(stream_t *streamptr, int vlistID)
         }
         break;
 #endif
+#ifdef HAVE_LIBGRIB
       case FILETYPE_GRB:
       case FILETYPE_GRB2:
         gribContainersNew(streamptr);
         break;
+#endif
+      default:
+        ;
       }
 }
 
@@ -2368,8 +1822,6 @@ streamUnpack(char * unpackBuffer, int unpackBufferSize,
   return retval;
 }
 
-
-
 /*
  * Local Variables:
  * c-file-style: "Java"
diff --git a/libcdi/src/stream_cdf.c b/libcdi/src/stream_cdf.c
index a832b97..290dd84 100644
--- a/libcdi/src/stream_cdf.c
+++ b/libcdi/src/stream_cdf.c
@@ -7,11 +7,19 @@
 //#define TEST_GROUPS 1
 
 #include <limits.h>
-#include <stdio.h>
-#include <string.h>
 #include <ctype.h>
 #include <math.h>
 #include <float.h>
+#ifdef HAVE_MMAP
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
+#ifdef HAVE_LIBPTHREAD
+#include <pthread.h>
+#endif
 
 #include <netcdf.h>
 
@@ -20,6 +28,7 @@
 #include "basetime.h"
 #include "gaussgrid.h"
 #include "cdi_int.h"
+#include "cdi_uuid.h"
 #include "stream_cdf.h"
 #include "cdf.h"
 #include "cdf_int.h"
@@ -27,17 +36,10 @@
 #include "vlist.h"
 
 //#define PROJECTION_TEST
-extern int CDI_cmor_mode;
 
 #undef  UNDEFID
 #define UNDEFID  CDI_UNDEFID
 
-
-#if defined HAVE_LIBNETCDF
-static void cdfDefGlobalAtts(stream_t *streamptr);
-static void cdfDefLocalAtts(stream_t *streamptr);
-#endif
-
 #define  BNDS_NAME  "bnds"
 
 #define  X_AXIS  1
@@ -55,7 +57,6 @@ typedef struct {
   char    name[CDI_MAX_NAME];
 }
 ncdim_t;
-
 #define  MAX_COORDVARS  4
 #define  MAX_AUXVARS    4
 
@@ -157,30 +158,30 @@ int get_timeunit(size_t len, const char *ptu)
       if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND;
     }
 
-  return (timeunit);
+  return timeunit;
 }
 
 static
-int isTimeUnits(const char *timeunits)
+bool isTimeUnits(const char *timeunits)
 {
-  int status = 0;
+  bool status = false;
 
   if ( strncmp(timeunits, "sec",    3) == 0 ||
        strncmp(timeunits, "minute", 6) == 0 ||
        strncmp(timeunits, "hour",   4) == 0 ||
        strncmp(timeunits, "day",    3) == 0 ||
-       strncmp(timeunits, "month",  5) == 0 ) status = 1;
+       strncmp(timeunits, "month",  5) == 0 ) status = true;
 
-  return (status);
+  return status;
 }
 
 static
-int isTimeAxisUnits(const char *timeunits)
+bool isTimeAxisUnits(const char *timeunits)
 {
   char *ptu, *tu;
   int timetype = -1;
   int timeunit;
-  int status = FALSE;
+  bool status = false;
 
   size_t len = strlen(timeunits);
   tu = (char *) Malloc((len+1)*sizeof(char));
@@ -203,13 +204,13 @@ int isTimeAxisUnits(const char *timeunits)
           else if ( memcmp(ptu, "since", 5) == 0 )
             timetype = TAXIS_RELATIVE;
 
-          if ( timetype != -1 ) status = TRUE;
+          if ( timetype != -1 ) status = true;
         }
     }
 
   Free(tu);
 
-  return (status);
+  return status;
 }
 
 static
@@ -272,24 +273,21 @@ void scanTimeString(const char *ptu, int *rdate, int *rtime)
 static
 int scanTimeUnit(const char *unitstr)
 {
-  int timeunit = -1;
   size_t len = strlen(unitstr);
-  timeunit = get_timeunit(len, unitstr);
+  int timeunit = get_timeunit(len, unitstr);
   if ( timeunit == -1 )
     Message("Unsupported TIMEUNIT: %s!", unitstr);
 
-  return (timeunit);
+  return timeunit;
 }
 
 static
 void setForecastTime(const char *timestr, taxis_t *taxis)
 {
-  int len;
-
   (*taxis).fdate = 0;
   (*taxis).ftime = 0;
 
-  len = (int) strlen(timestr);
+  int len = (int) strlen(timestr);
   if ( len == 0 ) return;
 
   int fdate = 0, ftime = 0;
@@ -302,19 +300,17 @@ void setForecastTime(const char *timestr, taxis_t *taxis)
 static
 int setBaseTime(const char *timeunits, taxis_t *taxis)
 {
-  char *ptu, *tu;
   int timetype = TAXIS_ABSOLUTE;
   int rdate = -1, rtime = -1;
-  int timeunit;
 
   size_t len = strlen(timeunits);
-  tu = (char *) Malloc((len+1) * sizeof (char));
+  char *tu = (char *) Malloc((len+1) * sizeof (char));
   memcpy(tu, timeunits, (len+1) * sizeof (char));
-  ptu = tu;
+  char *ptu = tu;
 
   for ( size_t i = 0; i < len; i++ ) ptu[i] = (char)tolower((int) ptu[i]);
 
-  timeunit = get_timeunit(len, ptu);
+  int timeunit = get_timeunit(len, ptu);
   if ( timeunit == -1 )
     {
       Message("Unsupported TIMEUNIT: %s!", timeunits);
@@ -370,7 +366,7 @@ int setBaseTime(const char *timeunits, taxis_t *taxis)
   if ( CDI_Debug )
     Message("timetype = %d  unit = %d", timetype, timeunit);
 
-  return (0);
+  return 0;
 }
 
 static
@@ -531,111 +527,7 @@ int cdfInqDatatype(int xtype, int lunsigned)
   else if ( xtype == NC_UINT64 )  datatype = DATATYPE_FLT64;
 #endif
 
-  return (datatype);
-}
-
-static
-int cdfDefDatatype(int datatype, int filetype)
-{
-  int xtype;
-
-  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
-    Error("CDI/netCDF library does not support complex numbers!");
-
-  if ( filetype == FILETYPE_NC4 )
-    {
-      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
-      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
-#if  defined  (HAVE_NETCDF4)
-      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_UBYTE;
-      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_USHORT;
-      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_UINT;
-#else
-      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
-#endif
-      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
-      else                                    xtype = NC_FLOAT;
-    }
-  else
-    {
-      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
-      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
-      else                                    xtype = NC_FLOAT;
-    }
-
-  return (xtype);
-}
-
-static inline void *
-resizeBuf(void **buf, size_t *bufSize, size_t reqSize)
-{
-  if (reqSize > *bufSize)
-    {
-      *buf = Realloc(*buf, reqSize);
-      *bufSize = reqSize;
-    }
-  return *buf;
-}
-
-static
-void defineAttributes(int vlistID, int varID, int fileID, int ncvarID)
-{
-  int natts, iatt;
-  int atttype, attlen;
-  size_t len;
-  char attname[CDI_MAX_NAME+1];
-  void *attBuf = NULL;
-  size_t attBufSize = 0;
-
-  vlistInqNatts(vlistID, varID, &natts);
-
-  for ( iatt = 0; iatt < natts; iatt++ )
-    {
-      vlistInqAtt(vlistID, varID, iatt, attname, &atttype, &attlen);
-
-      if ( attlen == 0 ) continue;
-
-      if ( atttype == DATATYPE_TXT )
-        {
-          size_t attSize = (size_t)attlen*sizeof(char);
-          char *atttxt = (char *)resizeBuf(&attBuf, &attBufSize, attSize);
-          vlistInqAttTxt(vlistID, varID, attname, attlen, atttxt);
-          len = (size_t)attlen;
-          cdf_put_att_text(fileID, ncvarID, attname, len, atttxt);
-        }
-      else if ( atttype == DATATYPE_INT16 || atttype == DATATYPE_INT32 )
-        {
-          size_t attSize = (size_t)attlen*sizeof(int);
-          int *attint = (int *)resizeBuf(&attBuf, &attBufSize, attSize);
-          vlistInqAttInt(vlistID, varID, attname, attlen, &attint[0]);
-          len = (size_t)attlen;
-          cdf_put_att_int(fileID, ncvarID, attname, atttype == DATATYPE_INT16 ? NC_SHORT : NC_INT, len, attint);
-        }
-      else if ( atttype == DATATYPE_FLT32 || atttype == DATATYPE_FLT64 )
-        {
-          size_t attSize = (size_t)attlen * sizeof(double);
-          double *attflt = (double *)resizeBuf(&attBuf, &attBufSize, attSize);
-          vlistInqAttFlt(vlistID, varID, attname, attlen, attflt);
-          len = (size_t)attlen;
-          if ( atttype == DATATYPE_FLT32 )
-            {
-              float attflt_sp[len];
-              for ( size_t i = 0; i < len; ++i ) attflt_sp[i] = (float)attflt[i];
-              cdf_put_att_float(fileID, ncvarID, attname, NC_FLOAT, len, attflt_sp);
-            }
-          else
-            cdf_put_att_double(fileID, ncvarID, attname, NC_DOUBLE, len, attflt);
-        }
-    }
-  Free(attBuf);
+  return datatype;
 }
 
 
@@ -649,11 +541,18 @@ void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
   int ivarID   = streamptr1->tsteps[tsID].records[recID].varID;
   int gridID   = vlistInqVarGrid(vlistID1, ivarID);
   int datasize = gridInqSize(gridID);
+  int datatype = vlistInqVarDatatype(vlistID1, ivarID);
 
-  double *data = (double *) Malloc((size_t)datasize * sizeof (double));
+  if ( datatype == DATATYPE_FLT32 ) memtype = MEMTYPE_FLOAT;
+
+  void *data = NULL;
+  if ( memtype == MEMTYPE_DOUBLE )
+    data = Malloc((size_t)datasize*sizeof(double));
+  else
+    data = Malloc((size_t)datasize*sizeof(float));
 
   int nmiss;
-  cdfReadRecord(streamptr1, data, &nmiss);
+  cdf_read_record(streamptr1, memtype, data, &nmiss);
   cdf_write_record(streamptr2, memtype, data, nmiss);
 
   Free(data);
@@ -692,75 +591,6 @@ void cdfDefRecord(stream_t *streamptr)
   (void)streamptr;
 }
 
-
-static
-void cdfWriteGridTraj(stream_t *streamptr, int gridID)
-{
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  int lonID = streamptr->xdimID[gridindex],
-    latID = streamptr->ydimID[gridindex];
-
-  double xlon = gridInqXval(gridID, 0),
-    xlat = gridInqYval(gridID, 0);
-  int tsID = streamptr->curTsID;
-  size_t index = (size_t)tsID;
-
-  cdf_put_var1_double(fileID, lonID, &index, &xlon);
-  cdf_put_var1_double(fileID, latID, &index, &xlat);
-}
-
-static
-void cdfReadGridTraj(stream_t *streamptr, int gridID)
-{
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  int lonID = streamptr->xdimID[gridindex];
-  int latID = streamptr->ydimID[gridindex];
-
-  int tsID = streamptr->curTsID;
-  size_t index = (size_t)tsID;
-
-  double xlon, xlat;
-  cdf_get_var1_double(fileID, lonID, &index, &xlon);
-  cdf_get_var1_double(fileID, latID, &index, &xlat);
-
-  gridDefXvals(gridID, &xlon);
-  gridDefYvals(gridID, &xlat);
-}
-
-
-static
-void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level)
-{
-#if  defined  (HAVE_NETCDF4)
-  int retval;
-  /* Set chunking, shuffle, and deflate. */
-  int shuffle = 1;
-  int deflate = 1;
-
-  if ( deflate_level < 1 || deflate_level > 9 ) deflate_level = 1;
-
-  if ((retval = nc_def_var_deflate(ncid, ncvarid, shuffle, deflate, deflate_level)))
-    {
-      Error("nc_def_var_deflate failed, status = %d", retval);
-    }
-#else
-  static int lwarn = TRUE;
-
-  if ( lwarn )
-    {
-      lwarn = FALSE;
-      Warning("Deflate compression failed, netCDF4 not available!");
-    }
-#endif
-}
-
-
 #if defined(NC_SZIP_NN_OPTION_MASK)
 static
 void cdfDefVarSzip(int ncid, int ncvarid)
@@ -779,7 +609,7 @@ void cdfDefVarSzip(int ncid, int ncvarid)
           if ( lwarn )
             {
               lwarn = FALSE;
-              Warning("netCDF4/Szip compression not compiled in!");
+              Warning("NetCDF4/Szip compression not compiled in!");
             }
         }
       else
@@ -789,64 +619,6 @@ void cdfDefVarSzip(int ncid, int ncvarid)
 #endif
 
 static
-void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
-{
-  if ( streamptr->vars[varID].defmiss == FALSE )
-    {
-      int fileID;
-      int ncvarid;
-      double missval;
-      int vlistID;
-      int xtype;
-
-      vlistID = streamptr->vlistID;
-      fileID  = streamptr->fileID;
-      ncvarid = streamptr->vars[varID].ncvarid;
-      missval = vlistInqVarMissval(vlistID, varID);
-
-      if ( lcheck && streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      xtype = cdfDefDatatype(dtype, streamptr->filetype);
-
-      if ( xtype == NC_BYTE && missval > 127 && missval < 256 ) xtype = NC_INT;
-
-      cdf_put_att_double(fileID, ncvarid, "_FillValue", (nc_type) xtype, 1, &missval);
-      cdf_put_att_double(fileID, ncvarid, "missing_value", (nc_type) xtype, 1, &missval);
-
-      if ( lcheck && streamptr->ncmode == 2 ) cdf_enddef(fileID);
-
-      streamptr->vars[varID].defmiss = TRUE;
-    }
-}
-
-
-void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss)
-{
-  int varID;
-  int levelID;
-
-  varID   = streamptr->record->varID;
-  levelID = streamptr->record->levelID;
-
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
-
-  cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
-}
-
-void cdfReadRecord(stream_t *streamptr, double *data, int *nmiss)
-{
-  if ( CDI_Debug ) Message("streamID = %d", streamptr->self);
-
-  int tsID    = streamptr->curTsID;
-  int vrecID  = streamptr->tsteps[tsID].curRecID;
-  int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-  int varID   = streamptr->tsteps[tsID].records[recID].varID;
-  int levelID = streamptr->tsteps[tsID].records[recID].levelID;
-
-  cdfReadVarSliceDP(streamptr, varID, levelID, data, nmiss);
-}
-
-static
 void cdfDefTimeValue(stream_t *streamptr, int tsID)
 {
   int fileID = streamptr->fileID;
@@ -1009,7 +781,7 @@ void cdfDefCalendar(int fileID, int ncvarid, int calendar)
   if ( len ) cdf_put_att_text(fileID, ncvarid, "calendar", len, calstr);
 }
 
-static
+
 void cdfDefTime(stream_t* streamptr)
 {
   int time_varid;
@@ -1111,7 +883,6 @@ void cdfDefComplex(stream_t *streamptr, int gridID)
 {
   char axisname[] = "nc2";
   int dimID = UNDEFID;
-  int gridID0, gridtype0;
   int vlistID = streamptr->vlistID;
   int fileID  = streamptr->fileID;
 
@@ -1121,8 +892,8 @@ void cdfDefComplex(stream_t *streamptr, int gridID)
     {
       if ( streamptr->xdimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_SPECTRAL || gridtype0 == GRID_FOURIER )
             {
               dimID = streamptr->xdimID[index];
@@ -1156,16 +927,12 @@ void cdfDefSP(stream_t *streamptr, int gridID)
   */
   char axisname[5] = "nspX";
   int index, iz = 0;
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
-  int ngrids;
-  int fileID;
-  int vlistID;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqSize(gridID)/2;
 
@@ -1173,8 +940,8 @@ void cdfDefSP(stream_t *streamptr, int gridID)
     {
       if ( streamptr->ydimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_SPECTRAL )
             {
               size_t dimlen0 = (size_t)gridInqSize(gridID0)/2;
@@ -1202,7 +969,7 @@ void cdfDefSP(stream_t *streamptr, int gridID)
       streamptr->ncmode = 2;
     }
 
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
   streamptr->ydimID[gridindex] = dimID;
 }
 
@@ -1212,16 +979,12 @@ void cdfDefFC(stream_t *streamptr, int gridID)
 {
   char axisname[5] = "nfcX";
   int index, iz = 0;
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
-  int ngrids;
-  int fileID;
-  int vlistID;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqSize(gridID)/2;
 
@@ -1229,8 +992,8 @@ void cdfDefFC(stream_t *streamptr, int gridID)
     {
       if ( streamptr->ydimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_FOURIER )
             {
               size_t dimlen0 = (size_t)gridInqSize(gridID0)/2;
@@ -1258,142 +1021,117 @@ void cdfDefFC(stream_t *streamptr, int gridID)
       streamptr->ncmode = 2;
     }
 
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
   streamptr->ydimID[gridindex] = dimID;
 }
 
+struct cdfDefTrajLatLonInqs {
+  int (*gridInqDimSize)(int gridID);
+  void (*gridInqDimName)(int gridID, char *dimname);
+  void (*gridInqDimStdname)(int gridID, char *dimstdname);
+  void (*gridInqDimLongname)(int gridID, char *dimlongname);
+  void (*gridInqDimUnits)(int gridID, char *dimunits);
+};
 
-static
-void cdfDefTrajLon(stream_t *streamptr, int gridID)
-{
-  char units[CDI_MAX_NAME];
-  char longname[CDI_MAX_NAME];
-  char stdname[CDI_MAX_NAME];
-  char axisname[CDI_MAX_NAME];
-  int gridtype, gridindex;
-  int dimID = UNDEFID;
-  int fileID;
-  int dimlen;
-  size_t len;
-  int ncvarid;
-  int vlistID;
-  int xtype = NC_DOUBLE;
-
-  if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
-
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
 
-  gridtype = gridInqType(gridID);
-  dimlen = gridInqXsize(gridID);
-  if ( dimlen != 1 ) Error("Xsize isn't 1 for %s grid!", gridNamePtr(gridtype));
+static void
+cdfDefTrajLatLon(stream_t *streamptr, int gridID,
+                 const struct cdfDefTrajLatLonInqs *inqs,
+                 int *dimID, const char *sizeName)
+{
+  nc_type xtype = gridInqPrec(gridID) == DATATYPE_FLT32 ? NC_FLOAT : NC_DOUBLE;
 
-  gridindex = vlistGridIndex(vlistID, gridID);
-  ncvarid = streamptr->xdimID[gridindex];
+  int vlistID = streamptr->vlistID;
+  int dimlen = inqs->gridInqDimSize(gridID);
+  if ( dimlen != 1 )
+    Error("%s isn't 1 for %s grid!", sizeName, gridNamePtr(gridInqType(gridID)));
 
-  gridInqXname(gridID, axisname);
-  gridInqXlongname(gridID, longname);
-  gridInqXstdname(gridID, stdname);
-  gridInqXunits(gridID, units);
+  int gridindex = vlistGridIndex(vlistID, gridID);
+  int ncvarid = dimID[gridindex];
 
   if ( ncvarid == UNDEFID )
     {
-      dimID = streamptr->basetime.ncvarid;
-
+      size_t len;
+      int dimNcID = streamptr->basetime.ncvarid;
+      int fileID  = streamptr->fileID;
       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-      cdf_def_var(fileID, axisname, (nc_type) xtype, 1, &dimID, &ncvarid);
-
-      if ( (len = strlen(stdname)) )
-        cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
-      if ( (len = strlen(longname)) )
-        cdf_put_att_text(fileID, ncvarid, "long_name", len, longname);
-      if ( (len = strlen(units)) )
-        cdf_put_att_text(fileID, ncvarid, "units", len, units);
-
+      {
+        char axisname[CDI_MAX_NAME];
+        inqs->gridInqDimName(gridID, axisname);
+        cdf_def_var(fileID, axisname, xtype, 1, &dimNcID, &ncvarid);
+      }
+      {
+        char stdname[CDI_MAX_NAME];
+        inqs->gridInqDimStdname(gridID, stdname);
+        if ( (len = strlen(stdname)) )
+          cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
+      }
+      {
+        char longname[CDI_MAX_NAME];
+        inqs->gridInqDimLongname(gridID, longname);
+        if ( (len = strlen(longname)) )
+          cdf_put_att_text(fileID, ncvarid, "long_name", len, longname);
+      }
+      {
+        char units[CDI_MAX_NAME];
+        inqs->gridInqDimUnits(gridID, units);
+        if ( (len = strlen(units)) )
+          cdf_put_att_text(fileID, ncvarid, "units", len, units);
+      }
       cdf_enddef(fileID);
       streamptr->ncmode = 2;
     }
 
-  streamptr->xdimID[gridindex] = ncvarid; /* var ID for trajectory !!! */
+  dimID[gridindex] = ncvarid; /* var ID for trajectory !!! */
 }
 
-
 static
-void cdfDefTrajLat(stream_t *streamptr, int gridID)
+void cdfDefTrajLon(stream_t *streamptr, int gridID)
 {
-  char units[] = "degrees_north";
-  char longname[] = "latitude";
-  char stdname[] = "latitude";
-  char axisname[] = "tlat";
-  int gridtype, gridindex;
-  int dimID = UNDEFID;
-  int fileID;
-  int dimlen;
-  size_t len;
-  int ncvarid;
-  int vlistID;
-  int xtype = NC_DOUBLE;
-
-  if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
-
-  vlistID = streamptr->vlistID;
-  fileID = streamptr->fileID;
-
-  gridtype = gridInqType(gridID);
-  dimlen = gridInqYsize(gridID);
-  if ( dimlen != 1 ) Error("Ysize isn't 1 for %s grid!", gridNamePtr(gridtype));
-
-  gridindex = vlistGridIndex(vlistID, gridID);
-  ncvarid = streamptr->ydimID[gridindex];
-
-  gridInqYname(gridID, axisname);
-  gridInqYlongname(gridID, longname);
-  gridInqYstdname(gridID, stdname);
-  gridInqYunits(gridID, units);
-
-  if ( ncvarid == UNDEFID )
-    {
-      dimID = streamptr->basetime.ncvarid;
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      cdf_def_var(fileID, axisname, (nc_type) xtype, 1, &dimID, &ncvarid);
-
-      if ( (len = strlen(stdname)) )
-        cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
-      if ( (len = strlen(longname)) )
-        cdf_put_att_text(fileID, ncvarid, "long_name", len, longname);
-      if ( (len = strlen(units)) )
-        cdf_put_att_text(fileID, ncvarid, "units", len, units);
+  static const struct cdfDefTrajLatLonInqs inqs =
+    { .gridInqDimSize = gridInqXsize,
+      .gridInqDimName = gridInqXname,
+      .gridInqDimStdname = gridInqXstdname,
+      .gridInqDimLongname = gridInqXlongname,
+      .gridInqDimUnits = gridInqXunits
+    };
+  cdfDefTrajLatLon(streamptr, gridID, &inqs, streamptr->xdimID, "Xsize");
+}
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-    }
 
-  streamptr->ydimID[gridindex] = ncvarid; /* var ID for trajectory !!! */
+static
+void cdfDefTrajLat(stream_t *streamptr, int gridID)
+{
+  static const struct cdfDefTrajLatLonInqs inqs =
+    { .gridInqDimSize = gridInqYsize,
+      .gridInqDimName = gridInqYname,
+      .gridInqDimStdname = gridInqYstdname,
+      .gridInqDimLongname = gridInqYlongname,
+      gridInqYunits
+  };
+  cdfDefTrajLatLon(streamptr, gridID, &inqs, streamptr->ydimID, "Ysize");
 }
 
 
 static
 int checkGridName(int type, char *axisname, int fileID, int vlistID, int gridID, int ngrids, int mode)
 {
-  int iz, index;
+  int index;
   int gridID0;
   int ncdimid;
   char axisname0[CDI_MAX_NAME];
   char axisname2[CDI_MAX_NAME];
-  int checkname;
   int status;
 
   /* check that the name is not already defined */
-  checkname = TRUE;
-  iz = 0;
+  int checkname = TRUE;
+  unsigned iz = 0;
 
   do
     {
       strcpy(axisname2, axisname);
-      if ( iz ) sprintf(&axisname2[strlen(axisname2)], "_%d", iz+1);
+      if ( iz ) sprintf(&axisname2[strlen(axisname2)], "_%u", iz+1);
 
       //status = nc_inq_varid(fileID, axisname2, &ncvarid);
       if ( type == 'V' ) /* type Var oder Dim */
@@ -1432,12 +1170,11 @@ int checkGridName(int type, char *axisname, int fileID, int vlistID, int gridID,
   while (checkname && iz <= 99);
 
 
-  if ( iz ) sprintf(&axisname[strlen(axisname)], "_%d", iz+1);
+  if ( iz ) sprintf(&axisname[strlen(axisname)], "_%u", iz+1);
 
-  return (iz);
+  return (int)iz;
 }
 
-
 static
 void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
 {
@@ -1447,40 +1184,37 @@ void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
   char axisname[CDI_MAX_NAME];
   int index;
   /*  int index2; */
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
   int dimIDs[2];
   int ngrids = 0;
-  int fileID;
   size_t len;
   int ncvarid = UNDEFID, ncbvarid = UNDEFID;
   int nvdimID = UNDEFID;
-  int vlistID;
-  int xtype = NC_DOUBLE;
+  nc_type xtype = NC_DOUBLE;
 
   if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
   if ( ndims ) ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqXsize(gridID);
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
 
   gridInqXname(gridID, axisname);
+  if ( axisname[0] == 0 ) Error("axis name undefined!");
+
   gridInqXlongname(gridID, longname);
   gridInqXstdname(gridID, stdname);
   gridInqXunits(gridID, units);
 
-  if ( axisname[0] == 0 ) Error("axis name undefined!");
-
   for ( index = 0; index < ngrids; index++ )
     {
       if ( streamptr->xdimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_GAUSSIAN    ||
                gridtype0 == GRID_LONLAT      ||
                gridtype0 == GRID_CURVILINEAR ||
@@ -1506,28 +1240,21 @@ void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
 
   if ( dimID == UNDEFID )
     {
-      int status;
-      status = checkGridName('V', axisname, fileID, vlistID, gridID, ngrids, 'X');
+      int status = checkGridName('V', axisname, fileID, vlistID, gridID, ngrids, 'X');
       if ( status == 0 && ndims )
         status = checkGridName('D', axisname, fileID, vlistID, gridID, ngrids, 'X');
 
       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-      if ( ndims )
-        {
-          cdf_def_dim(fileID, axisname, dimlen, &dimID);
-
-          if ( gridInqXboundsPtr(gridID) || gridInqYboundsPtr(gridID) )
-            {
-              size_t nvertex = 2;
-              if ( nc_inq_dimid(fileID, BNDS_NAME, &nvdimID) != NC_NOERR )
-                cdf_def_dim(fileID, BNDS_NAME, nvertex, &nvdimID);
-            }
-        }
+      if ( ndims ) cdf_def_dim(fileID, axisname, dimlen, &dimID);
 
-      if ( gridInqXvalsPtr(gridID) )
+      int gen_bounds = FALSE;
+      int grid_is_cyclic = gridIsCircular(gridID);
+      const double *pvals = gridInqXvalsPtr(gridID);
+      double *pbounds = NULL;
+      if ( pvals )
         {
-          cdf_def_var(fileID, axisname, (nc_type) xtype, ndims, &dimID, &ncvarid);
+          cdf_def_var(fileID, axisname, xtype, ndims, &dimID, &ncvarid);
 
           if ( (len = strlen(stdname)) )
             cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
@@ -1538,13 +1265,34 @@ void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
 
           cdf_put_att_text(fileID, ncvarid, "axis", 1, "X");
 
-          if ( gridInqXboundsPtr(gridID) && nvdimID != UNDEFID )
+          if ( gridInqXboundsPtr(gridID) )
+            pbounds = (double*) gridInqXboundsPtr(gridID);
+
+          if ( CDI_cmor_mode && grid_is_cyclic && !pbounds )
+            {
+              gen_bounds = TRUE;
+              pbounds = (double*) malloc(2*dimlen*sizeof(double));
+              for ( size_t i = 0; i < dimlen-1; ++i )
+                {
+                  pbounds[i*2+1]   = (pvals[i] + pvals[i+1])/2;
+                  pbounds[(i+1)*2] = (pvals[i] + pvals[i+1])/2;
+                }
+              pbounds[0] = (pvals[0] + pvals[dimlen-1]-360)/2;
+              pbounds[2*dimlen-1] = (pvals[dimlen-1] + pvals[0]+360)/2;
+            }
+          if ( pbounds )
+            {
+              size_t nvertex = 2;
+              if ( nc_inq_dimid(fileID, BNDS_NAME, &nvdimID) != NC_NOERR )
+                cdf_def_dim(fileID, BNDS_NAME, nvertex, &nvdimID);
+            }
+          if ( pbounds && nvdimID != UNDEFID )
             {
               strcat(axisname, "_");
               strcat(axisname, BNDS_NAME);
               dimIDs[0] = dimID;
               dimIDs[1] = nvdimID;
-              cdf_def_var(fileID, axisname, (nc_type) xtype, 2, dimIDs, &ncbvarid);
+              cdf_def_var(fileID, axisname, xtype, 2, dimIDs, &ncbvarid);
               cdf_put_att_text(fileID, ncvarid, "bounds", strlen(axisname), axisname);
             }
           /*
@@ -1559,8 +1307,9 @@ void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
       cdf_enddef(fileID);
       streamptr->ncmode = 2;
 
-      if ( ncvarid  != UNDEFID ) cdf_put_var_double(fileID, ncvarid, gridInqXvalsPtr(gridID));
-      if ( ncbvarid != UNDEFID ) cdf_put_var_double(fileID, ncbvarid, gridInqXboundsPtr(gridID));
+      if ( ncvarid  != UNDEFID ) cdf_put_var_double(fileID, ncvarid, pvals);
+      if ( ncbvarid != UNDEFID ) cdf_put_var_double(fileID, ncbvarid, pbounds);
+      if ( gen_bounds ) Free(pbounds);
 
       if ( ndims == 0 ) streamptr->ncxvarID[gridindex] = ncvarid;
     }
@@ -1568,7 +1317,6 @@ void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
   streamptr->xdimID[gridindex] = dimID;
 }
 
-
 static
 void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
 {
@@ -1578,40 +1326,37 @@ void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
   char axisname[CDI_MAX_NAME];
   int index;
   /*  int index2; */
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
   int dimIDs[2];
   int ngrids = 0;
-  int fileID;
   size_t len;
   int ncvarid = UNDEFID, ncbvarid = UNDEFID;
   int nvdimID = UNDEFID;
-  int vlistID;
-  int xtype = NC_DOUBLE;
+  nc_type xtype = NC_DOUBLE;
 
   if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
   if ( ndims ) ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqYsize(gridID);
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
 
   gridInqYname(gridID, axisname);
+  if ( axisname[0] == 0 ) Error("axis name undefined!");
+
   gridInqYlongname(gridID, longname);
   gridInqYstdname(gridID, stdname);
   gridInqYunits(gridID, units);
 
-  if ( axisname[0] == 0 ) Error("axis name undefined!");
-
   for ( index = 0; index < ngrids; index++ )
     {
       if ( streamptr->ydimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_GAUSSIAN    ||
                gridtype0 == GRID_LONLAT      ||
                gridtype0 == GRID_CURVILINEAR ||
@@ -1644,21 +1389,15 @@ void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
 
       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-      if ( ndims )
-        {
-          cdf_def_dim(fileID, axisname, dimlen, &dimID);
-
-          if ( gridInqXboundsPtr(gridID) || gridInqYboundsPtr(gridID) )
-            {
-              size_t nvertex = 2;
-              if ( nc_inq_dimid(fileID, BNDS_NAME, &nvdimID) != NC_NOERR )
-                cdf_def_dim(fileID, BNDS_NAME, nvertex, &nvdimID);
-            }
-        }
+      if ( ndims ) cdf_def_dim(fileID, axisname, dimlen, &dimID);
 
-      if ( gridInqYvalsPtr(gridID) )
+      int gen_bounds = FALSE;
+      int grid_is_cyclic = gridIsCircular(gridID);
+      const double *pvals = gridInqYvalsPtr(gridID);
+      double *pbounds = NULL;
+      if ( pvals )
         {
-          cdf_def_var(fileID, axisname, (nc_type) xtype, ndims, &dimID, &ncvarid);
+          cdf_def_var(fileID, axisname, xtype, ndims, &dimID, &ncvarid);
 
           if ( (len = strlen(stdname)) )
             cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
@@ -1669,13 +1408,34 @@ void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
 
           cdf_put_att_text(fileID, ncvarid, "axis", 1, "Y");
 
-          if ( gridInqYboundsPtr(gridID) && nvdimID != UNDEFID )
+          if ( gridInqYboundsPtr(gridID) )
+            pbounds = (double*) gridInqYboundsPtr(gridID);
+
+          if ( CDI_cmor_mode && grid_is_cyclic && !pbounds )
+            {
+              gen_bounds = TRUE;
+              pbounds = (double*) malloc(2*dimlen*sizeof(double));
+              for ( size_t i = 0; i < dimlen-1; ++i )
+                {
+                  pbounds[i*2+1]   = (pvals[i] + pvals[i+1])/2;
+                  pbounds[(i+1)*2] = (pvals[i] + pvals[i+1])/2;
+                }
+              pbounds[0] = (pvals[0] < 0) ? -90 : 90;
+              pbounds[2*dimlen-1] = (pvals[dimlen-1] < 0) ? -90 : 90;
+            }
+          if ( pbounds )
+            {
+              size_t nvertex = 2;
+              if ( nc_inq_dimid(fileID, BNDS_NAME, &nvdimID) != NC_NOERR )
+                cdf_def_dim(fileID, BNDS_NAME, nvertex, &nvdimID);
+            }
+          if ( pbounds && nvdimID != UNDEFID )
             {
               strcat(axisname, "_");
               strcat(axisname, BNDS_NAME);
               dimIDs[0] = dimID;
               dimIDs[1] = nvdimID;
-              cdf_def_var(fileID, axisname, (nc_type) xtype, 2, dimIDs, &ncbvarid);
+              cdf_def_var(fileID, axisname, xtype, 2, dimIDs, &ncbvarid);
               cdf_put_att_text(fileID, ncvarid, "bounds", strlen(axisname), axisname);
             }
           /*
@@ -1690,8 +1450,9 @@ void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
       cdf_enddef(fileID);
       streamptr->ncmode = 2;
 
-      if ( ncvarid  != UNDEFID ) cdf_put_var_double(fileID, ncvarid, gridInqYvalsPtr(gridID));
-      if ( ncbvarid != UNDEFID ) cdf_put_var_double(fileID, ncbvarid, gridInqYboundsPtr(gridID));
+      if ( ncvarid  != UNDEFID ) cdf_put_var_double(fileID, ncvarid, pvals);
+      if ( ncbvarid != UNDEFID ) cdf_put_var_double(fileID, ncbvarid, pbounds);
+      if ( gen_bounds ) Free(pbounds);
 
       if ( ndims == 0 ) streamptr->ncyvarID[gridindex] = ncvarid;
     }
@@ -1699,7 +1460,6 @@ void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
   streamptr->ydimID[gridindex] = dimID;
 }
 
-
 static
 void cdfGridCompress(int fileID, int ncvarid, int gridsize, int filetype, int comptype)
 {
@@ -1727,29 +1487,25 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
   char xdimname[4] = "x";
   char ydimname[4] = "y";
   int index;
-  int gridID0, gridtype0, gridindex;
   int xdimID = UNDEFID;
   int ydimID = UNDEFID;
   int dimIDs[3];
-  int ngrids;
-  int fileID;
   size_t len;
   int ncxvarid = UNDEFID, ncyvarid = UNDEFID;
   int ncbxvarid = UNDEFID, ncbyvarid = UNDEFID, ncavarid = UNDEFID;
   int nvdimID = UNDEFID;
-  int vlistID;
-  int xtype = NC_DOUBLE;
+  nc_type xtype = NC_DOUBLE;
 
   if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t xdimlen = (size_t)gridInqXsize(gridID);
   size_t ydimlen = (size_t)gridInqYsize(gridID);
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
 
   gridInqXname(gridID, xaxisname);
   gridInqXlongname(gridID, xlongname);
@@ -1764,8 +1520,8 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
     {
       if ( streamptr->xdimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_GAUSSIAN    ||
                gridtype0 == GRID_LONLAT      ||
                gridtype0 == GRID_CURVILINEAR ||
@@ -1817,7 +1573,7 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
 
       if ( gridInqXvalsPtr(gridID) )
         {
-          cdf_def_var(fileID, xaxisname, (nc_type) xtype, 2, dimIDs, &ncxvarid);
+          cdf_def_var(fileID, xaxisname, xtype, 2, dimIDs, &ncxvarid);
           cdfGridCompress(fileID, ncxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
 
           if ( (len = strlen(xstdname)) )
@@ -1837,7 +1593,7 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
               dimIDs[0] = ydimID;
               dimIDs[1] = xdimID;
               dimIDs[2] = nvdimID;
-              cdf_def_var(fileID, xaxisname, (nc_type) xtype, 3, dimIDs, &ncbxvarid);
+              cdf_def_var(fileID, xaxisname, xtype, 3, dimIDs, &ncbxvarid);
               cdfGridCompress(fileID, ncbxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
 
               cdf_put_att_text(fileID, ncxvarid, "bounds", strlen(xaxisname), xaxisname);
@@ -1846,7 +1602,7 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
 
       if ( gridInqYvalsPtr(gridID) )
         {
-          cdf_def_var(fileID, yaxisname, (nc_type) xtype, 2, dimIDs, &ncyvarid);
+          cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncyvarid);
           cdfGridCompress(fileID, ncyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
 
           if ( (len = strlen(ystdname)) )
@@ -1866,7 +1622,7 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
               dimIDs[0] = ydimID;
               dimIDs[1] = xdimID;
               dimIDs[2] = nvdimID;
-              cdf_def_var(fileID, yaxisname, (nc_type) xtype, 3, dimIDs, &ncbyvarid);
+              cdf_def_var(fileID, yaxisname, xtype, 3, dimIDs, &ncbyvarid);
               cdfGridCompress(fileID, ncbyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
 
               cdf_put_att_text(fileID, ncyvarid, "bounds", strlen(yaxisname), yaxisname);
@@ -1880,7 +1636,7 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
           static const char longname[] = "area of grid cell";
           static const char stdname[] = "cell_area";
 
-          cdf_def_var(fileID, yaxisname_, (nc_type) xtype, 2, dimIDs, &ncavarid);
+          cdf_def_var(fileID, yaxisname_, xtype, 2, dimIDs, &ncavarid);
 
           cdf_put_att_text(fileID, ncavarid, "standard_name", sizeof (stdname) - 1, stdname);
           cdf_put_att_text(fileID, ncavarid, "long_name", sizeof (longname) - 1, longname);
@@ -1904,23 +1660,18 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID)
   streamptr->ncavarID[gridindex] = ncavarid;
 }
 
-
 static
 void cdfDefRgrid(stream_t *streamptr, int gridID)
 {
   char axisname[7] = "rgridX";
   int index, iz = 0;
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
-  int ngrids;
-  int fileID;
-  int vlistID;
   int lwarn = TRUE;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqSize(gridID);
 
@@ -1928,8 +1679,8 @@ void cdfDefRgrid(stream_t *streamptr, int gridID)
     {
       if ( streamptr->xdimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_GAUSSIAN_REDUCED )
             {
               size_t dimlen0 = (size_t)gridInqSize(gridID0);
@@ -1949,7 +1700,7 @@ void cdfDefRgrid(stream_t *streamptr, int gridID)
     {
       if ( lwarn )
         {
-          Warning("Creating a netCDF file with data on a gaussian reduced grid.");
+          Warning("Creating a NetCDF file with data on a gaussian reduced grid.");
           Warning("The further processing of the resulting file is unsupported!");
           lwarn = FALSE;
         }
@@ -1965,25 +1716,20 @@ void cdfDefRgrid(stream_t *streamptr, int gridID)
       streamptr->ncmode = 2;
     }
 
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
   streamptr->xdimID[gridindex] = dimID;
 }
 
-
 static
 void cdfDefGdim(stream_t *streamptr, int gridID)
 {
   int index, iz = 0;
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
-  int ngrids;
-  int fileID;
-  int vlistID;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqSize(gridID);
 
@@ -1992,8 +1738,8 @@ void cdfDefGdim(stream_t *streamptr, int gridID)
       {
         if ( streamptr->xdimID[index] != UNDEFID )
           {
-            gridID0 = vlistGrid(vlistID, index);
-            gridtype0 = gridInqType(gridID0);
+            int gridID0 = vlistGrid(vlistID, index);
+            int gridtype0 = gridInqType(gridID0);
             if ( gridtype0 == GRID_GENERIC )
               {
                 size_t dimlen0 = (size_t)gridInqSize(gridID0);
@@ -2013,8 +1759,8 @@ void cdfDefGdim(stream_t *streamptr, int gridID)
       {
         if ( streamptr->ydimID[index] != UNDEFID )
           {
-            gridID0 = vlistGrid(vlistID, index);
-            gridtype0 = gridInqType(gridID0);
+            int gridID0 = vlistGrid(vlistID, index);
+            int gridtype0 = gridInqType(gridID0);
             if ( gridtype0 == GRID_GENERIC )
               {
                 size_t dimlen0 = (size_t)gridInqSize(gridID0);
@@ -2048,11 +1794,10 @@ void cdfDefGdim(stream_t *streamptr, int gridID)
       streamptr->ncmode = 2;
     }
 
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
   streamptr->xdimID[gridindex] = dimID;
 }
 
-
 static
 void cdfDefGridReference(stream_t *streamptr, int gridID)
 {
@@ -2083,7 +1828,7 @@ void cdfDefGridUUID(stream_t *streamptr, int gridID)
   if ( !cdiUUIDIsNull(uuidOfHGrid) )
     {
       char uuidOfHGridStr[37];
-      uuid2str(uuidOfHGrid, uuidOfHGridStr);
+      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
       if ( uuidOfHGridStr[0] != 0 && strlen(uuidOfHGridStr) == 36 )
         {
           int fileID  = streamptr->fileID;
@@ -2103,7 +1848,7 @@ void cdfDefZaxisUUID(stream_t *streamptr, int zaxisID)
   if ( uuidOfVGrid[0] != 0 )
     {
       char uuidOfVGridStr[37];
-      uuid2str(uuidOfVGrid, uuidOfVGridStr);
+      cdiUUID2Str(uuidOfVGrid, uuidOfVGridStr);
       if ( uuidOfVGridStr[0] != 0 && strlen(uuidOfVGridStr) == 36 )
         {
           int fileID  = streamptr->fileID;
@@ -2126,26 +1871,22 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
   char xaxisname[CDI_MAX_NAME];
   char yaxisname[CDI_MAX_NAME];
   int index;
-  int gridID0, gridtype0, gridindex;
   int dimID = UNDEFID;
-  int ngrids;
-  int fileID;
   size_t len;
   int ncxvarid = UNDEFID, ncyvarid = UNDEFID;
   int ncbxvarid = UNDEFID, ncbyvarid = UNDEFID, ncavarid = UNDEFID;
   int nvdimID = UNDEFID;
-  int vlistID;
-  int xtype = NC_DOUBLE;
+  nc_type xtype = NC_DOUBLE;
 
   if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  ngrids = vlistNgrids(vlistID);
+  int ngrids = vlistNgrids(vlistID);
 
   size_t dimlen = (size_t)gridInqSize(gridID);
-  gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = vlistGridIndex(vlistID, gridID);
 
   gridInqXname(gridID, xaxisname);
   gridInqXlongname(gridID, xlongname);
@@ -2160,8 +1901,8 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
     {
       if ( streamptr->xdimID[index] != UNDEFID )
         {
-          gridID0 = vlistGrid(vlistID, index);
-          gridtype0 = gridInqType(gridID0);
+          int gridID0 = vlistGrid(vlistID, index);
+          int gridtype0 = gridInqType(gridID0);
           if ( gridtype0 == GRID_UNSTRUCTURED )
             {
               size_t dimlen0 = (size_t)gridInqSize(gridID0);
@@ -2205,7 +1946,7 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
 
       if ( gridInqXvalsPtr(gridID) )
         {
-          cdf_def_var(fileID, xaxisname, (nc_type) xtype, 1, &dimID, &ncxvarid);
+          cdf_def_var(fileID, xaxisname, xtype, 1, &dimID, &ncxvarid);
           cdfGridCompress(fileID, ncxvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
 
           if ( (len = strlen(xstdname)) )
@@ -2222,7 +1963,7 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
               dimIDs[1] = nvdimID;
               strcat(xaxisname, "_");
               strcat(xaxisname, BNDS_NAME);
-              cdf_def_var(fileID, xaxisname, (nc_type) xtype, 2, dimIDs, &ncbxvarid);
+              cdf_def_var(fileID, xaxisname, xtype, 2, dimIDs, &ncbxvarid);
               cdfGridCompress(fileID, ncbxvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
 
               cdf_put_att_text(fileID, ncxvarid, "bounds", strlen(xaxisname), xaxisname);
@@ -2231,7 +1972,7 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
 
       if ( gridInqYvalsPtr(gridID) )
         {
-          cdf_def_var(fileID, yaxisname, (nc_type) xtype, 1, &dimID, &ncyvarid);
+          cdf_def_var(fileID, yaxisname, xtype, 1, &dimID, &ncyvarid);
           cdfGridCompress(fileID, ncyvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
 
           if ( (len = strlen(ystdname)) )
@@ -2248,7 +1989,7 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
               dimIDs[1] = nvdimID;
               strcat(yaxisname, "_");
               strcat(yaxisname, BNDS_NAME);
-              cdf_def_var(fileID, yaxisname, (nc_type) xtype, 2, dimIDs, &ncbyvarid);
+              cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncbyvarid);
               cdfGridCompress(fileID, ncbyvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
 
               cdf_put_att_text(fileID, ncyvarid, "bounds", strlen(yaxisname), yaxisname);
@@ -2262,7 +2003,7 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID)
           static const char longname[] = "area of grid cell";
           static const char stdname[] = "cell_area";
 
-          cdf_def_var(fileID, yaxisname_, (nc_type) xtype, 1, &dimID, &ncavarid);
+          cdf_def_var(fileID, yaxisname_, xtype, 1, &dimID, &ncavarid);
 
           cdf_put_att_text(fileID, ncavarid, "standard_name", sizeof (stdname) - 1, stdname);
           cdf_put_att_text(fileID, ncavarid, "long_name", sizeof (longname) - 1, longname);
@@ -2293,6 +2034,8 @@ void cdf_def_vct_echam(stream_t *streamptr, int zaxisID)
   if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
     {
       int ilev = zaxisInqVctSize(zaxisID)/2;
+      if ( ilev == 0 ) return;
+
       int mlev = ilev - 1;
       size_t start;
       size_t count = 1;
@@ -2308,12 +2051,6 @@ void cdf_def_vct_echam(stream_t *streamptr, int zaxisID)
           return;
         }
 
-      if ( ilev == 0 )
-        {
-          Warning("VCT missing");
-          return;
-        }
-
       int fileID = streamptr->fileID;
 
       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
@@ -2375,6 +2112,8 @@ void cdf_def_vct_cf(stream_t *streamptr, int zaxisID, int nclevID, int ncbndsID)
   if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
     {
       int ilev = zaxisInqVctSize(zaxisID)/2;
+      if ( ilev == 0 ) return;
+
       int mlev = ilev - 1;
       int hyaiid = 0, hybiid = 0, hyamid, hybmid;
       char tmpname[CDI_MAX_NAME];
@@ -2386,12 +2125,6 @@ void cdf_def_vct_cf(stream_t *streamptr, int zaxisID, int nclevID, int ncbndsID)
           return;
         }
 
-      if ( ilev == 0 )
-        {
-          Warning("VCT missing");
-          return;
-        }
-
       int fileID = streamptr->fileID;
 
       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
@@ -2883,8 +2616,8 @@ void cdfDefMapping(stream_t *streamptr, int gridID)
 
   if ( gridInqType(gridID) == GRID_SINUSOIDAL )
     {
-      char varname[] = "sinusoidal";
-      char mapname[] = "sinusoidal";
+      static const char varname[] = "sinusoidal";
+      static const char mapname[] = "sinusoidal";
 
       cdf_redef(fileID);
 
@@ -2902,8 +2635,8 @@ void cdfDefMapping(stream_t *streamptr, int gridID)
     }
   else if ( gridInqType(gridID) == GRID_LAEA )
     {
-      char varname[] = "laea";
-      char mapname[] = "lambert_azimuthal_equal_area";
+      static const char varname[] = "laea";
+      static const char mapname[] = "lambert_azimuthal_equal_area";
 
       cdf_redef(fileID);
 
@@ -2924,8 +2657,8 @@ void cdfDefMapping(stream_t *streamptr, int gridID)
     }
   else if ( gridInqType(gridID) == GRID_LCC2 )
     {
-      char varname[] = "Lambert_Conformal";
-      char mapname[] = "lambert_conformal_conic";
+      static const char varname[] = "Lambert_Conformal";
+      static const char mapname[] = "lambert_conformal_conic";
 
       cdf_redef(fileID);
 
@@ -3021,1693 +2754,69 @@ void cdfDefGrid(stream_t *streamptr, int gridID)
   else if ( gridtype == GRID_GAUSSIAN_REDUCED )
     {
       cdfDefRgrid(streamptr, gridID);
-    }
-  else if ( gridtype == GRID_SPECTRAL )
-    {
-      cdfDefComplex(streamptr, gridID);
-      cdfDefSP(streamptr, gridID);
-    }
-  else if ( gridtype == GRID_FOURIER )
-    {
-      cdfDefComplex(streamptr, gridID);
-      cdfDefFC(streamptr, gridID);
-    }
-  else if ( gridtype == GRID_TRAJECTORY )
-    {
-      cdfDefTrajLon(streamptr, gridID);
-      cdfDefTrajLat(streamptr, gridID);
-    }
-  else if ( gridtype == GRID_SINUSOIDAL || gridtype == GRID_LAEA || gridtype == GRID_LCC2 )
-    {
-      cdfDefXaxis(streamptr, gridID, 1);
-      cdfDefYaxis(streamptr, gridID, 1);
-
-      cdfDefMapping(streamptr, gridID);
-    }
-  /*
-  else if ( gridtype == GRID_LCC )
-    {
-      cdfDefLcc(streamptr, gridID);
-    }
-  */
-  else
-    {
-      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
-    }
-}
-
-static
-int cdfDefVar(stream_t *streamptr, int varID)
-{
-  int ncvarid = -1;
-  int xid = UNDEFID, yid = UNDEFID;
-  size_t xsize = 0, ysize = 0;
-  char varname[CDI_MAX_NAME];
-  int dims[4];
-  int lchunk = FALSE;
-  size_t chunks[4] = {0,0,0,0};
-  int ndims = 0;
-  int tablenum;
-  int dimorder[3];
-  size_t iax = 0;
-  char axis[5];
-  int ensID, ensCount, forecast_type;
-  int retval;
-
-  int fileID  = streamptr->fileID;
-
-  if ( CDI_Debug )
-    Message("streamID = %d, fileID = %d, varID = %d", streamptr->self, fileID, varID);
-
-  if ( streamptr->vars[varID].ncvarid != UNDEFID )
-    return streamptr->vars[varID].ncvarid;
-
-  int vlistID   = streamptr->vlistID;
-  int gridID    = vlistInqVarGrid(vlistID, varID);
-  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
-  int code      = vlistInqVarCode(vlistID, varID);
-  int param     = vlistInqVarParam(vlistID, varID);
-  int pnum, pcat, pdis;
-  cdiDecodeParam(param, &pnum, &pcat, &pdis);
-
-  int chunktype = vlistInqVarChunkType(vlistID, varID);
-
-  vlistInqVarDimorder(vlistID, varID, &dimorder);
-
-  int gridsize  = gridInqSize(gridID);
-  if ( gridsize > 1 ) lchunk = TRUE;
-  int gridtype  = gridInqType(gridID);
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  if ( gridtype != GRID_TRAJECTORY )
-    {
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
-      if ( xid != UNDEFID ) cdf_inq_dimlen(fileID, xid, &xsize);
-      if ( yid != UNDEFID ) cdf_inq_dimlen(fileID, yid, &ysize);
-    }
-
-  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-  int zid = streamptr->zaxisID[zaxisindex];
-  int zaxis_is_scalar = FALSE;
-  if ( zid == UNDEFID ) zaxis_is_scalar = zaxisInqScalar(zaxisID);
-
-  if ( dimorder[0] != 3 ) lchunk = FALSE; /* ZYX and ZXY */
-
-  if ( ((dimorder[0]>0)+(dimorder[1]>0)+(dimorder[2]>0)) < ((xid!=UNDEFID)+(yid!=UNDEFID)+(zid!=UNDEFID)) )
-    {
-      printf("zid=%d  yid=%d  xid=%d\n", zid, yid, xid);
-      Error("Internal problem, dimension order missing!");
-    }
-
-  int tid = streamptr->basetime.ncdimid;
-
-  if ( tsteptype != TSTEP_CONSTANT )
-    {
-      if ( tid == UNDEFID ) Error("Internal problem, time undefined!");
-      chunks[ndims] = 1;
-      dims[ndims++] = tid;
-      axis[iax++] = 'T';
-    }
-  /*
-  if ( zid != UNDEFID ) axis[iax++] = 'Z';
-  if ( zid != UNDEFID ) chunks[ndims] = 1;
-  if ( zid != UNDEFID ) dims[ndims++] = zid;
-
-  if ( yid != UNDEFID ) chunks[ndims] = ysize;
-  if ( yid != UNDEFID ) dims[ndims++] = yid;
-
-  if ( xid != UNDEFID ) chunks[ndims] = xsize;
-  if ( xid != UNDEFID ) dims[ndims++] = xid;
-  */
-  for ( int id = 0; id < 3; ++id )
-    {
-      if ( dimorder[id] == 3 && zid != UNDEFID )
-        {
-          axis[iax++] = 'Z';
-          chunks[ndims] = 1;
-          dims[ndims] = zid;
-          ndims++;
-        }
-      else if ( dimorder[id] == 2 && yid != UNDEFID )
-        {
-          if ( chunktype == CHUNK_LINES )
-            chunks[ndims] = 1;
-          else
-            chunks[ndims] = ysize;
-          dims[ndims] = yid;
-          ndims++;
-        }
-      else if ( dimorder[id] == 1 && xid != UNDEFID )
-        {
-          chunks[ndims] = xsize;
-          dims[ndims] = xid;
-          ndims++;
-        }
-    }
-
-  if ( CDI_Debug )
-    fprintf(stderr, "chunktype %d  chunks %d %d %d %d\n", chunktype, (int)chunks[0], (int)chunks[1], (int)chunks[2], (int)chunks[3]);
-
-  int tableID  = vlistInqVarTable(vlistID, varID);
-
-  const char *name     = vlistInqVarNamePtr(vlistID, varID);
-  const char *longname = vlistInqVarLongnamePtr(vlistID, varID);
-  const char *stdname  = vlistInqVarStdnamePtr(vlistID, varID);
-  const char *units    = vlistInqVarUnitsPtr(vlistID, varID);
-
-  if ( name     == NULL )     name = tableInqParNamePtr(tableID, code);
-  if ( longname == NULL ) longname = tableInqParLongnamePtr(tableID, code);
-  if ( units    == NULL )    units = tableInqParUnitsPtr(tableID, code);
-  if ( name )
-    {
-      int checkname;
-      int iz;
-      int status;
-
-      sprintf(varname, "%s", name);
-
-      checkname = TRUE;
-      iz = 0;
-
-      while ( checkname )
-        {
-          if ( iz ) sprintf(varname, "%s_%d", name, iz+1);
-
-          status = nc_inq_varid(fileID, varname, &ncvarid);
-          if ( status != NC_NOERR )
-            {
-              checkname = FALSE;
-            }
-
-          if ( checkname ) iz++;
-
-          if ( iz >= CDI_MAX_NAME ) Error("Double entry of variable name '%s'!", name);
-        }
-
-      if ( strcmp(name, varname) != 0 )
-        {
-          if ( iz == 1 )
-            Warning("Changed double entry of variable name '%s' to '%s'!", name, varname);
-          else
-            Warning("Changed multiple entry of variable name '%s' to '%s'!", name, varname);
-        }
-
-      name = varname;
-    }
-  else
-    {
-      if ( code < 0 ) code = -code;
-      if ( pnum < 0 ) pnum = -pnum;
-
-      if ( pdis == 255 )
-	sprintf(varname, "var%d", code);
-      else
-	sprintf(varname, "param%d.%d.%d", pnum, pcat, pdis);
-
-      char *varname2 = varname+strlen(varname);
-
-      int checkname = TRUE;
-      int iz = 0;
-
-      while ( checkname )
-        {
-          if ( iz ) sprintf(varname2, "_%d", iz+1);
-
-          int status = nc_inq_varid(fileID, varname, &ncvarid);
-          if ( status != NC_NOERR ) checkname = FALSE;
-
-          if ( checkname ) iz++;
-
-          if ( iz >= CDI_MAX_NAME ) break;
-        }
-
-      name = varname;
-      code = 0;
-      pdis = 255;
-    }
-
-  /* if ( streamptr->ncmode == 2 ) cdf_redef(fileID); */
-
-  int dtype = vlistInqVarDatatype(vlistID, varID);
-  int xtype = cdfDefDatatype(dtype, streamptr->filetype);
-
-  cdf_def_var(fileID, name, (nc_type) xtype, ndims, dims, &ncvarid);
-
-#if  defined  (HAVE_NETCDF4)
-  if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
-    {
-      if ( chunktype == CHUNK_AUTO )
-        retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
-      else
-        retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, chunks);
-
-      if ( retval ) Error("nc_def_var_chunking failed, status = %d", retval);
-    }
-#endif
-
-  if ( streamptr->comptype == COMPRESS_ZIP )
-    {
-      if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
-        {
-          cdfDefVarDeflate(fileID, ncvarid, streamptr->complevel);
-        }
-      else
-        {
-          if ( lchunk )
-            {
-              static int lwarn = TRUE;
-
-              if ( lwarn )
-                {
-                  lwarn = FALSE;
-                  Warning("Deflate compression is only available for netCDF4!");
-                }
-            }
-        }
-    }
-
-  if ( streamptr->comptype == COMPRESS_SZIP )
-    {
-      if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
-        {
-#if defined (NC_SZIP_NN_OPTION_MASK)
-          cdfDefVarSzip(fileID, ncvarid);
-#else
-          static int lwarn = TRUE;
-
-          if ( lwarn )
-            {
-              lwarn = FALSE;
-              Warning("netCDF4/SZIP compression not available!");
-            }
-#endif
-        }
-      else
-        {
-          static int lwarn = TRUE;
-
-          if ( lwarn )
-            {
-              lwarn = FALSE;
-              Warning("SZIP compression is only available for netCDF4!");
-            }
-        }
-    }
-
-  if ( stdname && *stdname )
-    cdf_put_att_text(fileID, ncvarid, "standard_name", strlen(stdname), stdname);
-
-  if ( longname && *longname )
-    cdf_put_att_text(fileID, ncvarid, "long_name", strlen(longname), longname);
-
-  if ( units && *units )
-    cdf_put_att_text(fileID, ncvarid, "units", strlen(units), units);
-
-  if ( code > 0 && pdis == 255 )
-    cdf_put_att_int(fileID, ncvarid, "code", NC_INT, 1, &code);
-
-  if ( pdis != 255 )
-    {
-      char paramstr[32];
-      cdiParamToString(param, paramstr, sizeof(paramstr));
-      cdf_put_att_text(fileID, ncvarid, "param", strlen(paramstr), paramstr);
-    }
-
-  if ( tableID != UNDEFID )
-    {
-      tablenum = tableInqNum(tableID);
-      if ( tablenum > 0 )
-        cdf_put_att_int(fileID, ncvarid, "table", NC_INT, 1, &tablenum);
-    }
-
-  char coordinates[CDI_MAX_NAME];
-  coordinates[0] = 0;
-
-  if ( zaxis_is_scalar )
-    {
-      int nczvarID = streamptr->nczvarID[zaxisindex];
-      if ( nczvarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, nczvarID, coordinates+len);
-        }
-    }
-
-  if ( gridtype != GRID_GENERIC && gridtype != GRID_LONLAT  && gridtype != GRID_CURVILINEAR )
-    {
-      size_t len = strlen(gridNamePtr(gridtype));
-      if ( len > 0 )
-        cdf_put_att_text(fileID, ncvarid, "grid_type", len, gridNamePtr(gridtype));
-    }
-
-  if ( gridIsRotated(gridID) )
-    {
-      char mapping[] = "rotated_pole";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
-    }
-
-  if ( gridtype == GRID_SINUSOIDAL )
-    {
-      char mapping[] = "sinusoidal";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
-    }
-  else if ( gridtype == GRID_LAEA )
-    {
-      char mapping[] = "laea";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
-    }
-  else if ( gridtype == GRID_LCC2 )
-    {
-      char mapping[] = "Lambert_Conformal";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
-    }
-  else if ( gridtype == GRID_TRAJECTORY )
-    {
-      cdf_put_att_text(fileID, ncvarid, "coordinates", 9, "tlon tlat" );
-    }
-  else if ( gridtype == GRID_LONLAT && xid == UNDEFID && yid == UNDEFID && gridsize == 1 )
-    {
-      int ncxvarID = streamptr->ncxvarID[gridindex];
-      int ncyvarID = streamptr->ncyvarID[gridindex];
-      if ( ncyvarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, ncyvarID, coordinates+len);
-        }
-      if ( ncxvarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, ncxvarID, coordinates+len);
-        }
-    }
-  else if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
-    {
-      char cellarea[CDI_MAX_NAME] = "area: ";
-      int ncxvarID = streamptr->ncxvarID[gridindex];
-      int ncyvarID = streamptr->ncyvarID[gridindex];
-      int ncavarID = streamptr->ncavarID[gridindex];
-      if ( ncyvarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, ncyvarID, coordinates+len);
-        }
-      if ( ncxvarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, ncxvarID, coordinates+len);
-        }
-
-      if ( ncavarID != CDI_UNDEFID )
-        {
-          size_t len = strlen(cellarea);
-          cdf_inq_varname(fileID, ncavarID, cellarea+len);
-          len = strlen(cellarea);
-          cdf_put_att_text(fileID, ncvarid, "cell_measures", len, cellarea);
-        }
-
-      if ( gridtype == GRID_UNSTRUCTURED )
-        {
-          int position = gridInqPosition(gridID);
-          if ( position > 0 )
-            cdf_put_att_int(fileID, ncvarid, "number_of_grid_in_reference", NC_INT, 1, &position);
-        }
-    }
-  else if ( gridtype == GRID_SPECTRAL || gridtype == GRID_FOURIER )
-    {
-      int gridTruncation = gridInqTrunc(gridID);
-      axis[iax++] = '-';
-      axis[iax++] = '-';
-      cdf_put_att_text(fileID, ncvarid, "axis", iax, axis);
-      cdf_put_att_int(fileID, ncvarid, "truncation", NC_INT, 1, &gridTruncation);
-    }
-
-  size_t len = strlen(coordinates);
-  if ( len ) cdf_put_att_text(fileID, ncvarid, "coordinates", len, coordinates);
-
-  /*  if ( xtype == NC_BYTE || xtype == NC_SHORT || xtype == NC_INT ) */
-    {
-      int laddoffset, lscalefactor;
-      double addoffset, scalefactor;
-      int astype = NC_DOUBLE;
-
-      addoffset    = vlistInqVarAddoffset(vlistID, varID);
-      scalefactor  = vlistInqVarScalefactor(vlistID, varID);
-      laddoffset   = IS_NOT_EQUAL(addoffset, 0);
-      lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
-
-      if ( laddoffset || lscalefactor )
-        {
-          if ( IS_EQUAL(addoffset,   (double) ((float) addoffset)) &&
-               IS_EQUAL(scalefactor, (double) ((float) scalefactor)) )
-            {
-              astype = NC_FLOAT;
-            }
-
-          if ( xtype == (int) NC_FLOAT ) astype = NC_FLOAT;
-
-          cdf_put_att_double(fileID, ncvarid, "add_offset",   (nc_type) astype, 1, &addoffset);
-          cdf_put_att_double(fileID, ncvarid, "scale_factor", (nc_type) astype, 1, &scalefactor);
-        }
-    }
-
-  if ( dtype == DATATYPE_UINT8 && xtype == NC_BYTE )
-    {
-      int validrange[2] = {0, 255};
-      cdf_put_att_int(fileID, ncvarid, "valid_range", NC_SHORT, 2, validrange);
-      cdf_put_att_text(fileID, ncvarid, "_Unsigned", 4, "true");
-    }
-
-  streamptr->vars[varID].ncvarid = ncvarid;
-
-  if ( vlistInqVarMissvalUsed(vlistID, varID) )
-    cdfDefVarMissval(streamptr, varID, vlistInqVarDatatype(vlistID, varID), 0);
-
-  if ( zid == -1 )
-    {
-      if ( zaxisInqType(zaxisID) == ZAXIS_CLOUD_BASE          ||
-           zaxisInqType(zaxisID) == ZAXIS_CLOUD_TOP           ||
-           zaxisInqType(zaxisID) == ZAXIS_ISOTHERM_ZERO       ||
-           zaxisInqType(zaxisID) == ZAXIS_TOA                 ||
-           zaxisInqType(zaxisID) == ZAXIS_SEA_BOTTOM          ||
-           zaxisInqType(zaxisID) == ZAXIS_LAKE_BOTTOM         ||
-           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM     ||
-           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM_TA  ||
-           zaxisInqType(zaxisID) == ZAXIS_SEDIMENT_BOTTOM_TW  ||
-           zaxisInqType(zaxisID) == ZAXIS_MIX_LAYER           ||
-           zaxisInqType(zaxisID) == ZAXIS_ATMOSPHERE )
-        {
-          zaxisInqName(zaxisID, varname);
-          cdf_put_att_text(fileID, ncvarid, "level_type", strlen(varname), varname);
-        }
-    }
-
-  if ( vlistInqVarEnsemble( vlistID,  varID, &ensID, &ensCount, &forecast_type ) )
-    {
-      /* void cdf_put_att_int(  int ncid, int varid, const char *name, nc_type xtype,
-	                        size_t len, const int *ip )
-       */
-	cdf_put_att_int(fileID, ncvarid, "realization", NC_INT, 1, &ensID);
-	cdf_put_att_int(fileID, ncvarid, "ensemble_members", NC_INT, 1, &ensCount);
-	cdf_put_att_int(fileID, ncvarid, "forecast_init_type", NC_INT, 1, &forecast_type);
-
-#ifdef DBG
-	if( DBG )
-	  {
-	    fprintf( stderr, "cdfDefVar :\n EnsID  %d\n Enscount %d\n Forecast init type %d\n",  ensID,
-		     ensCount,  forecast_type );
-	  }
-#endif
-    }
-
-  /* Attributes */
-  defineAttributes(vlistID, varID, fileID, ncvarid);
-
-  /* if ( streamptr->ncmode == 2 ) cdf_enddef(fileID); */
-
-  return ncvarid;
-}
-
-static
-void scale_add(size_t size, double *data, double addoffset, double scalefactor)
-{
-  int laddoffset;
-  int lscalefactor;
-
-  laddoffset   = IS_NOT_EQUAL(addoffset, 0);
-  lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
-
-  if ( laddoffset || lscalefactor )
-    {
-      for (size_t i = 0; i < size; ++i )
-        {
-          if ( lscalefactor ) data[i] *= scalefactor;
-          if ( laddoffset )   data[i] += addoffset;
-        }
-    }
-}
-
-static
-void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], size_t (*count)[4])
-{
-  int vlistID = streamptr->vlistID;
-  int tsID = streamptr->curTsID;
-  int gridID    = vlistInqVarGrid(vlistID, varID);
-  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
-  int gridindex = vlistGridIndex(vlistID, gridID);
-
-  if ( CDI_Debug ) Message("tsID = %d", tsID);
-
-  int xid = UNDEFID, yid = UNDEFID;
-  if ( gridInqType(gridID) == GRID_TRAJECTORY )
-    {
-      cdfReadGridTraj(streamptr, gridID);
-    }
-  else
-    {
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
-    }
-  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-  int zid = streamptr->zaxisID[zaxisindex];
-
-  int ndims = 0;
-#define addDimension(startCoord, length) do \
-    { \
-      (*start)[ndims] = startCoord; \
-      (*count)[ndims] = length; \
-      ndims++; \
-    } while(0)
-  if ( tsteptype != TSTEP_CONSTANT ) addDimension((size_t)tsID, 1);
-  if ( zid != UNDEFID ) addDimension(0, (size_t)zaxisInqSize(zaxisID));
-  if ( yid != UNDEFID ) addDimension(0, (size_t)gridInqYsize(gridID));
-  if ( xid != UNDEFID ) addDimension(0, (size_t)gridInqXsize(gridID));
-#undef addDimension
-
-  assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
-  assert(ndims <= (int)(sizeof(*count)/sizeof(**count)));
-
-  if ( CDI_Debug )
-    for (int idim = 0; idim < ndims; idim++)
-      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
-}
-
-//Scans the data array for missVals, optionally applying first a scale factor and then an offset.
-//Returns the number of missing + out-of-range values encountered.
-static
-size_t cdfDoInputDataTransformationDP(size_t valueCount, double *data, bool haveMissVal, double missVal, double scaleFactor, double offset, double validMin, double validMax)
- {
-  const bool haveOffset   = IS_NOT_EQUAL(offset, 0);
-  const bool haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1);
-  size_t missValCount = 0;
-
-  if ( IS_EQUAL(validMin, VALIDMISS) ) validMin = DBL_MIN;
-  if ( IS_EQUAL(validMax, VALIDMISS) ) validMax = DBL_MAX;
-
-  bool haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin,DBL_MIN));
-  assert(!haveRangeCheck || haveMissVal);
-
-  switch ((int)haveMissVal | ((int)haveScaleFactor << 1)
-          | ((int)haveOffset << 2) | ((int)haveRangeCheck << 3))
-    {
-    case 15: /* haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset */
-      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;
-        }
-      break;
-    case 13: /* haveRangeCheck & haveMissVal & haveOffset */
-      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;
-        }
-      break;
-    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;
-        }
-      break;
-    case 9: /* haveRangeCheck & haveMissVal */
-      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 : data[i];
-        }
-      break;
-    case 7: /* haveMissVal & haveScaleFactor & haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        if ( DBL_IS_EQUAL(data[i], missVal) )
-          missValCount++;
-        else
-          data[i] = data[i] * scaleFactor + offset;
-      break;
-    case 6: /* haveOffset & haveScaleFactor */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] = data[i] * scaleFactor + offset;
-      break;
-    case 5: /* haveMissVal & haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        if ( DBL_IS_EQUAL(data[i], missVal) )
-          missValCount++;
-        else
-          data[i] += offset;
-      break;
-    case 4: /* haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] += offset;
-      break;
-    case 3: /* haveMissVal & haveScaleFactor */
-      for ( size_t i = 0; i < valueCount; i++ )
-        if ( DBL_IS_EQUAL(data[i], missVal) )
-          missValCount++;
-        else
-          data[i] *= scaleFactor;
-      break;
-    case 2: /* haveScaleFactor */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] *= scaleFactor;
-      break;
-    case 1: /* haveMissVal */
-      for ( size_t i = 0; i < valueCount; i++ )
-        missValCount += (unsigned)DBL_IS_EQUAL(data[i], missVal);
-      break;
-    }
-
-  return missValCount;
-}
-
-static
-size_t cdfDoInputDataTransformationSP(size_t valueCount, float *data, bool haveMissVal, double missVal, double scaleFactor, double offset, double validMin, double validMax)
- {
-  const bool haveOffset   = IS_NOT_EQUAL(offset, 0);
-  const bool haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1);
-  size_t missValCount = 0;
-
-  if ( IS_EQUAL(validMin, VALIDMISS) ) validMin = DBL_MIN;
-  if ( IS_EQUAL(validMax, VALIDMISS) ) validMax = DBL_MAX;
-
-  bool haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin,DBL_MIN));
-  assert(!haveRangeCheck || haveMissVal);
-
-  switch ((int)haveMissVal | ((int)haveScaleFactor << 1)
-          | ((int)haveOffset << 2) | ((int)haveRangeCheck << 3))
-    {
-    case 15: /* haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset */
-      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);
-        }
-      break;
-    case 13: /* haveRangeCheck & haveMissVal & haveOffset */
-      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);
-        }
-      break;
-    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);
-        }
-      break;
-    case 9: /* haveRangeCheck & haveMissVal */
-      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 : data[i];
-        }
-      break;
-    case 7: /* haveMissVal & haveScaleFactor & haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        if ( DBL_IS_EQUAL(data[i], missVal) )
-          missValCount++;
-        else
-          data[i] = (float)(data[i] * scaleFactor + offset);
-      break;
-    case 6: /* haveOffset & haveScaleFactor */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] = (float)(data[i] * scaleFactor + offset);
-      break;
-    case 5: /* haveMissVal & haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        if ( DBL_IS_EQUAL(data[i], missVal) )
-          missValCount++;
-        else
-          data[i] = (float)(data[i] + offset);
-      break;
-    case 4: /* haveOffset */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] = (float)(data[i] + offset);
-      break;
-    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);
-      break;
-    case 2: /* haveScaleFactor */
-      for ( size_t i = 0; i < valueCount; i++ )
-        data[i] = (float)(data[i] * scaleFactor);
-      break;
-    case 1: /* haveMissVal */
-      for ( size_t i = 0; i < valueCount; i++ )
-        missValCount += (unsigned)DBL_IS_EQUAL(data[i], missVal);
-      break;
-    }
-
-  return missValCount;
-}
-
-static void
-cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dtype, long nvals, size_t xsize, size_t ysize, int swapxy, size_t *start, size_t *count, int memtype, const void *data, int nmiss)
-{
-  const double *pdata_dp = (const double *) data;
-  double *mdata_dp = NULL;
-  double *sdata_dp = NULL;
-  const float *pdata_sp = (const float *) data;
-  float *mdata_sp = NULL;
-  float *sdata_sp = NULL;
-
-  /*  if ( dtype == DATATYPE_INT8 || dtype == DATATYPE_INT16 || dtype == DATATYPE_INT32 ) */
-    {
-      bool laddoffset, lscalefactor;
-      double addoffset, scalefactor;
-      double missval;
-
-      addoffset    = vlistInqVarAddoffset(vlistID, varID);
-      scalefactor  = vlistInqVarScalefactor(vlistID, varID);
-      laddoffset   = IS_NOT_EQUAL(addoffset, 0);
-      lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
-
-      missval      = vlistInqVarMissval(vlistID, varID);
-
-      if ( laddoffset || lscalefactor )
-        {
-          if ( memtype == MEMTYPE_FLOAT )
-            {
-              mdata_sp = (float *) Malloc((size_t)nvals*sizeof(float));
-              memcpy(mdata_sp, pdata_sp, (size_t)nvals * sizeof (float));
-              pdata_sp = mdata_sp;
-
-              if ( nmiss > 0 )
-                {
-                  for (long i = 0; i < nvals; i++ )
-                    {
-                      double temp = mdata_sp[i];
-                      if ( !DBL_IS_EQUAL(temp, missval) )
-                        {
-                          if ( laddoffset )   temp -= addoffset;
-                          if ( lscalefactor ) temp /= scalefactor;
-                          mdata_sp[i] = (float)temp;
-                        }
-                    }
-                }
-              else
-                {
-                  for (long i = 0; i < nvals; i++ )
-                    {
-                      double temp = mdata_sp[i];
-                      if ( laddoffset )   temp -= addoffset;
-                      if ( lscalefactor ) temp /= scalefactor;
-                      mdata_sp[i] = (float)temp;
-                    }
-                }
-            }
-          else
-            {
-              mdata_dp = (double *) Malloc((size_t)nvals * sizeof(double));
-              memcpy(mdata_dp, pdata_dp, (size_t)nvals * sizeof(double));
-              pdata_dp = mdata_dp;
-
-              if ( nmiss > 0 )
-                {
-                  for (long i = 0; i < nvals; i++ )
-                    {
-                      if ( !DBL_IS_EQUAL(mdata_dp[i], missval) )
-                        {
-                          if ( laddoffset )   mdata_dp[i] -= addoffset;
-                          if ( lscalefactor ) mdata_dp[i] /= scalefactor;
-                        }
-                    }
-                }
-              else
-                {
-                  for (long i = 0; i < nvals; i++ )
-                    {
-                      if ( laddoffset )   mdata_dp[i] -= addoffset;
-                      if ( lscalefactor ) mdata_dp[i] /= scalefactor;
-                    }
-                }
-            }
-        }
-
-      if ( dtype == DATATYPE_UINT8 || dtype == DATATYPE_INT8 ||
-           dtype == DATATYPE_INT16 || dtype == DATATYPE_INT32 )
-        {
-          if ( memtype == MEMTYPE_FLOAT )
-            {
-              if ( mdata_sp == NULL )
-                {
-                  mdata_sp = (float *) Malloc((size_t)nvals * sizeof(float));
-                  memcpy(mdata_sp, pdata_sp, (size_t)nvals * sizeof(float));
-                  pdata_sp = mdata_sp;
-                }
-
-              for (long i = 0; i < nvals; i++ ) mdata_sp[i] = roundf(mdata_sp[i]);
-
-              if ( dtype == DATATYPE_UINT8 )
-                {
-                  nc_type xtype;
-                  cdf_inq_vartype(fileID, ncvarid, &xtype);
-                  if ( xtype == NC_BYTE )
-                    {
-                      for ( long i = 0; i < nvals; ++i )
-                        if ( mdata_sp[i] > 127 ) mdata_sp[i] -= 256;
-                    }
-                }
-            }
-          else
-            {
-              if ( mdata_dp == NULL )
-                {
-                  mdata_dp = (double *) Malloc((size_t)nvals * sizeof (double));
-                  memcpy(mdata_dp, pdata_dp, (size_t)nvals * sizeof (double));
-                  pdata_dp = mdata_dp;
-                }
-
-              for (long i = 0; i < nvals; i++ ) mdata_dp[i] = round(mdata_dp[i]);
-
-              if ( dtype == DATATYPE_UINT8 )
-                {
-                  nc_type xtype;
-                  cdf_inq_vartype(fileID, ncvarid, &xtype);
-                  if ( xtype == NC_BYTE )
-                    {
-                      for (long i = 0; i < nvals; ++i )
-                        if ( mdata_dp[i] > 127 ) mdata_dp[i] -= 256;
-                    }
-                }
-            }
-        }
-
-      if ( CDF_Debug && memtype != MEMTYPE_FLOAT )
-        {
-          double fmin, fmax;
-          fmin =  1.0e200;
-          fmax = -1.0e200;
-          for ( long i = 0; i < nvals; ++i )
-            {
-              if ( !DBL_IS_EQUAL(pdata_dp[i], missval) )
-                {
-                  if ( pdata_dp[i] < fmin ) fmin = pdata_dp[i];
-                  if ( pdata_dp[i] > fmax ) fmax = pdata_dp[i];
-                }
-            }
-          Message("nvals = %d, nmiss = %d, missval = %g, minval = %g, maxval = %g",
-                  nvals, nmiss, missval, fmin, fmax);
-        }
-    }
-
-  if ( swapxy )
-    {
-      if ( memtype == MEMTYPE_FLOAT )
-        {
-          /* malloc and the loop imply nvals >= ysize * xsize,
-           * but that is not checked and the types don't match */
-          sdata_sp = (float *) Malloc((size_t)nvals * sizeof (float));
-          for ( size_t j = 0; j < ysize; ++j )
-            for ( size_t i = 0; i < xsize; ++i )
-              sdata_sp[i*ysize+j] = pdata_sp[j*xsize+i];
-          pdata_sp = sdata_sp;
-        }
-      else
-        {
-          sdata_dp = (double *) Malloc((size_t)nvals * sizeof (double));
-          for ( size_t j = 0; j < ysize; ++j )
-            for ( size_t i = 0; i < xsize; ++i )
-              sdata_dp[i*ysize+j] = pdata_dp[j*xsize+i];
-          pdata_dp = sdata_dp;
-        }
-    }
-
-  if ( memtype == MEMTYPE_FLOAT )
-    cdf_put_vara_float(fileID, ncvarid, start, count, pdata_sp);
-  else
-    cdf_put_vara_double(fileID, ncvarid, start, count, pdata_dp);
-
-  if ( mdata_dp ) Free(mdata_dp);
-  if ( sdata_dp ) Free(sdata_dp);
-  if ( mdata_sp ) Free(mdata_sp);
-  if ( sdata_sp ) Free(sdata_sp);
-}
-
-
-void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
-{
-  int fileID;
-  int gridID;
-  int zaxisID;
-  int xid = UNDEFID, yid = UNDEFID, zid = UNDEFID;
-  int ncvarid;
-  size_t xsize = 0, ysize = 0;
-  size_t size;
-  size_t start[5];
-  size_t count[5];
-  long nvals;
-  int swapxy = FALSE;
-  int ndims = 0;
-  int idim;
-  int tsteptype;
-  int gridindex, zaxisindex;
-  int dtype;
-  int vlistID;
-
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
-
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
-
-  long ntsteps = streamptr->ntsteps;
-  if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
-
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
-
-  ncvarid = cdfDefVar(streamptr, varID);
-
-  gridID    = vlistInqVarGrid(vlistID, varID);
-  zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  tsteptype = vlistInqVarTsteptype(vlistID, varID);
-
-  gridindex = vlistGridIndex(vlistID, gridID);
-  if ( gridInqType(gridID) == GRID_TRAJECTORY )
-    {
-      cdfWriteGridTraj(streamptr, gridID);
-    }
-  else
-    {
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
-    }
-
-  zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-  zid = streamptr->zaxisID[zaxisindex];
-
-  if ( tsteptype != TSTEP_CONSTANT )
-    {
-      start[ndims] = (size_t)ntsteps - 1;
-      count[ndims] = 1;
-      ndims++;
-    }
-  if ( zid != UNDEFID )
-    {
-      start[ndims] = 0;
-      count[ndims] = (size_t)zaxisInqSize(zaxisID);
-      ndims++;
-    }
-  if ( yid != UNDEFID )
-    {
-      start[ndims] = 0;
-      cdf_inq_dimlen(fileID, yid, &size);
-      /*      count[ndims] = gridInqYsize(gridID); */
-      count[ndims] = size;
-      ndims++;
-    }
-  if ( xid != UNDEFID )
-    {
-      start[ndims] = 0;
-      cdf_inq_dimlen(fileID, xid, &size);
-      /*      count[ndims] = gridInqXsize(gridID); */
-      count[ndims] = size;
-      ndims++;
-    }
-
-  if ( CDI_Debug )
-    for (idim = 0; idim < ndims; idim++)
-      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
-
-  if ( streamptr->ncmode == 1 )
-    {
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-    }
-
-  dtype = vlistInqVarDatatype(vlistID, varID);
-
-  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
-
-  nvals = gridInqSize(gridID)*zaxisInqSize(zaxisID);
-
-  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
-
-}
-
-
-void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
-                         const int rect[][2], const void *data, int nmiss)
-{
-  int fileID;
-  int gridID;
-  int zaxisID;
-  int xid = UNDEFID, yid = UNDEFID, zid = UNDEFID;
-  int ncvarid;
-  size_t xsize = 0, ysize = 0;
-  size_t start[5];
-  size_t count[5];
-  long nvals;
-  int swapxy = FALSE;
-  int ndims = 0;
-  int idim;
-  int tsteptype;
-  int gridindex, zaxisindex;
-  int dtype;
-  int vlistID;
-  int streamID = streamptr->self;
-
-  if ( CDI_Debug )
-    Message("streamID = %d  varID = %d", streamID, varID);
-
-  vlistID = streamInqVlist(streamID);
-  fileID  = streamInqFileID(streamID);
-
-  long ntsteps = streamptr->ntsteps;
-  if ( CDI_Debug )
-    Message("ntsteps = %ld", ntsteps);
-
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
-
-  ncvarid = cdfDefVar(streamptr, varID);
-
-  gridID    = vlistInqVarGrid(vlistID, varID);
-  zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  tsteptype = vlistInqVarTsteptype(vlistID, varID);
-
-  gridindex = vlistGridIndex(vlistID, gridID);
-  if ( gridInqType(gridID) == GRID_TRAJECTORY )
-    {
-      cdfWriteGridTraj(streamptr, gridID);
-    }
-  else
-    {
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
-    }
-
-  zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-  zid = streamptr->zaxisID[zaxisindex];
-
-  if ( tsteptype != TSTEP_CONSTANT )
-    {
-      start[ndims] = (size_t)ntsteps - 1;
-      count[ndims] = 1;
-      ndims++;
-    }
-  if ( zid != UNDEFID )
-    {
-      int size = zaxisInqSize(zaxisID);
-      xassert(rect[2][0] >= 0 && rect[2][0] <= rect[2][1]
-              && rect[2][1] <= size);
-      start[ndims] = (size_t)rect[2][0];
-      count[ndims] = (size_t)rect[2][1] - (size_t)rect[2][0] + 1;
-      ndims++;
-    }
-  if ( yid != UNDEFID )
-    {
-      size_t size;
-      cdf_inq_dimlen(fileID, yid, &size);
-      xassert(rect[1][0] >= 0 && rect[1][0] <= rect[1][1]
-              && (size_t)rect[1][1] <= size);
-      start[ndims] = (size_t)rect[1][0];
-      count[ndims] = (size_t)rect[1][1] - (size_t)rect[1][0] + 1;
-      ndims++;
-    }
-  if ( xid != UNDEFID )
-    {
-      size_t size;
-      cdf_inq_dimlen(fileID, xid, &size);
-      xassert(rect[0][0] >= 0 && rect[0][0] <= rect[0][1]
-              && (size_t)rect[0][1] <= size);
-      start[ndims] = (size_t)rect[0][0];
-      count[ndims] = (size_t)rect[0][1] - (size_t)rect[0][0] + 1;
-      ndims++;
-    }
-
-  if ( CDI_Debug )
-    for (idim = 0; idim < ndims; idim++)
-      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
-
-  if ( streamptr->ncmode == 1 )
-    {
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-    }
-
-  dtype = vlistInqVarDatatype(vlistID, varID);
-
-  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
-
-  nvals = gridInqSize(gridID)*zaxisInqSize(zaxisID);
-
-  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals,
-                     xsize, ysize, swapxy, start, count, memtype, data, nmiss);
-}
-
-static
-size_t min_size(size_t a, size_t b)
-{
-  return a < b ? a : b;
-}
-
-static
-void transpose2dArrayDP(size_t inWidth, size_t inHeight, double* data)
-{
-  const size_t cacheBlockSize = 256;    // Purely an optimization parameter. Current value of 32 means we are handling 8kB blocks,
-                                       // which should be a decent compromise on many architectures.
-  
-#ifdef __cplusplus
-  double *temp[inHeight];
-  double *out[inWidth];
-  
-  temp[0] =  (double *) Malloc(inHeight * inWidth * sizeof(double));
-  out[0] = data;
-  
-  for(int i = 0; i < inWidth; i++)
-  {
-    out[i] = out[0] + (inHeight * i);
-  }
-
-  for(int i = 1; i < inHeight; i++)
-  {
-    temp[i] = temp[0] + (inWidth * i);
-  }
-  memcpy(temp[0], data, inHeight * inWidth * sizeof(double));
-#else
-  double (*temp)[inWidth] = (double (*)[inWidth]) Malloc(inHeight*sizeof(*temp));
-  double (*out)[inHeight] = (double (*)[inHeight])data;
-  memcpy(temp, data, inHeight*sizeof(*temp));
-#endif
-  
-  /*
-  for ( size_t y = 0; y < inHeight; ++y )
-    for ( size_t x = 0; x < inWidth; ++x )
-      out[x][y] = temp[y][x];
-  */
-
-  for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
-    {
-      for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
-        {
-          for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
-            {
-              for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
-                {
-                  out[x][y] = temp[y][x];
-                }
-            }
-        }
-    }
-
-  Free(temp[0]);
-}
-
-static
-void transpose2dArraySP(size_t inWidth, size_t inHeight, float* data)
-{
-  const size_t cacheBlockSize = 256;    // Purely an optimization parameter. Current value of 32 means we are handling 8kB blocks,
-                                       // which should be a decent compromise on many architectures.
-  
-#ifndef __cplusplus 
-  float (*temp)[inWidth] = (float (*)[inWidth]) Malloc(inHeight*sizeof(*temp));
-  float (*out)[inHeight] = (float (*)[inHeight])data;
-  memcpy(temp, data, inHeight*sizeof(*temp));
-  #else
-  float *temp[inWidth];
-  temp[0] =  (float *) Malloc(inWidth * inHeight * sizeof(float));
-  for(int i = 1; i < inHeight; i++)
-  {
-    temp[i] = temp[0] + (inWidth * i);
-  }
-
-  float **out = (float **)data;
-#endif
-  
-  /*
-  for ( size_t y = 0; y < inHeight; ++y )
-    for ( size_t x = 0; x < inWidth; ++x )
-      out[x][y] = temp[y][x];
-  */
-  
-  for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
-    {
-      for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
-        {
-          for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
-            {
-              for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
-                {
-                  out[x][y] = temp[y][x];
-                }
-            }
-        }
-    }
-
-  Free(temp);
-}
-
-static
-void cdfInqDimIds(stream_t *streamptr, int varId, int (*outDimIds)[3])
-{
-  int gridId = vlistInqVarGrid(streamptr->vlistID, varId);
-  int gridindex = vlistGridIndex(streamptr->vlistID, gridId);
-
-  (*outDimIds)[0] = (*outDimIds)[1] = (*outDimIds)[2] = UNDEFID;
-  switch ( gridInqType(gridId) )
-    {
-      case GRID_TRAJECTORY:
-        cdfReadGridTraj(streamptr, gridId);
-        break;
-
-      case GRID_UNSTRUCTURED:
-        (*outDimIds)[0] = streamptr->xdimID[gridindex];
-        break;
-
-      default:
-        (*outDimIds)[0] = streamptr->xdimID[gridindex];
-        (*outDimIds)[1] = streamptr->ydimID[gridindex];
-        break;
-    }
-
-  int zaxisID = vlistInqVarZaxis(streamptr->vlistID, varId);
-  int zaxisindex = vlistZaxisIndex(streamptr->vlistID, zaxisID);
-  (*outDimIds)[2] = streamptr->zaxisID[zaxisindex];
-}
-
-static
-int cdfGetSkipDim(int fileId, int ncvarid, int (*dimIds)[3])
-{
-  if((*dimIds)[0] != UNDEFID) return 0;
-  if((*dimIds)[1] != UNDEFID) return 0;
-  int nvdims;
-  cdf_inq_varndims(fileId, ncvarid, &nvdims);
-  if(nvdims != 3) return 0;
-
-  int varDimIds[3];
-  cdf_inq_vardimid(fileId, ncvarid, varDimIds);
-  size_t size = 0;
-  if ( (*dimIds)[2] == varDimIds[2] )
-    {
-      cdf_inq_dimlen(fileId, varDimIds[1], &size);
-      if ( size == 1 ) return 1;
-    }
-  else if ( (*dimIds)[2] == varDimIds[1] )
-    {
-      cdf_inq_dimlen(fileId, varDimIds[2], &size);
-      if ( size == 1 ) return 2;
-    }
-  return 0;
-}
-
-
-static
-void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, bool *outSwapXY, size_t (*start)[4], size_t (*count)[4])
-{
-  int tsID = streamptr->curTsID;
-  if ( CDI_Debug ) Message("tsID = %d", tsID);
-
-  int fileId = streamptr->fileID;
-  int vlistId = streamptr->vlistID;
-  int ncvarid = streamptr->vars[varId].ncvarid;
-
-  int gridId = vlistInqVarGrid(vlistId, varId);
-  int tsteptype = vlistInqVarTsteptype(vlistId, varId);
-  int gridsize = gridInqSize(gridId);
-
-  streamptr->numvals += gridsize;
-
-  int dimIds[3];    //this array joins the old variables xid, yid, and zid
-  cdfInqDimIds(streamptr, varId, &dimIds);
-
-  int skipdim = cdfGetSkipDim(fileId, ncvarid, &dimIds);
-
-  int dimorder[3];
-  vlistInqVarDimorder(vlistId, varId, &dimorder);
-
-  *outSwapXY = (dimorder[2] == 2 || dimorder[0] == 1) && dimIds[0] != UNDEFID && dimIds[1] != UNDEFID ;
-
-  int ndims = 0;
-
-#define addDimension(startIndex, extent) do {   \
-      (*start)[ndims] = startIndex; \
-      (*count)[ndims] = extent; \
-      ndims++; \
-  } while(0)
-
-  if ( tsteptype != TSTEP_CONSTANT ) addDimension((size_t)tsID, 1);
-  if ( skipdim == 1 ) addDimension(0, 1);
-
-  for ( int id = 0; id < 3; ++id )
-    {
-      size_t size;
-      int curDimId = dimIds[dimorder[id]-1];
-      if ( curDimId == UNDEFID ) continue;
-      switch ( dimorder[id] )
-        {
-          Error("Internal errror: Malformed dimension order encountered. Please report this bug.\n");
-          case 1:
-          case 2:
-            cdf_inq_dimlen(fileId, curDimId, &size);
-            addDimension(0, size);
-            break;
-
-          case 3:
-            addDimension((size_t)levelId, 1);
-            break;
-
-          default:
-            Error("Internal errror: Malformed dimension order encountered. Please report this bug.\n");
-        }
-    }
-
-  if ( skipdim == 2 ) addDimension(0, 1);
-
-  assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
-  assert(ndims <= (int)(sizeof(*count)/sizeof(**count)));
-
-#undef addDimension
-
-  if ( CDI_Debug )
-    for (int idim = 0; idim < ndims; idim++)
-      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
-
-  int nvdims;
-  cdf_inq_varndims(fileId, ncvarid, &nvdims);
-
-  if ( nvdims != ndims )
-    Error("Internal error, variable %s has an unsupported array structure!", vlistInqVarNamePtr(vlistId, varId));
-}
-
-
-void cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
-{
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  int ncvarid = streamptr->vars[varID].ncvarid;
-
-  int gridID  = vlistInqVarGrid(vlistID, varID);
-  int zaxisID = vlistInqVarZaxis(vlistID, varID);
-
-  size_t start[4];
-  size_t count[4];
-  cdfGetSlapDescription(streamptr, varID, &start, &count);
-
-  cdf_get_vara_double(fileID, ncvarid, start, count, data);
-
-  size_t size = (size_t)gridInqSize(gridID)*(size_t)zaxisInqSize(zaxisID);
-  double missval = vlistInqVarMissval(vlistID, varID);
-  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
-  double validRange[2];
-  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
-    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
-  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
-  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
-  size_t nmiss_ = cdfDoInputDataTransformationDP(size, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
-  assert(nmiss_ <= INT_MAX);
-  *nmiss = (int)nmiss_;
-}
-
-
-void cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss)
-{
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  int ncvarid = streamptr->vars[varID].ncvarid;
-
-  int gridID  = vlistInqVarGrid(vlistID, varID);
-  int zaxisID = vlistInqVarZaxis(vlistID, varID);
-
-  size_t start[4];
-  size_t count[4];
-  cdfGetSlapDescription(streamptr, varID, &start, &count);
-
-  cdf_get_vara_float(fileID, ncvarid, start, count, data);
-
-  size_t size = (size_t)gridInqSize(gridID) * (size_t)zaxisInqSize(zaxisID);
-  double missval = vlistInqVarMissval(vlistID, varID);
-  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
-  double validRange[2];
-  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
-    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
-  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
-  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
-  size_t nmiss_ = cdfDoInputDataTransformationSP(size, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
-  assert(nmiss_ <= INT_MAX);
-  *nmiss = (int)nmiss_;
-}
-
-
-void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data, int *nmiss)
-{
-  size_t start[4];
-  size_t count[4];
-
-  if ( CDI_Debug )
-    Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
-
-  int vlistID = streamptr->vlistID;
-  int fileID = streamptr->fileID;
-
-  bool swapxy;
-  cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
-
-  int ncvarid = streamptr->vars[varID].ncvarid;
-  int gridId = vlistInqVarGrid(vlistID, varID);
-  size_t gridsize = (size_t)gridInqSize(gridId);
-  size_t xsize = (size_t)gridInqXsize(gridId);
-  size_t ysize = (size_t)gridInqYsize(gridId);
-
-  if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT32 )
-    {
-      float *data_fp = (float *) Malloc(gridsize*sizeof(*data_fp));
-      cdf_get_vara_float(fileID, ncvarid, start, count, data_fp);
-      for ( size_t i = 0; i < gridsize; i++ )
-        data[i] = (double) data_fp[i];
-      Free(data_fp);
-    }
-  else if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
-    {
-      nc_type xtype;
-      cdf_inq_vartype(fileID, ncvarid, &xtype);
-      if ( xtype == NC_BYTE )
-        {
-          for ( size_t i = 0; i < gridsize; i++ )
-            if ( data[i] < 0 ) data[i] += 256;
-        }
-    }
-  else
-    {
-      cdf_get_vara_double(fileID, ncvarid, start, count, data);
-    }
-
-  if ( swapxy ) transpose2dArrayDP(ysize, xsize, data);
-
-  double missval = vlistInqVarMissval(vlistID, varID);
-  const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
-  double validRange[2];
-  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
-    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
-  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
-  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
-  size_t nmiss_ = cdfDoInputDataTransformationDP(gridsize, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
-  assert(nmiss_ <= INT_MAX);
-  *nmiss = (int)nmiss_;
-}
-
-
-void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data, int *nmiss)
-{
-  size_t start[4];
-  size_t count[4];
-
-  if ( CDI_Debug )
-    Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
-
-  int vlistID = streamptr->vlistID;
-  int fileID = streamptr->fileID;
-
-  bool swapxy;
-  cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
-
-  int ncvarid = streamptr->vars[varID].ncvarid;
-  int gridId = vlistInqVarGrid(vlistID, varID);
-  size_t gridsize = (size_t)gridInqSize(gridId);
-  size_t xsize = (size_t)gridInqXsize(gridId);
-  size_t ysize = (size_t)gridInqYsize(gridId);
-
-  if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT64 )
-    {
-      double *data_dp = (double *) Malloc(gridsize*sizeof(*data_dp));
-      cdf_get_vara_double(fileID, ncvarid, start, count, data_dp);
-      for ( size_t i = 0; i < gridsize; i++ )
-        data[i] = (float) data_dp[i];
-      Free(data_dp);
-    }
-  else if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
-    {
-      nc_type xtype;
-      cdf_inq_vartype(fileID, ncvarid, &xtype);
-      if ( xtype == NC_BYTE )
-        {
-          for ( size_t i = 0; i < gridsize; i++ )
-            if ( data[i] < 0 ) data[i] += 256;
-        }
-    }
-  else
-    {
-      cdf_get_vara_float(fileID, ncvarid, start, count, data);
-    }
-
-  if ( swapxy ) transpose2dArraySP(ysize, xsize, data);
-
-  double missval = vlistInqVarMissval(vlistID, varID);
-  bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
-  double validRange[2];
-  if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
-    validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
-  double addoffset   = vlistInqVarAddoffset(vlistID, varID);
-  double scalefactor = vlistInqVarScalefactor(vlistID, varID);
-  size_t nmiss_ = cdfDoInputDataTransformationSP(gridsize, data, haveMissVal, missval, scalefactor, addoffset, validRange[0], validRange[1]);
-  assert(nmiss_ <= INT_MAX);
-  *nmiss = (int)nmiss_;
-}
-
-
-void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
-{
-  size_t xsize = 0, ysize = 0;
-  size_t start[5];
-  size_t count[5];
-  int dimorder[3];
-  int xid = UNDEFID, yid = UNDEFID, zid = UNDEFID;
-
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  long ntsteps = streamptr->ntsteps;
-  if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
-
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
-
-  int ncvarid = cdfDefVar(streamptr, varID);
-
-  int gridID    = vlistInqVarGrid(vlistID, varID);
-  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
-  vlistInqVarDimorder(vlistID, varID, &dimorder);
-
-
-  if ( gridInqType(gridID) == GRID_TRAJECTORY )
+    }
+  else if ( gridtype == GRID_SPECTRAL )
     {
-      cdfWriteGridTraj(streamptr, gridID);
+      cdfDefComplex(streamptr, gridID);
+      cdfDefSP(streamptr, gridID);
     }
-  else
+  else if ( gridtype == GRID_FOURIER )
     {
-      int gridindex = vlistGridIndex(vlistID, gridID);
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
+      cdfDefComplex(streamptr, gridID);
+      cdfDefFC(streamptr, gridID);
     }
-  {
-    int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-    zid = streamptr->zaxisID[zaxisindex];
-  }
+  else if ( gridtype == GRID_TRAJECTORY )
+    {
+      cdfDefTrajLon(streamptr, gridID);
+      cdfDefTrajLat(streamptr, gridID);
+    }
+  else if ( gridtype == GRID_SINUSOIDAL || gridtype == GRID_LAEA || gridtype == GRID_LCC2 )
+    {
+      cdfDefXaxis(streamptr, gridID, 1);
+      cdfDefYaxis(streamptr, gridID, 1);
 
-  int swapxy = (dimorder[2] == 2 || dimorder[0] == 1) && xid != UNDEFID && yid != UNDEFID;
+      cdfDefMapping(streamptr, gridID);
+    }
   /*
-  printf("swapxy %d\n", swapxy);
-  printf("dimorder: %d %d %d\n", dimorder[0], dimorder[1], dimorder[2]);
+  else if ( gridtype == GRID_LCC )
+    {
+      cdfDefLcc(streamptr, gridID);
+    }
   */
-
-  size_t ndims = 0;
-  if ( tsteptype != TSTEP_CONSTANT )
+  else
     {
-      start[ndims] = (size_t)ntsteps - 1;
-      count[ndims] = 1;
-      ndims++;
+      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
     }
+}
+
+static
+void scale_add(size_t size, double *data, double addoffset, double scalefactor)
+{
+  int laddoffset;
+  int lscalefactor;
 
-  for ( int id = 0; id < 3; ++id )
+  laddoffset   = IS_NOT_EQUAL(addoffset, 0);
+  lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+
+  if ( laddoffset || lscalefactor )
     {
-      if ( dimorder[id] == 3 && zid != UNDEFID )
-        {
-          start[ndims] = (size_t)levelID;
-          count[ndims] = 1;
-          ndims++;
-        }
-      else if ( dimorder[id] == 2 && yid != UNDEFID )
-        {
-          start[ndims] = 0;
-          cdf_inq_dimlen(fileID, yid, &ysize);
-          count[ndims] = ysize;
-          ndims++;
-        }
-      else if ( dimorder[id] == 1 && xid != UNDEFID )
+      for (size_t i = 0; i < size; ++i )
         {
-          start[ndims] = 0;
-          cdf_inq_dimlen(fileID, xid, &xsize);
-          count[ndims] = xsize;
-          ndims++;
+          if ( lscalefactor ) data[i] *= scalefactor;
+          if ( laddoffset )   data[i] += addoffset;
         }
     }
-
-  if ( CDI_Debug )
-    for (size_t idim = 0; idim < ndims; idim++)
-      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
-
-  int dtype = vlistInqVarDatatype(vlistID, varID);
-
-  if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
-
-  long nvals = gridInqSize(gridID);
-
-  cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
-
 }
 
-
 static
 void cdfCreateRecords(stream_t *streamptr, int tsID)
 {
-  int varID, levelID, recID, vrecID, zaxisID;
-  int nlev, nvrecs;
-
-  int vlistID  = streamptr->vlistID;
-
   if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
 
   if ( streamptr->tsteps[tsID].nallrecs > 0 ) return;
 
+  int vlistID  = streamptr->vlistID;
+
   tsteps_t* sourceTstep = streamptr->tsteps;
   tsteps_t* destTstep = sourceTstep + tsID;
 
@@ -4718,7 +2827,7 @@ void cdfCreateRecords(stream_t *streamptr, int tsID)
 
   if ( tsID == 0 )
     {
-      nvrecs = nrecs; /* use all records at first timestep */
+      int nvrecs = nrecs; /* use all records at first timestep */
 
       streamptr->nrecs += nrecs;
 
@@ -4728,16 +2837,15 @@ void cdfCreateRecords(stream_t *streamptr, int tsID)
       destTstep->recordSize = nrecs;
       destTstep->curRecID   = UNDEFID;
       destTstep->recIDs     = (int *) Malloc((size_t)nvrecs*sizeof (int));;
-      for ( recID = 0; recID < nvrecs; recID++ ) destTstep->recIDs[recID] = recID;
+      for ( int recID = 0; recID < nvrecs; recID++ ) destTstep->recIDs[recID] = recID;
 
       record_t *records = destTstep->records;
 
-      recID = 0;
-      for ( varID = 0; varID < nvars; varID++ )
+      for ( int varID = 0, recID = 0; varID < nvars; varID++ )
         {
-          zaxisID = vlistInqVarZaxis(vlistID, varID);
-          nlev    = zaxisInqSize(zaxisID);
-          for ( levelID = 0; levelID < nlev; levelID++ )
+          int zaxisID = vlistInqVarZaxis(vlistID, varID);
+          int nlev    = zaxisInqSize(zaxisID);
+          for ( int levelID = 0; levelID < nlev; levelID++ )
             {
               recordInitEntry(&records[recID]);
               records[recID].varID   = (short)varID;
@@ -4748,12 +2856,12 @@ void cdfCreateRecords(stream_t *streamptr, int tsID)
     }
   else if ( tsID == 1 )
     {
-      nvrecs = 0;
-      for ( varID = 0; varID < nvars; varID++ )
+      int nvrecs = 0;
+      for ( int varID = 0; varID < nvars; varID++ )
         {
           if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
             {
-              zaxisID = vlistInqVarZaxis(vlistID, varID);
+              int zaxisID = vlistInqVarZaxis(vlistID, varID);
               nvrecs += zaxisInqSize(zaxisID);
             }
         }
@@ -4771,10 +2879,9 @@ void cdfCreateRecords(stream_t *streamptr, int tsID)
       if ( nvrecs )
         {
           destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
-          vrecID = 0;
-          for ( recID = 0; recID < nrecs; recID++ )
+          for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
             {
-              varID = destTstep->records[recID].varID;
+              int varID = destTstep->records[recID].varID;
               if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
                 {
                   destTstep->recIDs[vrecID++] = recID;
@@ -4786,7 +2893,7 @@ void cdfCreateRecords(stream_t *streamptr, int tsID)
     {
       if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
 
-      nvrecs = streamptr->tsteps[1].nrecs;
+      int nvrecs = streamptr->tsteps[1].nrecs;
 
       streamptr->nrecs += nvrecs;
 
@@ -4808,54 +2915,38 @@ void cdfCreateRecords(stream_t *streamptr, int tsID)
 static
 int cdfTimeDimID(int fileID, int ndims, int nvars)
 {
-  int dimid = UNDEFID;
-  int timedimid = UNDEFID;
-  char dimname[80];
-  char timeunits[CDI_MAX_NAME];
-  char attname[CDI_MAX_NAME];
-  char name[CDI_MAX_NAME];
-  nc_type xtype;
-  int nvdims, nvatts;
-  int dimids[9];
-  int varid, iatt;
-
-  for ( dimid = 0; dimid < ndims; dimid++ )
+  for ( int dimid = 0; dimid < ndims; dimid++ )
     {
+      char dimname[80];
       cdf_inq_dimname(fileID, dimid, dimname);
       if ( memcmp(dimname, "time", 4) == 0 )
-        {
-          timedimid = dimid;
-          break;
-        }
+        return dimid;
     }
 
-  if ( timedimid == UNDEFID )
+
+  for ( int varid = 0; varid < nvars; varid++ )
     {
-      for ( varid = 0; varid < nvars; varid++ )
+      int nvdims, nvatts, dimids[9];
+      cdf_inq_var(fileID, varid, NULL, NULL, &nvdims, dimids, &nvatts);
+      if ( nvdims == 1 )
         {
-          cdf_inq_var(fileID, varid, name, &xtype, &nvdims, dimids, &nvatts);
-          if ( nvdims == 1 )
+          for ( int iatt = 0; iatt < nvatts; iatt++ )
             {
-              for ( iatt = 0; iatt < nvatts; iatt++ )
+              char sbuf[CDI_MAX_NAME];
+              cdf_inq_attname(fileID, varid, iatt, sbuf);
+              if ( strncmp(sbuf, "units", 5) == 0 )
                 {
-                  cdf_inq_attname(fileID, varid, iatt, attname);
-                  if ( strncmp(attname, "units", 5) == 0 )
-                    {
-                      cdfGetAttText(fileID, varid, "units", sizeof(timeunits), timeunits);
-                      strtolower(timeunits);
+                  cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
+                  strtolower(sbuf);
 
-                      if ( isTimeUnits(timeunits) )
-                        {
-                          timedimid = dimids[0];
-                          break;
-                        }
-                    }
+                  if ( isTimeUnits(sbuf) )
+                    return dimids[0];
                 }
             }
         }
     }
 
-  return (timedimid);
+  return UNDEFID;
 }
 
 static
@@ -4975,9 +3066,9 @@ void cdfSetDim(ncvar_t *ncvars, int ncvarid, int dimid, int dimtype)
 }
 
 static
-int isLonAxis(const char *units, const char *stdname)
+bool isLonAxis(const char *units, const char *stdname)
 {
-  int status = FALSE;
+  bool status = false;
   char lc_units[16];
 
   memcpy(lc_units, units, 15);
@@ -4987,26 +3078,26 @@ int isLonAxis(const char *units, const char *stdname)
   if ( ((memcmp(lc_units, "degree", 6) == 0 || memcmp(lc_units, "radian", 6) == 0) &&
         (memcmp(stdname, "grid_longitude", 14) == 0 || memcmp(stdname, "longitude", 9) == 0)) )
     {
-      status = TRUE;
+      status = true;
     }
 
-  if ( status == FALSE &&
+  if ( status == false &&
        memcmp(stdname, "grid_latitude", 13) && memcmp(stdname, "latitude", 8) &&
        memcmp(lc_units, "degree", 6) == 0 )
     {
       int ioff = 6;
       if ( lc_units[ioff] == 's' ) ioff++;
       if ( lc_units[ioff] == '_' ) ioff++;
-      if ( lc_units[ioff] == 'e' ) status = TRUE;
+      if ( lc_units[ioff] == 'e' ) status = true;
     }
 
-  return (status);
+  return status;
 }
 
 static
-int isLatAxis(const char *units, const char *stdname)
+bool isLatAxis(const char *units, const char *stdname)
 {
-  int status = FALSE;
+  bool status = false;
   char lc_units[16];
 
   memcpy(lc_units, units, 15);
@@ -5016,26 +3107,26 @@ int isLatAxis(const char *units, const char *stdname)
   if ( ((memcmp(lc_units, "degree", 6) == 0 || memcmp(lc_units, "radian", 6) == 0) &&
         (memcmp(stdname, "grid_latitude", 13) == 0 || memcmp(stdname, "latitude", 8) == 0)) )
     {
-      status = TRUE;
+      status = true;
     }
 
-  if ( status == FALSE &&
+  if ( status == false &&
        memcmp(stdname, "grid_longitude", 14) && memcmp(stdname, "longitude", 9) &&
        memcmp(lc_units, "degree", 6) == 0 )
     {
       int ioff = 6;
       if ( lc_units[ioff] == 's' ) ioff++;
       if ( lc_units[ioff] == '_' ) ioff++;
-      if ( lc_units[ioff] == 'n' || lc_units[ioff] == 's' ) status = TRUE;
+      if ( lc_units[ioff] == 'n' || lc_units[ioff] == 's' ) status = true;
     }
 
-  return (status);
+  return status;
 }
 
 static
-int isDBLAxis(/*const char *units,*/ const char *longname)
+bool isDBLAxis(/*const char *units,*/ const char *longname)
 {
-  int status = FALSE;
+  bool status = false;
 
   if ( strcmp(longname, "depth below land")         == 0 ||
        strcmp(longname, "depth_below_land")         == 0 ||
@@ -5046,56 +3137,65 @@ int isDBLAxis(/*const char *units,*/ const char *longname)
            strcmp(ncvars[ncvarid].units, "dm") == 0 ||
            strcmp(ncvars[ncvarid].units, "m")  == 0 )
       */
-        status = TRUE;
+        status = true;
     }
 
-  return (status);
+  return status;
 }
 
 static
-int unitsIsMeter(const char *units)
+bool unitsIsHeight(const char *units)
 {
-  return (units[0] == 'm' && (!units[1] || strncmp(units, "meter", 5) == 0));
+  bool status = false;
+  int u0 = units[0];
+
+  if ( (u0=='m' && (!units[1] || strncmp(units, "meter", 5) == 0)) ||
+       (!units[2] && units[1]=='m' && (u0=='c' || u0=='d' || u0=='k')) )
+    {
+      status = true;
+    }
+
+  return status;
 }
 
 static
-int isDepthAxis(const char *stdname, const char *longname)
+bool isDepthAxis(const char *stdname, const char *longname)
 {
-  int status = FALSE;
+  bool status = false;
 
-  if ( strcmp(stdname, "depth") == 0 ) status = TRUE;
+  if ( strcmp(stdname, "depth") == 0 ) status = true;
 
-  if ( status == FALSE )
+  if ( status == false )
     if ( strcmp(longname, "depth_below_sea") == 0 ||
          strcmp(longname, "depth below sea") == 0 )
       {
-        status = TRUE;
+        status = true;
       }
 
-  return (status);
+  return status;
 }
 
 static
-int isHeightAxis(const char *stdname, const char *longname)
+bool isHeightAxis(const char *stdname, const char *longname)
 {
-  int status = FALSE;
+  bool status = false;
 
-  if ( strcmp(stdname, "height") == 0 ) status = TRUE;
+  if ( strcmp(stdname, "height") == 0 ) status = true;
 
-  if ( status == FALSE )
+  if ( status == false )
     if ( strcmp(longname, "height") == 0 ||
          strcmp(longname, "height above the surface") == 0 )
       {
-        status = TRUE;
+        status = true;
       }
 
-  return (status);
+  return status;
 }
 
 static
-int unitsIsPressure(const char *units)
+bool unitsIsPressure(const char *units)
 {
-  int status = FALSE;
+  bool status = false;
 
   if ( memcmp(units, "millibar", 8) == 0 ||
        memcmp(units, "mb", 2)       == 0 ||
@@ -5103,7 +3203,7 @@ int unitsIsPressure(const char *units)
        memcmp(units, "hPa", 3)      == 0 ||
        memcmp(units, "Pa", 2)       == 0 )
     {
-      status = TRUE;
+      status = true;
     }
 
   return status;
@@ -5158,9 +3258,9 @@ void scan_hybrid_formula(int ncid, int ncfvarid, int *apvarid, int *bvarid, int
 }
 
 static
-int isHybridSigmaPressureCoordinate(int ncid, int ncvarid, ncvar_t *ncvars, const ncdim_t *ncdims)
+bool isHybridSigmaPressureCoordinate(int ncid, int ncvarid, ncvar_t *ncvars, const ncdim_t *ncdims)
 {
-  int status = FALSE;
+  bool status = false;
   int ncfvarid = ncvarid;
   ncvar_t *ncvar = &ncvars[ncvarid];
 
@@ -5168,7 +3268,7 @@ int isHybridSigmaPressureCoordinate(int ncid, int ncvarid, ncvar_t *ncvars, cons
     {
       cdiConvention = CDI_CONVENTION_CF;
 
-      status = TRUE;
+      status = true;
       ncvar->zaxistype = ZAXIS_HYBRID;
       int dimid = ncvar->dimids[0];
       size_t dimlen = ncdims[dimid].len;
@@ -5489,7 +3589,7 @@ void cdfScanVarAttributes(int nvars, ncvar_t *ncvars, ncdim_t *ncdims,
                   if ( warn )
                     {
                       warn = FALSE;
-                      Warning("netCDF attribute grid_type='%s' unsupported!", attstring);
+                      Warning("NetCDF attribute grid_type='%s' unsupported!", attstring);
                     }
                 }
 
@@ -5528,7 +3628,7 @@ void cdfScanVarAttributes(int nvars, ncvar_t *ncvars, ncdim_t *ncdims,
                   if ( warn )
                     {
                       warn = FALSE;
-                      Warning("netCDF attribute level_type='%s' unsupported!", attstring);
+                      Warning("NetCDF attribute level_type='%s' unsupported!", attstring);
                     }
                 }
 
@@ -6143,7 +4243,7 @@ void verify_coordinate_vars_1(int ncid, int ndims, ncdim_t *ncdims, ncvar_t *ncv
                 {
                   ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
 		}
-	      else if ( unitsIsMeter(ncvars[ncvarid].units) )
+	      else if ( unitsIsHeight(ncvars[ncvarid].units) )
 		{
 		  if ( isDepthAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
 		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
@@ -6237,7 +4337,7 @@ void verify_coordinate_vars_2(int nvars, ncvar_t *ncvars)
                   ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
 		  continue;
 		}
-	      else if ( unitsIsMeter(ncvars[ncvarid].units) )
+	      else if ( unitsIsHeight(ncvars[ncvarid].units) )
 		{
 		  if ( isDepthAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
 		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
@@ -6264,94 +4364,624 @@ void verify_coordinate_vars_2(int nvars, ncvar_t *ncvars)
 	    }
 	}
     }
-}
+}
+
+#if defined (PROJECTION_TEST)
+static
+void copy_numeric_projatts(int gridID, int ncvarID, int ncfileID)
+{
+  int iatt, nvatts;
+  size_t attlen;
+  char attname[CDI_MAX_NAME];
+  nc_type xtype;
+
+  cdf_inq_varnatts(ncfileID, ncvarID, &nvatts);
+
+  for ( iatt = 0; iatt < nvatts; iatt++ )
+    {
+      cdf_inq_attname(ncfileID, ncvarID, iatt, attname);
+      cdf_inq_atttype(ncfileID, ncvarID, attname, &xtype);
+      cdf_inq_attlen(ncfileID, ncvarID, attname, &attlen);
+
+      //  printf("%s %d\n", attname, (int)attlen);
+    }
+
+}
+#endif
+
+static
+void grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
+{
+  if ( ncvar->chunked )
+    {
+      int ndims = ncvar->ndims;
+
+      if ( grid->type == GRID_UNSTRUCTURED )
+        {
+          if ( ncvar->chunks[ndims-1] == grid->size )
+            ncvar->chunktype = CHUNK_GRID;
+          else
+            ncvar->chunktype = CHUNK_AUTO;
+        }
+      else
+        {
+          if ( grid->xsize > 1 && grid->ysize > 1 && ndims > 1 &&
+               grid->xsize == ncvar->chunks[ndims-1] &&
+               grid->ysize == ncvar->chunks[ndims-2] )
+            ncvar->chunktype = CHUNK_GRID;
+          else if ( grid->xsize > 1 && grid->xsize == ncvar->chunks[ndims-1] )
+            ncvar->chunktype = CHUNK_LINES;
+          else
+            ncvar->chunktype = CHUNK_AUTO;
+        }
+    }
+}
+
+static struct gridVirtTable cdfLazyGridVtable;
+static double *cdfPendingLoad;
+#ifdef HAVE_LIBPTHREAD
+static pthread_once_t cdfLazyInitialized = PTHREAD_ONCE_INIT;
+#else
+static bool cdfLazyInitialized;
+#endif
+
+struct cdfLazyGrid
+{
+  grid_t base;
+  const struct gridVirtTable *baseVtable;
+  struct {
+    int datasetNCId, varNCId;
+  } cellAreaGet, xBoundsGet, yBoundsGet;
+  struct xyValGet {
+    double scalefactor, addoffset;
+    size_t start[3], count[3], size, dimsize;
+    int datasetNCId, varNCId;
+    short ndims;
+  } xValsGet, yValsGet;
+#ifdef HAVE_LIBPTHREAD
+  pthread_mutex_t loadSerialize;
+#endif
+};
+
+#ifdef HAVE_LIBPTHREAD
+#define lock_lazy_load(plGrid) pthread_mutex_lock(&((plGrid)->loadSerialize))
+#define unlock_lazy_load(plGrid) pthread_mutex_unlock(&((plGrid)->loadSerialize))
+#define destroy_lazy_load_lock(plGrid) pthread_mutex_destroy(&((plGrid)->loadSerialize))
+#define init_lazy_load_lock(plGrid) pthread_mutex_init(&((plGrid)->loadSerialize), NULL)
+#else
+#define lock_lazy_load(plGrid)
+#define unlock_lazy_load(plGrid)
+#define destroy_lazy_load_lock(plGrid)
+#define init_lazy_load_lock(plGrid)
+#endif
+
+static void cdfLazyGridDestroy(struct cdfLazyGrid *lazyGrid)
+{
+  lazyGrid->base.extraData = NULL;
+  if (lazyGrid->base.area == cdfPendingLoad)
+    lazyGrid->base.area = NULL;
+  if (lazyGrid->base.xvals == cdfPendingLoad)
+    lazyGrid->base.xvals = NULL;
+  if (lazyGrid->base.yvals == cdfPendingLoad)
+    lazyGrid->base.yvals = NULL;
+  if (lazyGrid->base.xbounds == cdfPendingLoad)
+    lazyGrid->base.xbounds = NULL;
+  if (lazyGrid->base.ybounds == cdfPendingLoad)
+    lazyGrid->base.ybounds = NULL;
+  destroy_lazy_load_lock(lazyGrid);
+}
+
+static void cdfLazyGridDelete(grid_t *grid)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  void (*baseDestroy)(grid_t *grid) = cdfGrid->baseVtable->destroy;
+  cdfLazyGridDestroy(cdfGrid);
+  baseDestroy(grid);
+}
+
+static void cdfLazyGridDestroyOnce(void)
+{
+  /*
+#ifdef HAVE_MMAP
+  size_t pgSize = cdiGetPageSize(false);
+  munmap(cdfPendingLoad, pgSize);
+#endif
+  */
+}
+
+static void
+cdfLazyGridDefArea(grid_t *grid, const double *area)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->area == cdfPendingLoad)
+    grid->area = NULL;
+  cdfGrid->cellAreaGet.datasetNCId = -1;
+  cdfGrid->cellAreaGet.varNCId = -1;
+  cdfGrid->baseVtable->defArea(grid, area);
+  unlock_lazy_load(cdfGrid);
+}
+
+
+static const double *
+cdfLazyGridInqAreaPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->area == cdfPendingLoad)
+    {
+      grid->area = (double *)Malloc((size_t)grid->size * sizeof(double));
+      cdf_get_var_double(lazyGrid->cellAreaGet.datasetNCId,
+                         lazyGrid->cellAreaGet.varNCId, grid->area);
+    }
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqAreaPtr(grid);
+}
+
+static void
+cdfLazyGridInqArea(grid_t *grid, double *area)
+{
+  grid->vtable->inqAreaPtr(grid);
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lazyGrid->baseVtable->inqArea(grid, area);
+}
+
+
+static void
+cdfLazyLoadXYVals(struct xyValGet *valsGet, double **valsp)
+{
+  double *grid_vals
+    = (double *)Malloc(valsGet->size * sizeof (double));
+  *valsp = grid_vals;
+  if ( valsGet->ndims == 3 )
+    cdf_get_vara_double(valsGet->datasetNCId, valsGet->varNCId,
+                        valsGet->start, valsGet->count, grid_vals);
+  else
+    cdf_get_var_double(valsGet->datasetNCId, valsGet->varNCId, grid_vals);
+  scale_add(valsGet->size, grid_vals, valsGet->addoffset, valsGet->scalefactor);
+}
+
+static const double *
+cdfLazyGridInqXValsPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->xvals == cdfPendingLoad)
+    cdfLazyLoadXYVals(&lazyGrid->xValsGet, &grid->xvals);
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqXValsPtr(grid);
+}
+
+static const double *
+cdfLazyGridInqYValsPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->yvals == cdfPendingLoad)
+    cdfLazyLoadXYVals(&lazyGrid->yValsGet, &grid->yvals);
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqYValsPtr(grid);
+}
+
+static double
+cdfLazyGridInqXYVal(grid_t *grid, size_t index,
+                    const struct xyValGet *valsGet, double *vals,
+                    const double *(*inqValsPtr)(grid_t *gridptr))
+{
+  size_t size = valsGet->size;
+  double v;
+  if ( vals == cdfPendingLoad )
+    {
+      /* prevent full load if only first/last values get inspected */
+      if ( index == 0 || index == size - 1 )
+        {
+          size_t indexND[3];
+          if ( valsGet->ndims == 3 )
+            {
+              indexND[0] = 0;
+              indexND[1] = index / valsGet->count[2];
+              indexND[2] = index % valsGet->count[2];
+            }
+          else if ( valsGet->ndims == 2)
+            {
+              indexND[0] = index / (size_t)grid->xsize;
+              indexND[1] = index % (size_t)grid->xsize;
+            }
+          else
+            indexND[0] = index;
+          cdf_get_var1_double(valsGet->datasetNCId, valsGet->varNCId,
+                              indexND, &v);
+        }
+      else
+        {
+          const double *grid_vals = inqValsPtr(grid);
+          v = grid_vals[index];
+        }
+    }
+  else if ( vals )
+    v = vals[index];
+  else
+    v = 0.0;
+  return v;
+}
+
+static void
+cdfLazyGridDefXVals(grid_t *grid, const double *vals)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->xvals == cdfPendingLoad)
+    grid->xvals = NULL;
+  cdfGrid->xValsGet.datasetNCId = -1;
+  cdfGrid->xValsGet.varNCId = -1;
+  cdfGrid->baseVtable->defXVals(grid, vals);
+  unlock_lazy_load(cdfGrid);
+}
+
+static void
+cdfLazyGridDefYVals(grid_t *grid, const double *vals)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->yvals == cdfPendingLoad)
+    grid->yvals = NULL;
+  cdfGrid->yValsGet.datasetNCId = -1;
+  cdfGrid->yValsGet.varNCId = -1;
+  cdfGrid->baseVtable->defYVals(grid, vals);
+  unlock_lazy_load(cdfGrid);
+}
+
+static double
+cdfLazyGridInqXVal(grid_t *grid, int index)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  double rv = cdfLazyGridInqXYVal(grid, (size_t)index, &lazyGrid->xValsGet,
+                                  grid->xvals, grid->vtable->inqXValsPtr);
+  unlock_lazy_load(lazyGrid);
+  return rv;
+}
+
+static double
+cdfLazyGridInqYVal(grid_t *grid, int index)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  double rv = cdfLazyGridInqXYVal(grid, (size_t)index, &lazyGrid->yValsGet,
+                                  grid->yvals, grid->vtable->inqYValsPtr);
+  unlock_lazy_load(lazyGrid);
+  return rv;
+}
+
+static int
+cdfLazyXYValGetCompare(struct cdfLazyGrid *lazyGridRef,
+                       struct cdfLazyGrid *lazyGridTest)
+{
+  struct xyValGet *valsGetXRef = &lazyGridRef->xValsGet,
+    *valsGetYRef = &lazyGridRef->yValsGet,
+    *valsGetXTest = &lazyGridTest->xValsGet,
+    *valsGetYTest = &lazyGridTest->yValsGet;
+  if (valsGetXRef->datasetNCId == -1
+      || valsGetXTest->datasetNCId == -1
+      || valsGetYRef->datasetNCId == -1
+      || valsGetYTest->datasetNCId == -1)
+    return lazyGridRef->baseVtable->compareXYFull(&lazyGridRef->base,
+                                                  &lazyGridTest->base);
+  return valsGetXRef->datasetNCId != valsGetXTest->datasetNCId
+    ||   valsGetXRef->varNCId     != valsGetXTest->varNCId
+    ||   valsGetYRef->datasetNCId != valsGetYTest->datasetNCId
+    ||   valsGetYRef->varNCId     != valsGetYTest->varNCId;
+}
+
+static int
+cdfLazyCompareXYFull(grid_t *gridRef, grid_t *gridTest)
+{
+  int diff;
+  struct cdfLazyGrid *lazyGridRef = (struct cdfLazyGrid *)gridRef;
+  if (gridTest->vtable == &cdfLazyGridVtable)
+    diff = cdfLazyXYValGetCompare(lazyGridRef, (struct cdfLazyGrid *)gridTest);
+  else
+    diff = lazyGridRef->baseVtable->compareXYFull(gridRef, gridTest);
+  return diff;
+}
+
+static int
+cdfLazyCompareXYAO(grid_t *gridRef, grid_t *gridTest)
+{
+  int diff;
+  struct cdfLazyGrid *lazyGridRef = (struct cdfLazyGrid *)gridRef;
+  if (gridTest->vtable == &cdfLazyGridVtable)
+    diff = cdfLazyXYValGetCompare(lazyGridRef, (struct cdfLazyGrid *)gridTest);
+  else
+    diff = lazyGridRef->baseVtable->compareXYAO(gridRef, gridTest);
+  return diff;
+}
+
+
+static const double *
+cdfLazyGridInqXBoundsPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->xbounds == cdfPendingLoad)
+    {
+      grid->xbounds = (double *)Malloc((size_t)grid->nvertex
+                                       * (size_t)grid->size * sizeof(double));
+      cdf_get_var_double(lazyGrid->xBoundsGet.datasetNCId,
+                         lazyGrid->xBoundsGet.varNCId, grid->xbounds);
+    }
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqXBoundsPtr(grid);
+}
+
+static void
+cdfLazyGridDefXBounds(grid_t *grid, const double *xbounds)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->xbounds == cdfPendingLoad)
+    grid->xbounds = NULL;
+  cdfGrid->xBoundsGet.datasetNCId = -1;
+  cdfGrid->xBoundsGet.varNCId = -1;
+  cdfGrid->baseVtable->defXBounds(grid, xbounds);
+  unlock_lazy_load(cdfGrid);
+}
+
+static void
+cdfLazyGridDefYBounds(grid_t *grid, const double *ybounds)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->ybounds == cdfPendingLoad)
+    grid->ybounds = NULL;
+  cdfGrid->yBoundsGet.datasetNCId = -1;
+  cdfGrid->yBoundsGet.varNCId = -1;
+  cdfGrid->baseVtable->defYBounds(grid, ybounds);
+  unlock_lazy_load(cdfGrid);
+}
+
+static const double *
+cdfLazyGridInqYBoundsPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->ybounds == cdfPendingLoad)
+    {
+      grid->ybounds = (double *)Malloc((size_t)grid->nvertex
+                                       * (size_t)grid->size * sizeof(double));
+      cdf_get_var_double(lazyGrid->yBoundsGet.datasetNCId,
+                         lazyGrid->yBoundsGet.varNCId, grid->ybounds);
+    }
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqYBoundsPtr(grid);
+}
+
+static void
+cdfLazyGridCopyScalarFields(grid_t *gridptrOrig, grid_t *gridptrDup)
+{
+  struct cdfLazyGrid *lazyGridDup = (struct cdfLazyGrid *)gridptrDup,
+    *lazyGridOrig = (struct cdfLazyGrid *)gridptrOrig;
+  lazyGridOrig->baseVtable->copyScalarFields(gridptrOrig, &lazyGridDup->base);
+  lazyGridDup->baseVtable = lazyGridOrig->baseVtable;
+  lazyGridDup->cellAreaGet = lazyGridOrig->cellAreaGet;
+  lazyGridDup->xBoundsGet = lazyGridOrig->xBoundsGet;
+  lazyGridDup->yBoundsGet = lazyGridOrig->yBoundsGet;
+  lazyGridDup->xValsGet = lazyGridOrig->xValsGet;
+  lazyGridDup->yValsGet = lazyGridOrig->yValsGet;
+  init_lazy_load_lock(lazyGridDup);
+}
+
+static void
+cdfLazyGridCopyArrayFields(grid_t *gridptrOrig, grid_t *gridptrDup)
+{
+  size_t nrowlon = (size_t)gridptrOrig->nrowlon;
+  size_t gridsize = (size_t)gridptrOrig->size;
+  int gridtype = gridptrOrig->type;
+  int irregular = gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED;
+  if ( nrowlon )
+    {
+      gridptrDup->rowlon = (int *)Malloc(nrowlon * sizeof (int));
+      memcpy(gridptrDup->rowlon, gridptrOrig->rowlon, nrowlon * sizeof(int));
+    }
+
+  if ( gridptrOrig->xvals != NULL && gridptrOrig->xvals != cdfPendingLoad )
+    {
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->xsize;
+
+      gridptrDup->xvals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->xvals, gridptrOrig->xvals, size * sizeof (double));
+    }
 
-#if defined (PROJECTION_TEST)
-static
-void copy_numeric_projatts(int gridID, int ncvarID, int ncfileID)
-{
-  int iatt, nvatts;
-  size_t attlen;
-  char attname[CDI_MAX_NAME];
-  nc_type xtype;
+  if ( gridptrOrig->yvals != NULL && gridptrOrig->yvals != cdfPendingLoad )
+    {
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->ysize;
 
-  cdf_inq_varnatts(ncfileID, ncvarID, &nvatts);
+      gridptrDup->yvals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->yvals, gridptrOrig->yvals, size * sizeof (double));
+    }
 
-  for ( iatt = 0; iatt < nvatts; iatt++ )
+  if ( gridptrOrig->xbounds != NULL && gridptrOrig->xbounds != cdfPendingLoad )
     {
-      cdf_inq_attname(ncfileID, ncvarID, iatt, attname);
-      cdf_inq_atttype(ncfileID, ncvarID, attname, &xtype);
-      cdf_inq_attlen(ncfileID, ncvarID, attname, &attlen);
+      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->xsize)
+        * (size_t)gridptrOrig->nvertex;
 
-      //  printf("%s %d\n", attname, (int)attlen);
+      gridptrDup->xbounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->xbounds, gridptrOrig->xbounds, size * sizeof (double));
+    }
+
+  if ( gridptrOrig->ybounds != NULL && gridptrOrig->ybounds != cdfPendingLoad )
+    {
+      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->ysize)
+        * (size_t)gridptrOrig->nvertex;
+
+      gridptrDup->ybounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->ybounds, gridptrOrig->ybounds, size * sizeof (double));
+    }
+
+  {
+    if ( gridptrOrig->area != NULL && gridptrOrig->area != cdfPendingLoad )
+      {
+        size_t size = gridsize;
+
+        gridptrDup->area = (double *)Malloc(size * sizeof (double));
+        memcpy(gridptrDup->area, gridptrOrig->area, size * sizeof (double));
+      }
+  }
+
+  if ( gridptrOrig->mask != NULL )
+    {
+      size_t size = gridsize;
+
+      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
+      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
     }
 
+  if ( gridptrOrig->mask_gme != NULL )
+    {
+      size_t size = gridsize;
+
+      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
+      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
+    }
+}
+
+static grid_t *
+cdfLazyGridCopy(grid_t *gridptrOrig)
+{
+  struct cdfLazyGrid *lazyGridDup
+    = (struct cdfLazyGrid *)Malloc(sizeof (*lazyGridDup));
+  gridptrOrig->vtable->copyScalarFields(gridptrOrig, &lazyGridDup->base);
+  gridptrOrig->vtable->copyArrayFields(gridptrOrig, &lazyGridDup->base);
+  return &lazyGridDup->base;
 }
+
+static void
+cdfLazyGridInitOnce(void)
+{
+  cdfLazyGridVtable = cdiGridVtable;
+  cdfLazyGridVtable.destroy = cdfLazyGridDelete;
+  cdfLazyGridVtable.copy = cdfLazyGridCopy;
+  cdfLazyGridVtable.copyScalarFields = cdfLazyGridCopyScalarFields;
+  cdfLazyGridVtable.copyArrayFields = cdfLazyGridCopyArrayFields;
+  cdfLazyGridVtable.defArea = cdfLazyGridDefArea;
+  cdfLazyGridVtable.inqAreaPtr = cdfLazyGridInqAreaPtr;
+  cdfLazyGridVtable.inqArea = cdfLazyGridInqArea;
+  cdfLazyGridVtable.inqXValsPtr = cdfLazyGridInqXValsPtr;
+  cdfLazyGridVtable.inqYValsPtr = cdfLazyGridInqYValsPtr;
+  cdfLazyGridVtable.inqXVal = cdfLazyGridInqXVal;
+  cdfLazyGridVtable.inqYVal = cdfLazyGridInqYVal;
+  cdfLazyGridVtable.defXVals = cdfLazyGridDefXVals;
+  cdfLazyGridVtable.defYVals = cdfLazyGridDefYVals;
+  cdfLazyGridVtable.compareXYFull = cdfLazyCompareXYFull;
+  cdfLazyGridVtable.compareXYAO = cdfLazyCompareXYAO;
+  cdfLazyGridVtable.defXBounds = cdfLazyGridDefXBounds;
+  cdfLazyGridVtable.defYBounds = cdfLazyGridDefYBounds;
+  cdfLazyGridVtable.inqXBoundsPtr = cdfLazyGridInqXBoundsPtr;
+  cdfLazyGridVtable.inqYBoundsPtr = cdfLazyGridInqYBoundsPtr;
+  /* create inaccessible memory area, if possible, this serves as
+   * dummy value for pointers to data not yet loaded */
+  /*
+#ifdef HAVE_MMAP
+  {
+    size_t pgSize = cdiGetPageSize(false);
+    static const char devZero[] = "/dev/zero";
+    int fd = open(devZero, O_RDWR);
+    if (fd == -1)
+      SysError("Could not open %s to map anonymous memory", devZero);
+    void *cdfInvalid = mmap(NULL, pgSize, PROT_NONE, MAP_PRIVATE, fd, 0);
+    if (cdfInvalid == MAP_FAILED)
+      SysError("Could not mmap anonymous memory");
+    cdfPendingLoad = cdfInvalid;
+    int rc = close(fd);
+    if (rc == -1)
+      SysError("Could not close %s file handle %d after mapping anonymous"
+               " memory", devZero, fd);
+  }
+#else
+  */
+  cdfPendingLoad = (double *)&cdfPendingLoad;
+  //#endif
+  atexit(cdfLazyGridDestroyOnce);
+#ifndef HAVE_LIBPTHREAD
+  cdfLazyInitialized = true;
 #endif
+}
 
-static
-void grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
+static void
+cdfBaseGridInit(grid_t *grid, int gridtype)
 {
-  if ( ncvar->chunked )
-    {
-      int ndims = ncvar->ndims;
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, 0);
+}
 
-      if ( grid->type == GRID_UNSTRUCTURED )
-        {
-          if ( ncvar->chunks[ndims-1] == grid->size )
-            ncvar->chunktype = CHUNK_GRID;
-          else
-            ncvar->chunktype = CHUNK_AUTO;
-        }
-      else
-        {
-          if ( grid->xsize > 1 && grid->ysize > 1 && ndims > 1 &&
-               grid->xsize == ncvar->chunks[ndims-1] &&
-               grid->ysize == ncvar->chunks[ndims-2] )
-            ncvar->chunktype = CHUNK_GRID;
-          else if ( grid->xsize > 1 && grid->xsize == ncvar->chunks[ndims-1] )
-            ncvar->chunktype = CHUNK_LINES;
-          else
-            ncvar->chunktype = CHUNK_AUTO;
-        }
-    }
+static void
+cdfLazyGridInit(struct cdfLazyGrid *grid, int gridtype)
+{
+#ifdef HAVE_LIBPTHREAD
+  pthread_once(&cdfLazyInitialized, cdfLazyGridInitOnce);
+#else
+  if (cdfLazyInitialized) ; else cdfLazyGridInitOnce();
+#endif
+  cdfBaseGridInit(&grid->base, gridtype);
+  grid->baseVtable = grid->base.vtable;
+  grid->cellAreaGet.datasetNCId = -1;
+  grid->cellAreaGet.varNCId = -1;
+  grid->xValsGet.datasetNCId = -1;
+  grid->xValsGet.varNCId = -1;
+  grid->yValsGet.datasetNCId = -1;
+  grid->yValsGet.varNCId = -1;
+  grid->xBoundsGet.datasetNCId = -1;
+  grid->xBoundsGet.varNCId = -1;
+  grid->yBoundsGet.datasetNCId = -1;
+  grid->yBoundsGet.varNCId = -1;
+  grid->base.vtable = &cdfLazyGridVtable;
+  init_lazy_load_lock(grid);
+}
+
+static void
+cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
+{
+  struct cdfLazyGrid *restrict grid = *gridpptr;
+  if (!grid)
+    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (*grid));
+  cdfLazyGridInit(grid, gridtype);
+}
+
+static void
+cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
+{
+  struct cdfLazyGrid *restrict grid = *gridpptr;
+  if (!grid)
+    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (grid_t));
+  cdfBaseGridInit((grid_t*)grid, gridtype);
 }
 
+
 /* define all input grids */
 static
 void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars, int timedimid, unsigned char *uuidOfHGrid, char *gridfile, int number_of_grid_used)
 {
-  int ncvarid, ncvarid2;
-  int nbdims;
-  int i;
-  int nvatts;
-  int skipvar;
-  size_t nvertex;
-  grid_t grid;
-  grid_t proj;
-  int gridindex;
-  char name[CDI_MAX_NAME];
-  int iatt;
   int ltwarn = TRUE;
-  size_t attlen;
-  char attname[CDI_MAX_NAME];
-  double datt;
+  struct cdfLazyGrid *restrict lazyGrid = NULL, *restrict lazyProj = NULL;
+#define grid (&lazyGrid->base)
+#define proj (&lazyProj->base)
 
-  for ( ncvarid = 0; ncvarid < nvars; ++ncvarid )
+  for ( int ncvarid = 0; ncvarid < nvars; ++ncvarid )
     {
       if ( ncvars[ncvarid].isvar && ncvars[ncvarid].gridID == UNDEFID )
 	{
-	  int xdimids[2] = {-1,-1}, ydimids[2] = {-1,-1};
+          int xdimids[2] = {-1,-1}, ydimids[2] = {-1,-1};
 	  int xdimid = -1, ydimid = -1;
-	  int xvarid = -1, yvarid = -1;
 	  int islon = 0, islat = 0;
 	  int nxdims = 0, nydims = 0;
-          size_t size = 0, np = 0;
+          size_t size = 0;
           size_t xsize = 0, ysize = 0;
-	  double xinc = 0, yinc = 0;
+	  double yinc = 0;
+          struct addIffNewRes projAdded = { .Id = CDI_UNDEFID, .isNew = 0 },
+            gridAdded  = { .Id = CDI_UNDEFID, .isNew = 0 };
 
 	  int ndims = ncvars[ncvarid].ndims;
-	  for ( i = 0; i < ndims; i++ )
+	  for ( int i = 0; i < ndims; i++ )
 	    {
 	      if ( ncvars[ncvarid].dimtype[i] == X_AXIS && nxdims < 2 )
 		{
@@ -6381,15 +5011,12 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 	      ydimid = ydimids[0];
 	    }
 
-	  if ( ncvars[ncvarid].xvarid != UNDEFID )
-	    xvarid = ncvars[ncvarid].xvarid;
-	  else if ( xdimid != UNDEFID )
-	    xvarid = ncdims[xdimid].ncvarid;
-
-	  if ( ncvars[ncvarid].yvarid != UNDEFID )
-	    yvarid = ncvars[ncvarid].yvarid;
-	  else if ( ydimid != UNDEFID )
-	    yvarid = ncdims[ydimid].ncvarid;
+	  int xvarid = ncvars[ncvarid].xvarid != UNDEFID
+	    ? ncvars[ncvarid].xvarid
+            : (xdimid != UNDEFID ? ncdims[xdimid].ncvarid : -1);
+          int yvarid = ncvars[ncvarid].yvarid != UNDEFID
+            ? ncvars[ncvarid].yvarid
+            : (ydimid != UNDEFID ? ncdims[ydimid].ncvarid : -1);
 
 	  /*
 	  if ( xdimid != UNDEFID )
@@ -6418,18 +5045,26 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 	  if ( ncvars[ncvarid].gridtype == UNDEFID || ncvars[ncvarid].gridtype == GRID_GENERIC )
 	    if ( xdimid != UNDEFID && xdimid == ydimid && nydims == 0 ) ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
 
-	  grid_init(&grid);
-	  grid_init(&proj);
+          if (CDI_netcdf_lazy_grid_load)
+            {
+              cdfLazyGridRenew(&lazyGrid, ncvars[ncvarid].gridtype);
+              cdfLazyGridRenew(&lazyProj, GRID_PROJECTION);
+            }
+          else
+            {
+              cdfBaseGridRenew(&lazyGrid, ncvars[ncvarid].gridtype);
+              cdfBaseGridRenew(&lazyProj, GRID_PROJECTION);
+            }
 
-	  grid.prec  = DATATYPE_FLT64;
-	  grid.trunc = ncvars[ncvarid].truncation;
+	  grid->prec  = DATATYPE_FLT64;
+	  grid->trunc = ncvars[ncvarid].truncation;
 
 	  if ( ncvars[ncvarid].gridtype == GRID_TRAJECTORY )
 	    {
 	      if ( ncvars[ncvarid].xvarid == UNDEFID )
-		Error("Longitude coordinate undefined for %s!", name);
+		Error("Longitude coordinate undefined for %s!", ncvars[ncvarid].name);
 	      if ( ncvars[ncvarid].yvarid == UNDEFID )
-		Error("Latitude coordinate undefined for %s!", name);
+		Error("Latitude coordinate undefined for %s!", ncvars[ncvarid].name);
 	    }
 	  else
 	    {
@@ -6492,7 +5127,7 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 
               if ( xvarid != UNDEFID )
 		{
-                  skipvar = TRUE;
+                  bool skipvar = true;
 		  islon = ncvars[xvarid].islon;
 		  ndims = ncvars[xvarid].ndims;
 		  if ( ndims == 2 || ndims == 3 )
@@ -6500,29 +5135,24 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 		      ncvars[ncvarid].gridtype = GRID_CURVILINEAR;
 		      size = xsize*ysize;
 		      /* Check size of 2 dimensional coordinate variables */
-		      {
-			int dimid = ncvars[xvarid].dimids[ndims-2];
-			size_t dimsize1 = ncdims[dimid].len;
-			dimid = ncvars[xvarid].dimids[ndims-1];
-			size_t dimsize2 = ncdims[dimid].len;
-			if ( dimsize1*dimsize2 == size ) skipvar = FALSE;
-		      }
+                      int dimid = ncvars[xvarid].dimids[ndims-2];
+                      size_t dimsize1 = ncdims[dimid].len;
+                      dimid = ncvars[xvarid].dimids[ndims-1];
+                      size_t dimsize2 = ncdims[dimid].len;
+                      skipvar = dimsize1*dimsize2 != size;
 		    }
 		  else if ( ndims == 1 )
 		    {
 		      size = xsize;
 		      /* Check size of 1 dimensional coordinate variables */
-		      {
-			int dimid = ncvars[xvarid].dimids[0];
-			size_t dimsize = ncdims[dimid].len;
-			if ( dimsize == size ) skipvar = FALSE;
-		      }
+                      int dimid = ncvars[xvarid].dimids[0];
+                      size_t dimsize = ncdims[dimid].len;
+                      skipvar = dimsize != size;
 		    }
 		  else if ( ndims == 0 && xsize == 0 )
 		    {
-                      xsize = 1;
-		      size = xsize;
-                      skipvar = FALSE;
+                      size = xsize = 1;
+                      skipvar = false;
 		    }
 
                   if ( skipvar )
@@ -6532,38 +5162,48 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
                       continue;
                     }
 
-		  if ( ncvars[xvarid].xtype == NC_FLOAT ) grid.prec = DATATYPE_FLT32;
-		  grid.xvals = (double *) Malloc(size*sizeof(double));
-
-		  if ( ltgrid )
-		    cdf_get_vara_double(ncvars[xvarid].ncid, xvarid, start, count, grid.xvals);
-		  else
-		    cdf_get_var_double(ncvars[xvarid].ncid, xvarid, grid.xvals);
-
-                  scale_add(size, grid.xvals, ncvars[xvarid].addoffset, ncvars[xvarid].scalefactor);
-
-		  strcpy(grid.xname, ncvars[xvarid].name);
-		  strcpy(grid.xlongname, ncvars[xvarid].longname);
-		  strcpy(grid.xunits, ncvars[xvarid].units);
+		  if ( ncvars[xvarid].xtype == NC_FLOAT ) grid->prec = DATATYPE_FLT32;
+                  if (CDI_netcdf_lazy_grid_load)
+                    {
+                      lazyGrid->xValsGet = (struct xyValGet){
+                        .scalefactor = ncvars[xvarid].scalefactor,
+                        .addoffset = ncvars[xvarid].addoffset,
+                        .start = { start[0], start[1], start[2] },
+                        .count = { count[0], count[1], count[2] },
+                        .size = size,
+                        .datasetNCId = ncvars[xvarid].ncid,
+                        .varNCId = xvarid,
+                        .ndims = (short)ndims,
+                      };
+                      grid->xvals = cdfPendingLoad;
+                    }
+                  else
+                    {
+                      grid->xvals = (double *) Malloc(size*sizeof(double));
+                      if ( ltgrid )
+                        cdf_get_vara_double(ncvars[xvarid].ncid, xvarid,
+                                            start, count, grid->xvals);
+                      else
+                        cdf_get_var_double(ncvars[xvarid].ncid, xvarid,
+                                           grid->xvals);
+                      scale_add(size, grid->xvals,
+                                ncvars[xvarid].addoffset,
+                                ncvars[xvarid].scalefactor);
+                    }
+		  strcpy(grid->xname, ncvars[xvarid].name);
+		  strcpy(grid->xlongname, ncvars[xvarid].longname);
+		  strcpy(grid->xunits, ncvars[xvarid].units);
 		  /* don't change the name !!! */
 		  /*
-		  if ( (len = strlen(grid.xname)) > 2 )
-		    if ( grid.xname[len-2] == '_' && isdigit((int) grid.xname[len-1]) )
-		      grid.xname[len-2] = 0;
+		  if ( (len = strlen(grid->xname)) > 2 )
+		    if ( grid->xname[len-2] == '_' && isdigit((int) grid->xname[len-1]) )
+		      grid->xname[len-2] = 0;
 		  */
-		  if ( islon && xsize > 1 )
-		    {
-		      xinc = fabs(grid.xvals[0] - grid.xvals[1]);
-		      for ( i = 2; i < (int) xsize; i++ )
-			if ( (fabs(grid.xvals[i-1] - grid.xvals[i]) - xinc) > (xinc/1000) ) break;
-
-		      if ( i < (int) xsize ) xinc = 0;
-		    }
 		}
 
 	      if ( yvarid != UNDEFID )
 		{
-                  skipvar = TRUE;
+                  bool skipvar = true;
 		  islat = ncvars[yvarid].islat;
 		  ndims = ncvars[yvarid].ndims;
 		  if ( ndims == 2 || ndims == 3 )
@@ -6578,7 +5218,7 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 			dimsize1 = ncdims[dimid].len;
 			dimid = ncvars[yvarid].dimids[ndims-1];
 			dimsize2 = ncdims[dimid].len;
-			if ( dimsize1*dimsize2 == size ) skipvar = FALSE;
+			skipvar = dimsize1*dimsize2 != size;
 		      }
 		    }
 		  else if ( ndims == 1 )
@@ -6592,14 +5232,13 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 			size_t dimsize;
 			dimid = ncvars[yvarid].dimids[0];
 			dimsize = ncdims[dimid].len;
-			if ( dimsize == size ) skipvar = FALSE;
+			skipvar = dimsize != size;
 		      }
 		    }
 		  else if ( ndims == 0 && ysize == 0 )
 		    {
-                      ysize = 1;
-		      size = ysize;
-                      skipvar = FALSE;
+                      size = ysize = 1;
+                      skipvar = false;
 		    }
 
                   if ( skipvar )
@@ -6609,33 +5248,57 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
                       continue;
                     }
 
-		  if ( ncvars[yvarid].xtype == NC_FLOAT ) grid.prec = DATATYPE_FLT32;
-		  grid.yvals = (double *) Malloc(size*sizeof(double));
-
-		  if ( ltgrid )
-		    cdf_get_vara_double(ncvars[yvarid].ncid, yvarid, start, count, grid.yvals);
-		  else
-		    cdf_get_var_double(ncvars[yvarid].ncid, yvarid, grid.yvals);
+		  if ( ncvars[yvarid].xtype == NC_FLOAT ) grid->prec = DATATYPE_FLT32;
+                  /* see below for when it's impossible to operate
+                   * without y values */
+                  if ( !CDI_netcdf_lazy_grid_load
+                       || ((ncvars[ncvarid].gridtype == UNDEFID ||
+                            ncvars[ncvarid].gridtype == GRID_GENERIC)
+                           && islat && (islon || xsize == 0)) )
+                    {
+                      grid->yvals = (double *) Malloc(size*sizeof(double));
 
-                  scale_add(size, grid.yvals, ncvars[yvarid].addoffset, ncvars[yvarid].scalefactor);
+                      if ( ltgrid )
+                        cdf_get_vara_double(ncvars[yvarid].ncid, yvarid, start, count, grid->yvals);
+                      else
+                        cdf_get_var_double(ncvars[yvarid].ncid, yvarid, grid->yvals);
 
-		  strcpy(grid.yname, ncvars[yvarid].name);
-		  strcpy(grid.ylongname, ncvars[yvarid].longname);
-		  strcpy(grid.yunits, ncvars[yvarid].units);
-		  /* don't change the name !!! */
-		  /*
-		  if ( (len = strlen(grid.yname)) > 2 )
-		    if ( grid.yname[len-2] == '_' && isdigit((int) grid.yname[len-1]) )
-		      grid.yname[len-2] = 0;
-		  */
-		  if ( islon && (int) ysize > 1 )
-		    {
-		      yinc = fabs(grid.yvals[0] - grid.yvals[1]);
-		      for ( i = 2; i < (int) ysize; i++ )
-			if ( (fabs(grid.yvals[i-1] - grid.yvals[i]) - yinc) > (yinc/1000) ) break;
+                      scale_add(size, grid->yvals, ncvars[yvarid].addoffset, ncvars[yvarid].scalefactor);
 
-		      if ( i < (int) ysize ) yinc = 0;
-		    }
+                      /* don't change the name !!! */
+                      /*
+                        if ( (len = strlen(grid->yname)) > 2 )
+                        if ( grid->yname[len-2] == '_' && isdigit((int) grid->yname[len-1]) )
+                        grid->yname[len-2] = 0;
+                      */
+                      if ( islon && (int) ysize > 1 )
+                        {
+                          yinc = fabs(grid->yvals[0] - grid->yvals[1]);
+                          for ( size_t i = 2; i < ysize; i++ )
+                            if ( (fabs(grid->yvals[i-1] - grid->yvals[i]) - yinc) > (yinc/1000) )
+                              {
+                                yinc = 0;
+                                break;
+                              }
+                        }
+                    }
+                  else
+                    {
+                      lazyGrid->yValsGet = (struct xyValGet){
+                        .scalefactor = ncvars[yvarid].scalefactor,
+                        .addoffset = ncvars[yvarid].addoffset,
+                        .start = { start[0], start[1], start[2] },
+                        .count = { count[0], count[1], count[2] },
+                        .size = size,
+                        .datasetNCId = ncvars[yvarid].ncid,
+                        .varNCId = yvarid,
+                        .ndims = (short)ndims,
+                      };
+                      grid->yvals = cdfPendingLoad;
+                    }
+                  strcpy(grid->yname, ncvars[yvarid].name);
+                  strcpy(grid->ylongname, ncvars[yvarid].longname);
+                  strcpy(grid->yunits, ncvars[yvarid].units);
 		}
 
 	      if      ( (int) ysize == 0 ) size = xsize;
@@ -6647,22 +5310,12 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 	  if ( ncvars[ncvarid].gridtype == UNDEFID ||
 	       ncvars[ncvarid].gridtype == GRID_GENERIC )
 	    {
-	      if ( islat && islon )
-		{
-		  if ( isGaussGrid(ysize, yinc, grid.yvals) )
-                    {
-                      ncvars[ncvarid].gridtype = GRID_GAUSSIAN;
-                      np = ysize/2;
-                    }
-                  else
-		    ncvars[ncvarid].gridtype = GRID_LONLAT;
-		}
-	      else if ( islat && !islon && xsize == 0 )
+	      if ( islat && (islon || xsize == 0) )
 		{
-		  if ( isGaussGrid(ysize, yinc, grid.yvals) )
+		  if ( isGaussGrid(ysize, yinc, grid->yvals) )
                     {
                       ncvars[ncvarid].gridtype = GRID_GAUSSIAN;
-                      np = ysize/2;
+                      grid->np = (int)(ysize/2);
                     }
                   else
 		    ncvars[ncvarid].gridtype = GRID_LONLAT;
@@ -6683,83 +5336,137 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 	    case GRID_UNSTRUCTURED:
 	    case GRID_CURVILINEAR:
 	      {
-		grid.size  = (int)size;
-		grid.xsize = (int)xsize;
-		grid.ysize = (int)ysize;
-                grid.np    = (int)np;
+		grid->size  = (int)size;
+		grid->xsize = (int)xsize;
+		grid->ysize = (int)ysize;
 		if ( xvarid != UNDEFID )
 		  {
-		    grid.xdef  = 1;
+		    grid->xdef  = 1;
 		    if ( ncvars[xvarid].bounds != UNDEFID )
 		      {
-			nbdims = ncvars[ncvars[xvarid].bounds].ndims;
+			int nbdims = ncvars[ncvars[xvarid].bounds].ndims;
 			if ( nbdims == 2 || nbdims == 3 )
 			  {
-			    nvertex = ncdims[ncvars[ncvars[xvarid].bounds].dimids[nbdims-1]].len;
-			    grid.nvertex = (int) nvertex;
-			    grid.xbounds = (double *) Malloc(nvertex*size*sizeof(double));
-			    cdf_get_var_double(ncvars[xvarid].ncid, ncvars[xvarid].bounds, grid.xbounds);
+			    size_t nvertex = ncdims[ncvars[ncvars[xvarid].bounds].dimids[nbdims-1]].len;
+			    grid->nvertex = (int)nvertex;
+                            if (CDI_netcdf_lazy_grid_load)
+                              {
+                                lazyGrid->xBoundsGet.datasetNCId
+                                  = ncvars[xvarid].ncid;
+                                lazyGrid->xBoundsGet.varNCId
+                                  = ncvars[xvarid].bounds;
+                                grid->xbounds = cdfPendingLoad;
+                              }
+                            else
+                              {
+                                grid->xbounds
+                                  = (double *)Malloc(nvertex * size
+                                                     * sizeof(double));
+                                cdf_get_var_double(ncvars[xvarid].ncid,
+                                                   ncvars[xvarid].bounds,
+                                                   grid->xbounds);
+                              }
 			  }
 		      }
 		  }
 		if ( yvarid != UNDEFID )
 		  {
-		    grid.ydef  = 1;
+		    grid->ydef  = 1;
 		    if ( ncvars[yvarid].bounds != UNDEFID )
 		      {
-			nbdims = ncvars[ncvars[yvarid].bounds].ndims;
+			int nbdims = ncvars[ncvars[yvarid].bounds].ndims;
 			if ( nbdims == 2 || nbdims == 3 )
 			  {
-			    nvertex = ncdims[ncvars[ncvars[yvarid].bounds].dimids[nbdims-1]].len;
-			    /*
-			    if ( nvertex != grid.nvertex )
+			    /* size_t nvertex = ncdims[ncvars[ncvars[yvarid].bounds].dimids[nbdims-1]].len;
+			    if ( nvertex != grid->nvertex )
 			      Warning("nvertex problem! nvertex x %d, nvertex y %d",
-				      grid.nvertex, (int) nvertex);
+				      grid->nvertex, (int) nvertex);
 			    */
-			    grid.ybounds = (double *) Malloc(nvertex*size*sizeof(double));
-			    cdf_get_var_double(ncvars[yvarid].ncid, ncvars[yvarid].bounds, grid.ybounds);
+                            if (CDI_netcdf_lazy_grid_load)
+                              {
+                                lazyGrid->yBoundsGet.datasetNCId
+                                  = ncvars[yvarid].ncid;
+                                lazyGrid->yBoundsGet.varNCId
+                                  = ncvars[yvarid].bounds;
+                                grid->ybounds = cdfPendingLoad;
+                              }
+                            else
+                              {
+                                int vid
+                                  = ncvars[ncvars[yvarid].bounds].dimids[nbdims-1];
+                                size_t nvertex = ncdims[vid].len;
+                                /*
+                                  if ( nvertex != grid->nvertex )
+                                  Warning("nvertex problem! nvertex x %d, nvertex y %d",
+                                  grid->nvertex, (int) nvertex);
+                                */
+                                grid->ybounds
+                                  = (double *)Malloc(nvertex * size
+                                                     * sizeof(double));
+                                cdf_get_var_double(ncvars[yvarid].ncid,
+                                                   ncvars[yvarid].bounds,
+                                                   grid->ybounds);
+                              }
 			  }
 		      }
 		  }
 
 		if ( ncvars[ncvarid].cellarea != UNDEFID )
-		  {
-		    grid.area = (double *) Malloc(size*sizeof(double));
-		    cdf_get_var_double(ncvars[ncvarid].ncid, ncvars[ncvarid].cellarea, grid.area);
-		  }
+                  {
+                    if (CDI_netcdf_lazy_grid_load)
+                      {
+                        grid->area = cdfPendingLoad;
+                        lazyGrid->cellAreaGet.datasetNCId
+                          = ncvars[ncvarid].ncid;
+                        lazyGrid->cellAreaGet.varNCId
+                          = ncvars[ncvarid].cellarea;
+                      }
+                    else
+                      {
+                        grid->area = (double *) Malloc(size*sizeof(double));
+                        cdf_get_var_double(ncvars[ncvarid].ncid,
+                                           ncvars[ncvarid].cellarea,
+                                           grid->area);
+                      }
+                  }
 
 		break;
 	      }
 	    case GRID_SPECTRAL:
 	      {
-		grid.size = (int)size;
-		grid.lcomplex = 1;
+		grid->size = (int)size;
+		grid->lcomplex = 1;
 		break;
 	      }
 	    case GRID_FOURIER:
 	      {
-		grid.size = (int)size;
+		grid->size = (int)size;
 		break;
 	      }
 	    case GRID_TRAJECTORY:
 	      {
-		grid.size = 1;
+		grid->size = 1;
 		break;
 	      }
 	    }
 
-	  grid.type = ncvars[ncvarid].gridtype;
+          if (grid->type != ncvars[ncvarid].gridtype)
+            {
+              int gridtype = ncvars[ncvarid].gridtype;
+              grid->type = gridtype;
+              cdiGridTypeInit(grid, gridtype, grid->size);
+            }
 
-	  if ( grid.size == 0 )
+	  if ( grid->size == 0 )
 	    {
 	      if ( (ncvars[ncvarid].ndims == 1 && ncvars[ncvarid].dimtype[0] == T_AXIS) ||
 		   (ncvars[ncvarid].ndims == 1 && ncvars[ncvarid].dimtype[0] == Z_AXIS) ||
 		   (ncvars[ncvarid].ndims == 2 && ncvars[ncvarid].dimtype[0] == T_AXIS && ncvars[ncvarid].dimtype[1] == Z_AXIS) )
 		{
-		  grid.type  = GRID_GENERIC;
-		  grid.size  = 1;
-		  grid.xsize = 0;
-		  grid.ysize = 0;
+		  grid->type  = GRID_GENERIC;
+		  grid->size  = 1;
+		  grid->xsize = 0;
+		  grid->ysize = 0;
 		}
 	      else
 		{
@@ -6769,18 +5476,21 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 		}
 	    }
 
-	  if ( number_of_grid_used != UNDEFID && (grid.type == UNDEFID || grid.type == GRID_GENERIC) )
-            grid.type   = GRID_UNSTRUCTURED;
+	  if ( number_of_grid_used != UNDEFID && (grid->type == UNDEFID || grid->type == GRID_GENERIC) )
+            grid->type   = GRID_UNSTRUCTURED;
 
-	  if ( number_of_grid_used != UNDEFID && grid.type == GRID_UNSTRUCTURED )
-            grid.number = number_of_grid_used;
+	  if ( number_of_grid_used != UNDEFID && grid->type == GRID_UNSTRUCTURED )
+            grid->number = number_of_grid_used;
 
 	  if ( ncvars[ncvarid].gmapid >= 0 && ncvars[ncvarid].gridtype != GRID_CURVILINEAR )
 	    {
+              int nvatts;
 	      cdf_inq_varnatts(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, &nvatts);
 
-	      for ( iatt = 0; iatt < nvatts; iatt++ )
+	      for ( int iatt = 0; iatt < nvatts; iatt++ )
 		{
+                  size_t attlen;
+                  char attname[CDI_MAX_NAME];
 		  cdf_inq_attname(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, iatt, attname);
 		  cdf_inq_attlen(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, &attlen);
 
@@ -6795,76 +5505,79 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 		      strtolower(attstring);
 
 		      if ( strcmp(attstring, "rotated_latitude_longitude") == 0 )
-			grid.isRotated = TRUE;
+			grid->isRotated = TRUE;
 		      else if ( strcmp(attstring, "sinusoidal") == 0 )
-			grid.type = GRID_SINUSOIDAL;
+			grid->type = GRID_SINUSOIDAL;
 		      else if ( strcmp(attstring, "lambert_azimuthal_equal_area") == 0 )
-			grid.type = GRID_LAEA;
+			grid->type = GRID_LAEA;
 		      else if ( strcmp(attstring, "lambert_conformal_conic") == 0 )
-			grid.type = GRID_LCC2;
+			grid->type = GRID_LCC2;
 		      else if ( strcmp(attstring, "lambert_cylindrical_equal_area") == 0 )
 			{
-			  proj.type = GRID_PROJECTION;
-			  proj.name = strdup(attstring);
+			  proj->type = GRID_PROJECTION;
+			  proj->name = strdup(attstring);
 			}
 		    }
 		  else if ( strcmp(attname, "earth_radius") == 0 )
 		    {
+                      double datt;
 		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
-		      grid.laea_a = datt;
-		      grid.lcc2_a = datt;
+		      grid->laea_a = datt;
+		      grid->lcc2_a = datt;
 		    }
 		  else if ( strcmp(attname, "longitude_of_projection_origin") == 0 )
 		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid.laea_lon_0);
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->laea_lon_0);
 		    }
 		  else if ( strcmp(attname, "longitude_of_central_meridian") == 0 )
 		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid.lcc2_lon_0);
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->lcc2_lon_0);
 		    }
 		  else if ( strcmp(attname, "latitude_of_projection_origin") == 0 )
 		    {
+                      double datt;
 		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
-		      grid.laea_lat_0 = datt;
-		      grid.lcc2_lat_0 = datt;
+		      grid->laea_lat_0 = datt;
+		      grid->lcc2_lat_0 = datt;
 		    }
 		  else if ( strcmp(attname, "standard_parallel") == 0 )
 		    {
 		      if ( attlen == 1 )
 			{
+                          double datt;
 			  cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
-			  grid.lcc2_lat_1 = datt;
-			  grid.lcc2_lat_2 = datt;
+			  grid->lcc2_lat_1 = datt;
+			  grid->lcc2_lat_2 = datt;
 			}
 		      else
 			{
 			  double datt2[2];
 			  cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 2, datt2);
-			  grid.lcc2_lat_1 = datt2[0];
-			  grid.lcc2_lat_2 = datt2[1];
+			  grid->lcc2_lat_1 = datt2[0];
+			  grid->lcc2_lat_2 = datt2[1];
 			}
 		    }
 		  else if ( strcmp(attname, "grid_north_pole_latitude") == 0 )
 		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid.ypole);
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->ypole);
 		    }
 		  else if ( strcmp(attname, "grid_north_pole_longitude") == 0 )
 		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid.xpole);
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->xpole);
 		    }
 		  else if ( strcmp(attname, "north_pole_grid_longitude") == 0 )
 		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid.angle);
+		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->angle);
 		    }
 		}
 	    }
 
-          if ( grid.type == GRID_UNSTRUCTURED )
+          if ( grid->type == GRID_UNSTRUCTURED )
             {
               int zdimid = UNDEFID;
               int xdimidx = -1, ydimidx = -1;
 
-              for ( i = 0; i < ndims; i++ )
+              for ( int i = 0; i < ndims; i++ )
                 {
                   if      ( ncvars[ncvarid].dimtype[i] == X_AXIS ) xdimidx = i;
                   else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) ydimidx = i;
@@ -6873,96 +5586,100 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 
               if ( xdimid != UNDEFID && ydimid != UNDEFID && zdimid == UNDEFID )
                 {
-                  if ( grid.xsize > grid.ysize && grid.ysize < 1000 )
+                  if ( grid->xsize > grid->ysize && grid->ysize < 1000 )
                     {
                       ncvars[ncvarid].dimtype[ydimidx] = Z_AXIS;
                       ydimid = UNDEFID;
-                      grid.size  = grid.xsize;
-                      grid.ysize = 0;
+                      grid->size  = grid->xsize;
+                      grid->ysize = 0;
                     }
-                  else if ( grid.ysize > grid.xsize && grid.xsize < 1000 )
+                  else if ( grid->ysize > grid->xsize && grid->xsize < 1000 )
                     {
                       ncvars[ncvarid].dimtype[xdimidx] = Z_AXIS;
                       xdimid = ydimid;
                       ydimid = UNDEFID;
-                      grid.size  = grid.ysize;
-                      grid.xsize = grid.ysize;
-                      grid.ysize = 0;
+                      grid->size  = grid->ysize;
+                      grid->xsize = grid->ysize;
+                      grid->ysize = 0;
                     }
                 }
 
-              if ( grid.size != grid.xsize )
+              if ( grid->size != grid->xsize )
                 {
                   Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
                   ncvars[ncvarid].isvar = -1;
                   continue;
                 }
 
-              if ( ncvars[ncvarid].position > 0 ) grid.position = ncvars[ncvarid].position;
-              if ( uuidOfHGrid[0] != 0 ) memcpy(grid.uuid, uuidOfHGrid, 16);
+              if ( ncvars[ncvarid].position > 0 ) grid->position = ncvars[ncvarid].position;
+              if ( uuidOfHGrid[0] != 0 ) memcpy(grid->uuid, uuidOfHGrid, 16);
             }
 
 #if defined (PROJECTION_TEST)
-	  if ( proj.type == GRID_PROJECTION )
+	  if ( proj->type == GRID_PROJECTION )
 	    {
-	      if ( grid.type == GRID_GENERIC )
+	      if ( grid->type == GRID_GENERIC )
 		{
-		  grid.type = GRID_CURVILINEAR;
+		  grid->type = GRID_CURVILINEAR;
 		}
 
-	      if ( grid.type == GRID_CURVILINEAR )
+	      if ( grid->type == GRID_CURVILINEAR )
 		{
-		  proj.size  = grid.size;
-		  proj.xsize = grid.xsize;
-                  proj.ysize = grid.ysize;
+                  proj->size  = grid->size;
+                  proj->xsize = grid->xsize;
+                  proj->ysize = grid->ysize;
 		}
 
-	      //  grid.proj = gridGenerate(proj);
+	      //  grid->proj = gridGenerate(proj);
 	    }
 #endif
 
 	  if ( CDI_Debug )
 	    {
 	      Message("grid: type = %d, size = %d, nx = %d, ny %d",
-		      grid.type, grid.size, grid.xsize, grid.ysize);
+		      grid->type, grid->size, grid->xsize, grid->ysize);
 	      Message("proj: type = %d, size = %d, nx = %d, ny %d",
-		      proj.type, proj.size, proj.xsize, proj.ysize);
+		      proj->type, proj->size, proj->xsize, proj->ysize);
 	    }
 
 #if defined (PROJECTION_TEST)
-	  if ( proj.type == GRID_PROJECTION )
+	  if ( proj->type == GRID_PROJECTION )
 	    {
-	      ncvars[ncvarid].gridID = varDefGrid(vlistID, &proj, 1);
+              projAdded = cdiVlistAddGridIfNew(vlistID, proj, 1);
+              ncvars[ncvarid].gridID = projAdded.Id;
 	      copy_numeric_projatts(ncvars[ncvarid].gridID, ncvars[ncvarid].gmapid, ncvars[ncvarid].ncid);
 	    }
 	  else
 #endif
-	    ncvars[ncvarid].gridID = varDefGrid(vlistID, &grid, 1);
+            {
+              gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 1);
+              ncvars[ncvarid].gridID = gridAdded.Id;
+            }
 
-          if ( grid.type == GRID_UNSTRUCTURED )
+          if ( grid->type == GRID_UNSTRUCTURED )
             {
               if ( gridfile[0] != 0 ) gridDefReference(ncvars[ncvarid].gridID, gridfile);
             }
 
-          if ( ncvars[ncvarid].chunked ) grid_set_chunktype(&grid, &ncvars[ncvarid]);
+          if ( ncvars[ncvarid].chunked ) grid_set_chunktype(grid, &ncvars[ncvarid]);
 
-	  gridindex = vlistGridIndex(vlistID, ncvars[ncvarid].gridID);
+	  int gridindex = vlistGridIndex(vlistID, ncvars[ncvarid].gridID);
 	  streamptr->xdimID[gridindex] = xdimid;
 	  streamptr->ydimID[gridindex] = ydimid;
-          if ( xdimid == -1 && ydimid == -1 && grid.size == 1 )
+          if ( xdimid == -1 && ydimid == -1 && grid->size == 1 )
             gridDefHasDims(ncvars[ncvarid].gridID, FALSE);
 
 	  if ( CDI_Debug )
 	    Message("gridID %d %d %s", ncvars[ncvarid].gridID, ncvarid, ncvars[ncvarid].name);
 
-	  for ( ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
+	  for ( int ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
 	    if ( ncvars[ncvarid2].isvar == TRUE && ncvars[ncvarid2].gridID == UNDEFID )
 	      {
 		int xdimid2 = UNDEFID, ydimid2 = UNDEFID, zdimid2 = UNDEFID;
                 int xdimidx = -1, ydimidx = -1;
 		int ndims2 = ncvars[ncvarid2].ndims;
 
-		for ( i = 0; i < ndims2; i++ )
+		for ( int i = 0; i < ndims2; i++ )
 		  {
 		    if ( ncvars[ncvarid2].dimtype[i] == X_AXIS )
 		      { xdimid2 = ncvars[ncvarid2].dimids[i]; xdimidx = i; }
@@ -6972,7 +5689,7 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 		      { zdimid2 = ncvars[ncvarid2].dimids[i]; }
 		  }
 
-                if ( ncvars[ncvarid2].gridtype == UNDEFID && grid.type == GRID_UNSTRUCTURED )
+                if ( ncvars[ncvarid2].gridtype == UNDEFID && grid->type == GRID_UNSTRUCTURED )
                   {
                     if ( xdimid == xdimid2 && ydimid2 != UNDEFID && zdimid2 == UNDEFID )
                       {
@@ -6991,7 +5708,9 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
                 if ( xdimid == xdimid2 &&
 		    (ydimid == ydimid2 || (xdimid == ydimid && ydimid2 == UNDEFID)) )
 		  {
-		    int same_grid = TRUE;
+		    int same_grid = ncvars[ncvarid].xvarid == ncvars[ncvarid2].xvarid
+                      && ncvars[ncvarid].yvarid == ncvars[ncvarid2].yvarid
+                      && ncvars[ncvarid].position == ncvars[ncvarid2].position;
                     /*
 		    if ( xvarid != -1 && ncvars[ncvarid2].xvarid != UNDEFID &&
 			 xvarid != ncvars[ncvarid2].xvarid ) same_grid = FALSE;
@@ -6999,10 +5718,6 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 		    if ( yvarid != -1 && ncvars[ncvarid2].yvarid != UNDEFID &&
 			 yvarid != ncvars[ncvarid2].yvarid ) same_grid = FALSE;
                     */
-		    if ( ncvars[ncvarid].xvarid != ncvars[ncvarid2].xvarid ) same_grid = FALSE;
-		    if ( ncvars[ncvarid].yvarid != ncvars[ncvarid2].yvarid ) same_grid = FALSE;
-
-		    if ( ncvars[ncvarid].position != ncvars[ncvarid2].position ) same_grid = FALSE;
 
 		    if ( same_grid )
 		      {
@@ -7014,10 +5729,26 @@ void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nva
 		  }
 	      }
 
-	  grid_free(&grid);
-	  grid_free(&proj);
+          if (gridAdded.isNew)
+            lazyGrid = NULL;
+          if (projAdded.isNew)
+            lazyProj = NULL;
 	}
     }
+  if (lazyGrid)
+    {
+      if (CDI_netcdf_lazy_grid_load) cdfLazyGridDestroy(lazyGrid);
+      grid_free(grid);
+      Free(grid);
+    }
+  if (lazyProj)
+    {
+      if (CDI_netcdf_lazy_grid_load) cdfLazyGridDestroy(lazyProj);
+      grid_free(proj);
+      Free(proj);
+    }
+#undef proj
+#undef grid
 }
 
 /* define all input zaxes */
@@ -7227,6 +5958,10 @@ int cmpvarname(const void *s1, const void *s2)
 static
 void define_all_vars(stream_t *streamptr, int vlistID, int instID, int modelID, int *varids, int nvars, int num_ncvars, ncvar_t *ncvars)
 {
+  if ( CDI_Debug )
+    {
+      for(int i = 0; i < nvars; i++) Message("varids[%d] = %d", i, varids[i]);
+    }
   if ( streamptr->sortname )
     {
       struct varinfo *varInfo
@@ -7244,6 +5979,10 @@ void define_all_vars(stream_t *streamptr, int vlistID, int instID, int modelID,
 	  varids[varID] = varInfo[varID].ncvarid;
 	}
       Free(varInfo);
+      if ( CDI_Debug )
+        {
+          for(int i = 0; i < nvars; i++) Message("sorted varids[%d] = %d", i, varids[i]);
+        }
     }
 
   for ( int varID1 = 0; varID1 < nvars; varID1++ )
@@ -7572,13 +6311,13 @@ void scan_global_attributes(int fileID, int vlistID, stream_t *streamptr, int ng
 	      else if ( strcmp(attname, "uuidOfHGrid") == 0 && attstrlen == 36 )
 		{
                   attstring[36] = 0;
-                  str2uuid(attstring, uuidOfHGrid);
+                  cdiStr2UUID(attstring, uuidOfHGrid);
                   //   printf("uuid: %d %s\n", attlen, attstring);
 		}
 	      else if ( strcmp(attname, "uuidOfVGrid") == 0 && attstrlen == 36 )
 		{
                   attstring[36] = 0;
-                  str2uuid(attstring, uuidOfVGrid);
+                  cdiStr2UUID(attstring, uuidOfVGrid);
 		}
 	      else
 		{
@@ -8407,144 +7146,6 @@ int cdfInqTimestep(stream_t * streamptr, int tsID)
 }
 
 
-void cdfEndDef(stream_t *streamptr)
-{
-  int varID;
-  int nvars;
-  int fileID;
-
-  fileID  = streamptr->fileID;
-
-  cdfDefGlobalAtts(streamptr);
-  cdfDefLocalAtts(streamptr);
-
-  if ( streamptr->accessmode == 0 )
-    {
-      nvars =  streamptr->nvars;
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      for ( varID = 0; varID < nvars; varID++ )
-	cdfDefVar(streamptr, varID);
-
-      if ( streamptr->ncmode == 2 )
-        {
-          if ( CDI_netcdf_hdr_pad == 0UL )
-            cdf_enddef(fileID);
-          else
-            cdf__enddef(fileID, CDI_netcdf_hdr_pad);
-        }
-
-      streamptr->accessmode = 1;
-    }
-}
-
-
-static void cdfDefInstitut(stream_t *streamptr)
-{
-  int fileID, instID;
-  size_t len;
-  int vlistID;
-
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
-  instID  = vlistInqInstitut(vlistID);
-
-  if ( instID != UNDEFID )
-    {
-      const char *longname = institutInqLongnamePtr(instID);
-      if ( longname )
-	{
-	  len = strlen(longname);
-	  if ( len > 0 )
-	    {
-	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-	      cdf_put_att_text(fileID, NC_GLOBAL, "institution", len, longname);
-	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
-	    }
-	}
-    }
-}
-
-
-static void cdfDefSource(stream_t *streamptr)
-{
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-  int modelID = vlistInqModel(vlistID);
-
-  if ( modelID != UNDEFID )
-    {
-      const char *longname = modelInqNamePtr(modelID);
-      if ( longname )
-	{
-          size_t len = strlen(longname);
-	  if ( len > 0 )
-	    {
-	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-	      cdf_put_att_text(fileID, NC_GLOBAL, "source", len, longname);
-	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
-	    }
-	}
-    }
-}
-
-
-static void cdfDefGlobalAtts(stream_t *streamptr)
-{
-  int natts;
-
-  if ( streamptr->globalatts ) return;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  cdfDefSource(streamptr);
-  cdfDefInstitut(streamptr);
-
-  vlistInqNatts(vlistID, CDI_GLOBAL, &natts);
-
-  if ( natts > 0 && streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-  defineAttributes(vlistID, CDI_GLOBAL, fileID, NC_GLOBAL);
-
-  if ( natts > 0 && streamptr->ncmode == 2 ) cdf_enddef(fileID);
-
-  streamptr->globalatts = 1;
-}
-
-
-static void cdfDefLocalAtts(stream_t *streamptr)
-{
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  if ( streamptr->localatts ) return;
-  if ( vlistInqInstitut(vlistID) != UNDEFID ) return;
-
-  streamptr->localatts = 1;
-
-  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-  for ( int varID = 0; varID < streamptr->nvars; varID++ )
-    {
-      int instID = vlistInqVarInstitut(vlistID, varID);
-      if ( instID != UNDEFID )
-	{
-          int ncvarid = streamptr->vars[varID].ncvarid;
-  	  const char *name = institutInqNamePtr(instID);
-	  if ( name )
-	    {
-              size_t len = strlen(name);
-	      cdf_put_att_text(fileID, ncvarid, "institution", len, name);
-	    }
-	}
-      }
-
-  if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
-}
-
-
 void cdfDefHistory(stream_t *streamptr, int size, const char *history)
 {
   int ncid = streamptr->fileID;
@@ -8567,7 +7168,22 @@ void cdfInqHistoryString(stream_t *streamptr, char *history)
 {
   int ncid = streamptr->fileID;
   if ( streamptr->historyID != UNDEFID )
-    cdf_get_att_text(ncid, NC_GLOBAL, "history", history);
+    {
+      nc_type atttype;
+      cdf_inq_atttype(ncid, NC_GLOBAL, "history", &atttype);
+
+      if ( atttype == NC_CHAR )
+        {
+          cdf_get_att_text(ncid, NC_GLOBAL, "history", history);
+        }
+#if  defined  (HAVE_NETCDF4)
+      else if ( atttype == NC_STRING )
+        {
+          // ToDo
+          Warning("History attribute with type NC_STRING unsupported!");
+        }
+#endif
+    }
 }
 
 
diff --git a/libcdi/src/stream_cdf.h b/libcdi/src/stream_cdf.h
index 47241e2..c0228b8 100644
--- a/libcdi/src/stream_cdf.h
+++ b/libcdi/src/stream_cdf.h
@@ -14,21 +14,21 @@ void   cdfDefRecord(stream_t * streamptr);
 
 void   cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
 
-void   cdfReadRecord(stream_t *streamptr, double *data, int *nmiss);
+void   cdf_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss);
 void   cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss);
 
-void   cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss);
-void   cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss);
-
+void   cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss);
 void   cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss);
 
-void   cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data, int *nmiss);
-void   cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data, int *nmiss);
+void   cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss);
 void   cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss);
 
 void   cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
                            const int rect[][2], const void *data, int nmiss);
 
+void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level);
+void cdfDefTime(stream_t* streamptr);
+
 #endif
 /*
  * Local Variables:
diff --git a/libcdi/src/stream_cgribex.c b/libcdi/src/stream_cgribex.c
index 693c772..445e4a9 100644
--- a/libcdi/src/stream_cgribex.c
+++ b/libcdi/src/stream_cgribex.c
@@ -4,7 +4,6 @@
 
 #include <limits.h>
 #include <stdio.h>
-// #include <float.h>  /* FLT_EPSILON */
 
 #include "dmemory.h"
 #include "cdi.h"
@@ -168,7 +167,8 @@ void cgribexGetGrid(stream_t *streamptr, int *isec2, double *fsec2, int *isec4,
       compyinc = FALSE;
     }
 
-  memset(grid, 0, sizeof(grid_t));
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, 0);
   switch (gridtype)
     {
     case GRID_LONLAT:
@@ -362,7 +362,7 @@ void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, d
 {
   int varID;
   int levelID = 0;
-  grid_t grid;
+  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
 
   int vlistID = streamptr->vlistID;
   int tsID    = streamptr->curTsID;
@@ -383,11 +383,13 @@ void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, d
   record->ilevel    = level1;
   record->ilevel2   = level2;
   record->ltype     = ISEC1_LevelType;
-  record->tsteptype = tsteptype;
+  record->tsteptype = (short)tsteptype;
 
-  cgribexGetGrid(streamptr, isec2, fsec2, isec4, &grid, iret);
+  cgribexGetGrid(streamptr, isec2, fsec2, isec4, grid, iret);
 
-  int gridID = varDefGrid(vlistID, &grid, 0);
+  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  int gridID = gridAdded.Id;
+  if (!gridAdded.isNew) Free(grid);
 
   int zaxistype = grib1ltypeToZaxisType(ISEC1_LevelType);
 
@@ -1308,12 +1310,13 @@ int cgribexScanTimestep(stream_t * streamptr)
 #endif
 
 #if  defined  (HAVE_LIBCGRIBEX)
-int cgribexDecode(unsigned char *gribbuffer, int gribsize, double *data, int gridsize,
+int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long datasize,
 		  int unreduced, int *nmiss, double missval)
 {
   int status = 0;
   int iret = 0, iword = 0;
   int isec0[2], isec1[4096], isec2[4096], isec3[2], isec4[512];
+  float fsec2f[512], fsec3f[2];
   double fsec2[512], fsec3[2];
   char hoper[2];
 
@@ -1322,8 +1325,12 @@ int cgribexDecode(unsigned char *gribbuffer, int gribsize, double *data, int gri
 
   FSEC3_MissVal = missval;
 
-  gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, data,
-	   gridsize, (int *)(void *)gribbuffer, gribsize, &iword, hoper, &iret);
+  if ( memtype == MEMTYPE_FLOAT )
+    gribExSP(isec0, isec1, isec2, fsec2f, isec3, fsec3f, isec4, (float*) data,
+             (int) datasize, (int*) gribbuffer, gribsize, &iword, hoper, &iret);
+  else
+    gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, (double*) data,
+             (int) datasize, (int*) gribbuffer, gribsize, &iword, hoper, &iret);
 
   if ( ISEC1_Sec2Or3Flag & 64 )
     *nmiss = ISEC4_NumValues - ISEC4_NumNonMissValues;
@@ -1333,19 +1340,30 @@ int cgribexDecode(unsigned char *gribbuffer, int gribsize, double *data, int gri
   if ( ISEC1_CenterID == 215 && (isec1[34] != 0 && isec1[34] != 255) )
     {
       double undef_pds, undef_eps;
-      int i;
-
       MCH_get_undef(isec1, &undef_pds, &undef_eps);
 
       *nmiss = 0;
-      for ( i = 0; i < gridsize; i++ )
-        if ( (fabs(data[i]-undef_pds) < undef_eps) || IS_EQUAL(data[i],FSEC3_MissVal) ) {
-          data[i] = missval;
-          (*nmiss)++;
+      if ( memtype == MEMTYPE_FLOAT )
+        {
+          float *restrict dataf = (float*) data;
+          for ( long i = 0; i < datasize; i++ )
+            if ( (fabs(dataf[i]-undef_pds) < undef_eps) || IS_EQUAL(dataf[i],FSEC3_MissVal) ) {
+              dataf[i] = (float)missval;
+              (*nmiss)++;
+            }
+        }
+      else
+        {
+          double *restrict datad = (double*) data;
+          for ( long i = 0; i < datasize; i++ )
+            if ( (fabs(datad[i]-undef_pds) < undef_eps) || IS_EQUAL(datad[i],FSEC3_MissVal) ) {
+              datad[i] = missval;
+              (*nmiss)++;
+            }
         }
     }
 
-  return (status);
+  return status;
 }
 #endif
 
@@ -1534,10 +1552,17 @@ void cgribexDefTime(int *isec1, int vdate, int vtime, int tsteptype, int numavg,
       rtime    = taxisInqRtime(taxisID);
 
       factor = cgribexDefDateTime(isec1, timeunit, rdate, rtime);
-
       timerange = cgribexDefTimerange(tsteptype, factor, calendar,
 				      rdate, rtime, vdate, vtime, &ip1, &ip2);
 
+      if ( ip2 > 0xFF && timeunit < TUNIT_YEAR )
+        {
+          timeunit++;
+          factor = cgribexDefDateTime(isec1, timeunit, rdate, rtime);
+          timerange = cgribexDefTimerange(tsteptype, factor, calendar,
+                                          rdate, rtime, vdate, vtime, &ip1, &ip2);
+        }
+
       if ( timerange == -1 || timerange == 3 )
 	{
 	  timetype = TAXIS_ABSOLUTE;
@@ -1714,8 +1739,6 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 	    ISEC2_LonIncr  = (int)lround(xinc*1000);
 	  }
 
-	// if ( fabs(xinc*1000 - ISEC2_LonIncr) > FLT_EPSILON ) ISEC2_LonIncr = 0;
-
 	if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
           {
             int np = gridInqNP(gridID);
@@ -1725,8 +1748,6 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 	else
 	  {
 	    ISEC2_LatIncr = (int)lround(yinc*1000);
-	    // if ( fabs(yinc*1000 - ISEC2_LatIncr) > FLT_EPSILON ) ISEC2_LatIncr = 0;
-
 	    if ( ISEC2_LatIncr < 0 ) ISEC2_LatIncr = -ISEC2_LatIncr;
 	  }
 
@@ -1760,12 +1781,12 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
       }
     case GRID_LCC:
       {
-	double originLon, originLat, lonParY, lat1, lat2, xincm, yincm;
-	int xsize, ysize;
-	int projflag, scanflag;
+	double originLon = 0.0, originLat = 0.0, lonParY = 0.0,
+          lat1 = 0.0, lat2 = 0.0, xincm = 0.0, yincm = 0.0;
+	int projflag = 0, scanflag = 0;
 
-	xsize = gridInqXsize(gridID);
-	ysize = gridInqYsize(gridID);
+	int xsize = gridInqXsize(gridID),
+          ysize = gridInqYsize(gridID);
 
 	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
 		   &projflag, &scanflag);
@@ -1781,7 +1802,7 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 	ISEC2_Lambert_dx     = (int)lround(xincm);
 	ISEC2_Lambert_dy     = (int)lround(yincm);
 	ISEC2_Lambert_LatSP  = 0;
-	ISEC2_Lambert_LatSP  = 0;
+	ISEC2_Lambert_LonSP  = 0;
 	ISEC2_Lambert_ProjFlag = projflag;
 	ISEC2_ScanFlag = scanflag;
 
@@ -1839,7 +1860,6 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
 {
   double level;
   int ilevel, zaxistype, ltype;
-  static bool lwarning = true;
   static bool lwarning_vct = true;
 
   zaxistype = zaxisInqType(zaxisID);
@@ -1934,11 +1954,6 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
 	  }
 
 	vctsize = zaxisInqVctSize(zaxisID);
-	if ( vctsize == 0 && lwarning )
-	  {
-	    Warning("VCT missing. ( param = %d, zaxisID = %d )", ISEC1_Parameter, zaxisID);
-	    lwarning = false;
-	  }
 	if ( vctsize > 255 )
 	  {
 	    ISEC2_NumVCP = 0;
@@ -1986,6 +2001,15 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
       {
 	level = zaxisInqLevel(zaxisID, levelID);
 
+	char units[128];
+	zaxisInqUnits(zaxisID, units);
+        if ( units[1] == 'm' && !units[2] )
+          {
+            if      ( units[0] == 'c' ) level *= 0.01;
+            else if ( units[0] == 'd' ) level *= 0.1;
+            else if ( units[0] == 'k' ) level *= 1000;
+          }
+
 	ilevel = (int) level;
 	ISEC1_LevelType = GRIB1_LTYPE_HEIGHT;
 	ISEC1_Level1    = ilevel;
@@ -2116,9 +2140,7 @@ void cgribexDefaultSec1(int *isec1)
 static
 void cgribexDefaultSec4(int *isec4)
 {
-  long i;
-
-  for ( i = 2; i <= 10; ++i ) isec4[i] = 0;
+  for ( int i = 2; i <= 10; ++i ) isec4[i] = 0;
 }
 
 static
@@ -2153,7 +2175,7 @@ void cgribexDefEnsembleVar(int *isec1, int vlistID, int varID)
 #if  defined  (HAVE_LIBCGRIBEX)
 size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const double *data, int nmiss, unsigned char *gribbuffer, size_t gribbuffersize)
+		     long datasize, const void *data, int nmiss, void *gribbuffer, size_t gribbuffersize)
 {
   size_t nbytes = 0;
   int gribsize;
@@ -2198,7 +2220,10 @@ size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridI
 
   if ( isec4[2] == 128 && isec4[3] == 64 )
     {
-      isec4[16] = (int) (1000*calculate_pfactor(data, ISEC2_PentaJ, isec4[17]));
+      if ( memtype == MEMTYPE_FLOAT )
+        isec4[16] = (int) (1000*calculate_pfactor_float((const float*) data, ISEC2_PentaJ, isec4[17]));
+      else
+        isec4[16] = (int) (1000*calculate_pfactor_double((const double*) data, ISEC2_PentaJ, isec4[17]));
       if ( isec4[16] < -10000 ) isec4[16] = -10000;
       if ( isec4[16] >  10000 ) isec4[16] =  10000;
     }
@@ -2213,15 +2238,15 @@ size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridI
 
   if ( memtype == MEMTYPE_FLOAT )
     gribExSP(isec0, isec1, isec2, fsec2f, isec3, fsec3f, isec4, (float*) data,
-             (int)datasize, (int *)(void *)gribbuffer, gribsize, &iword, "C", &iret);
+             (int) datasize, (int*) gribbuffer, gribsize, &iword, "C", &iret);
   else
     gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, (double*) data,
-             (int)datasize, (int *)(void *)gribbuffer, gribsize, &iword, "C", &iret);
+             (int) datasize, (int*) gribbuffer, gribsize, &iword, "C", &iret);
 
   if ( iret ) Error("Problem during GRIB encode (errno = %d)!", iret);
 
   nbytes = (size_t)iword * sizeof (int);
-  return (nbytes);
+  return nbytes;
 }
 #endif
 /*
diff --git a/libcdi/src/stream_cgribex.h b/libcdi/src/stream_cgribex.h
index 6fef957..43f3525 100644
--- a/libcdi/src/stream_cgribex.h
+++ b/libcdi/src/stream_cgribex.h
@@ -5,12 +5,12 @@ int cgribexScanTimestep1(stream_t * streamptr);
 int cgribexScanTimestep2(stream_t * streamptr);
 int cgribexScanTimestep(stream_t * streamptr);
 
-int cgribexDecode(unsigned char *gribbuffer, int gribsize, double *data, int gridsize,
+int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long datasize,
 		  int unreduced, int *nmiss, double missval);
 
 size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
-		     int vdate, int vtime, int tsteptype, int numavg, 
-		     long datasize, const double *data, int nmiss, unsigned char *gribbuffer, size_t gribbuffersize);
+		     int vdate, int vtime, int tsteptype, int numavg,
+		     long datasize, const void *data, int nmiss, void *gribbuffer, size_t gribbuffersize);
 
 #endif  /* _STREAM_CGRIBEX_H */
 /*
diff --git a/libcdi/src/stream_ext.c b/libcdi/src/stream_ext.c
index 0aaa821..048de70 100644
--- a/libcdi/src/stream_ext.c
+++ b/libcdi/src/stream_ext.c
@@ -206,44 +206,38 @@ static
 void extAddRecord(stream_t *streamptr, int param, int level, int xysize,
 		  size_t recsize, off_t position, int prec, int number)
 {
-  int leveltype;
-  int gridID = CDI_UNDEFID;
-  int levelID = 0;
-  int tsID, recID, varID;
-  record_t *record;
-  grid_t grid;
-  int vlistID;
-
-  vlistID = streamptr->vlistID;
-  tsID    = streamptr->curTsID;
-  recID   = recordNewEntry(streamptr, tsID);
-  record  = &streamptr->tsteps[tsID].records[recID];
-
-  (*record).size     = recsize;
-  (*record).position = position;
-  (*record).param     = param;
-  (*record).ilevel   = level;
-
-  memset(&grid, 0, sizeof(grid_t));
-  grid.type  = GRID_GENERIC;
-  grid.size  = xysize;
-  grid.xsize = xysize;
-  grid.ysize = 0;
-  grid.xvals = NULL;
-  grid.yvals = NULL;
-  gridID = varDefGrid(vlistID, &grid, 0);
+  int vlistID = streamptr->vlistID;
+  int tsID    = streamptr->curTsID;
+  int recID   = recordNewEntry(streamptr, tsID);
+  record_t *record  = &streamptr->tsteps[tsID].records[recID];
+
+  record->size     = recsize;
+  record->position = position;
+  record->param    = param;
+  record->ilevel   = level;
+
+  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
+  grid_init(grid);
+  cdiGridTypeInit(grid, GRID_GENERIC, xysize);
+  grid->xsize = xysize;
+  grid->ysize = 0;
+  grid->xvals = NULL;
+  grid->yvals = NULL;
+  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  int gridID = gridAdded.Id;
+  if (!gridAdded.isNew) Free(grid);
   /*
   if ( level == 0 ) leveltype = ZAXIS_SURFACE;
   else              leveltype = ZAXIS_GENERIC;
   */
-  leveltype = ZAXIS_GENERIC;
+  int leveltype = ZAXIS_GENERIC;
 
+  int varID, levelID = 0;
   varAddRecord(recID, param, gridID, leveltype, 0, level, 0, 0, 0,
-	       extInqDatatype(prec, number), &varID, &levelID, TSTEP_INSTANT, 0, 0, -1,
+               extInqDatatype(prec, number), &varID, &levelID, TSTEP_INSTANT, 0, 0, -1,
                NULL, NULL, NULL, NULL, NULL, NULL);
-
-  (*record).varID   = (short)varID;
-  (*record).levelID = (short)levelID;
+  record->varID   = (short)varID;
+  record->levelID = (short)levelID;
 
   streamptr->tsteps[tsID].nallrecs++;
   streamptr->nrecs++;
diff --git a/libcdi/src/stream_fcommon.c b/libcdi/src/stream_fcommon.c
index 7198c90..482a031 100644
--- a/libcdi/src/stream_fcommon.c
+++ b/libcdi/src/stream_fcommon.c
@@ -5,10 +5,9 @@
 #include "file.h"
 #include "stream_fcommon.h"
 
-void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1,
-                       const char *container_name)
-{
 
+void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1, const char *container_name)
+{
   int fileID1 = streamptr1->fileID;
   int fileID2 = streamptr2->fileID;
 
diff --git a/libcdi/src/stream_grb.c b/libcdi/src/stream_grb.c
index f619ab1..a56313a 100644
--- a/libcdi/src/stream_grb.c
+++ b/libcdi/src/stream_grb.c
@@ -1,11 +1,7 @@
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
 #endif
 
-#include <stdio.h>
-#include <string.h>
-
-#include "dmemory.h"
 #include "cdi.h"
 #include "cdi_int.h"
 #include "stream_cgribex.h"
@@ -14,8 +10,6 @@
 #include "file.h"
 #include "cgribex.h"  /* gribZip gribGetZip gribGinfo */
 #include "gribapi.h"
-#include "namespace.h"
-
 
 
 int grib1ltypeToZaxisType(int grib_ltype)
@@ -24,34 +18,34 @@ int grib1ltypeToZaxisType(int grib_ltype)
 
   switch ( grib_ltype )
     {
-    case GRIB1_LTYPE_SURFACE:            { zaxistype = ZAXIS_SURFACE;                break; }
-    case GRIB1_LTYPE_CLOUD_BASE:         { zaxistype = ZAXIS_CLOUD_BASE;             break; }
-    case GRIB1_LTYPE_CLOUD_TOP:          { zaxistype = ZAXIS_CLOUD_TOP;              break; }
-    case GRIB1_LTYPE_ISOTHERM0:          { zaxistype = ZAXIS_ISOTHERM_ZERO;          break; }
-    case GRIB1_LTYPE_TOA:                { zaxistype = ZAXIS_TOA;                    break; }
-    case GRIB1_LTYPE_SEA_BOTTOM:         { zaxistype = ZAXIS_SEA_BOTTOM;             break; }
-    case GRIB1_LTYPE_ATMOSPHERE:         { zaxistype = ZAXIS_ATMOSPHERE;             break; }
-    case GRIB1_LTYPE_MEANSEA:            { zaxistype = ZAXIS_MEANSEA;                break; }
+    case GRIB1_LTYPE_SURFACE:            zaxistype = ZAXIS_SURFACE;                break;
+    case GRIB1_LTYPE_CLOUD_BASE:         zaxistype = ZAXIS_CLOUD_BASE;             break;
+    case GRIB1_LTYPE_CLOUD_TOP:          zaxistype = ZAXIS_CLOUD_TOP;              break;
+    case GRIB1_LTYPE_ISOTHERM0:          zaxistype = ZAXIS_ISOTHERM_ZERO;          break;
+    case GRIB1_LTYPE_TOA:                zaxistype = ZAXIS_TOA;                    break;
+    case GRIB1_LTYPE_SEA_BOTTOM:         zaxistype = ZAXIS_SEA_BOTTOM;             break;
+    case GRIB1_LTYPE_ATMOSPHERE:         zaxistype = ZAXIS_ATMOSPHERE;             break;
+    case GRIB1_LTYPE_MEANSEA:            zaxistype = ZAXIS_MEANSEA;                break;
     case GRIB1_LTYPE_99:
-    case GRIB1_LTYPE_ISOBARIC:           { zaxistype = ZAXIS_PRESSURE;               break; }
-    case GRIB1_LTYPE_HEIGHT:             { zaxistype = ZAXIS_HEIGHT;                 break; }
-    case GRIB1_LTYPE_ALTITUDE:           { zaxistype = ZAXIS_ALTITUDE;	             break; }
+    case GRIB1_LTYPE_ISOBARIC:           zaxistype = ZAXIS_PRESSURE;               break;
+    case GRIB1_LTYPE_HEIGHT:             zaxistype = ZAXIS_HEIGHT;                 break;
+    case GRIB1_LTYPE_ALTITUDE:           zaxistype = ZAXIS_ALTITUDE;	           break;
     case GRIB1_LTYPE_SIGMA:
-    case GRIB1_LTYPE_SIGMA_LAYER:        { zaxistype = ZAXIS_SIGMA;	             break; }
+    case GRIB1_LTYPE_SIGMA_LAYER:        zaxistype = ZAXIS_SIGMA;	           break;
     case GRIB1_LTYPE_HYBRID:
-    case GRIB1_LTYPE_HYBRID_LAYER:       { zaxistype = ZAXIS_HYBRID;	             break; }
+    case GRIB1_LTYPE_HYBRID_LAYER:       zaxistype = ZAXIS_HYBRID;	           break;
     case GRIB1_LTYPE_LANDDEPTH:
-    case GRIB1_LTYPE_LANDDEPTH_LAYER:    { zaxistype = ZAXIS_DEPTH_BELOW_LAND;       break; }
-    case GRIB1_LTYPE_ISENTROPIC:         { zaxistype = ZAXIS_ISENTROPIC;             break; }
-    case GRIB1_LTYPE_SEADEPTH:           { zaxistype = ZAXIS_DEPTH_BELOW_SEA;        break; }
-    case GRIB1_LTYPE_LAKE_BOTTOM:        { zaxistype = ZAXIS_LAKE_BOTTOM;            break; }
-    case GRIB1_LTYPE_SEDIMENT_BOTTOM:    { zaxistype = ZAXIS_SEDIMENT_BOTTOM;        break; }
-    case GRIB1_LTYPE_SEDIMENT_BOTTOM_TA: { zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;     break; }
-    case GRIB1_LTYPE_SEDIMENT_BOTTOM_TW: { zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;     break; }
-    case GRIB1_LTYPE_MIX_LAYER:          { zaxistype = ZAXIS_MIX_LAYER;              break; }
+    case GRIB1_LTYPE_LANDDEPTH_LAYER:    zaxistype = ZAXIS_DEPTH_BELOW_LAND;       break;
+    case GRIB1_LTYPE_ISENTROPIC:         zaxistype = ZAXIS_ISENTROPIC;             break;
+    case GRIB1_LTYPE_SEADEPTH:           zaxistype = ZAXIS_DEPTH_BELOW_SEA;        break;
+    case GRIB1_LTYPE_LAKE_BOTTOM:        zaxistype = ZAXIS_LAKE_BOTTOM;            break;
+    case GRIB1_LTYPE_SEDIMENT_BOTTOM:    zaxistype = ZAXIS_SEDIMENT_BOTTOM;        break;
+    case GRIB1_LTYPE_SEDIMENT_BOTTOM_TA: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;     break;
+    case GRIB1_LTYPE_SEDIMENT_BOTTOM_TW: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;     break;
+    case GRIB1_LTYPE_MIX_LAYER:          zaxistype = ZAXIS_MIX_LAYER;              break;
     }
 
-  return (zaxistype);
+  return zaxistype;
 }
 
 
@@ -61,34 +55,34 @@ int grib2ltypeToZaxisType(int grib_ltype)
 
   switch ( grib_ltype )
     {
-    case GRIB2_LTYPE_SURFACE:            { zaxistype = ZAXIS_SURFACE;                break; }
-    case GRIB2_LTYPE_CLOUD_BASE:         { zaxistype = ZAXIS_CLOUD_BASE;             break; }
-    case GRIB2_LTYPE_CLOUD_TOP:          { zaxistype = ZAXIS_CLOUD_TOP;              break; }
-    case GRIB2_LTYPE_ISOTHERM0:          { zaxistype = ZAXIS_ISOTHERM_ZERO;          break; }
-    case GRIB2_LTYPE_TOA:                { zaxistype = ZAXIS_TOA;                    break; }
-    case GRIB2_LTYPE_SEA_BOTTOM:         { zaxistype = ZAXIS_SEA_BOTTOM;             break; }
-    case GRIB2_LTYPE_ATMOSPHERE:         { zaxistype = ZAXIS_ATMOSPHERE;             break; }
-    case GRIB2_LTYPE_MEANSEA:            { zaxistype = ZAXIS_MEANSEA;                break; }
-    case GRIB2_LTYPE_ISOBARIC:           { zaxistype = ZAXIS_PRESSURE;               break; }
-    case GRIB2_LTYPE_HEIGHT:             { zaxistype = ZAXIS_HEIGHT;                 break; }
-    case GRIB2_LTYPE_ALTITUDE:           { zaxistype = ZAXIS_ALTITUDE;               break; }
-    case GRIB2_LTYPE_SIGMA:              { zaxistype = ZAXIS_SIGMA;                  break; }
+    case GRIB2_LTYPE_SURFACE:            zaxistype = ZAXIS_SURFACE;                break;
+    case GRIB2_LTYPE_CLOUD_BASE:         zaxistype = ZAXIS_CLOUD_BASE;             break;
+    case GRIB2_LTYPE_CLOUD_TOP:          zaxistype = ZAXIS_CLOUD_TOP;              break;
+    case GRIB2_LTYPE_ISOTHERM0:          zaxistype = ZAXIS_ISOTHERM_ZERO;          break;
+    case GRIB2_LTYPE_TOA:                zaxistype = ZAXIS_TOA;                    break;
+    case GRIB2_LTYPE_SEA_BOTTOM:         zaxistype = ZAXIS_SEA_BOTTOM;             break;
+    case GRIB2_LTYPE_ATMOSPHERE:         zaxistype = ZAXIS_ATMOSPHERE;             break;
+    case GRIB2_LTYPE_MEANSEA:            zaxistype = ZAXIS_MEANSEA;                break;
+    case GRIB2_LTYPE_ISOBARIC:           zaxistype = ZAXIS_PRESSURE;               break;
+    case GRIB2_LTYPE_HEIGHT:             zaxistype = ZAXIS_HEIGHT;                 break;
+    case GRIB2_LTYPE_ALTITUDE:           zaxistype = ZAXIS_ALTITUDE;               break;
+    case GRIB2_LTYPE_SIGMA:              zaxistype = ZAXIS_SIGMA;                  break;
     case GRIB2_LTYPE_HYBRID:
- /* case GRIB2_LTYPE_HYBRID_LAYER: */    { zaxistype = ZAXIS_HYBRID;                 break; }
+ /* case GRIB2_LTYPE_HYBRID_LAYER: */    zaxistype = ZAXIS_HYBRID;                 break;
     case GRIB2_LTYPE_LANDDEPTH:
- /* case GRIB2_LTYPE_LANDDEPTH_LAYER: */ { zaxistype = ZAXIS_DEPTH_BELOW_LAND;       break; }
-    case GRIB2_LTYPE_ISENTROPIC:         { zaxistype = ZAXIS_ISENTROPIC;             break; }
-    case GRIB2_LTYPE_SNOW:               { zaxistype = ZAXIS_SNOW;                   break; }
-    case GRIB2_LTYPE_SEADEPTH:           { zaxistype = ZAXIS_DEPTH_BELOW_SEA;        break; }
-    case GRIB2_LTYPE_LAKE_BOTTOM:        { zaxistype = ZAXIS_LAKE_BOTTOM;            break; }
-    case GRIB2_LTYPE_SEDIMENT_BOTTOM:    { zaxistype = ZAXIS_SEDIMENT_BOTTOM;        break; }
-    case GRIB2_LTYPE_SEDIMENT_BOTTOM_TA: { zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;     break; }
-    case GRIB2_LTYPE_SEDIMENT_BOTTOM_TW: { zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;     break; }
-    case GRIB2_LTYPE_MIX_LAYER:          { zaxistype = ZAXIS_MIX_LAYER;              break; }
-    case GRIB2_LTYPE_REFERENCE:          { zaxistype = ZAXIS_REFERENCE;              break; }
+ /* case GRIB2_LTYPE_LANDDEPTH_LAYER: */ zaxistype = ZAXIS_DEPTH_BELOW_LAND;       break;
+    case GRIB2_LTYPE_ISENTROPIC:         zaxistype = ZAXIS_ISENTROPIC;             break;
+    case GRIB2_LTYPE_SNOW:               zaxistype = ZAXIS_SNOW;                   break;
+    case GRIB2_LTYPE_SEADEPTH:           zaxistype = ZAXIS_DEPTH_BELOW_SEA;        break;
+    case GRIB2_LTYPE_LAKE_BOTTOM:        zaxistype = ZAXIS_LAKE_BOTTOM;            break;
+    case GRIB2_LTYPE_SEDIMENT_BOTTOM:    zaxistype = ZAXIS_SEDIMENT_BOTTOM;        break;
+    case GRIB2_LTYPE_SEDIMENT_BOTTOM_TA: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;     break;
+    case GRIB2_LTYPE_SEDIMENT_BOTTOM_TW: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;     break;
+    case GRIB2_LTYPE_MIX_LAYER:          zaxistype = ZAXIS_MIX_LAYER;              break;
+    case GRIB2_LTYPE_REFERENCE:          zaxistype = ZAXIS_REFERENCE;              break;
     }
 
-  return (zaxistype);
+  return zaxistype;
 }
 
 
@@ -98,27 +92,27 @@ int zaxisTypeToGrib1ltype(int zaxistype)
 
   switch (zaxistype)
     {
-    case ZAXIS_SURFACE:               { grib_ltype = GRIB1_LTYPE_SURFACE;            break; }
-    case ZAXIS_MEANSEA:               { grib_ltype = GRIB1_LTYPE_MEANSEA;            break; }
-    case ZAXIS_HEIGHT:                { grib_ltype = GRIB1_LTYPE_HEIGHT;             break; }
-    case ZAXIS_ALTITUDE:              { grib_ltype = GRIB1_LTYPE_ALTITUDE;           break; }
-    case ZAXIS_SIGMA:                 { grib_ltype = GRIB1_LTYPE_SIGMA;              break; }
-    case ZAXIS_DEPTH_BELOW_SEA:       { grib_ltype = GRIB1_LTYPE_SEADEPTH;           break; }
-    case ZAXIS_ISENTROPIC:            { grib_ltype = GRIB1_LTYPE_ISENTROPIC;         break; }
-    case ZAXIS_CLOUD_BASE:            { grib_ltype = GRIB1_LTYPE_CLOUD_BASE;         break; }
-    case ZAXIS_CLOUD_TOP:             { grib_ltype = GRIB1_LTYPE_CLOUD_TOP;          break; }
-    case ZAXIS_ISOTHERM_ZERO:         { grib_ltype = GRIB1_LTYPE_ISOTHERM0;          break; }
-    case ZAXIS_TOA:                   { grib_ltype = GRIB1_LTYPE_TOA;                break; }
-    case ZAXIS_SEA_BOTTOM:            { grib_ltype = GRIB1_LTYPE_SEA_BOTTOM;         break; }
-    case ZAXIS_LAKE_BOTTOM:           { grib_ltype = GRIB1_LTYPE_LAKE_BOTTOM;        break; }
-    case ZAXIS_SEDIMENT_BOTTOM:       { grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM;    break; }
-    case ZAXIS_SEDIMENT_BOTTOM_TA:    { grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TA; break; }
-    case ZAXIS_SEDIMENT_BOTTOM_TW:    { grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TW; break; }
-    case ZAXIS_MIX_LAYER:             { grib_ltype = GRIB1_LTYPE_MIX_LAYER;          break; }
-    case ZAXIS_ATMOSPHERE:            { grib_ltype = GRIB1_LTYPE_ATMOSPHERE;         break; }
+    case ZAXIS_SURFACE:               grib_ltype = GRIB1_LTYPE_SURFACE;            break;
+    case ZAXIS_MEANSEA:               grib_ltype = GRIB1_LTYPE_MEANSEA;            break;
+    case ZAXIS_HEIGHT:                grib_ltype = GRIB1_LTYPE_HEIGHT;             break;
+    case ZAXIS_ALTITUDE:              grib_ltype = GRIB1_LTYPE_ALTITUDE;           break;
+    case ZAXIS_SIGMA:                 grib_ltype = GRIB1_LTYPE_SIGMA;              break;
+    case ZAXIS_DEPTH_BELOW_SEA:       grib_ltype = GRIB1_LTYPE_SEADEPTH;           break;
+    case ZAXIS_ISENTROPIC:            grib_ltype = GRIB1_LTYPE_ISENTROPIC;         break;
+    case ZAXIS_CLOUD_BASE:            grib_ltype = GRIB1_LTYPE_CLOUD_BASE;         break;
+    case ZAXIS_CLOUD_TOP:             grib_ltype = GRIB1_LTYPE_CLOUD_TOP;          break;
+    case ZAXIS_ISOTHERM_ZERO:         grib_ltype = GRIB1_LTYPE_ISOTHERM0;          break;
+    case ZAXIS_TOA:                   grib_ltype = GRIB1_LTYPE_TOA;                break;
+    case ZAXIS_SEA_BOTTOM:            grib_ltype = GRIB1_LTYPE_SEA_BOTTOM;         break;
+    case ZAXIS_LAKE_BOTTOM:           grib_ltype = GRIB1_LTYPE_LAKE_BOTTOM;        break;
+    case ZAXIS_SEDIMENT_BOTTOM:       grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM;    break;
+    case ZAXIS_SEDIMENT_BOTTOM_TA:    grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TA; break;
+    case ZAXIS_SEDIMENT_BOTTOM_TW:    grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TW; break;
+    case ZAXIS_MIX_LAYER:             grib_ltype = GRIB1_LTYPE_MIX_LAYER;          break;
+    case ZAXIS_ATMOSPHERE:            grib_ltype = GRIB1_LTYPE_ATMOSPHERE;         break;
     }
 
-  return (grib_ltype);
+  return grib_ltype;
 }
 
 
@@ -128,27 +122,27 @@ int zaxisTypeToGrib2ltype(int zaxistype)
 
   switch (zaxistype)
     {
-    case ZAXIS_SURFACE:               { grib_ltype = GRIB2_LTYPE_SURFACE;            break; }
-    case ZAXIS_MEANSEA:               { grib_ltype = GRIB2_LTYPE_MEANSEA;            break; }
-    case ZAXIS_HEIGHT:                { grib_ltype = GRIB2_LTYPE_HEIGHT;             break; }
-    case ZAXIS_ALTITUDE:              { grib_ltype = GRIB2_LTYPE_ALTITUDE;           break; }
-    case ZAXIS_SIGMA:                 { grib_ltype = GRIB2_LTYPE_SIGMA;              break; }
-    case ZAXIS_DEPTH_BELOW_SEA:       { grib_ltype = GRIB2_LTYPE_SEADEPTH;           break; }
-    case ZAXIS_ISENTROPIC:            { grib_ltype = GRIB2_LTYPE_ISENTROPIC;         break; }
-    case ZAXIS_CLOUD_BASE:            { grib_ltype = GRIB2_LTYPE_CLOUD_BASE;         break; }
-    case ZAXIS_CLOUD_TOP:             { grib_ltype = GRIB2_LTYPE_CLOUD_TOP;          break; }
-    case ZAXIS_ISOTHERM_ZERO:         { grib_ltype = GRIB2_LTYPE_ISOTHERM0;          break; }
-    case ZAXIS_TOA:                   { grib_ltype = GRIB2_LTYPE_TOA;                break; }
-    case ZAXIS_SEA_BOTTOM:            { grib_ltype = GRIB2_LTYPE_SEA_BOTTOM;         break; }
-    case ZAXIS_LAKE_BOTTOM:           { grib_ltype = GRIB2_LTYPE_LAKE_BOTTOM;        break; }
-    case ZAXIS_SEDIMENT_BOTTOM:       { grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM;    break; }
-    case ZAXIS_SEDIMENT_BOTTOM_TA:    { grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TA; break; }
-    case ZAXIS_SEDIMENT_BOTTOM_TW:    { grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TW; break; }
-    case ZAXIS_MIX_LAYER:             { grib_ltype = GRIB2_LTYPE_MIX_LAYER;          break; }
-    case ZAXIS_ATMOSPHERE:            { grib_ltype = GRIB2_LTYPE_ATMOSPHERE;         break; }
+    case ZAXIS_SURFACE:               grib_ltype = GRIB2_LTYPE_SURFACE;            break;
+    case ZAXIS_MEANSEA:               grib_ltype = GRIB2_LTYPE_MEANSEA;            break;
+    case ZAXIS_HEIGHT:                grib_ltype = GRIB2_LTYPE_HEIGHT;             break;
+    case ZAXIS_ALTITUDE:              grib_ltype = GRIB2_LTYPE_ALTITUDE;           break;
+    case ZAXIS_SIGMA:                 grib_ltype = GRIB2_LTYPE_SIGMA;              break;
+    case ZAXIS_DEPTH_BELOW_SEA:       grib_ltype = GRIB2_LTYPE_SEADEPTH;           break;
+    case ZAXIS_ISENTROPIC:            grib_ltype = GRIB2_LTYPE_ISENTROPIC;         break;
+    case ZAXIS_CLOUD_BASE:            grib_ltype = GRIB2_LTYPE_CLOUD_BASE;         break;
+    case ZAXIS_CLOUD_TOP:             grib_ltype = GRIB2_LTYPE_CLOUD_TOP;          break;
+    case ZAXIS_ISOTHERM_ZERO:         grib_ltype = GRIB2_LTYPE_ISOTHERM0;          break;
+    case ZAXIS_TOA:                   grib_ltype = GRIB2_LTYPE_TOA;                break;
+    case ZAXIS_SEA_BOTTOM:            grib_ltype = GRIB2_LTYPE_SEA_BOTTOM;         break;
+    case ZAXIS_LAKE_BOTTOM:           grib_ltype = GRIB2_LTYPE_LAKE_BOTTOM;        break;
+    case ZAXIS_SEDIMENT_BOTTOM:       grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM;    break;
+    case ZAXIS_SEDIMENT_BOTTOM_TA:    grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TA; break;
+    case ZAXIS_SEDIMENT_BOTTOM_TW:    grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TW; break;
+    case ZAXIS_MIX_LAYER:             grib_ltype = GRIB2_LTYPE_MIX_LAYER;          break;
+    case ZAXIS_ATMOSPHERE:            grib_ltype = GRIB2_LTYPE_ATMOSPHERE;         break;
     }
 
-  return (grib_ltype);
+  return grib_ltype;
 }
 
 
@@ -169,7 +163,7 @@ int grbBitsPerValue(int datatype)
 	bitsPerValue = 16;
     }
 
-  return (bitsPerValue);
+  return bitsPerValue;
 }
 
 
@@ -190,122 +184,6 @@ void grbDefRecord(stream_t * streamptr)
 }
 
 static
-int grbDecode(int filetype, unsigned char *gribbuffer, int gribsize, double *data, int gridsize,
-	      int unreduced, int *nmiss, double missval, int vlistID, int varID)
-{
-  int status = 0;
-
-#if  defined  (HAVE_LIBCGRIBEX)
-  if ( filetype == FILETYPE_GRB )
-    {
-#if  defined  (HAVE_LIBGRIB_API)
-      extern int cdiNAdditionalGRIBKeys;
-      if ( cdiNAdditionalGRIBKeys > 0 )
-	Error("CGRIBEX decode does not support reading of additional GRIB keys!");
-#endif
-      status = cgribexDecode(gribbuffer, gribsize, data, gridsize, unreduced, nmiss, missval);
-    }
-  else
-#endif
-#ifdef HAVE_LIBGRIB_API
-    status = gribapiDecode(gribbuffer, gribsize, data, gridsize, unreduced, nmiss, missval, vlistID, varID);
-#else
-    {
-      (void)vlistID; (void)varID;
-      Error("GRIB_API support not compiled in!");
-    }
-#endif
-
-  return (status);
-}
-
-
-static int grbUnzipRecord(unsigned char *gribbuffer, size_t *gribsize)
-{
-  int zip = 0;
-  int izip;
-  size_t igribsize;
-  size_t ogribsize;
-  long unzipsize;
-
-  igribsize = *gribsize;
-  ogribsize = *gribsize;
-
-  if ( (izip = gribGetZip((long)igribsize, gribbuffer, &unzipsize)) > 0 )
-    {
-      zip = izip;
-      if ( izip == 128 ) /* szip */
-	{
-	  unsigned char *itmpbuffer = NULL;
-	  size_t itmpbuffersize = 0;
-
-	  if ( unzipsize < (long) igribsize )
-	    {
-	      fprintf(stderr, "Decompressed size smaller than compressed size (in %ld; out %ld)!\n", (long)igribsize, unzipsize);
-	      return (0);
-	    }
-
-	  if ( itmpbuffersize < igribsize )
-	    {
-	      itmpbuffersize = igribsize;
-	      itmpbuffer = (unsigned char *) Realloc(itmpbuffer, itmpbuffersize);
-	    }
-
-	  memcpy(itmpbuffer, gribbuffer, itmpbuffersize);
-
-	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
-
-	  ogribsize = (size_t)gribUnzip(gribbuffer, unzipsize, itmpbuffer, (long)igribsize);
-
-	  Free(itmpbuffer);
-
-	  if ( ogribsize <= 0 ) Error("Decompression problem!");
-	}
-      else
-	{
-	  Error("Decompression for %d not implemented!", izip);
-	}
-    }
-
-  *gribsize = ogribsize;
-
-  return zip;
-}
-
-
-void grbReadRecord(stream_t * streamptr, double *data, int *nmiss)
-{
-  int filetype = streamptr->filetype;
-
-  unsigned char *gribbuffer = (unsigned char *) streamptr->record->buffer;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-  int tsID    = streamptr->curTsID;
-  int vrecID  = streamptr->tsteps[tsID].curRecID;
-  int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-  off_t recpos  = streamptr->tsteps[tsID].records[recID].position;
-  size_t recsize = streamptr->tsteps[tsID].records[recID].size;
-  int varID   = streamptr->tsteps[tsID].records[recID].varID;
-
-  int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
-
-  streamptr->numvals += gridsize;
-
-  fileSetPos(fileID, recpos, SEEK_SET);
-
-  if (fileRead(fileID, gribbuffer, recsize) != recsize)
-    Error("Failed to read GRIB record");
-
-  double missval = vlistInqVarMissval(vlistID, varID);
-
-  streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
-
-  grbDecode(filetype, gribbuffer, (int)recsize, data, gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
-}
-
-static
 int grbScanTimestep1(stream_t * streamptr)
 {
   int status = CDI_EUFTYPE;
@@ -323,7 +201,7 @@ int grbScanTimestep1(stream_t * streamptr)
     status = gribapiScanTimestep1(streamptr);
 #endif
 
-  return (status);
+  return status;
 }
 
 static
@@ -346,7 +224,7 @@ int grbScanTimestep2(stream_t * streamptr)
     status = gribapiScanTimestep2(streamptr);
 #endif
 
-  return (status);
+  return status;
 }
 
 static
@@ -370,7 +248,7 @@ int grbScanTimestep(stream_t * streamptr)
     Error("Sufficient GRIB support unavailable!");
 #endif
 
-  return (status);
+  return status;
 }
 
 
@@ -390,7 +268,7 @@ int grbInqContents(stream_t * streamptr)
 
   fileSetPos(fileID, 0, SEEK_SET);
 
-  return (status);
+  return status;
 }
 #endif
 
@@ -425,334 +303,7 @@ int grbInqTimestep(stream_t * streamptr, int tsID)
       nrecs = streamptr->tsteps[tsID].nrecs;
     }
 
-  return (nrecs);
-}
-
-
-void grbReadVarDP(stream_t * streamptr, int varID, double *data, int *nmiss)
-{
-  int filetype = streamptr->filetype;
-
-  unsigned char *gribbuffer = (unsigned char *) streamptr->record->buffer;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-  int tsID    = streamptr->curTsID;
-
-  int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
-
-  off_t currentfilepos = fileGetPos(fileID);
-
-
-  int isub     = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
-  int nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
-  *nmiss = 0;
-  for (int levelID = 0; levelID < nlevs; levelID++ )
-    {
-      int    recID   = streamptr->vars[varID].recordTable[isub].recordID[levelID];
-      off_t  recpos  = streamptr->tsteps[tsID].records[recID].position;
-      size_t recsize = streamptr->tsteps[tsID].records[recID].size;
-
-      fileSetPos(fileID, recpos, SEEK_SET);
-
-      fileRead(fileID, gribbuffer, recsize);
-
-      double missval = vlistInqVarMissval(vlistID, varID);
-
-      int imiss;
-
-      streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
-
-      grbDecode(filetype, gribbuffer, (int)recsize, &data[levelID*gridsize], gridsize,
-                streamptr->unreduced, &imiss, missval, vlistID, varID);
-
-      *nmiss += imiss;
-    }
-
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
-}
-
-
-void grbReadVarSliceDP(stream_t * streamptr, int varID, int levelID, double *data, int *nmiss)
-{
-  int filetype = streamptr->filetype;
-
-  unsigned char *gribbuffer = (unsigned char *) streamptr->record->buffer;
-
-  int vlistID = streamptr->vlistID;
-  int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
-  int tsID = streamptr->curTsID;
-
-  if ( CDI_Debug )
-    Message("gridID = %d gridsize = %d", gridID, gridsize);
-
-  int fileID = streamptr->fileID;
-
-  off_t currentfilepos = fileGetPos(fileID);
-
-  int    isub    = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
-
-
-  int    recID   = streamptr->vars[varID].recordTable[isub].recordID[levelID];
-  off_t  recpos  = streamptr->tsteps[tsID].records[recID].position;
-  size_t recsize = streamptr->tsteps[tsID].records[recID].size;
-
-  if ( recsize == 0 )
-    Error("Internal problem! Recordsize is zero for record %d at timestep %d",
-	  recID+1, tsID+1);
-
-  fileSetPos(fileID, recpos, SEEK_SET);
-
-  fileRead(fileID, gribbuffer, recsize);
-
-  double missval = vlistInqVarMissval(vlistID, varID);
-
-  streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
-
-  grbDecode(filetype, gribbuffer, (int)recsize, data, gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
-
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
-}
-
-static
-size_t grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
-		 int date, int time, int tsteptype, int numavg,
-		 size_t datasize, const double *data, int nmiss, unsigned char **gribbuffer,
-		 int comptype, void *gribContainer)
-{
-  size_t nbytes = 0;
-
-#if  defined  (HAVE_LIBCGRIBEX)
-  if ( filetype == FILETYPE_GRB )
-    {
-      size_t gribbuffersize = datasize*4+3000;
-      *gribbuffer = (unsigned char *) Malloc(gribbuffersize);
-
-      nbytes = cgribexEncode(memtype, varID, levelID, vlistID, gridID, zaxisID,
-			     date, time, tsteptype, numavg,
-			     (long)datasize, data, nmiss, *gribbuffer, gribbuffersize);
-    }
-  else
-#endif
-#ifdef HAVE_LIBGRIB_API
-    {
-      if ( memtype == MEMTYPE_FLOAT ) Error("gribapiEncode() not implemented for memtype float!");
-
-      size_t gribbuffersize;
-      nbytes = gribapiEncode(varID, levelID, vlistID, gridID, zaxisID,
-			     date, time, tsteptype, numavg,
-			     (long)datasize, data, nmiss, gribbuffer, &gribbuffersize,
-			     comptype, gribContainer);
-    }
-#else
-    Error("GRIB_API support not compiled in!");
-    (void)gribContainer;
-    (void)comptype;
-#endif
-
-
-  return (nbytes);
-}
-
-static
-size_t grbSzip(int filetype, unsigned char *gribbuffer, size_t gribbuffersize)
-{
-  size_t nbytes = 0;
-  unsigned char *buffer;
-  size_t buffersize;
-  static int lszip_warn = 1;
-
-  buffersize = gribbuffersize + 1000; /* compressed record can be greater than source record */
-  buffer = (unsigned char *) Malloc(buffersize);
-
-  /*  memcpy(buffer, gribbuffer, gribbuffersize); */
-
-  if ( filetype == FILETYPE_GRB )
-    {
-      nbytes = (size_t)gribZip(gribbuffer, (long) gribbuffersize, buffer, (long) buffersize);
-    }
-  else
-    {
-      if ( lszip_warn ) Warning("Szip compression of GRIB2 records not implemented!");
-      lszip_warn = 0;
-      nbytes = gribbuffersize;
-    }
-
-  Free(buffer);
-
-  return (nbytes);
-}
-
-
-void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
-{
-  size_t nwrite;
-  int fileID;
-  int gridID;
-  int zaxisID;
-  unsigned char *gribbuffer = NULL;
-  int tsID;
-  int vlistID;
-  int date, time;
-  int tsteptype;
-  int numavg = 0;
-  size_t nbytes;
-  int filetype;
-  void *gc = NULL;
-
-  filetype  = streamptr->filetype;
-  fileID    = streamptr->fileID;
-  vlistID   = streamptr->vlistID;
-  gridID    = vlistInqVarGrid(vlistID, varID);
-  zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  tsteptype = vlistInqVarTsteptype(vlistID, varID);
-
-  int comptype  = streamptr->comptype;
-
-  tsID      = streamptr->curTsID;
-  date      = streamptr->tsteps[tsID].taxis.vdate;
-  time      = streamptr->tsteps[tsID].taxis.vtime;
-  if ( vlistInqVarTimave(vlistID, varID) )
-    numavg = streamptr->tsteps[tsID].taxis.numavg;
-
-  if ( CDI_Debug )
-    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
-
-  size_t datasize = (size_t)gridInqSize(gridID);
-  /*
-  gribbuffersize = datasize*4+3000;
-  gribbuffer = (unsigned char *) Malloc(gribbuffersize);
-  */
-#if  defined  (HAVE_LIBCGRIBEX)
-  if ( filetype == FILETYPE_GRB )
-    {
-    }
-  else
-#endif
-    {
-#if defined (GRIBCONTAINER2D)
-      gribContainer_t **gribContainers =  (gribContainer_t **) streamptr->gribContainers;
-      gc = (void *) &gribContainers[varID][levelID];
-#else
-      gribContainer_t *gribContainers =  (gribContainer_t *) streamptr->gribContainers;
-      gc = (void *) &gribContainers[varID];
-#endif
-    }
-
-  if ( comptype != COMPRESS_JPEG && comptype != COMPRESS_SZIP ) comptype = COMPRESS_NONE;
-
-  if ( filetype == FILETYPE_GRB && comptype == COMPRESS_JPEG )
-    {
-      static int ljpeg_warn = 1;
-      if ( ljpeg_warn ) Warning("JPEG compression of GRIB1 records not available!");
-      ljpeg_warn = 0;
-    }
-
-  nbytes = grbEncode(filetype, memtype, varID, levelID, vlistID, gridID, zaxisID, date, time, tsteptype, numavg,
-		     datasize, (const double*) data, nmiss, &gribbuffer, comptype, gc);
-
-  if ( filetype == FILETYPE_GRB && streamptr->comptype == COMPRESS_SZIP )
-    nbytes = grbSzip(filetype, gribbuffer, nbytes);
-
-  {
-    size_t (*myFileWrite)(int fileID, const void *restrict buffer,
-                          size_t len, int tsID)
-      = (size_t (*)(int, const void *restrict, size_t, int))
-      namespaceSwitchGet(NSSWITCH_FILE_WRITE).func;
-    nwrite = myFileWrite(fileID, gribbuffer, nbytes, tsID);
-  }
-
-  if ( nwrite != nbytes )
-    {
-      perror(__func__);
-      Error("Failed to write GRIB slice!");
-    }
-
-  if ( gribbuffer ) Free(gribbuffer);
-}
-
-
-void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
-{
-  int vlistID, gridID, zaxisID, levelID, nlevs;
-  int gridsize;
-
-  vlistID  = streamptr->vlistID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  nlevs    = zaxisInqSize(zaxisID);
-
-  for ( levelID = 0; levelID < nlevs; levelID++ )
-    {
-      if ( memtype == MEMTYPE_FLOAT )
-        grb_write_var_slice(streamptr, varID, levelID, memtype, ((float*)data)+levelID*gridsize, nmiss);
-      else
-        grb_write_var_slice(streamptr, varID, levelID, memtype, ((double*)data)+levelID*gridsize, nmiss);
-    }
-}
-
-
-void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
-{
-  int filetype = streamptr1->filetype;
-
-  int fileID1 = streamptr1->fileID;
-  int fileID2 = streamptr2->fileID;
-
-  int tsID    = streamptr1->curTsID;
-  int vrecID  = streamptr1->tsteps[tsID].curRecID;
-  int recID   = streamptr1->tsteps[tsID].recIDs[vrecID];
-  off_t recpos  = streamptr1->tsteps[tsID].records[recID].position;
-  size_t recsize = streamptr1->tsteps[tsID].records[recID].size;
-
-  fileSetPos(fileID1, recpos, SEEK_SET);
-
-  /* round up recsize to next multiple of 8 */
-  size_t gribbuffersize = ((recsize + 7U) & ~7U);
-
-  unsigned char *gribbuffer = (unsigned char *) Malloc(gribbuffersize);
-
-  if (fileRead(fileID1, gribbuffer, recsize) != recsize)
-    Error("Could not read GRIB record for copying!");
-
-  size_t nbytes = recsize;
-
-  if ( filetype == FILETYPE_GRB )
-    {
-      long unzipsize;
-      int izip = gribGetZip((long)recsize, gribbuffer, &unzipsize);
-
-      if ( izip == 0 )
-        if ( streamptr2->comptype == COMPRESS_SZIP )
-          nbytes = grbSzip(filetype, gribbuffer, nbytes);
-    }
-
-  while ( nbytes & 7 ) gribbuffer[nbytes++] = 0;
-
-  size_t nwrite = fileWrite(fileID2, gribbuffer, nbytes);
-  if ( nwrite != nbytes )
-    {
-      perror(__func__);
-      Error("Could not write record for copying!");
-    }
-
-  Free(gribbuffer);
-}
-
-
-void grb_write_record(stream_t * streamptr, int memtype, const void *data, int nmiss)
-{
-  int varID, levelID;
-
-  varID   = streamptr->record->varID;
-  levelID = streamptr->record->levelID;
-
-  grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+  return nrecs;
 }
 
 
@@ -760,8 +311,6 @@ void streamInqGRIBinfo(int streamID, int *intnum, float *fltnum, off_t *bignum)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  stream_check_ptr(__func__, streamptr);
-
   int filetype = streamptr->filetype;
 
   if ( filetype == FILETYPE_GRB )
diff --git a/libcdi/src/stream_grb.h b/libcdi/src/stream_grb.h
index 13b802c..a2f334f 100644
--- a/libcdi/src/stream_grb.h
+++ b/libcdi/src/stream_grb.h
@@ -3,19 +3,19 @@
 
 int   grbBitsPerValue(int datatype);
 
-int   grbInqContents(stream_t * streamptr);
-int   grbInqTimestep(stream_t * streamptr, int tsID);
+int   grbInqContents(stream_t *streamptr);
+int   grbInqTimestep(stream_t *streamptr, int tsID);
 
-int   grbInqRecord(stream_t * streamptr, int *varID, int *levelID);
-void  grbDefRecord(stream_t * streamptr);
-void  grbReadRecord(stream_t * streamptr, double *data, int *nmiss);
-void  grb_write_record(stream_t * streamptr, int memtype, const void *data, int nmiss);
-void  grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1);
+int   grbInqRecord(stream_t *streamptr, int *varID, int *levelID);
+void  grbDefRecord(stream_t *streamptr);
+void  grb_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss);
+void  grb_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss);
+void  grbCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
 
-void  grbReadVarDP(stream_t * streamptr, int varID, double *data, int *nmiss);
-void  grb_write_var(stream_t * streamptr, int varID, int memtype, const void *data, int nmiss);
+void  grb_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss);
+void  grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss);
 
-void  grbReadVarSliceDP(stream_t * streamptr, int varID, int levelID, double *data, int *nmiss);
+void  grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss);
 void  grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss);
 
 int   grib1ltypeToZaxisType(int grib_ltype);
diff --git a/libcdi/src/stream_gribapi.c b/libcdi/src/stream_gribapi.c
index 6f29a05..737bc88 100644
--- a/libcdi/src/stream_gribapi.c
+++ b/libcdi/src/stream_gribapi.c
@@ -2,6 +2,7 @@
 #  include "config.h"
 #endif
 
+#if  defined  (HAVE_LIBGRIB_API)
 #include <limits.h>
 #include <stdio.h>
 
@@ -19,18 +20,14 @@
 #include "subtype.h"
 
 
-#if  defined  (HAVE_LIBGRIB_API)
 #  include "cgribex.h"      /* gribGetSize, gribRead, gribGetZip, GRIB1_LTYPE_99 */
 #  include "gribapi.h"
 
 #  include <grib_api.h>
-#endif
 
 extern int cdiInventoryMode;
 
-#if  defined  (HAVE_LIBGRIB_API)
-static const var_tile_t dummy_tiles = { -1, -1, -1, -1, -1, -1 };
-#endif
+static const var_tile_t dummy_tiles = { 0, -1, -1, -1, -1, -1 };
 
 typedef struct {
   int param;
@@ -45,7 +42,6 @@ typedef struct {
 } compvar2_t;
 
 
-#if  defined  (HAVE_LIBGRIB_API)
 static
 int gribapiGetZaxisType(long editionNumber, int grib_ltype)
 {
@@ -320,7 +316,7 @@ int calcLevel(int level_sf, long factor, long level)
 }
 
 static
-void grib2GetLevel(grib_handle *gh, int *leveltype1, int *leveltype2, int *lbounds, int *level1, 
+void grib2GetLevel(grib_handle *gh, int *leveltype1, int *leveltype2, int *lbounds, int *level1,
                    int *level2, int *level_sf, int *level_unit)
 {
   int status;
@@ -421,20 +417,14 @@ void gribapiGetString(grib_handle *gh, const char *key, char *string, size_t len
   else if ( length == 2 && memcmp(string, "~", length)       == 0 ) string[0] = 0;
 }
 
-#if  defined  (HAVE_LIBGRIB_API)
 static
 void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
                       size_t recsize, off_t position, int datatype, int comptype, const char *varname,
                       int leveltype1, int leveltype2, int lbounds, int level1, int level2, int level_sf, int level_unit,
                       const var_tile_t *tiles, int lread_additional_keys)
 {
-  int varID;
   int levelID = 0;
-  grid_t grid;
-  long lpar;
-  int status;
   char stdname[CDI_MAX_NAME], longname[CDI_MAX_NAME], units[CDI_MAX_NAME];
-  size_t vlen;
   long ens_index = 0, ens_count = 0, ens_forecast_type = 0;
 
   int vlistID = streamptr->vlistID;
@@ -448,15 +438,14 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
 
   // fprintf(stderr, "param %d %d %d %d\n", param, level1, level2, leveltype1);
 
-  (*record).size      = recsize;
-  (*record).position  = position;
-  (*record).param     = param;
-  (*record).ilevel    = level1;
-  (*record).ilevel2   = level2;
-  (*record).ltype     = leveltype1;
-  (*record).tsteptype = tsteptype;
-  if ( tiles ) (*record).tiles = *tiles;
-  else         (*record).tiles = dummy_tiles;
+  record->size      = recsize;
+  record->position  = position;
+  record->param     = param;
+  record->ilevel    = level1;
+  record->ilevel2   = level2;
+  record->ltype     = leveltype1;
+  record->tsteptype = (short)tsteptype;
+  record->tiles = tiles ? *tiles : dummy_tiles;
 
   //FIXME: This may leave the variable name unterminated (which is the behavior that I found in the code).
   //       I don't know precisely how this field is used, so I did not change this behavior to avoid regressions,
@@ -470,9 +459,12 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
   //       I. e. kick the fixed size array and allocate enough space, whatever that may be.
   strncpy(record->varname, varname, sizeof(record->varname));
 
-  gribapiGetGrid(gh, &grid);
+  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
+  gribapiGetGrid(gh, grid);
 
-  int gridID = varDefGrid(vlistID, &grid, 0);
+  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  int gridID = gridAdded.Id;
+  if (!gridAdded.isNew) Free(grid);
 
   int zaxistype = gribapiGetZaxisType(gribEditionNumber(gh), leveltype1);
 
@@ -481,17 +473,14 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
     case ZAXIS_HYBRID:
     case ZAXIS_HYBRID_HALF:
       {
-        size_t vctsize;
-        size_t dummy;
-        double *vctptr;
-
+        long lpar;
         GRIB_CHECK(grib_get_long(gh, "NV", &lpar), 0);
         /* FIXME: assert(lpar >= 0) */
-        vctsize = (size_t)lpar;
+        size_t vctsize = (size_t)lpar;
         if ( vctsize > 0 )
           {
-            vctptr = (double *) Malloc(vctsize*sizeof(double));
-            dummy = vctsize;
+            double *vctptr = (double *) Malloc(vctsize*sizeof(double));
+            size_t dummy = vctsize;
             GRIB_CHECK(grib_get_double_array(gh, "pv", vctptr, &dummy), 0);
             varDefVCT(vctsize, vctptr);
             Free(vctptr);
@@ -501,22 +490,20 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
     case ZAXIS_REFERENCE:
       {
         unsigned char uuid[CDI_UUID_SIZE];
-        long ltmp;
-        long nhlev, nvgrid;
-
+        long lpar;
         GRIB_CHECK(grib_get_long(gh, "NV", &lpar), 0);
         if ( lpar != 6 )
           {
             fprintf(stderr, "Warning ...\n");
           }
-        GRIB_CHECK(grib_get_long(gh, "nlev", &ltmp), 0);
-        nhlev = ltmp;
-        GRIB_CHECK(grib_get_long(gh, "numberOfVGridUsed", &ltmp), 0);
-        nvgrid = ltmp;
+        GRIB_CHECK(grib_get_long(gh, "nlev", &lpar), 0);
+        int nhlev = (int)lpar;
+        GRIB_CHECK(grib_get_long(gh, "numberOfVGridUsed", &lpar), 0);
+        int nvgrid = (int)lpar;
         size_t len = (size_t)CDI_UUID_SIZE;
         memset(uuid, 0, CDI_UUID_SIZE);
         GRIB_CHECK(grib_get_bytes(gh, "uuidOfVGrid", uuid, &len), 0);
-        varDefZAxisReference((int) nhlev, (int) nvgrid, uuid);
+        varDefZAxisReference(nhlev, nvgrid, uuid);
         break;
       }
     }
@@ -530,22 +517,19 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
 
   if ( varname[0] != 0 )
     {
-      vlen = CDI_MAX_NAME;
+      size_t vlen = CDI_MAX_NAME;
       gribapiGetString(gh, "name", longname, vlen);
       vlen = CDI_MAX_NAME;
       gribapiGetString(gh, "units", units, vlen);
-
-      {
-        vlen = CDI_MAX_NAME;
-        status = grib_get_string(gh, "cfName", stdname, &vlen);
-        if ( status != 0 || vlen <= 1 ) stdname[0] = 0;
-        else if ( strncmp(stdname, "unknown", 7) == 0 ) stdname[0] = 0;
-      }
+      vlen = CDI_MAX_NAME;
+      int status = grib_get_string(gh, "cfName", stdname, &vlen);
+      if ( status != 0 || vlen <= 1 || strncmp(stdname, "unknown", 7) == 0 )
+        stdname[0] = 0;
     }
   // fprintf(stderr, "param %d name %s %s %s\n", param, name, longname, units);
 
   /* add the previously read record data to the (intermediate) list of records */
-  int tile_index = -1;
+  int tile_index = 0, varID;
   varAddRecord(recID, param, gridID, zaxistype, lbounds, level1, level2, level_sf, level_unit,
 	       datatype, &varID, &levelID, tsteptype, numavg, leveltype1, leveltype2,
 	       varname, stdname, longname, units, tiles, &tile_index);
@@ -559,8 +543,7 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
     Get the ensemble Info from the grib-2 Tables and update the intermediate datastructure.
     Further update to the "vlist" is handled in the same way as for GRIB-1 by "cdi_generate_vars"
   */
-  status = grib_get_long(gh, "typeOfEnsembleForecast", &ens_forecast_type );
-  if ( status == 0 )
+  if ( grib_get_long(gh, "typeOfEnsembleForecast", &ens_forecast_type) == 0 )
     {
       GRIB_CHECK(grib_get_long(gh, "numberOfForecastsInEnsemble", &ens_count ), 0);
       GRIB_CHECK(grib_get_long(gh, "perturbationNumber", &ens_index ), 0);
@@ -570,13 +553,11 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
     varDefEnsembleInfo(varID, (int)ens_index, (int)ens_count, (int)ens_forecast_type);
 
   long typeOfGeneratingProcess = 0;
-  status = grib_get_long(gh, "typeOfGeneratingProcess", &typeOfGeneratingProcess);
-  if ( status == 0 )
+  if ( grib_get_long(gh, "typeOfGeneratingProcess", &typeOfGeneratingProcess) == 0 )
     varDefTypeOfGeneratingProcess(varID, (int) typeOfGeneratingProcess);
 
   long productDefinitionTemplate = 0;
-  status = grib_get_long(gh, "productDefinitionTemplateNumber", &productDefinitionTemplate);
-  if ( status == 0 )
+  if ( grib_get_long(gh, "productDefinitionTemplateNumber", &productDefinitionTemplate) == 0 )
     varDefProductDefinitionTemplate(varID, (int) productDefinitionTemplate);
 
   int    i;
@@ -609,8 +590,7 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
     {
       int modelID;
       long processID;
-      status = grib_get_long(gh, "generatingProcessIdentifier", &processID);
-      if ( status == 0 )
+      if ( grib_get_long(gh, "generatingProcessIdentifier", &processID) == 0 )
 	{
           /* FIXME: assert(processID >= INT_MIN && processID <= INT_MAX) */
 	  modelID = modelInq(varInqInst(varID), (int)processID, NULL);
@@ -646,7 +626,6 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
     Message("varID = %d  param = %d  zaxistype = %d  gridID = %d  levelID = %d",
 	    varID, param, zaxistype, gridID, levelID);
 }
-#endif
 
 static compvar2_t gribapiVarSet(int param, int level1, int level2, int leveltype, 
                                 int tsteptype, char *name, var_tile_t tiles_data)
@@ -667,9 +646,7 @@ static compvar2_t gribapiVarSet(int param, int level1, int level2, int leveltype
 
   return (compVar);
 }
-#endif
 
-#ifdef HAVE_LIBGRIB_API
 static
 int gribapiVarCompare(compvar2_t compVar, record_t record, int flag)
 {
@@ -689,25 +666,25 @@ int gribapiVarCompare(compvar2_t compVar, record_t record, int flag)
 
   compVar0.tiles = record.tiles;
 
-  int rstatus = memcmp(&compVar0, &compVar, sizeof(compvar2_t));
-
-  return (rstatus);
+  return memcmp(&compVar0, &compVar, sizeof(compvar2_t));
 }
 
-static void ensureBufferSize(size_t requiredSize, size_t* curSize, unsigned char **buffer) {
+static
+void ensureBufferSize(size_t requiredSize, size_t *curSize, void **buffer)
+{
   if ( *curSize < requiredSize )
     {
       *curSize = requiredSize;
-      *buffer = (unsigned char *) Realloc(*buffer, *curSize);
+      *buffer = Realloc(*buffer, *curSize);
     }
 }
 
 static
-grib_handle* gribapiGetDiskRepresentation(size_t recsize, size_t* buffersize, unsigned char** gribbuffer, int* outDatatype, int* outCompressionType, long* outUnzipsize)
+grib_handle *gribapiGetDiskRepresentation(size_t recsize, size_t *buffersize, void **gribbuffer, int *outDatatype, int *outCompressionType, long *outUnzipsize)
 {
   int lieee = FALSE;
 
-  grib_handle* gh = grib_handle_new_from_message(NULL, (void *) *gribbuffer, recsize);
+  grib_handle *gh = grib_handle_new_from_message(NULL, *gribbuffer, recsize);
   if(gribEditionNumber(gh) > 1)
     {
       size_t len = 256;
@@ -752,9 +729,7 @@ grib_handle* gribapiGetDiskRepresentation(size_t recsize, size_t* buffersize, un
     }
   return gh;
 }
-#endif
 
-#if  defined  (HAVE_LIBGRIB_API)
 typedef enum { CHECKTIME_OK, CHECKTIME_SKIP, CHECKTIME_STOP, CHECKTIME_INCONSISTENT } checkTimeResult;
 static checkTimeResult checkTime(stream_t* streamptr, compvar2_t compVar, const DateTime* verificationTime, const DateTime* expectedVTime) {
   // First determine whether the current record exists already.
@@ -782,7 +757,6 @@ static checkTimeResult checkTime(stream_t* streamptr, compvar2_t compVar, const
 
   return CHECKTIME_OK;
 }
-#endif
 
 #define gribWarning(text, nrecs, timestep, varname, param, level1, level2) do \
   { \
@@ -792,11 +766,10 @@ static checkTimeResult checkTime(stream_t* streamptr, compvar2_t compVar, const
   } \
 while(0)
 
-#if  defined  (HAVE_LIBGRIB_API)
 int gribapiScanTimestep1(stream_t * streamptr)
 {
   off_t recpos = 0;
-  unsigned char *gribbuffer = NULL;
+  void *gribbuffer = NULL;
   size_t buffersize = 0;
   DateTime datetime0 = { .date = 10101, .time = 0 };
   int nrecs_scanned = 0;        //Only used for debug output.
@@ -993,10 +966,8 @@ int gribapiScanTimestep1(stream_t * streamptr)
 
   return (0);
 }
-#endif
 
 
-#ifdef HAVE_LIBGRIB_API
 int gribapiScanTimestep2(stream_t * streamptr)
 {
   int rstatus = 0;
@@ -1013,7 +984,7 @@ int gribapiScanTimestep2(stream_t * streamptr)
   int vlistID = streamptr->vlistID;
   int taxisID = vlistInqTaxis(vlistID);
 
-  unsigned char *gribbuffer = (unsigned char *) streamptr->record->buffer;
+  void *gribbuffer = streamptr->record->buffer;
   size_t buffersize = streamptr->record->buffersize;
 
   int tsID = streamptr->rtsteps;
@@ -1062,7 +1033,7 @@ int gribapiScanTimestep2(stream_t * streamptr)
         ensureBufferSize((size_t)unzipsize + 100, &buffersize, &gribbuffer);
 
       nrecs_scanned++;
-      gh = grib_handle_new_from_message(NULL, (void *) gribbuffer, recsize);
+      gh = grib_handle_new_from_message(NULL, gribbuffer, recsize);
       GRIB_CHECK(my_grib_set_double(gh, "missingValue", cdiDefaultMissval), 0);
 
       int param = gribapiGetParam(gh);
@@ -1217,10 +1188,8 @@ int gribapiScanTimestep2(stream_t * streamptr)
 
   return (rstatus);
 }
-#endif
 
 
-#if  defined  (HAVE_LIBGRIB_API)
 int gribapiScanTimestep(stream_t * streamptr)
 {
   int vrecID, recID;
@@ -1241,7 +1210,7 @@ int gribapiScanTimestep(stream_t * streamptr)
 
   if ( streamptr->tsteps[tsID].recordSize == 0 )
     {
-      unsigned char* gribbuffer = (unsigned char *) streamptr->record->buffer;
+      void *gribbuffer = streamptr->record->buffer;
       size_t buffersize = streamptr->record->buffersize;
 
       cdi_create_records(streamptr, tsID);
@@ -1292,7 +1261,7 @@ int gribapiScanTimestep(stream_t * streamptr)
             ensureBufferSize((size_t)unzipsize + 100, &buffersize, &gribbuffer);
 
           nrecs_scanned++;
-	  gh = grib_handle_new_from_message(NULL, (void *) gribbuffer, recsize);
+	  gh = grib_handle_new_from_message(NULL, gribbuffer, recsize);
 	  GRIB_CHECK(my_grib_set_double(gh, "missingValue", cdiDefaultMissval), 0);
 
           int param = gribapiGetParam(gh);
@@ -1450,14 +1419,12 @@ int gribapiScanTimestep(stream_t * streamptr)
 
   return (int)streamptr->ntsteps;
 }
-#endif
 
 #ifdef gribWarning
 #undef gribWarning
 #endif
 
-#ifdef HAVE_LIBGRIB_API
-int gribapiDecode(unsigned char *gribbuffer, int gribsize, double *data, int gridsize,
+int gribapiDecode(void *gribbuffer, int gribsize, double *data, long gridsize,
 		  int unreduced, int *nmiss, double missval, int vlistID, int varID)
 {
   int status = 0;
@@ -1480,7 +1447,7 @@ int gribapiDecode(unsigned char *gribbuffer, int gribsize, double *data, int gri
     }
 
   size_t recsize = (size_t)gribsize;
-  grib_handle *gh = grib_handle_new_from_message(NULL, (void *) gribbuffer, recsize);
+  grib_handle *gh = grib_handle_new_from_message(NULL, gribbuffer, recsize);
   GRIB_CHECK(my_grib_set_double(gh, "missingValue", missval), 0);
 
   /* get the size of the values array*/
@@ -1489,8 +1456,8 @@ int gribapiDecode(unsigned char *gribbuffer, int gribsize, double *data, int gri
 
   // printf("values_size = %d  numberOfPoints = %ld\n", datasize, numberOfPoints);
 
-  if ( gridsize != (int) datasize )
-    Error("Internal problem: gridsize(%d) != datasize(%d)!", gridsize, datasize);
+  if ( gridsize != (long) datasize )
+    Error("Internal problem: gridsize(%ld) != datasize(%zu)!", gridsize, datasize);
   size_t dummy = datasize;
   GRIB_CHECK(grib_get_double_array(gh, "values", data, &dummy), 0);
 
@@ -1507,12 +1474,10 @@ int gribapiDecode(unsigned char *gribbuffer, int gribsize, double *data, int gri
 
   grib_handle_delete(gh);
 
-  return (status);
+  return status;
 }
-#endif
 
 
-#if  defined  (HAVE_LIBGRIB_API)
 static
 void gribapiDefInstitut(grib_handle *gh, int vlistID, int varID)
 {
@@ -1661,7 +1626,7 @@ void gribapiDefStepUnits(grib_handle *gh, int timeunit, int proDefTempNum, int g
     {
       GRIB_CHECK(my_grib_set_long(gh, "stepUnits", unitsOfTime), 0);
       if ( proDefTempNum == 8 || proDefTempNum == 11 )
-        GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime), 0);
+        GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitForTimeRange", unitsOfTime), 0);
       GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime), 0);
     }
 }
@@ -1834,6 +1799,7 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
   UNUSED(nmiss);
 
   int gridtype = gridInqType(gridID);
+  int gridsize = gridInqSize(gridID);
 
   if ( editionNumber <= 1 )
     if ( gridtype == GRID_GME || gridtype == GRID_UNSTRUCTURED )
@@ -1841,11 +1807,8 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 
   if ( gridtype == GRID_GENERIC )
     {
-      int xsize, ysize, gridsize;
-
-      gridsize = gridInqSize(gridID);
-      xsize = gridInqXsize(gridID);
-      ysize = gridInqYsize(gridID);
+      int xsize = gridInqXsize(gridID);
+      int ysize = gridInqYsize(gridID);
 
       if ( (ysize ==  32 || ysize ==  48 || ysize ==  64 ||
 	    ysize ==  96 || ysize == 160 || ysize == 192 ||
@@ -1869,7 +1832,7 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
     }
   else if ( gridtype == GRID_CURVILINEAR )
     {
-      if ( lwarn && gridInqSize(gridID) > 1 )
+      if ( lwarn && gridsize > 1 )
 	{
 	  lwarn = FALSE;
 	  Warning("Curvilinear grids are unsupported in GRIB format! Created wrong GDS!");
@@ -1883,13 +1846,13 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 
       if ( comptype )
         {
-          if ( comptype == COMPRESS_JPEG )
+          if ( comptype == COMPRESS_JPEG && gridsize > 1 )
             {
               static const char mesg[] = "grid_jpeg";
               size_t len = sizeof (mesg) - 1;
               GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
             }
-          else if ( comptype == COMPRESS_SZIP )
+          else if ( comptype == COMPRESS_SZIP && gridsize > 1 )
             {
               static const char mesg[] = "grid_ccsds";
               size_t len = sizeof (mesg) - 1;
@@ -1913,7 +1876,6 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
     case GRID_GAUSSIAN_REDUCED:
     case GRID_TRAJECTORY:
       {
-	int nlon = 0, nlat;
 	double xfirst = 0, xlast = 0, xinc = 0;
 	double yfirst = 0, ylast = 0, yinc = 0;
 	double latIncr;
@@ -1943,8 +1905,8 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	    GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
 	  }
 
-	nlon = gridInqXsize(gridID);
-	nlat = gridInqYsize(gridID);
+	int nlon = gridInqXsize(gridID);
+	int nlat = gridInqYsize(gridID);
 
 	if ( gridtype == GRID_GAUSSIAN_REDUCED )
 	  {
@@ -2035,10 +1997,9 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	*/
 	if ( gridIsRotated(gridID) )
 	  {
-	    double xpole, ypole, angle;
-	    xpole = gridInqXpole(gridID);
-	    ypole = gridInqYpole(gridID);
-	    angle = gridInqAngle(gridID);
+	    double xpole = gridInqXpole(gridID);
+	    double ypole = gridInqYpole(gridID);
+	    double angle = gridInqAngle(gridID);
 	    /* change from north to south pole */
 	    if ( fabs(ypole) > 0 ) ypole = -ypole;
 	    xpole =  xpole + 180;
@@ -2069,13 +2030,13 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
           }
         else
 	  {
-            if ( comptype == COMPRESS_JPEG )
+            if ( comptype == COMPRESS_JPEG && gridsize > 1 )
               {
                 static const char mesg[] = "grid_jpeg";
                 size_t len = sizeof (mesg) -1;
                 GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
               }
-            else if ( comptype == COMPRESS_SZIP )
+            else if ( comptype == COMPRESS_SZIP && gridsize > 1 )
               {
                 static const char mesg[] = "grid_ccsds";
                 size_t len = sizeof (mesg) -1;
@@ -2094,11 +2055,10 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
     case GRID_LCC:
       {
 	double originLon, originLat, lonParY, lat1, lat2, xincm, yincm;
-	int xsize, ysize;
 	int projflag, scanflag;
 
-	xsize = gridInqXsize(gridID);
-	ysize = gridInqYsize(gridID);
+	int xsize = gridInqXsize(gridID);
+	int ysize = gridInqYsize(gridID);
 
 	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
 		   &projflag, &scanflag);
@@ -2125,10 +2085,7 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
             GRIB_CHECK(my_grib_set_long(gh, "projectionCenterFlag", projflag), 0);
             GRIB_CHECK(my_grib_set_long(gh, "scanningMode", scanflag), 0);
           }
-        /*
-	ISEC2_Lambert_LatSP  = 0;
-	ISEC2_Lambert_LatSP  = 0;
-        */
+
 	break;
       }
     case GRID_SPECTRAL:
@@ -2143,19 +2100,19 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	GRIB_CHECK(my_grib_set_long(gh, "K", trunc), 0);
 	GRIB_CHECK(my_grib_set_long(gh, "M", trunc), 0);
 
-	// GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridInqSize(gridID)), 0);
+	// GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridsize), 0);
         /*
         if ( lieee )
           {
             printf("spectral_ieee\n");
-            if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridInqSize(gridID)), 0);
+            if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridsize, 0);
             static const char mesg[] = "spectral_ieee";
             size_t len = sizeof (mesg) -1;
             GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
           }
         else */ if ( gridInqComplexPacking(gridID) )
 	  {
-	    if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridInqSize(gridID)), 0);
+	    if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridsize), 0);
             static const char mesg[] = "spectral_complex";
             size_t len = sizeof (mesg) -1;
 	    GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
@@ -2184,8 +2141,8 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	GRIB_CHECK(my_grib_set_long(gh, "latitudeOfThePolePoint", 90000000), 0);
 	GRIB_CHECK(my_grib_set_long(gh, "longitudeOfThePolePoint", 0), 0);
 
-	GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridInqSize(gridID)), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "totalNumberOfGridPoints", gridInqSize(gridID)), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridsize), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "totalNumberOfGridPoints", gridsize), 0);
 
         if ( comptype == COMPRESS_SZIP )
           {
@@ -2293,7 +2250,6 @@ static
 void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID, int levelID, int gcinit, int proddef_template_num)
 {
   int lbounds = 0;
-  static int warning = 1;
   double dlevel1 = 0, dlevel2 = 0;
 
   int zaxistype = zaxisInqType(zaxisID);
@@ -2333,7 +2289,26 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
     case ZAXIS_DEPTH_BELOW_SEA:
     case ZAXIS_ISENTROPIC:
       {
-	if ( editionNumber <= 1 )
+        if ( zaxistype == ZAXIS_HEIGHT )
+          {
+            double sf = 1;
+            char units[128];
+            zaxisInqUnits(zaxisID, units);
+            if ( units[1] == 'm' && !units[2] )
+              {
+                if      ( units[0] == 'c' ) sf = 0.01;
+                else if ( units[0] == 'd' ) sf = 0.1;
+                else if ( units[0] == 'k' ) sf = 1000;
+              }
+            if ( IS_NOT_EQUAL(sf, 1) )
+              {
+                level   *= sf;
+                dlevel1 *= sf;
+                dlevel2 *= sf;
+              }
+          }
+
+        if ( editionNumber <= 1 )
           {
             gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", zaxisTypeToGrib1ltype(zaxistype));
             GRIB_CHECK(my_grib_set_long(gh, "level", (long)level), 0);
@@ -2410,15 +2385,11 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
         if ( !gcinit )
           {
             int vctsize = zaxisInqVctSize(zaxisID);
-            if ( vctsize == 0 && warning )
+            if ( vctsize > 0 )
               {
-                char paramstr[32];
-                cdiParamToString(param, paramstr, sizeof(paramstr));
-                Warning("VCT missing ( param = %s, zaxisID = %d )", paramstr, zaxisID);
-                warning = 0;
+                GRIB_CHECK(my_grib_set_long(gh, "PVPresent", 1), 0);
+                GRIB_CHECK(grib_set_double_array(gh, "pv", zaxisInqVctPtr(zaxisID), (size_t)vctsize), 0);
               }
-            GRIB_CHECK(my_grib_set_long(gh, "PVPresent", 1), 0);
-            GRIB_CHECK(grib_set_double_array(gh, "pv", zaxisInqVctPtr(zaxisID), (size_t)vctsize), 0);
           }
 
 	break;
@@ -2575,14 +2546,12 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
       }
     }
 }
-#endif
 
 /* #define GRIBAPIENCODETEST 1 */
 
-#ifdef HAVE_LIBGRIB_API
 size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const double *data, int nmiss, unsigned char **gribbuffer, size_t *gribbuffersize,
+		     long datasize, const double *data, int nmiss, void **gribbuffer, size_t *gribbuffersize,
 		     int comptype, void *gribContainer)
 {
   size_t recsize = 0;
@@ -2700,7 +2669,7 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
   GRIB_CHECK(grib_get_message(gh, (const void **)&dummy, &recsize), 0);
   recsize += 512; /* add some space for possible filling */
   *gribbuffersize = recsize;
-  *gribbuffer = (unsigned char *) Malloc(*gribbuffersize);
+  *gribbuffer = Malloc(*gribbuffersize);
 
   /* get a copy of the coded message */
   GRIB_CHECK(grib_get_message_copy(gh, *gribbuffer, &recsize), 0);
@@ -2711,7 +2680,7 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
 
   gc->init = TRUE;
 
-  return (recsize);
+  return recsize;
 }
 #endif
 
diff --git a/libcdi/src/stream_gribapi.h b/libcdi/src/stream_gribapi.h
index d3ff963..ac4755b 100644
--- a/libcdi/src/stream_gribapi.h
+++ b/libcdi/src/stream_gribapi.h
@@ -5,12 +5,12 @@ int gribapiScanTimestep1(stream_t * streamptr);
 int gribapiScanTimestep2(stream_t * streamptr);
 int gribapiScanTimestep(stream_t * streamptr);
 
-int gribapiDecode(unsigned char *gribbuffer, int gribsize, double *data, int gridsize,
+int gribapiDecode(void *gribbuffer, int gribsize, double *data, long datasize,
 		  int unreduced, int *nmiss, double missval, int vlistID, int varID);
 
 size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
-		     int vdate, int vtime, int tsteptype, int numavg, 
-		     long datasize, const double *data, int nmiss, unsigned char **gribbuffer, size_t *gribbuffersize,
+		     int vdate, int vtime, int tsteptype, int numavg,
+		     long datasize, const double *data, int nmiss, void **gribbuffer, size_t *gribbuffersize,
 		     int ljpeg, void *gribContainer);
 
 #endif  /* _STREAM_GRIBAPI_H */
diff --git a/libcdi/src/stream_ieg.c b/libcdi/src/stream_ieg.c
index b798514..20c08f9 100644
--- a/libcdi/src/stream_ieg.c
+++ b/libcdi/src/stream_ieg.c
@@ -266,9 +266,7 @@ calc_resfac(double xfirst, double xlast, double xinc, double yfirst, double ylas
 static
 void iegDefGrid(int *gdb, int gridID)
 {
-  int gridtype;
-
-  gridtype = gridInqType(gridID);
+  int gridtype = gridInqType(gridID);
 
   if ( gridtype == GRID_GENERIC )
     {
@@ -399,7 +397,6 @@ void iegDefLevel(int *pdb, int *gdb, double *vct, int zaxisID, int levelID)
 {
   double level;
   int ilevel, leveltype;
-  static int warning = 1;
   static int vct_warning = 1;
 
   leveltype = zaxisInqType(zaxisID);
@@ -443,12 +440,6 @@ void iegDefLevel(int *pdb, int *gdb, double *vct, int zaxisID, int levelID)
 	  }
 
 	vctsize = zaxisInqVctSize(zaxisID);
-	if ( vctsize == 0 && warning )
-	  {
-	    Warning("VCT missing. ( code = %d, zaxisID = %d )",
-		    IEG_P_Parameter(pdb), zaxisID);
-	    warning = 0;
-	  }
 	if ( vctsize > 100 )
 	  {
 	    /*	    IEG_G_NumVCP(gdb) = 0; */
@@ -644,23 +635,13 @@ static
 void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vct,
 		  size_t recsize, off_t position, int prec)
 {
-  int leveltype;
-  int gridID = UNDEFID;
   int levelID = 0;
-  int tsID, recID, varID;
-  int datatype;
-  int level1, level2;
-  int gridtype;
-  int lbounds = 0;
-  record_t *record;
-  grid_t grid;
-  int vlistID;
-
-  vlistID = streamptr->vlistID;
-  tsID    = streamptr->curTsID;
-  recID   = recordNewEntry(streamptr, tsID);
-  record  = &streamptr->tsteps[tsID].records[recID];
+  int vlistID = streamptr->vlistID;
+  int tsID    = streamptr->curTsID;
+  int recID   = recordNewEntry(streamptr, tsID);
+  record_t *record = &streamptr->tsteps[tsID].records[recID];
 
+  int level1, level2;
   if ( IEG_P_LevelType(pdb) == IEG_LTYPE_HYBRID_LAYER )
     {
       level1 = IEG_P_Level1(pdb);
@@ -680,21 +661,18 @@ void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vc
   record->ilevel2  = level2;
   record->ltype    = IEG_P_LevelType(pdb);
 
-  if ( IEG_G_GridType(gdb) == 0 || IEG_G_GridType(gdb) == 10 )
-    gridtype = GRID_LONLAT;
-  else if ( IEG_G_GridType(gdb) == 4 )
-    gridtype = GRID_GAUSSIAN;
-  else
-    gridtype = GRID_GENERIC;
+  int gridtype =
+   ( IEG_G_GridType(gdb) == 0 || IEG_G_GridType(gdb) == 10 ) ? GRID_LONLAT :
+    ( IEG_G_GridType(gdb) == 4 ) ? GRID_GAUSSIAN : GRID_GENERIC;
 
-  memset(&grid, 0, sizeof(grid_t));
-  grid.type  = gridtype;
-  grid.size  = IEG_G_NumLon(gdb)*IEG_G_NumLat(gdb);
-  grid.xsize = IEG_G_NumLon(gdb);
-  grid.ysize = IEG_G_NumLat(gdb);
-  grid.xinc  = 0;
-  grid.yinc  = 0;
-  grid.xdef  = 0;
+  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, IEG_G_NumLon(gdb)*IEG_G_NumLat(gdb));
+  grid->xsize = IEG_G_NumLon(gdb);
+  grid->ysize = IEG_G_NumLat(gdb);
+  grid->xinc  = 0;
+  grid->yinc  = 0;
+  grid->xdef  = 0;
 
   int iresfac = IEG_G_ResFac(gdb);
   if ( iresfac == 0 ) iresfac = 1000;
@@ -702,68 +680,70 @@ void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vc
 
   /* if ( IEG_G_FirstLon != 0 || IEG_G_LastLon != 0 ) */
   {
-    if ( grid.xsize > 1 )
+    if ( grid->xsize > 1 )
       {
 	if ( IEG_G_ResFlag(gdb) && IEG_G_LonIncr(gdb) > 0 )
-	  grid.xinc = IEG_G_LonIncr(gdb) * resfac;
+	  grid->xinc = IEG_G_LonIncr(gdb) * resfac;
 	else
-	  grid.xinc = (IEG_G_LastLon(gdb) - IEG_G_FirstLon(gdb)) * resfac / (grid.xsize - 1);
+	  grid->xinc = (IEG_G_LastLon(gdb) - IEG_G_FirstLon(gdb)) * resfac / (grid->xsize - 1);
 
 	/* correct xinc if necessary */
 	if ( IEG_G_FirstLon(gdb) == 0 && IEG_G_LastLon(gdb) > 354000 )
 	  {
-	    double xinc = 360. / grid.xsize;
-            /* FIXME: why not use grid.xinc != xinc as condition? */
-	    if ( fabs(grid.xinc-xinc) > 0.0 )
+	    double xinc = 360. / grid->xsize;
+            /* FIXME: why not use grid->xinc != xinc as condition? */
+	    if ( fabs(grid->xinc-xinc) > 0.0 )
 	      {
-		grid.xinc = xinc;
-		if ( CDI_Debug ) Message("set xinc to %g", grid.xinc);
+		grid->xinc = xinc;
+		if ( CDI_Debug ) Message("set xinc to %g", grid->xinc);
 	      }
 	  }
       }
-    grid.xfirst = IEG_G_FirstLon(gdb) * resfac;
-    grid.xlast  = IEG_G_LastLon(gdb)  * resfac;
-    grid.xdef   = 2;
+    grid->xfirst = IEG_G_FirstLon(gdb) * resfac;
+    grid->xlast  = IEG_G_LastLon(gdb)  * resfac;
+    grid->xdef   = 2;
   }
-  grid.ydef  = 0;
+  grid->ydef  = 0;
   /* if ( IEG_G_FirstLat != 0 || IEG_G_LastLat != 0 ) */
   {
-    if ( grid.ysize > 1 )
+    if ( grid->ysize > 1 )
       {
 	if ( IEG_G_ResFlag(gdb) && IEG_G_LatIncr(gdb) > 0 )
-	  grid.yinc = IEG_G_LatIncr(gdb) * resfac;
+	  grid->yinc = IEG_G_LatIncr(gdb) * resfac;
 	else
-	  grid.yinc = (IEG_G_LastLat(gdb) - IEG_G_FirstLat(gdb)) * resfac / (grid.ysize - 1);
+	  grid->yinc = (IEG_G_LastLat(gdb) - IEG_G_FirstLat(gdb)) * resfac / (grid->ysize - 1);
       }
-    grid.yfirst = IEG_G_FirstLat(gdb) * resfac;
-    grid.ylast  = IEG_G_LastLat(gdb)  * resfac;
-    grid.ydef   = 2;
+    grid->yfirst = IEG_G_FirstLat(gdb) * resfac;
+    grid->ylast  = IEG_G_LastLat(gdb)  * resfac;
+    grid->ydef   = 2;
   }
   /*
-  grid.xfirst= IEG_G_FirstLon(gdb) * resfac;
-  grid.xlast = IEG_G_LastLon(gdb) * resfac;
-  grid.xinc  = IEG_G_LonIncr(gdb) * resfac;
-  grid.xdef  = 2;
-  grid.yfirst= IEG_G_FirstLat(gdb) * resfac;
-  grid.ylast = IEG_G_LastLat(gdb) * resfac;
-  grid.yinc  = IEG_G_LatIncr(gdb) * resfac;
-  grid.ydef  = 2;
+  grid->xfirst= IEG_G_FirstLon(gdb) * resfac;
+  grid->xlast = IEG_G_LastLon(gdb) * resfac;
+  grid->xinc  = IEG_G_LonIncr(gdb) * resfac;
+  grid->xdef  = 2;
+  grid->yfirst= IEG_G_FirstLat(gdb) * resfac;
+  grid->ylast = IEG_G_LastLat(gdb) * resfac;
+  grid->yinc  = IEG_G_LatIncr(gdb) * resfac;
+  grid->ydef  = 2;
   */
-  grid.xvals = NULL;
-  grid.yvals = NULL;
+  grid->xvals = NULL;
+  grid->yvals = NULL;
 
-  grid.isRotated = FALSE;
+  grid->isRotated = FALSE;
   if ( IEG_G_GridType(gdb) == 10 )
     {
-      grid.isRotated = TRUE;
-      grid.ypole     = - IEG_G_LatSP(gdb) * resfac;
-      grid.xpole     =   IEG_G_LonSP(gdb) * resfac - 180;
-      grid.angle     = 0;
+      grid->isRotated = TRUE;
+      grid->ypole     = - IEG_G_LatSP(gdb) * resfac;
+      grid->xpole     =   IEG_G_LonSP(gdb) * resfac - 180;
+      grid->angle     = 0;
     }
 
-  gridID = varDefGrid(vlistID, &grid, 0);
+  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  int gridID = gridAdded.Id;
+  if (!gridAdded.isNew) Free(grid);
 
-  leveltype = iegGetZaxisType(IEG_P_LevelType(pdb));
+  int leveltype = iegGetZaxisType(IEG_P_LevelType(pdb));
 
   if ( leveltype == ZAXIS_HYBRID )
     {
@@ -776,10 +756,11 @@ void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vc
       varDefVCT(vctsize, tmpvct);
     }
 
-  if ( IEG_P_LevelType(pdb) == IEG_LTYPE_HYBRID_LAYER ) lbounds = 1;
+  int lbounds = IEG_P_LevelType(pdb) == IEG_LTYPE_HYBRID_LAYER ? 1 : 0;
 
-  datatype = iegInqDatatype(prec);
+  int datatype = iegInqDatatype(prec);
 
+  int varID;
   varAddRecord(recID, param, gridID, leveltype, lbounds, level1, level2, 0, 0,
 	       datatype, &varID, &levelID, TSTEP_INSTANT, 0, 0, -1,
                NULL, NULL, NULL, NULL, NULL, NULL);
diff --git a/libcdi/src/stream_read.c b/libcdi/src/stream_read.c
new file mode 100644
index 0000000..c4e9d7f
--- /dev/null
+++ b/libcdi/src/stream_read.c
@@ -0,0 +1,357 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cdi.h"
+#include "cdi_int.h"
+#include "stream_grb.h"
+#include "stream_cdf.h"
+#include "stream_srv.h"
+#include "stream_ext.h"
+#include "stream_ieg.h"
+#include "dmemory.h"
+#include "namespace.h"
+
+
+/* the single image implementation */
+static
+int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmiss)
+{
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
+
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
+
+  check_parg(data);
+  check_parg(nmiss);
+
+  stream_t *streamptr = stream_to_pointer(streamID);
+  int filetype = streamptr->filetype;
+
+  *nmiss = 0;
+
+  switch (filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      {
+        grb_read_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvReadVarDP(streamptr, varID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extReadVarDP(streamptr, varID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegReadVarDP(streamptr, varID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      {
+        cdf_read_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
+      }
+    }
+
+  return status;
+}
+
+/*
+ at Function  streamReadVar
+ at Title     Read a variable
+
+ at Prototype void streamReadVar(int streamID, int varID, double *data, int *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
+
+ at Description
+The function streamReadVar reads all the values of one time step of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVar(int streamID, int varID, double *data, int *nmiss)
+{
+  cdiStreamReadVar(streamID, varID, MEMTYPE_DOUBLE, data, nmiss);
+}
+
+/*
+ at Function  streamReadVarF
+ at Title     Read a variable
+
+ at Prototype void streamReadVar(int streamID, int varID, float *data, int *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
+
+ at Description
+The function streamReadVar reads all the values of one time step of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVarF(int streamID, int varID, float *data, int *nmiss)
+{
+  if ( cdiStreamReadVar(streamID, varID, MEMTYPE_FLOAT, data, nmiss) )
+    {
+      // In case the file format does not support single precision reading,
+      // we fall back to double precision reading, converting the data on the fly.
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      streamReadVar(streamID, varID, conversionBuffer, nmiss);
+      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
+      Free(conversionBuffer);
+    }
+}
+
+
+static
+int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, void *data, int *nmiss)
+{
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
+
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
+
+  check_parg(data);
+  check_parg(nmiss);
+
+  stream_t *streamptr = stream_to_pointer(streamID);
+  int filetype = streamptr->filetype;
+
+  *nmiss = 0;
+
+  switch (filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      {
+        grb_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      {
+        cdf_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+        break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+        status = 2;
+	break;
+      }
+    }
+
+  return status;
+}
+
+/*
+ at Function  streamReadVarSlice
+ at Title     Read a horizontal slice of a variable
+
+ at Prototype void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
+
+ at Description
+The function streamReadVarSlice reads all the values of a horizontal slice of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
+{
+  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, data, nmiss) )
+    {
+      Warning("Unexpected error returned from cdiStreamReadVarSlice()!");
+      size_t elementCount = (size_t)gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      memset(data, 0, elementCount * sizeof(*data));
+    }
+}
+
+/*
+ at Function  streamReadVarSliceF
+ at Title     Read a horizontal slice of a variable
+
+ at Prototype void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
+
+ at Description
+The function streamReadVarSliceF reads all the values of a horizontal slice of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
+{
+  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, data, nmiss) )
+    {
+      // In case the file format does not support single precision reading,
+      // we fall back to double precision reading, converting the data on the fly.
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      streamReadVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
+      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
+      Free(conversionBuffer);
+    }
+}
+
+static
+int stream_read_record(int streamID, int memtype, void *data, int *nmiss)
+{
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
+
+  check_parg(data);
+  check_parg(nmiss);
+
+  stream_t *streamptr = stream_to_pointer(streamID);
+
+  *nmiss = 0;
+
+  switch (streamptr->filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      grb_read_record(streamptr, memtype, data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      srvReadRecord(streamptr, (double *)data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      extReadRecord(streamptr, (double *)data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      iegReadRecord(streamptr, (double *)data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      cdf_read_record(streamptr, memtype, data, nmiss);
+      break;
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
+	break;
+      }
+    }
+
+  return status;
+}
+
+
+void streamReadRecord(int streamID, double *data, int *nmiss)
+{
+  stream_read_record(streamID, MEMTYPE_DOUBLE, (void *) data, nmiss);
+}
+
+
+void streamReadRecordF(int streamID, float *data, int *nmiss)
+{
+  if ( stream_read_record(streamID, MEMTYPE_FLOAT, (void *) data, nmiss) )
+    {
+      // In case the file format does not support single precision reading,
+      // we fall back to double precision reading, converting the data on the fly.
+      stream_t *streamptr = stream_to_pointer(streamID);
+      int tsID   = streamptr->curTsID;
+      int vrecID = streamptr->tsteps[tsID].curRecID;
+      int recID  = streamptr->tsteps[tsID].recIDs[vrecID];
+      int varID  = streamptr->tsteps[tsID].records[recID].varID;
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      streamReadRecord(streamID, conversionBuffer, nmiss);
+      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
+      Free(conversionBuffer);
+    }
+}
diff --git a/libcdi/src/stream_record.c b/libcdi/src/stream_record.c
index 3316cc4..ea43cd1 100644
--- a/libcdi/src/stream_record.c
+++ b/libcdi/src/stream_record.c
@@ -107,7 +107,6 @@ void streamInqRecord(int streamID, int *varID, int *levelID)
   check_parg(levelID);
 
   stream_t *streamptr = stream_to_pointer(streamID);
-  stream_check_ptr(__func__, streamptr);
 
   cdiDefAccesstype(streamID, TYPE_REC);
 
@@ -154,7 +153,6 @@ The function streamDefRecord defines the meta-data of the next record.
 void streamDefRecord(int streamID, int varID, int levelID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-  stream_check_ptr(__func__, streamptr);
 
   int tsID = streamptr->curTsID;
 
@@ -220,144 +218,13 @@ void streamDefRecord(int streamID, int varID, int levelID)
 }
 
 
-void streamReadRecord(int streamID, double *data, int *nmiss)
-{
-  check_parg(data);
-  check_parg(nmiss);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
-  stream_check_ptr(__func__, streamptr);
-
-  *nmiss = 0;
-
-  switch (streamptr->filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      grbReadRecord(streamptr, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      srvReadRecord(streamptr, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      extReadRecord(streamptr, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      iegReadRecord(streamptr, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      cdfReadRecord(streamptr, data, nmiss);
-      break;
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
-	break;
-      }
-    }
-}
-
-static void
-stream_write_record(int streamID, int memtype, const void *data, int nmiss)
-{
-  check_parg(data);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
-  stream_check_ptr(__func__, streamptr);
-
-  switch (streamptr->filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      grb_write_record(streamptr, memtype, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      if ( memtype == MEMTYPE_FLOAT ) Error("srvWriteRecord not implemented for memtype float!");
-      srvWriteRecord(streamptr, (const double *)data);
-      break;
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      if ( memtype == MEMTYPE_FLOAT ) Error("extWriteRecord not implemented for memtype float!");
-      extWriteRecord(streamptr, (const double *)data);
-      break;
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      if ( memtype == MEMTYPE_FLOAT ) Error("iegWriteRecord not implemented for memtype float!");
-      iegWriteRecord(streamptr, (const double *)data);
-      break;
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-	cdf_write_record(streamptr, memtype, data, nmiss);
-	break;
-      }
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
-	break;
-      }
-    }
-}
-
-/*
- at Function  streamWriteRecord
- at Title     Write a horizontal slice of a variable
-
- at Prototype void streamWriteRecord(int streamID, const double *data, int nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  data      Pointer to a block of double precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamWriteRecord writes the values of a horizontal slice (record) of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
- at EndFunction
-*/
-void streamWriteRecord(int streamID, const double *data, int nmiss)
-{
-  stream_write_record(streamID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
-}
-
-void streamWriteRecordF(int streamID, const float *data, int nmiss)
-{
-  stream_write_record(streamID, MEMTYPE_FLOAT, (const void *) data, nmiss);
-}
-
-
 void streamCopyRecord(int streamID2, int streamID1)
 {
-  stream_t *streamptr1 = stream_to_pointer(streamID1);
-  stream_t *streamptr2 = stream_to_pointer(streamID2);
-
-  stream_check_ptr(__func__, streamptr1);
-  stream_check_ptr(__func__, streamptr2);
-
-  int filetype1 = streamptr1->filetype;
-  int filetype2 = streamptr2->filetype;
-  int filetype  = FILETYPE_UNDEF;
+  stream_t *streamptr1 = stream_to_pointer(streamID1),
+    *streamptr2 = stream_to_pointer(streamID2);
+  int filetype1 = streamptr1->filetype,
+    filetype2 = streamptr2->filetype,
+    filetype  = FILETYPE_UNDEF;
 
   if ( filetype1 == filetype2 ) filetype = filetype2;
   else
diff --git a/libcdi/src/stream_srv.c b/libcdi/src/stream_srv.c
index ef89486..52752b0 100644
--- a/libcdi/src/stream_srv.c
+++ b/libcdi/src/stream_srv.c
@@ -102,23 +102,20 @@ int srvInqRecord(stream_t *streamptr, int *varID, int *levelID)
 
 void srvReadRecord(stream_t *streamptr, double *data, int *nmiss)
 {
-  int vlistID, fileID;
   int status;
-  int recID, vrecID, tsID;
-  off_t recpos;
   int header[8];
-  int varID, gridID;
+  int gridID;
   int i, size;
   double missval;
   void *srvp = streamptr->record->exsep;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
-  tsID    = streamptr->curTsID;
-  vrecID  = streamptr->tsteps[tsID].curRecID;
-  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-  recpos  = streamptr->tsteps[tsID].records[recID].position;
-  varID   = streamptr->tsteps[tsID].records[recID].varID;
+  int vlistID  = streamptr->vlistID;
+  int fileID   = streamptr->fileID;
+  int tsID     = streamptr->curTsID;
+  int vrecID   = streamptr->tsteps[tsID].curRecID;
+  int recID    = streamptr->tsteps[tsID].recIDs[vrecID];
+  int varID    = streamptr->tsteps[tsID].records[recID].varID;
+  off_t recpos = streamptr->tsteps[tsID].records[recID].position;
 
   fileSetPos(fileID, recpos, SEEK_SET);
 
@@ -153,23 +150,20 @@ void srvCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
 
 void srvDefRecord(stream_t *streamptr)
 {
-  int gridID;
   int header[8];
-  int xsize, ysize;
-  int datatype;
-  int pdis, pcat, pnum;
-  srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
+  Record *restrict record = streamptr->record;
+  srvrec_t *restrict srvp = (srvrec_t*) record->exsep;
+  int gridID = record->gridID;
 
-  gridID = streamptr->record->gridID;
-
-  cdiDecodeParam(streamptr->record->param, &pnum, &pcat, &pdis);
+  int pdis, pcat, pnum;
+  cdiDecodeParam(record->param, &pnum, &pcat, &pdis);
   header[0] = pnum;
-  header[1] = streamptr->record->level;
-  header[2] = streamptr->record->date;
-  header[3] = streamptr->record->time;
+  header[1] = record->level;
+  header[2] = record->date;
+  header[3] = record->time;
 
-  xsize = gridInqXsize(gridID);
-  ysize = gridInqYsize(gridID);
+  int xsize = gridInqXsize(gridID),
+    ysize = gridInqYsize(gridID);
   if ( xsize == 0 || ysize == 0 )
     {
       xsize = gridInqSize(gridID);
@@ -184,7 +178,7 @@ void srvDefRecord(stream_t *streamptr)
   header[6] = 0;
   header[7] = 0;
 
-  datatype = streamptr->record->prec;
+  int datatype = record->prec;
 
   srvp->dprec = srvDefDatatype(datatype);
 
@@ -215,15 +209,16 @@ void srv_add_record(stream_t *streamptr, int param, int level, int xsize, int ys
   record->param    = param;
   record->ilevel   = level;
 
-  grid_t grid;
-  memset(&grid, 0, sizeof(grid_t));
-  grid.type  = GRID_GENERIC;
-  grid.size  = xsize*ysize;
-  grid.xsize = xsize;
-  grid.ysize = ysize;
-  grid.xvals = NULL;
-  grid.yvals = NULL;
-  int gridID = varDefGrid(vlistID, &grid, 0);
+  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
+  grid_init(grid);
+  cdiGridTypeInit(grid, GRID_GENERIC, xsize*ysize);
+  grid->xsize = xsize;
+  grid->ysize = ysize;
+  grid->xvals = NULL;
+  grid->yvals = NULL;
+  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  int gridID = gridAdded.Id;
+  if (!gridAdded.isNew) Free(grid);
   /*
   if ( level == 0 ) leveltype = ZAXIS_SURFACE;
   else              leveltype = ZAXIS_GENERIC;
@@ -253,38 +248,29 @@ void srv_add_record(stream_t *streamptr, int param, int level, int xsize, int ys
 static
 void srvScanTimestep1(stream_t *streamptr)
 {
-  int header[8];
-  int prec = 0;
-  int status;
-  int fileID;
-  int rxsize = 0, rysize = 0;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
   DateTime datetime0 = { LONG_MIN, LONG_MIN };
-  int tsID;
-  int varID;
   off_t recpos;
-  int nrecords, nrecs, recID;
-  int taxisID = -1;
   taxis_t *taxis;
-  int vlistID;
   srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
 
   streamptr->curTsID = 0;
 
-  tsID  = tstepsNewEntry(streamptr);
-  taxis = &streamptr->tsteps[tsID].taxis;
+  {
+    int tsID  = tstepsNewEntry(streamptr);
+    if ( tsID != 0 )
+      Error("Internal problem! tstepsNewEntry returns %d", tsID);
+    taxis = &streamptr->tsteps[tsID].taxis;
+  }
 
-  if ( tsID != 0 )
-    Error("Internal problem! tstepsNewEntry returns %d", tsID);
 
-  fileID = streamptr->fileID;
+  int fileID = streamptr->fileID;
 
-  nrecs = 0;
+  int nrecs = 0;
   while ( TRUE )
     {
+      int header[8];
       recpos = fileGetPos(fileID);
-      status = srvRead(fileID, srvp);
+      int status = srvRead(fileID, srvp);
       if ( status != 0 )
 	{
 	  streamptr->ntsteps = 1;
@@ -294,15 +280,15 @@ void srvScanTimestep1(stream_t *streamptr)
 
       srvInqHeader(srvp, header);
 
-      prec   = srvp->dprec;
-      rcode  = header[0];
-      rlevel = header[1];
-      vdate  = header[2];
-      vtime  = header[3];
-      rxsize = header[4];
-      rysize = header[5];
+      int prec   = srvp->dprec;
+      int rcode  = header[0];
+      int rlevel = header[1];
+      int vdate  = header[2];
+      int vtime  = header[3];
+      int rxsize = header[4];
+      int rysize = header[5];
 
-      param = cdiEncodeParam(rcode, 255, 255);
+      int param = cdiEncodeParam(rcode, 255, 255);
 
       if ( nrecs == 0 )
 	{
@@ -311,11 +297,10 @@ void srvScanTimestep1(stream_t *streamptr)
 	}
       else
 	{
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
             if (    streamptr->tsteps[0].records[recID].param  == param
                  && streamptr->tsteps[0].records[recID].ilevel == rlevel )
-              break;
-	  if ( recID < nrecs ) break;
+              goto tstepScanLoopFinished;
 	  DateTime datetime = { .date = vdate, .time = vtime };
 	  if ( datetimeCmp(datetime, datetime0) )
 	    Warning("Inconsistent verification time for code %d level %d", rcode, rlevel);
@@ -329,21 +314,22 @@ void srvScanTimestep1(stream_t *streamptr)
       srv_add_record(streamptr, param, rlevel, rxsize, rysize, recsize, recpos, prec);
     }
 
+  tstepScanLoopFinished:
   streamptr->rtsteps = 1;
 
   cdi_generate_vars(streamptr);
 
-  taxisID = taxisCreate(TAXIS_ABSOLUTE);
+  int taxisID = taxisCreate(TAXIS_ABSOLUTE);
   taxis->type  = TAXIS_ABSOLUTE;
   taxis->vdate = (int)datetime0.date;
   taxis->vtime = (int)datetime0.time;
 
-  vlistID = streamptr->vlistID;
+  int vlistID = streamptr->vlistID;
   vlistDefTaxis(vlistID, taxisID);
 
   vlist_check_contents(vlistID);
 
-  nrecords = streamptr->tsteps[0].nallrecs;
+  int nrecords = streamptr->tsteps[0].nallrecs;
   if ( nrecords < streamptr->tsteps[0].recordSize )
     {
       streamptr->tsteps[0].recordSize = nrecords;
@@ -354,12 +340,12 @@ void srvScanTimestep1(stream_t *streamptr)
 
   streamptr->tsteps[0].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
   streamptr->tsteps[0].nrecs = nrecords;
-  for ( recID = 0; recID < nrecords; recID++ )
+  for ( int recID = 0; recID < nrecords; recID++ )
     streamptr->tsteps[0].recIDs[recID] = recID;
 
   if ( streamptr->ntsteps == -1 )
     {
-      tsID = tstepsNewEntry(streamptr);
+      int tsID = tstepsNewEntry(streamptr);
       if ( tsID != streamptr->rtsteps )
 	Error("Internal error. tsID = %d", tsID);
 
@@ -372,10 +358,8 @@ void srvScanTimestep1(stream_t *streamptr)
       if ( taxis->vdate == 0 && taxis->vtime == 0 )
 	{
 	  streamptr->ntsteps = 0;
-	  for ( varID = 0; varID < streamptr->nvars; varID++ )
-	    {
-	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-	    }
+	  for ( int varID = 0; varID < streamptr->nvars; varID++ )
+            vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
 	}
     }
 }
diff --git a/libcdi/src/stream_write.c b/libcdi/src/stream_write.c
new file mode 100644
index 0000000..eef2129
--- /dev/null
+++ b/libcdi/src/stream_write.c
@@ -0,0 +1,431 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cdi.h"
+#include "cdi_int.h"
+#include "stream_grb.h"
+#include "stream_cdf.h"
+#include "stream_srv.h"
+#include "stream_ext.h"
+#include "stream_ieg.h"
+#include "dmemory.h"
+#include "namespace.h"
+
+
+/* the single image implementation */
+int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, int nmiss)
+{
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
+
+  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
+
+  check_parg(data);
+
+  stream_t *streamptr = stream_to_pointer(streamID);
+  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
+    Error("Writing of non-trivial subtypes not yet implemented!");
+
+  // check taxis
+  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
+
+  int filetype = streamptr->filetype;
+
+  switch (filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      {
+        grb_write_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      {
+        cdf_write_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
+      }
+    }
+
+  return status;
+}
+
+/*
+ at Function  streamWriteVar
+ at Title     Write a variable
+
+ at Prototype void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to a block of double precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
+
+ at Description
+The function streamWriteVar writes the values of one time step of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
+{
+  void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype,
+                               const void *data, int nmiss)
+    = (void (*)(int, int, int, const void *, int))
+    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
+
+  myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+}
+
+/*
+ at Function  streamWriteVarF
+ at Title     Write a variable
+
+ at Prototype void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to a block of single precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
+
+ at Description
+The function streamWriteVarF writes the values of one time step of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
+{
+  int (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype,
+                              const void *data, int nmiss)
+    = (int (*)(int, int, int, const void *, int))
+    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
+  
+  if ( myCdiStreamWriteVar_(streamID, varID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
+    {
+      // In case the file format does not support single precision writing,
+      // we fall back to double precision writing, converting the data on the fly.
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
+      myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) conversionBuffer, nmiss);
+      Free(conversionBuffer);
+    }
+}
+
+static
+int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, int nmiss)
+{
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
+
+  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
+
+  check_parg(data);
+
+  stream_t *streamptr = stream_to_pointer(streamID);
+  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
+    Error("Writing of non-trivial subtypes not yet implemented!");
+
+  // check taxis
+  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
+
+  int filetype = streamptr->filetype;
+
+  switch (filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      {
+        grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+      break;
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
+      }
+    }
+
+  return status;
+}
+
+/*
+ at Function  streamWriteVarSlice
+ at Title     Write a horizontal slice of a variable
+
+ at Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to a block of double precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
+
+ at Description
+The function streamWriteVarSlice writes the values of a horizontal slice of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
+{
+  cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+}
+
+/*
+ at Function  streamWriteVarSliceF
+ at Title     Write a horizontal slice of a variable
+
+ at Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to a block of single precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
+
+ at Description
+The function streamWriteVarSliceF writes the values of a horizontal slice of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
+{
+  if ( cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
+    {
+      // In case the file format does not support single precision writing,
+      // we fall back to double precision writing, converting the data on the fly.
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
+      streamWriteVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
+      Free(conversionBuffer);
+    }
+}
+
+
+void
+streamWriteVarChunk(int streamID, int varID,
+                    const int rect[][2], const double *data, int nmiss)
+{
+  void (*myCdiStreamWriteVarChunk_)(int streamID, int varID, int memtype,
+                                    const int rect[][2], const void *data,
+                                    int nmiss)
+    = (void (*)(int, int, int, const int [][2], const void *, int))
+    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_CHUNK_).func;
+  myCdiStreamWriteVarChunk_(streamID, varID, MEMTYPE_DOUBLE, rect, data, nmiss);
+}
+
+/* single image implementation */
+void
+cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
+                        const int rect[][2], const void *data, int nmiss)
+{
+  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
+
+  stream_t *streamptr = stream_to_pointer(streamID);
+
+  // streamDefineTaxis(streamID);
+
+  int filetype = streamptr->filetype;
+
+  switch (filetype)
+    {
+#if defined (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+#endif
+#if defined (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+#endif
+#if defined (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+#endif
+#if defined (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+#endif
+#if  defined (HAVE_LIBGRIB) || defined (HAVE_LIBSERVICE)      \
+  || defined (HAVE_LIBEXTRA) || defined (HAVE_LIBIEG)
+      xabort("streamWriteVarChunk not implemented for filetype %s!",
+             strfiletype(filetype));
+      break;
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      cdf_write_var_chunk(streamptr, varID, memtype, rect, data, nmiss);
+      break;
+#endif
+    default:
+      Error("%s support not compiled in!", strfiletype(filetype));
+      break;
+    }
+}
+
+static
+int stream_write_record(int streamID, int memtype, const void *data, int nmiss)
+{
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
+
+  check_parg(data);
+
+  stream_t *streamptr = stream_to_pointer(streamID);
+
+  switch (streamptr->filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      grb_write_record(streamptr, memtype, data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      srvWriteRecord(streamptr, (const double *)data);
+      break;
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      extWriteRecord(streamptr, (const double *)data);
+      break;
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      iegWriteRecord(streamptr, (const double *)data);
+      break;
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      {
+	cdf_write_record(streamptr, memtype, data, nmiss);
+	break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
+	break;
+      }
+    }
+
+  return status;
+}
+
+/*
+ at Function  streamWriteRecord
+ at Title     Write a horizontal slice of a variable
+
+ at Prototype void streamWriteRecord(int streamID, const double *data, int nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  data      Pointer to a block of double precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
+
+ at Description
+The function streamWriteRecord writes the values of a horizontal slice (record) of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteRecord(int streamID, const double *data, int nmiss)
+{
+  stream_write_record(streamID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+}
+
+
+void streamWriteRecordF(int streamID, const float *data, int nmiss)
+{
+  if ( stream_write_record(streamID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
+    {
+      // In case the file format does not support single precision writing,
+      // we fall back to double precision writing, converting the data on the fly.
+      stream_t *streamptr = stream_to_pointer(streamID);
+      int varID  = streamptr->record->varID;
+      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
+      streamWriteRecord(streamID, conversionBuffer, nmiss);
+      Free(conversionBuffer);
+    }
+}
+
diff --git a/libcdi/src/subtype.c b/libcdi/src/subtype.c
index 70cdf0d..9c14901 100644
--- a/libcdi/src/subtype.c
+++ b/libcdi/src/subtype.c
@@ -79,7 +79,7 @@ enum {
 
 
 /* ------------------------------------------------------------------- */
-/* SUBROUTINES FOR ATTRIBUTE LISTS				       */
+/* SUBROUTINES FOR ATTRIBUTE LISTS                                     */
 /* ------------------------------------------------------------------- */
 
 
@@ -211,7 +211,7 @@ static void subtypeAttsDuplicate(struct subtype_attr_t *a1, struct subtype_entry
 
 
 /* ------------------------------------------------------------------- */
-/* SUBROUTINES FOR LIST OF ENTRIES				       */
+/* SUBROUTINES FOR LIST OF ENTRIES                                     */
 /* ------------------------------------------------------------------- */
 
 
@@ -335,7 +335,7 @@ static void subtypeEntryDuplicate(struct subtype_entry_t *a1, subtype_t* dst)
 
 
 /* ------------------------------------------------------------------- */
-/* SUBROUTINES FOR THE SUBTYPE ITSELF				       */
+/* SUBROUTINES FOR THE SUBTYPE ITSELF                                  */
 /* ------------------------------------------------------------------- */
 
 /* Print-out subtype data structure together with its attributes. */
@@ -546,7 +546,7 @@ void subtypeDefEntryDataP(struct subtype_entry_t *subtype_entry_ptr, int key, in
 
 
 /* ------------------------------------------------------------------- */
-/* IMPLEMENTATIONS FOR KEY-VALUE-PAIR QUERIES			       */
+/* IMPLEMENTATIONS FOR KEY-VALUE-PAIR QUERIES                          */
 /* ------------------------------------------------------------------- */
 
 
@@ -595,7 +595,7 @@ subtype_query_t matchAND(subtype_query_t q1, subtype_query_t q2)
 
 
 /* ------------------------------------------------------------------- */
-/* SPECIFIC IMPLEMENTATIONS FOR TILE SETS			       */
+/* SPECIFIC IMPLEMENTATIONS FOR TILE SETS                              */
 /* ------------------------------------------------------------------- */
 
 
@@ -607,39 +607,39 @@ void tilesetInsertP(subtype_t *s1, subtype_t *s2)
 {
   if (s1 == NULL)  Error("Internal error!");
   if (s2 == NULL)  Error("Internal error!");
-  struct subtype_entry_t 
+  struct subtype_entry_t
     *entry1 = s1->entries,
     *entry2 = s2->entries;
   struct subtype_attr_t *att_ptr2;
 
   /* test all entries of set 2 against set 1, to check if entry
      already exists: */
-  if (subtypeAttsCompare(s1->globals.atts, s2->globals.atts) != differ) 
+  if (subtypeAttsCompare(s1->globals.atts, s2->globals.atts) != differ)
     {
       while (entry1 != NULL) {
-	int found = 1;
-	entry2 = s2->entries;
-	while (entry2 != NULL) {
-	  found &= (subtypeAttsCompare(entry1->atts, entry2->atts) != differ);
-	  entry2 = entry2->next;
-	}
-	if (found) 
-	  {
-	    return;
-	  }
-	entry1 = entry1->next;
+        int found = 1;
+        entry2 = s2->entries;
+        while (entry2 != NULL) {
+          found &= (subtypeAttsCompare(entry1->atts, entry2->atts) != differ);
+          entry2 = entry2->next;
+        }
+        if (found)
+          {
+            return;
+          }
+        entry1 = entry1->next;
       }
-    
+
       entry2 = s2->entries;
       while (entry2 != NULL) {
-	entry1 = subtypeEntryInsert(s1);
-	
-	att_ptr2 = entry2->atts;
-	while (att_ptr2 != NULL) {
-	  (void) subtypeAttrInsert(entry1, att_ptr2->key, att_ptr2->val);
-	  att_ptr2 = att_ptr2->next;
-	}
-	entry2 = entry2->next;
+        entry1 = subtypeEntryInsert(s1);
+
+        att_ptr2 = entry2->atts;
+        while (att_ptr2 != NULL) {
+          (void) subtypeAttrInsert(entry1, att_ptr2->key, att_ptr2->val);
+          att_ptr2 = att_ptr2->next;
+        }
+        entry2 = entry2->next;
       }
     }
   else
@@ -655,7 +655,7 @@ void tilesetInsertP(subtype_t *s1, subtype_t *s2)
 
 
 /* ------------------------------------------------------------------- */
-/* IMPLEMENTATIONS FOR ROUTINES VISIBLE THROUGH CDI.H		       */
+/* IMPLEMENTATIONS FOR ROUTINES VISIBLE THROUGH CDI.H                  */
 /* ------------------------------------------------------------------- */
 
 
@@ -750,22 +750,22 @@ int subtypeInqSubEntry(int subtypeID, subtype_query_t criterion)
       int match = 1;
       /* test if this entry matches ALL criteria. */
       for (int j=0; (j<criterion.nAND) && (match); j++)
-	{
-	  if (CDI_Debug)  Message("check criterion %d :  %d --?-- %d", j,
-				  criterion.key_value_pairs[0][j], criterion.key_value_pairs[1][j]);
-	  struct subtype_attr_t* att_ptr = 
-	    subtypeAttrFind(entry->atts, criterion.key_value_pairs[0][j]);
-	  if (att_ptr == NULL)
-	    {
-	      match = 0;
-	      if (CDI_Debug)  Message("did not find %d", criterion.key_value_pairs[0][j]);
-	    }
-	  else
-	    {
-	      if (CDI_Debug)  Message("found %d", criterion.key_value_pairs[0][j]);
-	      match &= (att_ptr->val == criterion.key_value_pairs[1][j]);
-	    }
-	}
+        {
+          if (CDI_Debug)  Message("check criterion %d :  %d --?-- %d", j,
+                                  criterion.key_value_pairs[0][j], criterion.key_value_pairs[1][j]);
+          struct subtype_attr_t* att_ptr =
+            subtypeAttrFind(entry->atts, criterion.key_value_pairs[0][j]);
+          if (att_ptr == NULL)
+            {
+              match = 0;
+              if (CDI_Debug)  Message("did not find %d", criterion.key_value_pairs[0][j]);
+            }
+          else
+            {
+              if (CDI_Debug)  Message("found %d", criterion.key_value_pairs[0][j]);
+              match &= (att_ptr->val == criterion.key_value_pairs[1][j]);
+            }
+        }
       if (match) return entry->self;
     }
     entry = entry->next;
@@ -777,10 +777,50 @@ int subtypeInqSubEntry(int subtypeID, subtype_query_t criterion)
 int subtypeInqTile(int subtypeID, int tileindex, int attribute)
 {
   return subtypeInqSubEntry(subtypeID, 
-			    matchAND(keyValuePair(cdiSubtypeAttributeName[SUBTYPE_ATT_TILEINDEX], tileindex),
-				     keyValuePair(cdiSubtypeAttributeName[SUBTYPE_ATT_TILEATTRIBUTE], attribute)));
+                            matchAND(keyValuePair(cdiSubtypeAttributeName[SUBTYPE_ATT_TILEINDEX], tileindex),
+                                     keyValuePair(cdiSubtypeAttributeName[SUBTYPE_ATT_TILEATTRIBUTE], attribute)));
 }
 
+int subtypeInqAttribute(int subtypeID, int index, const char* key, int* outValue)
+{
+  //Validate input params.
+  if(subtypeID == CDI_UNDEFID) xabort("CDI_UNDEFID was passed to %s() as a subtypeID. Please check the origin of that ID.", __func__);
+  subtype_t *subtype_ptr = (subtype_t *)reshGetVal(subtypeID, &subtypeOps);
+  if(!subtype_ptr) xabort("Internal error: subtypeID %d resolved to NULL.", subtypeID);
+
+  if((unsigned)index >= (unsigned)subtype_ptr->nentries)
+    {
+      xabort("index argument of %s() is out of range. Expected 0 <= index < %d, but got index = %d.", __func__, subtype_ptr->nentries, index);
+    }
+
+#ifndef __cplusplus
+  if(!outValue) outValue = &(int){0};
+#else
+  int dummy = 0;
+  if(!outValue) outValue = &dummy;
+#endif
+
+  if(!key) return CDI_EINVAL;
+  int iKey = attribute_to_index(key);
+  if(iKey < 0) return CDI_EINVAL;
+
+  //Find the entry.
+  struct subtype_entry_t* entry = subtype_ptr->entries;
+  for(; index--; entry = entry->next) if(!entry) xabort("internal error: preliminary end of subtype entry list");
+
+  //Find the attribute.
+  for(struct subtype_attr_t* attribute = entry->atts; attribute; attribute = attribute->next)
+    {
+      if(attribute->key == iKey)
+        {
+          *outValue = attribute->val;
+          return CDI_NOERR;
+        }
+    }
+
+  //Failed to find the attribute if this point is reached.
+  return CDI_EINVAL;
+}
 
 /* Construct a new subtype for a tile set. If a corresponding subtype
  * already exists, then we return this subtype ID instead. 
@@ -837,7 +877,7 @@ int vlistInsertTrivialTileSubtype(int vlistID)
 
 
 /* ------------------------------------------------------------------- */
-/* NOT YET IMPLEMENTED						       */
+/* NOT YET IMPLEMENTED                                                 */
 /* ------------------------------------------------------------------- */
 
 static int subtypeGetPackSize( void * subtype_ptr, void *context)
diff --git a/libcdi/src/table.c b/libcdi/src/table.c
index 2babc18..a3eb991 100644
--- a/libcdi/src/table.c
+++ b/libcdi/src/table.c
@@ -360,7 +360,7 @@ int tableRead(const char *tablefile)
       */
       if ( id == 0 ) continue;
 
-      while ( isdigit((int) *pline) ) pline++; 
+      while ( isdigit((int) *pline) ) pline++;
 
       if ( strchr(pline, '|') )
 	err = decodeForm2(pline, name, longname, units);
@@ -369,7 +369,7 @@ int tableRead(const char *tablefile)
 
       if ( err ) continue;
 
-      if ( name[0] ) sprintf(name, "var%d", id);
+      if ( name[0] == 0 ) sprintf(name, "var%d", id);
 
       tableDefEntry(tableID, id, name, longname, units);
     }
diff --git a/libcdi/src/table.h b/libcdi/src/table.h
index faebeff..0c624f8 100644
--- a/libcdi/src/table.h
+++ b/libcdi/src/table.h
@@ -1,3 +1,4 @@
+/* Automatically generated, do not edit! */
 #ifndef _TABLE_H
 #define _TABLE_H
 
@@ -552,177 +553,177 @@ static const PAR mpiom1[] = {
 };
 
 static const PAR ecmwf[] = {
-  {   1, 0, "STRF",   "Stream function",                                            "m**2 s**-1"            },
-  {   2, 0, "VPOT",   "Velocity potential",                                         "m**2 s**-1"            },
-  {   3, 0, "PT",     "Potential temperature",                                      "K"                     },
-  {   4, 0, "EQPT",   "Equivalent potential temperature",                           "K"                     },
-  {   5, 0, "SEPT",   "Saturated equivalent potential temperature",                 "K"                     },
-  {  11, 0, "UDVW",   "U component of divergent wind",                              "m s**-1"               },
-  {  12, 0, "VDVW",   "V component of divergent wind",                              "m s**-1"               },
-  {  13, 0, "URTW",   "U component of rotational wind",                             "m s**-1"               },
-  {  14, 0, "VRTW",   "V component of rotational wind",                             "m s**-1"               },
-  {  21, 0, "UCTP",   "Unbalanced component of temperature",                        "K"                     },
-  {  22, 0, "UCLN",   "Unbalanced component of logarithm of surface pressure",       NULL                   },
-  {  23, 0, "UCDV",   "Unbalanced component of divergence",                         "s**-1"                 },
-  {  26, 0, "CL",     "Lake cover",                                                  NULL                   },
-  {  27, 0, "CVL",    "Low vegetation cover",                                        NULL                   },
-  {  28, 0, "CVH",    "High vegetation cover",                                       NULL                   },
-  {  29, 0, "TVL",    "Type of low vegetation",                                      NULL                   },
-  {  30, 0, "TVH",    "Type of high vegetation",                                     NULL                   },
-  {  31, 0, "CI",     "Sea-ice cover",                                               NULL                   },
-  {  32, 0, "ASN",    "Snow albedo",                                                 NULL                   },
-  {  33, 0, "RSN",    "Snow density kg",                                            "m**-3"                 },
-  {  34, 0, "SSTK",   "Sea surface temperature",                                    "K"                     },
-  {  35, 0, "ISTL1",  "Ice surface temperature layer 1",                            "K"                     },
-  {  36, 0, "ISTL2",  "Ice surface temperature layer 2",                            "K"                     },
-  {  37, 0, "ISTL3",  "Ice surface temperature layer 3",                            "K"                     },
-  {  38, 0, "ISTL4",  "Ice surface temperature layer 4",                            "K"                     },
-  {  39, 0, "SWVL1",  "Volumetric soil water layer 1",                              "m**3 m**-3"            },
-  {  40, 0, "SWVL2",  "Volumetric soil water layer 2",                              "m**3 m**-3"            },
-  {  41, 0, "SWVL3",  "Volumetric soil water layer 3",                              "m**3 m**-3"            },
-  {  42, 0, "SWVL4",  "Volumetric soil water layer 4",                              "m**3 m**-3"            },
-  {  43, 0, "SLT",    "Soil type",                                                   NULL                   },
-  {  44, 0, "ES",     "Snow evaporation m of water",                                 NULL                   },
-  {  45, 0, "SMLT",   "Snowmelt m of water",                                         NULL                   },
-  {  46, 0, "SDUR",   "Solar duration",                                             "s"                     },
-  {  47, 0, "DSRP",   "Direct solar radiation",                                     "w m**-2"               },
-  {  48, 0, "MAGSS",  "Magnitude of surface stress",                                "N m**-2 s"             },
-  {  49, 0, "WG10",   "Wind gust at 10 metres",                                     "m s**-1"               },
-  {  50, 0, "LSPF",   "Large-scale precipitation fraction",                         "s"                     },
-  {  51, 0, "MX2T24", "Maximum 2 metre temperature",                                "K"                     },
-  {  52, 0, "MN2T24", "Minimum 2 metre temperature",                                "K"                     },
-  {  53, 0, "MONT",   "Montgomery potential",                                       "m**2 s**-2"            },
-  {  54, 0, "PRES",   "Pressure",                                                   "Pa"                    },
-  {  55, 0, "MN2T24", "Mean 2 metre temperature past 24 hours",                     "K"                     },
-  {  56, 0, "MN2D24", "Mean 2 metre dewpoint temperature past 24 hours",            "K"                     },
-  {  60, 0, "PV",     "Potential vorticity",                                        "K m**2 kg**-1 s**-1"   },
-  { 127, 0, "AT",     "Atmospheric tide",                                            NULL                   },
-  { 128, 0, "BV",     "Budget values",                                               NULL                   },
-  { 129, 0, "Z",      "Geopotential",                                               "m**2 s**-2"            },
-  { 130, 0, "T",      "Temperature",                                                "K"                     },
-  { 131, 0, "U",      "U velocity",                                                 "m s**-1"               },
-  { 132, 0, "V",      "V velocity",                                                 "m s**-1"               },
-  { 133, 0, "Q",      "Specific humidity",                                          "kg kg**-1"             },
-  { 134, 0, "SP",     "Surface pressure",                                           "Pa"                    },
-  { 135, 0, "W",      "Vertical velocity",                                          "Pa s**-1"              },
-  { 136, 0, "TCW",    "Total column water",                                         "kg m**-2"              },
-  { 137, 0, "TCWV",   "Total column water vapour",                                  "kg m**-2"              },
-  { 138, 0, "VO",     "Vorticity (relative)",                                       "s**-1"                 },
-  { 139, 0, "STL1",   "Soil temperature level 1",                                   "K"                     },
-  { 140, 0, "SWL1",   "Soil wetness level 1 m of water",                             NULL                   },
-  { 141, 0, "SD",     "Snow depth         1 m of water equivalent",                  NULL                   },
-  { 142, 0, "LSP",    "Stratiform precipitation (Large scale precipitation)",       "m"                     },
-  { 143, 0, "CP",     "Convective precipitation",                                   "m"                     },
-  { 144, 0, "SF",     "Snowfall (convective + stratiform)",                         "m"                     },
-  { 145, 0, "BLD",    "Boundary layer dissipation",                                 "W m**-2 s"             },
-  { 146, 0, "SSHF",   "Surface sensible heat flux",                                 "W m**-2 s"             },
-  { 147, 0, "SLHF",   "Surface latent heat flux",                                   "W m**-2 s"             },
-  { 148, 0, "CHNK",   "Charnock",                                                    NULL                   },
-  { 149, 0, "SNR",    "Surface net radiation",                                      "W m**-2 s"             },
-  { 150, 0, "TNR",    "Top net radiation",                                           NULL                   },
-  { 151, 0, "MSL",    "Mean sea-level pressure",                                    "Pa"                    },
-  { 152, 0, "LNSP",   "Logarithm of surface pressure",                               NULL                   },
-  { 153, 0, "SWHR",   "Short-wave heating rate",                                    "K"                     },
-  { 154, 0, "LWHR",   "Long-wave heating rate",                                     "K"                     },
-  { 155, 0, "D",      "Divergence",                                                 "s**-1"                 },
-  { 156, 0, "GH",     "Height m Geopotential height",                                NULL                   },
-  { 157, 0, "R",      "Relative humidity",                                          "%"                     },
-  { 158, 0, "TSP",    "Tendency of surface pressure",                               "Pa s**-1"              },
-  { 159, 0, "BLH",    "Boundary layer height",                                      "m"                     },
-  { 160, 0, "SDOR",   "Standard deviation of orography",                             NULL                   },
-  { 161, 0, "ISOR",   "Anisotropy of sub-gridscale orography",                       NULL                   },
-  { 162, 0, "ANOR",   "Angle of sub-gridscale orography",                           "rad"                   },
-  { 163, 0, "SLOR",   "Slope of sub-gridscale orography",                            NULL                   },
-  { 164, 0, "TCC",    "Total cloud cover",                                           NULL                   },
-  { 165, 0, "U10M",   "10 metre U wind component",                                  "m s**-1"               },
-  { 166, 0, "V10M",   "10 metre V wind component",                                  "m s**-1"               },
-  { 167, 0, "T2M",    "2 metre temperature",                                        "K"                     },
-  { 168, 0, "D2M",    "2 metre dewpoint temperature",                               "K"                     },
-  { 169, 0, "SSRD",   "Surface solar radiation downwards",                          "W m**-2 s"             },
-  { 170, 0, "STL2",   "Soil temperature level 2",                                   "K"                     },
-  { 171, 0, "SWL2",   "Soil wetness level 2",                                       "m of water"            },
-  { 172, 0, "LSM",    "Land/sea mask",                                               NULL                   },
-  { 173, 0, "SR",     "Surface roughness",                                          "m"                     },
-  { 174, 0, "AL",     "Albedo",                                                      NULL                   },
-  { 175, 0, "STRD",   "Surface thermal radiation downwards",                        "W m**-2 s"             },
-  { 176, 0, "SSR",    "Surface solar radiation",                                    "W m**-2 s"             },
-  { 177, 0, "STR",    "Surface thermal radiation",                                  "W m**-2 s"             },
-  { 178, 0, "TSR",    "Top solar radiation",                                        "W m**-2 s"             },
-  { 179, 0, "TTR",    "Top thermal radiation",                                      "W m**-2 s"             },
-  { 180, 0, "EWSS",   "East/West surface stress",                                   "N m**-2 s"             },
-  { 181, 0, "NSSS",   "North/South surface stress",                                 "N m**-2 s"             },
-  { 182, 0, "E",      "Evaporation",                                                "m of water"            },
-  { 183, 0, "STL3",   "Soil temperature level 3",                                   "K"                     },
-  { 184, 0, "SWL3",   "Soil wetness level 3",                                       "m of water"            },
-  { 185, 0, "CCC",    "Convective cloud cover",                                      NULL                   },
-  { 186, 0, "LCC",    "Low cloud cover",                                             NULL                   },
-  { 187, 0, "MCC",    "Medium cloud cover",                                          NULL                   },
-  { 188, 0, "HCC",    "High cloud cover",                                            NULL                   },
-  { 189, 0, "SUND",   "Sunshine duration",                                          "s"                     },
-  { 190, 0, "EWOV",   "EW component of subgrid orographic variance",                "m**2"                  },
-  { 191, 0, "NSOV",   "NS component of subgrid orographic variance",                "m**2"                  },
-  { 192, 0, "NWOV",   "NWSE component of subgrid orographic variance",              "m**2"                  },
-  { 193, 0, "NEOV",   "NESW component of subgrid orographic variance",              "m**2"                  },
-  { 194, 0, "BTMP",   "Brightness temperature",                                     "K"                     },
-  { 195, 0, "LGWS",   "Lat. component of gravity wave stress",                      "N m**-2 s"             },
-  { 196, 0, "MGWS",   "Meridional component of gravity wave stress",                "N m**-2 s"             },
-  { 197, 0, "GWD",    "Gravity wave dissipation",                                   "W m**-2 s"             },
-  { 198, 0, "SRC",    "Skin reservoir content",                                     "m of water"            },
-  { 199, 0, "VEG",    "Vegetation fraction",                                         NULL                   },
-  { 200, 0, "VSO",    "Variance of sub-gridscale orography",                        "m**2"                  },
-  { 201, 0, "MX2T",   "Maximum 2 metre temperature since previous post-processing", "K"                     },
-  { 202, 0, "MN2T",   "Minimum 2 metre temperature since previous post-processing", "K"                     },
-  { 203, 0, "O3",     "Ozone mass mixing ratio",                                    "kg kg**-1"             },
-  { 204, 0, "PAW",    "Precipiation analysis weights",                               NULL                   },
-  { 205, 0, "RO",     "Runoff",                                                     "m"                     },
-  { 206, 0, "TCO3",   "Total column ozone",                                         "kg m**-2"              },
-  { 207, 0, "WS10",   "10 meter windspeed",                                         "m s**-1"               },
-  { 208, 0, "TSRC",   "Top net solar radiation, clear sky",                         "W m**-2"               },
-  { 209, 0, "TTRC",   "Top net thermal radiation, clear sky",                       "W m**-2"               },
-  { 210, 0, "SSRC",   "Surface net solar radiation, clear sky",                     "W m**-2"               },
-  { 211, 0, "STRC",   "Surface net thermal radiation, clear sky",                   "W m**-2"               },
-  { 212, 0, "SI",     "Solar insolation",                                           "W m**-2"               },
-  { 214, 0, "DHR",    "Diabatic heating by radiation",                              "K"                     },
-  { 215, 0, "DHVD",   "Diabatic heating by vertical diffusion",                     "K"                     },
-  { 216, 0, "DHCC",   "Diabatic heating by cumulus convection",                     "K"                     },
-  { 217, 0, "DHLC",   "Diabatic heating large-scale condensation",                  "K"                     },
-  { 218, 0, "VDZW",   "Vertical diffusion of zonal wind",                           "m s**-1"               },
-  { 219, 0, "VDMW",   "Vertical diffusion of meridional wind",                      "m s**-1"               },
-  { 220, 0, "EWGD",   "EW gravity wave drag tendency",                              "m s**-1"               },
-  { 221, 0, "NSGD",   "NS gravity wave drag tendency",                              "m s**-1"               },
-  { 222, 0, "CTZW",   "Convective tendency of zonal wind",                          "m s**-1"               },
-  { 223, 0, "CTMW",   "Convective tendency of meridional wind",                     "m s**-1"               },
-  { 224, 0, "VDH",    "Vertical diffusion of humidity",                             "kg kg**-1"             },
-  { 225, 0, "HTCC",   "Humidity tendency by cumulus convection",                    "kg kg**-1"             },
-  { 226, 0, "HTLC",   "Humidity tendency large-scale condensation",                 "kg kg**-1"             },
-  { 227, 0, "CRNH",   "Change from removing negative humidity",                     "kg kg**-1"             },
-  { 228, 0, "TP",     "Total precipitation",                                        "m"                     },
-  { 229, 0, "IEWS",   "Instantaneous X surface stress",                             "N m**-2"               },
-  { 230, 0, "INSS",   "Instantaneous Y surface stress",                             "N m**-2"               },
-  { 231, 0, "ISHF",   "Instantaneous surface heat flux",                            "W m**-2"               },
-  { 232, 0, "IE",     "Instantaneous moisture flux",                                "kg m**-2 s"            },
-  { 233, 0, "ASQ",    "Apparent surface humidity",                                  "kg kg**-1"             },
-  { 234, 0, "LSRH",   "Logarithm of surface roughness length for heat",              NULL                   },
-  { 235, 0, "SKT",    "Skin temperature",                                           "K"                     },
-  { 236, 0, "STL4",   "Soil temperature level 4",                                   "K"                     },
-  { 237, 0, "SWL4",   "Soil wetness level 4",                                       "m"                     },
-  { 238, 0, "TSN",    "Temperature of snow layer",                                  "K"                     },
-  { 239, 0, "CSF",    "Convective snowfall",                                        "m of water equivalent" },
-  { 240, 0, "LSF",    "Large-scale snowfall",                                       "m of water equivalent" },
-  { 241, 0, "ACF",    "Accumulated cloud fraction tendency",                         NULL                   },
-  { 242, 0, "ALW",    "Accumulated liquid water tendency",                           NULL                   },
-  { 243, 0, "FAL",    "Forecast albedo",                                             NULL                   },
-  { 244, 0, "FSR",    "Forecast surface roughness",                                 "m"                     },
-  { 245, 0, "FLSR",   "Forecast log of surface roughness for heat",                  NULL                   },
-  { 246, 0, "CLWC",   "Cloud liquid water content",                                 "kg kg**-1"             },
-  { 247, 0, "CIWC",   "Cloud ice water content",                                    "kg kg**-1"             },
-  { 248, 0, "CC",     "Cloud cover",                                                 NULL                   },
-  { 249, 0, "AIW",    "Accumulated ice water tendency",                              NULL                   },
-  { 250, 0, "ICE",    "Ice age",                                                     NULL                   },
-  { 251, 0, "ATTE",   "Adiabatic tendency of temperature",                          "K"                     },
-  { 252, 0, "ATHE",   "Adiabatic tendency of humidity",                             "kg kg**-1"             },
-  { 253, 0, "ATZE",   "Adiabatic tendency of zonal wind",                           "m s**-1"               },
-  { 254, 0, "ATMW",   "Adiabatic tendency of meridional wind",                      "m s**-1"               },
+  {   1, 0, "STRF",     "Stream function",                                            "m**2 s**-1"            },
+  {   2, 0, "VPOT",     "Velocity potential",                                         "m**2 s**-1"            },
+  {   3, 0, "PT",       "Potential temperature",                                      "K"                     },
+  {   4, 0, "EQPT",     "Equivalent potential temperature",                           "K"                     },
+  {   5, 0, "SEPT",     "Saturated equivalent potential temperature",                 "K"                     },
+  {  11, 0, "UDVW",     "U component of divergent wind",                              "m s**-1"               },
+  {  12, 0, "VDVW",     "V component of divergent wind",                              "m s**-1"               },
+  {  13, 0, "URTW",     "U component of rotational wind",                             "m s**-1"               },
+  {  14, 0, "VRTW",     "V component of rotational wind",                             "m s**-1"               },
+  {  21, 0, "UCTP",     "Unbalanced component of temperature",                        "K"                     },
+  {  22, 0, "UCLN",     "Unbalanced component of logarithm of surface pressure",       NULL                   },
+  {  23, 0, "UCDV",     "Unbalanced component of divergence",                         "s**-1"                 },
+  {  26, 0, "CL",       "Lake cover",                                                  NULL                   },
+  {  27, 0, "CVL",      "Low vegetation cover",                                        NULL                   },
+  {  28, 0, "CVH",      "High vegetation cover",                                       NULL                   },
+  {  29, 0, "TVL",      "Type of low vegetation",                                      NULL                   },
+  {  30, 0, "TVH",      "Type of high vegetation",                                     NULL                   },
+  {  31, 0, "CI",       "Sea-ice cover",                                               NULL                   },
+  {  32, 0, "ASN",      "Snow albedo",                                                 NULL                   },
+  {  33, 0, "RSN",      "Snow density kg",                                            "m**-3"                 },
+  {  34, 0, "SSTK",     "Sea surface temperature",                                    "K"                     },
+  {  35, 0, "ISTL1",    "Ice surface temperature layer 1",                            "K"                     },
+  {  36, 0, "ISTL2",    "Ice surface temperature layer 2",                            "K"                     },
+  {  37, 0, "ISTL3",    "Ice surface temperature layer 3",                            "K"                     },
+  {  38, 0, "ISTL4",    "Ice surface temperature layer 4",                            "K"                     },
+  {  39, 0, "SWVL1",    "Volumetric soil water layer 1",                              "m**3 m**-3"            },
+  {  40, 0, "SWVL2",    "Volumetric soil water layer 2",                              "m**3 m**-3"            },
+  {  41, 0, "SWVL3",    "Volumetric soil water layer 3",                              "m**3 m**-3"            },
+  {  42, 0, "SWVL4",    "Volumetric soil water layer 4",                              "m**3 m**-3"            },
+  {  43, 0, "SLT",      "Soil type",                                                   NULL                   },
+  {  44, 0, "ES",       "Snow evaporation m of water",                                 NULL                   },
+  {  45, 0, "SMLT",     "Snowmelt m of water",                                         NULL                   },
+  {  46, 0, "SDUR",     "Solar duration",                                             "s"                     },
+  {  47, 0, "DSRP",     "Direct solar radiation",                                     "w m**-2"               },
+  {  48, 0, "MAGSS",    "Magnitude of surface stress",                                "N m**-2 s"             },
+  {  49, 0, "WG10",     "Wind gust at 10 metres",                                     "m s**-1"               },
+  {  50, 0, "LSPF",     "Large-scale precipitation fraction",                         "s"                     },
+  {  51, 0, "MX2T24",   "Maximum 2 metre temperature",                                "K"                     },
+  {  52, 0, "MN2T24",   "Minimum 2 metre temperature",                                "K"                     },
+  {  53, 0, "MONT",     "Montgomery potential",                                       "m**2 s**-2"            },
+  {  54, 0, "PRES",     "Pressure",                                                   "Pa"                    },
+  {  55, 0, "MEAN2T24", "Mean 2 metre temperature past 24 hours",                     "K"                     },
+  {  56, 0, "MEAN2D24", "Mean 2 metre dewpoint temperature past 24 hours",            "K"                     },
+  {  60, 0, "PV",       "Potential vorticity",                                        "K m**2 kg**-1 s**-1"   },
+  { 127, 0, "AT",       "Atmospheric tide",                                            NULL                   },
+  { 128, 0, "BV",       "Budget values",                                               NULL                   },
+  { 129, 0, "Z",        "Geopotential",                                               "m**2 s**-2"            },
+  { 130, 0, "T",        "Temperature",                                                "K"                     },
+  { 131, 0, "U",        "U velocity",                                                 "m s**-1"               },
+  { 132, 0, "V",        "V velocity",                                                 "m s**-1"               },
+  { 133, 0, "Q",        "Specific humidity",                                          "kg kg**-1"             },
+  { 134, 0, "SP",       "Surface pressure",                                           "Pa"                    },
+  { 135, 0, "W",        "Vertical velocity",                                          "Pa s**-1"              },
+  { 136, 0, "TCW",      "Total column water",                                         "kg m**-2"              },
+  { 137, 0, "TCWV",     "Total column water vapour",                                  "kg m**-2"              },
+  { 138, 0, "VO",       "Vorticity (relative)",                                       "s**-1"                 },
+  { 139, 0, "STL1",     "Soil temperature level 1",                                   "K"                     },
+  { 140, 0, "SWL1",     "Soil wetness level 1 m of water",                             NULL                   },
+  { 141, 0, "SD",       "Snow depth         1 m of water equivalent",                  NULL                   },
+  { 142, 0, "LSP",      "Stratiform precipitation (Large scale precipitation)",       "m"                     },
+  { 143, 0, "CP",       "Convective precipitation",                                   "m"                     },
+  { 144, 0, "SF",       "Snowfall (convective + stratiform)",                         "m"                     },
+  { 145, 0, "BLD",      "Boundary layer dissipation",                                 "W m**-2 s"             },
+  { 146, 0, "SSHF",     "Surface sensible heat flux",                                 "W m**-2 s"             },
+  { 147, 0, "SLHF",     "Surface latent heat flux",                                   "W m**-2 s"             },
+  { 148, 0, "CHNK",     "Charnock",                                                    NULL                   },
+  { 149, 0, "SNR",      "Surface net radiation",                                      "W m**-2 s"             },
+  { 150, 0, "TNR",      "Top net radiation",                                           NULL                   },
+  { 151, 0, "MSL",      "Mean sea-level pressure",                                    "Pa"                    },
+  { 152, 0, "LNSP",     "Logarithm of surface pressure",                               NULL                   },
+  { 153, 0, "SWHR",     "Short-wave heating rate",                                    "K"                     },
+  { 154, 0, "LWHR",     "Long-wave heating rate",                                     "K"                     },
+  { 155, 0, "D",        "Divergence",                                                 "s**-1"                 },
+  { 156, 0, "GH",       "Height m Geopotential height",                                NULL                   },
+  { 157, 0, "R",        "Relative humidity",                                          "%"                     },
+  { 158, 0, "TSP",      "Tendency of surface pressure",                               "Pa s**-1"              },
+  { 159, 0, "BLH",      "Boundary layer height",                                      "m"                     },
+  { 160, 0, "SDOR",     "Standard deviation of orography",                             NULL                   },
+  { 161, 0, "ISOR",     "Anisotropy of sub-gridscale orography",                       NULL                   },
+  { 162, 0, "ANOR",     "Angle of sub-gridscale orography",                           "rad"                   },
+  { 163, 0, "SLOR",     "Slope of sub-gridscale orography",                            NULL                   },
+  { 164, 0, "TCC",      "Total cloud cover",                                           NULL                   },
+  { 165, 0, "U10M",     "10 metre U wind component",                                  "m s**-1"               },
+  { 166, 0, "V10M",     "10 metre V wind component",                                  "m s**-1"               },
+  { 167, 0, "T2M",      "2 metre temperature",                                        "K"                     },
+  { 168, 0, "D2M",      "2 metre dewpoint temperature",                               "K"                     },
+  { 169, 0, "SSRD",     "Surface solar radiation downwards",                          "W m**-2 s"             },
+  { 170, 0, "STL2",     "Soil temperature level 2",                                   "K"                     },
+  { 171, 0, "SWL2",     "Soil wetness level 2",                                       "m of water"            },
+  { 172, 0, "LSM",      "Land/sea mask",                                               NULL                   },
+  { 173, 0, "SR",       "Surface roughness",                                          "m"                     },
+  { 174, 0, "AL",       "Albedo",                                                      NULL                   },
+  { 175, 0, "STRD",     "Surface thermal radiation downwards",                        "W m**-2 s"             },
+  { 176, 0, "SSR",      "Surface solar radiation",                                    "W m**-2 s"             },
+  { 177, 0, "STR",      "Surface thermal radiation",                                  "W m**-2 s"             },
+  { 178, 0, "TSR",      "Top solar radiation",                                        "W m**-2 s"             },
+  { 179, 0, "TTR",      "Top thermal radiation",                                      "W m**-2 s"             },
+  { 180, 0, "EWSS",     "East/West surface stress",                                   "N m**-2 s"             },
+  { 181, 0, "NSSS",     "North/South surface stress",                                 "N m**-2 s"             },
+  { 182, 0, "E",        "Evaporation",                                                "m of water"            },
+  { 183, 0, "STL3",     "Soil temperature level 3",                                   "K"                     },
+  { 184, 0, "SWL3",     "Soil wetness level 3",                                       "m of water"            },
+  { 185, 0, "CCC",      "Convective cloud cover",                                      NULL                   },
+  { 186, 0, "LCC",      "Low cloud cover",                                             NULL                   },
+  { 187, 0, "MCC",      "Medium cloud cover",                                          NULL                   },
+  { 188, 0, "HCC",      "High cloud cover",                                            NULL                   },
+  { 189, 0, "SUND",     "Sunshine duration",                                          "s"                     },
+  { 190, 0, "EWOV",     "EW component of subgrid orographic variance",                "m**2"                  },
+  { 191, 0, "NSOV",     "NS component of subgrid orographic variance",                "m**2"                  },
+  { 192, 0, "NWOV",     "NWSE component of subgrid orographic variance",              "m**2"                  },
+  { 193, 0, "NEOV",     "NESW component of subgrid orographic variance",              "m**2"                  },
+  { 194, 0, "BTMP",     "Brightness temperature",                                     "K"                     },
+  { 195, 0, "LGWS",     "Lat. component of gravity wave stress",                      "N m**-2 s"             },
+  { 196, 0, "MGWS",     "Meridional component of gravity wave stress",                "N m**-2 s"             },
+  { 197, 0, "GWD",      "Gravity wave dissipation",                                   "W m**-2 s"             },
+  { 198, 0, "SRC",      "Skin reservoir content",                                     "m of water"            },
+  { 199, 0, "VEG",      "Vegetation fraction",                                         NULL                   },
+  { 200, 0, "VSO",      "Variance of sub-gridscale orography",                        "m**2"                  },
+  { 201, 0, "MX2T",     "Maximum 2 metre temperature since previous post-processing", "K"                     },
+  { 202, 0, "MN2T",     "Minimum 2 metre temperature since previous post-processing", "K"                     },
+  { 203, 0, "O3",       "Ozone mass mixing ratio",                                    "kg kg**-1"             },
+  { 204, 0, "PAW",      "Precipiation analysis weights",                               NULL                   },
+  { 205, 0, "RO",       "Runoff",                                                     "m"                     },
+  { 206, 0, "TCO3",     "Total column ozone",                                         "kg m**-2"              },
+  { 207, 0, "WS10",     "10 meter windspeed",                                         "m s**-1"               },
+  { 208, 0, "TSRC",     "Top net solar radiation, clear sky",                         "W m**-2"               },
+  { 209, 0, "TTRC",     "Top net thermal radiation, clear sky",                       "W m**-2"               },
+  { 210, 0, "SSRC",     "Surface net solar radiation, clear sky",                     "W m**-2"               },
+  { 211, 0, "STRC",     "Surface net thermal radiation, clear sky",                   "W m**-2"               },
+  { 212, 0, "SI",       "Solar insolation",                                           "W m**-2"               },
+  { 214, 0, "DHR",      "Diabatic heating by radiation",                              "K"                     },
+  { 215, 0, "DHVD",     "Diabatic heating by vertical diffusion",                     "K"                     },
+  { 216, 0, "DHCC",     "Diabatic heating by cumulus convection",                     "K"                     },
+  { 217, 0, "DHLC",     "Diabatic heating large-scale condensation",                  "K"                     },
+  { 218, 0, "VDZW",     "Vertical diffusion of zonal wind",                           "m s**-1"               },
+  { 219, 0, "VDMW",     "Vertical diffusion of meridional wind",                      "m s**-1"               },
+  { 220, 0, "EWGD",     "EW gravity wave drag tendency",                              "m s**-1"               },
+  { 221, 0, "NSGD",     "NS gravity wave drag tendency",                              "m s**-1"               },
+  { 222, 0, "CTZW",     "Convective tendency of zonal wind",                          "m s**-1"               },
+  { 223, 0, "CTMW",     "Convective tendency of meridional wind",                     "m s**-1"               },
+  { 224, 0, "VDH",      "Vertical diffusion of humidity",                             "kg kg**-1"             },
+  { 225, 0, "HTCC",     "Humidity tendency by cumulus convection",                    "kg kg**-1"             },
+  { 226, 0, "HTLC",     "Humidity tendency large-scale condensation",                 "kg kg**-1"             },
+  { 227, 0, "CRNH",     "Change from removing negative humidity",                     "kg kg**-1"             },
+  { 228, 0, "TP",       "Total precipitation",                                        "m"                     },
+  { 229, 0, "IEWS",     "Instantaneous X surface stress",                             "N m**-2"               },
+  { 230, 0, "INSS",     "Instantaneous Y surface stress",                             "N m**-2"               },
+  { 231, 0, "ISHF",     "Instantaneous surface heat flux",                            "W m**-2"               },
+  { 232, 0, "IE",       "Instantaneous moisture flux",                                "kg m**-2 s"            },
+  { 233, 0, "ASQ",      "Apparent surface humidity",                                  "kg kg**-1"             },
+  { 234, 0, "LSRH",     "Logarithm of surface roughness length for heat",              NULL                   },
+  { 235, 0, "SKT",      "Skin temperature",                                           "K"                     },
+  { 236, 0, "STL4",     "Soil temperature level 4",                                   "K"                     },
+  { 237, 0, "SWL4",     "Soil wetness level 4",                                       "m"                     },
+  { 238, 0, "TSN",      "Temperature of snow layer",                                  "K"                     },
+  { 239, 0, "CSF",      "Convective snowfall",                                        "m of water equivalent" },
+  { 240, 0, "LSF",      "Large-scale snowfall",                                       "m of water equivalent" },
+  { 241, 0, "ACF",      "Accumulated cloud fraction tendency",                         NULL                   },
+  { 242, 0, "ALW",      "Accumulated liquid water tendency",                           NULL                   },
+  { 243, 0, "FAL",      "Forecast albedo",                                             NULL                   },
+  { 244, 0, "FSR",      "Forecast surface roughness",                                 "m"                     },
+  { 245, 0, "FLSR",     "Forecast log of surface roughness for heat",                  NULL                   },
+  { 246, 0, "CLWC",     "Cloud liquid water content",                                 "kg kg**-1"             },
+  { 247, 0, "CIWC",     "Cloud ice water content",                                    "kg kg**-1"             },
+  { 248, 0, "CC",       "Cloud cover",                                                 NULL                   },
+  { 249, 0, "AIW",      "Accumulated ice water tendency",                              NULL                   },
+  { 250, 0, "ICE",      "Ice age",                                                     NULL                   },
+  { 251, 0, "ATTE",     "Adiabatic tendency of temperature",                          "K"                     },
+  { 252, 0, "ATHE",     "Adiabatic tendency of humidity",                             "kg kg**-1"             },
+  { 253, 0, "ATZE",     "Adiabatic tendency of zonal wind",                           "m s**-1"               },
+  { 254, 0, "ATMW",     "Adiabatic tendency of meridional wind",                      "m s**-1"               },
 };
 
 static const PAR remo[] = {
@@ -1224,7 +1225,8 @@ static const PAR cosmo250[] = {
 };
 
 
-static void tableDefault(void)
+static
+void tableDefault(void)
 {
   int tableID, instID, modelID;
 
@@ -1423,12 +1425,3 @@ static void tableDefault(void)
 }
 
 #endif  /* _TABLE_H */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
diff --git a/libcdi/src/taxis.c b/libcdi/src/taxis.c
index 20167ae..a0db8d5 100644
--- a/libcdi/src/taxis.c
+++ b/libcdi/src/taxis.c
@@ -1008,28 +1008,26 @@ void cdiEncodeTimevalue(int days, int secs, int timeunit, double *timevalue)
     }
 }
 
+
 void timeval2vtime(double timevalue, taxis_t *taxis, int *vdate, int *vtime)
 {
-  int year, month, day, hour, minute, second;
-  int rdate, rtime;
-  int timeunit;
-  int calendar;
-  int julday, secofday, days, secs;
+  int rdate = taxis->rdate;
+  int rtime = taxis->rtime;
 
-  *vdate = 0;
-  *vtime = 0;
-
-  timeunit = (*taxis).unit;
-  calendar = (*taxis).calendar;
-
-  rdate  = (*taxis).rdate;
-  rtime  = (*taxis).rtime;
-
-  if ( rdate == 0 && rtime == 0 && DBL_IS_EQUAL(timevalue, 0.) ) return;
+  if ( DBL_IS_EQUAL(timevalue, 0.) )
+    {
+      *vdate = rdate;
+      *vtime = rtime;
+      return;
+    }
 
+  int year, month, day, hour, minute, second;
   cdiDecodeDate(rdate, &year, &month, &day);
   cdiDecodeTime(rtime, &hour, &minute, &second);
 
+  int timeunit = taxis->unit;
+  int calendar = taxis->calendar;
+
   if ( timeunit == TUNIT_MONTH && calendar == CALENDAR_360DAYS )
     {
       timeunit = TUNIT_DAY;
@@ -1038,24 +1036,22 @@ void timeval2vtime(double timevalue, taxis_t *taxis, int *vdate, int *vtime)
 
   if ( timeunit == TUNIT_MONTH || timeunit == TUNIT_YEAR )
     {
-      int nmon, dpm;
-      double fmon;
-
       if ( timeunit == TUNIT_YEAR ) timevalue *= 12;
 
-      nmon = (int) timevalue;
-      fmon = timevalue - nmon;
+      int nmon = (int) timevalue;
+      double fmon = timevalue - nmon;
 
       month += nmon;
 
       while ( month > 12 ) { month -= 12; year++; }
       while ( month <  1 ) { month += 12; year--; }
 
-      dpm = days_per_month(calendar, year, month);
+      int dpm = days_per_month(calendar, year, month);
       timeunit = TUNIT_DAY;
       timevalue = fmon*dpm;
     }
 
+  int julday, secofday, days, secs;
   encode_caldaysec(calendar, year, month, day, hour, minute, second, &julday, &secofday);
 
   cdiDecodeTimevalue(timeunit, timevalue, &days, &secs);
@@ -1414,50 +1410,49 @@ taxisPrintKernel(taxis_t * taxisptr, FILE * fp)
   taxisInqVdateBounds ( taxisptr->self, &vdate_lb, &vdate_ub);
   taxisInqVtimeBounds ( taxisptr->self, &vtime_lb, &vtime_ub);
 
-  fprintf ( fp, "#\n");
-  fprintf ( fp, "# taxisID %d\n", taxisptr->self);
-  fprintf ( fp, "#\n");
-  fprintf ( fp, "self        = %d\n", taxisptr->self );
-  fprintf ( fp, "used        = %d\n", taxisptr->used );
-  fprintf ( fp, "type        = %d\n", taxisptr->type );
-  fprintf ( fp, "vdate       = %d\n", taxisptr->vdate );
-  fprintf ( fp, "vtime       = %d\n", taxisptr->vtime );
-  fprintf ( fp, "rdate       = %d\n", taxisptr->rdate );
-  fprintf ( fp, "rtime       = %d\n", taxisptr->rtime );
-  fprintf ( fp, "fdate       = %d\n", taxisptr->fdate );
-  fprintf ( fp, "ftime       = %d\n", taxisptr->ftime );
-  fprintf ( fp, "calendar    = %d\n", taxisptr->calendar );
-  fprintf ( fp, "unit        = %d\n", taxisptr->unit );
-  fprintf ( fp, "numavg      = %d\n", taxisptr->numavg );
-  fprintf ( fp, "climatology = %d\n", taxisptr->climatology );
-  fprintf ( fp, "has_bounds  = %d\n", taxisptr->has_bounds );
-  fprintf ( fp, "vdate_lb    = %d\n", vdate_lb );
-  fprintf ( fp, "vtime_lb    = %d\n", vtime_lb );
-  fprintf ( fp, "vdate_ub    = %d\n", vdate_ub );
-  fprintf ( fp, "vtime_ub    = %d\n", vtime_ub );
-  fprintf ( fp, "fc_unit     = %d\n", taxisptr->fc_unit );
-  fprintf ( fp, "fc_period   = %g\n", taxisptr->fc_period );
-  fprintf ( fp, "\n");
-}
-
-static void taxisPrint ( int taxisID )
-{
-  taxis_t * taxisptr;
-
-  taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
-  taxisPrintKernel ( taxisptr, stdout );
+  fprintf(fp,
+          "#\n"
+          "# taxisID %d\n"
+          "#\n"
+          "self        = %d\n"
+          "used        = %d\n"
+          "type        = %d\n"
+          "vdate       = %d\n"
+          "vtime       = %d\n"
+          "rdate       = %d\n"
+          "rtime       = %d\n"
+          "fdate       = %d\n"
+          "ftime       = %d\n"
+          "calendar    = %d\n"
+          "unit        = %d\n"
+          "numavg      = %d\n"
+          "climatology = %d\n"
+          "has_bounds  = %d\n"
+          "vdate_lb    = %d\n"
+          "vtime_lb    = %d\n"
+          "vdate_ub    = %d\n"
+          "vtime_ub    = %d\n"
+          "fc_unit     = %d\n"
+          "fc_period   = %g\n"
+          "\n", taxisptr->self, taxisptr->self,
+          taxisptr->used, taxisptr->type,
+          taxisptr->vdate, taxisptr->vtime,
+          taxisptr->rdate, taxisptr->rtime,
+          taxisptr->fdate, taxisptr->ftime,
+          taxisptr->calendar, taxisptr->unit,
+          taxisptr->numavg, taxisptr->climatology,
+          taxisptr->has_bounds,
+          vdate_lb, vtime_lb, vdate_ub, vtime_ub,
+          taxisptr->fc_unit, taxisptr->fc_period );
 }
 
 static int
 taxisCompareP(void *taxisptr1, void *taxisptr2)
 {
-  taxis_t * t1, * t2;
-
-  t1 = ( taxis_t * ) taxisptr1;
-  t2 = ( taxis_t * ) taxisptr2;
+  const taxis_t *t1 = ( const taxis_t * ) taxisptr1,
+    *t2 = ( const taxis_t * ) taxisptr2;
 
-  xassert ( t1 );
-  xassert ( t2 );
+  xassert ( t1 && t2 );
 
   return ! ( t1->used        == t2->used        &&
 	     t1->type        == t2->type        &&
diff --git a/libcdi/src/timebase.h b/libcdi/src/timebase.h
index 00ebf34..2f750df 100644
--- a/libcdi/src/timebase.h
+++ b/libcdi/src/timebase.h
@@ -3,6 +3,10 @@
 
 #include <inttypes.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* date format:  YYYYMMDD */
 /* time format:  hhmmss   */
 
@@ -22,6 +26,10 @@ double julday_sub(int julday1, int secofday1, int julday2, int secofday2, int *d
 void encode_juldaysec(int calendar, int year, int month, int day, int hour, int minute, int second, int *julday, int *secofday);
 void decode_juldaysec(int calendar, int julday, int secofday, int *year, int *month, int *day, int *hour, int *minute, int *second);
 
+#if defined (__cplusplus)
+}
+#endif
+
 #endif  /* _TIMEBASE_H */
 
 /*
diff --git a/libcdi/src/util.c b/libcdi/src/util.c
index 25f4845..cd8a6d2 100644
--- a/libcdi/src/util.c
+++ b/libcdi/src/util.c
@@ -13,7 +13,7 @@
 
 #include "cdi.h"
 #include "cdi_int.h"
-#include "create_uuid.h"
+#include "cdi_uuid.h"
 #include "dmemory.h"
 #include "binary.h"
 
@@ -67,7 +67,8 @@ enum {
   uuidNumHexChars = 36,
 };
 
-void uuid2str(const unsigned char *uuid, char *uuidstr)
+
+void cdiUUID2Str(const unsigned char *uuid, char *uuidstr)
 {
 
   if ( uuid == NULL || uuidstr == NULL ) return;
@@ -82,7 +83,7 @@ void uuid2str(const unsigned char *uuid, char *uuidstr)
 }
 
 
-int str2uuid(const char *uuidstr, unsigned char *uuid)
+int cdiStr2UUID(const char *uuidstr, unsigned char *uuid)
 {
   if ( uuid == NULL || uuidstr == NULL || strlen(uuidstr) != uuidNumHexChars)
     return -1;
@@ -151,8 +152,7 @@ char* cdiUnescapeSpaces(const char* string, const char** outStringEnd)
 #ifdef HAVE_DECL_UUID_GENERATE
 #include <sys/time.h>
 #include <uuid/uuid.h>
-void
-create_uuid(unsigned char *uuid)
+void cdiCreateUUID(unsigned char *uuid)
 {
   static int uuid_seeded = 0;
   static char uuid_rand_state[31 * sizeof (long)];
@@ -181,8 +181,7 @@ typedef uint8_t u_int8_t;
 typedef uint16_t u_int16_t;
 typedef uint32_t u_int32_t;
 #include <uuid.h>
-void
-create_uuid(unsigned char *uuid)
+void cdiCreateUUID(unsigned char *uuid)
 {
   uint32_t status;
   uuid_create((uuid_t *)(void *)uuid, &status);
@@ -194,8 +193,7 @@ create_uuid(unsigned char *uuid)
 }
 #else
 #include <sys/time.h>
-void
-create_uuid(unsigned char *uuid)
+void cdiCreateUUID(unsigned char *uuid)
 {
   static int uuid_seeded = 0;
   static char uuid_rand_state[31 * sizeof (long)];
diff --git a/libcdi/src/varscan.c b/libcdi/src/varscan.c
index e33e093..d89fa32 100644
--- a/libcdi/src/varscan.c
+++ b/libcdi/src/varscan.c
@@ -8,6 +8,7 @@
 
 #include "cdi.h"
 #include "cdi_int.h"
+#include "cdi_uuid.h"
 #include "dmemory.h"
 #include "resource_handle.h"
 #include "varscan.h"
@@ -395,39 +396,22 @@ int varInsertTileSubtype(vartable_t *vptr, const var_tile_t *tiles)
 {
   if ( tiles == NULL ) return -1;
 
-  int totalno_of_tileattr_pairs = -1;
-  int tileClassification = -1;
-  int numberOfTiles = -1;
-  int numberOfAttributes = -1;
-  int tileindex = -1;
-  int attribute = -1;
-
-  if ( tiles )
-    {
-      totalno_of_tileattr_pairs = tiles->totalno_of_tileattr_pairs;
-      tileClassification =  tiles->tileClassification;
-      numberOfTiles = tiles->numberOfTiles;
-      numberOfAttributes = tiles->numberOfAttributes;
-      tileindex = tiles->tileindex;
-      attribute = tiles->attribute;
-    }
-
   /* first, generate a subtype based on the info in "tiles". */
 
   subtype_t *subtype_ptr;
   subtypeAllocate(&subtype_ptr, SUBTYPE_TILES);
-  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_TOTALNO_OF_TILEATTR_PAIRS, totalno_of_tileattr_pairs);
-  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_TILE_CLASSIFICATION      , tileClassification);
-  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_NUMBER_OF_TILES          , numberOfTiles);
+  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_TOTALNO_OF_TILEATTR_PAIRS, tiles->totalno_of_tileattr_pairs);
+  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_TILE_CLASSIFICATION      , tiles->tileClassification);
+  subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_NUMBER_OF_TILES          , tiles->numberOfTiles);
 
   /*
    * Here, we create a tile set for comparison that contains only one
    * tile/attribute pair (based on "tiles").
    */
   struct subtype_entry_t *entry = subtypeEntryInsert(subtype_ptr);
-  subtypeDefEntryDataP(entry, SUBTYPE_ATT_NUMBER_OF_ATTR,            numberOfAttributes);
-  subtypeDefEntryDataP(entry, SUBTYPE_ATT_TILEINDEX,                 tileindex);
-  subtypeDefEntryDataP(entry, SUBTYPE_ATT_TILEATTRIBUTE,             attribute);
+  subtypeDefEntryDataP(entry, SUBTYPE_ATT_NUMBER_OF_ATTR,            tiles->numberOfAttributes);
+  subtypeDefEntryDataP(entry, SUBTYPE_ATT_TILEINDEX,                 tiles->tileindex);
+  subtypeDefEntryDataP(entry, SUBTYPE_ATT_TILEATTRIBUTE,             tiles->attribute);
 
   if (vptr->tiles == NULL) {
     vptr->tiles = subtype_ptr;
@@ -957,7 +941,7 @@ struct varDefZAxisSearchState
   int zaxistype;
   int nlevels;
   int lbounds;
-  double *levels;
+  const double *levels;
   const char *longname;
   const char *units;
   int ltype;
@@ -980,23 +964,19 @@ varDefZAxisSearch(int id, void *res, void *data)
 }
 
 
-int varDefZaxis(int vlistID, int zaxistype, int nlevels, double *levels, int lbounds,
-		double *levels1, double *levels2, int vctsize, double *vct, char *name,
-		char *longname, const char *units, int prec, int mode, int ltype1)
+int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, int lbounds,
+		const double *levels1, const double *levels2, int vctsize, const double *vct, char *name,
+		const char *longname, const char *units, int prec, int mode, int ltype1)
 {
   /*
     mode: 0 search in vlist and zaxis table
           1 search in zaxis table
    */
   int zaxisdefined = 0;
-  int nzaxis;
   int zaxisID = UNDEFID;
   int zaxisglobdefined = 0;
-  vlist_t *vlistptr;
-
-  vlistptr = vlist_to_pointer(vlistID);
-
-  nzaxis = vlistptr->nzaxis;
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
+  int nzaxis = vlistptr->nzaxis;
 
   if ( mode == 0 )
     for ( int index = 0; index < nzaxis; index++ )
@@ -1047,15 +1027,8 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, double *levels, int lbo
 	      zaxisDefUbounds(zaxisID, levels2);
 	    }
 
-	  if ( zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF )
-	    {
-	      /* if ( vctsize > 0 && vctsize >= 2*(nlevels+1)) */
-	      /* if ( vctsize > 0 && vctsize >= 2*(nlevels)) */
-	      if ( vctsize > 0 )
-		zaxisDefVct(zaxisID, vctsize, vct);
-	      else
-		Warning("VCT missing");
-	    }
+	  if ( (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF) && vctsize > 0 )
+            zaxisDefVct(zaxisID, vctsize, vct);
 
 	  zaxisDefName(zaxisID, name);
 	  zaxisDefLongname(zaxisID, longname);
diff --git a/libcdi/src/varscan.h b/libcdi/src/varscan.h
index 366ceba..c992a7f 100644
--- a/libcdi/src/varscan.h
+++ b/libcdi/src/varscan.h
@@ -15,9 +15,9 @@ void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds,
 void varDefVCT(size_t vctsize, double *vctptr);
 void varDefZAxisReference(int nlev, int nvgrid, unsigned char uuid[CDI_UUID_SIZE]);
 
-int  varDefZaxis(int vlistID, int zaxistype, int nlevels, double *levels, int lbounds,
-		 double *levels1, double *levels2, int vctsize, double *vct, char *name,
-		 char *longname, const char *units, int prec, int mode, int ltype);
+int  varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, int lbounds,
+		 const double *levels1, const double *levels2, int vctsize, const double *vct, char *name,
+		 const char *longname, const char *units, int prec, int mode, int ltype);
 
 void varDefMissval(int varID, double missval);
 void varDefCompType(int varID, int comptype);
diff --git a/libcdi/src/vlist.c b/libcdi/src/vlist.c
index 11e0822..f941413 100644
--- a/libcdi/src/vlist.c
+++ b/libcdi/src/vlist.c
@@ -93,7 +93,8 @@ vlist_t *vlist_to_pointer(int vlistID)
 static
 void vlist_init_entry(vlist_t *vlistptr)
 {
-  vlistptr->locked         = 0;
+  vlistptr->immutable      = 0;
+  vlistptr->internal       = 0;
   vlistptr->self           = CDI_UNDEFID;
   vlistptr->nvars          = 0;
   vlistptr->vars           = NULL;
@@ -158,32 +159,22 @@ static
 void vlist_copy(vlist_t *vlistptr2, vlist_t *vlistptr1)
 {
   int vlistID2 = vlistptr2->self;
+  int vlist2internal = vlistptr2->internal;
   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->atts.nelems = 0;
   vlistptr2->self = vlistID2;
 }
 
-void vlist_lock(int vlistID)
+void cdiVlistMakeInternal(int vlistID)
 {
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-
-  if ( !vlistptr->locked )
-    {
-      vlistptr->locked += 1;
-      reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
-    }
+  vlist_to_pointer(vlistID)->internal = 1;
 }
 
-
-void vlist_unlock(int vlistID)
+void cdiVlistMakeImmutable(int vlistID)
 {
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-
-  if ( vlistptr->locked )
-    {
-      vlistptr->locked -= 1;
-      reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
-    }
+  vlist_to_pointer(vlistID)->immutable = 1;
 }
 
 /*
@@ -277,12 +268,25 @@ void vlistDestroy(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  if ( vlistptr->locked != 0 )
-    Warning("Destroying of a locked object (vlistID=%d) failed!", vlistID);
+  if ( vlistptr->internal )
+    Warning("Attempt to destroy an internal vlist object by the user (vlistID=%d).", vlistID);
   else
     vlist_delete(vlistptr);
 }
 
+// destroy an internal vlist object
+void cdiVlistDestroy_(int vlistID)
+{
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
+
+  if(!vlistptr->internal)
+    Warning("Destroying a vlist object that is owned by the user.\n"
+            "This is most likely because of a missing vlistDestroy() in the application code.\n"
+            "If that's not the case, and you are absolutely certain about it, please report the bug.");
+
+  vlist_delete(vlistptr);
+}
+
 static
 void var_copy_entries(var_t *var2, var_t *var1)
 {
@@ -493,13 +497,8 @@ int vlist_generate_zaxis(int vlistID, int zaxistype, int nlevels, const double *
 	      zaxisDefUbounds(zaxisID, ubounds);
 	    }
 
-	  if ( zaxistype == ZAXIS_HYBRID )
-	    {
-	      if ( vctsize > 0 )
-		zaxisDefVct(zaxisID, vctsize, vct);
-	      else
-		Warning("VCT missing");
-	    }
+	  if ( zaxistype == ZAXIS_HYBRID && vctsize > 0 )
+            zaxisDefVct(zaxisID, vctsize, vct);
 	}
 
       nzaxis = vlistptr->nzaxis;
@@ -730,12 +729,12 @@ void vlistCat(int vlistID2, int vlistID1)
 
       var_copy_entries(&vars2[varID2], &vars1[varID]);
 
-      int nlevs = zaxisInqSize(vars1[varID].zaxisID);
       if ( vars1[varID].levinfo )
         {
-          vars2[varID2].levinfo = (levinfo_t *) Malloc((size_t)nlevs * sizeof(levinfo_t));
+          size_t nlevs = (size_t)zaxisInqSize(vars1[varID].zaxisID);
+          vars2[varID2].levinfo = (levinfo_t *) Malloc(nlevs * sizeof(levinfo_t));
           memcpy(vars2[varID2].levinfo, vars1[varID].levinfo,
-                 (size_t)nlevs * sizeof(levinfo_t));
+                 nlevs * sizeof(levinfo_t));
         }
 
       vars2[varID2].atts.nelems = 0;
@@ -1437,12 +1436,10 @@ int vlistSubtypeIndex(int vlistID, int subtypeID)
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
   int index;
-  for ( index = 0 ; index < vlistptr->nsubtypes ; index++ )
+  for(index = vlistptr->nsubtypes; index--; )
     if ( subtypeID == vlistptr->subtypeIDs[index] ) break;
 
-  if ( index == vlistptr->nsubtypes ) index = -1;
-
-  return (index);
+  return index;
 }
 
 
@@ -1519,6 +1516,7 @@ void vlistUnpack(char * buf, int size, int *position, int originNamespace,
   xassert(!force_id || p->self == targetID);
   if (!force_id)
     targetID = p->self;
+  cdiVlistMakeInternal(p->self);
   p->taxisID = namespaceAdaptKey(tempbuf[2], originNamespace);
   p->tableID = tempbuf[3];
   p->instID = namespaceAdaptKey(tempbuf[4], originNamespace);
diff --git a/libcdi/src/vlist.h b/libcdi/src/vlist.h
index 6fdd5cd..0179579 100644
--- a/libcdi/src/vlist.h
+++ b/libcdi/src/vlist.h
@@ -116,7 +116,10 @@ var_t;
 
 typedef struct
 {
-  int         locked;
+  //set when a vlist is passed to streamDefVlist() to safeguard against modifications of the wrong vlist object
+  bool    immutable;
+  //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         ngrids;
@@ -138,15 +141,15 @@ vlist_t;
 
 
 vlist_t *vlist_to_pointer(int vlistID);
+void cdiVlistMakeInternal(int vlistID);
+void cdiVlistMakeImmutable(int vlistID);
 void vlistCheckVarID(const char *caller, int vlistID, int varID);
-const char *vlistInqVarNamePtr(int vlistID, int varID);
-const char *vlistInqVarLongnamePtr(int vlistID, int varID);
 const char *vlistInqVarStdnamePtr(int vlistID, int varID);
-const char *vlistInqVarUnitsPtr(int vlistID, int varID);
 void     vlistDestroyVarName(int vlistID, int varID);
 void     vlistDestroyVarLongname(int vlistID, int varID);
 void     vlistDestroyVarStdname(int vlistID, int varID);
 void     vlistDestroyVarUnits(int vlistID, int varID);
+void     cdiVlistDestroy_(int vlistID);
 void     vlistDefVarTsteptype(int vlistID, int varID, int tsteptype);
 int      vlistInqVarMissvalUsed(int vlistID, int varID);
 int      vlistHasTime(int vlistID);
@@ -167,9 +170,6 @@ void vlistInqVarDimorder(int vlistID, int varID, int (*outDimorder)[3]);
 
 int vlist_att_compare(vlist_t *a, int varIDA, vlist_t *b, int varIDB, int attnum);
 
-void vlist_lock(int vlistID);
-void vlist_unlock(int vlistID);
-
 void resize_opt_grib_entries(var_t *var, int nentries);
 
 
diff --git a/libcdi/src/vlist_var.c b/libcdi/src/vlist_var.c
index 0d0d309..3ad263e 100644
--- a/libcdi/src/vlist_var.c
+++ b/libcdi/src/vlist_var.c
@@ -637,7 +637,7 @@ The function @func{vlistInqVarStdname} returns the standard name of a variable i
 otherwise the result is an empty string.
 
 @Result
- at func{vlistInqVarName} returns the standard name of the variable to the parameter stdname.
+ at func{vlistInqVarStdname} returns the standard name of the variable to the parameter stdname.
 
 @EndFunction
 */
@@ -1768,9 +1768,10 @@ void vlistDefVarIntKey(int vlistID, int varID, const char *name, int value)
   if (vlistptr == NULL)  Error("Internal error!");
   int idx;
 
-  if ( vlistptr->locked != 0 )
-    Error("User defined vlist object (vlistID=%d) isn't allowed!\n"
-          "Need a CDI internal vlist object from streamInqVlist(streamID).", vlistID);
+  if ( vlistptr->immutable )
+    Error("vlistDefVarIntKey() was called on an immutable vlist object (vlistID = %d)\n"
+          "Either call vlistDefVarIntKey() before passing the vlist object to streamDefVlist(),\n"
+          "or use the stream-internal vlist by calling streamInqVlist().", vlistID);
 
   for ( idx=0; idx<vlistptr->vars[varID].opt_grib_nentries; idx++)
     if ( (strcmp(name, vlistptr->vars[varID].opt_grib_kvpair[idx].keyword) == 0 ) &&
@@ -1830,9 +1831,10 @@ void vlistDefVarDblKey(int vlistID, int varID, const char *name, double value)
   if (vlistptr == NULL)  Error("Internal error!");
   int idx;
 
-  if ( vlistptr->locked != 0 )
-    Error("User defined vlist object (vlistID=%d) isn't allowed!\n"
-          "Need a CDI internal vlist object from streamInqVlist(streamID).", vlistID);
+  if ( vlistptr->immutable )
+    Error("vlistDefVarDblKey() was called on an immutable vlist object (vlistID = %d)\n"
+          "Either call vlistDefVarIntKey() before passing the vlist object to streamDefVlist(),\n"
+          "or use the stream-internal vlist by calling streamInqVlist().", vlistID);
 
   for ( idx=0; idx<vlistptr->vars[varID].opt_grib_nentries; idx++)
     if ( (strcmp(name, vlistptr->vars[varID].opt_grib_kvpair[idx].keyword) == 0 ) &&
@@ -2026,6 +2028,7 @@ int vlistVarCompare(vlist_t *a, int varIDA, vlist_t *b, int varIDB)
     | FCMPFLT(validrange[0]) | FCMPFLT(validrange[1]);
 #undef FCMP
 #undef FCMPFLT
+#undef FCMPSTR
 #undef FCMP2
   if ((diff |= ((pva->levinfo == NULL) ^ (pvb->levinfo == NULL))))
     return 1;
diff --git a/libcdi/src/zaxis.c b/libcdi/src/zaxis.c
index d61a5b9..10bdeaa 100644
--- a/libcdi/src/zaxis.c
+++ b/libcdi/src/zaxis.c
@@ -11,6 +11,7 @@
 #include "cdi.h"
 #include "cdi_cksum.h"
 #include "cdi_int.h"
+#include "cdi_uuid.h"
 #include "resource_handle.h"
 #include "resource_unpack.h"
 #include "varscan.h"
@@ -1194,7 +1195,6 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
   unsigned char uuid[CDI_UUID_SIZE];
   int levelID;
   int nbyte;
-  double level;
 
   xassert ( zaxisptr );
 
@@ -1223,16 +1223,14 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
 	  fprintf(fp, "%*s", nbyte0, "");
 	  nbyte = nbyte0;
 	}
-      level = zaxisInqLevel(zaxisID, levelID);
-      nbyte += fprintf(fp, "%.9g ", level);
+      nbyte += fprintf(fp, "%.9g ", zaxisptr->vals[levelID]);
     }
   fprintf(fp, "\n");
 
   if ( zaxisptr->lbounds && zaxisptr->ubounds )
     {
-      double level1, level2;
+      nbyte0 = fprintf(fp, "lbounds   = ");
       nbyte = nbyte0;
-      nbyte0 = fprintf(fp, "bounds    = ");
       for ( levelID = 0; levelID < nlevels; levelID++ )
 	{
 	  if ( nbyte > 80 )
@@ -1241,27 +1239,35 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
 	      fprintf(fp, "%*s", nbyte0, "");
 	      nbyte = nbyte0;
 	    }
-	  level1 = zaxisInqLbound(zaxisID, levelID);
-	  level2 = zaxisInqUbound(zaxisID, levelID);
-	  nbyte += fprintf(fp, "%.9g-%.9g ", level1, level2);
+	  nbyte += fprintf(fp, "%.9g ", zaxisptr->lbounds[levelID]);
+	}
+      fprintf(fp, "\n");
+
+      nbyte0 = fprintf(fp, "ubounds   = ");
+      nbyte = nbyte0;
+      for ( levelID = 0; levelID < nlevels; levelID++ )
+	{
+	  if ( nbyte > 80 )
+	    {
+	      fprintf(fp, "\n");
+	      fprintf(fp, "%*s", nbyte0, "");
+	      nbyte = nbyte0;
+	    }
+	  nbyte += fprintf(fp, "%.9g ", zaxisptr->ubounds[levelID]);
 	}
       fprintf(fp, "\n");
     }
 
   if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
     {
-      int i;
-      int vctsize;
-      const double *vct;
-
-      vctsize = zaxisptr->vctsize;
-      vct     = zaxisptr->vct;
+      int vctsize = zaxisptr->vctsize;
+      const double *vct = zaxisptr->vct;
       fprintf(fp, "vctsize   = %d\n", vctsize);
       if ( vctsize )
         {
           nbyte0 = fprintf(fp, "vct       = ");
           nbyte = nbyte0;
-          for ( i = 0; i < vctsize; i++ )
+          for ( int i = 0; i < vctsize; i++ )
             {
               if ( nbyte > 70 || i == vctsize/2 )
                 {
diff --git a/libcdi/tables/gen_tableheaderfile.in b/libcdi/tables/gen_tableheaderfile.in
index 0a393a2..54b3f8c 100755
--- a/libcdi/tables/gen_tableheaderfile.in
+++ b/libcdi/tables/gen_tableheaderfile.in
@@ -10,7 +10,8 @@ PTFILES=""
 #
 #########################################
 #
-exec 3<"$DEFTABLES"
+rm -f "$OFILE"
+exec 3<"$DEFTABLES" 4>"$OFILE"
 #
 item=0
 while read -u3 PTFILE[item] ; do
@@ -27,9 +28,9 @@ unset PTFILE[item]
 #
 #########################################
 #
-rm -f $OFILE
 #
-cat >> $OFILE <<EOF
+cat >&4 <<EOF
+/* Automatically generated, do not edit! */
 #ifndef _TABLE_H
 #define _TABLE_H
 
@@ -38,21 +39,20 @@ EOF
 for TFILE in "${PTFILE[@]}"; do
     echo "process: $TFILE"
     rm -f ptfile
-    ../app/createtable "$TFILE" - >>"$OFILE"
+    @abs_top_builddir@/app/createtable "$TFILE" - >&4
 done
 #
-cat >> $OFILE <<EOF
+cat >&4 <<EOF
 
-static void
-tableDefault(void)
+static
+void tableDefault(void)
 {
   int tableID, instID, modelID;
 
 EOF
 #
 settabvar() {
-  val=`grep $2 $1 | cut -f 2 -d "="`
-  echo $val
+  grep "$2" "$1" | cut -f 2 -d "="
 }
 #
 item=0
@@ -76,7 +76,7 @@ if [ -z $TABLE_SU ] ; then TABLE_SU=0; fi
 echo "ID = $TABLE_ID name=$TABLE_NA model=$TABLE_MO inistitut=$TABLE_IN center=$TABLE_CE subcenter=$TABLE_SU"
 TABLENAME=`echo ${TFBASENAME} | sed -e "s/\./_/g" `
 #
-cat >> $OFILE <<EOF
+cat >&4 <<EOF
 
   /*
    *  define table : ${TFBASENAME}
@@ -97,7 +97,7 @@ EOF
 #
 done
 #
-cat >> $OFILE <<EOF
+cat >&4 <<EOF
 }
 
 #endif  /* _TABLE_H */
diff --git a/libcdi/tests/cksum_read.c b/libcdi/tests/cksum_read.c
index 0b3493a..190b610 100644
--- a/libcdi/tests/cksum_read.c
+++ b/libcdi/tests/cksum_read.c
@@ -11,6 +11,10 @@
 #include "var_cksum.h"
 #include "stream_cksum.h"
 
+#ifdef __cplusplus
+#define PRIx32 ""
+#endif
+
 static struct cksum_table *
 read_table(const char *table_fname, size_t *table_len)
 {
diff --git a/libcdi/tests/cksum_write.c b/libcdi/tests/cksum_write.c
index 0e87873..68e848c 100644
--- a/libcdi/tests/cksum_write.c
+++ b/libcdi/tests/cksum_write.c
@@ -12,6 +12,7 @@
 #include <unistd.h>
 
 #include "cdi.h"
+#include "cdi_uuid.h"
 
 #include "cksum.h"
 #include "simple_model_helper.h"
@@ -226,11 +227,10 @@ main(int argc, char *argv[])
   /* add uuids to zaxis and grid */
   {
     unsigned char uuid[16];
-    int str2uuid(const char *uuidstr, unsigned char *uuid);
 
     static char gridUUIDTxt[] = "107d7a5b-348c-4d1a-90a9-d745914f2fb6";
 
-    str2uuid(gridUUIDTxt, uuid);
+    cdiStr2UUID(gridUUIDTxt, uuid);
     gridDefUUID(gridID, uuid);
 
     static char zaxisUUIDTxt[2][37] = {
@@ -240,7 +240,7 @@ main(int argc, char *argv[])
 
     for (int i = 0; i < 2; ++i)
       {
-        str2uuid(zaxisUUIDTxt[i], uuid);
+        cdiStr2UUID(zaxisUUIDTxt[i], uuid);
         zaxisDefUUID(zaxisID[i], uuid);
       }
   }
diff --git a/libcdi/tests/deco2d_model.c b/libcdi/tests/deco2d_model.c
index f86cb0a..838d318 100644
--- a/libcdi/tests/deco2d_model.c
+++ b/libcdi/tests/deco2d_model.c
@@ -31,13 +31,14 @@ typedef int MPI_Comm;
 #include "pio_write.h"
 
 #include "simple_model_helper.h"
-#include "create_uuid.h"
+#include "cdi_uuid.h"
 
 enum {
   ntfiles     = 2,
   nproma = 16,
 };
 
+
 static void
 modelRegionCompute(double region[], int nlev, int nlat, int nlon,
                    const int chunkStart[3], const int chunkSize[3],
@@ -148,10 +149,11 @@ modelRun(struct model_config setup, MPI_Comm comm)
     lats[i] = ((double)(i * 180))/nlat - 90.0;
   gridDefXvals ( gridID, lons );
   gridDefYvals ( gridID, lats );
+  if (setup.create_uuid)
   {
     unsigned char uuid[CDI_UUID_SIZE];
     if (rank == 0)
-      create_uuid(uuid);
+      cdiCreateUUID(uuid);
 #if USE_MPI
     MPI_Bcast(uuid, CDI_UUID_SIZE, MPI_UNSIGNED_CHAR, 0, comm);
 #endif
@@ -197,10 +199,11 @@ modelRun(struct model_config setup, MPI_Comm comm)
             = zaxisCreate(ZAXIS_PRESSURE, varDesc[varIdx].nlev);
           zaxisDefLevels(varDesc[varIdx].zaxisID, levs);
         }
+      if (setup.create_uuid)
       {
         unsigned char uuid[16];
         if (rank == 0)
-          create_uuid(uuid);
+          cdiCreateUUID(uuid);
 #if USE_MPI
         MPI_Bcast(uuid, CDI_UUID_SIZE, MPI_UNSIGNED_CHAR, 0, comm);
 #endif
@@ -213,6 +216,18 @@ modelRun(struct model_config setup, MPI_Comm comm)
         = (size_t)nlon * (size_t)nlat * (size_t)varDesc[varIdx].nlev;
 #ifdef USE_MPI
       {
+        for (size_t i = 0; i < varIdx; ++i)
+          if (varDesc[i].nlev == varLevs)
+            {
+              varDesc[varIdx].redist4gather = varDesc[i].redist4gather;
+              varDesc[varIdx].partDesc = varDesc[i].partDesc;
+              for (size_t j = 0; j < 2; ++j)
+                {
+                  varDesc[varIdx].start[j] = varDesc[i].start[j];
+                  varDesc[varIdx].chunkSize[j] = varDesc[i].chunkSize[j];
+                }
+              goto partDescriptionSet;
+            }
         int start[2], chunkSize[3], varSize[2] = { nlon, nlat };
         for (size_t i = 0; i < 2; ++i)
           {
@@ -229,13 +244,6 @@ modelRun(struct model_config setup, MPI_Comm comm)
         Xt_int varSizeXt[3] = { (Xt_int)nlon, (Xt_int)nlat, (Xt_int)varLevs };
         chunkSize[2] = varLevs;
         Xt_int varStartXt[3] = { start[0], start[1], 0 };
-        for (size_t i = 0; i < varIdx; ++i)
-          if (varDesc[i].nlev == varLevs)
-            {
-              varDesc[varIdx].redist4gather = varDesc[i].redist4gather;
-              varDesc[varIdx].partDesc = varDesc[i].partDesc;
-              goto gatherRedistSet;
-            }
         Xt_idxlist part_idxlist
           = xt_idxsection_new(0, (varLevs > 1 ? 3 : 2), varSizeXt,
                               chunkSize, varStartXt),
@@ -274,7 +282,7 @@ modelRun(struct model_config setup, MPI_Comm comm)
             Free(src_blocks);
             xt_xmap_delete(xmap4gather);
           }
-        gatherRedistSet: ;
+        partDescriptionSet: ;
       }
 #endif
       varDesc[varIdx].code = GRIB_USERDEF + (int)varIdx;
@@ -316,6 +324,14 @@ modelRun(struct model_config setup, MPI_Comm comm)
 	  taxisDefVdate(taxisID, vdatetime[1]);
 	  taxisDefVtime(taxisID, vdatetime[0]);
 	  streamDefTimestep ( streamID, tsID );
+          if (setup.filetype == FILETYPE_EXT)
+            {
+              /* EXTRA doesn't store time, only date
+               * set the value to 0 before checksumming, because a
+               * time field of 0 is what reading an EXTRA file will
+               * return */
+              vdatetime[0] = 0;
+            }
 	  for (size_t varIdx = 0; varIdx < nVars; ++varIdx)
 	    {
               size_t varLevs = (size_t)varDesc[varIdx].nlev;
diff --git a/libcdi/tests/pio_write.c b/libcdi/tests/pio_write.c
index b78463c..360f296 100644
--- a/libcdi/tests/pio_write.c
+++ b/libcdi/tests/pio_write.c
@@ -34,7 +34,7 @@ static const struct model_config default_setup
 #else
   = { .nlon = 12, .nts = 3, .nlat = 6, .nvars = 5,
       .filetype = FILETYPE_GRB, .datatype = DATATYPE_PACK24,
-      .compute_checksum = 1,
+      .compute_checksum = 1, .create_uuid = 0,
       .suffix = "grb",
       .max_nlev = 5,
 };
@@ -96,11 +96,13 @@ parse_unsignedarg(const char msg[])
 typedef int (*pioRoleFunc)(MPI_Comm commSuper, int IOMode, int nProcsIO);
 
 static void
-parse_long_option(int pioConfHandle, pioRoleFunc *pioRoleAssign,
+parse_long_option(struct model_config *restrict setup,
+                  int pioConfHandle, pioRoleFunc *pioRoleAssign,
                   const char *str)
 {
   static const char cacheRedistStr[] = "cache-redists",
-    pioRoleSchemeOptionStr[] = "pio-role-scheme";
+    pioRoleSchemeOptionStr[] = "pio-role-scheme",
+    uuidCreateOptionStr[] = "no-create-uuid";
   if (!strncmp(str, cacheRedistStr, sizeof (cacheRedistStr) - 1))
     {
 #ifdef USE_MPI
@@ -144,6 +146,14 @@ parse_long_option(int pioConfHandle, pioRoleFunc *pioRoleAssign,
                        pioRoleSchemeOptionStr);
 #endif
     }
+  else if (!strcmp(str, uuidCreateOptionStr + 3))
+    {
+      setup->create_uuid = true;
+    }
+  else if (!strcmp(str, uuidCreateOptionStr))
+    {
+      setup->create_uuid = false;
+    }
   else
     invalidOptionDie("unknown long option: %s\n", str);
 }
@@ -222,7 +232,7 @@ int main(int argc, char *argv[])
         break;
 #endif
       case 'q':
-        parse_long_option(pioConfHandle, &pioRoleAssign, optarg);
+        parse_long_option(&setup, pioConfHandle, &pioRoleAssign, optarg);
         break;
       case 'f':
         {
diff --git a/libcdi/tests/pio_write.h b/libcdi/tests/pio_write.h
index 9a9ed6a..78ea38f 100644
--- a/libcdi/tests/pio_write.h
+++ b/libcdi/tests/pio_write.h
@@ -11,7 +11,7 @@ struct model_config
 {
   int nlon, nlat, nts, max_nlev, nvars;
   int filetype, datatype;
-  bool compute_checksum;
+  bool compute_checksum, create_uuid;
   const char *suffix;
 };
 
diff --git a/libcdi/tests/simple_model.c b/libcdi/tests/simple_model.c
index f46c620..97222f1 100644
--- a/libcdi/tests/simple_model.c
+++ b/libcdi/tests/simple_model.c
@@ -29,7 +29,7 @@ typedef int MPI_Comm;
 #include "pio_write.h"
 
 #include "simple_model_helper.h"
-#include "create_uuid.h"
+#include "cdi_uuid.h"
 
 enum {
   ntfiles     = 2,
@@ -116,10 +116,11 @@ modelRun(struct model_config setup, MPI_Comm comm)
     lats[i] = ((double)(i * 180))/nlat - 90.0;
   gridDefXvals ( gridID, lons );
   gridDefYvals ( gridID, lats );
+  if (setup.create_uuid)
   {
     unsigned char uuid[CDI_UUID_SIZE];
     if (rank == 0)
-      create_uuid(uuid);
+      cdiCreateUUID(uuid);
 #if USE_MPI
     MPI_Bcast(uuid, CDI_UUID_SIZE, MPI_UNSIGNED_CHAR, 0, comm);
 #endif
@@ -165,10 +166,11 @@ modelRun(struct model_config setup, MPI_Comm comm)
             = zaxisCreate(ZAXIS_PRESSURE, varDesc[varIdx].nlev);
           zaxisDefLevels(varDesc[varIdx].zaxisID, levs);
         }
+      if (setup.create_uuid)
       {
         unsigned char uuid[16];
         if (rank == 0)
-          create_uuid(uuid);
+          cdiCreateUUID(uuid);
 #if USE_MPI
         MPI_Bcast(uuid, CDI_UUID_SIZE, MPI_UNSIGNED_CHAR, 0, comm);
 #endif
@@ -181,17 +183,25 @@ modelRun(struct model_config setup, MPI_Comm comm)
         = (size_t)nlon * (size_t)nlat * (size_t)varDesc[varIdx].nlev;
 #ifdef USE_MPI
       {
+        for (size_t i = 0; i < varIdx; ++i)
+          if (varDesc[i].nlev == varLevs)
+            {
+              varDesc[varIdx].partDesc = varDesc[i].partDesc;
+              varDesc[varIdx].start = varDesc[i].start;
+              varDesc[varIdx].chunkSize = varDesc[i].chunkSize;
+              goto partDescriptionSet;
+            }
         struct PPM_extent range
           = PPM_uniform_partition((struct PPM_extent){ 0,
                 (int32_t)varDesc[varIdx].size }, comm_size, rank);
         int start = range.first;
         int chunkSize = range.size;
-        Xt_idxlist idxlist
-          = xt_idxstripes_new(&(struct Xt_stripe){ .start = start,
-                .nstrides = chunkSize, .stride = 1 }, 1);
         varDesc[varIdx].start = start;
         varDesc[varIdx].chunkSize = chunkSize;
-        varDesc[varIdx].partDesc = idxlist;
+        varDesc[varIdx].partDesc
+          = xt_idxstripes_new(&(struct Xt_stripe){ .start = start,
+                .nstrides = chunkSize, .stride = 1 }, 1);
+        partDescriptionSet: ;
       }
 #endif
       varDesc[varIdx].code = GRIB_USERDEF + (int)varIdx;
@@ -245,23 +255,24 @@ modelRun(struct model_config setup, MPI_Comm comm)
 	    {
 #ifdef USE_MPI
               int start = varDesc[varIdx].start;
-              int chunk = varDesc[varIdx].chunkSize;
+              size_t chunkSize = (size_t)varDesc[varIdx].chunkSize;
 #else
-              int chunk = (int)varDesc[varIdx].size;
+              size_t chunkSize = varDesc[varIdx].size;
               int start = 0;
 #endif
-              if (varslice_size < (size_t)chunk)
+              if (varslice_size < chunkSize)
                 {
-                  varslice = (double *)realloc(varslice, (size_t)chunk * sizeof (var[0]));
-                  varslice_size = (size_t)chunk;
+                  varslice = (double *)Realloc(varslice, chunkSize * sizeof (var[0]));
+                  varslice_size = chunkSize;
                 }
-              modelRegionCompute(varslice, (size_t)start, (size_t)chunk,
+              modelRegionCompute(varslice, (size_t)start, chunkSize,
                                  varDesc[varIdx].nlev, nlat, nlon,
                                  tsID, lons, lats,
                                  mscale, mrscale);
               if (setup.compute_checksum)
                 {
 #if USE_MPI
+                  int chunk = (int)chunkSize;
                   xmpi(MPI_Gather(&chunk, 1, MPI_INT,
                                   chunks, 1, MPI_INT, 0, comm));
                   if (rank == 0)
@@ -270,7 +281,7 @@ modelRun(struct model_config setup, MPI_Comm comm)
                       for (size_t i = 1; i < (size_t)comm_size; ++i)
                         displs[i] = displs[i - 1] + chunks[i - 1];
                     }
-                  xmpi(MPI_Gatherv(varslice, chunk, MPI_DOUBLE,
+                  xmpi(MPI_Gatherv(varslice, (size_t)chunkSize, MPI_DOUBLE,
                                    var, chunks, displs, MPI_DOUBLE, 0, comm));
 #else
                   var = varslice;
@@ -342,6 +353,9 @@ modelRun(struct model_config setup, MPI_Comm comm)
       if (zID != CDI_UNDEFID)
         {
           zaxisDestroy(zID);
+#if USE_MPI
+          xt_idxlist_delete(varDesc[varIdx].partDesc);
+#endif
           for (size_t j = varIdx + 1; j < nVars; ++j)
             if (zID == varDesc[j].zaxisID)
               varDesc[j].zaxisID = CDI_UNDEFID;
diff --git a/libcdi/tests/test_resource_copy.c b/libcdi/tests/test_resource_copy.c
index c662fac..9d09677 100644
--- a/libcdi/tests/test_resource_copy.c
+++ b/libcdi/tests/test_resource_copy.c
@@ -6,7 +6,7 @@
 #include <string.h>
 
 #include "cdi.h"
-#include "create_uuid.h"
+#include "cdi_uuid.h"
 #include "dmemory.h"
 #include "error.h"
 #include "resource_handle.h"
@@ -87,7 +87,7 @@ static int defineGrid (void)
   gridDefComplexPacking ( gridID, 1 );
   {
     unsigned char uuid[CDI_UUID_SIZE];
-    create_uuid(uuid);
+    cdiCreateUUID(uuid);
     gridDefUUID(gridID, uuid);
   }
 
@@ -113,7 +113,7 @@ static int defineZaxis (void)
   zaxisDefWeights ( zaxisID, &levs[0] );
   {
     unsigned char uuid[CDI_UUID_SIZE];
-    create_uuid(uuid);
+    cdiCreateUUID(uuid);
     zaxisDefUUID(zaxisID, uuid);
   }
 
@@ -218,6 +218,7 @@ static int modelRun(MPI_Comm comm)
     streamID = streamOpenWrite("example.grb", FILETYPE_GRB);
     if ( streamID < 0 ) xabort ( "Could not open file" );
     defineStream ( streamID, vlistID );
+    vlistDestroy(temp.id1);
     vlistDestroy(temp.id2);
   }
 
diff --git a/m4/acx_options.m4 b/m4/acx_options.m4
index 7367fdd..94a5232 100644
--- a/m4/acx_options.m4
+++ b/m4/acx_options.m4
@@ -2,6 +2,7 @@ AC_DEFUN([ACX_OPTIONS],
 [
 #  ----------------------------------------------------------------------
 #  Checks for multithreaded compiling + linking
+ENABLE_THREADS=no
 AC_ARG_WITH([threads],
             [AC_HELP_STRING([--with-threads=<yes/no/directory>],
                             [Compile + link for multithreading [default=yes]])],
@@ -12,7 +13,8 @@ THREADS_LIBS=''
 AS_CASE([$with_threads],
         [no],[AC_MSG_CHECKING([multithreading])
               AC_MSG_RESULT([suppressed])],
-        [yes],[AX_PTHREAD([AC_DEFINE([HAVE_LIBPTHREAD],[1],[Define 1 for multithread support])],[AC_MSG_ERROR([multithreaded settings NOT found])])
+        [yes],[AX_PTHREAD([AC_DEFINE([HAVE_LIBPTHREAD],[1],[Define 1 for multithread support])
+                           ENABLE_THREADS=yes],[AC_MSG_ERROR([multithreaded settings NOT found])])
                LIBS="$PTHREAD_LIBS $LIBS"
                CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
                CC="$PTHREAD_CC"
@@ -22,8 +24,10 @@ AS_CASE([$with_threads],
              CPPFLAGS="-I$THREADS_ROOT/include $CPPFLAGS "
              AC_CHECK_HEADERS(pthread.h)
              AC_CHECK_LIB([pthread],[pthread_create])
+             ENABLE_THREADS=yes
              THREADS_LIBS=" -L$THREADS_ROOT/lib -lpthread"
              THREADS_INCLUDE=" -I$THREADS_ROOT/include"])
+AC_SUBST([ENABLE_THREADS])
 AC_SUBST([THREADS_INCLUDE])
 AC_SUBST([THREADS_LIBS])
 #  ----------------------------------------------------------------------
diff --git a/src/Adisit.c b/src/Adisit.c
index f085c25..a4ece15 100644
--- a/src/Adisit.c
+++ b/src/Adisit.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -328,9 +328,17 @@ void *Adisit(void *argument)
 
 	  offset = gridsize*levelID;
 
-	  if ( varID == thoID ) streamReadRecord(streamID1, tho.ptr+offset, &(tho.nmiss));
-	  if ( varID == saoID ) streamReadRecord(streamID1, sao.ptr+offset, &(sao.nmiss));
-	}
+	  if ( varID == thoID )
+            {
+              streamReadRecord(streamID1, tho.ptr+offset, &nmiss);
+              tho.nmiss = (size_t) nmiss;
+            }
+	  if ( varID == saoID )
+            {
+              streamReadRecord(streamID1, sao.ptr+offset, &nmiss);
+              sao.nmiss = (size_t) nmiss;
+            }
+        }
 
       if (operatorID == ADISIT )
         {
diff --git a/src/Afterburner.c b/src/Afterburner.c
index 034b836..c7a3f9f 100644
--- a/src/Afterburner.c
+++ b/src/Afterburner.c
@@ -50,10 +50,7 @@ void  scan_darray(char *namelist, const char *name, double *values, int maxValue
 
 long  get_nfft(void);
 
-char   *zaxisNamePtr(int leveltype);
-char   *vlistInqVarNamePtr(int vlistID, int varID);
-char   *vlistInqVarLongnamePtr(int vlistID, int varID);
-char   *vlistInqVarUnitsPtr(int vlistID, int varID);
+char zaxistypename[CDI_MAX_NAME];
 
 typedef struct {
   int lana, nrecs;
@@ -954,9 +951,10 @@ void after_defineLevel(struct Control *globs, struct Variable *vars)
 	    }
 	}
       else
-	Error( "%s level data unsupported for TYPE %d",
-	      zaxisNamePtr(zaxisInqType(iVertID)), globs->Type);	    
-
+        {
+          zaxisName(zaxisInqType(iVertID), zaxistypename);
+          Error("%s level data unsupported for TYPE %d", zaxistypename, globs->Type);	    
+        }
       break;
     }
   case 30:
@@ -1091,7 +1089,7 @@ void after_setCodes(struct Control *globs, struct Variable *vars, int maxCodes,
 {
   int code;
   int table, modelID, tableID;
-  char *name, *longname;
+  const char *name, *longname;
   int varID;
 
   if ( globs->Verbose ) lprintf(stdout);
@@ -1172,6 +1170,7 @@ void after_checkNamelist(struct Control *globs)
     }
 }
 
+#if defined(AFTERBURNER)
 static
 void after_usage(void)
 {
@@ -1186,8 +1185,8 @@ void after_usage(void)
   /*  fprintf(stderr, "     option -h : help (this output)\n"); */
   /*  fprintf(stderr, "     option -p : parallel read on\n"); */
   fprintf(stderr, "  <InputFiles> : ECHAM or ECMWF Ana or ReAna files\n");
-  fprintf(stderr, "  <OutputFile> : GRIB, netCDF or SERVICE format file\n");
-  fprintf(stderr, "<VarianceFile> : GRIB, netCDF or SERVICE format file\n");
+  fprintf(stderr, "  <OutputFile> : GRIB, NetCDF or SERVICE format file\n");
+  fprintf(stderr, "<VarianceFile> : GRIB, NetCDF or SERVICE format file\n");
   fprintf(stderr, "  namelist is read from <stdin>\n");
   fprintf(stderr, "  output is written to <stdout>\n\n");
 
@@ -1200,6 +1199,7 @@ void after_usage(void)
 
   exit(1);
 }
+#endif
 
 static
 void after_parini(struct Control *globs, struct Variable *vars)
@@ -1210,7 +1210,7 @@ void after_parini(struct Control *globs, struct Variable *vars)
     {
 #if defined(CDO)
       fprintf(stderr, "Default namelist: \n");
-      fprintf(stderr, "  TYPE = 0, CODE = -1, LEVEL = -1, MULTI = 0, DAYIN = 30, MEAN = 0, TIMESEL = -1, UNITSEL = 0\n");
+      fprintf(stderr, "  TYPE=0, CODE=-1, LEVEL=-1, INTERVAL=0, MEAN=0, EXTRAPOLATE=0\n");
 #endif
       fprintf(stdout, "Enter namelist parameter:\n");
     }
@@ -1221,7 +1221,9 @@ void after_parini(struct Control *globs, struct Variable *vars)
       if ( length == 0L )
 	{
 	  fprintf(stderr,"\n stdin not connected\n");
+#if defined(AFTERBURNER)
 	  after_usage();
+#endif
 	}
       fseek(stdin, 0L, SEEK_SET);
     }
@@ -1272,7 +1274,7 @@ void after_parini(struct Control *globs, struct Variable *vars)
   int gribFormat = scan_par_obsolate(namelist, "grib",   0);
   int cdfFormat  = scan_par_obsolate(namelist, "netcdf", 0);
 
-  if ( gribFormat && cdfFormat ) Error( "GRIB or netCDF?");
+  if ( gribFormat && cdfFormat ) Error( "GRIB or NetCDF?");
 
   switch ( fileFormat )
     {
@@ -1466,14 +1468,19 @@ void after_precntl(struct Control *globs, struct Variable *vars)
 	      if ( leveltype == ZAXIS_HYBRID && globs->nvct == 0 )
 		{
 		  nhzaxis++;
-		  if ( numlevel != (zaxisInqVctSize(zaxisID)/2 - 1) )
+                  int nvct = zaxisInqVctSize(zaxisID);
+		  if ( numlevel != (nvct/2 - 1) )
 		    {
-		      if ( ! (numlevel == 191 && zaxisInqVctSize(zaxisID) == 0) )
+                      if ( nvct == 0 )
+                        {
+                          if ( numlevel != 191 )
+                            Warning("VCT missing for hybrid level data with %d levels!", numlevel);
+                        }
+                      else
 			{
-			  Warning( "Skip %d hybrid level data with %d levels!",
-				  (zaxisInqVctSize(zaxisID)/2 - 1), numlevel);
-			  continue;
+			  Warning("Skip %d hybrid level data with %d levels!", (nvct/2 - 1), numlevel);
 			}
+                      continue;
 		    }
 		}
 
@@ -1522,8 +1529,7 @@ void after_precntl(struct Control *globs, struct Variable *vars)
 		    }
 
 		  if ( numlevel != (globs->nvct/2 - 1) )
-		    Error("Number of hybrid levels %d does not match vct levels %d",
-			  numlevel, globs->nvct/2-1);
+		    Error("Number of hybrid levels %d does not match VCT levels %d", numlevel, globs->nvct/2-1);
 
 		  if ( globs->Debug )
 		    for ( i = 0; i < globs->nvct/2; i++ )
@@ -1633,7 +1639,7 @@ void after_postcntl(struct Control *globs, struct Variable *vars)
   int ovarID, ogridID, ozaxisID;
   int ovarID2;
   int ivarID, instID, modelID, tableID;
-  char *name, *longname, *units;
+  const char *name, *longname, *units;
   char histstring[99];
   int datatype;
 
@@ -1652,9 +1658,10 @@ void after_postcntl(struct Control *globs, struct Variable *vars)
 	{
 	  gridID = vars[code].igridID;
 	  zaxisID = vars[code].izaxisID;
+          zaxisName(zaxisInqType(zaxisID), zaxistypename);
 	  fprintf(stderr," Detected Code %3d  grid %-8s size %5d  level %2d %-8s\n",
 		  code, gridNamePtr(gridInqType(gridID)), gridInqSize(gridID),
-		  zaxisInqSize(zaxisID), zaxisNamePtr(zaxisInqType(zaxisID)));
+		  zaxisInqSize(zaxisID), zaxistypename);
 	}
 
 
@@ -1756,41 +1763,47 @@ void after_postcntl(struct Control *globs, struct Variable *vars)
 	{
 	  gridID  = vars[code].ogridID;
 	  zaxisID = vars[code].ozaxisID;
+          zaxisName(zaxisInqType(zaxisID), zaxistypename);
 	  fprintf(stderr," Selected Code %3d  grid %-8s size %5d  level %2d %-8s\n",
 		  code, gridNamePtr(gridInqType(gridID)), gridInqSize(gridID),
-		  zaxisInqSize(zaxisID), zaxisNamePtr(zaxisInqType(zaxisID)));
+		  zaxisInqSize(zaxisID), zaxistypename);
 	}
 }
 
-#if defined(AFTERBURNER)
 static
 void after_readVct(struct Control *globs, const char *vctfile)
 {
   char line[1024];
-  int i, n;
+  int i, n, nlines = 0;
   double va, vb;
 
   FILE *fp = fopen(vctfile, "r");
   if ( fp == NULL ) SysError( "Open failed on %s", vctfile);
 
-  while ( fgets(line, 1023, fp) ) globs->nvct++;
-
-  globs->nvct *= 2;
+  while ( fgets(line, 1023, fp) )
+    {
+      if ( line[0] == '#' || line[0] == '\0' ) continue;
+      nlines++;
+    }
+  
+  globs->nvct = nlines*2;
   globs->vct = (double *) Malloc(globs->nvct*sizeof(double));
-
+ 
   rewind(fp);
-  for ( i = 0; i < globs->nvct/2; i++ )
+
+  i = 0;
+  while ( fgets(line, 1023, fp) )
     {
-      fgets(line, 1023, fp);
+      if ( line[0] == '#' || line[0] == '\0' ) continue;
       sscanf(line, "%d %lg %lg", &n, &va, &vb);
       globs->vct[i]               = va;
       globs->vct[i+globs->nvct/2] = vb;
+      i++;
     }
-  fprintf(stdout, "  Reading VCT for %d hybrid levels from file %s\n", globs->nvct/2-1, vctfile);
+  fprintf(stdout, "  Read VCT with %d hybrid levels from file %s\n", globs->nvct/2-1, vctfile);
 
   fclose(fp);
 }
-#endif
 
 #if defined(AFTERBURNER)
 static
@@ -2076,7 +2089,7 @@ void after_processing(struct Control *globs, struct Variable *vars)
 	Error("Can't write fourier coefficients to GRIB!");
       else if ( ofiletype == FILETYPE_NC || ofiletype == FILETYPE_NC2 ||
 		ofiletype == FILETYPE_NC4 )
-	Error("Can't write fourier coefficients to netCDF!");
+	Error("Can't write fourier coefficients to NetCDF!");
     }
 
   filename = strrchr(ifile,'/');
@@ -2335,7 +2348,7 @@ int afterburner(int argc, char *argv[])
       fprintf(stderr, "  Maximum ffts to run in parallel:  %ld\n", get_nfft());
     }
 
-  /* read option VCT */
+  /* read optional VCT */
   if ( Vctfile ) after_readVct(globs, Vctfile);
 
   /* --------------------- */
@@ -2368,6 +2381,12 @@ void *Afterburner(void *argument)
 
   globs->Verbose = cdoVerbose;
 
+  if ( operatorArgc() == 1 )
+    {
+      const char *vctfile = operatorArgv()[0];
+      after_readVct(globs, vctfile);
+    }
+
   struct Variable vars[MaxCodes+5];
   for ( int code = 0; code < MaxCodes+5; code++ ) after_variable_init(&vars[code]);
 
diff --git a/src/Arith.c b/src/Arith.c
index c6caf27..5c2277a 100644
--- a/src/Arith.c
+++ b/src/Arith.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -37,6 +37,7 @@ void *Arith(void *argument)
 {
   enum {FILL_NONE, FILL_TS, FILL_VAR, FILL_VARTS, FILL_FILE};
   int filltype = FILL_NONE;
+  int nmiss;
   int gridsize;
   int nrecs, nrecs2, nvars = 0, nlev, recID;
   int nlevels2 = 1;
@@ -250,8 +251,9 @@ void *Arith(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamIDx1, &varID, &levelID);
-	  streamReadRecord(streamIDx1, fieldx1->ptr, &fieldx1->nmiss);
-
+	  streamReadRecord(streamIDx1, fieldx1->ptr, &nmiss);
+          fieldx1->nmiss = (size_t) nmiss;
+          
 	  if ( tsID == 0 || filltype == FILL_NONE || filltype == FILL_FILE || filltype == FILL_VARTS )
 	    {
 	      int lstatus = nlevels2 > 1 ? varID == 0 : recID == 0;
@@ -259,7 +261,8 @@ void *Arith(void *argument)
 	      if ( lstatus || (filltype != FILL_VAR && filltype != FILL_VARTS) )
 		{
 		  streamInqRecord(streamIDx2, &varID2, &levelID2);
-		  streamReadRecord(streamIDx2, fieldx2->ptr, &fieldx2->nmiss);
+		  streamReadRecord(streamIDx2, fieldx2->ptr, &nmiss);
+                  fieldx2->nmiss = (size_t) nmiss;
 		}
 
 	      if ( filltype == FILL_TS )
@@ -308,7 +311,7 @@ void *Arith(void *argument)
 	  farfun(&field1, field2, operfunc);
 
 	  streamDefRecord(streamID3, varID, levelID);
-	  streamWriteRecord(streamID3, field1.ptr, field1.nmiss);
+	  streamWriteRecord(streamID3, field1.ptr, (int)field1.nmiss);
 	}
 
       tsID++;
diff --git a/src/Arithc.c b/src/Arithc.c
index b3aa92b..350802d 100644
--- a/src/Arithc.c
+++ b/src/Arithc.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -72,6 +72,7 @@ int *fill_vars(int vlistID)
 
 void *Arithc(void *argument)
 {
+  int nmiss;
   int nrecs, recID;
   int varID, levelID;
 
@@ -122,7 +123,8 @@ void *Arithc(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  streamReadRecord(streamID1, field.ptr, &field.nmiss);
+	  streamReadRecord(streamID1, field.ptr, &nmiss);
+          field.nmiss = (size_t) nmiss;
 
 	  if ( vars[varID] )
 	    {
@@ -138,8 +140,9 @@ void *Arithc(void *argument)
 		if ( DBL_IS_EQUAL(field.ptr[i], field.missval) ) field.nmiss++;
 	    }
 
+          nmiss = (int) field.nmiss;
 	  streamDefRecord(streamID2, varID, levelID);
-	  streamWriteRecord(streamID2, field.ptr, field.nmiss);
+	  streamWriteRecord(streamID2, field.ptr, nmiss);
 	}
       tsID++;
     }
diff --git a/src/Arithdays.c b/src/Arithdays.c
index 0db2bab..08bfda5 100644
--- a/src/Arithdays.c
+++ b/src/Arithdays.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,7 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "calendar.h"
 #include "pstream.h"
 
 
@@ -83,6 +84,7 @@ void *Arithdays(void *argument)
   int vdate, vtime;
   int year, month, day;
   int calendar;
+  int nmiss;
   double rconst;
   field_t field;
 
@@ -149,15 +151,16 @@ void *Arithdays(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  streamReadRecord(streamID1, field.ptr, &field.nmiss);
+	  streamReadRecord(streamID1, field.ptr, &nmiss);
 
+          field.nmiss   = (size_t)nmiss;
 	  field.grid    = vlistInqVarGrid(vlistID1, varID);
 	  field.missval = vlistInqVarMissval(vlistID1, varID);
 
 	  farcfun(&field, rconst, operfunc);
 
 	  streamDefRecord(streamID2, varID, levelID);
-	  streamWriteRecord(streamID2, field.ptr, field.nmiss);
+	  streamWriteRecord(streamID2, field.ptr, (int)field.nmiss);
 	}
       tsID++;
     }
diff --git a/src/Arithlat.c b/src/Arithlat.c
index ba58276..f2a9827 100644
--- a/src/Arithlat.c
+++ b/src/Arithlat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/CDIread.c b/src/CDIread.c
index e7aadc8..9561063 100644
--- a/src/CDIread.c
+++ b/src/CDIread.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -29,10 +29,10 @@ const char *filetypestr(int filetype)
     {
     case FILETYPE_GRB:  return ("GRIB");            break;
     case FILETYPE_GRB2: return ("GRIB2");           break;
-    case FILETYPE_NC:   return ("netCDF");          break;
-    case FILETYPE_NC2:  return ("netCDF2");         break;
-    case FILETYPE_NC4:  return ("netCDF4");         break;
-    case FILETYPE_NC4C: return ("netCDF4 classic"); break;
+    case FILETYPE_NC:   return ("NetCDF");          break;
+    case FILETYPE_NC2:  return ("NetCDF2");         break;
+    case FILETYPE_NC4:  return ("NetCDF4");         break;
+    case FILETYPE_NC4C: return ("NetCDF4 classic"); break;
     case FILETYPE_SRV:  return ("SERVICE");         break;
     case FILETYPE_EXT:  return ("EXTRA");           break;
     case FILETYPE_IEG:  return ("IEG");             break;
@@ -80,10 +80,10 @@ void print_stat(const char *sinfo, int memtype, int datatype, int filetype, off_
 
 void *CDIread(void *argument)
 {
-  int memtype = MEMTYPE_DOUBLE;
+  int memtype = CDO_Memtype;
   int streamID;
   int tsID, varID, levelID;
-  int gridsize, i, nmiss;
+  int gridsize, nmiss;
   int recID, nrecs;
   int vlistID;
   int filetype = -1, datatype = -1;
@@ -99,13 +99,6 @@ void *CDIread(void *argument)
 
   cdoInitialize(argument);
 
-  char *envstr = getenv("MEMTYPE");
-  if ( envstr )
-    {
-      if      ( strcmp(envstr, "float")  == 0 ) memtype = MEMTYPE_FLOAT;
-      else if ( strcmp(envstr, "double") == 0 ) memtype = MEMTYPE_DOUBLE;
-    }
-
   if ( cdoVerbose ) cdoPrint("parameter: <nruns>");
 
   if ( operatorArgc() > 1 ) cdoAbort("Too many arguments!");
@@ -152,9 +145,8 @@ void *CDIread(void *argument)
 
 	      if ( memtype == MEMTYPE_FLOAT )
 		{
-		  cdoAbort("streamReadRecordF not implemented!");
-		  // streamReadRecordF(streamID, farray, &nmiss);
-		  for ( i = 0; i < gridsize; ++i ) darray[i] = farray[i];
+                  streamReadRecordF(streamID, farray, &nmiss);
+                  //  for ( int i = 0; i < gridsize; ++i ) darray[i] = farray[i];
 		  data_size += gridsize*4;
 		}
 	      else
diff --git a/src/CDItest.c b/src/CDItest.c
index 7942956..70902a4 100644
--- a/src/CDItest.c
+++ b/src/CDItest.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/CDIwrite.c b/src/CDIwrite.c
index b71f3f2..529a7a8 100644
--- a/src/CDIwrite.c
+++ b/src/CDIwrite.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -30,10 +30,10 @@ const char *filetypestr(int filetype)
     {
     case FILETYPE_GRB:  return ("GRIB");            break;
     case FILETYPE_GRB2: return ("GRIB2");           break;
-    case FILETYPE_NC:   return ("netCDF");          break;
-    case FILETYPE_NC2:  return ("netCDF2");         break;
-    case FILETYPE_NC4:  return ("netCDF4");         break;
-    case FILETYPE_NC4C: return ("netCDF4 classic"); break;
+    case FILETYPE_NC:   return ("NetCDF");          break;
+    case FILETYPE_NC2:  return ("NetCDF2");         break;
+    case FILETYPE_NC4:  return ("NetCDF4");         break;
+    case FILETYPE_NC4C: return ("NetCDF4 classic"); break;
     case FILETYPE_SRV:  return ("SERVICE");         break;
     case FILETYPE_EXT:  return ("EXTRA");           break;
     case FILETYPE_IEG:  return ("IEG");             break;
@@ -91,7 +91,7 @@ void print_stat(const char *sinfo, int memtype, int datatype, int filetype, off_
 
 void *CDIwrite(void *argument)
 {
-  int memtype = MEMTYPE_DOUBLE;
+  int memtype = CDO_Memtype;
   int nvars = 10, nlevs = 0, ntimesteps = 30;
   const char *defaultgrid = "global_.2";
   int streamID;
@@ -116,13 +116,6 @@ void *CDIwrite(void *argument)
 
   cdoInitialize(argument);
 
-  char *envstr = getenv("MEMTYPE");
-  if ( envstr )
-    {
-      if      ( strcmp(envstr, "float")  == 0 ) memtype = MEMTYPE_FLOAT;
-      else if ( strcmp(envstr, "double") == 0 ) memtype = MEMTYPE_DOUBLE;
-    }
-
   if ( cdoVerbose ) cdoPrint("parameter: <nruns, <grid, <nlevs, <ntimesteps, <nvars>>>>>");
 
   if ( operatorArgc() > 5 ) cdoAbort("Too many arguments!");
@@ -200,7 +193,6 @@ void *CDIwrite(void *argument)
 	  vars[varID][levelID] = (double*) Malloc(gridsize*sizeof(double));
 	  for ( i = 0; i < gridsize; ++i )
 	    vars[varID][levelID][i] = varID + array[i]*(levelID+1);
-	  //    vars[varID][levelID][i] = varID + rand()/(RAND_MAX+1.0);
 	}
     }
 
diff --git a/src/CMOR.c b/src/CMOR.c
index 6b010e6..bba174e 100644
--- a/src/CMOR.c
+++ b/src/CMOR.c
@@ -1,51 +1,699 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
-#include "par_io.h"
 #include "pstream.h"
+#include <search.h>
+#include <ctype.h>
 
 #if defined(HAVE_LIBCMOR)
-//#include "cmor.h"
-#endif
+#include "cmor.h"
 
-void *CMOR(void *argument)
+struct cc_var
 {
-  cdoInitialize(argument);
+  int cdi_varID;
+  int cmor_varID;
+  char datatype;
+  void *data;
+};
 
-#if defined(HAVE_LIBCMOR)
-  /*
-  if ( cdoVerbose )
-    cdoPrint("Using CMOR version %d.%d.%d.", CMOR_VERSION_MAJOR, CMOR_VERSION_MINOR, CMOR_VERSION_PATCH);
-  */
-  int streamID = streamOpenRead(cdoStreamName(0));
+static struct cc_var *find_var(int cdi_varID, struct cc_var vars[], int nvars)
+{
+  for ( int i = 0; i < nvars; i++ )
+    if ( cdi_varID == vars[i].cdi_varID )
+      return &vars[i];
+  return NULL;
+}
+
+static char *trim(char *s)
+{
+  int n;
+  if (s == NULL) return s;
+  while ( *s != '\0' && (isspace(*s) || *s == '"') )
+    s++;
+  n = strlen(s);
+  while ( n > 0 && (isspace(s[n - 1]) || s[n - 1] == '"') )
+    n--;
+  s[n] = '\0';
+  return s;
+}
+
+static ENTRY *hinsert(const char *key, const char *value)
+{
+  /* Insert new keys. Do not overwrite values of existing keys. */
+  ENTRY e, *ep;
+
+  e.key = strdup(key);
+  e.data = (void *)strdup(value);
+  ep = hsearch(e, FIND);
+  if ( ep == NULL )
+    {
+      ep = hsearch(e, ENTER);
+    }
+  else
+    {
+      free(e.key);
+      free(e.data);
+    }
+  return ep;
+}
+
+static ENTRY *hreplace(const char *key, const char *value)
+{
+  /* Overwrites values of existing keys. */
+  ENTRY e, *ep;
+
+  e.key = strdup(key);
+  e.data = (void *)strdup(value);
+  ep = hsearch(e, FIND);
+  if ( ep == NULL )
+    {
+      ep = hsearch(e, ENTER);
+    }
+  else
+    {
+      free(e.key);
+      free(ep->data);
+      ep->data = e.data;
+    }
+  return ep;
+}
+
+static ENTRY *parse_kv(char *kvstr)
+{
+  char *key = trim(strtok(kvstr, "="));
+  char *value = trim(strtok(NULL, "="));
+  if ( key == NULL || value == NULL )
+    return NULL;
+  return hinsert(key, value);
+}
+
+static int parse_kv_file(const char *filename, int verbose)
+{
+  FILE *fp;
+  char line[CMOR_MAX_STRING], *comment;
+
+  fp = fopen(filename, "r");
+  if ( fp == NULL )
+    {
+      if ( verbose )
+        cdoWarning("cannot open '%s'", filename);
+      return 1;
+    }
+  while ( fgets(line, sizeof(line), fp) != NULL )
+    {
+      comment = strchr(line, '#');
+      if ( comment ) *comment = '\0';
+      parse_kv(line);
+    }
+  fclose(fp);
+  return 0;
+}
+
+static void parse_kv_cmdline(int nparams, char **params)
+{
+  int i, j, k, size;
+  char *p;
+
+  /* Assume key = value pairs. That is, if params[i] contains no '='
+   * then treat it as if it belongs to the value of params[i-1],
+   * separated by a ','.*/
+  i = 0;
+  while ( i < nparams )
+    {
+      j = 1;
+      size = strlen(params[i]) + 1;
+      while ( i + j < nparams && strchr(params[i + j], '=') == NULL )
+        {
+          size += strlen(params[i + j]) + 1;
+          j++;
+        }
+      p = (char *) Malloc(size);
+      strcpy(p, params[i]);
+      for (k = 1; k < j; k++)
+        {
+          strcat(p, ",");
+          strcat(p, params[i + k]);
+        }
+      parse_kv(p);
+      free(p);
+      i += j;
+    }
+}
+
+static char *get_val(char *key, char *def)
+{
+  ENTRY e, *ep;
+
+  e.key = key;
+  ep = hsearch(e, FIND);
+  if ( ep )
+    return (char *)ep->data;
+  else
+    return def;
+}
+
+static char *substitute(char *word)
+{
+  ENTRY e, *ep;
+  char *key;
+
+  key = (char *) Malloc(strlen(word) + 12);
+  sprintf(key, "substitute_%s", word);
+  e.key = key;
+  ep = hsearch(e, FIND);
+  Free(key);
+  if ( ep )
+    return (char *)ep->data;
+  else
+    return word;
+}
+
+static void dump_global_attributes(int streamID)
+{
+  int i, natts;
+  char name[CDI_MAX_NAME];
+  char buffer[8];
+  char *value;
+  int type, len;
+  int vlistID = streamInqVlist(streamID);
+
+  vlistInqNatts(vlistID, CDI_GLOBAL, &natts);
+  for ( i = 0; i < natts; i++ )
+    {
+      value = NULL;
+      vlistInqAtt(vlistID, CDI_GLOBAL, i, name, &type, &len);
+      switch ( type )
+        {
+        case DATATYPE_TXT:
+          value = Malloc(len + 1);
+          vlistInqAttTxt(vlistID, CDI_GLOBAL, name, len, value);
+          value[len] = '\0';
+          break;
+        case DATATYPE_INT32:
+          value = Malloc(CDI_MAX_NAME);
+          vlistInqAttInt(vlistID, CDI_GLOBAL, name, len, (int *)buffer);
+          snprintf(value, CDI_MAX_NAME, "%i", *(int *)buffer);
+          break;
+        case DATATYPE_FLT64:
+          value = Malloc(CDI_MAX_NAME);
+          vlistInqAttFlt(vlistID, CDI_GLOBAL, name, len, (double *)buffer);
+          snprintf(value, CDI_MAX_NAME, "%e", *(double *)buffer);
+          break;
+        default:
+          printf("Unsupported type %i name %s\n", type, name);
+        }
+      hinsert(name, value);
+      if ( value ) Free(value);
+    }
+}
+
+static void dump_special_attributes(int streamID)
+{
+  int fileID;
+  size_t historysize;
+  char *history, *new_history;
+  const char *value;
+  int vlistID = streamInqVlist(streamID);
+
+  /* Any new history will be appended to the existing history. */
+  fileID = pstreamFileID(streamID);
+  historysize = (size_t) streamInqHistorySize(fileID);
+  if ( historysize )
+    {
+      new_history = get_val("history", NULL);
+      if ( new_history ) historysize += strlen(new_history) + 1;
+      history = Malloc(historysize + 1);
+      memset(history, 0, historysize + 1);
+      streamInqHistoryString(fileID, history);
+      if ( new_history )
+        {
+          strcat(history, " ");
+          strcat(history, new_history);
+        }
+      hreplace("history", history);
+      Free(history);
+    }
+
+  value = institutInqLongnamePtr(vlistInqVarInstitut(vlistID, 0));
+  if ( value ) hinsert("institution", value);
+
+  value = modelInqNamePtr(vlistInqVarModel(vlistID, 0));
+  if ( value ) hinsert("source", value);
+}
+
+static void read_config_files(void)
+{
+  char *info_files;
+  char *filename;
+  char *home;
+  const char *dotconfig = ".cdocmorinfo";
+
+  /* Files from info key in command line. */
+  info_files = get_val("info", "");
+  filename = strtok(info_files, ",");
+  while ( filename != NULL )
+    {
+      parse_kv_file(trim(filename), 1);
+      filename = strtok(NULL, ",");
+    }
+
+  /* Config file in user's $HOME directory. */
+  home = getenv("HOME");
+  filename = Malloc(strlen(home) + strlen(dotconfig) + 2);
+  sprintf(filename, "%s/%s", home, dotconfig);
+  parse_kv_file(filename, 0);
+  Free(filename);
+
+  /* System wide configuration. */
+  parse_kv_file("/etc/cdocmor.info", 0);
+}
+
+static int in_list(char **list, const char *needle)
+{
+  while ( *list )
+    if ( strcmp(*list++, needle) == 0 )
+      return 1;
+  return 0;
+}
+
+static void setup(int streamID, char *table)
+{
+  char *chunk;
+  char *logfile;
+  int netcdf_file_action, exit_control;
+  int set_verbosity;
+  int create_subdirectories;
+  int *month_lengths;
+  int table_id;
+  int taxisID = vlistInqTaxis(streamInqVlist(streamID));
+  char *calendar;
+  double branch_time = atof(get_val("branch_time", "0.0"));
+
+  chunk = get_val("chunk", "replace");
+  if ( strcasecmp(chunk, "replace") == 0 )
+    netcdf_file_action = CMOR_REPLACE;
+  else if ( strcasecmp(chunk, "append") == 0 )
+    netcdf_file_action = CMOR_APPEND;
+
+  set_verbosity = CMOR_NORMAL;
+  if ( strcasecmp(get_val("set_verbosity", ""), "CMOR_QUIET") == 0 )
+    set_verbosity = CMOR_QUIET;
+
+  exit_control = CMOR_NORMAL;
+  if ( strcasecmp(get_val("exit_control", ""), "CMOR_EXIT_ON_MAJOR") == 0 )
+    exit_control = CMOR_EXIT_ON_MAJOR;
+  if ( strcasecmp(get_val("exit_control", ""), "CMOR_EXIT_ON_WARNING") == 0 )
+    exit_control = CMOR_EXIT_ON_WARNING;
+
+  logfile = get_val("logfile", NULL);
+
+  create_subdirectories = atoi(get_val("create_subdirectories", "0"));
+  cmor_setup(get_val("inpath", "/usr/share/cmor/"),
+             &netcdf_file_action,
+             &set_verbosity,
+             &exit_control,
+             logfile,
+             &create_subdirectories);
+
+  switch ( taxisInqCalendar(taxisID) )
+    {
+    case CALENDAR_STANDARD:
+      calendar = "gregorian";
+      break;
+    case CALENDAR_PROLEPTIC:
+      calendar = "proleptic_gregorian";
+      break;
+    case CALENDAR_360DAYS:
+      calendar = "360_day";
+      break;
+    case CALENDAR_365DAYS:
+      calendar = "noleap";
+      break;
+    case CALENDAR_366DAYS:
+      calendar = "all_leap";
+      break;
+    default:
+      cdoAbort("Unsupported calendar type.");
+    }
+
+  if ( get_val("month_lengths", NULL) )
+    {
+      char *month_lengths_str = strdup(get_val("month_lengths", ""));
+      char *month_str = strtok(month_lengths_str, ",");
+      int month = 0;
+      month_lengths = Malloc(12 * sizeof(int));
+      while ( month < 12 && month_str != NULL )
+        {
+          month_lengths[month++] = atoi(month_str);
+          month_str = strtok(NULL, ",");
+        }
+      if ( month != 12 )
+        cdoAbort("Invalid format for month_lengths");
+    }
+  else
+    {
+      month_lengths = NULL;
+    }
 
+  cmor_dataset(get_val("outpath", "./"),
+               get_val("experiment_id", ""),
+               get_val("institution", ""),
+               get_val("source", ""),
+               calendar,
+               atoi(get_val("realization", "1")),
+               get_val("contact", ""),
+               get_val("history", ""),
+               get_val("comment", ""),
+               get_val("references", ""),
+               atoi(get_val("leap_year", "0")),
+               atoi(get_val("leap_month", "0")),
+               month_lengths,
+               get_val("model_id", ""),
+               get_val("forcing", ""),
+               atoi(get_val("initialization_method", "1")),
+               atoi(get_val("physics_version", "1")),
+               get_val("institute_id", ""),
+               get_val("parent_experiment_id", ""),
+               &branch_time,
+               get_val("parent_experiment_rip", ""));
+
+  cmor_load_table(table, &table_id);
+  cmor_set_table(table_id);
+}
+
+static void define_variables(int streamID, struct cc_var vars[], int *nvars)
+{
   int vlistID = streamInqVlist(streamID);
   int taxisID = vlistInqTaxis(vlistID);
+  size_t gridsize = vlistGridsizeMax(vlistID);
+  struct cc_var *var;
+  int varID, gridID;
+  char name[CDI_MAX_NAME], units[CDI_MAX_NAME];
+  int length;
+  double *coord_vals, *cell_bounds;
+  int ndims, levels;
+  char missing_value[sizeof(double)];
+  double tolerance = 1e-4;
+  int axis_ids[CMOR_MAX_AXES];
+  char *select_vars = get_val("var", NULL);
+  int year, month, day, hour, minute, second;
+  int timeunit = taxisInqTunit(taxisID);
+  char taxis_units[CMOR_MAX_STRING];
+  char **name_list, *var_name;
+  int i;
+
+  cdiDecodeDate(taxisInqRdate(taxisID), &year, &month, &day);
+  cdiDecodeTime(taxisInqRtime(taxisID), &hour, &minute, &second);
+  if ( timeunit == TUNIT_QUARTER || timeunit == TUNIT_30MINUTES )
+    timeunit = TUNIT_MINUTE;
+  if ( timeunit == TUNIT_3HOURS ||
+       timeunit == TUNIT_6HOURS ||
+       timeunit == TUNIT_12HOURS )
+    timeunit = TUNIT_HOUR;
 
-  int gridsize = vlistGridsizeMax(vlistID);
-  double *array = (double*) Malloc(gridsize*sizeof(double));
+  sprintf(taxis_units, "%s since %d-%d-%d %02d:%02d:%02d",
+          tunitNamePtr(timeunit), year, month, day, hour,
+          minute, second);
 
-  int recID, varID, levelID, nrecs, nmiss;
-  int tsID = 0;
-  while ( (nrecs = streamInqTimestep(streamID, tsID)) )
+  if ( select_vars )
     {
-      for ( recID = 0; recID < nrecs; recID++ )
-        { 
+      name_list = Malloc((strlen(select_vars) + 1) * sizeof(char *));
+      var_name = strtok(select_vars, ",");
+      i = 0;
+      while ( var_name != NULL )
+        {
+          name_list[i++] = trim(var_name);
+          var_name = strtok(NULL, ",");
+        }
+      name_list[i] = NULL;
+    }
+  else
+    {
+      name_list = NULL;
+    }
+
+  *nvars = 0;
+  for ( varID = 0; varID < vlistNvars(vlistID); varID++ )
+    {
+      vlistInqVarName(vlistID, varID, name);
+      if ( name_list == NULL || in_list(name_list, name) )
+        {
+          var = &vars[(*nvars)++];
+          var->cdi_varID = varID;
+          gridID = vlistInqVarGrid(vlistID, varID);
+          ndims = 0;
+
+          /* Time-Axis */
+          cmor_axis(&axis_ids[ndims++],
+                    substitute("time"),
+                    taxis_units,
+                    0,
+                    NULL,
+                    0,
+                    NULL,
+                    0,
+                    NULL);
+
+          /* Z-Axis */
+          int zaxisID = vlistInqVarZaxis(vlistID, varID);
+          levels = zaxisInqSize(zaxisID);
+          if ( zaxisInqType(zaxisID) != ZAXIS_SURFACE )
+            {
+              coord_vals = Malloc(levels * sizeof(double));
+              zaxisInqLevels(zaxisID, coord_vals);
+              zaxisInqName(zaxisID, name);
+              zaxisInqUnits(zaxisID, units);
+              cmor_axis(&axis_ids[ndims++],
+                        substitute(name),
+                        units,
+                        levels,
+                        (void *)coord_vals,
+                        'd',
+                        NULL,
+                        0,
+                        NULL);
+            }
+
+          /* Y-Axis */
+          gridInqYname(gridID, name);
+          gridInqYunits(gridID, units);
+          length = gridInqYsize(gridID);
+          coord_vals = Malloc(length * sizeof(double));
+          gridInqYvals(gridID, coord_vals);
+          cell_bounds = Malloc(2 * length * sizeof(double));
+          gridInqYbounds(gridID, cell_bounds);
+          cmor_axis(&axis_ids[ndims++],
+                    substitute(name),
+                    units,
+                    length,
+                    (void *)coord_vals,
+                    'd',
+                    (void *)cell_bounds,
+                    2,
+                    NULL);
+
+          /* X-Axis */
+          gridInqXname(gridID, name);
+          gridInqXunits(gridID, units);
+          length = gridInqXsize(gridID);
+          coord_vals = Malloc(length * sizeof(double));
+          gridInqXvals(gridID, coord_vals);
+          cell_bounds = Malloc(2 * length * sizeof(double));
+          gridInqXbounds(gridID, cell_bounds);
+          cmor_axis(&axis_ids[ndims++],
+                    substitute(name),
+                    units,
+                    length,
+                    (void *)coord_vals,
+                    'd',
+                    (void *)cell_bounds,
+                    2,
+                    NULL);
+
+          /* Variable */
+          vlistInqVarUnits(vlistID, varID, units);
+          vlistInqVarName(vlistID, varID, name);
+          if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT32 )
+            {
+              var->datatype = 'f';
+              *(float *) missing_value = vlistInqVarMissval(vlistID, varID);
+              var->data = Malloc(gridsize * levels * sizeof(float));
+            }
+          else
+            {
+              var->datatype = 'd';
+              *(double *) missing_value = vlistInqVarMissval(vlistID, varID);
+              var->data = Malloc(gridsize * levels * sizeof(double));
+            }
+          cmor_variable(&var->cmor_varID,
+                        substitute(name),
+                        units,
+                        ndims,
+                        axis_ids,
+                        var->datatype,
+                        (void *) missing_value,
+                        &tolerance,
+                        NULL,
+                        NULL,
+                        NULL,
+                        NULL);
+        }
+    }
+  if ( name_list ) Free(name_list);
+}
+
+static void write_variables(int streamID, struct cc_var vars[], int nvars)
+{
+  struct cc_var *var;
+  int vlistID = streamInqVlist(streamID);
+  int taxisID = vlistInqTaxis(vlistID);
+  size_t gridsize = vlistGridsizeMax(vlistID);
+  double time_val;
+  double time_bnds[2];
+  double *time_bndsp;
+  int has_bnds = taxisHasBounds(taxisID);
+  int tsID;
+  int vdate0b, vdate1b;
+  int vtime0b, vtime1b;
+  juldate_t juldate, r_juldate;
+  int calendar = taxisInqCalendar(taxisID);
+  int tunitsec;
+  int nrecs;
+  int varID, levelID;
+  int nmiss;
+  double *buffer;
+  int i;
+
+  buffer = (double *) Malloc(gridsize * sizeof(double));
+
+  switch ( taxisInqTunit(taxisID) )
+    {
+    case TUNIT_MINUTE: tunitsec = 60; break;
+    case TUNIT_HOUR: tunitsec = 3600; break;
+    case TUNIT_DAY: tunitsec = 86400; break;
+    default: tunitsec = 3600;
+    }
+
+  r_juldate = juldate_encode(calendar,
+                             taxisInqRdate(taxisID),
+                             taxisInqRtime(taxisID));
+  tsID = 0;
+  while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
+    {
+      juldate = juldate_encode(calendar,
+                               taxisInqVdate(taxisID),
+                               taxisInqVtime(taxisID));
+      time_val = juldate_to_seconds(juldate_sub(juldate, r_juldate))
+        / tunitsec;
+
+      if ( has_bnds )
+        {
+          taxisInqVdateBounds(taxisID, &vdate0b, &vdate1b);
+          taxisInqVtimeBounds(taxisID, &vtime0b, &vtime1b);
+
+          juldate = juldate_encode(calendar, vdate0b, vtime0b);
+          time_bnds[0] = juldate_to_seconds(juldate_sub(juldate, r_juldate))
+            / tunitsec;
+
+          juldate = juldate_encode(calendar, vdate1b, vtime1b);
+          time_bnds[1] = juldate_to_seconds(juldate_sub(juldate, r_juldate))
+            / tunitsec;
+          time_bndsp = time_bnds;
+        }
+      else
+        {
+          time_bndsp = NULL;
+        }
+
+      while ( nrecs-- )
+        {
           streamInqRecord(streamID, &varID, &levelID);
-          streamReadRecord(streamID, array, &nmiss);
+          var = find_var(varID, vars, nvars);
+          if ( var )
+            {
+              if ( var->datatype == 'f' )
+                {
+                  streamReadRecord(streamID, buffer, &nmiss);
+                  for ( i = 0; i < gridsize; i++ )
+                    ((float *)var->data)[gridsize * levelID + i] =
+                      (float)buffer[i];
+                }
+              else
+                {
+                  streamReadRecord(streamID,
+                                   (double *)var->data + gridsize * levelID,
+                                   &nmiss);
+                }
+            }
         }
 
-      tsID++;
+      for ( i = 0; i < nvars; i++ )
+        cmor_write(vars[i].cmor_varID,
+                   vars[i].data,
+                   vars[i].datatype,
+                   NULL,
+                   1,
+                   &time_val,
+                   time_bndsp,
+                   NULL);
     }
+  Free(buffer);
+}
+#endif
+
+void *CMOR(void *argument)
+{
+  cdoInitialize(argument);
+
+#if defined(HAVE_LIBCMOR)
+  int nparams = operatorArgc();
+  char **params = operatorArgv();
+  int nvars, nvars_max;
+  int streamID;
+  struct cc_var *vars;
+
+  if ( nparams < 1 ) cdoAbort("Too few arguments!");
+
+  hcreate(100);
+
+  /* Command line config has highest priority. */
+  parse_kv_cmdline(nparams - 1, &params[1]);
+
+  /* Config files are read with descending priority. */
+  read_config_files();
+
+  streamID = streamOpenRead(cdoStreamName(0));
+  /* Existing attributes have lowest priority. */
+  dump_global_attributes(streamID);
+  dump_special_attributes(streamID);
+
+  nvars_max = vlistNvars(streamInqVlist(streamID));
+  vars = (struct cc_var *) Malloc(nvars_max * sizeof(struct cc_var));
+
+  setup(streamID, params[0]);
+  define_variables(streamID, vars, &nvars);
+  write_variables(streamID, vars, nvars);
 
   streamClose(streamID);
+  cmor_close();
 
-  if ( array ) Free(array);
+  hdestroy();
+  for ( int i = 0; i < nvars; i++ )
+    Free(vars[i].data);
+  Free(vars);
 #else
   cdoWarning("CMOR support not compiled in!");
 #endif
 
   cdoFinish();
-
   return 0;
 }
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
diff --git a/src/Cat.c b/src/Cat.c
index 476ac87..ceb8e7a 100644
--- a/src/Cat.c
+++ b/src/Cat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -30,24 +30,22 @@
 
 void *Cat(void *argument)
 {
-  int streamID1, streamID2 = CDI_UNDEFID;
+  bool lconstvars = true;
   int nrecs;
-  int tsID1, tsID2 = 0, recID, varID, levelID;
-  int vlistID1, vlistID2 = CDI_UNDEFID;
-  int taxisID1, taxisID2 = CDI_UNDEFID;
-  int lcopy = FALSE;
-  int gridsize;
+  int tsID2 = 0, varID, levelID;
+  int streamID2 = CDI_UNDEFID;
+  int vlistID2 = CDI_UNDEFID;
+  int taxisID2 = CDI_UNDEFID;
   int nmiss;
-  int ntsteps, nvars;
-  int timer_cat;
   double tw0 = 0, tw = 0;
   double *array = NULL;
 
   cdoInitialize(argument);
 
-  if ( UNCHANGED_RECORD ) lcopy = TRUE;
+  bool lcopy = false;
+  if ( UNCHANGED_RECORD ) lcopy = true;
 
-  timer_cat = timer_new("cat");
+  int timer_cat = timer_new("cat");
   if ( cdoTimer ) timer_start(timer_cat);
 
   int streamCnt = cdoStreamCnt();
@@ -58,10 +56,10 @@ void *Cat(void *argument)
       if ( cdoVerbose ) cdoPrint("Process file: %s", cdoStreamName(indf)->args);
       if ( cdoTimer ) tw0 = timer_val(timer_cat);
 
-      streamID1 = streamOpenRead(cdoStreamName(indf));
+      int streamID1 = streamOpenRead(cdoStreamName(indf));
 
-      vlistID1 = streamInqVlist(streamID1);
-      taxisID1 = vlistInqTaxis(vlistID1);
+      int vlistID1 = streamInqVlist(streamID1);
+      int taxisID1 = vlistInqTaxis(vlistID1);
 
       if ( indf == 0 )
 	{
@@ -91,8 +89,8 @@ void *Cat(void *argument)
 	      taxisID2 = taxisDuplicate(taxisID1);
 	      vlistDefTaxis(vlistID2, taxisID2);
 	  
-	      ntsteps = vlistNtsteps(vlistID1);
-	      nvars   = vlistNvars(vlistID1);
+	      int ntsteps = vlistNtsteps(vlistID1);
+	      int nvars   = vlistNvars(vlistID1);
 	      
 	      if ( ntsteps == 1 )
 		{
@@ -103,7 +101,8 @@ void *Cat(void *argument)
 		}
 
 	      if ( ntsteps == 0 && nfiles > 1 )
-		{		  
+		{
+                  lconstvars = false;
 		  for ( varID = 0; varID < nvars; ++varID )
 		    vlistDefVarTsteptype(vlistID2, varID, TSTEP_INSTANT);
 		}
@@ -113,7 +112,7 @@ void *Cat(void *argument)
 
 	  if ( ! lcopy )
 	    {
-	      gridsize = vlistGridsizeMax(vlistID1);
+	      size_t gridsize = (size_t) vlistGridsizeMax(vlistID1);
 	      array = (double*) Malloc(gridsize*sizeof(double));
 	    }
 	}
@@ -124,9 +123,9 @@ void *Cat(void *argument)
 
       int ntsteps = vlistNtsteps(vlistID1);
 
-      tsID1 = 0;
+      int tsID1 = 0;
       while ( (nrecs = streamInqTimestep(streamID1, tsID1)) )
-	{
+	{          
 	  {
 	    double fstatus = indf+1.;
 	    if ( ntsteps > 1 ) fstatus = indf+(tsID1+1.)/ntsteps;
@@ -137,9 +136,14 @@ void *Cat(void *argument)
 
 	  streamDefTimestep(streamID2, tsID2);
 	       
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
+
+              if ( lconstvars && tsID2 > 0 && tsID1 == 0 )
+                if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT )
+                  continue;
+
 	      streamDefRecord(streamID2,  varID,  levelID);
 
 	      if ( lcopy )
@@ -156,6 +160,7 @@ void *Cat(void *argument)
 	  tsID1++;
 	  tsID2++;
 	}
+      
       streamClose(streamID1);
 
       if ( cdoTimer ) tw = timer_val(timer_cat) - tw0;
diff --git a/src/CdoMagicsMapper.c b/src/CdoMagicsMapper.c
index 3996519..a982354 100644
--- a/src/CdoMagicsMapper.c
+++ b/src/CdoMagicsMapper.c
@@ -1,33 +1,37 @@
 #if defined(HAVE_CONFIG_H)
-#  include "config.h" /* HAVE_LIBMAGICS */
+#  include "config.h"
 #endif
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
 #include "CdoMagicsMapper.h"
 #include "magics_template_parser.h"
 
 #define PARAM_COUNT  sizeof( mapper ) / sizeof ( CdoMagicsMapper )
 
-/* extern int SetMagicsParameterValue( char *param_name, char *param_type, char *param_value ) */
+/* extern int SetMagicsParameterValue( const char *param_name, const char *param_type, const char *param_value ) */
 
-int Set_magics_param_CCOLS( char *user_name, char *param_value );
-int Reset_magics_param_CCOLS( char *user_name );
+int Set_magics_param_CCOLS( const char *user_name, const char *param_value );
+int Reset_magics_param_CCOLS( const char *user_name );
 
-int Set_magics_param_CLEVS( char *user_name, char *param_value );
-int Reset_magics_param_CLEVS( char *user_name );
+int Set_magics_param_CLEVS( const char *user_name, const char *param_value );
+int Reset_magics_param_CLEVS( const char *user_name );
 
-int Set_magics_param_CTABLE( char *user_name, char *param_value );
-int Reset_magics_param_CTABLE( char *user_name );
+int Set_magics_param_CTABLE( const char *user_name, const char *param_value );
+int Reset_magics_param_CTABLE( const char *user_name );
 
 /* Define an array of Mapper structures to sort. */
 
 typedef struct 
 
 {
-	char *cdo_name;
-	char *magics_name;
-	char *magics_type;
-	int  (*Set_magics_param)( char *user_name, char *param_value );  /* Function to Update the Corresponding Magics parameters */
-	int  (*Reset_magics_param)(char *user_name ); /* Function to Reset the Corresponding Magics parameters  */
+	const char *cdo_name;
+	const char *magics_name;
+	const char *magics_type;
+	int  (*Set_magics_param)( const char *user_name, const char *param_value );  /* Function to Update the Corresponding Magics parameters */
+	int  (*Reset_magics_param)(const char *user_name ); /* Function to Reset the Corresponding Magics parameters  */
 
 } CdoMagicsMapper;
 
@@ -58,93 +62,88 @@ CdoMagicsMapper mapper[] =
         }
 };
 
-int Compare( CdoMagicsMapper  *Parameter_one , CdoMagicsMapper *Parameter_two );
 
 void PrintResult ( const CdoMagicsMapper *c );
 
 
-int Set_magics_param_CCOLS( char *user_name, char *param_value )
+int Set_magics_param_CCOLS( const char *user_name, const char *param_value )
 
 {
-	if( user_name == NULL )
-		return 1;
-	printf("Setting the CCOLS magics params \n"); 
+  if( user_name == NULL )
+    return 1;
+  printf("Setting the CCOLS magics params \n"); 
         
-        SetMagicsParameterValue( "contour_shade_colour_method", "string", "list" );
-        SetMagicsParameterValue( "contour_shade_colour_list","stringarray", param_value );
+  SetMagicsParameterValue( "contour_shade_colour_method", "string", "list" );
+  SetMagicsParameterValue( "contour_shade_colour_list","stringarray", param_value );
 #if 0
 #endif
-	return 0;
+  return 0;
 }
 
 
-int Reset_magics_param_CCOLS( char *user_name )
-
+int Reset_magics_param_CCOLS( const char *user_name )
 {
-	printf("Re-Setting the CCOLS magics params \n"); 
-	return 0;
+  (void)user_name;
+  printf("Re-Setting the CCOLS magics params \n"); 
+  return 0;
 }
 
 
-int Set_magics_param_CLEVS( char *user_name, char *param_value )
-
+int Set_magics_param_CLEVS( const char *user_name, const char *param_value )
 {
-	if( user_name == NULL )
-		return 1;
+  if( user_name == NULL )
+    return 1;
 
-        SetMagicsParameterValue( "contour_level_selection_type","string", "level_list" );
-        SetMagicsParameterValue( "contour_level_list","floatarray", param_value );
+  SetMagicsParameterValue( "contour_level_selection_type","string", "level_list" );
+  SetMagicsParameterValue( "contour_level_list","floatarray", param_value );
 
-	return 0;
+  return 0;
 }
 
 
-int Reset_magics_param_CLEVS( char *user_name )
-
+int Reset_magics_param_CLEVS( const char *user_name )
 {
-        SetMagicsParameterValue( "contour_level_selection_type","string", "count" );
-	printf("Re-Setting the CLEVS magics params \n"); 
-	return 0;
+  (void)user_name;  
+  SetMagicsParameterValue( "contour_level_selection_type","string", "count" );
+  printf("Re-Setting the CLEVS magics params \n"); 
+  return 0;
 }
 
-int Set_magics_param_CTABLE( char *user_name, char *param_value )
-
+int Set_magics_param_CTABLE( const char *user_name, const char *param_value )
 {
-	if( user_name == NULL )
-		return 1;
-	printf("Setting the CTABLE magics params \n"); 
+  (void)param_value;
+  
+  if( user_name == NULL )
+    return 1;
+  printf("Setting the CTABLE magics params \n"); 
 #if 0
-#if defined(HAVE_LIBMAGICS)
-        SetMagicsParameterValue( "contour_level_list", "floatarray", param_value );
+  SetMagicsParameterValue( "contour_level_list", "floatarray", param_value );
 #endif
-#endif
-	return 0;
+  return 0;
 }
 
 
-int Reset_magics_param_CTABLE( char *user_name )
-
+int Reset_magics_param_CTABLE( const char *user_name )
 {
-	printf("Re-Setting the CTABLE magics params \n"); 
-	return 0;
+  (void)user_name;  
+  printf("Re-Setting the CTABLE magics params \n"); 
+  return 0;
 }
 
 
 /* This is the comparison function used for sorting and searching. */
      
-int Compare( CdoMagicsMapper *p1, CdoMagicsMapper *p2 )
-
+int Compare( const void *p1, const void *p2 )
 {
-	return strcmp ( p1->cdo_name, p2->cdo_name );
+  return strcmp ( ((CdoMagicsMapper *)p1)->cdo_name, ((CdoMagicsMapper *)p2)->cdo_name );
 }
      
      
 /* Print information about a critter. */
      
 void PrintResult ( const CdoMagicsMapper *c )
-
 {
-	printf ( "CDO Name:%s\t MAGICS Name:%s\t MAGICS Type:%s\n", c->cdo_name, c->magics_name, c->magics_type );
+  printf ( "CDO Name:%s\t MAGICS Name:%s\t MAGICS Type:%s\n", c->cdo_name, c->magics_name, c->magics_type );
 }
      
      
@@ -153,34 +152,33 @@ void PrintResult ( const CdoMagicsMapper *c )
 /* int GetMagicsParameterInfo( const char *user_name, char **magics_name, char **magics_type ) */
 
 int GetMagicsParameterInfo( const char *user_name, char *param_value )
-
 {
-       static int once = 1;
-       int ret_flag = 0;
-       CdoMagicsMapper target, *result;
-       target.cdo_name = (char *) user_name; 
-
-       if( once )
-       {
-       		qsort ( mapper, PARAM_COUNT, sizeof ( CdoMagicsMapper ), ( void * )Compare );
-		once = 0;
-       }
-
-       result = bsearch ( &target, mapper, PARAM_COUNT, sizeof ( CdoMagicsMapper ),
-                          ( void * )Compare );
-       if ( result )
-       {
-		result->Set_magics_param( result->cdo_name, param_value );
-
-		/*
-			*magics_name = result->magics_name;
-			*magics_type = result->magics_type;
-		*/
-       }
-       else
-       {
-	 /* Call the Reset functions of all the features to Reset the magics params to default in the calling function */
-         ret_flag = 1;
-       }
-       return ret_flag;
+  static int once = 1;
+  int ret_flag = 0;
+  CdoMagicsMapper target, *result;
+  target.cdo_name = (char *) user_name; 
+
+  if( once )
+    {
+      qsort (mapper, PARAM_COUNT, sizeof( CdoMagicsMapper ), Compare);
+      once = 0;
+    }
+
+  result = (CdoMagicsMapper*) bsearch(&target, mapper, PARAM_COUNT, sizeof ( CdoMagicsMapper ), Compare);
+  if ( result )
+    {
+      result->Set_magics_param( result->cdo_name, param_value );
+
+      /*
+       *magics_name = result->magics_name;
+       *magics_type = result->magics_type;
+       */
+    }
+  else
+    {
+      /* Call the Reset functions of all the features to Reset the magics params to default in the calling function */
+      ret_flag = 1;
+    }
+
+  return ret_flag;
 }
diff --git a/src/CdoMagicsMapper.h b/src/CdoMagicsMapper.h
index 06f5fc1..bd5798a 100644
--- a/src/CdoMagicsMapper.h
+++ b/src/CdoMagicsMapper.h
@@ -1,10 +1,6 @@
 #ifndef CDO_MAGICS_MAPPER_HH
 #define CDO_MAGICS_MAPPER_HH
 
-#include<stdio.h>
-#include<stdlib.h>
-#include<string.h>
-
 /* void FindMagicsStruct ( const char *user_name ); */
 
 int GetMagicsParameterInfo( const char *user_name, char *param_value );
diff --git a/src/Change.c b/src/Change.c
index efea385..597f2ba 100644
--- a/src/Change.c
+++ b/src/Change.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Change_e5slm.c b/src/Change_e5slm.c
index cef1c6f..d448fec 100644
--- a/src/Change_e5slm.c
+++ b/src/Change_e5slm.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Cloudlayer.c b/src/Cloudlayer.c
index 2626853..a2c2aea 100644
--- a/src/Cloudlayer.c
+++ b/src/Cloudlayer.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Collgrid.c b/src/Collgrid.c
index bf7a9a5..559dcfe 100644
--- a/src/Collgrid.c
+++ b/src/Collgrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -85,11 +85,14 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
   int lsouthnorth = TRUE;
   int gridID2 = -1;
   int idx;
-  int nx, ny, ix, iy, i, j, ij, offset;
+  int ny, ix, iy, i, j, ij, offset;
   int lregular = FALSE;
   int lcurvilinear = FALSE;
   double *xvals2 = NULL, *yvals2 = NULL;
 
+  int nx = -1;
+  if ( nxblocks != -1 ) nx = nxblocks;
+
   int gridID   = vlistGrid(ef[0].vlistID, igrid);
   int gridtype = gridInqType(gridID);
   if ( gridtype == GRID_GENERIC && gridInqXsize(gridID) == 0 && gridInqYsize(gridID) == 0 )
@@ -151,9 +154,15 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
               if ( yvals[fileID][0] > yvals[fileID][ysize[fileID]-1] ) lsouthnorth = FALSE;
             }
         }
+      else
+        {
+          xyinfo[fileID].x  = 0;
+          xyinfo[fileID].y  = 0;
+          xyinfo[fileID].id = fileID;
+        }
     }
 
-  if ( cdoVerbose )
+  if ( cdoVerbose && lregular )
     for ( int fileID = 0; fileID < nfiles; fileID++ )
       printf("1 %d %g %g \n",  xyinfo[fileID].id, xyinfo[fileID].x, xyinfo[fileID].y);
 
@@ -174,17 +183,19 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
         for ( int fileID = 0; fileID < nfiles; fileID++ )
           printf("3 %d %g %g \n",  xyinfo[fileID].id, xyinfo[fileID].x, xyinfo[fileID].y);
 
-      nx = 1;
-      for ( int fileID = 1; fileID < nfiles; fileID++ )
+      if ( nx <= 0 )
         {
-          if ( DBL_IS_EQUAL(xyinfo[0].y, xyinfo[fileID].y) ) nx++;
-          else break;
+          nx = 1;
+          for ( int fileID = 1; fileID < nfiles; fileID++ )
+            {
+              if ( DBL_IS_EQUAL(xyinfo[0].y, xyinfo[fileID].y) ) nx++;
+              else break;
+            }
         }
     }
   else
     {
-      nx = nxblocks;
-      if ( nx <= 0 ) cdoAbort("Parameter nx missing!");
+      if ( nx <= 0 ) nx = nfiles;
     }
 
   ny = nfiles/nx;
@@ -269,6 +280,15 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
   if ( xvals2 ) Free(xvals2);
   if ( yvals2 ) Free(yvals2);
 
+  for ( int fileID = 0; fileID < nfiles; fileID++ )
+    {
+      if ( xvals[fileID] ) Free(xvals[fileID]);
+      if ( yvals[fileID] ) Free(yvals[fileID]);
+    }
+  Free(xvals);
+  Free(yvals);
+  Free(xyinfo);
+
   char string[1024];
   string[0] = 0;
   gridID = vlistGrid(ef[0].vlistID, igrid);
@@ -285,22 +305,13 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
   gridInqYunits(gridID, string);
   gridDefYunits(gridID2, string);
 
-  for ( int fileID = 0; fileID < nfiles; fileID++ )
-    {
-      if ( xvals[fileID] ) Free(xvals[fileID]);
-      if ( yvals[fileID] ) Free(yvals[fileID]);
-    }
-  Free(xvals);
-  Free(yvals);
-  Free(xyinfo);
-
   return gridID2;
 }
 
 
 void *Collgrid(void *argument)
 {
-  int nxblocks = 1;
+  int nxblocks = -1;
   int varID, recID;
   int nrecs, nrecs0;
   int levelID;
@@ -476,8 +487,7 @@ void *Collgrid(void *argument)
 	{
 	  if ( gridIDs[i] != -1 ) 
 	    {
-	      if ( gridID == vlistGrid(vlistID2, i) )
-		vars[varID] = TRUE;
+	      if ( gridID == vlistGrid(vlistID2, i) ) vars[varID] = TRUE;
 	      break;
 	    }
 	}
diff --git a/src/Command.c b/src/Command.c
index d6c6a75..bc7b431 100644
--- a/src/Command.c
+++ b/src/Command.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Comp.c b/src/Comp.c
index 1a2f887..ad4be40 100644
--- a/src/Comp.c
+++ b/src/Comp.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Compc.c b/src/Compc.c
index da9abe7..cfdbc62 100644
--- a/src/Compc.c
+++ b/src/Compc.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Complextorect.c b/src/Complextorect.c
index c0c1940..04d432e 100644
--- a/src/Complextorect.c
+++ b/src/Complextorect.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -123,5 +123,5 @@ void *Complextorect(void *argument)
 
   cdoFinish();
 
-  return (NULL);
+  return 0;
 }
diff --git a/src/Cond.c b/src/Cond.c
index 7f34566..3233d09 100644
--- a/src/Cond.c
+++ b/src/Cond.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Cond2.c b/src/Cond2.c
index 1e7af49..6e08f73 100644
--- a/src/Cond2.c
+++ b/src/Cond2.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Condc.c b/src/Condc.c
index 41720a1..3979662 100644
--- a/src/Condc.c
+++ b/src/Condc.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Consecstat.c b/src/Consecstat.c
index 7ee6152..c48f4ed 100644
--- a/src/Consecstat.c
+++ b/src/Consecstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -128,7 +128,8 @@ void *Consecstat(void *argument)
   int histvdate = 0, histvtime = 0;
   int recID, nrecs;
   int varID, nvars;
-  int levelID, nlevels; 
+  int levelID, nlevels;
+  int nmiss;
   double refval = 0.0;
 
   field_t **vars = NULL, **hist = NULL, **periods = NULL;
@@ -199,7 +200,8 @@ void *Consecstat(void *argument)
     for ( recID = 0; recID < nrecs; recID++ )
     {
       streamInqRecord(istreamID, &varID, &levelID);
-      streamReadRecord(istreamID, field.ptr, &field.nmiss);
+      streamReadRecord(istreamID, field.ptr, &nmiss);
+      field.nmiss   = (size_t)nmiss;
       field.grid    = vlistInqVarGrid(ovlistID, varID);
       field.missval = vlistInqVarMissval(ovlistID, varID);
 
@@ -209,14 +211,14 @@ void *Consecstat(void *argument)
       {
         case CONSECSUM:
           streamDefRecord(ostreamID, varID, levelID);
-          streamWriteRecord(ostreamID, vars[varID][levelID].ptr, vars[varID][levelID].nmiss);
+          streamWriteRecord(ostreamID, vars[varID][levelID].ptr, (int)vars[varID][levelID].nmiss);
           break;
         case CONSECTS:
           if ( itsID != 0 )
           {
             selEndOfPeriod(&periods[varID][levelID], hist[varID][levelID], vars[varID][levelID], FALSE);
             streamDefRecord(ostreamID, varID, levelID);
-            streamWriteRecord(ostreamID, periods[varID][levelID].ptr, periods[varID][levelID].nmiss);
+            streamWriteRecord(ostreamID, periods[varID][levelID].ptr, (int)periods[varID][levelID].nmiss);
           }
 #if defined(_OPENMP)
 #pragma omp parallel for default(shared) schedule(static)
@@ -251,7 +253,7 @@ void *Consecstat(void *argument)
       {
         selEndOfPeriod(&periods[varID][levelID], hist[varID][levelID], vars[varID][levelID], TRUE);
         streamDefRecord(ostreamID, varID, levelID);
-        streamWriteRecord(ostreamID, periods[varID][levelID].ptr, periods[varID][levelID].nmiss);
+        streamWriteRecord(ostreamID, periods[varID][levelID].ptr, (int)periods[varID][levelID].nmiss);
       }
     }
   }
diff --git a/src/Copy.c b/src/Copy.c
index 508c899..411ae37 100644
--- a/src/Copy.c
+++ b/src/Copy.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -30,30 +30,27 @@
 
 void *Copy(void *argument)
 {
-  int SELALL, SZIP;
-  int operatorID;
-  int streamID1, streamID2 = CDI_UNDEFID;
+  bool lconstvars = true;
+  int streamID2 = CDI_UNDEFID;
+  int vlistID2 = CDI_UNDEFID;
+  int taxisID2 = CDI_UNDEFID;
   int nrecs;
-  int tsID1, tsID2, recID, varID, levelID;
-  int lcopy = FALSE;
-  int gridsize;
-  int vlistID1, vlistID2 = CDI_UNDEFID;
+  int recID, varID, levelID;
   int nmiss;
-  int streamCnt, nfiles, indf;
-  int taxisID1, taxisID2 = CDI_UNDEFID;
   int ntsteps, nvars;
   double *array = NULL;
   par_io_t parIO;
 
   cdoInitialize(argument);
 
-            cdoOperatorAdd("copy",   0, 0, NULL);
-  SELALL  = cdoOperatorAdd("selall", 0, 0, NULL);
-  SZIP    = cdoOperatorAdd("szip",   0, 0, NULL);
+                cdoOperatorAdd("copy",   0, 0, NULL);
+  int SELALL  = cdoOperatorAdd("selall", 0, 0, NULL);
+  int SZIP    = cdoOperatorAdd("szip",   0, 0, NULL);
 
-  if ( UNCHANGED_RECORD ) lcopy = TRUE;
+  bool lcopy = false;
+  if ( UNCHANGED_RECORD ) lcopy = true;
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   if ( operatorID == SZIP )
     {
@@ -61,18 +58,18 @@ void *Copy(void *argument)
       cdoCompLevel = 0;
     }
 
-  streamCnt = cdoStreamCnt();
-  nfiles = streamCnt - 1;
+  int streamCnt = cdoStreamCnt();
+  int nfiles = streamCnt - 1;
 
-  tsID2 = 0;
-  for ( indf = 0; indf < nfiles; indf++ )
+  int tsID2 = 0;
+  for ( int indf = 0; indf < nfiles; indf++ )
     {
       if ( cdoVerbose ) cdoPrint("Process file: %s", cdoStreamName(indf)->args);
 
-      streamID1 = streamOpenRead(cdoStreamName(indf));
+      int streamID1 = streamOpenRead(cdoStreamName(indf));
 
-      vlistID1 = streamInqVlist(streamID1);
-      taxisID1 = vlistInqTaxis(vlistID1);
+      int vlistID1 = streamInqVlist(streamID1);
+      int taxisID1 = vlistInqTaxis(vlistID1);
 
       if ( indf == 0 )
 	{
@@ -95,13 +92,14 @@ void *Copy(void *argument)
 
 	  if ( ntsteps == 0 && nfiles > 1 )
 	    {	      
+              lconstvars = false;
 	      for ( varID = 0; varID < nvars; ++varID )
 		vlistDefVarTsteptype(vlistID2, varID, TSTEP_INSTANT);
 	    }
 
 	  streamDefVlist(streamID2, vlistID2);
 
-	  gridsize = vlistGridsizeMax(vlistID1);
+	  int gridsize = vlistGridsizeMax(vlistID1);
 	  array = (double*) Malloc(gridsize*sizeof(double));
 	  if ( cdoParIO )
 	    {
@@ -115,7 +113,7 @@ void *Copy(void *argument)
 	  vlistCompare(vlistID1, vlistID2, CMP_ALL);
 	}
 
-      tsID1 = 0;
+      int tsID1 = 0;
       while ( (nrecs = streamInqTimestep(streamID1, tsID1)) )
 	{
 	  taxisCopyTimestep(taxisID2, taxisID1);
@@ -127,6 +125,11 @@ void *Copy(void *argument)
 	      if ( lcopy && (operatorID == SELALL || operatorID == SZIP) )
 		{
 		  streamInqRecord(streamID1, &varID, &levelID);
+
+                  if ( lconstvars && tsID2 > 0 && tsID1 == 0 )
+                    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT )
+                      continue;
+                  
 		  streamDefRecord(streamID2,  varID,  levelID);
 		  streamCopyRecord(streamID2, streamID1);
 		}
@@ -142,6 +145,11 @@ void *Copy(void *argument)
 		  else
 		    {
 		      streamInqRecord(streamID1, &varID, &levelID);
+
+                      if ( lconstvars && tsID2 > 0 && tsID1 == 0 )
+                        if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT )
+                          continue;
+
 		      streamReadRecord(streamID1, array, &nmiss);
 		    }
 		  /*
diff --git a/src/Deltime.c b/src/Deltime.c
index dbc08ff..9dd98ea 100644
--- a/src/Deltime.c
+++ b/src/Deltime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -164,5 +164,5 @@ void *Deltime(void *argument)
 
   cdoFinish();
 
-  return (NULL);
+  return 0;
 }
diff --git a/src/Derivepar.c b/src/Derivepar.c
index 28cb0b1..c878d96 100644
--- a/src/Derivepar.c
+++ b/src/Derivepar.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
   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
diff --git a/src/Detrend.c b/src/Detrend.c
index 315d306..6a1875d 100644
--- a/src/Detrend.c
+++ b/src/Detrend.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -56,12 +56,12 @@ void detrend(long nts, double missval1, double *array1, double *array2)
 	n++;
       }
 
-  work1 = DIV(SUB(sumjx, DIV(MUL(sumx, sumj), n) ),
-	      SUB(sumjj, DIV(MUL(sumj, sumj), n)) );
-  work2 = SUB(DIV(sumx, n), MUL(work1, DIV(sumj, n)));
+  work1 = DIVMN( SUBMN(sumjx, DIVMN( MULMN(sumx, sumj), n) ),
+	      SUBMN(sumjj, DIVMN( MULMN(sumj, sumj), n)) );
+  work2 = SUBMN( DIVMN(sumx, n), MULMN(work1, DIVMN(sumj, n)));
 
   for ( j = 0; j < nts; j++ )
-    array2[j] = SUB(array1[j], ADD(work2, MUL(j, work1)));
+    array2[j] = SUBMN(array1[j], ADDMN(work2, MULMN(j, work1)));
 }
 
 
diff --git a/src/Diff.c b/src/Diff.c
index 23dd7bb..9244412 100644
--- a/src/Diff.c
+++ b/src/Diff.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Distgrid.c b/src/Distgrid.c
index 27c13ae..9e97b83 100644
--- a/src/Distgrid.c
+++ b/src/Distgrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Duplicate.c b/src/Duplicate.c
index 18dcf87..6d7f563 100644
--- a/src/Duplicate.c
+++ b/src/Duplicate.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@ void *Duplicate(void *argument)
   int nvars, nlevel;
   int ntsteps;
   int *vdate = NULL, *vtime = NULL;
-  int idup, ndup = 1;
+  int idup, ndup = 2;
   field_t ***vars = NULL;
 
   cdoInitialize(argument);
diff --git a/src/EOFs.c b/src/EOFs.c
index d670010..695949c 100644
--- a/src/EOFs.c
+++ b/src/EOFs.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Echam5ini.c b/src/Echam5ini.c
index 43612d1..7e5bb2b 100644
--- a/src/Echam5ini.c
+++ b/src/Echam5ini.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -104,7 +104,7 @@ static
 void nce(int istat)
 {
   /*
-    This routine provides a simple interface to netCDF error message routine.
+    This routine provides a simple interface to NetCDF error message routine.
   */
 
   if ( istat != NC_NOERR ) cdoAbort(nc_strerror(istat));
@@ -268,7 +268,7 @@ int import_e5ml(const char *filename, VAR **vars)
   nvars = nvars_ml + 1;
 
 #else
-  cdoAbort("netCDF support not compiled in!");
+  cdoAbort("NetCDF support not compiled in!");
 #endif
 
   return (nvars);
@@ -605,7 +605,7 @@ void export_e5ml(const char *filename, VAR *vars, int nvars, int vdate, int vtim
   nce(nc_close(nc_file_id));
 
 #else
-  cdoAbort("netCDF support not compiled in!");
+  cdoAbort("NetCDF support not compiled in!");
 #endif
 }
 
@@ -1075,7 +1075,7 @@ int import_e5res(const char *filename, VAR **vars, ATTS *atts)
   nvars = varid;
 
 #else
-  cdoAbort("netCDF support not compiled in!");
+  cdoAbort("NetCDF support not compiled in!");
 #endif
 
   return (nvars);
@@ -1420,7 +1420,7 @@ void export_e5res(const char *filename, VAR *vars, int nvars)
   nce(nc_close(nc_file_id));
 
 #else
-  cdoAbort("netCDF support not compiled in!");
+  cdoAbort("NetCDF support not compiled in!");
 #endif
 }
 
diff --git a/src/Enlarge.c b/src/Enlarge.c
index 3d9268a..e1f5a71 100644
--- a/src/Enlarge.c
+++ b/src/Enlarge.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Enlargegrid.c b/src/Enlargegrid.c
index 0fca3c3..0a0aebe 100644
--- a/src/Enlargegrid.c
+++ b/src/Enlargegrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Ensstat.c b/src/Ensstat.c
index a7da8b6..7d142d4 100644
--- a/src/Ensstat.c
+++ b/src/Ensstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Ensstat3.c b/src/Ensstat3.c
index 45f6a66..98328df 100644
--- a/src/Ensstat3.c
+++ b/src/Ensstat3.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Ensval.c b/src/Ensval.c
index 1338930..f80c06d 100644
--- a/src/Ensval.c
+++ b/src/Ensval.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Eof3d.c b/src/Eof3d.c
index 5883300..b91c303 100644
--- a/src/Eof3d.c
+++ b/src/Eof3d.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Eofcoeff.c b/src/Eofcoeff.c
index 0a62b97..96c066f 100644
--- a/src/Eofcoeff.c
+++ b/src/Eofcoeff.c
@@ -2,7 +2,7 @@
  This file is part of CDO. CDO is a collection of Operators to
  manipulate and analyse Climate model Data.
  
- Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+ Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
  See COPYING file for copying and redistribution conditions.
  
  This program is free software; you can redistribute it and/or modify
@@ -127,8 +127,8 @@ void *Eofcoeff(void * argument)
          if ( levelID >= nlevs )
            cdoAbort("Internal error - too high levelID");
          
-         streamReadRecord(streamID1, eof[varID][levelID][eofID].ptr, 
-                          &eof[varID][levelID][eofID].nmiss);
+         streamReadRecord(streamID1, eof[varID][levelID][eofID].ptr, &nmiss);
+         eof[varID][levelID][eofID].nmiss = (size_t) nmiss;
        }
      eofID++;
    }
@@ -203,7 +203,8 @@ void *Eofcoeff(void * argument)
         {
           streamInqRecord(streamID2, &varID, &levelID);
           missval2 = vlistInqVarMissval(vlistID2, varID);
-          streamReadRecord(streamID2, in.ptr, &in.nmiss);  
+          streamReadRecord(streamID2, in.ptr, &nmiss);  
+          in.nmiss = (size_t) nmiss;
           
           for (eofID = 0; eofID < neof; eofID++ )
             {
diff --git a/src/Eofcoeff3d.c b/src/Eofcoeff3d.c
index e647975..db1d24f 100644
--- a/src/Eofcoeff3d.c
+++ b/src/Eofcoeff3d.c
@@ -2,7 +2,7 @@
  This file is part of CDO. CDO is a collection of Operators to
  manipulate and analyse Climate model Data.
  
- Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+ Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
  See COPYING file for copying and redistribution conditions.
  
  This program is free software; you can redistribute it and/or modify
@@ -127,8 +127,8 @@ void *Eofcoeff3d(void * argument)
          if ( levelID >= nlevs )
            cdoAbort("Internal error - too high levelID");
          
-         streamReadRecord(streamID1, eof[varID][levelID][eofID].ptr, 
-                          &eof[varID][levelID][eofID].nmiss);
+         streamReadRecord(streamID1, eof[varID][levelID][eofID].ptr, &nmiss);
+         eof[varID][levelID][eofID].nmiss = (size_t) nmiss;
        }
      eofID++;
    }
@@ -212,8 +212,8 @@ void *Eofcoeff3d(void * argument)
         {
           streamInqRecord(streamID2, &varID, &levelID);
           missval2 = vlistInqVarMissval(vlistID2, varID);
-          streamReadRecord(streamID2, in.ptr, &in.nmiss);  
-
+          streamReadRecord(streamID2, in.ptr, &nmiss);  
+          in.nmiss = (size_t) nmiss;
           
           for (eofID = 0; eofID < neof; eofID++ )
             {
@@ -248,7 +248,7 @@ void *Eofcoeff3d(void * argument)
       for ( eofID = 0; eofID < neof; eofID++ ) {
 	for ( varID = 0; varID < nvars; varID++ ) {
 	  streamDefRecord(streamIDs[eofID], varID, 0);
-	  streamWriteRecord(streamIDs[eofID],out[varID][eofID].ptr,out[varID][eofID].nmiss);
+	  streamWriteRecord(streamIDs[eofID], out[varID][eofID].ptr, (int)out[varID][eofID].nmiss);
 	}
       }
 
diff --git a/src/Exprf.c b/src/Exprf.c
index 54b232f..83ee7b3 100644
--- a/src/Exprf.c
+++ b/src/Exprf.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@
       Exprf      aexprf          Append evaluated expressions from script file
 */
 /*
-Operatoren: +, -, *, \, ^
+Operatoren: +, -, *, \, ^, ==, !=, >, <, >=, <=, <=>, &&, ||, ?:
 Functions: sqrt, exp, log, log10, sin, cos, tan, asin, acos, atan
 Functions: min, max, avg, std, var
 Constansts: M_PI, M_E
@@ -38,242 +38,512 @@ Constansts: M_PI, M_E
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
+#include "grid.h"
 #include "expr.h"
 
+void grid_cell_area(int gridID, double *array);
+int getSurfaceID(int vlistID);
 
-void *Expr(void *argument)
+static
+char *exprs_from_arg(const char *arg)
 {
-  int operatorID;
   char *exprs = NULL;
-  const char *exprf = NULL;
-  int streamID1, streamID2 = CDI_UNDEFID;
-  int offset;
-  int nrecs, nvars, nvars1, nvars2;
-  int gridID, zaxisID;
-  int tsID, recID, varID, levelID;
-  int vlistID1, vlistID2;
-  int gridsize, nlevel;
-  int nmiss;
-  int taxisID1, taxisID2;
-  //int lwarn = TRUE;
-  double missval;
-  double *array = NULL;
-  double *single1, *single2;
-  parse_parm_t parse_arg;
-  void *scanner;
-  int yy_scan_string(const char *str, void *scanner);
+  
+  size_t slen = strlen(arg);
+  exprs = (char*) Malloc(slen+2);
+  strcpy(exprs, operatorArgv()[0]);
+  if ( exprs[slen-1] != ';' )
+    {
+      exprs[slen]   = ';';
+      exprs[slen+1] = 0;
+    }
 
-  cdoInitialize(argument);
+  return exprs;
+}
 
-  yylex_init(&scanner);
-  yyset_extra(&parse_arg, scanner);
+static
+char *exprs_from_file(const char *exprf)
+{
+  char *exprs = NULL;
+  
+  /* Open expr script file for reading */
+  FILE *fp = fopen(exprf, "r");
+  if( fp == NULL ) cdoAbort("Open failed on %s", exprf);
 
+  struct stat filestat;
+  if ( stat(exprf, &filestat) != 0 ) cdoAbort("Stat failed on %s", exprf);
 
-# define REPLACES_VARIABLES(id) cdoOperatorF1(id)
-# define READS_COMMAND_LINE(id) cdoOperatorF2(id)
+  size_t fsize = (size_t) filestat.st_size;
+  exprs = (char*) Malloc(fsize+1);
 
-  cdoOperatorAdd("expr",   1, 1, "expressions");
-  cdoOperatorAdd("exprf",  1, 0, "expr script filename");
-  cdoOperatorAdd("aexpr",  0, 1, "expressions");
-  cdoOperatorAdd("aexprf", 0, 0, "expr script filename");
+  int ichar, ipos = 0;
+  while ( (ichar = fgetc(fp)) != EOF ) exprs[ipos++] = ichar;
 
-  operatorID = cdoOperatorID();
+  exprs[ipos] = 0;
+  if ( ipos == 0 ) cdoAbort("%s is empty!", exprf);
 
-  operatorInputArg(cdoOperatorEnter(operatorID));
+  fclose(fp);
 
-  if ( READS_COMMAND_LINE(operatorID) )
-    {
-      size_t slen;
+  return exprs;
+}
 
-      slen = strlen(operatorArgv()[0]);
-      exprs = (char*) Malloc(slen+2);
-      strcpy(exprs, operatorArgv()[0]);
-      if ( exprs[slen-1] != ';' )
-	{
-	  exprs[slen]   = ';';
-	  exprs[slen+1] = 0;
-	}
-    }
-  else
-    {
-      int ichar, ipos = 0;
-      FILE *fp;
-      size_t fsize;
-      struct stat filestat;
+#define MAX_PARAMS 4096
 
-      exprf = operatorArgv()[0];
 
-      /* Open script file for reading */
-      if( (fp = fopen(exprf, "r")) == NULL ) cdoAbort("Open failed on %s", exprf);
+static
+paramType *params_new(int vlistID)
+{
+  paramType *params = (paramType*) Malloc(MAX_PARAMS*sizeof(paramType));
+  memset(params, 0, MAX_PARAMS*sizeof(paramType));
 
-      if ( stat(exprf, &filestat) != 0 ) cdoAbort("Stat failed on %s", exprf);
+  int nvars1 = vlistNvars(vlistID);
 
-      fsize = (size_t) filestat.st_size;
-      exprs = (char*) Malloc(fsize+1);
+  char name[CDI_MAX_NAME];
+  char longname[CDI_MAX_NAME];
+  char units[CDI_MAX_NAME];
+  for ( int varID = 0; varID < nvars1; varID++ )
+    {
+      int gridID     = vlistInqVarGrid(vlistID, varID);
+      int zaxisID    = vlistInqVarZaxis(vlistID, varID);
+      int steptype   = vlistInqVarTsteptype(vlistID, varID);
+      int ngp        = gridInqSize(gridID);
+      int nlev       = zaxisInqSize(zaxisID);
+      double missval = vlistInqVarMissval(vlistID, varID);
+
+      vlistInqVarName(vlistID, varID, name);
+      vlistInqVarLongname(vlistID, varID, longname);
+      vlistInqVarUnits(vlistID, varID, units);
+      
+      params[varID].select   = false;
+      params[varID].remove   = false;
+      params[varID].lmiss    = true;
+      params[varID].coord    = 0;
+      params[varID].gridID   = gridID;
+      params[varID].zaxisID  = zaxisID;
+      params[varID].steptype = steptype;
+      params[varID].ngp      = ngp;
+      params[varID].nlev     = nlev;
+      params[varID].missval  = missval;
+      params[varID].nmiss    = 0;
+      params[varID].data     = NULL;
+      params[varID].name     = strdup(name);
+      params[varID].longname = strdup(longname);
+      params[varID].units    = strdup(units);
+    }
 
-      while ( (ichar = fgetc(fp)) != EOF ) exprs[ipos++] = ichar;
+  return params;
+}
 
-      exprs[ipos] = 0;
+static
+void params_add_coord(parse_param_t *parse_arg, int coord, int cdiID, int size, const char *units, const char *longname)
+{
+  int ncoords = parse_arg->ncoords;
+  if ( ncoords >= parse_arg->maxcoords )
+    cdoAbort("Too many coordinates (limit=%d)", parse_arg->maxcoords);
+  
+  parse_arg->coords[ncoords].needed   = false;
+  parse_arg->coords[ncoords].coord    = coord;
+  parse_arg->coords[ncoords].cdiID    = cdiID;
+  parse_arg->coords[ncoords].size     = size;
+  parse_arg->coords[ncoords].units    = NULL;
+  parse_arg->coords[ncoords].longname = NULL;
+  parse_arg->coords[ncoords].data     = NULL;
+  if ( units ) parse_arg->coords[ncoords].units = strdup(units);
+  if ( longname ) parse_arg->coords[ncoords].longname = strdup(longname);
+ 
+  parse_arg->ncoords++;
+}
 
-      if ( ipos == 0 ) cdoAbort("%s is empty!", exprf);
 
-      fclose(fp);
+int params_get_coordID(parse_param_t *parse_arg, int coord, int cdiID)
+{
+  int ncoords = parse_arg->ncoords;
+  for ( int coordID = 0; coordID < ncoords; ++coordID )
+    {
+      if ( parse_arg->coords[coordID].coord == coord &&
+           parse_arg->coords[coordID].cdiID == cdiID )
+        return coordID;
     }
 
-  if ( cdoVerbose ) cdoPrint(exprs);
-
+  cdoAbort("%s: coordinate %c not found!", __func__, coord);
+  
+  return -1;
+}
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+static
+void params_add_coordinates(int vlistID, parse_param_t *parse_arg)
+{
+  char longname[CDI_MAX_NAME];
+  char units[CDI_MAX_NAME];
+  int ngrids = vlistNgrids(vlistID);
+  for ( int index = 0; index < ngrids; ++index )
+    {
+      int gridID = vlistGrid(vlistID, index);
+      int size   = gridInqSize(gridID);
+      gridInqXunits(gridID, units);
+      params_add_coord(parse_arg, 'x', gridID, size, units, "longitude");
+      gridInqYunits(gridID, units);
+      params_add_coord(parse_arg, 'y', gridID, size, units, "latitude");
+      
+      params_add_coord(parse_arg, 'a', gridID, size, "m^2", "grid cell area");
+      params_add_coord(parse_arg, 'w', gridID, size, NULL, "grid cell area weights");
+    }
+  int nzaxis = vlistNzaxis(vlistID);
+  for ( int index = 0; index < nzaxis; ++index )
+    {
+      int zaxisID = vlistZaxis(vlistID, index);
+      int size    = zaxisInqSize(zaxisID);
+      zaxisInqUnits(zaxisID, units);
+      zaxisInqLongname(zaxisID, longname);
+      params_add_coord(parse_arg, 'z', zaxisID, size, units, longname);
+    }
+}
 
-  vlistID1 = streamInqVlist(streamID1);
+static
+int params_add_ts(parse_param_t *parse_arg)
+{
+  int varID = -1;
+  paramType *params = parse_arg->params;
+  if ( params )
+    {
+      varID = parse_arg->nparams;
+      if ( varID >= parse_arg->maxparams )
+        cdoAbort("Too many parameter (limit=%d)", parse_arg->maxparams);
+
+      params[varID].name     = strdup("_ts");
+      params[varID].gridID   = parse_arg->pointID;
+      params[varID].zaxisID  = parse_arg->surfaceID;
+      params[varID].steptype = TIME_VARIABLE;
+      params[varID].ngp      = 1;
+      params[varID].nlev     = 1;
+      
+      parse_arg->nparams++;
+    }
 
-  nvars1 = vlistNvars(vlistID1);
+  return varID;
+}
 
-  if ( REPLACES_VARIABLES(operatorID) )
+static
+void params_delete(paramType *params)
+{
+  if ( params )
     {
-      vlistID2 = vlistCreate();
-      nvars = 0;
+      for ( int varID = 0; varID < MAX_PARAMS; varID++ )
+        {
+          if ( params[varID].data )     Free(params[varID].data);
+          if ( params[varID].name )     Free(params[varID].name);
+          if ( params[varID].longname ) Free(params[varID].longname);
+          if ( params[varID].units )    Free(params[varID].units);
+        }
+      Free(params);
     }
+}
+
+void *Expr(void *argument)
+{
+  cdoInitialize(argument);
+
+  parse_param_t parse_arg;
+  void *scanner;
+  int yy_scan_string(const char *str, void *scanner);
+
+  yylex_init(&scanner);
+  yyset_extra(&parse_arg, scanner);
+
+#define REPLACES_VARIABLES(id) cdoOperatorF1(id)
+#define READS_COMMAND_LINE(id) cdoOperatorF2(id)
+
+  cdoOperatorAdd("expr",   1, 1, "expressions");
+  cdoOperatorAdd("exprf",  1, 0, "expr script filename");
+  cdoOperatorAdd("aexpr",  0, 1, "expressions");
+  cdoOperatorAdd("aexprf", 0, 0, "expr script filename");
+
+  int operatorID = cdoOperatorID();
+
+  operatorInputArg(cdoOperatorEnter(operatorID));
+
+  char *exprs = NULL;
+  if ( READS_COMMAND_LINE(operatorID) )
+    exprs = exprs_from_arg(operatorArgv()[0]);
   else
-    {
-      vlistID2 = vlistDuplicate(vlistID1);
-      nvars = nvars1;
-    }
+    exprs = exprs_from_file(operatorArgv()[0]);
 
-  parse_arg.init = 1;
-  parse_arg.vlistID1 = vlistID1;
-  parse_arg.vlistID2 = vlistID2;
-  parse_arg.nvars1   = 0;
-  parse_arg.debug    = 0;
-  if ( cdoVerbose ) parse_arg.debug    = 1;
-  parse_arg.gridID2  = -1;
-  parse_arg.zaxisID2 = -1;
-  parse_arg.tsteptype2  = -1;
-   
-  /* Set all input variables to 'needed' if replacing is switched off */
-  for ( varID = 0; varID < nvars1; varID++ )
-    parse_arg.var_needed[varID] = ! REPLACES_VARIABLES(operatorID);
+  if ( cdoVerbose ) cdoPrint(exprs);
 
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int vlistID1 = streamInqVlist(streamID1);
+  int nvars1 = vlistNvars(vlistID1);
+  int ngrids = vlistNgrids(vlistID1);
+  int nzaxis = vlistNzaxis(vlistID1);
+  int maxcoords = ngrids*4+nzaxis;
+
+  int pointID   = gridCreate(GRID_GENERIC, 1);
+  int surfaceID = getSurfaceID(vlistID1);
+
+  paramType *params = params_new(vlistID1);
+
+  parse_arg.maxparams  = MAX_PARAMS;
+  parse_arg.nparams    = nvars1;
+  parse_arg.nvars1     = nvars1;
+  parse_arg.init       = true;
+  parse_arg.debug      = false;
+  if ( cdoVerbose ) parse_arg.debug = true;
+  parse_arg.params     = params;
+  parse_arg.pointID    = pointID;
+  parse_arg.surfaceID  = surfaceID;
+  parse_arg.needed     = (bool*) Malloc(nvars1*sizeof(bool));
+  parse_arg.coords     = (coordType*) Malloc(maxcoords*sizeof(coordType));
+  parse_arg.maxcoords  = maxcoords;
+  parse_arg.ncoords    = 0;
+  
+  /* Set all input variables to 'needed' if replacing is switched off */
+  for ( int varID = 0; varID < nvars1; varID++ )
+    parse_arg.needed[varID] = ! REPLACES_VARIABLES(operatorID);
+
+  int vartsID = params_add_ts(&parse_arg);
+  parse_arg.tsID       = vartsID;
+  params_add_coordinates(vlistID1, &parse_arg);
+                  
+  CDO_parser_errorno = 0;
   yy_scan_string(exprs, scanner);
   yyparse(&parse_arg, scanner);
+  if ( CDO_parser_errorno != 0 ) cdoAbort("Syntax error!");
 
-  parse_arg.init = 0;
+  parse_arg.init = false;
 
-  nvars2 = vlistNvars(vlistID2);
-  if ( nvars2 == 0 ) cdoAbort("No output variable found!");
-
-  if ( cdoVerbose ) vlistPrint(vlistID2);
+  if ( cdoVerbose )
+    for ( int varID = 0; varID < nvars1; varID++ )
+      if ( parse_arg.needed[varID] )
+	cdoPrint("Needed var: %d %s", varID, params[varID].name);
 
   if ( cdoVerbose )
-    for ( varID = 0; varID < nvars1; varID++ )
-      if ( parse_arg.var_needed[varID] )
-	printf("Needed var: %d %s\n", varID, parse_arg.var[varID]);
+    for ( int varID = 0; varID < parse_arg.nparams; varID++ )
+      cdoPrint("var: %d %s ngp=%lu nlev=%lu coord=%c",
+               varID, params[varID].name, params[varID].ngp, params[varID].nlev, params[varID].coord);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
-  vlistDefTaxis(vlistID2, taxisID2);
+  int *varIDmap = (int*) Malloc(parse_arg.nparams*sizeof(int));
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int vlistID2 = vlistCreate();
+  if ( ! REPLACES_VARIABLES(operatorID) )
+    {
+      vlistClearFlag(vlistID1);
+      int pidx = 0;
+      for ( int varID = 0; varID < nvars1; varID++ )
+        {
+          params[varID].select = false;
+          if ( params[varID].remove == false )
+            {
+              varIDmap[pidx++] = varID;
+              int nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+              for ( int levID = 0; levID < nlevs; levID++ )
+                vlistDefFlag(vlistID1, varID, levID, TRUE);
+            }
+        }
+      vlistCopyFlag(vlistID2, vlistID1);
+    }
 
-  streamDefVlist(streamID2, vlistID2);
+  for ( int pidx = 0; pidx < parse_arg.nparams; pidx++ )
+    {
+      if ( pidx <  nvars1 && params[pidx].select == false ) continue;
+      if ( pidx >= nvars1 && params[pidx].name[0] == '_' ) continue;
+      if ( pidx >= nvars1 && params[pidx].remove == true ) continue;
+      if ( pidx >= nvars1 && params[pidx].coord ) continue;
+
+      int varID = vlistDefVar(vlistID2, params[pidx].gridID, params[pidx].zaxisID, params[pidx].steptype);
+      vlistDefVarName(vlistID2, varID, params[pidx].name);
+      if ( params[pidx].lmiss ) vlistDefVarMissval(vlistID2, varID, params[pidx].missval);
+      if ( params[pidx].units ) vlistDefVarUnits(vlistID2, varID, params[pidx].units);
+      if ( params[pidx].longname ) vlistDefVarLongname(vlistID2, varID, params[pidx].longname);
+      if ( memcmp(params[pidx].name, "var", 3) == 0 )
+        {
+          if ( strlen(params[pidx].name) > 3 && isdigit(params[pidx].name[3]) )
+            {
+              int code = atoi(params[pidx].name+3);
+              vlistDefVarCode(vlistID2, varID, code);
+            }
+        }
+      varIDmap[varID] = pidx;
+    }
 
-  parse_arg.vardata1 = (double**) Malloc(nvars1*sizeof(double*));
-  parse_arg.vardata2 = (double**) Malloc(nvars2*sizeof(double*));
+  int nvars2 = vlistNvars(vlistID2);
+  if ( nvars2 == 0 ) cdoAbort("No output variable found!");
 
-  for ( varID = 0; varID < nvars1; varID++ )
+  for ( int varID = 0; varID < nvars1; varID++ )
     {
-      gridID  = vlistInqVarGrid(vlistID1, varID);
-      zaxisID = vlistInqVarZaxis(vlistID1, varID);
-      /* parse_arg.missval[varID] = vlistInqVarMissval(vlistID1, varID); */
-
-      gridsize = gridInqSize(gridID);
-      nlevel   = zaxisInqSize(zaxisID);
-      if ( parse_arg.var_needed[varID] )
-	parse_arg.vardata1[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
-      else
-	parse_arg.vardata1[varID] = NULL;
+      if ( parse_arg.needed[varID] )
+        {
+          size_t ngp  = params[varID].ngp;
+          size_t nlev = params[varID].nlev;
+          params[varID].data = (double*) Malloc(ngp*nlev*sizeof(double));
+        }
     }
 
-  for ( varID = 0; varID < nvars; varID++ )
+  for ( int varID = parse_arg.nvars1; varID < parse_arg.nparams; varID++ )
     {
-      parse_arg.vardata2[varID] = parse_arg.vardata1[varID];
+      size_t ngp  = params[varID].ngp;
+      size_t nlev = params[varID].nlev;
+      params[varID].data = (double*) Malloc(ngp*nlev*sizeof(double));
     }
 
-  for ( varID = nvars; varID < nvars2; varID++ )
+  for ( int i = 0; i < parse_arg.ncoords; i++ )
     {
-      gridID  = vlistInqVarGrid(vlistID2, varID);
-      zaxisID = vlistInqVarZaxis(vlistID2, varID);
-
-      gridsize = gridInqSize(gridID);
-      nlevel   = zaxisInqSize(zaxisID);
-      parse_arg.vardata2[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
+      if ( parse_arg.coords[i].needed )
+        {
+          int coord = parse_arg.coords[i].coord;
+          if ( coord == 'x' || coord == 'y' || coord == 'a' || coord == 'w' )
+            {
+              int gridID = parse_arg.coords[i].cdiID;
+              size_t ngp = parse_arg.coords[i].size;
+              double *data = (double*) malloc(ngp*sizeof(double));
+              parse_arg.coords[i].data = data;
+              if ( coord == 'x' || coord == 'y' )
+                {
+                  if ( gridInqType(gridID) == GRID_GENERIC )
+                    cdoAbort("Grid has no geographical coordinates!");
+                  if ( gridInqType(gridID) == GRID_GME )
+                    gridID = gridToUnstructured(gridID, 0);
+                  if ( gridInqType(gridID) != GRID_UNSTRUCTURED && gridInqType(gridID) != GRID_CURVILINEAR )
+                    gridID = gridToCurvilinear(gridID, 0);
+                  
+                  if      ( coord == 'x' ) gridInqXvals(gridID, data);
+                  else if ( coord == 'y' ) gridInqYvals(gridID, data);
+              
+                  if ( gridID != parse_arg.coords[i].cdiID ) gridDestroy(gridID);
+                }
+              else if ( coord == 'a' )
+                {
+                  grid_cell_area(gridID, data);
+                }
+              else if ( coord == 'w' )
+                {
+                  data[0] = 1;
+                  if ( ngp > 1 )
+                    {
+                      int wstatus = gridWeights(gridID, data);
+                      if ( wstatus )
+                        cdoWarning("Grid cell bounds not available, using constant grid cell area weights!");
+                    }
+                }
+            }
+          else if ( coord == 'z' )
+            {
+              int zaxisID = parse_arg.coords[i].cdiID;
+              size_t nlev = parse_arg.coords[i].size;
+              double *data = (double*) malloc(nlev*sizeof(double));
+              parse_arg.coords[i].data = data;
+              zaxisInqLevels(zaxisID, data);
+            }
+          else
+            cdoAbort("Computation of coordinate %c not implemented!", coord);
+        }
+    }
+  
+  for ( int varID = parse_arg.nvars1; varID < parse_arg.nparams; varID++ )
+    {
+      int coord = params[varID].coord;
+      if ( coord )
+        {
+          char *varname = strdup(params[varID].name);
+          varname[strlen(varname)-2] = 0;
+          if ( coord == 'x' || coord == 'y' || coord == 'a' || coord == 'w' )
+            {
+              int coordID = params_get_coordID(&parse_arg, coord, params[varID].gridID);
+              int gridID = parse_arg.coords[coordID].cdiID;
+              size_t ngp = parse_arg.coords[coordID].size;
+              double *data = parse_arg.coords[coordID].data;
+              assert(gridID==params[varID].gridID);
+              assert(data!=NULL);
+
+              memcpy(params[varID].data, data, ngp*sizeof(double));
+            }
+          else if ( coord == 'z' )
+            {
+              int coordID = params_get_coordID(&parse_arg, coord, params[varID].zaxisID);
+              int zaxisID = parse_arg.coords[coordID].cdiID;
+              size_t nlev = parse_arg.coords[coordID].size;
+              double *data = parse_arg.coords[coordID].data;
+              assert(zaxisID==params[varID].zaxisID);
+              assert(data!=NULL);
+
+              memcpy(params[varID].data, data, nlev*sizeof(double));
+            }
+          else
+            cdoAbort("Computation of coordinate %c not implemented!", coord);
+
+          free(varname);
+        }
     }
+ 
+  if ( cdoVerbose ) vlistPrint(vlistID2);
+    
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
+  vlistDefTaxis(vlistID2, taxisID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
-  array = (double*) Malloc(gridsize*sizeof(double));
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
-  tsID = 0;
+  streamDefVlist(streamID2, vlistID2);
+
+  int nrecs;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
+      params[vartsID].data[0] = tsID+1;
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID);
-	       
-      for ( varID = 0; varID < nvars; varID++ ) parse_arg.nmiss[varID] = 0;
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int varID = 0; varID < nvars1; varID++ ) params[varID].nmiss = 0;
+
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
+          int varID, levelID;
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  if ( parse_arg.var_needed[varID] )
+	  if ( parse_arg.needed[varID] )
 	    {
-	      gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
-	      offset   = gridsize*levelID;
-	      single1  = parse_arg.vardata1[varID] + offset;
-	      streamReadRecord(streamID1, single1, &nmiss);
-	      parse_arg.nmiss[varID] += nmiss;
-	      /*
-	      if ( nmiss && lwarn )
-		{
-		  cdoWarning("Missing values unsupported for this operator!");
-		  lwarn = FALSE;
-		}
-	      */
+	      size_t offset = params[varID].ngp*levelID;
+	      double *vardata = params[varID].data + offset;
+              int nmiss;
+	      streamReadRecord(streamID1, vardata, &nmiss);
+	      params[varID].nmiss += nmiss;
 	    }
 	}
 
-      for ( varID = nvars; varID < nvars2; varID++ )
+      for ( int varID = 0; varID < nvars2; varID++ )
 	{
-	  gridID   = vlistInqVarGrid(vlistID2, varID);
-	  zaxisID  = vlistInqVarZaxis(vlistID2, varID);
-	  gridsize = gridInqSize(gridID);
-	  nlevel   = zaxisInqSize(zaxisID);
+          int pidx = varIDmap[varID];
+          if ( pidx < nvars1 ) continue;
+          size_t ngp  = params[pidx].ngp;
+          size_t nlev = params[pidx].nlev;
 
-	  memset(parse_arg.vardata2[varID], 0, gridsize*nlevel*sizeof(double));
+          params[pidx].nmiss = 0;
+	  memset(params[pidx].data, 0, ngp*nlev*sizeof(double));
 	}
 
       yy_scan_string(exprs, scanner);
       yyparse(&parse_arg, scanner);
 
-      for ( varID = 0; varID < nvars2; varID++ )
+      for ( int varID = 0; varID < nvars2; varID++ )
 	{
-	  gridID   = vlistInqVarGrid(vlistID2, varID);
-	  zaxisID  = vlistInqVarZaxis(vlistID2, varID);
-	  missval  = vlistInqVarMissval(vlistID2, varID);
+          int pidx = varIDmap[varID];
 
-	  gridsize = gridInqSize(gridID);
-	  nlevel   = zaxisInqSize(zaxisID);
-	  for ( levelID = 0; levelID < nlevel; levelID++ )
+          if ( tsID > 0 && params[pidx].steptype == TIME_CONSTANT ) continue;
+
+	  double missval = vlistInqVarMissval(vlistID2, varID);
+
+          size_t ngp = params[pidx].ngp;
+          int nlev = (int) params[pidx].nlev;
+	  for ( int levelID = 0; levelID < nlev; levelID++ )
 	    {
-	      long i;
-	      offset   = gridsize*levelID;
-	      single2  = parse_arg.vardata2[varID] + offset;
+              size_t offset = ngp*levelID;
+	      double *vardata = params[pidx].data + offset;
 
-	      nmiss = 0;
-	      for ( i = 0; i < gridsize; i++ )
-		if ( DBL_IS_EQUAL(single2[i], missval) ) nmiss++;
+	      int nmiss = 0;
+	      for ( size_t i = 0; i < ngp; i++ )
+		if ( DBL_IS_EQUAL(vardata[i], missval) ) nmiss++;
 
 	      streamDefRecord(streamID2, varID, levelID);
-	      streamWriteRecord(streamID2, single2, nmiss);
+	      streamWriteRecord(streamID2, vardata, nmiss);
 	    }
 	}
 
@@ -287,9 +557,23 @@ void *Expr(void *argument)
 
   yylex_destroy(scanner);
 
-  if ( array ) Free(array);
   if ( exprs ) Free(exprs);
 
+  params_delete(params);
+
+  if ( parse_arg.needed ) Free(parse_arg.needed);
+  if ( parse_arg.coords )
+    {
+      for ( int i = 0; i < parse_arg.ncoords; i++ )
+        {
+          if ( parse_arg.coords[i].data  ) Free(parse_arg.coords[i].data);
+          if ( parse_arg.coords[i].units ) Free(parse_arg.coords[i].units);
+          if ( parse_arg.coords[i].longname ) Free(parse_arg.coords[i].longname);
+        }
+      Free(parse_arg.coords);
+    }
+  if ( varIDmap ) Free(varIDmap);
+
   cdoFinish();
 
   return 0;
diff --git a/src/FC.c b/src/FC.c
index f764a4a..ffd30ce 100644
--- a/src/FC.c
+++ b/src/FC.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Filedes.c b/src/Filedes.c
index d081aaa..393570b 100644
--- a/src/Filedes.c
+++ b/src/Filedes.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -81,20 +81,46 @@ void printAtts(FILE *fp, int vlistID, int varID)
 }
 
 static
-void partab(FILE *fp, int vlistID, int option)
+void printHistory(FILE *fp, int streamID)
 {
+  int fileID = pstreamFileID(streamID);
+  size_t historysize = (size_t) streamInqHistorySize(fileID);
+  if ( historysize > 0 )
+    {
+      char *history = (char*) Malloc(historysize+1);
+      history[historysize] = 0;
+      streamInqHistoryString(fileID, history);
+      fprintf(fp, "  history=%s\n", history);
+    }
+}
+
+static
+void printSource(FILE *fp, int vlistID, int varID)
+{
+  /* institute info */
+  const char *instptr = institutInqLongnamePtr(vlistInqVarInstitut(vlistID, varID));
+  if ( instptr ) fprintf(fp, "  institution=%s\n", instptr);
+
+  /* source info */
+  const char *modelptr = modelInqNamePtr(vlistInqVarModel(vlistID, varID));
+  if ( modelptr ) fprintf(fp, "  source=%s\n", modelptr);
+}
+
+static
+void partab(FILE *fp, int streamID, int option)
+{
+  int vlistID = streamInqVlist(streamID);
   int varID, datatype = -1;
   int param;
   char pstr[32];
   char paramstr[32];
   char varname[CDI_MAX_NAME], varlongname[CDI_MAX_NAME], varstdname[CDI_MAX_NAME], varunits[CDI_MAX_NAME];
   int natts;
-  int nvars;
   int chunktype;
   int linebreak = 1;
   double missval;
       
-  nvars  = vlistNvars(vlistID);
+  int nvars = vlistNvars(vlistID);
   if ( option == 4 ) linebreak = 0;
 
   if ( option == 2 )
@@ -104,6 +130,8 @@ void partab(FILE *fp, int vlistID, int option)
 	{
 	  fprintf(fp, "&parameter\n");
 	  fprintf(fp, "  name=_GLOBAL_\n");
+          printHistory(fp, streamID);
+          printSource(fp, vlistID, 0);
 	  printAtts(fp, vlistID, CDI_GLOBAL);
 	  fprintf(fp, "/\n");
 	}
@@ -229,16 +257,16 @@ void filedes(int streamID)
       printf("  GRIB2 data\n");
       break;
     case FILETYPE_NC:
-      printf("  netCDF data\n");
+      printf("  NetCDF data\n");
       break;
     case FILETYPE_NC2:
-      printf("  netCDF2 data\n");
+      printf("  NetCDF2 data\n");
       break;
     case FILETYPE_NC4:
-      printf("  netCDF4 data\n");
+      printf("  NetCDF4 data\n");
       break;
     case FILETYPE_NC4C:
-      printf("  netCDF4 classic data\n");
+      printf("  NetCDF4 classic data\n");
       break;
     case FILETYPE_SRV:
       printf("  SERVICE data\n");
@@ -410,11 +438,10 @@ void *Filedes(void *argument)
   else if ( operatorID == PARTAB || operatorID == SPARTAB || operatorID == PARTAB2 )
     {
       int option = 1;
-
       if ( operatorID == SPARTAB ) option = 4;
       if ( operatorID == PARTAB2 ) option = 2;
       
-      partab(stdout, vlistID, option);
+      partab(stdout, streamID, option);
     }
   else if ( operatorID == FILEDES )
     {
diff --git a/src/Fillmiss.c b/src/Fillmiss.c
index d6ff705..5f1079c 100644
--- a/src/Fillmiss.c
+++ b/src/Fillmiss.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -409,6 +409,7 @@ void setmisstodis(field_t *field1, field_t *field2, int num_neighbors)
 
 void *Fillmiss(void *argument)
 {
+  int nmiss;
   int nrecs, recID, varID, levelID;
   void (*fill_method) (field_t *fin , field_t *fout , int) = NULL;
 
@@ -488,7 +489,8 @@ void *Fillmiss(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  streamReadRecord(streamID1, field1.ptr, &field1.nmiss);
+	  streamReadRecord(streamID1, field1.ptr, &nmiss);
+          field1.nmiss = (size_t) nmiss;
 
 	  streamDefRecord(streamID2, varID, levelID);
 
diff --git a/src/Filter.c b/src/Filter.c
index c65ca9f..9fb56a4 100644
--- a/src/Filter.c
+++ b/src/Filter.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Fldrms.c b/src/Fldrms.c
index 6a258c5..982c249 100644
--- a/src/Fldrms.c
+++ b/src/Fldrms.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -37,6 +37,7 @@ void *Fldrms(void *argument)
   int recID, nrecs;
   int tsID, varID, levelID;
   int lim;
+  int nmiss;
   int ndiffgrids;
   int needWeights = FALSE;
   double slon, slat;
@@ -122,9 +123,11 @@ void *Fldrms(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  streamReadRecord(streamID1, field1.ptr, &field1.nmiss);
+	  streamReadRecord(streamID1, field1.ptr, &nmiss);
+          field1.nmiss = (size_t) nmiss;
 	  streamInqRecord(streamID2, &varID, &levelID);
-	  streamReadRecord(streamID2, field2.ptr, &field2.nmiss);
+	  streamReadRecord(streamID2, field2.ptr, &nmiss);
+          field2.nmiss = (size_t) nmiss;
 
 	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
 	  field2.grid    = vlistInqVarGrid(vlistID2, varID);
@@ -152,7 +155,7 @@ void *Fldrms(void *argument)
 	  fldrms(field1, field2, &field3);
 
 	  streamDefRecord(streamID3, varID,  levelID);
-	  streamWriteRecord(streamID3, &sglval, field3.nmiss);
+	  streamWriteRecord(streamID3, &sglval, (int)field3.nmiss);
 	}
       tsID++;
     }
diff --git a/src/Fldstat.c b/src/Fldstat.c
index 73f0659..69bc186 100644
--- a/src/Fldstat.c
+++ b/src/Fldstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,9 @@
       Fldstat    fldmean         Field mean
       Fldstat    fldavg          Field average
       Fldstat    fldstd          Field standard deviation
-      Fldstat    fldstd1         Field standard deviation [Divisor is (n-1)]
+      Fldstat    fldstd1         Field standard deviation [Normalize by (n-1)]
       Fldstat    fldvar          Field variance
-      Fldstat    fldvar1         Field variance [Divisor is (n-1)]
+      Fldstat    fldvar1         Field variance [Normalize by (n-1)]
       Fldstat    fldpctl         Field percentiles
 */
 
@@ -210,9 +210,10 @@ void *Fldstat(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  streamReadRecord(streamID1, field.ptr, &field.nmiss);
+	  streamReadRecord(streamID1, field.ptr, &nmiss);
 
-	  field.grid = vlistInqVarGrid(vlistID1, varID);
+          field.nmiss   = (size_t)nmiss;
+          field.grid = vlistInqVarGrid(vlistID1, varID);
 	  field.size = gridInqSize(field.grid);
 
 	  if ( needWeights && field.grid != lastgrid )
@@ -222,7 +223,7 @@ void *Fldstat(void *argument)
 	      if ( useweights && field.size > 1 )
 		{
 		  int wstatus = gridWeights(field.grid, field.weight);
-		  if ( wstatus != 0 && tsID == 0 && levelID == 0 )
+		  if ( wstatus && tsID == 0 && levelID == 0 )
 		    {
 		      char varname[CDI_MAX_NAME];
 		      vlistInqVarName(vlistID1, varID, varname);
diff --git a/src/Fldstat2.c b/src/Fldstat2.c
index 049015e..b644138 100644
--- a/src/Fldstat2.c
+++ b/src/Fldstat2.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -56,8 +56,8 @@ double correlation_s(const double * restrict in0, const double * restrict in1,
     }
 
   out = IS_NOT_EQUAL(wsum0, 0) ?
-        DIV((sum01 * wsum0 - sum0 * sum1),
-	     SQRT((sum00 * wsum0 - sum0 * sum0) *
+        DIVMN((sum01 * wsum0 - sum0 * sum1),
+	     SQRTMN((sum00 * wsum0 - sum0 * sum0) *
 	          (sum11 * wsum0 - sum1 * sum1))) : missval1;
 
   return (out);
diff --git a/src/Fourier.c b/src/Fourier.c
index cea048c..c160373 100644
--- a/src/Fourier.c
+++ b/src/Fourier.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -212,5 +212,5 @@ void *Fourier(void *argument)
 
   cdoFinish();
 
-  return (NULL);
+  return 0;
 }
diff --git a/src/Gengrid.c b/src/Gengrid.c
index e91478e..31cc633 100644
--- a/src/Gengrid.c
+++ b/src/Gengrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Gradsdes.c b/src/Gradsdes.c
index 2c2b06a..e498e67 100644
--- a/src/Gradsdes.c
+++ b/src/Gradsdes.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -680,27 +680,24 @@ void ctl_options(FILE *gdp, int yrev, int zrev, int sequential, int bigendian, i
 static
 void ctl_undef(FILE *gdp, int vlistID)
 {
-  double missval;
-
-  missval = vlistInqVarMissval(vlistID, 0);
+  double missval = vlistInqVarMissval(vlistID, 0);
   fprintf(gdp, "UNDEF  %g\n", missval);
 }
 
 static
 void ctl_vars(FILE *gdp, int filetype, int vlistID, int nvarsout, int *vars)
 {
-  int varID, nvars;
   int ltype, code;
   int zaxisID, nlev;
   int i, j;
   int len;
   char varname[CDI_MAX_NAME], varlongname[CDI_MAX_NAME], varunits[CDI_MAX_NAME];
 
-  nvars   = vlistNvars(vlistID);
+  int nvars = vlistNvars(vlistID);
 
   fprintf(gdp, "VARS  %d\n", nvarsout);
 
-  for ( varID = 0; varID < nvars; varID++ )
+  for ( int varID = 0; varID < nvars; varID++ )
     {
       if ( vars[varID] == TRUE )
         {
@@ -1043,7 +1040,7 @@ void *Gradsdes(void *argument)
        filetype != FILETYPE_GRB )
     {
       if ( filetype == FILETYPE_NC )
-        //        cdoAbort("Unsupported file format: netCDF");
+        //        cdoAbort("Unsupported file format: NetCDF");
         ;
       else if ( filetype == FILETYPE_GRB2 )
         //cdoAbort("Unsupported file format: GRIB2");
@@ -1193,7 +1190,7 @@ void *Gradsdes(void *argument)
     }
   else if ( filetype == FILETYPE_NC )
     {
-      fprintf(gdp, "DTYPE  netCDF\n");
+      fprintf(gdp, "DTYPE  NetCDF\n");
     }
 
   /* XYHEADER */
diff --git a/src/Gridboxstat.c b/src/Gridboxstat.c
index 248d2bf..76b84d0 100644
--- a/src/Gridboxstat.c
+++ b/src/Gridboxstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,9 @@
       Gridboxstat    gridboxmean         Gridbox mean
       Gridboxstat    gridboxavg          Gridbox average
       Gridboxstat    gridboxstd          Gridbox standard deviation
-      Gridboxstat    gridboxstd1         Gridbox standard deviation [Divisor is (n-1)]
+      Gridboxstat    gridboxstd1         Gridbox standard deviation [Normalize by (n-1)]
       Gridboxstat    gridboxvar          Gridbox variance
-      Gridboxstat    gridboxvar1         Gridbox variance [Divisor is (n-1)]
+      Gridboxstat    gridboxvar1         Gridbox variance [Normalize by (n-1)]
 */
 
 
@@ -557,6 +557,7 @@ void gridboxstat(field_t *field1, field_t *field2, int xinc, int yinc, int statf
 
 void *Gridboxstat(void *argument)
 {
+  int nmiss;
   int lastgrid = -1;
   int wstatus = FALSE;
   int index;
@@ -638,7 +639,8 @@ void *Gridboxstat(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID1, &varID, &levelID);
-          streamReadRecord(streamID1, field1.ptr, &field1.nmiss);
+          streamReadRecord(streamID1, field1.ptr, &nmiss);
+          field1.nmiss = (size_t) nmiss;
 
           field1.grid = vlistInqVarGrid(vlistID1, varID);
           field1.size = gridInqSize(field1.grid);
@@ -662,7 +664,7 @@ void *Gridboxstat(void *argument)
           gridboxstat(&field1, &field2, xinc, yinc, operfunc);
           
           streamDefRecord(streamID2, varID,  levelID);
-          streamWriteRecord(streamID2, field2.ptr, field2.nmiss);
+          streamWriteRecord(streamID2, field2.ptr, (int)field2.nmiss);
         }
       tsID++;
     }
diff --git a/src/Gridcell.c b/src/Gridcell.c
index c0d4ec7..666f3eb 100644
--- a/src/Gridcell.c
+++ b/src/Gridcell.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -38,6 +38,44 @@ double orthodrome(double px1, double py1, double px2, double py2)
 }
 
 
+void grid_cell_area(int gridID, double *array)
+{
+  int gridtype = gridInqType(gridID);
+  if ( gridtype == GRID_LONLAT      ||
+       gridtype == GRID_GAUSSIAN    ||
+       gridtype == GRID_LCC         ||
+       gridtype == GRID_GME         ||
+       gridtype == GRID_CURVILINEAR ||
+       gridtype == GRID_UNSTRUCTURED )
+    {
+      if ( gridHasArea(gridID) )
+        {
+          if ( cdoVerbose ) cdoPrint("Using existing grid cell area!");
+          gridInqArea(gridID, array);
+        }
+      else
+        {
+          int status = gridGenArea(gridID, array);
+          if ( status == 1 )
+            cdoAbort("%s: Grid corner missing!", __func__);
+          else if ( status == 2 )
+            cdoAbort("%s: Can't compute grid cell area for this grid!", __func__);
+
+          int ngp = gridInqSize(gridID);
+          for ( int i = 0; i < ngp; ++i )
+            array[i] *= PlanetRadius*PlanetRadius;
+        }
+    }
+  else
+    {
+      if ( gridtype == GRID_GAUSSIAN_REDUCED )
+        cdoAbort("Unsupported grid type: %s, use CDO option -R to convert reduced to regular grid!",
+                 gridNamePtr(gridtype));
+      else
+        cdoAbort("%s: Unsupported grid type: %s", __func__, gridNamePtr(gridtype));
+    }
+}
+
 void *Gridcell(void *argument)
 {
   int GRIDAREA, GRIDWGTS, GRIDMASK, GRIDDX, GRIDDY;
@@ -135,39 +173,7 @@ void *Gridcell(void *argument)
 
   if ( operatorID == GRIDAREA )
     {
-      gridtype = gridInqType(gridID);
-      if ( gridtype == GRID_LONLAT      ||
-	   gridtype == GRID_GAUSSIAN    ||
-	   gridtype == GRID_LCC         ||
-	   gridtype == GRID_GME         ||
-	   gridtype == GRID_CURVILINEAR ||
-	   gridtype == GRID_UNSTRUCTURED )
-	{
-	  if ( gridHasArea(gridID) )
-	    {
-	      if ( cdoVerbose ) cdoPrint("Using existing grid cell area!");
-	      gridInqArea(gridID, array);
-	    }
-	  else
-	    {
-	      status = gridGenArea(gridID, array);
-	      if ( status == 1 )
-		cdoAbort("Grid corner missing!");
-	      else if ( status == 2 )
-		cdoAbort("Can't compute grid cell areas for this grid!");
-
-	      for ( i = 0; i < gridsize; ++i )
-		array[i] *= PlanetRadius*PlanetRadius;
-	    }
-	}
-      else
-	{
-	  if ( gridtype == GRID_GAUSSIAN_REDUCED )
-	    cdoAbort("Unsupported grid type: %s, use CDO option -R to convert reduced to regular grid!",
-		     gridNamePtr(gridtype));
-	  else
-	    cdoAbort("Unsupported grid type: %s", gridNamePtr(gridtype));
-	}
+      grid_cell_area(gridID, array);
     }
   else if ( operatorID == GRIDWGTS )
     {
diff --git a/src/Gridsearch.c b/src/Gridsearch.c
index 9be79af..4993765 100644
--- a/src/Gridsearch.c
+++ b/src/Gridsearch.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Harmonic.c b/src/Harmonic.c
index af39598..ba3db04 100644
--- a/src/Harmonic.c
+++ b/src/Harmonic.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Hi.c b/src/Hi.c
index f2d515a..1a93ce0 100755
--- a/src/Hi.c
+++ b/src/Hi.c
@@ -91,6 +91,7 @@ void *Hi(void *argument)
 {
   int streamID1, streamID2, streamID3, streamID4;
   int gridsize;
+  int nmiss;
   int nrecs, nrecs2, nrecs3, recID;
   int tsID;
   int gridID, zaxisID;
@@ -165,13 +166,16 @@ void *Hi(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID1, &levelID1);
-	  streamReadRecord(streamID1, field1.ptr, &field1.nmiss);
-
+	  streamReadRecord(streamID1, field1.ptr, &nmiss);
+          field1.nmiss = (size_t) nmiss;
+          
 	  streamInqRecord(streamID2, &varID2, &levelID2);
-	  streamReadRecord(streamID2, field2.ptr, &field2.nmiss);
+	  streamReadRecord(streamID2, field2.ptr, &nmiss);
+          field2.nmiss = (size_t) nmiss;
 	  
 	  streamInqRecord(streamID3, &varID3, &levelID3);
-	  streamReadRecord(streamID3, field3.ptr, &field3.nmiss);
+	  streamReadRecord(streamID3, field3.ptr, &nmiss);
+          field3.nmiss = (size_t) nmiss;
 	  
 	  if ( varID1 != varID2 || varID1 != varID3 || levelID1 != levelID2 || levelID1 != levelID3 )
 	    cdoAbort("Input streams have different structure!");
@@ -190,7 +194,7 @@ void *Hi(void *argument)
 	  farexpr(&field1, field2, field3, humidityIndex);
 	  
 	  streamDefRecord(streamID4, varID4, levelID1);
-	  streamWriteRecord(streamID4, field1.ptr, field1.nmiss);
+	  streamWriteRecord(streamID4, field1.ptr, (int)field1.nmiss);
 	}
 
       tsID++;
diff --git a/src/Histogram.c b/src/Histogram.c
index 5f1eb95..1805dc1 100644
--- a/src/Histogram.c
+++ b/src/Histogram.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Importamsr.c b/src/Importamsr.c
index 95bf82c..9217c6e 100644
--- a/src/Importamsr.c
+++ b/src/Importamsr.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Importbinary.c b/src/Importbinary.c
index 49e292b..91dc656 100644
--- a/src/Importbinary.c
+++ b/src/Importbinary.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Importcmsaf.c b/src/Importcmsaf.c
index e577cf2..8fa2b00 100644
--- a/src/Importcmsaf.c
+++ b/src/Importcmsaf.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Importobs.c b/src/Importobs.c
index 61fdf3c..fd38bec 100644
--- a/src/Importobs.c
+++ b/src/Importobs.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Info.c b/src/Info.c
index f9ffdb8..3c284f6 100644
--- a/src/Info.c
+++ b/src/Info.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Input.c b/src/Input.c
index 64a6a04..ca6de8a 100644
--- a/src/Input.c
+++ b/src/Input.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Intgrid.c b/src/Intgrid.c
index 7dc4493..2f82010 100644
--- a/src/Intgrid.c
+++ b/src/Intgrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Intgridtraj.c b/src/Intgridtraj.c
index 0765c6c..9cd9823 100644
--- a/src/Intgridtraj.c
+++ b/src/Intgridtraj.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Intlevel.c b/src/Intlevel.c
index ef3a61c..2009e9f 100644
--- a/src/Intlevel.c
+++ b/src/Intlevel.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Intlevel3d.c b/src/Intlevel3d.c
index 9d1dc1b..73033a6 100644
--- a/src/Intlevel3d.c
+++ b/src/Intlevel3d.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Intntime.c b/src/Intntime.c
index e36383a..a28e400 100644
--- a/src/Intntime.c
+++ b/src/Intntime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Inttime.c b/src/Inttime.c
index d61dfb9..fc9b8ea 100644
--- a/src/Inttime.c
+++ b/src/Inttime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Intyear.c b/src/Intyear.c
index 2e4c4d1..bbf83e6 100644
--- a/src/Intyear.c
+++ b/src/Intyear.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Invert.c b/src/Invert.c
index 2d519ad..fdad71c 100644
--- a/src/Invert.c
+++ b/src/Invert.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -135,21 +135,13 @@ void invertLonDes(int vlistID)
 static
 void invertLatDes(int vlistID)
 {
-  int index, ngrids;
-  int gridID1, gridID2;
-  int nlat, nlon, size;
-  int ilat, ilon;
-  int gridtype, nv, iv;
-  double *yv1, *yv2;
-  double *yb1, *yb2;
-
-  ngrids = vlistNgrids(vlistID);
-  for ( index = 0; index < ngrids; index++ )
+  int ngrids = vlistNgrids(vlistID);
+  for ( int index = 0; index < ngrids; index++ )
     {
-      gridID1 = vlistGrid(vlistID, index);
-      gridID2 = gridDuplicate(gridID1);
+      int gridID1 = vlistGrid(vlistID, index);
+      int gridID2 = gridDuplicate(gridID1);
 
-      gridtype = gridInqType(gridID1);
+      int gridtype = gridInqType(gridID1);
 
       if ( gridtype != GRID_GENERIC && gridtype != GRID_GAUSSIAN &&
 	   gridtype != GRID_LONLAT  && gridtype != GRID_CURVILINEAR )
@@ -157,32 +149,30 @@ void invertLatDes(int vlistID)
 
       if ( gridInqYvals(gridID1, NULL) )
 	{
-	  nlon  = gridInqXsize(gridID1);
-	  nlat  = gridInqYsize(gridID1);
+	  int nlon  = gridInqXsize(gridID1);
+	  int nlat  = gridInqYsize(gridID1);
 
-	  if ( gridtype == GRID_CURVILINEAR )
-	    size = nlon*nlat;
-	  else
-            size = nlat;
+          int size = nlat;
+	  if ( gridtype == GRID_CURVILINEAR ) size = nlon*nlat;
 
-	  yv1 = (double*) Malloc(size*sizeof(double));
-	  yv2 = (double*) Malloc(size*sizeof(double));
+	  double *yv1 = (double*) Malloc(size*sizeof(double));
+	  double *yv2 = (double*) Malloc(size*sizeof(double));
 
 
 	  if ( gridtype == GRID_CURVILINEAR )
 	    {
 	      gridInqXvals(gridID1, yv1);
 
-	      for ( ilat = 0; ilat < nlat; ilat++ )
-		for ( ilon = 0; ilon < nlon; ilon++ )
+	      for ( int ilat = 0; ilat < nlat; ilat++ )
+		for ( int ilon = 0; ilon < nlon; ilon++ )
 		  yv2[(nlat-ilat-1)*nlon + ilon] = yv1[ilat*nlon + ilon];
 
 	      gridDefXvals(gridID2, yv2);
 
 	      gridInqYvals(gridID1, yv1);
 
-	      for ( ilat = 0; ilat < nlat; ilat++ )
-		for ( ilon = 0; ilon < nlon; ilon++ )
+	      for ( int ilat = 0; ilat < nlat; ilat++ )
+		for ( int ilon = 0; ilon < nlon; ilon++ )
 		  yv2[(nlat-ilat-1)*nlon + ilon] = yv1[ilat*nlon + ilon];
 
 	      gridDefYvals(gridID2, yv2);
@@ -191,7 +181,7 @@ void invertLatDes(int vlistID)
 	    {
 	      gridInqYvals(gridID1, yv1);
 
-	      for ( ilat = 0; ilat < nlat; ilat++ )
+	      for ( int ilat = 0; ilat < nlat; ilat++ )
 		yv2[nlat-ilat-1] = yv1[ilat];
 
 	      gridDefYvals(gridID2, yv2);
@@ -203,31 +193,29 @@ void invertLatDes(int vlistID)
 
       if ( gridInqYbounds(gridID1, NULL) )
 	{
-	  nlon  = gridInqXsize(gridID1);
-	  nlat  = gridInqYsize(gridID1);
+	  int nlon  = gridInqXsize(gridID1);
+	  int nlat  = gridInqYsize(gridID1);
 
-	  nv = gridInqNvertex(gridID1);
+	  int nv = gridInqNvertex(gridID1);
 
-	  if ( gridtype == GRID_CURVILINEAR )
-	    size = nv*nlon*nlat;
-	  else
-            size = nv*nlat;
+          int size = nlat;
+	  if ( gridtype == GRID_CURVILINEAR ) size = nlon*nlat;
 
-	  yb1 = (double*) Malloc(size*sizeof(double));
-	  yb2 = (double*) Malloc(size*sizeof(double));
+	  double *yb1 = (double*) Malloc(size*sizeof(double));
+	  double *yb2 = (double*) Malloc(size*sizeof(double));
 
 	  gridInqYbounds(gridID1, yb1);
 
 	  if ( gridtype == GRID_CURVILINEAR )
 	    {
-	      for ( ilat = 0; ilat < nlat; ilat++ )
-		for ( ilon = 0; ilon < nlon; ilon++ )
-		  for ( iv = 0; iv < nv; iv++ )
+	      for ( int ilat = 0; ilat < nlat; ilat++ )
+		for ( int ilon = 0; ilon < nlon; ilon++ )
+		  for ( int iv = 0; iv < nv; iv++ )
 		    yb2[(nlat-ilat-1)*nlon*nv + ilon*nv + iv] = yb1[ilat*nlon*nv + ilon*nv + iv];
 	    }
 	  else
 	    {
-		for ( ilat = 0; ilat < nlat; ilat++ )
+		for ( int ilat = 0; ilat < nlat; ilat++ )
 		  {
 		    yb2[nlat*2-ilat*2-1] = yb1[ilat*2];
 		    yb2[nlat*2-ilat*2-2] = yb1[ilat*2+1];
diff --git a/src/Invertlev.c b/src/Invertlev.c
index a1fcb18..8183c61 100644
--- a/src/Invertlev.c
+++ b/src/Invertlev.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Isosurface.c b/src/Isosurface.c
index 777a7e9..0181d01 100644
--- a/src/Isosurface.c
+++ b/src/Isosurface.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Kvl.c b/src/Kvl.c
index 0e05ff0..f8bb495 100644
--- a/src/Kvl.c
+++ b/src/Kvl.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Log.c b/src/Log.c
index 83933ca..27a180b 100644
--- a/src/Log.c
+++ b/src/Log.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Maggraph.c b/src/Maggraph.c
index e801d44..4effca3 100644
--- a/src/Maggraph.c
+++ b/src/Maggraph.c
@@ -2,8 +2,7 @@
 #  include "config.h" /* HAVE_LIBMAGICS */
 #endif
 
-#include<limits.h>  /* TEMPORARY FIX, UNTIL NEXT MAGICS LIBRARY RELEASE */ 
-
+#include <limits.h>
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
@@ -11,28 +10,16 @@
 #include "pstream.h"
 
 #if defined(HAVE_LIBMAGICS)
-#include "magics_api.h"
-#endif
 
+#include "magics_api.h"
 
-#if defined(HAVE_LIBXML2)
-
-#include<libxml/parser.h>
-#include<libxml/tree.h>
-#include "template_parser.h"
 #include "magics_template_parser.h"
 #include "results_template_parser.h"
-#include <ctype.h>
-
-
-extern xmlNode  *magics_node;
-
-#endif
+#include "StringUtilities.h"
 
 #define DBG 0
 
-
-char *line_colours[] = {     "red", "green", "blue", "yellow", "cyan", "magenta",
+const char *line_colours[] = {"red", "green", "blue", "yellow", "cyan", "magenta",
 			     "avocado","beige", "brick", "brown", "burgundy",
 			     "charcoal", "chestnut", "coral", "cream", 
 			     "evergreen", "gold", 
@@ -52,18 +39,14 @@ char *line_colours[] = {     "red", "green", "blue", "yellow", "cyan", "magenta"
 			     "bluishpurple", "purple",
 			};
 
-char  *graph_params[] = {"ymin","ymax","sigma","stat","obsv","device"};
+const char  *graph_params[] = {"ymin","ymax","sigma","stat","obsv","device"};
 
 int graph_param_count = sizeof(graph_params)/sizeof(char*);
 int num_colours = sizeof( line_colours )/sizeof( char* );
 
-void VerifyGraphParameters( int num_param, char **param_names );
-int compareDateOrTimeStr( char *datetimestr1, char *datetimestr2, char *sep_char );
+int compareDateOrTimeStr( char *datetimestr1, char *datetimestr2, const char *sep_char );
 
-extern int checkdevice();
-extern int IsNumeric();
-extern void StrToUpperCase();
-extern int StringSplitWithSeperator();
+extern int checkdevice(char *device_in);
 
 extern char *DEVICE;
 extern char *DEVICE_TABLE;
@@ -73,14 +56,13 @@ extern int DEVICE_COUNT;
 static
 void maggraph(const char *plotfile, const char *varname,const char *varunits, long nfiles, long *nts, int **vdate, int **vtime, double **datatab, int nparam, char **params)
 {
-  
   char *lines[1];
   char *temp_str;
   char **split_str = NULL;
-  char *sep_char = "=";
+  const char *sep_char = "=";
   char **date_time_str[nfiles];
   char min_date_time_str[1024], max_date_time_str[1024];
-  int  min_index, max_index;
+  int  min_index = 0, max_index = 0;
   char vdatestr[32], vtimestr[32], legend_text_data[256];
   char vdatestr1[32], vtimestr1[32];
   char vdatestr2[32], vtimestr2[32];
@@ -91,11 +73,11 @@ void maggraph(const char *plotfile, const char *varname,const char *varunits, lo
   int count ;
   int num_years = 0, num_months = 0, num_days = 0;
   int ret;
-  long tsID, fileID, i, ntime_steps;
-  double *date_time;
+  long tsID, fileID, i, ntime_steps = 0;
+  double *date_time = NULL;
   double min_val = 1.0e+200, max_val = -1.0e+200;
-  double *mean_val, *std_dev_val;
-  double *spread_min, *spread_max;
+  double *mean_val = NULL, *std_dev_val = NULL;
+  double *spread_min = NULL, *spread_max = NULL;
   double y_min_val = 1.0e+200, y_max_val = -1.0e+200;
   
   if( DBG )
@@ -458,6 +440,7 @@ void maggraph(const char *plotfile, const char *varname,const char *varunits, lo
     split_str_count = 0;
     sep_char = "-";
     split_str_count = StringSplitWithSeperator( max_date_time_str, sep_char, &split_str );
+    (void)split_str_count;
     num_years  = atoi( split_str[0] );
     num_months = atoi( split_str[1] );
     num_days   = atoi( split_str[2] );
@@ -487,10 +470,7 @@ void maggraph(const char *plotfile, const char *varname,const char *varunits, lo
 	1. Loop over the Files
 	2. Loop over the number of time steps 
 	3. Set the attributes for the magics data and plot
-  */  
-   
-#if defined(HAVE_LIBMAGICS)
-
+  */
 
   /* magics_template_parser( magics_node ); */
 
@@ -701,14 +681,10 @@ void maggraph(const char *plotfile, const char *varname,const char *varunits, lo
   
   if( DBG )
     fprintf(stderr, "%s\n",lines[0]);
-
-#endif
-
 }
 
-int compareDateOrTimeStr( char *datetimestr1, char *datetimestr2, char *sep_char )
+int compareDateOrTimeStr( char *datetimestr1, char *datetimestr2, const char *sep_char )
 {
-  
   int    split_str_count1, split_str_count2;
   int	 i,flag[3]; /*  '3' since, three fields are expected in the input strings */
   char   **split_str1 = NULL;
@@ -754,12 +730,8 @@ int compareDateOrTimeStr( char *datetimestr1, char *datetimestr2, char *sep_char
     return 0;
 }
 
-
-#if defined(HAVE_LIBMAGICS)
-
 static
 void init_MAGICS( )
-
 {
   setenv( "MAGPLUS_QUIET","1",1 ); /* To suppress magics messages */
   mag_open();
@@ -770,53 +742,156 @@ void init_MAGICS( )
 
 }
 
-
 static
 void quit_MAGICS( )
-
 {
-
   mag_close ();
   if( DBG )
     fprintf( stdout,"Exiting From MAGICS\n" );
 
 }
 
+static
+void VerifyGraphParameters( int num_param, char **param_names )
+{
+  int i, j;
+  int  found = FALSE, syntax = TRUE, halt_flag = FALSE, split_str_count;
+  char **split_str = NULL;
+  const char *sep_char = "=";
+  char *temp_str;
+  
+  for ( i = 0; i < num_param; ++i )
+    {
+      split_str_count = 0;
+      found = FALSE;
+      syntax = TRUE;
+      split_str_count = StringSplitWithSeperator( param_names[i], sep_char, &split_str );
+      if( split_str_count > 1 ) 
+	{
+	  for ( j = 0; j < graph_param_count; ++j )
+	    {
+	      if( !strcmp( split_str[0], graph_params[j] ) )
+		{
+		  found = TRUE;
+		  if( !strcmp( split_str[0],"obsv" ) ||  !strcmp( split_str[0],"stat" ) )
+		    {  
+		      if( IsNumeric( split_str[1] ) )
+			syntax = FALSE;
+		      else 
+			{			
+			  temp_str = strdup( split_str[1] );    
+			  StrToUpperCase( temp_str );
+			  if( strcmp( temp_str,"TRUE" ) && strcmp( temp_str,"FALSE" ) )
+			    syntax = FALSE;			      
+			}
+		    }	 
+		      
+		  if( !strcmp( split_str[0],"ymin" ) ||  !strcmp( split_str[0],"ymax" ) || !strcmp( split_str[0],"sigma" )  )
+		    {
+		      if( !IsNumeric( split_str[1] ) )
+			syntax = FALSE;       
+		    }
+		    
+		    
+      		  if( !strcmp( split_str[0],"device" ) )
+		    {
+		      if( IsNumeric( split_str[1] ) )
+			syntax = FALSE;       
+		      else 
+			{
+			  if( !strcmp( split_str[0],"device" ) )
+			    {
+			      if( DBG )
+				fprintf( stderr,"Parameter value '%s'\n",split_str[1] );
+			      if( checkdevice( split_str[1] ) )
+				syntax = FALSE;
+
+                              /* Graph not supported in google earth format */
+                              if( !strcmp( split_str[1],"GIF_ANIMATION" ) || !strcmp( split_str[1],"gif_animation" ))
+                                {
+                                   syntax = FALSE;
+	                           fprintf( stderr,"Animation not supported for Graph!\n");
+                                   if( DBG )
+                                     fprintf( stderr,"Parameter value '%s'\n",split_str[1] );
+                                }
+                              if( !strcmp( split_str[1],"KML" ) || !strcmp( split_str[1],"kml" ) )
+                                {
+                                   syntax = FALSE;
+	                           fprintf( stderr," 'kml' format not supported for  Graph!\n");
+                                   if( DBG )
+                                     fprintf( stderr,"Parameter value '%s'\n",split_str[1] );
+                                }
+			    }
+			}
+		    }
+
+/*		    
+		  if( !strcmp( split_str[0],"xml" ) )
+		    {
+		      if( ( fp = fopen( split_str[1],"r") ) == NULL )
+			{
+			  fprintf( stderr,"Input XML File not found in specified path '%s'\n", split_str[1] );
+			  halt_flag = TRUE;
+			}
+		      else
+			{
+			  // HARDCODED THE FILE NAME .. TO BE SENT AS COMMAND LINE ARGUMENT FOR THE MAGICS OPERATOR 
+			  fclose(fp);
+			  init_XMLtemplate_parser( split_str[1] );
+			  updatemagics_and_results_nodes( );
+			}
+		    }
+*/
+		}
+	    }
+	}
+      else
+	{
+	  syntax = FALSE;
+	}
+	
+      if( found == FALSE )
+	{
+	  halt_flag = TRUE;
+	  fprintf( stderr,"Unknown parameter  '%s'!\n", param_names[i] );
+	} 
+      if( found == TRUE && syntax == FALSE )
+	{
+	  halt_flag = TRUE;
+	  fprintf( stderr,"Invalid parameter specification  '%s'!\n", param_names[i] );
+	}
+      Free( split_str );
+    }
+      
+    if( halt_flag == TRUE )
+    {
+      exit(0);
+    }
+}
 #endif
 
 #define NINC_ALLOC 1024
 
 void *Maggraph(void *argument)
 {
-  const char *ofilename;
+  cdoInitialize(argument);
+
+#if defined(HAVE_LIBMAGICS)
   char varname[CDI_MAX_NAME], units[CDI_MAX_NAME];
-  char **pnames = NULL;
   int varID, levelID;
   int gridID;
   int nrecs;
-  int tsID;
-  int streamID;
-  int vlistID, vlistID0 = -1;
+  int vlistID0 = -1;
   int nmiss;
-  int taxisID;
-  int **vdate = NULL, **vtime = NULL;
-  int fileID, nfiles;
-  long *nts, nts_alloc;
-  int nparam = 0;
-  double **datatab = NULL;
-  double val;
-  int i;
+  long nts_alloc;
   
-  cdoInitialize(argument);
-
-  nparam = operatorArgc();
-  pnames = operatorArgv();
+  int nparam = operatorArgc();
+  char **pnames = operatorArgv();
   
-  if( nparam )
-    VerifyGraphParameters(nparam,pnames);
+  if ( nparam ) VerifyGraphParameters(nparam,pnames);
   
-  nfiles = cdoStreamCnt() - 1;
-  ofilename = cdoStreamName(nfiles)->args;
+  int nfiles = cdoStreamCnt() - 1;
+  const char *ofilename = cdoStreamName(nfiles)->args;
   
   if( DBG )
     {
@@ -824,12 +899,12 @@ void *Maggraph(void *argument)
        fprintf( stderr," files %s\n",ofilename );
     }
 	
-  datatab = (double **) Malloc(nfiles*sizeof(double *));
-  vdate   = (int **) Malloc(nfiles*sizeof(int *));
-  vtime   = (int **) Malloc(nfiles*sizeof(int *));
-  nts     = (long*) Malloc(nfiles*sizeof(long));
+  double **datatab = (double **) Malloc(nfiles*sizeof(double *));
+  int **vdate   = (int **) Malloc(nfiles*sizeof(int *));
+  int **vtime   = (int **) Malloc(nfiles*sizeof(int *));
+  long *nts     = (long*) Malloc(nfiles*sizeof(long));
   
-  for ( fileID = 0; fileID < nfiles; fileID++ )
+  for ( int fileID = 0; fileID < nfiles; fileID++ )
     {
       datatab[fileID] = NULL;
       vdate[fileID]   = NULL;
@@ -837,16 +912,15 @@ void *Maggraph(void *argument)
       nts[fileID]     = 0;
     }
 
-  for ( fileID = 0; fileID < nfiles; fileID++ )
+  for ( int fileID = 0; fileID < nfiles; fileID++ )
     {
-      
-     
       if( DBG )
         fprintf( stderr," file %d is %s\n", fileID, cdoStreamName(fileID)->args );
-      streamID = streamOpenRead(cdoStreamName(fileID));
+      
+      int streamID = streamOpenRead(cdoStreamName(fileID));
 
-      vlistID = streamInqVlist(streamID);
-      taxisID = vlistInqTaxis(vlistID);
+      int vlistID = streamInqVlist(streamID);
+      int taxisID = vlistInqTaxis(vlistID);
 
       vlistInqVarUnits(vlistID, 0, units);
       if( DBG )
@@ -855,10 +929,13 @@ void *Maggraph(void *argument)
 	{
 	  vlistInqVarName(vlistID, 0, varname);
 	  
-	  
 	  gridID = vlistInqVarGrid(vlistID, 0);
+          int zaxisID = vlistInqVarZaxis(vlistID, 0);
+          int nvars = vlistNvars(vlistID);
 
+          if ( nvars > 1 ) cdoAbort("Input stream has more than on variable!");
 	  if ( gridInqSize(gridID) != 1 ) cdoAbort("Variable has more than one grid point!");
+	  if ( zaxisInqSize(zaxisID) != 1 ) cdoAbort("Variable has more than one level!");
 
 	  vlistID0 = vlistDuplicate(vlistID);
 	}
@@ -867,11 +944,11 @@ void *Maggraph(void *argument)
 	  vlistCompare(vlistID0, vlistID, CMP_ALL);
 	}
 
-      tsID = 0;
+      int tsID = 0;
       nts_alloc = 0;
       while ( (nrecs = streamInqTimestep(streamID, tsID)) )
 	{
-	  if ( nrecs != 1 ) cdoAbort("Input streams have more than one record!\n");
+	  if ( nrecs != 1 ) cdoAbort("Input stream has more than one point in time!");
 	  
 	  if ( tsID == 0 )
 	    {
@@ -890,7 +967,8 @@ void *Maggraph(void *argument)
 	      vdate[ fileID ]   = (int*) Realloc(vdate[fileID], nts_alloc*sizeof(int));
 	      vtime[ fileID ]   = (int*) Realloc(vtime[fileID], nts_alloc*sizeof(int));
 	    }
-	  
+
+          double val;
 	  streamInqRecord( streamID, &varID, &levelID );
 	  streamReadRecord( streamID, &val, &nmiss );	
 	  datatab[ fileID ][ tsID ] = val;
@@ -904,173 +982,47 @@ void *Maggraph(void *argument)
       streamClose(streamID);
     }
   
-#if defined(HAVE_LIBXML2)
   /* HARDCODED THE FILE NAME .. TO BE SENT AS COMMAND LINE ARGUMENT FOR THE MAGICS OPERATOR */
   /*
   init_XMLtemplate_parser( Filename );
   updatemagics_and_results_nodes( );
   */
-#endif
-
 
-#if defined(HAVE_LIBMAGICS)
   init_MAGICS( );
-#endif
 
   cdoPrint(" Creating PLOT for %s", varname);
   if( DBG )
     {
       fprintf(stderr, "Num params %d\n", nparam);
   
-      for( i = 0; i< nparam; i++ )
+      for( int i = 0; i< nparam; i++ )
 	fprintf(stderr, "Param %s\n", pnames[i]);
     }
   maggraph(ofilename, varname, units, nfiles, nts, vdate, vtime, datatab, nparam, pnames);
 
-#if defined(HAVE_LIBXML2)
   /* quit_XMLtemplate_parser( ); */
-#endif
 
-#if defined(HAVE_LIBMAGICS)
   quit_MAGICS( );
-#endif
 
   if ( vlistID0 != -1 ) vlistDestroy(vlistID0);
 
-  for ( fileID = 0; fileID < nfiles; fileID++ )
+  for ( int fileID = 0; fileID < nfiles; fileID++ )
     {
       if ( datatab[fileID] ) Free(datatab[fileID]);
     }
 
   Free(datatab);
 
-
   if ( vdate ) Free(vdate);
   if ( vtime ) Free(vtime);
 
-  cdoFinish();
-
-  return 0;
-}
-
-
-void VerifyGraphParameters( int num_param, char **param_names )
-
-{
-  int i, j;
-  int  found = FALSE, syntax = TRUE, halt_flag = FALSE, split_str_count;
-  char **split_str = NULL;
-  char *sep_char = "=";
-  char *temp_str;
+#else
   
-  for ( i = 0; i < num_param; ++i )
-    {
-      split_str_count = 0;
-      found = FALSE;
-      syntax = TRUE;
-      split_str_count = StringSplitWithSeperator( param_names[i], sep_char, &split_str );
-      if( split_str_count > 1 ) 
-	{
-	  for ( j = 0; j < graph_param_count; ++j )
-	    {
-	      if( !strcmp( split_str[0], graph_params[j] ) )
-		{
-		  found = TRUE;
-		  if( !strcmp( split_str[0],"obsv" ) ||  !strcmp( split_str[0],"stat" ) )
-		    {  
-		      if( IsNumeric( split_str[1] ) )
-			syntax = FALSE;
-		      else 
-			{			
-			  temp_str = strdup( split_str[1] );    
-			  StrToUpperCase( temp_str );
-			  if( strcmp( temp_str,"TRUE" ) && strcmp( temp_str,"FALSE" ) )
-			    syntax = FALSE;			      
-			}
-		    }	 
-		      
-		  if( !strcmp( split_str[0],"ymin" ) ||  !strcmp( split_str[0],"ymax" ) || !strcmp( split_str[0],"sigma" )  )
-		    {
-		      if( !IsNumeric( split_str[1] ) )
-			syntax = FALSE;       
-		    }
-		    
-		    
-      		  if( !strcmp( split_str[0],"device" ) )
-		    {
-		      if( IsNumeric( split_str[1] ) )
-			syntax = FALSE;       
-		      else 
-			{
-			  if( !strcmp( split_str[0],"device" ) )
-			    {
-			      if( DBG )
-				fprintf( stderr,"Parameter value '%s'\n",split_str[1] );
-			      if( checkdevice( split_str[1] ) )
-				syntax = FALSE;
+  cdoAbort("MAGICS support not compiled in!");
 
-                              /* Graph not supported in google earth format */
-                              if( !strcmp( split_str[1],"GIF_ANIMATION" ) || !strcmp( split_str[1],"gif_animation" ))
-                                {
-                                   syntax = FALSE;
-	                           fprintf( stderr,"Animation not supported for Graph!\n");
-                                   if( DBG )
-                                     fprintf( stderr,"Parameter value '%s'\n",split_str[1] );
-                                }
-                              if( !strcmp( split_str[1],"KML" ) || !strcmp( split_str[1],"kml" ) )
-                                {
-                                   syntax = FALSE;
-	                           fprintf( stderr," 'kml' format not supported for  Graph!\n");
-                                   if( DBG )
-                                     fprintf( stderr,"Parameter value '%s'\n",split_str[1] );
-                                }
-			    }
-			}
-		    }
+#endif
 
-/*		    
-		  if( !strcmp( split_str[0],"xml" ) )
-		    {
-		      if( ( fp = fopen( split_str[1],"r") ) == NULL )
-			{
-			  fprintf( stderr,"Input XML File not found in specified path '%s'\n", split_str[1] );
-			  halt_flag = TRUE;
-			}
-		      else
-			{
-#if defined(HAVE_LIBXML2)
-			  // HARDCODED THE FILE NAME .. TO BE SENT AS COMMAND LINE ARGUMENT FOR THE MAGICS OPERATOR 
-			  fclose(fp);
-			  init_XMLtemplate_parser( split_str[1] );
-			  updatemagics_and_results_nodes( );
-#endif			
-			}
-		    }
-*/
-		}
-	    }
-	}
-      else
-	{
-	  syntax = FALSE;
-	}
-	
-      if( found == FALSE )
-	{
-	  halt_flag = TRUE;
-	  fprintf( stderr,"Unknown parameter  '%s'!\n", param_names[i] );
-	} 
-      if( found == TRUE && syntax == FALSE )
-	{
-	  halt_flag = TRUE;
-	  fprintf( stderr,"Invalid parameter specification  '%s'!\n", param_names[i] );
-	}
-      Free( split_str );
-    }
-      
-    if( halt_flag == TRUE )
-    {
-      exit(0);
-    }
-    
+  cdoFinish();
+
+  return 0;
 }
diff --git a/src/Magplot.c b/src/Magplot.c
index 20d50b4..085c9b9 100644
--- a/src/Magplot.c
+++ b/src/Magplot.c
@@ -7,32 +7,41 @@
 #include "cdo_int.h"
 #include "grid.h"
 #include "pstream.h"
+
+
+#if defined(HAVE_LIBMAGICS)
+
 #include "magics_api.h"
 
-#include<libxml/parser.h>
-#include<libxml/tree.h>
-#include "template_parser.h"
 #include "magics_template_parser.h"
 #include "results_template_parser.h"
-
-xmlDoc *param_doc = NULL;
-xmlNode *root_node = NULL, *magics_node = NULL, *results_node = NULL;
+#include "StringUtilities.h"
 
 #define DBG 0
 
+/***** ADDED for handling plots with  defined lat lon min max *****/
+/*** LAT_MIN,LAT_MAX, LON_MIN,LON_MAX ****/
+/**** lat_min,lat_max,lon_min,lon_max ****/
+
+/****  
+subpage_lower_left_latitude 
+subpage_lower_left_longitude
+subpage_upper_right_latitude
+subpage_upper_right_longitude
+****/
 
 int CONTOUR, SHADED, GRFILL;
 
-char  *contour_params[] = {"min","max","count","interval","list","colour","thickness","style","RGB","device", "step_freq","file_split"};
+const char  *contour_params[] = {"min","max","count","interval","list","colour","thickness","style","RGB","device", "step_freq","file_split","lat_min","lat_max","lon_min","lon_max","projection"};
 int contour_param_count = sizeof(contour_params)/sizeof(char*);
 
-char  *shaded_params[] = {"min","max","count","interval","list","colour_min","colour_max","colourtable","RGB","colour_triad","device","step_freq","file_split"};
+const char  *shaded_params[] = {"min","max","count","interval","list","colour_min","colour_max","colour_table","RGB","colour_triad","device","step_freq","file_split","lat_min","lat_max","lon_min","lon_max","projection"};
 int shaded_param_count = sizeof(shaded_params)/sizeof(char*);
 
-char  *grfill_params[] = {"min","max","count","interval","list","colour_min","colour_max","colourtable","resolution","RGB","colour_triad","device","step_freq","file_split"};
+const char  *grfill_params[] = {"min","max","count","interval","list","colour_min","colour_max","colour_table","resolution","RGB","colour_triad","device","step_freq","file_split","lat_min","lat_max","lon_min","lon_max","projection"};
 int grfill_param_count = sizeof(grfill_params)/sizeof(char*);
 
-char  *STD_COLOUR_TABLE[] = {"red", "green", "blue", "yellow", "cyan", "magenta", "black", "avocado",
+const char  *STD_COLOUR_TABLE[] = {"red", "green", "blue", "yellow", "cyan", "magenta", "black", "avocado",
 			     "beige", "brick", "brown", "burgundy",
 			     "charcoal", "chestnut", "coral", "cream", 
 			     "evergreen", "gold", "grey", 
@@ -59,12 +68,22 @@ int  STD_COLOUR_COUNT = sizeof( STD_COLOUR_TABLE )/sizeof( char* );
 int  USR_COLOUR_COUNT =0;
 
 
-char *STYLE_TABLE[] = { "SOLID","DASH","DOT","CHAIN_DASH","CHAIN_DOT"};
+const char *STYLE_TABLE[] = { "SOLID","DASH","DOT","CHAIN_DASH","CHAIN_DOT"};
 int STYLE_COUNT = sizeof( STYLE_TABLE )/ sizeof( char *);
 
-char *DEVICE_TABLE[] = { "PS","EPS","PDF","PNG","GIF","GIF_ANIMATION","JPEG","SVG","KML"};
+const char *DEVICE_TABLE[] = { "PS","EPS","PDF","PNG","GIF","GIF_ANIMATION","JPEG","SVG","KML"};
 int DEVICE_COUNT = sizeof( DEVICE_TABLE )/ sizeof( char *);
 
+
+/*char *PROJECTION_TABLE[] = { "cylindrical", "polar_stereographic", "polar_north", "geos", "meteosat", "meteosat_57E", "goes_east", "lambert", "EPSG3857", "goode", "collignon", "mollweide", "robinson", "bonne", "google", "efas", "EPSG4326", "lambert_north_atlantic", "mercator", "cartesian", "taylor", "tephigram" };
+*/
+/** The following projections are having some issues to be clarified with Magics++ **/
+
+const char *PROJECTION_TABLE[] = { "cylindrical", "polar_stereographic", "polar_north", "geos", "meteosat", "meteosat_57E", "lambert", "EPSG3857", "goode", "collignon", "mollweide", "robinson", "bonne", "google", "efas", "EPSG4326", "lambert_north_atlantic", "mercator" };
+int PROJECTION_COUNT = sizeof( PROJECTION_TABLE )/ sizeof( char *);
+
+
+
 int ANIM_FLAG = 0, STEP_FREQ = 0; /* '0' for static images like jpeg,ps, etc.. , '1' for animation formats */
 
 
@@ -72,33 +91,27 @@ int checkcolour( char *colour_in );
 int ReadColourTable ( char *filepath );
 int checkstyle( char *style_in );
 int checkdevice( char *device_in );
-void VerifyPlotParameters( int num_param, char **param_names, int opID );
-
-extern int IsNumeric();
-extern void StrToUpperCase();
-extern void StrToLowerCase();
-extern int StringSplitWithSeperator();
-extern void StrReplaceChar( );
+int checkprojection( char *projection_in );
 
  /* Magics default values */
 int COUNT = 10, isRGB = FALSE,   THICKNESS = 1, NUM_LEVELS = 0, FILE_SPLIT = FALSE;
 double YMIN = 1.0e+200, YMAX = -1.0e+200, INTERVAL = 8.0, RESOLUTION = 10.0f, *LEV_LIST = NULL ;
-char *COLOUR = NULL, *COLOUR_MIN = NULL, *COLOUR_MAX = NULL, *STYLE = NULL, *DEVICE = NULL, *COLOUR_TRIAD = NULL;
+double LAT_MIN = 1.0e+200, LAT_MAX = -1.e+200;
+double LON_MIN = 1.0e+200, LON_MAX = -1.e+200;
+const char *COLOUR = NULL, *COLOUR_MIN = NULL, *COLOUR_MAX = NULL, *STYLE = NULL, *DEVICE = NULL, *COLOUR_TRIAD = NULL, *PROJECTION = NULL;
 
 
 static
-void magplot( const char *plotfile, int operatorID, const char *varname, const char *units, long nlon, long nlat, double *grid_center_lon, double *grid_center_lat, double *array,  int nparam, char **params, char *datetime )
+void magplot( const char *plotfile, int operatorID, const char *varname, const char *units, long nlon, long nlat, double *grid_center_lon, double *grid_center_lat, double *array,  int nparam, char **params, char *datetime, bool lregular)
 
 {
   long i;
   double dlon = 0, dlat = 0;
   char plotfilename[4096];
   char *titlename;
-  int j, split_str_count, split_str_count1;
-  char *sep_char = "=";
-  char **split_str = NULL, **split_str1 = NULL;
-  char *temp_str = NULL;
-  char  orig_char = ';', rep_char = ',';
+  int j, split_str_count;
+  const char *sep_char = "=";
+  char **split_str = NULL;
   char tempname[256];
   
   
@@ -116,47 +129,29 @@ void magplot( const char *plotfile, int operatorID, const char *varname, const c
            sep_char = "=";
            split_str_count = StringSplitWithSeperator( params[i], sep_char, &split_str );
 	
-           if( !strcmp( split_str[0],"min" ) )
-	     fprintf(stderr," Min Val %g\n",YMIN );
-	
-           if( !strcmp( split_str[0],"max" ) )
-	     fprintf(stderr,"Max Val %g\n",YMAX );
-	
-           if( !strcmp( split_str[0],"resolution" ) )
-	     fprintf( stderr,"RESOLUTION %g\n",RESOLUTION );
-	
-           if( !strcmp( split_str[0],"colour" ) ) 
-	     fprintf(stderr,"COLOUR %s\n",COLOUR );
+           if ( !strcmp( split_str[0],"min" ) )        fprintf(stderr,"Min Val %g\n",YMIN );
+           if ( !strcmp( split_str[0],"max" ) )        fprintf(stderr,"Max Val %g\n",YMAX );
+           // if ( !strcmp( split_str[0],"resolution" ) ) fprintf( stderr,"RESOLUTION %g\n",RESOLUTION );
+           if ( !strcmp( split_str[0],"colour" ) )     fprintf(stderr,"COLOUR %s\n",COLOUR );
+           if ( !strcmp( split_str[0],"colour_min" ) ) fprintf(stderr,"COLOUR %s\n",COLOUR_MIN );
+           if ( !strcmp( split_str[0],"colour_max" ) ) fprintf(stderr,"COLOUR %s\n",COLOUR_MAX );
+           if ( !strcmp( split_str[0],"interval" ) )   fprintf(stderr,"INTERVAL %f\n",INTERVAL );
+           if( !strcmp( split_str[0],"count" ) )       fprintf(stderr,"COUNT %d\n",COUNT );
 	
-           if( !strcmp( split_str[0],"colour_min" ) ) 
-	     fprintf(stderr,"COLOUR %s\n",COLOUR_MIN );
-	
-           if( !strcmp( split_str[0],"colour_max" ) ) 
-	     fprintf(stderr,"COLOUR %s\n",COLOUR_MAX );
-	
-           if( !strcmp( split_str[0],"interval" ) )
-	     fprintf( stderr,"INTERVAL %f\n",INTERVAL );
-	
-           if( !strcmp( split_str[0],"count" ) )
-	     fprintf( stderr,"COUNT %d\n",COUNT );
-	
-           if( !strcmp( split_str[0],"list" ) ) 
+           if ( !strcmp( split_str[0],"list" ) ) 
 	     {
-	        for( j = 0; j < split_str_count1; j++ )
-	           fprintf( stderr,"LIST %f\n",LEV_LIST[j] ); 
+               for( j = 0; j < split_str_count; j++ )  fprintf(stderr,"LIST %f\n",LEV_LIST[j] ); 
 	     }
 	
-           if( !strcmp( split_str[0],"thickness" ) )
-	     fprintf( stderr,"THICKNESS %d\n",THICKNESS );
-	
-           if( !strcmp( split_str[0],"style" ) )
-	     fprintf( stderr,"STYLE %s\n",STYLE );
-	
-           if( !strcmp( split_str[0],"device" ) )
-	     fprintf( stderr,"DEVICE %s\n",DEVICE );
-
-           if( !strcmp( split_str[0],"step_freq" ) )
-	     fprintf( stderr,"STEP_FREQ %d\n",STEP_FREQ );
+           if ( !strcmp( split_str[0],"thickness" ) )  fprintf(stderr,"THICKNESS %d\n",THICKNESS );
+           if ( !strcmp( split_str[0],"style" ) )      fprintf(stderr,"STYLE %s\n",STYLE );
+           if ( !strcmp( split_str[0],"device" ) )     fprintf(stderr,"DEVICE %s\n",DEVICE );
+           if ( !strcmp( split_str[0],"step_freq" ) )  fprintf(stderr,"STEP_FREQ %d\n",STEP_FREQ );
+           if ( !strcmp( split_str[0],"lat_min" ) )    fprintf(stderr,"Lat Min Val %g\n",LAT_MIN );
+           if ( !strcmp( split_str[0],"lat_max" ) )    fprintf(stderr,"Lat Max Val %g\n",LAT_MAX );
+           if ( !strcmp( split_str[0],"lon_min" ) )    fprintf(stderr,"Lon Min Val %g\n",LON_MIN );
+           if ( !strcmp( split_str[0],"lon_max" ) )    fprintf(stderr,"Lon Max Val %g\n",LON_MAX );
+           if ( !strcmp( split_str[0],"projection" ) ) fprintf(stderr,"PROJECTION %s\n",PROJECTION );
 
            Free(split_str);
         }
@@ -184,47 +179,75 @@ void magplot( const char *plotfile, int operatorID, const char *varname, const c
    
   mag_set2r("input_field", array, nlon, nlat);
 
-  /*
-  	mag_setc("input_field_organization", "REGULAR");
-  	mag_set2r("input_field_latitudes", grid_center_lat, nlon, nlat);
-  	mag_set2r("input_field_longitudes", grid_center_lon, nlon, nlat);
-  */
-
-  mag_setr("input_field_initial_latitude", grid_center_lat[0]);
-  mag_setr("input_field_latitude_step", dlat);
+  if ( lregular )
+    {
+      mag_setc("input_field_organization", "REGULAR");
+      // mag_setc("input_field_organization", "GAUSSIAN");
+
+      mag_setr("input_field_initial_latitude", grid_center_lat[0]);
+      mag_setr("input_field_latitude_step", dlat);
+        
+      mag_setr("input_field_initial_longitude", grid_center_lon[0]);
+      mag_setr("input_field_longitude_step", dlon);
+     }
+  else
+    {
+      mag_setc("input_field_organization", "NONREGULAR");
 
-  mag_setr("input_field_initial_longitude", grid_center_lon[0]);
-  mag_setr("input_field_longitude_step", dlon);
- 
+      mag_set2r("input_field_latitudes", grid_center_lat, nlon, nlat);
+      mag_set2r("input_field_longitudes", grid_center_lon, nlon, nlat);
+    }
+  
   /* magics_template_parser( magics_node ); */
   /* results_template_parser(results_node, varname ); */
 
-
   /* set up the coastline attributes */
   /* mag_setc ("map_coastline_colour", "khaki"); */
   /* mag_setc ("map_grid_colour",      "grey");  */ 
 
-
   /* Parameters common to all operators */
   if( DEVICE )                                
     {
       mag_setc ("output_format", DEVICE );
     }
 
+  if( PROJECTION )
+    {
+      mag_setc ( "subpage_map_projection", PROJECTION );
+    }
+
   mag_seti ("map_label_latitude_frequency",2);
   mag_seti ("map_label_longitude_frequency",2);
   /*mag_setr ("map_label_height",0.5);*/
   mag_setr ("map_label_height",0.4);
 
-
   /* define the contouring parameters */
   if ( operatorID == SHADED )
     {
-
       mag_setc ( "contour", "off" );
       mag_setc ( "contour_shade", "on" );
       mag_setc ( "contour_shade_method", "area_fill" );
       mag_setc ( "contour_label", "off" );
+
+      if( LAT_MIN < 1.0e+200  )
+        {
+	   mag_setr( "subpage_lower_left_latitude", LAT_MIN );
+        }
+
+      if( LON_MIN < 1.0e+200  )
+        {
+	   mag_setr( "subpage_lower_left_longitude", LON_MIN );
+        }
+
+      if( LAT_MAX > -1.0e+200 )
+        {
+	   mag_setr( "subpage_upper_right_latitude", LAT_MAX );
+        }
+
+      if( LON_MAX > -1.0e+200 )
+        {
+	   mag_setr( "subpage_upper_right_longitude", LON_MAX );
+        }
       
       if( YMIN < 1.0e+200  )
         {
@@ -238,13 +261,13 @@ void magplot( const char *plotfile, int operatorID, const char *varname, const c
 	   mag_setr( "contour_max_level", YMAX );
         }
       
-      if( COLOUR_MIN )
-	mag_setc( "contour_shade_min_level_colour", COLOUR_MIN );
-      
       if( COLOUR_MAX )
 	mag_setc( "contour_shade_max_level_colour", COLOUR_MAX );
 
-      if( INTERVAL != 8.0f )
+      if( COLOUR_MIN )
+	mag_setc( "contour_shade_min_level_colour", COLOUR_MIN );
+
+      if( IS_NOT_EQUAL(INTERVAL, 8.0f) )
 	{
 	  mag_setc( "contour_level_selection_type", "INTERVAL" );
 	  mag_setr( "contour_interval", INTERVAL );
@@ -267,7 +290,7 @@ void magplot( const char *plotfile, int operatorID, const char *varname, const c
 	  mag_setc( "contour_shade_colour_method", "LIST" );
 	  mag_set1c( "contour_shade_colour_list",( const char **)USR_COLOUR_TABLE, USR_COLOUR_COUNT ); 
 	}
-	
+          
       if( COLOUR_TRIAD )                                
 	{
 	  mag_setc( "contour_shade_colour_direction", COLOUR_TRIAD );
@@ -290,20 +313,38 @@ void magplot( const char *plotfile, int operatorID, const char *varname, const c
 
       if( DBG )
         {
-           mag_enqc ( "output_name", &tempname );
-           fprintf( stderr, " SHADED Done %s!\n",tempname );
-           fprintf( stderr, " SHADED Done!\n" );
+          mag_enqc ( "output_name", (char*)&tempname );
+          fprintf( stderr, " SHADED Done %s!\n",tempname );
+          fprintf( stderr, " SHADED Done!\n" );
         }
     }
   else if ( operatorID == CONTOUR )
     {
-
       mag_setc ("contour",                  "on");
       mag_setc ("contour_shade",            "off");
       mag_setc ("contour_label",            "on");
       mag_setc ("contour_highlight",        "off");
       
-    
+      if( LAT_MIN < 1.0e+200  )
+        {
+	   mag_setr( "subpage_lower_left_latitude", LAT_MIN );
+        }
+
+      if( LON_MIN < 1.0e+200  )
+        {
+	   mag_setr( "subpage_lower_left_longitude", LON_MIN );
+        }
+
+      if( LAT_MAX > -1.0e+200 )
+        {
+	   mag_setr( "subpage_upper_right_latitude", LAT_MAX );
+        }
+
+      if( LON_MAX > -1.0e+200 )
+        {
+	   mag_setr( "subpage_upper_right_longitude", LON_MAX );
+        }
+      
       if( YMIN < 1.0e+200  )
 	mag_setr( "contour_min_level", YMIN );
 
@@ -315,7 +356,7 @@ void magplot( const char *plotfile, int operatorID, const char *varname, const c
 	mag_setc( "contour_line_colour", COLOUR );
       
       
-      if( INTERVAL != 8.0f )
+      if( IS_NOT_EQUAL(INTERVAL, 8.0f) )
 	{
 	  mag_setc( "contour_level_selection_type", "INTERVAL" );
 	  mag_setr( "contour_interval", INTERVAL );
@@ -339,20 +380,44 @@ void magplot( const char *plotfile, int operatorID, const char *varname, const c
       if( STYLE )
       	  mag_setc( "contour_line_style", STYLE );
       
+      /* Adjust Set The page slightly to fit the legend */
+      mag_setr ( "subpage_x_length", 24. );
+      mag_setr ( "subpage_y_length", 30. );
+
       if( DBG )
         fprintf( stderr, " CONTOUR Done!\n" );
     }
   else if ( operatorID == GRFILL )
     {
-
       mag_setc ( "contour", "off" );
       mag_setc ( "contour_shade", "on" );
 
-      mag_setc ( "contour_shade_technique", "cell_shading" );
+      // mag_setc ( "contour_shade_technique", "cell_shading" );
+      mag_setc ( "contour_shade_technique", "grid_shading" );
 
       mag_setc ( "contour_shade_method", "area_fill" );
       mag_setc ( "contour_label", "off" );
       
+      if( LAT_MIN < 1.0e+200  )
+        {
+	   mag_setr( "subpage_lower_left_latitude", LAT_MIN );
+        }
+
+      if( LON_MIN < 1.0e+200  )
+        {
+	   mag_setr( "subpage_lower_left_longitude", LON_MIN );
+        }
+
+      if( LAT_MAX > -1.0e+200 )
+        {
+	   mag_setr( "subpage_upper_right_latitude", LAT_MAX );
+        }
+
+      if( LON_MAX > -1.0e+200 )
+        {
+	   mag_setr( "subpage_upper_right_longitude", LON_MAX );
+        }
+      
       if( YMIN < 1.0e+200  )
         {
 	   mag_setr( "contour_shade_min_level", YMIN );
@@ -379,7 +444,7 @@ void magplot( const char *plotfile, int operatorID, const char *varname, const c
       if( COLOUR_MAX )
 	mag_setc( "contour_shade_max_level_colour", COLOUR_MAX );
       
-      if( INTERVAL != 8.0f )
+      if( IS_NOT_EQUAL(INTERVAL, 8.0f) )
 	{
 	  mag_setc( "contour_level_selection_type", "INTERVAL" );
 	  mag_setr( "contour_interval", INTERVAL );
@@ -402,10 +467,10 @@ void magplot( const char *plotfile, int operatorID, const char *varname, const c
 	  mag_setc( "contour_shade_colour_method", "LIST" );
 	  mag_set1c( "contour_shade_colour_list",( const char ** ) USR_COLOUR_TABLE, USR_COLOUR_COUNT ); 
 	}
-	
-      if( RESOLUTION != 10.0f)
+      /*
+      if( IS_NOT_EQUAL(RESOLUTION, 10.0f) )
 	mag_setr( "contour_shade_cell_resolution", RESOLUTION );
-      
+      */
       if( COLOUR_TRIAD )                                
 	  mag_setc( "contour_shade_colour_direction", COLOUR_TRIAD );
 
@@ -448,10 +513,7 @@ void magplot( const char *plotfile, int operatorID, const char *varname, const c
   mag_setc("text_justification", "left");
   mag_text();
 
-  if( LEV_LIST ) 
-    Free(LEV_LIST);
-
-
+  if ( LEV_LIST ) Free(LEV_LIST);
 }
 
 
@@ -468,246 +530,31 @@ void init_MAGICS( )
     mag_setc(  "output_ps_split" , "on" );
 }
 
-static
-void quit_MAGICS( )
-{
-
-  mag_close ();
-  if( DBG )
-    fprintf( stderr,"Exiting From MAGICS\n" );
-
-}
-
-void *Magplot(void *argument)
-{
-  int operatorID;
-  int varID, recID;
-  int gridsize;
-  int gridID;
-  int nrecs;
-  int levelID;
-  int tsID;
-  int streamID;
-  int vlistID;
-  int nmiss;
-  int nlon, nlat;
-  int nlev;
-  int zaxisID, taxisID;
-  int vdate, vtime;
-  int nparam = 0;
-  int i;
-  char **pnames = NULL;
-  char varname[CDI_MAX_NAME];
-  double missval;
-  double *array = NULL;
-  double *grid_center_lat = NULL, *grid_center_lon = NULL;
-  char units[CDI_MAX_NAME];
-  char vdatestr[32], vtimestr[32], datetimestr[64];
-
-
-  cdoInitialize(argument);
-  
-  
-  nparam = operatorArgc();
-  pnames = operatorArgv();
-  
-  CONTOUR = cdoOperatorAdd("contour", 0, 0, NULL);
-  SHADED  = cdoOperatorAdd("shaded", 0, 0, NULL);
-  GRFILL  = cdoOperatorAdd("grfill", 0, 0, NULL);
-
-  operatorID = cdoOperatorID();
-  
-  if( nparam )
-    {
-      if( DBG )
-	{
-	  for( i = 0; i < nparam; i++ )
-	    fprintf( stderr,"Param %d is %s!\n",i+1, pnames[i] );
-	}
-      
-      VerifyPlotParameters( nparam, pnames, operatorID );
-    }
-
-  streamID = streamOpenRead(cdoStreamName(0));
-
-  vlistID = streamInqVlist(streamID);
-  taxisID = vlistInqTaxis(vlistID);
-
-  varID = 0;
-  gridID  = vlistInqVarGrid(vlistID, varID);
-  zaxisID = vlistInqVarZaxis(vlistID, varID);
-  missval = vlistInqVarMissval(vlistID, varID);
-
-  if ( gridInqType(gridID) == GRID_GME          ) cdoAbort("GME grid unspported!");
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED ) cdoAbort("Unstructured grid unspported!");
-
-  if ( gridInqType(gridID) != GRID_CURVILINEAR )
-    gridID = gridToCurvilinear(gridID, 1);
-
-  gridsize = gridInqSize(gridID);
-  nlon     = gridInqXsize(gridID);
-  nlat     = gridInqYsize(gridID);
-  nlev     = zaxisInqSize(zaxisID);
-
-  array           = (double*) Malloc(gridsize*sizeof(double));
-  grid_center_lat = (double*) Malloc(gridsize*sizeof(double));
-  grid_center_lon = (double*) Malloc(gridsize*sizeof(double));
-
-  gridInqYvals(gridID, grid_center_lat);
-  gridInqXvals(gridID, grid_center_lon);
-
-  /* Convert lat/lon units if required */
-  gridInqXunits(gridID, units);
-  grid_to_degree(units, gridsize, grid_center_lon, "grid center lon");
-  gridInqYunits(gridID, units);
-  grid_to_degree(units, gridsize, grid_center_lat, "grid center lat");
-					
-  tsID = 0;
-
-  /* HARDCODED THE FILE NAME .. TO BE SENT AS COMMAND LINE ARGUMENT FOR THE MAGICS OPERATOR */
-  /*
-     init_XMLtemplate_parser( Filename );
-     updatemagics_and_results_nodes( );
-  */
-
-
-  init_MAGICS( );
-
-  while ( (nrecs = streamInqTimestep(streamID, tsID)) )
-    {
-      if( ANIM_FLAG )
-        {
-      	  if( nrecs > 1 )
-	    {
-	      cdoWarning("File has more than one variable! Animation creation not possible!!! \n");
-	      break;
-            }
-      	  if( tsID % STEP_FREQ )
-	    {
-                tsID++;
-		continue;
-            }
-	}
-      else 	
-        {
-          if( STEP_FREQ )
-	    {
-          	if( tsID % STEP_FREQ )
-	    	  {
-                     tsID++;
-	             cdoWarning("NOT PLOTTING STEP %d!!!\n",tsID);
-	             continue;
-	    	  }
-            }
-         else 
-            {
-		if( tsID )
-		  {
-	   		cdoWarning("File variables have values at more than one time step! Images created for first time step!!!");
-           		cdoWarning("To plot steps at a particular interval, set 'step_freq' to the frequency of the steps to be plotted!!!");
-           		cdoWarning("To plot steps at random interval, set 'step_freq' to '1' and select the steps using the selection operators!!!");
-       	   		break;
-		  }
-	    }
-        }
-      
-      vdate = taxisInqVdate(taxisID);
-      vtime = taxisInqVtime(taxisID);
-	      
-      date2str(vdate, vdatestr, sizeof(vdatestr));
-      time2str(vtime, vtimestr, sizeof(vtimestr));
-      sprintf( datetimestr, "%s %s", vdatestr, vtimestr );
-      if( DBG )
-        fprintf( stderr,"Date %s Time %s\n",vdatestr, vtimestr );
-
-      for ( recID = 0; recID < nrecs; recID++ )
-	{
-	  streamInqRecord(streamID, &varID, &levelID);
-	  streamReadRecord(streamID, array, &nmiss);
-	  vlistInqVarName(vlistID, varID, varname);
-	  vlistInqVarUnits(vlistID, varID, units);
-
-	  if ( operatorID == SHADED || operatorID == CONTOUR || operatorID == GRFILL )
-          {
-                if( DBG )
-                  {
-                     if( operatorID == SHADED )
-                       fprintf( stderr," Creating SHADED PLOT for %s\n",varname );
-                     else if( operatorID == CONTOUR )
-                       fprintf( stderr," Creating CONTOUR PLOT for %s\n",varname );
-                     else if( operatorID == GRFILL )
-                       fprintf( stderr," Creating GRFILL PLOT for %s\n",varname );
-                  }
-
-                if( DBG )
-                  fprintf( stderr,"Plot %d\n",varID );
-	  	magplot(cdoStreamName(1)->args, operatorID, varname, units, nlon, nlat, grid_center_lon, grid_center_lat, array, nparam, pnames, datetimestr );
-          }
-	  else
-	  	fprintf(stderr,"operator not implemented\n");
-	}
-
-      if( DBG )
-        fprintf( stderr,"TimeStep %d\n",tsID );
-
-       
-      tsID++;
-      /*
-      if( !STEP_FREQ  && tsID )
-        {
-	   cdoWarning("File variables have values at more than one time step! Images created for first time step!!!");
-           cdoWarning("To plot steps at a particular interval, set 'step_freq' to the frequency of the steps to be plotted!!!");
-           cdoWarning("To plot steps at random interval, set 'step_freq' to '1' and select the steps using the selection operators!!!");
-       	   break;
-	}
-      else
-        {
-      	   tsID++;
-           if( DBG )
-             fprintf( stderr,"TimeStep %d\n",tsID );
-	}
-      */
-    }
-
-  if( ANIM_FLAG )
-    {
-      if( FILE_SPLIT == TRUE  ) 
-        cdoWarning("File split parameter ignored!!!");
-    }
-  quit_MAGICS( );
-
-  streamClose(streamID);
-
-  if ( array  ) Free(array);
-  if ( grid_center_lon ) Free(grid_center_lon);
-  if ( grid_center_lat ) Free(grid_center_lat);
-
-/*   quit_XMLtemplate_parser( ); */
-
-  cdoFinish();
-
-  return 0;
-
-}
-
+static
+void quit_MAGICS( )
+{
+  mag_close ();
+  if( DBG )
+    fprintf( stderr,"Exiting From MAGICS\n" );
+}
 
+static
 void VerifyPlotParameters( int num_param, char **param_names, int opID )
-
 {
   int i, j, k;
   int found = FALSE, syntax = TRUE, halt_flag = FALSE, /* file_found = TRUE, */ split_str_count;
-  int param_count;
-  char **params;
+  int param_count = 0;
+  const char **params = NULL;
   char **split_str = NULL, **split_str1 = NULL;
-  char *sep_char = "=";
+  const char *sep_char = "=";
   char *temp_str;
-  char  orig_char = ';', rep_char = ',';
+  const char  orig_char = ';', rep_char = ',';
   FILE *fp;
 
 /*  
   char  *contour_params[] = {"ymin","ymax","count","interval","list","colour","thickness","style"};
-  char  *shaded_params[]  = {"ymin","ymax","count","interval","list","colour_min","colour_max","colortable","step_freq"};
-  char  *grfill_params[]  = {"ymin","ymax","count","interval","list","colour_min","colour_max","colortable","resolution"};
+  char  *shaded_params[]  = {"ymin","ymax","count","interval","list","colour_min","colour_max","colour_table","step_freq"};
+  char  *grfill_params[]  = {"ymin","ymax","count","interval","list","colour_min","colour_max","colour_table","resolution"};
 */
 
 
@@ -748,7 +595,8 @@ void VerifyPlotParameters( int num_param, char **param_names, int opID )
 		  if( !strcmp( split_str[0],"colour" )     || !strcmp( split_str[0],"style" )       ||
 		      !strcmp( split_str[0],"colour_min" ) || !strcmp( split_str[0],"colour_max" )  ||
 		      !strcmp( split_str[0],"RGB" )        || !strcmp( split_str[0],"colour_triad" )||
-		      !strcmp( split_str[0],"device")      || !strcmp( split_str[0],"file_split" )
+		      !strcmp( split_str[0],"device")      || !strcmp( split_str[0],"file_split" )  ||
+		      !strcmp( split_str[0],"projection") 
 		    )
 		    {
 		      if( IsNumeric( split_str[1] ) )
@@ -856,12 +704,19 @@ void VerifyPlotParameters( int num_param, char **param_names, int opID )
 				     COLOUR_TRIAD = "anti_clockwise";
 				}
 			    }
+			  else if( !strcmp( split_str[0],"projection" ) )
+			    {
+			      if( checkprojection( split_str[1] ) )
+				syntax = FALSE;
+			    }
 			}
 		    }
 		      
-		  if( !strcmp( split_str[0],"min" )      ||  !strcmp( split_str[0],"max" )     ||
-		      !strcmp( split_str[0],"count" )     ||  !strcmp( split_str[0],"interval" ) ||
-		      !strcmp( split_str[0],"thickness" ) ||  !strcmp( split_str[0],"resolution" ) || 
+		  if( !strcmp( split_str[0],"min" )       ||  !strcmp( split_str[0],"max" )            ||
+		      !strcmp( split_str[0],"lat_min" )   ||  !strcmp( split_str[0],"lat_max" )        ||
+		      !strcmp( split_str[0],"lon_min" )   ||  !strcmp( split_str[0],"lon_max" )        ||
+		      !strcmp( split_str[0],"count" )     ||  !strcmp( split_str[0],"interval" )       ||
+		      !strcmp( split_str[0],"thickness" ) ||  !strcmp( split_str[0],"resolution" )     ||
 		      !strcmp( split_str[0],"step_freq" )
                     )
 		    {
@@ -897,10 +752,26 @@ void VerifyPlotParameters( int num_param, char **param_names, int opID )
 			     {
 	  	                STEP_FREQ = atoi( split_str[1] );
 			     }
+                           if( !strcmp( split_str[0],"lat_min" ) )
+	                     {
+	                        LAT_MIN = atof( split_str[1] );
+			     }
+                           if( !strcmp( split_str[0],"lat_max" ) )
+	                     {
+	  		        LAT_MAX = atof( split_str[1] );
+			     }
+                           if( !strcmp( split_str[0],"lon_min" ) )
+	                     {
+	                        LON_MIN = atof( split_str[1] );
+			     }
+                           if( !strcmp( split_str[0],"lon_max" ) )
+	                     {
+	  		        LON_MAX = atof( split_str[1] );
+			     }
 	                }
 		    }
 		    
-		  if( !strcmp( split_str[0],"colourtable" ) )
+		  if( !strcmp( split_str[0],"colour_table" ) )
 		    {
 		      if( ( fp = fopen( split_str[1],"r") ) == NULL )
 			{
@@ -973,12 +844,10 @@ void VerifyPlotParameters( int num_param, char **param_names, int opID )
 
 
 int checkcolour( char *colour_in )
-
 {
-
-    int i, n, found = FALSE;
+    int i, n;
     int split_str_count;
-    char *sep_char =",";
+    const char *sep_char =",";
     char **split_str = NULL;
     float  rgb_values[3];
     char temp[256];
@@ -1048,99 +917,96 @@ int checkcolour( char *colour_in )
 	  }
 	  
 	StrToLowerCase( colour_in );
-	for( i = 0 ; i < STD_COLOUR_COUNT; i++ )
+	for ( i = 0 ; i < STD_COLOUR_COUNT; i++ )
 	  {
-	    if( !strcmp( STD_COLOUR_TABLE[i], colour_in ) )
-	      {
-		found = TRUE;
-		return 0;
-	      }
+	    if ( !strcmp( STD_COLOUR_TABLE[i], colour_in ) ) return 0;
 	  }
-	  cdoWarning( "Specified Colour not in Standard colour list, resetting to blue(default colour)!" );
-	  return 1;
+        cdoWarning( "Specified Colour not in Standard colour list, resetting to blue(default colour)!" );
+        return 1;
       }
       
     if( DBG )  
-      cdoWarning( "Colour %s verified!",ref );  
+      cdoWarning( "Colour %s verified!",ref );
+
     return 0;
 }
 
 
-int ReadColourTable ( char *filepath )
-
+int ReadColourTable( char *filepath )
 {
+  int  i, num_colors = 0;
+  char  orig_char = ';', rep_char = ',';
     
-    FILE *fp;
-    int  i, num_colors;
-    char **temp_table = NULL;
-    char  orig_char = ';', rep_char = ',';
-    
-    fp = fopen( filepath,"r" );
+  FILE *fp = fopen( filepath,"r" );
     
-    if( !fp )
-      {
-	fprintf( stdout, "File Not available!" );
-	return 1;
-      }
+  if ( !fp )
+    {
+      fprintf( stdout, "File Not available!" );
+      return 1;
+    }
     
-    fscanf( fp, "%d", &num_colors );
+  fscanf( fp, "%d", &num_colors );
     
-    if( DBG )
-      fprintf( stderr, "Num Colours %d\n", num_colors );
+  if( DBG )
+    fprintf( stderr, "Num Colours %d\n", num_colors );
     
-    if( !num_colors )
-      {
-	cdoWarning("No colours found in File, proceeding with Standard Colour table!\n");
-	fclose(fp);
-	return 1;
-      }
+  if ( !num_colors )
+    {
+      cdoWarning("No colours found in File, proceeding with Standard Colour table!\n");
+      fclose(fp);
+      return 1;
+    }
     
-    USR_COLOUR_COUNT = 0;
-    USR_COLOUR_TABLE = ( char **) Malloc( num_colors * sizeof( char* ));
-    temp_table  = ( char **) Malloc( num_colors * sizeof( char* ));
+  USR_COLOUR_COUNT = 0;
+  USR_COLOUR_TABLE = ( char **) Malloc( num_colors * sizeof( char* ));
+  char **temp_table = ( char **) Malloc( num_colors * sizeof( char* ));
     
-    for( i =0; i < num_colors; i++ )
-      {
-         temp_table[i] = ( char *) Malloc(  256 * sizeof( char ));
-	 fscanf( fp, "%s", temp_table[i] );
-	 if( DBG )
-	   fprintf( stdout, "%s\n", temp_table[i] );
-      } 
+  for ( i = 0; i < num_colors; i++ )
+    {
+      temp_table[i] = (char *) Malloc(256 * sizeof( char ));
+      fscanf( fp, "%s", temp_table[i] );
+      if( DBG )
+        fprintf( stdout, "%s\n", temp_table[i] );
+    }
     
-    for( i = 0; i < num_colors; i++ )
-      {
-	  if( DBG )
-	    fprintf( stdout, "%s \n", temp_table[i] );
+  fclose(fp);
+
+  for ( i = 0; i < num_colors; i++ )
+    {
+      if( DBG )
+        fprintf( stdout, "%s \n", temp_table[i] );
 	  
-	  if( !checkcolour( temp_table[i] ) )
-	    {
-	      if( isRGB )
-		StrReplaceChar( temp_table[i], orig_char, rep_char ); /* replace ';' in RGB format to ',' */
+      if ( !checkcolour( temp_table[i] ) )
+        {
+          if( isRGB )
+            StrReplaceChar( temp_table[i], orig_char, rep_char ); /* replace ';' in RGB format to ',' */
 
-	      if( DBG )
-		fprintf( stdout, "Before appending %s\n", temp_table[i] );
-	      
-	      USR_COLOUR_TABLE[ USR_COLOUR_COUNT ] = strdup( temp_table[i] );
+          if( DBG )
+            fprintf( stdout, "Before appending %s\n", temp_table[i] );
+          
+          USR_COLOUR_TABLE[ USR_COLOUR_COUNT ] = strdup( temp_table[i] );
 	      
-	      /* strcpy( USR_COLOUR_TABLE[ USR_COLOUR_COUNT ], temp_table[i] ); */
-	      USR_COLOUR_COUNT++;
+          /* strcpy( USR_COLOUR_TABLE[ USR_COLOUR_COUNT ], temp_table[i] ); */
+          USR_COLOUR_COUNT++;
 	      
-	      if( DBG )
-		fprintf( stdout, "After appending %s\n", temp_table[i] );
-	    }
-      }
+          if( DBG )
+            fprintf( stdout, "After appending %s\n", temp_table[i] );
+        }
+    }
     
-    if( USR_COLOUR_COUNT < num_colors )
-      {
-	  cdoWarning( " Discarding improper format colours and continuing!\n" );
-      }
-      
-    fclose(fp);   
-    return 0;
+  if( USR_COLOUR_COUNT < num_colors )
+    {
+      cdoWarning( " Discarding improper format colours and continuing!\n" );
+    }
+
+  for ( i = 0; i < num_colors; i++ ) free(temp_table[i]);
+  free(temp_table);
+    
+  return 0;
 }
 
-int checkstyle( char *style_in )
 
+int checkstyle( char *style_in )
 {
     int i, found = FALSE;
     StrToUpperCase( style_in );
@@ -1165,7 +1031,6 @@ int checkstyle( char *style_in )
 
 
 int checkdevice( char *device_in )
-
 {
     int i, found = FALSE;
     StrToUpperCase( device_in );
@@ -1196,3 +1061,238 @@ int checkdevice( char *device_in )
     
     return 1; 
 }
+
+
+int checkprojection( char *projection_in )
+{
+    int i, found = FALSE;
+
+    /*StrToUpperCase( projection_in );*/
+
+    for( i = 0 ; i < PROJECTION_COUNT; i++ )
+      {
+	if( DBG )
+	  fprintf( stderr, "Input %s ref %s\n",projection_in, PROJECTION_TABLE[i] );
+	
+	if( !strcmp( PROJECTION_TABLE[i], projection_in ) )
+	  {
+	    found = TRUE;
+	    PROJECTION = projection_in;
+	    return 0;
+	  }
+      }
+      
+    if( !found )
+      {	
+	 cdoWarning( " Projection specified with Improper value!\n" );
+	 cdoWarning( " Specify one of the following:\n" );
+	 cdoWarning( " cylindrical polar_stereographic polar_north geos meteosat meteosat_57E geos_east lambert EPSG3857 goode collignon mollweide robinson bonne google efas EPSG4326 lambert_north_atlantic mercator cartesian taylor tephigram\n" );
+
+      }	
+    
+    return 1; 
+}
+#endif
+
+
+void *Magplot(void *argument)
+{
+  cdoInitialize(argument);
+
+#if defined(HAVE_LIBMAGICS)
+  int nrecs;
+  int levelID;
+  int nmiss;
+  char varname[CDI_MAX_NAME];
+  char units[CDI_MAX_NAME];
+  char vdatestr[32], vtimestr[32], datetimestr[64];
+  
+  int nparam = operatorArgc();
+  char **pnames = operatorArgv();
+  
+  CONTOUR = cdoOperatorAdd("contour", 0, 0, NULL);
+  SHADED  = cdoOperatorAdd("shaded", 0, 0, NULL);
+  GRFILL  = cdoOperatorAdd("grfill", 0, 0, NULL);
+
+  int operatorID = cdoOperatorID();
+
+  if( nparam )
+    {
+      if( DBG )
+	{
+	  for( int i = 0; i < nparam; i++ )
+	    fprintf( stderr,"Param %d is %s!\n",i+1, pnames[i] );
+	}
+      
+      VerifyPlotParameters( nparam, pnames, operatorID );
+    }
+
+  int streamID = streamOpenRead(cdoStreamName(0));
+
+  int vlistID = streamInqVlist(streamID);
+  int taxisID = vlistInqTaxis(vlistID);
+
+  int varID = 0;
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  // int zaxisID = vlistInqVarZaxis(vlistID, varID);
+  // double missval = vlistInqVarMissval(vlistID, varID);
+
+  int gridtype = gridInqType(gridID);
+  if ( gridtype == GRID_GME          ) cdoAbort("GME grid unspported!");
+  if ( gridtype == GRID_UNSTRUCTURED ) cdoAbort("Unstructured grid unspported!");
+
+  bool lregular = false;
+  if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN ) lregular = true;
+  
+  if ( gridtype != GRID_CURVILINEAR ) gridID = gridToCurvilinear(gridID, 1);
+
+  int gridsize = gridInqSize(gridID);
+  int nlon     = gridInqXsize(gridID);
+  int nlat     = gridInqYsize(gridID);
+  //int nlev     = zaxisInqSize(zaxisID);
+
+  double *array           = (double*) Malloc(gridsize*sizeof(double));
+  double *grid_center_lon = (double*) Malloc(gridsize*sizeof(double));
+  double *grid_center_lat = (double*) Malloc(gridsize*sizeof(double));
+
+  gridInqXvals(gridID, grid_center_lon);
+  gridInqYvals(gridID, grid_center_lat);
+
+  /* Convert lat/lon units if required */
+  gridInqXunits(gridID, units);
+  grid_to_degree(units, gridsize, grid_center_lon, "grid center lon");
+  gridInqYunits(gridID, units);
+  grid_to_degree(units, gridsize, grid_center_lat, "grid center lat");
+					
+  int tsID = 0;
+
+  /* HARDCODED THE FILE NAME .. TO BE SENT AS COMMAND LINE ARGUMENT FOR THE MAGICS OPERATOR */
+  /*
+     init_XMLtemplate_parser( Filename );
+     updatemagics_and_results_nodes( );
+  */
+
+
+  init_MAGICS( );
+
+  while ( (nrecs = streamInqTimestep(streamID, tsID)) )
+    {
+      if( ANIM_FLAG )
+        {
+      	  if( nrecs > 1 )
+	    {
+	      cdoWarning("File has more than one variable! Animation creation not possible!!! \n");
+	      break;
+            }
+      	  if( tsID % STEP_FREQ )
+	    {
+                tsID++;
+		continue;
+            }
+	}
+      else 	
+        {
+          if( STEP_FREQ )
+	    {
+          	if( tsID % STEP_FREQ )
+	    	  {
+                     tsID++;
+	             cdoWarning("NOT PLOTTING STEP %d!!!\n",tsID);
+	             continue;
+	    	  }
+            }
+         else 
+            {
+		if( tsID )
+		  {
+	   		cdoWarning("File variables have values at more than one time step! Images created for first time step!!!");
+           		cdoWarning("To plot steps at a particular interval, set 'step_freq' to the frequency of the steps to be plotted!!!");
+           		cdoWarning("To plot steps at random interval, set 'step_freq' to '1' and select the steps using the selection operators!!!");
+       	   		break;
+		  }
+	    }
+        }
+      
+      int vdate = taxisInqVdate(taxisID);
+      int vtime = taxisInqVtime(taxisID);
+	      
+      date2str(vdate, vdatestr, sizeof(vdatestr));
+      time2str(vtime, vtimestr, sizeof(vtimestr));
+      sprintf( datetimestr, "%s %s", vdatestr, vtimestr );
+      if( DBG )
+        fprintf( stderr,"Date %s Time %s\n",vdatestr, vtimestr );
+
+      for ( int recID = 0; recID < nrecs; recID++ )
+	{
+	  streamInqRecord(streamID, &varID, &levelID);
+	  streamReadRecord(streamID, array, &nmiss);
+	  vlistInqVarName(vlistID, varID, varname);
+	  vlistInqVarUnits(vlistID, varID, units);
+
+	  if ( operatorID == SHADED || operatorID == CONTOUR || operatorID == GRFILL )
+          {
+                if( DBG )
+                  {
+                     if( operatorID == SHADED )
+                       fprintf( stderr," Creating SHADED PLOT for %s\n",varname );
+                     else if( operatorID == CONTOUR )
+                       fprintf( stderr," Creating CONTOUR PLOT for %s\n",varname );
+                     else if( operatorID == GRFILL )
+                       fprintf( stderr," Creating GRFILL PLOT for %s\n",varname );
+                  }
+
+                if( DBG )
+                  fprintf( stderr,"Plot %d\n",varID );
+	  	magplot(cdoStreamName(1)->args, operatorID, varname, units, nlon, nlat, grid_center_lon, grid_center_lat, array, nparam, pnames, datetimestr, lregular);
+          }
+	  else
+	  	fprintf(stderr,"operator not implemented\n");
+	}
+
+      if( DBG )
+        fprintf( stderr,"TimeStep %d\n",tsID );
+
+       
+      tsID++;
+      /*
+      if( !STEP_FREQ  && tsID )
+        {
+	   cdoWarning("File variables have values at more than one time step! Images created for first time step!!!");
+           cdoWarning("To plot steps at a particular interval, set 'step_freq' to the frequency of the steps to be plotted!!!");
+           cdoWarning("To plot steps at random interval, set 'step_freq' to '1' and select the steps using the selection operators!!!");
+       	   break;
+	}
+      else
+        {
+      	   tsID++;
+           if( DBG )
+             fprintf( stderr,"TimeStep %d\n",tsID );
+	}
+      */
+    }
+
+  if( ANIM_FLAG )
+    {
+      if( FILE_SPLIT == TRUE  ) 
+        cdoWarning("File split parameter ignored!!!");
+    }
+  quit_MAGICS( );
+
+  streamClose(streamID);
+
+  if ( array  ) Free(array);
+  if ( grid_center_lon ) Free(grid_center_lon);
+  if ( grid_center_lat ) Free(grid_center_lat);
+
+/*   quit_XMLtemplate_parser( ); */
+#else
+  
+  cdoAbort("MAGICS support not compiled in!");
+
+#endif
+
+  cdoFinish();
+
+  return 0;
+
+}
diff --git a/src/Magvector.c b/src/Magvector.c
index f32b2f7..9c29ecd 100644
--- a/src/Magvector.c
+++ b/src/Magvector.c
@@ -8,33 +8,26 @@
 #include "grid.h"
 #include "pstream.h"
 
+
+#if defined(HAVE_LIBMAGICS)
+
 #include "magics_api.h"
 
-#include<libxml/parser.h>
-#include<libxml/tree.h>
-#include "template_parser.h"
 #include "magics_template_parser.h"
 #include "results_template_parser.h"
-
-extern xmlNode  *magics_node;
+#include "StringUtilities.h"
 
 #define DBG 0
 
 int VECTOR, STREAM;
-char  *vector_params[] = {"thin_fac","unit_vec","device","step_freq"};
+const char  *vector_params[] = {"thin_fac","unit_vec","device","step_freq"};
 int vector_param_count = sizeof(vector_params)/sizeof(char*);
 
-void VerifyVectorParameters( int num_param, char **param_names, int opID );
-
 /* Default Magics Values */
 double THIN_FAC = 2.0, UNIT_VEC = 25.0;
 extern int ANIM_FLAG,STEP_FREQ;
 
-extern int checkdevice();
-extern int IsNumeric();
-extern void StrToUpperCase();
-extern int StringSplitWithSeperator();
-
+extern int checkdevice(char *device_in);
 
 extern char *DEVICE;
 extern char *DEVICE_TABLE;
@@ -48,12 +41,13 @@ void magvector( const char *plotfile, int operatorID, const char *varname, long
         double dlon = 0, dlat = 0;
 	int split_str_count;
 	char plotfilename[4096];
-	char *sep_char= "=";
+	const char *sep_char= "=";
 	char **split_str=NULL;
 	char *temp_str = NULL;
 	char *titlename;
 	
-
+        (void)varname;
+        
 	if( uarray == NULL && varray == NULL )
 	  {
 	    fprintf( stderr," No Velocity Components in input file, cannot creaate Vector PLOT!\n" );
@@ -80,7 +74,8 @@ void magvector( const char *plotfile, int operatorID, const char *varname, long
 	    split_str_count = 0;
 	    sep_char = "=";
 	    split_str_count = StringSplitWithSeperator( params[i], sep_char, &split_str );
-	    
+	    (void)split_str_count;
+            
 	    if( !strcmp( split_str[0],"thin_fac" ) )
 	      {
 		THIN_FAC = atof( split_str[1] );
@@ -128,10 +123,6 @@ void magvector( const char *plotfile, int operatorID, const char *varname, long
 		dlat /= (nlat-1);
 	  }
 
-
-/* #if defined(HAVE_LIBMAGICS) */
-
-
         /* magics_template_parser( magics_node ); */
 
         /* results_template_parser(results_node, varname ); */
@@ -176,11 +167,11 @@ void magvector( const char *plotfile, int operatorID, const char *varname, long
 		mag_seti( "wind_arrow_thickness",1 );
 		mag_coast();
 		
-		if( THIN_FAC != 2.0f )
+		if( IS_NOT_EQUAL(THIN_FAC, 2.0f) )
 		  mag_setr("wind_thinning_factor",THIN_FAC);
 		
 		/*wind_arrow_unit_velocity */
-		if( UNIT_VEC != 25.0f )
+		if( IS_NOT_EQUAL(UNIT_VEC, 25.0f) )
 		  mag_setr("wind_arrow_unit_velocity",UNIT_VEC);
                 
 		mag_wind();
@@ -193,7 +184,6 @@ void magvector( const char *plotfile, int operatorID, const char *varname, long
 	  }
 }
 
-
 static
 void init_MAGICS( )
 
@@ -218,67 +208,148 @@ void quit_MAGICS( )
 
 }
 
-void *Magvector(void *argument)
+static
+void VerifyVectorParameters( int num_param, char **param_names, int opID )
 
 {
-  int operatorID;
-  int varID, recID;
-  int gridsize;
-  int gridID;
+  
+  int i, j;
+  int found = FALSE, syntax = TRUE, halt_flag = FALSE, split_str_count;
+  int param_count = 0;
+  const char **params = NULL;
+  char **split_str = NULL;
+  const char *sep_char = "=";
+
+  /* char  *vector_params[] = {"min","max","count","interval","list","colour","thickness","style","RGB"}; */
+
+  for ( i = 0; i < num_param; ++i )
+    {
+      split_str_count = 0;
+      found = FALSE;
+      syntax = TRUE;
+      split_str_count = StringSplitWithSeperator( param_names[i], sep_char, &split_str );
+      
+      if( DBG )
+	fprintf( stderr, "Verifying params!\n");
+      
+      if( split_str_count > 1 ) 
+	{
+	  
+	  if( opID == VECTOR )
+	    {
+	      param_count = vector_param_count;
+	      params = vector_params;
+	    }
+	  
+	  for ( j = 0; j < param_count; ++j )
+	    {
+	      if( !strcmp( split_str[0], params[j] ) )
+		{
+		  found = TRUE;
+		      
+		  if( !strcmp( split_str[0],"thin_fac" ) || !strcmp( split_str[0],"unit_vec" ) ||
+		      !strcmp( split_str[0],"step_freq" )
+                    )
+		    {
+		      if( !IsNumeric( split_str[1] ) )
+			syntax = FALSE;       
+		    }
+		    
+   		  if( !strcmp( split_str[0],"device" ) )
+		    {
+		      if( IsNumeric( split_str[1] ) )
+			syntax = FALSE;       
+		      else 
+			{
+			  if( !strcmp( split_str[0],"device" ) )
+			    {
+			      if( DBG )
+				fprintf( stderr,"Parameter value '%s'\n",split_str[1] );
+			      if( checkdevice( split_str[1] ) )
+				syntax = FALSE;
+
+                              /* Vector not supported in google earth format */
+			      if( !strcmp( split_str[1],"KML" ) || !strcmp( split_str[1],"kml" ) )
+                                {
+				   syntax = FALSE;
+			           if( DBG )
+				     fprintf( stderr,"Parameter value '%s'\n",split_str[1] );
+                                }
+			    }
+			}
+		    }
+		}
+	    }
+	}
+      else
+	{
+	  syntax = FALSE;
+	}
+	
+      if( found == FALSE )
+	{
+	  halt_flag = TRUE;
+	  fprintf( stderr,"Invalid parameter  '%s'\n", param_names[i] );
+	} 
+      if( found == TRUE && syntax == FALSE )
+	{
+	  halt_flag = TRUE;
+	  fprintf( stderr,"Invalid parameter specification  '%s'\n", param_names[i] );
+	}
+	
+      if( split_str ) 	  
+        Free( split_str );
+    }
+      
+    if( halt_flag == TRUE )
+    {
+      exit(0);
+    }
+}
+#endif
+
+
+void *Magvector(void *argument)
+{
+  cdoInitialize(argument);
+
+#if defined(HAVE_LIBMAGICS)
   int nrecs;
   int levelID;
-  int tsID;
-  int streamID;
-  int vlistID;
   int nmiss;
-  int nlon, nlat;
-  int nlev;
-  int zaxisID, taxisID;
-  int vdate, vtime;
-  int found;
-  int nparam = 0;
-  int i;
-  char **pnames = NULL;
   char varname[CDI_MAX_NAME];
-  double missval;
-  double *uarray = NULL;
-  double *varray = NULL;
-  double *grid_center_lat = NULL, *grid_center_lon = NULL;
   char units[CDI_MAX_NAME];
   char vdatestr[32],vtimestr[32],datetimestr[64];
 
-
-  cdoInitialize(argument);
-
-  nparam = operatorArgc();
-  pnames = operatorArgv();
+  int nparam = operatorArgc();
+  char **pnames = operatorArgv();
   
-  VECTOR  = cdoOperatorAdd("vector", 0, 0, NULL);
-  STREAM  = cdoOperatorAdd("stream", 0, 0, NULL);
+  int VECTOR  = cdoOperatorAdd("vector", 0, 0, NULL);
+  int STREAM  = cdoOperatorAdd("stream", 0, 0, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
   
-  if( nparam )
+  if ( nparam )
     {
       if( DBG )
 	{
-	  for( i = 0; i < nparam; i++ )
+	  for( int i = 0; i < nparam; i++ )
 	    fprintf( stderr,"Param %d is %s!\n",i+1, pnames[i] );
 	}
       
       VerifyVectorParameters( nparam, pnames, operatorID );
     }
 
-  streamID = streamOpenRead(cdoStreamName(0));
+  int streamID = streamOpenRead(cdoStreamName(0));
 
-  vlistID = streamInqVlist(streamID);
-  taxisID = vlistInqTaxis(vlistID);
+  int vlistID = streamInqVlist(streamID);
+  int taxisID = vlistInqTaxis(vlistID);
 
-  found = 0;
-  varID = 0;
-  gridID  = vlistInqVarGrid(vlistID, varID);
-  zaxisID = vlistInqVarZaxis(vlistID, varID);
-  missval = vlistInqVarMissval(vlistID, varID);
+  int found = 0;
+  int varID = 0;
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  // int zaxisID = vlistInqVarZaxis(vlistID, varID);
+  // double missval = vlistInqVarMissval(vlistID, varID);
 
   if ( gridInqType(gridID) == GRID_GME          ) cdoAbort("GME grid unspported!");
   if ( gridInqType(gridID) == GRID_UNSTRUCTURED ) cdoAbort("Unstructured grid unspported!");
@@ -286,15 +357,15 @@ void *Magvector(void *argument)
   if ( gridInqType(gridID) != GRID_CURVILINEAR )
     gridID = gridToCurvilinear(gridID, 1);
 
-  gridsize = gridInqSize(gridID);
-  nlon     = gridInqXsize(gridID);
-  nlat     = gridInqYsize(gridID);
-  nlev     = zaxisInqSize(zaxisID);
+  int gridsize = gridInqSize(gridID);
+  int nlon     = gridInqXsize(gridID);
+  int nlat     = gridInqYsize(gridID);
+  // int nlev     = zaxisInqSize(zaxisID);
 
-  uarray          = (double*) Malloc(gridsize*sizeof(double));
-  varray          = (double*) Malloc(gridsize*sizeof(double));
-  grid_center_lat = (double*) Malloc(gridsize*sizeof(double));
-  grid_center_lon = (double*) Malloc(gridsize*sizeof(double));
+  double *uarray          = (double*) Malloc(gridsize*sizeof(double));
+  double *varray          = (double*) Malloc(gridsize*sizeof(double));
+  double *grid_center_lat = (double*) Malloc(gridsize*sizeof(double));
+  double *grid_center_lon = (double*) Malloc(gridsize*sizeof(double));
 
   gridInqYvals(gridID, grid_center_lat);
   gridInqXvals(gridID, grid_center_lon);
@@ -305,7 +376,7 @@ void *Magvector(void *argument)
   gridInqYunits(gridID, units);
   grid_to_degree(units, gridsize, grid_center_lat, "grid center lat");
 					
-  tsID = 0;
+  int tsID = 0;
 
   /* HARDCODED THE FILE NAME .. TO BE SENT AS COMMAND LINE ARGUMENT FOR THE MAGICS OPERATOR */
   /*
@@ -335,14 +406,14 @@ void *Magvector(void *argument)
             }
         }
 
-      vdate = taxisInqVdate(taxisID);
-      vtime = taxisInqVtime(taxisID);
+      int vdate = taxisInqVdate(taxisID);
+      int vtime = taxisInqVtime(taxisID);
 	      
       date2str(vdate, vdatestr, sizeof(vdatestr));
       time2str(vtime, vtimestr, sizeof(vtimestr));
       sprintf(datetimestr, "%s %s", vdatestr,vtimestr);
 
-      for( recID = 0; recID < nrecs; recID++ )
+      for( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID, &varID, &levelID);
 
@@ -419,109 +490,13 @@ void *Magvector(void *argument)
 
   quit_MAGICS( );
 
-  cdoFinish();
-
-  return 0;
-
-}
-
-
-
-void VerifyVectorParameters( int num_param, char **param_names, int opID )
-
-{
+#else
   
-  int i, j;
-  int found = FALSE, syntax = TRUE, halt_flag = FALSE, split_str_count;
-  int param_count;
-  char **params;
-  char **split_str = NULL;
-  char *sep_char = "=";
+  cdoAbort("MAGICS support not compiled in!");
 
-  /* char  *vector_params[] = {"min","max","count","interval","list","colour","thickness","style","RGB"}; */
+#endif
 
-  for ( i = 0; i < num_param; ++i )
-    {
-      split_str_count = 0;
-      found = FALSE;
-      syntax = TRUE;
-      split_str_count = StringSplitWithSeperator( param_names[i], sep_char, &split_str );
-      
-      if( DBG )
-	fprintf( stderr, "Verifying params!\n");
-      
-      if( split_str_count > 1 ) 
-	{
-	  
-	  if( opID == VECTOR )
-	    {
-	      param_count = vector_param_count;
-	      params = vector_params;
-	    }
-	  
-	  for ( j = 0; j < param_count; ++j )
-	    {
-	      if( !strcmp( split_str[0], params[j] ) )
-		{
-		  found = TRUE;
-		      
-		  if( !strcmp( split_str[0],"thin_fac" ) || !strcmp( split_str[0],"unit_vec" ) ||
-		      !strcmp( split_str[0],"step_freq" )
-                    )
-		    {
-		      if( !IsNumeric( split_str[1] ) )
-			syntax = FALSE;       
-		    }
-		    
-   		  if( !strcmp( split_str[0],"device" ) )
-		    {
-		      if( IsNumeric( split_str[1] ) )
-			syntax = FALSE;       
-		      else 
-			{
-			  if( !strcmp( split_str[0],"device" ) )
-			    {
-			      if( DBG )
-				fprintf( stderr,"Parameter value '%s'\n",split_str[1] );
-			      if( checkdevice( split_str[1] ) )
-				syntax = FALSE;
+  cdoFinish();
 
-                              /* Vector not supported in google earth format */
-			      if( !strcmp( split_str[1],"KML" ) || !strcmp( split_str[1],"kml" ) )
-                                {
-				   syntax = FALSE;
-			           if( DBG )
-				     fprintf( stderr,"Parameter value '%s'\n",split_str[1] );
-                                }
-			    }
-			}
-		    }
-		}
-	    }
-	}
-      else
-	{
-	  syntax = FALSE;
-	}
-	
-      if( found == FALSE )
-	{
-	  halt_flag = TRUE;
-	  fprintf( stderr,"Invalid parameter  '%s'\n", param_names[i] );
-	} 
-      if( found == TRUE && syntax == FALSE )
-	{
-	  halt_flag = TRUE;
-	  fprintf( stderr,"Invalid parameter specification  '%s'\n", param_names[i] );
-	}
-	
-      if( split_str ) 	  
-        Free( split_str );
-    }
-      
-    if( halt_flag == TRUE )
-    {
-      exit(0);
-    }
-    
+  return 0;
 }
diff --git a/src/Makefile.am b/src/Makefile.am
index 14dfe12..9cdeff3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -10,6 +10,7 @@ libcdo_la_SOURCES =            \
                cdo_task.c      \
                cdo_task.h      \
                cdo_history.c   \
+               cdi_uuid.h      \
                after_sptrans.c \
                after_fctrans.c \
                after_dvtrans.c \
@@ -19,6 +20,7 @@ libcdo_la_SOURCES =            \
                afterburnerlib.c\
                afterburner.h   \
                vct_l191.h      \
+               calendar.h      \
                constants.h     \
                constants.c     \
                color.c         \
@@ -40,6 +42,8 @@ libcdo_la_SOURCES =            \
                exception.c     \
                expr.c          \
                expr.h          \
+               expr_fun.c      \
+               expr_fun.h      \
                expr_lex.c      \
                expr_yacc.c     \
                expr_yacc.h     \
@@ -257,6 +261,7 @@ cdo_SOURCES += Adisit.c        \
                Output.c        \
                Outputgmt.c     \
                Pack.c          \
+               Pardup.c        \
                Pinfo.c         \
                Pressure.c      \
                Regres.c        \
@@ -306,6 +311,7 @@ cdo_SOURCES += Adisit.c        \
                Templates.c     \
                Test.c          \
                Tests.c         \
+               Timedt.c        \
                Timcount.c      \
                Timpctl.c       \
                Timselpctl.c    \
@@ -320,7 +326,6 @@ cdo_SOURCES += Adisit.c        \
                Trend.c         \
                Trms.c          \
                Tstepcount.c    \
-               Vardup.c        \
                Vargen.c        \
                Varrms.c        \
                Vertintml.c     \
@@ -328,6 +333,7 @@ cdo_SOURCES += Adisit.c        \
                Vertstat.c      \
                Vertcum.c       \
                Vertwind.c      \
+               Verifygrid.c    \
                Wct.c           \
                Wind.c          \
                Writegrid.c     \
@@ -359,7 +365,7 @@ cdo_SOURCES += nearpt3c.h
 #               cellsearchorder.h
 #endif
 
-if ENABLE_MAGICS
+#if ENABLE_MAGICS
 cdo_SOURCES += Magplot.c       \
                Magvector.c     \
                Maggraph.c      \
@@ -373,7 +379,7 @@ cdo_SOURCES += Magplot.c       \
                StringUtilities.c   \
                CdoMagicsMapper.h   \
                CdoMagicsMapper.c
-endif
+#endif
 
 cdo_CPPFLAGS = -I$(top_srcdir)/libcdi/src
 cdo_LDADD    = libcdo.la $(top_builddir)/libcdi/src/libcdi.la
diff --git a/src/Makefile.in b/src/Makefile.in
index 53768be..a75a43f 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -80,30 +80,9 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 bin_PROGRAMS = cdo$(EXEEXT)
-#if ENABLE_NEARPT3
-#cdo_SOURCES +=           \
-#               nearpt3x.h      \
-#               nearpt3c.h      \
-#               nearpt3c.cc     \
-#               cellsearchorder.h
-#endif
- at ENABLE_MAGICS_TRUE@am__append_1 = Magplot.c       \
- at ENABLE_MAGICS_TRUE@               Magvector.c     \
- at ENABLE_MAGICS_TRUE@               Maggraph.c      \
- at ENABLE_MAGICS_TRUE@               template_parser.h   \
- at ENABLE_MAGICS_TRUE@               template_parser.c   \
- at ENABLE_MAGICS_TRUE@               results_template_parser.h   \
- at ENABLE_MAGICS_TRUE@               results_template_parser.c   \
- at ENABLE_MAGICS_TRUE@               magics_template_parser.h   \
- at ENABLE_MAGICS_TRUE@               magics_template_parser.c   \
- at ENABLE_MAGICS_TRUE@               StringUtilities.h   \
- at ENABLE_MAGICS_TRUE@               StringUtilities.c   \
- at ENABLE_MAGICS_TRUE@               CdoMagicsMapper.h   \
- at ENABLE_MAGICS_TRUE@               CdoMagicsMapper.c
-
- at ENABLE_ALL_STATIC_TRUE@am__append_2 = -all-static
+ at ENABLE_ALL_STATIC_TRUE@am__append_1 = -all-static
 noinst_PROGRAMS = cdotest$(EXEEXT)
- at ENABLE_ALL_STATIC_TRUE@am__append_3 = -all-static
+ at ENABLE_ALL_STATIC_TRUE@am__append_2 = -all-static
 subdir = src
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(srcdir)/config.h.in $(top_srcdir)/config/mkinstalldirs \
@@ -132,12 +111,12 @@ am_libcdo_la_OBJECTS = libcdo_la-cdo_pthread.lo libcdo_la-cdo_vlist.lo \
 	libcdo_la-color.lo libcdo_la-commandline.lo \
 	libcdo_la-datetime.lo libcdo_la-ecacore.lo \
 	libcdo_la-ecautil.lo libcdo_la-exception.lo libcdo_la-expr.lo \
-	libcdo_la-expr_lex.lo libcdo_la-expr_yacc.lo \
-	libcdo_la-features.lo libcdo_la-field.lo libcdo_la-field2.lo \
-	libcdo_la-fieldc.lo libcdo_la-fieldmem.lo \
-	libcdo_la-fieldmer.lo libcdo_la-fieldzon.lo \
-	libcdo_la-gradsdeslib.lo libcdo_la-grid.lo \
-	libcdo_la-grid_area.lo libcdo_la-grid_gme.lo \
+	libcdo_la-expr_fun.lo libcdo_la-expr_lex.lo \
+	libcdo_la-expr_yacc.lo libcdo_la-features.lo \
+	libcdo_la-field.lo libcdo_la-field2.lo libcdo_la-fieldc.lo \
+	libcdo_la-fieldmem.lo libcdo_la-fieldmer.lo \
+	libcdo_la-fieldzon.lo libcdo_la-gradsdeslib.lo \
+	libcdo_la-grid.lo libcdo_la-grid_area.lo libcdo_la-grid_gme.lo \
 	libcdo_la-grid_lcc.lo libcdo_la-grid_rot.lo \
 	libcdo_la-gridreference.lo libcdo_la-griddes.lo \
 	libcdo_la-griddes_h5.lo libcdo_la-griddes_nc.lo \
@@ -178,52 +157,6 @@ am__v_lt_0 = --silent
 am__v_lt_1 = 
 am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
-am__cdo_SOURCES_DIST = cdo.c Adisit.c Afterburner.c Arith.c Arithc.c \
-	Arithdays.c Arithlat.c CDItest.c CDIread.c CDIwrite.c Cat.c \
-	Change.c Change_e5slm.c Cloudlayer.c CMOR.c Collgrid.c \
-	Command.c Comp.c Compc.c Complextorect.c Cond.c Cond2.c \
-	Condc.c Consecstat.c Copy.c Deltime.c Derivepar.c Detrend.c \
-	Diff.c Distgrid.c Duplicate.c EOFs.c Eof3d.c EcaIndices.c \
-	Echam5ini.c Enlarge.c Enlargegrid.c Ensstat.c Ensstat3.c \
-	Ensval.c Eofcoeff.c Eofcoeff3d.c Exprf.c FC.c Filedes.c \
-	Fillmiss.c Filter.c Fldrms.c Fldstat.c Fldstat2.c Fourier.c \
-	Gengrid.c Gradsdes.c Gridboxstat.c Gridcell.c Gridsearch.c \
-	Harmonic.c Hi.c Histogram.c Importamsr.c Importbinary.c \
-	Importcmsaf.c Importobs.c Info.c Input.c Intgrid.c \
-	Intgridtraj.c Intlevel.c Intlevel3d.c Intntime.c Inttime.c \
-	Intyear.c Invert.c Invertlev.c Isosurface.c Kvl.c Log.c \
-	Maskbox.c Mastrfu.c Math.c Merge.c Mergegrid.c Mergetime.c \
-	Merstat.c Monarith.c Mrotuv.c Mrotuvb.c Ninfo.c Nmltest.c \
-	Output.c Outputgmt.c Pack.c Pinfo.c Pressure.c Regres.c \
-	Remap.c Remapeta.c Replace.c Replacevalues.c Rhopot.c Rotuv.c \
-	Runpctl.c Runstat.c Seascount.c Seaspctl.c Seasstat.c Selbox.c \
-	Select.c Seloperator.c Selrec.c Seltime.c Selvar.c Set.c \
-	Setbox.c Setgatt.c Setgrid.c Sethalo.c Setmiss.c Setpartab.c \
-	Setrcaname.c Settime.c Setzaxis.c Showinfo.c Sinfo.c Smooth9.c \
-	Sort.c Sorttimestamp.c Specinfo.c Spectral.c Spectrum.c \
-	Split.c Splitrec.c Splitsel.c Splittime.c Splityear.c SSOpar.c \
-	Subtrend.c Tee.c Templates.c Test.c Tests.c Timcount.c \
-	Timpctl.c Timselpctl.c Timselstat.c Timsort.c Timstat.c \
-	Timstat2.c Timstat3.c Tinfo.c Tocomplex.c Transpose.c Trend.c \
-	Trms.c Tstepcount.c Vardup.c Vargen.c Varrms.c Vertintml.c \
-	Vertintap.c Vertstat.c Vertcum.c Vertwind.c Wct.c Wind.c \
-	Writegrid.c Writerandom.c XTimstat.c YAR.c Yearmonstat.c \
-	Ydayarith.c Ydaypctl.c Ydaystat.c Ydrunpctl.c Ydrunstat.c \
-	Yhourarith.c Yhourstat.c Ymonarith.c Ymonpctl.c Ymonstat.c \
-	Yseaspctl.c Yseasstat.c Zonstat.c cdo.h nearpt3c.h Magplot.c \
-	Magvector.c Maggraph.c template_parser.h template_parser.c \
-	results_template_parser.h results_template_parser.c \
-	magics_template_parser.h magics_template_parser.c \
-	StringUtilities.h StringUtilities.c CdoMagicsMapper.h \
-	CdoMagicsMapper.c
- at ENABLE_MAGICS_TRUE@am__objects_1 = cdo-Magplot.$(OBJEXT) \
- at ENABLE_MAGICS_TRUE@	cdo-Magvector.$(OBJEXT) \
- at ENABLE_MAGICS_TRUE@	cdo-Maggraph.$(OBJEXT) \
- at ENABLE_MAGICS_TRUE@	cdo-template_parser.$(OBJEXT) \
- at ENABLE_MAGICS_TRUE@	cdo-results_template_parser.$(OBJEXT) \
- at ENABLE_MAGICS_TRUE@	cdo-magics_template_parser.$(OBJEXT) \
- at ENABLE_MAGICS_TRUE@	cdo-StringUtilities.$(OBJEXT) \
- at ENABLE_MAGICS_TRUE@	cdo-CdoMagicsMapper.$(OBJEXT)
 am_cdo_OBJECTS = cdo-cdo.$(OBJEXT) cdo-Adisit.$(OBJEXT) \
 	cdo-Afterburner.$(OBJEXT) cdo-Arith.$(OBJEXT) \
 	cdo-Arithc.$(OBJEXT) cdo-Arithdays.$(OBJEXT) \
@@ -266,7 +199,8 @@ am_cdo_OBJECTS = cdo-cdo.$(OBJEXT) cdo-Adisit.$(OBJEXT) \
 	cdo-Merstat.$(OBJEXT) cdo-Monarith.$(OBJEXT) \
 	cdo-Mrotuv.$(OBJEXT) cdo-Mrotuvb.$(OBJEXT) cdo-Ninfo.$(OBJEXT) \
 	cdo-Nmltest.$(OBJEXT) cdo-Output.$(OBJEXT) \
-	cdo-Outputgmt.$(OBJEXT) cdo-Pack.$(OBJEXT) cdo-Pinfo.$(OBJEXT) \
+	cdo-Outputgmt.$(OBJEXT) cdo-Pack.$(OBJEXT) \
+	cdo-Pardup.$(OBJEXT) cdo-Pinfo.$(OBJEXT) \
 	cdo-Pressure.$(OBJEXT) cdo-Regres.$(OBJEXT) \
 	cdo-Remap.$(OBJEXT) cdo-Remapeta.$(OBJEXT) \
 	cdo-Replace.$(OBJEXT) cdo-Replacevalues.$(OBJEXT) \
@@ -289,17 +223,18 @@ am_cdo_OBJECTS = cdo-cdo.$(OBJEXT) cdo-Adisit.$(OBJEXT) \
 	cdo-Splityear.$(OBJEXT) cdo-SSOpar.$(OBJEXT) \
 	cdo-Subtrend.$(OBJEXT) cdo-Tee.$(OBJEXT) \
 	cdo-Templates.$(OBJEXT) cdo-Test.$(OBJEXT) cdo-Tests.$(OBJEXT) \
-	cdo-Timcount.$(OBJEXT) cdo-Timpctl.$(OBJEXT) \
-	cdo-Timselpctl.$(OBJEXT) cdo-Timselstat.$(OBJEXT) \
-	cdo-Timsort.$(OBJEXT) cdo-Timstat.$(OBJEXT) \
-	cdo-Timstat2.$(OBJEXT) cdo-Timstat3.$(OBJEXT) \
-	cdo-Tinfo.$(OBJEXT) cdo-Tocomplex.$(OBJEXT) \
-	cdo-Transpose.$(OBJEXT) cdo-Trend.$(OBJEXT) cdo-Trms.$(OBJEXT) \
-	cdo-Tstepcount.$(OBJEXT) cdo-Vardup.$(OBJEXT) \
-	cdo-Vargen.$(OBJEXT) cdo-Varrms.$(OBJEXT) \
-	cdo-Vertintml.$(OBJEXT) cdo-Vertintap.$(OBJEXT) \
-	cdo-Vertstat.$(OBJEXT) cdo-Vertcum.$(OBJEXT) \
-	cdo-Vertwind.$(OBJEXT) cdo-Wct.$(OBJEXT) cdo-Wind.$(OBJEXT) \
+	cdo-Timedt.$(OBJEXT) cdo-Timcount.$(OBJEXT) \
+	cdo-Timpctl.$(OBJEXT) cdo-Timselpctl.$(OBJEXT) \
+	cdo-Timselstat.$(OBJEXT) cdo-Timsort.$(OBJEXT) \
+	cdo-Timstat.$(OBJEXT) cdo-Timstat2.$(OBJEXT) \
+	cdo-Timstat3.$(OBJEXT) cdo-Tinfo.$(OBJEXT) \
+	cdo-Tocomplex.$(OBJEXT) cdo-Transpose.$(OBJEXT) \
+	cdo-Trend.$(OBJEXT) cdo-Trms.$(OBJEXT) \
+	cdo-Tstepcount.$(OBJEXT) cdo-Vargen.$(OBJEXT) \
+	cdo-Varrms.$(OBJEXT) cdo-Vertintml.$(OBJEXT) \
+	cdo-Vertintap.$(OBJEXT) cdo-Vertstat.$(OBJEXT) \
+	cdo-Vertcum.$(OBJEXT) cdo-Vertwind.$(OBJEXT) \
+	cdo-Verifygrid.$(OBJEXT) cdo-Wct.$(OBJEXT) cdo-Wind.$(OBJEXT) \
 	cdo-Writegrid.$(OBJEXT) cdo-Writerandom.$(OBJEXT) \
 	cdo-XTimstat.$(OBJEXT) cdo-YAR.$(OBJEXT) \
 	cdo-Yearmonstat.$(OBJEXT) cdo-Ydayarith.$(OBJEXT) \
@@ -308,7 +243,12 @@ am_cdo_OBJECTS = cdo-cdo.$(OBJEXT) cdo-Adisit.$(OBJEXT) \
 	cdo-Yhourarith.$(OBJEXT) cdo-Yhourstat.$(OBJEXT) \
 	cdo-Ymonarith.$(OBJEXT) cdo-Ymonpctl.$(OBJEXT) \
 	cdo-Ymonstat.$(OBJEXT) cdo-Yseaspctl.$(OBJEXT) \
-	cdo-Yseasstat.$(OBJEXT) cdo-Zonstat.$(OBJEXT) $(am__objects_1)
+	cdo-Yseasstat.$(OBJEXT) cdo-Zonstat.$(OBJEXT) \
+	cdo-Magplot.$(OBJEXT) cdo-Magvector.$(OBJEXT) \
+	cdo-Maggraph.$(OBJEXT) cdo-template_parser.$(OBJEXT) \
+	cdo-results_template_parser.$(OBJEXT) \
+	cdo-magics_template_parser.$(OBJEXT) \
+	cdo-StringUtilities.$(OBJEXT) cdo-CdoMagicsMapper.$(OBJEXT)
 cdo_OBJECTS = $(am_cdo_OBJECTS)
 cdo_DEPENDENCIES = libcdo.la $(top_builddir)/libcdi/src/libcdi.la
 cdo_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -355,8 +295,7 @@ am__v_CCLD_ = $(am__v_CCLD_ at AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
 SOURCES = $(libcdo_la_SOURCES) $(cdo_SOURCES) $(cdotest_SOURCES)
-DIST_SOURCES = $(libcdo_la_SOURCES) $(am__cdo_SOURCES_DIST) \
-	$(cdotest_SOURCES)
+DIST_SOURCES = $(libcdo_la_SOURCES) $(cdo_SOURCES) $(cdotest_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -419,6 +358,7 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 ENABLE_CDI_LIB = @ENABLE_CDI_LIB@
 ENABLE_CGRIBEX = @ENABLE_CGRIBEX@
+ENABLE_CXX = @ENABLE_CXX@
 ENABLE_DATA = @ENABLE_DATA@
 ENABLE_EXTRA = @ENABLE_EXTRA@
 ENABLE_GRIB = @ENABLE_GRIB@
@@ -429,6 +369,7 @@ ENABLE_NC4 = @ENABLE_NC4@
 ENABLE_NC4HDF5 = @ENABLE_NC4HDF5@
 ENABLE_NETCDF = @ENABLE_NETCDF@
 ENABLE_SERVICE = @ENABLE_SERVICE@
+ENABLE_THREADS = @ENABLE_THREADS@
 EXEEXT = @EXEEXT@
 FCFLAGS = @FCFLAGS@
 FGREP = @FGREP@
@@ -558,43 +499,52 @@ top_srcdir = @top_srcdir@
 noinst_LTLIBRARIES = libcdo.la
 libcdo_la_SOURCES = cdo_int.h compare.h cdo_pthread.c cdo_vlist.c \
 	cdo_getopt.c cdo_getopt.h cdo_task.c cdo_task.h cdo_history.c \
-	after_sptrans.c after_fctrans.c after_dvtrans.c \
+	cdi_uuid.h after_sptrans.c after_fctrans.c after_dvtrans.c \
 	after_vertint.c after_vertint.h after_namelist.c \
-	afterburnerlib.c afterburner.h vct_l191.h constants.h \
-	constants.c color.c color.h commandline.c const.h counter.h \
-	datetime.c datetime.h dmemory.h ecacore.c ecacore.h ecautil.c \
-	ecautil.h error.h etopo.h temp.h mask.h exception.c expr.c \
-	expr.h expr_lex.c expr_yacc.c expr_yacc.h features.c field.c \
-	field.h field2.c fieldc.c fieldmem.c fieldmer.c fieldzon.c \
-	functs.h gradsdeslib.c gradsdeslib.h grid.c grid.h grid_area.c \
-	grid_gme.c grid_lcc.c grid_rot.c gridreference.c griddes.c \
-	griddes.h griddes_h5.c griddes_nc.c hetaeta.c hetaeta.h \
-	institution.c interpol.c interpol.h job.c juldate.c \
-	grid_search.c grid_search.h kvlist.c kvlist.h list.c list.h \
-	merge_sort2.c merge_sort2.h modules.c modules.h namelist.c \
-	namelist.h normal.c nth_element.c nth_element.h \
-	operator_help.h par_io.c par_io.h percentiles_hist.c \
-	percentiles_hist.h percentiles.c percentiles.h pipe.c pipe.h \
-	pragma_omp_atomic_update.h printinfo.h process.c process.h \
-	pstream.c pstream.h pstream_write.h pstream_int.h \
-	pthread_debug.c pthread_debug.h readline.c realtime.c remap.h \
-	remaplib.c remapsort.c remap_scrip_io.c remap_search_reg2d.c \
-	remap_search_latbins.c remap_store_link.c remap_store_link.h \
-	remap_store_link_cnsrv.c remap_store_link_cnsrv.h \
-	remap_conserv.c remap_conserv_scrip.c remap_distwgt.c \
-	remap_bicubic_scrip.c remap_bilinear_scrip.c stdnametable.c \
-	stdnametable.h specspace.c specspace.h statistic.c statistic.h \
-	table.c text.c text.h timebase.h timer.c userlog.c util.c \
-	util.h zaxis.c kdtreelib/kdtree.h kdtreelib/kdtree_cartesian.c \
-	kdtreelib/kdtree_common.c kdtreelib/kdtree_spherical.c \
-	kdtreelib/pmergesort.c kdtreelib/pqueue.c kdtreelib/pqueue.h \
-	clipping/clipping.c clipping/clipping.h clipping/area.c \
-	clipping/area.h clipping/ensure_array_size.c \
-	clipping/ensure_array_size.h clipping/geometry.h \
-	clipping/grid.h clipping/points.h clipping/dep_list.h \
-	clipping/grid_cell.c clipping/grid_cell.h \
+	afterburnerlib.c afterburner.h vct_l191.h calendar.h \
+	constants.h constants.c color.c color.h commandline.c const.h \
+	counter.h datetime.c datetime.h dmemory.h ecacore.c ecacore.h \
+	ecautil.c ecautil.h error.h etopo.h temp.h mask.h exception.c \
+	expr.c expr.h expr_fun.c expr_fun.h expr_lex.c expr_yacc.c \
+	expr_yacc.h features.c field.c field.h field2.c fieldc.c \
+	fieldmem.c fieldmer.c fieldzon.c functs.h gradsdeslib.c \
+	gradsdeslib.h grid.c grid.h grid_area.c grid_gme.c grid_lcc.c \
+	grid_rot.c gridreference.c griddes.c griddes.h griddes_h5.c \
+	griddes_nc.c hetaeta.c hetaeta.h institution.c interpol.c \
+	interpol.h job.c juldate.c grid_search.c grid_search.h \
+	kvlist.c kvlist.h list.c list.h merge_sort2.c merge_sort2.h \
+	modules.c modules.h namelist.c namelist.h normal.c \
+	nth_element.c nth_element.h operator_help.h par_io.c par_io.h \
+	percentiles_hist.c percentiles_hist.h percentiles.c \
+	percentiles.h pipe.c pipe.h pragma_omp_atomic_update.h \
+	printinfo.h process.c process.h pstream.c pstream.h \
+	pstream_write.h pstream_int.h pthread_debug.c pthread_debug.h \
+	readline.c realtime.c remap.h remaplib.c remapsort.c \
+	remap_scrip_io.c remap_search_reg2d.c remap_search_latbins.c \
+	remap_store_link.c remap_store_link.h remap_store_link_cnsrv.c \
+	remap_store_link_cnsrv.h remap_conserv.c remap_conserv_scrip.c \
+	remap_distwgt.c remap_bicubic_scrip.c remap_bilinear_scrip.c \
+	stdnametable.c stdnametable.h specspace.c specspace.h \
+	statistic.c statistic.h table.c text.c text.h timebase.h \
+	timer.c userlog.c util.c util.h zaxis.c kdtreelib/kdtree.h \
+	kdtreelib/kdtree_cartesian.c kdtreelib/kdtree_common.c \
+	kdtreelib/kdtree_spherical.c kdtreelib/pmergesort.c \
+	kdtreelib/pqueue.c kdtreelib/pqueue.h clipping/clipping.c \
+	clipping/clipping.h clipping/area.c clipping/area.h \
+	clipping/ensure_array_size.c clipping/ensure_array_size.h \
+	clipping/geometry.h clipping/grid.h clipping/points.h \
+	clipping/dep_list.h clipping/grid_cell.c clipping/grid_cell.h \
 	clipping/intersection.c clipping/utils.c clipping/utils.h
 #
+#if ENABLE_NEARPT3
+#cdo_SOURCES +=           \
+#               nearpt3x.h      \
+#               nearpt3c.h      \
+#               nearpt3c.cc     \
+#               cellsearchorder.h
+#endif
+
+#if ENABLE_MAGICS
 cdo_SOURCES = cdo.c Adisit.c Afterburner.c Arith.c Arithc.c \
 	Arithdays.c Arithlat.c CDItest.c CDIread.c CDIwrite.c Cat.c \
 	Change.c Change_e5slm.c Cloudlayer.c CMOR.c Collgrid.c \
@@ -611,34 +561,39 @@ cdo_SOURCES = cdo.c Adisit.c Afterburner.c Arith.c Arithc.c \
 	Intyear.c Invert.c Invertlev.c Isosurface.c Kvl.c Log.c \
 	Maskbox.c Mastrfu.c Math.c Merge.c Mergegrid.c Mergetime.c \
 	Merstat.c Monarith.c Mrotuv.c Mrotuvb.c Ninfo.c Nmltest.c \
-	Output.c Outputgmt.c Pack.c Pinfo.c Pressure.c Regres.c \
-	Remap.c Remapeta.c Replace.c Replacevalues.c Rhopot.c Rotuv.c \
-	Runpctl.c Runstat.c Seascount.c Seaspctl.c Seasstat.c Selbox.c \
-	Select.c Seloperator.c Selrec.c Seltime.c Selvar.c Set.c \
-	Setbox.c Setgatt.c Setgrid.c Sethalo.c Setmiss.c Setpartab.c \
-	Setrcaname.c Settime.c Setzaxis.c Showinfo.c Sinfo.c Smooth9.c \
-	Sort.c Sorttimestamp.c Specinfo.c Spectral.c Spectrum.c \
-	Split.c Splitrec.c Splitsel.c Splittime.c Splityear.c SSOpar.c \
-	Subtrend.c Tee.c Templates.c Test.c Tests.c Timcount.c \
-	Timpctl.c Timselpctl.c Timselstat.c Timsort.c Timstat.c \
-	Timstat2.c Timstat3.c Tinfo.c Tocomplex.c Transpose.c Trend.c \
-	Trms.c Tstepcount.c Vardup.c Vargen.c Varrms.c Vertintml.c \
-	Vertintap.c Vertstat.c Vertcum.c Vertwind.c Wct.c Wind.c \
-	Writegrid.c Writerandom.c XTimstat.c YAR.c Yearmonstat.c \
-	Ydayarith.c Ydaypctl.c Ydaystat.c Ydrunpctl.c Ydrunstat.c \
-	Yhourarith.c Yhourstat.c Ymonarith.c Ymonpctl.c Ymonstat.c \
-	Yseaspctl.c Yseasstat.c Zonstat.c cdo.h nearpt3c.h \
-	$(am__append_1)
+	Output.c Outputgmt.c Pack.c Pardup.c Pinfo.c Pressure.c \
+	Regres.c Remap.c Remapeta.c Replace.c Replacevalues.c Rhopot.c \
+	Rotuv.c Runpctl.c Runstat.c Seascount.c Seaspctl.c Seasstat.c \
+	Selbox.c Select.c Seloperator.c Selrec.c Seltime.c Selvar.c \
+	Set.c Setbox.c Setgatt.c Setgrid.c Sethalo.c Setmiss.c \
+	Setpartab.c Setrcaname.c Settime.c Setzaxis.c Showinfo.c \
+	Sinfo.c Smooth9.c Sort.c Sorttimestamp.c Specinfo.c Spectral.c \
+	Spectrum.c Split.c Splitrec.c Splitsel.c Splittime.c \
+	Splityear.c SSOpar.c Subtrend.c Tee.c Templates.c Test.c \
+	Tests.c Timedt.c Timcount.c Timpctl.c Timselpctl.c \
+	Timselstat.c Timsort.c Timstat.c Timstat2.c Timstat3.c Tinfo.c \
+	Tocomplex.c Transpose.c Trend.c Trms.c Tstepcount.c Vargen.c \
+	Varrms.c Vertintml.c Vertintap.c Vertstat.c Vertcum.c \
+	Vertwind.c Verifygrid.c Wct.c Wind.c Writegrid.c Writerandom.c \
+	XTimstat.c YAR.c Yearmonstat.c Ydayarith.c Ydaypctl.c \
+	Ydaystat.c Ydrunpctl.c Ydrunstat.c Yhourarith.c Yhourstat.c \
+	Ymonarith.c Ymonpctl.c Ymonstat.c Yseaspctl.c Yseasstat.c \
+	Zonstat.c cdo.h nearpt3c.h Magplot.c Magvector.c Maggraph.c \
+	template_parser.h template_parser.c results_template_parser.h \
+	results_template_parser.c magics_template_parser.h \
+	magics_template_parser.c StringUtilities.h StringUtilities.c \
+	CdoMagicsMapper.h CdoMagicsMapper.c
+#endif
 cdo_CPPFLAGS = -I$(top_srcdir)/libcdi/src
 cdo_LDADD = libcdo.la $(top_builddir)/libcdi/src/libcdi.la
-cdo_LDFLAGS = $(am__append_2)
+cdo_LDFLAGS = $(am__append_1)
 libcdo_la_CPPFLAGS = $(cdo_CPPFLAGS)
 cdotest_SOURCES = cdo_int.h	\
 	           cdotest.c
 
 cdotest_LDADD = $(cdo_LDADD)
 cdotest_CPPFLAGS = $(cdo_CPPFLAGS)
-cdotest_LDFLAGS = $(cdo_LDFLAGS) $(am__append_3)
+cdotest_LDFLAGS = $(cdo_LDFLAGS) $(am__append_2)
 
 #cdo-userlog.o: userlog.c config.h
 #	$(COMPILE) -DLOGPATH=${exec_prefix}/log -c -o cdo-userlog.o `test -f 'userlog.c' || echo '$(srcdir)/'`userlog.c
@@ -916,6 +871,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Output.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Outputgmt.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Pack.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Pardup.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Pinfo.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Pressure.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Regres.Po at am__quote@
@@ -967,6 +923,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Test.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Tests.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Timcount.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Timedt.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Timpctl.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Timselpctl.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Timselstat.Po at am__quote@
@@ -980,9 +937,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Trend.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Trms.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Tstepcount.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Vardup.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Vargen.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Varrms.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Verifygrid.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Vertcum.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Vertintap.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Vertintml.Po at am__quote@
@@ -1032,6 +989,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-ecautil.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-exception.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-expr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-expr_fun.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-expr_lex.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-expr_yacc.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-features.Plo at am__quote@
@@ -1263,6 +1221,13 @@ libcdo_la-expr.lo: expr.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcdo_la-expr.lo `test -f 'expr.c' || echo '$(srcdir)/'`expr.c
 
+libcdo_la-expr_fun.lo: expr_fun.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcdo_la-expr_fun.lo -MD -MP -MF $(DEPDIR)/libcdo_la-expr_fun.Tpo -c -o libcdo_la-expr_fun.lo `test -f 'expr_fun.c' || echo '$(srcdir)/'`expr_fun.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-expr_fun.Tpo $(DEPDIR)/libcdo_la-expr_fun.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='expr_fun.c' object='libcdo_la-expr_fun.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcdo_la-expr_fun.lo `test -f 'expr_fun.c' || echo '$(srcdir)/'`expr_fun.c
+
 libcdo_la-expr_lex.lo: expr_lex.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcdo_la-expr_lex.lo -MD -MP -MF $(DEPDIR)/libcdo_la-expr_lex.Tpo -c -o libcdo_la-expr_lex.lo `test -f 'expr_lex.c' || echo '$(srcdir)/'`expr_lex.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-expr_lex.Tpo $(DEPDIR)/libcdo_la-expr_lex.Plo
@@ -3062,6 +3027,20 @@ cdo-Pack.obj: Pack.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Pack.obj `if test -f 'Pack.c'; then $(CYGPATH_W) 'Pack.c'; else $(CYGPATH_W) '$(srcdir)/Pack.c'; fi`
 
+cdo-Pardup.o: Pardup.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Pardup.o -MD -MP -MF $(DEPDIR)/cdo-Pardup.Tpo -c -o cdo-Pardup.o `test -f 'Pardup.c' || echo '$(srcdir)/'`Pardup.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Pardup.Tpo $(DEPDIR)/cdo-Pardup.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Pardup.c' object='cdo-Pardup.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Pardup.o `test -f 'Pardup.c' || echo '$(srcdir)/'`Pardup.c
+
+cdo-Pardup.obj: Pardup.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Pardup.obj -MD -MP -MF $(DEPDIR)/cdo-Pardup.Tpo -c -o cdo-Pardup.obj `if test -f 'Pardup.c'; then $(CYGPATH_W) 'Pardup.c'; else $(CYGPATH_W) '$(srcdir)/Pardup.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Pardup.Tpo $(DEPDIR)/cdo-Pardup.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Pardup.c' object='cdo-Pardup.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Pardup.obj `if test -f 'Pardup.c'; then $(CYGPATH_W) 'Pardup.c'; else $(CYGPATH_W) '$(srcdir)/Pardup.c'; fi`
+
 cdo-Pinfo.o: Pinfo.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Pinfo.o -MD -MP -MF $(DEPDIR)/cdo-Pinfo.Tpo -c -o cdo-Pinfo.o `test -f 'Pinfo.c' || echo '$(srcdir)/'`Pinfo.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Pinfo.Tpo $(DEPDIR)/cdo-Pinfo.Po
@@ -3748,6 +3727,20 @@ cdo-Tests.obj: Tests.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Tests.obj `if test -f 'Tests.c'; then $(CYGPATH_W) 'Tests.c'; else $(CYGPATH_W) '$(srcdir)/Tests.c'; fi`
 
+cdo-Timedt.o: Timedt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Timedt.o -MD -MP -MF $(DEPDIR)/cdo-Timedt.Tpo -c -o cdo-Timedt.o `test -f 'Timedt.c' || echo '$(srcdir)/'`Timedt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Timedt.Tpo $(DEPDIR)/cdo-Timedt.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Timedt.c' object='cdo-Timedt.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Timedt.o `test -f 'Timedt.c' || echo '$(srcdir)/'`Timedt.c
+
+cdo-Timedt.obj: Timedt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Timedt.obj -MD -MP -MF $(DEPDIR)/cdo-Timedt.Tpo -c -o cdo-Timedt.obj `if test -f 'Timedt.c'; then $(CYGPATH_W) 'Timedt.c'; else $(CYGPATH_W) '$(srcdir)/Timedt.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Timedt.Tpo $(DEPDIR)/cdo-Timedt.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Timedt.c' object='cdo-Timedt.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Timedt.obj `if test -f 'Timedt.c'; then $(CYGPATH_W) 'Timedt.c'; else $(CYGPATH_W) '$(srcdir)/Timedt.c'; fi`
+
 cdo-Timcount.o: Timcount.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Timcount.o -MD -MP -MF $(DEPDIR)/cdo-Timcount.Tpo -c -o cdo-Timcount.o `test -f 'Timcount.c' || echo '$(srcdir)/'`Timcount.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Timcount.Tpo $(DEPDIR)/cdo-Timcount.Po
@@ -3944,20 +3937,6 @@ cdo-Tstepcount.obj: Tstepcount.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Tstepcount.obj `if test -f 'Tstepcount.c'; then $(CYGPATH_W) 'Tstepcount.c'; else $(CYGPATH_W) '$(srcdir)/Tstepcount.c'; fi`
 
-cdo-Vardup.o: Vardup.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Vardup.o -MD -MP -MF $(DEPDIR)/cdo-Vardup.Tpo -c -o cdo-Vardup.o `test -f 'Vardup.c' || echo '$(srcdir)/'`Vardup.c
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Vardup.Tpo $(DEPDIR)/cdo-Vardup.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Vardup.c' object='cdo-Vardup.o' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Vardup.o `test -f 'Vardup.c' || echo '$(srcdir)/'`Vardup.c
-
-cdo-Vardup.obj: Vardup.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Vardup.obj -MD -MP -MF $(DEPDIR)/cdo-Vardup.Tpo -c -o cdo-Vardup.obj `if test -f 'Vardup.c'; then $(CYGPATH_W) 'Vardup.c'; else $(CYGPATH_W) '$(srcdir)/Vardup.c'; fi`
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Vardup.Tpo $(DEPDIR)/cdo-Vardup.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Vardup.c' object='cdo-Vardup.obj' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Vardup.obj `if test -f 'Vardup.c'; then $(CYGPATH_W) 'Vardup.c'; else $(CYGPATH_W) '$(srcdir)/Vardup.c'; fi`
-
 cdo-Vargen.o: Vargen.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Vargen.o -MD -MP -MF $(DEPDIR)/cdo-Vargen.Tpo -c -o cdo-Vargen.o `test -f 'Vargen.c' || echo '$(srcdir)/'`Vargen.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Vargen.Tpo $(DEPDIR)/cdo-Vargen.Po
@@ -4056,6 +4035,20 @@ cdo-Vertwind.obj: Vertwind.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Vertwind.obj `if test -f 'Vertwind.c'; then $(CYGPATH_W) 'Vertwind.c'; else $(CYGPATH_W) '$(srcdir)/Vertwind.c'; fi`
 
+cdo-Verifygrid.o: Verifygrid.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Verifygrid.o -MD -MP -MF $(DEPDIR)/cdo-Verifygrid.Tpo -c -o cdo-Verifygrid.o `test -f 'Verifygrid.c' || echo '$(srcdir)/'`Verifygrid.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Verifygrid.Tpo $(DEPDIR)/cdo-Verifygrid.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Verifygrid.c' object='cdo-Verifygrid.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Verifygrid.o `test -f 'Verifygrid.c' || echo '$(srcdir)/'`Verifygrid.c
+
+cdo-Verifygrid.obj: Verifygrid.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Verifygrid.obj -MD -MP -MF $(DEPDIR)/cdo-Verifygrid.Tpo -c -o cdo-Verifygrid.obj `if test -f 'Verifygrid.c'; then $(CYGPATH_W) 'Verifygrid.c'; else $(CYGPATH_W) '$(srcdir)/Verifygrid.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Verifygrid.Tpo $(DEPDIR)/cdo-Verifygrid.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Verifygrid.c' object='cdo-Verifygrid.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Verifygrid.obj `if test -f 'Verifygrid.c'; then $(CYGPATH_W) 'Verifygrid.c'; else $(CYGPATH_W) '$(srcdir)/Verifygrid.c'; fi`
+
 cdo-Wct.o: Wct.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Wct.o -MD -MP -MF $(DEPDIR)/cdo-Wct.Tpo -c -o cdo-Wct.o `test -f 'Wct.c' || echo '$(srcdir)/'`Wct.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Wct.Tpo $(DEPDIR)/cdo-Wct.Po
diff --git a/src/Maskbox.c b/src/Maskbox.c
index ffd17eb..781c2ef 100644
--- a/src/Maskbox.c
+++ b/src/Maskbox.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Mastrfu.c b/src/Mastrfu.c
index e4dd31c..6ab75b8 100644
--- a/src/Mastrfu.c
+++ b/src/Mastrfu.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Math.c b/src/Math.c
index e7e1300..013432c 100644
--- a/src/Math.c
+++ b/src/Math.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -145,7 +145,7 @@ void *Math(void *argument)
                   break;
                 case SQRT:
                   for ( i = 0; i < gridsize; i++ )
-                    array2[i] = DBL_IS_EQUAL(array1[i], missval1) ? missval1 : SQRT(array1[i]);
+                    array2[i] = DBL_IS_EQUAL(array1[i], missval1) ? missval1 : SQRTMN(array1[i]);
                   break;
                 case EXP:
                   for ( i = 0; i < gridsize; i++ )
diff --git a/src/Merge.c b/src/Merge.c
index 6bc4254..3f30447 100644
--- a/src/Merge.c
+++ b/src/Merge.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Mergegrid.c b/src/Mergegrid.c
index fdd5229..0b5963b 100644
--- a/src/Mergegrid.c
+++ b/src/Mergegrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Mergetime.c b/src/Mergetime.c
index bfc45d5..7b97a70 100644
--- a/src/Mergetime.c
+++ b/src/Mergetime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -37,13 +37,11 @@ void *Mergetime(void *argument)
   int fileID;
   int taxisID1, taxisID2 = CDI_UNDEFID;
   int lcopy = FALSE;
-  int gridsize;
   int nmiss;
   int vdate, vtime;
   int last_vdate = -1, last_vtime = -1;
   int next_fileID;
   int skip_same_time = FALSE;
-  int process_timestep;
   double *array = NULL;
   typedef struct
   {
@@ -127,13 +125,13 @@ void *Mergetime(void *argument)
 
   if ( ! lcopy )
     {
-      gridsize = vlistGridsizeMax(sf[0].vlistID);
+      size_t gridsize = vlistGridsizeMax(sf[0].vlistID);
       array = (double*) Malloc(gridsize*sizeof(double));
     }
 
   while ( TRUE )
     {
-      process_timestep = TRUE;
+      bool process_timestep = true;
 
       next_fileID = -1;
       vdate = 0;
@@ -165,7 +163,7 @@ void *Mergetime(void *argument)
 	    time2str(vtime, vtimestr, sizeof(vtimestr));
 	    cdoPrint("Timestep %4d in stream %d (%s %s) already exists, skipped!",
 		     sf[fileID].tsID+1, sf[fileID].streamID, vdatestr, vtimestr);
-	    process_timestep = FALSE;
+	    process_timestep = false;
 	  }
 
       if ( process_timestep )
@@ -191,7 +189,12 @@ void *Mergetime(void *argument)
 	  for ( recID = 0; recID < sf[fileID].nrecs; recID++ )
 	    {
 	      streamInqRecord(sf[fileID].streamID, &varID, &levelID);
-	      streamDefRecord(streamID2,  varID,  levelID);
+
+              if ( tsID2 > 0 && sf[fileID].tsID == 0 )
+                if ( vlistInqVarTsteptype(sf[fileID].vlistID, varID) == TSTEP_CONSTANT )
+                  continue;
+
+              streamDefRecord(streamID2, varID, levelID);
 	  
 	      if ( lcopy )
 		{
diff --git a/src/Merstat.c b/src/Merstat.c
index da85562..cab72a0 100644
--- a/src/Merstat.c
+++ b/src/Merstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,9 @@
       Merstat    mermean         Meridional mean
       Merstat    meravg          Meridional average
       Merstat    merstd          Meridional standard deviation
-      Merstat    merstd          Meridional standard deviation [Divisor is (n-1)]
+      Merstat    merstd          Meridional standard deviation [Normalize by (n-1)]
       Merstat    mervar          Meridional variance
-      Merstat    mervar          Meridional variance [Divisor is (n-1)]
+      Merstat    mervar          Meridional variance [Normalize by (n-1)]
       Merstat    merpctl         Meridional percentiles
 */
 
@@ -43,6 +43,7 @@ void *Merstat(void *argument)
   int gridID1, gridID2 = -1, lastgrid = -1;
   int wstatus = FALSE;
   int index;
+  int nmiss;
   int recID, nrecs;
   int varID, levelID;
   int needWeights = FALSE;
@@ -140,8 +141,8 @@ void *Merstat(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  streamReadRecord(streamID1, field1.ptr, &field1.nmiss);
-
+	  streamReadRecord(streamID1, field1.ptr, &nmiss);
+          field1.nmiss = (size_t) nmiss;
 	  field1.grid = vlistInqVarGrid(vlistID1, varID);
 	  if ( needWeights && field1.grid != lastgrid )
 	    {
@@ -162,7 +163,7 @@ void *Merstat(void *argument)
 	    merfun(field1, &field2, operfunc);
 
 	  streamDefRecord(streamID2, varID,  levelID);
-	  streamWriteRecord(streamID2, field2.ptr, field2.nmiss);
+	  streamWriteRecord(streamID2, field2.ptr, (int)field2.nmiss);
 	}
       tsID++;
     }
diff --git a/src/Monarith.c b/src/Monarith.c
index 7014e11..1440e16 100644
--- a/src/Monarith.c
+++ b/src/Monarith.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -40,6 +40,7 @@ void *Monarith(void *argument)
   int tsID, tsID2;
   int varID, levelID;
   int offset;
+  int nmiss;
   int vlistID1, vlistID2, vlistID3;
   int taxisID1, taxisID2, taxisID3;
   int vdate;
@@ -140,8 +141,8 @@ void *Monarith(void *argument)
 	      gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
 	      offset   = gridsize*levelID;
 
-	      streamReadRecord(streamID2, vardata2[varID]+offset, &field2.nmiss);
-	      varnmiss2[varID][levelID] = field2.nmiss;
+	      streamReadRecord(streamID2, vardata2[varID]+offset, &nmiss);
+	      varnmiss2[varID][levelID] = nmiss;
 	    }
 
 	  tsID2++;
@@ -154,23 +155,22 @@ void *Monarith(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  streamReadRecord(streamID1, field1.ptr, &field1.nmiss);
+	  streamReadRecord(streamID1, field1.ptr, &nmiss);
+          field1.nmiss   = (size_t) nmiss;
+	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
+	  field1.missval = vlistInqVarMissval(vlistID1, varID);
 
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
 	  offset   = gridsize*levelID;
 	  memcpy(field2.ptr, vardata2[varID]+offset, gridsize*sizeof(double));
-	  field2.nmiss = varnmiss2[varID][levelID];
-
-	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
-	  field1.missval = vlistInqVarMissval(vlistID1, varID);
-
+	  field2.nmiss   = varnmiss2[varID][levelID];
 	  field2.grid    = vlistInqVarGrid(vlistID2, varID);
 	  field2.missval = vlistInqVarMissval(vlistID2, varID);
 
 	  farfun(&field1, field2, operfunc);
 
 	  streamDefRecord(streamID3, varID, levelID);
-	  streamWriteRecord(streamID3, field1.ptr, field1.nmiss);
+	  streamWriteRecord(streamID3, field1.ptr, (int)field1.nmiss);
 	}
 
       tsID++;
diff --git a/src/Mrotuv.c b/src/Mrotuv.c
index 3a4b951..4042276 100644
--- a/src/Mrotuv.c
+++ b/src/Mrotuv.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Mrotuvb.c b/src/Mrotuvb.c
index 26f39c1..749c7df 100644
--- a/src/Mrotuvb.c
+++ b/src/Mrotuvb.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Ninfo.c b/src/Ninfo.c
index e70a62e..607c205 100644
--- a/src/Ninfo.c
+++ b/src/Ninfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Nmltest.c b/src/Nmltest.c
index efbfbcc..5294c84 100644
--- a/src/Nmltest.c
+++ b/src/Nmltest.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Output.c b/src/Output.c
index f346dda..4ddfdd8 100644
--- a/src/Output.c
+++ b/src/Output.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Outputgmt.c b/src/Outputgmt.c
index f78be18..75c3cb9 100644
--- a/src/Outputgmt.c
+++ b/src/Outputgmt.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -18,11 +18,7 @@
 /*
    This module contains the following operators:
 
-*/
-/*
-  Output center or bounderies for GMT plotting
-
-  Plotting example:
+   Output field with grid cell center or cell bounds for plotting with GMT
 
     - outputcenter
     - outputbounds
@@ -44,108 +40,6 @@
 double intlin(double x, double y1, double x1, double y2, double x2);
 
 static
-int pnpoly(int npol, double *xp, double *yp, double x, double y)
-{
-  int i, j, c = 0;
-
-  for (i = 0, j = npol-1; i < npol; j = i++) {
-    if ((((yp[i]<=y) && (y<yp[j])) ||
-	 ((yp[j]<=y) && (y<yp[i]))) &&
-	(x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
-      
-      c = !c;
-  }
-  return c;
-}
-
-
-static
-double PolygonArea_old(int np, double *xp, double *yp)
-{
-  int i, j;
-  double area = 0;
-
-  for ( i = 0; i < np; i++ )
-    {
-      j = (i + 1) % np;
-      area += xp[i] * yp[j];
-      area -= yp[i] * xp[j];
-    }
-
-  area /= 2;
-  /* return(area < 0 ? -area : area); */
-  return (area);
-}
-
-
-static
-double PolygonArea(int np, double *xp, double *yp, double yc)
-{
-  int i, j;
-  double area = 0.;
-
-  /* Process area in Radians */
-   
-  for ( i = 0; i < np; i++ )
-    {
-      j = (i + 1) % np;
-      area += DEG2RAD*xp[i] * DEG2RAD*yp[j];
-      area -= DEG2RAD*yp[i] * DEG2RAD*xp[j];
-    }
-  area *= 0.5 * cos(DEG2RAD*yc);
-  return (area);
-}
-
-static
-int ccw(double p0x, double p0y, double p1x, double p1y, double p2x, double p2y)
-{
-  /*
-    This function says wether the point are orientated clockwise
-    +1 positive orientation
-    -1 negative orientation
-     0 points are on a line --> no orientation
-    
-    This is done by a comparision of the gradient of
-    dy1/dx1 = p1 - p0 vs.
-    dy2/dx2 = p2 - p0
-    To avoid singularities at dx1=0 OR dx2 = 0 we multiply with dx1*dx2
-  */
-  double dx1, dx2, dy1, dy2;
-
-  dx1 = p1x - p0x; dy1 = p1y - p0y;
-  dx2 = p2x - p0x; dy2 = p2y - p0y;
-  if ( dx1*dy2 > dy1*dx2 ) return +1;
-  if ( dx1*dy2 < dy1*dx2 ) return -1;
-  if ( (dx1*dx2 < 0 ) || (dy1*dy2 < 0)) return -1;
-  if ( (dx1*dx1 + dy1*dy1) < (dx2*dx2 + dy2*dy2)) return +1;
-
-  return 0;
-}
-
-static
-int intersect(double pix, double piy, double pjx, double pjy,
-              double pkx, double pky, double plx, double ply)
-{
-  /*This function returns if there is an intersection between the lines 
-    line1 between pi and pj and
-    line2 between pk and pl,
-    whereas pi = (pix, piy).
-      
-    This can done by means of ccw since the product of ccw(pi,pj,pk)*ccw(pi,pj,pl)
-    shows if pk and pl are on different or the same side(s) of the line1 (They must
-    have different signums to be on different sides).
-      
-    Consequently if and ONLY IF pk as well as pl are on different sides of line1
-    AND pi as well as pj are on different sides of line2 there HAS TO be an intersection.
-  */
-    
-  return ( ( ccw(pix, piy, pjx, pjy, pkx, pky) *
-	     ccw(pix, piy, pjx, pjy, plx, ply) <= 0 ) &&
-	   ( ccw(pkx, pky, plx, ply, pix, piy) *
-	     ccw(pkx, pky, plx, ply, pjx, pjy) <= 0 ) );
-}
-
-static
 int check_ncorner(int ncorner, const double *lon_bounds, const double *lat_bounds)
 {
   int ncorner_new = ncorner;
@@ -160,399 +54,6 @@ int check_ncorner(int ncorner, const double *lon_bounds, const double *lat_bound
   return ncorner_new;
 }
 
-static
-void verify_grid(int gridtype, int gridsize, int ncorner,
-		double *grid_center_lon, double *grid_center_lat,
-		double *grid_corner_lon, double *grid_corner_lat)
-{
-  int i0, i, j, k, l;
-  int l0;
-  int nout;
-  int isinside, convex, alone, isnegative;
-  const int mnv = ncorner+1;
-  int cuts[mnv][mnv];  
-  int *alone_cell;          
-  int check_corners;
-  double lon, lat = 0;
-  double lon_bounds[mnv], lat_bounds[mnv];
-  double area, sumarea;
-
-  alone_cell = (int*) Malloc(gridsize*ncorner*sizeof(int));
-
-  check_corners = 0; /* don't execute corner checking (last loop) */
-  nout = 0;
-  sumarea = 0;
-  /*
-  for ( i = 0; i < gridsize; ++i )
-    {
-      lon = grid_center_lon[i];
-      lat = grid_center_lat[i];
-      for ( k = 0; k < ncorner; ++k )
-        {
-          lon_bounds[k] = grid_corner_lon[i*ncorner+k];
-          lat_bounds[k] = grid_corner_lat[i*ncorner+k];
-          if ( (lon - lon_bounds[k]) > 270 ) lon_bounds[k] += 360;
-          if ( (lon_bounds[k] - lon) > 270 ) lon_bounds[k] -= 360;
-        }      
-      lon_bounds[ncorner] = lon_bounds[0];
-      lat_bounds[ncorner] = lat_bounds[0];
-      fprintf(stdout, " %6i %6i %9.4f %9.4f :",  nout, i+1, lon, lat);
-      for ( k = 0; k < ncorner; k++ )
-	fprintf(stdout, " %9.4f %9.4f : ", lon_bounds[k], lat_bounds[k]);
-      fprintf(stdout, "\n");
-    }
-  */
-
-  /* Check if center is inside bounds of cell */
-  for ( i = 0; i < gridsize; ++i )
-    {
-      lon = grid_center_lon[i];
-      lat = grid_center_lat[i];
-
-      for ( k = 0; k < ncorner; ++k )
-        {
-          lon_bounds[k] = grid_corner_lon[i*ncorner+k];
-          lat_bounds[k] = grid_corner_lat[i*ncorner+k];
-          if ( (lon - lon_bounds[k]) > 270 ) lon_bounds[k] += 360;
-          if ( (lon_bounds[k] - lon) > 270 ) lon_bounds[k] -= 360;
-        }      
-      lon_bounds[ncorner] = lon_bounds[0];
-      lat_bounds[ncorner] = lat_bounds[0];
-      
-      isinside = pnpoly(ncorner+1, lon_bounds, lat_bounds, lon, lat);
-
-      if ( !isinside ) nout++;
-      if ( !isinside && cdoVerbose )
-        {
-          if ( nout == 1 )
-            {
-              fprintf(stdout,"\n CENTER IS OUT OF BOUNDS");
-              fprintf(stdout,"\n                                               :");
-              for ( k = 0; k < ncorner; k++ )
-                fprintf(stdout, "          Corner %2i : ", k+1);
-              fprintf(stdout,"\n Number  Index center_lon center_lat area*10^6 :");
-              for ( k = 0; k < ncorner; k++ )
-                fprintf(stdout, "   lon_%2.2i    lat_%2.2i : ", k+1, k+1);
-              fprintf(stdout, "\n");
-            }
-          area = PolygonArea(ncorner+1, lon_bounds, lat_bounds,lat);
-          fprintf(stdout, " %6i %6i  %9.4f  %9.4f %9.5f :", 
-		  nout, i+1, lon, lat, area*pow(10,6));
-
-	  int ncorner_new = check_ncorner(ncorner, lon_bounds, lat_bounds);
-
-          for ( k = 0; k < ncorner_new; k++ )
-	    fprintf(stdout, "%9.4f %9.4f : ", lon_bounds[k], lat_bounds[k]);
-           for ( k = ncorner_new; k < ncorner; k++ )
-	     fprintf(stdout, "     ----      ---- : ");
-          fprintf(stdout, "\n");
-        }
-    }
-
-  if ( nout )
-    cdoWarning("%d of %d points out of bounds!", nout, gridsize);
-  
-  /* check that all cell bounds have the same orientation */
-  
-  nout = 0;
-  for ( i = 0; i < gridsize; ++i )
-    {
-      lon = grid_center_lon[i];
-      lat = grid_center_lat[i];
-      
-      for ( k = 0; k < ncorner; ++k )
-	{
-          lon_bounds[k] = grid_corner_lon[i*ncorner+k];
-          lat_bounds[k] = grid_corner_lat[i*ncorner+k];
-          if ( (grid_center_lon[i] - lon_bounds[k]) > 270 ) lon_bounds[k] += 360;
-          if ( (lon_bounds[k] - grid_center_lon[i]) > 270 ) lon_bounds[k] -= 360;
-	}
-      lon_bounds[ncorner] = lon_bounds[0];
-      lat_bounds[ncorner] = lat_bounds[0];
-      
-      area = PolygonArea(ncorner+1, lon_bounds, lat_bounds, lat);
-      
-      isnegative = area < 0 ? 1 : 0;
-      sumarea += area < 0 ? -area : area;
-      
-      if ( isnegative ) nout++;
-      
-      if ( isnegative && cdoVerbose )
-        {
-          if ( nout == 1 )
-            {
-              fprintf(stdout,"\n                                     :");
-              for ( k = 0; k < ncorner; k++ )
-                fprintf(stdout, "          Corner %2i : ", k+1);
-              fprintf(stdout,"\n Number  Index center_lon center_lat :");
-              for ( k = 0; k < ncorner; k++ )
-                fprintf(stdout, "   lon_%2.2i    lat_%2.2i : ", k+1, k+1);
-              fprintf(stdout, "\n");
-            }
-          fprintf(stdout, " %6i %6i  %9.4f  %9.4f :", nout, i+1, lon, lat);
-
-	  int ncorner_new = check_ncorner(ncorner, lon_bounds, lat_bounds);
-
-          for ( k = 0; k < ncorner_new; k++ )
-	    fprintf(stdout, "%9.4f %9.4f : ", lon_bounds[k], lat_bounds[k]);
-           for ( k = ncorner_new; k < ncorner; k++ )
-	     fprintf(stdout, "     ----      ---- : ");
-
-          fprintf(stdout, "\n");
-        }
-    }
-
-  if ( nout )
-    cdoWarning("%d of %d grid cells have wrong orientation!", nout, gridsize);
-
-  if ( cdoVerbose ) 
-    fprintf(stdout, "area-error: %9.5f%%\n", 100.*(sumarea - 4.*M_PI)/4.*M_PI );
-
-  if ( fabs(100.*(sumarea - 4.*M_PI)/4.*M_PI) > 0.1)
-    cdoWarning("area-error: %9.5f%%", 100.*(sumarea - 4.*M_PI)/4.*M_PI );
-  
-  /* check that all cells are convex */
-  
-  nout = 0;
-  for ( i0 = 0; i0 < gridsize; i0++ )
-    {
-      lon = grid_center_lon[i0];
-      lat = grid_center_lat[i0];
-
-      for ( k = 0; k < ncorner; k++ )
-	{
-	  lon_bounds[k] = grid_corner_lon[i0*ncorner+k];
-	  lat_bounds[k] = grid_corner_lat[i0*ncorner+k];
-	  /* Find cells that cover left and right border of the grid and adjust
-	     coordinates --> they become closed polygons on theta-phi plane! */
-	  if ( (lon - lon_bounds[k]) > 270 ) lon_bounds[k] += 360; 
-	  if ( (lon_bounds[k] - lon) > 270 ) lon_bounds[k] -= 360;
-	}
-      
-      /* Reset found cuts for the current cell before starting the search */
-      for ( i = 0; i < ncorner; i++ )
-	for ( j = 0; j < ncorner; j++ )
-	  cuts[i][j] = 0;
-      
-      /* Loops cover all combinations between inner lines of the Polygon
-	 Check whether each inner line is cut by an other (inner) one at least once. 
-	 - Only if there is a cut every inner line the Polygon is convex
-	 - We assume: Points are in either cyclic or anticyclic order
-      */
-      for ( i = 0; i < ncorner-1; i++ )
-	{
-          /* j = i+2 excludes lines from one corner to an other (j=i+1) and
-	     from one point to itself (j=i)*/
-          for ( j = i+2 ; j < ncorner; j++ )
-	    {
-              /* Exclude the line between the last and first corner */
-              if ( i == 0 && j == ncorner-1 ) continue;
-
-	      /* k = i+1: if starting point is in common lines to different corners
-		 do not intersect */
-              for ( k = i+1; k < ncorner - 1; k++ )
-		{                  
-                  if ( i == k ) l0 = j+1;
-                  else          l0 = k+2;
-
-                  for ( l = l0; l < ncorner; l++ )
-		    {
-                      if ( cuts[k][l] && cuts[i][j] ) continue;
-		      /* Exlude the line between the last and first corner 
-			 Exlude the line itself (l!=i, k!=j)
-			 Check if line ij and kl intersect each other.
-			 If so increment respective counters for intersections. 
-			 It is not relevant by which line a line is intersected - 
-			 it is only relevant if they is itersected! */
-                      if ( ! ( k==0 && l == ncorner-1 ) && ( l != j ) && ( k != j )  )
-			{
-                          if ( intersect(lon_bounds[i], lat_bounds[i], lon_bounds[j], lat_bounds[j],
-                                         lon_bounds[k], lat_bounds[k], lon_bounds[l], lat_bounds[l]) )
-			    {
-			      cuts[i][j]++; cuts[k][l]++; cuts[j][i]++; cuts[l][k]++;
-			    }
-			}
-		    }
-		}                  
-	    }
-	}
-
-      convex = 1;
-      /* The following loop covers all inner lines of the Polygon 
-	 (The assumption applies that the points are in cyclic order) */
-      for ( i = 0; i < ncorner-1; i++ )
-	for ( j = i+2; j < ncorner; j++)
-	  {
-	    if ( i == 0 && j == ncorner-1 ) continue;	   
-	    if ( ! cuts[i][j] ) convex = 0;
-	  }
-      if ( !convex ) nout++;        
-      if ( cdoVerbose && ( !convex ) )
-	{
-          if ( nout == 1 )
-	    {
-              fprintf(stdout,"\n NO CONVEX POLYGON");
-              fprintf(stdout,"\n                                       :");
-              for ( k = 0; k < ncorner; k++ )
-		fprintf(stdout, "            Corner %2i : ", k);
-              fprintf(stdout,"\n Number  Index  center_lon  center_lat :");
-              for ( k = 0; k < ncorner; k++ )
-		fprintf(stdout, "    lon_%2.2i     lat_%2.2i : ", k, k);
-              fprintf(stdout, "\n");
-	    }
-          
-          fprintf(stdout, " %6i %6i   %9.4f   %9.4f :", nout, i0+1, lon, lat);
-          for ( k = 0; k < ncorner; k++ )
-	    fprintf(stdout, "  %9.4f %9.4f : ", lon_bounds[k], lat_bounds[k]);
-          fprintf(stdout, "\n");         
-	}     
-    }
-
-  if ( nout )
-    cdoWarning("%d of %d cells are not Convex!", nout, gridsize);
-
-  if ( check_corners )
-    {
-      /* 
-	 Check if there is a corner at the same point of 
-	 an other cell foreach corner of each cell 
-      */
-      nout = 0;
-      for ( i = 0; i < gridsize*ncorner; i++ )
-	alone_cell[i] = 1;
-      
-      for ( i = 0; i < gridsize*ncorner; i++ )
-	{
-	  if ( ! alone_cell[i] ) continue;
-	  alone = 1;
-	  lon = grid_corner_lon[i];
-	  lat = grid_corner_lat[i];			
-	  for ( j = 0; j < gridsize*ncorner; j++ )
-	    if ( j != i && 
-		 IS_EQUAL(grid_corner_lat[j], lat) && 
-		 IS_EQUAL(grid_corner_lon[j], lon) )
-	      { alone = 0; alone_cell[i] = alone_cell[j] = 1; break; }
-	  if ( alone )
-	    {
-	      if      ( lon >= 180. ) lon -= 360.;
-	      else if ( lon  < 180. ) lon += 360.;
-	      for ( j = i+1; j < gridsize*ncorner; j++ )
-		if (j != i  && 
-		    IS_EQUAL(grid_corner_lat[j], lat) && 
-		    IS_EQUAL(grid_corner_lon[j], lon) )
-		  { alone = 0; alone_cell[i] = alone_cell[j] = 0; break; }
-	    }
-	  if ( alone )
-	    { 
-	      nout++;
-	      if ( cdoVerbose )
-		{
-		  if ( nout == 1 )
-		    {
-		      fprintf(stdout,"\n VERTEX ALONE ON GRID\n");
-		      fprintf(stdout," number cell-Index  Vert-Index :        lon        lat\n");
-		    }							
-		  fprintf(stdout, " %6i     %6i      %6i : %10.4f %10.4f\n", 
-			  nout, i/ncorner, i, grid_corner_lon[i], grid_corner_lat[i]);
-		}					
-	    }
-	}
-
-      if ( nout )
-	cdoWarning("%d of %d corners are lonely on the grid!", nout, gridsize*ncorner);
-    }
-
-  Free(alone_cell);
-}
-
-
-void verify_grid_old(int gridtype, int gridsize, int ncorner,
-		double *grid_center_lon, double *grid_center_lat,
-		double *grid_corner_lon, double *grid_corner_lat)
-{
-  int i, k;
-  int nout;
-  int isinside;
-  int isnegative;
-  double area;
-  double lon, lat;
-  double lon_bounds[ncorner], lat_bounds[ncorner];
-
-  /* check that all centers are inside the bounds */
-
-  nout = 0;
-  for ( i = 0; i < gridsize; ++i )
-    {
-      lon = grid_center_lon[i];
-      lat = grid_center_lat[i];
-
-      for ( k = 0; k < ncorner; ++k )
-	{
-	  lon_bounds[k] = grid_corner_lon[i*ncorner+k];
-	  lat_bounds[k] = grid_corner_lat[i*ncorner+k];
-	}
-
-      for ( k = 0; k < ncorner; ++k )
-	{
-	  if ( (lon - lon_bounds[k]) > 270 ) lon_bounds[k] += 360;
-	  if ( (lon_bounds[k] - lon) > 270 ) lon_bounds[k] -= 360;
-	}
-
-      lon_bounds[ncorner] = lon_bounds[0];
-      lat_bounds[ncorner] = lat_bounds[0];
-
-      isinside = pnpoly(ncorner+1, lon_bounds, lat_bounds, lon, lat);
-
-      if ( !isinside ) nout++;
-
-      if ( !isinside && cdoVerbose )
-	printf("center: %d %d %g %g %g %g %g %g %g %g %g %g\n", nout, i, lon, lat, lon_bounds[0], lat_bounds[0],
-	       lon_bounds[1], lat_bounds[1], lon_bounds[2], lat_bounds[2], lon_bounds[3], lat_bounds[3]);
-    }
-
-  if ( nout > 0 )
-    cdoWarning("%d of %d points out of bounds!", nout, gridsize);
-
-
-  /* check that all cell bounds have the same orientation */
-
-  nout = 0;
-  for ( i = 0; i < gridsize; ++i )
-    {
-      lon = grid_center_lon[i];
-      lat = grid_center_lat[i];
-
-      for ( k = 0; k < ncorner; ++k )
-	{
-	  lon_bounds[k] = grid_corner_lon[i*ncorner+k];
-	  lat_bounds[k] = grid_corner_lat[i*ncorner+k];
-	}
-
-      for ( k = 0; k < ncorner; ++k )
-	{
-	  if ( (grid_center_lon[i] - lon_bounds[k]) > 270 ) lon_bounds[k] += 360;
-	  if ( (lon_bounds[k] - grid_center_lon[i]) > 270 ) lon_bounds[k] -= 360;
-	}
-
-      lon_bounds[ncorner] = lon_bounds[0];
-      lat_bounds[ncorner] = lat_bounds[0];
-
-      area = PolygonArea_old(ncorner+1, lon_bounds, lat_bounds);
-
-      if ( area < 0 ) isnegative = 1;
-      else            isnegative = 0;
-
-      if ( isnegative ) nout++;
-
-      if ( isnegative && cdoVerbose )
-	printf("bounds: %d %d %g %g %g %g %g %g %g %g %g %g\n", nout, i, lon, lat, lon_bounds[0], lat_bounds[0],
-	       lon_bounds[1], lat_bounds[1], lon_bounds[2], lat_bounds[2], lon_bounds[3], lat_bounds[3]);
-    }
-
-  if ( nout > 0 )
-    cdoWarning("%d of %d grid cells have wrong orientation!", nout, gridsize);
-}
-
 
 void make_cyclic(double *array1, double *array2, int nlon, int nlat)
 {
@@ -576,65 +77,167 @@ void make_cyclic(double *array1, double *array2, int nlon, int nlat)
     }
 }
 
+static
+void array_stat(int ngp, double *restrict array, double missval, double *minval, double *maxval, double *meanval)
+{
+  double rmin = DBL_MAX;
+  double rmax = -DBL_MAX;
+  double rmean = 0;
+  
+  int nvals = 0;
+  for ( int i = 0; i < ngp; i++ )
+    {
+      if ( !DBL_IS_EQUAL(array[i], missval) )
+        {
+          if ( array[i] < rmin ) rmin = array[i];
+          if ( array[i] > rmax ) rmax = array[i];
+          rmean += array[i];
+          nvals++;
+        }
+    }
+
+  if ( IS_EQUAL(rmin,  DBL_MAX) ) rmin = missval;
+  if ( IS_EQUAL(rmax, -DBL_MAX) ) rmax = missval;
+
+  if ( nvals ) rmean /= nvals;
+  else         rmean = missval;
+
+  *minval = rmin;
+  *maxval = rmax;
+  *meanval = rmean;
+}
+
+static
+void output_vrml(int nlon, int nlat, int ngp, double *restrict array, double missval, CPT *cpt)
+{
+  double minval, maxval, meanval;
+  array_stat(ngp, array, missval, &minval, &maxval, &meanval);
+
+  double dx = 10./nlon;
+
+  printf("Viewpoint {\n");
+  printf("  description \"viewpoint1\"\n");
+  printf("  orientation 0 0 1 0\n");
+  printf("  position 0.0 0.0 10.0\n");
+  printf("}\n");
+  printf("\n");
+  printf("Background {\n");
+  printf("  skyColor [\n");
+  printf("    0.0 0.1 0.8,\n");
+  printf("    0.0 0.5 1.0,\n");
+  printf("    1.0 1.0 1.0\n");
+  printf("  ]\n");
+  printf("  skyAngle [0.785, 1.571]\n");
+  printf("\n");
+  printf("  groundColor [\n");
+  printf("    0.0 0.0 0.0,\n");
+  printf("    0.3 0.3 0.3,\n");
+  printf("    0.5 0.5 0.5\n");
+  printf("  ]\n");
+  printf("  groundAngle [0.785, 1.571]\n");
+  printf("}\n");
+  printf("\n");
+  printf("Transform {\n");
+  printf("  children [\n");
+  printf("    Shape {\n");
+  printf("      appearance Appearance {\n");
+  printf("        material Material {}\n");
+  printf("      }\n");
+  printf("      geometry ElevationGrid {\n");
+  printf("        colorPerVertex TRUE\n");
+  printf("        solid FALSE\n");
+  printf("        xDimension %d\n", nlon);
+  printf("        zDimension %d\n", nlat);
+  printf("        xSpacing %g\n", dx);
+  printf("        zSpacing %g\n", dx);
+  printf("        color Color {\n");
+  printf("          color [\n");
+  for ( int j = nlat-1; j >= 0 ; --j )
+    for ( int i = 0; i < nlon; ++i )
+      {
+        int r = 0, g = 0, b = 0;
+        double val = array[j*nlon+i];
+        
+        if ( !DBL_IS_EQUAL(val, missval) )
+          {
+            int n;
+            for ( n = 0; n < cpt->ncolors; n++ )
+              if ( val > cpt->lut[n].z_low && val <= cpt->lut[n].z_high ) break;
+            
+            if ( n == cpt->ncolors )
+              {
+                r = cpt->bfn[0].rgb[0];  g = cpt->bfn[0].rgb[1];  b = cpt->bfn[0].rgb[2];
+              }
+            else
+              {
+                //  r = cpt->lut[n].rgb_high[0];  g = cpt->lut[n].rgb_high[1];  b = cpt->lut[n].rgb_high[2];
+                r = intlin(val, cpt->lut[n].rgb_low[0], cpt->lut[n].z_low, cpt->lut[n].rgb_high[0], cpt->lut[n].z_high);
+                g = intlin(val, cpt->lut[n].rgb_low[1], cpt->lut[n].z_low, cpt->lut[n].rgb_high[1], cpt->lut[n].z_high);
+                b = intlin(val, cpt->lut[n].rgb_low[2], cpt->lut[n].z_low, cpt->lut[n].rgb_high[2], cpt->lut[n].z_high);
+              }
+          }
+        else
+          {
+            r = cpt->bfn[2].rgb[0];  g = cpt->bfn[2].rgb[1];  b = cpt->bfn[2].rgb[2]; 
+          }
+        printf(" %.3g %.3g %.3g,\n", r/255., g/255., b/255.);
+      }
+  printf("          ]\n");
+  printf("        }\n");
+  printf("        height [\n");
+
+  for ( int j = nlat-1; j >= 0 ; --j )
+    for ( int i = 0; i < nlon; ++i )
+      printf("%g,\n", array[j*nlon+i]);
+
+  printf("        ]\n");
+  printf("      }\n");
+  printf("    }\n");
+  printf("  ]\n");
+  printf("  translation -5 0 %g\n", -5.*nlat/nlon);
+  printf("  rotation 0.0 0.0 0.0 0.0\n");
+  printf("  scale 1.0 %g 1.0\n", 0.5/(maxval-minval));
+  printf("}\n");
+}
+
 
 void *Outputgmt(void *argument)
 {
-  int GRIDVERIFY, OUTPUTCENTER, OUTPUTCENTER2, OUTPUTCENTERCPT, OUTPUTBOUNDS;
-  int OUTPUTBOUNDSCPT, OUTPUTVECTOR, OUTPUTTRI, OUTPUTVRML;
-  int operatorID;
-  int process_data = TRUE;
   int i, j;
-  int varID0, varID, recID;
-  int nvals;
-  int gridsize = 0;
+  int varID0, recID;
   int gridsize2 = 0;
-  int gridID, code;
   int nrecs;
   int levelID;
-  int tsID;
-  int streamID = 0;
-  int vlistID;
   int nmiss;
-  int nlon, nlat, nalloc;
-  int nlev, lzon = FALSE, lmer = FALSE, lhov = FALSE;
+  int lzon = FALSE, lmer = FALSE, lhov = FALSE;
   int ncorner = 0, ic;
   int status;
   int lgrid_gen_bounds = FALSE, luse_grid_corner = FALSE;
-  int zaxisID, taxisID;
   int ninc = 1;
-  int vdate, vtime;
   char varname[CDI_MAX_NAME];
   double level;
-  double missval;
-  double *array = NULL;
   double *array2 = NULL;
-  double *parray;
   double *uf = NULL, *vf = NULL, *alpha = NULL, *auv = NULL;
-  double *grid_center_lat = NULL, *grid_center_lon = NULL;
   double *grid_center_lat2 = NULL, *grid_center_lon2 = NULL;
   double *grid_corner_lat = NULL, *grid_corner_lon = NULL;
-  double *plat, *plon;
-  double *zaxis_center_lev, *zaxis_lower_lev, *zaxis_upper_lev;
   int *grid_mask = NULL;
   FILE *cpt_fp;
   CPT cpt;
-  int grid_is_circular;
   char units[CDI_MAX_NAME];
   char vdatestr[32], vtimestr[32];	  
 
   cdoInitialize(argument);
 
-  GRIDVERIFY      = cdoOperatorAdd("gridverify",      0, 0, NULL);
-  OUTPUTCENTER    = cdoOperatorAdd("outputcenter",    0, 0, NULL);
-  OUTPUTCENTER2   = cdoOperatorAdd("outputcenter2",   0, 0, NULL);
-  OUTPUTCENTERCPT = cdoOperatorAdd("outputcentercpt", 0, 0, NULL);
-  OUTPUTBOUNDS    = cdoOperatorAdd("outputbounds",    0, 0, NULL);
-  OUTPUTBOUNDSCPT = cdoOperatorAdd("outputboundscpt", 0, 0, NULL);
-  OUTPUTVECTOR    = cdoOperatorAdd("outputvector",    0, 0, NULL);
-  OUTPUTTRI       = cdoOperatorAdd("outputtri",       0, 0, NULL);
-  OUTPUTVRML      = cdoOperatorAdd("outputvrml",      0, 0, NULL);
+  int OUTPUTCENTER    = cdoOperatorAdd("gmtxyz",          0, 0, NULL);
+  int OUTPUTCENTER2   = cdoOperatorAdd("outputcenter2",   0, 0, NULL);
+  int OUTPUTCENTERCPT = cdoOperatorAdd("outputcentercpt", 0, 0, NULL);
+  int OUTPUTBOUNDS    = cdoOperatorAdd("gmtcells",        0, 0, NULL);
+  int OUTPUTBOUNDSCPT = cdoOperatorAdd("outputboundscpt", 0, 0, NULL);
+  int OUTPUTVECTOR    = cdoOperatorAdd("outputvector",    0, 0, NULL);
+  int OUTPUTTRI       = cdoOperatorAdd("outputtri",       0, 0, NULL);
+  int OUTPUTVRML      = cdoOperatorAdd("outputvrml",      0, 0, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   if ( operatorID == OUTPUTVECTOR )
     {
@@ -644,20 +247,13 @@ void *Outputgmt(void *argument)
       if ( ninc < 1 ) cdoAbort("Increment must be greater than 0!");
     }
 
-  if ( operatorID == GRIDVERIFY  )
-    {
-      process_data = FALSE;
-      luse_grid_corner = TRUE;
-    }
-
   if ( operatorID == OUTPUTBOUNDS || operatorID == OUTPUTBOUNDSCPT )
     luse_grid_corner = TRUE;
 
   if ( operatorID == OUTPUTCENTERCPT || operatorID == OUTPUTBOUNDSCPT || operatorID == OUTPUTVRML )
     {
-      char *cpt_file;
-
-      cpt_file = operatorArgv()[0];
+       operatorCheckArgc(1);
+       char *cpt_file = operatorArgv()[0];
 
       if ( (cpt_fp = fopen (cpt_file, "r")) == NULL )
 	cdoAbort("Open failed on color palette table %s", cpt_file);
@@ -669,17 +265,17 @@ void *Outputgmt(void *argument)
       if ( cdoVerbose ) cptWrite(stderr, cpt);
     }
 
-  streamID = streamOpenRead(cdoStreamName(0));
+  int streamID = streamOpenRead(cdoStreamName(0));
 
-  vlistID = streamInqVlist(streamID);
-  taxisID = vlistInqTaxis(vlistID);
+  int vlistID = streamInqVlist(streamID);
+  int taxisID = vlistInqTaxis(vlistID);
 
-  varID = 0;
+  int varID = 0;
   vlistInqVarName(vlistID, varID, varname);
-  code    = vlistInqVarCode(vlistID, varID);
-  gridID  = vlistInqVarGrid(vlistID, varID);
-  zaxisID = vlistInqVarZaxis(vlistID, varID);
-  missval = vlistInqVarMissval(vlistID, varID);
+  int code    = vlistInqVarCode(vlistID, varID);
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  int zaxisID = vlistInqVarZaxis(vlistID, varID);
+  double missval = vlistInqVarMissval(vlistID, varID);
 
   if ( gridInqType(gridID) == GRID_GME ) gridID = gridToUnstructured(gridID, 1);
 
@@ -689,10 +285,10 @@ void *Outputgmt(void *argument)
       lgrid_gen_bounds = TRUE;
     }
 
-  gridsize = gridInqSize(gridID);
-  nlon     = gridInqXsize(gridID);
-  nlat     = gridInqYsize(gridID);
-  nlev     = zaxisInqSize(zaxisID);
+  int gridsize = gridInqSize(gridID);
+  int nlon     = gridInqXsize(gridID);
+  int nlat     = gridInqYsize(gridID);
+  int nlev     = zaxisInqSize(zaxisID);
 
   if ( gridInqMaskGME(gridID, NULL) )
     {
@@ -732,10 +328,10 @@ void *Outputgmt(void *argument)
   else
     ncorner = 4;
 
-  grid_is_circular = gridIsCircular(gridID);
+  int grid_is_circular = gridIsCircular(gridID);
 
-  grid_center_lat = (double*) Malloc(gridsize*sizeof(double));
-  grid_center_lon = (double*) Malloc(gridsize*sizeof(double));
+  double *grid_center_lat = (double*) Malloc(gridsize*sizeof(double));
+  double *grid_center_lon = (double*) Malloc(gridsize*sizeof(double));
 
   gridInqYvals(gridID, grid_center_lat);
   gridInqXvals(gridID, grid_center_lon);
@@ -746,9 +342,9 @@ void *Outputgmt(void *argument)
   gridInqYunits(gridID, units);
   grid_to_degree(units, gridsize, grid_center_lat, "grid center lat");
 
-  nvals = gridsize;
-  plon = grid_center_lon;
-  plat = grid_center_lat;
+  int nvals = gridsize;
+  double *plon = grid_center_lon;
+  double *plat = grid_center_lat;
 
   if ( operatorID == OUTPUTCENTER2 && grid_is_circular )
     {
@@ -773,16 +369,16 @@ void *Outputgmt(void *argument)
       plat = grid_center_lat2;
     }
 
-  zaxis_center_lev = (double*) Malloc(nlev*sizeof(double));
-  zaxis_lower_lev  = (double*) Malloc(nlev*sizeof(double));
-  zaxis_upper_lev  = (double*) Malloc(nlev*sizeof(double));
+  double *zaxis_center_lev = (double*) Malloc(nlev*sizeof(double));
+  double *zaxis_lower_lev  = (double*) Malloc(nlev*sizeof(double));
+  double *zaxis_upper_lev  = (double*) Malloc(nlev*sizeof(double));
 
   zaxisInqLevels(zaxisID, zaxis_center_lev);
 
   if ( luse_grid_corner )
     {
       if ( ncorner == 0 ) cdoAbort("grid corner missing!");
-      nalloc = ncorner*gridsize;
+      int nalloc = ncorner*gridsize;
       grid_corner_lat = (double*) Realloc(grid_corner_lat, nalloc*sizeof(double));
       grid_corner_lon = (double*) Realloc(grid_corner_lon, nalloc*sizeof(double));
 
@@ -828,13 +424,13 @@ void *Outputgmt(void *argument)
 
 	  if ( cdoVerbose )
 	    for ( i = 0; i < nlev; ++i )
-	      printf("level: %d %g %g %g\n",
+	      fprintf(stderr, "level: %d %g %g %g\n",
 		     i+1, zaxis_lower_lev[i], zaxis_center_lev[i], zaxis_upper_lev[i]);
 	}
     }
 
-  array = (double*) Malloc(gridsize*sizeof(double));
-  parray = array;
+  double *array = (double*) Malloc(gridsize*sizeof(double));
+  double *parray = array;
 						
   if ( operatorID == OUTPUTCENTER2 && grid_is_circular )
     {
@@ -850,17 +446,11 @@ void *Outputgmt(void *argument)
       auv   = (double*) Malloc(gridsize*sizeof(double));
     }
 
-  if ( operatorID == GRIDVERIFY )
-    verify_grid(gridInqType(gridID), gridsize, ncorner,
-		grid_center_lon, grid_center_lat,
-		grid_corner_lon, grid_corner_lat);
-
-  tsID = 0;
-  if ( process_data )
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID, tsID)) )
     {
-      vdate = taxisInqVdate(taxisID);
-      vtime = taxisInqVtime(taxisID);
+      int vdate = taxisInqVdate(taxisID);
+      int vtime = taxisInqVtime(taxisID);
 	      
       date2str(vdate, vdatestr, sizeof(vdatestr));
       time2str(vtime, vtimestr, sizeof(vtimestr));
@@ -914,35 +504,21 @@ void *Outputgmt(void *argument)
 
 	  if ( operatorID == OUTPUTCENTER || operatorID == OUTPUTCENTER2 || operatorID == OUTPUTCENTERCPT )
 	    {
+              if ( cdoVerbose )
+                {
+                  double minval, maxval, meanval;
+                  array_stat(gridsize, array, missval, &minval, &maxval, &meanval);
+                  double range = maxval - minval;
+                  fprintf(stderr, "makecpt -T%g/%g/%g -Crainbow > gmt.cpt\n", minval, maxval, range/20);
+                  fprintf(stderr, "pscontour -K -JQ0/10i -Rd -I -Cgmt.cpt data.gmt > gmtplot.ps\n");
+                  fprintf(stderr, "pscoast -O -J -R -Dc -W -B40g20 >> gmtplot.ps\n");
+                }
+
 	      for ( i = 0; i < nvals; i++ )
 		{
 		  if ( grid_mask )
 		    if ( grid_mask[i] == 0 ) continue;
 
-		  if ( operatorID == OUTPUTCENTERCPT )
-		    {
-		      int r = 0, g = 0, b = 0, n;
-
-		      if ( !DBL_IS_EQUAL(array[i], missval) )
-			{
-			  for ( n = 0; n < cpt.ncolors; n++ )
-			    if ( array[i] > cpt.lut[n].z_low && array[i] <= cpt.lut[n].z_high ) break;
-
-			  if ( n == cpt.ncolors )
-			    {
-			      r = cpt.bfn[0].rgb[0];  g = cpt.bfn[0].rgb[1];  b = cpt.bfn[0].rgb[2];
-			    }
-			  else
-			    {
-			      r = cpt.lut[n].rgb_high[0];  g = cpt.lut[n].rgb_high[1];  b = cpt.lut[n].rgb_high[2];
-			    }
-			}
-		      else
-			{
-			  r = cpt.bfn[2].rgb[0];  g = cpt.bfn[2].rgb[1];  b = cpt.bfn[2].rgb[2]; 
-			}
-		    }
-
 		  if ( operatorID == OUTPUTCENTER )
 		    {
 		      if ( lzon )
@@ -972,7 +548,7 @@ void *Outputgmt(void *argument)
 	    }
 	  else if ( operatorID == OUTPUTTRI )
 	    {
-	      int ij, c1, c2, c3;
+	      int c1, c2, c3;
 	      int mlon, ip1;
 	      if ( gridInqType(gridID) != GRID_CURVILINEAR ) cdoAbort("Unsupported grid!");
 
@@ -984,7 +560,6 @@ void *Outputgmt(void *argument)
 		    {
 		      ip1 = i+1;
 		      if ( i == nlon-1 ) ip1 = 0;
-		      ij = j*nlon+i;
 		      c1 = (j)*nlon+ip1;
 		      c2 = (j)*nlon+i;
 		      c3 = (j+1)*nlon+i;
@@ -1028,111 +603,26 @@ void *Outputgmt(void *argument)
 	    }
 	  else if ( operatorID == OUTPUTVRML )
 	    {
-	      double minval = 1e33;
-	      double maxval = -1e33;
-	      double meanval = 0;
-	      for ( i = 0; i < gridsize; i++ )
-		{
-		  if ( array[i] < minval ) minval = array[i];
-		  if ( array[i] > maxval ) maxval = array[i];
-		  meanval += array[i];
-		}
-	      meanval /= gridsize;
-
-	      double dx = 10./nlon;
-
-	      printf("Viewpoint {\n");
-	      printf("  description \"viewpoint1\"\n");
-	      printf("  orientation 0 0 1 0\n");
-	      printf("  position 0.0 0.0 10.0\n");
-	      printf("}\n");
-	      printf("\n");
-	      printf("Background {\n");
-	      printf("  skyColor [\n");
-	      printf("    0.0 0.1 0.8,\n");
-	      printf("    0.0 0.5 1.0,\n");
-	      printf("    1.0 1.0 1.0\n");
-	      printf("  ]\n");
-	      printf("  skyAngle [0.785, 1.571]\n");
-	      printf("\n");
-	      printf("  groundColor [\n");
-	      printf("    0.0 0.0 0.0,\n");
-	      printf("    0.3 0.3 0.3,\n");
-	      printf("    0.5 0.5 0.5\n");
-	      printf("  ]\n");
-	      printf("  groundAngle [0.785, 1.571]\n");
-	      printf("}\n");
-	      printf("\n");
-	      printf("Transform {\n");
-	      printf("  children [\n");
-	      printf("    Shape {\n");
-	      printf("      appearance Appearance {\n");
-	      printf("        material Material {}\n");
-	      printf("      }\n");
-	      printf("      geometry ElevationGrid {\n");
-    	      printf("        colorPerVertex TRUE\n");
-    	      printf("        solid FALSE\n");
-    	      printf("        xDimension %d\n", nlon);
-    	      printf("        zDimension %d\n", nlat);
-    	      printf("        xSpacing %g\n", dx);
-    	      printf("        zSpacing %g\n", dx);
-	      printf("        color Color {\n");
-	      printf("          color [\n");
-	      for ( j = nlat-1; j >= 0 ; --j )
-		for ( i = 0; i < nlon; ++i )
-		{
-		  int r = 0, g = 0, b = 0, n;
-		  double val = array[j*nlon+i];
-
-		  if ( !DBL_IS_EQUAL(val, missval) )
-		    {
-		      for ( n = 0; n < cpt.ncolors; n++ )
-			if ( val > cpt.lut[n].z_low && val <= cpt.lut[n].z_high ) break;
-		      
-		      if ( n == cpt.ncolors )
-			{
-			  r = cpt.bfn[0].rgb[0];  g = cpt.bfn[0].rgb[1];  b = cpt.bfn[0].rgb[2];
-			}
-		      else
-			{
-			  //  r = cpt.lut[n].rgb_high[0];  g = cpt.lut[n].rgb_high[1];  b = cpt.lut[n].rgb_high[2];
-			  r = intlin(val, cpt.lut[n].rgb_low[0], cpt.lut[n].z_low, cpt.lut[n].rgb_high[0], cpt.lut[n].z_high);
-			  g = intlin(val, cpt.lut[n].rgb_low[1], cpt.lut[n].z_low, cpt.lut[n].rgb_high[1], cpt.lut[n].z_high);
-			  b = intlin(val, cpt.lut[n].rgb_low[2], cpt.lut[n].z_low, cpt.lut[n].rgb_high[2], cpt.lut[n].z_high);
-			}
-		    }
-		  else
-		    {
-		      r = cpt.bfn[2].rgb[0];  g = cpt.bfn[2].rgb[1];  b = cpt.bfn[2].rgb[2]; 
-		    }
-		  printf(" %.3g %.3g %.3g,\n", r/255., g/255., b/255.);
-		}
-	      printf("          ]\n");
-	      printf("        }\n");
-    	      printf("        height [\n");
-	      //	      for ( j = 0; j < nlat; ++j )
-	      for ( j = nlat-1; j >= 0 ; --j )
-		{
-		  for ( i = 0; i < nlon; ++i )
-		    {
-		      printf("%g,\n", array[j*nlon+i]);
-		    }
-		}
-    	      printf("        ]\n");
-	      printf("      }\n");
-	      printf("    }\n");
-	      printf("  ]\n");
-	      printf("  translation -5 0 %g\n", -5.*nlat/nlon);
-	      printf("  rotation 0.0 0.0 0.0 0.0\n");
-	      printf("  scale 1.0 %g 1.0\n", 0.5/(maxval-minval));
-	      printf("}\n");
+              output_vrml(nlon, nlat, gridsize, array, missval, &cpt);
             }
 	  else if ( operatorID == OUTPUTBOUNDS || operatorID == OUTPUTBOUNDSCPT )
 	    {
+              if ( cdoVerbose )
+                {
+                  double minval, maxval, meanval;
+                  array_stat(gridsize, array, missval, &minval, &maxval, &meanval);
+                  double range = maxval - minval;
+                  fprintf(stderr, "makecpt -T%g/%g/%g -Crainbow > gmt.cpt\n", minval, maxval, range/20);
+                  fprintf(stderr, "psxy -K -JQ0/10i -Rd -L -Cgmt.cpt -m data.gmt > gmtplot.ps\n");
+                  // fprintf(stderr, "psxy -K -Jx0.028id -Rd -L -Cgmt.cpt -m data.gmt > gmtplot.ps\n");
+                  // fprintf(stderr, "psxy -K -JN0/10i -Rd -L -Cgmt.cpt -m data.gmt > gmtplot.ps\n");
+                  fprintf(stderr, "pscoast -O -J -R -Dc -W -B40g20 >> gmtplot.ps\n");
+                  fprintf(stderr, "ps2pdf gmtplot.ps\n");
+                }
+
 	      for ( i = 0; i < gridsize; i++ )
 		{
-		  if ( grid_mask )
-		    if ( grid_mask[i] == 0 ) continue;
+		  if ( grid_mask && grid_mask[i] == 0 ) continue;
 
 		  if ( !DBL_IS_EQUAL(array[i], missval) )
 		    fprintf(stdout, "> -Z%g", array[i]);
@@ -1172,8 +662,8 @@ void *Outputgmt(void *argument)
 		      double xlev[4], xlat[4];
 		      double levmin = zaxis_lower_lev[levelID];
 		      double levmax = zaxis_upper_lev[levelID];
-		      double latmin = grid_corner_lat[i*4+0];
-		      double latmax = grid_corner_lat[i*4+0];
+		      double latmin = grid_corner_lat[i*4];
+		      double latmax = grid_corner_lat[i*4];
 		      for ( ic = 1; ic < 4; ic++ )
 			{
 			  if ( grid_corner_lat[i*4+ic] < latmin ) latmin = grid_corner_lat[i*4+ic];
@@ -1196,8 +686,8 @@ void *Outputgmt(void *argument)
 		      double xlev[4], xlon[4];
 		      double levmin = zaxis_lower_lev[levelID];
 		      double levmax = zaxis_upper_lev[levelID];
-		      double lonmin = grid_corner_lon[i*4+0];
-		      double lonmax = grid_corner_lon[i*4+0];
+		      double lonmin = grid_corner_lon[i*4];
+		      double lonmax = grid_corner_lon[i*4];
 		      for ( ic = 1; ic < 4; ic++ )
 			{
 			  if ( grid_corner_lon[i*4+ic] < lonmin ) lonmin = grid_corner_lon[i*4+ic];
diff --git a/src/Pack.c b/src/Pack.c
index a55830d..8b0f44a 100644
--- a/src/Pack.c
+++ b/src/Pack.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Vardup.c b/src/Pardup.c
similarity index 95%
rename from src/Vardup.c
rename to src/Pardup.c
index 0f7ebc3..0fa1cfc 100644
--- a/src/Vardup.c
+++ b/src/Pardup.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -18,8 +18,8 @@
 /*
    This module contains the following operators:
 
-      Vardup     pardup          Duplicate parameters
-      Vardup     parmul          Multiply parameters
+      Pardup     pardup          Duplicate parameters
+      Pardup     parmul          Multiply parameters
 */
 
 #include <cdi.h>
@@ -28,7 +28,7 @@
 #include "pstream.h"
 
 
-void *Vardup(void *argument)
+void *Pardup(void *argument)
 {
   int nrecs;
   int recID, varID, varID2, levelID;
diff --git a/src/Pinfo.c b/src/Pinfo.c
index d568757..4adfd5b 100644
--- a/src/Pinfo.c
+++ b/src/Pinfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Pressure.c b/src/Pressure.c
index b617d47..471f785 100644
--- a/src/Pressure.c
+++ b/src/Pressure.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Regres.c b/src/Regres.c
index dc16dc2..fa557cf 100644
--- a/src/Regres.c
+++ b/src/Regres.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -139,14 +139,14 @@ void *Regres(void *argument)
 
       for ( i = 0; i < gridsize; i++ )
 	{
-	  temp1 = SUB(work[2][varID][levelID].ptr[i],
-		      DIV(MUL(work[0][varID][levelID].ptr[i], work[3][varID][levelID].ptr[i]), work[4][varID][levelID].ptr[i]));
-	  temp2 = SUB(work[1][varID][levelID].ptr[i],
-		      DIV(MUL(work[0][varID][levelID].ptr[i], work[0][varID][levelID].ptr[i]), work[4][varID][levelID].ptr[i]));
-
-	  field2.ptr[i] = DIV(temp1, temp2);
-	  field1.ptr[i] = SUB(DIV(work[3][varID][levelID].ptr[i], work[4][varID][levelID].ptr[i]),
-			      MUL(DIV(work[0][varID][levelID].ptr[i], work[4][varID][levelID].ptr[i]), field2.ptr[i]));
+	  temp1 = SUBMN(work[2][varID][levelID].ptr[i],
+		      DIVMN( MULMN(work[0][varID][levelID].ptr[i], work[3][varID][levelID].ptr[i]), work[4][varID][levelID].ptr[i]));
+	  temp2 = SUBMN(work[1][varID][levelID].ptr[i],
+		      DIVMN( MULMN(work[0][varID][levelID].ptr[i], work[0][varID][levelID].ptr[i]), work[4][varID][levelID].ptr[i]));
+
+	  field2.ptr[i] = DIVMN(temp1, temp2);
+	  field1.ptr[i] = SUBMN( DIVMN(work[3][varID][levelID].ptr[i], work[4][varID][levelID].ptr[i]),
+			      MULMN( DIVMN(work[0][varID][levelID].ptr[i], work[4][varID][levelID].ptr[i]), field2.ptr[i]));
 	}
 
       /*
diff --git a/src/Remap.c b/src/Remap.c
index 81919a8..bf41b82 100644
--- a/src/Remap.c
+++ b/src/Remap.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -831,7 +831,7 @@ void *Remap(void *argument)
 
   if ( lremapxxx )
     {
-      operatorInputArg("grid description file or name, remap weights file (SCRIP netCDF)");
+      operatorInputArg("grid description file or name, remap weights file (SCRIP NetCDF)");
       operatorCheckArgc(2);
       gridID2 = cdoDefineGrid(operatorArgv()[0]);
       remap_file = operatorArgv()[1];
diff --git a/src/Remapeta.c b/src/Remapeta.c
index 35d1146..44f7d2c 100644
--- a/src/Remapeta.c
+++ b/src/Remapeta.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
   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
@@ -35,11 +35,9 @@
 static 
 void setmissval(long nvals, int *imiss, double missval, double *array)
 {
-  long i;
-
   if ( imiss )
     {
-      for ( i = 0; i < nvals; ++i )
+      for ( long i = 0; i < nvals; ++i )
 	if ( imiss[i] ) array[i] = missval;
     }
 }
@@ -115,8 +113,7 @@ double *vctFromFile(const char *filename, int *nvct)
 
   while ( readline(fp, line, 1024) )
     {
-      if ( line[0] == '#' ) continue;
-      if ( line[0] == '\0' ) continue;
+      if ( line[0] == '#' || line[0] == '\0' ) continue;
 
       pline = line;
       num = (int) strtod(pline, &pline);
diff --git a/src/Replace.c b/src/Replace.c
index 4cedf6b..2782114 100644
--- a/src/Replace.c
+++ b/src/Replace.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Replacevalues.c b/src/Replacevalues.c
index 1de165f..3c49c2b 100644
--- a/src/Replacevalues.c
+++ b/src/Replacevalues.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Rhopot.c b/src/Rhopot.c
index e6b3fcb..5e9863a 100644
--- a/src/Rhopot.c
+++ b/src/Rhopot.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -296,9 +296,17 @@ void *Rhopot(void *argument)
 
 	  offset = gridsize*levelID;
 
-	  if ( varID == toID ) streamReadRecord(streamID1, to.ptr+offset, &(to.nmiss));
-	  if ( varID == saoID ) streamReadRecord(streamID1, sao.ptr+offset, &(sao.nmiss));
-	}
+	  if ( varID == toID )
+            {
+              streamReadRecord(streamID1, to.ptr+offset, &nmiss);
+              to.nmiss = (size_t) nmiss;
+            }
+	  if ( varID == saoID )
+            {
+              streamReadRecord(streamID1, sao.ptr+offset, &nmiss);
+              sao.nmiss = (size_t) nmiss;
+            }
+        }
 
       calc_rhopot(gridsize, nlevel, pressure, to, sao, rho); 
 
diff --git a/src/Rotuv.c b/src/Rotuv.c
index f5e9f10..a2f7672 100644
--- a/src/Rotuv.c
+++ b/src/Rotuv.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Runstat.c b/src/Runstat.c
index c973f19..1187ffa 100644
--- a/src/Runstat.c
+++ b/src/Runstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,9 @@
       Runstat    runmean         Running mean
       Runstat    runavg          Running average
       Runstat    runvar          Running variance
-      Runstat    runvar1         Running variance [Divisor is (n-1)]
+      Runstat    runvar1         Running variance [Normalize by (n-1)]
       Runstat    runstd          Running standard deviation
-      Runstat    runstd1         Running standard deviation [Divisor is (n-1)]
+      Runstat    runstd1         Running standard deviation [Normalize by (n-1)]
 */
 
 #include <cdi.h>
@@ -82,7 +82,7 @@ void *Runstat(void *argument)
   int lmean   = operfunc == func_mean || operfunc == func_avg;
   int lstd    = operfunc == func_std || operfunc == func_std1;
   int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  double divisor = operfunc == func_std1 || operfunc == func_var1;
+  int divisor = operfunc == func_std1 || operfunc == func_var1;
 
   int streamID1 = streamOpenRead(cdoStreamName(0));
 
diff --git a/src/Seascount.c b/src/Seascount.c
index 9c5c3c8..c8f2ef1 100644
--- a/src/Seascount.c
+++ b/src/Seascount.c
@@ -38,6 +38,7 @@ void *Seascount(void *argument)
   int varID, levelID, recID;
   int tsID;
   int otsID;
+  int nmiss;
   long nsets;
   int i;
   int year, month, day, seas, seas0 = 0;
@@ -131,7 +132,8 @@ void *Seascount(void *argument)
 		  vars1[varID][levelID].nmiss = gridsize;
                 }
 
-              streamReadRecord(streamID1, field.ptr, &field.nmiss);
+              streamReadRecord(streamID1, field.ptr, &nmiss);
+              field.nmiss   = (size_t)nmiss;
               field.grid    = vars1[varID][levelID].grid;
               field.missval = vars1[varID][levelID].missval;
 
@@ -158,7 +160,7 @@ void *Seascount(void *argument)
 	  if ( otsID && vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
 	  streamDefRecord(streamID2, varID, levelID);
-	  streamWriteRecord(streamID2, vars1[varID][levelID].ptr,  vars1[varID][levelID].nmiss);
+	  streamWriteRecord(streamID2, vars1[varID][levelID].ptr, (int)vars1[varID][levelID].nmiss);
         }
 
       if ( nrecs == 0 ) break;
diff --git a/src/Seasstat.c b/src/Seasstat.c
index 6ea36fa..b3e51c1 100644
--- a/src/Seasstat.c
+++ b/src/Seasstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,9 @@
       Seasstat   seasmean        Seasonal mean
       Seasstat   seasavg         Seasonal average
       Seasstat   seasvar         Seasonal variance
-      Seasstat   seasvar1        Seasonal variance [Divisor is (n-1)]
+      Seasstat   seasvar1        Seasonal variance [Normalize by (n-1)]
       Seasstat   seasstd         Seasonal standard deviation
-      Seasstat   seasstd1        Seasonal standard deviation [Divisor is (n-1)]
+      Seasstat   seasstd1        Seasonal standard deviation [Normalize by (n-1)]
 */
 
 
@@ -46,7 +46,7 @@ void *Seasstat(void *argument)
   int vdate1 = 0, vtime1 = 0;
   int nrecs;
   int varID, levelID, recID;
-  long nsets;
+  int nsets;
   int i;
   int year, month, day, seas, seas0 = 0;
   int nmiss;
@@ -76,7 +76,7 @@ void *Seasstat(void *argument)
   int lmean   = operfunc == func_mean || operfunc == func_avg;
   int lstd    = operfunc == func_std || operfunc == func_std1;
   int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  double divisor = operfunc == func_std1 || operfunc == func_var1;
+  int divisor = operfunc == func_std1 || operfunc == func_var1;
 
   int streamID1 = streamOpenRead(cdoStreamName(0));
 
@@ -180,7 +180,8 @@ void *Seasstat(void *argument)
 		}
 	      else
 		{
-		  streamReadRecord(streamID1, field.ptr, &field.nmiss);
+		  streamReadRecord(streamID1, field.ptr, &nmiss);
+                  field.nmiss   = (size_t)nmiss;
 		  field.grid    = vars1[varID][levelID].grid;
 		  field.missval = vars1[varID][levelID].missval;
 
@@ -272,7 +273,7 @@ void *Seasstat(void *argument)
 	  time2str(vtime0, vtimestr0, sizeof(vtimestr0));
 	  date2str(vdate1, vdatestr1, sizeof(vdatestr1));
 	  time2str(vtime1, vtimestr1, sizeof(vtimestr1));
-	  cdoPrint("season %3d %3s start %s %s end %s %s ntimesteps %d", 
+	  cdoPrint("season: %3d %3s  start: %s %s  end: %s %s ntimesteps: %d", 
 		   nseason, seas_name[seas0], vdatestr0, vtimestr0, vdatestr1, vtimestr1, nsets);
 	}
 
@@ -295,7 +296,7 @@ void *Seasstat(void *argument)
 	  if ( otsID && vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
 	  streamDefRecord(streamID2, varID, levelID);
-	  streamWriteRecord(streamID2, vars1[varID][levelID].ptr,  vars1[varID][levelID].nmiss);
+	  streamWriteRecord(streamID2, vars1[varID][levelID].ptr, (int)vars1[varID][levelID].nmiss);
 	}
 
       if ( nrecs == 0 ) break;
diff --git a/src/Selbox.c b/src/Selbox.c
index f33887d..829eaf6 100644
--- a/src/Selbox.c
+++ b/src/Selbox.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Select.c b/src/Select.c
index 1e7c0bb..c10a32b 100644
--- a/src/Select.c
+++ b/src/Select.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -54,13 +54,13 @@ static PARAMETER Parameter[] =
 static int NumParameter = sizeof(Parameter) / sizeof(Parameter[0]);
 */
 
-#define PML_DEF(name, size, txt)      int flag_##name[size]; int npar_##name = 0; int max_##name = size; const char str_##name[] = txt
+#define PML_DEF(name, size, txt)      bool flag_##name[size]; int npar_##name = 0; int max_##name = size; const char str_##name[] = txt
 #define PML_DEF_INT(name, size, txt)  int par_##name[size]; int name = 0; PML_DEF(name, size, txt)
 #define PML_DEF_FLT(name, size, txt)  double par_##name[size]; double name = 0; PML_DEF(name, size, txt)
-#define PML_DEF_WORD(name, size, txt) char *par_##name[size]; char *name = 0; PML_DEF(name, size, txt)
-#define PML_INIT_INT(name)            memset(flag_##name, 0, max_##name * sizeof(int))
-#define PML_INIT_FLT(name)            memset(flag_##name, 0, max_##name * sizeof(int))
-#define PML_INIT_WORD(name)           memset(flag_##name, 0, max_##name * sizeof(int))
+#define PML_DEF_WORD(name, size, txt) char *par_##name[size]; const char *name = 0; PML_DEF(name, size, txt)
+#define PML_INIT_INT(name)            memset(flag_##name, 0, max_##name * sizeof(bool))
+#define PML_INIT_FLT(name)            memset(flag_##name, 0, max_##name * sizeof(bool))
+#define PML_INIT_WORD(name)           memset(flag_##name, 0, max_##name * sizeof(bool))
 #define PML_ADD_INT(nml, name)        pmlAdd(nml, #name, PML_INT,  0, par_##name, sizeof(par_##name)/sizeof(int))
 #define PML_ADD_FLT(nml, name)        pmlAdd(nml, #name, PML_FLT,  0, par_##name, sizeof(par_##name)/sizeof(double))
 #define PML_ADD_WORD(nml, name)       pmlAdd(nml, #name, PML_WORD, 0, par_##name, sizeof(par_##name)/sizeof(char *))
@@ -74,6 +74,7 @@ static int NumParameter = sizeof(Parameter) / sizeof(Parameter[0]);
 #define PAR_CHECK_FLT(name)           par_check_flt(npar_##name, par_##name, flag_##name, name)
 #define PAR_CHECK_WORD(name)          par_check_word(npar_##name, par_##name, flag_##name, name)
 #define PAR_CHECK_DATE(name)          par_check_date(npar_##name, par_##name, flag_##name, name)
+#define PAR_CHECK_SEASON(name, month) par_check_season(npar_##name, par_##name, flag_##name, month)
 
 #define MAX_PLIST_ENTRY  256
 #define MAX_PML_ENTRY    256
@@ -130,13 +131,11 @@ void pml_init(pml_t *pml, const char *name)
 
 pml_t *pmlNew(const char *name)
 {
-  pml_t *pml;
-
-  pml = (pml_t*) Malloc(sizeof(pml_t));
+  pml_t *pml = (pml_t*) Malloc(sizeof(pml_t));
 
   pml_init(pml, name);
 
-  return (pml);
+  return pml;
 }
 
 
@@ -189,16 +188,13 @@ void pmlPrint(pml_t *pml)
 
 int pmlAdd(pml_t *pml, const char *name, int type, int dis, void *ptr, size_t size)
 {
-  pml_entry_t *pml_entry;
-  int entry = 0;
-
   if ( pml->size >= MAX_PML_ENTRY )
     {
       fprintf(stderr, "Too many entries in parameter list %s! (Max = %d)\n", pml->name, MAX_PML_ENTRY);
       return -1;
     }
 
-  pml_entry = (pml_entry_t*) Malloc(sizeof(pml_entry_t));
+  pml_entry_t *pml_entry = (pml_entry_t*) Malloc(sizeof(pml_entry_t));
 
   pml_entry->name = strdup(name);
   pml_entry->len  = strlen(name);
@@ -208,10 +204,10 @@ int pmlAdd(pml_t *pml, const char *name, int type, int dis, void *ptr, size_t si
   pml_entry->dis  = dis;
   pml_entry->occ  = 0;
 
-  entry = pml->size;
+  int entry = pml->size;
   pml->entry[pml->size++] = pml_entry;
 
-  return (entry);
+  return entry;
 }
 
 
@@ -235,7 +231,7 @@ int pmlNum(pml_t *pml, const char *name)
   if ( i == pml->size )
     fprintf(stderr, "Parameter list entry %s not found in %s\n", name, pml->name);
 
-  return (nocc);
+  return nocc;
 }
 
 void split_intstring(const char *intstr, int *first, int *last, int *inc);
@@ -278,17 +274,16 @@ int pml_add_entry(pml_entry_t *entry, char *arg)
       fprintf(stderr, "unsupported type!\n");
     }
 
-  return (status);
+  return status;
 }
 
 
 void pmlProcess(pml_entry_t *entry, int argc, char **argv)
 {
-  int i;
   char *parg;
   char *epos;
 
-  for ( i = 0; i < argc; ++i )
+  for ( int i = 0; i < argc; ++i )
     {
       parg = argv[i];
       if ( i == 0 )
@@ -313,10 +308,9 @@ int pmlRead(pml_t *pml, int argc, char **argv)
   int params[MAX_PML_ENTRY];
   int num_par[MAX_PML_ENTRY];
   int nparams = 0;
-  int i, istart;
+  int i;
   char *epos;
   size_t len;
-  char *parbuf;
   int bufsize = 0;
   int status = 0;
   /*
@@ -329,10 +323,10 @@ int pmlRead(pml_t *pml, int argc, char **argv)
       bufsize += len+1;
     }
 
-  parbuf = (char*) Malloc(bufsize*sizeof(char));
+  char *parbuf = (char*) Malloc(bufsize*sizeof(char));
   memset(parbuf, 0, bufsize*sizeof(char));
 
-  istart = 0;
+  int istart = 0;
   while ( istart < argc )
     {
       epos = strchr(argv[istart], '=');
@@ -353,7 +347,7 @@ int pmlRead(pml_t *pml, int argc, char **argv)
 
       if ( i == pml->size )
 	{
-	  fprintf(stderr, "Parameter >%s< has not a valid keyword!\n", argv[istart]);
+	  fprintf(stderr, "Parameter >%s< has an invalid keyword!\n", argv[istart]);
 	  status = 2;
 	  goto END_LABEL;
 	}
@@ -388,43 +382,43 @@ int pmlRead(pml_t *pml, int argc, char **argv)
 
   Free(parbuf);
 
-  return (status);
+  return status;
 }
 
 
-int par_check_int(int npar, int *parlist, int *flaglist, int par)
+bool par_check_int(int npar, int *parlist, bool *flaglist, int par)
 {
-  int found = 0;
+  bool found = false;
   for ( int i = 0; i < npar; i++ )
-    if ( par == parlist[i] ) { found = 1; flaglist[i] = TRUE;/* break;*/}
+    if ( par == parlist[i] ) { found = true; flaglist[i] = true;/* break;*/}
 
-  return (found);
+  return found;
 }
 
 
-int par_check_flt(int npar, double *parlist, int *flaglist, double par)
+bool par_check_flt(int npar, double *parlist, bool *flaglist, double par)
 {
-  int found = 0;
+  bool found = false;
   for ( int i = 0; i < npar; i++ )
-    if ( fabs(par - parlist[i]) < 1.e-4 ) { found = 1; flaglist[i] = TRUE;/* break;*/}
+    if ( fabs(par - parlist[i]) < 1.e-4 ) { found = true; flaglist[i] = true;/* break;*/}
 
-  return (found);
+  return found;
 }
 
 
-int par_check_word(int npar, char **parlist, int *flaglist, char *par)
+bool par_check_word(int npar, char **parlist, bool *flaglist, const char *par)
 {
-  int found = 0;
+  bool found = false;
   for ( int i = 0; i < npar; i++ )
-    if ( wildcardmatch(parlist[i], par) == 0 ) { found = 1; flaglist[i] = TRUE;/* break;*/}
+    if ( wildcardmatch(parlist[i], par) == 0 ) { found = true; flaglist[i] = true;/* break;*/}
 
-  return (found);
+  return found;
 }
 
 
-int par_check_date(int npar, char **parlist, int *flaglist, char *par)
+bool par_check_date(int npar, char **parlist, bool *flaglist, const char *par)
 {
-  int found = 0;
+  bool found = false;
   char wcdate[512];
 
   if ( *par == ' ' ) ++par;
@@ -433,33 +427,51 @@ int par_check_date(int npar, char **parlist, int *flaglist, char *par)
     {
       strcpy(wcdate, parlist[i]);
       strcat(wcdate, "*");
-      if ( wildcardmatch(wcdate, par) == 0 ) { found = 1; flaglist[i] = TRUE;/* break;*/}
+      if ( wildcardmatch(wcdate, par) == 0 ) { found = true; flaglist[i] = true;/* break;*/}
     }
 
-  return (found);
+  return found;
 }
 
+void season_to_months(const char *season, int *imonths);
 
-void par_check_int_flag(int npar, int *parlist, int *flaglist, const char *txt)
+bool par_check_season(int npar, char **parlist, bool *flaglist, int month)
+{
+  assert(month>=1&&month<=12);
+  bool found = false;
+  int imon[13]; /* 1-12 ! */
+
+  for ( int i = 0; i < npar; i++ )
+    {
+      for ( int m = 0; m < 13; ++m ) imon[m] = 0;
+      season_to_months(parlist[i], imon);
+      if ( imon[month] ) { found = true; flaglist[i] = true;/* break;*/}
+    }
+
+  return found;
+}
+
+
+void par_check_int_flag(int npar, int *parlist, bool *flaglist, const char *txt)
 {
   for ( int i = 0; i < npar; ++i )
-    if ( flaglist[i] == FALSE )
+    if ( flaglist[i] == false )
       cdoWarning("%s >%d< not found!", txt, parlist[i]);
 }
 
 
-void par_check_flt_flag(int npar, double *parlist, int *flaglist, const char *txt)
+void par_check_flt_flag(int npar, double *parlist, bool *flaglist, const char *txt)
 {
   for ( int i = 0; i < npar; ++i )
-    if ( flaglist[i] == FALSE )
+    if ( flaglist[i] == false )
       cdoWarning("%s >%g< not found!", txt, parlist[i]);
 }
 
 
-void par_check_word_flag(int npar, char **parlist, int *flaglist, const char *txt)
+void par_check_word_flag(int npar, char **parlist, bool *flaglist, const char *txt)
 {
   for ( int i = 0; i < npar; ++i )
-    if ( flaglist[i] == FALSE )
+    if ( flaglist[i] == false )
       cdoWarning("%s >%s< not found!", txt, parlist[i]);
 }
 
@@ -487,36 +499,33 @@ int vlist_get_psvarid(int vlistID, int zaxisID)
       if ( cdoVerbose && psvarid == -1 )
         cdoWarning("Surface pressure variable not found - %s", psname);
     }
-  
+
   return psvarid;
 }
 
 
 void *Select(void *argument)
 {
+  bool lconstvars = true;
   int streamID2 = CDI_UNDEFID;
-  int tsID1, tsID2, nrecs;
+  int nrecs;
   int nvars, nvars2, nlevs;
-  int zaxisID, levID;
+  int zaxisID;
   int varID2, levelID2;
-  int recID, varID, levelID;
-  int iparam;
-  int vdate, vtime;
+  int varID, levelID;
   int last_year = -999999999;
   char paramstr[32];
   char varname[CDI_MAX_NAME];
   char stdname[CDI_MAX_NAME];
+  char gname[CDI_MAX_NAME];
+  char zname[CDI_MAX_NAME];
   int vlistID0 = -1, vlistID2 = -1;
-  int i;
   int result = FALSE;
-  int gridsize;
-  int nmiss;
   int taxisID2 = CDI_UNDEFID;
   int ntsteps;
-  int ltimsel = FALSE;
-  int second;
-  int npar;
-  int *vars = NULL;
+  bool ltimsel = false;
+  bool *vars = NULL;
+  double **vardata2 = NULL;
   double *array = NULL;
   double fstartdate = -99999999999.;
   double fenddate   = -99999999999.;
@@ -529,13 +538,19 @@ void *Select(void *argument)
   PML_DEF_INT(hour,               24, "Hour");
   PML_DEF_INT(minute,             60, "Minute");
   PML_DEF_INT(code,             1024, "Code number");
-  PML_DEF_INT(ltype,            1024, "Level type");
   PML_DEF_INT(levidx,           1024, "Level index");
+  PML_DEF_INT(ltype,             256, "Level type");
+  PML_DEF_INT(zaxisnum,          256, "Zaxis number");
+  PML_DEF_INT(gridnum,           256, "Grid number");
   PML_DEF_FLT(level,            1024, "Level");
   PML_DEF_WORD(name,            1024, "Variable name");
   PML_DEF_WORD(param,           1024, "Parameter");
+  PML_DEF_WORD(zaxisname,        256, "Zaxis name");
+  PML_DEF_WORD(gridname,         256, "Grid name");
+  PML_DEF_WORD(steptype,          32, "Time step type");
   PML_DEF_WORD(startdate,          1, "Start date");
   PML_DEF_WORD(enddate,            1, "End date");
+  PML_DEF_WORD(season,            12, "Season");
   PML_DEF_WORD(date,            1024, "Date");
 
   PML_INIT_INT(timestep_of_year);
@@ -546,22 +561,28 @@ void *Select(void *argument)
   PML_INIT_INT(hour);
   PML_INIT_INT(minute);
   PML_INIT_INT(code);
-  PML_INIT_INT(ltype);
   PML_INIT_INT(levidx);
+  PML_INIT_INT(ltype);
+  PML_INIT_INT(zaxisnum);
+  PML_INIT_INT(gridnum);
   PML_INIT_FLT(level);
   PML_INIT_WORD(name);
   PML_INIT_WORD(param);
+  PML_INIT_WORD(zaxisname);
+  PML_INIT_WORD(gridname);
+  PML_INIT_WORD(steptype);
   PML_INIT_WORD(startdate);
   PML_INIT_WORD(enddate);
+  PML_INIT_WORD(season);
   PML_INIT_WORD(date);
 
   cdoInitialize(argument);
 
-  int SELECT  = cdoOperatorAdd("select", 0, 0, "parameter list");
-  int DELETE  = cdoOperatorAdd("delete", 0, 0, "parameter list");
+  int SELECT = cdoOperatorAdd("select", 0, 0, "parameter list");
+  int DELETE = cdoOperatorAdd("delete", 0, 0, "parameter list");
 
-  int lcopy = FALSE;
-  if ( UNCHANGED_RECORD ) lcopy = TRUE;
+  bool lcopy = false;
+  if ( UNCHANGED_RECORD ) lcopy = true;
 
   int operatorID = cdoOperatorID();
 
@@ -571,7 +592,7 @@ void *Select(void *argument)
   char **argnames = operatorArgv();
 
   if ( cdoVerbose )
-    for ( i = 0; i < nsel; i++ )
+    for ( int i = 0; i < nsel; i++ )
       printf("name %d = %s\n", i+1, argnames[i]);
 
   pml_t *pml = pmlNew("SELECT");
@@ -584,13 +605,19 @@ void *Select(void *argument)
   PML_ADD_INT(pml, hour);
   PML_ADD_INT(pml, minute);
   PML_ADD_INT(pml, code);
-  PML_ADD_INT(pml, ltype);
   PML_ADD_INT(pml, levidx);
+  PML_ADD_INT(pml, ltype);
+  PML_ADD_INT(pml, zaxisnum);
+  PML_ADD_INT(pml, gridnum);
   PML_ADD_FLT(pml, level);
   PML_ADD_WORD(pml, name);
   PML_ADD_WORD(pml, param);
+  PML_ADD_WORD(pml, zaxisname);
+  PML_ADD_WORD(pml, gridname);
+  PML_ADD_WORD(pml, steptype);
   PML_ADD_WORD(pml, startdate);
   PML_ADD_WORD(pml, enddate);
+  PML_ADD_WORD(pml, season);
   PML_ADD_WORD(pml, date);
 
   pmlRead(pml, nsel, argnames);
@@ -605,24 +632,28 @@ void *Select(void *argument)
   PML_NUM(pml, hour);
   PML_NUM(pml, minute);
   PML_NUM(pml, code);
-  PML_NUM(pml, ltype);
   PML_NUM(pml, levidx);
+  PML_NUM(pml, ltype);
+  PML_NUM(pml, zaxisnum);
+  PML_NUM(pml, gridnum);
   PML_NUM(pml, level);
   PML_NUM(pml, name);
   PML_NUM(pml, param);
+  PML_NUM(pml, zaxisname);
+  PML_NUM(pml, gridname);
+  PML_NUM(pml, steptype);
   PML_NUM(pml, startdate);
   PML_NUM(pml, enddate);
+  PML_NUM(pml, season);
   PML_NUM(pml, date);
-  /*
-  pmlDelete(pml);
-  */
 
   int streamCnt = cdoStreamCnt();
   int nfiles = streamCnt - 1;
 
   if ( !cdoVerbose && nfiles > 1 ) progressInit();
 
-  tsID2 = 0;
+  timestep = 0;
+  int tsID2 = 0;
   for ( int indf = 0; indf < nfiles; indf++ )
     {
       if ( !cdoVerbose && nfiles > 1 ) progressStatus(0, 1, (indf+1.)/nfiles);
@@ -633,13 +664,15 @@ void *Select(void *argument)
       int vlistID1 = streamInqVlist(streamID1);
       int taxisID1 = vlistInqTaxis(vlistID1);
 
+      bool lcopy_const = false;
+
       if ( indf == 0 )
 	{
 	  // vlistID0 = vlistDuplicate(vlistID1);
 
 	  vlistClearFlag(vlistID1);
 	  nvars = vlistNvars(vlistID1);
-	  vars  = (int*) Malloc(nvars*sizeof(int));
+	  vars  = (bool*) Malloc(nvars*sizeof(bool));
 
 	  if ( operatorID == DELETE )
 	    {
@@ -648,7 +681,7 @@ void *Select(void *argument)
 		{
 		  zaxisID = vlistInqVarZaxis(vlistID1, varID);
 		  nlevs   = zaxisInqSize(zaxisID);
-		  for ( levID = 0; levID < nlevs; levID++ )
+		  for ( int levID = 0; levID < nlevs; levID++ )
 		    vlistDefFlag(vlistID1, varID, levID, TRUE);
 		}
 	    }
@@ -659,8 +692,8 @@ void *Select(void *argument)
 
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
-	      iparam  = vlistInqVarParam(vlistID1, varID);
-	      code    = vlistInqVarCode(vlistID1, varID);
+	      int iparam = vlistInqVarParam(vlistID1, varID);
+	      code = vlistInqVarCode(vlistID1, varID);
 	      vlistInqVarName(vlistID1, varID, varname);
 	      vlistInqVarStdname(vlistID1, varID, stdname);
 
@@ -669,60 +702,79 @@ void *Select(void *argument)
 	      name  = varname;
 	      param = paramstr;
 
+	      int gridID  = vlistInqVarGrid(vlistID1, varID);
 	      zaxisID = vlistInqVarZaxis(vlistID1, varID);
 	      nlevs   = zaxisInqSize(zaxisID);
 	      ltype   = zaxis2ltype(zaxisID);
 
-
-	      vars[varID] = FALSE;
+              zaxisnum = vlistZaxisIndex(vlistID1, zaxisID)+1;
+              int zaxistype = zaxisInqType(zaxisID);
+              zaxisName(zaxistype, zname);
+              zaxisname = zname;
+
+              gridnum = vlistGridIndex(vlistID1, gridID)+1;
+              int gridtype = gridInqType(gridID);
+              gridName(gridtype, gname);
+              gridname = gname;
+
+              int tsteptype = vlistInqVarTsteptype(vlistID1, varID);
+              if      ( tsteptype == TSTEP_CONSTANT ) steptype = "constant";
+              else if ( tsteptype == TSTEP_INSTANT  ) steptype = "instant";
+              else if ( tsteptype == TSTEP_INSTANT2 ) steptype = "instant";
+              else if ( tsteptype == TSTEP_INSTANT3 ) steptype = "instant";
+              else if ( tsteptype == TSTEP_MIN      ) steptype = "min";
+              else if ( tsteptype == TSTEP_MAX      ) steptype = "max";
+              else if ( tsteptype == TSTEP_AVG      ) steptype = "avg";
+              else if ( tsteptype == TSTEP_ACCUM    ) steptype = "accum";
+              else if ( tsteptype == TSTEP_RANGE    ) steptype = "range";
+              else if ( tsteptype == TSTEP_DIFF     ) steptype = "diff";
+              else                                    steptype = "unknown";
+              
+	      vars[varID] = false;
+              bool found_code  = npar_code      && PAR_CHECK_INT(code);
+              bool found_name  = npar_name      && PAR_CHECK_WORD(name);
+              bool found_param = npar_param     && PAR_CHECK_WORD(param);
+              bool found_grid  = npar_gridnum   && PAR_CHECK_INT(gridnum);
+              bool found_gname = npar_gridname  && PAR_CHECK_WORD(gridname);
+              bool found_stype = npar_steptype  && PAR_CHECK_WORD(steptype);
+              bool found_ltype = npar_ltype     && PAR_CHECK_INT(ltype);
+              bool found_zaxis = npar_zaxisnum  && PAR_CHECK_INT(zaxisnum);
+              bool found_zname = npar_zaxisname && PAR_CHECK_WORD(zaxisname);
+              bool lvar  = found_code || found_name || found_param;
+              bool lstep = npar_steptype ? found_stype : true;
+              bool lgrid = (npar_gridnum || npar_gridname) ? (found_grid || found_gname) : true;
+              bool lvert = (npar_ltype || npar_zaxisnum || npar_zaxisname) ? (found_ltype || found_zaxis || found_zname) : true;
 	      
-	      if ( npar_ltype )
-		{
-		  if ( !vars[varID] && npar_code  && PAR_CHECK_INT(ltype) && PAR_CHECK_INT(code) )   vars[varID] = TRUE;
-		  if ( !vars[varID] && npar_name  && PAR_CHECK_INT(ltype) && PAR_CHECK_WORD(name) )  vars[varID] = TRUE;
-		  if ( !vars[varID] && npar_param && PAR_CHECK_INT(ltype) && PAR_CHECK_WORD(param) ) vars[varID] = TRUE;
-		  if ( !vars[varID] && !npar_code && !npar_name && !npar_param )
-		    {
-		      if ( PAR_CHECK_INT(ltype) ) vars[varID] = TRUE;
-		      else
-			{
-			  for ( levID = 0; levID < nlevs; levID++ )
-			    {
-			      levidx = levID + 1;
-			      level = zaxisInqLevel(zaxisID, levID);
-			      if ( !vars[varID] && npar_levidx && PAR_CHECK_INT(ltype) && PAR_CHECK_INT(levidx) )  vars[varID] = TRUE;
-			      if ( !vars[varID] && npar_level  && PAR_CHECK_INT(ltype) && PAR_CHECK_FLT(level)  )  vars[varID] = TRUE;
-			    }
-			}
-		    }
-		}
-	      else
-		{
-		  if ( !vars[varID] && npar_code  && PAR_CHECK_INT(code) )   vars[varID] = TRUE;
-		  if ( !vars[varID] && npar_name  && PAR_CHECK_WORD(name) )  vars[varID] = TRUE;
-		  if ( !vars[varID] && npar_param && PAR_CHECK_WORD(param) ) vars[varID] = TRUE;
-		  if ( !vars[varID] && !npar_code && !npar_name && !npar_param )
-		    {
-		      for ( levID = 0; levID < nlevs; levID++ )
-			{
-			  levidx = levID + 1;
-			  level = zaxisInqLevel(zaxisID, levID);
-			  if ( !vars[varID] && npar_levidx && PAR_CHECK_INT(levidx) )  vars[varID] = TRUE;
-			  if ( !vars[varID] && npar_level  && PAR_CHECK_FLT(level)  )  vars[varID] = TRUE;
-			}
-		    }
-		}
+              if ( !vars[varID] && lgrid && lvar) vars[varID] = true;
+              if ( !vars[varID] && lvert && lvar) vars[varID] = true;
+              if ( !vars[varID] && lstep && lvar) vars[varID] = true;
+              if ( !vars[varID] && !lvar )
+                {
+                  if      ( found_grid || found_gname ) vars[varID] = true;
+                  else if ( found_stype ) vars[varID] = true;
+                  else if ( found_ltype || found_zaxis || found_zname ) vars[varID] = true;
+                  else if ( npar_levidx || npar_level )
+                    {
+                      for ( int levID = 0; levID < nlevs; levID++ )
+                        {
+                          levidx = levID + 1;
+                          level = zaxisInqLevel(zaxisID, levID);
+                          if ( !vars[varID] && npar_levidx && PAR_CHECK_INT(levidx) )  vars[varID] = true;
+                          if ( !vars[varID] && npar_level  && PAR_CHECK_FLT(level)  )  vars[varID] = true;
+                        }
+                    }
+                }
 	    }
 
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
 	      if ( vars[varID] )
 		{
-		  zaxisID = vlistInqVarZaxis(vlistID1, varID);
+		  int zaxisID = vlistInqVarZaxis(vlistID1, varID);
                   if ( zaxisInqType(zaxisID) == ZAXIS_HYBRID )
                     {
                       int psvarid = vlist_get_psvarid(vlistID1, zaxisID);
-                      if ( psvarid != -1 && !vars[psvarid] ) vars[psvarid] = TRUE;
+                      if ( psvarid != -1 && !vars[psvarid] ) vars[psvarid] = true;
                     }
                 }
             }
@@ -734,7 +786,7 @@ void *Select(void *argument)
 		  zaxisID = vlistInqVarZaxis(vlistID1, varID);
 		  nlevs   = zaxisInqSize(zaxisID);
 
-		  for ( levID = 0; levID < nlevs; levID++ )
+		  for ( int levID = 0; levID < nlevs; levID++ )
 		    {
 		      levidx = levID + 1;
 		      level = zaxisInqLevel(zaxisID, levID);
@@ -765,38 +817,45 @@ void *Select(void *argument)
 	    }
 
 	  PAR_CHECK_INT_FLAG(code);
-	  PAR_CHECK_INT_FLAG(ltype);
 	  PAR_CHECK_INT_FLAG(levidx);
+	  PAR_CHECK_INT_FLAG(ltype);
+	  PAR_CHECK_INT_FLAG(zaxisnum);
+	  PAR_CHECK_INT_FLAG(gridnum);
 	  PAR_CHECK_FLT_FLAG(level);
 	  PAR_CHECK_WORD_FLAG(name);
 	  PAR_CHECK_WORD_FLAG(param);
+	  PAR_CHECK_WORD_FLAG(zaxisname);
+	  PAR_CHECK_WORD_FLAG(gridname);
+	  PAR_CHECK_WORD_FLAG(steptype);
 
-	  if ( npar_date || npar_startdate || npar_enddate ) ltimsel = TRUE;
-	  if ( npar_timestep_of_year || npar_timestep || npar_year || npar_month || npar_day || npar_hour || npar_minute ) ltimsel = TRUE;
+	  if ( npar_date || npar_startdate || npar_enddate || npar_season ) ltimsel = true;
+	  if ( npar_timestep_of_year || npar_timestep || npar_year || npar_month || npar_day || npar_hour || npar_minute ) ltimsel = true;
 
-	  npar = 0;
+	  int npar = 0;
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
 	      zaxisID = vlistInqVarZaxis(vlistID1, varID);
 	      nlevs   = zaxisInqSize(zaxisID);
-
-	      for ( levID = 0; levID < nlevs; levID++ )
-		if ( vlistInqFlag(vlistID1, varID, levID) == result ) break;
-	      
-	      if ( levID < nlevs ) npar++;
+	      for ( int levID = 0; levID < nlevs; levID++ )
+		if ( vlistInqFlag(vlistID1, varID, levID) == result )
+                  {
+                    npar++;
+                    break;
+                  }
 	    }
 
 	  if ( npar == 0 )
 	    {
-	      if ( ltimsel == TRUE )
+	      if ( ltimsel == true )
 		{
+                  lcopy_const = true;
+
 		  for ( varID = 0; varID < nvars; varID++ )
 		    {
-		      vars[varID] = TRUE;
+		      vars[varID] = true;
 		      zaxisID = vlistInqVarZaxis(vlistID1, varID);
 		      nlevs   = zaxisInqSize(zaxisID);
-
-		      for ( levID = 0; levID < nlevs; levID++ )
+		      for ( int levID = 0; levID < nlevs; levID++ )
 			vlistDefFlag(vlistID1, varID, levID, TRUE);
 		    }
 		}
@@ -813,7 +872,7 @@ void *Select(void *argument)
 	    {
 	      zaxisID = vlistInqVarZaxis(vlistID1, varID);
 	      nlevs   = zaxisInqSize(zaxisID);
-	      for ( levID = 0; levID < nlevs; levID++ )
+	      for ( int levID = 0; levID < nlevs; levID++ )
 		vlistDefFlag(vlistID0, varID, levID, vlistInqFlag(vlistID1, varID, levID));
 	    }
 
@@ -845,15 +904,16 @@ void *Select(void *argument)
 	  if ( ntsteps2 == 0 || ntsteps2 == 1 ) vlistDefNtsteps(vlistID2, ntsteps2);
 
 	  if ( ntsteps2 == 0 && nfiles > 1 )
-	    {	      
+	    {
+              lconstvars = false;
 	      for ( varID = 0; varID < nvars2; ++varID )
 		vlistDefVarTsteptype(vlistID2, varID, TSTEP_INSTANT);
 	    }
 
-	  /* add support for negative timestep values */
+	  // support for negative timestep values
 	  if ( npar_timestep > 0 && ntsteps > 0 && nfiles == 1 )
 	    {
-	      for ( i = 0; i < npar_timestep; i++ )
+	      for ( int i = 0; i < npar_timestep; i++ )
 		{
 		  if ( par_timestep[i] < 0 )
 		    {
@@ -866,7 +926,7 @@ void *Select(void *argument)
 
 	  if ( ! lcopy )
 	    {
-	      gridsize = vlistGridsizeMax(vlistID1);
+	      int gridsize = vlistGridsizeMax(vlistID1);
 	      if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
 	      array = (double*) Malloc(gridsize*sizeof(double));
 	    }
@@ -888,28 +948,35 @@ void *Select(void *argument)
 	  goto END_LABEL;
 	}
 
-      int lstop = FALSE;
-      tsID1 = 0;
+      if ( lcopy_const )
+        {
+          vardata2 = (double**) malloc(nvars2*sizeof(double));
+          for ( varID = 0; varID < nvars2; ++varID ) vardata2[varID] = NULL;
+        }
+
+      bool lstop = false;
+      int tsID1 = 0;
       while ( (nrecs = streamInqTimestep(streamID1, tsID1)) )
 	{
-	  int copytimestep = TRUE;
+          timestep++;
+	  bool copytimestep = true;
 
-	  if ( ltimsel == TRUE )
+	  if ( ltimsel == true )
 	    {
-	      copytimestep = FALSE;
-	      timestep = tsID1 + 1;
+	      copytimestep = false;
 
 	      if ( operatorID == SELECT && npar_timestep > 0 && timestep > par_timestep[npar_timestep-1] )
 		{
-		  lstop = TRUE;
+		  lstop = true;
 		  break;
 		}
 
-	      vdate = taxisInqVdate(taxisID1);
-	      vtime = taxisInqVtime(taxisID1);
-
+	      int vdate = taxisInqVdate(taxisID1);
+	      int vtime = taxisInqVtime(taxisID1);
+              int second;
 	      cdiDecodeDate(vdate, &year, &month, &day);
 	      cdiDecodeTime(vtime, &hour, &minute, &second);
+              UNUSED(season);
 
 	      if ( year != last_year )
 		{
@@ -919,20 +986,21 @@ void *Select(void *argument)
 
 	      timestep_of_year++;
 
-	      if ( npar_timestep && PAR_CHECK_INT(timestep) ) copytimestep = TRUE;
-	      if ( npar_timestep_of_year && PAR_CHECK_INT(timestep_of_year) ) copytimestep = TRUE;
+	      if ( npar_timestep && PAR_CHECK_INT(timestep) ) copytimestep = true;
+	      if ( npar_timestep_of_year && PAR_CHECK_INT(timestep_of_year) ) copytimestep = true;
 
 	      if ( !copytimestep && npar_date == 0 && npar_timestep == 0 && npar_timestep_of_year == 0 )
 		{
-		  int lyear = 0, lmonth = 0, lday = 0, lhour = 0, lminute = 0;
+		  bool lseason = false, lyear = false, lmonth = false, lday = false, lhour = false, lminute = false;
 
-		  if ( npar_year   == 0 || (npar_year   && PAR_CHECK_INT(year))   ) lyear   = TRUE;
-		  if ( npar_month  == 0 || (npar_month  && PAR_CHECK_INT(month))  ) lmonth  = TRUE;
-		  if ( npar_day    == 0 || (npar_day    && PAR_CHECK_INT(day))    ) lday    = TRUE;
-		  if ( npar_hour   == 0 || (npar_hour   && PAR_CHECK_INT(hour))   ) lhour   = TRUE;
-		  if ( npar_minute == 0 || (npar_minute && PAR_CHECK_INT(minute)) ) lminute = TRUE;
+		  if ( npar_season == 0 || (npar_season && PAR_CHECK_SEASON(season, month)) ) lseason   = true;
+		  if ( npar_year   == 0 || (npar_year   && PAR_CHECK_INT(year))   ) lyear   = true;
+		  if ( npar_month  == 0 || (npar_month  && PAR_CHECK_INT(month))  ) lmonth  = true;
+		  if ( npar_day    == 0 || (npar_day    && PAR_CHECK_INT(day))    ) lday    = true;
+		  if ( npar_hour   == 0 || (npar_hour   && PAR_CHECK_INT(hour))   ) lhour   = true;
+		  if ( npar_minute == 0 || (npar_minute && PAR_CHECK_INT(minute)) ) lminute = true;
 
-		  if ( lyear && lmonth && lday && lhour && lminute ) copytimestep = TRUE;
+		  if ( lseason && lyear && lmonth && lday && lhour && lminute ) copytimestep = true;
 		}
 
 	      double fdate = ((double)vdate) + ((double)vtime)/1000000.;
@@ -941,17 +1009,17 @@ void *Select(void *argument)
 		{
 		  if ( fdate > fenddate )
 		    {
-		      flag_enddate[0] = TRUE;
-		      copytimestep = FALSE;
+		      flag_enddate[0] = true;
+		      copytimestep = false;
 		      if ( operatorID == SELECT )
 			{
-			  lstop = TRUE;
+			  lstop = true;
 			  break;
 			}
 		    }
 		  else
 		    {
-		      copytimestep = TRUE;
+		      copytimestep = true;
 		    }
 		}
 
@@ -959,12 +1027,12 @@ void *Select(void *argument)
 		{
 		  if ( fdate < fstartdate )
 		    {
-		      copytimestep = FALSE;
+		      copytimestep = false;
 		    }
 		  else
 		    {
-		      flag_startdate[0] = TRUE;
-		      copytimestep = TRUE;
+		      flag_startdate[0] = true;
+		      copytimestep = true;
 		    }
 		}
 
@@ -974,30 +1042,57 @@ void *Select(void *argument)
                   char vdatetimestr[64];
                   datetime2str(vdate, vtime, vdatetimestr, sizeof(vdatetimestr));
                   date = vdatetimestr;
-                  if ( PAR_CHECK_DATE(date) ) copytimestep = TRUE;
+                  if ( PAR_CHECK_DATE(date) ) copytimestep = true;
                 }
 
 	      if ( operatorID == DELETE ) copytimestep = !copytimestep;
+
+              if ( copytimestep && indf == 0 && tsID1 == 0 ) lcopy_const = false;
 	    }
 
-	  if ( copytimestep == TRUE )
+	  if ( copytimestep == true )
 	    {
 	      if ( streamID2 == CDI_UNDEFID )
 		{
 		  streamID2 = streamOpenWrite(cdoStreamName(nfiles), cdoFiletype());
-
 		  streamDefVlist(streamID2, vlistID2);
 		}
 
 	      taxisCopyTimestep(taxisID2, taxisID1);
-
 	      streamDefTimestep(streamID2, tsID2);
-     
-	      for ( recID = 0; recID < nrecs; recID++ )
+
+              if ( lcopy_const && tsID2 == 0 )
+                {
+                  for ( varID2 = 0; varID2 < nvars2; ++varID2 )
+                    {
+                      if ( vardata2[varID2] )
+                        {
+                          double missval = vlistInqVarMissval(vlistID2, varID2);
+                          int gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID2));
+                          int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID2));
+                          for ( int levelID2 = 0; levelID2 < nlevel; ++levelID2 )
+                            {
+                              double *pdata = vardata2[varID2]+gridsize*levelID;
+                              int nmiss = 0;
+                              for ( int i = 0; i < gridsize; ++i )
+                                if ( DBL_IS_EQUAL(pdata[i], missval) ) nmiss++;
+
+                              streamDefRecord(streamID2, varID2, levelID2);
+                              streamWriteRecord(streamID2, pdata, nmiss);
+                            }
+                        }
+                    }
+                }
+              
+	      for ( int recID = 0; recID < nrecs; recID++ )
 		{
 		  streamInqRecord(streamID1, &varID, &levelID);
 		  if ( vlistInqFlag(vlistID0, varID, levelID) == TRUE )
 		    {
+                      if ( lconstvars && tsID2 > 0 && tsID1 == 0 )
+                        if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT )
+                          continue;
+
 		      varID2   = vlistFindVar(vlistID2, varID);
 		      levelID2 = vlistFindLevel(vlistID2, varID, levelID);
 		      
@@ -1008,13 +1103,38 @@ void *Select(void *argument)
 			}
 		      else
 			{
+                          int nmiss;
 			  streamReadRecord(streamID1, array, &nmiss);
 			  streamWriteRecord(streamID2, array, nmiss);
 			}
 		    }
 		}
-	      tsID2++;
+
+	      tsID2++;              
 	    }
+          else if ( lcopy_const && indf == 0 && tsID1 == 0 )
+            {
+	      for ( int recID = 0; recID < nrecs; recID++ )
+		{
+		  streamInqRecord(streamID1, &varID, &levelID);
+		  if ( vlistInqFlag(vlistID0, varID, levelID) == TRUE )
+		    {
+		      varID2 = vlistFindVar(vlistID2, varID);
+                      if ( vlistInqVarTsteptype(vlistID2, varID2) == TSTEP_CONSTANT )
+                        {
+                          levelID2 = vlistFindLevel(vlistID2, varID, levelID);
+                          int gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID2));
+                          if ( levelID == 0 )
+                            {
+                              int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID2));
+                              vardata2[varID2] = (double*) malloc(gridsize*nlevel*sizeof(double));
+                            }
+                          int nmiss;
+                          streamReadRecord(streamID1, vardata2[varID2]+gridsize*levelID, &nmiss);
+                        }
+		    }
+		}
+            }
 
 	  tsID1++;
 	}
@@ -1038,6 +1158,7 @@ void *Select(void *argument)
   PAR_CHECK_WORD_FLAG(startdate);
   UNUSED(str_enddate);
   //  PAR_CHECK_WORD_FLAG(enddate);
+  PAR_CHECK_WORD_FLAG(season);
   PAR_CHECK_WORD_FLAG(date);
 
   if ( streamID2 != CDI_UNDEFID ) streamClose(streamID2);
@@ -1049,10 +1170,17 @@ void *Select(void *argument)
 
   if ( array ) Free(array);
   if ( vars ) Free(vars);
+  if ( vardata2 )
+    {
+      for ( varID = 0; varID < nvars2; ++ varID )
+        if ( vardata2[varID] ) free(vardata2[varID]);
+
+      free(vardata2);
+    }
 
   if ( tsID2 == 0 ) cdoAbort("No timesteps selected!");
 
   cdoFinish();
 
-  return (NULL);
+  return 0;
 }
diff --git a/src/Seloperator.c b/src/Seloperator.c
index 7cab6cb..bc871d2 100644
--- a/src/Seloperator.c
+++ b/src/Seloperator.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Selrec.c b/src/Selrec.c
index 862d3ed..43b819c 100644
--- a/src/Selrec.c
+++ b/src/Selrec.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -64,7 +64,7 @@ void *Selrec(void *argument)
   filetype = streamInqFiletype(streamID1);
 
   if ( filetype == FILETYPE_NC || filetype == FILETYPE_NC2 || filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C )
-    cdoAbort("This operator does not work on netCDF data!");
+    cdoAbort("This operator does not work on NetCDF data!");
 
   vlistID1 = streamInqVlist(streamID1);
   vlistID2 = vlistDuplicate(vlistID1);
@@ -112,5 +112,5 @@ void *Selrec(void *argument)
 
   cdoFinish();
 
-  return (NULL);
+  return 0;
 }
diff --git a/src/Seltime.c b/src/Seltime.c
index eb7fa9b..30fd852 100644
--- a/src/Seltime.c
+++ b/src/Seltime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -22,9 +22,9 @@
       Seltime    seltime         Select times
       Seltime    selhour         Select hours
       Seltime    selday          Select days
-      Seltime    selmon          Select months
+      Seltime    selmonth        Select months
       Seltime    selyear         Select years
-      Seltime    selseas         Select seasons
+      Seltime    selseason       Select seasons
       Seltime    seldate         Select dates
       Seltime    selsmon         Select single month
 */
@@ -40,77 +40,58 @@
 #include "list.h"
 
 
+void season_to_months(const char *season, int *imonths)
+{
+  const char *smons = "JFMAMJJASONDJFMAMJJASOND";
+  const int imons[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+  assert(strlen(smons)==(sizeof(imons)/sizeof(int)));
+
+  size_t len = strlen(season);
+  if ( len == 3 && strcmp(season, "ANN") == 0 )
+    {
+      for ( size_t k = 0; k < 12; ++k ) imonths[k+1] = 1;
+    }
+  else
+    {
+      if ( len > 12 ) cdoAbort("Too many months %d (limit=12)!", (int)len);
+      //      char *sstr = strcasestr(smons, season); // nonstandard extension
+      const char *sstr = strstr(smons, season);
+      if ( sstr == NULL ) cdoAbort("Season %s not available!", season);
+      size_t ks = (size_t)(sstr-smons);
+      size_t ke = ks + len;
+      for ( size_t k = ks; k < ke; ++k ) imonths[imons[k]]++;
+    }
+}
+
 static
 int seaslist(LIST *ilist)
 {
-  int i;
-  char Seas[3];
-  int seas[4] = {FALSE, FALSE, FALSE, FALSE};
-  int imon[17]; /* 1-16 ! */
-  int ival;
-  size_t len;
-
-  int season_start = get_season_start();
+  int imon[13]; /* 1-12 ! */
+  for ( int i = 0; i < 13; ++i ) imon[i] = 0;
+
   int nsel = operatorArgc();
   if ( isdigit(*operatorArgv()[0]))
-    for ( i = 0; i < nsel; i++ )
-      {
-	ival = parameter2int(operatorArgv()[i]);
-	if      ( ival == 1 || ival == 13 ) seas[0] = TRUE;
-	else if ( ival == 2 || ival == 14 ) seas[1] = TRUE;
-	else if ( ival == 3 || ival == 15 ) seas[2] = TRUE;
-	else if ( ival == 4 || ival == 16 ) seas[3] = TRUE;
-	else cdoAbort("Season %d not available!", ival);
-      }
-  else
-    for ( i = 0; i < nsel; i++ )
-      {
-	len = strlen(operatorArgv()[i]);
-	if ( len > 3 ) len = 3;
-	while ( len-- > 0 ) Seas[len] = toupper(operatorArgv()[i][len]);
-	if ( season_start == START_DEC )
-	  {
-	    if      ( memcmp(Seas, "DJF", 3) == 0 ) seas[0] = TRUE;
-	    else if ( memcmp(Seas, "MAM", 3) == 0 ) seas[1] = TRUE;
-	    else if ( memcmp(Seas, "JJA", 3) == 0 ) seas[2] = TRUE;
-	    else if ( memcmp(Seas, "SON", 3) == 0 ) seas[3] = TRUE;
-	    else cdoAbort("Season %s not available!", operatorArgv()[i]);
-	  }
-	else
-	  {
-	    if      ( memcmp(Seas, "JFM", 3) == 0 ) seas[0] = TRUE;
-	    else if ( memcmp(Seas, "AMJ", 3) == 0 ) seas[1] = TRUE;
-	    else if ( memcmp(Seas, "JAS", 3) == 0 ) seas[2] = TRUE;
-	    else if ( memcmp(Seas, "OND", 3) == 0 ) seas[3] = TRUE;
-	    else cdoAbort("Season %s not available!", operatorArgv()[i]);
-	  }
-      }
-  
-  for ( i = 0; i < 17; ++i ) imon[i] = 0;
-  
-  if ( season_start == START_DEC )
     {
-      if ( seas[0] ) { imon[12]++; imon[ 1]++; imon[ 2]++; imon[13]++; }
-      if ( seas[1] ) { imon[ 3]++; imon[ 4]++; imon[ 5]++; imon[14]++; }
-      if ( seas[2] ) { imon[ 6]++; imon[ 7]++; imon[ 8]++; imon[15]++; }
-      if ( seas[3] ) { imon[ 9]++; imon[10]++; imon[11]++; imon[16]++; }
+      for ( int i = 0; i < nsel; i++ )
+        {
+          int ival = parameter2int(operatorArgv()[i]);
+          if      ( ival == 1 ) { imon[12]++; imon[ 1]++; imon[ 2]++; }
+          else if ( ival == 2 ) { imon[ 3]++; imon[ 4]++; imon[ 5]++; }
+          else if ( ival == 3 ) { imon[ 6]++; imon[ 7]++; imon[ 8]++; }
+          else if ( ival == 4 ) { imon[ 9]++; imon[10]++; imon[11]++; }
+          else cdoAbort("Season %d not available!", ival);
+        }
     }
   else
     {
-      if ( seas[0] ) { imon[ 1]++; imon[ 2]++; imon[ 3]++; imon[13]++; }
-      if ( seas[1] ) { imon[ 4]++; imon[ 5]++; imon[ 6]++; imon[14]++; }
-      if ( seas[2] ) { imon[ 7]++; imon[ 8]++; imon[ 9]++; imon[15]++; }
-      if ( seas[3] ) { imon[10]++; imon[11]++; imon[12]++; imon[16]++; }
+      for ( int i = 0; i < nsel; i++ )
+        season_to_months(operatorArgv()[i], imon);
     }
-  
+
   nsel = 0;
-  for ( i = 1; i < 17; ++i )
-    {
-      if ( imon[i] )
-	listSetInt(ilist, nsel++, i);
-    }
+  for ( int i = 1; i < 13; ++i ) if ( imon[i] ) listSetInt(ilist, nsel++, i);
 
-  return (nsel);
+  return nsel;
 }
 
 
@@ -223,9 +204,9 @@ void *Seltime(void *argument)
   int SELTIME     = cdoOperatorAdd("seltime",     func_time,     0, "times (format hh:mm:ss)");
   int SELHOUR     = cdoOperatorAdd("selhour",     func_time,     0, "hours");
   int SELDAY      = cdoOperatorAdd("selday",      func_date,     0, "days");
-  int SELMON      = cdoOperatorAdd("selmon",      func_date,     0, "months");
+  int SELMONTH    = cdoOperatorAdd("selmonth",    func_date,     0, "months");
   int SELYEAR     = cdoOperatorAdd("selyear",     func_date,     0, "years");
-  int SELSEAS     = cdoOperatorAdd("selseas",     func_date,     0, "seasons");
+  int SELSEASON   = cdoOperatorAdd("selseason",   func_date,     0, "seasons");
   int SELSMON     = cdoOperatorAdd("selsmon",     func_date,     0, "month[,nts1[,nts2]]");
 
   int operatorID = cdoOperatorID();
@@ -237,7 +218,7 @@ void *Seltime(void *argument)
 
   operatorInputArg(cdoOperatorEnter(operatorID));
 
-  if ( operatorID == SELSEAS )
+  if ( operatorID == SELSEASON )
     {
       nsel = seaslist(ilist);
     }
@@ -421,6 +402,10 @@ void *Seltime(void *argument)
 	      selfound[0]      = TRUE;
 	      selfound[nsel-1] = TRUE;
 	    }
+          else if ( selfval > fltarr[nsel-1] )
+            {
+              break;
+            }
 	}
       else
 	{
@@ -603,8 +588,7 @@ void *Seltime(void *argument)
     if ( its2 < nts2 )
       cdoWarning("%d timesteps missing after the last month!", nts2-its2);
 
-  if ( ! lcopy )
-    if ( array ) Free(array);
+  if ( array ) Free(array);
 
   for ( isel = 0; isel < nsel; isel++ )
     {
@@ -652,7 +636,7 @@ void *Seltime(void *argument)
 	    {
 	      cdoWarning("Day %d not found!", intarr[isel]);
 	    }
-	  else if ( operatorID == SELMON )
+	  else if ( operatorID == SELMONTH )
 	    {
 	      cdoWarning("Month %d not found!", intarr[isel]);
 	    }
@@ -660,7 +644,7 @@ void *Seltime(void *argument)
 	    {
 	      cdoWarning("Year %d not found!", intarr[isel]);
 	    }
-	  else if ( operatorID == SELSEAS )
+	  else if ( operatorID == SELSEASON )
 	    {
 	      if ( isel < 3 )
 		cdoWarning("Month %d not found!", intarr[isel]);
@@ -687,5 +671,5 @@ void *Seltime(void *argument)
 
   cdoFinish();
 
-  return (NULL);
+  return 0;
 }
diff --git a/src/Selvar.c b/src/Selvar.c
index f0fd924..7cfb7a8 100644
--- a/src/Selvar.c
+++ b/src/Selvar.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -144,6 +144,7 @@ void *Selvar(void *argument)
 
   int vlistID1 = streamInqVlist(streamID1);
   int nvars = vlistNvars(vlistID1);
+  int *vars = (int*) Malloc(nvars*sizeof(int));
 
   if ( operatorID == SELGRID && !args_are_numeric && nsel == 1 && strncmp(argnames[0], "var=", 4) == 0 )
     {
@@ -170,6 +171,8 @@ void *Selvar(void *argument)
   vlistClearFlag(vlistID1);
   for ( varID = 0; varID < nvars; varID++ )
     {
+      vars[varID] = FALSE;
+
       vlistInqVarName(vlistID1, varID, varname);
       vlistInqVarStdname(vlistID1, varID, stdname);
       param    = vlistInqVarParam(vlistID1, varID);
@@ -210,7 +213,7 @@ void *Selvar(void *argument)
 		}
 	      else if ( operatorID == SELSTDNAME )
 		{
-		  found = strcmp(argnames[isel], stdname) == 0;
+		  found = wildcardmatch(argnames[isel], stdname) == 0;
 		}
 	      else if ( operatorID == SELLEVEL )
 		{
@@ -265,22 +268,30 @@ void *Selvar(void *argument)
 	        {
 		  vlistDefFlag(vlistID1, varID, levID, !INVERTS_SELECTION(operatorID));
 		  selfound[isel] = TRUE;
+                  vars[varID] = TRUE;
 	        }
-
 	    }
 	}
     }
 
   int npar = 0;
+  for ( varID = 0; varID < nvars; varID++ ) if ( vars[varID] ) npar++;
+
   for ( varID = 0; varID < nvars; varID++ )
     {
-      zaxisID = vlistInqVarZaxis(vlistID1, varID);
-      nlevs   = zaxisInqSize(zaxisID);
-
-      for ( levID = 0; levID < nlevs; levID++ )
-	if ( vlistInqFlag(vlistID1, varID, levID) == TRUE ) break;
-	      
-      if ( levID < nlevs ) npar++;
+      if ( vars[varID] )
+        {
+          int zaxisID = vlistInqVarZaxis(vlistID1, varID);
+          if ( zaxisInqType(zaxisID) == ZAXIS_HYBRID )
+            {
+              int psvarid = vlist_get_psvarid(vlistID1, zaxisID);
+              if ( psvarid != -1 && !vars[psvarid] )
+                {
+                  vars[psvarid] = TRUE;
+                  vlistDefFlag(vlistID1, psvarid, 0, !INVERTS_SELECTION(operatorID));
+                }
+            }
+        }
     }
 
   for ( isel = 0; isel < nsel; isel++ )
@@ -408,6 +419,8 @@ void *Selvar(void *argument)
   if ( ! lcopy )
     if ( array ) Free(array);
 
+  if ( vars ) Free(vars);
+
   if ( selfound ) Free(selfound);
 
   listDelete(ilist);
@@ -415,5 +428,5 @@ void *Selvar(void *argument)
 
   cdoFinish();
 
-  return (NULL);
+  return 0;
 }
diff --git a/src/Set.c b/src/Set.c
index bb90b0b..dbfeca3 100644
--- a/src/Set.c
+++ b/src/Set.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Setbox.c b/src/Setbox.c
index d5cb8b3..bd1538f 100644
--- a/src/Setbox.c
+++ b/src/Setbox.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Setgatt.c b/src/Setgatt.c
index 27573bc..bab54ae 100644
--- a/src/Setgatt.c
+++ b/src/Setgatt.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Setgrid.c b/src/Setgrid.c
index ff1a1f2..b02fce6 100644
--- a/src/Setgrid.c
+++ b/src/Setgrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Sethalo.c b/src/Sethalo.c
index 7b55569..9c8c0c1 100644
--- a/src/Sethalo.c
+++ b/src/Sethalo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Setmiss.c b/src/Setmiss.c
index 8328734..a1f15e9 100644
--- a/src/Setmiss.c
+++ b/src/Setmiss.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Setpartab.c b/src/Setpartab.c
index fdabb6e..6915c5f 100644
--- a/src/Setpartab.c
+++ b/src/Setpartab.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -598,8 +598,7 @@ void check_data(int vlistID2, int varID2, int varID, var_t *vars, long gridsize,
 void *Setpartab(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
-  int varID2, levelID2;
+  int varID, levelID;
   int nmiss;
   int delvars = FALSE;
   int tableID = -1;
@@ -681,31 +680,54 @@ void *Setpartab(void *argument)
 
   if ( tableformat == 0 )
     {
-      for ( varID = 0; varID < nvars; varID++ )
-	vlistDefVarTable(vlistID2, varID, tableID);
+      /*
+        for ( int varID = 0; varID < nvars; varID++ )
+	  vlistDefVarTable(vlistID2, varID, tableID);
+      */
+      char name[CDI_MAX_NAME], longname[CDI_MAX_NAME], units[CDI_MAX_NAME];
+      for ( int varID = 0; varID < nvars; varID++ )
+        {
+          int param = vlistInqVarParam(vlistID2, varID);
+          int pdis, pcat, pnum;
+          cdiDecodeParam(param, &pnum, &pcat, &pdis);
+          if ( pdis == 255 )
+            {
+              int code = pnum;
+              if ( tableInqParName(tableID, code, name) == 0 )
+                {
+                  vlistDefVarName(vlistID2, varID, name);
+                  longname[0] = 0;
+                  tableInqParLongname(tableID, code, longname);
+                  vlistDefVarLongname(vlistID2, varID, longname);
+                  units[0] = 0;
+                  tableInqParUnits(tableID, code, units);
+                  vlistDefVarUnits(vlistID2, varID, units);
+                }
+            }
+          vlistDefVarTable(vlistID2, varID, tableID);
+        }
     }
   else
     {
       read_partab(ptmode, nvars, vlistID2, vars);
 
-      for ( varID = 0; varID < nvars; ++varID )
-	if ( vars[varID].remove ) break;
-
-      if ( varID < nvars ) delvars = TRUE;
+      for ( int varID = 0; varID < nvars; ++varID )
+	if ( vars[varID].remove )
+          {
+            delvars = TRUE;
+            break;
+          }
 
       if ( delvars )
 	{
-	  int levID, nlevs, zaxisID;
-	  int vlistIDx;
-
 	  vlistClearFlag(vlistID1);
 	  vlistClearFlag(vlistID2);
 
-	  for ( varID = 0; varID < nvars; varID++ )
+	  for ( int varID = 0; varID < nvars; varID++ )
 	    {
-	      zaxisID  = vlistInqVarZaxis(vlistID2, varID);
-	      nlevs    = zaxisInqSize(zaxisID);
-	      for ( levID = 0; levID < nlevs; levID++ )
+	      int zaxisID = vlistInqVarZaxis(vlistID2, varID);
+	      int nlevs   = zaxisInqSize(zaxisID);
+	      for ( int levID = 0; levID < nlevs; levID++ )
 		{
 		  vlistDefFlag(vlistID1, varID, levID, TRUE);
 		  vlistDefFlag(vlistID2, varID, levID, TRUE);
@@ -717,7 +739,7 @@ void *Setpartab(void *argument)
 		}
 	    }
 
-	  vlistIDx = vlistCreate();
+	  int vlistIDx = vlistCreate();
 	  vlistCopyFlag(vlistIDx, vlistID2);
 
 	  vlistDestroy(vlistID2);
@@ -725,7 +747,7 @@ void *Setpartab(void *argument)
 	  vlistID2 = vlistIDx;
 	}
 
-      for ( varID = 0; varID < nvars; ++varID )
+      for ( int varID = 0; varID < nvars; ++varID )
 	convertVarUnits(vars, varID, vars[varID].name);
     }
 
@@ -749,12 +771,12 @@ void *Setpartab(void *argument)
 
       streamDefTimestep(streamID2, tsID1);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
-	  varID2 = varID;
-	  levelID2 = levelID;
+	  int varID2 = varID;
+	  int levelID2 = levelID;
 
 	  if ( delvars )
 	    {
@@ -826,7 +848,7 @@ void *Setpartab(void *argument)
 #if defined(HAVE_UDUNITS2)
   UDUNITS_LOCK();
 
-  for ( varID = 0; varID < nvars; varID++ )
+  for ( int varID = 0; varID < nvars; varID++ )
     if ( vars[varID].ut_converter ) cv_free((cv_converter*)vars[varID].ut_converter);
 
   if ( ut_read )
diff --git a/src/Setrcaname.c b/src/Setrcaname.c
index d7d4407..79b7b75 100644
--- a/src/Setrcaname.c
+++ b/src/Setrcaname.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Settime.c b/src/Settime.c
index f6fe1e7..81a873b 100644
--- a/src/Settime.c
+++ b/src/Settime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -35,6 +35,7 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "calendar.h"
 #include "pstream.h"
 
 
@@ -113,7 +114,7 @@ void *Settime(void *argument)
   int nmiss;
   int gridsize;
   int tunit = TUNIT_DAY;
-  int ijulinc = 0, incperiod = 0, incunit = 0;
+  int ijulinc = 0, incperiod = 1, incunit = 86400;
   int year = 1, month = 1, day = 1, hour = 0, minute = 0, second = 0;
   int day0;
   int taxis_has_bounds, copy_timestep = FALSE;
@@ -174,10 +175,13 @@ void *Settime(void *argument)
       if ( operatorArgc() == 3 )
 	{
 	  const char *timeunits = operatorArgv()[2];
-	  incperiod = (int)strtol(timeunits, NULL, 10);
-	  if ( timeunits[0] == '-' || timeunits[0] == '+' ) timeunits++;
-	  while ( isdigit((int) *timeunits) ) timeunits++;
-
+          int ich = timeunits[0];
+          if ( ich == '-' || ich == '+' || isdigit(ich) )
+            {
+              incperiod = (int)strtol(timeunits, NULL, 10);
+              if ( ich == '-' || ich == '+' ) timeunits++;
+              while ( isdigit((int) *timeunits) ) timeunits++;
+            }
 	  get_tunits(timeunits, &incperiod, &incunit, &tunit);
 	}
       /* increment in seconds */
diff --git a/src/Setzaxis.c b/src/Setzaxis.c
index 2f94240..0adcc29 100644
--- a/src/Setzaxis.c
+++ b/src/Setzaxis.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Showinfo.c b/src/Showinfo.c
index e1a804c..b62d2c9 100644
--- a/src/Showinfo.c
+++ b/src/Showinfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Sinfo.c b/src/Sinfo.c
index bea40a0..9762015 100644
--- a/src/Sinfo.c
+++ b/src/Sinfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,7 @@
 #include "pstream.h"
 #include "util.h"
 
+#include "cdi_uuid.h"
 #include "printinfo.h"
 
 const char *tunit2str(int tunits)
@@ -127,11 +128,11 @@ void *Sinfo(void *argument)
 
       set_text_color(stdout, BRIGHT, BLACK);
       if ( lensemble )
-	fprintf(stdout, "%6d : Institut Source   Ttype    Einfo Levels Num    Points Num Dtype : ",  -(indf+1));
+	fprintf(stdout, "%6d : Institut Source   Steptype Einfo Levels Num    Points Num Dtype : ",  -(indf+1));
       else if ( nsubtypes > 0 )
-	fprintf(stdout, "%6d : Institut Source   Ttype    Subtypes Levels Num    Points Num Dtype : ",  -(indf+1));
+	fprintf(stdout, "%6d : Institut Source   Steptype Subtypes Levels Num    Points Num Dtype : ",  -(indf+1));
       else
-	fprintf(stdout, "%6d : Institut Source   Ttype    Levels Num    Points Num Dtype : ",  -(indf+1));
+	fprintf(stdout, "%6d : Institut Source   Steptype Levels Num    Points Num Dtype : ",  -(indf+1));
 
       if      ( operfunc == func_name ) fprintf(stdout, "Parameter name");
       else if ( operfunc == func_code ) fprintf(stdout, "Table Code");
diff --git a/src/Smooth9.c b/src/Smooth9.c
index b482901..53c44df 100644
--- a/src/Smooth9.c
+++ b/src/Smooth9.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Sort.c b/src/Sort.c
index 8941dbc..bebe4ac 100644
--- a/src/Sort.c
+++ b/src/Sort.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Sorttimestamp.c b/src/Sorttimestamp.c
index e9b4449..fe7fc79 100644
--- a/src/Sorttimestamp.c
+++ b/src/Sorttimestamp.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Specinfo.c b/src/Specinfo.c
index 71c8e11..406d964 100644
--- a/src/Specinfo.c
+++ b/src/Specinfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Spectral.c b/src/Spectral.c
index b4680d8..525ef47 100644
--- a/src/Spectral.c
+++ b/src/Spectral.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Spectrum.c b/src/Spectrum.c
index 8843729..3da32a5 100644
--- a/src/Spectrum.c
+++ b/src/Spectrum.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Split.c b/src/Split.c
index 44f38ed..b55743b 100644
--- a/src/Split.c
+++ b/src/Split.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Splitrec.c b/src/Splitrec.c
index c0d2605..f1d9371 100644
--- a/src/Splitrec.c
+++ b/src/Splitrec.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Splitsel.c b/src/Splitsel.c
index 71951db..71681f7 100644
--- a/src/Splitsel.c
+++ b/src/Splitsel.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -151,8 +151,11 @@ void *Splitsel(void *argument)
 	  {
 	    streamInqRecord(streamID1, &varID, &levelID);
 	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT )
-	      streamReadRecord(streamID1, vars[varID][levelID].ptr, &vars[varID][levelID].nmiss);
-	  }
+              {
+                streamReadRecord(streamID1, vars[varID][levelID].ptr, &nmiss);
+                vars[varID][levelID].nmiss = (size_t) nmiss;
+              }
+          }
     }
 
   index = 0;
diff --git a/src/Splittime.c b/src/Splittime.c
index 53589df..d7cdc6e 100644
--- a/src/Splittime.c
+++ b/src/Splittime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Splityear.c b/src/Splityear.c
index 507a2b7..bf1333f 100644
--- a/src/Splityear.c
+++ b/src/Splityear.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/StringUtilities.c b/src/StringUtilities.c
index 2181dcd..aa9c91f 100644
--- a/src/StringUtilities.c
+++ b/src/StringUtilities.c
@@ -1,69 +1,68 @@
+#include "cdo_int.h"
 #include "StringUtilities.h"
 
 #define DBG 0
 
-int StringSplitWithSeperator(  char *source_string, char *seperator, char*** ptr_split_string )
-
+int StringSplitWithSeperator(const char *source_string, const char *seperator, char*** ptr_split_string )
 {
-	char *duplicate_src = NULL, **temp_list = NULL , *temp_str = NULL, *saveptr;
-	int n = 0, i;
-	int str_len = 0, sep_count = 0;	
+  char *duplicate_src = NULL, **temp_list = NULL , *temp_str = NULL, *saveptr;
+  int n = 0, i;
+  int str_len = 0, sep_count = 0;	
 
-	str_len = strlen( source_string );
+  str_len = strlen( source_string );
 
-	if( !str_len )
-	  return 0;
+  if( !str_len )
+    return 0;
 
-	if( DBG )
-	  fprintf(stderr, "StringSplitWithSeperator Input str %s , seperator %s \n", source_string, seperator );
+  if( DBG )
+    fprintf(stderr, "StringSplitWithSeperator Input str %s , seperator %s \n", source_string, seperator );
 	
-	duplicate_src = strdup(source_string);
+  duplicate_src = strdup(source_string);
         
-	for( i = 0; i < str_len; i++ )
-	  {
-		 if( duplicate_src[i] == *seperator )  
-		   sep_count++;
-	  }	
+  for( i = 0; i < str_len; i++ )
+    {
+      if( duplicate_src[i] == *seperator )  
+        sep_count++;
+    }	
  
-	temp_list  = (char**) Malloc( sizeof( char* ) * (sep_count+1));
+  temp_list  = (char**) Malloc( sizeof( char* ) * (sep_count+1));
 	
-	if( DBG )
-	  fprintf(stderr, "Input str %s , seperator %s  sep count %d\n", duplicate_src, seperator, sep_count );
-	
-	while( ( temp_str = strtok_r( duplicate_src, seperator, &saveptr ) ) )
-          {
-	    temp_list[n] = temp_str;
-            n++;
-            duplicate_src = saveptr;
-          }
+  if( DBG )
+    fprintf(stderr, "Input str %s , seperator %s  sep count %d\n", duplicate_src, seperator, sep_count );
+  
+  while( ( temp_str = strtok_r( duplicate_src, seperator, &saveptr ) ) )
+    {
+      temp_list[n] = temp_str;
+      n++;
+      duplicate_src = saveptr;
+    }
           
-        if( DBG )
-	  {
-	    for( i = 0; i <  n; i++ )
-	      fprintf(stderr, "str  %s \n", temp_list[i] );  
-	  }
+  if( DBG )
+    {
+      for( i = 0; i <  n; i++ )
+        fprintf(stderr, "str  %s \n", temp_list[i] );  
+    }
 	  
-	*ptr_split_string = temp_list;
-
-	return n;
+  *ptr_split_string = temp_list;
+  
+  return n;
 }
 
 
-
 int IsNumeric (const char *s)
 {
-    char *ptr;
-    if (s == NULL || *s == '\0' || isspace(*s))
-      return 0;
+  char *ptr;
+  if (s == NULL || *s == '\0' || isspace(*s))
+    return 0;
     
-    strtod (s, &ptr);
-    return *ptr == '\0';
+  strtod (s, &ptr);
+  return *ptr == '\0';
 }
 
 
 void StrToUpperCase ( char *sPtr )
 {
-    while ( *sPtr != '\0' )
+  while ( *sPtr != '\0' )
     {
       *sPtr = toupper ( ( unsigned char ) *sPtr );
       ++sPtr;
@@ -73,7 +72,7 @@ void StrToUpperCase ( char *sPtr )
 
 void StrToLowerCase ( char *sPtr )
 {
-    while ( *sPtr != '\0' )
+  while ( *sPtr != '\0' )
     {
       *sPtr = tolower ( ( unsigned char ) *sPtr );
       ++sPtr;
@@ -83,7 +82,6 @@ void StrToLowerCase ( char *sPtr )
 /* To replace a single char with another single char in a given string */
 
 void StrReplaceChar( char *str_in, char orig_char, char rep_char )
-
 {
   
   char *ref = NULL;
@@ -107,4 +105,3 @@ void StrReplaceChar( char *str_in, char orig_char, char rep_char )
   
   return  ;     
 }
-
diff --git a/src/StringUtilities.h b/src/StringUtilities.h
index 53d6988..25724dd 100644
--- a/src/StringUtilities.h
+++ b/src/StringUtilities.h
@@ -1,12 +1,7 @@
 #ifndef STR_UTILITIES_H
 #define STR_UTILITIES_H
 
-#include<stdio.h>
-#include<string.h>
-#include<stdlib.h>
-#include <ctype.h>
-
-int StringSplitWithSeperator( char *source_string, char *seperator, char*** ptr_split_string );
+int StringSplitWithSeperator(const char *source_string, const char *seperator, char*** ptr_split_string );
 
 int IsNumeric (const char *s);
 
diff --git a/src/Subtrend.c b/src/Subtrend.c
index e364634..6ac1205 100644
--- a/src/Subtrend.c
+++ b/src/Subtrend.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -113,7 +113,7 @@ void *Subtrend(void *argument)
 	  missval1 = missval;
 	  missval2 = missval;
 	  for ( i = 0; i < gridsize; i++ )
-	    field4.ptr[i] = SUB(field1.ptr[i], ADD(vars2[varID][levelID].ptr[i], MUL(vars3[varID][levelID].ptr[i], tsID)));
+	    field4.ptr[i] = SUBMN(field1.ptr[i], ADDMN(vars2[varID][levelID].ptr[i], MULMN(vars3[varID][levelID].ptr[i], tsID)));
     
 	  nmiss = 0;
 	  for ( i = 0; i < gridsize; i++ )
diff --git a/src/Tee.c b/src/Tee.c
index 4b91160..73c3990 100644
--- a/src/Tee.c
+++ b/src/Tee.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Templates.c b/src/Templates.c
index 8954256..1a1b57f 100644
--- a/src/Templates.c
+++ b/src/Templates.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -23,39 +23,36 @@
 
 void *Template1(void *argument)
 {
-  int streamID1, streamID2 = CDI_UNDEFID;
   int nrecs;
-  int tsID, recID, varID, levelID;
-  int vlistID1, vlistID2;
-  int taxisID1, taxisID2;
+  int recID, varID, levelID;
   int lcopy = FALSE;
   int gridsize, nmiss;
-  double *array = NULL;
 
   cdoInitialize(argument);
 
   if ( UNCHANGED_RECORD ) lcopy = TRUE;
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
+  double *array = NULL;
   if ( ! lcopy )
     {
       gridsize = vlistGridsizeMax(vlistID1);
       array = (double*) Malloc(gridsize*sizeof(double));
     }
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
@@ -86,8 +83,7 @@ void *Template1(void *argument)
 
   vlistDestroy(vlistID2);
 
-  if ( ! lcopy )
-    if ( array ) Free(array);
+  if ( array ) Free(array);
 
   cdoFinish();
 
@@ -97,34 +93,29 @@ void *Template1(void *argument)
 
 void *Template2(void *argument)
 {
-  int streamID1, streamID2 = CDI_UNDEFID;
   int nrecs;
-  int tsID, recID, varID, levelID;
-  int vlistID1, vlistID2;
-  int gridsize;
+  int recID, varID, levelID;
   int nmiss;
-  int taxisID1, taxisID2;
-  double *array = NULL;
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
-  array = (double*) Malloc(gridsize*sizeof(double));
+  int gridsize = vlistGridsizeMax(vlistID1);
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
diff --git a/src/Test.c b/src/Test.c
index 07c8a14..e0c24bc 100644
--- a/src/Test.c
+++ b/src/Test.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Tests.c b/src/Tests.c
index d7ab0f6..9a87bc9 100644
--- a/src/Tests.c
+++ b/src/Tests.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Timcount.c b/src/Timcount.c
index 241230d..14ac303 100644
--- a/src/Timcount.c
+++ b/src/Timcount.c
@@ -49,6 +49,7 @@ void *Timcount(void *argument)
   int streamID1, streamID2;
   int vlistID1, vlistID2, taxisID1, taxisID2;
   int nvars;
+  int nmiss;
   int nwpv; // number of words per value; real:1  complex:2
   int *recVarID, *recLevelID;
   field_t **vars1 = NULL;
@@ -132,7 +133,8 @@ void *Timcount(void *argument)
 		  vars1[varID][levelID].nmiss = gridsize;
 		}
 
-              streamReadRecord(streamID1, field.ptr, &field.nmiss);
+              streamReadRecord(streamID1, field.ptr, &nmiss);
+              field.nmiss   = (size_t)nmiss;
               field.grid    = vars1[varID][levelID].grid;
 	      field.missval = vars1[varID][levelID].missval;
 
@@ -159,7 +161,7 @@ void *Timcount(void *argument)
 	  if ( otsID && vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
 	  streamDefRecord(streamID2, varID, levelID);
-	  streamWriteRecord(streamID2, vars1[varID][levelID].ptr,  vars1[varID][levelID].nmiss);
+	  streamWriteRecord(streamID2, vars1[varID][levelID].ptr,  (int)vars1[varID][levelID].nmiss);
 	}
 
       if ( nrecs == 0 ) break;
diff --git a/src/Timedt.c b/src/Timedt.c
new file mode 100644
index 0000000..981fea4
--- /dev/null
+++ b/src/Timedt.c
@@ -0,0 +1,121 @@
+/*
+  This file is part of CDO. CDO is a collection of Operators to
+  manipulate and analyse Climate model Data.
+
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  See COPYING file for copying and redistribution conditions.
+
+  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 Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+*/
+
+/*
+   This module contains the following operators:
+
+     Timedt    timedt         Delta t
+*/
+
+
+#include <cdi.h>
+#include "cdo.h"
+#include "cdo_int.h"
+#include "pstream.h"
+
+
+void *Timedt(void *argument)
+{
+  int varID, levelID;
+  int nmiss;
+
+  cdoInitialize(argument);
+
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
+
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
+  vlistDefTaxis(vlistID2, taxisID2);
+
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+
+  streamDefVlist(streamID2, vlistID2);
+
+  field_t **vars = field_malloc(vlistID1, FIELD_PTR);
+  
+  int gridsizemax = vlistGridsizeMax(vlistID1);
+  double *array1 = (double*) Malloc(gridsizemax*sizeof(double));
+  double *array2 = (double*) Malloc(gridsizemax*sizeof(double));
+
+  int tsID = 0;
+  int nrecs = streamInqTimestep(streamID1, tsID);
+  for ( int recID = 0; recID < nrecs; ++recID )
+    {
+      streamInqRecord(streamID1, &varID, &levelID);
+      streamReadRecord(streamID1, vars[varID][levelID].ptr, &nmiss);
+      vars[varID][levelID].nmiss = nmiss;
+    }
+
+  tsID++;
+  int tsID2 = 0;
+  while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
+    {
+      taxisCopyTimestep(taxisID2, taxisID1);
+      streamDefTimestep(streamID2, tsID2);
+
+      for ( int recID = 0; recID < nrecs; ++recID )
+        {
+          streamInqRecord(streamID1, &varID, &levelID);
+          streamReadRecord(streamID1, array1, &nmiss);
+
+          double missval = vars[varID][levelID].missval;
+          double *array0 = vars[varID][levelID].ptr;
+          int gridsize = vars[varID][levelID].size;
+          if ( nmiss || vars[varID][levelID].nmiss )
+            {
+              for ( int i = 0; i < gridsize; ++i )
+                {
+                  if ( DBL_IS_EQUAL(array0[i], missval) || DBL_IS_EQUAL(array1[i], missval) )
+                    array2[i] = missval;
+                  else
+                    array2[i] = array1[i] - array0[i];
+                }
+
+              nmiss = 0;
+              for ( int i = 0; i < gridsize; ++i )
+                if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
+            }
+          else
+            {
+              for ( int i = 0; i < gridsize; ++i )
+                array2[i] = array1[i] - array0[i];
+            }
+          
+          for ( int i = 0; i < gridsize; ++i ) array0[i] = array1[i];
+
+          streamDefRecord(streamID2, varID, levelID);
+          streamWriteRecord(streamID2, array2, nmiss);
+        }
+      
+      tsID++;
+      tsID2++;
+    }
+
+  free(array1);
+  free(array2);
+  field_free(vars, vlistID1);
+
+  streamClose(streamID2);
+  streamClose(streamID1);
+
+  cdoFinish();
+
+  return 0;
+}
diff --git a/src/Timselstat.c b/src/Timselstat.c
index 906e31b..a003dc2 100644
--- a/src/Timselstat.c
+++ b/src/Timselstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,9 @@
       Timselstat    timselmean         Time range mean
       Timselstat    timselavg          Time range average
       Timselstat    timselvar          Time range variance
-      Timselstat    timselvar1         Time range variance [Divisor is (n-1)]
+      Timselstat    timselvar1         Time range variance [Normalize by (n-1)]
       Timselstat    timselstd          Time range standard deviation
-      Timselstat    timselstd1         Time range standard deviation [Divisor is (n-1)]
+      Timselstat    timselstd1         Time range standard deviation [Normalize by (n-1)]
 */
 
 
@@ -75,7 +75,7 @@ void *Timselstat(void *argument)
   int lmean   = operfunc == func_mean || operfunc == func_avg;
   int lstd    = operfunc == func_std || operfunc == func_std1;
   int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  double divisor = operfunc == func_std1 || operfunc == func_var1;
+  int divisor = operfunc == func_std1 || operfunc == func_var1;
 
   int streamID1 = streamOpenRead(cdoStreamName(0));
 
@@ -159,7 +159,7 @@ void *Timselstat(void *argument)
 	      if ( nsets == 0 )
 		{
 		  streamReadRecord(streamID1, vars1[varID][levelID].ptr, &nmiss);
-		  vars1[varID][levelID].nmiss = nmiss;
+		  vars1[varID][levelID].nmiss = (size_t)nmiss;
 
 		  if ( nmiss > 0 || samp1[varID][levelID].ptr )
 		    {
@@ -176,7 +176,8 @@ void *Timselstat(void *argument)
 		}
 	      else
 		{
-		  streamReadRecord(streamID1, field.ptr, &field.nmiss);
+		  streamReadRecord(streamID1, field.ptr, &nmiss);
+                  field.nmiss   = (size_t)nmiss;
 		  field.grid    = vars1[varID][levelID].grid;
 		  field.missval = vars1[varID][levelID].missval;
 
@@ -268,7 +269,7 @@ void *Timselstat(void *argument)
 	  if ( otsID && vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
 	  streamDefRecord(streamID2, varID, levelID);
-	  streamWriteRecord(streamID2, vars1[varID][levelID].ptr,  vars1[varID][levelID].nmiss);
+	  streamWriteRecord(streamID2, vars1[varID][levelID].ptr, (int)vars1[varID][levelID].nmiss);
 	}
 
       if ( nrecs == 0 ) break;
diff --git a/src/Timsort.c b/src/Timsort.c
index 0fa5c85..56fa368 100644
--- a/src/Timsort.c
+++ b/src/Timsort.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Timstat.c b/src/Timstat.c
index dd65735..5e21483 100644
--- a/src/Timstat.c
+++ b/src/Timstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,45 +24,45 @@
       Timstat    timmean         Time mean
       Timstat    timavg          Time average
       Timstat    timvar          Time variance
-      Timstat    timvar1         Time variance [Divisor is (n-1)]
+      Timstat    timvar1         Time variance [Normalize by (n-1)]
       Timstat    timstd          Time standard deviation
-      Timstat    timstd1         Time standard deviation [Divisor is (n-1)]
+      Timstat    timstd1         Time standard deviation [Normalize by (n-1)]
       Hourstat   hourmin         Hourly minimum
       Hourstat   hourmax         Hourly maximum
       Hourstat   hoursum         Hourly sum
       Hourstat   hourmean        Hourly mean
       Hourstat   houravg         Hourly average
       Hourstat   hourvar         Hourly variance
-      Hourstat   hourvar1        Hourly variance [Divisor is (n-1)]
+      Hourstat   hourvar1        Hourly variance [Normalize by (n-1)]
       Hourstat   hourstd         Hourly standard deviation
-      Hourstat   hourstd1        Hourly standard deviation [Divisor is (n-1)]
+      Hourstat   hourstd1        Hourly standard deviation [Normalize by (n-1)]
       Daystat    daymin          Daily minimum
       Daystat    daymax          Daily maximum
       Daystat    daysum          Daily sum
       Daystat    daymean         Daily mean
       Daystat    dayavg          Daily average
       Daystat    dayvar          Daily variance
-      Daystat    dayvar1         Daily variance [Divisor is (n-1)]
+      Daystat    dayvar1         Daily variance [Normalize by (n-1)]
       Daystat    daystd          Daily standard deviation
-      Daystat    daystd1         Daily standard deviation [Divisor is (n-1)]
+      Daystat    daystd1         Daily standard deviation [Normalize by (n-1)]
       Monstat    monmin          Monthly minimum
       Monstat    monmax          Monthly maximum
       Monstat    monsum          Monthly sum
       Monstat    monmean         Monthly mean
       Monstat    monavg          Monthly average
       Monstat    monvar          Monthly variance
-      Monstat    monvar1         Monthly variance [Divisor is (n-1)]
+      Monstat    monvar1         Monthly variance [Normalize by (n-1)]
       Monstat    monstd          Monthly standard deviation
-      Monstat    monstd1         Monthly standard deviation [Divisor is (n-1)]
+      Monstat    monstd1         Monthly standard deviation [Normalize by (n-1)]
       Yearstat   yearmin         Yearly minimum
       Yearstat   yearmax         Yearly maximum
       Yearstat   yearsum         Yearly sum
       Yearstat   yearmean        Yearly mean
       Yearstat   yearavg         Yearly average
       Yearstat   yearvar         Yearly variance
-      Yearstat   yearvar1        Yearly variance [Divisor is (n-1)]
+      Yearstat   yearvar1        Yearly variance [Normalize by (n-1)]
       Yearstat   yearstd         Yearly standard deviation
-      Yearstat   yearstd1        Yearly standard deviation [Divisor is (n-1)]
+      Yearstat   yearstd1        Yearly standard deviation [Normalize by (n-1)]
 */
 
 
@@ -72,20 +72,22 @@
 #include "pstream.h"
 
 
+typedef struct {
+  short varID;
+  short levelID;
+} recinfo_t;
+
+
 void *Timstat(void *argument)
 {
+  enum {HOUR_LEN=4, DAY_LEN=6, MON_LEN=8, YEAR_LEN=10};
   int timestat_date = TIMESTAT_MEAN;
-  int gridsize;
-  int vdate = 0, vtime = 0;
   int vdate0 = 0, vtime0 = 0;
   int nrecs;
-  int varID, levelID, recID;
-  long nsets;
-  int i;
+  int varID, levelID;
   int streamID3 = -1;
   int vlistID3, taxisID3 = -1;
   int nmiss;
-  int nlevel;
   int lvfrac = FALSE;
   int nwpv; // number of words per value; real:1  complex:2
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
@@ -94,51 +96,51 @@ void *Timstat(void *argument)
 
   cdoInitialize(argument);
 
-  cdoOperatorAdd("timmin",    func_min,  DATE_LEN, NULL);
-  cdoOperatorAdd("timmax",    func_max,  DATE_LEN, NULL);
-  cdoOperatorAdd("timsum",    func_sum,  DATE_LEN, NULL);
-  cdoOperatorAdd("timmean",   func_mean, DATE_LEN, NULL);
-  cdoOperatorAdd("timavg",    func_avg,  DATE_LEN, NULL);
-  cdoOperatorAdd("timvar",    func_var,  DATE_LEN, NULL);
-  cdoOperatorAdd("timvar1",   func_var1, DATE_LEN, NULL);
-  cdoOperatorAdd("timstd",    func_std,  DATE_LEN, NULL);
-  cdoOperatorAdd("timstd1",   func_std1, DATE_LEN, NULL);
-  cdoOperatorAdd("yearmin",   func_min,  10, NULL);
-  cdoOperatorAdd("yearmax",   func_max,  10, NULL);
-  cdoOperatorAdd("yearsum",   func_sum,  10, NULL);
-  cdoOperatorAdd("yearmean",  func_mean, 10, NULL);
-  cdoOperatorAdd("yearavg",   func_avg,  10, NULL);
-  cdoOperatorAdd("yearvar",   func_var,  10, NULL);
-  cdoOperatorAdd("yearvar1",  func_var1, 10, NULL);
-  cdoOperatorAdd("yearstd",   func_std,  10, NULL);
-  cdoOperatorAdd("yearstd1",  func_std1, 10, NULL);
-  cdoOperatorAdd("monmin",    func_min,   8, NULL);
-  cdoOperatorAdd("monmax",    func_max,   8, NULL);
-  cdoOperatorAdd("monsum",    func_sum,   8, NULL);
-  cdoOperatorAdd("monmean",   func_mean,  8, NULL);
-  cdoOperatorAdd("monavg",    func_avg,   8, NULL);
-  cdoOperatorAdd("monvar",    func_var,   8, NULL);
-  cdoOperatorAdd("monvar1",   func_var1,  8, NULL);
-  cdoOperatorAdd("monstd",    func_std,   8, NULL);
-  cdoOperatorAdd("monstd1",   func_std1,  8, NULL);
-  cdoOperatorAdd("daymin",    func_min,   6, NULL);
-  cdoOperatorAdd("daymax",    func_max,   6, NULL);
-  cdoOperatorAdd("daysum",    func_sum,   6, NULL);
-  cdoOperatorAdd("daymean",   func_mean,  6, NULL);
-  cdoOperatorAdd("dayavg",    func_avg,   6, NULL);
-  cdoOperatorAdd("dayvar",    func_var,   6, NULL);
-  cdoOperatorAdd("dayvar1",   func_var1,  6, NULL);
-  cdoOperatorAdd("daystd",    func_std,   6, NULL);
-  cdoOperatorAdd("daystd1",   func_std1,  6, NULL);
-  cdoOperatorAdd("hourmin",   func_min,   4, NULL);
-  cdoOperatorAdd("hourmax",   func_max,   4, NULL);
-  cdoOperatorAdd("hoursum",   func_sum,   4, NULL);
-  cdoOperatorAdd("hourmean",  func_mean,  4, NULL);
-  cdoOperatorAdd("houravg",   func_avg,   4, NULL);
-  cdoOperatorAdd("hourvar",   func_var,   4, NULL);
-  cdoOperatorAdd("hourvar1",  func_var1,  4, NULL);
-  cdoOperatorAdd("hourstd",   func_std,   4, NULL);
-  cdoOperatorAdd("hourstd1",  func_std1,  4, NULL);
+  cdoOperatorAdd("timmin",    func_min,   DATE_LEN, NULL);
+  cdoOperatorAdd("timmax",    func_max,   DATE_LEN, NULL);
+  cdoOperatorAdd("timsum",    func_sum,   DATE_LEN, NULL);
+  cdoOperatorAdd("timmean",   func_mean,  DATE_LEN, NULL);
+  cdoOperatorAdd("timavg",    func_avg,   DATE_LEN, NULL);
+  cdoOperatorAdd("timvar",    func_var,   DATE_LEN, NULL);
+  cdoOperatorAdd("timvar1",   func_var1,  DATE_LEN, NULL);
+  cdoOperatorAdd("timstd",    func_std,   DATE_LEN, NULL);
+  cdoOperatorAdd("timstd1",   func_std1,  DATE_LEN, NULL);
+  cdoOperatorAdd("yearmin",   func_min,   YEAR_LEN, NULL);
+  cdoOperatorAdd("yearmax",   func_max,   YEAR_LEN, NULL);
+  cdoOperatorAdd("yearsum",   func_sum,   YEAR_LEN, NULL);
+  cdoOperatorAdd("yearmean",  func_mean,  YEAR_LEN, NULL);
+  cdoOperatorAdd("yearavg",   func_avg,   YEAR_LEN, NULL);
+  cdoOperatorAdd("yearvar",   func_var,   YEAR_LEN, NULL);
+  cdoOperatorAdd("yearvar1",  func_var1,  YEAR_LEN, NULL);
+  cdoOperatorAdd("yearstd",   func_std,   YEAR_LEN, NULL);
+  cdoOperatorAdd("yearstd1",  func_std1,  YEAR_LEN, NULL);
+  cdoOperatorAdd("monmin",    func_min,   MON_LEN, NULL);
+  cdoOperatorAdd("monmax",    func_max,   MON_LEN, NULL);
+  cdoOperatorAdd("monsum",    func_sum,   MON_LEN, NULL);
+  cdoOperatorAdd("monmean",   func_mean,  MON_LEN, NULL);
+  cdoOperatorAdd("monavg",    func_avg,   MON_LEN, NULL);
+  cdoOperatorAdd("monvar",    func_var,   MON_LEN, NULL);
+  cdoOperatorAdd("monvar1",   func_var1,  MON_LEN, NULL);
+  cdoOperatorAdd("monstd",    func_std,   MON_LEN, NULL);
+  cdoOperatorAdd("monstd1",   func_std1,  MON_LEN, NULL);
+  cdoOperatorAdd("daymin",    func_min,   DAY_LEN, NULL);
+  cdoOperatorAdd("daymax",    func_max,   DAY_LEN, NULL);
+  cdoOperatorAdd("daysum",    func_sum,   DAY_LEN, NULL);
+  cdoOperatorAdd("daymean",   func_mean,  DAY_LEN, NULL);
+  cdoOperatorAdd("dayavg",    func_avg,   DAY_LEN, NULL);
+  cdoOperatorAdd("dayvar",    func_var,   DAY_LEN, NULL);
+  cdoOperatorAdd("dayvar1",   func_var1,  DAY_LEN, NULL);
+  cdoOperatorAdd("daystd",    func_std,   DAY_LEN, NULL);
+  cdoOperatorAdd("daystd1",   func_std1,  DAY_LEN, NULL);
+  cdoOperatorAdd("hourmin",   func_min,   HOUR_LEN, NULL);
+  cdoOperatorAdd("hourmax",   func_max,   HOUR_LEN, NULL);
+  cdoOperatorAdd("hoursum",   func_sum,   HOUR_LEN, NULL);
+  cdoOperatorAdd("hourmean",  func_mean,  HOUR_LEN, NULL);
+  cdoOperatorAdd("houravg",   func_avg,   HOUR_LEN, NULL);
+  cdoOperatorAdd("hourvar",   func_var,   HOUR_LEN, NULL);
+  cdoOperatorAdd("hourvar1",  func_var1,  HOUR_LEN, NULL);
+  cdoOperatorAdd("hourstd",   func_std,   HOUR_LEN, NULL);
+  cdoOperatorAdd("hourstd1",  func_std1,  HOUR_LEN, NULL);
 
   int operatorID = cdoOperatorID();
   int operfunc   = cdoOperatorF1(operatorID);
@@ -147,7 +149,7 @@ void *Timstat(void *argument)
   int lmean   = operfunc == func_mean || operfunc == func_avg;
   int lstd    = operfunc == func_std || operfunc == func_std1;
   int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  double divisor = operfunc == func_std1 || operfunc == func_var1;
+  int divisor = operfunc == func_std1 || operfunc == func_var1;
 
   if ( operfunc == func_mean )
     {
@@ -179,13 +181,19 @@ void *Timstat(void *argument)
   if ( taxisInqType(taxisID2) == TAXIS_FORECAST ) taxisDefType(taxisID2, TAXIS_RELATIVE);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  int nvars    = vlistNvars(vlistID1);
-  int nrecords = vlistNrecs(vlistID1);
+  int nvars   = vlistNvars(vlistID1);
+  int maxrecs = vlistNrecs(vlistID1);
 
   if ( cmplen == 0 && CDO_Reduce_Dim )
     for ( varID = 0; varID < nvars; ++varID )
       vlistDefVarTsteptype(vlistID2, varID, TSTEP_CONSTANT);
 
+  const char *freq = NULL;
+  if      ( comparelen == DAY_LEN )  freq = "day";
+  else if ( comparelen == MON_LEN )  freq = "mon";
+  else if ( comparelen == YEAR_LEN ) freq = "year";
+  if ( freq ) vlistDefAttTxt(vlistID2, CDI_GLOBAL, "frequency", (int)strlen(freq), freq);
+
   int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
@@ -218,19 +226,25 @@ void *Timstat(void *argument)
       streamDefVlist(streamID3, vlistID3);
     }
 
-  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  recinfo_t *recinfo = (recinfo_t *) malloc(maxrecs*sizeof(recinfo_t));
 
   dtlist_type *dtlist = dtlist_new();
   dtlist_set_stat(dtlist, timestat_date);
   dtlist_set_calendar(dtlist, taxisInqCalendar(taxisID1));
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
   if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
 
+  int FIELD_MEMTYPE = 0;
+  if ( CDO_Memtype == MEMTYPE_FLOAT ) FIELD_MEMTYPE = MEMTYPE_FLOAT;
+
   field_t field;
   field_init(&field);
-  field.ptr = (double*) Malloc(gridsize*sizeof(double));
+  field.memtype = FIELD_MEMTYPE;
+  if ( FIELD_MEMTYPE == MEMTYPE_FLOAT )
+    field.ptrf = (float*) Malloc(gridsize*sizeof(float));
+  else
+    field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
   field_t **vars1 = field_malloc(vlistID1, FIELD_PTR);
   field_t **samp1 = field_malloc(vlistID1, FIELD_NONE);
@@ -241,42 +255,44 @@ void *Timstat(void *argument)
   int otsID = 0;
   while ( TRUE )
     {
-      nsets = 0;
+      int nsets = 0;
       while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
 	{
 	  dtlist_taxisInqTimestep(dtlist, taxisID1, nsets);
-	  vdate = dtlist_get_vdate(dtlist, nsets);
-	  vtime = dtlist_get_vtime(dtlist, nsets);
+	  int vdate = dtlist_get_vdate(dtlist, nsets);
+	  int vtime = dtlist_get_vtime(dtlist, nsets);
 
 	  if ( nsets == 0 ) SET_DATE(indate2, vdate, vtime);
 	  SET_DATE(indate1, vdate, vtime);
 
 	  if ( DATE_IS_NEQ(indate1, indate2, cmplen) ) break;
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
 
 	      if ( tsID == 0 )
 		{
-		  recVarID[recID]   = varID;
-		  recLevelID[recID] = levelID;
+                  recinfo[recID].varID   = varID;
+                  recinfo[recID].levelID = levelID;
 		}
 
-	      nwpv     = vars1[varID][levelID].nwpv;
-	      gridsize = gridInqSize(vars1[varID][levelID].grid);
+              field_t *pvar1 = &vars1[varID][levelID];
+              
+	      nwpv     = pvar1->nwpv;
+	      gridsize = gridInqSize(pvar1->grid);
 
 	      if ( nsets == 0 )
 		{
-		  streamReadRecord(streamID1, vars1[varID][levelID].ptr, &nmiss);
-		  vars1[varID][levelID].nmiss = nmiss;
+		  streamReadRecord(streamID1, pvar1->ptr, &nmiss);
+		  pvar1->nmiss = (size_t)nmiss;
 		  if ( nmiss > 0 || samp1[varID][levelID].ptr )
 		    {
 		      if ( samp1[varID][levelID].ptr == NULL )
 			samp1[varID][levelID].ptr = (double*) Malloc(nwpv*gridsize*sizeof(double));
 
-		      for ( i = 0; i < nwpv*gridsize; i++ )
-			if ( DBL_IS_EQUAL(vars1[varID][levelID].ptr[i], vars1[varID][levelID].missval) )
+		      for ( int i = 0; i < nwpv*gridsize; i++ )
+			if ( DBL_IS_EQUAL(pvar1->ptr[i], pvar1->missval) )
 			  samp1[varID][levelID].ptr[i] = 0;
 			else
 			  samp1[varID][levelID].ptr[i] = 1;
@@ -284,42 +300,52 @@ void *Timstat(void *argument)
 		}
 	      else
 		{
-		  streamReadRecord(streamID1, field.ptr, &field.nmiss);
-		  field.grid    = vars1[varID][levelID].grid;
-		  field.missval = vars1[varID][levelID].missval;
+                  if ( CDO_Memtype == MEMTYPE_FLOAT )
+                    streamReadRecordF(streamID1, field.ptrf, &nmiss);
+                  else
+                    streamReadRecord(streamID1, field.ptr, &nmiss);
+                  field.nmiss   = (size_t)nmiss;
+		  field.size    = gridsize;
+		  field.grid    = pvar1->grid;
+		  field.missval = pvar1->missval;
 		  if ( field.nmiss > 0 || samp1[varID][levelID].ptr )
 		    {
 		      if ( samp1[varID][levelID].ptr == NULL )
 			{
 			  samp1[varID][levelID].ptr = (double*) Malloc(nwpv*gridsize*sizeof(double));
-			  for ( i = 0; i < nwpv*gridsize; i++ )
+			  for ( int i = 0; i < nwpv*gridsize; i++ )
 			    samp1[varID][levelID].ptr[i] = nsets;
 			}
 
-		      for ( i = 0; i < nwpv*gridsize; i++ )
-			if ( !DBL_IS_EQUAL(field.ptr[i], vars1[varID][levelID].missval) )
+		      for ( int i = 0; i < nwpv*gridsize; i++ )
+			if ( !DBL_IS_EQUAL(field.ptr[i], pvar1->missval) )
 			  samp1[varID][levelID].ptr[i]++;
 		    }
 
 		  if ( lvarstd )
 		    {
-		      farsumq(&vars2[varID][levelID], field);
-		      farsum(&vars1[varID][levelID], field);
+                      field_t *pvar2 = &vars2[varID][levelID];
+		      farsumq(pvar2, field);
+		      farsum(pvar1, field);
 		    }
 		  else
 		    {
-		      farfun(&vars1[varID][levelID], field, operfunc);
+		      farfun(pvar1, field, operfunc);
 		    }
 		}
 	    }
 
 	  if ( nsets == 0 && lvarstd )
-	    for ( varID = 0; varID < nvars; varID++ )
-	      {
+            for ( int recID = 0; recID < maxrecs; recID++ )
+              {
+                int varID   = recinfo[recID].varID;
+                int levelID = recinfo[recID].levelID;
+                field_t *pvar1 = &vars1[varID][levelID];
+                field_t *pvar2 = &vars2[varID][levelID];
+
 		if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
-		nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-		for ( levelID = 0; levelID < nlevel; levelID++ )
-		  farmoq(&vars2[varID][levelID], vars1[varID][levelID]);
+
+                farmoq(pvar2, *pvar1);
 	      }
 
 	  vdate0 = vdate;
@@ -331,42 +357,38 @@ void *Timstat(void *argument)
       if ( nrecs == 0 && nsets == 0 ) break;
 
       if ( lmean )
-	for ( varID = 0; varID < nvars; varID++ )
-	  {
+        for ( int recID = 0; recID < maxrecs; recID++ )
+          {
+            int varID   = recinfo[recID].varID;
+            int levelID = recinfo[recID].levelID;
+            field_t *pvar1 = &vars1[varID][levelID];
+
 	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
-	    nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-	    for ( levelID = 0; levelID < nlevel; levelID++ )
-	      {
-		if ( samp1[varID][levelID].ptr == NULL )
-		  farcdiv(&vars1[varID][levelID], (double)nsets);
-		else
-                  {
-                    //   farround(&samp1[varID][levelID]); not necessary
-                    fardiv(&vars1[varID][levelID], samp1[varID][levelID]);
-                  }
-              }
+
+            if ( samp1[varID][levelID].ptr == NULL )
+              farcdiv(pvar1, (double)nsets);
+            else
+              fardiv(pvar1, samp1[varID][levelID]);
 	  }
       else if ( lvarstd )
-	for ( varID = 0; varID < nvars; varID++ )
-	  {
-	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
-	    nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-	    for ( levelID = 0; levelID < nlevel; levelID++ )
-	      {
-		if ( samp1[varID][levelID].ptr == NULL )
-		  {
-		    if ( lstd )
-		      farcstd(&vars1[varID][levelID], vars2[varID][levelID], nsets, divisor);
-		    else
-		      farcvar(&vars1[varID][levelID], vars2[varID][levelID], nsets, divisor);
-		  }
-		else
-		  {
-		    if ( lstd )
-		      farstd(&vars1[varID][levelID], vars2[varID][levelID], samp1[varID][levelID], divisor);
-		    else
-		      farvar(&vars1[varID][levelID], vars2[varID][levelID], samp1[varID][levelID], divisor);
-		  }
+        for ( int recID = 0; recID < maxrecs; recID++ )
+          {
+            int varID   = recinfo[recID].varID;
+            int levelID = recinfo[recID].levelID;
+            field_t *pvar1 = &vars1[varID][levelID];
+            field_t *pvar2 = &vars2[varID][levelID];
+
+            if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
+
+            if ( samp1[varID][levelID].ptr == NULL )
+              {
+                if ( lstd ) farcstd(pvar1, *pvar2, nsets, divisor);
+                else        farcvar(pvar1, *pvar2, nsets, divisor);
+              }
+            else
+              {
+                if ( lstd ) farstd(pvar1, *pvar2, samp1[varID][levelID], divisor);
+                else        farvar(pvar1, *pvar2, samp1[varID][levelID], divisor);
 	      }
 	  }
 
@@ -379,35 +401,36 @@ void *Timstat(void *argument)
 	}
 
       if ( lvfrac && operfunc == func_mean )
-	for ( varID = 0; varID < nvars; varID++ )
-	  {
+        for ( int recID = 0; recID < maxrecs; recID++ )
+          {
+            int varID   = recinfo[recID].varID;
+            int levelID = recinfo[recID].levelID;
+            field_t *pvar1 = &vars1[varID][levelID];
+
 	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
-	    nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-	    for ( levelID = 0; levelID < nlevel; levelID++ )
-	      {
-                nwpv     = vars1[varID][levelID].nwpv;
-                gridsize = gridInqSize(vars1[varID][levelID].grid);
-		missval  = vars1[varID][levelID].missval;
-		if ( samp1[varID][levelID].ptr )
-		  {
-		    int irun = 0;
-		    for ( i = 0; i < nwpv*gridsize; ++i )
-		      {
-			if ( (samp1[varID][levelID].ptr[i] / nsets) < vfrac )
-			  {
-			    vars1[varID][levelID].ptr[i] = missval;
-			    irun++;
-			  }
-		      }
-
-		    if ( irun )
-		      {
-			nmiss = 0;
-			for ( i = 0; i < nwpv*gridsize; ++i )
-			  if ( DBL_IS_EQUAL(vars1[varID][levelID].ptr[i], missval) ) nmiss++;
-			vars1[varID][levelID].nmiss = nmiss;
-		      }
-		  }
+
+            nwpv     = pvar1->nwpv;
+            gridsize = gridInqSize(pvar1->grid);
+            missval  = pvar1->missval;
+            if ( samp1[varID][levelID].ptr )
+              {
+                int irun = 0;
+                for ( int i = 0; i < nwpv*gridsize; ++i )
+                  {
+                    if ( (samp1[varID][levelID].ptr[i] / nsets) < vfrac )
+                      {
+                        pvar1->ptr[i] = missval;
+                        irun++;
+                      }
+                  }
+
+                if ( irun )
+                  {
+                    nmiss = 0;
+                    for ( int i = 0; i < nwpv*gridsize; ++i )
+                      if ( DBL_IS_EQUAL(pvar1->ptr[i], missval) ) nmiss++;
+                    pvar1->nmiss = (size_t)nmiss;
+                  }
 	      }
 	  }
 
@@ -420,15 +443,17 @@ void *Timstat(void *argument)
 	  streamDefTimestep(streamID3, otsID);
 	}
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < maxrecs; recID++ )
 	{
-	  varID   = recVarID[recID];
-	  levelID = recLevelID[recID];
+          int varID   = recinfo[recID].varID;
+          int levelID = recinfo[recID].levelID;
+          field_t *pvar1 = &vars1[varID][levelID];
 
 	  if ( otsID && vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
 	  streamDefRecord(streamID2, varID, levelID);
-	  streamWriteRecord(streamID2, vars1[varID][levelID].ptr,  vars1[varID][levelID].nmiss);
+	  streamWriteRecord(streamID2, pvar1->ptr, (int)pvar1->nmiss);
+          
 	  if ( cdoDiag )
 	    {
 	      if ( samp1[varID][levelID].ptr )
@@ -455,9 +480,7 @@ void *Timstat(void *argument)
   streamClose(streamID1);
 
   if ( field.ptr ) Free(field.ptr);
-
-  if ( recVarID   ) Free(recVarID);
-  if ( recLevelID ) Free(recLevelID);
+  Free(recinfo);
 
   cdoFinish();
 
diff --git a/src/Timstat2.c b/src/Timstat2.c
index b33791e..9b73a70 100644
--- a/src/Timstat2.c
+++ b/src/Timstat2.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -42,19 +42,19 @@ int correlation_t(long gridsize, double missval1, double missval2, int *nofvals,
 
       if ( nvals > 0 )
 	{
-	  temp0 = MUL(work0[i], work1[i]);
-	  temp1 = SUB(work4[i], DIV(temp0, nvals));
-	  temp2 = MUL(work0[i], work0[i]);
-	  temp3 = MUL(work1[i], work1[i]);
-	  temp4 = SUB(work2[i], DIV(temp2, nvals));
-	  temp5 = SUB(work3[i], DIV(temp3, nvals));
-	  temp6 = MUL(temp4, temp5);
-
-	  cor = DIV(temp1, SQRT(temp6));
-	  /*
-	    if      ( cor < -1)  cor = -1;
-	    else if ( cor >  1)  cor =  1;
-	  */
+	  temp0 = MULMN(work0[i], work1[i]);
+	  temp1 = SUBMN(work4[i], DIVMN(temp0, nvals));
+	  temp2 = MULMN(work0[i], work0[i]);
+	  temp3 = MULMN(work1[i], work1[i]);
+	  temp4 = SUBMN(work2[i], DIVMN(temp2, nvals));
+	  temp5 = SUBMN(work3[i], DIVMN(temp3, nvals));
+	  temp6 = MULMN(temp4, temp5);
+
+	  cor = DIVMN(temp1, SQRTMN(temp6));
+
+          if      ( cor < -1 )  cor = -1;
+          else if ( cor >  1 )  cor =  1;
+
 	  if ( DBL_IS_EQUAL(cor, missval1) ) nmiss++;
 	}
       else
@@ -87,8 +87,8 @@ int covariance_t(long gridsize, double missval1, double missval2, int *nofvals,
 
       if ( nvals > 0 )
 	{
-	  temp = DIV(MUL(work0[i], work1[i]), dnvals*dnvals);
-	  covar = SUB(DIV(work2[i], dnvals), temp);
+	  temp = DIVMN( MULMN(work0[i], work1[i]), dnvals*dnvals);
+	  covar = SUBMN( DIVMN(work2[i], dnvals), temp);
 
 	  if ( DBL_IS_EQUAL(covar, missval1) ) nmiss++;
 	}
diff --git a/src/Timstat3.c b/src/Timstat3.c
index 05060d3..84f6a00 100644
--- a/src/Timstat3.c
+++ b/src/Timstat3.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -44,7 +44,7 @@ void *Timstat3(void *argument)
   int nlevs;
   int i, iw, is;
   int varID, recID, levelID, gridID;
-  int nmiss3;
+  int nmiss;
   double rconst, risk;
   double fnvals0, fnvals1;
   double missval, missval1, missval2;
@@ -190,8 +190,9 @@ void *Timstat3(void *argument)
 		  recLevelID[recID] = levelID;	     	     
 		}	 
 
-	      streamReadRecord(streamID[is], in[is].ptr, &in[is].nmiss);
-	      
+	      streamReadRecord(streamID[is], in[is].ptr, &nmiss);
+	      in[is].nmiss = (size_t) nmiss;
+              
 	      for ( i = 0; i < gridsize; ++i )
 		{
 		  /*
@@ -235,11 +236,11 @@ void *Timstat3(void *argument)
 	      fnvals0 = iwork[0][varID][levelID][i];
 	      fnvals1 = iwork[1][varID][levelID][i];
 
-	      temp0 = DIV(MUL(fwork[0][varID][levelID].ptr[i], fwork[0][varID][levelID].ptr[i]), fnvals0);
-	      temp1 = DIV(MUL(fwork[2][varID][levelID].ptr[i], fwork[2][varID][levelID].ptr[i]), fnvals1);
-	      temp2 = SUB(fwork[1][varID][levelID].ptr[i], temp0);
-	      temp3 = SUB(fwork[3][varID][levelID].ptr[i], temp1);
-	      statistic = DIV(temp2, ADD(temp2, MUL(rconst, temp3)));
+	      temp0 = DIVMN( MULMN(fwork[0][varID][levelID].ptr[i], fwork[0][varID][levelID].ptr[i]), fnvals0);
+	      temp1 = DIVMN( MULMN(fwork[2][varID][levelID].ptr[i], fwork[2][varID][levelID].ptr[i]), fnvals1);
+	      temp2 = SUBMN(fwork[1][varID][levelID].ptr[i], temp0);
+	      temp3 = SUBMN(fwork[3][varID][levelID].ptr[i], temp1);
+	      statistic = DIVMN(temp2, ADDMN(temp2, MULMN(rconst, temp3)));
 	      
 	      if ( fnvals0 <= 1 || fnvals1 <= 1 )
 		fractil_1 = fractil_2 = missval1;
@@ -271,35 +272,35 @@ void *Timstat3(void *argument)
 	      for ( j = 0; j < n_in; j++ )
 		{
 		  fnvals = iwork[j][varID][levelID][i];
-		  tmp   = DIV(MUL(fwork[2*j][varID][levelID].ptr[i], fwork[2*j][varID][levelID].ptr[i]), fnvals);
-		  temp0 = ADD(temp0, DIV(SUB(fwork[2*j+1][varID][levelID].ptr[i], tmp), var_factor[j]));
-		  deg_of_freedom = ADD(deg_of_freedom, fnvals);
+		  tmp   = DIVMN( MULMN(fwork[2*j][varID][levelID].ptr[i], fwork[2*j][varID][levelID].ptr[i]), fnvals);
+		  temp0 = ADDMN(temp0, DIVMN( SUBMN(fwork[2*j+1][varID][levelID].ptr[i], tmp), var_factor[j]));
+		  deg_of_freedom = ADDMN(deg_of_freedom, fnvals);
 		}
 
 	      if ( !DBL_IS_EQUAL(temp0, missval1) && temp0 < 0 ) /* This is possible because */
 		temp0 = 0;	                                 /* of rounding errors       */
 
-	      stddev_estimator = SQRT(DIV(temp0, deg_of_freedom));
+	      stddev_estimator = SQRTMN( DIVMN(temp0, deg_of_freedom));
 	      mean_estimator = -rconst;
 	      for ( j = 0; j < n_in; j++ )
 		{
 		  fnvals = iwork[j][varID][levelID][i];
-		  mean_estimator = ADD(mean_estimator,
-				       MUL(mean_factor[j],
-					   DIV(fwork[2*j][varID][levelID].ptr[i], fnvals)));
+		  mean_estimator = ADDMN(mean_estimator,
+				       MULMN(mean_factor[j],
+					   DIVMN(fwork[2*j][varID][levelID].ptr[i], fnvals)));
 		}
 
 	      temp1 = 0;
 	      for ( j = 0; j < n_in; j++ )
 		{
 		  fnvals = iwork[j][varID][levelID][i];
-		  temp1 = ADD(temp1, DIV(MUL(MUL(mean_factor[j], mean_factor[j]),
+		  temp1 = ADDMN(temp1, DIVMN( MULMN( MULMN(mean_factor[j], mean_factor[j]),
 					     var_factor[j]), fnvals));
 		}
 
-	      norm = SQRT(temp1);
+	      norm = SQRTMN(temp1);
 	      
-	      temp2 = DIV(DIV(mean_estimator, norm), stddev_estimator);
+	      temp2 = DIVMN( DIVMN(mean_estimator, norm), stddev_estimator);
 	      fractil = deg_of_freedom < 1 ? missval1 :
 		student_t_inv (deg_of_freedom, 1 - risk/2, __func__);
 
@@ -308,12 +309,12 @@ void *Timstat3(void *argument)
 	    }
 	}
 
-      nmiss3 = 0;
+      nmiss = 0;
       for ( i = 0; i < gridsize; i++ )
-	if ( DBL_IS_EQUAL(out[0].ptr[i], missval1) ) nmiss3++;
+	if ( DBL_IS_EQUAL(out[0].ptr[i], missval1) ) nmiss++;
 
       streamDefRecord(streamID3, varID, levelID);
-      streamWriteRecord(streamID3, out[0].ptr, nmiss3);
+      streamWriteRecord(streamID3, out[0].ptr, nmiss);
     }
 
   for ( varID = 0; varID < nvars; varID++ )
diff --git a/src/Tinfo.c b/src/Tinfo.c
index c4b84aa..a4d21a1 100644
--- a/src/Tinfo.c
+++ b/src/Tinfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "calendar.h"
 #include "pstream.h"
 
 
diff --git a/src/Tocomplex.c b/src/Tocomplex.c
index fd55574..2e6630b 100644
--- a/src/Tocomplex.c
+++ b/src/Tocomplex.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -123,5 +123,5 @@ void *Tocomplex(void *argument)
 
   cdoFinish();
 
-  return (NULL);
+  return 0;
 }
diff --git a/src/Transpose.c b/src/Transpose.c
index d1d217d..27c64e4 100644
--- a/src/Transpose.c
+++ b/src/Transpose.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Trend.c b/src/Trend.c
index 322589f..b143ef3 100644
--- a/src/Trend.c
+++ b/src/Trend.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -145,14 +145,14 @@ void *Trend(void *argument)
 
       for ( i = 0; i < gridsize; i++ )
 	{
-	  temp1 = SUB(work[2][varID][levelID].ptr[i],
-		      DIV(MUL(work[0][varID][levelID].ptr[i], work[3][varID][levelID].ptr[i]), work[4][varID][levelID].ptr[i]));
-	  temp2 = SUB(work[1][varID][levelID].ptr[i],
-		      DIV(MUL(work[0][varID][levelID].ptr[i], work[0][varID][levelID].ptr[i]), work[4][varID][levelID].ptr[i]));
-
-	  field2.ptr[i] = DIV(temp1, temp2);
-	  field1.ptr[i] = SUB(DIV(work[3][varID][levelID].ptr[i], work[4][varID][levelID].ptr[i]),
-			      MUL(DIV(work[0][varID][levelID].ptr[i], work[4][varID][levelID].ptr[i]), field2.ptr[i]));
+	  temp1 = SUBMN(work[2][varID][levelID].ptr[i],
+		      DIVMN( MULMN(work[0][varID][levelID].ptr[i], work[3][varID][levelID].ptr[i]), work[4][varID][levelID].ptr[i]));
+	  temp2 = SUBMN(work[1][varID][levelID].ptr[i],
+		      DIVMN( MULMN(work[0][varID][levelID].ptr[i], work[0][varID][levelID].ptr[i]), work[4][varID][levelID].ptr[i]));
+
+	  field2.ptr[i] = DIVMN(temp1, temp2);
+	  field1.ptr[i] = SUBMN( DIVMN(work[3][varID][levelID].ptr[i], work[4][varID][levelID].ptr[i]),
+			      MULMN( DIVMN(work[0][varID][levelID].ptr[i], work[4][varID][levelID].ptr[i]), field2.ptr[i]));
 	}
 
       nmiss = 0;
diff --git a/src/Trms.c b/src/Trms.c
index 026731b..8c25e67 100644
--- a/src/Trms.c
+++ b/src/Trms.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -50,12 +50,12 @@ void trms(field_t field1, field_t field2, double *dp, field_t *field3)
     for ( i = 0; i < len; i++ ) 
       {
 	wp = w[i]*dp[k*len+i];
-	rsum  = ADD(rsum, MUL(wp, MUL(SUB(array2[k*len+i], array1[k*len+i]),
-				      SUB(array2[k*len+i], array1[k*len+i]))));
-	rsumw = ADD(rsumw, wp);
+	rsum  = ADDMN(rsum, MULMN(wp, MULMN( SUBMN(array2[k*len+i], array1[k*len+i]),
+				      SUBMN(array2[k*len+i], array1[k*len+i]))));
+	rsumw = ADDMN(rsumw, wp);
       }
 
-  ravg = SQRT(DIV(rsum, rsumw));
+  ravg = SQRTMN( DIVMN(rsum, rsumw));
 
   if ( DBL_IS_EQUAL(ravg, missval1) ) rnmiss++;
 
diff --git a/src/Tstepcount.c b/src/Tstepcount.c
index 94267f9..89acbae 100644
--- a/src/Tstepcount.c
+++ b/src/Tstepcount.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Vargen.c b/src/Vargen.c
index 4e89d3d..2a8237a 100644
--- a/src/Vargen.c
+++ b/src/Vargen.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -400,7 +400,7 @@ void *Vargen(void *argument)
               if ( operatorID == RANDOM )
                 {
                   for ( i = 0; i < gridsize; i++ )
-                    array[i] = rand()/(RAND_MAX+1.0);
+                    array[i] = ((double)rand())/((double)RAND_MAX);
                 }
               else if ( operatorID == SINCOS || operatorID == COSHILL )
                 {
diff --git a/src/Varrms.c b/src/Varrms.c
index 0a68f2c..c36b6fc 100644
--- a/src/Varrms.c
+++ b/src/Varrms.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Verifygrid.c b/src/Verifygrid.c
new file mode 100644
index 0000000..496ffb6
--- /dev/null
+++ b/src/Verifygrid.c
@@ -0,0 +1,1188 @@
+/*
+  This file is part of CDO. CDO is a collection of Operators to
+  manipulate and analyse Climate model Data.
+
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  See COPYING file for copying and redistribution conditions.
+
+  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 Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+*/
+
+/*
+   This module contains the following operators:
+*/
+
+#if defined(HAVE_CONFIG_H)
+#  include "config.h" /* VERSION */
+#endif
+
+#include <cdi.h>
+#include "cdo.h"
+#include "cdo_int.h"
+#include "grid.h"
+#include "pstream.h"
+#include "clipping/geometry.h"
+#include "clipping/clipping.c"
+#include "math.h"
+
+struct axis {
+  double axis_vector[3];
+};
+
+static double Euclidean_norm (double a[]) {
+
+  /* Computes the Euclidean norm of a vector given in Cartesian coordinates. */
+
+  return sqrt(pow(a[0],2) + pow(a[1],2) + pow(a[2],2));
+}
+
+static struct axis divide_by_scalar (struct axis a, double scalar) {
+
+  /* Component-wise scalar division of a three dimensional axis vector given in Cartesian coordinates. */
+
+  a.axis_vector[0] = a.axis_vector[0]/scalar;
+  a.axis_vector[1] = a.axis_vector[1]/scalar;
+  a.axis_vector[2] = a.axis_vector[2]/scalar;
+
+  return a;
+}
+
+static struct axis normalize_vector(struct axis a){
+
+  /* Normalizes an axis vector a by dividing it though its magnitude. */
+
+  a = divide_by_scalar(a, Euclidean_norm(a.axis_vector));
+
+  return a;
+}
+
+static struct axis compute_the_new_z_axis(double cell_corners_in_Euclidean_space[]){
+
+  /* Takes the first three corners/vertices of the cell and computes two edges originating at the first corner/vertex. These two edges are on the same plane as all the other vertices. THERE NEED TO BE AT LEAST THREE CORNERS. */
+
+  double edge_one[3] = {(cell_corners_in_Euclidean_space)[3 + 0] -(cell_corners_in_Euclidean_space)[0],
+			(cell_corners_in_Euclidean_space)[3 + 1] -(cell_corners_in_Euclidean_space)[1],
+			(cell_corners_in_Euclidean_space)[3 + 2] -(cell_corners_in_Euclidean_space)[2]};
+  
+  double edge_two[3] = {(cell_corners_in_Euclidean_space)[6 + 0] - (cell_corners_in_Euclidean_space)[0],
+			(cell_corners_in_Euclidean_space)[6 + 1] - (cell_corners_in_Euclidean_space)[1],
+			(cell_corners_in_Euclidean_space)[6 + 2] - (cell_corners_in_Euclidean_space)[2]};
+
+  struct axis new_z_axis;
+
+  /* The cross product of the two edges is the surface normal and the new z-axis. crossproduct_d is defined in clipping/geometry.h */
+  
+  crossproduct_d(edge_one, edge_two, new_z_axis.axis_vector);
+
+  new_z_axis = normalize_vector(new_z_axis);
+  
+  return new_z_axis;
+}
+
+ 
+static struct axis compute_the_new_y_axis(struct axis new_z_axis){
+
+  /* Then the new y-axis is the result of the cross product of the new z-axis and the old x-axis. crossproduct_d is defined in clipping/geometry.h */
+  
+  struct axis old_x_axis;
+ 
+  old_x_axis.axis_vector[0] = 1;
+  old_x_axis.axis_vector[1] = 0;
+  old_x_axis.axis_vector[2] = 0;
+
+  struct axis new_y_axis;
+  
+  crossproduct_d(new_z_axis.axis_vector, old_x_axis.axis_vector, new_y_axis.axis_vector);
+  
+  new_y_axis = normalize_vector(new_y_axis);
+
+  return new_y_axis;
+}
+
+static struct axis compute_the_new_x_axis(struct axis new_z_axis, struct axis new_y_axis){
+
+  /* The new x-axis is the result of the cross product of the new z-axis and the new y-axis. crossproduct_d is defined in clipping/geometry.h */
+  
+  struct axis new_x_axis;
+
+  crossproduct_d(new_y_axis.axis_vector, new_z_axis.axis_vector, new_x_axis.axis_vector);
+  
+  new_x_axis = normalize_vector(new_x_axis);
+
+  return new_x_axis;
+}
+
+static void project_Euclidean_corner_coordinates_onto_the_cell_plane(struct axis new_x_axis, struct axis new_y_axis, double (*p_cell_corners_in_Euclidean_space)[30], double (*p_cell_corners_on_cell_plane)[20], int ncorners){
+
+  /* All corner points are projected onto the new x- and y-axes. dotproduct is defined in clipping/clipping.c */
+
+  double corner_vector[3];
+
+  for (int corner_no = 0; corner_no < ncorners; corner_no++){
+    
+    for (int vector_component = 0; vector_component < 3; ++vector_component){
+      corner_vector[vector_component] = (*p_cell_corners_in_Euclidean_space)[(corner_no * 3) + vector_component];
+    }
+    
+    (*p_cell_corners_on_cell_plane)[(corner_no * 2) + 0] = dotproduct(new_x_axis.axis_vector, corner_vector);
+    (*p_cell_corners_on_cell_plane)[(corner_no * 2) + 1] = dotproduct(new_y_axis.axis_vector, corner_vector);  
+
+    }
+      
+  /* The last vertex is set to be the same as the first one in order to close the cell.*/
+
+  (*p_cell_corners_on_cell_plane)[(ncorners * 2) + 0] = (*p_cell_corners_on_cell_plane)[0];
+  (*p_cell_corners_on_cell_plane)[(ncorners * 2) + 1] = (*p_cell_corners_on_cell_plane)[1];
+  
+  /*
+  printf("The coordinates of the cell vertices on the cell plane are: ");
+
+  for (int corner_no =0; corner_no <= ncorners; corner_no++){
+    printf("(%f, %f) ", cell_corners_on_cell_plane[(corner_no * 2) + 0], cell_corners_on_cell_plane[(corner_no * 2) + 1]);
+  }
+
+  printf("\n\n");
+  */
+}
+
+static void project_Euclidean_center_coordinates_onto_the_cell_plane(struct axis new_x_axis, struct axis new_y_axis, double (*p_center_point_in_Euclidean_space)[3], double (*p_center_point_on_cell_plane)[2]){
+  
+  /* The center point is projected onto the new x- and -y-axes. dotproduct is defined in clipping/clipping.c  */
+
+  (*p_center_point_on_cell_plane)[0] = dotproduct((new_x_axis.axis_vector), (*p_center_point_in_Euclidean_space));
+  (*p_center_point_on_cell_plane)[1] = dotproduct((new_y_axis.axis_vector), (*p_center_point_in_Euclidean_space));
+  
+  /*
+  printf("The coordinates of the presumed center point of the cell on the cell plane are: (%f, %f)\n\n", (*p_center_point_on_cell_plane)[0], (*p_center_point_on_cell_plane)[1]);
+  */
+}
+
+static double is_point_left_of_edge(double point_on_line_1[2], double point_on_line_2[2], double point[2]){
+
+  /* 
+     Computes whether a point is left of the line through point_on_line_1 and point_on_line_2. This is part of the solution to the point in polygon problem.
+     Returns 0 if the point is on the line, > 0 if the point is left of the line, and < 0 if the point is right of the line.
+     This algorithm is by Dan Sunday (geomalgorithms.com) and is completely free for use and modification.
+  */
+  
+  /*
+  printf("Testing whether point (%f, %f) is left of the the edge from point (%f, %f) and point (%f, %f)... ", point[0], point[1], point_on_line_1[0], point_on_line_1[1], point_on_line_2[0], point_on_line_2[1]);
+  */
+  double answer = ((point_on_line_2[0] - point_on_line_1[0]) * (point[1] - point_on_line_1[1]) 
+		- (point[0] - point_on_line_1[0]) * (point_on_line_2[1] - point_on_line_1[1]));
+
+  if (answer == 0){
+    printf("the point lies on the edge.\n");
+  }
+
+  if (answer > 0){
+    printf("the point lies left of the edge.\n");
+  }
+
+  if (answer < 0){
+    printf("the point lies to the right of the edge.\n");
+  }
+
+  return answer;
+}
+
+static double is_point_left_of_edge_without_printfs(double point_on_line_1[2], double point_on_line_2[2], double point[2]){
+
+  /* 
+     Computes whether a point is left of the line through point_on_line_1 and point_on_line_2. This is part of the solution to the point in polygon problem.
+     Returns 0 if the point is on the line, > 0 if the point is left of the line, and < 0 if the point is right of the line.
+     This algorithm is by Dan Sunday (geomalgorithms.com) and is completely free for use and modification.
+  */
+  
+  /*
+  printf("Testing whether point (%f, %f) is left of the the edge from point (%f, %f) and point (%f, %f)... ", point[0], point[1], point_on_line_1[0], point_on_line_1[1], point_on_line_2[0], point_on_line_2[1]);
+  */
+  double answer = ((point_on_line_2[0] - point_on_line_1[0]) * (point[1] - point_on_line_1[1]) 
+		- (point[0] - point_on_line_1[0]) * (point_on_line_2[1] - point_on_line_1[1]));
+  return answer;
+}
+
+static int winding_numbers_algorithm_without_printfs(double cell_corners[], int number_corners, double point[]){
+  
+  /* 
+     Computes whether a point is inside the bounds of a cell. This is the solution to the point in polygon problem.
+     Returns 0 if the point is outside, returns 1 if the point is inside the cell.
+     Based on an algorithm by Dan Sunday (geomalgorithms.com). His algorithm is completely free for use and modification.
+  */
+  
+  int winding_number = 0;
+  
+  for (int i = 0;  i < number_corners; i++){
+    if (cell_corners[i * 2 + 1] <= point[1]){
+      if (cell_corners[(i + 1) * 2 + 1] > point[1]){
+	
+	double point_on_edge_1[2] = {cell_corners[i * 2 + 0], cell_corners[i * 2 + 1]};
+	double point_on_edge_2[2] = {cell_corners[(i + 1) * 2 + 0], cell_corners[(i + 1) * 2 + 1]};
+
+	if (is_point_left_of_edge_without_printfs(point_on_edge_1, point_on_edge_2, point) > 0){
+	  winding_number++;
+	}
+      }       
+    }
+    else { 
+      if (cell_corners[(i + 1) * 2 + 1] <= point[1]){
+	
+	double point_on_edge_1[2] = {cell_corners[i * 2 + 0], cell_corners[i * 2 + 1]};
+	double point_on_edge_2[2] = {cell_corners[(i + 1) * 2 + 0], cell_corners[(i + 1) * 2 + 1]};
+
+	if (is_point_left_of_edge_without_printfs(point_on_edge_1, point_on_edge_2, point) < 0){
+	  winding_number--;
+	}
+      }
+    }
+  }
+  return winding_number;
+}
+
+static int winding_numbers_algorithm_with_printfs(double cell_corners[], int number_corners, double point[]){
+  
+  /* 
+     Computes whether a point is inside the bounds of a cell. This is the solution to the point in polygon problem.
+     Returns 0 if the point is outside, returns 1 if the point is inside the cell.
+     Based on an algorithm by Dan Sunday (geomalgorithms.com). His algorithm is completely free for use and modification.
+  */
+
+  printf("Checking if the presumed center point lies within the bounds of the cell ... \n\n");
+  
+  int winding_number = 0;
+  
+  for (int i = 0;  i < number_corners; i++){
+    printf("Edge number %u from vertex (%f, %f) to vertex (%f, %f):\n\n", i+1, cell_corners[i * 2 + 0], cell_corners[i * 2 + 1], cell_corners[(i + 1) * 2 + 0], cell_corners[(i + 1) * 2 + 1]);
+    if (cell_corners[i * 2 + 1] <= point[1]){
+      if (cell_corners[(i + 1) * 2 + 1] > point[1]){
+	printf("There is an upward crossing of the ray y = %f.\n", point[1]);
+
+	double point_on_edge_1[2] = {cell_corners[i * 2 + 0], cell_corners[i * 2 + 1]};
+	double point_on_edge_2[2] = {cell_corners[(i + 1) * 2 + 0], cell_corners[(i + 1) * 2 + 1]};
+
+	if (is_point_left_of_edge(point_on_edge_1, point_on_edge_2, point) > 0){
+	  winding_number++;
+	  printf("The upward edge crossing happened on the right side of the presumed center point. The new winding number is increased to  %u.\n", winding_number);
+	}
+	else {
+	  printf("The downward edge crossing happened on the left side of the presumed center point. The winding number remains unchanged.\n");
+	}
+      } 
+      else {
+	printf("There is NO crossing of the ray y = %f.\n", point[1]);
+      }
+    }
+    else { 
+      if (cell_corners[(i + 1) * 2 + 1] <= point[1]){
+	printf("There is a downward crossing of the ray y = %f.\n", point[1]);
+
+	double point_on_edge_1[2] = {cell_corners[i * 2 + 0], cell_corners[i * 2 + 1]};
+	double point_on_edge_2[2] = {cell_corners[(i + 1) * 2 + 0], cell_corners[(i + 1) * 2 + 1]};
+
+	if (is_point_left_of_edge(point_on_edge_1, point_on_edge_2, point) < 0){
+	  winding_number--;
+	  printf("The downward edge crossing happened on the right side of the presumed center point. The new winding number is decreased to %u.\n", winding_number);
+	}
+	else {
+	  printf("The downward edge crossing happened on the left side of the presumed center point. The winding number remains unchanged.\n");
+	}
+      }
+      else {
+	printf("There is NO crossing of the ray y = %f.\n", point[1]);
+      }
+    }
+    printf("\n");
+  }
+  return winding_number;
+}
+
+static double perp_dot_product(double vector_one[2], double vector_two[2]){
+
+  /* 
+     The perp-dot product is used for testing if a simple polygon is convex. From Hill, F. S. Jr. "The Pleasures of 'Perp Dot' Products." Chapter II.5 in Graphics Gems IV, Academic Press, 1994
+     It uses a vector that is perpendicular to vector_one (rotated 90 degrees counterclockwise) to calculate the dot product with vector_two.
+     It is positive if vector_one is less than 90 degrees away from vector_two indicating a left turn between vector_one and vector_two, and is negative otherwise.
+     If all edges of a simple polygon wind the same way, it is convex.
+  */
+  
+  return (vector_one[0] * vector_two[1]) - (vector_one[1] - vector_two[0]);
+
+}
+
+static double sign(double x){
+
+  /* Is +1 if x is positive, -1 if x is negative and 0 if x is zero.*/
+
+  return (x > 0) -  (x < 0);
+}
+
+
+static int is_simple_polygon_convex(double cell_corners[], int number_corners){
+
+  /* Uses the perp-dot product to tell if a simple polygon, a cell, is convex. */
+
+  double direction = 0;
+
+  for (int i = 0; i < number_corners - 1; i++){
+
+    /* Tests in which direction edge B winds that is connected to edge A when walking along the polygon edges. Does so for all edges of the polygon. */
+
+    double edge_a[2] = {cell_corners[(i + 1) * 2 + 0] - cell_corners[i * 2 + 0], cell_corners[(i + 1) * 2 + 1] - cell_corners[i * 2 + 1]};
+    double edge_b[2] = {cell_corners[(i + 2) * 2 + 0] - cell_corners[(i + 1) * 2 + 0], cell_corners[(i + 2) * 2 + 1] - cell_corners[(i + 1) * 2 + 1]};
+    
+    double turns_to = sign(perp_dot_product(edge_a, edge_b));
+    
+    /* In the first iteration the direction of winding of the entire polygon is set. Better not be 0.*/
+
+    if (i == 1){
+      direction = turns_to;
+    }
+
+    if (sign(direction) != sign(turns_to)){
+      if (direction != 0){
+	return 0;
+      }
+    }
+    else{
+      direction = turns_to;
+    }      
+  }
+  return 1;
+}
+
+static double calculate_twice_the_polygon_area(double cell_corners[], int number_corners){
+
+  /* This algorithm works with non-convex and even self-intersecting polygons. It results in twice the area of the polygon. */
+  
+  double twice_the_polygon_area = 0;
+
+  for (int i = 0; i < number_corners - 1; i++){
+    
+    twice_the_polygon_area += (cell_corners[(i + 1) * 2 + 0] - cell_corners[i * 2 + 0]) * (cell_corners[(i + 1) * 2 + 1] - cell_corners[i * 2 + 1]);
+  }
+  return twice_the_polygon_area;
+}
+
+static int are_polygon_vertices_arranged_in_clockwise_order(double twice_the_cell_area){
+
+  /* A positive area indicates a clockwise arrangement of vertices, a negative area a counterclockwise arrangement. There should be an area to begin with. */
+  
+  double area_sign = sign(twice_the_cell_area);
+
+  if (area_sign > 0){
+    return 1;
+  }
+  if (area_sign < 0){
+    return 0;
+  }
+}
+
+
+
+double intlin(double x, double y1, double x1, double y2, double x2);
+
+static
+int pnpoly(int npol, double *xp, double *yp, double x, double y)
+{
+  int i, j, c = 0;
+
+  for (i = 0, j = npol-1; i < npol; j = i++) {
+    if ((((yp[i]<=y) && (y<yp[j])) ||
+	 ((yp[j]<=y) && (y<yp[i]))) &&
+	(x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
+      
+      c = !c;
+  }
+  return c;
+}
+
+
+static
+double PolygonArea_old(int np, double *xp, double *yp)
+{
+  int i, j;
+  double area = 0;
+
+  for ( i = 0; i < np; i++ )
+    {
+      j = (i + 1) % np;
+      area += xp[i] * yp[j];
+      area -= yp[i] * xp[j];
+    }
+
+  area /= 2;
+  /* return(area < 0 ? -area : area); */
+  return (area);
+}
+
+
+static
+double PolygonArea(int np, double *xp, double *yp, double yc)
+{
+  int i, j;
+  double area = 0.;
+
+  /* Process area in Radians */
+   
+  for ( i = 0; i < np; i++ )
+    {
+      j = (i + 1) % np;
+      area += DEG2RAD*xp[i] * DEG2RAD*yp[j];
+      area -= DEG2RAD*yp[i] * DEG2RAD*xp[j];
+    }
+  area *= 0.5 * cos(DEG2RAD*yc);
+  return (area);
+}
+
+static
+int ccw(double p0x, double p0y, double p1x, double p1y, double p2x, double p2y)
+{
+  /*
+    This function says wether the point are orientated clockwise
+    +1 positive orientation
+    -1 negative orientation
+     0 points are on a line --> no orientation
+    
+    This is done by a comparision of the gradient of
+    dy1/dx1 = p1 - p0 vs.
+    dy2/dx2 = p2 - p0
+    To avoid singularities at dx1=0 OR dx2 = 0 we multiply with dx1*dx2
+  */
+  double dx1, dx2, dy1, dy2;
+
+  dx1 = p1x - p0x; dy1 = p1y - p0y;
+  dx2 = p2x - p0x; dy2 = p2y - p0y;
+  if ( dx1*dy2 > dy1*dx2 ) return +1;
+  if ( dx1*dy2 < dy1*dx2 ) return -1;
+  if ( (dx1*dx2 < 0 ) || (dy1*dy2 < 0)) return -1;
+  if ( (dx1*dx1 + dy1*dy1) < (dx2*dx2 + dy2*dy2)) return +1;
+
+  return 0;
+}
+
+static
+int intersect(double pix, double piy, double pjx, double pjy,
+              double pkx, double pky, double plx, double ply)
+{
+  /*This function returns if there is an intersection between the lines 
+    line1 between pi and pj and
+    line2 between pk and pl,
+    whereas pi = (pix, piy).
+      
+    This can done by means of ccw since the product of ccw(pi,pj,pk)*ccw(pi,pj,pl)
+    shows if pk and pl are on different or the same side(s) of the line1 (They must
+    have different signums to be on different sides).
+      
+    Consequently if and ONLY IF pk as well as pl are on different sides of line1
+    AND pi as well as pj are on different sides of line2 there HAS TO be an intersection.
+  */
+    
+  return ( ( ccw(pix, piy, pjx, pjy, pkx, pky) *
+	     ccw(pix, piy, pjx, pjy, plx, ply) <= 0 ) &&
+	   ( ccw(pkx, pky, plx, ply, pix, piy) *
+	     ccw(pkx, pky, plx, ply, pjx, pjy) <= 0 ) );
+}
+
+static
+int check_ncorner(int ncorner, const double *lon_bounds, const double *lat_bounds)
+{
+  int ncorner_new = ncorner;
+  int k;
+
+  for ( k=ncorner-1; k>0; --k )
+    if ( IS_NOT_EQUAL(lon_bounds[k], lon_bounds[k-1]) ||
+	 IS_NOT_EQUAL(lat_bounds[k], lat_bounds[k-1]) ) break;
+
+  if ( k < ncorner-1 ) ncorner_new = k+1;
+
+  return ncorner_new;
+}
+
+static
+void verify_grid(int gridsize, int ncorner,
+		double *grid_center_lon, double *grid_center_lat,
+		double *grid_corner_lon, double *grid_corner_lat)
+{
+  int i0, i, j, k, l;
+  int l0;
+  int nout;
+  int isinside, convex, alone, isnegative;
+  const int mnv = ncorner+1;
+  int cuts[mnv][mnv];  
+  int *alone_cell;          
+  int check_corners;
+  double lon, lat = 0;
+  double lon_bounds[mnv], lat_bounds[mnv];
+  double area, sumarea;
+
+  alone_cell = (int*) Malloc(gridsize*ncorner*sizeof(int));
+
+  check_corners = 0; /* don't execute corner checking (last loop) */
+  nout = 0;
+  sumarea = 0;
+  /*
+  for ( i = 0; i < gridsize; ++i )
+    {
+      lon = grid_center_lon[i];
+      lat = grid_center_lat[i];
+      for ( k = 0; k < ncorner; ++k )
+        {
+          lon_bounds[k] = grid_corner_lon[i*ncorner+k];
+          lat_bounds[k] = grid_corner_lat[i*ncorner+k];
+          if ( (lon - lon_bounds[k]) > 270 ) lon_bounds[k] += 360;
+          if ( (lon_bounds[k] - lon) > 270 ) lon_bounds[k] -= 360;
+        }      
+      lon_bounds[ncorner] = lon_bounds[0];
+      lat_bounds[ncorner] = lat_bounds[0];
+      fprintf(stdout, " %6i %6i %9.4f %9.4f :",  nout, i+1, lon, lat);
+      for ( k = 0; k < ncorner; k++ )
+	fprintf(stdout, " %9.4f %9.4f : ", lon_bounds[k], lat_bounds[k]);
+      fprintf(stdout, "\n");
+    }
+  */
+
+  /* Check if center is inside bounds of cell */
+  for ( i = 0; i < gridsize; ++i )
+    {
+      lon = grid_center_lon[i];
+      lat = grid_center_lat[i];
+
+      for ( k = 0; k < ncorner; ++k )
+        {
+          lon_bounds[k] = grid_corner_lon[i*ncorner+k];
+          lat_bounds[k] = grid_corner_lat[i*ncorner+k];
+          if ( (lon - lon_bounds[k]) > 270 ) lon_bounds[k] += 360;
+          if ( (lon_bounds[k] - lon) > 270 ) lon_bounds[k] -= 360;
+        }      
+      lon_bounds[ncorner] = lon_bounds[0];
+      lat_bounds[ncorner] = lat_bounds[0];
+      
+      isinside = pnpoly(ncorner+1, lon_bounds, lat_bounds, lon, lat);
+
+      if ( !isinside ) nout++;
+      if ( !isinside && cdoVerbose )
+        {
+          if ( nout == 1 )
+            {
+              fprintf(stdout,"\n CENTER IS OUT OF BOUNDS");
+              fprintf(stdout,"\n                                               :");
+              for ( k = 0; k < ncorner; k++ )
+                fprintf(stdout, "          Corner %2i : ", k+1);
+              fprintf(stdout,"\n Number  Index center_lon center_lat area*10^6 :");
+              for ( k = 0; k < ncorner; k++ )
+                fprintf(stdout, "   lon_%2.2i    lat_%2.2i : ", k+1, k+1);
+              fprintf(stdout, "\n");
+            }
+          area = PolygonArea(ncorner+1, lon_bounds, lat_bounds,lat);
+          fprintf(stdout, " %6i %6i  %9.4f  %9.4f %9.5f :", 
+		  nout, i+1, lon, lat, area*pow(10,6));
+
+	  int ncorner_new = check_ncorner(ncorner, lon_bounds, lat_bounds);
+
+          for ( k = 0; k < ncorner_new; k++ )
+	    fprintf(stdout, "%9.4f %9.4f : ", lon_bounds[k], lat_bounds[k]);
+           for ( k = ncorner_new; k < ncorner; k++ )
+	     fprintf(stdout, "     ----      ---- : ");
+          fprintf(stdout, "\n");
+        }
+    }
+
+  if ( nout )
+    cdoWarning("%d of %d points out of bounds!", nout, gridsize);
+  
+  /* check that all cell bounds have the same orientation */
+  
+  nout = 0;
+  for ( i = 0; i < gridsize; ++i )
+    {
+      lon = grid_center_lon[i];
+      lat = grid_center_lat[i];
+      
+      for ( k = 0; k < ncorner; ++k )
+	{
+          lon_bounds[k] = grid_corner_lon[i*ncorner+k];
+          lat_bounds[k] = grid_corner_lat[i*ncorner+k];
+          if ( (grid_center_lon[i] - lon_bounds[k]) > 270 ) lon_bounds[k] += 360;
+          if ( (lon_bounds[k] - grid_center_lon[i]) > 270 ) lon_bounds[k] -= 360;
+	}
+      lon_bounds[ncorner] = lon_bounds[0];
+      lat_bounds[ncorner] = lat_bounds[0];
+      
+      area = PolygonArea(ncorner+1, lon_bounds, lat_bounds, lat);
+      
+      isnegative = area < 0 ? 1 : 0;
+      sumarea += area < 0 ? -area : area;
+      
+      if ( isnegative ) nout++;
+      
+      if ( isnegative && cdoVerbose )
+        {
+          if ( nout == 1 )
+            {
+              fprintf(stdout,"\n                                     :");
+              for ( k = 0; k < ncorner; k++ )
+                fprintf(stdout, "          Corner %2i : ", k+1);
+              fprintf(stdout,"\n Number  Index center_lon center_lat :");
+              for ( k = 0; k < ncorner; k++ )
+                fprintf(stdout, "   lon_%2.2i    lat_%2.2i : ", k+1, k+1);
+              fprintf(stdout, "\n");
+            }
+          fprintf(stdout, " %6i %6i  %9.4f  %9.4f :", nout, i+1, lon, lat);
+
+	  int ncorner_new = check_ncorner(ncorner, lon_bounds, lat_bounds);
+
+          for ( k = 0; k < ncorner_new; k++ )
+	    fprintf(stdout, "%9.4f %9.4f : ", lon_bounds[k], lat_bounds[k]);
+           for ( k = ncorner_new; k < ncorner; k++ )
+	     fprintf(stdout, "     ----      ---- : ");
+
+          fprintf(stdout, "\n");
+        }
+    }
+
+  if ( nout )
+    cdoWarning("%d of %d grid cells have wrong orientation!", nout, gridsize);
+
+  if ( cdoVerbose ) 
+    fprintf(stdout, "area-error: %9.5f%%\n", 100.*(sumarea - 4.*M_PI)/4.*M_PI );
+
+  if ( fabs(100.*(sumarea - 4.*M_PI)/4.*M_PI) > 0.1)
+    cdoWarning("area-error: %9.5f%%", 100.*(sumarea - 4.*M_PI)/4.*M_PI );
+  
+  /* check that all cells are convex */
+  
+  nout = 0;
+  for ( i0 = 0; i0 < gridsize; i0++ )
+    {
+      lon = grid_center_lon[i0];
+      lat = grid_center_lat[i0];
+
+      for ( k = 0; k < ncorner; k++ )
+	{
+	  lon_bounds[k] = grid_corner_lon[i0*ncorner+k];
+	  lat_bounds[k] = grid_corner_lat[i0*ncorner+k];
+	  /* Find cells that cover left and right border of the grid and adjust
+	     coordinates --> they become closed polygons on theta-phi plane! */
+	  if ( (lon - lon_bounds[k]) > 270 ) lon_bounds[k] += 360; 
+	  if ( (lon_bounds[k] - lon) > 270 ) lon_bounds[k] -= 360;
+	}
+      
+      /* Reset found cuts for the current cell before starting the search */
+      for ( i = 0; i < ncorner; i++ )
+	for ( j = 0; j < ncorner; j++ )
+	  cuts[i][j] = 0;
+      
+      /* Loops cover all combinations between inner lines of the Polygon
+	 Check whether each inner line is cut by an other (inner) one at least once. 
+	 - Only if there is a cut every inner line the Polygon is convex
+	 - We assume: Points are in either cyclic or anticyclic order
+      */
+      for ( i = 0; i < ncorner-1; i++ )
+	{
+          /* j = i+2 excludes lines from one corner to an other (j=i+1) and
+	     from one point to itself (j=i)*/
+          for ( j = i+2 ; j < ncorner; j++ )
+	    {
+              /* Exclude the line between the last and first corner */
+              if ( i == 0 && j == ncorner-1 ) continue;
+
+	      /* k = i+1: if starting point is in common lines to different corners
+		 do not intersect */
+              for ( k = i+1; k < ncorner - 1; k++ )
+		{                  
+                  if ( i == k ) l0 = j+1;
+                  else          l0 = k+2;
+
+                  for ( l = l0; l < ncorner; l++ )
+		    {
+                      if ( cuts[k][l] && cuts[i][j] ) continue;
+		      /* Exlude the line between the last and first corner 
+			 Exlude the line itself (l!=i, k!=j)
+			 Check if line ij and kl intersect each other.
+			 If so increment respective counters for intersections. 
+			 It is not relevant by which line a line is intersected - 
+			 it is only relevant if they is itersected! */
+                      if ( ! ( k==0 && l == ncorner-1 ) && ( l != j ) && ( k != j )  )
+			{
+                          if ( intersect(lon_bounds[i], lat_bounds[i], lon_bounds[j], lat_bounds[j],
+                                         lon_bounds[k], lat_bounds[k], lon_bounds[l], lat_bounds[l]) )
+			    {
+			      cuts[i][j]++; cuts[k][l]++; cuts[j][i]++; cuts[l][k]++;
+			    }
+			}
+		    }
+		}                  
+	    }
+	}
+
+      convex = 1;
+      /* The following loop covers all inner lines of the Polygon 
+	 (The assumption applies that the points are in cyclic order) */
+      for ( i = 0; i < ncorner-1; i++ )
+	for ( j = i+2; j < ncorner; j++)
+	  {
+	    if ( i == 0 && j == ncorner-1 ) continue;	   
+	    if ( ! cuts[i][j] ) convex = 0;
+	  }
+      if ( !convex ) nout++;        
+      if ( cdoVerbose && ( !convex ) )
+	{
+          if ( nout == 1 )
+	    {
+              fprintf(stdout,"\n NO CONVEX POLYGON");
+              fprintf(stdout,"\n                                       :");
+              for ( k = 0; k < ncorner; k++ )
+		fprintf(stdout, "            Corner %2i : ", k);
+              fprintf(stdout,"\n Number  Index  center_lon  center_lat :");
+              for ( k = 0; k < ncorner; k++ )
+		fprintf(stdout, "    lon_%2.2i     lat_%2.2i : ", k, k);
+              fprintf(stdout, "\n");
+	    }
+          
+          fprintf(stdout, " %6i %6i   %9.4f   %9.4f :", nout, i0+1, lon, lat);
+          for ( k = 0; k < ncorner; k++ )
+	    fprintf(stdout, "  %9.4f %9.4f : ", lon_bounds[k], lat_bounds[k]);
+          fprintf(stdout, "\n");         
+	}     
+    }
+
+  if ( nout )
+    cdoWarning("%d of %d cells are not Convex!", nout, gridsize);
+
+  if ( check_corners )
+    {
+      /* 
+	 Check if there is a corner at the same point of 
+	 an other cell foreach corner of each cell 
+      */
+      nout = 0;
+      for ( i = 0; i < gridsize*ncorner; i++ )
+	alone_cell[i] = 1;
+      
+      for ( i = 0; i < gridsize*ncorner; i++ )
+	{
+	  if ( ! alone_cell[i] ) continue;
+	  alone = 1;
+	  lon = grid_corner_lon[i];
+	  lat = grid_corner_lat[i];			
+	  for ( j = 0; j < gridsize*ncorner; j++ )
+	    if ( j != i && 
+		 IS_EQUAL(grid_corner_lat[j], lat) && 
+		 IS_EQUAL(grid_corner_lon[j], lon) )
+	      { alone = 0; alone_cell[i] = alone_cell[j] = 1; break; }
+	  if ( alone )
+	    {
+	      if      ( lon >= 180. ) lon -= 360.;
+	      else if ( lon  < 180. ) lon += 360.;
+	      for ( j = i+1; j < gridsize*ncorner; j++ )
+		if (j != i  && 
+		    IS_EQUAL(grid_corner_lat[j], lat) && 
+		    IS_EQUAL(grid_corner_lon[j], lon) )
+		  { alone = 0; alone_cell[i] = alone_cell[j] = 0; break; }
+	    }
+	  if ( alone )
+	    { 
+	      nout++;
+	      if ( cdoVerbose )
+		{
+		  if ( nout == 1 )
+		    {
+		      fprintf(stdout,"\n VERTEX ALONE ON GRID\n");
+		      fprintf(stdout," number cell-Index  Vert-Index :        lon        lat\n");
+		    }							
+		  fprintf(stdout, " %6i     %6i      %6i : %10.4f %10.4f\n", 
+			  nout, i/ncorner, i, grid_corner_lon[i], grid_corner_lat[i]);
+		}					
+	    }
+	}
+
+      if ( nout )
+	cdoWarning("%d of %d corners are lonely on the grid!", nout, gridsize*ncorner);
+    }
+
+  Free(alone_cell);
+}
+
+
+void verify_grid_old(int gridsize, int ncorner,
+		double *grid_center_lon, double *grid_center_lat,
+		double *grid_corner_lon, double *grid_corner_lat)
+{
+  int i, k;
+  int nout;
+  int isinside;
+  int isnegative;
+  double area;
+  double lon, lat;
+  double lon_bounds[ncorner], lat_bounds[ncorner];
+
+  /* check that all centers are inside the bounds */
+
+  nout = 0;
+  for ( i = 0; i < gridsize; ++i )
+    {
+      lon = grid_center_lon[i];
+      lat = grid_center_lat[i];
+
+      for ( k = 0; k < ncorner; ++k )
+	{
+	  lon_bounds[k] = grid_corner_lon[i*ncorner+k];
+	  lat_bounds[k] = grid_corner_lat[i*ncorner+k];
+	}
+
+      for ( k = 0; k < ncorner; ++k )
+	{
+	  if ( (lon - lon_bounds[k]) > 270 ) lon_bounds[k] += 360;
+	  if ( (lon_bounds[k] - lon) > 270 ) lon_bounds[k] -= 360;
+	}
+
+      lon_bounds[ncorner] = lon_bounds[0];
+      lat_bounds[ncorner] = lat_bounds[0];
+
+      isinside = pnpoly(ncorner+1, lon_bounds, lat_bounds, lon, lat);
+
+      if ( !isinside ) nout++;
+
+      if ( !isinside && cdoVerbose )
+	printf("center: %d %d %g %g %g %g %g %g %g %g %g %g\n", nout, i, lon, lat, lon_bounds[0], lat_bounds[0],
+	       lon_bounds[1], lat_bounds[1], lon_bounds[2], lat_bounds[2], lon_bounds[3], lat_bounds[3]);
+    }
+
+  if ( nout > 0 )
+    cdoWarning("%d of %d points out of bounds!", nout, gridsize);
+
+
+  /* check that all cell bounds have the same orientation */
+
+  nout = 0;
+  for ( i = 0; i < gridsize; ++i )
+    {
+      lon = grid_center_lon[i];
+      lat = grid_center_lat[i];
+
+      for ( k = 0; k < ncorner; ++k )
+	{
+	  lon_bounds[k] = grid_corner_lon[i*ncorner+k];
+	  lat_bounds[k] = grid_corner_lat[i*ncorner+k];
+	}
+
+      for ( k = 0; k < ncorner; ++k )
+	{
+	  if ( (grid_center_lon[i] - lon_bounds[k]) > 270 ) lon_bounds[k] += 360;
+	  if ( (lon_bounds[k] - grid_center_lon[i]) > 270 ) lon_bounds[k] -= 360;
+	}
+
+      lon_bounds[ncorner] = lon_bounds[0];
+      lat_bounds[ncorner] = lat_bounds[0];
+
+      area = PolygonArea_old(ncorner+1, lon_bounds, lat_bounds);
+
+      if ( area < 0 ) isnegative = 1;
+      else            isnegative = 0;
+
+      if ( isnegative ) nout++;
+
+
+      if ( isnegative && cdoVerbose )
+	printf("bounds: %d %d %g %g %g %g %g %g %g %g %g %g\n", nout, i, lon, lat, lon_bounds[0], lat_bounds[0],
+	       lon_bounds[1], lat_bounds[1], lon_bounds[2], lat_bounds[2], lon_bounds[3], lat_bounds[3]);
+    }
+
+  if ( nout > 0 )
+    cdoWarning("%d of %d grid cells have wrong orientation!", nout, gridsize);
+}
+
+
+static void verify_grid_test(int gridsize, int ncorner, double *grid_center_lon, double *grid_center_lat, double *grid_corner_lon, double *grid_corner_lat){
+
+
+
+  /* 
+     This function performs three tests on each cell of a given grid:
+
+     1) it tests whether all cell bounds have the same orientation, i.e. the corners of the cell are in clockwise or counterclockwise order
+     2) it tests whether the cell is convex
+     3) it tests whether the center point is within the bounds of the cell
+
+     It performs these tests after longitude and latitude on the unit circle have been converted first to Cartesian coordinates in Euclidean space and subsequently to two dimensional coordinates on the plane each cell occupies.  
+  */
+  
+  double center_point_in_Euclidean_space[3];
+
+  /* We are assuming a maximum number of corners of 9. The 10th corner is for closing the cell. */
+
+  double cell_corners_in_Euclidean_space[30];
+  double cell_corner_coordinates[3];
+  double center_point_on_cell_plane[2];
+  double cell_corners_on_cell_plane[20];
+
+  int cell_no;
+  int corner_no;
+
+  int no_of_cells_with_vertices_arranged_in_clockwise_order = 0;
+  int no_of_cells_with_vertices_arranged_in_counterclockwise_order = 0;
+  int no_of_convex_cells = 0;
+  int no_of_degenerate_cells = 0;
+  int no_of_cells_with_center_points_within_their_bounds = 0;
+
+  for (cell_no = 0; cell_no < gridsize; ++cell_no)
+    {
+       printf("Cell Number %d:\n\n", cell_no+1);
+       printf("Euclidean coordinates are:\n\n");
+       
+       /* 
+	  Latitude and longitude are spherical coordinates on a unit circle. Each such coordinate tuple is transformed into a triple of Cartesian coordinates in Euclidean space.
+	  This is first done for the presumed center point of the cell and then for all the corners of the cell. LLtoXYZ is defined in clipping/geometry.h 
+       */
+
+      LLtoXYZ(grid_center_lon[cell_no], grid_center_lat[cell_no], center_point_in_Euclidean_space);
+
+      for (corner_no = 0; corner_no < ncorner; ++corner_no)
+	{
+	  LLtoXYZ(grid_corner_lon[cell_no * ncorner + corner_no], grid_corner_lat[cell_no * ncorner + corner_no], cell_corner_coordinates);
+
+	  /* The components of the result vector are appended to the list of cell corner coordinates. */
+
+	  for (int vector_component = 0; vector_component < 3; ++vector_component){	    
+	    cell_corners_in_Euclidean_space[(corner_no * 3) + vector_component] = cell_corner_coordinates[vector_component];	  
+	  }
+	  printf("(%f, %f, %f) ", cell_corners_in_Euclidean_space[(corner_no * 3) + 0], cell_corners_in_Euclidean_space[(corner_no * 3) + 1], cell_corners_in_Euclidean_space[(corner_no * 3) + 2]);
+	}
+
+      /* We are creating a closed polygon/cell by setting the last corner to be the same as the first one. */
+
+      for (int vector_component = 0; vector_component < 3; ++vector_component){
+	cell_corners_in_Euclidean_space[(ncorner * 3) + vector_component] = cell_corners_in_Euclidean_space[vector_component];
+      }
+      
+      printf("\n\n");
+           
+
+      /*
+	Each cell corresponds to a two-dimensional polygon now in unknown orientation in three-dimensional space. Each cell and its center point are coplanar. THIS IS A GIVEN.
+	In order to solve the two-dimensional point-in-polygon problem for each cell, the three-dimensional coordinates of the polygon and its center point are projected onto the two-dimensional plane they form.
+        
+	This is done in the following steps:
+
+	1) Compute two vectors that lie on the cell plane. The first three corners of the cell are used to do this. THIS MEANS THAT AT LEAST THREE CORNERS MUST BE GIVEN.
+	   Then compute the normal of the cell plane the two vectors are on. The normal is the new z-axis.
+	2) Compute the new y-axis by computing the cross product of the new z-axis and the old x-axis.
+	3) Compute the new x-axis by computing the cross product of the new z-axis and the new y-axis.
+	4) Project every corner point onto the new x- and y-axes by using the dot product.
+
+	The result is a xy tuple for each corner and the presumend center point which is a projection onto the plane the xyz corner points form.
+      */
+      
+      struct axis new_z_axis = compute_the_new_z_axis(cell_corners_in_Euclidean_space);      
+      struct axis new_y_axis = compute_the_new_y_axis(new_z_axis);      
+      struct axis new_x_axis = compute_the_new_x_axis(new_z_axis, new_y_axis);
+      
+      project_Euclidean_corner_coordinates_onto_the_cell_plane(new_x_axis, new_y_axis, &cell_corners_in_Euclidean_space, &cell_corners_on_cell_plane, ncorner);
+      project_Euclidean_center_coordinates_onto_the_cell_plane(new_x_axis, new_y_axis, &center_point_in_Euclidean_space, &center_point_on_cell_plane);
+
+      /* Checking whether the cell has a size greater zero. */
+
+      double twice_the_cell_area = calculate_twice_the_polygon_area(cell_corners_on_cell_plane, ncorner);
+
+      if (twice_the_cell_area == 0){
+	printf("This cell is degenerate. Its area equals zero.\n\n");
+	no_of_degenerate_cells += 1;	
+	continue;	 
+      }
+
+      /* Checking whether the cell corners/polygon vertices are arranged in a clockwise or counterclockwise order. This is done by looking at the sign of the cell area. */
+
+      if (are_polygon_vertices_arranged_in_clockwise_order(twice_the_cell_area) == 1){
+	printf("The cell's corners are arranged in clockwise order.\n\n");
+	no_of_cells_with_vertices_arranged_in_clockwise_order += 1;
+      } else {
+	printf("The cell's corners are arranged in counterclockwise order.\n\n");
+	no_of_cells_with_vertices_arranged_in_counterclockwise_order += 1;
+      }
+  
+      /* Convexity of the cell is tested. */
+
+      printf("Checking if the cell is convex ... ");
+
+      if (is_simple_polygon_convex(cell_corners_on_cell_plane, ncorner) == 1){
+	printf("cell is convex!\n\n");
+	no_of_convex_cells += 1;
+      } else {
+	printf("cell is not convex!\n\n");
+	no_of_degenerate_cells += 1;
+      }
+    
+      /* The winding numbers algorithm is used to test whether the presumed center point is within the bounds of the cell. */
+        
+      int winding_number = winding_numbers_algorithm_without_printfs(cell_corners_on_cell_plane, ncorner, center_point_on_cell_plane);
+
+      if (winding_number == 0){
+	printf("The presumed center point lies OUTSIDE the bounds of the cell.\n\n\n\n");
+      } else {
+	printf("The presumed center point lies INSIDE the bounds of the cell.\n\n\n\n");
+	no_of_cells_with_center_points_within_their_bounds += 1;
+      }
+    }
+  
+  printf("There are %u cells in all.\n\n", gridsize );
+  printf("Number of cells with clockwise ordering of vertices: %u\n", no_of_cells_with_vertices_arranged_in_clockwise_order);
+  printf("Number of cells with counterclockwise ordering of vertices: %u\n", no_of_cells_with_vertices_arranged_in_counterclockwise_order);
+  printf("Number of convex cells: %u\n", no_of_convex_cells);
+  printf("Number of nonsimple or degenerate cells: %u\n", no_of_degenerate_cells);
+  printf("Number of cells with presumed center points within their bounds: %u\n", no_of_cells_with_center_points_within_their_bounds);
+  
+  /******************* TESTING ********************/
+
+  
+  double cell_corners_in_3D[30] = {1.5, 0, 1.5, 0, 1.5, 0, -1.5, 0, -1.5, 0, -1.5, 0, 1.5, 0, -1.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  double cell_corners_in_2D[20];
+  double center_point_in_3D[3] = {0.5, 0, 0.5};
+  double center_point_in_2D[2];
+
+  printf("\n\n\n\n\nTesting the projection on the cell plane:\n\n");
+
+  printf("The vertex coordinates in Euclidean space are: (%f, %f, %f), (%f, %f, %f), (%f, %f, %f), (%f, %f, %f)\n\n", cell_corners_in_3D[0], cell_corners_in_3D[1], cell_corners_in_3D[2], cell_corners_in_3D[3], cell_corners_in_3D[4], cell_corners_in_3D[5], cell_corners_in_3D[6], cell_corners_in_3D[7], cell_corners_in_3D[8], cell_corners_in_3D[9], cell_corners_in_3D[10], cell_corners_in_3D[11]);
+ 
+  printf("The center point coordinates in Euclidean space are: (%f, %f, %f)\n\n", center_point_in_3D[0], center_point_in_3D[1], center_point_in_3D[2]);
+
+  struct axis z_axis = compute_the_new_z_axis(cell_corners_in_3D);
+
+  printf("The new z-axis is: (%f, %f, %f)\n\n", z_axis.axis_vector[0], z_axis.axis_vector[1], z_axis.axis_vector[2]);
+
+  struct axis y_axis = compute_the_new_y_axis(z_axis);
+
+  printf("The new y-axis is: (%f, %f, %f)\n\n", y_axis.axis_vector[0], y_axis.axis_vector[1], y_axis.axis_vector[2]);
+
+  struct axis x_axis = compute_the_new_x_axis(z_axis, y_axis);
+ 
+  printf("The new x-axis is: (%f, %f, %f)\n\n", x_axis.axis_vector[0], x_axis.axis_vector[1], x_axis.axis_vector[2] );
+
+  project_Euclidean_corner_coordinates_onto_the_cell_plane(x_axis, y_axis, &cell_corners_in_3D, &cell_corners_in_2D, 4);
+      
+  printf("The new vertex coordinates are:(%f, %f), (%f, %f), (%f, %f), (%f, %f)\n\n", cell_corners_in_2D[0], cell_corners_in_2D[1], cell_corners_in_2D[2], cell_corners_in_2D[3], cell_corners_in_2D[4], cell_corners_in_2D[5], cell_corners_in_2D[6], cell_corners_in_2D[7]);
+
+  project_Euclidean_center_coordinates_onto_the_cell_plane(x_axis, y_axis, &center_point_in_3D, &center_point_in_2D);
+
+  printf("The new center point coordinates are: (%f, %f)\n\n", center_point_in_2D[0], center_point_in_2D[1]);
+
+  double double_the_area = calculate_twice_the_polygon_area(cell_corners_in_2D, 4);
+ 
+  printf("Are the vertices arranged in clockwise order? %u\n\n", are_polygon_vertices_arranged_in_clockwise_order(double_the_area));
+
+  printf("Is the cell convex? %u\n\n", is_simple_polygon_convex(cell_corners_in_2D, 4));
+
+  int winding_number = winding_numbers_algorithm_without_printfs(cell_corners_in_2D, 4, center_point_in_2D);
+
+  printf("If the winding number is 0 the presumed center point is outside the bounds of the cell. The winding number is: %d\n\n", winding_number);
+ 
+
+
+}
+
+void *Verifygrid(void *argument)
+{
+  bool lgrid_gen_bounds = false, luse_grid_corner = true;
+  double *grid_corner_lat = NULL, *grid_corner_lon = NULL;
+  char units[CDI_MAX_NAME];
+
+  cdoInitialize(argument);
+
+  int VERIFYGRID     = cdoOperatorAdd("verifygrid",  0,   0, NULL);
+  int VERIFYGRIDTEST = cdoOperatorAdd("verifygridtest",  0,   0, NULL);
+
+  int operatorID = cdoOperatorID();
+
+  int streamID = streamOpenRead(cdoStreamName(0));
+
+  int vlistID = streamInqVlist(streamID);
+
+  int gridID  = vlistInqVarGrid(vlistID, 0);
+
+  if ( gridInqType(gridID) == GRID_GME ) gridID = gridToUnstructured(gridID, 1);
+
+  if ( gridInqType(gridID) != GRID_UNSTRUCTURED && gridInqType(gridID) != GRID_CURVILINEAR )
+    {
+      gridID = gridToCurvilinear(gridID, 1);
+      lgrid_gen_bounds = TRUE;
+    }
+
+  int gridsize = gridInqSize(gridID);
+  /*
+  if ( gridInqMaskGME(gridID, NULL) )
+    {
+      int *grid_mask = (int*) Malloc(gridsize*sizeof(int));
+      gridInqMaskGME(gridID, grid_mask);
+      free(grid_mask);
+    }
+  */
+  int ncorner = 4;
+  if ( gridInqType(gridID) == GRID_UNSTRUCTURED )
+    ncorner = gridInqNvertex(gridID);
+
+  double *grid_center_lat = (double*) Malloc(gridsize*sizeof(double));
+  double *grid_center_lon = (double*) Malloc(gridsize*sizeof(double));
+
+  gridInqYvals(gridID, grid_center_lat);
+  gridInqXvals(gridID, grid_center_lon);
+
+  /* Convert lat/lon units if required */
+  gridInqXunits(gridID, units);
+  grid_to_degree(units, gridsize, grid_center_lon, "grid center lon");
+  gridInqYunits(gridID, units);
+  grid_to_degree(units, gridsize, grid_center_lat, "grid center lat");
+
+  if ( luse_grid_corner )
+    {
+      if ( ncorner == 0 ) cdoAbort("grid corner missing!");
+      int nalloc = ncorner*gridsize;
+      grid_corner_lat = (double*) Realloc(grid_corner_lat, nalloc*sizeof(double));
+      grid_corner_lon = (double*) Realloc(grid_corner_lon, nalloc*sizeof(double));
+
+      if ( gridInqYbounds(gridID, NULL) && gridInqXbounds(gridID, NULL) )
+	{
+	  gridInqYbounds(gridID, grid_corner_lat);
+	  gridInqXbounds(gridID, grid_corner_lon);
+	}
+      else
+	{
+	  if ( lgrid_gen_bounds )
+	    {
+	      char xunitstr[CDI_MAX_NAME];
+	      char yunitstr[CDI_MAX_NAME];
+	      gridInqXunits(gridID, xunitstr);
+	      gridInqYunits(gridID, yunitstr);
+	    }
+	  else
+	    cdoAbort("Grid corner missing!");
+	}
+
+
+      /* Note: using units from latitude instead from bounds */
+      grid_to_degree(units, ncorner*gridsize, grid_corner_lon, "grid corner lon");
+      grid_to_degree(units, ncorner*gridsize, grid_corner_lat, "grid corner lat");
+
+    }
+
+  streamClose(streamID);
+
+  if ( operatorID == VERIFYGRID )
+    verify_grid(gridsize, ncorner, grid_center_lon, grid_center_lat, grid_corner_lon, grid_corner_lat);
+  else
+    verify_grid_test(gridsize, ncorner, grid_center_lon, grid_center_lat, grid_corner_lon, grid_corner_lat);
+
+  if ( grid_center_lon ) Free(grid_center_lon);
+  if ( grid_center_lat ) Free(grid_center_lat);
+  if ( grid_corner_lon ) Free(grid_corner_lon);
+  if ( grid_corner_lat ) Free(grid_corner_lat);
+
+  cdoFinish();
+
+  return 0;
+}
diff --git a/src/Vertcum.c b/src/Vertcum.c
index 4d8be4a..5b1ba4b 100644
--- a/src/Vertcum.c
+++ b/src/Vertcum.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -39,7 +39,7 @@ void add_vars_mv(int gridsize, double missval, const double *restrict var1, cons
   double missval2 = missval;
   /*
   for ( int i = 0; i < gridsize; ++i )
-    var3[i] = ADD(var2[i], var1[i]);
+    var3[i] = ADDMN(var2[i], var1[i]);
   */
   for ( int i = 0; i < gridsize; ++i )
     {
diff --git a/src/Vertintap.c b/src/Vertintap.c
index 6c06773..5135a0e 100644
--- a/src/Vertintap.c
+++ b/src/Vertintap.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Vertintml.c b/src/Vertintml.c
index 325d16b..5a5087b 100644
--- a/src/Vertintml.c
+++ b/src/Vertintml.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Vertstat.c b/src/Vertstat.c
index a513a7e..fd75f68 100644
--- a/src/Vertstat.c
+++ b/src/Vertstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -25,9 +25,9 @@
       Vertstat   vertmean        Vertical mean
       Vertstat   vertavg         Vertical average
       Vertstat   vertvar         Vertical variance
-      Vertstat   vertvar1        Vertical variance [Divisor is (n-1)]
+      Vertstat   vertvar1        Vertical variance [Normalize by (n-1)]
       Vertstat   vertstd         Vertical standard deviation
-      Vertstat   vertstd1        Vertical standard deviation [Divisor is (n-1)]
+      Vertstat   vertstd1        Vertical standard deviation [Normalize by (n-1)]
 */
 
 
@@ -39,7 +39,7 @@
 
 #define IS_SURFACE_LEVEL(zaxisID)  (zaxisInqType(zaxisID) == ZAXIS_SURFACE && zaxisInqSize(zaxisID) == 1)
 
-static
+
 int getSurfaceID(int vlistID)
 {
   int surfID = -1;
@@ -96,7 +96,7 @@ void genLayerBounds(int nlev, double *levels, double *lbounds, double *ubounds)
     }
 }
 
-static
+
 int getLayerThickness(int genbounds, int index, int zaxisID, int nlev, double *thickness, double *weights)
 {
   int status = 0;
@@ -191,7 +191,7 @@ void *Vertstat(void *argument)
   int lmean   = operfunc == func_mean || operfunc == func_avg;
   int lstd    = operfunc == func_std || operfunc == func_std1;
   int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  double divisor = operfunc == func_std1 || operfunc == func_var1;
+  int divisor = operfunc == func_std1 || operfunc == func_var1;
 
   //int applyWeights = lmean;
 
@@ -337,7 +337,7 @@ void *Vertstat(void *argument)
 	  if ( levelID == 0 )
 	    {
 	      streamReadRecord(streamID1, vars1[varID].ptr, &nmiss);
-	      vars1[varID].nmiss = nmiss;
+	      vars1[varID].nmiss = (size_t)nmiss;
 
 	      if ( operatorID == VERTINT && IS_NOT_EQUAL(layer_thickness, 1.0) ) farcmul(&vars1[varID], layer_thickness);
 	      if ( lmean && IS_NOT_EQUAL(layer_weight, 1.0) ) farcmul(&vars1[varID], layer_weight);
@@ -369,7 +369,8 @@ void *Vertstat(void *argument)
 	    }
 	  else
 	    {
-	      streamReadRecord(streamID1, field.ptr, &field.nmiss);
+	      streamReadRecord(streamID1, field.ptr, &nmiss);
+              field.nmiss   = (size_t)nmiss;
 	      field.grid    = vars1[varID].grid;
 	      field.missval = vars1[varID].missval;
 
@@ -440,7 +441,7 @@ void *Vertstat(void *argument)
 		}
 
 	      streamDefRecord(streamID2, varID, 0);
-	      streamWriteRecord(streamID2, vars1[varID].ptr, vars1[varID].nmiss);
+	      streamWriteRecord(streamID2, vars1[varID].ptr, (int)vars1[varID].nmiss);
 	      vars1[varID].nsamp = 0;
 	    }
 	}
diff --git a/src/Vertwind.c b/src/Vertwind.c
index 92c2419..1345415 100644
--- a/src/Vertwind.c
+++ b/src/Vertwind.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Wct.c b/src/Wct.c
index 306e3a2..2f13f1f 100755
--- a/src/Wct.c
+++ b/src/Wct.c
@@ -28,7 +28,7 @@
 
 
 static const char WCT_NAME[]     = "wind_chill_temperature";
-static const char WCT_LONGNAME[] = "Windchill temperature describes the fact that low temperatures are felt to be even lower in case of wind. It is based on the rate of heat loss from exposed skin caused by wind and cold. It is calculated according to the empirical formula: 33 + (T - 33) * (0.478 + 0.237 * (SQRT(ff*3.6) - 0.0124 * ff * 3.6)) with T  = air temperature in degree Celsius, ff = 10 m wind speed in m/s. Windchill temperature is only defined for temperatures at or below 33 degr [...]
+static const char WCT_LONGNAME[] = "Windchill temperature describes the fact that low temperatures are felt to be even lower in case of wind. It is based on the rate of heat loss from exposed skin caused by wind and cold. It is calculated according to the empirical formula: 33 + (T - 33) * (0.478 + 0.237 * ( SQRTMN(ff*3.6) - 0.0124 * ff * 3.6)) with T  = air temperature in degree Celsius, ff = 10 m wind speed in m/s. Windchill temperature is only defined for temperatures at or below 33 d [...]
 static const char WCT_UNITS[]    = "Celsius";
 
 static const int FIRST_VAR = 0;
@@ -86,6 +86,7 @@ void *Wct(void *argument)
   int gridsize;
   int nrecs, nrecs2, recID;
   int tsID;
+  int nmiss;
   int gridID, zaxisID;
   int varID1, varID2, varID3;
   int levelID1, levelID2;
@@ -151,10 +152,12 @@ void *Wct(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID1, &levelID1);
-	  streamReadRecord(streamID1, field1.ptr, &field1.nmiss);
-
+	  streamReadRecord(streamID1, field1.ptr, &nmiss);
+          field1.nmiss = (size_t) nmiss;
+          
 	  streamInqRecord(streamID2, &varID2, &levelID2);
-	  streamReadRecord(streamID2, field2.ptr, &field2.nmiss);
+	  streamReadRecord(streamID2, field2.ptr, &nmiss);
+          field2.nmiss = (size_t) nmiss;
 	  
 	  if ( varID1 != varID2 || levelID1 != levelID2 )
 	    cdoAbort("Input streams have different structure!");
@@ -171,7 +174,7 @@ void *Wct(void *argument)
 	  farexpr(&field1, field2, windchillTemperature);
 	  
 	  streamDefRecord(streamID3, varID3, levelID1);
-	  streamWriteRecord(streamID3, field1.ptr, field1.nmiss);
+	  streamWriteRecord(streamID3, field1.ptr, (int)field1.nmiss);
 	}
 
       tsID++;
diff --git a/src/Wind.c b/src/Wind.c
index 8b1c2ab..0592310 100644
--- a/src/Wind.c
+++ b/src/Wind.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -164,7 +164,7 @@ void *Wind(void *argument)
 	  gridID1 = vlistInqVarGrid(vlistID1, varID1);
 
 	  if ( gridInqType(gridID1) != GRID_GAUSSIAN )
-	    cdoAbort("U-wind is not on gaussian grid!");
+	    cdoAbort("U-wind is not on Gaussian grid!");
 
 	  if ( gridID1 != vlistInqVarGrid(vlistID1, varID2) )
 	    cdoAbort("U and V wind must have the same grid represention!");
diff --git a/src/Writegrid.c b/src/Writegrid.c
index 0fcfa4c..9196236 100644
--- a/src/Writegrid.c
+++ b/src/Writegrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Writerandom.c b/src/Writerandom.c
index 528bd76..b1b18a9 100644
--- a/src/Writerandom.c
+++ b/src/Writerandom.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -82,7 +82,7 @@ void *Writerandom(void *argument)
 
       for ( rindex = nrecs-1; rindex >= 0; rindex-- )
 	{
-	  index = (int) (rindex*1.0*rand()/(RAND_MAX+1.0));
+	  index = (int) (rindex*((double)rand())/((double)RAND_MAX));
 	  /*	printf("rindex %d %d\n", rindex, index); */
 	  ipos = -1;
 	  for ( recID = 0; recID < nrecs; recID++ )
diff --git a/src/XTimstat.c b/src/XTimstat.c
index d87a9cf..b96f292 100644
--- a/src/XTimstat.c
+++ b/src/XTimstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,45 +24,45 @@
       Timstat    timmean         Time mean
       Timstat    timavg          Time average
       Timstat    timvar          Time variance
-      Timstat    timvar1         Time variance [Divisor is (n-1)]
+      Timstat    timvar1         Time variance [Normalize by (n-1)]
       Timstat    timstd          Time standard deviation
-      Timstat    timstd1         Time standard deviation [Divisor is (n-1)]
+      Timstat    timstd1         Time standard deviation [Normalize by (n-1)]
       Hourstat   hourmin         Hourly minimum
       Hourstat   hourmax         Hourly maximum
       Hourstat   hoursum         Hourly sum
       Hourstat   hourmean        Hourly mean
       Hourstat   houravg         Hourly average
       Hourstat   hourvar         Hourly variance
-      Hourstat   hourvar1        Hourly variance [Divisor is (n-1)]
+      Hourstat   hourvar1        Hourly variance [Normalize by (n-1)]
       Hourstat   hourstd         Hourly standard deviation
-      Hourstat   hourstd1        Hourly standard deviation [Divisor is (n-1)]
+      Hourstat   hourstd1        Hourly standard deviation [Normalize by (n-1)]
       Daystat    daymin          Daily minimum
       Daystat    daymax          Daily maximum
       Daystat    daysum          Daily sum
       Daystat    daymean         Daily mean
       Daystat    dayavg          Daily average
       Daystat    dayvar          Daily variance
-      Daystat    dayvar1         Daily variance [Divisor is (n-1)]
+      Daystat    dayvar1         Daily variance [Normalize by (n-1)]
       Daystat    daystd          Daily standard deviation
-      Daystat    daystd1         Daily standard deviation [Divisor is (n-1)]
+      Daystat    daystd1         Daily standard deviation [Normalize by (n-1)]
       Monstat    monmin          Monthly minimum
       Monstat    monmax          Monthly maximum
       Monstat    monsum          Monthly sum
       Monstat    monmean         Monthly mean
       Monstat    monavg          Monthly average
       Monstat    monvar          Monthly variance
-      Monstat    monvar1         Monthly variance [Divisor is (n-1)]
+      Monstat    monvar1         Monthly variance [Normalize by (n-1)]
       Monstat    monstd          Monthly standard deviation
-      Monstat    monstd1         Monthly standard deviation [Divisor is (n-1)]
+      Monstat    monstd1         Monthly standard deviation [Normalize by (n-1)]
       Yearstat   yearmin         Yearly minimum
       Yearstat   yearmax         Yearly maximum
       Yearstat   yearsum         Yearly sum
       Yearstat   yearmean        Yearly mean
       Yearstat   yearavg         Yearly average
       Yearstat   yearvar         Yearly variance
-      Yearstat   yearvar1        Yearly variance [Divisor is (n-1)]
+      Yearstat   yearvar1        Yearly variance [Normalize by (n-1)]
       Yearstat   yearstd         Yearly standard deviation
-      Yearstat   yearstd1        Yearly standard deviation [Divisor is (n-1)]
+      Yearstat   yearstd1        Yearly standard deviation [Normalize by (n-1)]
 */
 
 
@@ -70,13 +70,19 @@
 #include "cdo.h"
 #include "cdo_int.h"
 #include "cdo_task.h"
-//#include "pstream.h"
-#include "pstream_write.h"
+#include "pstream.h"
+//#include "pstream_write.h"
 
 
 typedef struct {
+  short varID;
+  short levelID;
+} recinfo_t;
+
+typedef struct {
   int tsIDnext;
   int streamID, nrecs;
+  recinfo_t *recinfo;
   field_t **vars;
 }
 readarg_t;
@@ -89,17 +95,33 @@ void *cdoReadTimestep(void *rarg)
   int varID, levelID, nmiss;
   readarg_t *readarg = (readarg_t *) rarg;
   field_t **input_vars = readarg->vars;
+  recinfo_t *recinfo = readarg->recinfo;
   int streamID = readarg->streamID;
   int tsIDnext = readarg->tsIDnext;
   int nrecs = readarg->nrecs;
 
+  // timer_start(timer_read);
+
   for ( int recID = 0; recID < nrecs; ++recID )
     {
       streamInqRecord(streamID, &varID, &levelID);
-      streamReadRecord(streamID, input_vars[varID][levelID].ptr2, &nmiss);
+
+      if ( tsIDnext == 1 && recinfo )
+        {
+          recinfo[recID].varID   = varID;
+          recinfo[recID].levelID = levelID;
+        }
+
+      if ( CDO_Memtype == MEMTYPE_FLOAT )
+        streamReadRecordF(streamID, (float*)input_vars[varID][levelID].ptr2, &nmiss);
+      else
+        streamReadRecord(streamID, (double*)input_vars[varID][levelID].ptr2, &nmiss);
+      
       input_vars[varID][levelID].nmiss2 = nmiss;
     }
 
+  // timer_stop(timer_read);
+
   num_recs = streamInqTimestep(streamID, tsIDnext);
 
   return ((void *) &num_recs);
@@ -108,13 +130,23 @@ void *cdoReadTimestep(void *rarg)
 static
 void cdoUpdateVars(int nvars, int vlistID, field_t **vars)
 {
+  void *tmp = NULL;
+
   for ( int varID = 0; varID < nvars; varID++ )
     {
       int nlevels = zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
       for ( int levelID = 0; levelID < nlevels; levelID++ )
         {
-          double *tmp = vars[varID][levelID].ptr;
-          vars[varID][levelID].ptr   = vars[varID][levelID].ptr2;
+          if ( CDO_Memtype == MEMTYPE_FLOAT )
+            {
+              tmp = vars[varID][levelID].ptrf;
+              vars[varID][levelID].ptrf = (float*) vars[varID][levelID].ptr2;
+            }
+          else
+            {
+              tmp = vars[varID][levelID].ptr;
+              vars[varID][levelID].ptr = (double*) vars[varID][levelID].ptr2;
+            }
           vars[varID][levelID].ptr2  = tmp;
           vars[varID][levelID].nmiss = vars[varID][levelID].nmiss2;
         }
@@ -124,18 +156,16 @@ void cdoUpdateVars(int nvars, int vlistID, field_t **vars)
 
 void *XTimstat(void *argument)
 {
+  enum {HOUR_LEN=4, DAY_LEN=6, MON_LEN=8, YEAR_LEN=10};
   int timestat_date = TIMESTAT_MEAN;
   int gridsize;
   int vdate = 0, vtime = 0;
   int vdate0 = 0, vtime0 = 0;
-  int nrecs;
-  int varID, levelID;
-  long nsets;
-  int i;
+  int varID;
+  int nsets;
   int streamID3 = -1;
   int vlistID3, taxisID3 = -1;
   int nmiss;
-  int nlevels;
   int lvfrac = FALSE;
   int nwpv; // number of words per value; real:1  complex:2
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
@@ -144,33 +174,33 @@ void *XTimstat(void *argument)
 
   cdoInitialize(argument);
 
-  cdoOperatorAdd("xtimmin",    func_min,  DATE_LEN, NULL);
-  cdoOperatorAdd("xtimmax",    func_max,  DATE_LEN, NULL);
-  cdoOperatorAdd("xtimsum",    func_sum,  DATE_LEN, NULL);
-  cdoOperatorAdd("xtimmean",   func_mean, DATE_LEN, NULL);
-  cdoOperatorAdd("xtimavg",    func_avg,  DATE_LEN, NULL);
-  cdoOperatorAdd("xtimvar",    func_var,  DATE_LEN, NULL);
-  cdoOperatorAdd("xtimvar1",   func_var1, DATE_LEN, NULL);
-  cdoOperatorAdd("xtimstd",    func_std,  DATE_LEN, NULL);
-  cdoOperatorAdd("xtimstd1",   func_std1, DATE_LEN, NULL);
-  cdoOperatorAdd("xyearmin",   func_min,  10, NULL);
-  cdoOperatorAdd("xyearmax",   func_max,  10, NULL);
-  cdoOperatorAdd("xyearsum",   func_sum,  10, NULL);
-  cdoOperatorAdd("xyearmean",  func_mean, 10, NULL);
-  cdoOperatorAdd("xyearavg",   func_avg,  10, NULL);
-  cdoOperatorAdd("xyearvar",   func_var,  10, NULL);
-  cdoOperatorAdd("xyearvar1",  func_var1, 10, NULL);
-  cdoOperatorAdd("xyearstd",   func_std,  10, NULL);
-  cdoOperatorAdd("xyearstd1",  func_std1, 10, NULL);
-  cdoOperatorAdd("xmonmin",    func_min,   8, NULL);
-  cdoOperatorAdd("xmonmax",    func_max,   8, NULL);
-  cdoOperatorAdd("xmonsum",    func_sum,   8, NULL);
-  cdoOperatorAdd("xmonmean",   func_mean,  8, NULL);
-  cdoOperatorAdd("xmonavg",    func_avg,   8, NULL);
-  cdoOperatorAdd("xmonvar",    func_var,   8, NULL);
-  cdoOperatorAdd("xmonvar1",   func_var1,  8, NULL);
-  cdoOperatorAdd("xmonstd",    func_std,   8, NULL);
-  cdoOperatorAdd("xmonstd1",   func_std1,  8, NULL);
+  cdoOperatorAdd("xtimmin",    func_min,   DATE_LEN, NULL);
+  cdoOperatorAdd("xtimmax",    func_max,   DATE_LEN, NULL);
+  cdoOperatorAdd("xtimsum",    func_sum,   DATE_LEN, NULL);
+  cdoOperatorAdd("xtimmean",   func_mean,  DATE_LEN, NULL);
+  cdoOperatorAdd("xtimavg",    func_avg,   DATE_LEN, NULL);
+  cdoOperatorAdd("xtimvar",    func_var,   DATE_LEN, NULL);
+  cdoOperatorAdd("xtimvar1",   func_var1,  DATE_LEN, NULL);
+  cdoOperatorAdd("xtimstd",    func_std,   DATE_LEN, NULL);
+  cdoOperatorAdd("xtimstd1",   func_std1,  DATE_LEN, NULL);
+  cdoOperatorAdd("xyearmin",   func_min,   YEAR_LEN, NULL);
+  cdoOperatorAdd("xyearmax",   func_max,   YEAR_LEN, NULL);
+  cdoOperatorAdd("xyearsum",   func_sum,   YEAR_LEN, NULL);
+  cdoOperatorAdd("xyearmean",  func_mean,  YEAR_LEN, NULL);
+  cdoOperatorAdd("xyearavg",   func_avg,   YEAR_LEN, NULL);
+  cdoOperatorAdd("xyearvar",   func_var,   YEAR_LEN, NULL);
+  cdoOperatorAdd("xyearvar1",  func_var1,  YEAR_LEN, NULL);
+  cdoOperatorAdd("xyearstd",   func_std,   YEAR_LEN, NULL);
+  cdoOperatorAdd("xyearstd1",  func_std1,  YEAR_LEN, NULL);
+  cdoOperatorAdd("xmonmin",    func_min,   MON_LEN, NULL);
+  cdoOperatorAdd("xmonmax",    func_max,   MON_LEN, NULL);
+  cdoOperatorAdd("xmonsum",    func_sum,   MON_LEN, NULL);
+  cdoOperatorAdd("xmonmean",   func_mean,  MON_LEN, NULL);
+  cdoOperatorAdd("xmonavg",    func_avg,   MON_LEN, NULL);
+  cdoOperatorAdd("xmonvar",    func_var,   MON_LEN, NULL);
+  cdoOperatorAdd("xmonvar1",   func_var1,  MON_LEN, NULL);
+  cdoOperatorAdd("xmonstd",    func_std,   MON_LEN, NULL);
+  cdoOperatorAdd("xmonstd1",   func_std1,  MON_LEN, NULL);
 
   int operatorID = cdoOperatorID();
   int operfunc   = cdoOperatorF1(operatorID);
@@ -179,7 +209,7 @@ void *XTimstat(void *argument)
   int lmean   = operfunc == func_mean || operfunc == func_avg;
   int lstd    = operfunc == func_std || operfunc == func_std1;
   int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  double divisor = operfunc == func_std1 || operfunc == func_var1;
+  int divisor = operfunc == func_std1 || operfunc == func_var1;
 
   if ( operfunc == func_mean )
     {
@@ -199,8 +229,8 @@ void *XTimstat(void *argument)
 
   int cmplen = DATE_LEN - comparelen;
 
-  // int streamID1 = streamOpenRead(cdoStreamName(0));
-  int streamID1 = streamOpenRead(cdoStreamName(0)->args);
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  //int streamID1 = streamOpenRead(cdoStreamName(0)->args);
 
   int vlistID1 = streamInqVlist(streamID1);
   int vlistID2 = vlistDuplicate(vlistID1);
@@ -218,6 +248,12 @@ void *XTimstat(void *argument)
     for ( varID = 0; varID < nvars; ++varID )
       vlistDefVarTsteptype(vlistID2, varID, TSTEP_CONSTANT);
 
+  const char *freq = NULL;
+  if      ( comparelen == DAY_LEN )  freq = "day";
+  else if ( comparelen == MON_LEN )  freq = "mon";
+  else if ( comparelen == YEAR_LEN ) freq = "year";
+  if ( freq ) vlistDefAttTxt(vlistID2, CDI_GLOBAL, "frequency", (int)strlen(freq), freq);
+
   int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
@@ -225,7 +261,6 @@ void *XTimstat(void *argument)
   if ( cdoDiag )
     {
       char filename[8192];
-
       strcpy(filename, cdoOperatorName(operatorID));
       strcat(filename, "_");
       strcat(filename, cdoStreamName(1)->args);
@@ -257,7 +292,9 @@ void *XTimstat(void *argument)
   gridsize = vlistGridsizeMax(vlistID1);
   if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
 
-  field_t **input_vars = field_malloc(vlistID1, FIELD_PTR | FIELD_PTR2);
+  int FIELD_MEMTYPE = 0;
+  if ( CDO_Memtype == MEMTYPE_FLOAT ) FIELD_MEMTYPE = FIELD_FLT;
+  field_t **input_vars = field_malloc(vlistID1, FIELD_PTR | FIELD_PTR2 | FIELD_MEMTYPE);
   field_t **vars1 = field_malloc(vlistID1, FIELD_PTR);
   field_t **samp1 = field_malloc(vlistID1, FIELD_NONE);
   field_t **vars2 = NULL;
@@ -267,7 +304,7 @@ void *XTimstat(void *argument)
   readarg.streamID = streamID1;
   readarg.vars = input_vars;
 
-  int lparallelread = TRUE;
+  int lparallelread = CDO_Parallel_Read;
   int ltsfirst = TRUE;
   void *read_task = NULL;
   void *readresult = NULL;
@@ -284,7 +321,10 @@ void *XTimstat(void *argument)
 
   int tsID  = 0;
   int otsID = 0;
-  nrecs = streamInqTimestep(streamID1, tsID);
+  int nrecs = streamInqTimestep(streamID1, tsID);
+  int maxrecs = nrecs;
+  recinfo_t *recinfo = (recinfo_t *) malloc(maxrecs*sizeof(recinfo_t));
+  
   tsID++;
   while ( TRUE )
     {
@@ -301,24 +341,13 @@ void *XTimstat(void *argument)
 	  if ( DATE_IS_NEQ(indate1, indate2, cmplen) ) break;
 
           readarg.tsIDnext = tsID;
-          readarg.nrecs = nrecs;
+          readarg.nrecs    = nrecs;
+          readarg.recinfo  = recinfo;
 
-          if ( ltsfirst || lparallelread  == FALSE )
+          if ( ltsfirst || lparallelread == FALSE )
             {
-              if ( lparallelread )
-                {
-                  cdo_task_start(read_task, cdoReadTimestep, &readarg);
-                }
-              else
-                {
-                  readresult = cdoReadTimestep(&readarg);
-                }
-              
-              if ( lparallelread )
-                {
-                  readresult = cdo_task_wait(read_task);
-                }
               ltsfirst = FALSE;
+              readresult = cdoReadTimestep(&readarg);
             }
           else
             {
@@ -335,68 +364,93 @@ void *XTimstat(void *argument)
               cdo_task_start(read_task, cdoReadTimestep, &readarg);
             }
 
-          for ( varID = 0; varID < nvars; varID++ )
+          if ( nsets == 0 )
             {
-              nlevels = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-              for ( levelID = 0; levelID < nlevels; levelID++ )
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) shared(maxrecs, recinfo, input_vars, vars1, samp1) if(maxrecs>1)
+#endif
+              for ( int recID = 0; recID < maxrecs; recID++ )
                 {
-                  nwpv     = vars1[varID][levelID].nwpv;
-                  gridsize = gridInqSize(vars1[varID][levelID].grid);
+                  int varID    = recinfo[recID].varID;
+                  int levelID  = recinfo[recID].levelID;
+
+                  field_t *pvar1 = &vars1[varID][levelID];
+                  field_t *pinput_var = &input_vars[varID][levelID];
+
+                  int nwpv     = pvar1->nwpv;
+                  int gridsize = pvar1->size;
+                  int nmiss    = pinput_var->nmiss;
 
-                  if ( nsets == 0 )
+                  farcpy(pvar1, *pinput_var);
+                  pvar1->nmiss = nmiss;
+                  if ( nmiss > 0 || samp1[varID][levelID].ptr )
                     {
-                      memcpy(vars1[varID][levelID].ptr, input_vars[varID][levelID].ptr, nwpv*gridsize*sizeof(double));
-                      nmiss = input_vars[varID][levelID].nmiss;
-                      vars1[varID][levelID].nmiss = nmiss;
-                      if ( nmiss > 0 || samp1[varID][levelID].ptr )
-                        {
-                          if ( samp1[varID][levelID].ptr == NULL )
-                            samp1[varID][levelID].ptr = (double*) Malloc(nwpv*gridsize*sizeof(double));
-
-                          for ( i = 0; i < nwpv*gridsize; i++ )
-                            if ( DBL_IS_EQUAL(vars1[varID][levelID].ptr[i], vars1[varID][levelID].missval) )
-                              samp1[varID][levelID].ptr[i] = 0;
-                            else
-                              samp1[varID][levelID].ptr[i] = 1;
-                        }
+                      if ( samp1[varID][levelID].ptr == NULL )
+                        samp1[varID][levelID].ptr = (double*) malloc(nwpv*gridsize*sizeof(double));
+                      
+                      for ( int i = 0; i < nwpv*gridsize; i++ )
+                        if ( DBL_IS_EQUAL(pvar1->ptr[i], pvar1->missval) )
+                          samp1[varID][levelID].ptr[i] = 0;
+                        else
+                          samp1[varID][levelID].ptr[i] = 1;
                     }
-                  else
-                    {
-                      nmiss = input_vars[varID][levelID].nmiss;
-                      if ( nmiss > 0 || samp1[varID][levelID].ptr )
-                        {
-                          if ( samp1[varID][levelID].ptr == NULL )
-                            {
-                              samp1[varID][levelID].ptr = (double*) Malloc(nwpv*gridsize*sizeof(double));
-                              for ( i = 0; i < nwpv*gridsize; i++ )
-                                samp1[varID][levelID].ptr[i] = nsets;
-                            }
-                          
-                          for ( i = 0; i < nwpv*gridsize; i++ )
-                            if ( !DBL_IS_EQUAL(input_vars[varID][levelID].ptr[i], vars1[varID][levelID].missval) )
-                              samp1[varID][levelID].ptr[i]++;
-                        }
+                }
+            }
+          else
+            {
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) shared(lvarstd, nsets, maxrecs, recinfo, input_vars, vars1, samp1, vars2, operfunc) if(maxrecs>1)
+#endif
+              for ( int recID = 0; recID < maxrecs; recID++ )
+                {
+                  int varID    = recinfo[recID].varID;
+                  int levelID  = recinfo[recID].levelID;
                   
-                      if ( lvarstd )
-                        {
-                          farsumq(&vars2[varID][levelID], input_vars[varID][levelID]);
-                          farsum(&vars1[varID][levelID], input_vars[varID][levelID]);
-                        }
-                      else
+                  field_t *pvar1 = &vars1[varID][levelID];
+                  field_t *pinput_var = &input_vars[varID][levelID];
+
+                  int nwpv     = pvar1->nwpv;
+                  int gridsize = pvar1->size;
+                  int nmiss    = pinput_var->nmiss;
+
+                  if ( nmiss > 0 || samp1[varID][levelID].ptr )
+                    {
+                      if ( samp1[varID][levelID].ptr == NULL )
                         {
-                          farfun(&vars1[varID][levelID], input_vars[varID][levelID], operfunc);
+                          samp1[varID][levelID].ptr = (double*) malloc(nwpv*gridsize*sizeof(double));
+                          for ( int i = 0; i < nwpv*gridsize; i++ )
+                            samp1[varID][levelID].ptr[i] = nsets;
                         }
+                          
+                      for ( int i = 0; i < nwpv*gridsize; i++ )
+                        if ( !DBL_IS_EQUAL(pinput_var->ptr[i], pvar1->missval) )
+                          samp1[varID][levelID].ptr[i]++;
                     }
-		}
-	    }
+                  
+		  if ( lvarstd )
+		    {
+                      field_t *pvar2 = &vars2[varID][levelID];
+		      farsumq(pvar2, *pinput_var);
+		      farsum(pvar1, *pinput_var);
+		    }
+		  else
+		    {
+		      farfun(pvar1, *pinput_var, operfunc);
+		    }
+                }
+            }
 
 	  if ( nsets == 0 && lvarstd )
-	    for ( varID = 0; varID < nvars; varID++ )
-	      {
+            for ( int recID = 0; recID < maxrecs; recID++ )
+              {
+                int varID   = recinfo[recID].varID;
+                int levelID = recinfo[recID].levelID;
+                field_t *pvar1 = &vars1[varID][levelID];
+                field_t *pvar2 = &vars2[varID][levelID];
+
 		if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
-		nlevels = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-		for ( levelID = 0; levelID < nlevels; levelID++ )
-		  farmoq(&vars2[varID][levelID], vars1[varID][levelID]);
+
+                farmoq(pvar2, *pvar1);
 	      }
 
 	  vdate0 = vdate;
@@ -408,42 +462,41 @@ void *XTimstat(void *argument)
       if ( nrecs == 0 && nsets == 0 ) break;
 
       if ( lmean )
-	for ( varID = 0; varID < nvars; varID++ )
-	  {
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) shared(vlistID1, nsets, maxrecs, recinfo, vars1, samp1) if(maxrecs>1)
+#endif
+        for ( int recID = 0; recID < maxrecs; recID++ )
+          {
+            int varID   = recinfo[recID].varID;
+            int levelID = recinfo[recID].levelID;
+            field_t *pvar1 = &vars1[varID][levelID];
+
 	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
-	    nlevels = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-	    for ( levelID = 0; levelID < nlevels; levelID++ )
-	      {
-		if ( samp1[varID][levelID].ptr == NULL )
-		  farcdiv(&vars1[varID][levelID], (double)nsets);
-		else
-                  {
-                    //   farround(&samp1[varID][levelID]); not necessary
-                    fardiv(&vars1[varID][levelID], samp1[varID][levelID]);
-                  }
-              }
+
+            if ( samp1[varID][levelID].ptr == NULL )
+              farcdiv(pvar1, (double)nsets);
+            else
+              fardiv(pvar1, samp1[varID][levelID]);
 	  }
       else if ( lvarstd )
-	for ( varID = 0; varID < nvars; varID++ )
-	  {
-	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
-	    nlevels = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-	    for ( levelID = 0; levelID < nlevels; levelID++ )
-	      {
-		if ( samp1[varID][levelID].ptr == NULL )
-		  {
-		    if ( lstd )
-		      farcstd(&vars1[varID][levelID], vars2[varID][levelID], nsets, divisor);
-		    else
-		      farcvar(&vars1[varID][levelID], vars2[varID][levelID], nsets, divisor);
-		  }
-		else
-		  {
-		    if ( lstd )
-		      farstd(&vars1[varID][levelID], vars2[varID][levelID], samp1[varID][levelID], divisor);
-		    else
-		      farvar(&vars1[varID][levelID], vars2[varID][levelID], samp1[varID][levelID], divisor);
-		  }
+        for ( int recID = 0; recID < maxrecs; recID++ )
+          {
+            int varID   = recinfo[recID].varID;
+            int levelID = recinfo[recID].levelID;
+            field_t *pvar1 = &vars1[varID][levelID];
+            field_t *pvar2 = &vars2[varID][levelID];
+
+            if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
+
+            if ( samp1[varID][levelID].ptr == NULL )
+              {
+                if ( lstd ) farcstd(pvar1, *pvar2, nsets, divisor);
+                else        farcvar(pvar1, *pvar2, nsets, divisor);
+              }
+            else
+              {
+                if ( lstd ) farstd(pvar1, *pvar2, samp1[varID][levelID], divisor);
+                else        farvar(pvar1, *pvar2, samp1[varID][levelID], divisor);
 	      }
 	  }
 
@@ -456,35 +509,36 @@ void *XTimstat(void *argument)
 	}
 
       if ( lvfrac && operfunc == func_mean )
-	for ( varID = 0; varID < nvars; varID++ )
-	  {
+        for ( int recID = 0; recID < maxrecs; recID++ )
+          {
+            int varID   = recinfo[recID].varID;
+            int levelID = recinfo[recID].levelID;
+            field_t *pvar1 = &vars1[varID][levelID];
+
 	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
-	    nlevels = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-	    for ( levelID = 0; levelID < nlevels; levelID++ )
-	      {
-                nwpv     = vars1[varID][levelID].nwpv;
-                gridsize = gridInqSize(vars1[varID][levelID].grid);
-		missval  = vars1[varID][levelID].missval;
-		if ( samp1[varID][levelID].ptr )
-		  {
-		    int irun = 0;
-		    for ( i = 0; i < nwpv*gridsize; ++i )
-		      {
-			if ( (samp1[varID][levelID].ptr[i] / nsets) < vfrac )
-			  {
-			    vars1[varID][levelID].ptr[i] = missval;
-			    irun++;
-			  }
-		      }
-
-		    if ( irun )
-		      {
-			nmiss = 0;
-			for ( i = 0; i < nwpv*gridsize; ++i )
-			  if ( DBL_IS_EQUAL(vars1[varID][levelID].ptr[i], missval) ) nmiss++;
-			vars1[varID][levelID].nmiss = nmiss;
-		      }
-		  }
+
+            nwpv     = pvar1->nwpv;
+            gridsize = gridInqSize(pvar1->grid);
+            missval  = pvar1->missval;
+            if ( samp1[varID][levelID].ptr )
+              {
+                int irun = 0;
+                for ( int i = 0; i < nwpv*gridsize; ++i )
+                  {
+                    if ( (samp1[varID][levelID].ptr[i] / nsets) < vfrac )
+                      {
+                        pvar1->ptr[i] = missval;
+                        irun++;
+                      }
+                  }
+
+                if ( irun )
+                  {
+                    nmiss = 0;
+                    for ( int i = 0; i < nwpv*gridsize; ++i )
+                      if ( DBL_IS_EQUAL(pvar1->ptr[i], missval) ) nmiss++;
+                    pvar1->nmiss = nmiss;
+                  }
 	      }
 	  }
 
@@ -497,22 +551,23 @@ void *XTimstat(void *argument)
 	  streamDefTimestep(streamID3, otsID);
 	}
 
-      for ( varID = 0; varID < nvars; ++varID )
+      for ( int recID = 0; recID < maxrecs; recID++ )
 	{
+          int varID   = recinfo[recID].varID;
+          int levelID = recinfo[recID].levelID;
+          field_t *pvar1 = &vars1[varID][levelID];
+
 	  if ( otsID && vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
-          nlevels = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
-          for ( levelID = 0; levelID < nlevels; ++ levelID )
+          streamDefRecord(streamID2, varID, levelID);
+	  streamWriteRecord(streamID2, pvar1->ptr,  pvar1->nmiss);
+              
+          if ( cdoDiag )
             {
-              streamDefRecord(streamID2, varID, levelID);
-              streamWriteRecord(streamID2, vars1[varID][levelID].ptr,  vars1[varID][levelID].nmiss);
-              if ( cdoDiag )
+              if ( samp1[varID][levelID].ptr )
                 {
-                  if ( samp1[varID][levelID].ptr )
-                    {
-                      streamDefRecord(streamID3, varID, levelID);
-                      streamWriteRecord(streamID3, samp1[varID][levelID].ptr, 0);
-                    }
+                  streamDefRecord(streamID3, varID, levelID);
+                  streamWriteRecord(streamID3, samp1[varID][levelID].ptr, 0);
                 }
             }
 	}
@@ -528,6 +583,7 @@ void *XTimstat(void *argument)
   if ( lvarstd ) field_free(vars2, vlistID1);
 
   dtlist_delete(dtlist);
+  Free(recinfo);
 
   if ( cdoDiag ) pstreamClose(streamID3);
   pstreamClose(streamID2);
diff --git a/src/YAR.c b/src/YAR.c
index 6869fa1..3c20746 100644
--- a/src/YAR.c
+++ b/src/YAR.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/Ydayarith.c b/src/Ydayarith.c
index aab9042..50568a4 100644
--- a/src/Ydayarith.c
+++ b/src/Ydayarith.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -30,24 +30,16 @@
 #include "pstream.h"
 
 
-#define  MAX_DAY   1232
+#define  MAX_DOY   373
 
 void *Ydayarith(void *argument)
 {
-  int operatorID;
-  int operfunc;
-  int streamID1, streamID2, streamID3;
-  int gridsize;
-  int nrecs, nvars, nlev, recID;
-  int tsID;
+  int nrecs;
   int varID, levelID;
-  int offset;
-  int vlistID1, vlistID2, vlistID3;
-  int taxisID1, taxisID2, taxisID3;
-  int vdate, year, mon, day;
-  field_t field1, field2;
-  int **varnmiss2[MAX_DAY];
-  double **vardata2[MAX_DAY];
+  int nmiss;
+  int year, month, day;
+  int **varnmiss2[MAX_DOY];
+  double **vardata2[MAX_DOY];
 
   cdoInitialize(argument);
 
@@ -56,69 +48,74 @@ void *Ydayarith(void *argument)
   cdoOperatorAdd("ydaymul", func_mul, 0, NULL);
   cdoOperatorAdd("ydaydiv", func_div, 0, NULL);
 
-  operatorID = cdoOperatorID();
-  operfunc = cdoOperatorF1(operatorID);
+  int operatorID = cdoOperatorID();
+  int operfunc = cdoOperatorF1(operatorID);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = vlistDuplicate(vlistID1);
 
   vlistCompare(vlistID1, vlistID2, CMP_ALL);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_t field1, field2;
   field_init(&field1);
   field_init(&field2);
   field1.ptr = (double*) Malloc(gridsize*sizeof(double));
   field2.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = vlistInqTaxis(vlistID2);
-  taxisID3 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = vlistInqTaxis(vlistID2);
+  int taxisID3 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID3, taxisID3);
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID3);
 
-  nvars  = vlistNvars(vlistID2);
+  int nvars = vlistNvars(vlistID2);
 
-  for ( day = 0; day < MAX_DAY ; day++ ) vardata2[day] = NULL;
+  for ( int dayoy = 0; dayoy < MAX_DOY ; dayoy++ ) vardata2[dayoy] = NULL;
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID2, tsID)) )
     {
-      vdate = taxisInqVdate(taxisID2);
+      int vdate = taxisInqVdate(taxisID2);
 
-      cdiDecodeDate(vdate, &year, &mon, &day);
-      day += mon*100;
-      if ( day < 0 || day >= MAX_DAY ) cdoAbort("Day %d out of range!", day);
+      cdiDecodeDate(vdate, &year, &month, &day);
 
-      if ( vardata2[day] != NULL ) cdoAbort("Day %d already allocatd!", day);
+      int dayoy = 0;
+      if ( month >= 1 && month <= 12 ) dayoy = (month-1)*31 + day;
 
-      vardata2[day]  = (double **) Malloc(nvars*sizeof(double *));
-      varnmiss2[day] = (int **) Malloc(nvars*sizeof(int *));
+      if ( dayoy < 0 || dayoy >= MAX_DOY )
+	cdoAbort("Day of year %d out of range (date=%d)!", dayoy, vdate);
+
+      if ( vardata2[dayoy] != NULL ) cdoAbort("Day of year %d already allocatd (date=%d)!", dayoy, vdate);
+
+      vardata2[dayoy]  = (double **) Malloc(nvars*sizeof(double *));
+      varnmiss2[dayoy] = (int **) Malloc(nvars*sizeof(int *));
 
       for ( varID = 0; varID < nvars; varID++ )
 	{
-	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
-	  nlev     = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
-	  vardata2[day][varID]  = (double*) Malloc(nlev*gridsize*sizeof(double));
-	  varnmiss2[day][varID] = (int*) Malloc(nlev*sizeof(int));
+          size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
+	  size_t nlev     = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
+	  vardata2[dayoy][varID]  = (double*) Malloc(nlev*gridsize*sizeof(double));
+	  varnmiss2[dayoy][varID] = (int*) Malloc(nlev*sizeof(int));
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID2, &varID, &levelID);
 
-	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
-	  offset   = gridsize*levelID;
+          size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
+	  size_t offset   = gridsize*levelID;
 
-	  streamReadRecord(streamID2, vardata2[day][varID]+offset, &field2.nmiss);
-	  varnmiss2[day][varID][levelID] = field2.nmiss;
+	  streamReadRecord(streamID2, vardata2[dayoy][varID]+offset, &nmiss);
+	  varnmiss2[dayoy][varID][levelID] = nmiss;
 	}
 
       tsID++;
@@ -128,26 +125,31 @@ void *Ydayarith(void *argument)
   tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      vdate = taxisInqVdate(taxisID1);
+      int vdate = taxisInqVdate(taxisID1);
+
+      cdiDecodeDate(vdate, &year, &month, &day);
+      
+      int dayoy = 0;
+      if ( month >= 1 && month <= 12 ) dayoy = (month-1)*31 + day;
 
-      cdiDecodeDate(vdate, &year, &mon, &day);
-      day += mon*100;
-      if ( day < 0 || day >= MAX_DAY ) cdoAbort("Day %d out of range!", day);
+      if ( dayoy < 0 || dayoy >= MAX_DOY )
+	cdoAbort("Day of year %d out of range (date=%d)!", dayoy, vdate);
 
       taxisCopyTimestep(taxisID3, taxisID1);
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  streamReadRecord(streamID1, field1.ptr, &field1.nmiss);
+	  streamReadRecord(streamID1, field1.ptr, &nmiss);
+          field1.nmiss = (size_t) nmiss;
 
-	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
-	  offset   = gridsize*levelID;
-	  if ( vardata2[day] == NULL ) cdoAbort("Day %d not found!", day);
-	  memcpy(field2.ptr, vardata2[day][varID]+offset, gridsize*sizeof(double));
-	  field2.nmiss = varnmiss2[day][varID][levelID];
+          size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
+          size_t offset   = gridsize*levelID;
+	  if ( vardata2[dayoy] == NULL ) cdoAbort("Day of year %d not found (date=%d)!", dayoy, vdate);
+	  memcpy(field2.ptr, vardata2[dayoy][varID]+offset, gridsize*sizeof(double));
+	  field2.nmiss = varnmiss2[dayoy][varID][levelID];
 
 	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
 	  field1.missval = vlistInqVarMissval(vlistID1, varID);
@@ -157,8 +159,9 @@ void *Ydayarith(void *argument)
 
 	  farfun(&field1, field2, operfunc);
 
+          nmiss = (int) field1.nmiss;
 	  streamDefRecord(streamID3, varID, levelID);
-	  streamWriteRecord(streamID3, field1.ptr, field1.nmiss);
+	  streamWriteRecord(streamID3, field1.ptr, nmiss);
 	}
       tsID++;
     }
@@ -167,17 +170,17 @@ void *Ydayarith(void *argument)
   streamClose(streamID2);
   streamClose(streamID1);
 
-  for ( day = 0; day < MAX_DAY ; day++ ) 
-    if ( vardata2[day] )
+  for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
+    if ( vardata2[dayoy] )
       {
 	for ( varID = 0; varID < nvars; varID++ )
 	  {
-	    Free(vardata2[day][varID]);
-	    Free(varnmiss2[day][varID]);
+	    Free(vardata2[dayoy][varID]);
+	    Free(varnmiss2[dayoy][varID]);
 	  }
 
-        Free(vardata2[day]);
-        Free(varnmiss2[day]);
+        Free(vardata2[dayoy]);
+        Free(varnmiss2[dayoy]);
       }
 
   if ( field1.ptr ) Free(field1.ptr);
diff --git a/src/Ydaypctl.c b/src/Ydaypctl.c
index e76b09c..b6239b1 100644
--- a/src/Ydaypctl.c
+++ b/src/Ydaypctl.c
@@ -34,26 +34,19 @@ int getmonthday(int date);
 
 void *Ydaypctl(void *argument)
 {
-  int gridsize;
   int varID;
   int recID;
   int gridID;
   int vdate, vtime;
   int year, month, day, dayoy;
-  int nrecs, nrecords;
+  int nrecs;
   int levelID;
-  int tsID;
-  int otsID;
-  long nsets[NDAY];
-  int streamID1, streamID2, streamID3, streamID4;
-  int vlistID1, vlistID2, vlistID3, vlistID4, taxisID1, taxisID2, taxisID3, taxisID4;
   int nmiss;
-  int nvars, nlevels;
-  int *recVarID, *recLevelID;
+  int nlevels;
   int vdates1[NDAY], vtimes1[NDAY];
-  int vdates2[NDAY], vtimes2[NDAY];
+  int vdates2[NDAY];
+  long nsets[NDAY];
   field_t **vars1[NDAY];
-  field_t field;
   HISTOGRAM_SET *hsets[NDAY];
 
   cdoInitialize(argument);
@@ -70,42 +63,44 @@ void *Ydaypctl(void *argument)
       nsets[dayoy] = 0;
     }
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
-  streamID3 = streamOpenRead(cdoStreamName(2));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID3 = streamOpenRead(cdoStreamName(2));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = streamInqVlist(streamID3);
-  vlistID4 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = streamInqVlist(streamID3);
+  int vlistID4 = vlistDuplicate(vlistID1);
 
   vlistCompare(vlistID1, vlistID2, CMP_ALL);
   vlistCompare(vlistID1, vlistID3, CMP_ALL);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = vlistInqTaxis(vlistID2);
-  taxisID3 = vlistInqTaxis(vlistID3);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = vlistInqTaxis(vlistID2);
+  int taxisID3 = vlistInqTaxis(vlistID3);
   /* TODO - check that time axes 2 and 3 are equal */
 
-  taxisID4 = taxisDuplicate(taxisID1);
+  int taxisID4 = taxisDuplicate(taxisID1);
   if ( taxisHasBounds(taxisID4) ) taxisDeleteBounds(taxisID4);
   vlistDefTaxis(vlistID4, taxisID4);
 
-  streamID4 = streamOpenWrite(cdoStreamName(3), cdoFiletype());
+  int streamID4 = streamOpenWrite(cdoStreamName(3), cdoFiletype());
 
   streamDefVlist(streamID4, vlistID4);
 
-  nvars    = vlistNvars(vlistID1);
-  nrecords = vlistNrecs(vlistID1);
+  int nvars    = vlistNvars(vlistID1);
+  int nrecords = vlistNrecs(vlistID1);
 
-  recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
+  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
+
+  field_t field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID2, tsID)) )
     {
       if ( nrecs != streamInqTimestep(streamID3, tsID) )
@@ -114,7 +109,7 @@ void *Ydaypctl(void *argument)
       vdate = taxisInqVdate(taxisID2);
       vtime = taxisInqVtime(taxisID2);
       
-      if ( vdate != taxisInqVdate(taxisID3) || vtime != taxisInqVtime(taxisID3) )
+      if ( vdate != taxisInqVdate(taxisID3) )
         cdoAbort("Verification dates at time step %d of %s and %s differ!", tsID+1, cdoStreamName(1)->args, cdoStreamName(2)->args);
         
       if ( cdoVerbose ) cdoPrint("process timestep: %d %d %d", tsID+1, vdate, vtime);
@@ -130,7 +125,6 @@ void *Ydaypctl(void *argument)
 	cdoAbort("Day %d out of range!", dayoy);
 
       vdates2[dayoy] = vdate;
-      vtimes2[dayoy] = vtime;
 
       if ( vars1[dayoy] == NULL )
 	{
@@ -210,14 +204,13 @@ void *Ydaypctl(void *argument)
       tsID++;
     }
 
-  otsID = 0;
+  int otsID = 0;
   for ( dayoy = 0; dayoy < NDAY; dayoy++ )
     if ( nsets[dayoy] )
       {
-        if ( vdates1[dayoy] != vdates2[dayoy] )
-          cdoAbort("Verification dates for day %d of %s, %s and %s are different!", dayoy, cdoStreamName(1)->args, cdoStreamName(2)->args, cdoStreamName(3)->args);
-        if ( vtimes1[dayoy] != vtimes2[dayoy] )
-          cdoAbort("Verification times for day %d of %s, %s and %s are different!", dayoy, cdoStreamName(1)->args, cdoStreamName(2)->args, cdoStreamName(3)->args);
+        if ( getmonthday(vdates1[dayoy]) !=  getmonthday(vdates2[dayoy]) )
+          cdoAbort("Verification dates for the day %d of %s and %s are different!",
+                   dayoy, cdoStreamName(0)->args, cdoStreamName(1)->args);
         
 	for ( varID = 0; varID < nvars; varID++ )
 	  {
diff --git a/src/Ydaystat.c b/src/Ydaystat.c
index d7edce8..51dfb5f 100644
--- a/src/Ydaystat.c
+++ b/src/Ydaystat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,9 @@
       Ydaystat   ydaymean        Multi-year daily mean
       Ydaystat   ydayavg         Multi-year daily average
       Ydaystat   ydayvar         Multi-year daily variance
-      Ydaystat   ydayvar1        Multi-year daily variance [Divisor is (n-1)]
+      Ydaystat   ydayvar1        Multi-year daily variance [Normalize by (n-1)]
       Ydaystat   ydaystd         Multi-year daily standard deviation
-      Ydaystat   ydaystd1        Multi-year daily standard deviation [Divisor is (n-1)]
+      Ydaystat   ydaystd1        Multi-year daily standard deviation [Normalize by (n-1)]
 */
 
 #include <cdi.h>
@@ -35,23 +35,19 @@
 #include "pstream.h"
 
 
-#define  NDAY       373
+#define  MAX_DOY       373
 
 
 void *Ydaystat(void *argument)
 {
-  int i;
-  int varID;
-  int recID;
-  int vdate, vtime;
-  int year, month, day, dayoy;
+  int varID, levelID;
+  int year, month, day;
   int nrecs;
-  int levelID;
-  long nsets[NDAY];
+  int nsets[MAX_DOY];
   int nmiss;
   int nlevel;
-  int vdates[NDAY], vtimes[NDAY];
-  field_t **vars1[NDAY], **vars2[NDAY], **samp1[NDAY];
+  int vdates[MAX_DOY], vtimes[MAX_DOY];
+  field_t **vars1[MAX_DOY], **vars2[MAX_DOY], **samp1[MAX_DOY];
 
   cdoInitialize(argument);
 
@@ -71,9 +67,9 @@ void *Ydaystat(void *argument)
   int lmean   = operfunc == func_mean || operfunc == func_avg;
   int lstd    = operfunc == func_std || operfunc == func_std1;
   int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  double divisor = operfunc == func_std1 || operfunc == func_var1;
+  int divisor = operfunc == func_std1 || operfunc == func_var1;
 
-  for ( dayoy = 0; dayoy < NDAY; dayoy++ )
+  for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
     {
       vars1[dayoy] = NULL;
       vars2[dayoy] = NULL;
@@ -111,20 +107,18 @@ void *Ydaystat(void *argument)
   int otsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      vdate = taxisInqVdate(taxisID1);
-      vtime = taxisInqVtime(taxisID1);
+      int vdate = taxisInqVdate(taxisID1);
+      int vtime = taxisInqVtime(taxisID1);
 
       if ( cdoVerbose ) cdoPrint("process timestep: %d %d %d", tsID+1, vdate, vtime);
 
       cdiDecodeDate(vdate, &year, &month, &day);
 
-      if ( month >= 1 && month <= 12 )
-	dayoy = (month-1)*31 + day;
-      else
-	dayoy = 0;
+      int dayoy = 0;
+      if ( month >= 1 && month <= 12 ) dayoy = (month-1)*31 + day;
 
-      if ( dayoy < 0 || dayoy >= NDAY )
-	cdoAbort("day of year %d out of range (date=%d)!", dayoy, vdate);
+      if ( dayoy < 0 || dayoy >= MAX_DOY )
+	cdoAbort("Day of year %d out of range (date=%d)!", dayoy, vdate);
 
       vdates[dayoy] = vdate;
       vtimes[dayoy] = vtime;
@@ -137,7 +131,7 @@ void *Ydaystat(void *argument)
 	    vars2[dayoy] = field_malloc(vlistID1, FIELD_PTR);
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -152,14 +146,14 @@ void *Ydaystat(void *argument)
 	  if ( nsets[dayoy] == 0 )
 	    {
 	      streamReadRecord(streamID1, vars1[dayoy][varID][levelID].ptr, &nmiss);
-	      vars1[dayoy][varID][levelID].nmiss = nmiss;
+	      vars1[dayoy][varID][levelID].nmiss = (size_t)nmiss;
 
 	      if ( nmiss > 0 || samp1[dayoy][varID][levelID].ptr )
 		{
 		  if ( samp1[dayoy][varID][levelID].ptr == NULL )
 		    samp1[dayoy][varID][levelID].ptr = (double*) Malloc(gridsize*sizeof(double));
 
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( int i = 0; i < gridsize; i++ )
 		    if ( DBL_IS_EQUAL(vars1[dayoy][varID][levelID].ptr[i],
 				      vars1[dayoy][varID][levelID].missval) )
 		      samp1[dayoy][varID][levelID].ptr[i] = 0;
@@ -169,7 +163,8 @@ void *Ydaystat(void *argument)
 	    }
 	  else
 	    {
-	      streamReadRecord(streamID1, field.ptr, &field.nmiss);
+	      streamReadRecord(streamID1, field.ptr, &nmiss);
+              field.nmiss   = (size_t)nmiss;
 	      field.grid    = vars1[dayoy][varID][levelID].grid;
 	      field.missval = vars1[dayoy][varID][levelID].missval;
 
@@ -178,11 +173,11 @@ void *Ydaystat(void *argument)
 		  if ( samp1[dayoy][varID][levelID].ptr == NULL )
 		    {
 		      samp1[dayoy][varID][levelID].ptr = (double*) Malloc(gridsize*sizeof(double));
-		      for ( i = 0; i < gridsize; i++ )
+		      for ( int i = 0; i < gridsize; i++ )
 			samp1[dayoy][varID][levelID].ptr[i] = nsets[dayoy];
 		    }
 		  
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( int i = 0; i < gridsize; i++ )
 		    if ( !DBL_IS_EQUAL(field.ptr[i], vars1[dayoy][varID][levelID].missval) )
 		      samp1[dayoy][varID][levelID].ptr[i]++;
 		}
@@ -214,13 +209,13 @@ void *Ydaystat(void *argument)
 
   // set the year to the minimum of years found on output timestep
   int outyear = 1e9;
-  for ( dayoy = 0; dayoy < NDAY; dayoy++ )
+  for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
     if ( nsets[dayoy] )
       {
         cdiDecodeDate(vdates[dayoy], &year, &month, &day);
         if ( year < outyear ) outyear = year;
       }
-  for ( dayoy = 0; dayoy < NDAY; dayoy++ )
+  for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
     if ( nsets[dayoy] )
       {
         cdiDecodeDate(vdates[dayoy], &year, &month, &day);
@@ -228,7 +223,7 @@ void *Ydaystat(void *argument)
         //  printf("vdates[%d] = %d  nsets = %d\n", dayoy, vdates[dayoy], nsets[dayoy]);
       }
 
-  for ( dayoy = 0; dayoy < NDAY; dayoy++ )
+  for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
     if ( nsets[dayoy] )
       {
 	if ( lmean )
@@ -272,7 +267,7 @@ void *Ydaystat(void *argument)
 	taxisDefVtime(taxisID2, vtimes[dayoy]);
 	streamDefTimestep(streamID2, otsID);
 
-	for ( recID = 0; recID < nrecords; recID++ )
+	for ( int recID = 0; recID < nrecords; recID++ )
 	  {
 	    varID   = recVarID[recID];
 	    levelID = recLevelID[recID];
@@ -281,13 +276,13 @@ void *Ydaystat(void *argument)
 
 	    streamDefRecord(streamID2, varID, levelID);
 	    streamWriteRecord(streamID2, vars1[dayoy][varID][levelID].ptr,
-			      vars1[dayoy][varID][levelID].nmiss);
+			      (int)vars1[dayoy][varID][levelID].nmiss);
 	  }
 
 	otsID++;
       }
 
-  for ( dayoy = 0; dayoy < NDAY; dayoy++ )
+  for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
     {
       if ( vars1[dayoy] != NULL )
 	{
diff --git a/src/Ydrunpctl.c b/src/Ydrunpctl.c
index 327d705..3d1654c 100644
--- a/src/Ydrunpctl.c
+++ b/src/Ydrunpctl.c
@@ -24,6 +24,7 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "calendar.h"
 #include "pstream.h"
 #include "percentiles_hist.h"
 
@@ -40,14 +41,11 @@ int getmonthday(int date)
 
 void *Ydrunpctl(void *argument)
 {
-  int gridsize;
   int varID;
   int recID;
   int gridID;
   int nrecs;
   int levelID;
-  int tsID;
-  int otsID;
   int inp, its;
   int nmiss;
   int nlevels;
@@ -58,7 +56,6 @@ void *Ydrunpctl(void *argument)
   int vdates2[NDAY] /*, vtimes2[NDAY]*/;
   int nsets[NDAY];
   int year, month, day, dayoy;
-  field_t field;
   HISTOGRAM_SET *hsets[NDAY];
     
   cdoInitialize(argument);
@@ -111,7 +108,9 @@ void *Ydrunpctl(void *argument)
   int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
   int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
+
+  field_t field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
@@ -124,7 +123,7 @@ void *Ydrunpctl(void *argument)
       vars1[its] = field_malloc(vlistID1, FIELD_PTR);
     }
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID2, tsID)) )
     {
       if ( nrecs != streamInqTimestep(streamID3, tsID) )
@@ -133,7 +132,7 @@ void *Ydrunpctl(void *argument)
       vdate = taxisInqVdate(taxisID2);
       vtime = taxisInqVtime(taxisID2);
       
-      if ( vdate != taxisInqVdate(taxisID3) || vtime != taxisInqVtime(taxisID3) )
+      if ( vdate != taxisInqVdate(taxisID3) )
         cdoAbort("Verification dates at time step %d of %s and %s differ!", tsID+1, cdoStreamName(1)->args, cdoStreamName(2)->args);
         
       if ( cdoVerbose ) cdoPrint("process timestep: %d %d %d", tsID+1, vdate, vtime);
@@ -286,13 +285,13 @@ void *Ydrunpctl(void *argument)
 	vdates1[dayoy] = cdiEncodeDate(outyear, month, day);
       }
   */
-  otsID = 0;
+  int otsID = 0;
   for ( dayoy = 0; dayoy < NDAY; dayoy++ )
     if ( nsets[dayoy] )
       {
         if ( getmonthday(vdates1[dayoy]) != getmonthday(vdates2[dayoy]) )
           cdoAbort("Verification dates for day %d of %s, %s and %s are different!",
-                   dayoy, cdoStreamName(1)->args, cdoStreamName(2)->args, cdoStreamName(3)->args);
+                   dayoy, cdoStreamName(0)->args, cdoStreamName(1)->args);
 
 	for ( varID = 0; varID < nvars; varID++ )
 	  {
diff --git a/src/Ydrunstat.c b/src/Ydrunstat.c
index 2d00b2a..a4acdc1 100644
--- a/src/Ydrunstat.c
+++ b/src/Ydrunstat.c
@@ -24,14 +24,15 @@
       Ydrunstat    ydrunmean         Multi-year daily running mean
       Ydrunstat    ydrunavg          Multi-year daily running average
       Ydrunstat    ydrunvar          Multi-year daily running variance
-      Ydrunstat    ydrunvar1         Multi-year daily running variance [Divisor is (n-1)]
+      Ydrunstat    ydrunvar1         Multi-year daily running variance [Normalize by (n-1)]
       Ydrunstat    ydrunstd          Multi-year daily running standard deviation
-      Ydrunstat    ydrunstd1         Multi-year daily running standard deviation [Divisor is (n-1)]
+      Ydrunstat    ydrunstd1         Multi-year daily running standard deviation [Normalize by (n-1)]
 */
 
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "calendar.h"
 #include "pstream.h"
 
 
@@ -427,9 +428,7 @@ void ydstatFinalize(YDAY_STATS *stats, int operfunc)
 {
   int varID, levelID, nvars, nlevels;
   int dayoy;
-  double divisor;
-
-  divisor = operfunc == func_std1 || operfunc == func_var1;
+  int divisor = operfunc == func_std1 || operfunc == func_var1;
 
   nvars = vlistNvars(stats->vlist);
   
diff --git a/src/Yearmonstat.c b/src/Yearmonstat.c
index eb35e3e..f341dbe 100644
--- a/src/Yearmonstat.c
+++ b/src/Yearmonstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "calendar.h"
 #include "pstream.h"
 
 
@@ -136,7 +137,7 @@ void *Yearmonstat(void *argument)
 	      if ( nsets == 0 )
 		{
 		  streamReadRecord(streamID1, vars1[varID][levelID].ptr, &nmiss);
-		  vars1[varID][levelID].nmiss = nmiss;
+		  vars1[varID][levelID].nmiss = (size_t) nmiss;
 
 		  farcmul(&vars1[varID][levelID], dpm);
 
@@ -154,7 +155,8 @@ void *Yearmonstat(void *argument)
 		}
 	      else
 		{
-		  streamReadRecord(streamID1, field.ptr, &field.nmiss);
+		  streamReadRecord(streamID1, field.ptr, &nmiss);
+                  field.nmiss   = (size_t) nmiss;
 		  field.grid    = vars1[varID][levelID].grid;
 		  field.missval = vars1[varID][levelID].missval;
 
@@ -219,7 +221,7 @@ void *Yearmonstat(void *argument)
 	  if ( otsID && vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
 	  streamDefRecord(streamID2, varID, levelID);
-	  streamWriteRecord(streamID2, vars1[varID][levelID].ptr,  vars1[varID][levelID].nmiss);
+	  streamWriteRecord(streamID2, vars1[varID][levelID].ptr,  (int)vars1[varID][levelID].nmiss);
 	}
 
       if ( nrecs == 0 ) break;
diff --git a/src/Yhourarith.c b/src/Yhourarith.c
index 41e080e..2e3f16a 100644
--- a/src/Yhourarith.c
+++ b/src/Yhourarith.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -71,6 +71,7 @@ void *Yhourarith(void *argument)
   int vlistID1, vlistID2, vlistID3;
   int taxisID1, taxisID2, taxisID3;
   int vdate, vtime;
+  int nmiss;
   int houroy;
   field_t field1, field2;
   int **varnmiss2[MAX_HOUR];
@@ -142,8 +143,8 @@ void *Yhourarith(void *argument)
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
 	  offset   = gridsize*levelID;
 
-	  streamReadRecord(streamID2, vardata2[houroy][varID]+offset, &field2.nmiss);
-	  varnmiss2[houroy][varID][levelID] = field2.nmiss;
+	  streamReadRecord(streamID2, vardata2[houroy][varID]+offset, &nmiss);
+	  varnmiss2[houroy][varID][levelID] = nmiss;
 	}
 
       tsID++;
@@ -166,23 +167,22 @@ void *Yhourarith(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  streamReadRecord(streamID1, field1.ptr, &field1.nmiss);
+	  streamReadRecord(streamID1, field1.ptr, &nmiss);
+          field1.nmiss = (size_t) nmiss;
+	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
+	  field1.missval = vlistInqVarMissval(vlistID1, varID);
 
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
 	  offset   = gridsize*levelID;
 	  memcpy(field2.ptr, vardata2[houroy][varID]+offset, gridsize*sizeof(double));
 	  field2.nmiss   = varnmiss2[houroy][varID][levelID];
-
-	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
-	  field1.missval = vlistInqVarMissval(vlistID1, varID);
-
 	  field2.grid    = vlistInqVarGrid(vlistID2, varID);
 	  field2.missval = vlistInqVarMissval(vlistID2, varID);
 
 	  farfun(&field1, field2, operfunc);
 
 	  streamDefRecord(streamID3, varID, levelID);
-	  streamWriteRecord(streamID3, field1.ptr, field1.nmiss);
+	  streamWriteRecord(streamID3, field1.ptr, (int)field1.nmiss);
 	}
 
       tsID++;
diff --git a/src/Yhourstat.c b/src/Yhourstat.c
index 8eddbb0..6b6c939 100644
--- a/src/Yhourstat.c
+++ b/src/Yhourstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,9 @@
       Yhourstat   yhourmean        Multi-year hourly mean
       Yhourstat   yhouravg         Multi-year hourly average
       Yhourstat   yhourvar         Multi-year hourly variance
-      Yhourstat   yhourvar1        Multi-year hourly variance [Divisor is (n-1)]
+      Yhourstat   yhourvar1        Multi-year hourly variance [Normalize by (n-1)]
       Yhourstat   yhourstd         Multi-year hourly standard deviation
-      Yhourstat   yhourstd1        Multi-year hourly standard deviation [Divisor is (n-1)]
+      Yhourstat   yhourstd1        Multi-year hourly standard deviation [Normalize by (n-1)]
 */
 
 #include <cdi.h>
@@ -77,7 +77,7 @@ void *Yhourstat(void *argument)
   int levelID;
   int tsID;
   int otsID;
-  long nsets[MAX_HOUR];
+  int nsets[MAX_HOUR];
   int streamID1, streamID2;
   int vlistID1, vlistID2, taxisID1, taxisID2;
   int nmiss;
@@ -85,7 +85,6 @@ void *Yhourstat(void *argument)
   int *recVarID, *recLevelID;
   int vdates[MAX_HOUR], vtimes[MAX_HOUR];
   int lmean = FALSE, lvarstd = FALSE, lstd = FALSE;
-  double divisor;
   field_t **vars1[MAX_HOUR], **vars2[MAX_HOUR], **samp1[MAX_HOUR];
   field_t field;
 
@@ -107,7 +106,7 @@ void *Yhourstat(void *argument)
   lmean   = operfunc == func_mean || operfunc == func_avg;
   lstd    = operfunc == func_std || operfunc == func_std1;
   lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  divisor = operfunc == func_std1 || operfunc == func_var1;
+  int divisor = operfunc == func_std1 || operfunc == func_var1;
 
   for ( houroy = 0; houroy < MAX_HOUR; ++houroy )
     {
@@ -178,7 +177,7 @@ void *Yhourstat(void *argument)
 	  if ( nsets[houroy] == 0 )
 	    {
 	      streamReadRecord(streamID1, vars1[houroy][varID][levelID].ptr, &nmiss);
-	      vars1[houroy][varID][levelID].nmiss = nmiss;
+	      vars1[houroy][varID][levelID].nmiss = (size_t) nmiss;
 
 	      if ( nmiss > 0 || samp1[houroy][varID][levelID].ptr )
 		{
@@ -195,7 +194,8 @@ void *Yhourstat(void *argument)
 	    }
 	  else
 	    {
-	      streamReadRecord(streamID1, field.ptr, &field.nmiss);
+	      streamReadRecord(streamID1, field.ptr, &nmiss);
+              field.nmiss   = (size_t) nmiss;
 	      field.grid    = vars1[houroy][varID][levelID].grid;
 	      field.missval = vars1[houroy][varID][levelID].missval;
 
@@ -291,7 +291,7 @@ void *Yhourstat(void *argument)
 
 	    streamDefRecord(streamID2, varID, levelID);
 	    streamWriteRecord(streamID2, vars1[houroy][varID][levelID].ptr,
-			      vars1[houroy][varID][levelID].nmiss);
+			      (int)vars1[houroy][varID][levelID].nmiss);
 	  }
 
 	otsID++;
diff --git a/src/Ymonarith.c b/src/Ymonarith.c
index 3b4e170..073456a 100644
--- a/src/Ymonarith.c
+++ b/src/Ymonarith.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -44,6 +44,7 @@ void *Ymonarith(void *argument)
   int tsID;
   int varID, levelID;
   int offset;
+  int nmiss;
   int vdate, year, mon, day;
   field_t field1, field2;
   int **varnmiss2[MAX_MON];
@@ -133,8 +134,8 @@ void *Ymonarith(void *argument)
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
 	  offset   = gridsize*levelID;
 
-	  streamReadRecord(streamID2, vardata2[mon][varID]+offset, &field2.nmiss);
-	  varnmiss2[mon][varID][levelID] = field2.nmiss;
+	  streamReadRecord(streamID2, vardata2[mon][varID]+offset, &nmiss);
+	  varnmiss2[mon][varID][levelID] = nmiss;
 	}
 
       tsID++;
@@ -167,24 +168,23 @@ void *Ymonarith(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  streamReadRecord(streamID1, field1.ptr, &field1.nmiss);
-
+	  streamReadRecord(streamID1, field1.ptr, &nmiss);
+          field1.nmiss = (size_t) nmiss;
+	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
+	  field1.missval = vlistInqVarMissval(vlistID1, varID);
+          
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
 	  offset   = gridsize*levelID;
 
 	  memcpy(field2.ptr, vardata2[mon][varID]+offset, gridsize*sizeof(double));
 	  field2.nmiss = varnmiss2[mon][varID][levelID];
-
-	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
-	  field1.missval = vlistInqVarMissval(vlistID1, varID);
-
 	  field2.grid    = vlistInqVarGrid(vlistID2, varID);
 	  field2.missval = vlistInqVarMissval(vlistID2, varID);
 
 	  farfun(&field1, field2, operfunc);
 
 	  streamDefRecord(streamID3, varID, levelID);
-	  streamWriteRecord(streamID3, field1.ptr, field1.nmiss);
+	  streamWriteRecord(streamID3, field1.ptr, (int)field1.nmiss);
 	}
       tsID++;
     }
diff --git a/src/Ymonpctl.c b/src/Ymonpctl.c
index 92b32b0..3ec0c8e 100644
--- a/src/Ymonpctl.c
+++ b/src/Ymonpctl.c
@@ -37,28 +37,21 @@ int getmonth(int date)
   return month;
 }
 
+
 void *Ymonpctl(void *argument)
 {
-  int gridsize;
   int varID;
   int recID;
   int gridID;
   int vdate, vtime;
   int year, month, day;
-  int nrecs, nrecords;
   int levelID;
-  int tsID;
-  int otsID;
-  long nsets[NMONTH];
-  int streamID1, streamID2, streamID3, streamID4;
-  int vlistID1, vlistID2, vlistID3, vlistID4, taxisID1, taxisID2, taxisID3, taxisID4;
   int nmiss;
-  int nvars, nlevels;
-  int *recVarID, *recLevelID;
+  int nrecs, nlevels;
   int vdates1[NMONTH], vtimes1[NMONTH];
   int vdates2[NMONTH];
+  long nsets[NMONTH];
   field_t **vars1[NMONTH];
-  field_t field;
   HISTOGRAM_SET *hsets[NMONTH];
 
   cdoInitialize(argument);
@@ -75,42 +68,44 @@ void *Ymonpctl(void *argument)
       nsets[month] = 0;
     }
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
-  streamID3 = streamOpenRead(cdoStreamName(2));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID3 = streamOpenRead(cdoStreamName(2));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = streamInqVlist(streamID3);
-  vlistID4 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = streamInqVlist(streamID3);
+  int vlistID4 = vlistDuplicate(vlistID1);
 
   vlistCompare(vlistID1, vlistID2, CMP_ALL);
   vlistCompare(vlistID1, vlistID3, CMP_ALL);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = vlistInqTaxis(vlistID2);
-  taxisID3 = vlistInqTaxis(vlistID3);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = vlistInqTaxis(vlistID2);
+  int taxisID3 = vlistInqTaxis(vlistID3);
   /* TODO - check that time axes 2 and 3 are equal */
 
-  taxisID4 = taxisDuplicate(taxisID1);
+  int taxisID4 = taxisDuplicate(taxisID1);
   if ( taxisHasBounds(taxisID4) ) taxisDeleteBounds(taxisID4);
   vlistDefTaxis(vlistID4, taxisID4);
 
-  streamID4 = streamOpenWrite(cdoStreamName(3), cdoFiletype());
+  int streamID4 = streamOpenWrite(cdoStreamName(3), cdoFiletype());
 
   streamDefVlist(streamID4, vlistID4);
 
-  nvars    = vlistNvars(vlistID1);
-  nrecords = vlistNrecs(vlistID1);
+  int nvars    = vlistNvars(vlistID1);
+  int nrecords = vlistNrecs(vlistID1);
 
-  recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
+  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
+
+  field_t field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID2, tsID)) )
     {
       if ( nrecs != streamInqTimestep(streamID3, tsID) )
@@ -119,7 +114,7 @@ void *Ymonpctl(void *argument)
       vdate = taxisInqVdate(taxisID2);
       vtime = taxisInqVtime(taxisID2);
       
-      if ( vdate != taxisInqVdate(taxisID3) || vtime != taxisInqVtime(taxisID3) )
+      if ( vdate != taxisInqVdate(taxisID3) )
         cdoAbort("Verification dates at time step %d of %s and %s differ!", tsID+1, cdoStreamName(1)->args, cdoStreamName(2)->args);
         
       if ( cdoVerbose ) cdoPrint("process timestep: %d %d %d", tsID+1, vdate, vtime);
@@ -202,13 +197,13 @@ void *Ymonpctl(void *argument)
       tsID++;
     }
 
-  otsID = 0;
+  int otsID = 0;
   for ( month = 0; month < NMONTH; month++ )
     if ( nsets[month] )
       {
         if ( getmonth(vdates1[month]) != getmonth(vdates2[month]) )
-          cdoAbort("Verification dates for month %d of %s, %s and %s are different!",
-                   month, cdoStreamName(1)->args, cdoStreamName(2)->args, cdoStreamName(3)->args);
+          cdoAbort("Verification dates for the month %d of %s and %s are different!",
+                   month, cdoStreamName(0)->args, cdoStreamName(1)->args);
 
 	for ( varID = 0; varID < nvars; varID++ )
 	  {
diff --git a/src/Ymonstat.c b/src/Ymonstat.c
index de72f65..0dd2db4 100644
--- a/src/Ymonstat.c
+++ b/src/Ymonstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,9 @@
       Ymonstat   ymonmean        Multi-year monthly mean
       Ymonstat   ymonavg         Multi-year monthly average
       Ymonstat   ymonvar         Multi-year monthly variance
-      Ymonstat   ymonvar1        Multi-year monthly variance [Divisor is (n-1)]
+      Ymonstat   ymonvar1        Multi-year monthly variance [Normalize by (n-1)]
       Ymonstat   ymonstd         Multi-year monthly standard deviation
-      Ymonstat   ymonstd1        Multi-year monthly standard deviation [Divisor is (n-1)]
+      Ymonstat   ymonstd1        Multi-year monthly standard deviation [Normalize by (n-1)]
 */
 
 
@@ -67,7 +67,7 @@ void *Ymonstat(void *argument)
   int levelID;
   int tsID;
   int otsID;
-  long nsets[NMONTH];
+  int nsets[NMONTH];
   int streamID1, streamID2;
   int vlistID1, vlistID2, taxisID1, taxisID2;
   int nmiss;
@@ -77,7 +77,6 @@ void *Ymonstat(void *argument)
   int mon[NMONTH];
   int nmon = 0;
   int lmean = FALSE, lvarstd = FALSE, lstd = FALSE;
-  double divisor;
   field_t **vars1[NMONTH], **vars2[NMONTH], **samp1[NMONTH];
   field_t field;
 
@@ -99,7 +98,7 @@ void *Ymonstat(void *argument)
   lmean   = operfunc == func_mean || operfunc == func_avg;
   lstd    = operfunc == func_std || operfunc == func_std1;
   lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  divisor = operfunc == func_std1 || operfunc == func_var1;
+  int divisor = operfunc == func_std1 || operfunc == func_var1;
 
   for ( month = 0; month < NMONTH; month++ )
     {
@@ -174,7 +173,7 @@ void *Ymonstat(void *argument)
 	  if ( nsets[month] == 0 )
 	    {
 	      streamReadRecord(streamID1, vars1[month][varID][levelID].ptr, &nmiss);
-	      vars1[month][varID][levelID].nmiss = nmiss;
+	      vars1[month][varID][levelID].nmiss = (size_t) nmiss;
 
 	      if ( nmiss > 0 || samp1[month][varID][levelID].ptr )
 		{
@@ -191,7 +190,8 @@ void *Ymonstat(void *argument)
 	    }
 	  else
 	    {
-	      streamReadRecord(streamID1, field.ptr, &field.nmiss);
+	      streamReadRecord(streamID1, field.ptr, &nmiss);
+              field.nmiss   = (size_t) nmiss;
 	      field.grid    = vars1[month][varID][levelID].grid;
 	      field.missval = vars1[month][varID][levelID].missval;
 
@@ -315,7 +315,7 @@ void *Ymonstat(void *argument)
 
 	  streamDefRecord(streamID2, varID, levelID);
 	  streamWriteRecord(streamID2, vars1[month][varID][levelID].ptr,
-			    vars1[month][varID][levelID].nmiss);
+			    (int)vars1[month][varID][levelID].nmiss);
 	}
 
       otsID++;
diff --git a/src/Yseaspctl.c b/src/Yseaspctl.c
index 5501679..014c697 100644
--- a/src/Yseaspctl.c
+++ b/src/Yseaspctl.c
@@ -40,6 +40,7 @@ void set_date(int vdate_new, int vtime_new, date_time_t *datetime);
 
 int getmonthday(int date);
 
+
 void *Yseaspctl(void *argument)
 {
   int varID;
@@ -49,9 +50,9 @@ void *Yseaspctl(void *argument)
   int year, month, day, seas;
   int nrecs;
   int levelID;
-  long nsets[NSEAS];
   int nmiss;
   int nlevels;
+  long nsets[NSEAS];
   date_time_t datetime1[NSEAS], datetime2[NSEAS];
   field_t **vars1[NSEAS];
   HISTOGRAM_SET *hsets[NSEAS];
@@ -120,7 +121,7 @@ void *Yseaspctl(void *argument)
       vdate = taxisInqVdate(taxisID2);
       vtime = taxisInqVtime(taxisID2);
       
-      if ( vdate != taxisInqVdate(taxisID3) || vtime != taxisInqVtime(taxisID3) )
+      if ( vdate != taxisInqVdate(taxisID3) )
         cdoAbort("Verification dates at time step %d of %s and %s differ!", tsID+1, cdoStreamName(1)->args, cdoStreamName(2)->args);
         
       if ( cdoVerbose ) cdoPrint("process timestep: %d %d %d", tsID+1, vdate, vtime);
@@ -212,8 +213,8 @@ void *Yseaspctl(void *argument)
     if ( nsets[seas] )
       {
         if ( getmonthday(datetime1[seas].vdate) != getmonthday(datetime2[seas].vdate) )
-          cdoAbort("Verification dates for season %d of %s, %s and %s are different!",
-                   seas, cdoStreamName(1)->args, cdoStreamName(2)->args, cdoStreamName(3)->args);
+          cdoAbort("Verification dates for the season %d of %s and %s are different!",
+                   seas, cdoStreamName(0)->args, cdoStreamName(1)->args);
 
 	for ( varID = 0; varID < nvars; varID++ )
 	  {
diff --git a/src/Yseasstat.c b/src/Yseasstat.c
index 18559c2..e8795e9 100644
--- a/src/Yseasstat.c
+++ b/src/Yseasstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,9 @@
       Yseasstat  yseasmean       Multi-year seasonally mean
       Yseasstat  yseasavg        Multi-year seasonally average
       Yseasstat  yseasvar        Multi-year seasonally variance
-      Yseasstat  yseasvar1       Multi-year seasonally variance [Divisor is (n-1)]
+      Yseasstat  yseasvar1       Multi-year seasonally variance [Normalize by (n-1)]
       Yseasstat  yseasstd        Multi-year seasonally standard deviation
-      Yseasstat  yseasstd1       Multi-year seasonally standard deviation [Divisor is (n-1)]
+      Yseasstat  yseasstd1       Multi-year seasonally standard deviation [Normalize by (n-1)]
 */
 
 #include <cdi.h>
@@ -68,7 +68,7 @@ void *Yseasstat(void *argument)
   int year, month, day, seas;
   int nrecs;
   int levelID;
-  long nsets[NSEAS];
+  int nsets[NSEAS];
   int nmiss;
   int nlevel;
   date_time_t datetime[NSEAS];
@@ -102,7 +102,7 @@ void *Yseasstat(void *argument)
   int lmean   = operfunc == func_mean || operfunc == func_avg;
   int lstd    = operfunc == func_std || operfunc == func_std1;
   int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  double divisor = operfunc == func_std1 || operfunc == func_var1;
+  int divisor = operfunc == func_std1 || operfunc == func_var1;
 
   int streamID1 = streamOpenRead(cdoStreamName(0));
 
@@ -165,7 +165,7 @@ void *Yseasstat(void *argument)
 	  if ( nsets[seas] == 0 )
 	    {
 	      streamReadRecord(streamID1, vars1[seas][varID][levelID].ptr, &nmiss);
-	      vars1[seas][varID][levelID].nmiss = nmiss;
+	      vars1[seas][varID][levelID].nmiss = (size_t)nmiss;
 
 	      if ( nmiss > 0 || samp1[seas][varID][levelID].ptr )
 		{
@@ -182,7 +182,8 @@ void *Yseasstat(void *argument)
 	    }
 	  else
 	    {
-	      streamReadRecord(streamID1, field.ptr, &field.nmiss);
+	      streamReadRecord(streamID1, field.ptr, &nmiss);
+              field.nmiss   = (size_t)nmiss;
 	      field.grid    = vars1[seas][varID][levelID].grid;
 	      field.missval = vars1[seas][varID][levelID].missval;
 
@@ -278,7 +279,7 @@ void *Yseasstat(void *argument)
 
 	    streamDefRecord(streamID2, varID, levelID);
 	    streamWriteRecord(streamID2, vars1[seas][varID][levelID].ptr,
-			      vars1[seas][varID][levelID].nmiss);
+			      (int)vars1[seas][varID][levelID].nmiss);
 	  }
 
 	otsID++;
diff --git a/src/Zonstat.c b/src/Zonstat.c
index 59bec47..cda3eed 100644
--- a/src/Zonstat.c
+++ b/src/Zonstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.1
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -25,9 +25,9 @@
       Zonstat    zonmean         Zonal mean
       Zonstat    zonavg          Zonal average
       Zonstat    zonstd          Zonal standard deviation
-      Zonstat    zonstd1         Zonal standard deviation [Divisor is (n-1)]
+      Zonstat    zonstd1         Zonal standard deviation [Normalize by (n-1)]
       Zonstat    zonvar          Zonal variance
-      Zonstat    zonvar1         Zonal variance [Divisor is (n-1)]
+      Zonstat    zonvar1         Zonal variance [Normalize by (n-1)]
       Zonstat    zonpctl         Zonal percentiles
 */
 
@@ -44,6 +44,7 @@ void *Zonstat(void *argument)
   int gridID1 = -1, gridID2 = -1;
   int zongridID = -1;
   int index;
+  int nmiss;
   int recID, nrecs;
   int varID, levelID;
 
@@ -153,8 +154,9 @@ void *Zonstat(void *argument)
       for ( recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  streamReadRecord(streamID1, field1.ptr, &field1.nmiss);
+	  streamReadRecord(streamID1, field1.ptr, &nmiss);
 
+          field1.nmiss   = (size_t) nmiss;
 	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
 	  field1.missval = vlistInqVarMissval(vlistID1, varID);
 	  field2.missval = vlistInqVarMissval(vlistID1, varID);
@@ -173,7 +175,7 @@ void *Zonstat(void *argument)
 	    }
 
 	  streamDefRecord(streamID2, varID,  levelID);
-	  streamWriteRecord(streamID2, field2.ptr, field2.nmiss);
+	  streamWriteRecord(streamID2, field2.ptr, (int)field2.nmiss);
 	}
       tsID++;
     }
diff --git a/src/after_sptrans.c b/src/after_sptrans.c
index 8492960..777feb1 100644
--- a/src/after_sptrans.c
+++ b/src/after_sptrans.c
@@ -18,7 +18,13 @@
 #define  HAVE_OPENMP4  1
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 void gaussaw(double *pa, double *pw, size_t nlat);
+#if defined (__cplusplus)
+}
+#endif
 
 static
 void jspleg1(double *pleg, double plat, int ktrunc, double *work)
diff --git a/libcdi/src/calendar.h b/src/calendar.h
similarity index 80%
copy from libcdi/src/calendar.h
copy to src/calendar.h
index c5836e9..cd7ea77 100644
--- a/libcdi/src/calendar.h
+++ b/src/calendar.h
@@ -1,15 +1,22 @@
 #ifndef _CALENDAR_H
 #define _CALENDAR_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 void encode_caldaysec(int calendar, int year, int month, int day, int hour, int minute, int second,
 		      int *julday, int *secofday);
-void decode_caldaysec(int calendar, int julday, int secofday, 
+void decode_caldaysec(int calendar, int julday, int secofday,
 		      int *year, int *month, int *day, int *hour, int *minute, int *second);
 
 int calendar_dpy(int calendar);
 int days_per_year(int calendar, int year);
 int days_per_month(int calendar, int year, int month);
 
+#if defined (__cplusplus)
+}
+#endif
 
 #endif  /* _CALENDAR_H */
 /*
diff --git a/src/cdi_uuid.h b/src/cdi_uuid.h
new file mode 100644
index 0000000..6f215ca
--- /dev/null
+++ b/src/cdi_uuid.h
@@ -0,0 +1,42 @@
+#ifndef CDI_UUID_H
+#define CDI_UUID_H
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "cdi.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline int cdiUUIDIsNull(const unsigned char uuid[])
+{
+  int isNull = 1;
+  for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
+    isNull &= (uuid[i] == 0);
+  return isNull;
+}
+
+void cdiCreateUUID(unsigned char uuid[CDI_UUID_SIZE]);
+
+void cdiUUID2Str(const unsigned char uuid[], char uuidstr[]);
+int cdiStr2UUID(const char *uuidstr, unsigned char uuid[]);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif
+
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
diff --git a/src/cdo.c b/src/cdo.c
index 4105d2e..29a65a3 100644
--- a/src/cdo.c
+++ b/src/cdo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,12 @@
 //#define _XOPEN_SOURCE 600 /* gethostname */
 #endif
 
+#if defined (HAVE_EXECINFO_H)
+#include <execinfo.h>
+#endif
+
+#include <signal.h>
+#include <fenv.h>
 #include <ctype.h>
 /*#include <malloc.h>*/ /* mallopt and malloc_stats */
 #include <sys/stat.h>
@@ -73,6 +79,7 @@ static int numThreads = 0;
 static int timer_total;
 static int CDO_netcdf_hdr_pad = 0;
 static int CDO_Rusage = 0;
+static const char *username;
 
 void gridsearch_set_method(const char *methodstr);
 
@@ -96,6 +103,59 @@ void gridsearch_set_method(const char *methodstr);
           } \
       }
 
+#define ISME  (strcmp(username, "\x6d\x32\x31\x34\x30\x30\x33") == 0)
+
+static
+void cdo_stackframe(void)
+{
+#if defined HAVE_EXECINFO_H && defined HAVE_BACKTRACE
+  void *callstack[32];
+  int frames = backtrace(callstack, 32);
+  char **messages = backtrace_symbols(callstack, frames);
+
+  fprintf(stderr, "[bt] Execution path:\n");
+  if ( messages ) {
+    for ( int i = 0; i < frames; ++i )
+      fprintf(stderr, "[bt] %s\n", messages[i]);
+    free(messages);
+  }
+#endif
+}
+
+static
+int cdo_feenableexcept(int excepts)
+{
+#if defined HAVE_FEENABLEEXCEPT
+  int feenableexcept(int);
+  int old_excepts = feenableexcept(excepts);
+  return old_excepts;
+#else
+  static fenv_t fenv;
+  unsigned new_excepts = ((unsigned)excepts) & FE_ALL_EXCEPT;
+  int old_excepts = -1;  // previous masks
+
+  if ( fegetenv(&fenv) ) return -1;
+#if defined(HAVE_FENV_T___CONTROL) && defined(HAVE_FENV_T___MXCSR)
+  old_excepts = (int) (fenv.__control & FE_ALL_EXCEPT);
+
+  // unmask
+  fenv.__control &= ~new_excepts;
+  fenv.__mxcsr   &= ~(new_excepts << 7);
+#endif
+
+  return ( fesetenv(&fenv) ? -1 : (int)old_excepts );
+#endif
+}
+
+static
+void cdo_sig_handler(int signo)
+{
+  if ( signo == SIGFPE )
+    {
+      cdo_stackframe();
+      cdoAbort("floating-point exception!");
+    }
+}
 
 static
 void cdo_version(void)
@@ -143,14 +203,19 @@ void cdo_usage(void)
   fprintf(stderr, "    -b <nbits>     Set the number of bits for the output precision\n");
   fprintf(stderr, "                   (I8/I16/I32/F32/F64 for nc/nc2/nc4/nc4c; F32/F64 for grb2/srv/ext/ieg; P1 - P24 for grb/grb2)\n");
   fprintf(stderr, "                   Add L or B to set the byteorder to Little or Big endian\n");
+  if ( ISME )
+    {
+      fprintf(stderr, "    --enableexcept <except>\n");
+      fprintf(stderr, "                   Set individual floating-point traps (DIVBYZERO, INEXACT, INVALID, OVERFLOW, UNDERFLOW, ALL_EXCEPT)\n");
+    }
   fprintf(stderr, "    -f, --format <format>\n");
   fprintf(stderr, "                   Format of the output file. (grb/grb2/nc/nc2/nc4/nc4c/srv/ext/ieg)\n");
   fprintf(stderr, "    -g <grid>      Set default grid name or file. Available grids: \n");
   fprintf(stderr, "                   n<N>, t<RES>, tl<RES>, global_<DXY>, r<NX>x<NY>, g<NX>x<NY>, gme<NI>, lon=<LON>/lat=<LAT>\n");
   fprintf(stderr, "    -h, --help     Help information for the operators\n");
-  fprintf(stderr, "    --history      Do not append to netCDF \"history\" global attribute\n");
+  fprintf(stderr, "    --history      Do not append to NetCDF \"history\" global attribute\n");
   fprintf(stderr, "    --netcdf_hdr_pad, --hdr_pad, --header_pad <nbr>\n");
-  fprintf(stderr, "                   Pad netCDF output header with nbr bytes\n");
+  fprintf(stderr, "                   Pad NetCDF output header with nbr bytes\n");
   /*
   fprintf(stderr, "    -i <inst>      Institution name/file\n");
   fprintf(stderr, "                   Predefined instituts: ");
@@ -166,19 +231,20 @@ void cdo_usage(void)
   fprintf(stderr, "    -m <missval>   Set the default missing value (default: %g)\n", cdiInqMissval());
   fprintf(stderr, "    --no_warnings  Inhibit warning messages\n");
   fprintf(stderr, "    -O             Overwrite existing output file, if checked\n");
+  fprintf(stderr, "    --operators    List of all operators\n");
 #if defined(_OPENMP)
   fprintf(stderr, "    -P <nthreads>  Set number of OpenMP threads\n");
 #endif
   fprintf(stderr, "    --percentile <method>\n");
   fprintf(stderr, "                   Percentile method: nrank, nist, numpy, numpy_lower, numpy_higher, numpy_nearest\n");
-  fprintf(stderr, "    -Q             Alphanumeric sorting of netCDF parameter names\n");
-  fprintf(stderr, "    --reduce_dim   Reduce netCDF dimensions (module: TIMSTAT, FLDSTAT)\n");
-  fprintf(stderr, "    -R, --regular  Convert GRIB1 data from reduced to regular grid (only with cgribex)\n");
+  fprintf(stderr, "    -Q             Alphanumeric sorting of NetCDF parameter names\n");
+  fprintf(stderr, "    --reduce_dim   Reduce NetCDF dimensions (module: TIMSTAT, FLDSTAT)\n");
+  fprintf(stderr, "    -R, --regular  Convert GRIB1 data from reduced to regular grid (cgribex only)\n");
   fprintf(stderr, "    -r             Generate a relative time axis\n");
   fprintf(stderr, "    -S             Create an extra output stream for the module TIMSTAT. This stream\n");
   fprintf(stderr, "                   contains the number of non missing values for each output period.\n");
   fprintf(stderr, "    -s, --silent   Silent mode\n");
-  fprintf(stderr, "    -t <partab>    Set GRIB1 default parameter table name or file\n");
+  fprintf(stderr, "    -t <partab>    Set GRIB1 default parameter table name or file (cgribex only)\n");
   fprintf(stderr, "                   Predefined tables: ");
   for ( int id = 0; id < tableInqNumber(); id++ )
     if ( (name = tableInqNamePtr(id)) )
@@ -190,17 +256,20 @@ void cdo_usage(void)
   fprintf(stderr, "    -W             Print extra warning messages\n");
   fprintf(stderr, "    -z szip        SZIP compression of GRIB1 records\n");
   fprintf(stderr, "       jpeg        JPEG compression of GRIB2 records\n");
-  fprintf(stderr, "        zip[_1-9]  Deflate compression of netCDF4 variables\n");
+  fprintf(stderr, "        zip[_1-9]  Deflate compression of NetCDF4 variables\n");
   reset_text_color(stderr);
   fprintf(stderr, "\n");
 
   fprintf(stderr, "  Operators:\n");
+  fprintf(stderr, "    Use option --operators for a list of all operators.\n");
+  /*
   set_text_color(stderr, RESET, GREEN);
   operatorPrintAll();
   reset_text_color(stderr);
+  */
 
   fprintf(stderr, "\n");
-  fprintf(stderr, "  CDO version %s, Copyright (C) 2003-2015 Uwe Schulzweida\n", VERSION);
+  fprintf(stderr, "  CDO version %s, Copyright (C) 2003-2016 Uwe Schulzweida\n", VERSION);
   //  fprintf(stderr, "  Available from <http://mpimet.mpg.de/cdo>\n");
   fprintf(stderr, "  This is free software and comes with ABSOLUTELY NO WARRANTY\n");
   fprintf(stderr, "  Report bugs to <http://mpimet.mpg.de/cdo>\n");
@@ -211,11 +280,11 @@ void cdo_init_is_tty(void)
 {
   struct stat statbuf;
   fstat(0, &statbuf);
-  if ( S_ISCHR(statbuf.st_mode) ) stdin_is_tty = 1;  
+  if ( S_ISCHR(statbuf.st_mode) ) stdin_is_tty = 1;
   fstat(1, &statbuf);
-  if ( S_ISCHR(statbuf.st_mode) ) stdout_is_tty = 1;  
+  if ( S_ISCHR(statbuf.st_mode) ) stdout_is_tty = 1;
   fstat(2, &statbuf);
-  if ( S_ISCHR(statbuf.st_mode) ) stderr_is_tty = 1;  
+  if ( S_ISCHR(statbuf.st_mode) ) stderr_is_tty = 1;
 }
 
 static
@@ -266,7 +335,6 @@ void cdoPrintHelp(const char *phelp[]/*, char *xoperator*/)
     }
 }
 
-
 static
 void cdoSetDebug(int level)
 {
@@ -517,43 +585,37 @@ void setDefaultFileType(const char *filetypestr, int labort)
     }
 }
 
-#if defined(malloc)
-#undef malloc
-#undef free
-#endif
-
 #define NTESTS 11
 #include <inttypes.h>
 static
 int getMemAlignment(void)
 {
   int ma = -1;
-  int i, k;
   double *ptr[NTESTS];
   int64_t iptr;
   size_t tsize[NTESTS] = {1, 3, 5, 9, 17, 33, 69, 121, 251, 510, 1025};
   size_t ma_check[4] = {8, 16, 32, 64};
   int ma_result[4] = {1, 1, 1, 1};
 
-  for ( i = 0; i < NTESTS; ++i )
+  for ( int i = 0; i < NTESTS; ++i )
     {
-      ptr[i] = (double*) Malloc(tsize[i]);
+      ptr[i] = (double*) malloc(tsize[i]);
       iptr = (int64_t) ptr[i];
-      for ( k = 0; k < 4; ++k ) if ( iptr%ma_check[k] ) ma_result[k] = 0; 
+      for ( int k = 0; k < 4; ++k ) if ( iptr%ma_check[k] ) ma_result[k] = 0; 
     }
-  for ( i = 0; i < NTESTS; ++i ) Free(ptr[i]);
+  for ( int i = 0; i < NTESTS; ++i ) free(ptr[i]);
 
-  for ( i = NTESTS-1; i >= 0; i-- )
+  for ( int i = NTESTS-1; i >= 0; i-- )
     {
-      ptr[i] = (double*) Malloc(tsize[i]+5);
+      ptr[i] = (double*) malloc(tsize[i]+5);
       iptr = (int64_t) ptr[i];
-      for ( k = 0; k < 4; ++k ) if ( iptr%ma_check[k] ) ma_result[k] = 0; 
+      for ( int k = 0; k < 4; ++k ) if ( iptr%ma_check[k] ) ma_result[k] = 0; 
     }
-  for ( i = 0; i < NTESTS; ++i ) Free(ptr[i]);
+  for ( int i = 0; i < NTESTS; ++i ) free(ptr[i]);
 
-  for ( k = 0; k < 4; ++k ) if ( ma_result[k] ) ma = ma_check[k];
+  for ( int k = 0; k < 4; ++k ) if ( ma_result[k] ) ma = ma_check[k];
 
-  return (ma);
+  return ma;
 }
 
 
@@ -645,6 +707,13 @@ void get_env_vars(void)
 {
   char *envstr;
 
+  username = getenv("LOGNAME");
+  if ( username == NULL )
+    {
+      username = getenv("USER");
+      if ( username == NULL ) username = "unknown";
+    }
+
   envstr = getenv("CDO_GRID_SEARCH_DIR");
   if ( envstr )
     {
@@ -777,19 +846,7 @@ void get_env_vars(void)
             fprintf(stderr, "CDO_COLOR = %s\n", envstr);
         }
     }
-  else
-    {
-      if ( CDO_Color == FALSE )
-        {
-          const char *username = getenv("LOGNAME");
-          if ( username == NULL )
-            {
-              username = getenv("USER");
-              if ( username == NULL ) username = "unknown";
-            }
-          if ( strcmp(username, "\x6d\x32\x31\x34\x30\x30\x33") == 0 ) CDO_Color = TRUE;
-        }
-    }
+  else if ( CDO_Color == FALSE && ISME ) CDO_Color = TRUE;
 }
 
 static
@@ -1005,7 +1062,7 @@ long str_to_int(const char *intstring)
       if ( fact ) intval = fact*atol(intstring);
     }
 
-  return (intval);
+  return intval;
 }
 
 static
@@ -1018,6 +1075,8 @@ int parse_options_long(int argc, char *argv[])
   int lgridsearchradius;
   int lremap_genweights;
   int lpercentile;
+  int lprintoperators = 0;
+  int lenableexcept;
 
   struct cdo_option opt_long[] =
     {
@@ -1029,9 +1088,12 @@ int parse_options_long(int argc, char *argv[])
       { "gridsearchnn",      required_argument,      &lgridsearchnn,  1  },
       { "gridsearchradius",  required_argument,  &lgridsearchradius,  1  },
       { "remap_genweights",  required_argument,  &lremap_genweights,  1  },
+      { "enableexcept",      required_argument,      &lenableexcept,  1  },
       { "cmor",                    no_argument,      &CDO_CMOR_Mode,  1  },
       { "reduce_dim",              no_argument,     &CDO_Reduce_Dim,  1  },
+      { "float",                   no_argument,        &CDO_Memtype,  MEMTYPE_FLOAT  },
       { "rusage",                  no_argument,         &CDO_Rusage,  1  },
+      { "operators",               no_argument,    &lprintoperators,  1  },
       { "no_warnings",             no_argument,           &_Verbose,  0  },
       { "format",            required_argument,                NULL, 'f' },
       { "help",                    no_argument,                NULL, 'h' },
@@ -1055,8 +1117,9 @@ int parse_options_long(int argc, char *argv[])
       lgridsearchnn = 0;
       lgridsearchradius = 0;
       lremap_genweights = 0;
+      lenableexcept = 0;
 
-      c = cdo_getopt_long(argc, argv, "f:b:e:P:p:g:i:k:l:m:n:t:D:z:aBCcdhLMOQRrsSTuVvWXZ", opt_long, NULL);
+      c = cdo_getopt_long(argc, argv, "f:b:e:P:g:i:k:l:m:n:t:D:z:aBCcdhLMOpQRrsSTuVvWXZ", opt_long, NULL);
       if ( c == -1 ) break;
 
       switch (c)
@@ -1081,6 +1144,19 @@ int parse_options_long(int argc, char *argv[])
             {
               percentile_set_method(CDO_optarg);
             }
+          else if ( lenableexcept )
+            {
+              int except = -1;
+              if      ( strcmp(CDO_optarg, "DIVBYZERO")  == 0 ) except = FE_DIVBYZERO;
+              else if ( strcmp(CDO_optarg, "INEXACT")    == 0 ) except = FE_INEXACT;
+              else if ( strcmp(CDO_optarg, "INVALID")    == 0 ) except = FE_INVALID;
+              else if ( strcmp(CDO_optarg, "OVERFLOW")   == 0 ) except = FE_OVERFLOW;
+              else if ( strcmp(CDO_optarg, "UNDERFLOW")  == 0 ) except = FE_UNDERFLOW;
+              else if ( strcmp(CDO_optarg, "ALL_EXCEPT") == 0 ) except = FE_ALL_EXCEPT;
+              if ( except < 0 ) cdoAbort("option --%s: unsupported argument: %s", "enableexcept", CDO_optarg);
+              cdo_feenableexcept((unsigned)except);
+              if ( signal(SIGFPE, cdo_sig_handler) == SIG_ERR ) cdoWarning("can't catch SIGFPE!");
+            }
           else if ( luse_fftw )
             {
               int intarg = parameter2int(CDO_optarg);
@@ -1190,8 +1266,7 @@ int parse_options_long(int argc, char *argv[])
           numThreads = atoi(CDO_optarg);
           break;
         case 'p':
-          fprintf(stderr, "CDO option -p is not available anymore, please use -b <bits>!\n");
-          //setDefaultDataTypeByte(CDO_optarg);
+          CDO_Parallel_Read = TRUE;
           break;
         case 'Q':
           cdiDefGlobal("SORTNAME", TRUE);
@@ -1239,6 +1314,15 @@ int parse_options_long(int argc, char *argv[])
         }
     }
 
+  if ( lprintoperators )
+    {
+      set_text_color(stderr, RESET, GREEN);
+      operatorPrintList();
+      //operatorPrintAll();
+      reset_text_color(stderr);
+      return 1;
+    }
+  
   return 0;
 }
 
@@ -1304,6 +1388,13 @@ int main(int argc, char *argv[])
 
   if ( Debug || Version ) cdo_version();
 
+  if ( Debug )
+    {
+      fprintf(stderr, "stdin_is_tty:   %d\n", stdin_is_tty);
+      fprintf(stderr, "stdout_is_tty:  %d\n", stdout_is_tty);
+      fprintf(stderr, "stderr_is_tty:  %d\n", stderr_is_tty);
+    }
+
   if ( Debug ) print_system_info();
 
   check_stacksize();
@@ -1351,7 +1442,7 @@ int main(int argc, char *argv[])
   if ( numThreads > 0 )
     {
       fprintf(stderr, "Option -P failed, OpenMP support not compiled in!\n");
-      return(-1);
+      return -1;
     }
 #endif
 
@@ -1375,7 +1466,7 @@ int main(int argc, char *argv[])
       lstop = TRUE;
     }
 
-  if ( lstop ) return (status);
+  if ( lstop ) return status;
 
   if ( cdoDefaultTableID != CDI_UNDEFID ) cdiDefTableID(cdoDefaultTableID);
 
@@ -1395,11 +1486,11 @@ int main(int argc, char *argv[])
         {
           if ( DebugLevel == 0 ) DebugLevel = 1;
           cdoSetDebug(DebugLevel);
-         }
+        }
 
-      timer_total      = timer_new("total");
-      timer_read       = timer_new("read");
-      timer_write      = timer_new("write");
+      timer_total  = timer_new("total");
+      timer_read   = timer_new("read");
+      timer_write  = timer_new("write");
 
       timer_start(timer_total);
 
@@ -1426,5 +1517,5 @@ int main(int argc, char *argv[])
 
   if ( CDO_Rusage ) cdo_rusage();
 
-  return (status);
+  return status;
 }
diff --git a/src/cdo.h b/src/cdo.h
index 569c938..bb6f03c 100644
--- a/src/cdo.h
+++ b/src/cdo.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/cdo_getopt.c b/src/cdo_getopt.c
index b188657..35df1da 100644
--- a/src/cdo_getopt.c
+++ b/src/cdo_getopt.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/cdo_getopt.h b/src/cdo_getopt.h
index 777e2ab..0575bd4 100644
--- a/src/cdo_getopt.h
+++ b/src/cdo_getopt.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/cdo_history.c b/src/cdo_history.c
index 2753385..3c41291 100644
--- a/src/cdo_history.c
+++ b/src/cdo_history.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,7 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "cdi_uuid.h"
 
 static char *ghistory = NULL;
 static size_t ghistorysize = 0;
@@ -123,18 +124,14 @@ void cdo_def_creation_date(int vlistID)
 }
 
 
-void create_uuid(unsigned char uuid[CDI_UUID_SIZE]);
-void uuid2str(const unsigned char *uuid, char *uuidstr);
-
-
 #define UUIDSTR_SIZE (CDI_UUID_SIZE*2 + 4)
 
 static
 void get_uuid(char uuidstr[UUIDSTR_SIZE])
 {
   unsigned char uuid[CDI_UUID_SIZE];
-  create_uuid(uuid);
-  uuid2str(uuid, uuidstr);
+  cdiCreateUUID(uuid);
+  cdiUUID2Str(uuid, uuidstr);
 }
 
 
diff --git a/src/cdo_int.h b/src/cdo_int.h
index e9d490f..94590c7 100644
--- a/src/cdo_int.h
+++ b/src/cdo_int.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -121,10 +121,6 @@ void time2str(int time, char *timestr, int maxlen);
 const char * tunit2str(int tunits);
 const char * calendar2str(int calendar);
 
-int     days_per_month(int calendar, int year, int month);
-int     days_per_year(int calendar, int year);
-int     calendar_dpy(int calendar);
-
 void    defineGrid(const char *gridarg);
 void    defineInstitution(const char *instarg);
 int     defineTable(const char *tablearg);
@@ -152,4 +148,24 @@ double parameter2double(const char *string);
 int    parameter2int(const char *string);
 int    parameter2intlist(const char *string);
 
+int referenceToGrid(int gridID1);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void cdiDefTableID(int tableID);
+
+void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *xvals);
+void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *yvals);
+
+void gaussaw(double *restrict pa, double *restrict pw, size_t nlat);
+
+int qu2reg3_double(double *pfield, int *kpoint, int klat, int klon,
+		   double msval, int *kret, int omisng, int operio, int oveggy);
+
+#if defined (__cplusplus)
+}
+#endif
+
 #endif  /* _CDO_INT_H */
diff --git a/src/cdo_pthread.c b/src/cdo_pthread.c
index 591b5f1..44622cc 100644
--- a/src/cdo_pthread.c
+++ b/src/cdo_pthread.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/cdo_vlist.c b/src/cdo_vlist.c
index ff12869..42f13ae 100644
--- a/src/cdo_vlist.c
+++ b/src/cdo_vlist.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -44,9 +44,8 @@ void compare_lat_reg2d(int ysize, int gridID1, int gridID2)
       else
 	{
 	  for ( int i = 0; i < ysize; ++i )
-	    if ( fabs(yvals1[i] - yvals2[i]) > 1.e-5 )
+	    if ( fabs(yvals1[i] - yvals2[i]) > 3.e-5 )
 	      {
-		// printf("lat %g %g %g\n", yvals1[i], yvals2[i], yvals1[i] - yvals2[i]);
 		cdoWarning("Grid latitudes differ!");
 		break;
 	      }
@@ -69,7 +68,7 @@ void compare_lon_reg2d(int xsize, int gridID1, int gridID2)
       gridInqXvals(gridID2, xvals2);
 		  
       for ( int i = 0; i < xsize; ++i )
-	if ( fabs(xvals1[i] - xvals2[i]) > 1.e-5 )
+	if ( fabs(xvals1[i] - xvals2[i]) > 3.e-5 )
 	  {
 	    cdoWarning("Grid longitudes differ!");
 	    break;
@@ -137,7 +136,7 @@ void compareGrids(int gridID1, int gridID2)
 	  compare_grid_unstructured(gridID1, gridID2);
 	}
     }
-  else
+  else if ( gridInqSize(gridID1) > 1 )
     {
       cdoWarning("Grids have different types! First grid: %s; second grid: %s",
 		 gridNamePtr(gridInqType(gridID1)), gridNamePtr(gridInqType(gridID2)));
@@ -197,10 +196,41 @@ void vlistCompare(int vlistID1, int vlistID2, int flag)
       
       if ( flag & CMP_NLEVEL )
 	{
-	  if ( zaxisInqSize(vlistInqVarZaxis(vlistID1, varID)) !=
-	       zaxisInqSize(vlistInqVarZaxis(vlistID2, varID)) )
-	    cdoAbort("Number of levels of the input parameters do not match!");
-	}
+          int zaxisID1 = vlistInqVarZaxis(vlistID1, varID);
+          int zaxisID2 = vlistInqVarZaxis(vlistID2, varID);
+          if ( zaxisID1 != zaxisID2 )
+            {
+              int nlev1 = zaxisInqSize(zaxisID1);
+              int nlev2 = zaxisInqSize(zaxisID2);
+              if ( nlev1 != nlev2 )
+                cdoAbort("Number of levels of the input parameters do not match!");
+
+              double *lev1 = (double*) Malloc(nlev1*sizeof(double));
+              double *lev2 = (double*) Malloc(nlev1*sizeof(double));
+              zaxisInqLevels(zaxisID1, lev1);
+              zaxisInqLevels(zaxisID2, lev2);
+              
+              int ldiffer = FALSE;
+              for ( int i = 0; i < nlev1; ++i )
+                if ( IS_NOT_EQUAL(lev1[i], lev2[i]) )
+                  { ldiffer = TRUE; break; }
+              if ( ldiffer )
+                {
+                  ldiffer = FALSE;
+                  for ( int i = 0; i < nlev1; ++i )
+                    if ( IS_NOT_EQUAL(lev1[i], lev2[nlev1-1-i]) )
+                      { ldiffer = TRUE; break; }
+
+                  if ( ldiffer )
+                    cdoWarning("Input parameters have different levels!");
+                  else
+                    cdoWarning("Z-axis orientation differ!");
+                }
+              
+              Free(lev1);
+              Free(lev2);
+            }
+        }
     }
 
   if ( flag & CMP_GRID )
@@ -227,15 +257,13 @@ void vlistCompare(int vlistID1, int vlistID2, int flag)
 	if ( strcmp(names1[varID], names2[varID]) != 0 ) break;
 
       if ( varID == nvars )
-	cdoPrint("Use the CDO option -Q to sort the parameter names, if you have netCDF input files!");
+	cdoPrint("Use the CDO option -Q to sort the parameter names, if you have NetCDF input files!");
     }
 }
 
 
 int vlistCompareX(int vlistID1, int vlistID2, int flag)
 {
-  int varID;
-
   int nvars = vlistNvars(vlistID1);
   int nvars2 = vlistNvars(vlistID2);
   int nlevels2 = zaxisInqSize(vlistInqVarZaxis(vlistID2, 0));
@@ -243,7 +271,7 @@ int vlistCompareX(int vlistID1, int vlistID2, int flag)
   if ( nvars2 != 1 )
     cdoAbort("Internal problem, vlistCompareX() called with unexpected vlistID2 argument!");
 
-  for ( varID = 0; varID < nvars; varID++ )
+  for ( int varID = 0; varID < nvars; varID++ )
     {
       if ( flag & CMP_GRIDSIZE )
 	{
diff --git a/src/commandline.c b/src/commandline.c
index d1f0889..2d9d43b 100644
--- a/src/commandline.c
+++ b/src/commandline.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/compare.h b/src/compare.h
index 717d7b2..6aeb13a 100644
--- a/src/compare.h
+++ b/src/compare.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/config.h.in b/src/config.h.in
index 574c13c..39c5388 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -12,6 +12,9 @@
 /* Define to 1 for DATA support */
 #undef ENABLE_DATA
 
+/* Define to 1 if you have the `backtrace' function. */
+#undef HAVE_BACKTRACE
+
 /* Define to 1 if you have the <cmor.h> header file. */
 #undef HAVE_CMOR_H
 
@@ -25,6 +28,18 @@
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #undef HAVE_DLFCN_H
 
+/* Define to 1 if you have the <execinfo.h> header file. */
+#undef HAVE_EXECINFO_H
+
+/* Define to 1 if you have the `feenableexcept' function. */
+#undef HAVE_FEENABLEEXCEPT
+
+/* Define to 1 if `__control' is a member of `fenv_t'. */
+#undef HAVE_FENV_T___CONTROL
+
+/* Define to 1 if `__mxcsr' is a member of `fenv_t'. */
+#undef HAVE_FENV_T___MXCSR
+
 /* Define to 1 if you have the <fftw3.h> header file. */
 #undef HAVE_FFTW3_H
 
diff --git a/src/dmemory.h b/src/dmemory.h
index d59d136..90ec1f0 100644
--- a/src/dmemory.h
+++ b/src/dmemory.h
@@ -10,6 +10,10 @@
 #define  WITH_FUNCTION_NAME
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern size_t  memTotal(void);
 extern void    memDebug(int debug);
 extern void    memExitOnError(void);
@@ -21,6 +25,10 @@ extern void   *memCalloc (size_t nmemb, size_t size, const char *file, const cha
 extern void   *memMalloc (size_t size, const char *file, const char *functionname, int line);
 extern void    memFree   (void *ptr, const char *file, const char *functionname, int line);
 
+#if defined (__cplusplus)
+}
+#endif
+
 #if  defined  WITH_FUNCTION_NAME
 #  define  Realloc(p, s)  memRealloc((p), (s), __FILE__, __func__, __LINE__)
 #  define   Calloc(n, s)   memCalloc((n), (s), __FILE__, __func__, __LINE__)
@@ -35,15 +43,6 @@ extern void    memFree   (void *ptr, const char *file, const char *functionname,
 
 #endif /* DEBUG_MEMORY */
 
-void *cdiXmalloc(size_t, const char *, const char *, int);
-#define xmalloc(size) cdiXmalloc((size), __FILE__, __func__,  __LINE__ )
-
-void *cdiXcalloc(size_t, size_t, const char *, const char *, int);
-#define xcalloc(nmemb,size) cdiXcalloc((nmemb), (size), __FILE__, __func__, __LINE__)
-
-void *cdiXrealloc(void *, size_t, const char *, const char *, int);
-#define xrealloc(p,size) cdiXrealloc((p), (size), __FILE__, __func__, __LINE__)
-
 #endif /* _DMEMORY_H */
 /*
  * Local Variables:
diff --git a/src/ecacore.c b/src/ecacore.c
index a5edf9f..5a43380 100755
--- a/src/ecacore.c
+++ b/src/ecacore.c
@@ -36,6 +36,7 @@ void eca1(const ECA_REQUEST_1 *request)
 {
   const int operatorID = cdoOperatorID();
   
+  int nmiss;
   int cmplen;
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
   int gridsize;
@@ -224,7 +225,8 @@ void eca1(const ECA_REQUEST_1 *request)
                   if ( IS_SET(request->var2.h3) ) var23[levelID].nmiss = gridsize; 
                 }
 
-              streamReadRecord(istreamID, field1.ptr, &field1.nmiss);
+              streamReadRecord(istreamID, field1.ptr, &nmiss);
+              field1.nmiss   = (size_t)nmiss;
               field1.grid    = var12[levelID].grid;
               field1.missval = var12[levelID].missval;
               
@@ -402,6 +404,7 @@ void eca2(const ECA_REQUEST_2 *request)
 {
   const int operatorID = cdoOperatorID();
   
+  int nmiss;
   int cmplen;
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
   int gridsize;
@@ -611,11 +614,13 @@ void eca2(const ECA_REQUEST_2 *request)
                     var22[levelID].nmiss = gridsize;
                 }
 
-              streamReadRecord(istreamID1, field1.ptr, &field1.nmiss);
+              streamReadRecord(istreamID1, field1.ptr, &nmiss);
+              field1.nmiss   = (size_t)nmiss;
               field1.grid    = gridID;
               field1.missval = missval1;
               
-              streamReadRecord(istreamID2, field2.ptr, &field2.nmiss);
+              streamReadRecord(istreamID2, field2.ptr, &nmiss);
+              field2.nmiss   = (size_t)nmiss;
               field2.grid    = gridID;
               field2.missval = missval2;
 
@@ -789,6 +794,7 @@ void eca3(const ECA_REQUEST_3 *request)
 {
   const int operatorID = cdoOperatorID();
 
+  int nmiss;
   int cmplen;
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
   int gridsize;
@@ -930,11 +936,13 @@ void eca3(const ECA_REQUEST_3 *request)
                   var2[levelID].nmiss = gridsize;
                 }
 
-              streamReadRecord(istreamID1, field1.ptr, &field1.nmiss);
+              streamReadRecord(istreamID1, field1.ptr, &nmiss);
+              field1.nmiss   = (size_t)nmiss;
               field1.grid    = var1[levelID].grid;
               field1.missval = var1[levelID].missval;
 
-              streamReadRecord(istreamID2, field2.ptr, &field2.nmiss);
+              streamReadRecord(istreamID2, field2.ptr, &nmiss);
+              field2.nmiss   = (size_t)nmiss;
               field2.grid    = var1[levelID].grid;
               field2.missval = var1[levelID].missval;
 
@@ -994,6 +1002,7 @@ void eca4(const ECA_REQUEST_4 *request)
 {
   const int operatorID = cdoOperatorID();
 
+  int nmiss;
   int cmplen;
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
   int gridsize, gridtype;
@@ -1171,7 +1180,8 @@ void eca4(const ECA_REQUEST_4 *request)
   if ( streamInqTimestep(istreamID2, itsID) )
     {
       streamInqRecord(istreamID2, &varID, &levelID);
-      streamReadRecord(istreamID2, mask.ptr, &mask.nmiss);
+      streamReadRecord(istreamID2, mask.ptr, &nmiss);
+      mask.nmiss   = (size_t)nmiss;
       mask.grid    = gridID;
       mask.missval = vlistInqVarMissval(ivlistID2, 0);
 
@@ -1238,9 +1248,10 @@ void eca4(const ECA_REQUEST_4 *request)
                   endDateWithHist[1][levelID].nmiss   = gridsize;
                 }
 
-              streamReadRecord(istreamID1, fieldGt.ptr, &fieldGt.nmiss);
+              streamReadRecord(istreamID1, fieldGt.ptr, &nmiss);
+              fieldGt.nmiss   = (size_t)nmiss;
               memcpy(fieldLt.ptr, fieldGt.ptr, gridsize*sizeof(double));
-              fieldLt.nmiss = fieldGt.nmiss;
+              fieldLt.nmiss   = fieldGt.nmiss;
               fieldGt.grid    = startCount[levelID].grid;
               fieldGt.missval = startCount[levelID].missval;
               fieldLt.grid    = startCount[levelID].grid;
diff --git a/src/error.h b/src/error.h
index 02323b4..13a712f 100644
--- a/src/error.h
+++ b/src/error.h
@@ -1,6 +1,9 @@
 #ifndef _ERROR_H
 #define _ERROR_H
 
+#include <stdarg.h>
+#include <stdlib.h>
+
 #ifndef  WITH_CALLER_NAME
 #define  WITH_CALLER_NAME
 #endif
@@ -9,6 +12,10 @@
 #define  _VERBOSE   2     /* Error flag: report errors  */
 #define  _DEBUG     4     /* Error flag: debug          */
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern int _ExitOnError;  /* If set to 1, exit on error (default 1)       */
 extern int _Verbose;      /* If set to 1, errors are reported (default 1) */
 extern int _Debug;        /* If set to 1, debuggig (default 0)            */
@@ -16,6 +23,8 @@ extern int _Debug;        /* If set to 1, debuggig (default 0)            */
 void SysError_(const char *caller, const char *fmt, ...);
 void    Error_(const char *caller, const char *fmt, ...);
 void  Warning_(const char *caller, const char *fmt, ...);
+/* delegate used by Warning_ unless mode is PIO */
+void cdiWarning(const char *caller, const char *fmt, va_list ap);
 void  Message_(const char *caller, const char *fmt, ...);
 
 #if  defined  WITH_CALLER_NAME
@@ -34,4 +43,44 @@ void  Message_(const char *caller, const char *fmt, ...);
 #  define   Message(...)   Message_((void *), __VA_ARGS__)
 #endif
 
+/* If we're not using GNU C, elide __attribute__ */
+#ifndef __GNUC__
+#  define  __attribute__(x)  /*NOTHING*/
+#endif
+
+void cdiAbortC(const char *caller, const char *filename,
+               const char *functionname, int line,
+               const char *errorString, ... )
+  __attribute__((noreturn));
+#define xabortC(caller, ...)                                    \
+  cdiAbortC(caller, __FILE__, __func__, __LINE__, __VA_ARGS__ )
+#define xabort(...)                                             \
+  cdiAbortC(NULL, __FILE__, __func__, __LINE__, __VA_ARGS__ )
+#define cdiAbort(file, func, line, ...)                 \
+  cdiAbortC(NULL, (file), (func), (line), __VA_ARGS__)
+
+#define xassert(arg) do {                       \
+    if ((arg)) { } else {                       \
+      xabort("assertion `" #arg "` failed");}   \
+  } while(0)
+
+void
+cdiAbortC_serial(const char *caller, const char *filename,
+                 const char *functionname, int line,
+                 const char *errorString, va_list ap)
+  __attribute__((noreturn));
+
+#if defined (__cplusplus)
+}
+#endif
+
 #endif  /* _ERROR_H */
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
diff --git a/src/exception.c b/src/exception.c
index 5aa0cf1..1197283 100644
--- a/src/exception.c
+++ b/src/exception.c
@@ -10,6 +10,7 @@
 #include "process.h"
 #include "error.h"
 
+void pstreamCloseAll(void);
 
 void cdiOpenError(int cdiErrno, const char *fmt, const char *path)
 {	
@@ -32,50 +33,38 @@ void cdiOpenError(int cdiErrno, const char *fmt, const char *path)
       switch (filetype)
 	{
 	case FILETYPE_GRB:
-	  {
-	    break;
-	  }
+          break;
 	case FILETYPE_GRB2:
-	  {
-	    fprintf(stderr, "To create a CDO application with GRIB2 support use: ./configure --with-netcdf=<GRIB_API root directory> ...\n");
-	    break;
-	  }
+          fprintf(stderr, "To create a CDO application with GRIB2 support use: ./configure --with-netcdf=<GRIB_API root directory> ...\n");
+          break;
 	case FILETYPE_SRV:
-	  {
-	    break;
-	  }
+          break;
 	case FILETYPE_EXT:
-	  {
-	    break;
-	  }
+          break;
 	case FILETYPE_IEG:
-	  {
-	    break;
-	  }
+          break;
 	case FILETYPE_NC:
 	case FILETYPE_NC2:
 	case FILETYPE_NC4:
 	case FILETYPE_NC4C:
-	  {
-	    const char *ncv = (filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C) ? "4" : ((filetype == FILETYPE_NC2) ? "2" : "");
+          {
+            const char *ncv = (filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C) ? "4" : ((filetype == FILETYPE_NC2) ? "2" : "");
 #if defined HAVE_LIBNETCDF
-	    fprintf(stderr, "CDO was build with a netCDF version which doesn't support netCDF%s data!\n", ncv);
+            fprintf(stderr, "CDO was build with a NetCDF version which doesn't support NetCDF%s data!\n", ncv);
 #else
-	    fprintf(stderr, "To create a CDO application with netCDF%s support use: ./configure --with-netcdf=<netCDF%s root directory> ...\n", ncv, ncv);
+            fprintf(stderr, "To create a CDO application with NetCDF%s support use: ./configure --with-netcdf=<NetCDF%s root directory> ...\n", ncv, ncv);
 #endif
-	    break;
-	  }
+            break;
+          }
 	default:
-	  {
-	    break;
-	  }
+          break;
 	}
     }
   
+  if ( _ExitOnError ) pstreamCloseAll();
   if ( _ExitOnError ) exit(EXIT_FAILURE);
 }
 
-void pstreamCloseAll(void);
 void cdoAbort(const char *fmt, ...)
 {
   va_list args;
diff --git a/src/expr.c b/src/expr.c
index 6bf2d8f..bea9b41 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1,17 +1,44 @@
+/*
+  This file is part of CDO. CDO is a collection of Operators to
+  manipulate and analyse Climate model Data.
+
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  See COPYING file for copying and redistribution conditions.
+
+  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 Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+*/
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
 #include <errno.h>
 #include <ctype.h>
+#include <assert.h>
 
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
 #include "field.h"
 #include "expr.h"
+#include "expr_fun.h"
 #include "expr_yacc.h"
 
+
+static const char *ExIn[] = {"expr", "init"};
+static const char *tmpvnm = "_tmp_";
+int pointID = -1;
+int surfaceID = -1;
+
+enum {FT_STD, FT_CONST, FT_FLD, FT_VERT, FT_COORD, FT_1C};
+
 #define    COMPLT(x,y)  ((x) < (y) ? 1 : 0)
 #define    COMPGT(x,y)  ((x) > (y) ? 1 : 0)
 #define    COMPLE(x,y)  ((x) <= (y) ? 1 : 0)
@@ -31,64 +58,154 @@
 #define MVCOMPAND(x,y)  (DBL_IS_EQUAL((x),missval1) ? missval1 : COMPAND(x,y))
 #define  MVCOMPOR(x,y)  (DBL_IS_EQUAL((x),missval1) ? missval1 : COMPOR(x,y))
 
-static double f_int(double x)  { return ((int)(x)); }
-static double f_nint(double x) { return (round(x)); }
-static double f_sqr(double x)  { return (x*x);      }
+static double f_int(double x)          { return (int)(x); }
+static double f_nint(double x)         { return round(x); }
+static double f_sqr(double x)          { return x*x;      }
+static double f_rad(double x)          { return x*M_PI/180.; }
+static double f_deg(double x)          { return x*180./M_PI; }
+static double pt_ngp(paramType *p)     { return p->ngp;   }
+static double pt_nlev(paramType *p)    { return p->nlev;  }
+static double pt_size(paramType *p)    { return p->ngp*p->nlev; }
+static double pt_missval(paramType *p) { return p->missval; }
 
 typedef struct {
   int type;
-  const char *name;                      /* function name            */
-  double (*func)(double);          /* pointer to function      */
+  int flag;
+  const char *name;  // function name
+  void (*func)();    // pointer to function
 }
 func_t;
 
 static func_t fun_sym_tbl[] =
 {
-  /* scalar functions */
-  {0, "abs",   fabs},
-  {0, "floor", floor},
-  {0, "ceil",  ceil},
-  {0, "int",   f_int},
-  {0, "nint",  f_nint},
-  {0, "sqr",   f_sqr},
-  {0, "sqrt",  sqrt},
-  {0, "exp",   exp},
-  {0, "erf",   erf},
-  {0, "log",   log},
-  {0, "log10", log10},
-  {0, "sin",   sin},
-  {0, "cos",   cos},
-  {0, "tan",   tan},
-  {0, "sinh",  sinh},
-  {0, "cosh",  cosh},
-  {0, "tanh",  tanh},
-  {0, "asin",  asin},
-  {0, "acos",  acos},
-  {0, "atan",  atan},
-  {0, "asinh", asinh},
-  {0, "acosh", acosh},
-  {0, "atanh", atanh},
-  {0, "gamma", tgamma},
-
-  /* array functions
-  {1, "min",   min},
-  {1, "max",   max},
-  {1, "sum",   sum},
-  {1, "avg",   avg},
-  {1, "mean",  mean},
-  {1, "std",   std},
-  {1, "var",   var},
-  */
+  // scalar functions
+  {FT_STD, 0, "abs",   (void (*)()) fabs},
+  {FT_STD, 0, "floor", (void (*)()) floor},
+  {FT_STD, 0, "ceil",  (void (*)()) ceil},
+  {FT_STD, 0, "int",   (void (*)()) f_int},
+  {FT_STD, 0, "nint",  (void (*)()) f_nint},
+  {FT_STD, 0, "sqr",   (void (*)()) f_sqr},
+  {FT_STD, 0, "sqrt",  (void (*)()) sqrt},
+  {FT_STD, 0, "exp",   (void (*)()) exp},
+  {FT_STD, 0, "erf",   (void (*)()) erf},
+  {FT_STD, 0, "log",   (void (*)()) log},
+  {FT_STD, 0, "log10", (void (*)()) log10},
+  {FT_STD, 0, "sin",   (void (*)()) sin},
+  {FT_STD, 0, "cos",   (void (*)()) cos},
+  {FT_STD, 0, "tan",   (void (*)()) tan},
+  {FT_STD, 0, "sinh",  (void (*)()) sinh},
+  {FT_STD, 0, "cosh",  (void (*)()) cosh},
+  {FT_STD, 0, "tanh",  (void (*)()) tanh},
+  {FT_STD, 0, "asin",  (void (*)()) asin},
+  {FT_STD, 0, "acos",  (void (*)()) acos},
+  {FT_STD, 0, "atan",  (void (*)()) atan},
+  {FT_STD, 0, "asinh", (void (*)()) asinh},
+  {FT_STD, 0, "acosh", (void (*)()) acosh},
+  {FT_STD, 0, "atanh", (void (*)()) atanh},
+  {FT_STD, 0, "gamma", (void (*)()) tgamma},
+  {FT_STD, 0, "rad",   (void (*)()) f_rad},
+  {FT_STD, 0, "deg",   (void (*)()) f_deg},
+
+  // constant functions
+  {FT_CONST, 0, "ngp",     (void (*)()) pt_ngp},      // number of horizontal grid points
+  {FT_CONST, 0, "nlev",    (void (*)()) pt_nlev},     // number of vertical levels
+  {FT_CONST, 0, "size",    (void (*)()) pt_size},     // ngp*nlev
+  {FT_CONST, 0, "missval", (void (*)()) pt_missval},  // Returns the missing value of a variable
+
+  // cdo field functions (Reduce grid to point)
+  {FT_FLD, 0, "fldmin",  (void (*)()) fldmin},
+  {FT_FLD, 0, "fldmax",  (void (*)()) fldmax},
+  {FT_FLD, 0, "fldsum",  (void (*)()) fldsum},
+  {FT_FLD, 1, "fldmean", (void (*)()) fldmean},
+  {FT_FLD, 1, "fldavg",  (void (*)()) fldavg},
+  {FT_FLD, 1, "fldstd",  (void (*)()) fldstd},
+  {FT_FLD, 1, "fldstd1", (void (*)()) fldstd1},
+  {FT_FLD, 1, "fldvar",  (void (*)()) fldvar},
+  {FT_FLD, 1, "fldvar1", (void (*)()) fldvar1},
+
+  // cdo field functions (Reduce level to point)
+  {FT_VERT, 0, "vertmin",  (void (*)()) fldmin},
+  {FT_VERT, 0, "vertmax",  (void (*)()) fldmax},
+  {FT_VERT, 0, "vertsum",  (void (*)()) fldsum},
+  {FT_VERT, 1, "vertmean", (void (*)()) fldmean},
+  {FT_VERT, 1, "vertavg",  (void (*)()) fldavg},
+  {FT_VERT, 1, "vertstd",  (void (*)()) fldstd},
+  {FT_VERT, 1, "vertstd1", (void (*)()) fldstd1},
+  {FT_VERT, 1, "vertvar",  (void (*)()) fldvar},
+  {FT_VERT, 1, "vertvar1", (void (*)()) fldvar1},
+  
+  {FT_COORD, 0, "clon",       NULL},
+  {FT_COORD, 0, "clat",       NULL},
+  {FT_COORD, 0, "clev",       NULL},
+  {FT_COORD, 0, "gridarea",   NULL},
+  {FT_COORD, 0, "gridweight", NULL},
+
+  {FT_1C, 0, "sellevel",  NULL},
+  {FT_1C, 0, "sellevidx", NULL},
 };
 
 static int NumFunc = sizeof(fun_sym_tbl) / sizeof(fun_sym_tbl[0]);
 
 static
+void node_data_delete(nodeType *p)
+{
+  if ( p )
+    {
+      if ( p->param.data ) { Free(p->param.data); p->param.data = NULL;}
+    }
+}
+
+static
+void node_delete(nodeType *p)
+{
+  if ( p )
+    {
+      if ( p->type == typeVar ) node_data_delete(p);
+      Free(p);
+    }
+}
+
+static
+int get_funcID(const char *fun)
+{
+  int funcID = -1;
+  for ( int i = 0; i < NumFunc; i++ )
+    if ( strcmp(fun, fun_sym_tbl[i].name) == 0 )
+      { 
+	funcID = i;
+	break;
+      }
+
+  if ( funcID == -1 ) cdoAbort("Function >%s< not available!", fun);
+
+  return funcID;
+}
+
+static
+void param_meta_copy(paramType *out, paramType *in)
+{
+  out->gridID   = in->gridID;
+  out->zaxisID  = in->zaxisID;
+  out->steptype = in->steptype;
+  out->ngp      = in->ngp;
+  out->nlev     = in->nlev;
+  out->missval  = in->missval;
+  out->nmiss    = 0;
+  out->coord    = 0;
+  out->lmiss    = true;
+  out->name     = NULL;
+  out->longname = NULL;
+  out->units    = NULL;
+  out->data     = NULL;
+}
+
+static
 nodeType *expr_con_con(int oper, nodeType *p1, nodeType *p2)
 {
-  nodeType *p = (nodeType*) Malloc(sizeof(nodeType));
+  nodeType *p = (nodeType*) Calloc(1, sizeof(nodeType));
 
-  p->type = typeCon;
+  p->type    = typeCon;
+  p->ltmpobj = true;
 
   double cval1 = p1->u.con.value;
   double cval2 = p2->u.con.value;
@@ -105,41 +222,41 @@ nodeType *expr_con_con(int oper, nodeType *p1, nodeType *p2)
 
   p->u.con.value = cval1;
 
-  return (p);
+  return p;
 }
 
 static
-void oper_expr_con_var(int oper, int nmiss, long n, double missval1, double missval2,
+void oper_expr_con_var(int oper, bool nmiss, size_t n, double missval1, double missval2,
                        double *restrict odat, double cval, const double *restrict idat)
 {
-  long i;
+  size_t i;
 
   switch ( oper )
     {
     case '+':
-      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = ADD(cval, idat[i]);
+      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = ADDMN(cval, idat[i]);
       else         for ( i=0; i<n; ++i ) odat[i] = cval + idat[i];
       break;
     case '-':
-      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = SUB(cval, idat[i]);
+      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = SUBMN(cval, idat[i]);
       else         for ( i=0; i<n; ++i ) odat[i] = cval - idat[i];
       break;
     case '*':
-      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = MUL(cval, idat[i]);
+      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = MULMN(cval, idat[i]);
       else         for ( i=0; i<n; ++i ) odat[i] = cval * idat[i];
       break;
     case '/':
-      for ( i=0; i<n; ++i ) odat[i] = DIV(cval, idat[i]);
+      for ( i=0; i<n; ++i ) odat[i] = DIVMN(cval, idat[i]);
       break;
     case '^':
-      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = POW(cval, idat[i]);
+      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = POWMN(cval, idat[i]);
       else         for ( i=0; i<n; ++i ) odat[i] = pow(cval, idat[i]);
       break;
-    case '<':
+    case LT:
       if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = MVCOMPLT(cval, idat[i]);
       else         for ( i=0; i<n; ++i ) odat[i] =   COMPLT(cval, idat[i]);
       break;
-    case '>':
+    case GT:
       if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = MVCOMPGT(cval, idat[i]);
       else         for ( i=0; i<n; ++i ) odat[i] =   COMPGT(cval, idat[i]);
       break;
@@ -177,38 +294,38 @@ void oper_expr_con_var(int oper, int nmiss, long n, double missval1, double miss
 }
 
 static
-void oper_expr_var_con(int oper, int nmiss, long n, double missval1, double missval2,
+void oper_expr_var_con(int oper, bool nmiss, size_t n, double missval1, double missval2,
                        double *restrict odat, const double *restrict idat, double cval)
 {
-  long i;
+  size_t i;
 
   switch ( oper )
     {
     case '+':
-      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = ADD(idat[i], cval);
+      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = ADDMN(idat[i], cval);
       else         for ( i=0; i<n; ++i ) odat[i] = idat[i] + cval;
       break;
     case '-':
-      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = SUB(idat[i], cval);
+      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = SUBMN(idat[i], cval);
       else         for ( i=0; i<n; ++i ) odat[i] = idat[i] - cval;
       break;
     case '*':
-      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = MUL(idat[i], cval);
+      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = MULMN(idat[i], cval);
       else         for ( i=0; i<n; ++i ) odat[i] = idat[i] * cval;
       break;
     case '/':
-      if ( nmiss || IS_EQUAL(cval, 0) ) for ( i=0; i<n; ++i ) odat[i] = DIV(idat[i], cval);
+      if ( nmiss || IS_EQUAL(cval, 0) ) for ( i=0; i<n; ++i ) odat[i] = DIVMN(idat[i], cval);
       else                              for ( i=0; i<n; ++i ) odat[i] = idat[i] / cval;
       break;
     case '^':
-      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = POW(idat[i], cval);
+      if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = POWMN(idat[i], cval);
       else         for ( i=0; i<n; ++i ) odat[i] = pow(idat[i], cval);
       break;
-    case '<':
+    case LT:
       if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = MVCOMPLT(idat[i], cval);
       else         for ( i=0; i<n; ++i ) odat[i] =   COMPLT(idat[i], cval);
       break;
-    case '>':
+    case GT:
       if ( nmiss ) for ( i=0; i<n; ++i ) odat[i] = MVCOMPGT(idat[i], cval);
       else         for ( i=0; i<n; ++i ) odat[i] =   COMPGT(idat[i], cval);
       break;
@@ -241,33 +358,33 @@ void oper_expr_var_con(int oper, int nmiss, long n, double missval1, double miss
       else         for ( i=0; i<n; ++i ) odat[i] =   COMPOR(idat[i], cval);
       break;
     default:
-      cdoAbort("%s: operator %c unsupported!", __func__, oper);
+      cdoAbort("%s: operator '%c' unsupported!", __func__, oper);
       break;
     }
 }
 
 static
-void oper_expr_var_var(int oper, int nmiss, long ngp, double missval1, double missval2,
+void oper_expr_var_var(int oper, bool nmiss, size_t ngp, double missval1, double missval2,
                        double *restrict odat, const double *restrict idat1, const double *restrict idat2)
 {
-  long i;
+  size_t i;
 
   switch ( oper )
     {
     case '+':
-      if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = ADD(idat1[i], idat2[i]);
+      if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = ADDMN(idat1[i], idat2[i]);
       else         for ( i=0; i<ngp; ++i ) odat[i] = idat1[i] + idat2[i];
       break;
     case '-':
-      if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = SUB(idat1[i], idat2[i]);
+      if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = SUBMN(idat1[i], idat2[i]);
       else         for ( i=0; i<ngp; ++i ) odat[i] = idat1[i] - idat2[i];
       break;
     case '*':
-      if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = MUL(idat1[i], idat2[i]);
+      if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = MULMN(idat1[i], idat2[i]);
       else         for ( i=0; i<ngp; ++i ) odat[i] = idat1[i] * idat2[i];
       break;
     case '/':
-      if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = DIV(idat1[i], idat2[i]);
+      if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = DIVMN(idat1[i], idat2[i]);
       else
         {
           for ( i = 0; i < ngp; ++i )
@@ -278,14 +395,14 @@ void oper_expr_var_var(int oper, int nmiss, long ngp, double missval1, double mi
         }
       break;
     case '^':
-      if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = POW(idat1[i], idat2[i]);
+      if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = POWMN(idat1[i], idat2[i]);
       else         for ( i=0; i<ngp; ++i ) odat[i] = pow(idat1[i], idat2[i]);
       break;
-    case '<':
+    case LT:
       if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = MVCOMPLT(idat1[i], idat2[i]);
       else         for ( i=0; i<ngp; ++i ) odat[i] =   COMPLT(idat1[i], idat2[i]);
       break;
-    case '>':
+    case GT:
       if ( nmiss ) for ( i=0; i<ngp; ++i ) odat[i] = MVCOMPGT(idat1[i], idat2[i]);
       else         for ( i=0; i<ngp; ++i ) odat[i] =   COMPGT(idat1[i], idat2[i]);
       break;
@@ -318,443 +435,728 @@ void oper_expr_var_var(int oper, int nmiss, long ngp, double missval1, double mi
       else         for ( i=0; i<ngp; ++i ) odat[i] =   COMPOR(idat1[i], idat2[i]);
       break;
     default:
-      cdoAbort("%s: operator %d (%c) unsupported!", __func__, (int)oper, oper);
+      cdoAbort("%s: operator %d (%c) unsupported!", __func__, oper, oper);
       break;
     }
 }
 
 static
-nodeType *expr_con_var(int oper, nodeType *p1, nodeType *p2)
+nodeType *expr_con_var(int init, int oper, nodeType *p1, nodeType *p2)
 {
-  int gridID   = p2->gridID;
-  int zaxisID  = p2->zaxisID;
-  int nmiss    = p2->nmiss;
-  double missval1 = p2->missval;
-  double missval2 = p2->missval;
+  size_t ngp   = p2->param.ngp;
+  size_t nlev  = p2->param.nlev;
+  size_t nmiss = p2->param.nmiss;
+  double missval1 = p2->param.missval;
+  double missval2 = p2->param.missval;
 
-  int ngp  = gridInqSize(gridID);
-  int nlev = zaxisInqSize(zaxisID);
-  long n   = ngp*nlev;
-  long i;
+  size_t n = ngp*nlev;
 
-  nodeType *p = (nodeType*) Malloc(sizeof(nodeType));
+  nodeType *p = (nodeType*) Calloc(1, sizeof(nodeType));
 
   p->type     = typeVar;
-  p->tmpvar   = 1;
-  p->u.var.nm = strdupx("tmp");
-  p->gridID   = gridID;
-  p->zaxisID  = zaxisID;
-  p->missval  = missval1;
-
-  p->data = (double*) Malloc(n*sizeof(double));
-  double *restrict odat = p->data;
-  const double *restrict idat = p2->data;
-  double cval = p1->u.con.value;
-
-  oper_expr_con_var(oper, nmiss, n, missval1, missval2, odat, cval, idat);
+  p->ltmpobj  = true;
+  p->u.var.nm = strdup(tmpvnm);
+  param_meta_copy(&p->param, &p2->param);
+  p->param.name = p->u.var.nm;
 
-  nmiss = 0;
-  for ( i = 0; i < n; i++ )
-    if ( DBL_IS_EQUAL(p->data[i], missval1) ) nmiss++;
+  if ( ! init )
+    {
+      p->param.data = (double*) Malloc(n*sizeof(double));
+      double *restrict odat = p->param.data;
+      const double *restrict idat = p2->param.data;
+      double cval = p1->u.con.value;
 
-  p->nmiss = nmiss;
+      oper_expr_con_var(oper, nmiss>0, n, missval1, missval2, odat, cval, idat);
 
-  if ( p2->tmpvar ) Free(p2->data);
+      nmiss = 0;
+      for ( size_t i = 0; i < n; i++ )
+        if ( DBL_IS_EQUAL(odat[i], missval1) ) nmiss++;
 
-  return (p);
+      p->param.nmiss = nmiss;
+    }
+  
+  return p;
 }
 
 static
-nodeType *expr_var_con(int oper, nodeType *p1, nodeType *p2)
+nodeType *expr_var_con(int init, int oper, nodeType *p1, nodeType *p2)
 {
-  int gridID   = p1->gridID;
-  int zaxisID  = p1->zaxisID;
-  int nmiss    = p1->nmiss;
-  double missval1 = p1->missval;
-  double missval2 = p1->missval;
+  size_t ngp   = p1->param.ngp;
+  size_t nlev  = p1->param.nlev;
+  size_t nmiss = p1->param.nmiss;
+  double missval1 = p1->param.missval;
+  double missval2 = p1->param.missval;
 
-  int ngp  = gridInqSize(gridID);
-  int nlev = zaxisInqSize(zaxisID);
-  long n   = ngp*nlev;
-  long i;
+  size_t n = ngp*nlev;
 
-  nodeType *p = (nodeType*) Malloc(sizeof(nodeType));
+  nodeType *p = (nodeType*) Calloc(1, sizeof(nodeType));
 
   p->type     = typeVar;
-  p->tmpvar   = 1;
-  p->u.var.nm = strdupx("tmp");
-  p->gridID   = gridID;
-  p->zaxisID  = zaxisID;
-  p->missval  = missval1;
+  p->ltmpobj  = true;
+  p->u.var.nm = strdup(tmpvnm);
+  param_meta_copy(&p->param, &p1->param);
+  p->param.name = p->u.var.nm;
 
-  p->data = (double*) Malloc(n*sizeof(double));
-  double *restrict odat = p->data;
-  const double *restrict idat = p1->data;
-  double cval = p2->u.con.value;
-
-  oper_expr_var_con(oper, nmiss, n, missval1, missval2, odat, idat, cval);
-
-  nmiss = 0;
-  for ( i = 0; i < n; i++ )
-    if ( DBL_IS_EQUAL(p->data[i], missval1) ) nmiss++;
+  if ( ! init )
+    {
+      p->param.data = (double*) Malloc(n*sizeof(double));
+      double *restrict odat = p->param.data;
+      const double *restrict idat = p1->param.data;
+      double cval = p2->u.con.value;
 
-  p->nmiss = nmiss;
+      oper_expr_var_con(oper, nmiss>0, n, missval1, missval2, odat, idat, cval);
 
-  if ( p1->tmpvar ) Free(p1->data);
+      nmiss = 0;
+      for ( size_t i = 0; i < n; i++ )
+        if ( DBL_IS_EQUAL(odat[i], missval1) ) nmiss++;
 
-  return (p);
+      p->param.nmiss = nmiss;
+    }
+  
+  return p;
 }
 
 static
-nodeType *expr_var_var(int oper, nodeType *p1, nodeType *p2)
+nodeType *expr_var_var(int init, int oper, nodeType *p1, nodeType *p2)
 {
-  long i;
-  long nlev, k;
-  long loff, loff1, loff2;
-  int nmiss;
+  nodeType *px = p1;
+  size_t nmiss1 = p1->param.nmiss;
+  size_t nmiss2 = p2->param.nmiss;
+  double missval1 = p1->param.missval;
+  double missval2 = p2->param.missval;
 
-  int nmiss1 = p1->nmiss;
-  int nmiss2 = p2->nmiss;
-  double missval1 = p1->missval;
-  double missval2 = p2->missval;
+  size_t ngp1 = p1->param.ngp;
+  size_t ngp2 = p2->param.ngp;
 
-  long ngp1 = gridInqSize(p1->gridID);
-  long ngp2 = gridInqSize(p2->gridID);
+  size_t ngp = ngp1;
 
-  if ( ngp1 != ngp2 && ngp2 != 1 ) cdoAbort("Number of grid points differ. ngp1 = %ld, ngp2 = %ld", ngp1, ngp2);
+  if ( ngp1 != ngp2 )
+    {
+      if ( ngp1 == 1 || ngp2 == 1 )
+        {
+          if ( ngp1 == 1 ) { ngp = ngp2; px = p2; }
+        }
+      else 
+        {
+          cdoAbort("%s: Number of grid points differ (%s[%ld] <-> %s[%ld])",
+                   __func__, p1->param.name, ngp1, p2->param.name, ngp2);
+        }
+    }
 
-  long ngp = ngp1;
+  size_t nlev1 = p1->param.nlev;
+  size_t nlev2 = p2->param.nlev;
 
-  long nlev1 = zaxisInqSize(p1->zaxisID);
-  long nlev2 = zaxisInqSize(p2->zaxisID);
+  size_t nlev = nlev1;
+  if ( nlev1 != nlev2 )
+    {
+      if ( nlev1 == 1 || nlev2 == 1 )
+        {
+          if ( nlev1 == 1 ) { nlev = nlev2; px = p2; }
+        }
+      else 
+        {
+          cdoAbort("%s: Number of levels differ (%s[%ld] <-> %s[%ld])",
+                   __func__, p1->param.name, nlev1, p2->param.name, nlev2);
+        }
+    }
 
-  nodeType *p = (nodeType*) Malloc(sizeof(nodeType));
+  nodeType *p = (nodeType*) Calloc(1, sizeof(nodeType));
 
   p->type     = typeVar;
-  p->tmpvar   = 1;
-  p->u.var.nm = strdupx("tmp");
+  p->ltmpobj  = true;
+  p->u.var.nm = strdup(tmpvnm);
 
-  if ( nlev1 > nlev2 )
-    {
-      nlev = nlev1;
-      p->gridID  = p1->gridID;
-      p->zaxisID = p1->zaxisID;
-      p->missval = p1->missval;
-      if ( nlev2 != 1 ) cdoAbort("nlev2 = %d must be 1!", nlev2);
-    }
-  else if ( nlev2 > nlev1 )
-    {
-      nlev = nlev2;
-      p->gridID  = p2->gridID;
-      p->zaxisID = p2->zaxisID;
-      p->missval = p2->missval;
-      if ( nlev1 != 1 ) cdoAbort("nlev1 = %d must be 1!", nlev1);
-    }
-  else
+  param_meta_copy(&p->param, &px->param);
+
+  int steptype1 = p1->param.steptype;
+  int steptype2 = p2->param.steptype;
+
+  if ( p->param.steptype == TSTEP_CONSTANT )
     {
-      nlev = nlev1;
-      p->gridID  = p1->gridID;
-      p->zaxisID = p1->zaxisID;
-      p->missval = p1->missval;
+      if ( steptype1 != TSTEP_CONSTANT )
+        p->param.steptype = steptype1;
+      else if ( steptype2 != TSTEP_CONSTANT )
+        p->param.steptype = steptype2;
     }
 
-  p->data = (double*) Malloc(ngp*nlev*sizeof(double));
+  p->param.name = p->u.var.nm;
+  //printf("%s %s nmiss %ld %ld\n", p->u.var.nm, px->param.name, nmiss1, nmiss2);
 
-  for ( k = 0; k < nlev; k++ )
+  if ( ! init )
     {
-      loff = k*ngp;
+      p->param.data = (double*) Malloc(ngp*nlev*sizeof(double));
 
-      if ( nlev1 == 1 ) loff1 = 0;
-      else              loff1 = k*ngp1;
+      for ( size_t k = 0; k < nlev; k++ )
+        {
+          size_t loff1 = 0, loff2 = 0;
+          size_t loff = k*ngp;
 
-      if ( nlev2 == 1 ) loff2 = 0;
-      else              loff2 = k*ngp2;
+          if ( nlev1 > 1 ) loff1 = k*ngp1;
+          if ( nlev2 > 1 ) loff2 = k*ngp2;
 
-      const double *restrict idat1 = p1->data+loff1;
-      const double *restrict idat2 = p2->data+loff2;
-      double *restrict odat = p->data+loff;
-      int nmiss = nmiss1 > 0 || nmiss2 > 0;
+          const double *restrict idat1 = p1->param.data+loff1;
+          const double *restrict idat2 = p2->param.data+loff2;
+          double *restrict odat = p->param.data+loff;
+          int nmiss = nmiss1 > 0 || nmiss2 > 0;
 
-      if ( ngp2 == 1 )
-        oper_expr_var_con(oper, nmiss, ngp, missval1, missval2, odat, idat1, idat2[0]);
-      else
-        oper_expr_var_var(oper, nmiss, ngp, missval1, missval2, odat, idat1, idat2);
+          if ( ngp1 != ngp2 )
+            {
+              if ( ngp2 == 1 )
+                oper_expr_var_con(oper, nmiss, ngp, missval1, missval2, odat, idat1, idat2[0]);
+              else
+                oper_expr_con_var(oper, nmiss, ngp, missval1, missval2, odat, idat1[0], idat2);
+            }
+          else
+            {
+              oper_expr_var_var(oper, nmiss, ngp, missval1, missval2, odat, idat1, idat2);
+            }
+          }
+
+      size_t nmiss = 0;
+      for ( size_t i = 0; i < ngp*nlev; i++ )
+        if ( DBL_IS_EQUAL(p->param.data[i], missval1) ) nmiss++;
+
+      p->param.nmiss = nmiss;
     }
+  
+  return p;
+}
+
+static
+void ex_copy_var(int init, nodeType *p2, nodeType *p1)
+{
+  if ( cdoVerbose ) cdoPrint("\t%s\tcopy\t%s[L%lu][N%lu] = %s[L%lu][N%lu]",
+                             ExIn[init], p2->param.name, p2->param.nlev, p2->param.ngp, p1->param.name, p2->param.nlev, p2->param.ngp);
+  
+  size_t ngp = p1->param.ngp;
+  assert(ngp > 0);
 
-  nmiss = 0;
-  for ( i = 0; i < ngp*nlev; i++ )
-    if ( DBL_IS_EQUAL(p->data[i], missval1) ) nmiss++;
+  if ( ngp != p2->param.ngp )
+    cdoAbort("%s: Number of grid points differ (%s[%d] = %s[%d])",
+             __func__, p2->param.name, p2->param.ngp, p1->param.name, ngp);
 
-  p->nmiss = nmiss;
+  size_t nlev = p1->param.nlev;
+  assert(nlev > 0);
 
-  if ( p1->tmpvar ) Free(p1->data);
-  if ( p2->tmpvar ) Free(p2->data);
+  if ( nlev != p2->param.nlev )
+    cdoAbort("%s: Number of levels differ (%s[%d] = %s[%d])",
+             __func__, p2->param.name, p2->param.nlev, p1->param.name, nlev);
 
-  return (p);
+  if ( ! init )
+    {
+      double *restrict odat = p2->param.data;
+      const double *restrict idat = p1->param.data;
+      for ( size_t i = 0; i < ngp*nlev; ++i ) odat[i] = idat[i];
+  
+      p2->param.missval = p1->param.missval;
+      p2->param.nmiss   = p1->param.nmiss;
+    }
 }
 
 static
-void ex_copy(nodeType *p2, nodeType *p1)
+void ex_copy_con(int init, nodeType *p2, nodeType *p1)
 {
-  long i;
+  double cval = p1->u.con.value;
 
-  if ( cdoVerbose ) printf("\tcopy %s\n", p1->u.var.nm);
+  if ( cdoVerbose ) cdoPrint("\t%s\tcopy\t%s[L%lu][N%lu] = %g", ExIn[init], p2->param.name, p2->param.nlev, p2->param.ngp, cval);
+  
+  size_t ngp = p2->param.ngp;
+  assert(ngp > 0);
 
-  long ngp1 = gridInqSize(p1->gridID);
-  long ngp2 = gridInqSize(p2->gridID);
+  size_t nlev = p2->param.nlev;
+  assert(nlev > 0);
 
-  if ( ngp1 != ngp2 )
-    cdoAbort("Number of grid points differ. ngp1 = %d, ngp2 = %d", ngp1, ngp2);
-
-  long ngp = ngp2;
-  long nlev = zaxisInqSize(p2->zaxisID);
+  if ( ! init )
+    {
+      double *restrict odat = p2->param.data;
+      assert(odat != NULL);
 
-  for ( i = 0; i < ngp*nlev; i++ ) p2->data[i] = p1->data[i];
+      for ( size_t i = 0; i < ngp*nlev; ++i ) odat[i] = cval;
+    }
+}
 
-  p2->missval = p1->missval;
-  p2->nmiss   = p1->nmiss;
+static
+void ex_copy(int init, nodeType *p2, nodeType *p1)
+{
+  if ( p1->type == typeCon )
+    ex_copy_con(init, p2, p1);
+  else
+    ex_copy_var(init, p2, p1);
 }
 
 static
-nodeType *expr(int oper, nodeType *p1, nodeType *p2)
+nodeType *expr(int init, int oper, nodeType *p1, nodeType *p2)
 {
-  nodeType *p = NULL;
+  if ( p1 == NULL || p2 == NULL ) return  NULL;
+  
+  const char *coper = "???";
 
-  if ( p1->type == typeVar && p2->type == typeVar )
+  if ( cdoVerbose )
     {
-      p = expr_var_var(oper, p1, p2);
-      if ( cdoVerbose )
-	printf("\t%s %c %s\n", p1->u.var.nm, oper, p2->u.var.nm);
+      switch ( oper )
+        {
+        case '+':  coper = "+"; break;
+        case '-':  coper = "-"; break;
+        case '*':  coper = "*"; break;
+        case '/':  coper = "/"; break;
+        case '^':  coper = "^"; break;
+        case LT:   coper = ">"; break;
+        case GT:   coper = "<"; break;
+        case LE:   coper = "<="; break;
+        case GE:   coper = ">="; break;
+        case NE:   coper = "!="; break;
+        case EQ:   coper = "=="; break;
+        case LEG:  coper = "<=>"; break;
+        case AND:  coper = "&&"; break;
+        case OR:   coper = "||"; break;
+        }
     }
-  else if ( p1->type == typeCon && p2->type == typeCon )
+
+ nodeType *p = NULL;
+
+  if ( p1->type == typeVar && p2->type == typeVar )
     {
-      p = expr_con_con(oper, p1, p2);
+      p = expr_var_var(init, oper, p1, p2);
       if ( cdoVerbose )
-	printf("\t%g %c %g\n", p1->u.con.value, oper, p2->u.con.value);
+	cdoPrint("\t%s\tarith\t%s[L%lu][N%lu] = %s %s %s", ExIn[init], p->u.var.nm, p->param.nlev, p->param.ngp, p1->u.var.nm, coper, p2->u.var.nm);
     }
   else if ( p1->type == typeVar && p2->type == typeCon )
     {
-      p = expr_var_con(oper, p1, p2);
+      p = expr_var_con(init, oper, p1, p2);
       if ( cdoVerbose )
-	printf("\t%s %c %g\n", p1->u.var.nm, oper, p2->u.con.value);
+	cdoPrint("\t%s\tarith\t%s[L%lu][N%lu] = %s %s %g", ExIn[init], p->u.var.nm, p->param.nlev, p->param.ngp, p1->u.var.nm, coper, p2->u.con.value);
     }
   else if ( p1->type == typeCon && p2->type == typeVar )
     {
-      p = expr_con_var(oper, p1, p2);
+      p = expr_con_var(init, oper, p1, p2);
       if ( cdoVerbose )
-	printf("\t%g %c %s\n", p1->u.con.value, oper, p2->u.var.nm);
+	cdoPrint("\t%s\tarith\t%s[L%lu][N%lu] = %g %s %s", ExIn[init], p->u.var.nm, p->param.nlev, p->param.ngp, p1->u.con.value, coper, p2->u.var.nm);
+    }
+  else if ( p1->type == typeCon && p2->type == typeCon )
+    {
+      p = expr_con_con(oper, p1, p2);
+      if ( cdoVerbose )
+	cdoPrint("\t%s\tarith\t%g = %g %s %g", ExIn[init], p->u.con.value, p1->u.con.value, coper, p2->u.con.value);
     }
   else
     cdoAbort("Internal problem!");
 
-  return (p);
+  if ( p1->ltmpobj ) node_delete(p1);
+  if ( p2->ltmpobj ) node_delete(p2);
+
+  return p;
 }
 
 static
-nodeType *ex_fun_con(char *fun, nodeType *p1)
+nodeType *ex_fun_con(int funcID, nodeType *p1)
 {
-  int i;
-  int funcID = -1;
+  int functype = fun_sym_tbl[funcID].type;
+  if ( functype != FT_STD ) cdoAbort("Function %s not available for constant values!", fun_sym_tbl[funcID].name);
 
-  nodeType *p = (nodeType*) Malloc(sizeof(nodeType));
+  nodeType *p = (nodeType*) Calloc(1, sizeof(nodeType));
 
-  p->type = typeCon;
+  p->type    = typeCon;
+  p->ltmpobj = true;
 
-  for ( i = 0; i < NumFunc; i++)
-    if ( fun_sym_tbl[i].type == 0 )
-      if ( strcmp(fun, fun_sym_tbl[i].name) == 0 )
-	{ 
-	  funcID = i;
-	  break;
-	}
-
-  if ( funcID == -1 )
-    cdoAbort("Function >%s< not available!", fun);
+  double (*exprfunc)(double) = (double (*)(double)) fun_sym_tbl[funcID].func;
+  p->u.con.value = exprfunc(p1->u.con.value);
 
-  p->u.con.value = fun_sym_tbl[funcID].func(p1->u.con.value);
+  if ( p1->ltmpobj ) node_delete(p1);
+  else Free(p1);
 
-  return (p);
+  return p;
 }
 
 static
-nodeType *ex_fun_var(char *fun, nodeType *p1)
+nodeType *ex_fun_var(int init, int funcID, nodeType *p1)
 {
-  long i;
-  int funcID = -1;
-  int gridID  = p1->gridID;
-  int zaxisID = p1->zaxisID;
-  int nmiss   = p1->nmiss;
-  double missval = p1->missval;
+  const char *funcname = fun_sym_tbl[funcID].name;
+  int functype = fun_sym_tbl[funcID].type;
+  int funcflag = fun_sym_tbl[funcID].flag;
 
-  long ngp  = gridInqSize(gridID);
-  long nlev = zaxisInqSize(zaxisID);
+  size_t ngp  = p1->param.ngp;
+  size_t nlev = p1->param.nlev;
+  size_t nmiss = p1->param.nmiss;
+  double missval = p1->param.missval;
 
-  nodeType *p = (nodeType*) Malloc(sizeof(nodeType));
+  nodeType *p = (nodeType*) Calloc(1, sizeof(nodeType));
 
   p->type     = typeVar;
-  p->tmpvar   = 1;
-  p->u.var.nm = strdupx("tmp");
-  p->gridID   = gridID;
-  p->zaxisID  = zaxisID;
-  p->missval  = missval;
-
-  p->data = (double*) Malloc(ngp*nlev*sizeof(double));
-
-  for ( i = 0; i < NumFunc; i++)
-    if ( strcmp(fun, fun_sym_tbl[i].name) == 0 )
-      { 
-	funcID = i;
-	break;
-      }
+  p->ltmpobj  = true;
+  p->u.var.nm = strdup(tmpvnm);
 
-  if ( funcID == -1 )
-    cdoAbort("Function >%s< not available!", fun);
+  param_meta_copy(&p->param, &p1->param);
 
-  if ( nmiss > 0 )
+  if ( functype == FT_CONST )
     {
-      for ( i = 0; i < ngp*nlev; i++ )
-	{
-	  errno = -1;
-	  p->data[i] = DBL_IS_EQUAL(p1->data[i], missval) ? missval : fun_sym_tbl[funcID].func(p1->data[i]);
-	  if ( errno == EDOM || errno == ERANGE ) p->data[i] = missval;
-	  else if ( isnan(p->data[i]) )  p->data[i] = missval;
-	}
+      p->type = typeCon;
+      double (*exprfunc)(paramType*) = (double (*)(paramType*)) fun_sym_tbl[funcID].func;
+      p->u.con.value = exprfunc(&p1->param);
     }
-  else
+  else if ( functype == FT_FLD )
     {
-      for ( i = 0; i < ngp*nlev; i++ )
-	{
-	  errno = -1;
-	  p->data[i] = fun_sym_tbl[funcID].func(p1->data[i]);
-	  if ( errno == EDOM || errno == ERANGE ) p->data[i] = missval;
-	  else if ( isnan(p->data[i]) )  p->data[i] = missval;
-	}
+      p->param.gridID = pointID;
+      p->param.ngp    = 1;
+    }
+  else if ( functype == FT_VERT )
+    {
+      p->param.zaxisID = surfaceID;
+      p->param.nlev    = 1;
     }
 
-  nmiss = 0;
-  for ( i = 0; i < ngp*nlev; i++ )
-    if ( DBL_IS_EQUAL(p->data[i], missval) ) nmiss++;
+  if ( ! init )
+    {
+      p->param.data = (double*) Malloc(p->param.ngp*p->param.nlev*sizeof(double));
+      double *restrict pdata  = p->param.data;
+      double *restrict p1data = p1->param.data;
+  
+      if ( functype == FT_STD )
+        {
+          double (*exprfunc)(double) = (double (*)(double)) fun_sym_tbl[funcID].func;
+          if ( nmiss > 0 )
+            {
+              for ( size_t i = 0; i < ngp*nlev; i++ )
+                {
+                  errno = -1;
+                  pdata[i] = DBL_IS_EQUAL(p1data[i], missval) ? missval : exprfunc(p1data[i]);
+                  if ( errno == EDOM || errno == ERANGE ) pdata[i] = missval;
+                  else if ( isnan(pdata[i]) ) pdata[i] = missval;
+                }
+            }
+          else
+            {
+              for ( size_t i = 0; i < ngp*nlev; i++ )
+                {
+                  errno = -1;
+                  pdata[i] = exprfunc(p1data[i]);
+                  if ( errno == EDOM || errno == ERANGE ) pdata[i] = missval;
+                  else if ( isnan(pdata[i]) ) pdata[i] = missval;
+                }
+            }
+        }
+      else if ( functype == FT_FLD )
+        {
+          field_t field;
+          double *weights = NULL;
+          //if ( funcflag == 1 ) weights = fld_weights(p1->param.gridID, ngp);
+          if ( funcflag == 1 )
+            {
+              weights = p1->param.weight;
+              assert(weights!=NULL);
+            }
+          
+          double (*exprfunc)(field_t) = (double (*)(field_t)) fun_sym_tbl[funcID].func;
+          for ( size_t k = 0; k < nlev; k++ )
+            {
+              fld_field_init(&field, nmiss, missval, ngp, p1data+k*ngp, weights);
+              pdata[k] = exprfunc(field);
+            }
+          //if ( weights ) Free(weights);
+        }
+      else if ( functype == FT_VERT )
+        {
+          field_t field;
+          double *weights = NULL;
+          if ( funcflag == 1 ) weights = vert_weights(p1->param.zaxisID, nlev);
+          double *array = (double*) Malloc(nlev*sizeof(double));
+          double (*exprfunc)(field_t) = (double (*)(field_t)) fun_sym_tbl[funcID].func;
+          for ( size_t i = 0; i < ngp; i++ )
+            {
+              for ( size_t k = 0; k < nlev; k++ ) array[k] = p1data[k*ngp+i];
+              fld_field_init(&field, nmiss, missval, nlev, array, weights);
+              pdata[i] = exprfunc(field);
+            }
+          if ( array ) Free(array);
+          if ( weights ) Free(weights);
+        }
+      else if ( functype == FT_CONST )
+        {
+        }
+      else
+        cdoAbort("Intermal error, wrong function type (%d) for %s()!", functype, funcname);
 
-  p->nmiss = nmiss;
+      nmiss = 0;
+      for ( size_t i = 0; i < p->param.ngp*p->param.nlev; i++ )
+        if ( DBL_IS_EQUAL(pdata[i], missval) ) nmiss++;
 
-  if ( p1->tmpvar ) Free(p1->data);
+      p->param.nmiss = nmiss;
+    }
 
-  return (p);
+  if ( p1->ltmpobj ) node_delete(p1);
+  else Free(p1);
+  
+  return p;
 }
 
 static
-nodeType *ex_fun(char *fun, nodeType *p1)
+nodeType *ex_fun(int init, int funcID, nodeType *p1)
 {
   nodeType *p = NULL;
 
   if ( p1->type == typeVar )
     {
-      p = ex_fun_var(fun, p1);
-      if ( cdoVerbose ) printf("\t%s (%s)\n", fun, p1->u.var.nm);
+      if ( cdoVerbose ) cdoPrint("\t%s\tfunc\t%s (%s)", ExIn[init], fun_sym_tbl[funcID].name, p1->u.var.nm);
+      p = ex_fun_var(init, funcID, p1);
     }
   else if ( p1->type == typeCon )
     {
-      p = ex_fun_con(fun, p1);
-      if ( cdoVerbose ) printf("\t%s (%g)\n", fun, p1->u.con.value);
+      if ( cdoVerbose ) cdoPrint("\t%s\tfunc\t%s (%g)", ExIn[init], fun_sym_tbl[funcID].name, p1->u.con.value);
+      p = ex_fun_con(funcID, p1);
     }
   else
     cdoAbort("Internal problem!");
 
-  return (p);
+  return p;
 }
 
 static
-nodeType *ex_uminus_var(nodeType *p1)
+size_t get_levidx(size_t nlev, const double *data, double value, const char *funcname)
 {
-  int gridID  = p1->gridID;
-  int zaxisID = p1->zaxisID;
-  int nmiss   = p1->nmiss;
-  double missval = p1->missval;
+  size_t levidx;
+  
+  for ( levidx = 0; levidx < nlev; ++levidx )
+    if ( IS_EQUAL(data[levidx], value) )
+      break;
+  if ( levidx == nlev ) cdoAbort("%s(): level %g not found!", funcname, value);
+
+  return levidx;
+}
+
+static
+nodeType *fun1c(int init, int funcID, nodeType *p1, double value, parse_param_t *parse_arg)
+{  
+  const char *funcname = fun_sym_tbl[funcID].name;            
+  if ( p1->type != typeVar ) cdoAbort("Parameter of function %s() needs to be a variable!", funcname);
+  if ( p1->ltmpobj ) cdoAbort("Temorary objects not allowed in function %s()!", funcname);
 
-  long ngp  = gridInqSize(gridID);
-  long nlev = zaxisInqSize(zaxisID);
+  size_t ngp   = p1->param.ngp;
+  size_t nlev  = p1->param.nlev;
+  size_t nmiss = p1->param.nmiss;
+  double missval = p1->param.missval;
 
-  nodeType *p = (nodeType*) Malloc(sizeof(nodeType));
+  nodeType *p = (nodeType*) Calloc(1, sizeof(nodeType));
 
   p->type     = typeVar;
-  p->tmpvar   = 1;
-  p->u.var.nm = strdupx("tmp");
-  p->gridID   = gridID;
-  p->zaxisID  = zaxisID;
-  p->missval  = missval;
+  p->ltmpobj  = true;
+  p->u.var.nm = strdup(tmpvnm);
+  param_meta_copy(&p->param, &p1->param);
+  p->param.name = p->u.var.nm;
 
-  p->data = (double*) Malloc(ngp*nlev*sizeof(double));
+  p->param.nlev = 1;
 
-  if ( nmiss > 0 )
+  int zaxisID = p1->param.zaxisID;
+  int coordID = params_get_coordID(parse_arg, 'z', zaxisID);
+  size_t levidx = 0;
+  
+  double *data = NULL;
+  if ( init )
     {
-      for ( long i = 0; i < ngp*nlev; i++ )
-	p->data[i] = DBL_IS_EQUAL(p1->data[i], missval) ? missval : -(p1->data[i]);
+      parse_arg->coords[coordID].needed = true;
+
+      data = (double*) malloc(nlev*sizeof(double));
+      zaxisInqLevels(zaxisID, data);
     }
   else
     {
-      for ( long i = 0; i < ngp*nlev; i++ )
-	p->data[i] = -(p1->data[i]);
+      data = parse_arg->coords[coordID].data;
+    }
+
+  if ( strcmp(funcname, "sellevidx") == 0 )
+    {
+      long ilevidx = lround(value);
+      if ( ilevidx < 1 || ilevidx > (long)nlev )
+        cdoAbort("%s(): level index %ld out of range (range: 1-%lu)!", funcname, ilevidx, nlev);
+      levidx = (size_t) ilevidx - 1;
+    }
+  else if ( strcmp(funcname, "sellevel") == 0 )
+    {
+      levidx = get_levidx(nlev, data, value, funcname);
+    }
+  else
+    cdoAbort("Function %s() not implemented!", funcname);
+
+  if ( init )
+    {
+      double level = data[levidx];
+      int zaxisID2 = zaxisCreate(zaxisInqType(zaxisID), 1);
+      zaxisDefLevels(zaxisID2, &level);
+      p->param.zaxisID = zaxisID2;
+    }
+
+  if ( init ) Free(data);
+
+  if ( ! init )
+    {
+      p->param.data = (double*) Malloc(ngp*sizeof(double));
+      double *restrict pdata = p->param.data;
+      const double *restrict p1data = p1->param.data+ngp*levidx;
+
+      for ( size_t i = 0; i < ngp; i++ ) pdata[i] = p1data[i];
+
+      if ( nmiss > 0 )
+        {
+          nmiss = 0;
+          for ( size_t i = 0; i < ngp; i++ )
+            if ( DBL_IS_EQUAL(pdata[i], missval) ) nmiss++;
+        }
+
+      p->param.nmiss = nmiss;
+    }
+
+  if ( p1->ltmpobj ) node_delete(p1);
+
+  return p;
+}
+
+static
+nodeType *coord_fun(int init, int funcID, nodeType *p1, parse_param_t *parse_arg)
+{  
+  const char *funcname = fun_sym_tbl[funcID].name;            
+  if ( p1->type != typeVar ) cdoAbort("Parameter of function %s() needs to be a variable!", funcname);
+  if ( p1->ltmpobj ) cdoAbort("Temorary objects not allowed in function %s()!", funcname);
+            
+  size_t len = 3 + strlen(p1->u.var.nm);
+  char *cname = (char*) Calloc(len, 1);
+  strcpy(cname, p1->u.var.nm);
+            
+  if      ( strcmp(funcname, "clon") == 0 ) strcat(cname, ".x");
+  else if ( strcmp(funcname, "clat") == 0 ) strcat(cname, ".y");
+  else if ( strcmp(funcname, "clev") == 0 ) strcat(cname, ".z");
+  else if ( strcmp(funcname, "gridarea")   == 0 ) strcat(cname, ".a");
+  else if ( strcmp(funcname, "gridweight") == 0 ) strcat(cname, ".w");
+  else cdoAbort("Implementation missing for function %s!", funcname);
+  
+  Free(p1->u.var.nm);
+  p1->u.var.nm = cname;
+
+  nodeType *p = expr_run(p1, parse_arg);
+  p->param.lmiss = false;
+
+  if ( ! init )
+    {
+      /*
+      size_t ngp  = p1->param.ngp;
+      size_t nlev = p1->param.nlev;
+      p->param.data = (double*) Malloc(ngp*nlev*sizeof(double));
+      double *restrict pdata  = p->param.data;
+      double *restrict p1data = p1->param.data;
+
+      for ( size_t i = 0; i < ngp*nlev; i++ ) pdata[i] = p1data[i];
+      */
     }
+  /*
+  Free(cname);
+  Free(p1);
+  */
+  return p;
+}
+
+static
+nodeType *ex_uminus_var(int init, nodeType *p1)
+{
+  size_t ngp   = p1->param.ngp;
+  size_t nlev  = p1->param.nlev;
+  size_t nmiss = p1->param.nmiss;
+  double missval = p1->param.missval;
+
+  nodeType *p = (nodeType*) Calloc(1, sizeof(nodeType));
+
+  p->type     = typeVar;
+  p->ltmpobj  = true;
+  p->u.var.nm = strdup(tmpvnm);
+  param_meta_copy(&p->param, &p1->param);
+  p->param.name = p->u.var.nm;
+
+  if ( ! init )
+    {
+      p->param.data = (double*) Malloc(ngp*nlev*sizeof(double));
+      double *restrict pdata = p->param.data;
+      const double *restrict p1data = p1->param.data;
 
-  p->nmiss = nmiss;
+      if ( nmiss > 0 )
+        {
+          for ( size_t i = 0; i < ngp*nlev; i++ )
+            pdata[i] = DBL_IS_EQUAL(p1data[i], missval) ? missval : -(p1data[i]);
+        }
+      else
+        {
+          for ( size_t i = 0; i < ngp*nlev; i++ )
+            pdata[i] = -(p1data[i]);
+        }
+
+      p->param.nmiss = nmiss;
+    }
+
+  if ( p1->ltmpobj ) node_delete(p1);
   
-  return (p);
+  return p;
 }
 
 static
 nodeType *ex_uminus_con(nodeType *p1)
 {
-  nodeType *p = (nodeType*) Malloc(sizeof(nodeType));
+  nodeType *p = (nodeType*) Calloc(1, sizeof(nodeType));
 
-  p->type = typeCon;
+  p->type    = typeCon;
+  p->ltmpobj = true;
 
   p->u.con.value = -(p1->u.con.value);
 
-  return (p);
+  return p;
 }
 
 static
-nodeType *ex_uminus(nodeType *p1)
+nodeType *ex_uminus(int init, nodeType *p1)
 {
   nodeType *p = NULL;
 
   if ( p1->type == typeVar )
     {
-      p = ex_uminus_var(p1);
-      if ( cdoVerbose ) printf("\t- (%s)\n", p1->u.var.nm);
+      if ( cdoVerbose ) cdoPrint("\t%s\tneg\t- (%s)", ExIn[init], p1->u.var.nm);
+      p = ex_uminus_var(init, p1);
     }
   else if ( p1->type == typeCon )
     {
+      if ( cdoVerbose ) cdoPrint("\t%s\tneg\t- (%g)", ExIn[init], p1->u.con.value);
       p = ex_uminus_con(p1);
-      if ( cdoVerbose ) printf("\t- (%g)\n", p1->u.con.value);
     }
   else
     cdoAbort("Internal problem!");
 
-  return (p);
+  return p;
 }
 
 static
-nodeType *ex_ifelse(nodeType *p1, nodeType *p2, nodeType *p3)
+nodeType *ex_ifelse(int init, nodeType *p1, nodeType *p2, nodeType *p3)
 {
-  if ( cdoVerbose ) printf("\t %s ? %s : %s\n", p1->u.var.nm, p2->u.var.nm, p3->u.var.nm);
-
   if ( p1->type == typeCon ) cdoAbort("expr?expr:expr: First expression is a constant but must be a variable!");
 
-  int nmiss1 = p1->nmiss;
-  long ngp1 = gridInqSize(p1->gridID);
-  long nlev1 = zaxisInqSize(p1->zaxisID);
-  double missval1 = p1->missval;
-  double *pdata1 = p1->data;
+  if ( cdoVerbose )
+    {
+      fprintf(stderr, "cdo expr:\t%s\tifelse\t%s[L%lu][N%lu] ? ", ExIn[init], p1->u.var.nm, p1->param.nlev, p1->param.ngp);
+      if ( p2->type == typeCon )
+        printf("%g : ", p2->u.con.value);
+      else
+        printf("%s[L%lu][N%lu] : ", p2->u.var.nm, p2->param.nlev, p2->param.ngp);
+      if ( p3->type == typeCon )
+        printf("%g\n", p3->u.con.value);
+      else
+        printf("%s[L%lu][N%lu]\n", p3->u.var.nm, p3->param.nlev, p3->param.ngp);
+    }
+
+  size_t nmiss1 = p1->param.nmiss;
+  size_t ngp1   = p1->param.ngp;
+  size_t nlev1  = p1->param.nlev;
+  double missval1 = p1->param.missval;
 
-  long ngp = ngp1;
-  long nlev = nlev1;
+  size_t ngp = ngp1;
+  size_t nlev = nlev1;
   nodeType *px = p1;
 
   double missval2 = missval1;
-  double *pdata2;
-  long ngp2 = 1;
-  long nlev2 = 1;
+  double *pdata2 = NULL;
+  size_t ngp2 = 1;
+  size_t nlev2 = 1;
   
   if ( p2->type == typeCon )
     {
@@ -762,12 +1164,12 @@ nodeType *ex_ifelse(nodeType *p1, nodeType *p2, nodeType *p3)
     }
   else
     {
-      ngp2 = gridInqSize(p2->gridID);
-      nlev2 = zaxisInqSize(p2->zaxisID);
-      missval2 = p2->missval;
-      pdata2 = p2->data;
+      ngp2 = p2->param.ngp;
+      nlev2 = p2->param.nlev;
+      missval2 = p2->param.missval;
+      pdata2 = p2->param.data;
       if ( ngp2 > 1 && ngp2 != ngp1 )
-	cdoAbort("expr?expr:expr: Number of grid points differ. ngp1 = %ld, ngp2 = %ld", ngp1, ngp2);
+	cdoAbort("expr?expr:expr: Number of grid points differ (ngp1 = %ld, ngp2 = %ld)", ngp1, ngp2);
       if ( nlev2 > 1 && nlev2 != nlev )
 	{
 	  if ( nlev == 1 )
@@ -776,14 +1178,14 @@ nodeType *ex_ifelse(nodeType *p1, nodeType *p2, nodeType *p3)
 	      px = p2;
 	    }
 	  else
-	    cdoAbort("expr?expr:expr: Number of levels differ. nlev = %ld, nlev2 = %ld", nlev, nlev2);
+	    cdoAbort("expr?expr:expr: Number of levels differ (nlev = %ld, nlev2 = %ld)", nlev, nlev2);
 	}
     }
 
   double missval3 = missval1;
-  double *pdata3;
-  long ngp3 = 1;
-  long nlev3 = 1;
+  double *pdata3 = NULL;
+  size_t ngp3 = 1;
+  size_t nlev3 = 1;
   
   if ( p3->type == typeCon )
     {
@@ -791,12 +1193,12 @@ nodeType *ex_ifelse(nodeType *p1, nodeType *p2, nodeType *p3)
     }
   else
     {
-      ngp3 = gridInqSize(p3->gridID);
-      nlev3 = zaxisInqSize(p3->zaxisID);
-      missval3 = p3->missval;
-      pdata3 = p3->data;
+      ngp3 = p3->param.ngp;
+      nlev3 = p3->param.nlev;
+      missval3 = p3->param.missval;
+      pdata3 = p3->param.data;
       if ( ngp3 > 1 && ngp3 != ngp1 )
-	cdoAbort("expr?expr:expr: Number of grid points differ. ngp1 = %ld, ngp3 = %ld", ngp1, ngp3);
+	cdoAbort("expr?expr:expr: Number of grid points differ (ngp1 = %ld, ngp3 = %ld)", ngp1, ngp3);
       if ( nlev3 > 1 && nlev3 != nlev )
 	{
 	  if ( nlev == 1 )
@@ -805,73 +1207,86 @@ nodeType *ex_ifelse(nodeType *p1, nodeType *p2, nodeType *p3)
 	      px = p3;
 	    }
 	  else
-	    cdoAbort("expr?expr:expr: Number of levels differ. nlev = %ld, nlev3 = %ld", nlev, nlev3);
+	    cdoAbort("expr?expr:expr: Number of levels differ (nlev = %ld, nlev3 = %ld)", nlev, nlev3);
 	}
     }
 
-  nodeType *p = (nodeType*) Malloc(sizeof(nodeType));
+  nodeType *p = (nodeType*) Calloc(1, sizeof(nodeType));
 
   p->type     = typeVar;
-  p->tmpvar   = 1;
-  p->u.var.nm = strdupx("tmp");
+  p->ltmpobj  = true;
+  p->u.var.nm = strdup(tmpvnm);
 
-  p->gridID  = px->gridID;
-  p->zaxisID = px->zaxisID;
-  p->missval = px->missval;
+  param_meta_copy(&p->param, &px->param);
+  p->param.name = p->u.var.nm;
 
-  p->data = (double*) Malloc(ngp*nlev*sizeof(double));
+  if ( ! init )
+    {
+      size_t nmiss = 0;
+      double *pdata1 = p1->param.data;
+      
+      p->param.data = (double*) Malloc(ngp*nlev*sizeof(double));
 
-  long loff, loff1, loff2, loff3;
+      for ( size_t k = 0; k < nlev; ++k )
+        {
+          size_t loff1, loff2, loff3;
+          size_t loff = k*ngp;
 
-  for ( long k = 0; k < nlev; ++k )
-    {
-      loff = k*ngp;
+          if ( nlev1 == 1 ) loff1 = 0;
+          else              loff1 = k*ngp;
 
-      if ( nlev1 == 1 ) loff1 = 0;
-      else              loff1 = k*ngp;
+          if ( nlev2 == 1 ) loff2 = 0;
+          else              loff2 = k*ngp;
 
-      if ( nlev2 == 1 ) loff2 = 0;
-      else              loff2 = k*ngp;
+          if ( nlev3 == 1 ) loff3 = 0;
+          else              loff3 = k*ngp;
 
-      if ( nlev3 == 1 ) loff3 = 0;
-      else              loff3 = k*ngp;
+          const double *restrict idat1 = pdata1+loff1;
+          const double *restrict idat2 = pdata2+loff2;
+          const double *restrict idat3 = pdata3+loff3;
+          double *restrict odat = p->param.data+loff;
 
-      const double *restrict idat1 = pdata1+loff1;
-      const double *restrict idat2 = pdata2+loff2;
-      const double *restrict idat3 = pdata3+loff3;
-      double *restrict odat = p->data+loff;
+          double ival2 = idat2[0];
+          double ival3 = idat3[0];
+          for ( size_t i = 0; i < ngp; ++i ) 
+            {
+              if ( ngp2 > 1 ) ival2 = idat2[i];
+              if ( ngp3 > 1 ) ival3 = idat3[i];
+
+              if ( nmiss1 && DBL_IS_EQUAL(idat1[i], missval1) )
+                odat[i] = missval1;
+              else if ( IS_NOT_EQUAL(idat1[i], 0) )
+                odat[i] = DBL_IS_EQUAL(ival2, missval2) ? missval1 : ival2;
+              else
+                odat[i] = DBL_IS_EQUAL(ival3, missval3) ? missval1 : ival3;
+            }
 
-      double ival2 = idat2[0];
-      double ival3 = idat3[0];
-      for ( long i = 0; i < ngp; ++i ) 
-	{
-	  if ( ngp2 > 1 ) ival2 = idat2[i];
-	  if ( ngp3 > 1 ) ival3 = idat3[i];
+          for ( size_t i = 0; i < ngp; i++ )
+            if ( DBL_IS_EQUAL(odat[i], missval1) ) nmiss++;
+        }
 
-	  if ( nmiss1 && DBL_IS_EQUAL(idat1[i], missval1) )
-	    odat[i] = missval1;
-	  else if ( IS_NOT_EQUAL(idat1[i], 0) )
-	    odat[i] = DBL_IS_EQUAL(ival2, missval2) ? missval1 : ival2;
-	  else
-	    odat[i] = DBL_IS_EQUAL(ival3, missval3) ? missval1 : ival3;
-	}
+      p->param.nmiss = nmiss;
     }
 
-  return (p);
-}
+  if ( p1->ltmpobj ) node_delete(p1);
+  if ( p2->ltmpobj ) node_delete(p2);
+  if ( p3->ltmpobj ) node_delete(p3);
 
-
-int exNode(nodeType *p, parse_parm_t *parse_arg)
+  return p;
+}
+/*
+static
+int exNode(nodeType *p, parse_param_t *parse_arg)
 {
-  if ( ! p ) return(0);
+  if ( ! p ) return 0;
 
-  /* node is leaf */
+  // node is leaf
   if ( p->type == typeCon || p->type == typeVar || p->u.opr.nops == 0 )
     {
       return 0;
     }
 
-  /* node has children */
+  // node has children
   for ( int k = 0; k < p->u.opr.nops; k++ )
     {
       exNode(p->u.opr.op[k], parse_arg);
@@ -879,249 +1294,353 @@ int exNode(nodeType *p, parse_parm_t *parse_arg)
 
   return 0;
 }
+*/
 
-
-nodeType *expr_run(nodeType *p, parse_parm_t *parse_arg)
+static
+int param_search_name(int nparam, paramType *params, const char *name)
 {
-  int gridID1 = -1, zaxisID1 = -1, tsteptype1 = -1;
-  double missval = 0;
-  char varname[256];
-  int varID, nvars;
-  nodeType *rnode = NULL;
-
-  if ( ! p ) return (rnode);
+  int varID = -1;
 
-  /*  if ( ! parse_arg->init ) { exNode(p, parse_arg); return 0; } */
-
-  switch ( p->type )
+  for ( varID = nparam-1; varID >= 0; --varID )
     {
-    case typeCon:       
-      if ( parse_arg->init )
-	{
-	  if ( parse_arg->debug )
-	    printf("\tpush const \t%g\n", p->u.con.value);
-	}
-      else
-	{
-	  rnode = p;
-	}
-
-      break;
-    case typeVar:
-      /*    if ( parse_arg->init ) */
-	{
-	  if ( parse_arg->debug )
-	    printf("\tpush var \t%s\n", p->u.var.nm);
-
-	  nvars = vlistNvars(parse_arg->vlistID1);
-	  for ( varID = 0; varID < nvars; varID++ )
-	    {
-	      vlistInqVarName(parse_arg->vlistID1, varID, varname);
-	      if ( strcmp(varname, p->u.var.nm) == 0 ) break;
-	    }
-
-	  if ( varID == nvars )
-	    {
-	      cdoAbort("Variable >%s< not found!", p->u.var.nm);
-	    }
-	  else
-	    {
-	      int nlev1, nlev2 = 0;
-	      if ( varID >= MAX_VARS ) cdoAbort("Too many parameter (limit=%d)!", MAX_VARS);
-
-	      if ( parse_arg->var_needed[varID] == 0 )
-		{
+      if ( strcmp(params[varID].name, name) == 0 ) break;
+    }
 
-		  parse_arg->var[varID] = strdupx(p->u.var.nm);
-		  parse_arg->varID[varID] = varID;
-		  parse_arg->var_needed[varID] = 1;
-		}
+  return varID;
+}
 
-	      gridID1    = vlistInqVarGrid(parse_arg->vlistID1, varID);
-	      zaxisID1   = vlistInqVarZaxis(parse_arg->vlistID1, varID);
-	      tsteptype1 = vlistInqVarTsteptype(parse_arg->vlistID1, varID);
-	      missval    = vlistInqVarMissval(parse_arg->vlistID1, varID);
-	      nlev1 = zaxisInqSize(zaxisID1);
 
-	      parse_arg->missval2 = missval;
+nodeType *expr_run(nodeType *p, parse_param_t *parse_arg)
+{
+  pointID = parse_arg->pointID;
+  surfaceID = parse_arg->surfaceID;
+  int init = parse_arg->init;
+  paramType *params = parse_arg->params;
+  int varID;
+  nodeType *rnode = NULL;
 
-	      if ( parse_arg->gridID2 == -1 )
-		parse_arg->gridID2 = gridID1;
+  if ( ! p ) return rnode;
 
-	      if ( parse_arg->zaxisID2 != -1 ) nlev2 = zaxisInqSize(parse_arg->zaxisID2);
+  /*  if ( ! init ) { exNode(p, parse_arg); return 0; } */
 
-	      if ( parse_arg->zaxisID2 == -1 || (nlev1 > 1 && nlev2 == 1) )
-		parse_arg->zaxisID2 = zaxisID1;
+  switch ( p->type )
+    {
+    case typeCom:
+      {
+        const char *cname = p->u.com.cname;
+        const char *vname = p->u.com.vname;
+        if ( parse_arg->debug ) cdoPrint("\tstatement\t\t%s(%s)", cname, vname);
+
+        varID = param_search_name(parse_arg->nparams, params, vname);
+        if ( varID == -1 ) cdoAbort("Variable %s not found, needed for statement %s(%s)!", vname, cname, vname);
+
+        if ( init )
+          {
+            if ( strcmp(cname, "remove") == 0 )
+              {
+                params[varID].remove = true;
+              }
+          }
+        else
+          {
+            if ( strcmp(cname, "print") == 0 )
+              {
+                size_t maxout = 100;
+                int vartsID = parse_arg->tsID;
+                int steptype = params[varID].steptype;
+                size_t ngp = params[varID].ngp;
+                size_t nlev = params[varID].nlev;
+                const double *data = params[varID].data;
+                long tsID = lround(params[vartsID].data[0]);
+                for ( size_t k = 0; k < nlev; ++k )
+                  for ( size_t i = 0; i < ngp; ++i )
+                    {
+                      if ( i < maxout || (ngp > maxout && i >= (ngp-maxout)) )
+                        {
+                          if ( steptype == TIME_CONSTANT )
+                            fprintf(stdout, "   %s[lev=%lu:gp=%lu] = %g\n", vname, k+1, i+1, data[k*ngp+i]);
+                          else
+                            fprintf(stdout, "   %s[ts=%ld:lev=%lu:gp=%lu] = %g\n", vname, tsID, k+1, i+1, data[k*ngp+i]);
+                        }
+                      else if ( i == maxout )
+                        {
+                          fprintf(stdout, "   .......\n");
+                        }
+                    }
+              }
+          }
+        
+        break;
+      }
+    case typeCon:
+      {
+        if ( parse_arg->debug ) cdoPrint("\tpush\tconst\t%g", p->u.con.value);
 
-	      if ( parse_arg->tsteptype2 == -1 || parse_arg->tsteptype2 == TSTEP_CONSTANT )
-		parse_arg->tsteptype2 = tsteptype1;
-	    }
-	}
-	/* else */
-	{ 
-	  if ( parse_arg->debug )
-	    printf("var: %s %d %d %d\n", p->u.var.nm, varID, gridID1, zaxisID1);
-	  p->gridID  = gridID1;
-	  p->zaxisID = zaxisID1;
-	  p->missval = missval;
-          p->nmiss   = 0;
-	  if ( ! parse_arg->init )
-	    {
-	      p->data  = parse_arg->vardata1[varID];
-	      p->nmiss = parse_arg->nmiss[varID];
-	    }
-	  p->tmpvar  = 0;
-	  rnode = p;
-	}
+        rnode = p;
 
-      break;
+        break;
+      }
+    case typeVar:
+      {
+        const char *vnm = p->u.var.nm;
+        varID = param_search_name(parse_arg->nparams, params, vnm);
+        if ( varID == -1 && init )
+          {
+            size_t len = strlen(vnm);
+            int coord = vnm[len-1];
+            if ( len > 2 && vnm[len-2] == '.' )
+              {
+                if ( coord == 'x' || coord == 'y' || coord == 'a' || coord == 'w' )
+                  {
+                    char *varname = strdup(vnm);
+                    varname[len-2] = 0;
+                    varID = param_search_name(parse_arg->nparams, params, varname);
+                    free(varname);
+                    if ( varID == -1 )
+                      {
+                        cdoAbort("Coordinate %c: variable >%s< not found!", coord, varname);
+                      }
+                    else
+                      {
+                        int nvarID = parse_arg->nparams;
+                        if ( nvarID >= parse_arg->maxparams )
+                          cdoAbort("Too many parameter (limit=%d)", parse_arg->maxparams);
+
+                        int coordID = params_get_coordID(parse_arg, coord, params[varID].gridID);
+                        parse_arg->coords[coordID].needed = true;
+                        const char *units = parse_arg->coords[coordID].units;
+                        const char *longname = parse_arg->coords[coordID].longname;
+
+                        params[nvarID].coord    = coord;
+                        params[nvarID].lmiss    = false;
+                        params[nvarID].name     = strdup(vnm);
+                        params[nvarID].missval  = params[varID].missval;
+                        params[nvarID].gridID   = params[varID].gridID;
+                        params[nvarID].zaxisID  = parse_arg->surfaceID;
+                        params[nvarID].steptype = TIME_CONSTANT;
+                        params[nvarID].ngp      = params[varID].ngp;
+                        params[nvarID].nlev     = 1;
+                        if ( units ) params[nvarID].units = strdup(units);
+                        if ( longname ) params[nvarID].longname = strdup(longname);
+                        parse_arg->nparams++;
+                        varID = nvarID;
+                      }
+                  }
+                else if ( coord == 'z' )
+                  {
+                    char *varname = strdup(vnm);
+                    varname[len-2] = 0;
+                    varID = param_search_name(parse_arg->nparams, params, varname);
+                    free(varname);
+                    if ( varID == -1 )
+                      {
+                        cdoAbort("Coordinate %c: variable >%s< not found!", coord, varname);
+                      }
+                    else
+                      {
+                        int nvarID = parse_arg->nparams;
+                        if ( nvarID >= parse_arg->maxparams )
+                          cdoAbort("Too many parameter (limit=%d)", parse_arg->maxparams);
+                          
+                        int coordID = params_get_coordID(parse_arg, coord, params[varID].zaxisID);
+                        parse_arg->coords[coordID].needed = true;
+                        const char *units = parse_arg->coords[coordID].units;
+                        const char *longname = parse_arg->coords[coordID].longname;
+                                     
+                        params[nvarID].coord    = coord;
+                        params[nvarID].lmiss    = false;
+                        params[nvarID].name     = strdup(vnm);
+                        params[nvarID].missval  = params[varID].missval;
+                        params[nvarID].gridID   = parse_arg->pointID;
+                        params[nvarID].zaxisID  = params[varID].zaxisID;
+                        params[nvarID].steptype = TIME_CONSTANT;
+                        params[nvarID].ngp      = 1;
+                        params[nvarID].nlev     = params[varID].nlev;
+                        if ( units ) params[nvarID].units = strdup(units);
+                        if ( longname ) params[nvarID].longname = strdup(longname);
+                        parse_arg->nparams++;
+                        varID = nvarID;
+                      }
+                  }
+              }
+          }
+        if ( varID == -1 )
+          {
+            cdoAbort("Variable >%s< not found!", p->u.var.nm);
+          }
+        else if ( init )
+          {
+            if ( varID < parse_arg->nvars1 && parse_arg->needed[varID] == false )
+              {
+                parse_arg->needed[varID] = true;
+              }
+          }
+
+
+        param_meta_copy(&p->param, &params[varID]);
+        p->param.coord    = params[varID].coord;
+        p->param.lmiss    = params[varID].lmiss;
+        p->param.name     = params[varID].name;
+        p->param.longname = params[varID].longname;
+        p->param.units    = params[varID].units;
+        p->ltmpobj = false;
+        /*
+        if ( parse_arg->debug )
+          printf("var: u.var.nm=%s name=%s gridID=%d zaxisID=%d ngp=%d nlev=%d  varID=%d\n",
+                 p->u.var.nm, p->param.name, p->param.gridID, p->param.zaxisID, p->param.ngp, p->param.nlev, varID);
+        */
+        if ( ! init )
+          {
+            p->param.data  = params[varID].data;
+            p->param.nmiss = params[varID].nmiss;
+          }
+
+        if ( parse_arg->debug ) cdoPrint("\tpush\tvar\t%s[L%lu][N%lu]", vnm, p->param.nlev, p->param.ngp);
+
+        rnode = p;
+
+        break;
+      }
+    case typeFun1c:
+      {
+        int funcID = get_funcID(p->u.fun1c.name);
+        int functype = fun_sym_tbl[funcID].type;
+        
+        nodeType *fnode = expr_run(p->u.fun1c.op, parse_arg);
+        
+        if ( functype == FT_1C )
+          {
+            double value = p->u.fun1c.value;
+            rnode = fun1c(init, funcID, fnode, value, parse_arg);
+          }
+
+        break;
+      }
     case typeFun:
-      if ( parse_arg->init )
-	{
-	  expr_run(p->u.fun.op, parse_arg);
-
-	  if ( parse_arg->debug )
-	    printf("\tcall \t%s\n", p->u.fun.name);
-	}
-      else
-	{
-	  rnode = ex_fun(p->u.fun.name, expr_run(p->u.fun.op, parse_arg));
-	}
-      break;
+      {
+        int funcID = get_funcID(p->u.fun.name);
+        int functype = fun_sym_tbl[funcID].type;
+
+        nodeType *fnode = expr_run(p->u.fun.op, parse_arg);
+
+        if ( functype == FT_COORD )
+          {
+            rnode = coord_fun(init, funcID, fnode, parse_arg);
+          }
+        else
+          {
+            int functype = fun_sym_tbl[funcID].type;
+            int funcflag = fun_sym_tbl[funcID].flag;
+            if ( functype == FT_FLD && funcflag == 1 )
+              {
+                int coordID = params_get_coordID(parse_arg, 'w', fnode->param.gridID);
+                if ( init )
+                  parse_arg->coords[coordID].needed = true;
+                else
+                  fnode->param.weight = parse_arg->coords[coordID].data;
+              }
+            rnode = ex_fun(init, funcID, fnode);
+            // if ( fnode->ltmpobj ) node_delete(fnode);
+            // Free(fnode);
+          }
+        
+        break;
+      }
     case typeOpr:
       switch( p->u.opr.oper )
 	{
         case '=':
-	  parse_arg->gridID2    = -1;
-	  parse_arg->zaxisID2   = -1;
-          parse_arg->tsteptype2 = -1;
-
-	  rnode = expr_run(p->u.opr.op[1], parse_arg);
-
-	  if ( parse_arg->init )
-	    {
-	      if ( parse_arg->debug )
-		printf("\tpop  var \t%s\n", p->u.opr.op[0]->u.var.nm);
-	      /*
-	      if ( p->u.opr.op[1]->type != typeVar )
-		cdoAbort("Operand not variable!");
-	      */
-	      if ( parse_arg->gridID2 == -1 || parse_arg->zaxisID2 == -1 || parse_arg->tsteptype2 == -1 )
-		cdoAbort("Operand not variable!");
-
-	      varID = vlistDefVar(parse_arg->vlistID2, parse_arg->gridID2, parse_arg->zaxisID2, parse_arg->tsteptype2);
-	      const char *varname = p->u.opr.op[0]->u.var.nm;
-	      vlistDefVarName(parse_arg->vlistID2, varID, varname);
-	      vlistDefVarMissval(parse_arg->vlistID2, varID, parse_arg->missval2);
-	      if ( memcmp(varname, "var", 3) == 0 )
-		{
-		  if ( strlen(varname) > 3 && isdigit(varname[3]) )
-		    {
-		      int code = atoi(varname+3);
-		      vlistDefVarCode(parse_arg->vlistID2, varID, code);
-		    }
-		}
-	    }
-	  else
-	    {
-	      if ( parse_arg->debug )
-		printf("\tpop var\t%s\t%s\n", p->u.opr.op[0]->u.var.nm, rnode->u.var.nm);
-
-	      nvars = vlistNvars(parse_arg->vlistID2);
-	      for ( varID = nvars-1; varID >= 0; varID-- )
-		{
-		  vlistInqVarName(parse_arg->vlistID2, varID, varname);
-		  if ( strcmp(varname, p->u.opr.op[0]->u.var.nm) == 0 ) break;
-		}
-
-	      if ( varID < 0 )
-		{
-		  cdoAbort("Variable >%s< not found!", p->u.opr.op[0]->u.var.nm);
-		}
-	      else
-		{
-		  parse_arg->gridID2  = vlistInqVarGrid(parse_arg->vlistID2, varID);
-		  parse_arg->zaxisID2 = vlistInqVarZaxis(parse_arg->vlistID2, varID);
-		  parse_arg->tsteptype2 = vlistInqVarTsteptype(parse_arg->vlistID2, varID);
-		  missval  = vlistInqVarMissval(parse_arg->vlistID2, varID);
-	      
-		  p->gridID  = parse_arg->gridID2;
-		  p->zaxisID = parse_arg->zaxisID2;
-		  p->missval = missval;
-		  p->data    = parse_arg->vardata2[varID];
-		  p->tmpvar  = 0;
-
-		  ex_copy(p, rnode);
-
-		  if ( rnode->tmpvar ) Free(rnode->data);
-		}
-	    }
-
-	  break;
-        case UMINUS:    
-	  if ( parse_arg->init )
-	    {
-	      expr_run(p->u.opr.op[0], parse_arg);
-
-	      if ( parse_arg->debug )
-		printf("\tneg\n");
-	    }
-	  else
-	    {
-	      rnode = ex_uminus(expr_run(p->u.opr.op[0], parse_arg));
-	    }
-
-	  break;
-        case '?':    
-	  if ( parse_arg->init )
-	    {
-	      expr_run(p->u.opr.op[0], parse_arg);
-	      expr_run(p->u.opr.op[1], parse_arg);
-	      expr_run(p->u.opr.op[2], parse_arg);
-
-	      if ( parse_arg->debug )
-		printf("\t?:\n");
-	    }
-	  else
-	    {
-	      rnode = ex_ifelse(expr_run(p->u.opr.op[0], parse_arg),
-			        expr_run(p->u.opr.op[1], parse_arg),
-			        expr_run(p->u.opr.op[2], parse_arg));
-	    }
-
-	  break;
+          {
+            rnode = expr_run(p->u.opr.op[1], parse_arg);
+
+            const char *varname2 = p->u.opr.op[0]->u.var.nm;
+
+            if ( parse_arg->debug )
+              {
+                if ( rnode && rnode->type == typeVar)
+                  cdoPrint("\tpop\tvar\t%s[L%lu][N%lu]", varname2, rnode->param.nlev, rnode->param.ngp);
+                else
+                  cdoPrint("\tpop\tconst\t%s", varname2);
+              }
+
+            if ( init )
+              {
+                varID = param_search_name(parse_arg->nparams, params, varname2);
+                if ( varID >= 0 )
+                  {
+                    if ( varID < parse_arg->nvars1 )
+                      {
+                        params[varID].select = true;
+                        parse_arg->needed[varID] = true;
+                      }
+                    else if ( params[varID].coord )
+                      cdoAbort("Coordinate variable %s is read only!", varname2);
+                    /*
+                      else
+                      cdoWarning("Variable %s already defined!", varname2);
+                    */
+                  }
+                else if ( p->u.opr.op[1]->type != typeCon )
+                  {
+                    varID = parse_arg->nparams;
+                    if ( varID >= parse_arg->maxparams )
+                      cdoAbort("Too many parameter (limit=%d)", parse_arg->maxparams);
+
+                    param_meta_copy(&params[varID], &rnode->param);
+                    params[varID].coord = 0;
+                    params[varID].lmiss = rnode->param.lmiss;
+                    params[varID].name  = strdup(varname2);
+                    params[varID].nmiss = rnode->param.nmiss;
+                    if ( rnode->param.units ) params[varID].units = strdup(rnode->param.units);
+                    if ( rnode->param.longname ) params[varID].longname = strdup(rnode->param.longname);
+                    parse_arg->nparams++;
+                  }
+              }
+            else
+              {
+                varID = param_search_name(parse_arg->nparams, params, varname2);
+                if ( varID < 0 ) cdoAbort("Variable >%s< not found!", varname2);
+                else if ( params[varID].coord ) cdoAbort("Coordinate variable %s is read only!", varname2);
+                param_meta_copy(&p->param, &params[varID]);
+                p->param.name  = params[varID].name;
+                p->param.data  = params[varID].data;
+                p->ltmpobj     = false;
+                
+                ex_copy(init, p, rnode);
+                params[varID].nmiss = p->param.nmiss;
+              }
+            
+            if ( rnode && rnode->ltmpobj ) { node_delete(rnode); rnode = NULL; }
+            // else Free(rnode);
+
+            break;
+          }
+        case UMINUS:
+          {
+            rnode = ex_uminus(init, expr_run(p->u.opr.op[0], parse_arg));
+
+            break;
+          }
+        case '?':
+          {
+            rnode = ex_ifelse(init,
+                              expr_run(p->u.opr.op[0], parse_arg),
+                              expr_run(p->u.opr.op[1], parse_arg),
+                              expr_run(p->u.opr.op[2], parse_arg));
+            
+            break;
+          }
         default:
-	  if ( parse_arg->init )
-	    {
-	      expr_run(p->u.opr.op[0], parse_arg);
-	      expr_run(p->u.opr.op[1], parse_arg);
-	      if ( parse_arg->debug )
-		switch( p->u.opr.oper )
-		  {
-		  case '+':  printf("\tadd\n"); break;
-		  case '-':  printf("\tsub\n"); break;
-		  case '*':  printf("\tmul\n"); break;
-		  case '/':  printf("\tdiv\n"); break;
-		  case '<':  printf("\tcompLT\n"); break;
-		  case '>':  printf("\tcompGT\n"); break;
-		  case LE:   printf("\tcompLE\n"); break;
-		  case GE:   printf("\tcompGE\n"); break;
-		  case NE:   printf("\tcompNE\n"); break;
-		  case EQ:   printf("\tcompEQ\n"); break;
-		  case LEG:  printf("\tcompLEG\n"); break;
-		  case AND:  printf("\tcompAND\n"); break;
-		  case OR:   printf("\tcompOR\n"); break;
-		  }
-	    }
-	  else
-	    {
-	      rnode = expr(p->u.opr.oper, expr_run(p->u.opr.op[0], parse_arg),
-			                  expr_run(p->u.opr.op[1], parse_arg));
-	    }
-          break;
+          {
+            rnode = expr(init, p->u.opr.oper,
+                         expr_run(p->u.opr.op[0], parse_arg),
+                         expr_run(p->u.opr.op[1], parse_arg));
+
+            break;
+          }
         }
       break;
     }
 
-  return (rnode);
+  return rnode;
 }
diff --git a/src/expr.h b/src/expr.h
index 6d3cebc..f8a013f 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -1,111 +1,162 @@
+/*
+  This file is part of CDO. CDO is a collection of Operators to
+  manipulate and analyse Climate model Data.
+
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  See COPYING file for copying and redistribution conditions.
+
+  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 Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+*/
+
 #include <stdio.h>
+#include <stdbool.h>
 
+#ifdef __cplusplus
 #ifndef register
 #define register
 #endif
-
-#ifdef __cplusplus
 #ifndef fileno
 int fileno(FILE *stream);
 #endif
 #endif
 
-#ifndef strdupx
-#ifndef strdup
-char *strdup(const char *s);
-#endif
-#define strdupx  strdup
-/*
-#define strdupx(s)			          \
-({					      	  \
-   const char *__old = (s);			  \
-   size_t __len = strlen(__old) + 1;		  \
-   char *__new = Malloc(__len);	  \
-   (char *) memcpy(__new, __old, __len);	  \
-})
-*/
-#endif
+extern int CDO_parser_errorno;
+
 
+typedef enum { typeCon, typeVar, typeFun, typeFun1c, typeOpr, typeCom } nodeEnum;
 
-typedef enum { typeCon, typeVar, typeFun, typeOpr } nodeEnum;
+// commands
+typedef struct {
+  char *cname;                // command name
+  char *vname;                // variable name
+} comNodeType;
 
-/* constants */
+// constants
 typedef struct {
-  double value;               /* value of constant */
+  double value;               // value of constant
 } conNodeType;
 
-/* variables */
+// variables
 typedef struct {
-  char *nm;                   /* variable name */
+  char *nm;                   // variable name
 } varNodeType;
 
-/* functions */
+// 1c functions
 typedef struct {
-  char *name;                 /* function name */
-  struct nodeTypeTag *op;     /* operand       */
+  char *name;                 // function name
+  double value;               // value of constant
+  struct nodeTypeTag *op;     // operand
+} fun1cNodeType;
+
+// functions
+typedef struct {
+  char *name;                 // function name
+  struct nodeTypeTag *op;     // operand
 } funNodeType;
 
-/* operators */
+// operators
 typedef struct {
-  int oper;                   /* operator              */
-  int nops;                   /* number of operands    */
-  struct nodeTypeTag *op[1];  /* operands (expandable) */
+  int oper;                   // operator             
+  int nops;                   // number of operands   
+  struct nodeTypeTag *op[1];  // operands (expandable)
 } oprNodeType;
 
+// parameter
+typedef struct {
+  bool       select;
+  bool       remove;
+  bool       lmiss;
+  int        coord;
+  int        gridID;
+  int        zaxisID;
+  int        steptype;
+  size_t     ngp;
+  size_t     nlev;
+  size_t     nmiss;
+  char      *name;
+  char      *longname;
+  char      *units;
+  double     missval;
+  double    *data;
+  double    *weight;
+} paramType;
+
+
 typedef struct nodeTypeTag {
-  int tmpvar;
-  int gridID, zaxisID;
-  int nmiss;
-  double missval;
-  double *data;
-  nodeEnum type;              /* type of node */
-
-  /* union must be last entry in nodeType */
-  /* because operNodeType may dynamically increase */
+  bool      ltmpobj;
+  paramType param;
+
+  nodeEnum  type;             // type of node
+
+  // union must be last entry in nodeType
+  // because operNodeType may dynamically increase
   union {
-    conNodeType con;          /* constants   */
-    varNodeType var;          /* variables   */
-    funNodeType fun;          /* functions   */
-    oprNodeType opr;          /* operators   */
+    comNodeType com;          // commands
+    conNodeType con;          // constants
+    varNodeType var;          // variables
+    funNodeType fun;          // functions
+    fun1cNodeType fun1c;      // functions
+    oprNodeType opr;          // operators
   } u;
 } nodeType;
 
-#define MAX_VARS 1024
-
-typedef struct{ /* prs_sct */
-  int    vlistID1, vlistID2;
-  int    nvars1, nvars2;
-  int    nmiss[MAX_VARS];
-  int    varID[MAX_VARS];
-  int    var_needed[MAX_VARS];
-  char   *var[MAX_VARS];
-  int    init;
-  int    debug;
-  int    gridID2;
-  int    zaxisID2;
-  int    tsteptype2;
-  double missval2;
-  double **vardata1, **vardata2;
-} parse_parm_t;
+
+typedef struct {
+  bool       needed;
+  int        coord;
+  int        cdiID;
+  int        size;
+  char      *units;
+  char      *longname;
+  double    *data;
+} coordType;
+
+
+typedef struct {
+  bool       init;
+  bool       debug;
+  bool      *needed;
+  int        maxparams;
+  int        nparams;
+  int        nvars1;
+  int        ncoords;
+  int        maxcoords;
+  int        tsID;
+  int        pointID;
+  int        surfaceID;
+  coordType *coords;
+  paramType *params;
+} parse_param_t;
 
 
 typedef union{
-    double cvalue;              /* constant value */
-    char *varnm;                /* variable name  */
-    char *fname;                /* function name  */
-    nodeType *nPtr;             /* node pointer   */
+  double    cvalue;           // constant value
+  char     *varnm;            // variable name 
+  char     *fname;            // function name 
+  nodeType *nPtr;             // node pointer  
 } stype_t;
 
 
 #define YYSTYPE        stype_t
-#define YY_EXTRA_TYPE  parse_parm_t *
+#define YY_EXTRA_TYPE  parse_param_t *
 
-#define YY_DECL int yylex(YYSTYPE *yylval_param, parse_parm_t *parse_arg, void *yyscanner)
+#define YY_DECL int yylex(YYSTYPE *yylval_param, parse_param_t *parse_arg, void *yyscanner)
 YY_DECL;
 
-int  yyparse(parse_parm_t *parse_arg, void*);
+int  yyparse(parse_param_t *parse_arg, void*);
 void yyerror(void *parse_arg, void *scanner, const char *errstr);
 
 int  yylex_init(void **);
 int  yylex_destroy(void *);
 void yyset_extra(YY_EXTRA_TYPE, void *);
+
+nodeType *expr_run(nodeType *p, parse_param_t *parse_arg);
+int params_get_coordID(parse_param_t *parse_arg, int coord, int cdiID);
+
diff --git a/src/expr_fun.c b/src/expr_fun.c
new file mode 100644
index 0000000..ab478e4
--- /dev/null
+++ b/src/expr_fun.c
@@ -0,0 +1,76 @@
+/*
+  This file is part of CDO. CDO is a collection of Operators to
+  manipulate and analyse Climate model Data.
+
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  See COPYING file for copying and redistribution conditions.
+
+  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 Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+*/
+
+#include "cdo_int.h"
+#include "grid.h"
+
+
+void fld_field_init(field_t *field, size_t nmiss, double missval, size_t ngp, double *array, double *w)
+{
+  field_init(field);
+
+  field->size    = ngp;
+  field->nmiss   = nmiss;
+  field->missval = missval;
+  field->ptr     = array;
+  field->weight  = w;
+}
+
+
+double *fld_weights(int gridID, size_t ngp)
+{
+  static bool lwarn = true;
+  double *weights = (double*) Malloc(ngp*sizeof(double));
+  for ( size_t i = 0; i < ngp; ++i ) weights[i] = 1;
+
+  if ( ngp > 1 )
+    {
+      int wstatus = gridWeights(gridID, weights);
+      if ( wstatus != 0 && lwarn )
+        {
+          lwarn = false;
+          cdoWarning("Grid cell bounds not available, using constant grid cell area weights!");
+        }
+    }
+
+  return weights;
+}
+
+
+int getLayerThickness(int genbounds, int index, int zaxisID, int nlev, double *thickness, double *weights);
+
+double *vert_weights(int zaxisID, size_t nlev)
+{
+  static bool lwarn = true;
+  double *weights = (double*) Malloc(nlev*sizeof(double));
+  double *thickness = (double*) Malloc(nlev*sizeof(double));
+  for ( size_t i = 0; i < nlev; ++i ) weights[i] = 1;
+
+  if ( nlev > 1 )
+    {
+      int wstatus = getLayerThickness(0, 0, zaxisID, nlev, thickness, weights);
+      if ( wstatus != 0 && lwarn && nlev > 1 )
+        {
+          lwarn = false;
+          cdoWarning("Layer bounds not available, using constant vertical weights!");
+        }
+    }
+
+  Free(thickness);
+  
+  return weights;
+}
diff --git a/src/cdo.h b/src/expr_fun.h
similarity index 67%
copy from src/cdo.h
copy to src/expr_fun.h
index 569c938..4f48d54 100644
--- a/src/cdo.h
+++ b/src/expr_fun.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -15,9 +15,11 @@
   GNU General Public License for more details.
 */
 
-#ifndef _CDO_H
-#define _CDO_H
+#ifndef _EXPR_FUN_H
+#define _EXPR_FUN_H
 
-#include "text.h"
+void fld_field_init(field_t *field, size_t nmiss, double missval, size_t ngp, double *array, double *w);
+double *fld_weights(int gridID, size_t ngp);
+double *vert_weights(int zaxisID, size_t nlev);
 
-#endif  /* _CDO_H */
+#endif
diff --git a/src/expr_lex.c b/src/expr_lex.c
index e931959..5572444 100644
--- a/src/expr_lex.c
+++ b/src/expr_lex.c
@@ -8,8 +8,8 @@
 
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 37
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 0
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -159,7 +159,15 @@ typedef void* yyscan_t;
 
 /* Size of default input buffer. */
 #ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
 #define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
 #endif
 
 /* The state buf must be large enough to hold one state per character in the main buffer.
@@ -181,6 +189,7 @@ typedef size_t yy_size_t;
 #define EOB_ACT_LAST_MATCH 2
 
     #define YY_LESS_LINENO(n)
+    #define YY_LINENO_REWIND_TO(ptr)
     
 /* Return all but the first "n" matched characters back to the input stream. */
 #define yyless(n) \
@@ -326,7 +335,7 @@ void yyfree (void * ,yyscan_t yyscanner );
 
 /* Begin user sect3 */
 
-#define yywrap(yyscanner) 1
+#define yywrap(yyscanner) (/*CONSTCOND*/1)
 #define YY_SKIP_YYWRAP
 
 typedef unsigned char YY_CHAR;
@@ -338,6 +347,9 @@ typedef int yy_state_type;
 static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
 static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
 static int yy_get_next_buffer (yyscan_t yyscanner );
+#if defined(__GNUC__) && __GNUC__ >= 3
+__attribute__((__noreturn__))
+#endif
 static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
 
 /* Done after the current pattern has been matched and before the
@@ -350,8 +362,8 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
 	*yy_cp = '\0'; \
 	yyg->yy_c_buf_p = yy_cp;
 
-#define YY_NUM_RULES 17
-#define YY_END_OF_BUFFER 18
+#define YY_NUM_RULES 22
+#define YY_END_OF_BUFFER 23
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -359,45 +371,51 @@ struct yy_trans_info
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_acclist[91] =
+static yyconst flex_int16_t yy_acclist[123] =
     {   0,
-        4,    4,   18,   16,   17,   15,   16,   17,   15,   17,
-       16,   17,    1,   16,   17,   16,   17,    7,   16,   17,
-        4,    7,   16,   17,    4,   16,   17,    7,   16,   17,
-        7,   16,   17,    7,   16,   17,    6,   16,   17,16389,
-        4,    6,   16,   17,16389,    6,   16,   17,16389,    6,
-       16,   17,16389,   16,   17,   15,   12,    1,   13,    4,
-        4,    4,    4,   10,   11,    9, 8197,    6,16389,    4,
-        6,16389,    6,16389,   14,    4,    4,    8,    4,    6,
-    16389,    3,    6,16389,    6,16389,    4,    2,    6,16389
+        4,    4,   23,   21,   22,   20,   21,   22,   20,   22,
+       21,   22,    1,   21,   22,   21,   22,   10,   21,   22,
+        4,   10,   21,   22,    4,   21,   22,   15,   21,   22,
+       10,   21,   22,   14,   21,   22,    9,   21,   22,16391,
+        4,    9,   21,   22,16391,    9,   21,   22,16391,    9,
+       21,   22,16391,    9,   21,   22,16391,    9,   21,   22,
+    16391,   21,   22,   20,   17,    1,   18,    4,    4,    4,
+        4,   13,   16,   12, 8199,    8,    9,16391,    4,    9,
+    16391,    9,16391,    9,16391,    9,16391,   19,    4,    4,
+       11,    8,    4,    9,16391,    3,    9,16391,    9,16391,
+
+        9,16391,    9,16391,    4,    2,    9,16391,    9,16391,
+        9,16391,    9,16391,    9,16391,    6, 8199,    9,16391,
+        5, 8199
     } ;
 
-static yyconst flex_int16_t yy_accept[52] =
+static yyconst flex_int16_t yy_accept[67] =
     {   0,
         1,    2,    3,    4,    6,    9,   11,   13,   16,   18,
        21,   25,   28,   31,   34,   37,   41,   46,   50,   54,
-       56,   57,   58,   59,   60,   61,   62,   62,   63,   64,
-       64,   65,   66,   67,   67,   68,   70,   70,   73,   75,
-       76,   76,   77,   78,   79,   82,   85,   87,   88,   91,
-       91
+       58,   62,   64,   65,   66,   67,   68,   69,   70,   70,
+       71,   72,   72,   73,   74,   75,   75,   76,   77,   79,
+       79,   82,   84,   86,   88,   89,   89,   90,   91,   92,
+       93,   96,   99,  101,  103,  105,  106,  109,  111,  113,
+      115,  117,  119,  121,  123,  123
     } ;
 
-static yyconst flex_int32_t yy_ec[256] =
+static yyconst YY_CHAR yy_ec[256] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    2,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    4,    5,    1,    6,    1,    1,    7,    1,    8,
-        9,    9,   10,    1,   10,   11,    9,   12,   12,   12,
+        9,    9,   10,    9,   10,   11,    9,   12,   12,   12,
        12,   12,   12,   12,   12,   12,   12,    9,    9,   13,
        14,   15,    9,    1,   16,   16,   16,   17,   18,   16,
        16,   16,   19,   16,   16,   17,   20,   16,   16,   21,
        16,   16,   16,   16,   16,   16,   16,   16,   16,   16,
         1,    1,    1,    9,   22,    1,   16,   16,   16,   17,
 
-       23,   16,   16,   16,   16,   16,   16,   17,   16,   16,
-       16,   16,   16,   16,   16,   16,   16,   16,   16,   16,
-       16,   16,    9,   24,    9,    1,    1,    1,    1,    1,
+       23,   16,   16,   16,   24,   16,   16,   17,   25,   26,
+       27,   28,   16,   29,   16,   30,   16,   31,   16,   16,
+       16,   16,    9,   32,    9,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -414,65 +432,82 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[25] =
+static yyconst YY_CHAR yy_meta[33] =
     {   0,
         1,    1,    2,    3,    1,    1,    1,    3,    1,    1,
-        1,    3,    1,    1,    1,    3,    3,    3,    3,    3,
-        3,    3,    3,    1
+        3,    3,    1,    1,    1,    4,    4,    4,    4,    4,
+        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,
+        4,    1
     } ;
 
-static yyconst flex_int16_t yy_base[53] =
+static yyconst flex_uint16_t yy_base[69] =
     {   0,
-        0,    0,   87,   88,   23,   26,   72,    0,   78,   88,
-       19,   32,   70,   69,   68,   30,   31,   52,   37,   57,
-       44,   88,    0,   88,    0,   88,   41,    0,    0,   42,
-       65,   88,   88,   53,   88,   57,   66,   23,   45,   88,
-       65,   53,   56,   88,   53,   49,   50,   88,   36,   88,
-       73,   29
+        0,    0,  140,  152,   31,   34,  125,    0,  131,  152,
+       27,   40,  122,   99,   95,   38,   51,   60,   31,   44,
+       55,   60,   72,  152,    0,  152,   65,  152,   69,   68,
+        0,   77,   69,  152,  152,   86,  152,    0,   83,   57,
+       30,   86,   87,   90,  152,   48,   49,   89,  152,    0,
+       93,   98,  102,  106,  107,  152,  110,  113,  114,  119,
+      118,  152,  125,  152,  152,  145,  147,   44
     } ;
 
-static yyconst flex_int16_t yy_def[53] =
+static yyconst flex_int16_t yy_def[69] =
     {   0,
-       50,    1,   50,   50,   50,   50,   50,   51,   50,   50,
-       50,   50,   50,   50,   50,   52,   52,   52,   52,   50,
-       50,   50,   51,   50,   11,   50,   50,   11,   12,   50,
-       50,   50,   50,   50,   50,   19,   50,   18,   19,   50,
-       50,   50,   50,   50,   19,   19,   19,   50,   19,    0,
-       50,   50
+       65,    1,   65,   65,   65,   65,   65,   66,   65,   65,
+       65,   65,   65,   65,   65,   67,   67,   67,   18,   18,
+       18,   65,   65,   65,   66,   65,   65,   65,   65,   65,
+       12,   65,   65,   65,   65,   65,   65,   68,   18,   65,
+       18,   18,   18,   18,   65,   65,   65,   65,   65,   68,
+       18,   18,   18,   18,   18,   65,   18,   18,   18,   18,
+       18,   65,   18,   65,    0,   65,   65,   65
     } ;
 
-static yyconst flex_int16_t yy_nxt[113] =
+static yyconst flex_uint16_t yy_nxt[185] =
     {   0,
         4,    5,    6,    5,    7,    8,    9,   10,   10,   10,
        11,   12,   13,   14,   15,   16,   17,   18,   16,   19,
-       16,   16,   18,   20,   21,   21,   21,   21,   21,   21,
-       25,   36,   50,   34,   34,   26,   27,   35,   35,   45,
-       34,   27,   28,   29,   35,   21,   21,   21,   26,   30,
-       41,   37,   42,   43,   30,   34,   34,   36,   39,   35,
-       35,   37,   46,   38,   42,   47,   36,   43,   49,   26,
-       36,   36,   48,   23,   36,   23,   42,   43,   36,   44,
-       40,   33,   32,   31,   24,   22,   50,    3,   50,   50,
-       50,   50,   50,   50,   50,   50,   50,   50,   50,   50,
-
-       50,   50,   50,   50,   50,   50,   50,   50,   50,   50,
-       50,   50
+       16,   16,   18,   16,   16,   16,   16,   20,   21,   16,
+       16,   22,   23,   23,   23,   23,   23,   23,   27,   65,
+       65,   36,   39,   28,   29,   37,   51,   50,   38,   29,
+       30,   31,   42,   65,   36,   39,   28,   32,   37,   47,
+       47,   38,   32,   36,   65,   28,   39,   37,   48,   40,
+       38,   41,   43,   23,   23,   23,   27,   44,   46,   27,
+       47,   28,   29,   49,   28,   29,   40,   29,   48,   36,
+       29,   45,   65,   37,   39,   65,   65,   39,   39,   65,
+
+       48,   39,   65,   52,   39,   56,   53,   65,   35,   39,
+       54,   65,   34,   39,   55,   65,   65,   39,   39,   65,
+       57,   39,   65,   65,   39,   39,   62,   65,   65,   39,
+       39,   58,   64,   59,   65,   33,   39,   26,   24,   65,
+       63,   65,   60,   65,   61,   25,   65,   25,   25,   39,
+       39,    3,   65,   65,   65,   65,   65,   65,   65,   65,
+       65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
+       65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
+       65,   65,   65,   65
     } ;
 
-static yyconst flex_int16_t yy_chk[113] =
+static yyconst flex_int16_t yy_chk[185] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    5,    5,    5,    6,    6,    6,
-       11,   52,   38,   16,   17,   11,   11,   16,   17,   38,
-       19,   11,   12,   12,   19,   21,   21,   21,   12,   12,
-       27,   30,   27,   30,   12,   18,   34,   49,   19,   18,
-       34,   18,   39,   18,   42,   39,   39,   43,   47,   42,
-       46,   47,   43,   51,   45,   51,   41,   37,   36,   31,
-       20,   15,   14,   13,    9,    7,    3,   50,   50,   50,
-       50,   50,   50,   50,   50,   50,   50,   50,   50,   50,
-
-       50,   50,   50,   50,   50,   50,   50,   50,   50,   50,
-       50,   50
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    5,    5,    5,    6,    6,    6,   11,   41,
+       19,   16,   19,   11,   11,   16,   41,   68,   16,   11,
+       12,   12,   19,   20,   17,   20,   12,   12,   17,   46,
+       47,   17,   12,   18,   21,   47,   21,   18,   40,   18,
+       18,   18,   20,   23,   23,   23,   27,   21,   29,   30,
+       29,   27,   27,   33,   30,   30,   32,   27,   32,   36,
+       30,   22,   39,   36,   39,   42,   43,   42,   43,   44,
+
+       48,   44,   51,   42,   51,   48,   42,   52,   15,   52,
+       43,   53,   14,   53,   44,   54,   55,   54,   55,   57,
+       53,   57,   58,   59,   58,   59,   60,   61,   60,   61,
+       60,   54,   63,   55,   63,   13,   63,    9,    7,    3,
+       61,    0,   58,    0,   59,   66,    0,   66,   66,   67,
+       67,   65,   65,   65,   65,   65,   65,   65,   65,   65,
+       65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
+       65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
+       65,   65,   65,   65
     } ;
 
 #define YY_TRAILING_MASK 0x2000
@@ -516,7 +551,7 @@ goto find_rule; \
    LPH [A-Za-z_] Alphabetic character
    LPHDGT [A-Za-z0-9_] Alphanumeric character
    XPN [eE][+-]?[0-9]+ Real number Exponent */
-#line 520 "expr_lex.c"
+#line 555 "expr_lex.c"
 
 #define INITIAL 0
 
@@ -604,11 +639,11 @@ void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
 
 FILE *yyget_in (yyscan_t yyscanner );
 
-void yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+void yyset_in  (FILE * _in_str ,yyscan_t yyscanner );
 
 FILE *yyget_out (yyscan_t yyscanner );
 
-void yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+void yyset_out  (FILE * _out_str ,yyscan_t yyscanner );
 
 yy_size_t yyget_leng (yyscan_t yyscanner );
 
@@ -616,11 +651,11 @@ char *yyget_text (yyscan_t yyscanner );
 
 int yyget_lineno (yyscan_t yyscanner );
 
-void yyset_lineno (int line_number ,yyscan_t yyscanner );
+void yyset_lineno (int _line_number ,yyscan_t yyscanner );
 
 int yyget_column  (yyscan_t yyscanner );
 
-void yyset_column (int column_no ,yyscan_t yyscanner );
+void yyset_column (int _column_no ,yyscan_t yyscanner );
 
 YYSTYPE * yyget_lval (yyscan_t yyscanner );
 
@@ -638,6 +673,10 @@ extern int yywrap (yyscan_t yyscanner );
 #endif
 #endif
 
+#ifndef YY_NO_UNPUT
+    
+#endif
+
 #ifndef yytext_ptr
 static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
 #endif
@@ -658,7 +697,12 @@ static int input (yyscan_t yyscanner );
 
 /* Amount of stuff to slurp up with each read. */
 #ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
 #define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
 #endif
 
 /* Copy whatever the last rule matched to the standard output. */
@@ -747,7 +791,7 @@ extern int yylex \
 
 /* Code executed at the end of each rule. */
 #ifndef YY_BREAK
-#define YY_BREAK break;
+#define YY_BREAK /*LINTED*/break;
 #endif
 
 #define YY_RULE_SETUP \
@@ -757,16 +801,11 @@ extern int yylex \
  */
 YY_DECL
 {
-	register yy_state_type yy_current_state;
-	register char *yy_cp, *yy_bp;
-	register int yy_act;
+	yy_state_type yy_current_state;
+	char *yy_cp, *yy_bp;
+	int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-#line 36 "expr_lex.l"
-
-
-#line 769 "expr_lex.c"
-
     yylval = yylval_param;
 
 	if ( !yyg->yy_init )
@@ -801,7 +840,13 @@ YY_DECL
 		yy_load_buffer_state(yyscanner );
 		}
 
-	while ( 1 )		/* loops until end-of-file is reached */
+	{
+#line 36 "expr_lex.l"
+
+
+#line 848 "expr_lex.c"
+
+	while ( /*CONSTCOND*/1 )		/* loops until end-of-file is reached */
 		{
 		yy_cp = yyg->yy_c_buf_p;
 
@@ -821,18 +866,18 @@ YY_DECL
 yy_match:
 		do
 			{
-			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 51 )
+				if ( yy_current_state >= 66 )
 					yy_c = yy_meta[(unsigned int) yy_c];
 				}
 			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 			*yyg->yy_state_ptr++ = yy_current_state;
 			++yy_cp;
 			}
-		while ( yy_base[yy_current_state] != 88 );
+		while ( yy_base[yy_current_state] != 152 );
 
 yy_find_action:
 		yy_current_state = *--yyg->yy_state_ptr;
@@ -914,79 +959,108 @@ YY_RULE_SETUP
 	YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 60 "expr_lex.l"
+#line 59 "expr_lex.l"
+{ return REMOVE; }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 61 "expr_lex.l"
+{ return PRINT; }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 63 "expr_lex.l"
 {
-                yylval->fname = (char *) strdupx(yytext);
+                yylval->fname = strdup(yytext);
                 return FUNCTION;
              } /* end functions */
 	YY_BREAK
-case 6:
+case 8:
 YY_RULE_SETUP
-#line 66 "expr_lex.l"
+#line 68 "expr_lex.l"
 {
-                yylval->varnm = (char *) strdupx(yytext);
+                /* Recognize coordinates, e.g., var_nm.x (lon of var_nm) */
+                yylval->varnm = strdup(yytext);
                 return VARIABLE;
              }
 	YY_BREAK
-case 7:
+case 9:
 YY_RULE_SETUP
-#line 72 "expr_lex.l"
+#line 74 "expr_lex.l"
+{
+                yylval->varnm = strdup(yytext);
+                return VARIABLE;
+             }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 80 "expr_lex.l"
 {
                 return *yytext;
              }
 	YY_BREAK
-case 8:
+case 11:
 YY_RULE_SETUP
-#line 76 "expr_lex.l"
+#line 84 "expr_lex.l"
 return LEG;
 	YY_BREAK
-case 9:
+case 12:
 YY_RULE_SETUP
-#line 77 "expr_lex.l"
+#line 85 "expr_lex.l"
 return GE;
 	YY_BREAK
-case 10:
+case 13:
 YY_RULE_SETUP
-#line 78 "expr_lex.l"
+#line 86 "expr_lex.l"
 return LE;
 	YY_BREAK
-case 11:
+case 14:
 YY_RULE_SETUP
-#line 79 "expr_lex.l"
+#line 87 "expr_lex.l"
+return GT;
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 88 "expr_lex.l"
+return LT;
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 89 "expr_lex.l"
 return EQ;
 	YY_BREAK
-case 12:
+case 17:
 YY_RULE_SETUP
-#line 80 "expr_lex.l"
+#line 90 "expr_lex.l"
 return NE;
 	YY_BREAK
-case 13:
+case 18:
 YY_RULE_SETUP
-#line 81 "expr_lex.l"
+#line 91 "expr_lex.l"
 return AND;
 	YY_BREAK
-case 14:
+case 19:
 YY_RULE_SETUP
-#line 82 "expr_lex.l"
+#line 92 "expr_lex.l"
 return OR;
 	YY_BREAK
-case 15:
-/* rule 15 can match eol */
+case 20:
+/* rule 20 can match eol */
 YY_RULE_SETUP
-#line 84 "expr_lex.l"
+#line 94 "expr_lex.l"
 ;       /* ignore whitespace */
 	YY_BREAK
-case 16:
+case 21:
 YY_RULE_SETUP
-#line 86 "expr_lex.l"
+#line 96 "expr_lex.l"
 yyerror(NULL, NULL, "Unknown character");
 	YY_BREAK
-case 17:
+case 22:
 YY_RULE_SETUP
-#line 87 "expr_lex.l"
+#line 97 "expr_lex.l"
 ECHO;
 	YY_BREAK
-#line 990 "expr_lex.c"
+#line 1064 "expr_lex.c"
 			case YY_STATE_EOF(INITIAL):
 				yyterminate();
 
@@ -1117,6 +1191,7 @@ ECHO;
 			"fatal flex scanner internal error--no action found" );
 	} /* end of action switch */
 		} /* end of scanning one token */
+	} /* end of user's declarations */
 } /* end of yylex */
 
 /* yy_get_next_buffer - try to read in a new buffer
@@ -1129,9 +1204,9 @@ ECHO;
 static int yy_get_next_buffer (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
-	register char *source = yyg->yytext_ptr;
-	register int number_to_move, i;
+	char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	char *source = yyg->yytext_ptr;
+	yy_size_t number_to_move, i;
 	int ret_val;
 
 	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
@@ -1160,7 +1235,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 	/* Try to read more data. */
 
 	/* First move last chars to start of buffer. */
-	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+	number_to_move = (yy_size_t) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
 
 	for ( i = 0; i < number_to_move; ++i )
 		*(dest++) = *(source++);
@@ -1234,8 +1309,8 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
     static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
 {
-	register yy_state_type yy_current_state;
-	register char *yy_cp;
+	yy_state_type yy_current_state;
+	char *yy_cp;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
 	yy_current_state = yyg->yy_start;
@@ -1245,11 +1320,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
 	for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
 		{
-		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 51 )
+			if ( yy_current_state >= 66 )
 				yy_c = yy_meta[(unsigned int) yy_c];
 			}
 		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1266,18 +1341,18 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
  */
     static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
 {
-	register int yy_is_jam;
+	int yy_is_jam;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
 
-	register YY_CHAR yy_c = 1;
+	YY_CHAR yy_c = 1;
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 51 )
+		if ( yy_current_state >= 66 )
 			yy_c = yy_meta[(unsigned int) yy_c];
 		}
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 50);
+	yy_is_jam = (yy_current_state == 65);
 	if ( ! yy_is_jam )
 		*yyg->yy_state_ptr++ = yy_current_state;
 
@@ -1285,6 +1360,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 	return yy_is_jam ? 0 : yy_current_state;
 }
 
+#ifndef YY_NO_UNPUT
+
+#endif
+
 #ifndef YY_NO_INPUT
 #ifdef __cplusplus
     static int yyinput (yyscan_t yyscanner)
@@ -1438,7 +1517,7 @@ static void yy_load_buffer_state  (yyscan_t yyscanner)
 	if ( ! b )
 		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
-	b->yy_buf_size = size;
+	b->yy_buf_size = (yy_size_t)size;
 
 	/* yy_ch_buf has to be 2 characters longer than the size given because
 	 * we need to put in 2 end-of-buffer characters.
@@ -1599,7 +1678,7 @@ static void yyensure_buffer_stack (yyscan_t yyscanner)
 		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
 		 * immediate realloc on the next call.
          */
-		num_to_alloc = 1;
+		num_to_alloc = 1; // After all that talk, this was set to 1 anyways...
 		yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
 								(num_to_alloc * sizeof(struct yy_buffer_state*)
 								, yyscanner);
@@ -1616,7 +1695,7 @@ static void yyensure_buffer_stack (yyscan_t yyscanner)
 	if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
 
 		/* Increase the buffer to prepare for a possible push. */
-		int grow_size = 8 /* arbitrary grow size */;
+		yy_size_t grow_size = 8 /* arbitrary grow size */;
 
 		num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
 		yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
@@ -1693,7 +1772,7 @@ YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len
 	YY_BUFFER_STATE b;
 	char *buf;
 	yy_size_t n;
-	int i;
+	yy_size_t i;
     
 	/* Get memory for full buffer, including space for trailing EOB's. */
 	n = _yybytes_len + 2;
@@ -1724,7 +1803,9 @@ YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len
 
 static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
 {
-    	(void) fprintf( stderr, "%s\n", msg );
+	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	(void)yyg;
+	(void) fprintf( stderr, "%s\n", msg );
 	exit( YY_EXIT_FAILURE );
 }
 
@@ -1830,10 +1911,10 @@ void yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
 }
 
 /** Set the current line number.
- * @param line_number
+ * @param _line_number line number
  * @param yyscanner The scanner object.
  */
-void yyset_lineno (int  line_number , yyscan_t yyscanner)
+void yyset_lineno (int  _line_number , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
@@ -1841,14 +1922,14 @@ void yyset_lineno (int  line_number , yyscan_t yyscanner)
         if (! YY_CURRENT_BUFFER )
            YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
     
-    yylineno = line_number;
+    yylineno = _line_number;
 }
 
 /** Set the current column.
- * @param line_number
+ * @param _column_no column number
  * @param yyscanner The scanner object.
  */
-void yyset_column (int  column_no , yyscan_t yyscanner)
+void yyset_column (int  _column_no , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
@@ -1856,25 +1937,25 @@ void yyset_column (int  column_no , yyscan_t yyscanner)
         if (! YY_CURRENT_BUFFER )
            YY_FATAL_ERROR( "yyset_column called with no buffer" );
     
-    yycolumn = column_no;
+    yycolumn = _column_no;
 }
 
 /** Set the input stream. This does not discard the current
  * input buffer.
- * @param in_str A readable stream.
+ * @param _in_str A readable stream.
  * @param yyscanner The scanner object.
  * @see yy_switch_to_buffer
  */
-void yyset_in (FILE *  in_str , yyscan_t yyscanner)
+void yyset_in (FILE *  _in_str , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    yyin = in_str ;
+    yyin = _in_str ;
 }
 
-void yyset_out (FILE *  out_str , yyscan_t yyscanner)
+void yyset_out (FILE *  _out_str , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    yyout = out_str ;
+    yyout = _out_str ;
 }
 
 int yyget_debug  (yyscan_t yyscanner)
@@ -1883,10 +1964,10 @@ int yyget_debug  (yyscan_t yyscanner)
     return yy_flex_debug;
 }
 
-void yyset_debug (int  bdebug , yyscan_t yyscanner)
+void yyset_debug (int  _bdebug , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    yy_flex_debug = bdebug ;
+    yy_flex_debug = _bdebug ;
 }
 
 /* Accessor methods for yylval and yylloc */
@@ -2045,7 +2126,10 @@ int yylex_destroy  (yyscan_t yyscanner)
 #ifndef yytext_ptr
 static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
 {
-	register int i;
+	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	(void)yyg;
+
+	int i;
 	for ( i = 0; i < n; ++i )
 		s1[i] = s2[i];
 }
@@ -2054,7 +2138,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysca
 #ifdef YY_NEED_STRLEN
 static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
 {
-	register int n;
+	int n;
 	for ( n = 0; s[n]; ++n )
 		;
 
@@ -2064,11 +2148,16 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
 
 void *yyalloc (yy_size_t  size , yyscan_t yyscanner)
 {
+	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	(void)yyg;
 	return (void *) malloc( size );
 }
 
 void *yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
 {
+	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	(void)yyg;
+
 	/* The cast to (char *) in the following accommodates both
 	 * implementations that use char* generic pointers, and those
 	 * that use void* generic pointers.  It works with the latter
@@ -2081,12 +2170,14 @@ void *yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
 
 void yyfree (void * ptr , yyscan_t yyscanner)
 {
+	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	(void)yyg;
 	free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
 }
 
 #define YYTABLES_NAME "yytables"
 
-#line 87 "expr_lex.l"
+#line 97 "expr_lex.l"
 
 
 
diff --git a/src/expr_yacc.c b/src/expr_yacc.c
index 2b69bca..d1a5384 100644
--- a/src/expr_yacc.c
+++ b/src/expr_yacc.c
@@ -69,12 +69,14 @@
 #include <string.h>
 #include <stdarg.h>
 
+#include "dmemory.h"
+
 #include "expr.h"
 #include "expr_yacc.h" /* expr_yacc.h (y.tab.h) is produced from expr_yacc.y by parser generator */
 
 /* Bison manual p. 60 describes how to call yyparse() with arguments */
 /* #define YYPARSE_PARAM parse_arg */
-/* #define YYLEX_PARAM   ((parse_parm_t *) parse_arg, void *yyscanner) */
+/* #define YYLEX_PARAM   ((parse_param_t *) parse_arg, void *yyscanner) */
 
   /* #define YYPURE 1 *//* ??? */
 
@@ -83,12 +85,13 @@ nodeType *expr_opr(int oper, int nops, ...);
 nodeType *expr_var(char *nm);
 nodeType *expr_con(double value);
 nodeType *expr_fun(char *fname, nodeType *p);
+nodeType *expr_fun1c(char *fname, nodeType *op, double value);
+nodeType *expr_com(const char *cname, char *vname);
 
 void freeNode(nodeType *p);
-int expr_run(nodeType *p, parse_parm_t *parse_arg);
 
 
-#line 92 "expr_yacc.c" /* yacc.c:339  */
+#line 95 "expr_yacc.c" /* yacc.c:339  */
 
 # ifndef YY_NULLPTR
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -103,7 +106,7 @@ int expr_run(nodeType *p, parse_parm_t *parse_arg);
 # undef YYERROR_VERBOSE
 # define YYERROR_VERBOSE 1
 #else
-# define YYERROR_VERBOSE 0
+# define YYERROR_VERBOSE 1
 #endif
 
 /* In a future release of Bison, this section will be replaced
@@ -126,40 +129,48 @@ extern int yydebug;
     CONSTANT = 258,
     VARIABLE = 259,
     FUNCTION = 260,
-    LEG = 261,
-    GE = 262,
-    LE = 263,
-    EQ = 264,
-    NE = 265,
-    AND = 266,
-    OR = 267,
-    UMINUS = 268
+    REMOVE = 261,
+    PRINT = 262,
+    AND = 263,
+    OR = 264,
+    LEG = 265,
+    GE = 266,
+    LE = 267,
+    EQ = 268,
+    NE = 269,
+    GT = 270,
+    LT = 271,
+    UMINUS = 272
   };
 #endif
 /* Tokens.  */
 #define CONSTANT 258
 #define VARIABLE 259
 #define FUNCTION 260
-#define LEG 261
-#define GE 262
-#define LE 263
-#define EQ 264
-#define NE 265
-#define AND 266
-#define OR 267
-#define UMINUS 268
+#define REMOVE 261
+#define PRINT 262
+#define AND 263
+#define OR 264
+#define LEG 265
+#define GE 266
+#define LE 267
+#define EQ 268
+#define NE 269
+#define GT 270
+#define LT 271
+#define UMINUS 272
 
 /* Value type.  */
 
 
 
-int yyparse (parse_parm_t *parse_arg, void *scanner);
+int yyparse (parse_param_t *parse_arg, void *scanner);
 
 #endif /* !YY_YY_EXPR_YACC_H_INCLUDED  */
 
 /* Copy the second part of user declarations.  */
 
-#line 163 "expr_yacc.c" /* yacc.c:358  */
+#line 174 "expr_yacc.c" /* yacc.c:358  */
 
 #ifdef short
 # undef short
@@ -401,21 +412,21 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  3
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   182
+#define YYLAST   186
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  29
+#define YYNTOKENS  32
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  6
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  31
+#define YYNRULES  35
 /* YYNSTATES -- Number of states.  */
-#define YYNSTATES  61
+#define YYNSTATES  75
 
 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
    by yylex, with out-of-bounds checking.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   268
+#define YYMAXUTOK   272
 
 #define YYTRANSLATE(YYX)                                                \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -428,15 +439,15 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-      27,    28,    15,    13,     2,    14,     2,    16,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    21,    24,
-      12,    19,    11,    20,     2,     2,     2,     2,     2,     2,
+      30,    27,    19,    17,    31,    18,     2,    20,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    23,    25,
+       2,    26,     2,    22,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,    22,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,    24,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    25,     2,    26,     2,     2,     2,     2,
+       2,     2,     2,    28,     2,    29,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -450,30 +461,31 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    17,    18,    23
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    21
 };
 
 #if YYDEBUG
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,    53,    53,    57,    58,    62,    63,    64,    65,    66,
-      70,    71,    75,    76,    77,    78,    79,    80,    81,    82,
-      83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
-      93,    94
+       0,    58,    58,    62,    63,    67,    68,    69,    70,    71,
+      72,    73,    77,    78,    82,    83,    84,    85,    86,    87,
+      88,    89,    90,    91,    92,    93,    94,    95,    96,    97,
+      98,    99,   100,   101,   102,   103
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE || 0
+#if YYDEBUG || YYERROR_VERBOSE || 1
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
   "$end", "error", "$undefined", "CONSTANT", "VARIABLE", "FUNCTION",
-  "LEG", "GE", "LE", "EQ", "NE", "'>'", "'<'", "'+'", "'-'", "'*'", "'/'",
-  "AND", "OR", "'='", "'?'", "':'", "'^'", "UMINUS", "';'", "'{'", "'}'",
-  "'('", "')'", "$accept", "program", "function", "stmt", "stmt_list",
-  "expr", YY_NULLPTR
+  "REMOVE", "PRINT", "AND", "OR", "LEG", "GE", "LE", "EQ", "NE", "GT",
+  "LT", "'+'", "'-'", "'*'", "'/'", "UMINUS", "'?'", "':'", "'^'", "';'",
+  "'='", "')'", "'{'", "'}'", "'('", "','", "$accept", "program",
+  "function", "stmt", "stmt_list", "expr", YY_NULLPTR
 };
 #endif
 
@@ -483,15 +495,16 @@ static const char *const yytname[] =
 static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,    62,    60,    43,    45,    42,    47,   266,   267,    61,
-      63,    58,    94,   268,    59,   123,   125,    40,    41
+     265,   266,   267,   268,   269,   270,   271,    43,    45,    42,
+      47,   272,    63,    58,    94,    59,    61,    41,   123,   125,
+      40,    44
 };
 # endif
 
-#define YYPACT_NINF -15
+#define YYPACT_NINF -25
 
 #define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-15)))
+  (!!((Yystate) == (-25)))
 
 #define YYTABLE_NINF -1
 
@@ -502,13 +515,14 @@ static const yytype_uint16 yytoknum[] =
      STATE-NUM.  */
 static const yytype_int16 yypact[] =
 {
-     -15,     2,    33,   -15,   -15,    11,   -14,    36,   -15,    33,
-      36,   -15,   104,    36,   -15,    36,   -15,   -15,   -15,    29,
-      58,    36,    36,    36,    36,    36,    36,    36,    36,    36,
-      36,    36,    36,    36,    36,    36,   -15,   123,    81,   -15,
-     -15,   -15,   152,   152,   152,   152,   152,   152,   152,   160,
-     160,   -13,   -13,   -10,   -10,   142,     7,   -15,   -15,    36,
-     -10
+     -25,     5,    36,   -25,   -25,   -16,   -24,     7,     8,    33,
+     -25,    36,    33,   -25,   103,   -25,    33,    33,   -13,   -12,
+     -25,   -20,   -25,    28,    83,    33,    33,    33,    33,    33,
+      33,    33,    33,    33,    33,    33,    33,    33,    33,    33,
+     -25,   121,    59,    19,    22,   -25,   -25,   -25,   154,   154,
+     162,   162,   162,   162,   162,   162,   162,    65,    65,   -20,
+     -20,   139,    24,   -25,   -25,    42,   -25,   -25,    33,    23,
+      46,   -20,   -25,    25,   -25
 };
 
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -516,25 +530,26 @@ static const yytype_int16 yypact[] =
      means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       4,     0,     2,     1,    12,    13,     0,     0,     5,     0,
-       0,     3,     0,     0,     8,     0,    13,    14,    10,     0,
+       4,     0,     2,     1,    14,    15,     0,     0,     0,     0,
+       5,     0,     0,     3,     0,     8,     0,     0,     0,     0,
+      15,    16,    12,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     6,     0,     0,     9,
-      11,    30,    26,    22,    23,    25,    24,    20,    19,    15,
-      16,    17,    18,    27,    28,     0,    21,     7,    31,     0,
-      29
+       6,     0,     0,     0,     0,    11,    13,    32,    29,    30,
+      28,    24,    25,    27,    26,    22,    21,    17,    18,    19,
+      20,     0,    23,     7,    35,     0,     9,    10,     0,     0,
+       0,    31,    34,     0,    33
 };
 
   /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -15,   -15,   -15,    -8,   -15,    -7
+     -25,   -25,   -25,   -10,   -25,    -9
 };
 
   /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
-      -1,     1,     2,    11,    19,    12
+      -1,     1,     2,    13,    23,    14
 };
 
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
@@ -542,79 +557,80 @@ static const yytype_int8 yydefgoto[] =
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_uint8 yytable[] =
 {
-      17,    18,     3,    20,    32,    33,    37,    34,    38,    35,
-      34,    40,    35,    15,    42,    43,    44,    45,    46,    47,
-      48,    49,    50,    51,    52,    53,    54,    55,    56,    35,
-      13,     0,     4,     5,     6,    14,     4,     5,     6,     4,
-      16,     6,     0,     7,     0,     0,     0,     7,     0,     0,
-       7,     0,    60,     8,     9,    39,    10,     8,     9,     0,
-      10,     0,     0,    10,    21,    22,    23,    24,    25,    26,
-      27,    28,    29,    30,    31,    32,    33,     0,    34,     0,
-      35,     0,     0,     0,     0,     0,    41,    21,    22,    23,
-      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
-       0,    34,     0,    35,     0,     0,     0,     0,     0,    58,
-      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-      31,    32,    33,     0,    34,     0,    35,     0,    36,    21,
-      22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
-      32,    33,     0,    34,     0,    35,     0,    57,    21,    22,
-      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
-      33,     0,    34,    59,    35,    28,    29,    30,    31,    32,
-      33,     0,    34,     0,    35,    30,    31,    32,    33,     0,
-      34,     0,    35
+      21,    22,    38,    24,    39,     3,    17,    41,    42,    15,
+      16,    18,    19,    46,    43,    44,    48,    49,    50,    51,
+      52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
+      62,     4,     5,     6,     7,     8,     4,    20,     6,     4,
+       5,     6,     7,     8,    66,    69,     9,    67,    39,    73,
+      72,     9,    74,    10,     9,     0,    11,    45,    12,    71,
+      70,    10,     0,    12,    11,     0,    12,    25,    26,    27,
+      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
+       0,    38,     0,    39,    36,    37,    64,    38,     0,    39,
+      65,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,    37,     0,    38,     0,    39,     0,     0,
+      47,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,    37,     0,    38,     0,    39,    40,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      36,    37,     0,    38,     0,    39,    63,    25,    26,    27,
+      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
+       0,    38,    68,    39,    27,    28,    29,    30,    31,    32,
+      33,    34,    35,    36,    37,     0,    38,     0,    39,    34,
+      35,    36,    37,     0,    38,     0,    39
 };
 
 static const yytype_int8 yycheck[] =
 {
-       7,     9,     0,    10,    17,    18,    13,    20,    15,    22,
-      20,    19,    22,    27,    21,    22,    23,    24,    25,    26,
-      27,    28,    29,    30,    31,    32,    33,    34,    35,    22,
-      19,    -1,     3,     4,     5,    24,     3,     4,     5,     3,
-       4,     5,    -1,    14,    -1,    -1,    -1,    14,    -1,    -1,
-      14,    -1,    59,    24,    25,    26,    27,    24,    25,    -1,
-      27,    -1,    -1,    27,     6,     7,     8,     9,    10,    11,
-      12,    13,    14,    15,    16,    17,    18,    -1,    20,    -1,
-      22,    -1,    -1,    -1,    -1,    -1,    28,     6,     7,     8,
+       9,    11,    22,    12,    24,     0,    30,    16,    17,    25,
+      26,     4,     4,    23,    27,    27,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
+      39,     3,     4,     5,     6,     7,     3,     4,     5,     3,
+       4,     5,     6,     7,    25,     3,    18,    25,    24,     3,
+      27,    18,    27,    25,    18,    -1,    28,    29,    30,    68,
+      18,    25,    -1,    30,    28,    -1,    30,     8,     9,    10,
+      11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
+      -1,    22,    -1,    24,    19,    20,    27,    22,    -1,    24,
+      31,     8,     9,    10,    11,    12,    13,    14,    15,    16,
+      17,    18,    19,    20,    -1,    22,    -1,    24,    -1,    -1,
+      27,     8,     9,    10,    11,    12,    13,    14,    15,    16,
+      17,    18,    19,    20,    -1,    22,    -1,    24,    25,     8,
        9,    10,    11,    12,    13,    14,    15,    16,    17,    18,
-      -1,    20,    -1,    22,    -1,    -1,    -1,    -1,    -1,    28,
-       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
-      16,    17,    18,    -1,    20,    -1,    22,    -1,    24,     6,
-       7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
-      17,    18,    -1,    20,    -1,    22,    -1,    24,     6,     7,
-       8,     9,    10,    11,    12,    13,    14,    15,    16,    17,
-      18,    -1,    20,    21,    22,    13,    14,    15,    16,    17,
-      18,    -1,    20,    -1,    22,    15,    16,    17,    18,    -1,
-      20,    -1,    22
+      19,    20,    -1,    22,    -1,    24,    25,     8,     9,    10,
+      11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
+      -1,    22,    23,    24,    10,    11,    12,    13,    14,    15,
+      16,    17,    18,    19,    20,    -1,    22,    -1,    24,    17,
+      18,    19,    20,    -1,    22,    -1,    24
 };
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
      symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    30,    31,     0,     3,     4,     5,    14,    24,    25,
-      27,    32,    34,    19,    24,    27,     4,    34,    32,    33,
-      34,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      15,    16,    17,    18,    20,    22,    24,    34,    34,    26,
-      32,    28,    34,    34,    34,    34,    34,    34,    34,    34,
-      34,    34,    34,    34,    34,    34,    34,    24,    28,    21,
-      34
+       0,    33,    34,     0,     3,     4,     5,     6,     7,    18,
+      25,    28,    30,    35,    37,    25,    26,    30,     4,     4,
+       4,    37,    35,    36,    37,     8,     9,    10,    11,    12,
+      13,    14,    15,    16,    17,    18,    19,    20,    22,    24,
+      25,    37,    37,    27,    27,    29,    35,    27,    37,    37,
+      37,    37,    37,    37,    37,    37,    37,    37,    37,    37,
+      37,    37,    37,    25,    27,    31,    25,    25,    23,     3,
+      18,    37,    27,     3,    27
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    29,    30,    31,    31,    32,    32,    32,    32,    32,
-      33,    33,    34,    34,    34,    34,    34,    34,    34,    34,
-      34,    34,    34,    34,    34,    34,    34,    34,    34,    34,
-      34,    34
+       0,    32,    33,    34,    34,    35,    35,    35,    35,    35,
+      35,    35,    36,    36,    37,    37,    37,    37,    37,    37,
+      37,    37,    37,    37,    37,    37,    37,    37,    37,    37,
+      37,    37,    37,    37,    37,    37
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     1,     2,     0,     1,     2,     4,     2,     3,
-       1,     2,     1,     1,     2,     3,     3,     3,     3,     3,
-       3,     3,     3,     3,     3,     3,     3,     3,     3,     5,
-       3,     4
+       0,     2,     1,     2,     0,     1,     2,     4,     2,     4,
+       4,     3,     1,     2,     1,     1,     2,     3,     3,     3,
+       3,     3,     3,     3,     3,     3,     3,     3,     3,     3,
+       3,     5,     3,     7,     6,     4
 };
 
 
@@ -690,7 +706,7 @@ do {                                                                      \
 `----------------------------------------*/
 
 static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, parse_parm_t *parse_arg, void *scanner)
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, parse_param_t *parse_arg, void *scanner)
 {
   FILE *yyo = yyoutput;
   YYUSE (yyo);
@@ -711,7 +727,7 @@ yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvalue
 `--------------------------------*/
 
 static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, parse_parm_t *parse_arg, void *scanner)
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, parse_param_t *parse_arg, void *scanner)
 {
   YYFPRINTF (yyoutput, "%s %s (",
              yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
@@ -749,7 +765,7 @@ do {                                                            \
 `------------------------------------------------*/
 
 static void
-yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, parse_parm_t *parse_arg, void *scanner)
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, parse_param_t *parse_arg, void *scanner)
 {
   unsigned long int yylno = yyrline[yyrule];
   int yynrhs = yyr2[yyrule];
@@ -1029,7 +1045,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
 `-----------------------------------------------*/
 
 static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, parse_parm_t *parse_arg, void *scanner)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, parse_param_t *parse_arg, void *scanner)
 {
   YYUSE (yyvaluep);
   YYUSE (parse_arg);
@@ -1051,7 +1067,7 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, parse_parm_t *pars
 `----------*/
 
 int
-yyparse (parse_parm_t *parse_arg, void *scanner)
+yyparse (parse_param_t *parse_arg, void *scanner)
 {
 /* The lookahead symbol.  */
 int yychar;
@@ -1299,181 +1315,205 @@ yyreduce:
   switch (yyn)
     {
         case 2:
-#line 53 "expr_yacc.y" /* yacc.c:1646  */
-    { return(0); }
-#line 1305 "expr_yacc.c" /* yacc.c:1646  */
+#line 58 "expr_yacc.y" /* yacc.c:1646  */
+    { return 0; }
+#line 1321 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 3:
-#line 57 "expr_yacc.y" /* yacc.c:1646  */
-    { expr_run((yyvsp[0].nPtr), (parse_parm_t *) parse_arg); freeNode((yyvsp[0].nPtr)); }
-#line 1311 "expr_yacc.c" /* yacc.c:1646  */
+#line 62 "expr_yacc.y" /* yacc.c:1646  */
+    { expr_run((yyvsp[0].nPtr), (parse_param_t *) parse_arg); freeNode((yyvsp[0].nPtr)); }
+#line 1327 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 5:
-#line 62 "expr_yacc.y" /* yacc.c:1646  */
+#line 67 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(';', 2, NULL, NULL); }
-#line 1317 "expr_yacc.c" /* yacc.c:1646  */
+#line 1333 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 6:
-#line 63 "expr_yacc.y" /* yacc.c:1646  */
+#line 68 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = (yyvsp[-1].nPtr); }
-#line 1323 "expr_yacc.c" /* yacc.c:1646  */
+#line 1339 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 7:
-#line 64 "expr_yacc.y" /* yacc.c:1646  */
+#line 69 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr('=', 2, expr_var((yyvsp[-3].varnm)), (yyvsp[-1].nPtr)); }
-#line 1329 "expr_yacc.c" /* yacc.c:1646  */
+#line 1345 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 8:
-#line 65 "expr_yacc.y" /* yacc.c:1646  */
+#line 70 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr('=', 2, expr_var((yyvsp[-1].varnm)), expr_var((yyvsp[-1].varnm))); }
-#line 1335 "expr_yacc.c" /* yacc.c:1646  */
+#line 1351 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 9:
-#line 66 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = (yyvsp[-1].nPtr); }
-#line 1341 "expr_yacc.c" /* yacc.c:1646  */
+#line 71 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_com("remove", (yyvsp[-2].varnm)); }
+#line 1357 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 10:
-#line 70 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = (yyvsp[0].nPtr); }
-#line 1347 "expr_yacc.c" /* yacc.c:1646  */
+#line 72 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_com("print", (yyvsp[-2].varnm)); }
+#line 1363 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 11:
-#line 71 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr(';', 2, (yyvsp[-1].nPtr), (yyvsp[0].nPtr)); }
-#line 1353 "expr_yacc.c" /* yacc.c:1646  */
+#line 73 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = (yyvsp[-1].nPtr); }
+#line 1369 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 12:
-#line 75 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_con((yyvsp[0].cvalue)); }
-#line 1359 "expr_yacc.c" /* yacc.c:1646  */
+#line 77 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = (yyvsp[0].nPtr); }
+#line 1375 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 13:
-#line 76 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_var((yyvsp[0].varnm)); }
-#line 1365 "expr_yacc.c" /* yacc.c:1646  */
+#line 78 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr(';', 2, (yyvsp[-1].nPtr), (yyvsp[0].nPtr)); }
+#line 1381 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 14:
-#line 77 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr(UMINUS, 1, (yyvsp[0].nPtr)); }
-#line 1371 "expr_yacc.c" /* yacc.c:1646  */
+#line 82 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_con((yyvsp[0].cvalue)); }
+#line 1387 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 15:
-#line 78 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr('+', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1377 "expr_yacc.c" /* yacc.c:1646  */
+#line 83 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_var((yyvsp[0].varnm)); }
+#line 1393 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 16:
-#line 79 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr('-', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1383 "expr_yacc.c" /* yacc.c:1646  */
+#line 84 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr(UMINUS, 1, (yyvsp[0].nPtr)); }
+#line 1399 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 17:
-#line 80 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr('*', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1389 "expr_yacc.c" /* yacc.c:1646  */
+#line 85 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr('+', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1405 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 18:
-#line 81 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr('/', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1395 "expr_yacc.c" /* yacc.c:1646  */
+#line 86 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr('-', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1411 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 19:
-#line 82 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr('<', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1401 "expr_yacc.c" /* yacc.c:1646  */
+#line 87 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr('*', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1417 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 20:
-#line 83 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr('>', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1407 "expr_yacc.c" /* yacc.c:1646  */
+#line 88 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr('/', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1423 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 21:
-#line 84 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr('^', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1413 "expr_yacc.c" /* yacc.c:1646  */
+#line 89 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr(LT,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1429 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 22:
-#line 85 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr(GE,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1419 "expr_yacc.c" /* yacc.c:1646  */
+#line 90 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr(GT,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1435 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 23:
-#line 86 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr(LE,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1425 "expr_yacc.c" /* yacc.c:1646  */
+#line 91 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr('^', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1441 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 24:
-#line 87 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr(NE,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1431 "expr_yacc.c" /* yacc.c:1646  */
+#line 92 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr(GE,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1447 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 25:
-#line 88 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr(EQ,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1437 "expr_yacc.c" /* yacc.c:1646  */
+#line 93 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr(LE,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1453 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 26:
-#line 89 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr(LEG, 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1443 "expr_yacc.c" /* yacc.c:1646  */
+#line 94 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr(NE,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1459 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 27:
-#line 90 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr(AND, 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1449 "expr_yacc.c" /* yacc.c:1646  */
+#line 95 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr(EQ,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1465 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 28:
-#line 91 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr(OR,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1455 "expr_yacc.c" /* yacc.c:1646  */
+#line 96 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr(LEG, 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1471 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 29:
-#line 92 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_opr('?', 3, (yyvsp[-4].nPtr), (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1461 "expr_yacc.c" /* yacc.c:1646  */
+#line 97 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr(AND, 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1477 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 30:
-#line 93 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = (yyvsp[-1].nPtr); }
-#line 1467 "expr_yacc.c" /* yacc.c:1646  */
+#line 98 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr(OR,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1483 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
   case 31:
-#line 94 "expr_yacc.y" /* yacc.c:1646  */
+#line 99 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_opr('?', 3, (yyvsp[-4].nPtr), (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
+#line 1489 "expr_yacc.c" /* yacc.c:1646  */
+    break;
+
+  case 32:
+#line 100 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = (yyvsp[-1].nPtr); }
+#line 1495 "expr_yacc.c" /* yacc.c:1646  */
+    break;
+
+  case 33:
+#line 101 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_fun1c((yyvsp[-6].fname), (yyvsp[-4].nPtr), - (yyvsp[-1].cvalue)); }
+#line 1501 "expr_yacc.c" /* yacc.c:1646  */
+    break;
+
+  case 34:
+#line 102 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_fun1c((yyvsp[-5].fname), (yyvsp[-3].nPtr), (yyvsp[-1].cvalue)); }
+#line 1507 "expr_yacc.c" /* yacc.c:1646  */
+    break;
+
+  case 35:
+#line 103 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_fun((yyvsp[-3].fname), (yyvsp[-1].nPtr)); }
-#line 1473 "expr_yacc.c" /* yacc.c:1646  */
+#line 1513 "expr_yacc.c" /* yacc.c:1646  */
     break;
 
 
-#line 1477 "expr_yacc.c" /* yacc.c:1646  */
+#line 1517 "expr_yacc.c" /* yacc.c:1646  */
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -1701,7 +1741,7 @@ yyreturn:
 #endif
   return yyresult;
 }
-#line 97 "expr_yacc.y" /* yacc.c:1906  */
+#line 106 "expr_yacc.y" /* yacc.c:1906  */
 
 
 #define SIZEOF_NODETYPE ((char *)&p->u.con - (char *)p)
@@ -1709,11 +1749,9 @@ yyreturn:
 nodeType *expr_con(double value)
 {
   nodeType *p = NULL;
-  size_t nodeSize;
-
   /* allocate node */
-  nodeSize = SIZEOF_NODETYPE + sizeof(conNodeType);
-  if ((p = (nodeType*) malloc(nodeSize)) == NULL)
+  size_t nodeSize = SIZEOF_NODETYPE + sizeof(conNodeType);
+  if ( (p = (nodeType*) Calloc(1, nodeSize)) == NULL )
     yyerror(NULL, NULL, "Out of memory");
 
   /* copy information */
@@ -1726,16 +1764,14 @@ nodeType *expr_con(double value)
 nodeType *expr_var(char *nm)
 {
   nodeType *p = NULL;
-  size_t nodeSize;
-
   /* allocate node */
-  nodeSize = SIZEOF_NODETYPE + sizeof(varNodeType);
-  if ((p = (nodeType*) malloc(nodeSize)) == NULL)
+  size_t nodeSize = SIZEOF_NODETYPE + sizeof(varNodeType);
+  if ( (p = (nodeType*) Calloc(1, nodeSize)) == NULL )
     yyerror(NULL, NULL, "Out of memory");
 
   /* copy information */
   p->type = typeVar;
-  p->u.var.nm = strdupx(nm);
+  p->u.var.nm = strdup(nm);
 
   return p;
 }
@@ -1743,39 +1779,67 @@ nodeType *expr_var(char *nm)
 nodeType *expr_fun(char *fname, nodeType *op)
 {
   nodeType *p = NULL;
-  size_t nodeSize;
-
   /* allocate node */
-  nodeSize = SIZEOF_NODETYPE + sizeof(funNodeType);
-  if ((p = (nodeType*) malloc(nodeSize)) == NULL)
+  size_t nodeSize = SIZEOF_NODETYPE + sizeof(funNodeType);
+  if ( (p = (nodeType*) Calloc(1, nodeSize)) == NULL )
     yyerror(NULL, NULL, "Out of memory");
 
   /* copy information */
   p->type = typeFun;
-  p->u.fun.name = strdupx(fname);
+  p->u.fun.name = strdup(fname);
   p->u.fun.op   = op;
 
   return p;
 }
 
-nodeType *expr_opr(int oper, int nops, ...)
+nodeType *expr_fun1c(char *fname, nodeType *op, double value)
 {
-  va_list ap;
   nodeType *p = NULL;
-  size_t nodeSize;
-  int i;
+  /* allocate node */
+  size_t nodeSize = SIZEOF_NODETYPE + sizeof(fun1cNodeType);
+  if ( (p = (nodeType*) Calloc(1, nodeSize)) == NULL )
+    yyerror(NULL, NULL, "Out of memory");
 
+  /* copy information */
+  p->type = typeFun1c;
+  p->u.fun1c.name  = strdup(fname);
+  p->u.fun1c.op    = op;
+  p->u.fun1c.value = value;
+
+  return p;
+}
+
+nodeType *expr_com(const char *cname, char *vname)
+{
+  nodeType *p = NULL;
   /* allocate node */
-  nodeSize = SIZEOF_NODETYPE + sizeof(oprNodeType) + (nops - 1)*sizeof(nodeType*);
-  if ((p = (nodeType*) malloc(nodeSize)) == NULL)
+  size_t nodeSize = SIZEOF_NODETYPE + sizeof(comNodeType);
+  if ( (p = (nodeType*) Calloc(1, nodeSize)) == NULL )
+    yyerror(NULL, NULL, "Out of memory");
+
+  /* copy information */
+  p->type = typeCom;
+  p->u.com.cname = strdup(cname);
+  p->u.com.vname = strdup(vname);
+
+  return p;
+}
+
+nodeType *expr_opr(int oper, int nops, ...)
+{
+  nodeType *p = NULL;
+  /* allocate node */
+  size_t nodeSize = SIZEOF_NODETYPE + sizeof(oprNodeType) + (nops - 1)*sizeof(nodeType*);
+  if ( (p = (nodeType*) Calloc(1, nodeSize)) == NULL )
     yyerror(NULL, NULL, "Out of memory");
 
   /* copy information */
   p->type = typeOpr;
   p->u.opr.oper = oper;
   p->u.opr.nops = nops;
+  va_list ap;
   va_start(ap, nops);
-  for (i = 0; i < nops; i++)
+  for ( int i = 0; i < nops; i++ )
     p->u.opr.op[i] = va_arg(ap, nodeType*);
   va_end(ap);
 
@@ -1784,22 +1848,23 @@ nodeType *expr_opr(int oper, int nops, ...)
 
 void freeNode(nodeType *p)
 {
-  int i;
-
-  if ( ! p ) return;
+  if ( !p ) return;
 
-  if (p->type == typeOpr)
+  if ( p->type == typeOpr )
     {
-      for (i = 0; i < p->u.opr.nops; i++)
+      for ( int i = 0; i < p->u.opr.nops; i++ )
 	freeNode(p->u.opr.op[i]);
     }
   
-  free (p);
+  Free(p);
 }
 
+int CDO_parser_errorno = 0;
+
 void yyerror(void *parse_arg, void *scanner, const char *errstr)
 {
-  fprintf(stdout, "%s!\n", errstr);
+  fprintf(stderr, "%s!\n", errstr);
+  CDO_parser_errorno = -1;
 }
 /*
 int main(void)
@@ -1809,7 +1874,7 @@ int main(void)
   void *scanner;
   int yy_scan_string(const char *str, void *scanner);
 
-  parse_parm_t parse_arg;
+  parse_param_t parse_arg;
 
   printf("%s\n", fexpr);
 
diff --git a/src/expr_yacc.h b/src/expr_yacc.h
index 5705f8a..0b18e1b 100644
--- a/src/expr_yacc.h
+++ b/src/expr_yacc.h
@@ -48,33 +48,41 @@ extern int yydebug;
     CONSTANT = 258,
     VARIABLE = 259,
     FUNCTION = 260,
-    LEG = 261,
-    GE = 262,
-    LE = 263,
-    EQ = 264,
-    NE = 265,
-    AND = 266,
-    OR = 267,
-    UMINUS = 268
+    REMOVE = 261,
+    PRINT = 262,
+    AND = 263,
+    OR = 264,
+    LEG = 265,
+    GE = 266,
+    LE = 267,
+    EQ = 268,
+    NE = 269,
+    GT = 270,
+    LT = 271,
+    UMINUS = 272
   };
 #endif
 /* Tokens.  */
 #define CONSTANT 258
 #define VARIABLE 259
 #define FUNCTION 260
-#define LEG 261
-#define GE 262
-#define LE 263
-#define EQ 264
-#define NE 265
-#define AND 266
-#define OR 267
-#define UMINUS 268
+#define REMOVE 261
+#define PRINT 262
+#define AND 263
+#define OR 264
+#define LEG 265
+#define GE 266
+#define LE 267
+#define EQ 268
+#define NE 269
+#define GT 270
+#define LT 271
+#define UMINUS 272
 
 /* Value type.  */
 
 
 
-int yyparse (parse_parm_t *parse_arg, void *scanner);
+int yyparse (parse_param_t *parse_arg, void *scanner);
 
 #endif /* !YY_YY_EXPR_YACC_H_INCLUDED  */
diff --git a/src/features.c b/src/features.c
index 4b91b56..120a601 100644
--- a/src/features.c
+++ b/src/features.c
@@ -90,6 +90,9 @@ void printFeatures(void)
 #if defined(HAVE_LIBFFTW3)
   fprintf(stderr, " FFTW3");
 #endif
+#if defined(HAVE_LIBCMOR)
+  fprintf(stderr, " CMOR");
+#endif
 #if defined(__AVX2__)
   fprintf(stderr, " AVX2");
 #elif defined(__AVX__)
diff --git a/src/field.c b/src/field.c
index 9a81cae..74eaa3f 100644
--- a/src/field.c
+++ b/src/field.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -23,59 +23,28 @@
 
 double crps_det_integrate(double *a, const double d, const size_t n);
 
-double _FADD_(const double x, const double y, const double missval1, const double missval2)
-{
-  return FADD(x,y);
-}
-
-double _FSUB_(const double x, const double y, const double missval1, const double missval2)
-{
-  return FSUB(x, y);
-}
-
-double _FMUL_(const double x, const double y, const double missval1, const double missval2)
-{
-  return FMUL(x, y);
-}
-
-double _FDIV_(const double x, const double y, const double missval1, const double missval2)
-{
-  return FDIV(x, y);
-}
-
-double _FPOW_(const double x, const double y, const double missval1, const double missval2)
-{
-  return FPOW(x, y);
-}
-
-double _FSQRT_(const double x, const double missval1)
-{
-  return FSQRT(x);
-}
-
-
-double fldfun(field_t field, const int function)
+double fldfun(field_t field, int function)
 {
   double rval = 0;
 
-  // Why is this not a switch-case statement?
-  if      ( function == func_min  )  rval = fldmin(field);
-  else if ( function == func_max  )  rval = fldmax(field);
-  else if ( function == func_sum  )  rval = fldsum(field);
-  else if ( function == func_mean )  rval = fldmean(field);
-  else if ( function == func_avg  )  rval = fldavg(field);
-  else if ( function == func_std  )  rval = fldstd(field);
-  else if ( function == func_std1 )  rval = fldstd1(field);
-  else if ( function == func_var  )  rval = fldvar(field);
-  else if ( function == func_var1 )  rval = fldvar1(field);
+  switch (function)
+    {
+    case func_min:    rval = fldmin(field);  break;
+    case func_max:    rval = fldmax(field);  break;
+    case func_sum:    rval = fldsum(field);  break;
+    case func_mean:   rval = fldmean(field); break;
+    case func_avg:    rval = fldavg(field);  break;
+    case func_std:    rval = fldstd(field);  break;
+    case func_std1:   rval = fldstd1(field); break;
+    case func_var:    rval = fldvar(field);  break;
+    case func_var1:   rval = fldvar1(field); break;
+    case func_crps:   rval = fldcrps(field); break;
+    case func_brs:    rval = fldbrs(field);  break;
+    case func_rank:   rval = fldrank(field); break;
+    case func_roc:    rval = fldroc(field);  break;
+    default: cdoAbort("%s: function %d not implemented!", __func__, function);
+    }
   
-  else if ( function == func_crps )  rval = fldcrps(field);
-  else if ( function == func_brs )   rval = fldbrs(field);
-
-  else if ( function == func_rank )  rval = fldrank(field);
-  else if ( function == func_roc )   rval = fldroc(field);
-  else cdoAbort("%s: function %d not implemented!", __func__, function);
-
   return rval;
 }
 
@@ -91,7 +60,7 @@ double fldrank(field_t field)
   const size_t len       = field.size-1;
   size_t j;
   
-  if ( nmiss )  return(missval);
+  if ( nmiss ) return missval;
 
   sort_iter_single(len,array, 1);
 
@@ -136,8 +105,8 @@ double fldcrps(field_t field)
 
 double fldbrs(field_t field) 
 {
-  const size_t    len   = field.size;
   const int     nmiss   = field.nmiss;
+  const size_t    len   = field.size;
   double *array   = field.ptr;
   const double missval  = field.missval;
 
@@ -169,17 +138,17 @@ double fldbrs(field_t field)
 
 double fldmin(field_t field)
 {
-  size_t   i;
+  const int nmiss      = field.nmiss > 0;
   const size_t len     = field.size;
-  const int    nmiss   = field.nmiss;
   const double missval = field.missval;
-  const double *restrict array  = field.ptr;
-  double rmin = 0;
+  const double *restrict array = field.ptr;
+  double rmin = DBL_MAX;
 
-  if ( nmiss > 0 )
+  assert(array!=NULL);
+
+  if ( nmiss )
     {
-      rmin = DBL_MAX;
-      for ( i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	if ( !DBL_IS_EQUAL(array[i], missval) )
 	  if ( array[i] < rmin ) rmin = array[i];
 
@@ -188,29 +157,28 @@ double fldmin(field_t field)
     }
   else
     {
-      rmin = array[0];
       //#pragma simd reduction(min:rmin) 
-      for ( i = 1; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	if ( array[i] < rmin )  rmin = array[i];
     }
 
-  return (rmin);
+  return rmin;
 }
 
 
 double fldmax(field_t field)
 {
-  size_t   i;
+  const int nmiss      = field.nmiss > 0;
   const size_t len     = field.size;
-  const int    nmiss   = field.nmiss;
   const double missval = field.missval;
-  double *array  = field.ptr;
-  double rmax = 0;
+  const double *restrict array = field.ptr;
+  double rmax = -DBL_MAX;
+
+  assert(array!=NULL);
 
   if ( nmiss > 0 )
     {
-      rmax = -DBL_MAX;
-      for ( i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
         if ( !DBL_IS_EQUAL(array[i], missval) )
           if ( array[i] > rmax ) rmax = array[i];
       
@@ -219,28 +187,29 @@ double fldmax(field_t field)
     }
   else
     {
-      rmax = array[0];
-      for ( i = 1; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
         if ( array[i] > rmax )  rmax = array[i];
     }
 
-  return (rmax);
+  return rmax;
 }
 
 
 double fldsum(field_t field)
 {
-  size_t   i;
-  size_t   nvals   = 0;
+  const int nmiss      = field.nmiss > 0;
   const size_t len     = field.size;
-  const int    nmiss   = field.nmiss;
   const double missval = field.missval;
-  double *array  = field.ptr;
+  const double *restrict array = field.ptr;
   double rsum = 0;
 
-  if ( nmiss > 0 )
+  assert(array!=NULL);
+
+  if ( nmiss )
     {
-      for ( i = 0; i < len; i++ ) 
+      size_t nvals = 0;
+
+      for ( size_t i = 0; i < len; i++ ) 
 	if ( !DBL_IS_EQUAL(array[i], missval) )
 	  {
 	    rsum += array[i];
@@ -251,28 +220,30 @@ double fldsum(field_t field)
     }
   else
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	rsum += array[i];
     }
 
-  return (rsum);
+  return rsum;
 }
 
 
 double fldmean(field_t field)
 {
-  size_t   i;
+  const int nmiss       = field.nmiss > 0;
   const size_t len      = field.size;
-  const int    nmiss    = field.nmiss;
   const double missval1 = field.missval;
   const double missval2 = field.missval;
-  double *array   = field.ptr;
-  double *w       = field.weight;
-  double rsum = 0, rsumw = 0, ravg = 0;
+  const double *restrict array = field.ptr;
+  const double *restrict w     = field.weight;
+  double rsum = 0, rsumw = 0;
 
-  if ( nmiss > 0 )
+  assert(array!=NULL);
+  assert(w!=NULL);
+
+  if ( nmiss )
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	if ( !DBL_IS_EQUAL(array[i], missval1) && !DBL_IS_EQUAL(w[i], missval1) )
 	  {
 	    rsum  += w[i] * array[i];
@@ -281,120 +252,125 @@ double fldmean(field_t field)
     }
   else
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	{
 	  rsum  += w[i] * array[i];
 	  rsumw += w[i];
 	}
     }
 
-  ravg = DIV(rsum, rsumw);
+  double ravg = DIVMN(rsum, rsumw);
 
-  return (ravg);
+  return ravg;
 }
 
 
 double fldavg(field_t field)
 {
-  size_t   i;
+  const int nmiss       = field.nmiss > 0;
   const size_t len      = field.size;
-  const int    nmiss    = field.nmiss;
   const double missval1 = field.missval;
   const double missval2 = field.missval;
-  double *array   = field.ptr;
-  double *w       = field.weight;
-  double rsum = 0, rsumw = 0, ravg = 0;
+  const double *restrict array = field.ptr;
+  const double *restrict w     = field.weight;
+  double rsum = 0, rsumw = 0;
 
-  if ( nmiss > 0 )
+  assert(array!=NULL);
+  assert(w!=NULL);
+
+  if ( nmiss )
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	if ( !DBL_IS_EQUAL(w[i], missval1) )
 	  {
-	    rsum  = ADD(rsum, MUL(w[i], array[i]));
-	    rsumw = ADD(rsumw, w[i]);
+	    rsum  = ADDMN(rsum, MULMN(w[i], array[i]));
+	    rsumw = ADDMN(rsumw, w[i]);
 	  }
     }
   else
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	{
 	  rsum  += w[i] * array[i];
 	  rsumw += w[i];
 	}
     }
 
-  ravg = DIV(rsum, rsumw);
+  double ravg = DIVMN(rsum, rsumw);
 
-  return (ravg);
+  return ravg;
 }
 
 static
 void prevarsum(const double *restrict array, const double *restrict w, size_t len, int nmiss, 
-	       double missval, double *restrict rsum, double *restrict rsumw, double *restrict rsumq, double *restrict rsumwq)
+	       double missval, double *rsum, double *rsumw, double *rsumq, double *rsumwq)
 { 
-  size_t i;
-  *rsum = *rsumw = 0;
-  *rsumq = *rsumwq = 0;
+  assert(array!=NULL);
+  assert(w!=NULL);
 
-  if ( nmiss > 0 )
+  double xsum = 0, xsumw = 0;
+  double xsumq = 0, xsumwq = 0;
+
+  if ( nmiss )
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
         if ( !DBL_IS_EQUAL(array[i], missval) && !DBL_IS_EQUAL(w[i], missval) )
           {
-            *rsum   += w[i] * array[i];
-            *rsumq  += w[i] * array[i] * array[i];
-            *rsumw  += w[i];
-            *rsumwq += w[i] * w[i];
+            xsum   += w[i] * array[i];
+            xsumq  += w[i] * array[i] * array[i];
+            xsumw  += w[i];
+            xsumwq += w[i] * w[i];
           }
     }
   else
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
         {
-          *rsum   += w[i] * array[i];
-          *rsumq  += w[i] * array[i] * array[i];
-          *rsumw  += w[i];
-          *rsumwq += w[i] * w[i];
+          xsum   += w[i] * array[i];
+          xsumq  += w[i] * array[i] * array[i];
+          xsumw  += w[i];
+          xsumwq += w[i] * w[i];
         }
     }
+
+  *rsum   = xsum;
+  *rsumq  = xsumq;
+  *rsumw  = xsumw;
+  *rsumwq = xsumwq;
 }
 
 
 double fldvar(field_t field)
 {
+  const int    nmiss   = field.nmiss > 0;
   const size_t len     = field.size;
-  const int    nmiss   = field.nmiss;
   const double missval = field.missval;
-  double *array  = field.ptr;
-  double *w      = field.weight;
   double rsum, rsumw;
   double rsumq, rsumwq;
 
-  prevarsum(array, w, len, nmiss, missval, &rsum, &rsumw, &rsumq, &rsumwq);
+  prevarsum(field.ptr, field.weight, len, nmiss, missval, &rsum, &rsumw, &rsumq, &rsumwq);
 
   double rvar = IS_NOT_EQUAL(rsumw, 0) ? (rsumq*rsumw - rsum*rsum) / (rsumw*rsumw) : missval;
   if ( rvar < 0 && rvar > -1.e-5 ) rvar = 0;
 
-  return (rvar);
+  return rvar;
 }
 
 
 double fldvar1(field_t field)
 {
+  const int    nmiss   = field.nmiss > 0;
   const size_t len     = field.size;
-  const int    nmiss   = field.nmiss;
   const double missval = field.missval;
-  double *array  = field.ptr;
-  double *w      = field.weight;
   double rsum, rsumw;
   double rsumq, rsumwq;
 
-  prevarsum(array, w, len, nmiss, missval, &rsum, &rsumw, &rsumq, &rsumwq);
+  prevarsum(field.ptr, field.weight, len, nmiss, missval, &rsum, &rsumw, &rsumq, &rsumwq);
 
   double rvar = (rsumw*rsumw > rsumwq) ? (rsumq*rsumw - rsum*rsum) / (rsumw*rsumw - rsumwq) : missval;
   if ( rvar < 0 && rvar > -1.e-5 ) rvar = 0;
 
-  return (rvar);
+  return rvar;
 }
 
 
@@ -453,9 +429,9 @@ void fldrms(field_t field, field_t field2, field_t *field3)
       for ( i = 0; i < len; i++ ) 
 	if ( !DBL_IS_EQUAL(w[i], missval1) )
 	  {
-	    rsum  = ADD(rsum, MUL(w[i], MUL(SUB(array2[i], array1[i]),
-                                            SUB(array2[i], array1[i]))));
-	    rsumw = ADD(rsumw, w[i]);
+	    rsum  = ADDMN(rsum, MULMN(w[i], MULMN( SUBMN(array2[i], array1[i]),
+                                            SUBMN(array2[i], array1[i]))));
+	    rsumw = ADDMN(rsumw, w[i]);
 	  }
     }
     /*
@@ -469,7 +445,7 @@ void fldrms(field_t field, field_t field2, field_t *field3)
     }
     */
 
-  ravg = SQRT(DIV(rsum, rsumw));
+  ravg = SQRTMN( DIVMN(rsum, rsumw));
 
   if ( DBL_IS_EQUAL(ravg, missval1) ) rnmiss++;
 
@@ -507,9 +483,9 @@ void varrms(field_t field, field_t field2, field_t *field3)
 	for ( i = 0; i < len; i++ )
 	  /*	  if ( !DBL_IS_EQUAL(w[i], missval1) ) */
 	    {
-	      rsum  = ADD(rsum, MUL(w[i], MUL(SUB(array2[k*len+i], array1[k*len+i]),
-                                              SUB(array2[k*len+i], array1[k*len+i]))));
-	      rsumw = ADD(rsumw, w[i]);
+	      rsum  = ADDMN(rsum, MULMN(w[i], MULMN( SUBMN(array2[k*len+i], array1[k*len+i]),
+                                              SUBMN(array2[k*len+i], array1[k*len+i]))));
+	      rsumw = ADDMN(rsumw, w[i]);
 	    }
     }
     /*
@@ -523,7 +499,7 @@ void varrms(field_t field, field_t field2, field_t *field3)
     }
     */
 
-  ravg = SQRT(DIV(rsum, rsumw));
+  ravg = SQRTMN( DIVMN(rsum, rsumw));
 
   if ( DBL_IS_EQUAL(ravg, missval1) ) rnmiss++;
 
@@ -613,19 +589,19 @@ double crps_det_integrate(double *a, const double d, const size_t n)
 #if defined(_OPENMP)
 #pragma omp parallel for if ( n>10000 ) shared(a) private(i) \
   reduction(+:area) schedule(static,10000) 
-#endif                                                     /* **************************** */
-  for ( i=1; i<n; i++ ) {                                  /* INTEGRATE CURVE AREA         */
-    if ( a[i] < d )                                        /* left of heavyside            */
+#endif                                                         /* **************************** */
+  for ( i=1; i<n; i++ ) {                                      /* INTEGRATE CURVE AREA         */
+    if ( a[i] < d )                                            /* left of heavyside            */
       area += (a[i]-a[i-1])*(double)i*i/n/n;                   /*                              */
-    else if ( a[i-1] > d )                                 /* right of heavyside           */
-      area += (a[i]-a[i-1])*(1.-(double)i/n)*(1.-(double)i/n);              /*                              */
-    else if ( a[i-1] < d && a[i] > d ) {                   /* hitting jump pf heavyside    */
+    else if ( a[i-1] > d )                                     /* right of heavyside           */
+      area += (a[i]-a[i-1])*(1.-(double)i/n)*(1.-(double)i/n); /*                              */
+    else if ( a[i-1] < d && a[i] > d ) {                       /* hitting jump pf heavyside    */
       area += (d-a[i-1]) * (double)i*i/n/n;                    /* (occurs exactly once!)       */
-      area += (a[i]-d) * (1.-(double)i/n)*(1.-(double)i/n);                 /* **************************** */
+      area += (a[i]-d) * (1.-(double)i/n)*(1.-(double)i/n);    /* **************************** */
     }
   }
 
 
-  return(area);
+  return area;
 }
 
diff --git a/src/field.h b/src/field.h
index 9f6f8d8..6c07c28 100644
--- a/src/field.h
+++ b/src/field.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -18,6 +18,9 @@
 #ifndef _FIELD_H
 #define _FIELD_H
 
+#include <math.h>
+#include "compare.h"
+
 double var_to_std(double rvar, double missval);
 
 enum field_flag {
@@ -25,46 +28,70 @@ enum field_flag {
   FIELD_PTR   =  2,
   FIELD_WGT   =  4,
   FIELD_PTR2  =  8,
-  FIELD_ALL   =  FIELD_PTR | FIELD_WGT
+  FIELD_FLT   = 16,
+  FIELD_ALL   = FIELD_PTR | FIELD_WGT
 };
 
 
-#define  FADD(x,y)  (DBL_IS_EQUAL((x),missval1) || DBL_IS_EQUAL((y),missval2) ? missval1 : (x)+(y))
-#define  FSUB(x,y)  (DBL_IS_EQUAL((x),missval1) || DBL_IS_EQUAL((y),missval2) ? missval1 : (x)-(y))
-#define  FMUL(x,y)  (DBL_IS_EQUAL((x),0.)||IS_EQUAL((y),0.) ? 0 : DBL_IS_EQUAL((x),missval1) || DBL_IS_EQUAL((y),missval2) ? missval1 : (x)*(y))
-#define  FDIV(x,y)  (DBL_IS_EQUAL((x),missval1) || DBL_IS_EQUAL((y),missval2) || DBL_IS_EQUAL((y),0.) ? missval1 : (x)/(y))
-#define  FPOW(x,y)  (DBL_IS_EQUAL((x),missval1) || DBL_IS_EQUAL((y),missval2) ? missval1 : pow((x),(y)))
-#define  FSQRT(x)   (DBL_IS_EQUAL((x),missval1) || (x)<0 ? missval1 : sqrt(x))
+#define  MADDMN(x,y)  (DBL_IS_EQUAL((x),missval1) || DBL_IS_EQUAL((y),missval2) ? missval1 : (x)+(y))
+#define  MSUBMN(x,y)  (DBL_IS_EQUAL((x),missval1) || DBL_IS_EQUAL((y),missval2) ? missval1 : (x)-(y))
+#define  MMULMN(x,y)  (DBL_IS_EQUAL((x),missval1) || DBL_IS_EQUAL((y),missval2) ? missval1 : (x)*(y))
+#define  MDIVMN(x,y)  (DBL_IS_EQUAL((x),missval1) || DBL_IS_EQUAL((y),missval2) || DBL_IS_EQUAL((y),0.) ? missval1 : (x)/(y))
+#define  MPOWMN(x,y)  (DBL_IS_EQUAL((x),missval1) || DBL_IS_EQUAL((y),missval2) ? missval1 : pow((x),(y)))
+#define  MSQRTMN(x)   (DBL_IS_EQUAL((x),missval1) || (x)<0 ? missval1 : sqrt(x))
+
+
+#define  ADD(x,y)  ((x)+(y))
+#define  SUB(x,y)  ((x)-(y))
+#define  MUL(x,y)  ((x)*(y))
+#define  DIV(x,y)  (IS_EQUAL((y),0.) ? missval1 : (x)/(y))
+#define  POW(x,y)  pow((x),(y))
+#define  SQRT(x)   sqrt(x)
+
 
+#define  ADDM(x,y)  (IS_EQUAL((x),missval1) || IS_EQUAL((y),missval2) ? missval1 : (x)+(y))
+#define  SUBM(x,y)  (IS_EQUAL((x),missval1) || IS_EQUAL((y),missval2) ? missval1 : (x)-(y))
+#define  MULM(x,y)  (IS_EQUAL((x),missval1) || IS_EQUAL((y),missval2) ? missval1 : (x)*(y))
+#define  DIVM(x,y)  (IS_EQUAL((x),missval1) || IS_EQUAL((y),missval2) || IS_EQUAL((y),0.) ? missval1 : (x)/(y))
+#define  POWM(x,y)  (IS_EQUAL((x),missval1) || IS_EQUAL((y),missval2) ? missval1 : pow((x),(y)))
+#define  SQRTM(x)   (IS_EQUAL((x),missval1) || (x)<0 ? missval1 : sqrt(x))
 
-double _FADD_(const double x, const double y, const double missval1, const double missval2);
-double _FSUB_(const double x, const double y, const double missval1, const double missval2);
-double _FMUL_(const double x, const double y, const double missval1, const double missval2);
-double _FDIV_(const double x, const double y, const double missval1, const double missval2);
-double _FPOW_(const double x, const double y, const double missval1, const double missval2);
-double _FSQRT_(const double x, const double missval1);
 
+#define  ADDMN(x,y)  FADDMN(x, y, missval1, missval2)
+#define  SUBMN(x,y)  FSUBMN(x, y, missval1, missval2)
+#define  MULMN(x,y)  FMULMN(x, y, missval1, missval2)
+#define  DIVMN(x,y)  FDIVMN(x, y, missval1, missval2)
+#define  POWMN(x,y)  FPOWMN(x, y, missval1, missval2)
+#define  SQRTMN(x)   FSQRTMN(x, missval1)
 
-#define ADD(x,y)  _FADD_(x, y, missval1, missval2)
-#define SUB(x,y)  _FSUB_(x, y, missval1, missval2)
-#define MUL(x,y)  _FMUL_(x, y, missval1, missval2)
-#define DIV(x,y)  _FDIV_(x, y, missval1, missval2)
-#define POW(x,y)  _FPOW_(x, y, missval1, missval2)
-#define SQRT(x)   _FSQRT_(x, missval1)
 
+static inline
+double FADDMN(double x, double y, double missval1, double missval2) { return MADDMN(x,y);}
+static inline
+double FSUBMN(double x, double y, double missval1, double missval2) { return MSUBMN(x, y);}
+static inline
+double FMULMN(double x, double y, double missval1, double missval2) { return MMULMN(x, y);}
+static inline
+double FDIVMN(double x, double y, double missval1, double missval2) { return MDIVMN(x, y);}
+static inline
+double FPOWMN(double x, double y, double missval1, double missval2) { return MPOWMN(x, y);}
+static inline
+double FSQRTMN(double x, double missval1) { return MSQRTMN(x);}
 
 typedef struct {
   int      nwpv; // number of words per value; real:1  complex:2
+  int      memtype;
   int      grid;
   int      zaxis;
   size_t   size;
-  int      nsamp;
-  int      nmiss;
-  int      nmiss2;
+  size_t   nsamp;
+  size_t   nmiss;
+  size_t   nmiss2;
   double   missval;
   double  *weight;
   double  *ptr;
-  double  *ptr2;
+  float   *ptrf;
+  void    *ptr2;
 }
 field_t;
 
@@ -78,7 +105,7 @@ void      field_free(field_t **field, const int vlistID);
 
 /* field.c */
 
-double fldfun(field_t field, const int function);
+double fldfun(field_t field, int function);
 double fldmin(field_t field);
 double fldmax(field_t field);
 double fldsum(field_t field);
@@ -147,8 +174,9 @@ void farround(field_t *field);
 
 /* field2.c */
 
-void farfun(field_t *field1, field_t field2, const int function);
+void farfun(field_t *field1, field_t field2, int function);
 
+void farcpy(field_t *field1, field_t field2);
 void faradd(field_t *field1, field_t field2);
 void farsum(field_t *field1, field_t field2);
 void farsumw(field_t *field1, field_t field2, double w);
@@ -160,16 +188,14 @@ void farmul(field_t *field1, field_t field2);
 void fardiv(field_t *field1, field_t field2);
 void farmin(field_t *field1, field_t field2);
 void farmax(field_t *field1, field_t field2);
-void farvar(field_t *field1, field_t field2, field_t field3, const double divisor);
-void farstd(field_t *field1, field_t field2, field_t field3, const double divisor);
-void farcvar(field_t *field1, field_t field2, const double rconst1, const double divisor);
-void farcstd(field_t *field1, field_t field2, const double rconst1, const double divisor);
+void farvar(field_t *field1, field_t field2, field_t field3, int divisor);
+void farstd(field_t *field1, field_t field2, field_t field3, int divisor);
+void farcvar(field_t *field1, field_t field2, int nsets, int divisor);
+void farcstd(field_t *field1, field_t field2, int nsets, int divisor);
 void farmoq(field_t *field1, field_t field2);
 void farmoqw(field_t *field1, field_t field2, double w);
 void faratan2(field_t *field1, field_t field2);
 
-/* RQ */
 void farcount(field_t *field1, field_t field2);
-/* QR */
 
 #endif  /* _FIELD_H */
diff --git a/src/field2.c b/src/field2.c
index 40b871d..30a2458 100644
--- a/src/field2.c
+++ b/src/field2.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -15,132 +15,159 @@
   GNU General Public License for more details.
 */
 
+#include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
-#include <cdi.h>
 
-#if 0
-#ifdef __SSE2__
-#include <emmintrin.h>
-#endif
-#endif
 
-void farfun(field_t *field1, field_t field2, const int function)
+void farfun(field_t *field1, field_t field2, int function)
 {
-  if      ( function == func_add   ) faradd(field1, field2);
-  else if ( function == func_min   ) farmin(field1, field2);
-  else if ( function == func_max   ) farmax(field1, field2);
-  else if ( function == func_sum   ) farsum(field1, field2);
-  else if ( function == func_mean  ) farsum(field1, field2);
-  else if ( function == func_avg   ) faradd(field1, field2);
-  else if ( function == func_sub   ) farsub(field1, field2);
-  else if ( function == func_mul   ) farmul(field1, field2);
-  else if ( function == func_div   ) fardiv(field1, field2);
-  else if ( function == func_atan2 ) faratan2(field1, field2);
-  else cdoAbort("%s: function %d not implemented!", __func__, function);
+  switch (function)
+    {
+    case func_add:   faradd(field1, field2);   break;
+    case func_min:   farmin(field1, field2);   break;
+    case func_max:   farmax(field1, field2);   break;
+    case func_sum:   farsum(field1, field2);   break;
+    case func_mean:  farsum(field1, field2);   break;
+    case func_avg:   faradd(field1, field2);   break;
+    case func_sub:   farsub(field1, field2);   break;
+    case func_mul:   farmul(field1, field2);   break;
+    case func_div:   fardiv(field1, field2);   break;
+    case func_atan2: faratan2(field1, field2); break;
+    default: cdoAbort("%s: function %d not implemented!", __func__, function);
+    }
 }
 
 static
-void arradd(const size_t n, double * restrict a, const double * restrict b)
+int farsetnmiss(int len, double *restrict array, double missval)
 {
-  // SSE2 version is 15% faster than the original loop (tested with gcc47)
-#if 0
-  //#ifdef __SSE2__ /*__SSE2__*/ // bug in this code!!!
-  size_t i;
-  const size_t residual =  n % 8;
-  const size_t ofs = n - residual;
+  int nmiss = 0;
 
-  __m128d *av = (__m128d *) a; // assume 16-byte aligned
-  __m128d *bv = (__m128d *) b; // assume 16-byte aligned
-  for ( i = 0; i < n/2; i+=4 )
+  if ( DBL_IS_NAN(missval) )
     {
-      av[i  ] = _mm_add_pd(av[i  ], bv[i  ]);
-      av[i+1] = _mm_add_pd(av[i+1], bv[i+1]);
-      av[i+2] = _mm_add_pd(av[i+2], bv[i+2]);
-      av[i+3] = _mm_add_pd(av[i+3], bv[i+3]);
+      for ( int i = 0; i < len; i++ )
+        if ( DBL_IS_EQUAL(array[i], missval) || array[i] < 0 )
+          {
+            array[i] = missval;
+            nmiss++;
+          }
+    }
+  else
+    {
+      for ( int i = 0; i < len; i++ )
+        if ( IS_EQUAL(array[i], missval) || array[i] < 0 )
+          {
+            array[i] = missval;
+            nmiss++;
+          }
     }
-  printf("residual, ofs, n %ld %ld %ld\n", residual, ofs, n);
-  for ( i = 0; i < residual; i++ )  a[ofs+i] += b[ofs+i];
-
-#else
-
-#if defined(_OPENMP)
-#pragma omp parallel for default(none) shared(a,b)
-#endif
-  for ( size_t i = 0; i < n; i++ ) a[i] += b[i];
 
-#endif
+  return nmiss;
 }
 
-static
-void arraddw(const size_t n, double * restrict a, const double * restrict b, double w)
+
+void farcpy(field_t *field1, field_t field2)
 {
-#if defined(_OPENMP)
-#pragma omp parallel for default(none) shared(a,b,w)
-#endif
-  for ( size_t i = 0; i < n; i++ ) a[i] += w*b[i];
+  int nwpv = field1->nwpv;
+  int gridsize1 = field1->size;
+  int gridsize2 = field2.size;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1 = field1->ptr;
+  const double *restrict array2 = field2.ptr;
+  const float *restrict array2f = field2.ptrf;
+
+  if ( gridsize1 == 0 ) gridsize1 = gridInqSize(field1->grid);
+  if ( gridsize2 == 0 ) gridsize2 = gridInqSize(field2.grid);
+
+  if ( nwpv != 2 ) nwpv = 1;
+
+  int len = nwpv*gridsize1;
+
+  if ( len != nwpv*gridsize2 )
+    cdoAbort("Fields have different gridsize (%s)", __func__);
+
+  if ( field2.memtype == MEMTYPE_FLOAT )
+    for ( int i = 0; i < len; i++ ) array1[i] = array2f[i];
+  else
+    for ( int i = 0; i < len; i++ ) array1[i] = array2[i];
 }
 
 
 void faradd(field_t *field1, field_t field2)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1  = field1->ptr;
+  const double *restrict array2  = field2.ptr;
+  const float *restrict array2f = field2.ptrf;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ ) 
-	array1[i] = ADD(array1[i], array2[i]);
+      for ( int i = 0; i < len; i++ ) 
+	array1[i] = ADDMN(array1[i], array2[i]);
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      arradd(len, array1, array2);
+      if ( field2.memtype == MEMTYPE_FLOAT )
+        {
+          for ( int i = 0; i < len; i++ ) array1[i] += array2f[i];
+        }
+      else
+        {
+          //#if defined(_OPENMP)
+          //#pragma omp parallel for default(none) shared(a,b)
+          //#endif
+          for ( int i = 0; i < len; i++ ) array1[i] += array2[i];
+        }
     }
 }
 
 
 void farsum(field_t *field1, field_t field2)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  int nwpv = field1->nwpv;
+  int gridsize1 = field1->size;
+  int gridsize2 = field2.size;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1 = field1->ptr;
+  const double *restrict array2 = field2.ptr;
+  const float *restrict array2f = field2.ptrf;
+
+  if ( gridsize1 == 0 ) gridsize1 = gridInqSize(field1->grid);
+  if ( gridsize2 == 0 ) gridsize2 = gridInqSize(field2.grid);
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridsize1;
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != nwpv*gridsize2 )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  {
 	    if ( !DBL_IS_EQUAL(array1[i], missval1) )
@@ -150,39 +177,45 @@ void farsum(field_t *field1, field_t field2)
 	  }
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      arradd(len, array1, array2);
+      if ( field2.memtype == MEMTYPE_FLOAT )
+        {
+          for ( int i = 0; i < len; i++ ) array1[i] += array2f[i];
+        }
+      else
+        {
+          for ( int i = 0; i < len; i++ ) array1[i] += array2[i];
+        }
     }
 }
 
 
 void farsumw(field_t *field1, field_t field2, double w)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1  = field1->ptr;
+  const double *restrict array2  = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  {
 	    if ( !DBL_IS_EQUAL(array1[i], missval1) )
@@ -192,12 +225,15 @@ void farsumw(field_t *field1, field_t field2, double w)
 	  }
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      arraddw(len, array1, array2, w);
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) shared(array1,array2,w,len)
+#endif
+      for ( int i = 0; i < len; i++ ) array1[i] += w*array2[i];
     }
 }
 
@@ -211,15 +247,14 @@ void farsumw(field_t *field1, field_t field2, double w)
  */
 void farsumtr(field_t *occur, field_t field, const double refval)
 {
-  size_t   i, len;
   double omissval = occur->missval;
-  double  *oarray = occur->ptr;
   double fmissval = field.missval;
-  double  *farray = field.ptr;
+  double *restrict oarray = occur->ptr;
+  double *restrict farray = field.ptr;
 
-  len    = (size_t) gridInqSize(occur->grid);
+  int len = gridInqSize(occur->grid);
 
-  if ( len != (size_t) gridInqSize(field.grid) )
+  if ( len != gridInqSize(field.grid) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( occur->nmiss > 0 || field.nmiss > 0 )
@@ -227,7 +262,7 @@ void farsumtr(field_t *occur, field_t field, const double refval)
 #if defined(_OPENMP)
 #pragma omp parallel for default(shared) schedule(static)
 #endif
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(farray[i], fmissval) )
 	  {
 	    if ( !DBL_IS_EQUAL(oarray[i], omissval) )
@@ -242,7 +277,7 @@ void farsumtr(field_t *occur, field_t field, const double refval)
 	}
 
       occur->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(oarray[i], omissval) ) occur->nmiss++;
     }
   else
@@ -250,7 +285,7 @@ void farsumtr(field_t *occur, field_t field, const double refval)
 #if defined(_OPENMP)
 #pragma omp parallel for default(shared)
 #endif
-      for ( i = 0; i < len; i++ ) 
+      for ( int i = 0; i < len; i++ ) 
 	oarray[i] = (DBL_IS_EQUAL(farray[i], refval)) ? 0.0 : oarray[i] + 1.0;
     }
 }
@@ -258,27 +293,27 @@ void farsumtr(field_t *occur, field_t field, const double refval)
 
 void farsumq(field_t *field1, field_t field2)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1  = field1->ptr;
+  const double *restrict array2  = field2.ptr;
+  const float *restrict array2f = field2.ptrf;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  {
 	    if ( !DBL_IS_EQUAL(array1[i], missval1) )
@@ -288,40 +323,45 @@ void farsumq(field_t *field1, field_t field2)
 	  }
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( i = 0; i < len; i++ ) 
-	array1[i] += array2[i]*array2[i];
+      if ( field2.memtype == MEMTYPE_FLOAT )
+        {
+          for ( int i = 0; i < len; i++ ) array1[i] += ((double)array2f[i])*array2f[i];
+        }
+      else
+        {
+          for ( int i = 0; i < len; i++ ) array1[i] += array2[i]*array2[i];
+        }
     }
 }
 
 
 void farsumqw(field_t *field1, field_t field2, double w)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1  = field1->ptr;
+  const double *restrict array2  = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  {
 	    if ( !DBL_IS_EQUAL(array1[i], missval1) )
@@ -331,12 +371,12 @@ void farsumqw(field_t *field1, field_t field2, double w)
 	  }
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( int i = 0; i < len; i++ ) 
 	array1[i] += w*array2[i]*array2[i];
     }
 }
@@ -344,36 +384,35 @@ void farsumqw(field_t *field1, field_t field2, double w)
 
 void farsub(field_t *field1, field_t field2)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1  = field1->ptr;
+  const double *restrict array2  = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ ) 
-	array1[i] = SUB(array1[i], array2[i]);
+      for ( int i = 0; i < len; i++ ) 
+	array1[i] = SUBMN(array1[i], array2[i]);
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( int i = 0; i < len; i++ ) 
 	array1[i] -= array2[i];
     }
 }
@@ -381,36 +420,35 @@ void farsub(field_t *field1, field_t field2)
 
 void farmul(field_t *field1, field_t field2)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1  = field1->ptr;
+  const double *restrict array2  = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ ) 
-	array1[i] = MUL(array1[i], array2[i]);
+      for ( int i = 0; i < len; i++ ) 
+	array1[i] = MULMN(array1[i], array2[i]);
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( int i = 0; i < len; i++ ) 
 	array1[i] *= array2[i];
     }
 }
@@ -418,81 +456,78 @@ void farmul(field_t *field1, field_t field2)
 
 void fardiv(field_t *field1, field_t field2)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const double missval1 = field1->missval;
+  int nwpv  = field1->nwpv;
+  int grid1 = field1->grid;
+  int grid2 = field2.grid;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
   double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const double missval2 = field2.missval;
   double *array2  = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
-  for ( i = 0; i < len; i++ ) 
-    array1[i] = DIV(array1[i], array2[i]);
+  for ( int i = 0; i < len; i++ ) 
+    array1[i] = DIVMN(array1[i], array2[i]);
 
   field1->nmiss = 0;
-  for ( i = 0; i < len; i++ )
+  for ( int i = 0; i < len; i++ )
     if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
 }
 
 
 void faratan2(field_t *field1, field_t field2)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  int nwpv  = field1->nwpv;
+  int grid1 = field1->grid;
+  int grid2 = field2.grid;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1 = field1->ptr;
+  const double *restrict array2 = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
-  for ( i = 0; i < len; i++ ) 
+  for ( int i = 0; i < len; i++ ) 
     array1[i] = DBL_IS_EQUAL(array1[i],missval1) || DBL_IS_EQUAL(array2[i],missval2) ? missval1 : atan2(array1[i], array2[i]);
 
   field1->nmiss = 0;
-  for ( i = 0; i < len; i++ )
+  for ( int i = 0; i < len; i++ )
     if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
 }
 
 
 void farmin(field_t *field1, field_t field2)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1 = field1->ptr;
+  const double *restrict array2 = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	{
 	  array1[i] = DBL_IS_EQUAL(array2[i], missval2) ? array1[i] :
 	              DBL_IS_EQUAL(array1[i], missval1) ? array2[i] :
@@ -500,12 +535,12 @@ void farmin(field_t *field1, field_t field2)
 	}
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	array1[i] = MIN(array1[i], array2[i]);
     }
 }
@@ -513,27 +548,26 @@ void farmin(field_t *field1, field_t field2)
 
 void farmax(field_t *field1, field_t field2)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1 = field1->ptr;
+  const double *restrict array2 = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	{
 	  array1[i] = DBL_IS_EQUAL(array2[i], missval2) ? array1[i] :
 	              DBL_IS_EQUAL(array1[i], missval1) ? array2[i] :
@@ -541,362 +575,206 @@ void farmax(field_t *field1, field_t field2)
 	}
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	array1[i] = MAX(array1[i], array2[i]);
     }
 }
 
-// not used
-void farvar0(field_t *field1, field_t field2, field_t field3)
+
+void farvar(field_t *field1, field_t field2, field_t field3, int divisor)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
-  const int    nmiss3   = field3.nmiss;
-  const double missval3 = field3.missval;
-  double *array3  = field3.ptr;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1  = field1->ptr;
+  const double *restrict array2  = field2.ptr;
+  const double *restrict array3  = field3.ptr;
+  double temp;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
-  if ( nmiss1 > 0 || nmiss2 > 0 || nmiss3 > 0 )
+  if ( (nmiss1 || nmiss2) /*&& (DBL_IS_NAN(missval1) || DBL_IS_NAN(missval2))*/ )
     {
-      for ( i = 0; i < len; i++ )
-	{
-	  if ( !DBL_IS_EQUAL(array1[i], missval1) && !DBL_IS_EQUAL(array2[i], missval2) && !DBL_IS_EQUAL(array3[i], missval3) )
-	    {
-	      array1[i] = array2[i]*array3[i] - (array1[i]*array3[i])*(array1[i]*array3[i]);
-	      if ( array1[i] < 0 && array1[i] > -1.e-5 ) array1[i] = 0;
-	    }
-	  else
-	    array1[i] = missval1;
-	}
+      for ( int i = 0; i < len; i++ )
+        {
+          temp      = DIV( MULMN(array1[i], array1[i]), array3[i]);
+          array1[i] = DIV( SUBMN(array2[i], temp), array3[i]-divisor);
+          if ( array1[i] < 0 && array1[i] > -1.e-5 ) array1[i] = 0;
+        }
     }
   else
     {
-      for ( i = 0; i < len; i++ )
-	{
-	  array1[i] = array2[i]*array3[i] - (array1[i]*array3[i])*(array1[i]*array3[i]);
-	  if ( array1[i] < 0 && array1[i] > -1.e-5 ) array1[i] = 0;
-	}
+      for ( int i = 0; i < len; i++ )
+        {
+          temp      = DIV( MUL(array1[i], array1[i]), array3[i]);
+          array1[i] = DIV( SUB(array2[i], temp), array3[i]-divisor);
+          if ( array1[i] < 0 && array1[i] > -1.e-5 ) array1[i] = 0;
+        }
     }
 
-  field1->nmiss = 0;
-  for ( i = 0; i < len; i++ )
-    if ( DBL_IS_EQUAL(array1[i], missval1) || array1[i] < 0 )
-      {
-	array1[i] = missval1;
-	field1->nmiss++;
-      }
+  field1->nmiss = farsetnmiss(len, array1, missval1);
 }
 
 
-void farvar(field_t *field1, field_t field2, field_t field3, const double divisor)
+void farstd(field_t *field1, field_t field2, field_t field3, int divisor)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
-  double *array3  = field3.ptr;
-  double temp;
+  int nwpv  = field1->nwpv;
+  int grid1 = field1->grid;
+  int grid2 = field2.grid;
+  double missval1 = field1->missval;
+  double *restrict array1  = field1->ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
-    cdoAbort("Fields have different gridsize (%s)", __func__);
-
-  for ( i = 0; i < len; i++ )
-    {
-      temp      = DIV( MUL(array1[i], array1[i]), array3[i]);
-      array1[i] = DIV( SUB(array2[i], temp), array3[i]-divisor);
-      if ( array1[i] < 0 && array1[i] > -1.e-5 ) array1[i] = 0;
-    }
-
-  field1->nmiss = 0;
-  for ( i = 0; i < len; i++ )
-    if ( DBL_IS_EQUAL(array1[i], missval1) || array1[i] < 0 )
-      {
-	array1[i] = missval1;
-	field1->nmiss++;
-      }
-}
-
-// not used
-void farstd0(field_t *field1, field_t field2, field_t field3)
-{
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  int    grid2    = field2.grid;
-
-  if ( nwpv != 2 ) nwpv = 1;
-
-  len = (size_t) (nwpv*gridInqSize(grid1));
-
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
-    cdoAbort("Fields have different gridsize (%s)", __func__);
-
-  farvar0(field1, field2, field3);
-
-  field1->nmiss = 0;
-  for ( i = 0; i < len; i++ )
-    if ( DBL_IS_EQUAL(array1[i], missval1) || array1[i] < 0 )
-      {
-	array1[i] = missval1;
-	field1->nmiss++;
-      }
-    else
-      {
-	array1[i] = IS_NOT_EQUAL(array1[i], 0) ? sqrt(array1[i]) : 0;
-      }
-}
-
-
-void farstd(field_t *field1, field_t field2, field_t field3, const double divisor)
-{
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-
-  if ( nwpv != 2 ) nwpv = 1;
-
-  len = (size_t) (nwpv*gridInqSize(grid1));
-
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   farvar(field1, field2, field3, divisor);
 
-  field1->nmiss = 0;
-  for ( i = 0; i < len; i++ )
+  int nmiss = 0;
+  for ( int i = 0; i < len; i++ )
     if ( DBL_IS_EQUAL(array1[i], missval1) || array1[i] < 0 )
       {
 	array1[i] = missval1;
-	field1->nmiss++;
+	nmiss++;
       }
     else
       {
 	array1[i] = IS_NOT_EQUAL(array1[i], 0) ? sqrt(array1[i]) : 0;
       }
+  field1->nmiss = nmiss;
 }
 
-// not used
-void farcvar0(field_t *field1, field_t field2, const double rconst1)
+
+void farcvar(field_t *field1, field_t field2, int nsets, int divisor)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
-  int    nmiss3   = 0;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  const int nsetx = nsets - divisor;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1  = field1->ptr;
+  const double *restrict array2  = field2.ptr;
+  double temp;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
-  if ( DBL_IS_EQUAL(rconst1, missval1) ) nmiss3 = 1;
-
-  if ( nmiss1 > 0 || nmiss2 > 0 || nmiss3 > 0 )
+  if ( nsetx == 0 )
     {
-      for ( i = 0; i < len; i++ )
-	{
-	  if ( !DBL_IS_EQUAL(array1[i], missval1) && !DBL_IS_EQUAL(array2[i], missval2) && nmiss3 == 0 )
-	    {
-	      array1[i] = array2[i]*rconst1 - (array1[i]*rconst1)*(array1[i]*rconst1);
-	      if ( array1[i] < 0 && array1[i] > -1.e-5 ) array1[i] = 0;
-	    }
-	  else
-	    array1[i] = missval1;
-	}
+      for ( int i = 0; i < len; i++ ) array1[i] = missval1;
     }
-  else
+  else if ( (nmiss1 || nmiss2) /*&& (DBL_IS_NAN(missval1) || DBL_IS_NAN(missval2))*/ )
     {
-      for ( i = 0; i < len; i++ )
-	{
-	  array1[i] = array2[i]*rconst1 - (array1[i]*rconst1)*(array1[i]*rconst1);
-	  if ( array1[i] < 0 && array1[i] > -1.e-5 ) array1[i] = 0;
-	}
+      for ( int i = 0; i < len; i++ )
+        {
+          temp      = MULMN(array1[i], array1[i]) / nsets;
+          array1[i] = SUBMN(array2[i], temp) / nsetx;
+          if ( array1[i] < 0 && array1[i] > -1.e-5 ) array1[i] = 0;
+        }
     }
-
-  field1->nmiss = 0;
-  for ( i = 0; i < len; i++ )
-    if ( DBL_IS_EQUAL(array1[i], missval1) || array1[i] < 0 )
-      {
-	array1[i] = missval1;
-	field1->nmiss++;
-      }
-}
-
-
-void farcvar(field_t *field1, field_t field2, const double rconst1, const double divisor)
-{
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
-  double temp;
-
-  if ( nwpv != 2 ) nwpv = 1;
-
-  len = (size_t) (nwpv*gridInqSize(grid1));
-
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
-    cdoAbort("Fields have different gridsize (%s)", __func__);
-
-  for ( i = 0; i < len; i++ )
+  else
     {
-      temp      = DIV( MUL(array1[i], array1[i]), rconst1);
-      array1[i] = DIV( SUB(array2[i], temp), rconst1-divisor);
-      if ( array1[i] < 0 && array1[i] > -1.e-5 ) array1[i] = 0;
+      for ( int i = 0; i < len; i++ )
+        {
+          temp      = MUL(array1[i], array1[i]) / nsets;
+          array1[i] = SUB(array2[i], temp) / nsetx;
+          if ( array1[i] < 0 && array1[i] > -1.e-5 ) array1[i] = 0;
+        }
     }
 
-  field1->nmiss = 0;
-  for ( i = 0; i < len; i++ )
-    if ( DBL_IS_EQUAL(array1[i], missval1) || array1[i] < 0 )
-      {
-	array1[i] = missval1;
-	field1->nmiss++;
-      }
+  field1->nmiss = farsetnmiss(len, array1, missval1);
 }
 
-// not used
-void farcstd0(field_t *field1, field_t field2, const double rconst1)
-{
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-
-  if ( nwpv != 2 ) nwpv = 1;
-
-  len = (size_t) (nwpv*gridInqSize(grid1));
-
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
-    cdoAbort("Fields have different gridsize (%s)", __func__);
-
-  farcvar0(field1, field2, rconst1);
 
-  field1->nmiss = 0;
-  for ( i = 0; i < len; i++ )
-    if ( DBL_IS_EQUAL(array1[i], missval1) || array1[i] < 0 )
-      {
-	array1[i] = missval1;
-	field1->nmiss++;
-      }
-    else
-      {
-	array1[i] = IS_NOT_EQUAL(array1[i], 0) ? sqrt(array1[i]) : 0;
-      }
-}
-
-
-void farcstd(field_t *field1, field_t field2, const double rconst1, const double divisor)
+void farcstd(field_t *field1, field_t field2, int nsets, int divisor)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
+  int nwpv  = field1->nwpv;
+  int grid1 = field1->grid;
+  int grid2 = field2.grid;
+  double missval1 = field1->missval;
+  double *restrict array1 = field1->ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
-  farcvar(field1, field2, rconst1, divisor);
+  farcvar(field1, field2, nsets, divisor);
 
-  field1->nmiss = 0;
-  for ( i = 0; i < len; i++ )
+  int nmiss = 0;
+  for ( int i = 0; i < len; i++ )
     if ( DBL_IS_EQUAL(array1[i], missval1) || array1[i] < 0 )
       {
 	array1[i] = missval1;
-	field1->nmiss++;
+	nmiss++;
       }
     else
       {
 	array1[i] = IS_NOT_EQUAL(array1[i], 0) ? sqrt(array1[i]) : 0;
       }
+  field1->nmiss = nmiss;
 }
 
 
 void farmoq(field_t *field1, field_t field2)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
   double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  double *restrict array1 = field1->ptr;
+  const double *restrict array2 = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  array1[i] = array2[i]*array2[i];
 	else
 	  array1[i] = missval1;
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( int i = 0; i < len; i++ ) 
 	array1[i] = array2[i]*array2[i];
     }
 }
@@ -904,44 +782,41 @@ void farmoq(field_t *field1, field_t field2)
 
 void farmoqw(field_t *field1, field_t field2, double w)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
   double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  double *restrict array1 = field1->ptr;
+  const double *restrict array2 = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  array1[i] = w*array2[i]*array2[i];
 	else
 	  array1[i] = missval1;
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( int i = 0; i < len; i++ ) 
 	array1[i] = w*array2[i]*array2[i];
     }
 }
 
-
-/* RQ */
 /**
  * Counts the number of nonmissing values. The result of the operation
  * is computed according to the following rules:
@@ -957,27 +832,26 @@ void farmoqw(field_t *field1, field_t field2, double w)
  */  
 void farcount(field_t *field1, field_t field2)
 {
-  size_t   i, len;
-  int          nwpv     = field1->nwpv;
-  const int    grid1    = field1->grid;
-  const int    nmiss1   = field1->nmiss;
-  const double missval1 = field1->missval;
-  double *array1  = field1->ptr;
-  const int    grid2    = field2.grid;
-  const int    nmiss2   = field2.nmiss;
-  const double missval2 = field2.missval;
-  double *array2  = field2.ptr;
+  int nwpv   = field1->nwpv;
+  int grid1  = field1->grid;
+  int grid2  = field2.grid;
+  int nmiss1 = field1->nmiss;
+  int nmiss2 = field2.nmiss;
+  double missval1 = field1->missval;
+  double missval2 = field2.missval;
+  double *restrict array1 = field1->ptr;
+  const double *restrict array2 = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  len = (size_t) (nwpv*gridInqSize(grid1));
+  int len = nwpv*gridInqSize(grid1);
 
-  if ( len != (size_t) (nwpv*gridInqSize(grid2)) )
+  if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  {
 	    if ( !DBL_IS_EQUAL(array1[i], missval1) )
@@ -987,13 +861,12 @@ void farcount(field_t *field1, field_t field2)
 	  }
 
       field1->nmiss = 0;
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( i = 0; i < len; i++ ) 
+      for ( int i = 0; i < len; i++ ) 
 	array1[i] += 1.0;
     }
 }
-/* QR */
diff --git a/src/fieldc.c b/src/fieldc.c
index 5ff2f8d..d6846c0 100644
--- a/src/fieldc.c
+++ b/src/fieldc.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -47,7 +47,7 @@ void farcmul(field_t *field, double rconst)
   if ( nmiss > 0 )
     {
       for ( i = 0; i < len; i++ ) 
-	array[i] = MUL(array[i], rconst);
+	array[i] = MULMN(array[i], rconst);
     }
   else
     {
@@ -76,7 +76,7 @@ void farcdiv(field_t *field, double rconst)
   if ( nmiss > 0 || IS_EQUAL(rconst, 0) )
     {
       for ( i = 0; i < len; i++ )
-	array[i] = DIV(array[i], rconst);
+	array[i] = DIVMN(array[i], rconst);
 
       if ( IS_EQUAL(rconst, 0) ) field->nmiss = len;
     }
@@ -102,7 +102,7 @@ void farcadd(field_t *field, double rconst)
   if ( nmiss > 0 )
     {
       for ( i = 0; i < len; i++ ) 
-	array[i] = ADD(array[i], rconst);
+	array[i] = ADDMN(array[i], rconst);
     }
   else
     {
@@ -129,7 +129,7 @@ void farinv(field_t *field)
   len    = gridInqSize(grid);
 
   for ( i = 0; i < len; i++ ) 
-    array[i] = DIV(1.0, array[i]);
+    array[i] = DIVMN(1.0, array[i]);
 
   field->nmiss = 0;
   for ( i = 0; i < len; i++ )
diff --git a/src/fieldmem.c b/src/fieldmem.c
index 128ee3f..7b65956 100644
--- a/src/fieldmem.c
+++ b/src/fieldmem.c
@@ -3,6 +3,7 @@
 
 #include <cdi.h>
 #include <cdo.h>
+#include <cdo_int.h>
 #include "dmemory.h"
 #include "field.h"
 #include "util.h"
@@ -37,9 +38,11 @@ field_t **field_allocate(int vlistID, int ptype, int init)
 
 	  field[varID][levelID].nwpv    = nwpv;
 	  field[varID][levelID].grid    = gridID;
+	  field[varID][levelID].size    = gridsize;
 	  field[varID][levelID].nsamp   = 0;
 	  field[varID][levelID].nmiss   = 0;
 	  field[varID][levelID].nmiss2  = 0;
+	  if ( ptype & FIELD_FLT ) field[varID][levelID].memtype = MEMTYPE_FLOAT;
 	  field[varID][levelID].missval = missval;
 	  field[varID][levelID].ptr     = NULL;
 	  field[varID][levelID].ptr2    = NULL;
@@ -47,15 +50,31 @@ field_t **field_allocate(int vlistID, int ptype, int init)
 
 	  if ( ptype & FIELD_PTR )
 	    {
-	      field[varID][levelID].ptr = (double*) Malloc(nwpv*gridsize*sizeof(double));
-	      if ( init ) memset(field[varID][levelID].ptr, 0, nwpv*gridsize*sizeof(double));
-	    }
+              if ( ptype & FIELD_FLT )
+                {
+                  field[varID][levelID].ptrf = (float*) Malloc(nwpv*gridsize*sizeof(float));
+                  if ( init ) memset(field[varID][levelID].ptrf, 0, nwpv*gridsize*sizeof(float));
+                }
+              else
+                {
+                  field[varID][levelID].ptr = (double*) Malloc(nwpv*gridsize*sizeof(double));
+                  if ( init ) memset(field[varID][levelID].ptr, 0, nwpv*gridsize*sizeof(double));
+                }
+            }
 
 	  if ( ptype & FIELD_PTR2 )
 	    {
-	      field[varID][levelID].ptr2 = (double*) Malloc(nwpv*gridsize*sizeof(double));
-	      if ( init ) memset(field[varID][levelID].ptr2, 0, nwpv*gridsize*sizeof(double));
-	    }
+              if ( ptype & FIELD_FLT )
+                {
+                  field[varID][levelID].ptr2 = Malloc(nwpv*gridsize*sizeof(float));
+                  if ( init ) memset(field[varID][levelID].ptr2, 0, nwpv*gridsize*sizeof(float));
+                }
+              else
+                {
+                  field[varID][levelID].ptr2 = Malloc(nwpv*gridsize*sizeof(double));
+                  if ( init ) memset(field[varID][levelID].ptr2, 0, nwpv*gridsize*sizeof(double));
+                }
+            }
 
 	  if ( ptype & FIELD_WGT )
 	    {
@@ -90,6 +109,7 @@ void field_free(field_t **field, int vlistID)
       for ( int levelID = 0; levelID < nlevel; ++levelID )
 	{
 	  if ( field[varID][levelID].ptr )    Free(field[varID][levelID].ptr);
+	  if ( field[varID][levelID].ptrf )   Free(field[varID][levelID].ptrf);
 	  if ( field[varID][levelID].ptr2 )   Free(field[varID][levelID].ptr2);
        	  if ( field[varID][levelID].weight ) Free(field[varID][levelID].weight);
 	}
diff --git a/src/fieldmer.c b/src/fieldmer.c
index ad65dcd..eb36d56 100644
--- a/src/fieldmer.c
+++ b/src/fieldmer.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -205,7 +205,7 @@ void mermean(field_t field1, field_t *field2)
 	    }
 	}
 
-      ravg = DIV(rsum, rsumw);
+      ravg = DIVMN(rsum, rsumw);
 
       if ( DBL_IS_EQUAL(ravg, missval1) ) rnmiss++;
 
@@ -240,7 +240,7 @@ void meravg(field_t field1, field_t *field2)
 	  for ( j = 0; j < ny; j++ )
 	    if ( !DBL_IS_EQUAL(w[j*nx+i], missval1) )
 	      {
-		rsum  = ADD(rsum, MUL(w[j*nx+i], array[j*nx+i]));
+		rsum  = ADDMN(rsum, MULMN(w[j*nx+i], array[j*nx+i]));
 		rsumw += w[j*nx+i];
 	      }
 	}
@@ -253,7 +253,7 @@ void meravg(field_t field1, field_t *field2)
 	    }
 	}
 
-      ravg = DIV(rsum, rsumw);
+      ravg = DIVMN(rsum, rsumw);
 
       if ( DBL_IS_EQUAL(ravg, missval1) ) rnmiss++;
 
diff --git a/src/fieldzon.c b/src/fieldzon.c
index bb8ce2e..1c7415e 100644
--- a/src/fieldzon.c
+++ b/src/fieldzon.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -262,7 +262,7 @@ void zonmean(field_t field1, field_t *field2)
 	    }
 	}
 
-      ravg = DIV(rsum, rsumw);
+      ravg = DIVMN(rsum, rsumw);
 
       if ( DBL_IS_EQUAL(ravg, missval1) ) rnmiss++;
 
@@ -295,7 +295,7 @@ void zonavg(field_t field1, field_t *field2)
 	{
 	  for ( i = 0; i < nx; i++ )
 	    {
-	      rsum   = ADD(rsum, array[j*nx+i]);
+	      rsum   = ADDMN(rsum, array[j*nx+i]);
 	      rsumw += 1;
 	    }
 	}
@@ -308,7 +308,7 @@ void zonavg(field_t field1, field_t *field2)
 	    }
 	}
 
-      ravg = DIV(rsum, rsumw);
+      ravg = DIVMN(rsum, rsumw);
 
       if ( DBL_IS_EQUAL(ravg, missval1) ) rnmiss++;
 
diff --git a/src/grid.c b/src/grid.c
index ce90efe..411ea6e 100644
--- a/src/grid.c
+++ b/src/grid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -35,8 +35,6 @@
 #include "error.h"
 #include "grid.h"
 
-int referenceToGrid(int gridID1);
-
 
 static
 void scale_vec(double scalefactor, long nvals, double *restrict values)
@@ -120,7 +118,7 @@ int gridToZonal(int gridID1)
       Error("Gridtype %s unsupported!", gridNamePtr(gridtype));
     }
 
-  return (gridID2);
+  return gridID2;
 }
 
 
@@ -159,7 +157,7 @@ int gridToMeridional(int gridID1)
       Error("Gridtype %s unsupported!", gridNamePtr(gridtype));
     }
 
-  return (gridID2);
+  return gridID2;
 }
 
 
@@ -250,7 +248,7 @@ double genYmin(double y1, double y2)
   if ( cdoVerbose )
     cdoPrint("genYmin: y1 = %g  y2 = %g  dy = %g  ymin = %g", y1, y2, dy, ymin);
 
-  return (ymin);
+  return ymin;
 }
 
 static
@@ -266,7 +264,7 @@ double genYmax(double y1, double y2)
   if ( cdoVerbose )
     cdoPrint("genYmax: y1 = %g  y2 = %g  dy = %g  ymax = %g", y1, y2, dy, ymax);
 
-  return (ymax);
+  return ymax;
 }
 
 
@@ -456,7 +454,7 @@ char *gen_param(const char *fmt, ...)
   rstr = (char*) Malloc(len*sizeof(char));
   memcpy(rstr, str, len*sizeof(char));
 
-  return (rstr);
+  return rstr;
 }
 
 static
@@ -690,14 +688,8 @@ void grib_get_reduced_row(long pl,double lon_first,double lon_last,long* npoints
   }
 
   if (*ilon_first<0) *ilon_first+=pl;
-
-  return;
 }
 
-
-int qu2reg3_double(double *pfield, int *kpoint, int klat, int klon,
-		   double msval, int *kret, int omisng, int operio, int oveggy);
-
 static
 int qu2reg_subarea(int gridsize, int np, double xfirst, double xlast, 
 		   double *array, int *rowlon, int ny, double missval, int *iret, int lmiss, int lperio, int lveggy)
@@ -787,7 +779,7 @@ int qu2reg_subarea(int gridsize, int np, double xfirst, double xlast,
   Free(work);
   Free(pwork);
 
-  return (nx);
+  return nx;
 }
 
 
@@ -803,7 +795,7 @@ void field2regular(int gridID1, int gridID2, double missval, double *array, int
 
   gridtype = gridInqType(gridID1);
 
-  if ( gridtype != GRID_GAUSSIAN_REDUCED ) Error("Not a reduced gaussian grid!");
+  if ( gridtype != GRID_GAUSSIAN_REDUCED ) Error("Not a reduced Gaussian grid!");
 
   lmiss = nmiss > 0;
   lperio = 1;
@@ -849,7 +841,7 @@ int gridToRegular(int gridID1)
 
   gridtype = gridInqType(gridID1);
 
-  if ( gridtype != GRID_GAUSSIAN_REDUCED ) Error("Not a reduced gaussian grid!");
+  if ( gridtype != GRID_GAUSSIAN_REDUCED ) Error("Not a reduced Gaussian grid!");
 
   ny = gridInqYsize(gridID1);
   np = gridInqNP(gridID1);
@@ -906,7 +898,7 @@ int gridToRegular(int gridID1)
   Free(xvals);
   Free(yvals);
 
-  return (gridID2);
+  return gridID2;
 }
 
 static
@@ -914,8 +906,7 @@ void gridCopyMask(int gridID1, int gridID2, long gridsize)
 {
   if ( gridInqMask(gridID1, NULL) )
     {
-      int *mask;
-      mask = (int*) Malloc(gridsize*sizeof(int));
+      int *mask = (int*) Malloc(gridsize*sizeof(int));
       gridInqMask(gridID1, mask);
       gridDefMask(gridID2, mask);
       Free(mask);
@@ -937,14 +928,13 @@ int check_range(long n, double *vals, double valid_min, double valid_max)
 	}
     }
 
-  return (status);
+  return status;
 }
 
 
 int gridToCurvilinear(int gridID1, int lbounds)
 {
   long index;
-
   int gridtype = gridInqType(gridID1);
   size_t gridsize = (size_t) gridInqSize(gridID1);
   int gridID2  = gridCreate(GRID_CURVILINEAR, (int) gridsize);
@@ -959,13 +949,10 @@ int gridToCurvilinear(int gridID1, int lbounds)
     case GRID_LAEA:
     case GRID_SINUSOIDAL:
       {
-	long i, j;
+	double xscale = 1, yscale = 1;
 	double *xvals = NULL, *yvals = NULL;
-	double *xvals2D, *yvals2D;
 	double *xbounds = NULL, *ybounds = NULL;
-	double *xbounds2D, *ybounds2D;
 	char xunits[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
-	double xscale = 1, yscale = 1;
 
 	int nx = gridInqXsize(gridID1);
 	int ny = gridInqYsize(gridID1);
@@ -997,14 +984,14 @@ int gridToCurvilinear(int gridID1, int lbounds)
 	gridDefXsize(gridID2, nx);
 	gridDefYsize(gridID2, ny);
 
-	xvals2D = (double*) Malloc(gridsize*sizeof(double));
-	yvals2D = (double*) Malloc(gridsize*sizeof(double));
+	double *xvals2D = (double*) Malloc(gridsize*sizeof(double));
+	double *yvals2D = (double*) Malloc(gridsize*sizeof(double));
 
 
 	if ( gridtype == GRID_LCC )
 	  {
-	    for ( j = 0; j < ny; j++ )
-	      for ( i = 0; i < nx; i++ )
+	    for ( int j = 0; j < ny; j++ )
+	      for ( int i = 0; i < nx; i++ )
 		{
 		  xvals2D[j*nx+i] = i+1;
 		  yvals2D[j*nx+i] = j+1;
@@ -1014,25 +1001,34 @@ int gridToCurvilinear(int gridID1, int lbounds)
 	  }
 	else
 	  {
+            /*
 	    if ( ! (gridInqXvals(gridID1, NULL) && gridInqYvals(gridID1, NULL)) )
-	      Error("Grid has no values");
-
-	    xvals = (double*) Malloc(nx*sizeof(double));
-	    yvals = (double*) Malloc(ny*sizeof(double));
-
-	    gridInqXvals(gridID1, xvals);
-	    gridInqYvals(gridID1, yvals);
-
+	      Error("Grid has no coordinates");
+            */
+            if ( nx == 0 ) nx = 1;
+            if ( ny == 0 ) ny = 1;
+
+            xvals = (double*) Malloc(nx*sizeof(double));
+            yvals = (double*) Malloc(ny*sizeof(double));
+            
+            if ( gridInqXvals(gridID1, NULL) )
+              gridInqXvals(gridID1, xvals);
+            else
+              for ( int i = 0; i < nx; ++i ) xvals[i] = 0;
+            
+            if ( gridInqYvals(gridID1, NULL) )
+              gridInqYvals(gridID1, yvals);
+            else
+              for ( int i = 0; i < ny; ++i ) yvals[i] = 0;
+            
 	    if ( gridIsRotated(gridID1) )
-	      {
-		double xpole, ypole, angle;
+	      {		
+		double xpole = gridInqXpole(gridID1);
+		double ypole = gridInqYpole(gridID1);
+		double angle = gridInqAngle(gridID1);
 		
-		xpole = gridInqXpole(gridID1);
-		ypole = gridInqYpole(gridID1);
-		angle = gridInqAngle(gridID1);
-		
-		for ( j = 0; j < ny; j++ )
-		  for ( i = 0; i < nx; i++ )
+		for ( int j = 0; j < ny; j++ )
+		  for ( int i = 0; i < nx; i++ )
 		    {
 		      xvals2D[j*nx+i] = lamrot_to_lam(yvals[j], xvals[i], ypole, xpole, angle);
 		      yvals2D[j*nx+i] = phirot_to_phi(yvals[j], xvals[i], ypole, angle);
@@ -1040,8 +1036,8 @@ int gridToCurvilinear(int gridID1, int lbounds)
 	      }
 	    else
 	      {
-		for ( j = 0; j < ny; j++ )
-		  for ( i = 0; i < nx; i++ )
+		for ( int j = 0; j < ny; j++ )
+		  for ( int i = 0; i < nx; i++ )
 		    {
 		      xvals2D[j*nx+i] = xscale*xvals[i];
 		      yvals2D[j*nx+i] = yscale*yvals[j];
@@ -1073,11 +1069,11 @@ int gridToCurvilinear(int gridID1, int lbounds)
 
 	if ( gridtype == GRID_LCC )
 	  {		
-	    xbounds2D = (double*) Malloc(4*gridsize*sizeof(double));
-	    ybounds2D = (double*) Malloc(4*gridsize*sizeof(double));
+	    double *xbounds2D = (double*) Malloc(4*gridsize*sizeof(double));
+	    double *ybounds2D = (double*) Malloc(4*gridsize*sizeof(double));
 
-	    for ( j = 0; j < ny; j++ )
-	      for ( i = 0; i < nx; i++ )
+	    for ( int j = 0; j < ny; j++ )
+	      for ( int i = 0; i < nx; i++ )
 		{
 		  index = j*4*nx + 4*i;
 
@@ -1150,8 +1146,8 @@ int gridToCurvilinear(int gridID1, int lbounds)
 
 	    if ( xbounds && ybounds )
 	      {
-		xbounds2D = (double*) Malloc(4*gridsize*sizeof(double));
-		ybounds2D = (double*) Malloc(4*gridsize*sizeof(double));
+		double *xbounds2D = (double*) Malloc(4*gridsize*sizeof(double));
+		double *ybounds2D = (double*) Malloc(4*gridsize*sizeof(double));
 
 		if ( gridIsRotated(gridID1) )
 		  {
@@ -1163,8 +1159,8 @@ int gridToCurvilinear(int gridID1, int lbounds)
 			 gridtype == GRID_LAEA       || 
 			 gridtype == GRID_LCC2 )
 		      {
-			for ( j = 0; j < ny; j++ )
-			  for ( i = 0; i < nx; i++ )
+			for ( int j = 0; j < ny; j++ )
+			  for ( int i = 0; i < nx; i++ )
 			    {
 			      index = j*4*nx + 4*i;
 
@@ -1233,18 +1229,15 @@ int gridToCurvilinear(int gridID1, int lbounds)
       }
     }
 
-  return (gridID2);
+  return gridID2;
 }
 
 
 int gridToUnstructured(int gridID1, int lbounds)
 {
-  int gridID2;
-  int gridtype, gridsize;
-
-  gridtype = gridInqType(gridID1);
-  gridsize = gridInqSize(gridID1);
-  gridID2  = gridCreate(GRID_UNSTRUCTURED, gridsize);
+  int gridtype = gridInqType(gridID1);
+  int gridsize = gridInqSize(gridID1);
+  int gridID2  = gridCreate(GRID_UNSTRUCTURED, gridsize);
   gridDefPrec(gridID2, DATATYPE_FLT32);
 	  
   switch (gridtype)
@@ -1252,11 +1245,6 @@ int gridToUnstructured(int gridID1, int lbounds)
     case GRID_LONLAT:
     case GRID_GAUSSIAN:
       {
-	long i, j;
-	int nx, ny;
-	double *xvals, *yvals;
-	double *xvals2D, *yvals2D;
-
 	gridDefXname(gridID2, "lon");
 	gridDefYname(gridID2, "lat");
 	gridDefXlongname(gridID2, "longitude");
@@ -1266,31 +1254,29 @@ int gridToUnstructured(int gridID1, int lbounds)
 
 	gridDefNvertex(gridID2, 4);
 
-	nx = gridInqXsize(gridID1);
-	ny = gridInqYsize(gridID1);
+	int nx = gridInqXsize(gridID1);
+	int ny = gridInqYsize(gridID1);
 	 
 	gridDefXsize(gridID2, gridsize);
 	gridDefYsize(gridID2, gridsize);
 
-	xvals = (double*) Malloc(nx*sizeof(double));
-	yvals = (double*) Malloc(ny*sizeof(double));
+	double *xvals = (double*) Malloc(nx*sizeof(double));
+	double *yvals = (double*) Malloc(ny*sizeof(double));
 
-	xvals2D = (double*) Malloc(gridsize*sizeof(double));
-	yvals2D = (double*) Malloc(gridsize*sizeof(double));
+	double *xvals2D = (double*) Malloc(gridsize*sizeof(double));
+	double *yvals2D = (double*) Malloc(gridsize*sizeof(double));
 
 	gridInqXvals(gridID1, xvals);
 	gridInqYvals(gridID1, yvals);
 
 	if ( gridIsRotated(gridID1) )
-	  {
-	    double xpole, ypole, angle;
-	    
-	    xpole = gridInqXpole(gridID1);
-	    ypole = gridInqYpole(gridID1);
-	    angle = gridInqAngle(gridID1);
+	  {	    
+	    double xpole = gridInqXpole(gridID1);
+	    double ypole = gridInqYpole(gridID1);
+	    double angle = gridInqAngle(gridID1);
 		
-	    for ( j = 0; j < ny; j++ )
-	      for ( i = 0; i < nx; i++ )
+	    for ( int j = 0; j < ny; j++ )
+	      for ( int i = 0; i < nx; i++ )
 		{
 		  xvals2D[j*nx+i] = lamrot_to_lam(yvals[j], xvals[i], ypole, xpole, angle);
 		  yvals2D[j*nx+i] = phirot_to_phi(yvals[j], xvals[i], ypole, angle);
@@ -1298,8 +1284,8 @@ int gridToUnstructured(int gridID1, int lbounds)
 	  }
 	else
 	  {
-	    for ( j = 0; j < ny; j++ )
-	      for ( i = 0; i < nx; i++ )
+	    for ( int j = 0; j < ny; j++ )
+	      for ( int i = 0; i < nx; i++ )
 		{
 		  xvals2D[j*nx+i] = xvals[i];
 		  yvals2D[j*nx+i] = yvals[j];
@@ -1315,7 +1301,6 @@ int gridToUnstructured(int gridID1, int lbounds)
 	if ( lbounds )
 	  {
 	    double *xbounds = NULL, *ybounds = NULL;
-	    double *xbounds2D, *ybounds2D;
 
 	    if ( gridInqXbounds(gridID1, NULL) )
 	      {
@@ -1342,8 +1327,8 @@ int gridToUnstructured(int gridID1, int lbounds)
 
 	    if ( xbounds && ybounds )
 	      {
-		xbounds2D = (double*) Malloc(4*gridsize*sizeof(double));
-		ybounds2D = (double*) Malloc(4*gridsize*sizeof(double));
+		double *xbounds2D = (double*) Malloc(4*gridsize*sizeof(double));
+		double *ybounds2D = (double*) Malloc(4*gridsize*sizeof(double));
 
 		if ( gridIsRotated(gridID1) )
 		  {
@@ -1383,21 +1368,17 @@ int gridToUnstructured(int gridID1, int lbounds)
       }
     case GRID_GME:
       {
-	int nd, ni, ni2, ni3;
-	long i, j;
 	int nv = 6;
-	int *imask;
-	double *xvals, *yvals;
 	double *xbounds = NULL, *ybounds = NULL;
 
-	nd  = gridInqGMEnd(gridID1);
-	ni  = gridInqGMEni(gridID1);
-	ni2 = gridInqGMEni2(gridID1);
-	ni3 = gridInqGMEni3(gridID1);
+	int nd  = gridInqGMEnd(gridID1);
+	int ni  = gridInqGMEni(gridID1);
+	int ni2 = gridInqGMEni2(gridID1);
+	int ni3 = gridInqGMEni3(gridID1);
 
-	imask   = (int*) Malloc(gridsize*sizeof(int));
-	xvals   = (double*) Malloc(gridsize*sizeof(double));
-	yvals   = (double*) Malloc(gridsize*sizeof(double));
+	int *imask = (int*) Malloc(gridsize*sizeof(int));
+	double *xvals = (double*) Malloc(gridsize*sizeof(double));
+	double *yvals = (double*) Malloc(gridsize*sizeof(double));
 	if ( lbounds )
 	  {
 	    xbounds = (double*) Malloc(nv*gridsize*sizeof(double));
@@ -1406,13 +1387,13 @@ int gridToUnstructured(int gridID1, int lbounds)
 
 	gme_grid(lbounds, gridsize, xvals, yvals, xbounds, ybounds, imask, ni, nd, ni2, ni3);
 	
-	for ( i = 0; i < gridsize; i++ )
+	for ( int i = 0; i < gridsize; i++ )
 	  {
 	    xvals[i] *= RAD2DEG;
 	    yvals[i] *= RAD2DEG;
 
 	    if ( lbounds )
-	      for ( j = 0; j < nv; j++ )
+	      for ( int j = 0; j < nv; j++ )
 		{
 		  xbounds[i*nv + j] *= RAD2DEG;
 		  ybounds[i*nv + j] *= RAD2DEG;
@@ -1456,7 +1437,7 @@ int gridToUnstructured(int gridID1, int lbounds)
       }
     }
 
-  return (gridID2);
+  return gridID2;
 }
 
 
@@ -1473,7 +1454,7 @@ int gridCurvilinearToRegular(int gridID1)
   gridtype = gridInqType(gridID1);
   gridsize = gridInqSize(gridID1);
 
-  if ( gridtype != GRID_CURVILINEAR ) return (gridID2);
+  if ( gridtype != GRID_CURVILINEAR ) return gridID2;
 
   nx = gridInqXsize(gridID1);
   ny = gridInqYsize(gridID1);
@@ -1538,7 +1519,7 @@ int gridCurvilinearToRegular(int gridID1)
   Free(xvals);
   Free(yvals);
 
-  return (gridID2);
+  return gridID2;
 }
 
 
@@ -1585,7 +1566,7 @@ int gridGenWeights(int gridID, double *grid_area, double *grid_wgts)
   
   if ( grid_mask ) Free(grid_mask);
 
-  return (status);
+  return status;
 }
 
 
@@ -1672,7 +1653,7 @@ int gridWeightsOld(int gridID, double *weights)
 	}
     }
 
-  return (status);
+  return status;
 }
 
 
@@ -1731,5 +1712,5 @@ int gridWeights(int gridID, double *grid_wgts)
   */
   Free(grid_area);
 
-  return (w_status);
+  return w_status;
 }
diff --git a/src/grid.h b/src/grid.h
index 6d542d1..aaaeea3 100644
--- a/src/grid.h
+++ b/src/grid.h
@@ -34,12 +34,8 @@ void grid_cell_center_to_bounds_X2D(const char* xunitstr, long xsize, long ysize
 void grid_cell_center_to_bounds_Y2D(const char* yunitstr, long xsize, long ysize,
 				    const double* restrict grid_center_lat, double* restrict grid_corner_lat);
 
-void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *xvals);
-void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *yvals);
-
 int  gridWeights(int gridID, double *weights);
 int  gridGenArea(int gridID, double *area);
-void gaussaw(double pa[], double pw[], size_t nlat);
 
 int referenceToGrid(int gridID);
 int gridToZonal(int gridID);
diff --git a/src/grid_area.c b/src/grid_area.c
index 0c8e3ca..fdd3622 100644
--- a/src/grid_area.c
+++ b/src/grid_area.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -56,7 +56,7 @@ double yac_huiliers_area(int num_corners, double *cell_corner_lon, double *cell_
   double area = huiliers_area(cell);
   area /= (EarthRadius*EarthRadius);
 
-  return (area);
+  return area;
 }
 */
 static
@@ -166,7 +166,7 @@ double mod_cell_area(int num_corners, double *cell_corner_lon, double *cell_corn
       if ( area < 0.0 ) area = 0.0;
     }
 
-  return (area);
+  return area;
 }
 
 /** area of a spherical triangle based on L'Huilier's Theorem
@@ -206,7 +206,7 @@ double mod_tri_area(const double *restrict u, const double *restrict v, const do
 
   double area = fabs(4.0 * atan(sqrt(fabs(t))));
 
-  return (area);
+  return area;
 }
 
  /*
@@ -245,7 +245,7 @@ double mod_huiliers_area(int num_corners, double *cell_corner_lon, double *cell_
       if ( i < (num_corners-1) ) { pnt2[0] = pnt3[0]; pnt2[1] = pnt3[1]; pnt2[2] = pnt3[2]; }
     }
 
-  return (sum);
+  return sum;
 }
 
 static
@@ -279,26 +279,19 @@ double mod_huiliers_area2(int num_corners, double *cell_corner_lon, double *cell
       sum += mod_tri_area(pnt1, pnt2, pnt3);
     }
 
-  return (sum);
+  return sum;
 }
 
 
 int gridGenArea(int gridID, double* area)
 {
   int status = 0;
-  int gridtype;
   int lgrid_gen_bounds = FALSE;
   int lgriddestroy = FALSE;
-  long i;
-  long nv, gridsize;
-  int* grid_mask = NULL;
-  double* grid_center_lon = NULL;
-  double* grid_center_lat = NULL;
-  double* grid_corner_lon = NULL;
-  double* grid_corner_lat = NULL;
-
-  gridsize = gridInqSize(gridID);
-  gridtype = gridInqType(gridID);
+  long nv;
+
+  long gridsize = gridInqSize(gridID);
+  int gridtype = gridInqType(gridID);
 
   if ( gridtype != GRID_LONLAT      &&
        gridtype != GRID_GAUSSIAN    &&
@@ -319,8 +312,11 @@ int gridGenArea(int gridID, double* area)
 	{
 	  lgriddestroy = TRUE;
 	  gridID = gridToUnstructured(gridID, 1);
+          /*
 	  grid_mask = (int*) Malloc(gridsize*sizeof(int));
 	  gridInqMaskGME(gridID, grid_mask);
+          if ( grid_mask ) Free(grid_mask);
+          */
 	}
       else
 	{
@@ -338,7 +334,7 @@ int gridGenArea(int gridID, double* area)
 	    {
 	      lgriddestroy = TRUE;
 	      gridID = referenceToGrid(gridID);
-	      if ( gridID == -1 ) return (1);
+	      if ( gridID == -1 ) return 1;
 	    }
 	}
     }
@@ -354,14 +350,14 @@ int gridGenArea(int gridID, double* area)
     {
       cdoWarning("Computation of grid cell area weights failed, grid cell center coordinates missing!");
       status = 1;
-      return (status);
+      return status;
     }
 
   if ( nv == 0 )
     {
       cdoWarning("Computation of grid cell area weights failed, grid cell corner coordinates missing!");
       status = 1;
-      return (status);
+      return status;
     }
 
   char xunitstr[CDI_MAX_NAME];
@@ -369,14 +365,14 @@ int gridGenArea(int gridID, double* area)
   gridInqXunits(gridID, xunitstr);
   gridInqYunits(gridID, yunitstr);
 
-  grid_center_lon = (double*) Malloc(gridsize*sizeof(double));
-  grid_center_lat = (double*) Malloc(gridsize*sizeof(double));
+  double *grid_center_lon = (double*) Malloc(gridsize*sizeof(double));
+  double *grid_center_lat = (double*) Malloc(gridsize*sizeof(double));
 
   gridInqXvals(gridID, grid_center_lon);
   gridInqYvals(gridID, grid_center_lat);
 
-  grid_corner_lon = (double*) Malloc(nv*gridsize*sizeof(double));
-  grid_corner_lat = (double*) Malloc(nv*gridsize*sizeof(double));
+  double *grid_corner_lon = (double*) Malloc(nv*gridsize*sizeof(double));
+  double *grid_corner_lat = (double*) Malloc(nv*gridsize*sizeof(double));
 
   if ( gridInqYbounds(gridID, NULL) && gridInqXbounds(gridID, NULL) )
     {
@@ -398,7 +394,7 @@ int gridGenArea(int gridID, double* area)
       else
 	{
 	  status = 1;
-	  return (status);
+	  return status;
 	}
     }
   
@@ -418,7 +414,7 @@ int gridGenArea(int gridID, double* area)
 #pragma omp parallel for default(none)  \
   shared(findex,gridsize,area,nv,grid_corner_lon,grid_corner_lat,grid_center_lon,grid_center_lat)
 #endif
-  for ( int i = 0; i < gridsize; ++i )
+  for ( long i = 0; i < gridsize; ++i )
     {
       int lprogress = 1;
       if ( cdo_omp_get_thread_num() != 0 ) lprogress = 0;
@@ -439,15 +435,23 @@ int gridGenArea(int gridID, double* area)
   if ( cdoVerbose )
     {
       double total_area = 0;
-      for ( i = 0; i < gridsize; ++i ) total_area += area[i];
+      for ( long i = 0; i < gridsize; ++i ) total_area += area[i];
       cdoPrint("Total area = %g steradians", total_area);
     }
 
+  if ( gridsize < 20 )
+    {
+      double total_area = 0;
+      for ( long i = 0; i < gridsize; ++i ) total_area += area[i];
+      int nzero = 0;
+      for ( long i = 0; i < gridsize; ++i ) if ( IS_EQUAL(area[i], 0.) ) nzero++;
+      if ( IS_EQUAL(total_area, 0.) ) status = 2;
+    }
+
   Free(grid_center_lon);
   Free(grid_center_lat);
   Free(grid_corner_lon);
   Free(grid_corner_lat);
-  if ( grid_mask ) Free(grid_mask);
 
-  return (status);
+  return status;
 }
diff --git a/src/grid_search.c b/src/grid_search.c
index bb66c84..19b1e46 100644
--- a/src/grid_search.c
+++ b/src/grid_search.c
@@ -31,6 +31,14 @@ static inline void LLtoXYZ_f(double lon, double lat, float *restrict xyz)
    xyz[2] = sin(lat);
 }
 
+static inline void LLtoXYZ_kd(double lon, double lat, kdata_t *restrict xyz)
+{
+   double cos_lat = cos(lat);
+   xyz[0] = KDATA_SCALE(cos_lat * cos(lon));
+   xyz[1] = KDATA_SCALE(cos_lat * sin(lon));
+   xyz[2] = KDATA_SCALE(sin(lat));
+}
+
 static
 float square(const float x)
 {
@@ -54,17 +62,20 @@ void gridsearch_set_method(const char *methodstr)
 }
 
 
-struct gridsearch *gridsearch_create_reg2d(unsigned nx, unsigned ny, const double *restrict lons, const double *restrict lats)
+struct gridsearch *gridsearch_create_reg2d(unsigned lcyclic, unsigned nx, unsigned ny, const double *restrict lons, const double *restrict lats)
 {
   struct gridsearch *gs = (struct gridsearch *) Calloc(1, sizeof(struct gridsearch));
 
   gs->nx = nx;
   gs->ny = ny;
 
-  double *reg2d_center_lon = (double *) Malloc((nx+1)*sizeof(double));
+  unsigned nxm = nx;
+  if ( lcyclic ) nxm++;
+
+  double *reg2d_center_lon = (double *) Malloc(nxm*sizeof(double));
   double *reg2d_center_lat = (double *) Malloc(ny*sizeof(double));
 
-  memcpy(reg2d_center_lon, lons, (nx+1)*sizeof(double));
+  memcpy(reg2d_center_lon, lons, nxm*sizeof(double));
   memcpy(reg2d_center_lat, lats, ny*sizeof(double));
 
   double *coslon = (double *) Malloc(nx*sizeof(double));
@@ -103,17 +114,17 @@ struct kdNode *gs_create_kdtree(unsigned n, const double *restrict lons, const d
   struct kd_point *pointlist = (struct kd_point *) Malloc(n * sizeof(struct kd_point));  
   // see  example_cartesian.c
   if ( cdoVerbose ) printf("kdtree lib init 3D: n=%d  nthreads=%d\n", n, ompNumThreads);
-  float min[3], max[3];
+  kdata_t min[3], max[3];
   min[0] = min[1] = min[2] =  1e9;
   max[0] = max[1] = max[2] = -1e9;
-  float *restrict point;
+  kdata_t *restrict point;
 #if defined(HAVE_OPENMP4)
 #pragma omp simd
 #endif
   for ( unsigned i = 0; i < n; i++ ) 
     {
       point = pointlist[i].point;
-      LLtoXYZ_f(lons[i], lats[i], point);
+      LLtoXYZ_kd(lons[i], lats[i], point);
       for ( unsigned j = 0; j < 3; ++j )
         {
           min[j] = point[j] < min[j] ? point[j] : min[j];
@@ -295,15 +306,16 @@ kdNode *gs_nearest_kdtree(kdNode *kdt, double lon, double lat, double *prange)
   if ( kdt == NULL ) return NULL;
   
   float range0 = gs_set_range(prange);
-  float range = range0;
+  kdata_t range = KDATA_SCALE(range0);
 
-  float point[3];
-  LLtoXYZ_f(lon, lat, point);
+  kdata_t point[3];
+  LLtoXYZ_kd(lon, lat, point);
 
   kdNode *node = kd_nearest(kdt, point, &range, 3);
 
-  if ( !(range < range0) ) node = NULL;
-  if ( prange ) *prange = range;
+  float frange = KDATA_INVSCALE(range);
+  if ( !(frange < range0) ) node = NULL;
+  if ( prange ) *prange = frange;
 
   return node;
 }
@@ -419,19 +431,20 @@ struct pqueue *gridsearch_qnearest(struct gridsearch *gs, double lon, double lat
 {
   if ( gs->kdt == NULL ) return NULL;
   
-  float point[3];
+  kdata_t point[3];
   float range0 = gs_set_range(prange);
-  float range = range0;
+  kdata_t range = KDATA_SCALE(range0);
   struct pqueue *result = NULL;
 
-  LLtoXYZ_f(lon, lat, point);
+  LLtoXYZ_kd(lon, lat, point);
 
   if ( gs )
     {
       result = kd_qnearest(gs->kdt, point, &range, nnn, 3);
       // printf("range %g %g %g %p\n", lon, lat, range, node);
 
-      if ( !(range < range0) )
+      float frange = KDATA_INVSCALE(range);
+      if ( !(frange < range0) )
         {
           if ( result )
             {
@@ -442,7 +455,7 @@ struct pqueue *gridsearch_qnearest(struct gridsearch *gs, double lon, double lat
             }
           result = NULL;
         }
-      if ( prange ) *prange = range;
+      if ( prange ) *prange = frange;
     }
   
   return result;
diff --git a/src/grid_search.h b/src/grid_search.h
index 36e5888..b973c54 100644
--- a/src/grid_search.h
+++ b/src/grid_search.h
@@ -43,7 +43,7 @@ struct gridsearch {
 };
 
 
-struct gridsearch *gridsearch_create_reg2d(unsigned nx, unsigned ny, const double *restrict lons, const double *restrict lats);
+struct gridsearch *gridsearch_create_reg2d(unsigned lcyclic, unsigned nx, unsigned ny, const double *restrict lons, const double *restrict lats);
 struct gridsearch *gridsearch_create(unsigned n, const double *restrict lons, const double *restrict lats);
 struct gridsearch *gridsearch_create_nn(unsigned n, const double *restrict lons, const double *restrict lats);
 void gridsearch_delete(struct gridsearch *gs);
diff --git a/src/griddes.c b/src/griddes.c
index 7f67be2..6e83343 100644
--- a/src/griddes.c
+++ b/src/griddes.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -34,6 +34,7 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "cdi_uuid.h"
 #include "grid.h"
 #include "griddes.h"
 #include "error.h"
@@ -667,7 +668,6 @@ double readflt(const char *filename, const char *name, const char *pline)
   return (val);
 }
 
-void str2uuid(const char *uuidstr, unsigned char *uuid);
 
 int gridFromFile(FILE *gfp, const char *dname)
 {
@@ -809,7 +809,7 @@ int gridFromFile(FILE *gfp, const char *dname)
 	{
 	  char uuidOfHGridStr[256];
 	  strcpy(uuidOfHGridStr, skipSeparator(pline + len));
-	  str2uuid(uuidOfHGridStr, grid.uuid);
+	  cdiStr2UUID(uuidOfHGridStr, grid.uuid);
 	}
       else if ( cmpstrlen(pline, "xsize", len)  == 0 )
 	{
@@ -1878,7 +1878,7 @@ int cdoDefineGrid(const char *gridfile)
 
       if ( cmpstrlen(buffer, "CDF", len) == 0 )
 	{
-	  if ( cdoDebug ) cdoPrint("Grid from netCDF file");
+	  if ( cdoDebug ) cdoPrint("Grid from NetCDF file");
 	  gridID = gridFromNCfile(filename);
 	}
 
@@ -1895,7 +1895,7 @@ int cdoDefineGrid(const char *gridfile)
 	{
 	  if ( cmpstrlen(buffer+1, "HDF", len) == 0 )
 	    {
-	      if ( cdoDebug ) cdoPrint("Grid from netCDF4 file");
+	      if ( cdoDebug ) cdoPrint("Grid from NetCDF4 file");
 	      gridID = gridFromNCfile(filename);
 	    }
 	}
diff --git a/src/griddes_nc.c b/src/griddes_nc.c
index 7e21d71..5d185bc 100644
--- a/src/griddes_nc.c
+++ b/src/griddes_nc.c
@@ -19,7 +19,7 @@
 static void nce(int istat)
 {
   /*
-    This routine provides a simple interface to netCDF error message routine.
+    This routine provides a simple interface to NetCDF error message routine.
   */
   if ( istat != NC_NOERR ) cdoAbort(nc_strerror(istat));
 }
@@ -30,7 +30,7 @@ int cdf_openread(const char *filename)
 {
   int fileID = -1;
 #if defined(HAVE_LIBNETCDF)
-  int nc_file_id;      /* netCDF grid file id           */
+  int nc_file_id;      /* NetCDF grid file id           */
 
   openLock();
   int istat = nc_open(filename, NC_NOWRITE, &nc_file_id);
@@ -39,7 +39,7 @@ int cdf_openread(const char *filename)
     cdoAbort("Open failed on %s! %s", filename, nc_strerror(istat));
   fileID = nc_file_id;
 #else
-  cdoWarning("netCDF support not compiled in!");
+  cdoWarning("NetCDF support not compiled in!");
 #endif
 
   return (fileID);
@@ -50,16 +50,16 @@ int gridFromNCfile(const char *gridfile)
 {
   int gridID = -1;
 #if defined(HAVE_LIBNETCDF)
-  int nc_file_id;      /* netCDF grid file id           */
-  int nc_gridsize_id;  /* netCDF grid size dim id       */
-  int nc_gridcorn_id;  /* netCDF grid corner dim id     */
-  int nc_gridrank_id;  /* netCDF grid rank dim id       */
-  int nc_griddims_id;  /* netCDF grid dimension size id */
-  int nc_gridclat_id;  /* netCDF grid corner lat var id */
-  int nc_gridclon_id;  /* netCDF grid corner lon var id */
-  int nc_gridlat_id;   /* netCDF grid center lat var id */
-  int nc_gridlon_id;   /* netCDF grid center lon var id */
-  int nc_gridmask_id;  /* netCDF grid mask id           */
+  int nc_file_id;      /* NetCDF grid file id           */
+  int nc_gridsize_id;  /* NetCDF grid size dim id       */
+  int nc_gridcorn_id;  /* NetCDF grid corner dim id     */
+  int nc_gridrank_id;  /* NetCDF grid rank dim id       */
+  int nc_griddims_id;  /* NetCDF grid dimension size id */
+  int nc_gridclat_id;  /* NetCDF grid corner lat var id */
+  int nc_gridclon_id;  /* NetCDF grid corner lon var id */
+  int nc_gridlat_id;   /* NetCDF grid center lat var id */
+  int nc_gridlon_id;   /* NetCDF grid center lon var id */
+  int nc_gridmask_id;  /* NetCDF grid mask id           */
 
   nc_type xtype;
   size_t attlen;
@@ -151,7 +151,7 @@ int gridFromNCfile(const char *gridfile)
   nce(nc_close(nc_file_id));
 
 #else
-  cdoWarning("netCDF support not compiled in!");
+  cdoWarning("NetCDF support not compiled in!");
 #endif
 
   return (gridID);
@@ -161,15 +161,15 @@ int gridFromNCfile(const char *gridfile)
 void writeNCgrid(const char *gridfile, int gridID, int *grid_imask)
 {
 #if defined(HAVE_LIBNETCDF)
-  int nc_file_id;      /* netCDF grid file id           */
-  int nc_gridsize_id;  /* netCDF grid size dim id       */
-  int nc_gridcorn_id;  /* netCDF grid corner dim id     */
-  int nc_gridrank_id;  /* netCDF grid rank dim id       */
-  int nc_griddims_id;  /* netCDF grid dimension size id */
-  int nc_gridclat_id;  /* netCDF grid corner lat var id */
-  int nc_gridclon_id;  /* netCDF grid corner lon var id */
-  int nc_gridlat_id;   /* netCDF grid center lat var id */
-  int nc_gridlon_id;   /* netCDF grid center lon var id */
+  int nc_file_id;      /* NetCDF grid file id           */
+  int nc_gridsize_id;  /* NetCDF grid size dim id       */
+  int nc_gridcorn_id;  /* NetCDF grid corner dim id     */
+  int nc_gridrank_id;  /* NetCDF grid rank dim id       */
+  int nc_griddims_id;  /* NetCDF grid dimension size id */
+  int nc_gridclat_id;  /* NetCDF grid corner lat var id */
+  int nc_gridclon_id;  /* NetCDF grid corner lon var id */
+  int nc_gridlat_id;   /* NetCDF grid center lat var id */
+  int nc_gridlon_id;   /* NetCDF grid center lon var id */
   int nc_gridxsize_id, nc_gridysize_id, nc_grdimask_id;
 
   nc_type xtype;
@@ -211,7 +211,7 @@ void writeNCgrid(const char *gridfile, int gridID, int *grid_imask)
   else
     cdoWarning("Unknown units supplied for grid!");
 
-  /* create netCDF dataset for this grid */
+  /* create NetCDF dataset for this grid */
   
   nce(nc_create(gridfile, NC_CLOBBER, &nc_file_id));
 
@@ -331,6 +331,6 @@ void writeNCgrid(const char *gridfile, int gridID, int *grid_imask)
   nce(nc_close(nc_file_id));
 
 #else
-  Error("netCDF support not compiled in!");
+  Error("NetCDF support not compiled in!");
 #endif
 }
diff --git a/src/gridreference.c b/src/gridreference.c
index 7a360b0..5c4d049 100644
--- a/src/gridreference.c
+++ b/src/gridreference.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/institution.c b/src/institution.c
index c53edd7..5ceaf5a 100644
--- a/src/institution.c
+++ b/src/institution.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/juldate.c b/src/juldate.c
index 736ec05..54a2154 100644
--- a/src/juldate.c
+++ b/src/juldate.c
@@ -1,11 +1,6 @@
 #include <cdi.h>
 #include "cdo_int.h"
-
-
-void encode_caldaysec(int calendar, int year, int month, int day, int hour, int minute, int second,
-		      int *julday, int *secofday);
-void decode_caldaysec(int calendar, int julday, int secofday, 
-		      int *year, int *month, int *day, int *hour, int *minute, int *second);
+#include "calendar.h"
 
 
 juldate_t juldate_encode(int calendar, int date, int time)
diff --git a/src/kdtreelib/kdtree.h b/src/kdtreelib/kdtree.h
index 398b3f3..ee24ef0 100644
--- a/src/kdtreelib/kdtree.h
+++ b/src/kdtreelib/kdtree.h
@@ -22,10 +22,29 @@
 #include <stdio.h>
 #include <string.h>
 
+#define  KD_FLOAT 1
+#define  KD_INT   2
+
+#define  KD_TYPE  KD_FLOAT
+
+#if KD_TYPE == KD_INT
+typedef int kdata_t;
+#  define KDATA_SFAC     20000.
+#  define KDATA_SCALE(x) ((int) (0.5+KDATA_SFAC*(x)))
+#  define KDATA_INVSCALE(x) ((x)/KDATA_SFAC)
+#  define KDATA_ABS(x)   abs(x)
+#else
+typedef float kdata_t;
+#  define KDATA_SCALE(x) (x)
+#  define KDATA_INVSCALE(x) (x)
+#  define KDATA_ABS(x)   fabs(x)
+#endif
+
+
 #define KD_MAX_DIM 3
 
 typedef struct kd_point {
-    float point[KD_MAX_DIM];
+    kdata_t point[KD_MAX_DIM];
     unsigned index;
 } kd_point;
 
@@ -34,13 +53,13 @@ typedef struct kd_point {
  * \brief kd-tree node structure definition 
  */
 typedef struct kdNode {
-    float location[KD_MAX_DIM]; /*!<vector to the node's location */
-    float min[KD_MAX_DIM];      /*!<vector to the min coordinates of the hyperrectangle */
-    float max[KD_MAX_DIM];      /*!<vector to the max coordinates of the hyperrectangle */
-    int split;                  /*!<axis along which the tree bifurcates */
-    unsigned index;             /*!<optional index value */
-    struct kdNode *left;        /*!<the left child of the tree node */
-    struct kdNode *right;       /*!<the right child of the tree node */
+    struct kdNode *left;          /*!<the left child of the tree node */
+    struct kdNode *right;         /*!<the right child of the tree node */
+    kdata_t location[KD_MAX_DIM]; /*!<vector to the node's location */
+    kdata_t min[KD_MAX_DIM];      /*!<vector to the min coordinates of the hyperrectangle */
+    kdata_t max[KD_MAX_DIM];      /*!<vector to the max coordinates of the hyperrectangle */
+    int split;                    /*!<axis along which the tree bifurcates */
+    unsigned index;               /*!<optional index value */
 } kdNode;
 
 /*!
@@ -49,7 +68,7 @@ typedef struct kdNode {
  */
 typedef struct resItem {
     struct kdNode *node;        /*!<pointer to a kdNode */
-    float dist_sq;              /*!<distance squared as the priority */
+    kdata_t dist_sq;            /*!<distance squared as the priority */
 } resItem;
 
 /*!
@@ -57,10 +76,10 @@ typedef struct resItem {
  * \brief priority queue (min-max heap)
  */
 typedef struct pqueue {
+    struct resItem **d;         /*!<pointer to an array of result items */
     uint32_t size;              /*!<current length of the queue */
     uint32_t avail;             /*!<currently allocated queue elements */
     uint32_t step;              /*!<step size in which new elements are allocated */
-    struct resItem **d;         /*!<pointer to an array of result items */
 } pqueue;
 
 /*!
@@ -68,11 +87,11 @@ typedef struct pqueue {
  * \brief arguments passed to the threaded kd-Tree construction
  */
 typedef struct kd_thread_data {
-    int max_threads;
     struct kd_point *points;
+    kdata_t min[KD_MAX_DIM];
+    kdata_t max[KD_MAX_DIM];
     unsigned long nPoints;
-    float min[KD_MAX_DIM];
-    float max[KD_MAX_DIM];
+    int max_threads;
     int depth;
     int dim;
 } kd_thread_data;
@@ -94,14 +113,14 @@ struct resItem **pqpeek_max(struct pqueue *q, struct resItem **d);
 void *kd_malloc(size_t size, const char *msg);
 int kd_isleaf(struct kdNode *n);
 /* Cartesian */
-float kd_sqr(float a);
-float kd_min(float x, float y);
+kdata_t kd_sqr(kdata_t a);
+kdata_t kd_min(kdata_t x, kdata_t y);
 /* Spherical */
-float kd_sph_orth_dist(float *p1, float *p2, int split);
-float kd_sph_dist_sq(float *x, float *y);
-float kd_sph_dist(float *x, float *y);
-float kd_sph_bearing(float *p1, float *p2);
-float kd_sph_xtd(float *p1, float *p2, float *p3);
+kdata_t kd_sph_orth_dist(kdata_t *p1, kdata_t *p2, int split);
+kdata_t kd_sph_dist_sq(kdata_t *x, kdata_t *y);
+kdata_t kd_sph_dist(kdata_t *x, kdata_t *y);
+kdata_t kd_sph_bearing(kdata_t *p1, kdata_t *p2);
+kdata_t kd_sph_xtd(kdata_t *p1, kdata_t *p2, kdata_t *p3);
 
 /* helper functions for debugging */
 void kd_printNode(struct kdNode *node);
@@ -110,60 +129,60 @@ void kd_printTree(struct kdNode *node);
 /* Functions for building and destroying trees */
 void kd_freeNode(kdNode * node);
 struct kdNode *kd_allocNode(struct kd_point *points, unsigned long pivot,
-                            float *min, float *max, int dim, int axis);
+                            kdata_t *min, kdata_t *max, int dim, int axis);
 void kd_destroyTree(struct kdNode *node);
 struct kd_thread_data *kd_buildArg(struct kd_point *points,
                                    unsigned long nPoints,
-                                   float *min, float *max,
+                                   kdata_t *min, kdata_t *max,
                                    int depth, int max_threads,
                                    int dim);
 struct kdNode *kd_buildTree(struct kd_point *points, unsigned long nPoints,
-                            float *min, float *max, int dim, int max_threads);
+                            kdata_t *min, kdata_t *max, int dim, int max_threads);
 void *kd_doBuildTree(void *threadarg);
 struct kdNode *kd_sph_buildTree(struct kd_point *points,
                                 unsigned long nPoints,
-                                float *min, float *max,
+                                kdata_t *min, kdata_t *max,
                                 int max_threads);
 void *kd_sph_doBuildTree(void *threadarg);
 
 /* Functions for range searches 
  * Cartesian
  */
-int kd_isPointInRect(struct kdNode *node, float *min, float *max, int dim);
-int kd_isRectInRect(struct kdNode *node, float *min, float *max, int dim);
-int kd_rectOverlapsRect(struct kdNode *node, float *min, float *max, int dim);
-struct pqueue *kd_ortRangeSearch(struct kdNode *node, float *min, float *max,
+int kd_isPointInRect(struct kdNode *node, kdata_t *min, kdata_t *max, int dim);
+int kd_isRectInRect(struct kdNode *node, kdata_t *min, kdata_t *max, int dim);
+int kd_rectOverlapsRect(struct kdNode *node, kdata_t *min, kdata_t *max, int dim);
+struct pqueue *kd_ortRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max,
                                  int dim);
-int kd_doOrtRangeSearch(struct kdNode *node, float *min, float *max, int dim,
+int kd_doOrtRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max, int dim,
                         struct pqueue *res);
-struct kdNode *kd_nearest(struct kdNode *node, float *p, float *max_dist_sq,
+struct kdNode *kd_nearest(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
                           int dim);
-struct pqueue *kd_qnearest(struct kdNode *node, float *p,
-                           float *max_dist_sq, unsigned int q, int dim);
-int kd_doQnearest(struct kdNode *node, float *p,
-                  float *max_dist_sq, unsigned int q, int dim,
+struct pqueue *kd_qnearest(struct kdNode *node, kdata_t *p,
+                           kdata_t *max_dist_sq, unsigned int q, int dim);
+int kd_doQnearest(struct kdNode *node, kdata_t *p,
+                  kdata_t *max_dist_sq, unsigned int q, int dim,
                   struct pqueue *res);
-struct pqueue *kd_range(struct kdNode *node, float *p, float *max_dist_sq,
+struct pqueue *kd_range(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
                         int dim, int ordered);
-int kd_doRange(struct kdNode *node, float *p, float *max_dist_sq,
+int kd_doRange(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
                int dim, struct pqueue *res, int ordered);
 /* spherical */
-int kd_sph_isPointInRect(struct kdNode *node, float *min, float *max);
-int kd_sph_isRectInRect(struct kdNode *node, float *min, float *max);
-int kd_sph_rectOverlapsRect(struct kdNode *node, float *min, float *max);
-struct pqueue *kd_sph_ortRangeSearch(struct kdNode *node, float *min,
-                                     float *max);
-int kd_sph_doOrtRangeSearch(struct kdNode *node, float *min, float *max,
+int kd_sph_isPointInRect(struct kdNode *node, kdata_t *min, kdata_t *max);
+int kd_sph_isRectInRect(struct kdNode *node, kdata_t *min, kdata_t *max);
+int kd_sph_rectOverlapsRect(struct kdNode *node, kdata_t *min, kdata_t *max);
+struct pqueue *kd_sph_ortRangeSearch(struct kdNode *node, kdata_t *min,
+                                     kdata_t *max);
+int kd_sph_doOrtRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max,
                             struct pqueue *res);
-struct kdNode *kd_sph_nearest(struct kdNode *node, float *p,
-                              float *max_dist_sq);
-struct pqueue *kd_sph_qnearest(struct kdNode *node, float *p,
-                               float *max_dist_sq, unsigned int q);
-int kd_sph_doQnearest(struct kdNode *node, float *p,
-                      float *max_dist_sq, unsigned int q, struct pqueue *res);
-struct pqueue *kd_sph_range(struct kdNode *node, float *p, float *max_dist_sq,
+struct kdNode *kd_sph_nearest(struct kdNode *node, kdata_t *p,
+                              kdata_t *max_dist_sq);
+struct pqueue *kd_sph_qnearest(struct kdNode *node, kdata_t *p,
+                               kdata_t *max_dist_sq, unsigned int q);
+int kd_sph_doQnearest(struct kdNode *node, kdata_t *p,
+                      kdata_t *max_dist_sq, unsigned int q, struct pqueue *res);
+struct pqueue *kd_sph_range(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
                             int ordered);
-int kd_sph_doRange(struct kdNode *node, float *p, float *max_dist_sq,
+int kd_sph_doRange(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
                    struct pqueue *res, int ordered);
 
 /* Functions for results heaps */
diff --git a/src/kdtreelib/kdtree_cartesian.c b/src/kdtreelib/kdtree_cartesian.c
index 46181a2..11a2be7 100644
--- a/src/kdtreelib/kdtree_cartesian.c
+++ b/src/kdtreelib/kdtree_cartesian.c
@@ -15,35 +15,31 @@
 
    ********************************************************************* */
 
-
 static
-float square(const float x)
+kdata_t square(const kdata_t x)
 {
   return x*x;
 }
 
 static
-float kd_dist_sq(const float *restrict a, const float *restrict b, int dim)
+kdata_t kd_dist_sq(const kdata_t *restrict a, const kdata_t *restrict b, int dim)
 {
   return (square((a[0]-b[0]))+square((a[1]-b[1]))+square((a[2]-b[2])));
 }
 
-inline float
-kd_dist_sq_ori(float *x, float *y, int dim)
+inline kdata_t
+kd_dist_sq_ori(kdata_t *x, kdata_t *y, int dim)
 {
-    int i;
-    float dsq = 0;
-
-    if (!x || !y)
-        return -1;
+    if (!x || !y) return -1;
 
-    for(i = 0; i < dim; i++)
+    kdata_t dsq = 0;
+    for(int i = 0; i < dim; i++)
         dsq += kd_sqr(x[i] - y[i]);
     return dsq;
 }
 
-inline float
-kd_min(float x, float y)
+inline kdata_t
+kd_min(kdata_t x, kdata_t y)
 {
     return x < y ? x : y;
 }
@@ -86,7 +82,7 @@ kd_min(float x, float y)
  */
 struct kdNode *
 kd_buildTree(struct kd_point *points, unsigned long nPoints,
-             float *min, float *max, int dim, int max_threads)
+             kdata_t *min, kdata_t *max, int dim, int max_threads)
 {
     struct kd_thread_data *my_data;
     struct kdNode *tree;
@@ -108,7 +104,7 @@ kd_buildTree(struct kd_point *points, unsigned long nPoints,
 /* Returns 1 if node is a point in the hyperrectangle defined by
    minimum and maximum vectors min and max. */
 int
-kd_isPointInRect(struct kdNode *node, float *min, float *max, int dim)
+kd_isPointInRect(struct kdNode *node, kdata_t *min, kdata_t *max, int dim)
 {
     int i;
 
@@ -126,7 +122,7 @@ kd_isPointInRect(struct kdNode *node, float *min, float *max, int dim)
    the HR described by the minimum and maximum vectors min and
    max. Returns 0 otherwise. */
 int
-kd_isRectInRect(struct kdNode *node, float *min, float *max, int dim)
+kd_isRectInRect(struct kdNode *node, kdata_t *min, kdata_t *max, int dim)
 {
     int i;
 
@@ -144,7 +140,7 @@ kd_isRectInRect(struct kdNode *node, float *min, float *max, int dim)
    the minimum and maximum vectors min and max. Returns 0
    otherwise. */
 int
-kd_rectOverlapsRect(struct kdNode *node, float *min, float *max, int dim)
+kd_rectOverlapsRect(struct kdNode *node, kdata_t *min, kdata_t *max, int dim)
 {
     int i;
 
@@ -175,7 +171,7 @@ kd_rectOverlapsRect(struct kdNode *node, float *min, float *max, int dim)
  * \return  Pointer to a priority queue, NULL in case of problems.
 */
 struct pqueue *
-kd_ortRangeSearch(struct kdNode *node, float *min, float *max, int dim)
+kd_ortRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max, int dim)
 {
     struct pqueue *res;
     uint32_t i;
@@ -196,7 +192,7 @@ kd_ortRangeSearch(struct kdNode *node, float *min, float *max, int dim)
 /* This is the orthogonal range search. Returns 1 if okay, 0 in case
    of problems. */
 int
-kd_doOrtRangeSearch(struct kdNode *node, float *min, float *max,
+kd_doOrtRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max,
                     int dim, struct pqueue *res)
 {
 
@@ -243,10 +239,10 @@ kd_doOrtRangeSearch(struct kdNode *node, float *min, float *max,
  * neigbor.
  */
 struct kdNode *
-kd_nearest(struct kdNode *node, float *p, float *max_dist_sq, int dim)
+kd_nearest(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq, int dim)
 {
     struct kdNode *nearer, *further, *nearest = NULL, *tmp, *tmp_nearest;
-    float dist_sq, tmp_dist_sq, dx;
+    kdata_t dist_sq, tmp_dist_sq, dx;
 
     if (!node)
         return NULL;
@@ -271,8 +267,8 @@ kd_nearest(struct kdNode *node, float *p, float *max_dist_sq, int dim)
     if (!further)
         return nearest;
 
-    dx = kd_min(fabs(p[node->split] - further->min[node->split]),
-                fabs(p[node->split] - further->max[node->split]));
+    dx = kd_min(KDATA_ABS(p[node->split] - further->min[node->split]),
+                KDATA_ABS(p[node->split] - further->max[node->split]));
     if (*max_dist_sq > kd_sqr(dx)) {
         /*
          * some part of the further hyper-rectangle is in the search
@@ -318,8 +314,8 @@ kd_nearest(struct kdNode *node, float *p, float *max_dist_sq, int dim)
  * in case of problems.
  */
 struct pqueue *
-kd_qnearest(struct kdNode *node, float *p,
-            float *max_dist_sq, unsigned int q, int dim)
+kd_qnearest(struct kdNode *node, kdata_t *p,
+            kdata_t *max_dist_sq, unsigned int q, int dim)
 {
     struct pqueue *res;
     uint32_t i;
@@ -348,11 +344,11 @@ kd_qnearest(struct kdNode *node, float *p,
  */
 // Uwe Schulzweida: extract kd_check_dist() from kd_doQnearest()
 static int
-kd_check_dist(struct kdNode *node, float *p,
-              float *max_dist_sq, unsigned int q, int dim, struct pqueue *res)
+kd_check_dist(struct kdNode *node, kdata_t *p,
+              kdata_t *max_dist_sq, unsigned int q, int dim, struct pqueue *res)
 {
     struct resItem *point, *item;
-    float dist_sq;
+    kdata_t dist_sq;
 
     dist_sq = kd_dist_sq(node->location, p, dim);
     if (dist_sq < *max_dist_sq && kd_isleaf(node)) {
@@ -395,11 +391,11 @@ kd_check_dist(struct kdNode *node, float *p,
 }
 
 int
-kd_doQnearest(struct kdNode *node, float *p,
-              float *max_dist_sq, unsigned int q, int dim, struct pqueue *res)
+kd_doQnearest(struct kdNode *node, kdata_t *p,
+              kdata_t *max_dist_sq, unsigned int q, int dim, struct pqueue *res)
 {
     struct kdNode *nearer, *further;
-    float dx;
+    kdata_t dx;
 
     if (!node) return 1;
 
@@ -416,8 +412,8 @@ kd_doQnearest(struct kdNode *node, float *p,
 
     if (!further) return 1;
 
-    dx = kd_min(fabs(p[node->split] - further->min[node->split]),
-                fabs(p[node->split] - further->max[node->split]));
+    dx = kd_min(KDATA_ABS(p[node->split] - further->min[node->split]),
+                KDATA_ABS(p[node->split] - further->max[node->split]));
     if (*max_dist_sq > kd_sqr(dx)) {
         /*
          * some part of the further hyper-rectangle is in the search
@@ -448,7 +444,7 @@ kd_doQnearest(struct kdNode *node, float *p,
  * NULL in case of problems.
  */
 struct pqueue *
-kd_range(struct kdNode *node, float *p, float *max_dist_sq,
+kd_range(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
          int dim, int ordered)
 {
     struct pqueue *res;
@@ -470,13 +466,13 @@ kd_range(struct kdNode *node, float *p, float *max_dist_sq,
 
 /* This is the range search. Returns 1 if okay, 0 in case of problems */
 int
-kd_doRange(struct kdNode *node, float *p, float *max_dist_sq,
+kd_doRange(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
            int dim, struct pqueue *res, int ordered)
 {
 
     struct kdNode *nearer, *further;
     struct resItem *point;
-    float dist_sq, dx;
+    kdata_t dist_sq, dx;
 
     if (!node)
         return 1;
@@ -504,8 +500,8 @@ kd_doRange(struct kdNode *node, float *p, float *max_dist_sq,
     if (!further)
         return 1;
 
-    dx = kd_min(fabs(p[node->split] - further->min[node->split]),
-                fabs(p[node->split] - further->max[node->split]));
+    dx = kd_min(KDATA_ABS(p[node->split] - further->min[node->split]),
+                KDATA_ABS(p[node->split] - further->max[node->split]));
     if (*max_dist_sq > kd_sqr(dx)) {
         /*
          * some part of the further hyper-rectangle is in the search
diff --git a/src/kdtreelib/kdtree_common.c b/src/kdtreelib/kdtree_common.c
index 25c2927..5c1317e 100644
--- a/src/kdtreelib/kdtree_common.c
+++ b/src/kdtreelib/kdtree_common.c
@@ -27,10 +27,10 @@ kd_malloc(size_t size, const char *msg)
     return ptr;
 }
 
-float
-kd_sqr(float x)
+kdata_t
+kd_sqr(kdata_t x)
 {
-    return x == 0.0 ? 0.0 : x * x;
+    return x == 0 ? 0 : x * x;
 }
 
 int
@@ -93,15 +93,10 @@ _compPoints0(const void *p1, const void *p2)
     struct kd_point *a = (struct kd_point *) p1;
     struct kd_point *b = (struct kd_point *) p2;
 
-    if      (a->point[0] > b->point[0]) return  1;
-    else if (a->point[0] < b->point[0]) return -1;
-    else
-      {
-        if      ( a->index > b->index ) return  1;
-        else if ( a->index < b->index ) return -1;
+    int ret = (a->point[0] > b->point[0]) ? 1 : (a->point[0] < b->point[0]) ? -1 : 0;
+    if ( ret == 0 ) ret = (a->index > b->index) ? 1 : (a->index < b->index) ? -1 : 0;
 
-        return 0;
-      }
+    return ret;
 }
 
 static int
@@ -110,15 +105,10 @@ _compPoints1(const void *p1, const void *p2)
     struct kd_point *a = (struct kd_point *) p1;
     struct kd_point *b = (struct kd_point *) p2;
 
-    if      (a->point[1] > b->point[1]) return  1;
-    else if (a->point[1] < b->point[1]) return -1;
-    else
-      {
-        if      ( a->index > b->index ) return  1;
-        else if ( a->index < b->index ) return -1;
+    int ret = (a->point[1] > b->point[1]) ? 1 : (a->point[1] < b->point[1]) ? -1 : 0;
+    if ( ret == 0 ) ret = (a->index > b->index) ? 1 : (a->index < b->index) ? -1 : 0;
 
-        return 0;
-      }
+    return ret;
 }
 
 static int
@@ -127,15 +117,10 @@ _compPoints2(const void *p1, const void *p2)
     struct kd_point *a = (struct kd_point *) p1;
     struct kd_point *b = (struct kd_point *) p2;
 
-    if      (a->point[2] > b->point[2]) return  1;
-    else if (a->point[2] < b->point[2]) return -1;
-    else
-      {
-        if      ( a->index > b->index ) return  1;
-        else if ( a->index < b->index ) return -1;
+    int ret = (a->point[2] > b->point[2]) ? 1 : (a->point[2] < b->point[2]) ? -1 : 0;
+    if ( ret == 0 ) ret = (a->index > b->index) ? 1 : (a->index < b->index) ? -1 : 0;
 
-        return 0;
-      }
+    return ret;
 }
 
 void *
@@ -143,11 +128,11 @@ kd_doBuildTree(void *threadarg)
 {
     int sortaxis;
     unsigned long pivot;
-    float tmpMinLeft[KD_MAX_DIM], tmpMaxLeft[KD_MAX_DIM], tmpMinRight[KD_MAX_DIM], tmpMaxRight[KD_MAX_DIM];
+    kdata_t tmpMinLeft[KD_MAX_DIM], tmpMaxLeft[KD_MAX_DIM], tmpMinRight[KD_MAX_DIM], tmpMaxRight[KD_MAX_DIM];
     struct kdNode *node;
     struct kd_point *points;
     unsigned long nPoints;
-    float *min, *max;
+    kdata_t *min, *max;
     int depth, dim, max_threads;
     pthread_t threads[2];
     pthread_attr_t attr;
@@ -189,8 +174,8 @@ kd_doBuildTree(void *threadarg)
     if ((node = kd_allocNode(points, pivot, min, max, sortaxis, dim)) == NULL)
         return NULL;
 
-    memcpy(tmpMinLeft, min, dim * sizeof(float));
-    memcpy(tmpMaxLeft, max, dim * sizeof(float));
+    memcpy(tmpMinLeft, min, dim * sizeof(kdata_t));
+    memcpy(tmpMaxLeft, max, dim * sizeof(kdata_t));
     tmpMaxLeft[sortaxis] = node->location[sortaxis];
     argleft =
         kd_buildArg(points, pivot, tmpMinLeft, tmpMaxLeft,
@@ -210,8 +195,8 @@ kd_doBuildTree(void *threadarg)
         }
     }
 
-    memcpy(tmpMinRight, min, dim * sizeof(float));
-    memcpy(tmpMaxRight, max, dim * sizeof(float));
+    memcpy(tmpMinRight, min, dim * sizeof(kdata_t));
+    memcpy(tmpMaxRight, max, dim * sizeof(kdata_t));
     tmpMinRight[sortaxis] = node->location[sortaxis];
     argright = kd_buildArg(&points[pivot], nPoints - pivot,
                            tmpMinRight, tmpMaxRight, depth + 1,
@@ -255,7 +240,7 @@ kd_freeNode(kdNode *node)
 struct kd_thread_data *
 kd_buildArg(struct kd_point *points,
             unsigned long nPoints,
-            float *min, float *max,
+            kdata_t *min, kdata_t *max,
             int depth, int max_threads, int dim)
 {
     struct kd_thread_data *d;
@@ -264,8 +249,8 @@ kd_buildArg(struct kd_point *points,
         return NULL;
     d->points = points;
     d->nPoints = nPoints;
-    memcpy(d->min, min, dim*sizeof(float));
-    memcpy(d->max, max, dim*sizeof(float));
+    memcpy(d->min, min, dim*sizeof(kdata_t));
+    memcpy(d->max, max, dim*sizeof(kdata_t));
     d->depth = depth;
     d->max_threads = max_threads;
     d->dim = dim;
@@ -275,16 +260,16 @@ kd_buildArg(struct kd_point *points,
 
 struct kdNode *
 kd_allocNode(struct kd_point *points, unsigned long pivot,
-             float *min, float *max, int axis, int dim)
+             kdata_t *min, kdata_t *max, int axis, int dim)
 {
     struct kdNode *node;
 
     if ((node = (kdNode *)kd_malloc(sizeof(kdNode), "kd_allocNode (node): ")) == NULL)
         return NULL;
     node->split = axis;
-    memcpy(node->location, points[pivot].point, dim * sizeof(float));
-    memcpy(node->min, min, dim * sizeof(float));
-    memcpy(node->max, max, dim * sizeof(float));
+    memcpy(node->location, points[pivot].point, dim * sizeof(kdata_t));
+    memcpy(node->min, min, dim * sizeof(kdata_t));
+    memcpy(node->max, max, dim * sizeof(kdata_t));
     node->left = node->right = NULL;
     node->index = 0;
     return node;
diff --git a/src/kdtreelib/kdtree_spherical.c b/src/kdtreelib/kdtree_spherical.c
index 511790b..ff41230 100644
--- a/src/kdtreelib/kdtree_spherical.c
+++ b/src/kdtreelib/kdtree_spherical.c
@@ -11,11 +11,11 @@
    general utility functions 
 
    ********************************************************************* */
-inline float
-kd_sph_dist_sq(float *x, float *y)
+inline kdata_t
+kd_sph_dist_sq(kdata_t *x, kdata_t *y)
 {
-    float ds;
-    /*float arg;*/
+    kdata_t ds;
+    /*kdata_t arg;*/
 
     if (!x || !y)
         return -1;
@@ -29,10 +29,10 @@ kd_sph_dist_sq(float *x, float *y)
     return kd_sqr(ds);
 }
 
-inline float
-kd_sph_dist(float *x, float *y)
+inline kdata_t
+kd_sph_dist(kdata_t *x, kdata_t *y)
 {
-    float ds;
+    kdata_t ds;
 
     if (!x || !y)
         return -1;
@@ -42,10 +42,10 @@ kd_sph_dist(float *x, float *y)
     return ds;
 }
 
-float
-kd_sph_bearing(float *p1, float *p2)
+kdata_t
+kd_sph_bearing(kdata_t *p1, kdata_t *p2)
 {
-    float x, y;
+    kdata_t x, y;
     
     x = cos(p1[1]) * sin(p2[1]) - sin(p1[1]) * cos(p2[1]) * cos(p2[0] - p1[0]);
     y = sin(p2[0] - p1[0]) * cos(p2[1]);
@@ -62,10 +62,10 @@ kd_sph_bearing(float *p1, float *p2)
  *
  * \return distance of p3 from the great circle connecting p1 and p2. 
  */
-float 
-kd_sph_xtd(float *p1, float *p2, float *p3)
+kdata_t 
+kd_sph_xtd(kdata_t *p1, kdata_t *p2, kdata_t *p3)
 {
-    float d13, theta13, theta12;
+    kdata_t d13, theta13, theta12;
     
     d13 = kd_sph_dist(p1, p3);
     theta13 = kd_sph_bearing(p1, p3);
@@ -74,12 +74,12 @@ kd_sph_xtd(float *p1, float *p2, float *p3)
 }
 
 
-float
-kd_sph_orth_dist(float *p1, float *p2, int split)
+kdata_t
+kd_sph_orth_dist(kdata_t *p1, kdata_t *p2, int split)
 {
 
-    float ra2, dec2;
-    float dx;
+    kdata_t ra2, dec2;
+    kdata_t dx;
 
     if (split == 1) {
         ra2 = p1[0];
@@ -129,7 +129,7 @@ kd_sph_orth_dist(float *p1, float *p2, int split)
  */
 struct kdNode *
 kd_sph_buildTree(struct kd_point *points, unsigned long nPoints,
-                 float *min, float *max, int max_threads)
+                 kdata_t *min, kdata_t *max, int max_threads)
 {
     struct kd_thread_data *my_data;
     struct kdNode *tree;
@@ -154,7 +154,7 @@ kd_sph_buildTree(struct kd_point *points, unsigned long nPoints,
 /* Returns 1 if node is a point in the hyperrectangle defined by
    minimum and maximum vectors min and max. */
 int
-kd_sph_isPointInRect(struct kdNode *node, float *min, float *max)
+kd_sph_isPointInRect(struct kdNode *node, kdata_t *min, kdata_t *max)
 {
     if (node == NULL)
         return 0;
@@ -178,7 +178,7 @@ kd_sph_isPointInRect(struct kdNode *node, float *min, float *max)
    the HR described by the minimum and maximum vectors min and
    max. Returns 0 otherwise. */
 int
-kd_sph_isRectInRect(struct kdNode *node, float *min, float *max)
+kd_sph_isRectInRect(struct kdNode *node, kdata_t *min, kdata_t *max)
 {
     if (node == NULL)
         return 0;
@@ -242,7 +242,7 @@ kd_sph_isRectInRect(struct kdNode *node, float *min, float *max)
    by the minimum and maximum vectors min and max. Returns 0
    otherwise. */
 int
-kd_sph_rectOverlapsRect(struct kdNode *node, float *min, float *max)
+kd_sph_rectOverlapsRect(struct kdNode *node, kdata_t *min, kdata_t *max)
 {
     if (node == NULL)
         return 0;
@@ -274,7 +274,7 @@ kd_sph_rectOverlapsRect(struct kdNode *node, float *min, float *max)
  * Rectangle must not cross the meridian!
 */
 struct pqueue *
-kd_sph_ortRangeSearch(struct kdNode *node, float *min, float *max)
+kd_sph_ortRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max)
 {
     struct pqueue *res;
     uint32_t i;
@@ -296,7 +296,7 @@ kd_sph_ortRangeSearch(struct kdNode *node, float *min, float *max)
 /* This is the orthogonal range search. Returns 1 if okay, 0 in case
    of problems. */
 int
-kd_sph_doOrtRangeSearch(struct kdNode *node, float *min, float *max,
+kd_sph_doOrtRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max,
                         struct pqueue *res)
 {
 
@@ -342,11 +342,11 @@ kd_sph_doOrtRangeSearch(struct kdNode *node, float *min, float *max,
  * neigbor.
  */
 struct kdNode *
-kd_sph_nearest(struct kdNode *node, float *p, float *max_dist_sq)
+kd_sph_nearest(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq)
 {
     struct kdNode *nearer, *further, *nearest, *tmp, *tmp_nearest;
-    float dist_sq, tmp_dist_sq, dx;
-    float p1[2], p2[2];
+    kdata_t dist_sq, tmp_dist_sq, dx;
+    kdata_t p1[2], p2[2];
 
     if (!node)
         return NULL;
@@ -431,8 +431,8 @@ kd_sph_nearest(struct kdNode *node, float *p, float *max_dist_sq)
  * in case of problems.
  */
 struct pqueue *
-kd_sph_qnearest(struct kdNode *node, float *p,
-                float *max_dist_sq, unsigned int q)
+kd_sph_qnearest(struct kdNode *node, kdata_t *p,
+                kdata_t *max_dist_sq, unsigned int q)
 {
     struct pqueue *res;
     uint32_t i;
@@ -460,13 +460,13 @@ kd_sph_qnearest(struct kdNode *node, float *p,
  * return 1 if okay, zero in case of problems
  */
 int
-kd_sph_doQnearest(struct kdNode *node, float *p, float *max_dist_sq,
+kd_sph_doQnearest(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
                   unsigned int q, struct pqueue *res)
 {
     struct kdNode *nearer, *further;
     struct resItem *point, *item;
-    float dist_sq, dx;
-    float p1[2], p2[2];
+    kdata_t dist_sq, dx;
+    kdata_t p1[2], p2[2];
 
     if (!node)
         return 1;
@@ -585,7 +585,7 @@ kd_sph_doQnearest(struct kdNode *node, float *p, float *max_dist_sq,
  * NULL in case of problems.
  */
 struct pqueue *
-kd_sph_range(struct kdNode *node, float *p, float *max_dist_sq, int ordered)
+kd_sph_range(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq, int ordered)
 {
     struct pqueue *res;
     uint32_t i;
@@ -606,14 +606,14 @@ kd_sph_range(struct kdNode *node, float *p, float *max_dist_sq, int ordered)
 
 /* This is the range search. Returns 1 if okay, 0 in case of problems */
 int
-kd_sph_doRange(struct kdNode *node, float *p, float *max_dist_sq,
+kd_sph_doRange(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
                struct pqueue *res, int ordered)
 {
 
     struct kdNode *nearer, *further;
     struct resItem *point;
-    float dist_sq, dx;
-    float p1[2], p2[2];
+    kdata_t dist_sq, dx;
+    kdata_t p1[2], p2[2];
 
     if (!node)
         return 1;
diff --git a/src/kvlist.c b/src/kvlist.c
index 0315c14..f6e5e4a 100644
--- a/src/kvlist.c
+++ b/src/kvlist.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/kvlist.h b/src/kvlist.h
index 3d0ca33..53d8ecd 100644
--- a/src/kvlist.h
+++ b/src/kvlist.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/list.c b/src/list.c
index 3158d76..607d7aa 100644
--- a/src/list.c
+++ b/src/list.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/list.h b/src/list.h
index 49a9fe2..e42a55c 100644
--- a/src/list.h
+++ b/src/list.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/magics_template_parser.c b/src/magics_template_parser.c
index dc4c23e..63759a5 100644
--- a/src/magics_template_parser.c
+++ b/src/magics_template_parser.c
@@ -2,25 +2,34 @@
 #  include "config.h" /* HAVE_LIBMAGICS */
 #endif
 
+#include "cdo_int.h"
 #include "magics_template_parser.h"
 #include "StringUtilities.h"
 
+#if defined(HAVE_LIBXML2)
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#endif
+
+#if defined(HAVE_LIBMAGICS)
 #include "magics_api.h"
+#endif
 
-#define DBG 0 
 
+#define DBG 0 
 
-extern xmlNode *magics_node;
+extern void *magics_node;
 
 
 /* Recursive function that sets the Magics parameters from the XML structure */
 
-int magics_template_parser( xmlNode *a_node ) 
-
+int magics_template_parser( void *node ) 
 {
+#if defined(HAVE_LIBXML2)
+    xmlNode *a_node = (xmlNode*) node;
     int param_set_flag;
     xmlNode *cur_node = NULL;
-    xmlChar    *param_name,*param_type,*param_value,*value;
+    const char *param_name,*param_type,*param_value;
 
     if( a_node == NULL )
         return 0;
@@ -29,21 +38,20 @@ int magics_template_parser( xmlNode *a_node )
     fprintf( stdout,"Parsing the magics Node \n");
 #endif
 
-    if( !strcmp( a_node->name, "magics" ) )
+    if( !strcmp( (const char*)a_node->name, "magics" ) )
     {
- 	value = xmlGetProp( a_node, "version" );
+      const char *value = (const char*) xmlGetProp( a_node, (const xmlChar *)"version" );
 
-        if( value )
+      if( value )
         {
-	    	if( DBG )
-			printf( "Version %s \n", value ); 
+          if( DBG )
+            printf( "Version %s \n", value ); 
 
-		if( atof( value ) > 3.0f ) 
-		{
-			return 1;
-		}
+          if( atof( value ) > 3.0f ) 
+            {
+              return 1;
+            }
         }
-
     }
 
 
@@ -73,33 +81,40 @@ int magics_template_parser( xmlNode *a_node )
 	    else
 	    {
 		
-		param_name = xmlGetProp( cur_node,"parameter");
-		param_type = xmlGetProp(cur_node,"type");
-		param_value = xmlGetProp(cur_node,"value");
+              param_name = (const char *)xmlGetProp(cur_node, (const xmlChar *)"parameter");
+              param_type = (const char *)xmlGetProp(cur_node, (const xmlChar *)"type");
+              param_value = (const char *)xmlGetProp(cur_node, (const xmlChar *)"value");
 #if 0
     		printf( "\t\tAttr name: %s Type: %s Value: %s \n", param_name,param_type,param_value);
 #endif
 		
-    		param_set_flag = SetMagicsParameterValue( param_name, param_type, param_value );
+    		param_set_flag = SetMagicsParameterValue(param_name, param_type, param_value );
 		
 		if( param_set_flag )
 			printf(" Error in Setting the Parameter %s\n",param_name );
 	    }
         }
     }
-    return 0;
+#else
+  
+  cdoAbort("XML2 support not compiled in!");
+  
+#endif
+
+  return 0;
 }
 
-int SetMagicsParameterValue( char *param_name, char *param_type, char *param_value )
 
+int SetMagicsParameterValue( const char *param_name, const char *param_type, const char *param_value )
 {
-	int i, ret_flag = 0;
+	int ret_flag = 0;
+#if defined(HAVE_LIBMAGICS)
+	int i;
 	int split_str_count = 0;
 	char **split_str = NULL;
-	char *sep_char = ",";
-	char *search_char = ";";
+	const char *sep_char = ",";
+	const char *search_char = ";";
 	double *float_param_list = NULL;
-	int *int_param_list = NULL;
 
 	if( param_name == NULL )
 	  {
@@ -194,14 +209,14 @@ int SetMagicsParameterValue( char *param_name, char *param_type, char *param_val
 		split_str_count = StringSplitWithSeperator( param_value, sep_char, &split_str );
 		if( split_str_count )
 		  {
-		    int_param_list = (double*) Malloc(sizeof( int ) * split_str_count );
-			for( i = 0; i < split_str_count; i++ )
-			{
-				int_param_list[i] = atoi( split_str[i] );			
-			}
-			mag_set1i( param_name, int_param_list, split_str_count );		
-			Free( int_param_list );
-			Free( split_str );
+		    int *int_param_list = (int*) Malloc(sizeof( int ) * split_str_count );
+                    for( i = 0; i < split_str_count; i++ )
+                      {
+                        int_param_list[i] = atoi( split_str[i] );			
+                      }
+                    mag_set1i( param_name, int_param_list, split_str_count );		
+                    Free( int_param_list );
+                    Free( split_str );
 		  }
 	  }
 
@@ -236,6 +251,7 @@ int SetMagicsParameterValue( char *param_name, char *param_type, char *param_val
 		ret_flag = 3;
 		fprintf(stderr, "Unknown Parameter Type\n" );
 	  }
-
+#endif
+        
 	return ret_flag;
 }
diff --git a/src/magics_template_parser.h b/src/magics_template_parser.h
index 01192b2..a87999b 100644
--- a/src/magics_template_parser.h
+++ b/src/magics_template_parser.h
@@ -1,15 +1,8 @@
 #ifndef MAGICS_TEMPLATE_PARSER_HH
 #define MAGICS_TEMPLATE_PARSER_HH
-#endif
-
-#include<stdio.h>
-#include<string.h>
-#include<stdlib.h>
-#include<locale.h>
 
-#include<libxml/parser.h>
-#include<libxml/tree.h>
+int magics_template_parser( void *node );
 
-int magics_template_parser( xmlNode * a_node );
+int SetMagicsParameterValue( const char *param_name, const char *param_type, const char *param_value );
 
-int SetMagicsParameterValue( char *param_name, char *param_type, char *param_value );
+#endif
diff --git a/src/modules.c b/src/modules.c
index aaa413f..861bcf5 100644
--- a/src/modules.c
+++ b/src/modules.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -26,15 +26,16 @@
 #include "error.h"
 
 
-#define  MAX_MOD_OPERATORS  128         /* maximum number of operators for a module */
+#define  MAX_MOD_OPERATORS  128               // maximum number of operators for a module
 
 typedef struct {
-  void  *(*func)(void *);                     /* Module                   */
-  const char **help;                          /* Help                     */
-  const char  *operators[MAX_MOD_OPERATORS];  /* Operator names           */
-  short  number;                              /* Allowed number type      */
-  short  streamInCnt;                         /* Number of input streams  */
-  short  streamOutCnt;                        /* Number of output streams */
+  void  *(*func)(void *);                     // Module
+  const char **help;                          // Help
+  const char  *operators[MAX_MOD_OPERATORS];  // Operator names
+  short  mode;                                // Module mode: 0:intern 1:extern
+  short  number;                              // Allowed number type
+  short  streamInCnt;                         // Number of input streams
+  short  streamOutCnt;                        // Number of output streams
 }
 modules_t;
 
@@ -128,6 +129,7 @@ void *Nmltest(void *argument);
 void *Output(void *argument);
 void *Outputgmt(void *argument);
 void *Pack(void *argument);
+void *Pardup(void *argument);
 void *Pinfo(void *argument);
 void *Pressure(void *argument);
 void *Regres(void *argument);
@@ -180,6 +182,7 @@ void *Test(void *argument);
 void *Test2(void *argument);
 void *Testdata(void *argument);
 void *Tests(void *argument);
+void *Timedt(void *argument);
 void *Timsort(void *argument);
 void *Timcount(void *argument);
 void *Timpctl(void *argument);
@@ -195,7 +198,6 @@ void *Transpose(void *argument);
 void *Trend(void *argument);
 void *Trms(void *argument);
 void *Tstepcount(void *argument);
-void *Vardup(void *argument);
 void *Vargen(void *argument);
 void *Varrms(void *argument);
 void *Vertintml(void *argument);
@@ -203,6 +205,7 @@ void *Vertintap(void *argument);
 void *Vertstat(void *argument);
 void *Vertcum(void *argument);
 void *Vertwind(void *argument);
+void *Verifygrid(void *argument);
 void *Wind(void *argument);
 void *Writegrid(void *argument);
 void *Writerandom(void *argument);
@@ -267,15 +270,13 @@ void *Hurr(void *argument);
 //void *Hi(void *argument);
 void *Wct(void *argument);
 
-#if defined(HAVE_LIBMAGICS) && defined(HAVE_LIBXML2)
 void *Magplot(void *argument);
 void *Magvector(void *argument);
 void *Maggraph(void *argument);
-#endif
 
 
 #define  AdisitOperators        {"adisit", "adipot"}
-#define  AfterburnerOperators   {"afterburner", "after"}
+#define  AfterburnerOperators   {"after"}
 #define  ArithOperators         {"add",  "sub",  "mul",  "div", "min", "max", "atan2"}
 #define  ArithcOperators        {"addc", "subc", "mulc", "divc", "mod"}
 #define  ArithdaysOperators     {"muldpm", "divdpm", "muldpy", "divdpy", "muldoy"}
@@ -309,8 +310,8 @@ void *Maggraph(void *argument);
 #define  EnlargeOperators       {"enlarge"}
 #define  EnlargegridOperators   {"enlargegrid"}
 #define  EnsstatOperators       {"ensmin", "ensmax", "enssum", "ensmean", "ensavg", "ensvar", "ensvar1", "ensstd", "ensstd1", "enspctl"}
-#define  Ensstat3Operators      {"ensrkhist_space","ensrkhist_time","ensroc"}
-#define  EnsvalOperators        {"enscrps","ensbrs"}
+#define  Ensstat3Operators      {"ensrkhistspace", "ensrkhisttime", "ensroc"}
+#define  EnsvalOperators        {"enscrps", "ensbrs"}
 #define  EofcoeffOperators      {"eofcoeff"}
 #define  Eofcoeff3dOperators    {"eofcoeff3d"}
 #define  EOFsOperators          {"eof", "eofspatial", "eoftime"}
@@ -334,7 +335,7 @@ void *Maggraph(void *argument);
 #define  HarmonicOperators      {"harmonic"}
 #define  HistogramOperators     {"histcount", "histsum", "histmean", "histfreq"}
 #define  ImportamsrOperators    {"import_amsr"}
-#define  ImportbinaryOperators  {"import_binary", "import_grads"}
+#define  ImportbinaryOperators  {"import_binary"}
 #define  ImportcmsafOperators   {"import_cmsaf"}
 #define  ImportobsOperators     {"import_obs"}
 #define  InfoOperators          {"info", "infop", "infon", "infoc", "map"}
@@ -368,9 +369,10 @@ void *Maggraph(void *argument);
 #define  OutputOperators        {"output", "outputint", "outputsrv", "outputext", "outputf", "outputts", \
                                  "outputfld", "outputarr", "outputxyz"}
 #define  OutputtabOperators     {"outputtab"}
-#define  OutputgmtOperators     {"gridverify", "outputcenter", "outputcenter2", "outputcentercpt", "outputbounds", \
+#define  OutputgmtOperators     {"gmtxyz", "gmtcells", "outputcenter2", "outputcentercpt", \
                                  "outputboundscpt", "outputvector", "outputtri", "outputvrml"}
 #define  PackOperators          {"pack"}
+#define  PardupOperators        {"pardup", "parmul"}
 #define  PinfoOperators         {"pinfo", "pinfov"}
 #define  PressureOperators      {"pressure_fl", "pressure_hl", "deltap"}
 #define  RegresOperators        {"regres"}
@@ -400,7 +402,7 @@ void *Maggraph(void *argument);
                                  "selzaxis", "selzaxisname", "seltabnum", "delparam", "delcode", "delname", "selltype"}
 #define  SeloperatorOperators   {"seloperator"}
 #define  SelrecOperators        {"selrec"}
-#define  SeltimeOperators       {"seltimestep", "selyear", "selseas", "selmon", "selday", "selhour", "seldate", \
+#define  SeltimeOperators       {"seltimestep", "selyear", "selseason", "selmonth", "selday", "selhour", "seldate", \
                                  "seltime", "selsmon"}
 #define  SetOperators           {"setcode", "setparam", "setname", "setunit", "setlevel", "setltype", "settabnum"}
 #define  SetboxOperators        {"setclonlatbox", "setcindexbox"}
@@ -438,6 +440,7 @@ void *Maggraph(void *argument);
 #define  Test2Operators         {"test2"}
 #define  TestdataOperators      {"testdata"}
 #define  TestsOperators         {"normal", "studentt", "chisquare", "beta", "fisher"}
+#define  TimedtOperators        {"timedt"}
 #define  TimsortOperators       {"timsort"}
 #define  TimcountOperators      {"timcount"}
 #define    YearcountOperators   {"yearcount"}
@@ -468,7 +471,6 @@ void *Maggraph(void *argument);
 #define  TrendOperators         {"trend"}
 #define  TrmsOperators          {"trms"}
 #define  TstepcountOperators    {"tstepcount"}
-#define  VardupOperators        {"pardup", "parmul"}
 #define  VargenOperators        {"random", "const", "sincos", "coshill", "for", "topo", "temp", "mask", "stdatm"}
 #define  VarrmsOperators        {"varrms"}
 #define  VertintmlOperators     {"ml2pl", "ml2hl", "ml2plx", "ml2hlx", "ml2pl_lp", "ml2hl_lp", "ml2plx_lp", "ml2hlx_lp"}
@@ -476,6 +478,7 @@ void *Maggraph(void *argument);
 #define  VertstatOperators      {"vertmin", "vertmax", "vertsum", "vertint", "vertmean", "vertavg", "vertstd", "vertstd1", "vertvar", "vertvar1"}
 #define  VertcumOperators       {"vertcum", "vertcumhl"}
 #define  VertwindOperators      {"vertwind"}
+#define  VerifygridOperators    {"verifygrid", "verifygridtest"}
 #define  WindOperators          {"uv2dv", "uv2dvl", "dv2uv", "dv2uvl", "dv2ps"}
 #define  WritegridOperators     {"writegrid"}
 #define  WriterandomOperators   {"writerandom"}
@@ -546,327 +549,329 @@ void *Maggraph(void *argument);
 #define  HiOperators            {"hi"}
 #define  WctOperators           {"wct"}
 
-#if defined(HAVE_LIBMAGICS) && defined(HAVE_LIBXML2)
 #define  MagplotOperators       {"contour", "shaded", "grfill"}
-#define  MagvectorOperators     {"vector", "stream"}
+#define  MagvectorOperators     {"vector"}
 #define  MaggraphOperators      {"graph"}
-#endif
 
 static modules_t Modules[] =
 {
-  /* stream out -1 means usage of obase */
+  // stream in  -1 means: unlimited number of input streams
+  // stream out -1 means: usage of obase
   /*
-    function        help function      operator names          number     num streams
-                                                               type       in  out
+    function        help function      operator names          mode number     num streams
+                                                                    type       in  out
   */
-  { Adisit,         AdisitHelp,        AdisitOperators,        CDI_REAL,  1,  1 },
-  { Afterburner,    AfterburnerHelp,   AfterburnerOperators,   CDI_REAL, -1,  1 },
-  { Arith,          ArithHelp,         ArithOperators,         CDI_REAL,  2,  1 },
-  { Arithc,         ArithcHelp,        ArithcOperators,        CDI_REAL,  1,  1 },
-  { Arithdays,      ArithdaysHelp,     ArithdaysOperators,     CDI_REAL,  1,  1 },
-  { Arithlat,       NULL,              ArithlatOperators,      CDI_REAL,  1,  1 },
-  { Cat,            CopyHelp,          CatOperators,           CDI_REAL, -1,  1 },
-  { CDItest,        NULL,              CDItestOperators,       CDI_REAL,  1,  1 },
-  { CDIread,        NULL,              CDIreadOperators,       CDI_REAL,  1,  0 },
-  { CDIwrite,       NULL,              CDIwriteOperators,      CDI_REAL,  0,  1 },
-  { Change,         ChangeHelp,        ChangeOperators,        CDI_REAL,  1,  1 },
-  { Change_e5slm,   NULL,              Change_e5slmOperators,  CDI_REAL,  1,  1 },
-  { Cloudlayer,     NULL,              CloudlayerOperators,    CDI_REAL,  1,  1 },
-  { CMOR,           NULL,              CMOROperators,          CDI_REAL,  1,  0 },
-  { Collgrid,       CollgridHelp,      CollgridOperators,      CDI_REAL, -1,  1 },
-  { Command,        NULL,              CommandOperators,       CDI_REAL,  1,  0 },
-  { Comp,           CompHelp,          CompOperators,          CDI_REAL,  2,  1 },
-  { Compc,          CompcHelp,         CompcOperators,         CDI_REAL,  1,  1 },
-  { Complextorect,  NULL,              ComplextorectOperators, CDI_COMP,  1,  2 },
-  { Cond,           CondHelp,          CondOperators,          CDI_REAL,  2,  1 },
-  { Cond2,          Cond2Help,         Cond2Operators,         CDI_REAL,  3,  1 },
-  { Condc,          CondcHelp,         CondcOperators,         CDI_REAL,  1,  1 },
-  { Consecstat,     ConsecstatHelp,    ConsecstatOperators,    CDI_REAL,  1,  1 },
-  { Copy,           CopyHelp,          CopyOperators,          CDI_REAL, -1,  1 },
-  { Deltime,        NULL,              DeltimeOperators,       CDI_REAL,  1,  1 },
-  { Derivepar,      DeriveparHelp,     DeriveparOperators,     CDI_REAL,  1,  1 },
-  { Detrend,        DetrendHelp,       DetrendOperators,       CDI_REAL,  1,  1 },
-  { Diff,           DiffHelp,          DiffOperators,          CDI_REAL,  2,  0 },
-  { Distgrid,       DistgridHelp,      DistgridOperators,      CDI_REAL,  1,  1 },
-  { Duplicate,      DuplicateHelp,     DuplicateOperators,     CDI_REAL,  1,  1 },
-  { Echam5ini,      NULL,              Echam5iniOperators,     CDI_REAL,  1,  1 },
-  { Enlarge,        EnlargeHelp,       EnlargeOperators,       CDI_REAL,  1,  1 },
-  { Enlargegrid,    NULL,              EnlargegridOperators,   CDI_REAL,  1,  1 },
-  { Ensstat,        EnsstatHelp,       EnsstatOperators,       CDI_REAL, -1,  1 },
-  { Ensstat3,       Ensstat2Help,      Ensstat3Operators,      CDI_REAL, -1,  1 },
-  { Ensval,         EnsvalHelp,        EnsvalOperators,        CDI_REAL, -1,  1 },
-  { Eofcoeff,       EofcoeffHelp,      EofcoeffOperators,      CDI_REAL,  2, -1 },
-  { Eofcoeff3d,     EofcoeffHelp,      Eofcoeff3dOperators,    CDI_REAL,  2, -1 },
-  { EOFs,           EOFsHelp,          EOFsOperators,          CDI_REAL,  1,  2 },
-  { EOF3d,          EOFsHelp,          EOF3dOperators,         CDI_REAL,  1,  2 },
-  { Expr,           ExprHelp,          ExprOperators,          CDI_REAL,  1,  1 },
-  { FC,             NULL,              FCOperators,            CDI_REAL,  1,  1 },
-  { Filedes,        FiledesHelp,       FiledesOperators,       CDI_BOTH,  1,  0 },
-  { Fillmiss,       NULL,              FillmissOperators,      CDI_REAL,  1,  1 },
-  { Filter,         FilterHelp,        FilterOperators,        CDI_REAL,  1,  1 },
-  { Fldrms,         NULL,              FldrmsOperators,        CDI_REAL,  2,  1 },
-  { Fldstat,        FldstatHelp,       FldstatOperators,       CDI_REAL,  1,  1 },
-  { Fldstat2,       FldcorHelp,        FldcorOperators,        CDI_REAL,  2,  1 },
-  { Fldstat2,       FldcovarHelp,      FldcovarOperators,      CDI_REAL,  2,  1 },
-  { Fourier,        NULL,              FourierOperators,       CDI_COMP,  1,  1 },
-  { Gengrid,        NULL,              GengridOperators,       CDI_REAL,  2,  1 },
-  { Gradsdes,       GradsdesHelp,      GradsdesOperators,      CDI_REAL,  1,  0 },
-  { Gridboxstat,    GridboxstatHelp,   GridboxstatOperators,   CDI_REAL,  1,  1 },
-  { Gridcell,       GridcellHelp,      GridcellOperators,      CDI_REAL,  1,  1 },
-  { Gridsearch,     NULL,              GridsearchOperators,    CDI_REAL,  0,  0 },
-  { Harmonic,       NULL,              HarmonicOperators,      CDI_REAL,  1,  1 },
-  { Histogram,      HistogramHelp,     HistogramOperators,     CDI_REAL,  1,  1 },
-  { Importamsr,     ImportamsrHelp,    ImportamsrOperators,    CDI_REAL,  1,  1 },
-  { Importbinary,   ImportbinaryHelp,  ImportbinaryOperators,  CDI_REAL,  1,  1 },
-  { Importcmsaf,    ImportcmsafHelp,   ImportcmsafOperators,   CDI_REAL,  1,  1 },
-  { Importobs,      NULL,              ImportobsOperators,     CDI_REAL,  1,  1 },
-  { Info,           InfoHelp,          InfoOperators,          CDI_BOTH, -1,  0 },
-  { Input,          InputHelp,         InputOperators,         CDI_REAL,  0,  1 },
-  { Intgrid,        NULL,              IntgridOperators,       CDI_REAL,  1,  1 },
-  { Intgridtraj,    NULL,              IntgridtrajOperators,   CDI_REAL,  1,  1 },
-  { Intlevel,       IntlevelHelp,      IntlevelOperators,      CDI_REAL,  1,  1 },
-  { Intlevel3d,     Intlevel3dHelp,    Intlevel3dOperators,    CDI_REAL,  2,  1 },
-  { Inttime,        InttimeHelp,       InttimeOperators,       CDI_REAL,  1,  1 },
-  { Intntime,       InttimeHelp,       IntntimeOperators,      CDI_REAL,  1,  1 },
-  { Intyear,        IntyearHelp,       IntyearOperators,       CDI_REAL,  2, -1 },
-  { Invert,         InvertHelp,        InvertOperators,        CDI_REAL,  1,  1 },
-  { Invertlev,      InvertlevHelp,     InvertlevOperators,     CDI_REAL,  1,  1 },
-  { Isosurface,     NULL,              IsosurfaceOperators,    CDI_REAL,  1,  1 },
-  { Kvl,            NULL,              KvlOperators,           CDI_REAL,  0,  0 },
-  { Log,            NULL,              LogOperators,           CDI_REAL,  1,  0 },
-  { Maskbox,        MaskboxHelp,       MaskboxOperators,       CDI_REAL,  1,  1 },
-  { Maskbox,        MaskregionHelp,    MaskregionOperators,    CDI_REAL,  1,  1 },
-  { Mastrfu,        MastrfuHelp,       MastrfuOperators,       CDI_REAL,  1,  1 },
-  { Math,           MathHelp,          MathOperators,          CDI_BOTH,  1,  1 },
-  { Merge,          MergeHelp,         MergeOperators,         CDI_REAL, -1,  1 },
-  { Mergetime,      MergeHelp,         MergetimeOperators,     CDI_REAL, -1,  1 },
-  { Mergegrid,      MergegridHelp,     MergegridOperators,     CDI_REAL,  2,  1 },
-  { Merstat,        MerstatHelp,       MerstatOperators,       CDI_REAL,  1,  1 },
-  { Monarith,       MonarithHelp,      MonarithOperators,      CDI_REAL,  2,  1 },
-  { Mrotuv,         NULL,              MrotuvOperators,        CDI_REAL,  1,  2 },
-  { Mrotuvb,        NULL,              MrotuvbOperators,       CDI_REAL,  2,  1 },
-  { Ninfo,          NinfoHelp,         NinfoOperators,         CDI_BOTH,  1,  0 },
-  { Nmltest,        NULL,              NmltestOperators,       CDI_REAL,  0,  0 },
-  { Output,         OutputHelp,        OutputOperators,        CDI_REAL, -1,  0 },
-  { Output,         OutputtabHelp,     OutputtabOperators,     CDI_REAL, -1,  0 },
-  { Outputgmt,      NULL,              OutputgmtOperators,     CDI_REAL,  1,  0 },
-  { Pack,           NULL,              PackOperators,          CDI_REAL,  1,  1 },
-  { Pinfo,          NULL,              PinfoOperators,         CDI_REAL,  1,  1 },
-  { Pressure,       NULL,              PressureOperators,      CDI_REAL,  1,  1 },
-  { Regres,         RegresHelp,        RegresOperators,        CDI_REAL,  1,  1 },
-  { Remap,          RemapHelp,         RemapOperators,         CDI_REAL,  1,  1 },
-  { Remap,          RemapbilHelp,      RemapbilOperators,      CDI_REAL,  1,  1 },
-  { Remap,          RemapbicHelp,      RemapbicOperators,      CDI_REAL,  1,  1 },
-  { Remap,          RemapnnHelp,       RemapnnOperators,       CDI_REAL,  1,  1 },
-  { Remap,          RemapdisHelp,      RemapdisOperators,      CDI_REAL,  1,  1 },
-  { Remap,          RemapyconHelp,     RemapyconOperators,     CDI_REAL,  1,  1 },
-  { Remap,          RemapconHelp,      RemapconOperators,      CDI_REAL,  1,  1 },
-  { Remap,          Remapcon2Help,     Remapcon2Operators,     CDI_REAL,  1,  1 },
-  { Remap,          RemaplafHelp,      RemaplafOperators,      CDI_REAL,  1,  1 },
-  { Remap,          NULL,              RemapgridOperators,     CDI_REAL,  1,  1 },
-  { Remapeta,       RemapetaHelp,      RemapetaOperators,      CDI_REAL,  1,  1 },
-  { Replace,        ReplaceHelp,       ReplaceOperators,       CDI_REAL,  2,  1 },
-  { Replacevalues,  ReplacevaluesHelp, ReplacevaluesOperators, CDI_REAL,  1,  1 },
-  { Rhopot,         RhopotHelp,        RhopotOperators,        CDI_REAL,  1,  1 },
-  { Rotuv,          RotuvbHelp,        RotuvOperators,         CDI_REAL,  1,  1 },
-  { Runpctl,        RunpctlHelp,       RunpctlOperators,       CDI_REAL,  1,  1 },
-  { Runstat,        RunstatHelp,       RunstatOperators,       CDI_REAL,  1,  1 },
-  { Seascount,      NULL,              SeascountOperators,     CDI_BOTH,  1,  1 },
-  { Seaspctl,       SeaspctlHelp,      SeaspctlOperators,      CDI_REAL,  3,  1 },
-  { Seasstat,       SeasstatHelp,      SeasstatOperators,      CDI_REAL,  1,  1 },
-  { Selbox,         SelboxHelp,        SelboxOperators,        CDI_BOTH,  1,  1 },
-  { Select,         SelectHelp,        SelectOperators,        CDI_BOTH, -1,  1 },
-  { Selvar,         SelvarHelp,        SelvarOperators,        CDI_BOTH,  1,  1 },
-  { Selrec,         SelvarHelp,        SelrecOperators,        CDI_BOTH,  1,  1 },
-  { Seloperator,    NULL,              SeloperatorOperators,   CDI_REAL,  1,  1 },
-  { Seltime,        SeltimeHelp,       SeltimeOperators,       CDI_BOTH,  1,  1 },
-  { Set,            SetHelp,           SetOperators,           CDI_BOTH,  1,  1 },
-  { Setbox,         SetboxHelp,        SetboxOperators,        CDI_REAL,  1,  1 },
-  { Setgatt,        SetgattHelp,       SetgattOperators,       CDI_BOTH,  1,  1 },
-  { Setgrid,        SetgridHelp,       SetgridOperators,       CDI_BOTH,  1,  1 },
-  { Sethalo,        SethaloHelp,       SethaloOperators,       CDI_REAL,  1,  1 },
-  { Setmiss,        SetmissHelp,       SetmissOperators,       CDI_REAL,  1,  1 },
-  { Fillmiss,       SetmissHelp,       SetmisstonnOperators,   CDI_REAL,  1,  1 },
-  { Setpartab,      SetHelp,           Setpartab0Operators,    CDI_REAL,  1,  1 },
-  { Setpartab,      SetpartabHelp,     SetpartabOperators,     CDI_REAL,  1,  1 },
-  { Setrcaname,     NULL,              SetrcanameOperators,    CDI_REAL,  1,  1 },
-  { Settime,        SettimeHelp,       SettimeOperators,       CDI_BOTH,  1,  1 },
-  { Setzaxis,       SetzaxisHelp,      SetzaxisOperators,      CDI_BOTH,  1,  1 },
-  { Showinfo,       ShowinfoHelp,      ShowinfoOperators,      CDI_BOTH,  1,  0 },
-  { Sinfo,          SinfoHelp,         SinfoOperators,         CDI_BOTH, -1,  0 },
-  { Smooth9,        Smooth9Help,       Smooth9Operators,       CDI_REAL,  1,  1 },
-  { Sort,           NULL,              SortOperators,          CDI_REAL,  1,  1 },
-  { Sorttimestamp,  NULL,              SorttimestampOperators, CDI_REAL, -1,  1 },
-  { Specinfo,       NULL,              SpecinfoOperators,      CDI_REAL,  0,  0 },
-  { Spectral,       SpectralHelp,      SpectralOperators,      CDI_REAL,  1,  1 },
-  { Spectrum,       NULL,              SpectrumOperators,      CDI_REAL,  1,  1 },
-  { Split,          SplitHelp,         SplitOperators,         CDI_BOTH,  1, -1 },
-  { Splitrec,       SplitHelp,         SplitrecOperators,      CDI_BOTH,  1, -1 },
-  { Splitsel,       SplitselHelp,      SplitselOperators,      CDI_BOTH,  1, -1 },
-  { Splittime,      SplittimeHelp,     SplittimeOperators,     CDI_BOTH,  1, -1 },
-  { Splityear,      SplittimeHelp,     SplityearOperators,     CDI_BOTH,  1, -1 },
-  { SSOpar,         NULL,              SSOparOperators,        CDI_REAL,  1,  1 },
-  { Subtrend,       SubtrendHelp,      SubtrendOperators,      CDI_REAL,  3,  1 },
-  { Template1,      NULL,              Template1Operators,     CDI_REAL,  1,  1 },
-  { Tee,            NULL,              TeeOperators,           CDI_REAL,  2,  1 },
-  { Template2,      NULL,              Template2Operators,     CDI_REAL,  1,  1 },
-  { Test,           NULL,              TestOperators,          CDI_REAL,  1,  1 },
-  { Test2,          NULL,              Test2Operators,         CDI_REAL,  2,  1 },
-  { Testdata,       NULL,              TestdataOperators,      CDI_REAL,  1,  1 },
-  { Tests,          NULL,              TestsOperators,         CDI_REAL,  1,  1 },
-  { Timcount,       NULL,              TimcountOperators,      CDI_BOTH,  1,  1 },
-  { Timcount,       NULL,              YearcountOperators,     CDI_BOTH,  1,  1 },
-  { Timcount,       NULL,              MoncountOperators,      CDI_BOTH,  1,  1 },
-  { Timcount,       NULL,              DaycountOperators,      CDI_BOTH,  1,  1 },
-  { Timcount,       NULL,              HourcountOperators,     CDI_BOTH,  1,  1 },
-  { Timpctl,        TimpctlHelp,       TimpctlOperators,       CDI_REAL,  3,  1 },
-  { Timpctl,        YearpctlHelp,      YearpctlOperators,      CDI_REAL,  3,  1 },
-  { Timpctl,        MonpctlHelp,       MonpctlOperators,       CDI_REAL,  3,  1 },
-  { Timpctl,        DaypctlHelp,       DaypctlOperators,       CDI_REAL,  3,  1 },
-  { Timpctl,        HourpctlHelp,      HourpctlOperators,      CDI_REAL,  3,  1 },
-  { Timselpctl,     TimselpctlHelp,    TimselpctlOperators,    CDI_REAL,  3,  1 },
-  { Timsort,        TimsortHelp,       TimsortOperators,       CDI_REAL,  1,  1 },
-  { Timselstat,     TimselstatHelp,    TimselstatOperators,    CDI_REAL,  1,  1 },
-  { XTimstat,       NULL,              XTimstatOperators,      CDI_BOTH,  1,  1 },
-  { Timstat,        TimstatHelp,       TimstatOperators,       CDI_BOTH,  1,  1 },
-  { Timstat,        YearstatHelp,      YearstatOperators,      CDI_BOTH,  1,  1 },
-  { Timstat,        MonstatHelp,       MonstatOperators,       CDI_BOTH,  1,  1 },
-  { Timstat,        DaystatHelp,       DaystatOperators,       CDI_BOTH,  1,  1 },
-  { Timstat,        HourstatHelp,      HourstatOperators,      CDI_BOTH,  1,  1 },
-  { Timstat2,       TimcorHelp,        TimcorOperators,        CDI_REAL,  2,  1 },
-  { Timstat2,       TimcovarHelp,      TimcovarOperators,      CDI_REAL,  2,  1 },
-  { Timstat3,       NULL,              Timstat3Operators,      CDI_REAL,  2,  1 },
-  { Tinfo,          NULL,              TinfoOperators,         CDI_BOTH,  1,  0 },
-  { Tocomplex,      NULL,              TocomplexOperators,     CDI_REAL,  1,  1 },
-  { Transpose,      NULL,              TransposeOperators,     CDI_REAL,  1,  1 },
-  { Trend,          TrendHelp,         TrendOperators,         CDI_REAL,  1,  2 },
-  { Trms,           NULL,              TrmsOperators,          CDI_REAL,  2,  1 },
-  { Tstepcount,     NULL,              TstepcountOperators,    CDI_REAL,  1,  1 },
-  { Vardup,         NULL,              VardupOperators,        CDI_REAL,  1,  1 },
-  { Vargen,         VargenHelp,        VargenOperators,        CDI_REAL,  0,  1 },
-  { Varrms,         NULL,              VarrmsOperators,        CDI_REAL,  2,  1 },
-  { Vertintml,      VertintmlHelp,     VertintmlOperators,     CDI_REAL,  1,  1 },
-  { Vertintap,      VertintapHelp,     VertintapOperators,     CDI_REAL,  1,  1 },
-  { Vertstat,       VertstatHelp,      VertstatOperators,      CDI_REAL,  1,  1 },
-  { Vertcum,        NULL,              VertcumOperators,       CDI_REAL,  1,  1 },
-  { Vertwind,       NULL,              VertwindOperators,      CDI_REAL,  1,  1 },
-  { Wind,           WindHelp,          WindOperators,          CDI_REAL,  1,  1 },
-  { Writegrid,      NULL,              WritegridOperators,     CDI_REAL,  1,  1 },  /* no cdi output */
-  { Writerandom,    NULL,              WriterandomOperators,   CDI_REAL,  1,  1 },
-  { YAR,            NULL,              YAROperators,           CDI_REAL,  1,  1 },
-  { Yearmonstat,    YearmonstatHelp,   YearmonstatOperators,   CDI_REAL,  1,  1 },
-  { Ydayarith,      YdayarithHelp,     YdayarithOperators,     CDI_REAL,  2,  1 },
-  { Ydaypctl,       YdaypctlHelp,      YdaypctlOperators,      CDI_REAL,  3,  1 },
-  { Ydaystat,       YdaystatHelp,      YdaystatOperators,      CDI_REAL,  1,  1 },
-  { Ydrunpctl,      YdrunpctlHelp,     YdrunpctlOperators,     CDI_REAL,  3,  1 },
-  { Ydrunstat,      YdrunstatHelp,     YdrunstatOperators,     CDI_REAL,  1,  1 },
-  { Yhourarith,     YhourarithHelp,    YhourarithOperators,    CDI_REAL,  2,  1 },
-  { Yhourstat,      YhourstatHelp,     YhourstatOperators,     CDI_REAL,  1,  1 },
-  { Ymonarith,      YmonarithHelp,     YmonarithOperators,     CDI_REAL,  2,  1 },
-  { Ymonarith,      YseasarithHelp,    YseasarithOperators,    CDI_REAL,  2,  1 },
-  { Ymonpctl,       YmonpctlHelp,      YmonpctlOperators,      CDI_REAL,  3,  1 },
-  { Ymonstat,       YmonstatHelp,      YmonstatOperators,      CDI_REAL,  1,  1 },
-  { Yseaspctl,      YseaspctlHelp,     YseaspctlOperators,     CDI_REAL,  3,  1 },
-  { Yseasstat,      YseasstatHelp,     YseasstatOperators,     CDI_REAL,  1,  1 },
-  { Zonstat,        ZonstatHelp,       ZonstatOperators,       CDI_REAL,  1,  1 },
-  { EcaCfd,         EcaCfdHelp,        EcaCfdOperators,        CDI_REAL,  1,  1 },
-  { EcaCsu,         EcaCsuHelp,        EcaCsuOperators,        CDI_REAL,  1,  1 },
-  { EcaCwdi,        EcaCwdiHelp,       EcaCwdiOperators,       CDI_REAL,  2,  1 },
-  { EcaCwfi,        EcaCwfiHelp,       EcaCwfiOperators,       CDI_REAL,  2,  1 },
-  { EcaEtr,         EcaEtrHelp,        EcaEtrOperators,        CDI_REAL,  2,  1 },
-  { EcaFd,          EcaFdHelp,         EcaFdOperators,         CDI_REAL,  1,  1 },
-  { EcaGsl,         EcaGslHelp,        EcaGslOperators,        CDI_REAL,  2,  1 },
-  { EcaHd,          EcaHdHelp,         EcaHdOperators,         CDI_REAL,  1,  1 },
-  { EcaHwdi,        EcaHwdiHelp,       EcaHwdiOperators,       CDI_REAL,  2,  1 },
-  { EcaHwfi,        EcaHwfiHelp,       EcaHwfiOperators,       CDI_REAL,  2,  1 },
-  { EcaId,          EcaIdHelp,         EcaIdOperators,         CDI_REAL,  1,  1 },
-  { EcaSu,          EcaSuHelp,         EcaSuOperators,         CDI_REAL,  1,  1 },
-  { EcaTr,          EcaTrHelp,         EcaTrOperators,         CDI_REAL,  1,  1 },
-  { EcaTg10p,       EcaTg10pHelp,      EcaTg10pOperators,      CDI_REAL,  2,  1 },
-  { EcaTg90p,       EcaTg90pHelp,      EcaTg90pOperators,      CDI_REAL,  2,  1 },
-  { EcaTn10p,       EcaTn10pHelp,      EcaTn10pOperators,      CDI_REAL,  2,  1 },
-  { EcaTn90p,       EcaTn90pHelp,      EcaTn90pOperators,      CDI_REAL,  2,  1 },
-  { EcaTx10p,       EcaTx10pHelp,      EcaTx10pOperators,      CDI_REAL,  2,  1 },
-  { EcaTx90p,       EcaTx90pHelp,      EcaTx90pOperators,      CDI_REAL,  2,  1 },
-  { EcaCdd,         EcaCddHelp,        EcaCddOperators,        CDI_REAL,  1,  1 },
-  { EcaCwd,         EcaCwdHelp,        EcaCwdOperators,        CDI_REAL,  1,  1 },
-  { EcaRr1,         EcaRr1Help,        EcaRr1Operators,        CDI_REAL,  1,  1 },
-  { EcaPd,          EcaPdHelp,         EcaPdOperators,         CDI_REAL,  1,  1 },
-  { EcaR75p,        EcaR75pHelp,       EcaR75pOperators,       CDI_REAL,  2,  1 },
-  { EcaR75ptot,     EcaR75ptotHelp,    EcaR75ptotOperators,    CDI_REAL,  2,  1 },
-  { EcaR90p,        EcaR90pHelp,       EcaR90pOperators,       CDI_REAL,  2,  1 },
-  { EcaR90ptot,     EcaR90ptotHelp,    EcaR90ptotOperators,    CDI_REAL,  2,  1 },
-  { EcaR95p,        EcaR95pHelp,       EcaR95pOperators,       CDI_REAL,  2,  1 },
-  { EcaR95ptot,     EcaR95ptotHelp,    EcaR95ptotOperators,    CDI_REAL,  2,  1 },
-  { EcaR99p,        EcaR99pHelp,       EcaR99pOperators,       CDI_REAL,  2,  1 },
-  { EcaR99ptot,     EcaR99ptotHelp,    EcaR99ptotOperators,    CDI_REAL,  2,  1 },
-  { EcaRx1day,      EcaRx1dayHelp,     EcaRx1dayOperators,     CDI_REAL,  1,  1 },
-  { EcaRx5day,      EcaRx5dayHelp,     EcaRx5dayOperators,     CDI_REAL,  1,  1 },
-  { EcaSdii,        EcaSdiiHelp,       EcaSdiiOperators,       CDI_REAL,  1,  1 },
-  { Fdns,           FdnsHelp,          FdnsOperators,          CDI_REAL,  2,  1 },
-  { Strwin,         StrwinHelp,        StrwinOperators,        CDI_REAL,  1,  1 },
-  { Strbre,         StrbreHelp,        StrbreOperators,        CDI_REAL,  1,  1 },
-  { Strgal,         StrgalHelp,        StrgalOperators,        CDI_REAL,  1,  1 },
-  { Hurr,           HurrHelp,          HurrOperators,          CDI_REAL,  1,  1 },
-  /*  { Hi,             NULL,              HiOperators,        CDI_REAL,  3,  1 }, */
-  { Wct,            WctHelp,           WctOperators,           CDI_REAL,  2,  1 },
-#if defined(HAVE_LIBMAGICS) && defined(HAVE_LIBXML2)
-  { Magplot,        NULL,              MagplotOperators,       CDI_REAL,  1,  1 },
-  { Magvector,      NULL,              MagvectorOperators,     CDI_REAL,  1,  1 },
-  { Maggraph,       NULL,              MaggraphOperators,      CDI_REAL, -1,  1 },
-#endif
+  { Adisit,         AdisitHelp,        AdisitOperators,        1,   CDI_REAL,  1,  1 },
+  { Afterburner,    AfterburnerHelp,   AfterburnerOperators,   1,   CDI_REAL, -1,  1 },
+  { Arith,          ArithHelp,         ArithOperators,         1,   CDI_REAL,  2,  1 },
+  { Arithc,         ArithcHelp,        ArithcOperators,        1,   CDI_REAL,  1,  1 },
+  { Arithdays,      ArithdaysHelp,     ArithdaysOperators,     1,   CDI_REAL,  1,  1 },
+  { Arithlat,       NULL,              ArithlatOperators,      1,   CDI_REAL,  1,  1 },
+  { Cat,            CopyHelp,          CatOperators,           1,   CDI_REAL, -1,  1 },
+  { CDItest,        NULL,              CDItestOperators,       1,   CDI_REAL,  1,  1 },
+  { CDIread,        NULL,              CDIreadOperators,       1,   CDI_REAL,  1,  0 },
+  { CDIwrite,       NULL,              CDIwriteOperators,      1,   CDI_REAL,  0,  1 },
+  { Change,         ChangeHelp,        ChangeOperators,        1,   CDI_REAL,  1,  1 },
+  { Change_e5slm,   NULL,              Change_e5slmOperators,  0,   CDI_REAL,  1,  1 },
+  { Cloudlayer,     NULL,              CloudlayerOperators,    1,   CDI_REAL,  1,  1 },
+  { CMOR,           NULL,              CMOROperators,          1,   CDI_REAL,  1,  0 },
+  { Collgrid,       CollgridHelp,      CollgridOperators,      1,   CDI_REAL, -1,  1 },
+  { Command,        NULL,              CommandOperators,       0,   CDI_REAL,  1,  0 },
+  { Comp,           CompHelp,          CompOperators,          1,   CDI_REAL,  2,  1 },
+  { Compc,          CompcHelp,         CompcOperators,         1,   CDI_REAL,  1,  1 },
+  { Complextorect,  NULL,              ComplextorectOperators, 1,   CDI_COMP,  1,  2 },
+  { Cond,           CondHelp,          CondOperators,          1,   CDI_REAL,  2,  1 },
+  { Cond2,          Cond2Help,         Cond2Operators,         1,   CDI_REAL,  3,  1 },
+  { Condc,          CondcHelp,         CondcOperators,         1,   CDI_REAL,  1,  1 },
+  { Consecstat,     ConsecstatHelp,    ConsecstatOperators,    1,   CDI_REAL,  1,  1 },
+  { Copy,           CopyHelp,          CopyOperators,          1,   CDI_REAL, -1,  1 },
+  { Deltime,        NULL,              DeltimeOperators,       1,   CDI_REAL,  1,  1 },
+  { Derivepar,      DeriveparHelp,     DeriveparOperators,     1,   CDI_REAL,  1,  1 },
+  { Detrend,        DetrendHelp,       DetrendOperators,       1,   CDI_REAL,  1,  1 },
+  { Diff,           DiffHelp,          DiffOperators,          1,   CDI_REAL,  2,  0 },
+  { Distgrid,       DistgridHelp,      DistgridOperators,      1,   CDI_REAL,  1,  1 },
+  { Duplicate,      DuplicateHelp,     DuplicateOperators,     1,   CDI_REAL,  1,  1 },
+  { Echam5ini,      NULL,              Echam5iniOperators,     1,   CDI_REAL,  1,  1 },
+  { Enlarge,        EnlargeHelp,       EnlargeOperators,       1,   CDI_REAL,  1,  1 },
+  { Enlargegrid,    NULL,              EnlargegridOperators,   0,   CDI_REAL,  1,  1 },
+  { Ensstat,        EnsstatHelp,       EnsstatOperators,       1,   CDI_REAL, -1,  1 },
+  { Ensstat3,       Ensstat2Help,      Ensstat3Operators,      1,   CDI_REAL, -1,  1 },
+  { Ensval,         EnsvalHelp,        EnsvalOperators,        1,   CDI_REAL, -1,  1 },
+  { Eofcoeff,       EofcoeffHelp,      EofcoeffOperators,      1,   CDI_REAL,  2, -1 },
+  { Eofcoeff3d,     EofcoeffHelp,      Eofcoeff3dOperators,    1,   CDI_REAL,  2, -1 },
+  { EOFs,           EOFsHelp,          EOFsOperators,          1,   CDI_REAL,  1,  2 },
+  { EOF3d,          EOFsHelp,          EOF3dOperators,         1,   CDI_REAL,  1,  2 },
+  { Expr,           ExprHelp,          ExprOperators,          1,   CDI_REAL,  1,  1 },
+  { FC,             NULL,              FCOperators,            1,   CDI_REAL,  1,  1 },
+  { Filedes,        FiledesHelp,       FiledesOperators,       1,   CDI_BOTH,  1,  0 },
+  { Fillmiss,       NULL,              FillmissOperators,      1,   CDI_REAL,  1,  1 },
+  { Filter,         FilterHelp,        FilterOperators,        1,   CDI_REAL,  1,  1 },
+  { Fldrms,         NULL,              FldrmsOperators,        1,   CDI_REAL,  2,  1 },
+  { Fldstat,        FldstatHelp,       FldstatOperators,       1,   CDI_REAL,  1,  1 },
+  { Fldstat2,       FldcorHelp,        FldcorOperators,        1,   CDI_REAL,  2,  1 },
+  { Fldstat2,       FldcovarHelp,      FldcovarOperators,      1,   CDI_REAL,  2,  1 },
+  { Fourier,        NULL,              FourierOperators,       1,   CDI_COMP,  1,  1 },
+  { Gengrid,        NULL,              GengridOperators,       1,   CDI_REAL,  2,  1 },
+  { Gradsdes,       GradsdesHelp,      GradsdesOperators,      1,   CDI_REAL,  1,  0 },
+  { Gridboxstat,    GridboxstatHelp,   GridboxstatOperators,   1,   CDI_REAL,  1,  1 },
+  { Gridcell,       GridcellHelp,      GridcellOperators,      1,   CDI_REAL,  1,  1 },
+  { Gridsearch,     NULL,              GridsearchOperators,    0,   CDI_REAL,  0,  0 },
+  { Harmonic,       NULL,              HarmonicOperators,      1,   CDI_REAL,  1,  1 },
+  { Histogram,      HistogramHelp,     HistogramOperators,     1,   CDI_REAL,  1,  1 },
+  { Importamsr,     ImportamsrHelp,    ImportamsrOperators,    1,   CDI_REAL,  1,  1 },
+  { Importbinary,   ImportbinaryHelp,  ImportbinaryOperators,  1,   CDI_REAL,  1,  1 },
+  { Importcmsaf,    ImportcmsafHelp,   ImportcmsafOperators,   1,   CDI_REAL,  1,  1 },
+  { Importobs,      NULL,              ImportobsOperators,     1,   CDI_REAL,  1,  1 },
+  { Info,           InfoHelp,          InfoOperators,          1,   CDI_BOTH, -1,  0 },
+  { Input,          InputHelp,         InputOperators,         1,   CDI_REAL,  0,  1 },
+  { Intgrid,        NULL,              IntgridOperators,       1,   CDI_REAL,  1,  1 },
+  { Intgridtraj,    NULL,              IntgridtrajOperators,   1,   CDI_REAL,  1,  1 },
+  { Intlevel,       IntlevelHelp,      IntlevelOperators,      1,   CDI_REAL,  1,  1 },
+  { Intlevel3d,     Intlevel3dHelp,    Intlevel3dOperators,    1,   CDI_REAL,  2,  1 },
+  { Inttime,        InttimeHelp,       InttimeOperators,       1,   CDI_REAL,  1,  1 },
+  { Intntime,       InttimeHelp,       IntntimeOperators,      1,   CDI_REAL,  1,  1 },
+  { Intyear,        IntyearHelp,       IntyearOperators,       1,   CDI_REAL,  2, -1 },
+  { Invert,         InvertHelp,        InvertOperators,        1,   CDI_REAL,  1,  1 },
+  { Invertlev,      InvertlevHelp,     InvertlevOperators,     1,   CDI_REAL,  1,  1 },
+  { Isosurface,     NULL,              IsosurfaceOperators,    1,   CDI_REAL,  1,  1 },
+  { Kvl,            NULL,              KvlOperators,           1,   CDI_REAL,  0,  0 },
+  { Log,            NULL,              LogOperators,           0,   CDI_REAL,  1,  0 },
+  { Maskbox,        MaskboxHelp,       MaskboxOperators,       1,   CDI_REAL,  1,  1 },
+  { Maskbox,        MaskregionHelp,    MaskregionOperators,    1,   CDI_REAL,  1,  1 },
+  { Mastrfu,        MastrfuHelp,       MastrfuOperators,       1,   CDI_REAL,  1,  1 },
+  { Math,           MathHelp,          MathOperators,          1,   CDI_BOTH,  1,  1 },
+  { Merge,          MergeHelp,         MergeOperators,         1,   CDI_REAL, -1,  1 },
+  { Mergetime,      MergeHelp,         MergetimeOperators,     1,   CDI_REAL, -1,  1 },
+  { Mergegrid,      MergegridHelp,     MergegridOperators,     1,   CDI_REAL,  2,  1 },
+  { Merstat,        MerstatHelp,       MerstatOperators,       1,   CDI_REAL,  1,  1 },
+  { Monarith,       MonarithHelp,      MonarithOperators,      1,   CDI_REAL,  2,  1 },
+  { Mrotuv,         NULL,              MrotuvOperators,        1,   CDI_REAL,  1,  2 },
+  { Mrotuvb,        NULL,              MrotuvbOperators,       1,   CDI_REAL,  2,  1 },
+  { Ninfo,          NinfoHelp,         NinfoOperators,         1,   CDI_BOTH,  1,  0 },
+  { Nmltest,        NULL,              NmltestOperators,       0,   CDI_REAL,  0,  0 },
+  { Output,         OutputHelp,        OutputOperators,        1,   CDI_REAL, -1,  0 },
+  { Output,         OutputtabHelp,     OutputtabOperators,     1,   CDI_REAL, -1,  0 },
+  { Outputgmt,      OutputgmtHelp,     OutputgmtOperators,     1,   CDI_REAL,  1,  0 },
+  { Pack,           NULL,              PackOperators,          1,   CDI_REAL,  1,  1 },
+  { Pardup,         NULL,              PardupOperators,        1,   CDI_REAL,  1,  1 },
+  { Pinfo,          NULL,              PinfoOperators,         1,   CDI_REAL,  1,  1 },
+  { Pressure,       NULL,              PressureOperators,      1,   CDI_REAL,  1,  1 },
+  { Regres,         RegresHelp,        RegresOperators,        1,   CDI_REAL,  1,  1 },
+  { Remap,          RemapHelp,         RemapOperators,         1,   CDI_REAL,  1,  1 },
+  { Remap,          RemapbilHelp,      RemapbilOperators,      1,   CDI_REAL,  1,  1 },
+  { Remap,          RemapbicHelp,      RemapbicOperators,      1,   CDI_REAL,  1,  1 },
+  { Remap,          RemapnnHelp,       RemapnnOperators,       1,   CDI_REAL,  1,  1 },
+  { Remap,          RemapdisHelp,      RemapdisOperators,      1,   CDI_REAL,  1,  1 },
+  { Remap,          RemapyconHelp,     RemapyconOperators,     1,   CDI_REAL,  1,  1 },
+  { Remap,          RemapconHelp,      RemapconOperators,      1,   CDI_REAL,  1,  1 },
+  { Remap,          Remapcon2Help,     Remapcon2Operators,     1,   CDI_REAL,  1,  1 },
+  { Remap,          RemaplafHelp,      RemaplafOperators,      1,   CDI_REAL,  1,  1 },
+  { Remap,          NULL,              RemapgridOperators,     1,   CDI_REAL,  1,  1 },
+  { Remapeta,       RemapetaHelp,      RemapetaOperators,      1,   CDI_REAL,  1,  1 },
+  { Replace,        ReplaceHelp,       ReplaceOperators,       1,   CDI_REAL,  2,  1 },
+  { Replacevalues,  ReplacevaluesHelp, ReplacevaluesOperators, 1,   CDI_REAL,  1,  1 },
+  { Rhopot,         RhopotHelp,        RhopotOperators,        1,   CDI_REAL,  1,  1 },
+  { Rotuv,          RotuvbHelp,        RotuvOperators,         1,   CDI_REAL,  1,  1 },
+  { Runpctl,        RunpctlHelp,       RunpctlOperators,       1,   CDI_REAL,  1,  1 },
+  { Runstat,        RunstatHelp,       RunstatOperators,       1,   CDI_REAL,  1,  1 },
+  { Seascount,      NULL,              SeascountOperators,     1,   CDI_BOTH,  1,  1 },
+  { Seaspctl,       SeaspctlHelp,      SeaspctlOperators,      1,   CDI_REAL,  3,  1 },
+  { Seasstat,       SeasstatHelp,      SeasstatOperators,      1,   CDI_REAL,  1,  1 },
+  { Selbox,         SelboxHelp,        SelboxOperators,        1,   CDI_BOTH,  1,  1 },
+  { Select,         SelectHelp,        SelectOperators,        1,   CDI_BOTH, -1,  1 },
+  { Selvar,         SelvarHelp,        SelvarOperators,        1,   CDI_BOTH,  1,  1 },
+  { Selrec,         SelvarHelp,        SelrecOperators,        1,   CDI_BOTH,  1,  1 },
+  { Seloperator,    NULL,              SeloperatorOperators,   1,   CDI_REAL,  1,  1 },
+  { Seltime,        SeltimeHelp,       SeltimeOperators,       1,   CDI_BOTH,  1,  1 },
+  { Set,            SetHelp,           SetOperators,           1,   CDI_BOTH,  1,  1 },
+  { Setbox,         SetboxHelp,        SetboxOperators,        1,   CDI_REAL,  1,  1 },
+  { Setgatt,        SetgattHelp,       SetgattOperators,       1,   CDI_BOTH,  1,  1 },
+  { Setgrid,        SetgridHelp,       SetgridOperators,       1,   CDI_BOTH,  1,  1 },
+  { Sethalo,        SethaloHelp,       SethaloOperators,       1,   CDI_REAL,  1,  1 },
+  { Setmiss,        SetmissHelp,       SetmissOperators,       1,   CDI_REAL,  1,  1 },
+  { Fillmiss,       SetmissHelp,       SetmisstonnOperators,   1,   CDI_REAL,  1,  1 },
+  { Setpartab,      SetHelp,           Setpartab0Operators,    1,   CDI_REAL,  1,  1 },
+  { Setpartab,      SetpartabHelp,     SetpartabOperators,     1,   CDI_REAL,  1,  1 },
+  { Setrcaname,     NULL,              SetrcanameOperators,    1,   CDI_REAL,  1,  1 },
+  { Settime,        SettimeHelp,       SettimeOperators,       1,   CDI_BOTH,  1,  1 },
+  { Setzaxis,       SetzaxisHelp,      SetzaxisOperators,      1,   CDI_BOTH,  1,  1 },
+  { Showinfo,       ShowinfoHelp,      ShowinfoOperators,      1,   CDI_BOTH,  1,  0 },
+  { Sinfo,          SinfoHelp,         SinfoOperators,         1,   CDI_BOTH, -1,  0 },
+  { Smooth9,        Smooth9Help,       Smooth9Operators,       1,   CDI_REAL,  1,  1 },
+  { Sort,           NULL,              SortOperators,          1,   CDI_REAL,  1,  1 },
+  { Sorttimestamp,  NULL,              SorttimestampOperators, 1,   CDI_REAL, -1,  1 },
+  { Specinfo,       NULL,              SpecinfoOperators,      1,   CDI_REAL,  0,  0 },
+  { Spectral,       SpectralHelp,      SpectralOperators,      1,   CDI_REAL,  1,  1 },
+  { Spectrum,       NULL,              SpectrumOperators,      1,   CDI_REAL,  1,  1 },
+  { Split,          SplitHelp,         SplitOperators,         1,   CDI_BOTH,  1, -1 },
+  { Splitrec,       SplitHelp,         SplitrecOperators,      1,   CDI_BOTH,  1, -1 },
+  { Splitsel,       SplitselHelp,      SplitselOperators,      1,   CDI_BOTH,  1, -1 },
+  { Splittime,      SplittimeHelp,     SplittimeOperators,     1,   CDI_BOTH,  1, -1 },
+  { Splityear,      SplittimeHelp,     SplityearOperators,     1,   CDI_BOTH,  1, -1 },
+  { SSOpar,         NULL,              SSOparOperators,        0,   CDI_REAL,  1,  1 },
+  { Subtrend,       SubtrendHelp,      SubtrendOperators,      1,   CDI_REAL,  3,  1 },
+  { Tee,            NULL,              TeeOperators,           1,   CDI_REAL,  2,  1 },
+  { Template1,      NULL,              Template1Operators,     0,   CDI_REAL,  1,  1 },
+  { Template2,      NULL,              Template2Operators,     0,   CDI_REAL,  1,  1 },
+  { Test,           NULL,              TestOperators,          0,   CDI_REAL,  1,  1 },
+  { Test2,          NULL,              Test2Operators,         0,   CDI_REAL,  2,  1 },
+  { Testdata,       NULL,              TestdataOperators,      0,   CDI_REAL,  1,  1 },
+  { Tests,          NULL,              TestsOperators,         0,   CDI_REAL,  1,  1 },
+  { Timcount,       NULL,              TimcountOperators,      1,   CDI_BOTH,  1,  1 },
+  { Timcount,       NULL,              YearcountOperators,     1,   CDI_BOTH,  1,  1 },
+  { Timcount,       NULL,              MoncountOperators,      1,   CDI_BOTH,  1,  1 },
+  { Timcount,       NULL,              DaycountOperators,      1,   CDI_BOTH,  1,  1 },
+  { Timcount,       NULL,              HourcountOperators,     1,   CDI_BOTH,  1,  1 },
+  { Timpctl,        TimpctlHelp,       TimpctlOperators,       1,   CDI_REAL,  3,  1 },
+  { Timpctl,        YearpctlHelp,      YearpctlOperators,      1,   CDI_REAL,  3,  1 },
+  { Timpctl,        MonpctlHelp,       MonpctlOperators,       1,   CDI_REAL,  3,  1 },
+  { Timpctl,        DaypctlHelp,       DaypctlOperators,       1,   CDI_REAL,  3,  1 },
+  { Timpctl,        HourpctlHelp,      HourpctlOperators,      1,   CDI_REAL,  3,  1 },
+  { Timselpctl,     TimselpctlHelp,    TimselpctlOperators,    1,   CDI_REAL,  3,  1 },
+  { Timedt,         NULL,              TimedtOperators,        1,   CDI_REAL,  1,  1 },
+  { Timsort,        TimsortHelp,       TimsortOperators,       1,   CDI_REAL,  1,  1 },
+  { Timselstat,     TimselstatHelp,    TimselstatOperators,    1,   CDI_REAL,  1,  1 },
+  { XTimstat,       NULL,              XTimstatOperators,      0,   CDI_BOTH,  1,  1 },
+  { Timstat,        TimstatHelp,       TimstatOperators,       1,   CDI_BOTH,  1,  1 },
+  { Timstat,        YearstatHelp,      YearstatOperators,      1,   CDI_BOTH,  1,  1 },
+  { Timstat,        MonstatHelp,       MonstatOperators,       1,   CDI_BOTH,  1,  1 },
+  { Timstat,        DaystatHelp,       DaystatOperators,       1,   CDI_BOTH,  1,  1 },
+  { Timstat,        HourstatHelp,      HourstatOperators,      1,   CDI_BOTH,  1,  1 },
+  { Timstat2,       TimcorHelp,        TimcorOperators,        1,   CDI_REAL,  2,  1 },
+  { Timstat2,       TimcovarHelp,      TimcovarOperators,      1,   CDI_REAL,  2,  1 },
+  { Timstat3,       NULL,              Timstat3Operators,      1,   CDI_REAL,  2,  1 },
+  { Tinfo,          NULL,              TinfoOperators,         1,   CDI_BOTH,  1,  0 },
+  { Tocomplex,      NULL,              TocomplexOperators,     1,   CDI_REAL,  1,  1 },
+  { Transpose,      NULL,              TransposeOperators,     1,   CDI_REAL,  1,  1 },
+  { Trend,          TrendHelp,         TrendOperators,         1,   CDI_REAL,  1,  2 },
+  { Trms,           NULL,              TrmsOperators,          0,   CDI_REAL,  2,  1 },
+  { Tstepcount,     NULL,              TstepcountOperators,    1,   CDI_REAL,  1,  1 },
+  { Vargen,         VargenHelp,        VargenOperators,        1,   CDI_REAL,  0,  1 },
+  { Varrms,         NULL,              VarrmsOperators,        0,   CDI_REAL,  2,  1 },
+  { Vertintml,      VertintmlHelp,     VertintmlOperators,     1,   CDI_REAL,  1,  1 },
+  { Vertintap,      VertintapHelp,     VertintapOperators,     1,   CDI_REAL,  1,  1 },
+  { Vertstat,       VertstatHelp,      VertstatOperators,      1,   CDI_REAL,  1,  1 },
+  { Vertcum,        NULL,              VertcumOperators,       1,   CDI_REAL,  1,  1 },
+  { Vertwind,       NULL,              VertwindOperators,      1,   CDI_REAL,  1,  1 },
+  { Verifygrid,     NULL,              VerifygridOperators,    1,   CDI_REAL,  1,  0 },
+  { Wind,           WindHelp,          WindOperators,          1,   CDI_REAL,  1,  1 },
+  { Writegrid,      NULL,              WritegridOperators,     1,   CDI_REAL,  1,  1 },  /* no cdi output */
+  { Writerandom,    NULL,              WriterandomOperators,   1,   CDI_REAL,  1,  1 },
+  { YAR,            NULL,              YAROperators,           0,   CDI_REAL,  1,  1 },
+  { Yearmonstat,    YearmonstatHelp,   YearmonstatOperators,   1,   CDI_REAL,  1,  1 },
+  { Ydayarith,      YdayarithHelp,     YdayarithOperators,     1,   CDI_REAL,  2,  1 },
+  { Ydaypctl,       YdaypctlHelp,      YdaypctlOperators,      1,   CDI_REAL,  3,  1 },
+  { Ydaystat,       YdaystatHelp,      YdaystatOperators,      1,   CDI_REAL,  1,  1 },
+  { Ydrunpctl,      YdrunpctlHelp,     YdrunpctlOperators,     1,   CDI_REAL,  3,  1 },
+  { Ydrunstat,      YdrunstatHelp,     YdrunstatOperators,     1,   CDI_REAL,  1,  1 },
+  { Yhourarith,     YhourarithHelp,    YhourarithOperators,    1,   CDI_REAL,  2,  1 },
+  { Yhourstat,      YhourstatHelp,     YhourstatOperators,     1,   CDI_REAL,  1,  1 },
+  { Ymonarith,      YmonarithHelp,     YmonarithOperators,     1,   CDI_REAL,  2,  1 },
+  { Ymonarith,      YseasarithHelp,    YseasarithOperators,    1,   CDI_REAL,  2,  1 },
+  { Ymonpctl,       YmonpctlHelp,      YmonpctlOperators,      1,   CDI_REAL,  3,  1 },
+  { Ymonstat,       YmonstatHelp,      YmonstatOperators,      1,   CDI_REAL,  1,  1 },
+  { Yseaspctl,      YseaspctlHelp,     YseaspctlOperators,     1,   CDI_REAL,  3,  1 },
+  { Yseasstat,      YseasstatHelp,     YseasstatOperators,     1,   CDI_REAL,  1,  1 },
+  { Zonstat,        ZonstatHelp,       ZonstatOperators,       1,   CDI_REAL,  1,  1 },
+  { EcaCfd,         EcaCfdHelp,        EcaCfdOperators,        1,   CDI_REAL,  1,  1 },
+  { EcaCsu,         EcaCsuHelp,        EcaCsuOperators,        1,   CDI_REAL,  1,  1 },
+  { EcaCwdi,        EcaCwdiHelp,       EcaCwdiOperators,       1,   CDI_REAL,  2,  1 },
+  { EcaCwfi,        EcaCwfiHelp,       EcaCwfiOperators,       1,   CDI_REAL,  2,  1 },
+  { EcaEtr,         EcaEtrHelp,        EcaEtrOperators,        1,   CDI_REAL,  2,  1 },
+  { EcaFd,          EcaFdHelp,         EcaFdOperators,         1,   CDI_REAL,  1,  1 },
+  { EcaGsl,         EcaGslHelp,        EcaGslOperators,        1,   CDI_REAL,  2,  1 },
+  { EcaHd,          EcaHdHelp,         EcaHdOperators,         1,   CDI_REAL,  1,  1 },
+  { EcaHwdi,        EcaHwdiHelp,       EcaHwdiOperators,       1,   CDI_REAL,  2,  1 },
+  { EcaHwfi,        EcaHwfiHelp,       EcaHwfiOperators,       1,   CDI_REAL,  2,  1 },
+  { EcaId,          EcaIdHelp,         EcaIdOperators,         1,   CDI_REAL,  1,  1 },
+  { EcaSu,          EcaSuHelp,         EcaSuOperators,         1,   CDI_REAL,  1,  1 },
+  { EcaTr,          EcaTrHelp,         EcaTrOperators,         1,   CDI_REAL,  1,  1 },
+  { EcaTg10p,       EcaTg10pHelp,      EcaTg10pOperators,      1,   CDI_REAL,  2,  1 },
+  { EcaTg90p,       EcaTg90pHelp,      EcaTg90pOperators,      1,   CDI_REAL,  2,  1 },
+  { EcaTn10p,       EcaTn10pHelp,      EcaTn10pOperators,      1,   CDI_REAL,  2,  1 },
+  { EcaTn90p,       EcaTn90pHelp,      EcaTn90pOperators,      1,   CDI_REAL,  2,  1 },
+  { EcaTx10p,       EcaTx10pHelp,      EcaTx10pOperators,      1,   CDI_REAL,  2,  1 },
+  { EcaTx90p,       EcaTx90pHelp,      EcaTx90pOperators,      1,   CDI_REAL,  2,  1 },
+  { EcaCdd,         EcaCddHelp,        EcaCddOperators,        1,   CDI_REAL,  1,  1 },
+  { EcaCwd,         EcaCwdHelp,        EcaCwdOperators,        1,   CDI_REAL,  1,  1 },
+  { EcaRr1,         EcaRr1Help,        EcaRr1Operators,        1,   CDI_REAL,  1,  1 },
+  { EcaPd,          EcaPdHelp,         EcaPdOperators,         1,   CDI_REAL,  1,  1 },
+  { EcaR75p,        EcaR75pHelp,       EcaR75pOperators,       1,   CDI_REAL,  2,  1 },
+  { EcaR75ptot,     EcaR75ptotHelp,    EcaR75ptotOperators,    1,   CDI_REAL,  2,  1 },
+  { EcaR90p,        EcaR90pHelp,       EcaR90pOperators,       1,   CDI_REAL,  2,  1 },
+  { EcaR90ptot,     EcaR90ptotHelp,    EcaR90ptotOperators,    1,   CDI_REAL,  2,  1 },
+  { EcaR95p,        EcaR95pHelp,       EcaR95pOperators,       1,   CDI_REAL,  2,  1 },
+  { EcaR95ptot,     EcaR95ptotHelp,    EcaR95ptotOperators,    1,   CDI_REAL,  2,  1 },
+  { EcaR99p,        EcaR99pHelp,       EcaR99pOperators,       1,   CDI_REAL,  2,  1 },
+  { EcaR99ptot,     EcaR99ptotHelp,    EcaR99ptotOperators,    1,   CDI_REAL,  2,  1 },
+  { EcaRx1day,      EcaRx1dayHelp,     EcaRx1dayOperators,     1,   CDI_REAL,  1,  1 },
+  { EcaRx5day,      EcaRx5dayHelp,     EcaRx5dayOperators,     1,   CDI_REAL,  1,  1 },
+  { EcaSdii,        EcaSdiiHelp,       EcaSdiiOperators,       1,   CDI_REAL,  1,  1 },
+  { Fdns,           FdnsHelp,          FdnsOperators,          1,   CDI_REAL,  2,  1 },
+  { Strwin,         StrwinHelp,        StrwinOperators,        1,   CDI_REAL,  1,  1 },
+  { Strbre,         StrbreHelp,        StrbreOperators,        1,   CDI_REAL,  1,  1 },
+  { Strgal,         StrgalHelp,        StrgalOperators,        1,   CDI_REAL,  1,  1 },
+  { Hurr,           HurrHelp,          HurrOperators,          1,   CDI_REAL,  1,  1 },
+  /*  { Hi,             NULL,              HiOperators,        1,   CDI_REAL,  3,  1 }, */
+  { Wct,            WctHelp,           WctOperators,           1,   CDI_REAL,  2,  1 },
+  { Magplot,        MagplotHelp,       MagplotOperators,       1,   CDI_REAL,  1,  1 },
+  { Magvector,      MagvectorHelp,     MagvectorOperators,     1,   CDI_REAL,  1,  1 },
+  { Maggraph,       MaggraphHelp,      MaggraphOperators,      1,   CDI_REAL, -1,  1 },
 };							       
 							       
 static int NumModules = sizeof(Modules) / sizeof(Modules[0]);
 
 static const char *opalias[][2] =
 {
-  {"anomaly",             "ymonsub"    },
-  {"deltap_fl",           "deltap"     },
-  {"diffv",               "diffn"      },
-  {"covar0",              "timcovar"   },
-  {"covar0r",             "fldcovar"   },
-  {"gather",              "collgrid"   },
-  {"geopotheight",        "gheight"    },
-  {"ggstat",              "info"       },
-  {"ggstats",             "sinfo"      },
-  {"globavg",             "fldavg"     },
-  {"infos",               "sinfo"      },
-  {"infov",               "infon"      },
-  {"intgrid",             "intgridbil" },
-  {"log",                 "ln"         },
-  {"lmean",               "ymonmean"   },
-  {"lmmean",              "ymonmean"   },
-  {"lmavg",               "ymonavg"    },
-  {"lmstd",               "ymonstd"    },
-  {"lsmean",              "yseasmean"  },
-  {"chvar",               "chname"     },
-  {"ncode",               "npar"       },
-  {"nvar",                "npar"       },
-  {"outputkey",           "outputtab"  },
-  {"vardes",              "pardes"     },
-  {"delvar",              "delname"    },
-  {"vardup",              "pardup"     },
-  {"varmul",              "parmul"     },
-  {"read_e5ml",           "import_e5ml"},
-  {"remapcon1",           "remaplaf"   },
-  {"remapdis1",           "remapnn"    },
-  {"scatter",             "distgrid"   },
-  {"showvar",             "showname"   },
-  {"selgridname",         "selgrid"    },
-  {"selvar",              "selname"    },
-  {"setvar",              "setname"    },
-  {"setpartabv",          "setpartabn" },
-  {"sinfov",              "sinfon"     },
-  {"sortvar",             "sortname"   },
-  {"splitvar",            "splitname"  },
-  {"sort",                "timsort"    },
-  {"write_e5ml",          "export_e5ml"},
-  {"eca_r1mm",            "eca_rr1"    },
+  {"afterburner",         "after"},
+  {"anomaly",             "ymonsub"},
+  {"deltap_fl",           "deltap"},
+  {"diffv",               "diffn"},
+  {"covar0",              "timcovar"},
+  {"covar0r",             "fldcovar"},
+  {"gather",              "collgrid"},
+  {"geopotheight",        "gheight"},
+  {"ggstat",              "info"},
+  {"ggstats",             "sinfo"},
+  {"globavg",             "fldavg"},
+  {"import_grads",        "import_binary"},
+  {"infos",               "sinfo"},
+  {"infov",               "infon"},
+  {"intgrid",             "intgridbil"},
+  {"log",                 "ln"},
+  {"lmean",               "ymonmean"},
+  {"lmmean",              "ymonmean"},
+  {"lmavg",               "ymonavg"},
+  {"lmstd",               "ymonstd"},
+  {"lsmean",              "yseasmean"},
+  {"chvar",               "chname"},
+  {"ncode",               "npar"},
+  {"nvar",                "npar"},
+  {"outputkey",           "outputtab"},
+  {"vardes",              "pardes"},
+  {"selvar",              "selname"},
+  {"delvar",              "delname"},
+  {"remapcon1",           "remaplaf"},
+  {"remapdis1",           "remapnn"},
+  {"scatter",             "distgrid"},
+  {"showvar",             "showname"},
+  {"selgridname",         "selgrid"},
+  {"setvar",              "setname"},
+  {"setpartabv",          "setpartabn"},
+  {"sinfov",              "sinfon"},
+  {"sortvar",             "sortname"},
+  {"splitvar",            "splitname"},
+  {"sort",                "timsort"},
+  {"eca_r1mm",            "eca_rr1"},
   {"fpressure",           "pressure_fl"},
   {"hpressure",           "pressure_hl"},
-  {"ensrkhistspace",      "ensrkhist_space"},
-  {"ensrkhisttime",       "ensrkhist_time"}
+  {"ensrkhist_space",     "ensrkhistspace"},
+  {"ensrkhist_time",      "ensrkhisttime"},
+  {"gridverify",          "verifygrid"},
+  {"outputcenter",        "gmtxyz"},
+  {"outputbounds",        "gmtcells"},
+  {"selseas",             "selseason"},
+  {"selmon",              "selmonth"},
 };
 
 static int nopalias = sizeof(opalias) / (2*sizeof(opalias[0][0]));
@@ -1045,15 +1050,15 @@ void operatorPrintAll(void)
 
   for ( i = 0; i < NumModules; i++ )
     {
-      j = 0;
-      while ( Modules[i].operators[j] )
-	{
-	  opernames[nop++] = Modules[i].operators[j++];
+      if ( Modules[i].mode )
+        {
+          j = 0;
+          while ( Modules[i].operators[j] )
+            opernames[nop++] = Modules[i].operators[j++];
 	}
     }
-  /*
-   * Add operator aliases
-   */
+
+  // Add operator aliases
   for ( i = 0; i < nopalias; i++ )
     {
       opernames[nop++] = opalias[i][0];
@@ -1073,3 +1078,112 @@ void operatorPrintAll(void)
     }
   fprintf(pout, "\n");
 }
+
+
+void operatorPrintList(void)
+{
+  int i, j, nbyte, nop = 0;
+  const char *opernames[4096];
+  FILE *pout = stdout;
+
+  for ( i = 0; i < NumModules; i++ )
+    {
+      if ( Modules[i].mode )
+        {
+          j = 0;
+          while ( Modules[i].operators[j] )
+            opernames[nop++] = Modules[i].operators[j++];
+        }
+    }
+
+  // Add operator aliases
+  for ( i = 0; i < nopalias; i++ )
+    {
+      opernames[nop++] = opalias[i][0];
+    }
+
+  qsort(opernames, nop, sizeof(char *), cmpname);
+
+  for ( i = 0; i < nop; i++ )
+    {
+      int iname = -1;
+      int ialias = -1;
+      size_t operlen = strlen(opernames[i]);
+      const char *pdes = NULL;
+      const char **phelp = NULL;
+      const char **help = NULL;
+
+      for ( j = 0; j < nopalias; j++ )
+        {
+          if ( strcmp(opernames[i], opalias[j][0]) == 0 )
+            {
+              ialias = j;
+              break;
+            }
+        }
+
+      if ( ialias == -1 ) help = operatorHelp((char *)opernames[i]);
+
+      phelp = help;
+      if ( phelp )
+        {
+          int loper = FALSE;
+          int index = 0;
+          while ( *phelp )
+            {
+              if ( loper )
+                {
+                  if ( *phelp[0] == '\0' ) break;
+                  const char *ph = *phelp;
+                  while ( *ph != '\0' )
+                    {
+                      if ( *ph != ' ' ) break;
+                      ph++;
+                    }
+                  if ( *ph != '\0' && strncmp(ph, opernames[i], operlen) == 0 && ph[operlen] == ' ' )
+                    {
+                      ph += operlen;
+                      while ( *ph != '\0' )
+                        {
+                          if ( *ph != ' ' ) break;
+                          ph++;
+                        }
+                      if ( *ph != '\0' ) pdes = ph;
+                    }
+                }
+              
+              if ( strcmp(*phelp, "NAME") == 0 ) iname = index+1;
+              if ( strcmp(*phelp, "OPERATORS") == 0 ) loper = TRUE;
+              index++;
+              phelp++;
+            }
+        }
+
+      phelp = help;
+      if ( phelp && pdes == NULL && iname >= 0 )
+        {
+          const char *ph = phelp[iname];
+          while ( *ph != '\0' )
+            {
+              if ( *ph != ' ' ) break;
+              ph++;
+            }
+          if ( *ph != '\0' && strncmp(ph, opernames[i], operlen) == 0 && ph[operlen] == ' ' )
+            {
+              ph += operlen;
+              while ( *ph != '\0' )
+                {
+                  if ( *ph != ' ' && *ph != '-' ) break;
+                  ph++;
+                }
+              if ( *ph != '\0' ) pdes = ph;
+            }      
+        }
+
+      nbyte = fprintf(pout, "%s ", opernames[i]);
+      for ( int i = nbyte; i <= 16; ++i ) fprintf(pout, " ");
+      if ( pdes ) fprintf(pout, "%s", pdes);
+      else if ( ialias >= 0 )  fprintf(pout, "--> %s", opalias[ialias][1]);
+      fprintf(pout, "\n");
+    }
+}
diff --git a/src/modules.h b/src/modules.h
index 6021381..1820184 100644
--- a/src/modules.h
+++ b/src/modules.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -27,5 +27,6 @@ int operatorStreamOutCnt(char *operatorName);
 int operatorStreamNumber(char *operatorName);
 
 void operatorPrintAll(void);
+void operatorPrintList(void);
 
 #endif  /* _MODULES_H */
diff --git a/src/namelist.c b/src/namelist.c
index 8cb3c04..9f10466 100644
--- a/src/namelist.c
+++ b/src/namelist.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/namelist.h b/src/namelist.h
index 57a82e5..60b5017 100644
--- a/src/namelist.h
+++ b/src/namelist.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/operator_help.h b/src/operator_help.h
index 94c7c16..f509516 100644
--- a/src/operator_help.h
+++ b/src/operator_help.h
@@ -226,10 +226,10 @@ static const char *DuplicateHelp[] = {
     "",
     "DESCRIPTION",
     "    This operator duplicates the contents of ifile and writes the result to ofile.",
-    "    The optional parameter sets the number of duplicates, the default is 1.",
+    "    The optional parameter sets the number of duplicates, the default is 2.",
     "",
     "PARAMETER",
-    "    ndup  INTEGER  Number of duplicates, default is 1.",
+    "    ndup  INTEGER  Number of duplicates, default is 2.",
     NULL
 };
 
@@ -436,10 +436,10 @@ static const char *CollgridHelp[] = {
     "    This operator collects the data of the input files to one output file. ",
     "    All input files need to have the same variables and the same number of timesteps on a different",
     "    horizonal grid region. A source region must be a structured longitude/latitude grid box.",
-    "    The parameter nx needs to be specified only for curvilinear grids.",
+    "    The parameter nx needs to be specified only non regular lon/lat grids.",
     "",
     "PARAMETER",
-    "    nx     INTEGER  Number of regions in x direction, only needed for curvilinear grids",
+    "    nx     INTEGER  Number of regions in x direction [default: number of input files]",
     "    names  STRING   Comma separated list of variable names [default: all variables]",
     "",
     "NOTE",
@@ -472,9 +472,14 @@ static const char *SelectHelp[] = {
     "    name              STRING  Comma separated list of variable names.",
     "    param             STRING  Comma separated list of parameter identifiers.",
     "    code              INTEGER Comma separated list of code numbers.",
-    "    ltype             INTEGER Comma separated list of GRIB level types.",
-    "    levidx            INTEGER Comma separated list of index of levels.",
     "    level             FLOAT   Comma separated list of vertical levels.",
+    "    levidx            INTEGER Comma separated list of index of levels.",
+    "    zaxisname         STRING  Comma separated list of zaxis names.",
+    "    zaxisnum          INTEGER Comma separated list of zaxis numbers.",
+    "    ltype             INTEGER Comma separated list of GRIB level types.",
+    "    gridname          STRING  Comma separated list of grid names.",
+    "    gridnum           INTEGER Comma separated list of grid numbers.",
+    "    steptype          STRING  Comma separated list of timestep types.",
     "    date              STRING  Comma separated list of dates (format YYYY-MM-DDThh:mm:ss).",
     "    startdate         STRING  Start date (format YYYY-MM-DDThh:mm:ss).",
     "    enddate           STRING  End date (format YYYY-MM-DDThh:mm:ss).",
@@ -482,8 +487,9 @@ static const char *SelectHelp[] = {
     "    hour              INTEGER Comma separated list of hours.",
     "    day               INTEGER Comma separated list of days.",
     "    month             INTEGER Comma separated list of months.",
+    "    season            STRING  Comma separated list of seasons (substring of DJFMAMJJASOND or ANN).",
     "    year              INTEGER Comma separated list of years.",
-    "    timestep          INTEGER Comma separated list of timesteps. Negative values selects timesteps from the end (netCDF only).",
+    "    timestep          INTEGER Comma separated list of timesteps. Negative values selects timesteps from the end (NetCDF only).",
     "    timestep_of_year  INTEGER Comma separated list of timesteps of year.",
     NULL
 };
@@ -559,7 +565,7 @@ static const char *SelvarHelp[] = {
 
 static const char *SeltimeHelp[] = {
     "NAME",
-    "    seltimestep, seltime, selhour, selday, selmon, selyear, selseas, seldate, ",
+    "    seltimestep, seltime, selhour, selday, selmonth, selyear, selseason, seldate, ",
     "    selsmon - Select timesteps",
     "",
     "SYNOPSIS",
@@ -567,9 +573,9 @@ static const char *SeltimeHelp[] = {
     "    seltime,times  ifile ofile",
     "    selhour,hours  ifile ofile",
     "    selday,days  ifile ofile",
-    "    selmon,months  ifile ofile",
+    "    selmonth,months  ifile ofile",
     "    selyear,years  ifile ofile",
-    "    selseas,seasons  ifile ofile",
+    "    selseason,seasons  ifile ofile",
     "    seldate,date1[,date2]  ifile ofile",
     "    selsmon,month[,nts1[,nts2]]  ifile ofile",
     "",
@@ -586,11 +592,11 @@ static const char *SeltimeHelp[] = {
     "                 Selects all timesteps with a hour in a user given list.",
     "    selday       Select days",
     "                 Selects all timesteps with a day in a user given list.",
-    "    selmon       Select months",
+    "    selmonth     Select months",
     "                 Selects all timesteps with a month in a user given list.",
     "    selyear      Select years",
     "                 Selects all timesteps with a year in a user given list.",
-    "    selseas      Select seasons",
+    "    selseason    Select seasons",
     "                 Selects all timesteps with a month of a season in a user given list.",
     "    seldate      Select dates",
     "                 Selects all timesteps with a date in a user given range.",
@@ -598,13 +604,13 @@ static const char *SeltimeHelp[] = {
     "                 Selects a month and optional an arbitrary number of timesteps before and after this month.",
     "",
     "PARAMETER",
-    "    timesteps  INTEGER  Comma separated list of timesteps. Negative values selects timesteps from the end (netCDF only).",
+    "    timesteps  INTEGER  Comma separated list of timesteps. Negative values selects timesteps from the end (NetCDF only).",
     "    times      STRING   Comma separated list of times (format hh:mm:ss).",
     "    hours      INTEGER  Comma separated list of hours.",
     "    days       INTEGER  Comma separated list of days.",
     "    months     INTEGER  Comma separated list of months.",
     "    years      INTEGER  Comma separated list of years.",
-    "    seasons    STRING   Comma separated list of seasons (DJF, MAM, JJA, SON).",
+    "    seasons    STRING   Comma separated list of seasons (substring of DJFMAMJJASOND or ANN).",
     "    date1      STRING   Start date (format YYYY-MM-DDThh:mm:ss).",
     "    date2      STRING   End date (format YYYY-MM-DDThh:mm:ss) [default: date1].",
     "    nts1       INTEGER  Number of timesteps before the selected month [default: 0].",
@@ -842,7 +848,7 @@ static const char *SetpartabHelp[] = {
     "     convert         & INTEGER     & Set to 1 to convert the unit if necessary",
     "    ",
     "    The search key for the variable depends on the operator. Use setpartabn to search variables by the name.",
-    "    This is typically used for netCDF datasets. The operator setpartabp searches variables by the parameter ID.",
+    "    This is typically used for NetCDF datasets. The operator setpartabp searches variables by the parameter ID.",
     "",
     "OPERATORS",
     "    setpartabp  Set parameter table",
@@ -950,7 +956,7 @@ static const char *SettimeHelp[] = {
     "    units     STRING   Base units of the time axis (seconds, minutes, hours, days, months, years)",
     "    date      STRING   Date (format: YYYY-MM-DD)",
     "    time      STRING   Time (format: hh:mm:ss)",
-    "    inc       STRING   Optional increment (seconds, minutes, hours, days, months, years) [default: 0hour]",
+    "    inc       STRING   Optional increment (seconds, minutes, hours, days, months, years) [default: 1hour]",
     "    calendar  STRING   Calendar (standard, proleptic_gregorian, 360_day, 365_day, 366_day)",
     "    sval      STRING   Shift value (e.g. -3hour)",
     NULL
@@ -1089,7 +1095,7 @@ static const char *SetgattHelp[] = {
     "    attfile            STRING  File name which contains global text attributes",
     "",
     "NOTE",
-    "    Besides netCDF none of the supported data formats supports global attributes.",
+    "    Besides NetCDF none of the supported data formats supports global attributes.",
     NULL
 };
 
@@ -1299,6 +1305,9 @@ static const char *ExprHelp[] = {
     "DESCRIPTION",
     "    This module arithmetically processes every timestep of the input dataset.",
     "    Each individual assignment statement have to end with a semi-colon.",
+    "    Unlike regular variables, temporary variables are never written to the output stream.",
+    "    To define a temporary variable simply prefix the variable name with an underscore (e.g. _varname)",
+    "    when the variable is declared.",
     "    ",
     "    The following operators are supported:",
     "    ",
@@ -1309,18 +1318,21 @@ static const char *ExprHelp[] = {
     "         *      & multiplication      & x * y     & Product of x and y ",
     "         /      & division            & x / y     & Quotient of x and y",
     "         ^      & exponentiation      & x ^ y     & Exponentiates x with y ",
-    "         ==     & equal to            & x == y    & 1, if x equal to y; else 0",
-    "         !=     & not equal to        & x != y    & 1, if x not equal to y; else 0",
-    "         >      & greater than        & x > y     & 1, if x greater than y; else 0",
-    "         <      & less than           & x < y     & 1, if x less than y; else 0",
-    "         >=     & greater equal       & x >= y    & 1, if x greater equal y; else 0",
-    "         <=     & less equal          & x <= y    & 1, if x less equal y; else 0",
+    "         ==     & equal to            & x == y    &  1, if x equal to y; else 0",
+    "         !=     & not equal to        & x != y    &  1, if x not equal to y; else 0",
+    "         >      & greater than        & x > y     &  1, if x greater than y; else 0",
+    "         <      & less than           & x < y     &  1, if x less than y; else 0",
+    "         >=     & greater equal       & x >= y    &  1, if x greater equal y; else 0",
+    "         <=     & less equal          & x <= y    &  1, if x less equal y; else 0",
     "         <=>    & less equal greater  & x <=> y   & -1, if x less y; 1, if x greater y; else 0 ",
-    "         &&     & logical AND         & x && y    & 1, if x and y not equal 0; else 0",
-    "         ||     & logical OR          & x || y    & 1, if x or y not equal 0; else 0",
+    "         &&     & logical AND         & x && y    &  1, if x and y not equal 0; else 0",
+    "         ||     & logical OR          & x || y    &  1, if x or y not equal 0; else 0",
     "         ?:     & ternary conditional & x ? y : z & y, if x not equal 0, else z ",
     "    ",
-    "    The following intrinsic functions are available:",
+    "    The following functions are supported:",
+    "    ",
+    "    Math intrinsics:",
+    "    ",
     "    abs(x)  "    "    Absolute value of x",
     "    floor(x)"    "    Round to largest integral value not greater than x",
     "    ceil(x) "    "    Round to smallest integral value not less than x",
@@ -1337,6 +1349,37 @@ static const char *ExprHelp[] = {
     "    asin(x) "    "    Arc-sine of x, where x is specified in radians",
     "    acos(x) "    "    Arc-cosine of x, where x is specified in radians",
     "    atan(x) "    "    Arc-tangent of x, where x is specified in radians",
+    "    rad(x)  "    "    Convert x from degrees to radians",
+    "    deg(x)  "    "    Convert x from radians to degrees",
+    "    ",
+    "    Coordinates:",
+    "    ",
+    "    clon(x)    "    "    Longitude coordinate of x (available only if x has geographical coordinates) ",
+    "    clat(x)    "    "    Latitude coordinate of x (available only if x has geographical coordinates) ",
+    "    gridarea(x)"    "    Grid cell area of x (available only if x has geographical coordinates) ",
+    "    clev(x)    "    "    Level coordinate of x (0, if x is a 2D surface variable)",
+    "    ",
+    "    Constants:",
+    "    ",
+    "    ngp(x)    "    "    Number of horizontal grid points",
+    "    nlev(x)   "    "    Number of vertical levels",
+    "    size(x)   "    "    Total number of elements (ngp(x)*nlev(x))",
+    "    missval(x)"    "    Returns the missing value of variable x",
+    "    ",
+    "    Statistical values over a field:",
+    "    ",
+    "    fldmin(x), fldmax(x), fldsum(x), fldmean(x), fldavg(x), fldstd(x), fldstd1(x), fldvar(x), fldvar1(x)",
+    "    ",
+    "    Vertical statistical values:",
+    "    ",
+    "    vertmin(x), vertmax(x), vertsum(x), vertmean(x), vertavg(x), vertstd(x), vertstd1(x), vertvar(x), vertvar1(x)",
+    "    ",
+    "    Miscellaneous:",
+    "    ",
+    "    sellevel(x,k) "    "    Select level k of variable x",
+    "    sellevidx(x,k)"    "    Select level index k of variable x",
+    "    remove(x)     "    "    Remove variable x from output stream",
+    "    ",
     "",
     "OPERATORS",
     "    expr    Evaluate expressions",
@@ -1357,7 +1400,7 @@ static const char *ExprHelp[] = {
 static const char *MathHelp[] = {
     "NAME",
     "    abs, int, nint, pow, sqr, sqrt, exp, ln, log10, sin, cos, tan, asin, acos, ",
-    "    reci - Mathematical functions",
+    "    atan, reci - Mathematical functions",
     "",
     "SYNOPSIS",
     "    <operator>  ifile ofile",
@@ -1395,6 +1438,8 @@ static const char *MathHelp[] = {
     "           o(t,x) = asin(i(t,x))",
     "    acos   Arc cosine",
     "           o(t,x) = acos(i(t,x))",
+    "    atan   Arc tangent",
+    "           o(t,x) = atan(i(t,x))",
     "    reci   Reciprocal value",
     "           o(t,x) = 1 / i(t,x)",
     NULL
@@ -1673,19 +1718,19 @@ static const char *EnsstatHelp[] = {
     "    ensavg   Ensemble average",
     "             o(t,x) = avg{i1(t,x), i2(t,x), ..., in(t,x)}",
     "    ensstd   Ensemble standard deviation",
-    "             Divisor is n.",
+    "             Normalize by n.",
     "             ",
     "             o(t,x) = std{i1(t,x), i2(t,x), ..., in(t,x)}",
-    "    ensstd1  Ensemble standard deviation",
-    "             Divisor is (n-1).",
+    "    ensstd1  Ensemble standard deviation (n-1)",
+    "             Normalize by (n-1).",
     "             ",
     "             o(t,x) = std1{i1(t,x), i2(t,x), ..., in(t,x)}",
     "    ensvar   Ensemble variance",
-    "             Divisor is n.",
+    "             Normalize by n.",
     "             ",
     "             o(t,x) = var{i1(t,x), i2(t,x), ..., in(t,x)}",
-    "    ensvar1  Ensemble variance",
-    "             Divisor is (n-1).",
+    "    ensvar1  Ensemble variance (n-1)",
+    "             Normalize by (n-1).",
     "             ",
     "             o(t,x) = var1{i1(t,x), i2(t,x), ..., in(t,x)}",
     "    enspctl  Ensemble percentiles",
@@ -1837,22 +1882,22 @@ static const char *FldstatHelp[] = {
     "             o(t,1) = avg{i(t,x'), x_1<x'<=x_n}",
     "             weighted by area weights obtained by the input field.",
     "    fldstd   Field standard deviation",
-    "             Divisor is n. For every gridpoint x_1, ..., x_n of the same field it is:",
+    "             Normalize by n. For every gridpoint x_1, ..., x_n of the same field it is:",
     "             ",
     "             o(t,1) = std{i(t,x'), x_1<x'<=x_n}",
     "             weighted by area weights obtained by the input field.",
-    "    fldstd1  Field standard deviation",
-    "             Divisor is (n-1). For every gridpoint x_1, ..., x_n of the same field it is:",
+    "    fldstd1  Field standard deviation (n-1)",
+    "             Normalize by (n-1). For every gridpoint x_1, ..., x_n of the same field it is:",
     "             ",
     "             o(t,1) = std1{i(t,x'), x_1<x'<=x_n}",
     "             weighted by area weights obtained by the input field.",
     "    fldvar   Field variance",
-    "             Divisor is n. For every gridpoint x_1, ..., x_n of the same field it is:",
+    "             Normalize by n. For every gridpoint x_1, ..., x_n of the same field it is:",
     "             ",
     "             o(t,1) = var{i(t,x'), x_1<x'<=x_n}",
     "             weighted by area weights obtained by the input field.",
-    "    fldvar1  Field variance",
-    "             Divisor is (n-1). For every gridpoint x_1, ..., x_n of the same field it is:",
+    "    fldvar1  Field variance (n-1)",
+    "             Normalize by (n-1). For every gridpoint x_1, ..., x_n of the same field it is:",
     "             ",
     "             o(t,1) = var1{i(t,x'), x_1<x'<=x_n}",
     "             weighted by area weights obtained by the input field.",
@@ -1893,13 +1938,13 @@ static const char *ZonstatHelp[] = {
     "    zonavg   Zonal average",
     "             For every latitude the average over all longitudes is computed.",
     "    zonstd   Zonal standard deviation",
-    "             For every latitude the standard deviation over all longitudes is computed. Divisor is n.",
-    "    zonstd1  Zonal standard deviation",
-    "             For every latitude the standard deviation over all longitudes is computed. Divisor is (n-1). ",
+    "             For every latitude the standard deviation over all longitudes is computed. Normalize by n.",
+    "    zonstd1  Zonal standard deviation (n-1)",
+    "             For every latitude the standard deviation over all longitudes is computed. Normalize by (n-1). ",
     "    zonvar   Zonal variance",
-    "             For every latitude the variance over all longitudes is computed. Divisor is n.",
-    "    zonvar1  Zonal variance",
-    "             For every latitude the variance over all longitudes is computed. Divisor is (n-1).",
+    "             For every latitude the variance over all longitudes is computed. Normalize by n.",
+    "    zonvar1  Zonal variance (n-1)",
+    "             For every latitude the variance over all longitudes is computed. Normalize by (n-1).",
     "    zonpctl  Zonal percentiles",
     "             For every latitude the pth percentile over all longitudes is computed.",
     "",
@@ -1935,13 +1980,13 @@ static const char *MerstatHelp[] = {
     "    meravg   Meridional average",
     "             For every longitude the area weighted average over all latitudes is computed.",
     "    merstd   Meridional standard deviation",
-    "             For every longitude the standard deviation over all latitudes is computed. Divisor is n.",
-    "    merstd1  Meridional standard deviation",
-    "             For every longitude the standard deviation over all latitudes is computed. Divisor is (n-1).",
+    "             For every longitude the standard deviation over all latitudes is computed. Normalize by n.",
+    "    merstd1  Meridional standard deviation (n-1)",
+    "             For every longitude the standard deviation over all latitudes is computed. Normalize by (n-1).",
     "    mervar   Meridional variance",
-    "             For every longitude the variance over all latitudes is computed. Divisor is n.",
-    "    mervar1  Meridional variance",
-    "             For every longitude the variance over all latitudes is computed. Divisor is (n-1).",
+    "             For every longitude the variance over all latitudes is computed. Normalize by n.",
+    "    mervar1  Meridional variance (n-1)",
+    "             For every longitude the variance over all latitudes is computed. Normalize by (n-1).",
     "    merpctl  Meridional percentiles",
     "             For every longitude the pth percentile over all latitudes is computed.",
     "",
@@ -1976,13 +2021,13 @@ static const char *GridboxstatHelp[] = {
     "    gridboxavg   Gridbox average",
     "                 Average of the selected grid boxes.",
     "    gridboxstd   Gridbox standard deviation",
-    "                 Standard deviation of the selected grid boxes. Divisor is n.",
-    "    gridboxstd1  Gridbox standard deviation",
-    "                 Standard deviation of the selected grid boxes. Divisor is (n-1).",
+    "                 Standard deviation of the selected grid boxes. Normalize by n.",
+    "    gridboxstd1  Gridbox standard deviation (n-1)",
+    "                 Standard deviation of the selected grid boxes. Normalize by (n-1).",
     "    gridboxvar   Gridbox variance",
-    "                 Variance of the selected grid boxes. Divisor is n.",
-    "    gridboxvar1  Gridbox variance",
-    "                 Variance of the selected grid boxes. Divisor is (n-1).",
+    "                 Variance of the selected grid boxes. Normalize by n.",
+    "    gridboxvar1  Gridbox variance (n-1)",
+    "                 Variance of the selected grid boxes. Normalize by (n-1).",
     "",
     "PARAMETER",
     "    nx  INTEGER  Number of grid boxes in x direction",
@@ -2015,13 +2060,13 @@ static const char *VertstatHelp[] = {
     "    vertavg   Vertical average",
     "              For every gridpoint the layer weighted average over all levels is computed.",
     "    vertstd   Vertical standard deviation",
-    "              For every gridpoint the standard deviation over all levels is computed. Divisor is n.",
-    "    vertstd1  Vertical standard deviation",
-    "              For every gridpoint the standard deviation over all levels is computed. Divisor is (n-1).",
+    "              For every gridpoint the standard deviation over all levels is computed. Normalize by n.",
+    "    vertstd1  Vertical standard deviation (n-1)",
+    "              For every gridpoint the standard deviation over all levels is computed. Normalize by (n-1).",
     "    vertvar   Vertical variance",
-    "              For every gridpoint the variance over all levels is computed. Divisor is n.",
-    "    vertvar1  Vertical variance",
-    "              For every gridpoint the variance over all levels is computed. Divisor is (n-1).",
+    "              For every gridpoint the variance over all levels is computed. Normalize by n.",
+    "    vertvar1  Vertical variance (n-1)",
+    "              For every gridpoint the variance over all levels is computed. Normalize by (n-1).",
     NULL
 };
 
@@ -2066,22 +2111,22 @@ static const char *TimselstatHelp[] = {
     "                ",
     "                o(t,x) = avg{i(t',x), t1 < t' <= tn}",
     "    timselstd   Time range standard deviation",
-    "                Divisor is n. For every adjacent sequence t1, ...., tn of timesteps of the same ",
+    "                Normalize by n. For every adjacent sequence t1, ...., tn of timesteps of the same ",
     "                selected time range it is",
     "                ",
     "                o(t,x) = std{i(t',x), t1 < t' <= tn}",
-    "    timselstd1  Time range standard deviation",
-    "                Divisor is (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same ",
+    "    timselstd1  Time range standard deviation (n-1)",
+    "                Normalize by (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same ",
     "                selected time range it is",
     "                ",
     "                o(t,x) = std1{i(t',x), t1 < t' <= tn}",
     "    timselvar   Time range variance",
-    "                Divisor is n. For every adjacent sequence t1, ...., tn of timesteps of the same ",
+    "                Normalize by n. For every adjacent sequence t1, ...., tn of timesteps of the same ",
     "                selected time range it is",
     "                ",
     "                o(t,x) = var{i(t',x), t1 < t' <= tn}",
-    "    timselvar1  Time range variance",
-    "                Divisor is (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same ",
+    "    timselvar1  Time range variance (n-1)",
+    "                Normalize by (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same ",
     "                selected time range it is",
     "                ",
     "                o(t,x) = var1{i(t',x), t1 < t' <= tn}",
@@ -2150,19 +2195,19 @@ static const char *RunstatHelp[] = {
     "    runavg   Running average",
     "             o(t+(nts-1)/2,x) = avg{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}",
     "    runstd   Running standard deviation",
-    "             Divisor is n. ",
+    "             Normalize by n. ",
     "             ",
     "             o(t+(nts-1)/2,x) = std{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}",
-    "    runstd1  Running standard deviation",
-    "             Divisor is (n-1). ",
+    "    runstd1  Running standard deviation (n-1)",
+    "             Normalize by (n-1). ",
     "             ",
     "             o(t+(nts-1)/2,x) = std1{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}",
     "    runvar   Running variance",
-    "             Divisor is n. ",
+    "             Normalize by n. ",
     "             ",
     "             o(t+(nts-1)/2,x) = var{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}",
-    "    runvar1  Running variance",
-    "             Divisor is (n-1). ",
+    "    runvar1  Running variance (n-1)",
+    "             Normalize by (n-1). ",
     "             ",
     "             o(t+(nts-1)/2,x) = var1{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}",
     "",
@@ -2220,19 +2265,19 @@ static const char *TimstatHelp[] = {
     "    timavg   Time average",
     "             o(1,x) = avg{i(t',x), t_1<t'<=t_n}",
     "    timstd   Time standard deviation",
-    "             Divisor is n. ",
+    "             Normalize by n. ",
     "             ",
     "             o(1,x) = std{i(t',x), t_1<t'<=t_n}",
-    "    timstd1  Time standard deviation",
-    "             Divisor is (n-1). ",
+    "    timstd1  Time standard deviation (n-1)",
+    "             Normalize by (n-1). ",
     "             ",
     "             o(1,x) = std1{i(t',x), t_1<t'<=t_n}",
     "    timvar   Time variance",
-    "             Divisor is n. ",
+    "             Normalize by n. ",
     "             ",
     "             o(1,x) = var{i(t',x), t_1<t'<=t_n}",
-    "    timvar1  Time variance",
-    "             Divisor is (n-1). ",
+    "    timvar1  Time variance (n-1)",
+    "             Normalize by (n-1). ",
     "             ",
     "             o(1,x) = var1{i(t',x), t_1<t'<=t_n}",
     NULL
@@ -2300,19 +2345,19 @@ static const char *HourstatHelp[] = {
     "              ",
     "              o(t,x) = avg{i(t',x), t_1<t'<=t_n}",
     "    hourstd   Hourly standard deviation",
-    "              Divisor is n. For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:",
+    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:",
     "              ",
     "              o(t,x) = std{i(t',x), t_1<t'<=t_n}",
-    "    hourstd1  Hourly standard deviation",
-    "              Divisor is (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:",
+    "    hourstd1  Hourly standard deviation (n-1)",
+    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:",
     "              ",
     "              o(t,x) = std1{i(t',x), t_1<t'<=t_n}",
     "    hourvar   Hourly variance",
-    "              Divisor is n. For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:",
+    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:",
     "              ",
     "              o(t,x) = var{i(t',x), t_1<t'<=t_n}",
-    "    hourvar1  Hourly variance",
-    "              Divisor is (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:",
+    "    hourvar1  Hourly variance (n-1)",
+    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:",
     "              ",
     "              o(t,x) = var1{i(t',x), t_1<t'<=t_n}",
     NULL
@@ -2383,19 +2428,19 @@ static const char *DaystatHelp[] = {
     "             ",
     "             o(t,x) = avg{i(t',x), t_1<t'<=t_n}",
     "    daystd   Daily standard deviation",
-    "             Divisor is n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
     "             ",
     "             o(t,x) = std{i(t',x), t_1<t'<=t_n}",
-    "    daystd1  Daily standard deviation",
-    "             Divisor is (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "    daystd1  Daily standard deviation (n-1)",
+    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
     "             ",
     "             o(t,x) = std1{i(t',x), t_1<t'<=t_n}",
     "    dayvar   Daily variance",
-    "             Divisor is n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
     "             ",
     "             o(t,x) = var{i(t',x), t_1<t'<=t_n}",
-    "    dayvar1  Daily variance",
-    "             Divisor is (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "    dayvar1  Daily variance (n-1)",
+    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
     "             ",
     "             o(t,x) = var1{i(t',x), t_1<t'<=t_n}",
     NULL
@@ -2466,19 +2511,19 @@ static const char *MonstatHelp[] = {
     "             ",
     "             o(t,x) = avg{i(t',x), t_1<t'<=t_n}",
     "    monstd   Monthly standard deviation",
-    "             Divisor is n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
     "             ",
     "             o(t,x) = std{i(t',x), t_1 < t' <= t_n}",
-    "    monstd1  Monthly standard deviation",
-    "             Divisor is (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "    monstd1  Monthly standard deviation (n-1)",
+    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
     "             ",
     "             o(t,x) = std1{i(t',x), t_1 < t' <= t_n}",
     "    monvar   Monthly variance",
-    "             Divisor is n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
     "             ",
     "             o(t,x) = var{i(t',x), t_1 < t' <= t_n}",
-    "    monvar1  Monthly variance",
-    "             Divisor is (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "    monvar1  Monthly variance (n-1)",
+    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
     "             ",
     "             o(t,x) = var1{i(t',x), t_1 < t' <= t_n}",
     NULL
@@ -2571,19 +2616,19 @@ static const char *YearstatHelp[] = {
     "              ",
     "              o(t,x) = avg{i(t',x), t_1<t'<=t_n}",
     "    yearstd   Yearly standard deviation",
-    "              Divisor is n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
     "              ",
     "              o(t,x) = std{i(t',x), t_1 < t' <= t_n}",
-    "    yearstd1  Yearly standard deviation",
-    "              Divisor is (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "    yearstd1  Yearly standard deviation (n-1)",
+    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
     "              ",
     "              o(t,x) = std1{i(t',x), t_1 < t' <= t_n}",
     "    yearvar   Yearly variance",
-    "              Divisor is n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
     "              ",
     "              o(t,x) = var{i(t',x), t_1 < t' <= t_n}",
-    "    yearvar1  Yearly variance",
-    "              Divisor is (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "    yearvar1  Yearly variance (n-1)",
+    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
     "              ",
     "              o(t,x) = var1{i(t',x), t_1 < t' <= t_n}",
     "",
@@ -2634,7 +2679,7 @@ static const char *SeasstatHelp[] = {
     "    Depending on the chosen operator the minimum, maximum, sum, average, variance",
     "    or standard deviation of timesteps of the same season is written to ofile.",
     "    The time stamp in ofile is from the middle contributing timestep of ifile.",
-    "    Be careful about the first and the last output timestep , they may be incorrect values ",
+    "    Be careful about the first and the last output timestep, they may be incorrect values ",
     "    if the seasons have incomplete timesteps.",
     "",
     "OPERATORS",
@@ -2659,19 +2704,19 @@ static const char *SeasstatHelp[] = {
     "              ",
     "              o(t,x) = avg{i(t',x), t1 < t' <= tn}",
     "    seasstd   Seasonal standard deviation",
-    "              Divisor is n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
     "              ",
     "              o(t,x) = std{i(t',x), t1 < t' <= tn}",
-    "    seasstd1  Seasonal standard deviation",
-    "              Divisor is (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "    seasstd1  Seasonal standard deviation (n-1)",
+    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
     "              ",
     "              o(t,x) = std1{i(t',x), t1 < t' <= tn}",
     "    seasvar   Seasonal variance",
-    "              Divisor is n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
     "              ",
     "              o(t,x) = var{i(t',x), t1 < t' <= tn}",
-    "    seasvar1  Seasonal variance",
-    "              Divisor is (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "    seasvar1  Seasonal variance (n-1)",
+    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
     "              ",
     "              o(t,x) = var1{i(t',x), t1 < t' <= tn}",
     NULL
@@ -2691,7 +2736,7 @@ static const char *SeaspctlHelp[] = {
     "    the environment variable CDO_PCTL_NBINS to a different value. The files ifile2 and ",
     "    ifile3 should be the result of corresponding seasmin and seasmax operations, respectively.",
     "    The time stamp in ofile is from the middle contributing timestep of ifile1.",
-    "    Be careful about the first and the last output timestep , they may be incorrect values ",
+    "    Be careful about the first and the last output timestep, they may be incorrect values ",
     "    if the seasons have incomplete timesteps.",
     "    For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
     "    ",
@@ -2742,25 +2787,25 @@ static const char *YhourstatHelp[] = {
     "                                ...",
     "               o(8784,x) = avg{i(t,x), day(i(t)) = 8784}",
     "    yhourstd   Multi-year hourly standard deviation",
-    "               Divisor is n. ",
+    "               Normalize by n. ",
     "               ",
     "               o(0001,x) = std{i(t,x), day(i(t)) = 0001}",
     "                                ...",
     "               o(8784,x) = std{i(t,x), day(i(t)) = 8784}",
-    "    yhourstd1  Multi-year hourly standard deviation",
-    "               Divisor is (n-1). ",
+    "    yhourstd1  Multi-year hourly standard deviation (n-1)",
+    "               Normalize by (n-1). ",
     "               ",
     "               o(0001,x) = std1{i(t,x), day(i(t)) = 0001}",
     "                                ...",
     "               o(8784,x) = std1{i(t,x), day(i(t)) = 8784}",
     "    yhourvar   Multi-year hourly variance",
-    "               Divisor is n. ",
+    "               Normalize by n. ",
     "               ",
     "               o(0001,x) = var{i(t,x), day(i(t)) = 0001}",
     "                                ...",
     "               o(8784,x) = var{i(t,x), day(i(t)) = 8784}",
-    "    yhourvar1  Multi-year hourly variance",
-    "               Divisor is (n-1). ",
+    "    yhourvar1  Multi-year hourly variance (n-1)",
+    "               Normalize by (n-1). ",
     "               ",
     "               o(0001,x) = var1{i(t,x), day(i(t)) = 0001}",
     "                                ...",
@@ -2804,25 +2849,25 @@ static const char *YdaystatHelp[] = {
     "                               ...",
     "              o(366,x) = avg{i(t,x), day(i(t)) = 366}",
     "    ydaystd   Multi-year daily standard deviation",
-    "              Divisor is n. ",
+    "              Normalize by n. ",
     "              ",
     "              o(001,x) = std{i(t,x), day(i(t)) = 001}",
     "                               ...",
     "              o(366,x) = std{i(t,x), day(i(t)) = 366}",
-    "    ydaystd1  Multi-year daily standard deviation",
-    "              Divisor is (n-1). ",
+    "    ydaystd1  Multi-year daily standard deviation (n-1)",
+    "              Normalize by (n-1). ",
     "              ",
     "              o(001,x) = std1{i(t,x), day(i(t)) = 001}",
     "                               ...",
     "              o(366,x) = std1{i(t,x), day(i(t)) = 366}",
     "    ydayvar   Multi-year daily variance",
-    "              Divisor is n. ",
+    "              Normalize by n. ",
     "              ",
     "              o(001,x) = var{i(t,x), day(i(t)) = 001}",
     "                               ...",
     "              o(366,x) = var{i(t,x), day(i(t)) = 366}",
-    "    ydayvar1  Multi-year daily variance",
-    "              Divisor is (n-1). ",
+    "    ydayvar1  Multi-year daily variance (n-1)",
+    "              Normalize by (n-1). ",
     "              ",
     "              o(001,x) = var1{i(t,x), day(i(t)) = 001}",
     "                               ...",
@@ -2895,25 +2940,25 @@ static const char *YmonstatHelp[] = {
     "                               ...",
     "              o(12,x) = avg{i(t,x), month(i(t)) = 12}",
     "    ymonstd   Multi-year monthly standard deviation",
-    "              Divisor is n. ",
+    "              Normalize by n. ",
     "              ",
     "              o(01,x) = std{i(t,x), month(i(t)) = 01}",
     "                               ...",
     "              o(12,x) = std{i(t,x), month(i(t)) = 12}",
-    "    ymonstd1  Multi-year monthly standard deviation",
-    "              Divisor is (n-1). ",
+    "    ymonstd1  Multi-year monthly standard deviation (n-1)",
+    "              Normalize by (n-1). ",
     "              ",
     "              o(01,x) = std1{i(t,x), month(i(t)) = 01}",
     "                               ...",
     "              o(12,x) = std1{i(t,x), month(i(t)) = 12}",
     "    ymonvar   Multi-year monthly variance",
-    "              Divisor is n. ",
+    "              Normalize by n. ",
     "              ",
     "              o(01,x) = var{i(t,x), month(i(t)) = 01}",
     "                               ...",
     "              o(12,x) = var{i(t,x), month(i(t)) = 12}",
-    "    ymonvar1  Multi-year monthly variance",
-    "              Divisor is (n-1). ",
+    "    ymonvar1  Multi-year monthly variance (n-1)",
+    "              Normalize by (n-1). ",
     "              ",
     "              o(01,x) = var1{i(t,x), month(i(t)) = 01}",
     "                               ...",
@@ -2997,7 +3042,7 @@ static const char *YseasstatHelp[] = {
     "               o(2,x) = std{i(t,x), month(i(t)) = 03, 04, 05}",
     "               o(3,x) = std{i(t,x), month(i(t)) = 06, 07, 08}",
     "               o(4,x) = std{i(t,x), month(i(t)) = 09, 10, 11}",
-    "    yseasstd1  Multi-year seasonal standard deviation",
+    "    yseasstd1  Multi-year seasonal standard deviation (n-1)",
     "               o(1,x) = std1{i(t,x), month(i(t)) = 12, 01, 02}",
     "               o(2,x) = std1{i(t,x), month(i(t)) = 03, 04, 05}",
     "               o(3,x) = std1{i(t,x), month(i(t)) = 06, 07, 08}",
@@ -3007,7 +3052,7 @@ static const char *YseasstatHelp[] = {
     "               o(2,x) = var{i(t,x), month(i(t)) = 03, 04, 05}",
     "               o(3,x) = var{i(t,x), month(i(t)) = 06, 07, 08}",
     "               o(4,x) = var{i(t,x), month(i(t)) = 09, 10, 11}",
-    "    yseasvar1  Multi-year seasonal variance",
+    "    yseasvar1  Multi-year seasonal variance (n-1)",
     "               o(1,x) = var1{i(t,x), month(i(t)) = 12, 01, 02}",
     "               o(2,x) = var1{i(t,x), month(i(t)) = 03, 04, 05}",
     "               o(3,x) = var1{i(t,x), month(i(t)) = 06, 07, 08}",
@@ -3090,25 +3135,25 @@ static const char *YdrunstatHelp[] = {
     "                                ...",
     "               o(366,x) = avg{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}",
     "    ydrunstd   Multi-year daily running standard deviation",
-    "               Divisor is n. ",
+    "               Normalize by n. ",
     "               ",
     "               o(001,x) = std{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 001}",
     "                                ...",
     "               o(366,x) = std{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 366}",
-    "    ydrunstd1  Multi-year daily running standard deviation",
-    "               Divisor is (n-1). ",
+    "    ydrunstd1  Multi-year daily running standard deviation (n-1)",
+    "               Normalize by (n-1). ",
     "               ",
     "               o(001,x) = std1{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 001}",
     "                                ...",
     "               o(366,x) = std1{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 366}",
     "    ydrunvar   Multi-year daily running variance",
-    "               Divisor is n. ",
+    "               Normalize by n. ",
     "               ",
     "               o(001,x) = var{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}",
     "                                ...",
     "               o(366,x) = var{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}",
-    "    ydrunvar1  Multi-year daily running variance",
-    "               Divisor is (n-1). ",
+    "    ydrunvar1  Multi-year daily running variance (n-1)",
+    "               Normalize by (n-1). ",
     "               ",
     "               o(001,x) = var1{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}",
     "                                ...",
@@ -3411,7 +3456,7 @@ static const char *RemapbilHelp[] = {
     "              Performs a bilinear interpolation on all input fields.",
     "    genbil    Generate bilinear interpolation weights",
     "              Generates bilinear interpolation weights for the first input field and writes the",
-    "              result to a file. The format of this file is netCDF following the SCRIP convention.",
+    "              result to a file. The format of this file is NetCDF following the SCRIP convention.",
     "              Use the operator remap to apply this remapping weights to a data file with the same source grid.",
     "",
     "PARAMETER",
@@ -3442,7 +3487,7 @@ static const char *RemapbicHelp[] = {
     "              Performs a bicubic interpolation on all input fields.",
     "    genbic    Generate bicubic interpolation weights",
     "              Generates bicubic interpolation weights for the first input field and writes the",
-    "              result to a file. The format of this file is netCDF following the SCRIP convention.",
+    "              result to a file. The format of this file is NetCDF following the SCRIP convention.",
     "              Use the operator remap to apply this remapping weights to a data file with the same source grid.",
     "",
     "PARAMETER",
@@ -3471,7 +3516,7 @@ static const char *RemapnnHelp[] = {
     "             Performs a nearest neighbor remapping on all input fields.",
     "    gennn    Generate nearest neighbor remap weights",
     "             Generates nearest neighbor remapping weights for the first input field and writes the result to a file.",
-    "             The format of this file is netCDF following the SCRIP convention.",
+    "             The format of this file is NetCDF following the SCRIP convention.",
     "             Use the operator remap to apply this remapping weights to a data file with the same source grid.",
     "",
     "PARAMETER",
@@ -3507,7 +3552,7 @@ static const char *RemapdisHelp[] = {
     "    gendis    Generate distance-weighted average remap weights",
     "              Generates distance-weighted average remapping weights of the four nearest neighbor",
     "              values for the first input field and writes the result to a file.",
-    "              The format of this file is netCDF following the SCRIP convention.",
+    "              The format of this file is NetCDF following the SCRIP convention.",
     "              Use the operator remap to apply this remapping weights to a data file with the same source grid.",
     "",
     "PARAMETER",
@@ -3542,7 +3587,7 @@ static const char *RemapyconHelp[] = {
     "               Performs a first order conservative remapping on all input fields.",
     "    genycon    Generate 1st order conservative remap weights",
     "               Generates first order conservative remapping weights for the first input field and",
-    "               writes the result to a file. The format of this file is netCDF following the SCRIP convention.",
+    "               writes the result to a file. The format of this file is NetCDF following the SCRIP convention.",
     "               Use the operator remap to apply this remapping weights to a data file with the same source grid.",
     "",
     "PARAMETER",
@@ -3581,7 +3626,7 @@ static const char *RemapconHelp[] = {
     "              Performs a first order conservative remapping on all input fields.",
     "    gencon    Generate 1st order conservative remap weights",
     "              Generates first order conservative remapping weights for the first input field and",
-    "              writes the result to a file. The format of this file is netCDF following the SCRIP convention.",
+    "              writes the result to a file. The format of this file is NetCDF following the SCRIP convention.",
     "              Use the operator remap to apply this remapping weights to a data file with the same source grid.",
     "",
     "PARAMETER",
@@ -3610,8 +3655,7 @@ static const char *Remapcon2Help[] = {
     "    remapcon2, gencon2 - Second order conservative remapping",
     "",
     "SYNOPSIS",
-    "    remapcon2,grid  ifile ofile",
-    "    gencon2,grid2  ifile ofile",
+    "    <operator>,grid  ifile ofile",
     "",
     "DESCRIPTION",
     "    This module contains operators for a second order conservative remapping of fields between grids in spherical coordinates.",
@@ -3625,7 +3669,7 @@ static const char *Remapcon2Help[] = {
     "               Performs a second order conservative remapping on all input fields.",
     "    gencon2    Generate 2nd order conservative remap weights",
     "               Generates second order conservative remapping weights for the first input field and",
-    "               writes the result to a file. The format of this file is netCDF following the SCRIP convention.",
+    "               writes the result to a file. The format of this file is NetCDF following the SCRIP convention.",
     "               Use the operator remap to apply this remapping weights to a data file with the same source grid.",
     "",
     "PARAMETER",
@@ -3667,7 +3711,7 @@ static const char *RemaplafHelp[] = {
     "              Performs a largest area fraction remapping on all input fields.",
     "    genlaf    Generate largest area fraction remap weights",
     "              Generates largest area fraction remapping weights for the first input field and",
-    "              writes the result to a file. The format of this file is netCDF following the SCRIP convention.",
+    "              writes the result to a file. The format of this file is NetCDF following the SCRIP convention.",
     "              Use the operator remap to apply this remapping weights to a data file with the same source grid.",
     "",
     "PARAMETER",
@@ -3694,14 +3738,14 @@ static const char *RemapHelp[] = {
     "    Firstly the generation of the interpolation weights, which is the most time-consuming part.",
     "    These interpolation weights can be reused for every remapping process with the operator remap.",
     "    This operator remaps all input fields to a new horizontal grid. The remap type and ",
-    "    the interpolation weights of one input grid are read from a netCDF file. More weights ",
-    "    are computed if the input fields are on different grids. The netCDF file with the ",
+    "    the interpolation weights of one input grid are read from a NetCDF file. More weights ",
+    "    are computed if the input fields are on different grids. The NetCDF file with the ",
     "    weights should follow the SCRIP convention. Normally these weights come from a previous",
     "    call to one of the genXXX operators (e.g. genbil) or were created by the original SCRIP package.",
     "",
     "PARAMETER",
     "    grid     STRING  Target grid description file or name",
-    "    weights  STRING  Interpolation weights (SCRIP netCDF file)",
+    "    weights  STRING  Interpolation weights (SCRIP NetCDF file)",
     "",
     "ENVIRONMENT",
     "    CDO_REMAP_NORM       ",
@@ -3765,7 +3809,7 @@ static const char *RemapetaHelp[] = {
     "",
     "NOTE",
     "    The code numbers or the variable names of the required parameter have to follow the ECHAM convention.",
-    "    Presently, the vertical coordinate definition of a netCDF file has also to follow the ECHAM convention.",
+    "    Presently, the vertical coordinate definition of a NetCDF file has also to follow the ECHAM convention.",
     "    This means:",
     "    - the dimension of the full level coordinate and the corresponding variable is called mlev,",
     "    - the dimension of the half level coordinate and the corresponding variable is called ilev (ilev must have one element more than mlev)",
@@ -3794,7 +3838,7 @@ static const char *VertintmlHelp[] = {
     "    The input file should contain the log. surface pressure or the surface pressure.",
     "    To interpolate the temperature, the surface geopotential is also needed.",
     "    The pressure, temperature, and surface geopotential are identified by their GRIB1 code number",
-    "    or netCDF CF standard name.",
+    "    or NetCDF CF standard name.",
     "    Supported parameter tables are: WMO standard table number 2 and ECMWF local table number 128.",
     "    Use the alias  ml2plx/ml2hlx or the environment variable EXTRAPOLATE",
     "    to extrapolate missing values. This operator requires all variables on the same horizontal grid.",
@@ -3829,14 +3873,14 @@ static const char *VertintapHelp[] = {
     "DESCRIPTION",
     "    Interpolate 3D variables on hybrid sigma height coordinates to pressure levels.",
     "    The input file must contain the 3D air pressure. The air pressure is identified",
-    "    by the netCDF CF standard name air_pressure.",
+    "    by the NetCDF CF standard name air_pressure.",
     "    This operator requires all variables on the same horizontal grid.",
     "",
     "PARAMETER",
     "    plevels  FLOAT  Pressure levels in pascal",
     "",
     "NOTE",
-    "    This is a specific implementation for netCDF files from the ICON model, it may not work with data from other sources.",
+    "    This is a specific implementation for NetCDF files from the ICON model, it may not work with data from other sources.",
     NULL
 };
 
@@ -4238,6 +4282,28 @@ static const char *OutputtabHelp[] = {
     NULL
 };
 
+static const char *OutputgmtHelp[] = {
+    "NAME",
+    "    gmtxyz, gmtcells - GMT output",
+    "",
+    "SYNOPSIS",
+    "    <operator>  ifile",
+    "",
+    "DESCRIPTION",
+    "    This module prints the first field of the input dataset to standard output.",
+    "    The output can be used to generate 2D Lon/Lat plots with GMT.",
+    "    The format of the output depends on the chosen operator.",
+    "",
+    "OPERATORS",
+    "    gmtxyz    GMT xyz format",
+    "              The operator exports the first field to the GMT xyz ASCII format.",
+    "              The output can be used to create contour plots with the GMT module pscontour.",
+    "    gmtcells  GMT multiple segment format",
+    "              The operator exports the first field to the GMT multiple segment ASCII format.",
+    "              The output can be used to create shaded gridfill plots with the GMT module psxy.",
+    NULL
+};
+
 static const char *GradsdesHelp[] = {
     "NAME",
     "    gradsdes - GrADS data descriptor file",
@@ -4246,7 +4312,7 @@ static const char *GradsdesHelp[] = {
     "    gradsdes[,mapversion]  ifile",
     "",
     "DESCRIPTION",
-    "    Creates a GrADS data descriptor file. Supported file formats are GRIB1, netCDF, SERVICE, ",
+    "    Creates a GrADS data descriptor file. Supported file formats are GRIB1, NetCDF, SERVICE, ",
     "    EXTRA and IEG. For GRIB1 files the GrADS map file is also generated. For SERVICE and EXTRA",
     "    files the grid have to be specified with the CDO option '-g <grid>'. This module takes ifile",
     "    in order to create filenames for the descriptor (ifile.ctl) and the map (ifile.gmp) file.",
@@ -4266,7 +4332,7 @@ static const char *AfterburnerHelp[] = {
     "    after - ECHAM standard post processor",
     "",
     "SYNOPSIS",
-    "    after  ifiles ofile",
+    "    after[,vct]  ifiles ofile",
     "",
     "DESCRIPTION",
     "    The \"afterburner\" is the standard post processor for ECHAM data which provides the following operations:",
@@ -4351,6 +4417,9 @@ static const char *AfterburnerHelp[] = {
     "        0/10/11  & 152  LnPs               &  0",
     "        0/10/11  & 155  divergence         &  0",
     "         >11     & all codes               &  0/1",
+    "",
+    "PARAMETER",
+    "    vct  STRING  File with VCT in ASCII format",
     NULL
 };
 
@@ -4813,6 +4882,162 @@ static const char *HurrHelp[] = {
     NULL
 };
 
+static const char *MagplotHelp[] = {
+    "NAME",
+    "    contour, shaded, grfill - Lat/Lon plot",
+    "",
+    "SYNOPSIS",
+    "    <operator>,params  ifile obase",
+    "",
+    "DESCRIPTION",
+    "    The operators in this module generates 2D Lon/Lat plots.",
+    "    The data for the plot is read from ifile.",
+    "    Only data on rectilinear Lon/Lat grids are supported.",
+    "    The output file will be named <obase>_<param>.<device> where param is the parameter name and",
+    "    device is the device name. The default output file format is postscript,",
+    "    this can be changed with the device parameter.",
+    "    The type of the plot depends on the choosen operator.",
+    "    ",
+    "    Here is a list of all common plot parameters:",
+    "    ",
+    "     Keyname     & Type    & Description      ",
+    "     device      & STRING  & Output device (ps, eps, pdf, png, gif, gif_animation, jpeg, svg, kml)",
+    "     projection  & STRING  & Projection (cylindrical, polar_stereographic, robinson, mercator)",
+    "     style       & STRING  & Contour line style (solid, dash, dot, chain_dash, chain_dot)",
+    "     min         & FLOAT   & Minimum value",
+    "     max         & FLOAT   & Maximum value",
+    "     lon_max     & FLOAT   & Maximum longitude of the image",
+    "     lon_min     & FLOAT   & Minimum longitude of the image",
+    "     lat_max     & FLOAT   & Maximum latitude of the image",
+    "     lat_min     & FLOAT   & Minimum latitude of the image",
+    "     count       & INTEGER & Number of Contour levels / Colour bands  ",
+    "     interval    & FLOAT   & Interval in data units between two bands lines",
+    "     list        & INTEGER & List of levels to be plotted",
+    "     RGB         & STRING  & TRUE or FALSE, to  indicate, if the input colour is in RGB format",
+    "     step_freq   & INTEGER & Frequency of time steps to be considered for making the animation",
+    "                 &         & (device=gif_animation). Default value is \"1\" (all time steps).",
+    "                 &         & Will be ignored if input file has multiple variables.",
+    "     file_split  & STRING  & TRUE or FALSE, to split the output file for each variable, if input has",
+    "                 &         & multiple variables. Default value is \"FALSE\". Valid only for \"PS\" format.",
+    "",
+    "OPERATORS",
+    "    contour  Contour plot",
+    "             The operator contour generates the discrete contour lines of the input field values.",
+    "             The following additional parameters are valid for contour operator,",
+    "             module in addition to the common plot parameters:",
+    "             ",
+    "              Keyname      & Type    & Description      ",
+    "              colour       & STRING  & Colour for drawing the contours",
+    "              thickness    & FLOAT   & Thickness of the contour line",
+    "              style        & STRING  & Line Style can be \"SOLID\", \"DASH\", \"DOT\", \"CHAIN_DASH\",",
+    "                           &         & \"CHAIN_DOT\"",
+    "    shaded   Shaded contour plot",
+    "             The operator shaded generates the filled contours of the given input field values.",
+    "             The following additional parameters are valid for shaded contour and gridfill operator,",
+    "             in addition to the common plot parameters.",
+    "             ",
+    "              Keyname      & Type    & Description      ",
+    "              colour_min   & STRING  & Colour for the Minimum colour band",
+    "              colour_max   & STRING  & Colour for the Minimum colour band",
+    "              colour_triad & STRING  & Direction of colour sequencing for shading \"CW\" or \"ACW\",",
+    "                           &         & to denote \"clockwise\" and \"anticlockwise\" respectively.",
+    "                           &         & To be used in conjunction with \"colour_min\", \"colour_max\"",
+    "                           &         & options. Default is \"ACW\"",
+    "              colour_table & STRING  & File with user specified colours with the format as",
+    "             ",
+    "             Example file for 6 colours in RGB format:",
+    "             	6",
+    "             	RGB(0.0;0.0;1.0)",
+    "             	RGB(0.0;0.0;0.5)",
+    "             	RGB(0.0;0.5;0.5)",
+    "             	RGB(0.0;1.0;0.0)",
+    "             	RGB(0.5;0.5;0.0)",
+    "             	RGB(1.0;0.0;0.0)",
+    "             ",
+    "    grfill   Shaded gridfill plot",
+    "             The operator grfill is similar to satellite imaging and shades each cell (pixel) according",
+    "             to the value of the field at that cell.",
+    "",
+    "PARAMETER",
+    "    params  STRING   Comma separated list of plot parameters",
+    "",
+    "NOTE",
+    "    All colour parameter can be either standard name or in RGB format.",
+    "    The valid standard name strings for \"colour\" are:",
+    "    ",
+    "    \"red\", \"green\", \"blue\", \"yellow\", \"cyan\", \"magenta\", \"black\", \"avocado\", \"beige\",",
+    "    \"brick\", \"brown\", \"burgundy\", \"charcoal\", \"chestnut\", \"coral\", \"cream\", \"evergreen\",",
+    "    \"gold\", \"grey\", \"khaki\", \"kellygreen\", \"lavender\", \"mustard\", \"navy\", \"ochre\",",
+    "    \"olive\", \"peach\", \"pink\", \"rose\", \"rust\", \"sky\", \"tan\", \"tangerine\", \"turquoise\",",
+    "    \"violet\", \"reddishpurple\", \"purplered\", \"purplishred\", \"orangishred\", \"redorange\",",
+    "    \"reddishorange\", \"orange\", \"yellowishorange\", \"orangeyellow\", \"orangishyellow\",",
+    "    \"greenishyellow\", \"yellowgreen\", \"yellowishgreen\", \"bluishgreen\", \"bluegreen\",",
+    "    \"greenishblue\", \"purplishblue\", \"bluepurple\", \"bluishpurple\", \"purple\", \"white\"",
+    NULL
+};
+
+static const char *MagvectorHelp[] = {
+    "NAME",
+    "    vector - Lat/Lon vector plot",
+    "",
+    "SYNOPSIS",
+    "    vector,params  ifile obase",
+    "",
+    "DESCRIPTION",
+    "    This operator generates 2D Lon/Lat vector plots.",
+    "    The data for the plot is read from ifile. The input is expected to contain two velocity",
+    "    components. Only data on rectilinear Lon/Lat grids are supported.",
+    "    The output file will be named <obase>.<device> where device is the device name. ",
+    "    The default output file format is postscript, this can be changed with the device parameter.",
+    "    ",
+    "    Here is a list of all vector plot parameters:",
+    "    ",
+    "     Keyname     & Type    & Description      ",
+    "     device      & STRING  & Output device (ps, eps, pdf, png, gif, gif_animation, jpeg, svg, kml)",
+    "     projection  & STRING  & Projection (cylindrical, polar_stereographic, robinson, mercator)",
+    "     thin_fac    & FLOAT   & Controls the actual number of wind arrows or flags plotted (default 2).",
+    "     unit_vec    & FLOAT   & Wind speed in m/s represented by a unit vector (1.0cm)",
+    "     step_freq   & INTEGER & Frequency of time steps to be considered for making the animation",
+    "                 &         & (device=gif_animation). Default value is \"1\" (all time steps).",
+    "                 &         & Will be ignored if input file has multiple variables.",
+    "",
+    "PARAMETER",
+    "    params  STRING   Comma separated list of plot parameters",
+    NULL
+};
+
+static const char *MaggraphHelp[] = {
+    "NAME",
+    "    graph - Line graph plot",
+    "",
+    "SYNOPSIS",
+    "    graph,params  ifiles ofile",
+    "",
+    "DESCRIPTION",
+    "    This operator generates line graph plots.",
+    "    The data for the plot is read from ifiles. The result is written to ofile.",
+    "    The default output file format is postscript, this can be changed with the device parameter.",
+    "    ",
+    "    Here is a list of all graph plot parameters:",
+    "    ",
+    "     Keyname    & Type    & Description      ",
+    "     device     & STRING  & Output device (ps, eps, pdf, png, gif, gif_animation, jpeg, svg, kml)",
+    "     ymin       & FLOAT   & Minimum value of the y-axis data ",
+    "     ymax       & FLOAT   & Maximum value of the y-axis data ",
+    "     stat       & STRING  & \"TRUE\" or \"FALSE\", to switch on the mean computation. Default is \"FALSE\".",
+    "                &         & Will be overridden to \"FALSE\", if input files have unequal number of time",
+    "                &         & steps or different start/end times. ",
+    "     sigma      & FLOAT   & Standard deviation value for generating shaded back ground around the mean value.",
+    "                &         & To be used in conjunction with 'stat=\"TRUE\"' ",
+    "     obsv       & STRING  & To indicate if the input files have an observation data, by setting to \"TRUE\".",
+    "                &         & Default value is \"FALSE\". The observation data should be the first file in the",
+    "                &         & input file list. The observation data is always plotted in black colour. ",
+    "",
+    "PARAMETER",
+    "    params  STRING   Comma separated list of plot parameters",
+    NULL
+};
+
 static const char *EcaCddHelp[] = {
     "NAME",
     "    eca_cdd - Consecutive dry days index per time period",
diff --git a/src/pipe.c b/src/pipe.c
index 8ca8f67..44120cb 100644
--- a/src/pipe.c
+++ b/src/pipe.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/pipe.h b/src/pipe.h
index 8bb7891..964878f 100644
--- a/src/pipe.h
+++ b/src/pipe.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/printinfo.h b/src/printinfo.h
index c68c2ec..4b5055f 100644
--- a/src/printinfo.h
+++ b/src/printinfo.h
@@ -3,18 +3,6 @@
 #define DATE_FORMAT "%5.4d-%2.2d-%2.2d"
 #define TIME_FORMAT "%2.2d:%2.2d:%2.2d"
 
-void uuid2str(const unsigned char uuid[CDI_UUID_SIZE], char *uuidstr);
-
-static inline
-int cdiUUIDIsNull(const unsigned char uuid[CDI_UUID_SIZE])
-{
-  int isNull = 1;
-  for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
-    isNull &= (uuid[i] == 0);
-  return isNull;
-}
-
-
 void datetime2str(int date, int time, char *datetimestr, int maxlen)
 {
   int year, month, day;
@@ -63,16 +51,16 @@ void printFiletype(int streamID, int vlistID)
       printf("GRIB2");
       break;
     case FILETYPE_NC:
-      printf("netCDF");
+      printf("NetCDF");
       break;
     case FILETYPE_NC2:
-      printf("netCDF2");
+      printf("NetCDF2");
       break;
     case FILETYPE_NC4:
-      printf("netCDF4");
+      printf("NetCDF4");
       break;
     case FILETYPE_NC4C:
-      printf("netCDF4 classic");
+      printf("NetCDF4 classic");
       break;
     case FILETYPE_SRV:
       printf("SERVICE");
@@ -385,7 +373,7 @@ void printGridInfo(int vlistID)
       if ( !cdiUUIDIsNull(uuidOfHGrid) )
         {
           char uuidOfHGridStr[37];
-          uuid2str(uuidOfHGrid, uuidOfHGridStr);
+          cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
           if ( uuidOfHGridStr[0] != 0  && strlen(uuidOfHGridStr) == 36 )
             {
 	      fprintf(stdout, "%33s : %s\n", "uuid", uuidOfHGridStr);
@@ -502,7 +490,7 @@ void printZaxisInfo(int vlistID)
           if ( !cdiUUIDIsNull(uuidOfVGrid) )
             {
               char uuidOfVGridStr[37];
-              uuid2str(uuidOfVGrid, uuidOfVGridStr);
+              cdiUUID2Str(uuidOfVGrid, uuidOfVGridStr);
               if ( uuidOfVGridStr[0] != 0  && strlen(uuidOfVGridStr) == 36 )
                 {
                   fprintf(stdout, "%33s : ", "uuid");
diff --git a/src/process.c b/src/process.c
index a6b4af6..19410e0 100644
--- a/src/process.c
+++ b/src/process.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -352,10 +352,11 @@ argument_t *glob_pattern(const char *restrict string)
   char **p;
 
   wordexp_t glob_results;
+  glob_results.we_wordc = 0;
   argument_t *argument = NULL;
 
   // glob the input argument or do even more shell magic
-  wordexp(string, &glob_results, flags);
+  int status = wordexp(string, &glob_results, flags);
 
   // How much space do we need?
   for ( p = glob_results.we_wordv, cnt = glob_results.we_wordc; cnt; p++, cnt-- )
@@ -374,7 +375,7 @@ argument_t *glob_pattern(const char *restrict string)
       if ( cnt < glob_results.we_wordc-1 ) strcat(argument->args, " ");
     }
 
-  wordfree(&glob_results);
+  if ( status == 0 ) wordfree(&glob_results);
 
   return argument;
 }
diff --git a/src/process.h b/src/process.h
index 5b0e830..e4ff3cb 100644
--- a/src/process.h
+++ b/src/process.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/pstream.c b/src/pstream.c
index 9c222e5..d66055a 100644
--- a/src/pstream.c
+++ b/src/pstream.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -141,7 +141,7 @@ pstream_t *pstream_to_pointer(int idx)
   else
     Error("pstream index %d undefined!", idx);
 
-  return (pstreamptr);
+  return pstreamptr;
 }
 
 /* Create an index from a pointer */
@@ -173,7 +173,7 @@ int pstream_from_pointer(pstream_t *ptr)
   else
     Error("Internal problem (pointer %p undefined)", ptr);
 
-  return (idx);
+  return idx;
 }
 
 static
@@ -210,7 +210,7 @@ pstream_t *pstream_new_entry(void)
 
   if ( pstreamptr ) pstream_init_entry(pstreamptr);
 
-  return (pstreamptr);
+  return pstreamptr;
 }
 
 static
@@ -274,7 +274,7 @@ int pstreamFindID(const char *name)
 
   if ( pstreamID == _pstream_max ) pstreamID = -1;
 
-  return (pstreamID);
+  return pstreamID;
 }
 
 
@@ -282,7 +282,7 @@ int pstreamIsPipe(int pstreamID)
 {
   pstream_t *pstreamptr = pstream_to_pointer(pstreamID);
 
-  return (pstreamptr->ispipe);
+  return pstreamptr->ispipe;
 }
 
 
@@ -524,8 +524,12 @@ int pstreamOpenRead(const argument_t *argument)
 	pthread_mutex_lock(&streamOpenReadMutex);
 #endif
       int fileID = streamOpenRead(filename);
-      if ( fileID < 0 ) cdiOpenError(fileID, "Open failed on >%s<", filename);
-
+      if ( fileID < 0 )
+        {
+          pstreamptr->isopen = FALSE;
+          cdiOpenError(fileID, "Open failed on >%s<", filename);
+        }
+      
       if ( cdoDefaultFileType == CDI_UNDEFID )
 	cdoDefaultFileType = streamInqFiletype(fileID);
       /*
@@ -547,7 +551,7 @@ int pstreamOpenRead(const argument_t *argument)
 
   if ( pstreamID < 0 ) cdiOpenError(pstreamID, "Open failed on >%s<", argument->args);
   
-  return (pstreamID);
+  return pstreamID;
 }
 
 static
@@ -698,13 +702,13 @@ int pstreamOpenWrite(const argument_t *argument, int filetype)
 
 	  if ( cdoCompType == COMPRESS_SZIP &&
 	       (filetype != FILETYPE_GRB && filetype != FILETYPE_GRB2 && filetype != FILETYPE_NC4 && filetype != FILETYPE_NC4C) )
-	    cdoWarning("SZIP compression not available for non GRIB/netCDF4 data!");
+	    cdoWarning("SZIP compression not available for non GRIB/NetCDF4 data!");
 
 	  if ( cdoCompType == COMPRESS_JPEG && filetype != FILETYPE_GRB2 )
 	    cdoWarning("JPEG compression not available for non GRIB2 data!");
 
 	  if ( cdoCompType == COMPRESS_ZIP && (filetype != FILETYPE_NC4 && filetype != FILETYPE_NC4C) )
-	    cdoWarning("Deflate compression not available for non netCDF4 data!");
+	    cdoWarning("Deflate compression not available for non NetCDF4 data!");
 	}
       /*
       if ( cdoDefaultInstID != CDI_UNDEFID )
@@ -718,7 +722,7 @@ int pstreamOpenWrite(const argument_t *argument, int filetype)
       pstreamptr->filetype = filetype;
    }
 
-  return (pstreamID);
+  return pstreamID;
 }
 
 
@@ -771,7 +775,7 @@ int pstreamOpenAppend(const argument_t *argument)
       pstreamptr->fileID = fileID;
     }
 
-  return (pstreamID);
+  return pstreamID;
 }
 
 
@@ -1157,6 +1161,34 @@ void pstreamReadRecord(int pstreamID, double *data, int *nmiss)
 }
 
 
+void pstreamReadRecordF(int pstreamID, float *data, int *nmiss)
+{
+  if ( data == NULL ) cdoAbort("Data pointer not allocated (pstreamReadRecord)!");
+
+  pstream_t *pstreamptr = pstream_to_pointer(pstreamID);
+
+#if defined(HAVE_LIBPTHREAD)
+  if ( pstreamptr->ispipe )
+    {
+      cdoAbort("pipeReadRecord not implemented for memtype float!");
+      // pipeReadRecord(pstreamptr, data, nmiss);
+    }
+  else
+#endif
+    {
+      if ( processNums() == 1 && ompNumThreads == 1 ) timer_start(timer_read);
+#if defined(HAVE_LIBPTHREAD)
+      if ( cdoLockIO ) pthread_mutex_lock(&streamMutex);
+#endif
+      streamReadRecordF(pstreamptr->fileID, data, nmiss);
+#if defined(HAVE_LIBPTHREAD)
+      if ( cdoLockIO ) pthread_mutex_unlock(&streamMutex);
+#endif
+      if ( processNums() == 1 && ompNumThreads == 1 ) timer_stop(timer_read);
+    }
+}
+
+
 void pstreamCheckDatarange(pstream_t *pstreamptr, int varID, double *array, int nmiss)
 {
   long i;
@@ -1383,7 +1415,7 @@ int pstreamInqTimestep(int pstreamID, int tsID)
       pstreamptr->tsID = tsID;
     }
 
-  return (nrecs);
+  return nrecs;
 }
 
 
@@ -1645,7 +1677,7 @@ int pstreamInqFiletype(int pstreamID)
 #endif
     filetype = streamInqFiletype(pstreamptr->fileID);
 
-  return (filetype);
+  return filetype;
 }
 
 
@@ -1662,9 +1694,10 @@ int pstreamInqByteorder(int pstreamID)
 #endif
     byteorder = streamInqByteorder(pstreamptr->fileID);
 
-  return (byteorder);
+  return byteorder;
 }
 
+ 
 void pstreamInqGRIBinfo(int pstreamID, int *intnum, float *fltnum, off_t *bignum)
 {
   pstream_t *pstreamptr = pstream_to_pointer(pstreamID);
@@ -1673,6 +1706,14 @@ void pstreamInqGRIBinfo(int pstreamID, int *intnum, float *fltnum, off_t *bignum
 }
 
 
+int pstreamFileID(int pstreamID)
+{
+  pstream_t *pstreamptr = pstream_to_pointer(pstreamID);
+
+  return pstreamptr->fileID;
+}
+
+
 void cdoVlistCopyFlag(int vlistID2, int vlistID1)
 {
 #if defined(HAVE_LIBPTHREAD)
diff --git a/src/pstream.h b/src/pstream.h
index 4550d4b..59b5c06 100644
--- a/src/pstream.h
+++ b/src/pstream.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -36,6 +36,7 @@
 #define  streamInqRecord          pstreamInqRecord
 
 #define  streamReadRecord         pstreamReadRecord
+#define  streamReadRecordF        pstreamReadRecordF
 
 #define  streamCopyRecord         pstreamCopyRecord
 
@@ -58,10 +59,13 @@ int     pstreamInqTimestep(int pstreamID, int tsID);
 int     pstreamInqRecord(int pstreamID, int *varID, int *levelID);
 
 void    pstreamReadRecord(int pstreamID, double *data, int *nmiss);
+void    pstreamReadRecordF(int pstreamID, float *data, int *nmiss);
 void    pstreamCopyRecord(int pstreamIDdest, int pstreamIDsrc);
 
 void    pstreamInqGRIBinfo(int pstreamID, int *intnum, float *fltnum, off_t *bignum);
 
+int     pstreamFileID(int pstreamID);
+
 void    cdoVlistCopyFlag(int vlistID2, int vlistID1);
 
 #endif  /* _PSTREAM_H */
diff --git a/src/pstream_int.h b/src/pstream_int.h
index daa5f49..72e5501 100644
--- a/src/pstream_int.h
+++ b/src/pstream_int.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/pstream_write.h b/src/pstream_write.h
index 3feb228..fb1a595 100644
--- a/src/pstream_write.h
+++ b/src/pstream_write.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/readline.c b/src/readline.c
index 4bfdfb0..b2d0e20 100644
--- a/src/readline.c
+++ b/src/readline.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/remap.h b/src/remap.h
index d85435d..92a979f 100644
--- a/src/remap.h
+++ b/src/remap.h
@@ -236,4 +236,7 @@ int rect_grid_search(long *ii, long *jj, double x, double y, long nxm, long nym,
 
 void remapgrid_get_lonlat(remapgrid_t *grid, unsigned cell_add, double *plon, double *plat);
 
+void remapCheckArea(int grid_size, double *restrict cell_area, const char *name);
+void remapCheckWeights(long num_links, int num_wts, int norm_opt, int *src_cell_add, int *tgt_cell_add, double *wts);
+
 #endif  /* _REMAP_H */
diff --git a/src/remap_conserv.c b/src/remap_conserv.c
index 85b3bf3..7055407 100644
--- a/src/remap_conserv.c
+++ b/src/remap_conserv.c
@@ -4,6 +4,100 @@
 #include "remap.h"
 #include "remap_store_link.h"
 
+#include "clipping/clipping.h"
+#include "clipping/area.h"
+#include "clipping/geometry.h"
+
+//#define STIMER
+
+#ifdef STIMER
+#include <time.h>
+#endif
+
+typedef struct {
+  enum yac_edge_type *src_edge_type;
+  long srch_corners;
+  long max_srch_cells;
+  double *partial_areas;
+  double *partial_weights;
+  struct grid_cell *src_grid_cells;
+  struct grid_cell *overlap_buffer;
+} search_t;
+
+static
+void search_realloc(long num_srch_cells, search_t *search)
+{
+  long max_srch_cells  = search->max_srch_cells;
+  double *partial_areas   = search->partial_areas;
+  double *partial_weights = search->partial_weights;
+  struct grid_cell *overlap_buffer = search->overlap_buffer;
+  struct grid_cell *src_grid_cells = search->src_grid_cells;
+
+  if ( num_srch_cells > max_srch_cells )
+    {
+      partial_areas   = (double*) realloc(partial_areas,   num_srch_cells*sizeof(double));
+      partial_weights = (double*) realloc(partial_weights, num_srch_cells*sizeof(double));
+      overlap_buffer = (struct grid_cell*) realloc(overlap_buffer, num_srch_cells*sizeof(struct grid_cell));
+      src_grid_cells = (struct grid_cell*) realloc(src_grid_cells, num_srch_cells*sizeof(struct grid_cell));
+
+      for ( long n = max_srch_cells; n < num_srch_cells; ++n )
+        {
+          overlap_buffer[n].array_size      = 0;
+          overlap_buffer[n].num_corners     = 0;
+          overlap_buffer[n].edge_type       = NULL;
+          overlap_buffer[n].coordinates_x   = NULL;
+          overlap_buffer[n].coordinates_y   = NULL;
+          overlap_buffer[n].coordinates_xyz = NULL;
+        }
+
+      for ( long n = max_srch_cells; n < num_srch_cells; ++n )
+        {
+          src_grid_cells[n].array_size      = search->srch_corners;
+          src_grid_cells[n].num_corners     = search->srch_corners;
+          src_grid_cells[n].edge_type       = search->src_edge_type;
+          src_grid_cells[n].coordinates_x   = (double*) malloc(search->srch_corners*sizeof(double));
+          src_grid_cells[n].coordinates_y   = (double*) malloc(search->srch_corners*sizeof(double));
+          src_grid_cells[n].coordinates_xyz = (double*) malloc(3*search->srch_corners*sizeof(double));
+        }
+
+      max_srch_cells = num_srch_cells;
+
+      search->max_srch_cells  = max_srch_cells;
+      search->partial_areas   = partial_areas;
+      search->partial_weights = partial_weights;
+      search->overlap_buffer  = overlap_buffer;
+      search->src_grid_cells  = src_grid_cells;
+    }
+}
+
+static
+void search_free(search_t *search)
+{
+  long max_srch_cells  = search->max_srch_cells;
+  double *partial_areas   = search->partial_areas;
+  double *partial_weights = search->partial_weights;
+  struct grid_cell *overlap_buffer = search->overlap_buffer;
+  struct grid_cell *src_grid_cells = search->src_grid_cells;
+
+  for ( long n = 0; n < max_srch_cells; n++ )
+    {
+      if ( overlap_buffer[n].array_size > 0 )
+        {
+          Free(overlap_buffer[n].coordinates_x);
+          Free(overlap_buffer[n].coordinates_y);
+          if ( overlap_buffer[n].coordinates_xyz ) Free(overlap_buffer[n].coordinates_xyz);
+          if ( overlap_buffer[n].edge_type ) Free(overlap_buffer[n].edge_type);
+        }
+      
+      Free(src_grid_cells[n].coordinates_x);
+      Free(src_grid_cells[n].coordinates_y);
+      Free(src_grid_cells[n].coordinates_xyz);
+    }
+
+  Free(partial_areas);
+  Free(partial_weights);
+}
+
 
 int rect_grid_search2(long *imin, long *imax, double xmin, double xmax, long nxm, const double *restrict xm);
 
@@ -108,7 +202,7 @@ long get_srch_cells_reg2d(const int *restrict src_grid_dims,
 
   if ( debug ) printf(" -> num_srch_cells: %ld\n", num_srch_cells);
 
-  return (num_srch_cells);
+  return num_srch_cells;
 }
 
 static
@@ -250,9 +344,6 @@ void boundbox_from_corners1r(long ic, long nc, const double *restrict corner_lon
 }
 
 //#if defined(HAVE_LIBYAC)
-#include "clipping/clipping.h"
-#include "clipping/area.h"
-#include "clipping/geometry.h"
 
 static
 double gridcell_area(struct grid_cell cell)
@@ -261,12 +352,12 @@ double gridcell_area(struct grid_cell cell)
 }
 
 static
-void cdo_compute_overlap_areas(unsigned N,
-			       struct grid_cell *overlap_buffer,
-			       struct grid_cell *source_cells,
-			       struct grid_cell  target_cell,
-			       double *partial_areas)
+void cdo_compute_overlap_areas(unsigned N, search_t *search, struct grid_cell target_cell)
 {
+  double *partial_areas   = search->partial_areas;
+  struct grid_cell *overlap_buffer = search->overlap_buffer;
+  struct grid_cell *source_cells = search->src_grid_cells;
+
   /* Do the clipping and get the cell for the overlapping area */
 
   yac_cell_clipping(N, source_cells, target_cell, overlap_buffer);
@@ -325,14 +416,13 @@ static enum cell_type get_cell_type(struct grid_cell target_cell) {
 }
 */
 static
-void cdo_compute_concave_overlap_areas(unsigned N,
-				       struct grid_cell *overlap_buffer,
-				       struct grid_cell *source_cell,
-				       struct grid_cell  target_cell,
-				       double target_node_x,
-				       double target_node_y,
-				       double * partial_areas)
+void cdo_compute_concave_overlap_areas(unsigned N, search_t *search, struct grid_cell target_cell,
+				       double target_node_x, double target_node_y)
 {
+  double *partial_areas   = search->partial_areas;
+  struct grid_cell *overlap_buffer = search->overlap_buffer;
+  struct grid_cell *source_cell = search->src_grid_cells;
+
   /*
   enum cell_type target_cell_type = UNDEF_CELL;
 
@@ -490,18 +580,18 @@ int get_lonlat_circle_index(remapgrid_t *remap_grid)
 
   //printf("lonlat_circle_index %d\n", lonlat_circle_index);
 
-  return (lonlat_circle_index);
+  return lonlat_circle_index;
 }
 
 
 static
-void normalize_weights(remapgrid_t *tgt_grid, remapvars_t *rv)
+void remapNormalizeWeights(remapgrid_t *tgt_grid, remapvars_t *rv)
 {
-  /* Include centroids in weights and normalize using destination area if requested */
-  long num_wts = rv->num_wts;
+  // Include centroids in weights and normalize using destination area if requested
   long num_links = rv->num_links;
-  long tgt_cell_add;       /* current linear address for target grid cell   */
-  double norm_factor = 0;  /* factor for normalizing wts */
+  int num_wts = rv->num_wts;
+  int tgt_cell_add;       // current linear address for target grid cell
+  double norm_factor = 0; // factor for normalizing wts
 
   if ( rv->norm_opt == NORM_OPT_DESTAREA )
     {
@@ -510,7 +600,7 @@ void normalize_weights(remapgrid_t *tgt_grid, remapvars_t *rv)
 #endif
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) \
-  shared(num_wts, num_links, rv, tgt_grid)	\
+  shared(num_wts, num_links, rv, tgt_grid) \
   private(tgt_cell_add, norm_factor)
 #endif
       for ( long n = 0; n < num_links; ++n )
@@ -532,7 +622,7 @@ void normalize_weights(remapgrid_t *tgt_grid, remapvars_t *rv)
 #endif
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) \
-  shared(num_wts, num_links, rv, tgt_grid)	\
+  shared(num_wts, num_links, rv, tgt_grid) \
   private(tgt_cell_add, norm_factor)
 #endif
       for ( long n = 0; n < num_links; ++n )
@@ -552,53 +642,94 @@ void normalize_weights(remapgrid_t *tgt_grid, remapvars_t *rv)
     }
 }
 
+static
+void set_yac_coordinates(int remap_grid_type, int cell_add, int num_cell_corners, remapgrid_t *remap_grid, struct grid_cell *yac_grid_cell)
+{
+  if ( remap_grid_type == REMAP_GRID_TYPE_REG2D )
+    {
+      int nx = remap_grid->dims[0];
+      int iy = cell_add/nx;
+      int ix = cell_add - iy*nx;
+      const double *restrict reg2d_corner_lon = remap_grid->reg2d_corner_lon;
+      const double *restrict reg2d_corner_lat = remap_grid->reg2d_corner_lat;
+      double *restrict coordinates_x = yac_grid_cell->coordinates_x;
+      double *restrict coordinates_y = yac_grid_cell->coordinates_y;
+
+      coordinates_x[0] = reg2d_corner_lon[ix  ];
+      coordinates_y[0] = reg2d_corner_lat[iy  ];
+      coordinates_x[1] = reg2d_corner_lon[ix+1];
+      coordinates_y[1] = reg2d_corner_lat[iy  ];
+      coordinates_x[2] = reg2d_corner_lon[ix+1];
+      coordinates_y[2] = reg2d_corner_lat[iy+1];
+      coordinates_x[3] = reg2d_corner_lon[ix  ];
+      coordinates_y[3] = reg2d_corner_lat[iy+1];
+    }
+  else
+    {
+      const double *restrict cell_corner_lon = remap_grid->cell_corner_lon;
+      const double *restrict cell_corner_lat = remap_grid->cell_corner_lat;
+      double *restrict coordinates_x = yac_grid_cell->coordinates_x;
+      double *restrict coordinates_y = yac_grid_cell->coordinates_y;
+      for ( int ic = 0; ic < num_cell_corners; ++ic )
+        {
+          coordinates_x[ic] = cell_corner_lon[cell_add*num_cell_corners+ic];
+          coordinates_y[ic] = cell_corner_lat[cell_add*num_cell_corners+ic];
+        }
+    }
+      
+  const double *restrict coordinates_x = yac_grid_cell->coordinates_x;
+  const double *restrict coordinates_y = yac_grid_cell->coordinates_y;
+  double *restrict coordinates_xyz = yac_grid_cell->coordinates_xyz;
+  for ( int ic = 0; ic < num_cell_corners; ++ic )
+    LLtoXYZ(coordinates_x[ic], coordinates_y[ic], coordinates_xyz+ic*3);
+}
+
+static
+void reg2d_bound_box(remapgrid_t *remap_grid, double *grid_bound_box)
+{
+  int nx = remap_grid->dims[0];
+  int ny = remap_grid->dims[1];
+  const double *restrict reg2d_corner_lon = remap_grid->reg2d_corner_lon;
+  const double *restrict reg2d_corner_lat = remap_grid->reg2d_corner_lat;
+
+  grid_bound_box[0] = reg2d_corner_lat[0];
+  grid_bound_box[1] = reg2d_corner_lat[ny];
+  if ( grid_bound_box[0] > grid_bound_box[1] )
+    {
+      grid_bound_box[0] = reg2d_corner_lat[ny];
+      grid_bound_box[1] = reg2d_corner_lat[0];
+    }
+  grid_bound_box[2] = reg2d_corner_lon[0];
+  grid_bound_box[3] = reg2d_corner_lon[nx];
+}
+
 
 void remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapvars_t *rv)
 {
-  /* local variables */
-
-  int    lcheck = TRUE;
-
-  long   ioffset;
-  long   src_num_cell_corners;
-  long   tgt_num_cell_corners;
-  long   src_cell_add;       /* current linear address for source grid cell   */
-  long   k;                  /* generic counters                        */
-  long   nbins;
-  long   num_wts;
-  long   max_srch_cells;     /* num cells in restricted search arrays  */
-  long   num_srch_cells;     /* num cells in restricted search arrays  */
-  long   srch_corners;       /* num of corners of srch cells           */
-  int*   srch_add;           /* global address of cells in srch arrays */
-  int    i;
+  int lcheck = TRUE;
+  int srch_corners;  // num of corners of srch cells
 
   /* Variables necessary if segment manages to hit pole */
-  long nx = 0, ny = 0;
   int src_remap_grid_type = src_grid->remap_grid_type;
   int tgt_remap_grid_type = tgt_grid->remap_grid_type;
-  double src_grid_bound_box[4];
-  int lyac = FALSE;
   extern int timer_remap_con;
 
   if ( cdoVerbose ) cdoPrint("Called %s()", __func__);
 
   progressInit();
 
-  nbins = src_grid->num_srch_bins;
-  num_wts = rv->num_wts;
-
   if ( cdoTimer ) timer_start(timer_remap_con);
 
-  long src_grid_size = src_grid->size;
-  long tgt_grid_size = tgt_grid->size;
+  int src_grid_size = src_grid->size;
+  int tgt_grid_size = tgt_grid->size;
 
-  src_num_cell_corners = src_grid->num_cell_corners;
-  tgt_num_cell_corners = tgt_grid->num_cell_corners;
+  int src_num_cell_corners = src_grid->num_cell_corners;
+  int tgt_num_cell_corners = tgt_grid->num_cell_corners;
 
   int max_num_cell_corners = src_num_cell_corners;
   if ( tgt_num_cell_corners > max_num_cell_corners ) max_num_cell_corners = tgt_num_cell_corners;
 
-  enum yac_edge_type great_circle_type[32];
+  enum yac_edge_type great_circle_type[max_num_cell_corners];
   for ( int i = 0; i < max_num_cell_corners; ++i ) great_circle_type[i] = GREAT_CIRCLE;
 
   enum yac_edge_type lonlat_circle_type[] = {LON_CIRCLE, LAT_CIRCLE, LON_CIRCLE, LAT_CIRCLE, LON_CIRCLE};
@@ -627,14 +758,12 @@ void remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapva
   if ( !(tgt_num_cell_corners < 4 || target_cell_type == LON_LAT_CELL) )
     {
       if ( tgt_grid->cell_center_lon == NULL || tgt_grid->cell_center_lat == NULL )
-	cdoAbort("Internal problem (remap_weights_conserv): missing target point coordinates!");
+	cdoAbort("Internal problem (%s): missing target point coordinates!", __func__);
     }
 
-  double tgt_area;
 
-  struct grid_cell* tgt_grid_cell;
-  struct grid_cell* tgt_grid_cell2[ompNumThreads];  
-  for ( i = 0; i < ompNumThreads; ++i )
+  struct grid_cell *tgt_grid_cell2[ompNumThreads];  
+  for ( int i = 0; i < ompNumThreads; ++i )
     {
       tgt_grid_cell2[i] = (struct grid_cell*) Malloc(sizeof(struct grid_cell));
       tgt_grid_cell2[i]->array_size      = tgt_num_cell_corners;
@@ -645,76 +774,52 @@ void remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapva
       tgt_grid_cell2[i]->coordinates_xyz = (double*) Malloc(3*tgt_num_cell_corners*sizeof(double));
     }
 
-  struct grid_cell* src_grid_cells;
-  struct grid_cell* overlap_buffer;
-  struct grid_cell* src_grid_cells2[ompNumThreads];
-  struct grid_cell* overlap_buffer2[ompNumThreads];
-  for ( i = 0; i < ompNumThreads; ++i )
-    {
-      src_grid_cells2[i] = NULL;
-      overlap_buffer2[i] = NULL;
-    }
-
-  double* partial_areas;
-  double* partial_weights;
-  double* partial_areas2[ompNumThreads];
-  double* partial_weights2[ompNumThreads];
-  for ( i = 0; i < ompNumThreads; ++i )
+  search_t search[ompNumThreads];
+  for ( int i = 0; i < ompNumThreads; ++i )
     {
-      partial_areas2[i]   = NULL;
-      partial_weights2[i] = NULL;
+      search[i].srch_corners    = src_num_cell_corners;
+      search[i].src_edge_type   = src_edge_type;
+      search[i].max_srch_cells  = 0;
+      search[i].partial_areas   = NULL;
+      search[i].partial_weights = NULL;
+      search[i].src_grid_cells  = NULL;
+      search[i].overlap_buffer  = NULL;
     }
 
-  long max_srch_cells2[ompNumThreads];
-  for ( i = 0; i < ompNumThreads; ++i )
-    max_srch_cells2[i] = 0;
-
-  int* srch_add2[ompNumThreads];
-  for ( i = 0; i < ompNumThreads; ++i )
+  int *srch_add2[ompNumThreads];
+  for ( int i = 0; i < ompNumThreads; ++i )
     srch_add2[i] = (int*) Malloc(src_grid_size*sizeof(int));
 
   srch_corners = src_num_cell_corners;
 
+  double src_grid_bound_box[4];
   if ( src_remap_grid_type == REMAP_GRID_TYPE_REG2D )
-    {
-      nx = src_grid->dims[0];
-      ny = src_grid->dims[1];
-     
-      src_grid_bound_box[0] = src_grid->reg2d_corner_lat[0];
-      src_grid_bound_box[1] = src_grid->reg2d_corner_lat[ny];
-      if ( src_grid_bound_box[0] > src_grid_bound_box[1] )
-	{
-	  src_grid_bound_box[0] = src_grid->reg2d_corner_lat[ny];
-	  src_grid_bound_box[1] = src_grid->reg2d_corner_lat[0];
-	}
-      src_grid_bound_box[2] = src_grid->reg2d_corner_lon[0];
-      src_grid_bound_box[3] = src_grid->reg2d_corner_lon[nx];
-      //printf("src_grid   lon: %g %g lat: %g %g\n", RAD2DEG*src_grid_bound_box[2],RAD2DEG*src_grid_bound_box[3],RAD2DEG*src_grid_bound_box[0],RAD2DEG*src_grid_bound_box[1] );
-    }
+    reg2d_bound_box(src_grid, src_grid_bound_box);
 
   weightlinks_t *weightlinks = (weightlinks_t *) Malloc(tgt_grid_size*sizeof(weightlinks_t));
   
   double findex = 0;
 
-  int sum_srch_cells = 0;
-  int sum_srch_cells2 = 0;
+  long sum_srch_cells = 0;
+  long sum_srch_cells2 = 0;
 
+#ifdef STIMER
+  double stimer = 0;
+#endif
   /* Loop over destination grid */
 
 #if defined(_OPENMP)
 #pragma omp parallel for schedule(dynamic) default(none)                   \
-  shared(ompNumThreads, lyac, nbins, num_wts, src_remap_grid_type, tgt_remap_grid_type, src_grid_bound_box,	\
-	 src_edge_type, tgt_edge_type, partial_areas2, partial_weights2,  \
-         rv, cdoVerbose, max_srch_cells2, tgt_num_cell_corners, target_cell_type, \
-         weightlinks, \
-         srch_corners, src_grid, tgt_grid, tgt_grid_size, src_grid_size, nx, \
-	 overlap_buffer2, src_grid_cells2, srch_add2, tgt_grid_cell2, findex, sum_srch_cells, sum_srch_cells2) \
-  private(srch_add, tgt_grid_cell, tgt_area, k, num_srch_cells, max_srch_cells,  \
-	  partial_areas, partial_weights, overlap_buffer, src_grid_cells, src_cell_add, ioffset)
+  shared(ompNumThreads, src_remap_grid_type, tgt_remap_grid_type, src_grid_bound_box, \
+	 rv, cdoVerbose, tgt_num_cell_corners, target_cell_type, \
+         weightlinks,  srch_corners, src_grid, tgt_grid, tgt_grid_size, src_grid_size, \
+	 search, srch_add2, tgt_grid_cell2, findex, sum_srch_cells, sum_srch_cells2)
 #endif
   for ( long tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add )
     {
       double partial_weight;
+      long src_cell_add;       /* current linear address for source grid cell   */
+      long num_srch_cells;
       long n, num_weights, num_weights_old;
       int ompthID = cdo_omp_get_thread_num();
 
@@ -726,19 +831,20 @@ void remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapva
 
       weightlinks[tgt_cell_add].nlinks = 0;	
 
-      srch_add = srch_add2[ompthID];
-      tgt_grid_cell = tgt_grid_cell2[ompthID];
+      int *srch_add = srch_add2[ompthID];
+      struct grid_cell *tgt_grid_cell = tgt_grid_cell2[ompthID];
 
       /* Get search cells */
-
+#ifdef STIMER
+      clock_t start = clock();
+#endif
+          
       if ( src_remap_grid_type == REMAP_GRID_TYPE_REG2D && tgt_remap_grid_type == REMAP_GRID_TYPE_REG2D )
 	{
 	  double tgt_cell_bound_box[4];
 	  boundbox_from_corners_reg2d(tgt_cell_add, tgt_grid->dims, tgt_grid->reg2d_corner_lon, tgt_grid->reg2d_corner_lat, tgt_cell_bound_box);
 	  restrict_boundbox(src_grid_bound_box, tgt_cell_bound_box);
-	  if ( 0 && cdoVerbose )
-	    printf("bound_box %ld  lon: %g %g lat: %g %g\n",
-		   tgt_cell_add, RAD2DEG*tgt_cell_bound_box[2],RAD2DEG*tgt_cell_bound_box[3],RAD2DEG*tgt_cell_bound_box[0],RAD2DEG*tgt_cell_bound_box[1] );
+
 	  num_srch_cells = get_srch_cells_reg2d(src_grid->dims, src_grid->reg2d_corner_lat, src_grid->reg2d_corner_lon,
 						tgt_cell_bound_box, srch_add);
 
@@ -751,9 +857,7 @@ void remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapva
 	  double tgt_cell_bound_box[4];
 	  boundbox_from_corners1(tgt_cell_add, tgt_num_cell_corners, tgt_grid->cell_corner_lon, tgt_grid->cell_corner_lat, tgt_cell_bound_box);
 	  restrict_boundbox(src_grid_bound_box, tgt_cell_bound_box);
-	  if ( 0 && cdoVerbose )
-	    printf("bound_box %ld  lon: %g %g lat: %g %g\n",
-		   tgt_cell_add, RAD2DEG*tgt_cell_bound_box[2],RAD2DEG*tgt_cell_bound_box[3],RAD2DEG*tgt_cell_bound_box[0],RAD2DEG*tgt_cell_bound_box[1] );
+
 	  num_srch_cells = get_srch_cells_reg2d(src_grid->dims, src_grid->reg2d_corner_lat, src_grid->reg2d_corner_lon,
 						tgt_cell_bound_box, srch_add);
 
@@ -766,9 +870,14 @@ void remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapva
 	  restr_t tgt_cell_bound_box_r[4];
 	  boundbox_from_corners1r(tgt_cell_add, tgt_num_cell_corners, tgt_grid->cell_corner_lon, tgt_grid->cell_corner_lat, tgt_cell_bound_box_r);
 
+          long nbins = src_grid->num_srch_bins;
 	  num_srch_cells = get_srch_cells(tgt_cell_add, nbins, tgt_grid->bin_addr, src_grid->bin_addr,
 					  tgt_cell_bound_box_r, src_grid->cell_bound_box, src_grid_size, srch_add);
 	}
+#ifdef STIMER
+      clock_t finish = clock();
+      stimer += ((double)(finish-start))/CLOCKS_PER_SEC;
+#endif
 
       if ( 0 && cdoVerbose ) sum_srch_cells += num_srch_cells;
 
@@ -777,202 +886,41 @@ void remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapva
 
       if ( num_srch_cells == 0 ) continue;
 
-      if ( tgt_remap_grid_type == REMAP_GRID_TYPE_REG2D )
-	{
-	  long nx = tgt_grid->dims[0];
-	  long iy = tgt_cell_add/nx;
-	  long ix = tgt_cell_add - iy*nx;
-
-	  tgt_grid_cell->coordinates_x[0] = tgt_grid->reg2d_corner_lon[ix  ];
-	  tgt_grid_cell->coordinates_y[0] = tgt_grid->reg2d_corner_lat[iy  ];
-	  tgt_grid_cell->coordinates_x[1] = tgt_grid->reg2d_corner_lon[ix+1];
-	  tgt_grid_cell->coordinates_y[1] = tgt_grid->reg2d_corner_lat[iy  ];
-	  tgt_grid_cell->coordinates_x[2] = tgt_grid->reg2d_corner_lon[ix+1];
-	  tgt_grid_cell->coordinates_y[2] = tgt_grid->reg2d_corner_lat[iy+1];
-	  tgt_grid_cell->coordinates_x[3] = tgt_grid->reg2d_corner_lon[ix  ];
-	  tgt_grid_cell->coordinates_y[3] = tgt_grid->reg2d_corner_lat[iy+1];
-	}
-      else
-	{
-	  for ( int ic = 0; ic < tgt_num_cell_corners; ++ic )
-	    {
-	      tgt_grid_cell->coordinates_x[ic] = tgt_grid->cell_corner_lon[tgt_cell_add*tgt_num_cell_corners+ic];
-	      tgt_grid_cell->coordinates_y[ic] = tgt_grid->cell_corner_lat[tgt_cell_add*tgt_num_cell_corners+ic];
-	    }
-	}
-      
-      for ( int ic = 0; ic < tgt_num_cell_corners; ++ic )
-	LLtoXYZ(tgt_grid_cell->coordinates_x[ic], tgt_grid_cell->coordinates_y[ic], tgt_grid_cell->coordinates_xyz+ic*3);
-
-      //printf("target: %ld\n", tgt_cell_add);
-      if ( lyac )
-        if ( tgt_cell_add == 174752 )
-	  {
-	    for ( int n = 0; n < tgt_num_cell_corners; ++n )
-	      {
-		printf("  TargetCell.coordinates_x[%d] = %g*rad;\n", n, tgt_grid_cell->coordinates_x[n]/DEG2RAD);
-		printf("  TargetCell.coordinates_y[%d] = %g*rad;\n", n, tgt_grid_cell->coordinates_y[n]/DEG2RAD);
-	      }
-	    /*
-	    printf("> -Z1\n");
-	    for ( int n = 0; n < tgt_num_cell_corners; ++n )
-		printf("  %g %g\n", tgt_grid_cell->coordinates_x[n]/DEG2RAD, tgt_grid_cell->coordinates_y[n]/DEG2RAD);
-	      printf("  %g %g\n", tgt_grid_cell->coordinates_x[0]/DEG2RAD, tgt_grid_cell->coordinates_y[0]/DEG2RAD);
-	    */
-	  }
-      
-      /* Create search arrays */
-
-      max_srch_cells  = max_srch_cells2[ompthID];
-      partial_areas   = partial_areas2[ompthID];
-      partial_weights = partial_weights2[ompthID];
-      overlap_buffer  = overlap_buffer2[ompthID];
-      src_grid_cells  = src_grid_cells2[ompthID];
+      set_yac_coordinates(tgt_remap_grid_type, tgt_cell_add, tgt_num_cell_corners, tgt_grid, tgt_grid_cell);
 
-      if ( num_srch_cells > max_srch_cells )
-	{
-          partial_areas   = (double*) realloc(partial_areas,   num_srch_cells*sizeof(double));
-	  partial_weights = (double*) realloc(partial_weights, num_srch_cells*sizeof(double));
-          overlap_buffer = (struct grid_cell*) realloc(overlap_buffer, num_srch_cells*sizeof(struct grid_cell));
-	  src_grid_cells = (struct grid_cell*) realloc(src_grid_cells, num_srch_cells*sizeof(struct grid_cell));
+      /* Create search arrays */
 
-          for ( n = max_srch_cells; n < num_srch_cells; ++n )
-	    {
-	      overlap_buffer[n].array_size      = 0;
-	      overlap_buffer[n].num_corners     = 0;
-	      overlap_buffer[n].edge_type       = NULL;
-	      overlap_buffer[n].coordinates_x   = NULL;
-	      overlap_buffer[n].coordinates_y   = NULL;
-	      overlap_buffer[n].coordinates_xyz = NULL;
-	    }
+      search_realloc(num_srch_cells, &search[ompthID]);
 
-	  for ( n = max_srch_cells; n < num_srch_cells; ++n )
-	    {
-	      src_grid_cells[n].array_size      = srch_corners;
-	      src_grid_cells[n].num_corners     = srch_corners;
-	      src_grid_cells[n].edge_type       = src_edge_type;
-	      src_grid_cells[n].coordinates_x   = (double*) malloc(srch_corners*sizeof(double));
-	      src_grid_cells[n].coordinates_y   = (double*) malloc(srch_corners*sizeof(double));
-	      src_grid_cells[n].coordinates_xyz = (double*) malloc(3*srch_corners*sizeof(double));
-            }
-
-	  max_srch_cells = num_srch_cells;
-
-	  max_srch_cells2[ompthID]  = max_srch_cells;
-	  partial_areas2[ompthID]   = partial_areas;
-	  partial_weights2[ompthID] = partial_weights;
-	  overlap_buffer2[ompthID]  = overlap_buffer;
-	  src_grid_cells2[ompthID]  = src_grid_cells;
-	}
+      double *partial_areas   = search[ompthID].partial_areas;
+      double *partial_weights = search[ompthID].partial_weights;
+      struct grid_cell *src_grid_cells = search[ompthID].src_grid_cells;
 
-      // printf("  int ii = 0;\n");
       for ( n = 0; n < num_srch_cells; ++n )
 	{
-	  long srch_corners_new = srch_corners;
-
+	  int srch_corners_new = srch_corners;
 	  src_cell_add = srch_add[n];
-
-	  if ( src_remap_grid_type == REMAP_GRID_TYPE_REG2D )
-	    {
-	      int ix, iy;
-
-	      iy = src_cell_add/nx;
-	      ix = src_cell_add - iy*nx;
-
-	      src_grid_cells[n].coordinates_x[0] = src_grid->reg2d_corner_lon[ix  ];
-	      src_grid_cells[n].coordinates_y[0] = src_grid->reg2d_corner_lat[iy  ];
-	      src_grid_cells[n].coordinates_x[1] = src_grid->reg2d_corner_lon[ix+1];
-	      src_grid_cells[n].coordinates_y[1] = src_grid->reg2d_corner_lat[iy  ];
-	      src_grid_cells[n].coordinates_x[2] = src_grid->reg2d_corner_lon[ix+1];
-	      src_grid_cells[n].coordinates_y[2] = src_grid->reg2d_corner_lat[iy+1];
-	      src_grid_cells[n].coordinates_x[3] = src_grid->reg2d_corner_lon[ix  ];
-	      src_grid_cells[n].coordinates_y[3] = src_grid->reg2d_corner_lat[iy+1];
-	      /*
-	      printf("source1: %ld %ld", num_srch_cells, n);
-	      for ( k = 0; k < srch_corners; ++k )
-		printf(" %g %g", src_grid_cells[n].coordinates_x[k]/DEG2RAD, src_grid_cells[n].coordinates_y[k]/DEG2RAD);
-	      printf("\n");
-	      */
-	    }
-	  else
-	    {
-	      ioffset = src_cell_add*srch_corners;
-	      /*
-	      for ( k = srch_corners-1; k > 0; --k )
-		{
-		  if ( IS_NOT_EQUAL(src_grid->cell_corner_lon[ioffset+k], src_grid->cell_corner_lon[ioffset+k-1]) ||
-		       IS_NOT_EQUAL(src_grid->cell_corner_lat[ioffset+k], src_grid->cell_corner_lat[ioffset+k-1]) )
-		    break;
-		}
-	      if ( k != srch_corners-1 ) printf("%ld %ld %ld %ld\n", tgt_cell_add, n, srch_corners, k+1);
-
-	      if ( k != srch_corners-1 )
-		{
-		  srch_corners_new = k+1;
-		  src_grid_cells[n].num_corners = srch_corners_new;
-		}
-	      */
-	      for ( k = 0; k < srch_corners_new; ++k )
-		{
-		  src_grid_cells[n].coordinates_x[k] = src_grid->cell_corner_lon[ioffset+k];
-		  src_grid_cells[n].coordinates_y[k] = src_grid->cell_corner_lat[ioffset+k];
-		}
-	      /*
-	      for ( k = 0; k < srch_corners_new; ++k )
-		{
-		  printf("  SourceCell[ii].coordinates_x[%ld] = %g*rad;\n", k, src_grid_cells[n].coordinates_x[k]/DEG2RAD);
-		  printf("  SourceCell[ii].coordinates_y[%ld] = %g*rad;\n", k, src_grid_cells[n].coordinates_y[k]/DEG2RAD);
-		}
-	      */
-	      /*
-	      printf("source2: %ld %ld", num_srch_cells, n);
-	      for ( k = 0; k < srch_corners_new; ++k )
-		printf(" %g %g", src_grid_cells[n].coordinates_x[k]/DEG2RAD, src_grid_cells[n].coordinates_y[k]/DEG2RAD);
-	      printf("\n");
-	      */
-	    }
-
-	  for ( int ic = 0; ic < srch_corners_new; ++ic )
-	    LLtoXYZ(src_grid_cells[n].coordinates_x[ic], src_grid_cells[n].coordinates_y[ic], src_grid_cells[n].coordinates_xyz+ic*3);
-
-	  if ( lyac )
-	    if ( tgt_cell_add == 174752 )
-	    {
-	      // printf("n %d\n", (int)n);
-	      for ( k = 0; k < srch_corners_new; ++k )
-		{
-		  printf("  SourceCell[ii].coordinates_x[%ld] = %g*rad;\n", k, src_grid_cells[n].coordinates_x[k]/DEG2RAD);
-		  printf("  SourceCell[ii].coordinates_y[%ld] = %g*rad;\n", k, src_grid_cells[n].coordinates_y[k]/DEG2RAD);
-		}
-	      printf("  ii++;\n");
-	      /*
-	      printf("> -Z1\n");
-	      for ( k = 0; k < srch_corners_new; ++k )
-		printf("  %g %g\n", src_grid_cells[n].coordinates_x[k]/DEG2RAD, src_grid_cells[n].coordinates_y[k]/DEG2RAD);
-	      printf("  %g %g\n", src_grid_cells[n].coordinates_x[0]/DEG2RAD, src_grid_cells[n].coordinates_y[0]/DEG2RAD);
-	      */
-	    }
+          set_yac_coordinates(src_remap_grid_type, src_cell_add, srch_corners_new, src_grid, &src_grid_cells[n]);
 	}
 
       if ( tgt_num_cell_corners < 4 || target_cell_type == LON_LAT_CELL )
 	{
-	  cdo_compute_overlap_areas(num_srch_cells, overlap_buffer, src_grid_cells, *tgt_grid_cell, partial_areas);
+	  cdo_compute_overlap_areas(num_srch_cells, &search[ompthID], *tgt_grid_cell);
 	}
       else
 	{
 	  double cell_center_lon = tgt_grid->cell_center_lon[tgt_cell_add];
 	  double cell_center_lat = tgt_grid->cell_center_lat[tgt_cell_add];
-	  cdo_compute_concave_overlap_areas(num_srch_cells, overlap_buffer, src_grid_cells, *tgt_grid_cell, cell_center_lon, cell_center_lat, partial_areas);
+	  cdo_compute_concave_overlap_areas(num_srch_cells, &search[ompthID], *tgt_grid_cell, cell_center_lon, cell_center_lat);
 	}
 
-      tgt_area = gridcell_area(*tgt_grid_cell);
-      // tgt_area = cell_area(tgt_grid_cell);
+      double tgt_area = gridcell_area(*tgt_grid_cell);
+      // double tgt_area = cell_area(tgt_grid_cell);
 
       for ( num_weights = 0, n = 0; n < num_srch_cells; ++n )
 	{
 	  if ( partial_areas[n] > 0 )
 	    {
-	      //printf(">>>>   %d %d %g %g\n", (int)tgt_cell_add, srch_add[n], tgt_area, partial_areas[n]);
 	      partial_areas[num_weights] = partial_areas[n];
 	      srch_add[num_weights] = srch_add[n];
 	      num_weights++;
@@ -989,16 +937,12 @@ void remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapva
 
       for ( n = 0; n < num_weights; ++n )
 	partial_weights[n] *= tgt_area;
-      //#endif
 
       num_weights_old = num_weights;
-      for ( num_weights = 0, n = 0; n < num_weights_old; ++n )
+      num_weights = 0;
+      for ( n = 0; n < num_weights_old; ++n )
 	{
 	  src_cell_add = srch_add[n];
-
-	  if ( 0 && cdoVerbose )
-	    printf("tgt_cell_add %ld, src_cell_add %ld,  partial_weights[n] %g, tgt_area  %g\n", tgt_cell_add, src_cell_add, partial_weights[n], tgt_area);
-
 	  if ( partial_weights[n] <= 0. ) src_cell_add = -1;
 	  if ( src_cell_add != -1 )
 	    {
@@ -1011,7 +955,6 @@ void remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapva
       for ( n = 0; n < num_weights; ++n )
 	{
 	  partial_weight = partial_weights[n];
-
 	  src_cell_add = srch_add[n];
 
 #if defined(_OPENMP)
@@ -1056,101 +999,61 @@ void remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapva
 
       tgt_grid->cell_area[tgt_cell_add] = tgt_area; 
       // printf("area %d %g %g\n", tgt_cell_add, tgt_grid->cell_area[tgt_cell_add], tgt_area);
-    }
+  }
+
+#ifdef STIMER
+printf("stime = %gs\n", stimer);
+#endif
 
   if ( 0 && cdoVerbose )
     {
-      printf("sum_srch_cells : %d\n", sum_srch_cells);
-      printf("sum_srch_cells2: %d\n", sum_srch_cells2);
+      printf("sum_srch_cells : %ld\n", sum_srch_cells);
+      printf("sum_srch_cells2: %ld\n", sum_srch_cells2);
     }
 
   /* Finished with all cells: deallocate search arrays */
-  long n;
 
-  for ( i = 0; i < ompNumThreads; ++i )
+  for ( int ompthID = 0; ompthID < ompNumThreads; ++ompthID )
     {
-      for ( n = 0; n < max_srch_cells2[i]; n++ )
-	{
-	  if ( overlap_buffer2[i][n].array_size > 0 )
-	    {
-	      Free(overlap_buffer2[i][n].coordinates_x);
-	      Free(overlap_buffer2[i][n].coordinates_y);
-	      if ( overlap_buffer2[i][n].coordinates_xyz ) Free(overlap_buffer2[i][n].coordinates_xyz);
-	      if ( overlap_buffer2[i][n].edge_type ) Free(overlap_buffer2[i][n].edge_type);
-	    }
-
-	  Free(src_grid_cells2[i][n].coordinates_x);
-	  Free(src_grid_cells2[i][n].coordinates_y);
-	  Free(src_grid_cells2[i][n].coordinates_xyz);
-	}
-      Free(src_grid_cells2[i]);
-      Free(overlap_buffer2[i]);
+      search_free(&search[ompthID]);
 
-      Free(partial_areas2[i]);
-      Free(partial_weights2[i]);
+      Free(tgt_grid_cell2[ompthID]->coordinates_x);
+      Free(tgt_grid_cell2[ompthID]->coordinates_y);
+      Free(tgt_grid_cell2[ompthID]->coordinates_xyz);
+      Free(tgt_grid_cell2[ompthID]);
 
-      Free(tgt_grid_cell2[i]->coordinates_x);
-      Free(tgt_grid_cell2[i]->coordinates_y);
-      Free(tgt_grid_cell2[i]->coordinates_xyz);
-      Free(tgt_grid_cell2[i]);
-
-      Free(srch_add2[i]);
+      Free(srch_add2[ompthID]);
     }
-
+  
   weightlinks2remaplinks(1, tgt_grid_size, weightlinks, rv);
 
   if ( weightlinks ) Free(weightlinks);
 
-  /* Normalize using destination area if requested */
-  normalize_weights(tgt_grid, rv);
-
-  long num_links = rv->num_links;
+  // Normalize weights using destination area if requested
+  remapNormalizeWeights(tgt_grid, rv);
 
-  if ( cdoVerbose )
-    cdoPrint("Total number of links = %ld", rv->num_links);
+  if ( cdoVerbose ) cdoPrint("Total number of links = %ld", rv->num_links);
   
-  for ( n = 0; n < src_grid_size; ++n )
+  for ( int n = 0; n < src_grid_size; ++n )
     if ( IS_NOT_EQUAL(src_grid->cell_area[n], 0) ) src_grid->cell_frac[n] /= src_grid->cell_area[n];
 
-  for ( n = 0; n < tgt_grid_size; ++n )
+  for ( int n = 0; n < tgt_grid_size; ++n )
     if ( IS_NOT_EQUAL(tgt_grid->cell_area[n], 0) ) tgt_grid->cell_frac[n] /= tgt_grid->cell_area[n];
 
-  /* Perform some error checking on final weights  */
-
+  // Perform some error checking on final weights
   if ( lcheck )
     {
-      for ( n = 0; n < src_grid_size; ++n )
-	{
-	  if ( src_grid->cell_area[n] < -.01 )
-	    cdoPrint("Source grid area error: %d %g", n, src_grid->cell_area[n]);
-	}
+      remapCheckArea(src_grid_size, src_grid->cell_area, "Source");
+      remapCheckArea(tgt_grid_size, tgt_grid->cell_area, "Target");
 
-      for ( n = 0; n < tgt_grid_size; ++n )
-	{
-	  if ( tgt_grid->cell_area[n] < -.01 )
-	    cdoPrint("Target grid area error: %d %g", n, tgt_grid->cell_area[n]);
-	}
-
-      for ( n = 0; n < num_links; ++n )
-	{
-	  src_cell_add = rv->src_cell_add[n];
-	  long tgt_cell_add = rv->tgt_cell_add[n];
-
-	  if ( rv->wts[n*num_wts] < -0.01 )
-	    cdoPrint("Map weight < 0! grid1idx=%d grid2idx=%d nlink=%d wts=%g",
-		     src_cell_add, tgt_cell_add, n, rv->wts[n*num_wts]);
-
-	  if ( rv->norm_opt != NORM_OPT_NONE && rv->wts[n*num_wts] > 1.01 )
-	    cdoPrint("Map weight > 1! grid1idx=%d grid2idx=%d nlink=%d wts=%g",
-		     src_cell_add, tgt_cell_add, n, rv->wts[n*num_wts]);
-	}
-    } // lcheck
+      remapCheckWeights(rv->num_links, rv->num_wts, rv->norm_opt, rv->src_cell_add, rv->tgt_cell_add, rv->wts);
+    }
 
   if ( cdoTimer ) timer_stop(timer_remap_con);
 
-} /* remap_weights_conserv */
+} // remap_weights_conserv
 
 
 void remap_conserv(remapgrid_t *src_grid, remapgrid_t *tgt_grid, const double* restrict src_array, double* restrict tgt_array, double missval)
 {
-} /* remap_conserv */
+} // remap_conserv
diff --git a/src/remap_conserv_scrip.c b/src/remap_conserv_scrip.c
index 7dee2ea..9ecfa3f 100644
--- a/src/remap_conserv_scrip.c
+++ b/src/remap_conserv_scrip.c
@@ -1895,11 +1895,11 @@ void scrip_remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, r
 
   if ( lcheck )
     {
+      remapCheckArea(src_grid_size, src_grid->cell_area, "Source");
+      remapCheckArea(tgt_grid_size, tgt_grid->cell_area, "Target");
+
       for ( n = 0; n < src_grid_size; ++n )
 	{
-	  if ( src_grid->cell_area[n] < -.01 )
-	    cdoPrint("Source grid area error: %d %g", n, src_grid->cell_area[n]);
-
 	  if ( src_centroid_lat[n] < -PIH-.01 || src_centroid_lat[n] > PIH+.01 )
 	    cdoPrint("Source grid centroid lat error: %d %g", n, src_centroid_lat[n]);
 
@@ -1909,8 +1909,6 @@ void scrip_remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, r
 
       for ( n = 0; n < tgt_grid_size; ++n )
 	{
-	  if ( tgt_grid->cell_area[n] < -.01 )
-	    cdoPrint("Target grid area error: %d %g", n, tgt_grid->cell_area[n]);
 	  if ( tgt_centroid_lat[n] < -PIH-.01 || tgt_centroid_lat[n] > PIH+.01 )
 	    cdoPrint("Target grid centroid lat error: %d %g", n, tgt_centroid_lat[n]);
 
@@ -1918,19 +1916,7 @@ void scrip_remap_conserv_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, r
 	  tgt_centroid_lon[n] = 0;
 	}
 
-      for ( n = 0; n < num_links; ++n )
-	{
-	  src_cell_add = rv->src_cell_add[n];
-	  tgt_cell_add = rv->tgt_cell_add[n];
-
-	  if ( rv->wts[3*n] < -0.01 )
-	    cdoPrint("Map weight < 0! grid1idx=%d grid2idx=%d nlink=%d wts=%g",
-		     src_cell_add, tgt_cell_add, n, rv->wts[3*n]);
-
-	  if ( rv->norm_opt != NORM_OPT_NONE && rv->wts[3*n] > 1.01 )
-	    cdoPrint("Map weight > 1! grid1idx=%d grid2idx=%d nlink=%d wts=%g",
-		     src_cell_add, tgt_cell_add, n, rv->wts[3*n]);
-	}
+      remapCheckWeights(num_links, 3, rv->norm_opt, rv->src_cell_add, rv->tgt_cell_add, rv->wts);
 
       for ( n = 0; n < num_links; ++n )
 	{
diff --git a/src/remap_distwgt.c b/src/remap_distwgt.c
index e5b0f9c..4bfbcf6 100644
--- a/src/remap_distwgt.c
+++ b/src/remap_distwgt.c
@@ -377,6 +377,7 @@ void remap_distwgt_weights(unsigned num_neighbors, remapgrid_t *src_grid, remapg
   unsigned tgt_grid_size = tgt_grid->size;
   unsigned nx = src_grid->dims[0];
   unsigned ny = src_grid->dims[1];
+  unsigned lcyclic = src_grid->is_cyclic;
 
   weightlinks_t *weightlinks = (weightlinks_t *) Malloc(tgt_grid_size*sizeof(weightlinks_t));
   weightlinks[0].addweights = (addweight_t *) Malloc(num_neighbors*tgt_grid_size*sizeof(addweight_t));
@@ -394,7 +395,7 @@ void remap_distwgt_weights(unsigned num_neighbors, remapgrid_t *src_grid, remapg
 
   struct gridsearch *gs = NULL;
   if ( remap_grid_type == REMAP_GRID_TYPE_REG2D )
-    gs = gridsearch_create_reg2d(nx, ny, src_grid->reg2d_center_lon, src_grid->reg2d_center_lat);
+    gs = gridsearch_create_reg2d(lcyclic, nx, ny, src_grid->reg2d_center_lon, src_grid->reg2d_center_lat);
   else if ( num_neighbors == 1 )
     gs = gridsearch_create_nn(src_grid_size, src_grid->cell_center_lon, src_grid->cell_center_lat);
   else
@@ -484,6 +485,7 @@ void remap_distwgt(unsigned num_neighbors, remapgrid_t *src_grid, remapgrid_t *t
   unsigned tgt_grid_size = tgt_grid->size;
   unsigned nx = src_grid->dims[0];
   unsigned ny = src_grid->dims[1];
+  unsigned lcyclic = src_grid->is_cyclic;
 
   int nbr_mask[num_neighbors];    // mask at nearest neighbors
   int nbr_add[num_neighbors];     // source address at nearest neighbors
@@ -496,7 +498,7 @@ void remap_distwgt(unsigned num_neighbors, remapgrid_t *src_grid, remapgrid_t *t
 
   struct gridsearch *gs = NULL;
   if ( src_remap_grid_type == REMAP_GRID_TYPE_REG2D )
-    gs = gridsearch_create_reg2d(nx, ny, src_grid->reg2d_center_lon, src_grid->reg2d_center_lat);
+    gs = gridsearch_create_reg2d(lcyclic, nx, ny, src_grid->reg2d_center_lon, src_grid->reg2d_center_lat);
   else if ( num_neighbors == 1 )
     gs = gridsearch_create_nn(src_grid_size, src_grid->cell_center_lon, src_grid->cell_center_lat);
   else
diff --git a/src/remap_scrip_io.c b/src/remap_scrip_io.c
index 951b05d..372576f 100644
--- a/src/remap_scrip_io.c
+++ b/src/remap_scrip_io.c
@@ -23,10 +23,7 @@ void remapgrid_alloc(int map_type, remapgrid_t *grid);
 static
 void nce(int istat)
 {
-  /*
-    This routine provides a simple interface to netCDF error message routine.
-  */
-
+  // This routine provides a simple interface to NetCDF error message routine.
   if ( istat != NC_NOERR ) cdoAbort(nc_strerror(istat));
 }
 #endif
@@ -35,20 +32,17 @@ void nce(int istat)
 void write_remap_scrip(const char *interp_file, int map_type, int submap_type, int num_neighbors,
 		       int remap_order, remapgrid_t src_grid, remapgrid_t tgt_grid, remapvars_t rv)
 {
-  /*
-    Writes remap data to a netCDF file using SCRIP conventions
-  */
+  // Writes remap data to a NetCDF file using SCRIP conventions
   /*
     Input variables:
 
     interp_file  ! filename for remap data
   */
-
 #if defined(HAVE_LIBNETCDF)
 
-  /* Local variables */
+  // Local variables
 
-  int nc_file_id;           /* id for netCDF file                       */
+  int nc_file_id;           /* id for NetCDF file                       */
   int nc_srcgrdsize_id;     /* id for source grid size                  */
   int nc_dstgrdsize_id;     /* id for destination grid size             */
   int nc_srcgrdcorn_id = 0; /* id for number of source grid corners     */
@@ -77,7 +71,7 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
   int nc_dstadd_id;         /* id for map destination address           */
   int nc_rmpmatrix_id;      /* id for remapping matrix                  */
 
-  int nc_dims2_id[2];       /* netCDF ids for 2d array dims             */
+  int nc_dims2_id[2];       /* NetCDF ids for 2d array dims             */
 
   const char *map_name = "SCRIP remapping with CDO";
   char normalize_opt[64] = "unknown";
@@ -87,7 +81,6 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
   char tgt_grid_name[64] = "dest grid";
   const char *src_grid_units = "radians";
   const char *tgt_grid_units = "radians";
-  long i;
   int lgridarea = FALSE;
   int writemode = NC_CLOBBER;
 
@@ -146,9 +139,10 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
       break;
     }
 
+  /*
   if ( rv.num_links == 0 )
     cdoAbort("Number of remap links is 0, no remap weights found!");
-
+  */
   {
     size_t nele1 = 4*8 + 4;
     size_t nele2 = 4*8 + 4;
@@ -161,7 +155,7 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
     if ( cdoVerbose )
       cdoPrint("Filesize for remap weights: ~%lu", (unsigned long) filesize);
     
-    if ( filesize > 0x7FFFFC00 ) /* 2**31 - 1024 (<2GB) */
+    if ( filesize > 0x7FFFFC00 ) // 2**31 - 1024 (<2GB)
       {
 #if defined(NC_64BIT_OFFSET)
 	writemode = NC_CLOBBER | NC_64BIT_OFFSET;
@@ -171,34 +165,34 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
       }
   }
 
-  /* Create netCDF file for mapping and define some global attributes */
+  // Create NetCDF file for mapping and define some global attributes
   nce(nc_create(interp_file, writemode, &nc_file_id));
 
-  /* Map name */
+  // Map name
   nce(nc_put_att_text(nc_file_id, NC_GLOBAL, "title", strlen(map_name), map_name));
 
-  /* Normalization option */
+  // Normalization option
   nce(nc_put_att_text(nc_file_id, NC_GLOBAL, "normalization", strlen(normalize_opt), normalize_opt));
 
-  /* Map method */
+  // Map method
   nce(nc_put_att_text(nc_file_id, NC_GLOBAL, "map_method", strlen(map_method), map_method));
 
-  /* Remap order */
+  // Remap order
   if ( map_type == MAP_TYPE_CONSERV && submap_type == SUBMAP_TYPE_NONE )
     nce(nc_put_att_int(nc_file_id, NC_GLOBAL, "remap_order", NC_INT, 1L, &remap_order));
 
-  /* File convention */
+  // File convention
   strcpy(tmp_string, "SCRIP");
   nce(nc_put_att_text(nc_file_id, NC_GLOBAL, "conventions", strlen(tmp_string), tmp_string));
 
-  /* Source and destination grid names */
+  // Source and destination grid names
   gridName(gridInqType(src_grid.gridID), src_grid_name);
   nce(nc_put_att_text(nc_file_id, NC_GLOBAL, "source_grid", strlen(src_grid_name), src_grid_name));
 
   gridName(gridInqType(tgt_grid.gridID), tgt_grid_name);
   nce(nc_put_att_text(nc_file_id, NC_GLOBAL, "dest_grid", strlen(tgt_grid_name), tgt_grid_name));
 
-  /* History */
+  // History
   time_t date_and_time_in_sec = time(NULL);
   if ( date_and_time_in_sec != -1 )
     {
@@ -212,41 +206,41 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
   if ( CDO_Version_Info )
     nce(nc_put_att_text(nc_file_id, NC_GLOBAL, "CDO", (int)strlen(cdoComment())+1, cdoComment()));
 
-  /* Prepare netCDF dimension info */
+  // Prepare NetCDF dimension info
 
-  /* Define grid size dimensions */
+  // Define grid size dimensions
   nce(nc_def_dim(nc_file_id, "src_grid_size", src_grid.size, &nc_srcgrdsize_id));
   nce(nc_def_dim(nc_file_id, "dst_grid_size", tgt_grid.size, &nc_dstgrdsize_id));
 
-  /* Define grid corner dimension */
+  // Define grid corner dimension
   if ( src_grid.lneed_cell_corners )
     nce(nc_def_dim(nc_file_id, "src_grid_corners", src_grid.num_cell_corners, &nc_srcgrdcorn_id));
   if ( tgt_grid.lneed_cell_corners )
     nce(nc_def_dim(nc_file_id, "dst_grid_corners", tgt_grid.num_cell_corners, &nc_dstgrdcorn_id));
 
-  /* Define grid rank dimension */
+  // Define grid rank dimension
   nce(nc_def_dim(nc_file_id, "src_grid_rank", src_grid.rank, &nc_srcgrdrank_id));
   nce(nc_def_dim(nc_file_id, "dst_grid_rank", tgt_grid.rank, &nc_dstgrdrank_id));
 
-  /* Define map size dimensions */
+  // Define map size dimensions
   nce(nc_def_dim(nc_file_id, "num_links", rv.num_links, &nc_numlinks_id));
   nce(nc_def_dim(nc_file_id, "num_wgts", rv.num_wts, &nc_numwgts_id));
        
-  /* Define grid dimensions */
+  // Define grid dimensions
   nce(nc_def_var(nc_file_id, "src_grid_dims", NC_INT, 1, &nc_srcgrdrank_id, &nc_srcgrddims_id));
   nce(nc_def_var(nc_file_id, "dst_grid_dims", NC_INT, 1, &nc_dstgrdrank_id, &nc_dstgrddims_id));
 
-  /* Define all arrays for netCDF descriptors */
+  // Define all arrays for NetCDF descriptors
 
-  /* Define grid center latitude array */
+  // Define grid center latitude array
   nce(nc_def_var(nc_file_id, "src_grid_center_lat", NC_DOUBLE, 1, &nc_srcgrdsize_id, &nc_srcgrdcntrlat_id));
   nce(nc_def_var(nc_file_id, "dst_grid_center_lat", NC_DOUBLE, 1, &nc_dstgrdsize_id, &nc_dstgrdcntrlat_id));
 
-  /* Define grid center longitude array */
+  // Define grid center longitude array
   nce(nc_def_var(nc_file_id, "src_grid_center_lon", NC_DOUBLE, 1, &nc_srcgrdsize_id, &nc_srcgrdcntrlon_id));
   nce(nc_def_var(nc_file_id, "dst_grid_center_lon", NC_DOUBLE, 1, &nc_dstgrdsize_id, &nc_dstgrdcntrlon_id));
 
-  /* Define grid corner lat/lon arrays */
+  // Define grid corner lat/lon arrays
 
   nc_dims2_id[0] = nc_srcgrdsize_id;
   nc_dims2_id[1] = nc_srcgrdcorn_id;
@@ -266,7 +260,8 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
       nce(nc_def_var(nc_file_id, "dst_grid_corner_lon", NC_DOUBLE, 2, nc_dims2_id, &nc_dstgrdcrnrlon_id));
     }
 
-  /* Define units for all coordinate arrays */
+  // Define units for all coordinate arrays
+
   nce(nc_put_att_text(nc_file_id, nc_srcgrdcntrlat_id, "units", strlen(src_grid_units), src_grid_units));
   nce(nc_put_att_text(nc_file_id, nc_dstgrdcntrlat_id, "units", strlen(tgt_grid_units), tgt_grid_units));
   nce(nc_put_att_text(nc_file_id, nc_srcgrdcntrlon_id, "units", strlen(src_grid_units), src_grid_units));
@@ -282,7 +277,7 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
       nce(nc_put_att_text(nc_file_id, nc_dstgrdcrnrlon_id, "units", strlen(tgt_grid_units), tgt_grid_units));
     }
 
-  /* Define grid mask */
+  // Define grid mask
 
   nce(nc_def_var(nc_file_id, "src_grid_imask", NC_INT, 1, &nc_srcgrdsize_id, &nc_srcgrdimask_id));
   nce(nc_put_att_text(nc_file_id, nc_srcgrdimask_id, "units", 8, "unitless"));
@@ -290,7 +285,7 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
   nce(nc_def_var(nc_file_id, "dst_grid_imask", NC_INT, 1, &nc_dstgrdsize_id, &nc_dstgrdimask_id));
   nce(nc_put_att_text(nc_file_id, nc_dstgrdimask_id, "units", 8, "unitless"));
 
-  /* Define grid area arrays */
+  // Define grid area arrays
 
   if ( lgridarea )
     {
@@ -301,7 +296,7 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
       nce(nc_put_att_text(nc_file_id, nc_dstgrdarea_id, "units", 14, "square radians"));
     }
 
-  /* Define grid fraction arrays */
+  // Define grid fraction arrays
 
   nce(nc_def_var(nc_file_id, "src_grid_frac", NC_DOUBLE, 1, &nc_srcgrdsize_id, &nc_srcgrdfrac_id));
   nce(nc_put_att_text(nc_file_id, nc_srcgrdfrac_id, "units", 8, "unitless"));
@@ -309,7 +304,7 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
   nce(nc_def_var(nc_file_id, "dst_grid_frac", NC_DOUBLE, 1, &nc_dstgrdsize_id, &nc_dstgrdfrac_id));
   nce(nc_put_att_text(nc_file_id, nc_dstgrdfrac_id, "units", 8, "unitless"));
 
-  /* Define mapping arrays */
+  // Define mapping arrays
 
   nce(nc_def_var(nc_file_id, "src_address", NC_INT, 1, &nc_numlinks_id, &nc_srcadd_id));      
   nce(nc_def_var(nc_file_id, "dst_address", NC_INT, 1, &nc_numlinks_id, &nc_dstadd_id));
@@ -319,12 +314,12 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
 
   nce(nc_def_var(nc_file_id, "remap_matrix", NC_DOUBLE, 2, nc_dims2_id, &nc_rmpmatrix_id));
 
-  /* End definition stage */
+  // End definition stage
   
   nce(nc_enddef(nc_file_id));
 
 
-  /* Write mapping data */
+  // Write mapping data
 
   nce(nc_put_var_int(nc_file_id, nc_srcgrddims_id, src_grid.dims));
   nce(nc_put_var_int(nc_file_id, nc_dstgrddims_id, tgt_grid.dims));
@@ -365,7 +360,7 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
 
   nce(nc_put_var_double(nc_file_id, nc_dstgrdfrac_id, tgt_grid.cell_frac));
 
-  for ( i = 0; i < rv.num_links; i++ )
+  for ( long i = 0; i < rv.num_links; i++ )
     {
       rv.src_cell_add[i]++;
       rv.tgt_cell_add[i]++;
@@ -379,19 +374,17 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
   nce(nc_close(nc_file_id));
 
 #else
-  cdoAbort("netCDF support not compiled in!");
+  cdoAbort("NetCDF support not compiled in!");
 #endif
 
-}  /* write_remap_scrip */
+}  // write_remap_scrip
 
 /*****************************************************************************/
 
 void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *map_type, int *submap_type, int *num_neighbors,
 		      int *remap_order, remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapvars_t *rv)
 {
-  /*
-    The routine reads a netCDF file to extract remapping info in SCRIP format
-  */
+  // The routine reads a NetCDF file to extract remapping info in SCRIP format
   /*
     Input variables
 
@@ -399,11 +392,11 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
   */
 #if defined(HAVE_LIBNETCDF)
 
-  /* Local variables */
+  // Local variables
 
   int lgridarea = FALSE;
   int status;
-  int nc_file_id;           /* id for netCDF file                       */
+  int nc_file_id;           /* id for NetCDF file                       */
   int nc_srcgrdsize_id;     /* id for source grid size                  */
   int nc_dstgrdsize_id;     /* id for destination grid size             */
   int nc_srcgrdcorn_id;     /* id for number of source grid corners     */
@@ -432,8 +425,6 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
   int nc_dstadd_id;         /* id for map destination address           */
   int nc_rmpmatrix_id;      /* id for remapping matrix                  */
 
-  long i;                   /* dummy index */
-
   char map_name[1024];
   char map_method[64];      /* character string for map_type             */
   char normalize_opt[64];   /* character string for normalization option */
@@ -446,13 +437,12 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
 
   int gridID1_gme_c = -1;
 
+  // Open file and read some global information
 
-  /* Open file and read some global information */
-
-  /* nce(nc_open(interp_file, NC_NOWRITE, &nc_file_id)); */
+  // nce(nc_open(interp_file, NC_NOWRITE, &nc_file_id));
   nc_file_id = cdf_openread(interp_file);
 
-  /* Map name */
+  // Map name
 
   nce(nc_get_att_text(nc_file_id, NC_GLOBAL, "title", map_name));
   nce(nc_inq_attlen(nc_file_id, NC_GLOBAL, "title", &attlen));
@@ -464,8 +454,7 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
       cdoPrint("From file: %s", interp_file);
     }
 
-  /* Normalization option */
-
+  // Normalization option
   nce(nc_get_att_text(nc_file_id, NC_GLOBAL, "normalization", normalize_opt));
   nce(nc_inq_attlen(nc_file_id, NC_GLOBAL, "normalization", &attlen));
   normalize_opt[attlen] = 0;
@@ -487,8 +476,7 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
   if ( cdoVerbose )
     cdoPrint("normalize_opt = %s", normalize_opt);
 
-  /* Map method */
-
+  // Map method
   nce(nc_get_att_text (nc_file_id, NC_GLOBAL, "map_method", map_method));
   nce(nc_inq_attlen(nc_file_id, NC_GLOBAL, "map_method", &attlen));
   map_method[attlen] = 0;
@@ -537,8 +525,7 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
 
   *map_type = rv->map_type;
 
-  /* File convention */
-
+  // File convention
   nce(nc_get_att_text (nc_file_id, NC_GLOBAL, "conventions", convention));
   nce(nc_inq_attlen(nc_file_id, NC_GLOBAL, "conventions", &attlen));
   convention[attlen] = 0;
@@ -552,9 +539,9 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
         cdoAbort("Unknown file convention!");
     }
 
-  /* Read some additional global attributes */
+  // Read some additional global attributes
 
-  /* Source and destination grid names */
+  // Source and destination grid names
 
   nce(nc_get_att_text (nc_file_id, NC_GLOBAL, "source_grid", src_grid_name));
   nce(nc_inq_attlen(nc_file_id, NC_GLOBAL, "source_grid", &attlen));
@@ -567,11 +554,11 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
   if ( cdoVerbose )
     cdoPrint("Remapping between: %s and %s", src_grid_name, tgt_grid_name);
 
-  /* Initialize remapgrid structure */
+  // Initialize remapgrid structure
   remapgrid_init(src_grid);
   remapgrid_init(tgt_grid);
 
-  /* Read dimension information */
+  // Read dimension information
 
   nce(nc_inq_dimid(nc_file_id, "src_grid_size", &nc_srcgrdsize_id));
   nce(nc_inq_dimlen(nc_file_id, nc_srcgrdsize_id, &dimlen));
@@ -616,10 +603,10 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
   nce(nc_inq_dimid(nc_file_id, "num_links", &nc_numlinks_id));
   nce(nc_inq_dimlen(nc_file_id, nc_numlinks_id, &dimlen));
   rv->num_links = dimlen;
-
+  /*
   if ( rv->num_links == 0 )
     cdoAbort("Number of remap links is 0, no remap weights found!");
-
+  */
   nce(nc_inq_dimid(nc_file_id, "num_wgts", &nc_numwgts_id));
   nce(nc_inq_dimlen(nc_file_id, nc_numwgts_id, &dimlen));
   rv->num_wts = dimlen;
@@ -645,14 +632,20 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
 
   rv->resize_increment = (int) (0.1 * MAX(src_grid->size, tgt_grid->size));
 
-  /* Allocate address and weight arrays for mapping 1 */
+  // Allocate address and weight arrays for mapping 1
 
-  rv->src_cell_add = (int*) Malloc(rv->num_links*sizeof(int));
-  rv->tgt_cell_add = (int*) Malloc(rv->num_links*sizeof(int));
+  rv->src_cell_add = NULL;
+  rv->tgt_cell_add = NULL;
+  rv->wts = NULL;
+  if ( rv->num_links > 0 )
+    {
+      rv->src_cell_add = (int*) Malloc(rv->num_links*sizeof(int));
+      rv->tgt_cell_add = (int*) Malloc(rv->num_links*sizeof(int));
 
-  rv->wts = (double*) Malloc(rv->num_wts*rv->num_links*sizeof(double));
+      rv->wts = (double*) Malloc(rv->num_wts*rv->num_links*sizeof(double));
+    }
 
-  /* Get variable ids */
+  // Get variable ids
 
   nce(nc_inq_varid(nc_file_id, "src_grid_dims", &nc_srcgrddims_id));
   nce(nc_inq_varid(nc_file_id, "src_grid_imask", &nc_srcgrdimask_id));
@@ -688,7 +681,7 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
   nce(nc_inq_varid(nc_file_id, "dst_address", &nc_dstadd_id));
   nce(nc_inq_varid(nc_file_id, "remap_matrix", &nc_rmpmatrix_id));
 
-  /* Read all variables */
+  // Read all variables
 
   nce(nc_get_var_int(nc_file_id, nc_srcgrddims_id, src_grid->dims));
 
@@ -754,23 +747,26 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
 
   nce(nc_get_var_double(nc_file_id, nc_dstgrdfrac_id, tgt_grid->cell_frac));
 
-  nce(nc_get_var_int(nc_file_id, nc_srcadd_id, rv->src_cell_add));
-  nce(nc_get_var_int(nc_file_id, nc_dstadd_id, rv->tgt_cell_add));
-
-  for ( i = 0; i < rv->num_links; i++ )
+  if ( rv->num_links > 0 )
     {
-      rv->src_cell_add[i]--;
-      rv->tgt_cell_add[i]--;
-    }
+      nce(nc_get_var_int(nc_file_id, nc_srcadd_id, rv->src_cell_add));
+      nce(nc_get_var_int(nc_file_id, nc_dstadd_id, rv->tgt_cell_add));
+
+      for ( long i = 0; i < rv->num_links; i++ )
+        {
+          rv->src_cell_add[i]--;
+          rv->tgt_cell_add[i]--;
+        }
 
-  nce(nc_get_var_double(nc_file_id, nc_rmpmatrix_id, rv->wts));
+      nce(nc_get_var_double(nc_file_id, nc_rmpmatrix_id, rv->wts));
+    }
 
-  /* Close input file */
+  // Close input file
 
   nce(nc_close(nc_file_id));
 
 #else
-  cdoAbort("netCDF support not compiled in!");
+  cdoAbort("NetCDF support not compiled in!");
 #endif
 
   rv->links.option    = FALSE;
@@ -780,4 +776,4 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
   rv->links.src_add   = NULL;
   rv->links.dst_add   = NULL;
   rv->links.w_index   = NULL;
-}  /* read_remap_scrip */
+}  // read_remap_scrip
diff --git a/src/remaplib.c b/src/remaplib.c
index dfb8321..1c45eb2 100644
--- a/src/remaplib.c
+++ b/src/remaplib.c
@@ -1852,3 +1852,28 @@ void reorder_links(remapvars_t *rv)
       printf("loop %ld  nlinks %ld\n", j+1, nlinks);
     }
 }
+
+
+void remapCheckArea(int grid_size, double *restrict cell_area, const char *name)
+{
+  for ( int n = 0; n < grid_size; ++n )
+    {
+      if ( cell_area[n] < -.01 )
+        cdoPrint("%s grid area error: %d %g", name, n, cell_area[n]);
+    }
+}
+
+
+void remapCheckWeights(long num_links, int num_wts, int norm_opt, int *src_cell_add, int *tgt_cell_add, double *wts)
+{
+  for ( long n = 0; n < num_links; ++n )
+    {
+      if ( wts[n*num_wts] < -0.01 )
+        cdoPrint("Map weight < 0! grid1idx=%d grid2idx=%d nlink=%d wts=%g",
+                 src_cell_add[n], tgt_cell_add[n], n, wts[n*num_wts]);
+
+      if ( norm_opt != NORM_OPT_NONE && wts[n*num_wts] > 1.01 )
+        cdoPrint("Map weight > 1! grid1idx=%d grid2idx=%d nlink=%d wts=%g",
+                 src_cell_add[n], tgt_cell_add[n], n, wts[n*num_wts]);
+    }
+}
diff --git a/src/results_template_parser.c b/src/results_template_parser.c
index c8872f0..c68ba70 100644
--- a/src/results_template_parser.c
+++ b/src/results_template_parser.c
@@ -1,52 +1,62 @@
+#if defined(HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "cdo_int.h"
 #include "template_parser.h"
 #include "magics_template_parser.h"
 #include "results_template_parser.h"
 
-#define DBG_MSG 0 
+#if defined(HAVE_LIBXML2)
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#endif
 
 
-/* extern int GetMagicsParameterInfo( const char *user_name, char **magics_name, char **magics_type ); */
+#define DBG_MSG 0 
 
-extern int GetMagicsParameterInfo(  char *user_name, xmlChar *param_value );
+/* extern int GetMagicsParameterInfo( const char *user_name, char **magics_name, char **magics_type ); */
 
-extern xmlNode *results_node;
+extern int GetMagicsParameterInfo(  const char *user_name, char *param_value );
 
 
 /* Recursive function that sets the results parameters from the XML structure */
 
-int results_template_parser( xmlNode * a_node, const char *varname ) 
-
+int results_template_parser( void * node, const char *varname ) 
 {
+#if defined(HAVE_LIBXML2)
+    xmlNode *a_node = (xmlNode*) node;
     xmlNode *cur_node = NULL;
     xmlAttrPtr attr = NULL;
-    xmlChar    *param_name,*param_value,*value;
-    char       *param_type;
+    xmlChar *param_value;
 
 	
-    if( a_node == NULL )
-	return 1;
+    if ( a_node == NULL )
+      return 1;
 
-    if( !strcmp( a_node->name, "results" ) )
+    if ( !strcmp( (const char*)a_node->name, "results" ) )
     {
- 	value = xmlGetProp( a_node, "version" );
+      const char *value = (const char*) xmlGetProp( a_node, (const xmlChar *)"version" );
 
-	if( value )
+      if ( value )
 	{
-    		if( DBG_MSG )
-			printf( "Version %s \n", value ); 
+          if ( DBG_MSG )
+            printf( "Version %s \n", value ); 
 
-		if( atof( value ) > 3.0f ) 
-		{
-			return 1;
-		}
+          if ( atof( value ) > 3.0f ) 
+            {
+              return 1;
+            }
 	}
     }
 
 
     for ( cur_node = a_node->children; cur_node; cur_node = cur_node->next )
     {
-	param_name = NULL;
-	param_type = NULL;
+#if 0
+	xmlChar *param_name = NULL;
+	char *param_type = NULL;
+#endif
 	param_value = NULL;
 
         if ( cur_node->type == XML_ELEMENT_NODE )
@@ -73,7 +83,7 @@ int results_template_parser( xmlNode * a_node, const char *varname )
 	      printf( "Finding varname = %s  result_name = %s\n", varname, xmlGetProp( cur_node,"name") );
 #endif
 
-	      if ( strcmp( varname, xmlGetProp( cur_node,"name" ) ) == 0 )
+	      if ( strcmp( varname, (const char*)xmlGetProp( cur_node,(xmlChar *)"name" ) ) == 0 )
 	      {
 #if 0
 	          printf( "Found varname = %s  result_name = %s\n", varname, xmlGetProp( cur_node,"name") );
@@ -87,7 +97,7 @@ int results_template_parser( xmlNode * a_node, const char *varname )
 			  param_value = xmlNodeGetContent( attr->children );
 
 			  /* if( !GetMagicsParameterInfo( attr->name, &magics_param_name, &param_type ) ) */
-			  if( !GetMagicsParameterInfo( (char *) attr->name, param_value ) )
+			  if( !GetMagicsParameterInfo( (const char *) attr->name, (char *) param_value ) )
 			  {
 
 #if 0
@@ -117,5 +127,11 @@ int results_template_parser( xmlNode * a_node, const char *varname )
 	    }
         }
     }
-    return 0;
+#else
+  
+  cdoAbort("XML2 support not compiled in!");
+  
+#endif
+
+  return 0;
 }
diff --git a/src/results_template_parser.h b/src/results_template_parser.h
index 09eeb6a..2d73a0e 100644
--- a/src/results_template_parser.h
+++ b/src/results_template_parser.h
@@ -1,13 +1,6 @@
 #ifndef RESULTS_TEMPLATE_PARSER_HH
 #define RESULTS_TEMPLATE_PARSER_HH
 
-#include<stdio.h>
-#include<string.h>
-#include<stdlib.h>
-
-#include<libxml/parser.h>
-#include<libxml/tree.h>
-
- int results_template_parser( xmlNode * a_node, const char *varname ); 
+int results_template_parser( void *node, const char *varname ); 
 
 #endif
diff --git a/src/table.c b/src/table.c
index f506f96..0b92d76 100644
--- a/src/table.c
+++ b/src/table.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/template_parser.c b/src/template_parser.c
index f6b4617..cab207c 100644
--- a/src/template_parser.c
+++ b/src/template_parser.c
@@ -1,134 +1,165 @@
+#if defined(HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "cdo_int.h"
 #include "template_parser.h"
 #include "magics_template_parser.h"
 #include "results_template_parser.h"
 
-#define DBG_MSG 0 
-
+#if defined(HAVE_LIBXML2)
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+xmlNode *root_node;
+xmlDoc *param_doc;
+#endif
 
-extern xmlNode *root_node, *magics_node, *results_node;
-extern xmlDoc *param_doc;
 
-extern int magics_template_parser();
-extern int results_template_parser();
+#define DBG_MSG 0 
 
+void *magics_node, *results_node;
 
+// not used
+static
 int template_parser(  char *Filename, const char *varname )
-
 {
-        xmlDoc         *doc = NULL;
-        xmlNode        *root_element = NULL;
+#if defined(HAVE_LIBXML2)
+  xmlDoc         *doc = NULL;
+  xmlNode        *root_element = NULL;
+
+  doc = xmlReadFile( Filename, NULL, 0 );
+  if ( doc == NULL )
+    {
+      printf( "Error: Could not parse the file \"%s\"\n", Filename );
+      return (1);
+    }
+  else
+    {
+      /* 
+         Get the name of the root element node 
+         If "magics" , call "magics" parser
+         If "results", call "results" parser
+      */                      
 
-        doc = xmlReadFile( Filename, NULL, 0 );
-        if ( doc == NULL )
+      root_element = xmlDocGetRootElement( doc );
+		  
+      if( !strcmp( (const char*)root_element->name, "magics" ) )
         {
-                  printf( "Error: Could not parse the file \"%s\"\n", Filename );
-        	  return (1);
+          if ( magics_template_parser( root_element ) == 1 )
+            {
+              printf( "Un-Supported version of Magics++! \n" );
+              return (2);
+            }
         }
-        else
+      else if( !strcmp( (const char*)root_element->name, "results" ) )
         {
-                  /* 
-		     Get the name of the root element node 
-		     If "magics" , call "magics" parser
-		     If "results", call "results" parser
-		  */                      
-
-                  root_element = xmlDocGetRootElement( doc );
-		  
-		  if( !strcmp( root_element->name, "magics" ) )
-		  {
-                  	if ( magics_template_parser( root_element ) == 1 )
-		  	{
-				printf( "Un-Supported version of Magics++! \n" );
-	        		return (2);
-			}
-		  }
-		  else if( !strcmp( root_element->name, "results" ) )
-		  {
-                  	results_template_parser( root_element, varname );
-			 /* Needs some error handling */
-		  }
-
-                  /*** free the document ***/
-                  xmlFreeDoc( doc );
+          results_template_parser( root_element, varname );
+          /* Needs some error handling */
         }
 
-        /*** Free the global variables that may
-         *   have been allocated by the parser. 
-        ***/
-
-        xmlCleanupParser();
+      /*** free the document ***/
+      xmlFreeDoc( doc );
+    }
+  
+  /*** Free the global variables that may
+   *   have been allocated by the parser. 
+   ***/
+
+  xmlCleanupParser();
+#else
+  
+  cdoAbort("XML2 support not compiled in!");
+  
+#endif
 
-        return 0;
+  return 0;
 }
 
 
 int init_XMLtemplate_parser( char *Filename )
-
 {
-        param_doc = xmlReadFile( Filename, NULL, 0 );
-        if ( param_doc == NULL )
-        {
-                  printf( "Error: Could not parse the file \"%s\"\n", Filename );
-        	  return (1);
-        }
-        else
-        {
-		  fprintf( stderr, "XML file %s being parsed \n", Filename );
-                  root_node = xmlDocGetRootElement( param_doc );
-        }
-        return 0;
-}
+#if defined(HAVE_LIBXML2)
+  param_doc = xmlReadFile( Filename, NULL, 0 );
+  if ( param_doc == NULL )
+    {
+      printf( "Error: Could not parse the file \"%s\"\n", Filename );
+      return (1);
+    }
+  else
+    {
+      fprintf( stderr, "XML file %s being parsed \n", Filename );
+      root_node = xmlDocGetRootElement( param_doc );
+    }
+#else
+  
+  cdoAbort("XML2 support not compiled in!");
+  
+#endif
 
+  return 0;
+}
 
-int updatemagics_and_results_nodes(  )
 
+int updatemagics_and_results_nodes(void)
 {
-    xmlNode *cur_node = NULL;
+#if defined(HAVE_LIBXML2)
+  xmlNode *cur_node = NULL;
 	
-    if( root_node == NULL )
+  if( root_node == NULL )
     {
-        printf( "Invalid Root Node\n" );
-    	return 0;
+      printf( "Invalid Root Node\n" );
+      return 0;
     }
 
-    for ( cur_node = root_node->children; cur_node; cur_node = cur_node->next )
+  for ( cur_node = root_node->children; cur_node; cur_node = cur_node->next )
     {   
-        if ( cur_node->type == XML_ELEMENT_NODE )
+      if ( cur_node->type == XML_ELEMENT_NODE )
         {   
-    
-#if 0
-            fprintf( stdout, "Node Name: %s \n", cur_node->name );
+#if DBG_MSG
+          fprintf( stdout, "Node Name: %s \n", cur_node->name );
 #endif
-            if( !strcmp( cur_node->name, "magics" ) ) 
+          if( !strcmp( (const char*)cur_node->name, "magics" ) ) 
             {
-		magics_node = cur_node;
-#if 0
-                fprintf( stdout, "Node Name: %s \n", cur_node->name );
+              magics_node = (void*) cur_node;
+#if DBG_MSG
+              fprintf( stdout, "Node Name: %s \n", cur_node->name );
 #endif
 	    }  
 
-            if( !strcmp( cur_node->name, "results" ) ) 
+          if( !strcmp( (const char*)cur_node->name, "results" ) ) 
             {
-		results_node = cur_node;
-#if 0
-                fprintf( stdout, "Node Name: %s \n", cur_node->name );
+              results_node = (void*) cur_node;
+#if DBG_MSG
+              fprintf( stdout, "Node Name: %s \n", cur_node->name );
 #endif
 	    }  
 	}
     }
-    return 0;
-}
+#else
+  
+  cdoAbort("XML2 support not compiled in!");
+  
+#endif
 
+  return 0;
+}
 
-int quit_XMLtemplate_parser( )
 
+int quit_XMLtemplate_parser(void)
 {
-        xmlFreeDoc( param_doc );
-        xmlCleanupParser( );
-	if( param_doc == NULL )
-		printf( "Cleaned XML parser\n" );
-#if 0
-        fprintf( stdout, "Cleaned XML parser\n" );
+#if defined(HAVE_LIBXML2)
+  xmlFreeDoc( param_doc );
+  xmlCleanupParser( );
+  if( param_doc == NULL )
+    printf( "Cleaned XML parser\n" );
+#if DBG_MSG
+  fprintf( stdout, "Cleaned XML parser\n" );
 #endif
-	return 0;
+#else
+  
+  cdoAbort("XML2 support not compiled in!");
+  
+#endif
+
+  return 0;
 }
diff --git a/src/template_parser.h b/src/template_parser.h
index 42b4dba..88b2dd3 100644
--- a/src/template_parser.h
+++ b/src/template_parser.h
@@ -1,22 +1,8 @@
 #ifndef TEMPLATE_PARSER_HH
 #define TEMPLATE_PARSER_HH
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <locale.h>
-
-#if defined(HAVE_LIBXML2)
-#include<libxml/parser.h>
-#include<libxml/tree.h>
-
-
-int template_parser( char *Filename, const char *varname );
 int init_XMLtemplate_parser( char *Filename );
-int updatemagics_and_results_nodes( );
-int quit_XMLtemplate_parser( );
-
-
-#endif
+int updatemagics_and_results_nodes(void);
+int quit_XMLtemplate_parser(void);
 
 #endif
diff --git a/src/timebase.h b/src/timebase.h
index 716bb60..2f750df 100644
--- a/src/timebase.h
+++ b/src/timebase.h
@@ -3,6 +3,10 @@
 
 #include <inttypes.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* date format:  YYYYMMDD */
 /* time format:  hhmmss   */
 
@@ -22,4 +26,18 @@ double julday_sub(int julday1, int secofday1, int julday2, int secofday2, int *d
 void encode_juldaysec(int calendar, int year, int month, int day, int hour, int minute, int second, int *julday, int *secofday);
 void decode_juldaysec(int calendar, int julday, int secofday, int *year, int *month, int *day, int *hour, int *minute, int *second);
 
+#if defined (__cplusplus)
+}
+#endif
+
 #endif  /* _TIMEBASE_H */
+
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
diff --git a/src/timer.c b/src/timer.c
index 2d82828..f1d32bd 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/src/util.c b/src/util.c
index 4339f61..d07e3e4 100644
--- a/src/util.c
+++ b/src/util.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -85,6 +85,9 @@ int CDO_CMOR_Mode        = FALSE;
 
 int cdoDiag              = FALSE;
 
+int CDO_Memtype          = MEMTYPE_DOUBLE;
+int CDO_Parallel_Read    = FALSE;
+
 int CDO_Reduce_Dim       = FALSE;
 int CDO_Append_History   = TRUE;
 int CDO_Reset_History    = FALSE;
@@ -516,27 +519,30 @@ int fileExists(const char *restrict filename)
 
 int userFileOverwrite(const char *restrict filename)
 {
-  int status = 0, len;
-  char line[1024], *pline;
+  int status = 0;
 
-  fprintf(stderr, "File %s already exists, overwrite? (yes/no): ", filename);
-  readline(stdin, line, 1024);
-  pline = line;
-  while ( isspace((int) *pline) ) pline++;
-  len = strlen(pline);
-  if ( len == 3 )
+  if ( stdin_is_tty && stderr_is_tty )
     {
-      if ( pline[0] == 'y' && pline[1] == 'e' && pline[2] == 's' )
-        status = 1;
-      else if ( pline[0] == 'Y' && pline[1] == 'E' && pline[2] == 'S' )
-        status = 1;
-    }
-  else if ( len == 1 )
-    {
-      if ( pline[0] == 'y' ) status = 1;
+      fprintf(stderr, "File %s already exists, overwrite? (yes/no): ", filename);
+      char line[1024];
+      readline(stdin, line, 1024);
+      char *pline = line;
+      while ( isspace((int) *pline) ) pline++;
+      int len = (int) strlen(pline);
+      if ( len == 3 )
+        {
+          if ( pline[0] == 'y' && pline[1] == 'e' && pline[2] == 's' )
+            status = 1;
+          else if ( pline[0] == 'Y' && pline[1] == 'E' && pline[2] == 'S' )
+            status = 1;
+        }
+      else if ( len == 1 )
+        {
+          if ( pline[0] == 'y' || pline[0] == 'Y' ) status = 1;
+        }
     }
 
-  return (status);
+  return status;
 }
 
 
diff --git a/src/util.h b/src/util.h
index 33444c8..e3cbddc 100644
--- a/src/util.h
+++ b/src/util.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -45,6 +45,8 @@
 extern char *Progname;
 extern char *cdoGridSearchDir;
 extern int CDO_Reduce_Dim;
+extern int CDO_Memtype;
+extern int CDO_Parallel_Read;
 extern int CDO_Append_History;
 extern int CDO_Reset_History;
 extern int timer_read, timer_write; // refactor: both pstream.c and CDIread.c CDIwrite.c defined in cdo.c
@@ -198,7 +200,6 @@ void cdoGenFileSuffix(char *filesuffix, size_t maxlen, int filetype, int vlistID
 
 void writeNCgrid(const char *gridfile, int gridID, int *imask);
 void defineZaxis(const char *zaxisarg);
-void cdiDefTableID(int tableID);
 
 int gridFromName(const char *gridname);
 int zaxisFromName(const char *zaxisname);
diff --git a/src/zaxis.c b/src/zaxis.c
index 68e1b3b..8478317 100644
--- a/src/zaxis.c
+++ b/src/zaxis.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
diff --git a/test/Copy_netcdf.test.in b/test/Collgrid.test.in
similarity index 60%
copy from test/Copy_netcdf.test.in
copy to test/Collgrid.test.in
index 98b4525..06c6470 100644
--- a/test/Copy_netcdf.test.in
+++ b/test/Collgrid.test.in
@@ -1,5 +1,5 @@
 #! @SHELL@
-echo 1..1 # Number of tests to be executed.
+echo 1..9 # Number of tests to be executed.
 #
 test -n "$CDO"      || CDO=cdo
 test -n "$DATAPATH" || DATAPATH=./data
@@ -7,21 +7,32 @@ test -n "$DATAPATH" || DATAPATH=./data
 CDOOUT=cout
 CDOERR=cerr
 #
+GRIDTYPES="regular generic curvilinear"
+DISTS="4,3 12,1 1,6"
+#
 NTEST=1
 #
-for OPERATOR in copy; do
-  for FILE in testfile01c.nc; do
+for GRIDTYPE in $GRIDTYPES; do
+  for DIST in $DISTS; do
     RSTAT=0
+    GT=$(echo $GRIDTYPE | cut -c1)
+    FILE=data${GT}.nc
     IFILE=$DATAPATH/${FILE}
     OFILE=${OPERATOR}_${FILE}
 
-    CDOTEST="$OPERATOR $FILE"
-    CDOCOMMAND="$CDO $OPERATOR $IFILE $OFILE"
+    CDOTEST="$GRIDTYPE $DIST"
 
     if [ "@ENABLE_NETCDF@" = yes ] ; then
+      nx=$(echo $DIST | sed 's/,.*//')
+      NX=""
+      if [ $FILE != datar.nc ] ; then NX=",$nx" ; fi
+      CDOCOMMAND="$CDO collgrid$NX xxx* $OFILE"
       echo "Running test: $NTEST"
       echo "$CDOCOMMAND"
 
+      $CDO distgrid,$DIST $IFILE xxx
+      test $? -eq 0 || let RSTAT+=1
+
       $CDOCOMMAND
       test $? -eq 0 || let RSTAT+=1
 
@@ -29,6 +40,8 @@ for OPERATOR in copy; do
       test $? -eq 0 || let RSTAT+=1
       test -s $CDOOUT && let RSTAT+=1
       cat $CDOOUT $CDOERR
+ 
+      rm -f $OFILE xxx*
 
       test $RSTAT -eq 0 && echo "ok $NTEST - $CDOTEST"
       test $RSTAT -eq 0 || echo "not ok $NTEST - $CDOTEST"
@@ -37,7 +50,6 @@ for OPERATOR in copy; do
     fi
 
     let NTEST+=1
-    rm -f $OFILE
   done
 done
 #
diff --git a/test/Copy_netcdf.test.in b/test/Copy_netcdf.test.in
index 98b4525..5bdc4be 100644
--- a/test/Copy_netcdf.test.in
+++ b/test/Copy_netcdf.test.in
@@ -1,5 +1,5 @@
 #! @SHELL@
-echo 1..1 # Number of tests to be executed.
+echo 1..5 # Number of tests to be executed.
 #
 test -n "$CDO"      || CDO=cdo
 test -n "$DATAPATH" || DATAPATH=./data
@@ -7,10 +7,12 @@ test -n "$DATAPATH" || DATAPATH=./data
 CDOOUT=cout
 CDOERR=cerr
 #
+FILES="datar.nc datag.nc datac.nc datau.nc testfile01c.nc"
+#
 NTEST=1
 #
 for OPERATOR in copy; do
-  for FILE in testfile01c.nc; do
+  for FILE in $FILES; do
     RSTAT=0
     IFILE=$DATAPATH/${FILE}
     OFILE=${OPERATOR}_${FILE}
diff --git a/test/Expr.test.in b/test/Expr.test.in
new file mode 100644
index 0000000..db9accd
--- /dev/null
+++ b/test/Expr.test.in
@@ -0,0 +1,64 @@
+#! @SHELL@
+echo 1..2 # Number of tests to be executed.
+#
+test -n "$CDO"      || CDO=cdo
+test -n "$DATAPATH" || DATAPATH=./data
+#
+CDOOUT=cout
+CDOERR=cerr
+FORMAT="-f srv -b 32"
+#
+IFILE=$DATAPATH/pl_data
+NTEST=1
+#
+FINSTR=finstr
+#
+function testfunc()
+{
+  RSTAT=0
+
+  CDOTEST="instruction set $NTEST"
+  echo "Running test: $NTEST - $CDOTEST"
+
+  for EXPR in expr aexpr; do
+    RFILE=$DATAPATH/${EXPR}${NTEST}_ref
+    OFILE=${EXPR}${NTEST}_res
+
+    for FILE in "" "f"; do
+
+      if [ "$FILE" = "f" ] ; then
+        echo $INSTR > $FINSTR
+        CDOCOMMAND="$CDO $FORMAT $EXPR${FILE},$FINSTR $IFILE $OFILE"
+      else
+        CDOCOMMAND="$CDO $FORMAT $EXPR,$INSTR $IFILE $OFILE"
+      fi
+      
+      echo "$CDOCOMMAND"
+
+      $CDOCOMMAND
+      test $? -eq 0 || let RSTAT+=1
+
+      $CDO diff $RFILE $OFILE > $CDOOUT 2> $CDOERR
+      test $? -eq 0 || let RSTAT+=1
+      test -s $CDOOUT && let RSTAT+=1
+      cat $CDOOUT $CDOERR
+
+      rm -f $OFILE $FINSTR
+    done
+  done
+
+  test $RSTAT -eq 0 && echo "ok $NTEST - $CDOTEST"
+  test $RSTAT -eq 0 || echo "not ok $NTEST - $CDOTEST"
+
+  let NTEST+=1
+}
+#
+INSTR="_clev=clev(var130);pottemp=var130*((100000/_clev)^0.287);"
+testfunc
+#
+INSTR="var1=(var129>0)?(var130-273.15):var152;"
+testfunc
+#
+rm -f $CDOOUT $CDOERR
+#
+exit 0
diff --git a/test/Makefile.am b/test/Makefile.am
index 2c543bc..50e2f7c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -11,9 +11,10 @@ TEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
                   $(top_srcdir)/config/tap-driver.sh
 
 # tests which should pass
-TESTS = File.test Read_grib.test Read_netcdf.test Copy_netcdf.test Cat.test Gridarea.test Detrend.test \
+TESTS = threads.test wildcard.test File.test Read_grib.test Read_netcdf.test Copy_netcdf.test Cat.test Gridarea.test Detrend.test \
         Genweights.test Remap.test Select.test Spectral.test Ymonstat.test Timstat.test Ensstat.test \
-        Enspctl.test Fldstat.test Fldpctl.test Vertint.test Afterburner.test Arith.test Gradsdes.test wildcard.test
+        Enspctl.test Fldstat.test Fldpctl.test Vertint.test Afterburner.test Arith.test Expr.test \
+        Gradsdes.test Collgrid.test
 
 # tests which should fail
 XFAIL_TESTS = 
diff --git a/test/Makefile.in b/test/Makefile.in
index 3d6bc8d..3de2043 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -90,8 +90,9 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(srcdir)/Fldstat.test.in $(srcdir)/Fldpctl.test.in \
 	$(srcdir)/Ensstat.test.in $(srcdir)/Enspctl.test.in \
 	$(srcdir)/Afterburner.test.in $(srcdir)/Detrend.test.in \
-	$(srcdir)/Arith.test.in $(srcdir)/Gradsdes.test.in \
-	$(srcdir)/wildcard.test.in README
+	$(srcdir)/Arith.test.in $(srcdir)/Expr.test.in \
+	$(srcdir)/Gradsdes.test.in $(srcdir)/Collgrid.test.in \
+	$(srcdir)/threads.test.in $(srcdir)/wildcard.test.in README
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
@@ -107,7 +108,8 @@ CONFIG_CLEAN_FILES = File.test Read_grib.test Read_netcdf.test \
 	Remap.test Select.test Spectral.test Timstat.test Vertint.test \
 	Ymonstat.test Fldstat.test Fldpctl.test Ensstat.test \
 	Enspctl.test Afterburner.test Detrend.test Arith.test \
-	Gradsdes.test wildcard.test
+	Expr.test Gradsdes.test Collgrid.test threads.test \
+	wildcard.test
 CONFIG_CLEAN_VPATH_FILES =
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
@@ -367,6 +369,7 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 ENABLE_CDI_LIB = @ENABLE_CDI_LIB@
 ENABLE_CGRIBEX = @ENABLE_CGRIBEX@
+ENABLE_CXX = @ENABLE_CXX@
 ENABLE_DATA = @ENABLE_DATA@
 ENABLE_EXTRA = @ENABLE_EXTRA@
 ENABLE_GRIB = @ENABLE_GRIB@
@@ -377,6 +380,7 @@ ENABLE_NC4 = @ENABLE_NC4@
 ENABLE_NC4HDF5 = @ENABLE_NC4HDF5@
 ENABLE_NETCDF = @ENABLE_NETCDF@
 ENABLE_SERVICE = @ENABLE_SERVICE@
+ENABLE_THREADS = @ENABLE_THREADS@
 EXEEXT = @EXEEXT@
 FCFLAGS = @FCFLAGS@
 FGREP = @FGREP@
@@ -516,9 +520,10 @@ TEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
 
 
 # tests which should pass
-TESTS = File.test Read_grib.test Read_netcdf.test Copy_netcdf.test Cat.test Gridarea.test Detrend.test \
+TESTS = threads.test wildcard.test File.test Read_grib.test Read_netcdf.test Copy_netcdf.test Cat.test Gridarea.test Detrend.test \
         Genweights.test Remap.test Select.test Spectral.test Ymonstat.test Timstat.test Ensstat.test \
-        Enspctl.test Fldstat.test Fldpctl.test Vertint.test Afterburner.test Arith.test Gradsdes.test wildcard.test
+        Enspctl.test Fldstat.test Fldpctl.test Vertint.test Afterburner.test Arith.test Expr.test \
+        Gradsdes.test Collgrid.test
 
 
 #        $(top_srcdir)/test/test_Remap.sh \
@@ -607,8 +612,14 @@ Detrend.test: $(top_builddir)/config.status $(srcdir)/Detrend.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Arith.test: $(top_builddir)/config.status $(srcdir)/Arith.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+Expr.test: $(top_builddir)/config.status $(srcdir)/Expr.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Gradsdes.test: $(top_builddir)/config.status $(srcdir)/Gradsdes.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+Collgrid.test: $(top_builddir)/config.status $(srcdir)/Collgrid.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+threads.test: $(top_builddir)/config.status $(srcdir)/threads.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 wildcard.test: $(top_builddir)/config.status $(srcdir)/wildcard.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 
diff --git a/test/data/Makefile.am b/test/data/Makefile.am
index ed23996..0a32f15 100644
--- a/test/data/Makefile.am
+++ b/test/data/Makefile.am
@@ -1,5 +1,6 @@
 INPUTDATA = ts_mm_5years hl_l19.grb t21_geosp_tsurf.grb bathy4.grb pl_data pl_data.grb detrend_data \
-            grib_testfile01.grb grib_testfile02.grb netcdf_testfile01.nc netcdf_testfile02.nc testfile01c.nc
+            grib_testfile01.grb grib_testfile02.grb netcdf_testfile01.nc netcdf_testfile02.nc testfile01c.nc \
+            datar.nc datac.nc datau.nc datag.nc
 
 FILE_REF     = file_F32_srv_ref
 GRIB_REF     = grib_testfile01_sinfo_ref grib_testfile01_info_ref grib_testfile02_sinfo_ref grib_testfile02_info_ref
@@ -15,6 +16,8 @@ REMAP_REF    = n16_bic_ref n16_bil_ref n16_con_ref n16_ycon_ref n16_laf_ref n16_
                n32_bic_ref n32_bil_ref n32_con_ref n32_ycon_ref n32_laf_ref n32_nn_ref n32_dis_ref
 SELECT_REF   = select1_ref select2_ref select3_ref select4_ref select5_ref
 DETREND_REF  = detrend_ref
+EXPR_REF     = expr1_ref aexpr1_ref expr2_ref aexpr2_ref
+THREAD_REF   = thread1_ref
 GRADSDES_REF = pl_data.ctl pl_data.gmp
 
-EXTRA_DIST = $(INPUTDATA) $(FILE_REF) $(GRIB_REF) $(NETCDF_REF) $(YMONSTAT_REF) $(TIMSTAT_REF) $(FLDSTAT_REF) $(FLDPSTAT_REF) $(ENSPSTAT_REF) $(SPECTRAL_REF) $(VERTINT_REF) $(REMAP_REF) $(SELECT_REF) $(DETREND_REF) $(GRADSDES_REF)
+EXTRA_DIST = $(INPUTDATA) $(FILE_REF) $(GRIB_REF) $(NETCDF_REF) $(YMONSTAT_REF) $(TIMSTAT_REF) $(FLDSTAT_REF) $(FLDPSTAT_REF) $(ENSPSTAT_REF) $(SPECTRAL_REF) $(VERTINT_REF) $(REMAP_REF) $(SELECT_REF) $(DETREND_REF) $(THREAD_REF) $(EXPR_REF) $(GRADSDES_REF)
diff --git a/test/data/Makefile.in b/test/data/Makefile.in
index b74aa9d..5ae555f 100644
--- a/test/data/Makefile.in
+++ b/test/data/Makefile.in
@@ -149,6 +149,7 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 ENABLE_CDI_LIB = @ENABLE_CDI_LIB@
 ENABLE_CGRIBEX = @ENABLE_CGRIBEX@
+ENABLE_CXX = @ENABLE_CXX@
 ENABLE_DATA = @ENABLE_DATA@
 ENABLE_EXTRA = @ENABLE_EXTRA@
 ENABLE_GRIB = @ENABLE_GRIB@
@@ -159,6 +160,7 @@ ENABLE_NC4 = @ENABLE_NC4@
 ENABLE_NC4HDF5 = @ENABLE_NC4HDF5@
 ENABLE_NETCDF = @ENABLE_NETCDF@
 ENABLE_SERVICE = @ENABLE_SERVICE@
+ENABLE_THREADS = @ENABLE_THREADS@
 EXEEXT = @EXEEXT@
 FCFLAGS = @FCFLAGS@
 FGREP = @FGREP@
@@ -286,7 +288,8 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 INPUTDATA = ts_mm_5years hl_l19.grb t21_geosp_tsurf.grb bathy4.grb pl_data pl_data.grb detrend_data \
-            grib_testfile01.grb grib_testfile02.grb netcdf_testfile01.nc netcdf_testfile02.nc testfile01c.nc
+            grib_testfile01.grb grib_testfile02.grb netcdf_testfile01.nc netcdf_testfile02.nc testfile01c.nc \
+            datar.nc datac.nc datau.nc datag.nc
 
 FILE_REF = file_F32_srv_ref
 GRIB_REF = grib_testfile01_sinfo_ref grib_testfile01_info_ref grib_testfile02_sinfo_ref grib_testfile02_info_ref
@@ -303,8 +306,10 @@ REMAP_REF = n16_bic_ref n16_bil_ref n16_con_ref n16_ycon_ref n16_laf_ref n16_nn_
 
 SELECT_REF = select1_ref select2_ref select3_ref select4_ref select5_ref
 DETREND_REF = detrend_ref
+EXPR_REF = expr1_ref aexpr1_ref expr2_ref aexpr2_ref
+THREAD_REF = thread1_ref
 GRADSDES_REF = pl_data.ctl pl_data.gmp
-EXTRA_DIST = $(INPUTDATA) $(FILE_REF) $(GRIB_REF) $(NETCDF_REF) $(YMONSTAT_REF) $(TIMSTAT_REF) $(FLDSTAT_REF) $(FLDPSTAT_REF) $(ENSPSTAT_REF) $(SPECTRAL_REF) $(VERTINT_REF) $(REMAP_REF) $(SELECT_REF) $(DETREND_REF) $(GRADSDES_REF)
+EXTRA_DIST = $(INPUTDATA) $(FILE_REF) $(GRIB_REF) $(NETCDF_REF) $(YMONSTAT_REF) $(TIMSTAT_REF) $(FLDSTAT_REF) $(FLDPSTAT_REF) $(ENSPSTAT_REF) $(SPECTRAL_REF) $(VERTINT_REF) $(REMAP_REF) $(SELECT_REF) $(DETREND_REF) $(THREAD_REF) $(EXPR_REF) $(GRADSDES_REF)
 all: all-am
 
 .SUFFIXES:
diff --git a/test/data/aexpr1_ref b/test/data/aexpr1_ref
new file mode 100644
index 0000000..dd5af96
Binary files /dev/null and b/test/data/aexpr1_ref differ
diff --git a/test/data/aexpr2_ref b/test/data/aexpr2_ref
new file mode 100644
index 0000000..ae26e64
Binary files /dev/null and b/test/data/aexpr2_ref differ
diff --git a/test/data/datac.nc b/test/data/datac.nc
new file mode 100644
index 0000000..0a330ed
Binary files /dev/null and b/test/data/datac.nc differ
diff --git a/test/data/datag.nc b/test/data/datag.nc
new file mode 100644
index 0000000..75ab4d5
Binary files /dev/null and b/test/data/datag.nc differ
diff --git a/test/data/datar.nc b/test/data/datar.nc
new file mode 100644
index 0000000..d0313db
Binary files /dev/null and b/test/data/datar.nc differ
diff --git a/test/data/datau.nc b/test/data/datau.nc
new file mode 100644
index 0000000..db33c57
Binary files /dev/null and b/test/data/datau.nc differ
diff --git a/test/data/expr1_ref b/test/data/expr1_ref
new file mode 100644
index 0000000..64f3700
Binary files /dev/null and b/test/data/expr1_ref differ
diff --git a/test/data/expr2_ref b/test/data/expr2_ref
new file mode 100644
index 0000000..cf28d14
Binary files /dev/null and b/test/data/expr2_ref differ
diff --git a/test/data/grib_testfile01_sinfo_ref b/test/data/grib_testfile01_sinfo_ref
index fe92662..ab59641 100644
--- a/test/data/grib_testfile01_sinfo_ref
+++ b/test/data/grib_testfile01_sinfo_ref
@@ -1,5 +1,5 @@
    File format : GRIB
-    -1 : Institut Source   Ttype    Levels Num    Points Num Dtype : Parameter ID
+    -1 : Institut Source   Steptype Levels Num    Points Num Dtype : Parameter ID
      1 : unknown  unknown  instant       1   1      2592   1  P16  : 1             
    Grid coordinates :
      1 : lonlat                   : points=2592 (72x36)
diff --git a/test/data/grib_testfile02_sinfo_ref b/test/data/grib_testfile02_sinfo_ref
index cebd3b5..ef42506 100644
--- a/test/data/grib_testfile02_sinfo_ref
+++ b/test/data/grib_testfile02_sinfo_ref
@@ -1,5 +1,5 @@
    File format : GRIB
-    -1 : Institut Source   Ttype    Levels Num    Points Num Dtype : Parameter ID
+    -1 : Institut Source   Steptype Levels Num    Points Num Dtype : Parameter ID
      1 : unknown  unknown  instant       1   1         1   1  P0   : 1             
    Grid coordinates :
      1 : lonlat                   : points=1 (1x1)
diff --git a/test/data/netcdf_testfile01_sinfon_ref b/test/data/netcdf_testfile01_sinfon_ref
index f575024..1b77b6c 100644
--- a/test/data/netcdf_testfile01_sinfon_ref
+++ b/test/data/netcdf_testfile01_sinfon_ref
@@ -1,5 +1,5 @@
-   File format : netCDF
-    -1 : Institut Source   Ttype    Levels Num    Points Num Dtype : Parameter name
+   File format : NetCDF
+    -1 : Institut Source   Steptype Levels Num    Points Num Dtype : Parameter name
      1 : unknown  unknown  instant       1   1      2592   1  I16  : tem           
    Grid coordinates :
      1 : lonlat                   : points=2592 (72x36)
diff --git a/test/data/netcdf_testfile02_sinfon_ref b/test/data/netcdf_testfile02_sinfon_ref
index 5111e1f..3a5fa76 100644
--- a/test/data/netcdf_testfile02_sinfon_ref
+++ b/test/data/netcdf_testfile02_sinfon_ref
@@ -1,5 +1,5 @@
-   File format : netCDF
-    -1 : Institut Source   Ttype    Levels Num    Points Num Dtype : Parameter name
+   File format : NetCDF
+    -1 : Institut Source   Steptype Levels Num    Points Num Dtype : Parameter name
      1 : unknown  unknown  instant       1   1         1   1  F32  : for           
    Grid coordinates :
      1 : lonlat                   : points=1 (1x1)
diff --git a/test/data/thread1_ref b/test/data/thread1_ref
new file mode 100644
index 0000000..4707c1e
Binary files /dev/null and b/test/data/thread1_ref differ
diff --git a/test/threads.test.in b/test/threads.test.in
new file mode 100644
index 0000000..dae35d1
--- /dev/null
+++ b/test/threads.test.in
@@ -0,0 +1,55 @@
+#! @SHELL@
+echo 1..1 # Number of tests to be executed.
+#
+test -n "$CDO"      || CDO=cdo
+test -n "$DATAPATH" || DATAPATH=./data
+#
+CDOOUT=cout
+CDOERR=cerr
+FORMAT="-f srv -b 32"
+#
+IFILE=$DATAPATH/pl_data
+NTEST=1
+#
+function testfunc()
+{
+  RSTAT=0
+
+  CDOTEST="chaining set $NTEST"
+  echo "Running test: $NTEST - $CDOTEST"
+
+  RFILE=$DATAPATH/thread${NTEST}_ref
+  OFILE=thread${NTEST}_res
+
+  CDOCOMMAND="$CDO $FORMAT $INSTR $IFILE $OFILE"
+      
+  echo "$CDOCOMMAND"
+
+  if [ "@ENABLE_THREADS@" = yes ] ; then
+
+    $CDOCOMMAND
+    test $? -eq 0 || let RSTAT+=1
+
+    $CDO diff $RFILE $OFILE > $CDOOUT 2> $CDOERR
+    test $? -eq 0 || let RSTAT+=1
+    test -s $CDOOUT && let RSTAT+=1
+    cat $CDOOUT $CDOERR
+
+    rm -f $OFILE
+
+    test $RSTAT -eq 0 && echo "ok $NTEST - $CDOTEST"
+    test $RSTAT -eq 0 || echo "not ok $NTEST - $CDOTEST"
+  else
+    test $RSTAT -eq 0 && echo "ok $NTEST - $CDOTEST # SKIP threads not enabled"
+  fi
+  
+  let NTEST+=1
+  rm -f $OFILE
+}
+#
+INSTR="-fldmean -timmean -select,code=129,130,152"
+testfunc 
+#
+rm -f $CDOOUT $CDOERR
+#
+exit 0

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/cdo.git



More information about the debian-science-commits mailing list