[Git][debian-gis-team/nco][master] 4 commits: New upstream version 5.2.9

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Sat Oct 19 05:33:09 BST 2024



Bas Couwenberg pushed to branch master at Debian GIS Project / nco


Commits:
61519eee by Bas Couwenberg at 2024-10-19T06:26:21+02:00
New upstream version 5.2.9
- - - - -
273a8e32 by Bas Couwenberg at 2024-10-19T06:26:42+02:00
Update upstream source from tag 'upstream/5.2.9'

Update to upstream version '5.2.9'
with Debian dir 9ca9d1a45d422a557490f4323dfdf6d05feaaab6
- - - - -
7414d3ad by Bas Couwenberg at 2024-10-19T06:26:54+02:00
New upstream release.

- - - - -
8b958756 by Bas Couwenberg at 2024-10-19T06:27:30+02:00
Set distribution to unstable.

- - - - -


24 changed files:

- bld/nco.spec
- bld/nco_dst.pl
- configure
- configure.ac
- configure.eg
- data/ncclimo
- data/ncremap
- debian/changelog
- doc/ANNOUNCE
- doc/ChangeLog
- doc/VERSION
- doc/debian.txt
- doc/index.shtml
- doc/nco.texi
- src/nco/nco.h
- src/nco/nco_ctl.c
- src/nco/nco_netcdf.c
- src/nco/nco_netcdf.h
- src/nco/nco_rgr.c
- src/nco/nco_s1d.c
- src/nco/nco_s1d.h
- src/nco/nco_scm.c
- src/nco/nco_sng_utl.c
- src/nco/nco_var_utl.c


Changes:

=====================================
bld/nco.spec
=====================================
@@ -2,17 +2,17 @@
 # http://cvs.fedoraproject.org/viewvc/devel/nco/nco.spec?view=co
 
 Name:           nco
-Version:        5.2.6
+Version:        5.2.9
 Release:        1%{?dist}
 Summary:        Programs that manipulate netCDF files
 Group:          Applications/Engineering
 License:        BSD
 URL:            http://nco.sf.net/
 
-# Obtain NCO version 5.2.6-1 tar.gz from Sourceforge using CVS:
+# Obtain NCO version 5.2.9-1 tar.gz from Sourceforge using CVS:
 # cvs -d:pserver:anonymous at nco.cvs.sf.net:/cvsroot/nco login
-# cvs -z3 -d:pserver:anonymous at nco.cvs.sf.net:/cvsroot/nco co -r nco-5.2.6-1 -d nco-%{version} nco
-# tar czf nco-%{version}.tar.gz --exclude='nco-5.2.6/debian*' --exclude='.cvsignore' --exclude=ncap_lex.c --exclude='ncap_yacc.[ch]' ./nco-%{version}
+# cvs -z3 -d:pserver:anonymous at nco.cvs.sf.net:/cvsroot/nco co -r nco-5.2.9-1 -d nco-%{version} nco
+# tar czf nco-%{version}.tar.gz --exclude='nco-5.2.9/debian*' --exclude='.cvsignore' --exclude=ncap_lex.c --exclude='ncap_yacc.[ch]' ./nco-%{version}
 Source0:        nco-%{version}.tar.gz
 #Patch0:		nco_install_C_headers.patch
 #Patch1:         nco_find_udunits-dat.patch
@@ -108,7 +108,10 @@ fi
 # %{_libdir}/libnco++.so
 
 %changelog
-* Tue Aug 23 2024 Charlie Zender <zender at uci.edu> - 5.2.8-1
+* Fri Oct 18 2024 Charlie Zender <zender at uci.edu> - 5.2.8-1
+- new upstream 5.2.9
+
+* Mon Sep 02 2024 Charlie Zender <zender at uci.edu> - 5.2.8-1
 - new upstream 5.2.8
 
 * Tue Jul 23 2024 Charlie Zender <zender at uci.edu> - 5.2.7-1


=====================================
bld/nco_dst.pl
=====================================
@@ -5,20 +5,20 @@
 
 # Usage:
 # Export tagged, public versions
-# /usr/bin/scp ${DATA}/nco-5.2.7.tar.gz zender,nco at web.sf.net:/home/project-web/nco/htdocs/src
-
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --bld --cln nco-5.2.7 # Build, do not release on SF
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --bld --cln --sf nco-5.2.7 # Build, release on SF
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --nst_all nco-5.2.7 # Install, do not build
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --bld --cln --nst_all nco-5.2.7 # Build and install
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --acd_cnt nco-5.2.7
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --acd_prs nco-5.2.7
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --cgd_cnt nco-5.2.7
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --cray_prs nco-5.2.7
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --bbl_cnt nco-5.2.7
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --blk_cnt nco-5.2.7
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --dat_cnt nco-5.2.7
-# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --ute_prs nco-5.2.7
+# /usr/bin/scp ${DATA}/nco-5.2.9.tar.gz zender,nco at web.sf.net:/home/project-web/nco/htdocs/src
+
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --bld --cln nco-5.2.9 # Build, do not release on SF
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --bld --cln --sf nco-5.2.9 # Build, release on SF
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --nst_all nco-5.2.9 # Install, do not build
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --bld --cln --nst_all nco-5.2.9 # Build and install
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --acd_cnt nco-5.2.9
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --acd_prs nco-5.2.9
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --cgd_cnt nco-5.2.9
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --cray_prs nco-5.2.9
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --bbl_cnt nco-5.2.9
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --blk_cnt nco-5.2.9
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --dat_cnt nco-5.2.9
+# ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --ute_prs nco-5.2.9
 
 # Export daily snapshot
 # ${HOME}/nco/bld/nco_dst.pl --dbg=2 
@@ -256,7 +256,7 @@ if($bld){
 # Set up FTP server
     chdir $dst_pth_pfx or die "$prg_nm: ERROR unable to chdir to $dst_pth_pfx: $!\n"; # $! is system error string
     cmd_prc("$cp_cmd $doc_fl ./$dst_vrs/doc"); # Copy derived documentation to source directory
-    cmd_prc("$tar_cmd cvzf $dst_fl --exclude='nco-5.2.7/debian*' --exclude='.cvsignore' --exclude=ncap_lex.c --exclude=ncap_yacc.[ch] ./$dst_vrs"); # Create gzipped tarfile
+    cmd_prc("$tar_cmd cvzf $dst_fl --exclude='nco-5.2.9/debian*' --exclude='.cvsignore' --exclude=ncap_lex.c --exclude=ncap_yacc.[ch] ./$dst_vrs"); # Create gzipped tarfile
     cmd_prc("$rsh_cmd $www_mch $rm_cmd $www_drc/src/$dst_fl"); # Remove any distribution with same name
     if($dly_snp){cmd_prc("$rsh_cmd $www_mch $rm_cmd -r $www_drc/src/nco-????????.tar.gz");} # Remove previous daily snapshots from WWW server
     cmd_prc("$rcp_cmd $dst_fl $www_mch:$www_drc/src"); # Copy local tarfile to WWW server


=====================================
configure
=====================================
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.72 for NCO netCDF Operators 5.2.8.
+# Generated by GNU Autoconf 2.72 for NCO netCDF Operators 5.2.9.
 #
 # Report bugs to <nco-bugs at lists.sourceforge.net>.
 #
@@ -616,8 +616,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='NCO netCDF Operators'
 PACKAGE_TARNAME='nco'
-PACKAGE_VERSION='5.2.8'
-PACKAGE_STRING='NCO netCDF Operators 5.2.8'
+PACKAGE_VERSION='5.2.9'
+PACKAGE_STRING='NCO netCDF Operators 5.2.9'
 PACKAGE_BUGREPORT='nco-bugs at lists.sourceforge.net'
 PACKAGE_URL=''
 
@@ -1426,7 +1426,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 NCO netCDF Operators 5.2.8 to adapt to many kinds of systems.
+'configure' configures NCO netCDF Operators 5.2.9 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1498,7 +1498,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of NCO netCDF Operators 5.2.8:";;
+     short | recursive ) echo "Configuration of NCO netCDF Operators 5.2.9:";;
    esac
   cat <<\_ACEOF
 
@@ -1670,7 +1670,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-NCO netCDF Operators configure 5.2.8
+NCO netCDF Operators configure 5.2.9
 generated by GNU Autoconf 2.72
 
 Copyright (C) 2023 Free Software Foundation, Inc.
@@ -2449,7 +2449,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 NCO netCDF Operators $as_me 5.2.8, which was
+It was created by NCO netCDF Operators $as_me 5.2.9, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -4549,7 +4549,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='nco'
- VERSION='5.2.8'
+ VERSION='5.2.9'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -23047,7 +23047,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 NCO netCDF Operators $as_me 5.2.8, which was
+This file was extended by NCO netCDF Operators $as_me 5.2.9, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -23115,7 +23115,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-NCO netCDF Operators config.status 5.2.8
+NCO netCDF Operators config.status 5.2.9
 configured by $0, generated by GNU Autoconf 2.72,
   with options \\"\$ac_cs_config\\"
 


=====================================
configure.ac
=====================================
@@ -56,7 +56,7 @@
 # 20170808: Choose between traditional version and Git-based version
 # If Git, consider that Linux dynamic libraries will have full messy name, MacOS will not
 # https://stackoverflow.com/questions/43526939/how-to-insert-git-based-version-in-autoconf-managed-project
-AC_INIT([NCO netCDF Operators],[5.2.8],[nco-bugs at lists.sourceforge.net],[nco])
+AC_INIT([NCO netCDF Operators],[5.2.9],[nco-bugs at lists.sourceforge.net],[nco])
 
 # Print GNU copyright in configure script
 AC_COPYRIGHT


=====================================
configure.eg
=====================================
@@ -332,7 +332,7 @@ scp nco.configure.foo nco.config.log.foo nco.libtool.foo nco.make.foo dust.ess.u
 # Latest ticket to build NCO: 381695 on 20180413
 # Latest sysadmin-compiled module usage: module load netcdf-c/4.7.4 nco/4.9.3 # 20201208
 # Personal recipe last modified: 20240221 (fix E3SMU paths, use anaconda, not bld/Makefile)
-# Personal recipe last borken: 20231129 /gpfs/alpine/cli115/proj-shared/e3sm-unified/base/envs/e3sm_unified_1.9.1_login/lib/libnetcdf.so: undefined reference to `H5Pset_dxpl_mpio'
+# Personal recipe last borken: 20231129 /gpfs/alpine/cli115/proj-shared/e3sm-unified/base/envs/e3sm_unified_1.9.1_login/lib/libnetcdf.so: undefined reference to `H5Pset_dxpl_mpio' <-- Fix by manual linking to -lmfhdf -ldf -lhdf5_hl -lhdf5 
 # Personal recipe last successful: 20240220
 export LINUX_CC='gcc -std=c99 -pedantic -D_DEFAULT_SOURCE'
 export LINUX_CXX='g++ -std=c++11'
@@ -341,7 +341,7 @@ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/ccs/proj/cli115/software/e3sm-unified
 export NETCDF_ROOT=/ccs/proj/cli115/software/e3sm-unified/base/envs/e3sm_unified_latest
 export PATH=${PATH}:/ccs/proj/cli115/software/e3sm-unified/base/envs/e3sm_unified_latest/bin
 cd ~/nco;git reset --hard origin/master
-cd ~/nco;CC=${LINUX_CC} CXX=${LINUX_CXX} NETCDF_ROOT=${HOME}/anaconda ./configure --disable-ccr --prefix=${HOME} --bindir=${MY_BIN_DIR} --datadir=${HOME}/nco/data --libdir=${MY_LIB_DIR} --mandir=${HOME}/nco/man > nco.configure.foo 2>&1
+cd ~/nco;CC=${LINUX_CC} CXX=${LINUX_CXX} NETCDF_ROOT=${HOME}/anaconda ./configure --prefix=${HOME} --bindir=${MY_BIN_DIR} --datadir=${HOME}/nco/data --libdir=${MY_LIB_DIR} --mandir=${HOME}/nco/man > nco.configure.foo 2>&1
 # cd ~/nco/bld;make ANTLR_ROOT=${HOME} ANTLR_LIB=${MY_LIB_DIR} NETCDF_ROOT=${NETCDF_ROOT} OPTS=D OMP=Y allinone;cd -
 # !Andes
 


=====================================
data/ncclimo
=====================================
@@ -1111,11 +1111,13 @@ let mth_nbr=${yr_end_rth}*12+${mth_end_rth}-${yr_srt_rth}*12-${mth_srt_rth}+1
 let mth_srtm1=${mth_srt_rth}-1
 let mth_endp1=${mth_end_rth}+1
 if [ ${mth_srtm1} -eq 0 ]; then
+    let mth_srtm1=12
     mm_srtm1='12'
 else # !mth_srtm1
     mm_srtm1=`printf "%02d" ${mth_srtm1}`
 fi # !mth_srtm1
 if [ ${mth_endp1} -eq 13 ]; then
+    let mth_endp1=1
     mm_endp1='01'
 else # !mth_endp1
     mm_endp1=`printf "%02d" ${mth_endp1}`
