File: nccf

package info (click to toggle)
nco 5.3.6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 38,260 kB
  • sloc: ansic: 84,963; cpp: 28,654; sh: 14,071; perl: 5,996; makefile: 2,009; lex: 1,009; python: 127; csh: 40
file content (197 lines) | stat: -rwxr-xr-x 8,790 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/bin/sh

# Purpose: CF-check netCDF3/netCDF4/HDF4/HDF5 files
# Dismember them first if necessary or requested
# Dismembering places each input file group in separate netCDF3 output file 
# Described in NCO User Guide at http://nco.sf.net/nco.html#nccf
# Originally incarnated as ncdismember in NCO 4.3.6, September 2013 
# Re-incarnated with getopt as nccf in NCO 4.5.1, July 2015
# Requirements: NCO 4.3.x+, UNIX shell utilities awk, grep, sed
# Optional: Decker CFchecker https://bitbucket.org/mde_/cfchecker
# Currently handles three checkers:
# NERC http://puma.nerc.ac.uk/cgi-bin/cf-checker.pl
# Decker checker cf
# IOOS checker (unsupported): https://data.ioos.us/compliance
# JPL MCC checker (unsupported, based on IOOS): http://podaac-uat.jpl.nasa.gov/mcc

# Usage:
# nccf -c cf_chk -f fl_in -i drc_in -o drc_out -n nco_opt -v cf_vrs
# where fl_in is input file/URL to check/dismember, drc_in/out are
# input and output directories, respectively
# CF-compliance check is performed by default, unless -c 'no' is given
# Default checker is Decker's cfchecker installed locally
# Specify cf_chk=nerc for smallified uploads to NERC checker
# Option cf_vrs is CF version to check
# Option nco_opt passes straight-through to ncks
# Arguments must not use shell expansion/globbing
# NB: nccf does not clean-up output directory, so user must
# chmod a+x ~/sh/nccf
# Examples:
# nccf ~/nco/data/mdl_1.nc /data/zender/tmp
# nccf http://dust.ess.uci.edu/nco/mdl_1.nc /tmp
# nccf http://thredds-test.ucar.edu/thredds/dodsC/testdods/foo.nc /tmp
# nccf ~/nco/data/mdl_1.nc /data/zender/nco/tmp cf
# nccf ~/nco/data/mdl_1.nc /data/zender/nco/tmp nerc
# nccf ~/nco/data/mdl_1.nc /data/zender/nco/tmp cf 1.3
# nccf ~/nco/data/mdl_1.nc /data/zender/nco/tmp cf 1.5 --fix_rec_dmn=all

# Set script name
spt_nm=`basename ${0}` # [sng] Script name

# Set fonts for legibility
fnt_nrm=`tput sgr0` # Normal
fnt_bld=`tput bold` # Bold
fnt_rvr=`tput smso` # Reverse

# Command-line argument defaults
fl_in="${HOME}/nco/data/mdl_1.nc" # [sng] Input file to dismember/check
drc_in='' # [sng] Input directory
drc_out="${DATA}/nco/tmp" # [sng] Output directory
#cf_chk='dck' # [sng] Checker
cf_chk='nerc' # [sng] Checker
cf_flg='Yes' # [flg] CF-check files?
cf_vrs='1.5' # [sng] Compliance-check this CF version (e.g., '1.5')
opt='' # [flg] Additional ncks options (e.g., '--fix_rec_dmn=all')
# Use single quotes to pass multiple arguments to opt=${5}
# Otherwise arguments would be seen as ${5}, ${6}, ${7} ...