@@ -1215,7 +1217,7 @@ if [ ${inp_aut} = 'No' ] && [ ${inp_glb} = 'No' ] && [ ${inp_psn} = 'No' ] && [
     if [ ${bch_pbs} = 'Yes' ]; then
 	echo "${spt_nm}: HINT PBS batch job environment detected, pipe to stdin not allowed, try positional arguments instead"
     else # !bch_pbs
-	echo "${spt_nm}: HINT An easy way to provide lengthy or complex filenames to pipe input file list to stdin with, e.g., 'ls *.nc | ${spt_nm}'"
+	echo "${spt_nm}: HINT Provide a list of lengthy or complex filenames as a pipe to stdin with, e.g., 'ls *.nc | ${spt_nm}'"
     fi # !bch_pbs
     exit 1
 fi # !tms_flg
@@ -2799,6 +2801,7 @@ if [ "${tms_flg}" = 'Yes' ]; then
 	done # !fl_idx
 	yyyy_srt_sgm[${sgm_idx}]=`printf "%04d" ${yr_srt_sgm}`
 	yyyy_end_sgm[${sgm_idx}]=`printf "%04d" ${yr_end_sgm}`
+	# 202401001: fxm: presumably could cause value too great for base error?
 	let yr_endp1_sgm=${yr_end_sgm}+1
 	yyyy_endp1_sgm[${sgm_idx}]=`printf "%04d" ${yr_endp1_sgm}`
 
@@ -2806,11 +2809,14 @@ if [ "${tms_flg}" = 'Yes' ]; then
 	mm_end_sgm[${sgm_idx}]='12'
 	mm_srt_sgm[${sgm_idx}]=${mm_srt}
 	if [ ${sgm_idx} -eq ${sgm_nbrm1} ]; then
+	    let mth_end_sgm=${mth_end_rth}
 	    mm_end_sgm[${sgm_idx}]=${mm_end}
 	else # !sgm_idx
+	    let mth_end_sgm=${mth_srtm1}
 	    mm_end_sgm[${sgm_idx}]=${mm_srtm1}
 	fi # !sgm_idx
-	let mm_endp1_sgm=${mm_end_sgm}+1
+	# 202401001: fxm: Causes error "value too great for base (error token is "08")"
+	let mm_endp1_sgm=${mth_end_sgm}+1
 	mm_endp1_sgm[${sgm_idx}]=`printf "%02d" ${mm_endp1_sgm}`
 
 	# Sanity check that all files exist before wasting time and space on concatenation
@@ -3019,7 +3025,7 @@ if [ "${tms_flg}" = 'Yes' ]; then
 		    for ((var_idx=var_idx_srt;var_idx<=var_idx_end;var_idx++)); do
 			wait ${avg_pid[${var_idx}]}
 			if [ "$?" -eq 0 ]; then
-			    printf "`date`: Globally and regional statistics ${cmd_stt[${var_idx}]##* }\n"
+			    printf "`date`: Global and regional statistics ${cmd_stt[${var_idx}]##* }\n"
 			else
 			    printf "${spt_nm}: ERROR Failed in global and regional statistics. cmd_stt[${var_idx}] failed. Debug this:\n${cmd_stt[${var_idx}]}\n"
 			    # 20190323: exiting parent here creates orphans, kill live children then exit


=====================================
data/ncremap
=====================================
@@ -310,6 +310,7 @@ fi # !hrd_pth && !NCO_PATH_OVERRIDE
 # ncremap -P mpasocean -7 -L 1 -m ${DATA}/maps/map_EC30to60E2r2_to_cmip6_180x360_aave.20220301.nc ${DATA}/bm/mpov2_EC30to60E2r2l60.nc ~/foo_mpov2.nc
 # ncremap -P mpasocean -7 -L 1 -m ${DATA}/maps/map_IcoswISC30E3r5_to_cmip6_180x360_traave.20231201.nc ${DATA}/bm/mpov3_IcoswISC30E3r5l64.nc ~/foo_mpov3.nc
 # ncremap -P eamxx -7 -L 1 -m ${DATA}/maps/map_ne1024pg2_to_fv256x512_mono.20201201.nc ${DATA}/bm/screamv1_ne1024pg2l128.nc ~/foo_eamxx.nc
+# ncremap --ps_nm=lnsp -v asn,t --vrt_out=${DATA}/grids/vrt_hyb_L72.nc ${DATA}/hdf/ecmwf_ifs_f640L137.nc ~/foo.nc
 # Regrid:
 # ls ${DATA}/ne30/raw/*1979*.nc | ncremap -m ${DATA}/maps/map_ne30np4_to_fv129x256_aave.20150901.nc -O ${DATA}/ne30/rgr
 # ls ${DATA}/ne30/raw/*1979*.nc | ncremap -j 3 -m ${DATA}/maps/map_ne30np4_to_fv129x256_aave.20150901.nc -O ${DATA}/ne30/rgr # Batch-parallelism
@@ -1927,7 +1928,9 @@ if [ "${prc_typ}" = 'eamxx' ]; then
 	# 20240110: EAMXX also uses dim2 dimension for time_bnds
 	#pdq_opt='-a ilev,lev,dim2,ncol'
 	# 20230304: EAMxx may have been vertically interpolated to pure-pressure levels prior to horizontal regridding
-	pdq_opt='-a ilev,lev,plev,dim2,ncol'
+	#pdq_opt='-a ilev,lev,plev,dim2,ncol'
+	# 20241002: EAMxx may have COSP dimensions in order cosp_tau,cosp_cth or cosp_tau,cosp_prs, and spectral dimensions lwband,swband
+	pdq_opt='-a time,lwband,swband,ilev,lev,plev,cosp_tau,cosp_cth,cosp_prs,dim2,ncol'
 	# NB: ncpdq is invoked iff performing horizontal regridding (vertical interpolation works fine either way)
     fi # !pdq_opt && !pdq_flg
     if [ -z "${ps_nm}" ]; then


=====================================
debian/changelog
=====================================
@@ -1,3 +1,9 @@
+nco (5.2.9-1) unstable; urgency=medium
+
+  * New upstream release.
+
+ -- Bas Couwenberg <sebastic at debian.org>  Sat, 19 Oct 2024 06:27:21 +0200
+
 nco (5.2.8-1) unstable; urgency=medium
 
   * New upstream release.


=====================================
doc/ANNOUNCE
=====================================
@@ -1,70 +1,69 @@
 $Header$ -*-text-*-
 
-netCDF Operators NCO version 5.2.8 topple the technocracy
+netCDF Operators NCO version 5.2.9 scratch an itch
 
 http://nco.sf.net (Homepage, Mailing lists, Help)
 http://github.com/nco/nco (Source Code, Issues, Releases)
 
 What's new?
-Version 5.2.8 mostly contains features and fixes for regridding
-and climatology generation. Climatologies now allow the choice
-between two statistics (sums and means) to output as regional/global
-timeseries. The regridder fixes corner case behavior when the
-sub-gridscale (SGS) fraction is a missing value (as in ELM/CLM).
-Many improvements to the robustness and helpfulness of WARNINGs
-and ERRORs are included. Upgrades are encouraged for everyone
-who uses the regridder on ELM/CLM/CTSM datasets.
+Version 5.2.9 significantly improves the unpacking of ELM/CLM/CTSM
+history and restart datasets. ncclimo and ncremap benefit from a
+few updates and fixes. This release many be skipped if these changes
+do not interest you.
+
+Work on 5.3.0 is underway and includes yet more capability in
+unpacking ELM/CLM history/restart files.
 
 Enjoy,
 Charlie
 
 NEW FEATURES (full details always in ChangeLog):
 
-A. ncclimo has two new options to control global/regional timeseries:
---rgn_stt=avg|sum and --sum_scl=sum_scl. These options allow the user
-to choose which statistic, sums or averages, to output with
-global/regional timeseries for all variables. The option --rgn_stt=avg
-is identical to the current timeseries output by the --rgn_avg switch
-(which will be deprecated eventually). When invoked with --rgn_stt=sum
-the averaged field is multiplied by the sum of the area variable.
-For fields that are area-intensive (e.g., fluxes per unit area) this
-results in the total net flux over the area. However, the field must
-employ the same area units as the Area variable for this to be true.
-For example, fields given in m-2 would need to employ an Area variable
-in m2. Unfortunately, many people love non-SI units so that is rarely
-the case! For example, ELM and CLM archive Area in km2, so a scale
-factor of one million is needed to correct the sum for many variables.
-EAM and CAM use sr-1 for Area so it needs a different scale factor.
-That is why ncclimo accepts a second new option --sum_scl=sum_scl.
-This scale factor multiplies the integrated field value, and allows
-the user to generate timeseries in the desired units for any field.
-The whole procedure is model and variable-specific and we are open
-to suggestions to make it more useful. Example usage is: 
-
-# Timeseries of global GPP in grams/s for ELM/CLM:
-ncclimo -P elm --split --rgn_stt=sum --sum_scl=1.0e6 -v GPP ...
-# Timeseries of global GPP in GT C/yr for ELM/CLM:
-ncclimo -P elm --split --rgn_stt=sum --sum_scl=1.0e6*3600*24*365/1.0e12 -v GPP ...
-# Timeseries of global column vapor in kg for EAM/CAM:
-ncclimo -P eam --split --rgn_stt=sum --sum_scl=6.37122e6^2 -v TMQ ...
-http://nco.sf.net/nco.html#ncclimo
-http://nco.sf.net/nco.html#rgn_stt
-http://nco.sf.net/nco.html#sum_scl
+A. ncks leveled-up the way it unpacks ELM/CLM history/restart files. 
+This is by far the biggest feature in this release.
+New features include support for PFTs in history files, support
+for topounits in ELM (PCT_LANDUNIT, PCT_NAT_PFT, TS_TOPO), a
+workaround for invalid topounits coordinates, and outputting a pft 
+coordinate variable with vegetation names.
+
+ncks --s1d history_h2.nc out.nc # History files usually h2, h3...
+ncks --s1d --hrz=history.nc restart.nc out.nc # Restart files
+
+http://nco.sf.net/nco.html#s1d
+http://nco.sf.net/nco.html#unpack_sparse
+
+B. ncremap now automagically horizontall regids the latest EAMxx and
+SCREAM files without needing manual invocation of long, hairy
+options. In particular, users can invoke
+
+ncremap -P eamxx --map=map.nc eamxx.nc out.nc
+
+instead of this:
+
+ncremap -P eamxx
+--prm_opt=time,lwband,swband,ilev,lev,plev,cosp_tau,cosp_cth,cosp_prs,dim2,ncol
+--map=map.nc eamxx.nc out.nc
+
+http://nco.sf.net/nco.html#eamxx
 
 BUG FIXES:
    
-A. ncks --chk_map fixes a mix-up introduced in 5.2.7 where the new
-area_b diagnostics were mis-labeled and show the location of min/max
-on the area_a grid instead of the area_b grid. The workaround is to
-use 5.2.6 or earlier. The solution is to upgrade.
-
-B. ncremap fixes a problem where portions of missing values (aka
-_FillValue) could infect destination cells whose sub-gridscale (SGS)
-fractions equal _FillValue. This problem can arise in ELM/CLM
-datasets because their 'landfrac' variable sets non-land areas to the
-missing value (a practice of questionable value). Thanks to Chloe
-Whicker-Clarke for reporting this issue. There is no workaround. The
-solution is to upgrade. 
+A. ncremap fixes a regression with the vertical interpolation of ECMWF
+datasets in IFS format. The regression, introduced 1-2 years ago,
+causes the interpolation to abort. To vertically interpolate a hybrid
+coordinate dataset in IFS format, one must now specify that the
+surface pressure variable is named lnsp: 
+
+ncremap --ps_nm=lnsp --vrt_grd=vrt_grd.nc in.nc out.nc
+
+Thanks to Erik Koene for reporting this issue. There is no
+workaround. The solution is to upgrade, or to use an older NCO
+version, e.g., 4.9.0.
+http://nco.sf.net/nco.html#vrt_hyb_ifs
+
+B. ncclimo fixes an illegal Bash string->numeric conversion error.
+This error could occur when invoking non-default start and end
+months. There is no workaround. The solution is to upgrade. 
 
 Full release statement at http://nco.sf.net/ANNOUNCE
     
@@ -73,8 +72,8 @@ KNOWN PROBLEMS DUE TO NCO:
 This section of ANNOUNCE reports and reminds users of the
 existence and severity of known, not yet fixed, problems. 
 These problems occur with NCO 5.2.7 built/tested under
-MacOS 14.6.1 with netCDF 4.9.3-RC1 on HDF5 1.14.3 and with
-Linux FC40 with netCDF 4.9.2 on HDF5 1.14.1.
+MacOS 15.0 with netCDF 4.9.4-development on HDF5 1.14.3
+and with Linux FC40 with netCDF 4.9.2 on HDF5 1.14.3.
 
 A. NOT YET FIXED (NCO problem)
    Correctly read arrays of NC_STRING with embedded delimiters in ncatted arguments


=====================================
doc/ChangeLog
=====================================
@@ -1,3 +1,90 @@
+2024-10-18  Charlie Zender  <zender at uci.edu>
+
+	* NCO 5.2.9 release procedure:
+	cd ~/nco;git commit -a -m 'Version 5.2.9: Empathy Card';git push
+	git tag -a 5.2.9 -m 'all: NC_FillValue; ncclimo: fix bsh syn; ncks: S1D pft dsk rdr, topounits, workaround, pft crd, sanitize, fflush; ncremap: fix ECMWF IFS, eamxx pdq';git push --tags
+
+	* Progress inferring pft_sng_out from global attributes, though remains off by default
+
+	* Read pft_nbr_nbr_in from history files
+
+2024-10-17  Charlie Zender  <zender at uci.edu>
+
+	* NCO 5.2.9-alpha03 release procedure:
+	cd ~/nco;git commit -a -m 'Version 5.2.9-alpha03: Palenque';git push
+	git tag -a 5.2.9-alpha03 -m 'ncks: S1D finish topounits, workaround bad topos1d_[ij]xy, address sanitize';git push --tags
+
+	* Activate pft_sng_out though disable inferring from global attributes
+
+	* Enable Clang address sanitizer with -fsanitize=address
+
+	* Account for lvl_nbr (i.e., ltype dimension) in unpacking nco_s1d_tpo variables
+
+	* Change storage order ot nco_s1d_tpo to always be lat,lon
+
+	* Discover buggy topos1d_[ij]xy in input files, provide workaround by replacing with grids1d_[ij]xy
+
+	* Sanity check that tpo_nbr_in == grd_nbr_in
+
+	* Sanity check that mec_nbr_in == mec_nbr_out
+
+	* Correct argument order of nco_malloc_dbg() call in nco_cpy_var_val()
+
+	* Define lnd_typ_crr=nco_lnd_ilun_nil for Gridcell and Topounit	variables so diagnostic printing can work
+
+	* Print var_nm in nco_def_var() debugging output
+
+	* Add fflush() to tidy debugging output
+
+2024-10-16  Charlie Zender  <zender at uci.edu>
+
+	* Store enumerated PFT and CFT in pft coordinate variable
+
+2024-10-15  Charlie Zender  <zender at uci.edu>
+
+	* Output pft coordinate as NC_STRING (not 2D NC_CHAR) when fl_fmt_out == NC_FORMAT_NETCDF4
+
+	* NCO 5.2.9-alpha02 release procedure:
+	cd ~/nco;git commit -a -m 'Version 5.2.9-alpha02: Adieu Borrego';git push
+	git tag -a 5.2.9-alpha02 -m 'ncclimo: fix bsh syn, fix eamxx pdq; ncks: S1D fix hst pft, add pft crd';git push --tags
+
+	* Add PFT string coordinate to output files
+
+	* Assume PFT storage order in history files is same as in restart files
+	This shifts the original convention that worked with beth_in.nc to the newer eva_h2.nc convention
+
+2024-10-14  Charlie Zender  <zender at uci.edu>
+
+	* Define dmn_cnt_out before using it to determine lvl_nbr in nco_s1d.c:nco_s1d_unpack()
+
+2024-10-02  Charlie Zender  <zender at uci.edu>
+
+	* Fix typo pdq_opt='-a ilev,l%8jev,plev,dim2,ncol' that causes eamxx regridding to fail
+
+2024-10-01  Charlie Zender  <zender at uci.edu>
+
+	* Fix illegal Bash string->numeric conversion error with mm_endp1_sgm definition
+
+2024-09-27  Charlie Zender  <zender at uci.edu>
+
+	* Replace _FillValue by NC_FillValue in nco.h (verified on MacOS w/4.9.4-dev and Linux w/4.9.2)
+
+2024-09-26  Charlie Zender  <zender at uci.edu>
+
+	* NCO 5.2.9-alpha01 release procedure:
+	cd ~/nco;git commit -a -m 'Version 5.2.9-alpha01: Camp Rick';git push
+	git tag -a 5.2.9-alpha01 -m 'Functionally identical to 5.2.8 + ECMWF IFS fixes';git push --tags
+
+	* Update vertical interpolation regressions with ECMWF IFS documentaiton in nco.texi
+
+	* Require --ps_nm=lnsp for ECMWF IFS hybrid coordinates
+
+	* Fix vertical interpolation regressions with ECMWF IFS hybrid coordinates
+
+2024-09-11  Charlie Zender  <zender at uci.edu>
+
+	* Shift from clang++ -std=c++17 and clang to clang++ -std=c++23	and clang -std=c23 on MacOS
+
 2024-09-02  Charlie Zender  <zender at uci.edu>
 
 	* NCO 5.2.8 release procedure:


=====================================
doc/VERSION
=====================================
@@ -1 +1 @@
-5.2.8
+5.2.9


=====================================
doc/debian.txt
=====================================
@@ -29,18 +29,18 @@ apt-get install dh-make debhelper devscripts fakeroot gnupg debian-policy develo
 
 2. Debian build procedure recommends placing entire package source in
    subdirectory of main package. 
-   For starters, we wish to create .debs of tagged releases, e.g., nco-5.2.8
-   First we create a clean source distribution of nco and place it in nco-5.2.8
+   For starters, we wish to create .debs of tagged releases, e.g., nco-5.2.9
+   First we create a clean source distribution of nco and place it in nco-5.2.9
    Until we know what is necessary, however, we just copy a snapshot
    
    2.1 Clean all build files from development directory
 
 cd ~/nco;make distclean;cd bld;make clean;cd ~
 tar cvzf ./nco/nco.tar.gz ./nco/*
-cd ~/nco;tar xvzf nco.tar.gz;mv nco nco-5.2.8
-/bin/rm nco.tar.gz;tar cvzf nco-5.2.8.tar.gz ./nco-5.2.8/*
-cd ~/nco/nco-5.2.8
-dh_make -e zender at uci.edu -f ../nco-5.2.8.tar.gz
+cd ~/nco;tar xvzf nco.tar.gz;mv nco nco-5.2.9
+/bin/rm nco.tar.gz;tar cvzf nco-5.2.9.tar.gz ./nco-5.2.9/*
+cd ~/nco/nco-5.2.9
+dh_make -e zender at uci.edu -f ../nco-5.2.9.tar.gz
 
     2.2 The preceding steps created template debian files for a .deb,
     Those files now reside in ~/nco/debian.
@@ -55,7 +55,7 @@ dh_make -e zender at uci.edu -f ../nco-5.2.8.tar.gz
    from previous build
 
    cd ~/nco;/bin/rm *.gz
-   cd ~/nco/nco-5.2.8
+   cd ~/nco/nco-5.2.9
    dpkg-buildpackage -rfakeroot > foo 2>&1
    dpkg-buildpackage -rsudo > foo 2>&1
 
@@ -84,33 +84,33 @@ patch -p0 < nco_X.Y.Z-3.diff   # Patch destination with Debian diff
    make tags
 # Put cute version-specific string in nco_ctl.c:nco_nmn_get()
 # Install correct version numbers before updating Debian
-# tags-query replace 5.2.8 with X.Y.Z+1
+# tags-query replace 5.2.9 with X.Y.Z+1
 # If tags-query replace does not work, be sure to manually change
 # versions in configure.ac, debian/files, doc/ANNOUNCE, doc/debian.txt,
 # doc/index.shtml, doc/nco.texi, bld/nco_dst.pl, doc/VERSION
 # 20141201: Change NCO_VERSION_PATCH in src/nco.h!!!!!!!!!!!!!!!!!!!!!!
-   cd ~/nco/debian;dch -b --force-distribution --distribution=unstable -v 5.2.8-1 # Update changelog (-b forces this version number)
+   cd ~/nco/debian;dch -b --force-distribution --distribution=unstable -v 5.2.9-1 # Update changelog (-b forces this version number)
    emacs ~/nco/bld/nco.spec # Update changelog
 # For unknown reason rules file may lose its executable bit
    chmod a+x ~/nco/debian/rules
 # Rebuild autotools so new version # propagates
    cd ~/nco;aclocal;autoheader;automake --foreign;autoconf
 # Save all files in emacs before tagging
-   ${HOME}/nco/bld/nco_dst.pl --dbg=2 --bld --cln nco-5.2.8
+   ${HOME}/nco/bld/nco_dst.pl --dbg=2 --bld --cln nco-5.2.9
 # Upload tarball to SF https://sourceforge.net/projects/nco/files 
-   cd;scp dust.ess.uci.edu:/var/www/html/nco/src/nco-5.2.8.tar.gz .
+   cd;scp dust.ess.uci.edu:/var/www/html/nco/src/nco-5.2.9.tar.gz .
 
 7. Ubuntu PPA
 https://help.launchpad.net/Packaging/PPA
-dput NCO nco_5.2.8-2~ppa1_source.changes
+dput NCO nco_5.2.9-2~ppa1_source.changes
 sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com
 
 # Location of build diagnostics for mentors to help 
-http://dust.ess.uci.edu/nco/src/nco_5.2.8-1.dpkg-buildpackage.txt
-http://dust.ess.uci.edu/nco/src/nco_5.2.8-1.dsc
-http://dust.ess.uci.edu/nco/src/nco_5.2.8-1_i386.changes
-http://dust.ess.uci.edu/nco/src/nco_5.2.8-1_i386.deb
-http://dust.ess.uci.edu/nco/src/nco_5.2.8.orig.tar.gz
+http://dust.ess.uci.edu/nco/src/nco_5.2.9-1.dpkg-buildpackage.txt
+http://dust.ess.uci.edu/nco/src/nco_5.2.9-1.dsc
+http://dust.ess.uci.edu/nco/src/nco_5.2.9-1_i386.changes
+http://dust.ess.uci.edu/nco/src/nco_5.2.9-1_i386.deb
+http://dust.ess.uci.edu/nco/src/nco_5.2.9.orig.tar.gz
 
 # Becoming a Debian developer
 http://www.debian.org/devel/join/newmaint
@@ -164,31 +164,31 @@ Matej Vela <vela at debian.org>, Daniel Baumann <daniel at debian.org>, Warren Turkal
 # export LD_LIBRARY_PATH=/usr/lib:/lib:/usr/X11R6/lib
 # sudo aptitude install antlr bison flex gsl-bin libgsl0-dev libantlr-dev netcdf-bin libnetcdfc7 libnetcdf-dev texinfo libcurl4-gnutls-dev libexpat1-dev libxml2-dev udunits-bin libudunits2-0 libudunits2-dev
 cd ~/nco;cvc
-sudo /bin/rm -rf ${DATA}/nco-5.2.8 ${DATA}/nco_5.2.8* ${DATA}/debian # Cleanup last build. sudo necessary for removal because dpkg-buildpackage uses sudo?
-# cd ${DATA};cvs -d zender at nco.cvs.sf.net:/cvsroot/nco export -kkv -r nco-5.2.8-1 -d nco-5.2.8 nco # Export based on tag
-cd ${DATA};cvs -d zender at nco.cvs.sf.net:/cvsroot/nco export -kkv -D "1 second ago" -d nco-5.2.8 nco # Export most recent
-tar cvzf ./nco_5.2.8.orig.tar.gz --exclude='nco-5.2.8/debian*' --exclude='.cvsignore' --exclude='ncap_lex.c' --exclude='ncap_yacc.[ch]' ./nco-5.2.8 
-/bin/rm -rf ${DATA}/nco-5.2.8 # Remove cvs-exported directory
-tar xvzf ./nco_5.2.8.orig.tar.gz # Untar to get directory without excluded files
-mkdir -p ${DATA}/nco-5.2.8/debian/source;cd ~/nco/debian;/bin/cp changelog compat control convert copyright doc-base files info rules ${DATA}/nco-5.2.8/debian;cd ~/nco/debian/source;/bin/cp format ${DATA}/nco-5.2.8/debian/source # Replace debian directory with _CURRENT_ (main trunk) settings
+sudo /bin/rm -rf ${DATA}/nco-5.2.9 ${DATA}/nco_5.2.9* ${DATA}/debian # Cleanup last build. sudo necessary for removal because dpkg-buildpackage uses sudo?
+# cd ${DATA};cvs -d zender at nco.cvs.sf.net:/cvsroot/nco export -kkv -r nco-5.2.9-1 -d nco-5.2.9 nco # Export based on tag
+cd ${DATA};cvs -d zender at nco.cvs.sf.net:/cvsroot/nco export -kkv -D "1 second ago" -d nco-5.2.9 nco # Export most recent
+tar cvzf ./nco_5.2.9.orig.tar.gz --exclude='nco-5.2.9/debian*' --exclude='.cvsignore' --exclude='ncap_lex.c' --exclude='ncap_yacc.[ch]' ./nco-5.2.9 
+/bin/rm -rf ${DATA}/nco-5.2.9 # Remove cvs-exported directory
+tar xvzf ./nco_5.2.9.orig.tar.gz # Untar to get directory without excluded files
+mkdir -p ${DATA}/nco-5.2.9/debian/source;cd ~/nco/debian;/bin/cp changelog compat control convert copyright doc-base files info rules ${DATA}/nco-5.2.9/debian;cd ~/nco/debian/source;/bin/cp format ${DATA}/nco-5.2.9/debian/source # Replace debian directory with _CURRENT_ (main trunk) settings
 #export DEB_BUILD_OPTIONS='disable-dap-netcdf disable-netcdf4 disable-udunits2'; # Disable optional packages based on available Debian support
-#cd ${DATA}/nco-5.2.8;dpkg-buildpackage -rsudo -uc -us > ~/foo.nco 2>&1 # -uc -us: Do not sign changes or source files
-#cd ${DATA}/nco-5.2.8;dpkg-buildpackage -rsudo -sa > ~/foo.nco 2>&1 # -sa: Include _orig.tar.gz in .changes 
-cd ${DATA}/nco-5.2.8;dpkg-buildpackage -rsudo > ~/foo.nco 2>&1
+#cd ${DATA}/nco-5.2.9;dpkg-buildpackage -rsudo -uc -us > ~/foo.nco 2>&1 # -uc -us: Do not sign changes or source files
+#cd ${DATA}/nco-5.2.9;dpkg-buildpackage -rsudo -sa > ~/foo.nco 2>&1 # -sa: Include _orig.tar.gz in .changes 
+cd ${DATA}/nco-5.2.9;dpkg-buildpackage -rsudo > ~/foo.nco 2>&1
 sudo dpkg --remove nco
-sudo dpkg --install ${DATA}/nco_5.2.8-1_*.deb
+sudo dpkg --install ${DATA}/nco_5.2.9-1_*.deb
 cd ~/nco/bld;MY_BIN_DIR=/usr/bin ../bm/nco_bm.pl --regress
 # http://lintian.debian.org/full/zender@uci.edu.html
-lintian ${DATA}/nco_5.2.8-1_*.deb
-ls -l ${DATA}/nco_5.2.8*
+lintian ${DATA}/nco_5.2.9-1_*.deb
+ls -l ${DATA}/nco_5.2.9*
 m ~/foo.nco
 # Upload Ubuntu (rather than Debian) packages to websites
-scp ${DATA}/nco_5.2.8* dust.ess.uci.edu:/var/www/html/nco/src
-scp ${DATA}/nco_5.2.8* zender,nco at web.sf.net:/home/project-web/nco/htdocs/src
+scp ${DATA}/nco_5.2.9* dust.ess.uci.edu:/var/www/html/nco/src
+scp ${DATA}/nco_5.2.9* zender,nco at web.sf.net:/home/project-web/nco/htdocs/src
 # NB: Make sure RPMs build before uploading to debian, since changing
 # Debian versions is a PITA
 # NB: Only upload pbuilder Debian Sid (not personal Ubuntu) .deb builds to Debian mentors
-# cd ${DATA};dupload -t mentors nco_5.2.8-1_*.changes
+# cd ${DATA};dupload -t mentors nco_5.2.9-1_*.changes
 bsrc # Reset shell environment for regular development
 
 # New build system #2
@@ -202,52 +202,52 @@ DIST=sid sudo pbuilder update # Update chroot before building package in it
 # dget http://ftp.debian.org/debian/pool/main/n/nco/nco_3.9.0-1.dsc
 # dget http://ftp.debian.org/debian/pool/main/n/netcdf/netcdf_3.6.1-1.dsc
 # apt-get source nco # Get package source
-sudo /bin/rm /var/cache/pbuilder/result/nco_5.2.8* # Cleanup prior build
+sudo /bin/rm /var/cache/pbuilder/result/nco_5.2.9* # Cleanup prior build
 # To pass DEB_BUILD_OPTIONS to pbuilder while using sudo, one must first
 # modify sudoers with visudo to prevent sudo from resetting environment
 #export DEB_BUILD_OPTIONS='disable-dap-netcdf disable-netcdf4 disable-udunits2'; # Disable optional packages based on available Debian support
-cd ${DATA};DIST=sid sudo pbuilder build nco_5.2.8-1.dsc > ~/foo.nco.pbuilder 2>&1
-cd /var/cache/pbuilder/result;debsign -k6F635D10 nco_5.2.8-1_*.changes
-lintian /var/cache/pbuilder/result/nco_5.2.8-1_*.deb
+cd ${DATA};DIST=sid sudo pbuilder build nco_5.2.9-1.dsc > ~/foo.nco.pbuilder 2>&1
+cd /var/cache/pbuilder/result;debsign -k6F635D10 nco_5.2.9-1_*.changes
+lintian /var/cache/pbuilder/result/nco_5.2.9-1_*.deb
 sudo dpkg --remove nco
-sudo dpkg --install /var/cache/pbuilder/result/nco_5.2.8-1_*.deb
+sudo dpkg --install /var/cache/pbuilder/result/nco_5.2.9-1_*.deb
 cd ~/nco/bld;MY_BIN_DIR=/usr/bin ../bm/nco_bm.pl --regress
 # NB: Upload pbuilder Debian Sid packages to Debian mentors, but not
 # to personal or NCO websites since most people use Ubuntu not Debian
 # NB: Debian versions are a PITA, ensure RPMs build before uploading to Debian
-cd /var/cache/pbuilder/result;dupload -t mentors nco_5.2.8-1_*.changes
+cd /var/cache/pbuilder/result;dupload -t mentors nco_5.2.9-1_*.changes
 
 # RPM builds as root
 export rpm_root='/usr/src/redhat'
 # export sudo_sng='' # sudo not-necessary when builing in user directories
 export sudo_sng='sudo' # sudo necessary when building in system directories
 cd ~/nco;cvc;cvu
-/bin/rm -rf ${DATA}/nco-5.2.8 ${DATA}/nco-5.2.8* # Cleanup last build
+/bin/rm -rf ${DATA}/nco-5.2.9 ${DATA}/nco-5.2.9* # Cleanup last build
 ${sudo_sng} /bin/rm -r -f \
-${rpm_root}/BUILD/nco-5.2.8 \
-${rpm_root}/RPMS/i386/nco-5.2.8-?.i386.rpm \
-${rpm_root}/RPMS/i386/nco-debuginfo-5.2.8-?.i386.rpm \
-${rpm_root}/RPMS/i386/nco-devel-5.2.8-?.i386.rpm \
-${rpm_root}/SOURCES/nco-5.2.8.tar.gz \
-${rpm_root}/SPECS/nco-5.2.8.spec \
-${rpm_root}/SRPMS/nco-5.2.8-?.src.rpm
-cd ${DATA};cvs -d zender at nco.cvs.sf.net:/cvsroot/nco export -kkv -r nco-5.2.8-1 -d nco-5.2.8 nco # Export based on tag
-${sudo_sng} ln -s ${HOME}/nco/bld/nco.spec ${rpm_root}/SPECS/nco-5.2.8.spec
-tar cvzf ./nco-5.2.8.tar.gz --exclude='nco-5.2.8/debian*' --exclude='.cvsignore' --exclude='ncap_lex.c' --exclude='ncap_yacc.[ch]' ./nco-5.2.8 
-${sudo_sng} /bin/cp ${DATA}/nco-5.2.8.tar.gz ${rpm_root}/SOURCES
+${rpm_root}/BUILD/nco-5.2.9 \
+${rpm_root}/RPMS/i386/nco-5.2.9-?.i386.rpm \
+${rpm_root}/RPMS/i386/nco-debuginfo-5.2.9-?.i386.rpm \
+${rpm_root}/RPMS/i386/nco-devel-5.2.9-?.i386.rpm \
+${rpm_root}/SOURCES/nco-5.2.9.tar.gz \
+${rpm_root}/SPECS/nco-5.2.9.spec \
+${rpm_root}/SRPMS/nco-5.2.9-?.src.rpm
+cd ${DATA};cvs -d zender at nco.cvs.sf.net:/cvsroot/nco export -kkv -r nco-5.2.9-1 -d nco-5.2.9 nco # Export based on tag
+${sudo_sng} ln -s ${HOME}/nco/bld/nco.spec ${rpm_root}/SPECS/nco-5.2.9.spec
+tar cvzf ./nco-5.2.9.tar.gz --exclude='nco-5.2.9/debian*' --exclude='.cvsignore' --exclude='ncap_lex.c' --exclude='ncap_yacc.[ch]' ./nco-5.2.9 
+${sudo_sng} /bin/cp ${DATA}/nco-5.2.9.tar.gz ${rpm_root}/SOURCES
 cd ${rpm_root}/SPECS
-${sudo_sng} rpmbuild -ba --sign nco-5.2.8.spec > ~/foo.nco 2>&1
+${sudo_sng} rpmbuild -ba --sign nco-5.2.9.spec > ~/foo.nco 2>&1
 scp \
-${rpm_root}/RPMS/i386/nco-5.2.8-?.i386.rpm \
-${rpm_root}/RPMS/i386/nco-debuginfo-5.2.8-?.i386.rpm \
-${rpm_root}/RPMS/i386/nco-devel-5.2.8-?.i386.rpm \
-${rpm_root}/SRPMS/nco-5.2.8-?.src.rpm \
+${rpm_root}/RPMS/i386/nco-5.2.9-?.i386.rpm \
+${rpm_root}/RPMS/i386/nco-debuginfo-5.2.9-?.i386.rpm \
+${rpm_root}/RPMS/i386/nco-devel-5.2.9-?.i386.rpm \
+${rpm_root}/SRPMS/nco-5.2.9-?.src.rpm \
 dust.ess.uci.edu:/var/www/html/nco/src
 scp \
-${rpm_root}/RPMS/i386/nco-5.2.8-?.i386.rpm \
-${rpm_root}/RPMS/i386/nco-debuginfo-5.2.8-?.i386.rpm \
-${rpm_root}/RPMS/i386/nco-devel-5.2.8-?.i386.rpm \
-${rpm_root}/SRPMS/nco-5.2.8-?.src.rpm \
+${rpm_root}/RPMS/i386/nco-5.2.9-?.i386.rpm \
+${rpm_root}/RPMS/i386/nco-debuginfo-5.2.9-?.i386.rpm \
+${rpm_root}/RPMS/i386/nco-devel-5.2.9-?.i386.rpm \
+${rpm_root}/SRPMS/nco-5.2.9-?.src.rpm \
 zender,nco at web.sf.net:/home/project-web/nco/htdocs/src
 
 # RPM builds as user
@@ -256,33 +256,33 @@ zender,nco at web.sf.net:/home/project-web/nco/htdocs/src
 export rpm_root="${DATA}/rpm/nco"
 #cd ~/nco;cvc;cvu # This risks committing unwanted *.[ch]pp files
 mkdir -p ${DATA}/rpm/nco/TMP ${DATA}/rpm/nco/BUILD
-/bin/rm -rf ${DATA}/nco-5.2.8 ${DATA}/nco-5.2.8* # Cleanup last build
+/bin/rm -rf ${DATA}/nco-5.2.9 ${DATA}/nco-5.2.9* # Cleanup last build
 /bin/rm -r -f \
-${rpm_root}/nco-5.2.8-?.src.rpm \
-${rpm_root}/nco-5.2.8.spec \
-${rpm_root}/nco-5.2.8.tar.gz \
-${rpm_root}/*/nco-5.2.8-?.*.rpm \
-${rpm_root}/*/nco-debuginfo-5.2.8-?.*.rpm \
-${rpm_root}/*/nco-devel-5.2.8-?.*.rpm
-# cd ${DATA};cvs -d zender at nco.cvs.sf.net:/cvsroot/nco export -kkv -r nco-5.2.8-1 -d nco-5.2.8 nco # Export based on tag
-cd ${DATA};cvs -d zender at nco.cvs.sf.net:/cvsroot/nco export -kkv -D "1 second ago" -dnco-5.2.8 nco # Export most recent and build as 5.2.8-1
-tar cvzf ./nco-5.2.8.tar.gz --exclude='nco-5.2.8/debian*' --exclude='.cvsignore' --exclude='ncap_lex.c' --exclude='ncap_yacc.[ch]' ./nco-5.2.8 
-/bin/cp ${DATA}/nco-5.2.8.tar.gz ${rpm_root}
+${rpm_root}/nco-5.2.9-?.src.rpm \
+${rpm_root}/nco-5.2.9.spec \
+${rpm_root}/nco-5.2.9.tar.gz \
+${rpm_root}/*/nco-5.2.9-?.*.rpm \
+${rpm_root}/*/nco-debuginfo-5.2.9-?.*.rpm \
+${rpm_root}/*/nco-devel-5.2.9-?.*.rpm
+# cd ${DATA};cvs -d zender at nco.cvs.sf.net:/cvsroot/nco export -kkv -r nco-5.2.9-1 -d nco-5.2.9 nco # Export based on tag
+cd ${DATA};cvs -d zender at nco.cvs.sf.net:/cvsroot/nco export -kkv -D "1 second ago" -dnco-5.2.9 nco # Export most recent and build as 5.2.9-1
+tar cvzf ./nco-5.2.9.tar.gz --exclude='nco-5.2.9/debian*' --exclude='.cvsignore' --exclude='ncap_lex.c' --exclude='ncap_yacc.[ch]' ./nco-5.2.9 
+/bin/cp ${DATA}/nco-5.2.9.tar.gz ${rpm_root}
 ln -s ${HOME}/nco/bld/nco.spec ${rpm_root}/nco.spec
 cd ${rpm_root}
 rpmbuild -ba --sign nco.spec > ~/foo.nco 2>&1
-rpmlint ${rpm_root}/*/nco-5.2.8-?.*.rpm
+rpmlint ${rpm_root}/*/nco-5.2.9-?.*.rpm
 sudo yum remove nco
-sudo yum install ${rpm_root}/*/nco-5.2.8-?.*.rpm
+sudo yum install ${rpm_root}/*/nco-5.2.9-?.*.rpm
 scp \
-${rpm_root}/*/nco-5.2.8-?.*.rpm \
-${rpm_root}/*/nco-debuginfo-5.2.8-?.*.rpm \
-${rpm_root}/*/nco-devel-5.2.8-?.*.rpm \
-${rpm_root}/nco-5.2.8-?.*.src.rpm \
+${rpm_root}/*/nco-5.2.9-?.*.rpm \
+${rpm_root}/*/nco-debuginfo-5.2.9-?.*.rpm \
+${rpm_root}/*/nco-devel-5.2.9-?.*.rpm \
+${rpm_root}/nco-5.2.9-?.*.src.rpm \
 dust.ess.uci.edu:/var/www/html/nco/src
 scp \
-${rpm_root}/*/nco-5.2.8-?.*.rpm \
-${rpm_root}/*/nco-debuginfo-5.2.8-?.*.rpm \
-${rpm_root}/*/nco-devel-5.2.8-?.*.rpm \
-${rpm_root}/nco-5.2.8-?.*.src.rpm \
+${rpm_root}/*/nco-5.2.9-?.*.rpm \
+${rpm_root}/*/nco-debuginfo-5.2.9-?.*.rpm \
+${rpm_root}/*/nco-devel-5.2.9-?.*.rpm \
+${rpm_root}/nco-5.2.9-?.*.src.rpm \
 zender,nco at web.sf.net:/home/project-web/nco/htdocs/src


=====================================
doc/index.shtml
=====================================
@@ -71,7 +71,7 @@ Try to disable Spammers' machines:
 <p><h1 align="center">Bienvenue sur le netCDF Operator (NCO) site</h1>
 
 <p><h2>
-Current stable NCO version is 5.2.8 released <!--#flastmod file="src/nco-5.2.8.tar.gz"-->
+Current stable NCO version is 5.2.9 released <!--#flastmod file="src/nco-5.2.9.tar.gz"-->
 </h2>
 
 <table border=0 width=100%>
@@ -155,7 +155,8 @@ and
 <h2>Recent Releases & Milestones</h2>
 
 <ul>
-<li>2024 Oct ??: 5.2.9 <i>In Progress...</i>
+<li>2024 Nov ??: 5.3.0 <i>In Progress...</i>
+<li>2024 Oct 18: 5.2.9 S1D features
 <li>2024 Sep 02: 5.2.8 ncclimo --rgn_stt
 <li>2024 Jul 22: 5.2.7 ncclimo/ncremap fixes
 <li>2024 Jun 20: 5.2.6 Fix 5.2.5 ncremap
@@ -659,16 +660,20 @@ Identical copies of those tarballs are also stored
 <a href="http://nco.sf.net/src">here</a> on SourceForge for historical
 continuity.
 You may retrieve the source of tagged versions directly with, e.g.,
-<tt>git clone -b 5.2.8 http://github.com/nco/nco.git nco-5.2.8</tt></a>.
+<tt>git clone -b 5.2.9 http://github.com/nco/nco.git nco-5.2.9</tt></a>.
 <ul>
-<li><b>NCO 5.3.0</b>: (<i>Future</i>)
+<li><b>NCO 5.3.1</b>: (<i>Future</i>)
 netCDF4 user-defined types support;
 <tt>ncks --xtn</tt> better extensive variable treatment?;
 <tt>ncks --bsa</tt> Byte-swap algoritm;
 <tt>ncremap</tt> small-circle weights;</li>
-<li><b>NCO 5.2.9</b>: (<i>In Progress, features in-progress or complete include</i>)
+<li><b>NCO 5.3.0</b>: (<i>In Progress, features in-progress or complete include</i>)
 <tt>ncremap</tt> CF Convention for longitude vertices in map-files</li>
-<li><b>NCO 5.2.8</b>: (<i>Current Stable Release</i>)
+<li><b>NCO 5.2.9</b>: (<i>Current Stable Release</i>)
+<tt>ncclimo fix Bash syntax</tt>;
+<tt>ncks --s1d</tt> pft order, topounits;
+<tt>ncremap</tt> ECMWF vrt, EAMxx pdq</li>
+<li><b>NCO 5.2.8</b>: 
 <tt>ncclimo --rgn_stt, --sum_scl</tt>;
 <tt>ncks --chk_map area_b</tt> fix;
 <tt>ncremap</tt> fix sub-SGS issue</li>
@@ -842,7 +847,7 @@ Or, alternatively, permanently add conda-forge (which teems with goodies besides
 ‘<tt>conda config --add channels conda-forge</tt>’, then
 install NCO with ‘<tt>conda install nco</tt>’.
 The default NCO installed by <tt>conda</tt> is generally within a month of the latest release. 
-<li><a href="https://github.com/conda-forge/nco-feedstock">nco-5.2.8</a> Executables Anaconda-compatible. Maintained by Filipe Fernandes.</li>
+<li><a href="https://github.com/conda-forge/nco-feedstock">nco-5.2.9</a> Executables Anaconda-compatible. Maintained by Filipe Fernandes.</li>
 Thanks to Rich Signell, Filipe Fernandes, Pedro Vicente, Xylar Asay-Davis and others for developing and maintaining the NCO package for conda.
 </ul>
 
@@ -851,7 +856,7 @@ Thanks to Rich Signell, Filipe Fernandes, Pedro Vicente, Xylar Asay-Davis and ot
 <h3><a href="http://www.debian.org">Debian</a> and <a href="http://www.ubuntu.com">Ubuntu</a> GNU/Linux</a></h3>
 <ul>
 <!--
-<li><a href="http://www.debian.org">Debian</a> and <a href="http://www.ubuntu.com">Ubuntu</a> GNU/Linux-compatible Intel systems, prebuilt binary executable <a href="http://www.debian.org">deb</a>: <a href="http://packages.debian.org/testing/math/nco.html">nco-5.2.8</a></li>
+<li><a href="http://www.debian.org">Debian</a> and <a href="http://www.ubuntu.com">Ubuntu</a> GNU/Linux-compatible Intel systems, prebuilt binary executable <a href="http://www.debian.org">deb</a>: <a href="http://packages.debian.org/testing/math/nco.html">nco-5.2.9</a></li>
 -->
 <a href="http://packages.debian.org/unstable/science/nco">Debian NCO</a> and 
 <a href="https://launchpad.net/ubuntu/+source/nco">Ubuntu NCO</a> homepages.
@@ -859,8 +864,8 @@ Thanks to Rich Signell, Filipe Fernandes, Pedro Vicente, Xylar Asay-Davis and ot
 NCO packages in the Debian/Ubuntu repositories (e.g., Sid and Raring) generally lag the packages distributed here by 6–12 months.
 <a name="beta"></a><a name="prerelease"> <!-- http://nco.sf.net#beta -->
 Newer (beta- or pre-release) packages are often available for intrepid Debian/Ubuntu users as described <a href="https://github.com/nco/nco/tree/master/doc/beta.txt">here</a>.
-<dt>Debian package for most recent NCO release (install with, e.g., ‘<tt>dpkg --install nco_5.2.8-1_i386.deb</tt>’):</dt>
-<li><a href="https://launchpad.net/ubuntu/+source/nco/5.2.8-1">nco_5.2.8-1_amd64.deb</a> : Executables AMD64-compatible</li>
+<dt>Debian package for most recent NCO release (install with, e.g., ‘<tt>dpkg --install nco_5.2.9-1_i386.deb</tt>’):</dt>
+<li><a href="https://launchpad.net/ubuntu/+source/nco/5.2.9-1">nco_5.2.9-1_amd64.deb</a> : Executables AMD64-compatible</li>
 Thanks to Daniel Baumann, Sebastian Couwenberg, Barry deFreese, Francesco Lovergine, 
 Brian Mays, Rorik Peterson, and Matej Vela for their help packaging
 NCO for Debian over the years. 
@@ -902,12 +907,12 @@ Thanks to Gavin Burris and Kyle Wilcox for documenting build procedures for RHEL
 <h3><a href="http://www.apple.com/macosx/">MacOS Darwin</a></h3>
 <ul>
 <!-- 
-# MacOS 14.5 (Ventura) systems (firn, sastrugi, spectral):
+# MacOS 15.0 (Sequoia) systems (firn, sastrugi, spectral):
 /usr/bin/scp ~/nco/doc/index.shtml zender,nco at web.sf.net:/home/project-web/nco/htdocs
-cd ~/bin;tar cvzf ${DATA}/nco-5.2.8.macos.14.5.tar.gz nc*;scp ${DATA}/nco-5.2.8.macos.14.5.tar.gz zender,nco at web.sf.net:/home/project-web/nco/htdocs/src
+cd ~/bin;tar cvzf ${DATA}/nco-5.2.9.macos.15.0.tar.gz nc*;scp ${DATA}/nco-5.2.9.macos.15.0.tar.gz zender,nco at web.sf.net:/home/project-web/nco/htdocs/src
 -->
 The most up-to-date executables are probably those in the tarball below. Those unfamiliar with installing executables from tarballs may try the (older) <a href="http://en.wikipedia.org/wiki/Apple_Disk_Image">DMG</a> files (you may need to add <tt>/opt/local/bin</tt> to your executable path to access those operators).
-<li><a href="src/nco-5.2.8.macos.14.5.tar.gz">nco-5.2.8.macos.14.5.tar.gz</a> (<!--#fsize file="src/nco-5.2.8.macos.14.5.tar.gz"-->): Executables MacOS 14.5-compatible (last updated <!--#flastmod file="src/nco-5.2.8.macos.14.5.tar.gz"-->). Maintained by NCO Project.</li>
+<li><a href="src/nco-5.2.9.macos.15.0.tar.gz">nco-5.2.9.macos.15.0.tar.gz</a> (<!--#fsize file="src/nco-5.2.9.macos.15.0.tar.gz"-->): Executables MacOS 15.0-compatible (last updated <!--#flastmod file="src/nco-5.2.9.macos.15.0.tar.gz"-->). Maintained by NCO Project.</li>
 <li><a href="http://fink.sf.net">Fink</a> packages for <a href="http://fink.sf.net/pdb/package.php/nco">NCO</a>: Currently NCO 4.9.5. Maintained by Alexander Hansen.</li> 
 <li><a href="http://brew.sh">Homebrew</a> packages for <a href="https://formulae.brew.sh/formula/nco">NCO</a>: Currently NCO 5.1.5. Install with ‘<tt>brew install nco</tt>’. Maintained by Carlo Cabrera, Ian Lancaster, Alejandro Soto, and others over the years.</li> 
 <li><a href="http://trac.macosforge.org/projects/macports/wiki">MacPorts</a> infrastructure for <a href="https://ports.macports.org/port/nco">NCO</a>: <a href="https://ports.macports.org/port/nco">Portfile</a>: Currently NCO 5.1.1. Install with ‘<tt>sudo port install nco</tt>’. Maintained by Takeshi Enomoto.</li>
@@ -1110,12 +1115,12 @@ On the <a href="https://sourceforge.net/p/nco/bugs">Bug Tickets</a> site.</li>
 The simplest way to acquire the source is to download the compressed tarball:
 <ul>
 <li>
-<!-- scp ${DATA}/nco-5.2.8.tar.gz zender,nco at web.sf.net:/home/project-web/nco/htdocs/src -->
-<a href="https://github.com/nco/nco/archive/5.2.8.tar.gz">nco-5.2.8.tar.gz</a> 
-(<!--#fsize file="src/nco-5.2.8.tar.gz"--> compressed tar-file)<br>
-<!--#exec cmd="openssl dgst -md5 src/nco-5.2.8.tar.gz"--><br>
-<!--#exec cmd="openssl dgst -sha1 src/nco-5.2.8.tar.gz"--><br>
-<!--#exec cmd="openssl dgst -sha256 src/nco-5.2.8.tar.gz"--> 
+<!-- scp ${DATA}/nco-5.2.9.tar.gz zender,nco at web.sf.net:/home/project-web/nco/htdocs/src -->
+<a href="https://github.com/nco/nco/archive/5.2.9.tar.gz">nco-5.2.9.tar.gz</a> 
+(<!--#fsize file="src/nco-5.2.9.tar.gz"--> compressed tar-file)<br>
+<!--#exec cmd="openssl dgst -md5 src/nco-5.2.9.tar.gz"--><br>
+<!--#exec cmd="openssl dgst -sha1 src/nco-5.2.9.tar.gz"--><br>
+<!--#exec cmd="openssl dgst -sha256 src/nco-5.2.9.tar.gz"--> 
 </li>
 </ul>
 
@@ -1136,8 +1141,8 @@ To avoid the churn that comes with using the latest snapshot,
 potential contributors may wish to retrieve a recent tagged (i.e.,
 stable and released) version, 
 This command retrieves the entire NCO repository (< 20 MB) and
-then checks out NCO version <tt>5.2.8</tt>:
-<p><tt>git clone https://github.com/nco/nco.git;cd nco;git checkout 5.2.8</tt></p>
+then checks out NCO version <tt>5.2.9</tt>:
+<p><tt>git clone https://github.com/nco/nco.git;cd nco;git checkout 5.2.9</tt></p>
 However, the most efficient way to actively track and develop NCO is to
 retrieve the current (“bleeding edge”) NCO snapshot.
 This command retrieves the latest NCO master branch into a local
@@ -1147,12 +1152,12 @@ directory named <tt>nco</tt>:
 Track changes to the development version using
 <p><tt>cd nco;git pull</tt></p>
 One difference between running a "tagged" release 
-(e.g., <tt>5.2.8</tt>) and the development version is that the
+(e.g., <tt>5.2.9</tt>) and the development version is that the
 tagged release operators will print a valid version number (e.g.,
-<tt>5.2.8</tt>) when asked to do so with the <tt>-r</tt> flag
+<tt>5.2.9</tt>) when asked to do so with the <tt>-r</tt> flag
 (e.g., <tt>ncks -r</tt>).
 Snapshots will include the sub-version and patch-level in the version
-information (e.g., <tt>5.2.8-alpha06</tt>). 
+information (e.g., <tt>5.2.9-alpha06</tt>). 
 
 <!--
 <a name="doxy"></a>
@@ -1335,9 +1340,9 @@ As of 20131101 there is no Cygwin package for ANTLR, and the Cygwin netCDF packa
 
 <li>Once you have installed the pre-requisites as shown above, you may then build the latest stable NCO and install it in, e.g., <tt>/usr/local</tt> with: 
 <tt>
-<dt>wget https://github.com/nco/nco/archive/5.2.8.tar.gz</dt>
-<dt>tar xvzf 5.2.8.tar.gz</dt>
-<dt>cd nco-5.2.8</dt>
+<dt>wget https://github.com/nco/nco/archive/5.2.9.tar.gz</dt>
+<dt>tar xvzf 5.2.9.tar.gz</dt>
+<dt>cd nco-5.2.9</dt>
 <dt>./configure --prefix=/usr/local</dt>
 <dt>make</dt>
 <dt>sudo make install</dt>


=====================================
doc/nco.texi
=====================================
@@ -128,12 +128,12 @@ Octave TeXInfo manual shows clean TeXInfo structure
 @setfilename nco.info
 
 @c Define edition, date, ...
- at set nco-edition 5.2.8
- at set doc-edition 5.2.8
+ at set nco-edition 5.2.9
+ at set doc-edition 5.2.9
 @set copyright-years 1995--2024
 @set update-year 2024
- at set update-date 2 September 2024
- at set update-month September 2024
+ at set update-date 18 October 2024
+ at set update-month October 2024
 
 @settitle @acronym{NCO} @value{nco-edition} User Guide
 
@@ -7104,6 +7104,7 @@ The third example uses a convenience switch introduced to reduce typing.
 
 @html
 <a name="grd_cmd"></a> <!-- http://nco.sf.net/nco.html#grd_cmd -->
+<a name="xmp_grd"></a> <!-- http://nco.sf.net/nco.html#xmp_grd -->
 @end html
 Generating common grids:
 @cindex @acronym{ECMWF IFS} grid
@@ -7115,14 +7116,14 @@ Generating common grids:
 @cindex @acronym{Equi-angular} grid
 @example
 @verbatim
-# Through version 4.7.5 (August, 2018), ncks performed grid-generation
+# Access to grid-generation was through ncks, not ncremap, until version 4.7.6
 # 180x360 (1x1 degree) Equi-Angular grid, first longitude centered at Greenwich
 # This is NOT the CMIP6 1x1 grid
 ncks --rgr ttl='Equi-Angular grid 180x360'#latlon=180,360#lat_typ=uni#lon_typ=grn_ctr \
      --rgr scrip=${DATA}/grids/180x360_SCRIP.20150901.nc \
      ~zender/nco/data/in.nc ~/foo.nc
 
-# As of version 4.7.6 (August, 2018), ncremap supports more concise commands
+# Version 4.7.6+ (August, 2018), supports the preferred, more concise, ncremap syntax:
 # This is NOT the CMIP6 1x1 grid
 ncremap -G ttl='Equi-Angular grid 180x360'#latlon=180,360#lat_typ=uni#lon_typ=grn_ctr \
         -g ${DATA}/grids/180x360_SCRIP.20180901.nc
@@ -7223,11 +7224,11 @@ ncremap -7 --dfl_lvl=1 -G ttl='Cap/FV ECMWF ERA5 grid 0.25x0.25 degree, dimensio
 ncremap -7 --dfl_lvl=1 -G ttl='CRUNCEP Equi-Angular 0.5x0.5 degree uniform grid, dimensions 360x720, cell edges on Poles/Equator and Prime Meridian/Date Line'#latlon=360,720#lat_typ=uni#lon_typ=Grn_wst \
         -g ${DATA}/grids/cruncep_360x720.nc
 
-# 360x720 ELM/MOSART grid, first longitude west edge at DateLine (NB: ELM defines r05, starts at Dateline)
+# 360x720 ELM/MOSART grid, first longitude west edge at DateLine (NB: starts at Dateline, "r" stands for "river" grid)
 ncremap -7 --dfl_lvl=1 -G ttl='Equi-Angular 0.5x0.5 degree uniform grid (r05), dimensions 360x720, cell edges on Poles/Equator and Date Line/Prime Meridian'#latlon=360,720#lat_typ=uni#lon_typ=180_wst \
         -g ${DATA}/grids/r05_360x720.nc
 
-# 720x1440 ELM/MOSART grid, first longitude west edge at DateLine (NB: ELM defines r025, starts at Dateline)
+# 720x1440 ELM/MOSART grid, first longitude west edge at DateLine (NB: starts at Dateline, "r" stands for "river" grid)
 ncremap -7 --dfl_lvl=1 -G ttl='Equi-Angular 0.25x0.25 degree uniform grid (r025), dimensions 720x1440, cell edges on Poles/Equator and Date Line/Prime Meridian'#latlon=720,1440#lat_typ=uni#lon_typ=180_wst \
         -g ${DATA}/grids/r025_720x1440.nc
 
@@ -19782,9 +19783,9 @@ automatically abstracted and used to template and generate all the
 filenames based on the specified @var{yr_srt} and @var{yr_end}. 
 @example
 @verbatim
-ncclimo --c merra2_198001.nc --start=1980 --end=1999 
-ncclimo --c cesm_1980-01.nc --start=1980 --end=1999 
-ncclimo --c eamxx_1980-01-00000.nc --start=1980 --end=1999 
+ncclimo -c merra2_198001.nc --start=1980 --end=1999 --drc_in=${drc}
+ncclimo -c cesm_1980-01.nc --start=1980 --end=1999 --drc_in=${drc}
+ncclimo -c eamxx_1980-01-00000.nc --start=1980 --end=1999 --drc_in=${drc}
 @end verbatim
 @end example
 Please tell us any common dataset filename regular expressions that you would
@@ -19896,8 +19897,8 @@ In climate generation mode, output climo file names are constructed by
 default with the same @var{caseid} as the input files.
 The @var{fml_nm}, if supplied, replaces @var{caseid} in output climo
 names, which are of the form
- at var{fml_nm}_XX_YYYYMM_YYYYMM.nc where @var{XX} is the month or seasonal
-abbreviation.
+ at code{@var{fml_nm}_XX_YYYYMM_YYYYMM.nc} where @var{XX} is the month or
+seasonal abbreviation.
 Use @samp{-f @var{fml_nm}} to simplify long names, avoid overlap, etc.
 Example values of @var{fml_nm} are @samp{control}, @samp{experiment},
 and (for a single-variable climo) @samp{FSNT}.
@@ -24166,6 +24167,9 @@ feature to make it more useful.
 @cindex restart files
 @cindex sparse format
 @cindex @acronym{S1D} format
+ at cindex @acronym{ELM} files
+ at cindex @acronym{CLM} files
+ at cindex @acronym{CTSM} files
 @cindex @code{--unpack_sparse}
 @cindex @code{--s1d}
 @cindex @code{--sparse}
@@ -27980,9 +27984,9 @@ idiosyncratic model values and then invoke the Sub-gridscale
 The @acronym{MOD04} procedure unpacks input data.
 The @acronym{EAMxx} procedures permute input data dimensions into this
 order prior to horizontal regridding:
- at code{ilev,lev,dim2,ncol}, and cause the vertical interpolation
-routine to look for surface pressure under the name @code{ps} instead
-of @code{PS}.
+ at code{time,lwband,swband,ilev,lev,plev,cosp_tau,cosp_cth,cosp_prs,dim2,ncol},
+and cause the vertical interpolation routine to look for surface
+pressure under the name @code{ps} instead of @code{PS}.
 The @acronym{MPAS} procedures permute input data dimensions into this
 order: 
 @code{Time,depth,nVertInterfaces,nVertLevels,nVertLevelsP1,nZBGCTracers,nBioLayersP1,nAlgaeIceLayers,nDisIronIceLayers,nIceLayers,maxEdges,MaxEdges2,nCategories,R3,ONE,TWO,FOUR,nEdges,nCells},
@@ -29285,10 +29289,20 @@ ncap2 -O -v -s 'defdim("ilev",11);defdim("lev",10);P0=100000.0; \
 @acronym{NCO} currently has no other means of representing pure sigma
 vertical grids (as opposed to pure pressure grids).
 
+ at html
+<a name="vrt_hyb_ifs"></a> <!-- http://nco.sf.net/nco.html#vrt_hyb_ifs -->
+ at end html
 As of July 2019 and @acronym{NCO} @w{version 4.8.1}, @acronym{NCO} 
 supports regridding @acronym{ECMWF} datasets in @acronym{IFS} hybrid
 vertical coordinate format to @acronym{CESM}/@acronym{E3SM}-format
 hybrid vertical grids. 
+Unfortunately there was a regression and this functionality was
+broken between about 2023--2024 (the workaround is to use older
+ at acronym{NCO} versions like 4.9.0).
+ at acronym{NCO} once agains supports this functionality as of October
+2024 (@acronym{NCO} @w{version 5.2.9}), though now the user must
+employ the @samp{--ps_nm=lnsp} option shown below.
+
 The native @acronym{IFS} hybrid datasets that we have seen store
 pressure coordinates in terms of a slightly different formula that
 employs the log of surface pressure (@code{lnsp}) instead of surface
@@ -29309,6 +29323,90 @@ half-layer coordinate and employs distinct dimensions (@code{nhym} and
 @code{lev_2} for full-layer (i.e., midlayer) and  half-layer
 (i.e., interface) for all other variables.
 
+To invoke @command{ncremap} on a hybrid coordinate dataset in
+ at acronym{IFS} format, one must specify that the surface pressure 
+variable is named @code{lnsp}. 
+No modifications to the @acronym{IFS} dataset are necessary.
+The vertical grid file should be in @acronym{CESM}/@acronym{E3SM} format.
+ at example
+ at verbatim
+zender at spectral:~$ ncks -m -C -v lnsp,hyai,hyam,hybi,hybm,lev,lev_2 ifs.nc
+netcdf ecmwf_ifs_f640L137 {
+  dimensions:
+    lev = 137 ;
+    lev_2 = 1 ;
+    nhyi = 138 ;
+    nhym = 137 ;
+
+  variables:
+    double hyai(nhyi) ;
+      hyai:long_name = "hybrid A coefficient at layer interfaces" ;
+      hyai:units = "Pa" ;
+    double hyam(nhym) ;
+      hyam:long_name = "hybrid A coefficient at layer midpoints" ;
+      hyam:units = "Pa" ;
+    double hybi(nhyi) ;
+      hybi:long_name = "hybrid B coefficient at layer interfaces" ;
+      hybi:units = "1" ;
+    double hybm(nhym) ;
+      hybm:long_name = "hybrid B coefficient at layer midpoints" ;
+      hybm:units = "1" ;
+    double lev(lev) ;
+      lev:standard_name = "hybrid_sigma_pressure" ;
+      lev:long_name = "hybrid level at layer midpoints" ;
+      lev:formula = "hyam hybm (mlev=hyam+hybm*aps)" ;
+      lev:formula_terms = "ap: hyam b: hybm ps: aps" ;
+      lev:units = "level" ;
+      lev:positive = "down" ;
+    double lev_2(lev_2) ;
+      lev_2:standard_name = "hybrid_sigma_pressure" ;
+      lev_2:long_name = "hybrid level at layer midpoints" ;
+      lev_2:formula = "hyam hybm (mlev=hyam+hybm*aps)" ;
+      lev_2:formula_terms = "ap: hyam b: hybm ps: aps" ;
+      lev_2:units = "level" ;
+      lev_2:positive = "down" ;
+    float lnsp(time,lev_2,lat,lon) ;
+      lnsp:long_name = "Logarithm of surface pressure" ;
+      lnsp:param = "25.3.0" ;
+} // group /
+zender at spectral:~$ ncks -m vrt_grd.nc
+netcdf vrt_hyb_L72 {
+  dimensions:
+    ilev = 73 ;
+    lev = 72 ;
+
+  variables:
+    double P0 ;
+      P0:long_name = "reference pressure" ;
+      P0:units = "Pa" ;
+
+    double hyai(ilev) ;
+      hyai:long_name = "hybrid A coefficient at layer interfaces" ;
+
+    double hyam(lev) ;
+      hyam:long_name = "hybrid A coefficient at layer midpoints" ;
+
+    double hybi(ilev) ;
+      hybi:long_name = "hybrid B coefficient at layer interfaces" ;
+
+    double hybm(lev) ;
+      hybm:long_name = "hybrid B coefficient at layer midpoints" ;
+} // group /
+zender at spectral:~$ ncremap --ps_nm=lnsp --vrt_grd=vrt_grd.nc ifs.nc out.nc
+zender at spectral:~$ 
+ at end verbatim
+ at end example
+The @acronym{IFS} file can be horizontally regridded in the same
+invocation. 
+ at command{ncremap} automagically handles all of the other details.
+Currently @command{ncremap} can only interpolate data from (not to) an 
+ at acronym{IFS}-format hybrid vertical grid data file.
+To interpolate to an @acronym{IFS}-format hybrid vertical grid, one
+must place the destination vertical grid into a
+ at acronym{CESM/E3SM}-format hybrid vertical grid file (see above) 
+that includes a @code{PS} surface pressure field (not @code{lnsp}
+log-surface pressure) for the destination grid.
+
 The @code{lev} and @code{ilev} coordinates of a hybrid grid are
 defined by the hybrid coefficients and reference pressure, and are
 by convention stored in millibars (not Pascals) as follows:


=====================================
src/nco/nco.h
=====================================
@@ -231,6 +231,11 @@ extern "C" {
   /*#define NCO_HSH_TRV_OBJ */
 #undef NCO_HSH_TRV_OBJ
 
+  /* 20240927: netCDF 4.9.3 switched "_FillValue" to NC_FillValue macro */
+#ifndef NC_FillValue
+# define NC_FillValue      "_FillValue"
+#endif /* !NC_FillValue */
+
   /* NCO_MSS_VAL_SNG names attribute whose value is "skipped" by arithmetic, aka the missing value attribute
      Attribute name should be either "missing_value" or "_FillValue" */
 #ifndef NCO_MSS_VAL_SNG
@@ -311,11 +316,13 @@ extern "C" {
 
 # ifdef NCO_USE_FILL_VALUE
   /* This arcane get()/set() usage necessary because TKN2SNG() macro above is broken. TODO nco905 */
-  char nco_mss_val_sng[]="_FillValue"; /* [sng] Missing value attribute name */
+  //  char nco_mss_val_sng[]="_FillValue"; /* [sng] Missing value attribute name */
+  char nco_mss_val_sng[]=NC_FillValue; /* [sng] Missing value attribute name */
   char nco_not_mss_val_sng[]="missing_value"; /* [sng] Not missing value attribute name */
 # else /* !NCO_USE_FILL_VALUE */
   char nco_mss_val_sng[]="missing_value"; /* [sng] Missing value attribute name */
-  char nco_not_mss_val_sng[]="_FillValue"; /* [sng] Not missing value attribute name */
+  //  char nco_not_mss_val_sng[]="_FillValue"; /* [sng] Not missing value attribute name */
+  char nco_not_mss_val_sng[]=NC_FillValue; /* [sng] Not missing value attribute name */
 # endif /* !NCO_USE_FILL_VALUE */
   char *nco_mss_val_sng_get(void){return nco_mss_val_sng;} /* [sng] Missing value attribute name */
   char *nco_not_mss_val_sng_get(void){return nco_not_mss_val_sng;} /* [sng] Not missing value attribute name */
@@ -373,7 +380,7 @@ extern "C" {
 # define NCO_VERSION_MINOR 2
 #endif /* !NCO_VERSION_MINOR */
 #ifndef NCO_VERSION_PATCH
-# define NCO_VERSION_PATCH 8
+# define NCO_VERSION_PATCH 9
 #endif /* !NCO_VERSION_PATCH */
 #ifndef NCO_VERSION_NOTE
 # define NCO_VERSION_NOTE "" /* Blank for final versions, non-blank (e.g., "-beta73") for pre-release versions */
@@ -383,7 +390,7 @@ extern "C" {
 # define NCO_LIB_VERSION ( NCO_VERSION_MAJOR * 100 + NCO_VERSION_MINOR * 10 + NCO_VERSION_PATCH )
 #endif /* !NCO_LIB_VERSION */
 #ifndef NCO_VERSION
-# define NCO_VERSION "5.2.8"
+# define NCO_VERSION "5.2.9"
 #endif /* !NCO_VERSION */
 
 /* Compatibility tokens new to netCDF4 netcdf.h: */


=====================================
src/nco/nco_ctl.c
=====================================
@@ -767,7 +767,7 @@ nco_cnf_prn(void) /* [fnc] Print NCO configuration and help text */
   /* NB: Keep configuration option tokens consistent among configure.ac, bld/Makefile, and nco_ctl.c
      Alphabetize list by first word in English text description of token */
   (void)fprintf(stdout,"Configuration Option:\tActive?\tMeaning or Reference:\nCheck _FillValue\t%s\thttp://nco.sf.net/nco.html#mss_val\nCommunity Codec Repo\t%s\thttp://github.com/ccr/ccr\nDAP support\t\t%s\thttp://nco.sf.net/nco.html#dap\nDebugging: Custom\t%s\tPedantic, bounds checking (slowest execution)\nDebugging: Symbols\t%s\tProduce symbols for debuggers (e.g., dbx, gdb)\nGNU Scientific Library\t%s\thttp://nco.sf.net/nco.html#gsl\nHDF4 support\t\t%s\thttp://nco.sf.net/nco.html#hdf4\nInternationalization\t%s\thttp://nco.sf.net/nco.html#i18n (pre-alpha)\nLogging\t\t\t%s\thttp://nco.sf.net/nco.html#dbg\nnetCDF3 64-bit offset\t%s\thttp://nco.sf.net/nco.html#lfs\nnetCDF3 64-bit data\t%s\thttp://nco.sf.net/nco.html#cdf5\nnetCDF4/HDF5 support\t%s\thttp://nco.sf.net/nco.html#nco4\nOpenMP SMP threading\t%s\thttp://nco.sf.net/nco.html#omp\nRegular Expressions\t%s\thttp://nco.sf.net/nco.html#rx\nUDUnits2 conversions\t%s\thttp://nco.sf.net/nco.html#udunits\n%s",
-		(!strcmp("_FillValue",nco_mss_val_sng_get())) ? "Yes" : "No",
+		(!strcmp(NC_FillValue,nco_mss_val_sng_get())) ? "Yes" : "No",
 #if defined(ENABLE_CCR) && (ENABLE_CCR)
 		"Yes",
 #else /* !ENABLE_CCR */


=====================================
src/nco/nco_netcdf.c
=====================================
@@ -2050,7 +2050,25 @@ nco_def_var(const int nc_id,const char * const var_nm,const nc_type var_typ,cons
   /* Purpose: Wrapper for nc_def_var() */
   const char fnc_nm[]="nco_def_var()";
   int rcd;
+
+  /* Make this condition true to print debugging information prior to variable definition */
+  if(0){
+    char dmn_nm[NC_MAX_NAME+1L];
+    int dmn_idx; /* [idx] Dimension index */
+    long dmn_cnt;
+    size_t var_sz=1ULL; /* [nbr] Number of elements in variable (will be self-multiplied) */
+    (void)fprintf(stderr,"%s: INFO %s prior to defining %s with %d dimensions\n","libnco",fnc_nm,var_nm,dmn_nbr);
+    for(dmn_idx=0;dmn_idx<dmn_nbr;dmn_idx++){
+      rcd=nco_inq_dim(nc_id,dmn_id[dmn_idx],dmn_nm,&dmn_cnt);
+      (void)fprintf(stderr,"%s: DEBUG quark73 dmn_idx = %d, dmn_id[%d] = %d, dmn_cnt[%d] = %ld, dmn_nm = %s\n",fnc_nm,dmn_idx,dmn_idx,dmn_id[dmn_idx],dmn_idx,dmn_cnt,dmn_nm);
+      var_sz*=dmn_cnt;
+      if(dmn_idx == dmn_nbr-1) (void)fprintf(stderr,"%s: Total variable size = %ld\n",fnc_nm,var_sz);
+      (void)fflush(stderr);
+    } /* !dmn_idx */
+  } /* !dbg */
+
   rcd=nc_def_var(nc_id,var_nm,var_typ,dmn_nbr,dmn_id,var_id);
+
   if(rcd == NC_EBADNAME){
     char att_nm[]="hdf_name"; /* [sng] Attribute to preserve original name */
     char *nm_nc=NULL; /* [sng] netCDF-compatible name */
@@ -2068,25 +2086,12 @@ nco_def_var(const int nc_id,const char * const var_nm,const nc_type var_typ,cons
     rcd=NCO_PUT_ATT_CHAR(nc_id,*var_id,att_nm,NC_CHAR,(size_t)strlen(var_nm),(const nco_char *)var_nm);
     if(nm_nc) free(nm_nc);
     if(rcd == NC_NOERR) (void)fprintf(stdout,"Original variable name is preserved in \"%s\" attribute.\n",att_nm);
+    (void)fflush(stdout);
   } /* !rcd */
 
-  if(0){
-    char var_nm[NC_MAX_NAME+1L];
-    char dmn_nm[NC_MAX_NAME+1L];
-    int dmn_idx; /* [idx] Dimension index */
-    long dmn_cnt;
-    size_t var_sz=1ULL; /* [nbr] Number of elements in variable (will be self-multiplied) */
-    (void)fprintf(stderr,"%s: INFO %s defining %s with %d dimensions\n","libnco",fnc_nm,var_nm,dmn_nbr);
-    for(dmn_idx=0;dmn_idx<dmn_nbr;dmn_idx++){
-      rcd=nco_inq_dim(nc_id,dmn_id[dmn_idx],dmn_nm,&dmn_cnt);
-      (void)fprintf(stdout,"%s: DEBUG quark73 dmn_idx = %d, dmn_id[%d] = %d, dmn_cnt[%d] = %ld, dmn_nm = %s\n",fnc_nm,dmn_idx,dmn_idx,dmn_id[dmn_idx],dmn_idx,dmn_cnt,dmn_nm);
-      var_sz*=dmn_cnt;
-      if(dmn_idx == dmn_nbr-1) (void)fprintf(stderr,"%s: Total variable size = %ld\n",fnc_nm,var_sz);
-    } /* !dmn_idx */
-  } /* !dbg */
-
   if(rcd != NC_NOERR){
     (void)fprintf(stdout,"ERROR: %s failed to nc_def_var() variable \"%s\"\n",fnc_nm,var_nm);
+    (void)fflush(stdout);
     nco_err_exit(rcd,"nco_def_var()");
   } /* !rcd */
 
@@ -3130,7 +3135,7 @@ nco_inq_att(const int nc_id,const int var_id,const char * const att_nm,nc_type *
   if(rcd != NC_NOERR){
     (void)fprintf(stderr,"ERROR: %s unable to inquire attribute var_id: %d, att_nm: %s\n",fnc_nm,var_id,att_nm);
     nco_err_exit(rcd,fnc_nm);
-  } /* endif */
+  } /* !rcd */
   return rcd;
 } /* !nco_inq_att */
 
@@ -3148,7 +3153,7 @@ nco_inq_att_flg(const int nc_id,const int var_id,const char * const att_nm,nc_ty
   if(rcd != NC_NOERR){
     (void)fprintf(stderr,"ERROR: %s unable to inquire attribute var_id: %d, att_nm: %s\n",fnc_nm,var_id,att_nm);
     nco_err_exit(rcd,fnc_nm);
-  } /* endif */
+  } /* !rcd */
   return rcd;
 } /* !nco_inq_att_flg */
 
@@ -3173,7 +3178,7 @@ nco_inq_attid_flg(const int nc_id,const int var_id,const char * const att_nm,int
   if(rcd != NC_NOERR){
     (void)fprintf(stderr,"ERROR: %s unable to inquire attribute var_id: %d, att_nm: %s\n",fnc_nm,var_id,att_nm);
     nco_err_exit(rcd,fnc_nm);
-  } /* endif */
+  } /* !rcd */
   return rcd;
 } /* !nco_inq_attid_flg */
 
@@ -3318,7 +3323,7 @@ nco_put_att(const int nc_id,const int var_id,const char * const att_nm,const nc_
   default: nco_dfl_case_nc_type_err(); break;
   } /* end switch */
   /* 20170811: netCDF 4.5.0-development enforced rule attempting to add _FillValue to root/group (NC_GLOBAL) returns NC_EGLOBAL */
-  if(rcd == NC_EGLOBAL && !strcmp(att_nm,"_FillValue")){
+  if(rcd == NC_EGLOBAL && !strcmp(att_nm,NC_FillValue)){
     char grp_nm[NC_MAX_NAME+1L];
     (void)nco_inq_grpname(nc_id,grp_nm);
     (void)fprintf(stdout,"WARNING: %s received NC_EGLOBAL error writing attribute \"%s\" to metadata for group \"%s\". netCDF 4.5.0-development forbids writing the _FillValue attribute to global or group metadata, though earlier versions allow it. Proceeding normally without writing %s attribute...\n",fnc_nm,att_nm,grp_nm,att_nm);
@@ -3417,10 +3422,10 @@ nco_get_att(const int nc_id,const int var_id,const char * const att_nm,void * co
     char var_nm[NC_MAX_NAME+1L];
     (void)nco_inq_varname(nc_id,var_id,var_nm);
     (void)fprintf(stderr,"ERROR: %s unable to get attribute var_id: %d, var_nm: %s, att_nm: %s\n",fnc_nm,var_id,var_nm,att_nm);
-  } /* endif */
+  } /* !rcd */
   if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_get_att()");
   return rcd;
-} /* !nco_get_att */
+} /* !nco_get_att() */
 /* End Attribute routines */
 
 /* Begin netCDF4 stubs */


=====================================
src/nco/nco_netcdf.h
=====================================
@@ -207,6 +207,11 @@
 # define NC_FORMAT_64BIT_DATA	NC_FORMAT_CDF5
 #endif
 
+/* 20240927: netCDF 4.9.3 switched "_FillValue" to NC_FillValue macro */
+#ifndef NC_FillValue
+# define NC_FillValue      "_FillValue"
+#endif /* !NC_FillValue */
+
 /* netcdf.h added tokens specifically for DAP in 2012?
    Started annotating these error codes in nco_err_exit() in NCO 4.4.6 in 201409 */
 #ifndef NC_EIO


=====================================
src/nco/nco_rgr.c
=====================================
@@ -1710,7 +1710,7 @@ nco_ntp_vrt /* [fnc] Interpolate vertically */
        ECMWF provides "hya?" as a constant in Pa and "hyb?" as a dimensionless coefficient of PS, whereas CAM/EAM provides "hya?" and "hyb?" both as dimensionless coefficients of P0 and PS
        ECMWF provides "lev" and "lev_2" with midpoint and surface pressure indices (not values), respectively, whereas CAM/EAM provides "lev" and "ilev" coordinate values in hPa
        ECMWF provides dimensionless "lnsp" for log(surface pressure) whereas CAM/EAM provide "PS" for surface pressure in Pa
-       ECMWF "lnsp" has degenerate level dimension "lev_2" whereas CAM/EAM "PS" has no "ilev" dimension
+       ECMWF "lnsp" has degenerate level dimension "lev_2" whereas CAM/EAM "PS" has no "ilev" dimension (this leads ncks to detect an additional, artificial, horizontal dimension when inspecting surface pressure)
        ECMWF uses hya? instead of reference pressure whereas CAM/EAM provides "P0" in hPa */
 
     if(flg_grd_hyb_cameam){
@@ -2834,7 +2834,7 @@ nco_ntp_vrt /* [fnc] Interpolate vertically */
       if(!has_mss_val && flg_need_msv){
 	val_unn mss_val_dfl; /* [] Default _FillValue */
 	mss_val_dfl=nco_mss_val_dfl_get(NC_INT);
-	rcd=nco_put_att(out_id,mlc_id,"_FillValue",NC_INT,1L,(void *)(&mss_val_dfl));
+	rcd=nco_put_att(out_id,mlc_id,NC_FillValue,NC_INT,1L,(void *)(&mss_val_dfl));
       } /* !has_mss_val, !flg_need_msv */
     } /* !flg_mlc_out */
   } /* !flg_grd_out_dpt_3D */
@@ -3015,7 +3015,7 @@ nco_ntp_vrt /* [fnc] Interpolate vertically */
   dmn_cnt_out=(long *)nco_malloc(dmn_nbr_max*sizeof(long));
 
   aed_sct aed_mtd_fll_val;
-  char *att_nm_fll_val=strdup("_FillValue");
+  char *att_nm_fll_val=strdup(NC_FillValue);
   int flg_pck; /* [flg] Variable is packed on disk  */
   float mss_val_flt;
   if(flg_add_msv_att){
@@ -3190,11 +3190,16 @@ nco_ntp_vrt /* [fnc] Interpolate vertically */
   size_t grd_nbr=grd_sz_in; /* [nbr] Horizonal grid size */
 
   /* Results of heuristic method of determining whether vertical or horizontal MRV dimension */
+  int dmn_hrz_dgn_nbr=0; /* [nbr] Number of "degenerate" or "artificial" horizontal dimensions expected to be detected */
+  /* ECMWF/IFS defines log of surface pressure with degenerate dimension "lev_2" */
+  if(flg_grd_hyb_ecmwf) dmn_hrz_dgn_nbr=1;
+  /* [nbr] Remove degernate/horizontal dimensions from number of detected input horizontal dimensions */
+  dmn_hrz_nbr_in-=dmn_hrz_dgn_nbr;
   if(dmn_hrz_nbr_in == 0 || grd_sz_in == 1L){flg_grd_hrz_0D=True;}
   else if(dmn_hrz_nbr_in == 1){flg_grd_hrz_1D=True;}
   else if(dmn_hrz_nbr_in == 2){flg_grd_hrz_2D=True;}
   if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(stdout,"%s: INFO %s reports flg_hrz_mrv = %d, dmn_hrz_nbr_in = %d, grd_sz_in = %ld, flg_grd_hrz_0D = %d, flg_grd_hrz_1D = %d, flg_grd_hrz_2D = %d\n",nco_prg_nm_get(),fnc_nm,flg_hrz_mrv,dmn_hrz_nbr_in,grd_sz_in,flg_grd_hrz_0D,flg_grd_hrz_1D,flg_grd_hrz_2D);
-  assert(dmn_hrz_nbr_in <= 2);
+  assert(dmn_hrz_nbr_in >= 0 && dmn_hrz_nbr_in <= 2);
   
   /* Using naked stdin/stdout/stderr in parallel region generates warning
      Copy appropriate filehandle to variable scoped as shared in parallel clause */
@@ -6083,7 +6088,7 @@ nco_rgr_wgt /* [fnc] Regrid with external weights */
 	    if(!has_mss_val){
 	      val_unn mss_val_dfl; /* [] Default _FillValue */
 	      mss_val_dfl=nco_mss_val_dfl_get(var_typ_out);
-	      rcd=nco_put_att(out_id,var_id_out,"_FillValue",var_typ_out,1L,(void *)(&mss_val_dfl));
+	      rcd=nco_put_att(out_id,var_id_out,NC_FillValue,var_typ_out,1L,(void *)(&mss_val_dfl));
 	    } /* !has_mss_val */
 	  } /* !flg_add_fll */
 	} /* !flg_rgr */
@@ -11958,7 +11963,7 @@ nco_grd_nfr /* [fnc] Infer SCRIP-format grid file from input data file */
     aed_mtd.mode=aed_create;
     (void)nco_aed_prc(out_id,fc_nd_id,aed_mtd);
     if(att_nm) att_nm=(char *)nco_free(att_nm);
-    att_nm=strdup("_FillValue");
+    att_nm=strdup(NC_FillValue);
     aed_mtd.att_nm=att_nm;
     aed_mtd.var_nm=fc_nd_nm;
     aed_mtd.id=fc_nd_id;


=====================================
src/nco/nco_s1d.c
=====================================
@@ -68,7 +68,7 @@ nco_lnd_typ_sng /* [fnc] Convert landunit-type enum to string */
   return (char *)NULL;
 } /* !nco_lnd_typ_sng() */
 
-const char * /* O [sng] String describing PFT type */
+char * /* O [sng] String describing PFT type */
 nco_pft_typ_sng /* [fnc] Convert PFT-type enum to string */
 (const int nco_pft_typ) /* I [enm] PFT type enum */
 {
@@ -89,16 +89,13 @@ nco_pft_typ_sng /* [fnc] Convert PFT-type enum to string */
   case nco_pft_ipft_c3_arctic_grass: return "C3 Arctic grass"; /* 12 */
   case nco_pft_ipft_c3_non_arctic_grass: return "C3 non-Arctic grass"; /* 13 */
   case nco_pft_ipft_c4_grass: return "C4 grass"; /* 14 */
+    /* 20241017: ELMv3 includes C3 crop and irrigated in natpft dimension (natpft=17)
+       Previously, AFAIK, ELM datasets always had natpft=15
+       Also Eva h2, h3 history files still have natpft=15
+       These final two enumerates are not accessed unless natpft >= 17 */
   case nco_pft_ipft_c3_crop: return "C3 crop"; /* 15 */
   case nco_pft_ipft_c3_irrigated: return "C3 irrigated"; /* 16 */
-  case nco_pft_ipft_corn: return "Corn"; /* 17 */
-  case nco_pft_ipft_irrigated_corn: return "Irrigated corn"; /* 18 */
-  case nco_pft_ipft_spring_temperate_cereal: return "Spring temperate cereal"; /* 19 */
-  case nco_pft_ipft_irrigated_spring_temperate_cereal: return "Irrigated spring temperate cereal"; /* 20 */
-  case nco_pft_ipft_winter_temperate_cereal: return "Winter temperate cereal"; /* 21 */
-  case nco_pft_ipft_irrigated_winter_temperate_cereal: return "Irrigated winter temperate cereal"; /* 22 */
-  case nco_pft_ipft_soybean: return "Soybean"; /* 23 */
-  case nco_pft_ipft_irrigated_soybean: return "Irrigated soybean"; /* 24 */
+
   default: nco_dfl_case_generic_err((int)nco_pft_typ); break;
   } /* !nco_pft_typ_enm */
 