function fnc_usg_prn {
    # Print usage
    printf "\nQuick documentation for ${fnt_bld}${spt_nm}${fnt_nrm} (read script for more thorough explanation)\n\n"
    printf "${fnt_rvr}Basic usage:${fnt_nrm} ${fnt_bld}$spt_nm -c cf_chk -f fl_in -o drc_out${fnt_nrm}\n\n"
    echo "Command-line options:"
    echo "${fnt_rvr}-c${fnt_nrm} ${fnt_bld}cf_chk${fnt_nrm}   CF checker to use (empty means none) (default ${fnt_bld}${cf_chk}${fnt_nrm})"
    echo "${fnt_rvr}-d${fnt_nrm} ${fnt_bld}dbg_lvl${fnt_nrm}  Debugging level (default ${fnt_bld}${dbg_lvl}${fnt_nrm})"
    echo "${fnt_rvr}-f${fnt_nrm} ${fnt_bld}fl_in${fnt_nrm}    Input file (default ${fnt_bld}${fl_in}${fnt_nrm})"
    echo "${fnt_rvr}-i${fnt_nrm} ${fnt_bld}drc_in${fnt_nrm}   Input directory ${fnt_bld}drc_in${fnt_nrm} (default ${fnt_bld}${drc_in}${fnt_nrm})"
    echo "${fnt_rvr}-n${fnt_nrm} ${fnt_bld}nco_opt${fnt_nrm}  NCO options (empty means none) (default ${fnt_bld}${nco_opt}${fnt_nrm})"
    echo "${fnt_rvr}-o${fnt_nrm} ${fnt_bld}drc_out${fnt_nrm}  Output directory (default ${fnt_bld}${drc_out}${fnt_nrm})"
    echo "${fnt_rvr}-v${fnt_nrm} ${fnt_bld}cf_vrs${fnt_nrm}   Version of CF to use (default ${fnt_bld}${cf_vrs}${fnt_nrm})"
    printf "\n"
    printf "Examples: ${fnt_bld}$spt_nm -c ${caseid} -s ${yyyy_srt} -e ${yyyy_end} -i ${drc_in} -o ${drc_out} ${fnt_nrm}\n"
    printf "\n\n"
    exit 1
} # end fnc_usg_prn()

# Check argument number and complain accordingly
arg_nbr=$#
#echo -e \\n"dbg: Number of arguments: ${arg_nbr}"
if [ ${arg_nbr} -eq 0 ]; then
  fnc_usg_prn
fi # !arg_nbr

# Parse command-line options:
cmd_ln="${@}"
while getopts :c:d:f:hi:n:o::v: OPT; do
    case ${OPT} in
	c) cf_chk=${OPTARG} ;; # Checker to use
	d) dbg_lvl=${OPTARG} ;; # Debugging level
	f) fl_in=${OPTARG} ;; # Input file 
	i) drc_in=${OPTARG} ;; # Input directory
	n) nco_opt=${OPTARG} ;; # NCO options
	o) drc_out=${OPTARG} ;; # Output directory
	v) cf_vrs=${OPTARG} ;; # CF Version
	h) fnc_usg_prn ;; # Help
	\?) # Unrecognized option
	    echo -e \\n"Option -${fnt_bld}$OPTARG${fnt_nrm} not allowed."
	    fnc_usg_prn ;;
    esac
done
shift $((OPTIND-1)) # Advance one argument

# Derived variables
chk_dck='n'
chk_nrc='n'
if [ ${cf_chk} = 'nerc' ]; then
    chk_nrc='y'
fi # chk_nrc
if [ ${cf_chk} != '0' ] && [ ${cf_chk} != 'nerc' ]; then
    chk_dck='y'
    hash cfchecker 2>/dev/null || { echo >&2 "Local cfchecker command not found, will smallify and upload to NERC checker instead"; chk_nrc='y'; chk_dck='n'; }
fi # !cf_chk

# Print initial state
if [ ${dbg_lvl} -ge 1 ]; then
    printf "dbg: chk_dck  = ${chk_dck}\n"
    printf "dbg: chk_nerc = ${chk_nerc}\n"
    printf "dbg: cf_chk   = ${cf_chk}\n"
    printf "dbg: cf_flg   = ${cf_flg}\n"
    printf "dbg: cf_vrs   = ${cf_vrs}\n"
    printf "dbg: dbg_lvl  = ${dbg_lvl}\n"
    printf "dbg: drc_in   = ${drc_in}\n"
    printf "dbg: drc_out  = ${drc_out}\n"
    printf "dbg: mdl_nm   = ${mdl_nm}\n"
    printf "dbg: nco_opt  = ${nco_opt}\n"
fi # !dbg

# Human-readable summary
echo "Checking and/or dismembering file ${fl_in}"
if [ ${dbg_lvl} -ge 1 ]; then
    printf "${spt_nm} invoked with command:\n"
    echo "${spt_nm} ${cmd_ln}"
fi # !dbg
date_srt=$(date +"%s")
printf "Started at `date`.\n"