@@ -125,22 +122,21 @@ nco_s1d_sng /* [fnc] Convert sparse-1D type enum to string */
 } /* !nco_s1d_sng() */
 
 int /* O [rcd] Return code */
-nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
+nco_s1d_unpack /* [fnc] Unpack sparse-1D ELM/CLM variables into full file */
 (rgr_sct * const rgr, /* I/O [sct] Regridding structure */
  trv_tbl_sct * const trv_tbl) /* I/O [sct] Traversal Table */
 {
-  /* Purpose: Read sparse CLM/ELM input file, inflate and write into output file */
+  /* Purpose: Read sparse ELM/CLM input file, inflate and write into output file */
 
   /* Usage:
      ncks -D 1 -O -C --s1d ~/data/bm/elm_mali_bg_hst.nc ~/foo.nc
+     ncks -D 1 -O -C --s1d --hrz=${DATA}/bm/elmv3_r05l15.nc ~/data/bm/elmv3_rst_r05l15.nc ~/foo.nc
      ncks -D 1 -O -C --s1d -v cols1d_topoglc --hrz=${DATA}/bm/elm_mali_ig_hst.nc ${DATA}/bm/elm_mali_rst.nc ~/foo.nc
-     ncks -D 1 -O -C --s1d -v GPP,pfts1d_wtgcell ~/beth_in.nc ~/foo.nc
+     ncks -D 1 -O -C --s1d -v GPP,pfts1d_wtgcell ~/eva_h2.nc ~/foo.nc
      ncremap --dbg=1 --vrb=3 --devnull=No --nco='--dbg=1' -P elm -m ${DATA}/maps/map_ne30np4_to_fv128x256_aave.20160301.nc ~/foo.nc ~/foo_rgr.nc */
 
-  /* 20240131: Unpacking an r05 ELM restart file into latxlon format is storage-intensive
-     Converting an r05 gis_1to10km IG simulation on imua took ~2 hrs and ballooned the filesize from ~7 GB to ~7 TB!
-     Always subset before converting the input restart file
-     ncks -D 1 -O -C --s1d --hrz=${DATA}/bm/elm_mali_ig_hst.nc ${DATA}/bm/elm_mali_rst.nc ~/foo.nc */
+  /* 20240920: Unpacking an standard r05 ELM restart file into latxlon format is NOT storage-intensive
+     Converting an r05 B simulation on imua took ~1 minute and reduced the filesize from ~14 GB to ~9 GB */
 
   const char fnc_nm[]="nco_s1d_unpack()"; /* [sng] Function name */
 
@@ -154,9 +150,13 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 
   char dmn_nm[NC_MAX_NAME]; /* [sng] Dimension name */
   char *grd_nm_in=(char *)strdup("gridcell");
-  char *lnd_nm_in=(char *)strdup("landunit");
+  char *lnd_nm_in=(char *)strdup("landunit"); /* Canonical landunit sparse dimension name, used in history and restart files */
+  // 20241017 fxm: replace dimension name "ltype" with "landunit" in all output files?
+  //char *ltype_nm_in=(char *)strdup("ltype"); /* Gridded landunit dimension name used in history (PCT_LANDUNIT, eva_h2.nc) files */
   char *clm_nm_in=(char *)strdup("column");
+  char *mec_nm_in=(char *)strdup("glc_nec"); /* 20241017: glc_nec is only present in IG/BG restarts as an "orphaned dimension" (no variables use it) so ncks -m does not print it. Use ncdump -h to see it. */
   char *pft_nm_in=(char *)strdup("pft");
+  char *pft_ntr_nm_in=(char *)strdup("natpft");
   char *tpo_nm_in=(char *)strdup("topounit");
 
   char *levcan_nm_in=(char *)strdup("levcan");
@@ -168,6 +168,8 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   char *numrad_nm_in=(char *)strdup("numrad");
     
   char *mec_nm_out=(char *)strdup("mec");
+  char *pft_sng_lng_nm_out=(char *)strdup("pft_sng_lng");
+  char *pft_chr_out=NULL; /* [sng] Coordinate array of PFT strings */
 
   int fl_out_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Output file format */
   int fll_md_old; /* [enm] Old fill mode */
@@ -191,6 +193,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   long int pft_idx;
   long int tpo_idx;
 
+  nco_string *pft_sng_out=NULL; /* [sng] Coordinate array of PFT strings */
   nco_bool flg_var_mpt; /* [flg] Variable has no valid values */
 
   size_t idx_dbg=rgr->idx_dbg; /* [idx] User-specifiable debugging location */
@@ -214,6 +217,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   int dmn_id_lon_in=NC_MIN_INT; /* [id] Dimension ID */
 
   nco_bool FL_RTR_RMT_LCN;
+  nco_bool flg_cft=False; /* [flg] Dataset contains crop PFTs, i.e., CFTs */
   nco_bool flg_grd_1D=False; /* [flg] Unpacked data are on unstructured (1D) grid */
   nco_bool flg_grd_2D=False; /* [flg] Unpacked data are on rectangular (2D) grid */
   nco_bool flg_grd_dat=False; /* [flg] Use horizontal grid from required input data file */
@@ -221,12 +225,12 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   nco_bool flg_nm_hst=False; /* [flg] Names in data file are as in history files ("ltype_"...) */
   nco_bool flg_nm_rst=False; /* [flg] Names in data file are as in restart files ("ilun_"...) */
 
-  /* Does data file have unstructured grid? 
+  /* Does data file have unstructured grid?
      MB: Routine must handle two semantically distinct meanings of "column":
      1. The horizontal dimension in an unstructured grid
      2. A fraction of a landunit, which is itself a fraction of a CTSM/ELM gridcell
         In particular, a column is a fraction of a vegetated, urban, glacier, or crop landunit
-     This routine distinguishes these meanings by abbreviating (1) as "col" and (2) as "clm" 
+     We distinguish these meanings by abbreviating definition (1) as "col" and definition (2) as "clm" 
      This usage maintains the precedent that "col" is the horizontal unstructured dimension in nco_rgr.c
      It is necessary though unintuitive that "cols1d" variable metadata will use the "clm" abbreviation */
   if(col_nm_in && (rcd=nco_inq_dimid_flg(in_id,col_nm_in,&dmn_id_col_in)) == NC_NOERR) /* do nothing */; 
@@ -334,7 +338,9 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   int dmn_id_clm_in=NC_MIN_INT; /* [id] Dimension ID */
   int dmn_id_grd_in=NC_MIN_INT; /* [id] Dimension ID */
   int dmn_id_lnd_in=NC_MIN_INT; /* [id] Dimension ID */
+  int dmn_id_mec_in=NC_MIN_INT; /* [id] Dimension ID */
   int dmn_id_pft_in=NC_MIN_INT; /* [id] Dimension ID */
+  int dmn_id_pft_ntr_in=NC_MIN_INT; /* [id] Dimension ID */
   int dmn_id_tpo_in=NC_MIN_INT; /* [id] Dimension ID */
 
   nco_bool flg_s1d_clm=False; /* [flg] Dataset contains sparse variables for columns */
@@ -352,7 +358,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
     (void)fprintf(stderr,"%s: ERROR %s reports input data file lacks expected global attributes\n",nco_prg_nm_get(),fnc_nm);
     nco_exit(EXIT_FAILURE);
   } /* !flg_nm_hst */
-  if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO %s will assume input attributes and variables use CLM/ELM %s naming conventions like %s\n",nco_prg_nm_get(),fnc_nm,flg_nm_hst ? "history file" : "restart file",flg_nm_hst ? "\"ltype_...\"" : "\"ilun_...\"");
+  if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO %s will assume input attributes and variables use ELM/CLM %s naming conventions like %s\n",nco_prg_nm_get(),fnc_nm,flg_nm_hst ? "history file" : "restart file",flg_nm_hst ? "\"ltype_...\"" : "\"ilun_...\"");
 
   rcd=nco_inq_varid_flg(in_id,"cols1d_lat",&cols1d_lat_id);
   if(cols1d_lat_id != NC_MIN_INT) flg_s1d_clm=True;
@@ -372,6 +378,10 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
     rcd=nco_inq_varid(in_id,"grid1d_ixy",&grid1d_ixy_id);
     rcd=nco_inq_varid(in_id,"grid1d_jxy",&grid1d_jxy_id);
     rcd=nco_inq_varid(in_id,"grid1d_lon",&grid1d_lon_id);
+    /* NB: 20241017: grid1d_[ij]xy are only needed when topo1d_[ij]xy are invalid
+     And in that case, we read grid1d_[ij]xy values directly into topo1d_[ij]xy */
+    //int *grid1d_ixy=NULL; /* [idx] Gridcell 2D longitude index */
+    //int *grid1d_jxy=NULL; /* [idx] Gridcell 2D latitude index */
   } /* !flg_s1d_grd */
      
   rcd=nco_inq_varid_flg(in_id,"land1d_lat",&land1d_lat_id);