# Prepare and move-to output directory
fl_stb=$(basename ${fl_in})
drc_out=${drc_out}/${fl_stb}
mkdir -p ${drc_out}
cd ${drc_out}

# Obtain group list
grp_lst=`ncks --cdl -m ${fl_in} | grep '// group' | awk '{$1=$2=$3="";sub(/^  */,"",$0);print}'`
IFS=$'\n' # Change Internal-Field-Separator from <Space><Tab><Newline> to <Newline>
for grp_in in ${grp_lst} ; do
    # Replace slashes by dots for output group filenames
    grp_out=`echo ${grp_in} | sed 's/\///' | sed 's/\//./g'`
    if [ "${grp_out}" = '' ]; then grp_out='root' ; fi
    # Tell older NCO/netCDF if HDF4 with --hdf4 switch (signified by .hdf/.HDF suffix)
    hdf4=`echo ${fl_in} | awk '{if(match(tolower($1),".hdf$")) hdf4="--hdf4"; print hdf4}'`
    # Flatten to netCDF3, anchor, no history, no temporary file, padding, HDF4 flag, options
    cmd="ncks -O -3 -G : -g ${grp_in}/ -h --no_tmp_fl --hdr_pad=40 ${hdf4} ${opt} ${fl_in} ${drc_out}/${grp_out}.nc"
    # Use eval in case ${opt} contains multiple arguments separated by whitespace
    eval ${cmd}
    if [ ${chk_dck} = 'y' ]; then
       # Decker checker needs Conventions <= 1.6
       no_bck_sls=`echo ${drc_out}/${grp_out} | sed 's/\\\ / /g'`
       ncatted -h -a Conventions,global,o,c,CF-${cf_vrs} ${no_bck_sls}.nc
    else # !chk_dck
       echo ${drc_out}/${grp_out}.nc
    fi # !chk_dck
done
if [ ${chk_dck} = 'y' ]; then
    echo 'Decker CFchecker reports CF-compliance of each group in flat netCDF3 format'
    cfchecker -c ${cf_vrs} *.nc
fi
if [ ${chk_nrc} = 'y' ]; then
    # Smallification and NERC upload from qdcf script by Phil Rasch (PJR)
    echo 'Using remote CFchecker http://puma.nerc.ac.uk/cgi-bin/cf-checker.pl'
    cf_lcn='http://puma.nerc.ac.uk/cgi-bin/cf-checker.pl'
    for fl in ${drc_out}/*.nc ; do
	fl_sml=${fl}
	cf_out=${fl%.nc}.html
	dmns=`ncdump -h ${fl_in} | sed -n -e '/dimensions/,/variables/p' | grep = | sed -e 's/=.*//'`
	hyp_sml=''
	for dmn in ${dmns}; do
	    dmn_lc=`echo ${dmn} | tr "[:upper:]" "[:lower:]"`
	    if [ ${dmn_lc} = 'lat' ] || [ ${dmn_lc} = 'latitude' ] || [ ${dmn_lc} = 'lon' ] || [ ${dmn_lc} = 'longitude' ] || [ ${dmn_lc} = 'time' ]; then
		hyp_sml=`echo ${hyp_sml}" -d ${dmn},0"`
	    fi # !dmn_lc
	done
	# Create small version of input file by sampling only first element of lat, lon, time
	ncks -O ${hyp_sml} ${fl} ${fl_sml}
	# Send small file to NERC checker
	curl --form cfversion=1.6 --form upload=@${fl_sml} --form press="Check%20file" ${cf_lcn} -o ${cf_out}
	# Strip most HTML to improve readability
	cat ${cf_out} | sed -e "s/<[^>]*>//g" -e "/DOCTYPE/,/\]\]/d" -e "s/CF-Convention//g" -e "s/Output of//g" -e "s/Compliance Checker//g" -e "s/Check another//g" -e "s/CF-Checker follows//g" -e "s/Received//g" -e "s/for NetCDF//g" -e "s/NetCDF format//g" -e "s/against CF version 1//g" -e "s/\.\.\.//g"
	echo "Full NERC compliance-check log for ${fl} in ${cf_out}"
    done
fi # !nerc

date_end=$(date +"%s")
printf "Completed climatology generation for model-run ${caseid} at `date`.\n"
date_dff=$((date_end-date_srt))
echo "Elapsed time $((date_dff/60))m$((date_dff % 60))s"

exit 0