@@ -410,7 +420,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   } /* !flg_s1d_tpo */
   
   if(!(flg_s1d_clm || flg_s1d_lnd || flg_s1d_pft || flg_s1d_tpo)){
-    (void)fprintf(stderr,"%s: ERROR %s does not detect any of the key variables (currently cols1d_lat, land1d_lat, pfts1d_lat, topo1d_lat) used to indicate presence of sparse-packed (S1D) variables\nHINT: Be sure the target dataset (file) contains S1D variables---not all CLM/ELM history (as opposed to restart) files do\n",nco_prg_nm_get(),fnc_nm);
+    (void)fprintf(stderr,"%s: ERROR %s does not detect any of the key variables (currently cols1d_lat, land1d_lat, pfts1d_lat, topo1d_lat) used to indicate presence of sparse-packed (S1D) variables\nHINT: Be sure the target dataset (file) contains S1D variables---not all ELM/CLM history (as opposed to restart) files do. For example, default ELM/CLM h0 (monthly) history files typically contain no S1D variables.\n",nco_prg_nm_get(),fnc_nm);
     nco_exit(EXIT_FAILURE);
   } /* !flg_s1d_clm... */
 
@@ -527,19 +537,24 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   long clm_nbr_in=NC_MIN_INT; /* [nbr] Number of columns in input data */
   long grd_nbr_in=NC_MIN_INT; /* [nbr] Number of gridcells in input data */
   long lnd_nbr_in=NC_MIN_INT; /* [nbr] Number of landunits in input data */
+  long mec_nbr_in=NC_MIN_INT; /* [nbr] Number of MECs in input data */
   long pft_nbr_in=NC_MIN_INT; /* [nbr] Number of PFTs in input data */
+  long pft_ntr_nbr_in=NC_MIN_INT; /* [nbr] Number of natural PFTs in input data */
   long tpo_nbr_in=NC_MIN_INT; /* [nbr] Number of topounits in input data */
   long clm_nbr_out=NC_MIN_INT; /* [nbr] Number of columns in output data */
   long grd_nbr_out=NC_MIN_INT; /* [nbr] Number of gridcells in output data */
   long lnd_nbr_out=NC_MIN_INT; /* [nbr] Number of landunits in output data */
   long mec_nbr_out=NC_MIN_INT; /* [nbr] Number of MECs in output data */
   long pft_nbr_out=NC_MIN_INT; /* [nbr] Number of PFTs in output data */
+  long pft_sng_lng_out=NC_MIN_INT; /* [nbr] Max length of PFT string in output data */
   long tpo_nbr_out=NC_MIN_INT; /* [nbr] Number of topounits in output data */
   if(need_clm) rcd=nco_inq_dimlen(in_id,dmn_id_clm_in,&clm_nbr_in);
   if(need_grd) rcd=nco_inq_dimlen(in_id,dmn_id_grd_in,&grd_nbr_in);
   if(need_lnd) rcd=nco_inq_dimlen(in_id,dmn_id_lnd_in,&lnd_nbr_in);
   if(need_pft) rcd=nco_inq_dimlen(in_id,dmn_id_pft_in,&pft_nbr_in);
   if(need_tpo) rcd=nco_inq_dimlen(in_id,dmn_id_tpo_in,&tpo_nbr_in);
+  /* 20241017: I think topounits are an abstract layer between gridcells and landunits. E3SMv3 introduced topounits with the simplest usage, tpo_nbr_in == grd_nbr_in so that each gridcell is a single topounit. However, in the future some gridcells may have multiple topounits, with each topounit having its own landunits (and so on). I think topounits will generally be used to represent distinct topographic slopes/catchments with a gridcell, e.g., sunlit side of mountains vs shaded side. */
+  if(need_tpo && need_grd && tpo_nbr_in != grd_nbr_in) (void)fprintf(stdout,"%s: WARNING %s reports number of topounits and gridcells are unequal. Expect mayhem. tpo_nbr_in = %ld != %ld = grd_nbr_in\n",nco_prg_nm_get(),fnc_nm,tpo_nbr_in,grd_nbr_in);
 
   int dmn_id_levcan_in=NC_MIN_INT; /* [id] Dimension ID */
   int dmn_id_levgrnd_in=NC_MIN_INT; /* [id] Dimension ID */
@@ -674,6 +689,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   int dmn_id_lnd_out=NC_MIN_INT; /* [id] Dimension ID */
   int dmn_id_mec_out=NC_MIN_INT; /* [id] Dimension ID */
   int dmn_id_pft_out=NC_MIN_INT; /* [id] Dimension ID */
+  int dmn_id_pft_sng_lng_out=NC_MIN_INT; /* [id] Dimension ID */
 
   char *levcan_nm_out=NULL;
   char *levgrnd_nm_out=NULL;
@@ -708,6 +724,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   int ilun_urban_hd; /* 8 [enm] */
   int ilun_urban_md; /* 9 [enm] */
   if(flg_nm_hst){
+    /* Names in data file are as in history files ("ltype_"...) */
     rcd=nco_get_att(in_id,NC_GLOBAL,"ltype_vegetated_or_bare_soil",&ilun_vegetated_or_bare_soil,NC_INT);
     rcd=nco_get_att(in_id,NC_GLOBAL,"ltype_crop",&ilun_crop,NC_INT);
     rcd=nco_get_att(in_id,NC_GLOBAL,"ltype_landice",&ilun_landice,NC_INT);
@@ -718,6 +735,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
     rcd=nco_get_att(in_id,NC_GLOBAL,"ltype_urban_hd",&ilun_urban_hd,NC_INT);
     rcd=nco_get_att(in_id,NC_GLOBAL,"ltype_urban_md",&ilun_urban_md,NC_INT);
   }else{ /* !flg_nm_hst */
+    /* Names in data file are as in restart files ("ilun_"...) */
     rcd=nco_get_att(in_id,NC_GLOBAL,"ilun_vegetated_or_bare_soil",&ilun_vegetated_or_bare_soil,NC_INT);
     rcd=nco_get_att(in_id,NC_GLOBAL,"ilun_crop",&ilun_crop,NC_INT);
     rcd=nco_get_att(in_id,NC_GLOBAL,"ilun_landice",&ilun_landice,NC_INT);
@@ -752,9 +770,21 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
       while(cols1d_ityplun[clm_idx++] == ilun_landice_multiple_elevation_classes) mec_nbr_out++;
       break;
     } /* !clm_idx */
-    /* NB: landice_MEC (ilun=4, usually) landunits have 10 (always, AFAICT) glacier elevation classes */
+    /* Glacier landunits (ilun=4, usually) with active glaciers (e.g., IG cases) have 10 (always, AFAICT) glacier elevation classes
+       20241016: IG restart files store the number of elevation classes in orphaned dimension named "glc_nec"
+       Restart files without active glaciers do not contain the "glc_nec" dimension
+       All ELM restart files also contain an orphaned dimension named "levtrc"---not sure what it is for */
     if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: INFO mec_nbr_out = %ld\n",nco_prg_nm_get(),mec_nbr_out);
     if(mec_nbr_out > 0) need_mec=True;
+    if(need_mec){
+      /* Sanity check. Allow for input files that have MECs yet lack "glc_nec" due to NCO skipping orphaned dimensions. */
+      rcd=nco_inq_dimid_flg(in_id,mec_nm_in,&dmn_id_mec_in);
+      if(rcd == NC_NOERR){
+	nco_inq_dimlen(in_id,dmn_id_mec_in,&mec_nbr_in);
+	assert(mec_nbr_in == mec_nbr_out);
+      } /* !rcd */
+      rcd=NC_NOERR;
+    } /* !need_mec */
     
     cols1d_ixy=(int *)nco_malloc(clm_nbr_in*sizeof(int));
     rcd=nco_get_var(in_id,cols1d_ixy_id,cols1d_ixy,NC_INT);
@@ -766,7 +796,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   } /* !need_clm */
     
   /* Determine output Grid dimension if needed:
-     CLM/ELM 'gridcell' dimension counts each gridcell that contains land
+     ELM/CLM 'gridcell' dimension counts each gridcell that contains land
      Replace this dimension by horizontal dimension(s) in input data file */
   if(need_grd){
     if(flg_grd_1D) grd_nbr_out=col_nbr;
@@ -792,6 +822,13 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 
   /* Determine output PFT dimension if needed */
   //double *pfts1d_wtgcell=NULL; /* [frc] PFT weight relative to corresponding gridcell */
+  /* ELM history files contain a dimension named "natpft" that contains the number of natural PFTs (including bare ground)
+     AFAICT, the variable PCT_NAT_PFT(time,natpft,lat,lon) is the exclusive user of this dimension
+     ELM restart files do not contain the natpft dimension
+     However, we need natpft for restart files in order to parse crop names in global attributes 
+     How to obtain natpft for restart files? */
+#define NCO_PFT_NTR_MAX 16 /* Maximum number of natural PFTs (not counting bare ground) */
+  const int pft_ntr_max=NCO_PFT_NTR_MAX; /* [nbr] Maximum number of natural PFTs (not counting bare ground) */
   int *pfts1d_active=NULL; /* [flg] PFT active flag (1=active, 0=inactive) */
   int *pfts1d_ityp_veg=NULL; /* [enm] PFT vegetation type */
   int *pfts1d_ityplun=NULL; /* [enm] PFT landunit type */
@@ -820,7 +857,13 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
       //while(pfts1d_ityp_veg[++pft_idx] != 0) pft_nbr_out++;
       //      break;
     } /* !pft_idx */
+    if(pft_nbr_out > pft_ntr_max) flg_cft=True;
     if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: INFO pft_nbr_out = %ld\n",nco_prg_nm_get(),pft_nbr_out);
+    if(flg_nm_hst){
+      rcd=nco_inq_dimid(in_id,pft_ntr_nm_in,&dmn_id_pft_ntr_in);
+      rcd=nco_inq_dimlen(in_id,dmn_id_pft_ntr_in,&pft_ntr_nbr_in);
+      if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: INFO pft_ntr_nbr_in = %ld\n",nco_prg_nm_get(),pft_ntr_nbr_in);
+    } /* !flg_nm_hst */
 
     pfts1d_ixy=(int *)nco_malloc(pft_nbr_in*sizeof(int));
     rcd=nco_get_var(in_id,pfts1d_ixy_id,pfts1d_ixy,NC_INT);
@@ -846,13 +889,45 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
       topo1d_jxy=(int *)nco_malloc(tpo_nbr_in*sizeof(int));
       rcd=nco_get_var(in_id,topo1d_jxy_id,topo1d_jxy,NC_INT);
     } /* !flg_grd_2D */
+
+    if(flg_nm_hst){
+      /* 20241017: eva_h2.nc, eva_h3.nc has empty (all values are zero) topo1d_ixy, topo1d_jxy, 
+	 These are supposed to be (1-based) Fortran indices to corresponding longitude and latitude gridcells of the topounit
+	 If any index is zero, ... fxm */
+      nco_bool flg_rpl_tpo_wth_grd=False; /* [flg] Replace topo1d_[ij]xy values with grid1d_[ij]xy values */
+      for(tpo_idx=0;tpo_idx<tpo_nbr_in;tpo_idx++){
+	if((topo1d_ixy[tpo_idx] <= 0) || (topo1d_jxy[tpo_idx] <= 0)){
+	  (void)fprintf(stdout,"%s: WARNING %s reports invalid topounit latitude and/or longitude indices: topo1d_ixy[%ld] = %d, topo1d_jxy[%ld] = %d. These are supposed to be (1-based) Fortran indices to corresponding longitude and latitude gridcells of the topounit. By definition/convention, each Fortran index must be > 0. In other words, this input dataset, presumably produced by ELM, contains invalid variables. Contact the ELM authors and/or upgrade ELM to fix the root cause of this problem.\n",nco_prg_nm_get(),fnc_nm,tpo_idx,topo1d_ixy[tpo_idx],tpo_idx,topo1d_ixy[tpo_idx]);
+	  if((grid1d_ixy_id != NC_MIN_INT) && (grid1d_jxy_id != NC_MIN_INT)){
+	    (void)fprintf(stdout,"%s: WARNING %s Attempting workaround: Will replace invalid topo1d_[ij]xy values with grid1d_[ij]xy values, respectively.\nCross your fingers...\n",nco_prg_nm_get(),fnc_nm);
+	    flg_rpl_tpo_wth_grd=True;
+	  }else{
+	    (void)fprintf(stdout,"%s: ERROR %s Unable to work around invalid topo1d_[ij]xy values because grid1d_[ij]xy values are not present to be used as replacements\n",nco_prg_nm_get(),fnc_nm);
+	    nco_exit(EXIT_FAILURE);
+	  } /* !grid1d_ixy_id */
+	} /* !topo1d_ixy */
+	if(flg_rpl_tpo_wth_grd){
+	  /* Overwrite topo1d_[ij]xy with grid1d_[ij]xy */
+	  rcd=nco_get_var(in_id,grid1d_ixy_id,topo1d_ixy,NC_INT);
+	  if(flg_grd_2D){
+	    rcd=nco_get_var(in_id,grid1d_jxy_id,topo1d_jxy,NC_INT);
+	  } /* !flg_grd_2D */
+	} /* !flg_rpl_tpo_wth_grd */
+      } /* !tpo_idx */
+      
+    } /* !flg_nm_hst */
     
   } /* !need_tpo */
   
+  (void)fflush(stdout);
+
   /* Define unpacked versions of needed dimensions before all else */
   if(need_clm && clm_nbr_out > 0L) rcd=nco_def_dim(out_id,clm_nm_out,clm_nbr_out,&dmn_id_clm_out);
   if(need_lnd && lnd_nbr_out > 0L) rcd=nco_def_dim(out_id,lnd_nm_out,lnd_nbr_out,&dmn_id_lnd_out);
   if(need_pft && pft_nbr_out > 0L) rcd=nco_def_dim(out_id,pft_nm_out,pft_nbr_out,&dmn_id_pft_out);
+#define NCO_PFT_MAX_SNG_LNG 36
+  pft_sng_lng_out=NCO_PFT_MAX_SNG_LNG;
+  if(need_pft && pft_nbr_out > 0L) rcd=nco_def_dim(out_id,pft_sng_lng_nm_out,pft_sng_lng_out,&dmn_id_pft_sng_lng_out);
 
   /* MECs can be a new output dimension if they are enumerated in input (MEC is a column-level sub-unit of a glacier landunit) */
   if(need_mec && mec_nbr_out > 0L) rcd=nco_def_dim(out_id,mec_nm_out,mec_nbr_out,&dmn_id_mec_out);
@@ -1048,7 +1123,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   /* levgrnd coordinate: ncks -v lev.? ${DATA}/bm/elmv3_r05l15.nc */
   const double levgrnd[15]={0.007100635,0.027925,0.06225858,0.1188651,0.2121934,0.3660658,0.6197585,1.038027,1.727635,2.864607,4.739157,7.829766,12.92532,21.32647,35.17762}; /* [m] Coordinate lake levels */
   int levgrnd_out_id=NC_MIN_INT; /* [id] Variable ID for levgrnd */
-  if(need_levgrnd){
+  if(need_levgrnd && levgrnd_nbr_out == 15){
     dmn_ids_out[0]=dmn_id_levgrnd_out;
     rcd+=nco_def_var(out_id,levgrnd_nm_out,NC_DOUBLE,dmn_nbr_1D,dmn_ids_out,&levgrnd_out_id);
     if(nco_cmp_glb_get()) rcd+=nco_flt_def_out(out_id,levgrnd_out_id,NULL,nco_flt_flg_prc_fll);
@@ -1081,14 +1156,129 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
     rcd=nco_char_att_put(out_id,mec_nm_out,"units","meter");
   } /* !need_mec */
     
+  /* PFT coordinate  */
+  int pft_out_id=NC_MIN_INT; /* [id] Variable ID for PFT coordinate */
+  //if(False){
+  if(need_pft){
+    dmn_ids_out[0]=dmn_id_pft_out;
+    dmn_ids_out[1]=dmn_id_pft_sng_lng_out;
+    /* Assemble PFT coordinate as list of strings */
+    if(fl_out_fmt == NC_FORMAT_NETCDF4){
+      pft_sng_out=(nco_string *)nco_calloc(pft_nbr_out,sizeof(nco_string));
+    }else{
+      pft_chr_out=(char *)nco_calloc(pft_nbr_out*pft_sng_lng_out,sizeof(char));
+    } /* !fl_out_fmt */
+    
+    /* Gather natural PFT names
+       PFT indexing is complicated, and smacks of Fortran conventions
+       PFT ityp = 0 is bare ground/not vegetated 
+       PFT ityp = 0 is a valid ityp even though bare ground is not a "true" PFT, and all gridded output PFT fields skip this ityp
+       PFT ityp = 1 is Needleleaf evergreen temperate tree (the first true PFT)
+       PFT ityp = 14 is C4 grass is often the last natural PFT
+
+       ELMv3 control has natpft = 17 and...
+       :ipft_c3_crop = 15 ;
+       :ipft_c3_irrigated = 16 ;
+       PFT ityp = 15 is C3 crop
+       PFT ityp = 16 is C3 irrigated, last "natural PFT"
+
+       Eva h2 file has natpft = 15 and...
+       :cft_c3_crop = 1 ;
+       :cft_c3_irrigated = 2 ;
+
+       Our output gridded datasets use the C-convention and are zero-based
+       Hence our output PFT element 0 represents PFT ityp 1 == Needleleaf evergreen temperate tree
+       We accomplish this by adding 1 to pft_idx in call to nco_pft_typ_sng() */
+    for(pft_idx=0;pft_idx<pft_ntr_max;pft_idx++){
+      if(fl_out_fmt == NC_FORMAT_NETCDF4){
+	pft_sng_out[pft_idx]=nco_pft_typ_sng(pft_idx+1);
+      }else{
+	strcpy(pft_chr_out+pft_idx*pft_sng_lng_out,nco_pft_typ_sng(pft_idx+1));
+      } /* !fl_out_fmt */
+    } /* !pft_idx */
+    /* Restart files enumerate all (natural and crop) PFTs in global attributes
+       History files enumerate only crop PFTs (i.e., CFTs) in global attributes */
+    char *cft_nm_crr=NULL; /* [sng] Crop functional type descriptor */
+    for(pft_idx=pft_ntr_max;pft_idx<pft_nbr_out;pft_idx++){
+      /* Label includes Fortran PFT and CFT ityp so add 1 to pft_idx */
+      cft_nm_crr=(char *)strdup("PFT ityp %02ld, CFT ityp %02ld");
+      sprintf(cft_nm_crr,cft_nm_crr,pft_idx+1,pft_idx+1-pft_ntr_max);
+      if(fl_out_fmt == NC_FORMAT_NETCDF4){
+	pft_sng_out[pft_idx]=cft_nm_crr;
+      }else{
+	strcpy(pft_chr_out+pft_idx*pft_sng_lng_out,cft_nm_crr);
+      } /* !fl_out_fmt */
+    } /* !pft_idx */
+    if(fl_out_fmt == NC_FORMAT_NETCDF4){
+      rcd+=nco_def_var(out_id,pft_nm_out,NC_STRING,dmn_nbr_1D,dmn_ids_out,&pft_out_id);
+    }else{
+      rcd+=nco_def_var(out_id,pft_nm_out,NC_CHAR,dmn_nbr_2D,dmn_ids_out,&pft_out_id);
+    } /* !fl_out_fmt */
+    var_crt_nbr++;
+    rcd=nco_char_att_put(out_id,pft_nm_out,"long_name","PFT Descriptor");
+    rcd=nco_char_att_put(out_id,pft_nm_out,"note","Storage uses C (0-based indexing) convention and does not include space for PFT ityp 0 == bare ground/not vegetated. Thus PFT ityp is one more than the storage index. For example, storage index 0 is PFT ityp 1 == Needleleaf evergreen temperate tree. Often the last natural PFT is ityp 14 == C4 grass, although sometimes it is ityp 16 == C3 irrigated. The presence of crop PFTs (i.e., CFTs) in data fields is indicated by an extended PFT type index whose enumeration is sequential with natural PFTs. Often the first crop is c3_crop with PFT ityp 15 and CFT ityp = 1, although sometimes it is corn with PFT ityp 17 and CFT ityp = 1. The last CFT ityp is the total PFT dimension size minus the number of natural PFTs.");
+
+#if false    
+    char att_nm[NC_MAX_NAME+1L]; /* [sng] Attribute name */
+    int att_glb_nbr; /* [nbr] Number of global attributes */
+    rcd=nco_inq(in_id,(int *)NULL,(int *)NULL,&att_glb_nbr,(int *)NULL);
+    (void)fprintf(stdout,"%s: DEBUG att_glb_nbr = %d\n",nco_prg_nm_get(),att_glb_nbr);
+    int att_idx;
+    long att_sz;
+    nc_type att_typ;
+
+    char cft_xpr[]="cft_";
+    char pft_xpr[]="ipft_";
+    char *cft_ptr=NULL;
+    char *pft_ptr=NULL;
+    char *cft_crr=NULL;
+    char *pft_crr=NULL;
+    int cft_nbr_crr=0; /* [nbr] Current number of CFT attributes read */
+    int pft_nbr_crr=0; /* [nbr] Current number of PFT attributes read */
+    for(att_idx=0;att_idx<att_glb_nbr;att_idx++){
+      rcd=nco_inq_attname(in_id,NC_GLOBAL,att_idx,att_nm);
+      rcd=nco_inq_att(in_id,NC_GLOBAL,att_nm,&att_typ,&att_sz);
+      if(flg_nm_hst){
+	if((cft_ptr=strcasestr(att_nm,cft_xpr))){
+	  cft_nbr_crr++;
+	  /* Add four to eliminate the "cft_" portion of the attribute name */
+	  cft_crr=(char *)strdup(cft_ptr+4);
+	  pft_idx=pft_ntr_nbr_in-2+cft_nbr_crr;
+	  if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: DEBUG %s reports cft_nbr_crr = %d, pft_idx = %d, cft_crr = %s\n",nco_prg_nm_get(),fnc_nm,cft_nbr_crr,pft_idx,cft_crr);
+	  if(fl_out_fmt == NC_FORMAT_NETCDF4){
+	    if(pft_idx >= 0) pft_sng_out[pft_idx]=cft_crr;
+	  }else{
+	    if(pft_idx >= 0) strcpy(pft_chr_out+pft_idx*pft_sng_lng_out,cft_crr);
+	  } /* !fl_out_fmt */
+	} /* !cft_ptr */
+      } /* !flg_nm_hst */
+      if(flg_nm_rst){
+	if((pft_ptr=strcasestr(att_nm,pft_xpr))){
+	  pft_nbr_crr++;
+	  pft_idx=pft_nbr_crr-2;
+	  pft_crr=(char *)strdup(pft_ptr);
+	  if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: DEBUG %s reports pft_nbr_crr = %d, pft_idx = %d, pft_crr = %s\n",nco_prg_nm_get(),fnc_nm,pft_nbr_crr,pft_idx,pft_crr);
+	  if(fl_out_fmt == NC_FORMAT_NETCDF4){
+	    if(pft_idx >= 0) pft_sng_out[pft_idx]=pft_crr;
+	  }else{
+	    if(pft_idx >= 0) strcpy(pft_chr_out+pft_idx*pft_sng_lng_out,pft_crr);
+	  } /* !fl_out_fmt */
+	} /* !pft_ptr */
+      } /* !flg_nm_rst */
+    } /* !att_idx */
+    if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: INFO Read cft_nbr_crr = %d CFT attributes and pft_nbr_crr = %d PFT attributes\n",nco_prg_nm_get(),cft_nbr_crr,pft_nbr_crr);
+#endif /* !false */
+    (void)fflush(stdout);
+  } /* !need_pft */
+  
   double mss_val_dbl;
   double mss_val_cmp_dbl; /* Missing value for comparison to double precision values */
-
+  
   int flg_pck; /* [flg] Variable is packed on disk  */
   int nco_s1d_typ; /* [enm] Sparse-1D type of input variable */
-
+  
   long mrv_idx; /* [idx] MRV index */
-  long mrv_nbr; /* [nbr] Product of sizes of dimensions following (thus MRV) column|gridcell|landunit|pft|topounit dimension, e.g., lev*|numrad */
+  long mrv_nbr; /* [nbr] Product of sizes of dimensions following (thus MRV than) column|gridcell|landunit|pft|topounit dimension, e.g., lev*|numrad */
 
   nco_bool flg_add_spt_crd; /* [flg] Add spatial coordinates to S1D variable */
   nco_bool has_mss_val; /* [flg] Has numeric missing value attribute */
@@ -1194,7 +1384,6 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 	       NB: Not sure where to put the lnd_typ=1 values in gridcells that also have MEC */
 	    idx_s1d_crr=NC_MIN_INT;
 
-	    /* fxm: got to here with topounits */
 	    switch(var_typ_in){
 	    case NC_FLOAT: for(idx_in=0;idx_in<var_sz_in;idx_in++)
 		if(var_val_in.fp[idx_in] != 0.0f && var_val_in.fp[idx_in] != mss_val_cmp_dbl){
@@ -1209,7 +1398,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 		} /* !var_val_in.dp */
 	      break;
 	    case NC_INT: for(idx_in=0;idx_in<var_sz_in;idx_in++)
-		if(var_val_in.ip[idx_in] != 0.0 && var_val_in.ip[idx_in] != mss_val_cmp_dbl){
+		if(var_val_in.ip[idx_in] != 0 && var_val_in.ip[idx_in] != mss_val_cmp_dbl){
 		  idx_s1d_crr=idx_in/mrv_nbr;
 		  break;
 		} /* !var_val_in.ip */
@@ -1219,9 +1408,8 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 	      nco_dfl_case_nc_type_err();
 	      break;
 	    } /* !var_typ_in */
-	      //(void)fprintf(stdout,"%s: DEBUG quark1\n",nco_prg_nm_get());
 	    if(idx_in == var_sz_in){
-	      (void)fprintf(fp_stdout,"%s: INFO %s reports %s has no valid values in input, so will be all missing values in output too...\n",nco_prg_nm_get(),fnc_nm,var_nm);
+	      (void)fprintf(fp_stdout,"%s: INFO %s reports %s has no valid values, output will be all _FillValue\n",nco_prg_nm_get(),fnc_nm,var_nm);
 	      flg_var_mpt=True;
 	    } /* !idx_in */
 	    lnd_typ_crr=NC_MIN_INT;
@@ -1230,8 +1418,8 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 	      case nco_s1d_clm:	lnd_typ_crr=cols1d_ityplun[idx_s1d_crr]; break;
 	      case nco_s1d_lnd:	lnd_typ_crr=land1d_ityplun[idx_s1d_crr]; break;
 	      case nco_s1d_pft:	lnd_typ_crr=pfts1d_ityplun[idx_s1d_crr]; break;
-	      case nco_s1d_tpo:
-	      case nco_s1d_grd:
+	      case nco_s1d_grd: lnd_typ_crr=nco_lnd_ilun_nil; break; /* Gridcell variables may contain multiple landunits */
+	      case nco_s1d_tpo: lnd_typ_crr=nco_lnd_ilun_nil; break; /* Topounit variables may contain multiple landunits */
 	      default: break;
 	      } /* !nco_s1d_typ */
 	      /* Is variable is defined on MECs? */
@@ -1262,7 +1450,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 		  if(val_vld) break;
 		} /* !clm_idx */
 		if(val_vld) has_mec=trv_tbl->lst[idx_tbl].has_mec=True;
-		if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(fp_stdout,"%s: DEBUG %s exited MEC search at mrv_idx = %ld, clm_idx = %ld, idx_in = %ld, has_mec = %d\n",nco_prg_nm_get(),var_nm,mrv_idx,clm_idx,idx_in,has_mec);
+		if(nco_dbg_lvl_get() >= nco_dbg_fl) (void)fprintf(fp_stdout,"%s: DEBUG %s exited MEC search at mrv_idx = %ld, clm_idx = %ld, idx_in = %ld, has_mec = %d\n",nco_prg_nm_get(),var_nm,mrv_idx,clm_idx,idx_in,has_mec);
 	      } /* !nco_s1d_typ */
 	    } /* !idx_s1d_crr */
 	    if(var_val_in.vp) var_val_in.vp=(void *)nco_free(var_val_in.vp);
@@ -1425,6 +1613,13 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   if(need_levgrnd && levgrnd_out_id != NC_MIN_INT) rcd=nco_put_var(out_id,levgrnd_out_id,(void *)levgrnd,NC_DOUBLE);
   if(need_levlak && levlak_out_id != NC_MIN_INT) rcd=nco_put_var(out_id,levlak_out_id,(void *)levlak,NC_DOUBLE);
   if(need_mec && mec_out_id != NC_MIN_INT) rcd=nco_put_var(out_id,mec_out_id,(void *)mec,NC_DOUBLE);
+  if(need_pft && pft_out_id != NC_MIN_INT){
+    if(fl_out_fmt == NC_FORMAT_NETCDF4){
+      rcd=nco_put_var(out_id,pft_out_id,(void *)pft_sng_out,NC_STRING);
+    }else{
+      rcd=nco_put_var(out_id,pft_out_id,(void *)pft_chr_out,NC_CHAR);
+    } /* !fl_out_fmt */
+  } /* !need_pft */
 
   /* Free pre-allocated array space */
   if(dmn_ids_in) dmn_ids_in=(int *)nco_free(dmn_ids_in);
@@ -1442,8 +1637,8 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   long lvl_idx; /* [idx] Level index */
   long lvl_nbr; /* [nbr] Number of levels */
 
-  //size_t val_in_fst; /* [nbr] Number of elements by which current N-D slab input values are offset from origin */
-  //size_t val_out_fst; /* [nbr] Number of elements by which current N-D slab output values are offset from origin */
+  size_t val_in_fst; /* [nbr] Number of elements by which current N-D slab input values are offset from origin */
+  size_t val_out_fst; /* [nbr] Number of elements by which current N-D slab output values are offset from origin */
 
   if(idx_dbg == 0L) idx_dbg=11;
   if(nco_dbg_lvl_get() >= nco_dbg_var){
@@ -1537,10 +1732,24 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 	  if(nco_dbg_lvl_get() >= nco_dbg_fl) (void)fprintf(fp_stdout,"%s: INFO define block for %s dmn_idx = %d, dmn_id = %d, mrv_nbr = %ld\n",nco_prg_nm_get(),var_nm,dmn_idx,dmn_id,mrv_nbr);
 	} /* !dmn_idx */
 	
-	/* Compute number and size of non-lat/lon or non-col dimensions (e.g., level, time, species, wavelength)
+	for(dmn_idx=0;dmn_idx<dmn_nbr_out;dmn_idx++){
+	  rcd=nco_inq_dimlen(out_id,dmn_ids_out[dmn_idx],dmn_cnt_out+dmn_idx);
+	  if(dmn_cnt_out[dmn_idx] == 0L){
+	    /* No records have been written, so overwrite zero output record size with input record size */
+	    char dmn_rec_nm[NC_MAX_NAME]; /* [sng] Record dimension name */
+	    int dmn_rec_id_in;
+	    rcd=nco_inq_dimname(out_id,dmn_ids_out[dmn_idx],dmn_rec_nm);
+	    rcd=nco_inq_dimid(in_id,dmn_rec_nm,&dmn_rec_id_in);
+	    rcd=nco_inq_dimlen(in_id,dmn_rec_id_in,dmn_cnt_out+dmn_idx);
+	  } /* !dmn_cnt_out */
+	  var_sz_out*=dmn_cnt_out[dmn_idx];
+	  dmn_srt[dmn_idx]=0L;
+	} /* !dmn_idx */
+
+	/* Compute number and size of non-lat/lon or non-col dimensions (e.g., level, time, crop species, wavelength)
 	   Denote their convolution by level or 'lvl' for shorthand
 	   There are lvl_nbr elements for each lat/lon or col position
-	   Dimensions CLM/ELM dimensions that count in "lvl_nbr" include all lev* dimensions, time, numrad */
+	   ELM/CLM dimensions that count in "lvl_nbr" include all lev* dimensions, time, numrad */
 	lvl_nbr=1L;
 	/* Restart files are generally ordered (column|gridcell|landunit|pft|topounit,lev*|numrad)
 	   Restart files unroll the MEC dimension into the column dimension
@@ -1550,8 +1759,9 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 	   
 	   History files are generally ordered (time,lev*,[column|pft]|[lat,lon|lndgrid])
 	   Most history file fields contain MRV horizontal spatial dimensions
-	   However Beth Drewniak's beth_in.nc fields have no horizontal spatial dimensions,
-	   and place lev* as LRV (like normal history fields) not MRV (like normal "vanilla" restart files) */
+	   However Beth Drewniak's beth_in.nc fields and Eva Sinha's eva_h2.nc/eva_h3.nc fields have no horizontal spatial dimensions,
+	   and place lev* as LRV (like normal history fields) not MRV (like normal "vanilla" restart files)
+	   Examples of such fields include AR(time,pft), GPP(time,pft) */
 	if(flg_nm_hst)
 	  for(dmn_idx=0;dmn_idx<dmn_nbr_out-dmn_nbr_hrz_crd;dmn_idx++)
 	    lvl_nbr*=dmn_cnt_out[dmn_idx];
@@ -1559,19 +1769,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 	  for(dmn_idx=0;dmn_idx<dmn_nbr_out-dmn_nbr_hrz_crd;dmn_idx++)
 	    lvl_nbr*=1L;
 
-	for(dmn_idx=0;dmn_idx<dmn_nbr_out;dmn_idx++){
-	  rcd=nco_inq_dimlen(out_id,dmn_ids_out[dmn_idx],dmn_cnt_out+dmn_idx);
-	  if(dmn_cnt_out[dmn_idx] == 0L){
-	    /* No records have been written, so overwrite zero output record size with input record size */
-	    char dmn_rec_nm[NC_MAX_NAME]; /* [sng] Record dimension name */
-	    int dmn_rec_id_in;
-	    rcd=nco_inq_dimname(out_id,dmn_ids_out[dmn_idx],dmn_rec_nm);
-	    rcd=nco_inq_dimid(in_id,dmn_rec_nm,&dmn_rec_id_in);
-	    rcd=nco_inq_dimlen(in_id,dmn_rec_id_in,dmn_cnt_out+dmn_idx);
-	  } /* !dmn_cnt_out */
-	  var_sz_out*=dmn_cnt_out[dmn_idx];
-	  dmn_srt[dmn_idx]=0L;
-	} /* !dmn_idx */
+	if(nco_dbg_lvl_get() >= nco_dbg_fl) (void)fprintf(stdout,"%s: DEBUG %s lvl_nbr = %ld\n",nco_prg_nm_get(),var_nm,lvl_nbr);
 
 	var_val_in.vp=(void *)nco_malloc_dbg(var_sz_in*nco_typ_lng(var_typ_in),fnc_nm,"Unable to malloc() input value buffer");
 	var_val_out.vp=(void *)nco_malloc_dbg(var_sz_out*nco_typ_lng(var_typ_out),fnc_nm,"Unable to malloc() output value buffer");
@@ -1654,6 +1852,11 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 	nco_s1d_typ=nco_s1d_nil;
 	for(dmn_idx=0;dmn_idx<dmn_nbr_in;dmn_idx++){
 	  dmn_id=dmn_ids_in[dmn_idx];
+	  /* 20241017: A note of caution
+	     This loop overrides the first s1d_typ encountered with the second (if any) encountered
+	     History variables, e.g., float PCT_LANDUNIT(time,ltype,topounit), can contain both landunit and topounit dimensions
+	     However, in such cases the input landunit dimension uses the gridded name "ltype" not the S1D name "landunit"
+	     That should prevent mistakes in confusing s1d_lnd with s1d_tpo variables */
 	  if(dmn_id == dmn_id_clm_in) nco_s1d_typ=nco_s1d_clm;
 	  else if(dmn_id == dmn_id_grd_in) nco_s1d_typ=nco_s1d_grd;
 	  else if(dmn_id == dmn_id_lnd_in) nco_s1d_typ=nco_s1d_lnd;
@@ -1680,7 +1883,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 	    } /* !var_val_in.dp */
 	  break;
 	case NC_INT: for(idx_in=0;idx_in<var_sz_in;idx_in++)
-	    if(var_val_in.ip[idx_in] != 0.0 && var_val_in.ip[idx_in] != mss_val_cmp_dbl){
+	    if(var_val_in.ip[idx_in] != 0 && var_val_in.ip[idx_in] != mss_val_cmp_dbl){
 	      idx_s1d_crr=idx_in/mrv_nbr;
 	      break;
 	    } /* !var_val_in.ip */
@@ -1697,7 +1900,8 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 	  case nco_s1d_clm: lnd_typ_crr=cols1d_ityplun[idx_s1d_crr]; break;
 	  case nco_s1d_lnd: lnd_typ_crr=land1d_ityplun[idx_s1d_crr]; break;
 	  case nco_s1d_pft: lnd_typ_crr=pfts1d_ityplun[idx_s1d_crr]; break;
-	  case nco_s1d_grd:
+	  case nco_s1d_grd: lnd_typ_crr=nco_lnd_ilun_nil; break; /* Gridcell variables may contain multiple landunits */
+	  case nco_s1d_tpo: lnd_typ_crr=nco_lnd_ilun_nil; break; /* Topounit variables may contain multiple landunits */
 	  default: break;
 	  } /* !nco_s1d_typ */
 	} /* !idx_s1d_crr */
@@ -1718,20 +1922,24 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 	  for(lvl_idx=0;lvl_idx<lvl_nbr;lvl_idx++){
 	    /* PFT variable dimension ordering, from LRV to MRV:
 	       Restart input: PFT, lev*|numrad, e.g., T_REF2M_MIN_INST(pft), fabd_sun(pft,numrad), tlai_z(pft,levcan)
-	       History input: time, PFT, lev*|numrad, spatial
-	       NCO Output   : time, PFT, lev*|numrad, spatial */
+	       History input: time, PFT, lev*|numrad, horizontal
+	       NCO Output   : time, PFT, lev*|numrad, horizontal */
 	    for(pft_idx=0;pft_idx<pft_nbr_in;pft_idx++){
 
 	      pft_typ=pfts1d_ityp_veg[pft_idx]; /* [1 <= pft_typ <= pft_nbr_out] */
-	      /* Skip bare ground so output array contains only vegetated types */
+
+	      /* Skip bare ground so output array contains only vegetated types
+		 20241016: Allow bare ground so output PFT dimension size is natpft instead of natpft-1? */
 	      if(!pft_typ) continue;
 
 	      /* grd_idx is 0-based index relative to the origin of the horizontal grid, pfts1d is 1-based
 		 [0 <= grd_idx_out <= col_nbr_out-1L], [1 <= pfts1d_ixy <= col_nbr_out]
-		 Storage order for history fields (Beth's GPP, anyway) is lon,lat
+		 Storage for Beth's GPP is lon,lat (20241014: I think this was true, but deleted the dataset to test it)
+		 Storage for Eva's GPP and h2 history fields lat,lon (20241014: verified)
+		 20241014: Difference between Beth's and Eva's GPP makes me worry that history field storage order convention changes
 		 Storage order for restart fields (e.g., DZSNO) is lat,lon */
-	      if(flg_nm_hst) grd_idx_out= flg_grd_1D ? pfts1d_ixy[pft_idx]-1L : (pfts1d_ixy[pft_idx]-1L)*lat_nbr+(pfts1d_jxy[pft_idx]-1L);
-	      if(flg_nm_rst) grd_idx_out= flg_grd_1D ? pfts1d_ixy[pft_idx]-1L : (pfts1d_jxy[pft_idx]-1L)*lon_nbr+(pfts1d_ixy[pft_idx]-1L);
+	      //if(flg_nm_hst) grd_idx_out= flg_grd_1D ? pfts1d_ixy[pft_idx]-1L : (pfts1d_ixy[pft_idx]-1L)*lat_nbr+(pfts1d_jxy[pft_idx]-1L);
+	      if(flg_nm_hst || flg_nm_rst) grd_idx_out= flg_grd_1D ? pfts1d_ixy[pft_idx]-1L : (pfts1d_jxy[pft_idx]-1L)*lon_nbr+(pfts1d_ixy[pft_idx]-1L);
 
 	      for(mrv_idx=0;mrv_idx<mrv_nbr;mrv_idx++){
 		/* Recall that lev*|numrad are MRV in restart input, and are LRV in output where lev*|numrad precedes column,[lat,lon|lndgrid] */
@@ -1760,25 +1968,28 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 	  /* Turn TS_TOPO(topounit) into TS_TOPO(lndgrid) or TS_TOPO(lat,lon)
 	     20240131: This curently works only for single-timestep files
 	     In general, must enclose this in outer loop over (time x level) */
+	  val_in_fst=0L;
+	  val_out_fst=0L;
 	  for(lvl_idx=0;lvl_idx<lvl_nbr;lvl_idx++){
 	    /* Topounit variable dimension ordering, from LRV to MRV:
 	       Restart input: topounit, e.g., TS_TOPO(topounit)
-	       History input: N/A
-	       NCO Output   : time, spatial */
+	       History input: time, ltype, topounit, e.g., PCT_LANDUNIT(time,ltype,topounit), PCT_NAT_PFT(time,natpft,topounit)
+	       NCO Output   : time, horizontal */
 	    for(tpo_idx=0;tpo_idx<tpo_nbr_in;tpo_idx++){
 
 	      /* grd_idx is 0-based index relative to the origin of the horizontal grid, topo1d is 1-based
 		 [0 <= grd_idx_out <= col_nbr_out-1L], [1 <= topo1d_ixy <= col_nbr_out]
-		 Storage order for history fields is N/A
-		 Storage order for restart fields (e.g., TS_TOPO is lat,lon */
-	      if(flg_nm_hst) grd_idx_out= flg_grd_1D ? topo1d_ixy[tpo_idx]-1L : (topo1d_ixy[tpo_idx]-1L)*lat_nbr+(topo1d_jxy[tpo_idx]-1L);
-	      if(flg_nm_rst) grd_idx_out= flg_grd_1D ? topo1d_ixy[tpo_idx]-1L : (topo1d_jxy[tpo_idx]-1L)*lon_nbr+(topo1d_ixy[tpo_idx]-1L);
+		 Storage order for history fields (e.g., PCT_LANDUNIT, PCT_NAT_PFT) is lat,lon 
+		 Storage order for restart fields (e.g., TS_TOPO) is lat,lon */
+	      // if(flg_nm_hst) grd_idx_out= flg_grd_1D ? topo1d_ixy[tpo_idx]-1L : (topo1d_ixy[tpo_idx]-1L)*lat_nbr+(topo1d_jxy[tpo_idx]-1L);
+	      grd_idx_out= flg_grd_1D ? topo1d_ixy[tpo_idx]-1L : (topo1d_jxy[tpo_idx]-1L)*lon_nbr+(topo1d_ixy[tpo_idx]-1L);
 
 	      for(mrv_idx=0;mrv_idx<mrv_nbr;mrv_idx++){
 		/* Recall that lev*|numrad are MRV in restart input, and are LRV in output where lev*|numrad precedes column,[lat,lon|lndgrid] */
 		if(flg_nm_hst) idx_in=tpo_idx;
 		if(flg_nm_rst) idx_in=tpo_idx*mrv_nbr+mrv_idx;
-		idx_out=grd_idx_out;
+		idx_in=val_in_fst+idx_in;
+		idx_out=val_out_fst+grd_idx_out;
 		switch(var_typ_out){
 		case NC_FLOAT: var_val_out.fp[idx_out]=var_val_in.fp[idx_in]; break;
 		case NC_DOUBLE: var_val_out.dp[idx_out]=var_val_in.dp[idx_in]; break;
@@ -1790,6 +2001,8 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 		} /* !var_typ_out */
 	      } /* !mrv_idx */
 	    } /* !tpo_idx */
+	    val_in_fst+=tpo_nbr_in;
+	    val_out_fst+=grd_sz_out;
 	  } /* !lvl_idx */
 	} /* !nco_s1d_tpo */
 	
@@ -1800,8 +2013,8 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
 
 	  /* MEC variable dimension ordering, from LRV to MRV:
 	     Restart input: MEC, lev*, e.g., DZSNO(column,levsno), H2OSOI_ICE(column,levtot), T_SOISNO(column,levtot), ZSNO(column,levsno), flx_absdn(column,levsno1), qflx_snofrz_lyr(column,levsno), snw_rds(column,levsno)
-	     History input: time, lev*, spatial, e.g., SNO_BW(time,levsno,lat,lon)
-	     NCO Output   : time, MEC, lev*, spatial
+	     History input: time, lev*, horizontal, e.g., SNO_BW(time,levsno,lat,lon)
+	     NCO Output   : time, MEC, lev*, horizontal
 	     ncks --trd -C -d column,0,11 -v DZSNO,cols1d_gridcell_index ${DATA}/bm/elm_mali_rst.nc | m */
 	  mec_idx=0;
 	  if(nco_dbg_lvl_get() >= nco_dbg_fl) (void)fprintf(fp_stdout,"%s: INFO unpack block for %s clm_nbr = %ld, mec_nbr = %ld, mrv_nbr = %ld\n",nco_prg_nm_get(),var_nm,clm_nbr_in,(has_mec) ? mec_nbr_out : 0,mrv_nbr);
@@ -1904,7 +2117,7 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
     } /* !xtr */
   } /* end (OpenMP parallel for) loop over idx_tbl */
   if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"\n");
-  if(nco_dbg_lvl_get() >= nco_dbg_fl) (void)fprintf(stdout,"%s: INFO %s completion report: Variables interpolated = %d, copied unmodified = %d, omitted = %d, created = %d\n",nco_prg_nm_get(),fnc_nm,var_rgr_nbr,var_cpy_nbr,var_xcl_nbr,var_crt_nbr);
+  if(nco_dbg_lvl_get() >= nco_dbg_fl) (void)fprintf(stdout,"%s: INFO %s completion report: Variables unpacked = %d, copied unmodified = %d, omitted = %d, created = %d\n",nco_prg_nm_get(),fnc_nm,var_rgr_nbr,var_cpy_nbr,var_xcl_nbr,var_crt_nbr);
 
   /* Free output data memory */
   if(cols1d_active) cols1d_active=(int *)nco_free(cols1d_active);
@@ -1932,6 +2145,9 @@ nco_s1d_unpack /* [fnc] Unpack sparse-1D CLM/ELM variables into full file */
   if(grd_nm_out) grd_nm_out=(char *)nco_free(grd_nm_out);
   if(lnd_nm_out) lnd_nm_out=(char *)nco_free(lnd_nm_out);
   if(pft_nm_out) pft_nm_out=(char *)nco_free(pft_nm_out);
+  if(pft_chr_out) pft_chr_out=(char *)nco_free(pft_chr_out);
+  if(pft_sng_out) pft_sng_out=(nco_string *)nco_free(pft_sng_out);
+  if(pft_sng_lng_nm_out) pft_sng_lng_nm_out=(char *)nco_free(pft_sng_lng_nm_out);
   if(tpo_nm_out) tpo_nm_out=(char *)nco_free(tpo_nm_out);
 
   if(levcan_nm_in) levcan_nm_in=(char *)nco_free(levcan_nm_in);


=====================================
src/nco/nco_s1d.h
=====================================
@@ -75,6 +75,9 @@ extern "C" {
 
   /* Types used in landunit structure */
   typedef enum nco_pft_typ_enm{ /* [enm] Landunit type enum */
+    /* NB: This structure is kind of useless because it is user-defined
+       Restart files enumerate all PFTs in global attributes
+       History files enumerate only crop PFTs (i.e., CFTs) in global attributes */
     nco_pft_ipft_not_vegetated=0, /* Not vegetated */
     nco_pft_ipft_needleleaf_evergreen_temperate_tree=1, /* Needleleaf evergreen temperate tree */
     nco_pft_ipft_needleleaf_evergreen_boreal_tree=2, /* Needleleaf evergreen boreal tree */
@@ -90,27 +93,23 @@ extern "C" {
     nco_pft_ipft_c3_arctic_grass=12, /* C3 Arctic grass */
     nco_pft_ipft_c3_non_arctic_grass=13, /* C3 non-Arctic grass */
     nco_pft_ipft_c4_grass=14, /* C4 grass */
+    /* 20241017: ELMv3 includes C3 crop and irrigated in natpft dimension (natpft=17)
+       Previously, AFAIK, ELM datasets always had natpft=15
+       Also Eva h2, h3 history files still have natpft=15
+       These final two enumerates are not accessed unless natpft >= 17 */
     nco_pft_ipft_c3_crop=15, /* C3 crop */
     nco_pft_ipft_c3_irrigated=16, /* C3 irrigated */
-    nco_pft_ipft_corn=17, /* Corn */
-    nco_pft_ipft_irrigated_corn=18, /* Irrigated corn */
-    nco_pft_ipft_spring_temperate_cereal=19, /* Spring temperate cereal */
-    nco_pft_ipft_irrigated_spring_temperate_cereal=20, /* Irrigated spring temperate cereal */
-    nco_pft_ipft_winter_temperate_cereal=21, /* Winter temperate cereal */
-    nco_pft_ipft_irrigated_winter_temperate_cereal=22, /* Irrigated winter temperate cereal */
-    nco_pft_ipft_soybean=23, /* Soybean */
-    nco_pft_ipft_irrigated_soybean=24, /* Irrigated soybean */
   } nco_pft_typ_enm;
 
   /* Types used in Sparse-1D structure */
   typedef enum nco_s1d_typ_enm{ /* [enm] Sparse-1D type enum */
-    nco_s1d_nil=0,
-    nco_s1d_unk, /* Unknown or unclassified sparse-type */
-    nco_s1d_clm, /* Sparse-1D Column (cols1d) format */
-    nco_s1d_grd, /* Sparse-1D Gridcell (grid1d) format */
-    nco_s1d_lnd, /* Sparse-1D Landunit (land1d) format */
-    nco_s1d_pft, /* Sparse-1D PFT (pfts1d) format */
-    nco_s1d_tpo, /* Sparse-1D Topounit (topo1d) format */
+    nco_s1d_nil=0, /* Unset sparse-type */
+    nco_s1d_unk=1, /* Unknown or unclassified sparse-type */
+    nco_s1d_clm=2, /* Sparse-1D Column (cols1d) format */
+    nco_s1d_grd=3, /* Sparse-1D Gridcell (grid1d) format */
+    nco_s1d_lnd=4, /* Sparse-1D Landunit (land1d) format */
+    nco_s1d_pft=5, /* Sparse-1D PFT (pfts1d) format */
+    nco_s1d_tpo=6, /* Sparse-1D Topounit (topo1d) format */
   } nco_s1d_typ_enm;
 
   const char * /* O [sng] String describing column type */
@@ -121,7 +120,7 @@ extern "C" {
   nco_lnd_typ_sng /* [fnc] Convert landunit type enum to string */
   (const int nco_lnd_typ); /* I [enm] Landunit type enum */
 
-  const char * /* O [sng] String describing PFT type */
+  char * /* O [sng] String describing PFT type */
   nco_pft_typ_sng /* [fnc] Convert PFT-type enum to string */
   (const int nco_pft_typ); /* I [enm] PFT type enum */
 


=====================================
src/nco/nco_scm.c
=====================================
@@ -210,7 +210,7 @@ nco_nmn_get(void) /* [fnc] Return mnemonic that describes current NCO version */
   /* Purpose: Return mnemonic describing current NCO version
      20191221: ncremap/ncclimo print left quote and first word of this string, so one-word strings look best
      20200117: fixed this limitation, multi-word versions work fine */
-  return "Sitton Peak";
+  return "Empathy Card";
 } /* !nco_nmn_get() */
 
 void


=====================================
src/nco/nco_sng_utl.c
=====================================
@@ -406,7 +406,7 @@ nm_cf_chk /* [fnc] Check that variable/dimension/attribute name is CF-compliant
       /* First character must be alphabetic */
       if(isalpha(chr_crr)) continue;
       /* netCDF library-defined attributes with leading underscores are only exceptions allowed to above rule */
-      if(flg_ndr && !strcmp(nm,"_FillValue"))
+      if(flg_ndr && !strcmp(nm,NC_FillValue))
 	continue;
     }else if(idx_chr > 0){
       /* Remaining characters must be alphanumeric or underscores */


=====================================
src/nco/nco_var_utl.c
=====================================
@@ -81,7 +81,7 @@ nco_cpy_var_val /* [fnc] Copy variable from input to output file, no limits */
   } /* end loop over dim */
 
   /* Allocate enough space to hold variable */
-  void_ptr=(void *)nco_malloc_dbg(var_sz*nco_typ_lng(var_typ),"Unable to malloc() value buffer when copying hyperslab from input to output file",fnc_nm);
+  void_ptr=(void *)nco_malloc_dbg(var_sz*nco_typ_lng(var_typ),fnc_nm,"Unable to malloc() value buffer when copying hyperslab from input to output file");
 
   /* 20150114: Keep PPC code in single block for easier reuse */
   int ppc=NC_MAX_INT; /* [nbr] Precision-preserving compression, i.e., number of sig. digits/bits */



View it on GitLab: https://salsa.debian.org/debian-gis-team/nco/-/compare/cce52fb1e803f545eb9aa92566e5add513445705...8b9587567b6db613170b14ca76849f278bd183a4

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/nco/-/compare/cce52fb1e803f545eb9aa92566e5add513445705...8b9587567b6db613170b14ca76849f278bd183a4
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20241019/71062d5f/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list