[3847] | 1 | function parse_dir { |
---|
[3870] | 2 | # Syntax: parse_dir <dir> <dir_struct> [<patch1 ... patchN>] |
---|
| 3 | # $1: directory to parse |
---|
| 4 | # $2: directory structure |
---|
| 5 | # [$3...]: <dset>:<var>=<val> patches |
---|
| 6 | # Purpose: parse directory <dir> with structure <dir_struct> and export all variables. |
---|
| 7 | # If $dataset = $dset, the value of <var> obtain with parsing is replaced with <val>. |
---|
| 8 | local d s |
---|
| 9 | d=$1; shift; s=$1; shift |
---|
[3847] | 10 | while :; do |
---|
[3870] | 11 | $(eval echo "export ${s%%/*}=${d%%/*}") |
---|
[3847] | 12 | s=${s#*/}; d=${d#*/} |
---|
| 13 | if [ "$s" = "${s#*/}" ]; then break; fi |
---|
| 14 | done |
---|
[3870] | 15 | while [ $# -ge 1 ]; do if [ $dataset = ${1%:*} ]; then eval export ${1#*:}; fi; shift; done |
---|
| 16 | unset d s |
---|
[3847] | 17 | } |
---|
| 18 | #================================================================================== |
---|
[3870] | 19 | function replace_1 { |
---|
| 20 | # $1: string $2: <patch>=<replacement string> |
---|
| 21 | local out=$1 |
---|
| 22 | while [ "${out%${2%=*}*}" != "$out" ]; do out=${out%${2%=*}*}"${2#*=}"${out##*${2#=*}*}; done |
---|
| 23 | echo $out; unset out; return 0 |
---|
| 24 | } |
---|
| 25 | #================================================================================== |
---|
| 26 | function replace { |
---|
| 27 | # same as "replace_1", but with several <patch>=<replacement string> arguments. |
---|
| 28 | local out=$1; shift |
---|
| 29 | while [ $# -ne 0 ]; do out=$(replace_1 $out "$1"); shift; done |
---|
| 30 | echo $out; unset out; return 0 |
---|
| 31 | } |
---|
| 32 | #================================================================================== |
---|
[3847] | 33 | function addc { |
---|
[3870] | 34 | local s="$1"; while [ ${#s} -lt $2 ]; do s="_$s"; done ; echo "$s"; unset s |
---|
[3847] | 35 | } |
---|
| 36 | #================================================================================== |
---|
| 37 | function progress_bar { |
---|
| 38 | # $1: iteration $2: iterations number $3: length of the bar |
---|
| 39 | local n bar |
---|
| 40 | bar=`echo "scale=1 ; (100*$1)/$2" | bc` |
---|
| 41 | bar="`addc "$bar" 5`% [" |
---|
| 42 | n=`echo "scale=0 ; ($3*$1)/$2" | bc` |
---|
| 43 | if [ $n -ne 0 ]; then bar="$bar"`eval "printf '='%.0s {1..$n}"`; fi |
---|
| 44 | n=$(($3-$n)) |
---|
| 45 | if [ $n -ne 0 ]; then bar="$bar"`eval "printf '.'%.0s {1..$n}"`']\r'; fi |
---|
| 46 | echo -ne $bar; if [ $2 -eq $1 ]; then echo; fi |
---|
| 47 | unset n bar |
---|
| 48 | } |
---|
| 49 | #================================================================================== |
---|
| 50 | function extract { |
---|
| 51 | # Input arguments: |
---|
| 52 | # $1: v_in,v_ou (input/output variable names) |
---|
| 53 | # $2: f_in,f_ou (input/output files names) |
---|
| 54 | # $3: Ymin,Ymax,dY (min/max available years, years/file number) |
---|
| 55 | # $4: nmrg (number of additional months before and after) |
---|
| 56 | # |
---|
| 57 | # Purpose: |
---|
| 58 | # * Extract year $Y for variable $v_in from files $f_in containing data from |
---|
| 59 | # $Ymin to $Ymax, where each input file contains $dY years |
---|
| 60 | # * Outputs are stored in file $f_ou, and variable renamed $v_ou. |
---|
| 61 | # * Optionally, add before/after the 12 months the $nmrg previous/next months. |
---|
| 62 | # - Y=Ymin (missing Ymin-1) => $nmrg last months of year $Y used instead. |
---|
| 63 | # - Y=Ymax (missing Ymax+1) => $nmrg first months of year $Y used instead. |
---|
| 64 | # |
---|
| 65 | # Remark: First record of first file has to be january $Ymin. |
---|
| 66 | # |
---|
| 67 | local v_in v_ou d_in f_ou Ymin Ymax Yb Ye Y dY nbm nmrg it fin fou fm ff fp ib ie |
---|
| 68 | v_in="${1%%,*}"; v_ou="${1#*,}"; shift |
---|
| 69 | f_in="${1%%,*}"; f_ou="${1#*,}"; shift |
---|
| 70 | Ymin="${1%%,*}"; Ymax="${1#*,}"; dY="${Ymax#*,}"; Ymax="${Ymax%%,*}"; shift |
---|
| 71 | Y=$1; shift; if [ $# -eq 1 ]; then nmrg=$1; else nmrg=0; fi |
---|
| 72 | if [ $dY -eq $((Ymax-Ymin+1)) ]; then dY=0; fi #--- SINGLE FILE |
---|
| 73 | ff=actu_${v_in}_${Y}.nc; fm=""; fp="" |
---|
| 74 | #--- INITIAL AND FINAL YEAR OF FILE CONTAINING CURRENT YEAR |
---|
| 75 | if [ $dY -eq 0 ]; then |
---|
| 76 | Yb=$Ymin; Ye=$Ymax |
---|
| 77 | else |
---|
| 78 | Yb=$((dY*(Y/dY))); Ye=$((Yb+dY-1)); Ye=$(($Ye>$Ymax?$Ymax:$Ye)) |
---|
| 79 | fi |
---|
| 80 | nbm=$((12*(Ye-Yb+1)-1)) #--- MONTHS NUMBER OF CURRENT FILE |
---|
| 81 | it=$((12*(Y-Yb))) #--- JANUARY INDEX IN CURRENT FILE |
---|
| 82 | fin=`var=$v_in; Yb=$Yb; Ye=$Ye; eval echo $f_in` #--- CURRENT FILE NAME |
---|
| 83 | fou=`var=$v_ou; Y=$Y; eval echo $f_ou` #--- OUTPUT FILE NAME |
---|
| 84 | ib=$(($it<=nmrg?0:$((it-nmrg)))) #--- INDEX OF FIRST USED MONTH |
---|
| 85 | ie=$(($((it+11+mrg))>=$nbm?$nbm:$((it+11+nmrg)))) #--- INDEX OF LAST USED MONTHF |
---|
| 86 | rm -f $ff ; rm -f $ff ; ncks -d time,$ib,$ie $fin $ff |
---|
| 87 | #--- MISSING PREVIOUS YEAR LAST MONTHS => CURRENT YEAR INSTEAD |
---|
| 88 | if [ $it -lt $nmrg ]; then fm="prev_${v_in}_${Y}.nc"; rm -f $fm |
---|
| 89 | if [[ $Y -eq $Ymin || $dY -eq 0 ]]; then ncks -d time,$((it-nmrg+12)),11 $fin $fm |
---|
| 90 | else Yb=$((dY*((Y-1)/dY))); Ye=$((Yb+dY-1)); Ye=$(($Ye>$Ymax?$Ymax:$Ye)) |
---|
| 91 | ncks -d time,$((12*(Ye-Yb+1)-nmrg+it)),$((12*(Ye-Yb+1)-1)) `var=$v_in; Yb=$Yb; Ye=$Ye; eval echo $f_in` $fm |
---|
| 92 | fi |
---|
| 93 | fi |
---|
| 94 | #--- MISSING FOLLOWING YEAR FIRST MONTHS => CURRENT YEAR INSTEAD |
---|
| 95 | if [ $((it+nmrg+11)) -gt $nbm ]; then fp="next_${v_in}_${Y}.nc"; rm -f $fp |
---|
| 96 | if [[ $Y -eq $Ymax || $dY -eq 0 ]]; then ncks -d time,$((nbm-11)),$((it+nmrg-1)) $fin $fp |
---|
| 97 | else Yb=$((dY*((Y+1)/dY))); Ye=$((Yb+dY-1)); Ye=$(($Ye>$Ymax?$Ymax:$Ye)) |
---|
| 98 | ncks -d time,0,$((nmrg-1)) `var=$v_in; Yb=$Yb; Ye=$Ye; eval echo $f_in` $fp |
---|
| 99 | fi |
---|
| 100 | fi |
---|
| 101 | if [ ! -d ${fou%/*} ]; then mkdir -p ${fou%/*}; fi |
---|
| 102 | if [[ "$fm" != "" || "$fp" != "" ]]; then |
---|
| 103 | rm -f $fou ; ncrcat $fm $ff $fp $fou ; rm -f $fm $ff $fp |
---|
| 104 | else |
---|
| 105 | mv $ff $fou |
---|
| 106 | fi |
---|
| 107 | if [ "$v_in" != "$v_ou" ]; then |
---|
| 108 | ncrename -v $v_in,$v_ou $fou > /dev/null 2>&1 |
---|
| 109 | fi |
---|
| 110 | } |
---|
| 111 | #================================================================================== |
---|
| 112 | function make_clim { |
---|
| 113 | # Input arguments: |
---|
| 114 | # $1: variable name $2: input files name |
---|
| 115 | # $3: beg-end years $4: index for january (optional, starting from 0) |
---|
| 116 | # |
---|
| 117 | # Purpose: |
---|
| 118 | # Create a 12 months climatology for a variable using 1-year monthly files. |
---|
| 119 | # |
---|
| 120 | # Remark: |
---|
| 121 | # Files with additional months are usable if the index for january is given (default: 0) |
---|
| 122 | # |
---|
| 123 | local f_ou f0 Yb Ye ib ie M MM |
---|
| 124 | Yb="${3%%-*}"; Ye="${3#*-}" |
---|
| 125 | if [ $# -eq 4 ]; then ib=$4; else ib=0; fi; ie=$((ib+11)) #=== INDEX $ib FOR JANUARY |
---|
| 126 | for M in $(eval echo {$ib..$ie}); do |
---|
| 127 | MM=$((M+1-ib)); if [ $MM -le 9 ]; then MM=0$MM; fi |
---|
| 128 | for Y in `eval echo {${Yb}..${Ye}}`; do |
---|
| 129 | f_ou=$(var=$1; Y=$Y; eval echo $2) |
---|
| 130 | rm -f ${1}_$Y$MM.nc ; ncks -d time,$M $(var=$1; Y=$Y; eval echo $f_ou) ${1}_$Y$MM.nc |
---|
| 131 | done |
---|
| 132 | rm -f ${1}_$MM.nc ; ncra ${1}_????$MM.nc ${1}_$MM.nc ; rm -f ${1}_????$MM.nc |
---|
| 133 | progress_bar $((M+1-ib)) $((ie-ib+1)) 50 |
---|
| 134 | done |
---|
| 135 | f_ou=$(var=$1; Y=${Yb}_${Ye}_clim; eval echo $2) |
---|
[3870] | 136 | if [ ! -p ${f_ou%/*} ]; then mkdir -p ${f_ou%/*}; fi |
---|
[3847] | 137 | rm -f $f_ou ; ncrcat ${1}_??.nc $f_ou ; rm -f ${1}_??.nc |
---|
| 138 | f0=`var=$1; Y='YYYY'; eval echo $2`; f0=$(var=$1; Y='YYYY'; eval echo $f0); f0=${f0##*/} |
---|
| 139 | ncatted -a comment,global,a,c,"\nClimatology from $Yb to $Ye using file(s) $f0" $f_ou |
---|
| 140 | } |
---|
| 141 | #================================================================================== |
---|
| 142 | function str2ascii() { |
---|
| 143 | LC_CTYPE=C printf '%d' "'$1" |
---|
| 144 | } |
---|
| 145 | |
---|
| 146 | #================================================================================== |
---|
| 147 | function deblank { |
---|
| 148 | #--- REMOVE UNEXPECTED CHARACTERS (IN PARTICULAR THOSE WEIRD ASCII(0) CHARS) |
---|
| 149 | local a |
---|
| 150 | a=$1; while [ `str2ascii ${a:0:1}` -lt 32 ]; do a=${a:1:${#a}}; done; echo $a |
---|
| 151 | } |
---|
| 152 | |
---|
| 153 | #================================================================================== |
---|
| 154 | function dim_nam { |
---|
| 155 | #--- GET DIMENSION $2 (X/Y/Z/T) NAME FOR FILE $1 |
---|
| 156 | #--- SPECIAL CASE: RETURN 'Seasons' IF "$2" = "S". |
---|
| 157 | local a v Units |
---|
| 158 | case $2 in |
---|
| 159 | X) Units='degrees_east degree_east degree_e degrees_e "degrees east" "degree east" degreee degreese' ;; |
---|
| 160 | Y) Units='degrees_north degree_north degree_n degrees_n "degrees north" "degree north" degreen degreesn' ;; |
---|
| 161 | Z) Units='pa pascal pascals hpa millibar millibars mbar mbars mb bar bars atm atms atmosphere atmospheres' ;; |
---|
| 162 | T) Units=' since' ;; |
---|
| 163 | S) echo Seasons; return 0 ;; |
---|
| 164 | *) echo "error in dim_nam: unrecognized axis $2"; return 1 ;; |
---|
| 165 | esac |
---|
| 166 | for u in $Units; do |
---|
| 167 | case $2 in |
---|
| 168 | X|Y|Z) a=`ncdump -h $1 | grep -i ':units = "'"$u"'"'` ;; |
---|
| 169 | T) a=`ncdump -h $1 | grep -i $u | grep ':units = "'` ;; |
---|
| 170 | esac |
---|
| 171 | if [ "$a" != "" ]; then |
---|
| 172 | if [ "$2" = "Z" ]; then v=${a%%:*}; v=`deblank $v` |
---|
| 173 | if [ "`ncdump -h $1 | grep -i "$v($v)"`" != "" ]; then break; fi |
---|
| 174 | else break |
---|
| 175 | fi |
---|
| 176 | fi |
---|
| 177 | done |
---|
| 178 | if [[ "$a" = "" && "$2" = "Z" ]]; then a=`ncdump -h $1 | grep -i ':positive = "'`; fi |
---|
| 179 | if [ "$a" = "" ]; then echo "error in dim_nam: unable to recognize axis $2"; return 1; fi |
---|
| 180 | echo ${a%%:*}; return 0 |
---|
| 181 | } |
---|
| 182 | |
---|
| 183 | #================================================================================== |
---|
| 184 | function test_var { |
---|
| 185 | # Input arguments: |
---|
| 186 | # $1: file name $2: variable name |
---|
| 187 | ncdump -h $1 | grep "double $2" > /dev/null; if [ $? -eq 0 ]; then return 0; fi |
---|
| 188 | ncdump -h $1 | grep "float $2" > /dev/null; return $? |
---|
| 189 | } |
---|
| 190 | #================================================================================== |
---|
| 191 | function get_boundsvar { |
---|
| 192 | # Input arguments: |
---|
| 193 | # $1: file name $2: variable name |
---|
| 194 | local a=$(ncdump -h $1 | grep -P "\t$2:bounds") |
---|
| 195 | if [ "$a" != "${a#*\"}" ]; then a=${a#*\"}; echo ${a%\"*}; else echo ""; fi |
---|
| 196 | } |
---|
| 197 | #================================================================================== |
---|
| 198 | function rename_bounds { |
---|
| 199 | # Input arguments: |
---|
| 200 | # $1: file name $2: variable name $3: new variable name |
---|
| 201 | # returns: $old_var,$old_boundvar,$new_boundvar |
---|
| 202 | local vin=$(get_boundsvar $1 $2) beg end vou |
---|
| 203 | if [ "$vin" = "" ]; then return 1; fi |
---|
| 204 | beg=${vin##*$2}; if [ "$beg" = "$vin" ]; then beg=$vin; fi |
---|
| 205 | beg=${vin%%$2*}; if [ "$end" = "$vin" ]; then end=$vin; fi |
---|
| 206 | if [[ "$beg" = "" && "$end" = "" ]]; then return 1; fi |
---|
| 207 | vou=$beg$3$end |
---|
| 208 | echo "$2,$vin,$vou" |
---|
| 209 | } |
---|
| 210 | #================================================================================== |
---|
| 211 | function rename_dims { |
---|
| 212 | # Input arguments: |
---|
| 213 | # $1: file name $2...: <axis>:<target_name> (axis=X,Y,Z or T) |
---|
| 214 | # |
---|
| 215 | # Purpose: |
---|
| 216 | # Rename dimensions, dimensional variables. |
---|
| 217 | # In case of boundary grid variables with bounds_<variable> names are available, |
---|
| 218 | # they are renamed together with the corresponding "bounds" attributes. |
---|
| 219 | local vio f=$1 att="" ren="" nam_in nam_ou |
---|
| 220 | shift |
---|
| 221 | while [ $# -ge 1 ]; do |
---|
| 222 | nam_ou=${1##*:}; nam_in=$(dim_nam $f ${1%:*}); shift |
---|
| 223 | if [ "$nam_in" != "$nam_ou" ]; then |
---|
| 224 | ren="$ren -d $nam_in,$nam_ou -v $nam_in,$nam_ou" |
---|
| 225 | #--- CHECK WETHER "bounds" ATTRIBUTE IS THERE |
---|
| 226 | vio="$(rename_bounds $f $nam_in $nam_ou)" |
---|
| 227 | if [ "$vio" != "" ]; then |
---|
| 228 | att="$att -a bounds,$nam_ou,m,c,${vio##*,}"; ren="$ren -v ${vio#*,}" |
---|
| 229 | fi |
---|
| 230 | fi |
---|
| 231 | done |
---|
| 232 | if [ "$ren" != "" ]; then ncrename $ren $f 2>&1 > /dev/null ; fi |
---|
| 233 | if [ "$att" != "" ]; then ncatted $att $f 2>&1 > /dev/null ; fi |
---|
| 234 | } |
---|
| 235 | #================================================================================== |
---|
| 236 | function zonal_mean { |
---|
| 237 | # Input arguments: |
---|
| 238 | # $1: input file $2: output file |
---|
| 239 | local tmp=tmp.$$.nc |
---|
[3870] | 240 | if [ ! -d ${2%/*} ]; then mkdir -p ${2%/*}; fi |
---|
[3847] | 241 | ncwa -a longitude $1 $tmp ; mv $tmp $2 #--- Zonal mean |
---|
| 242 | ncks -O -x -v longitude $2 $tmp ; mv $tmp $2 #--- Remove longitude |
---|
| 243 | v="bounds_longitude"; test_var $2 $v #--- Remove bounds vars |
---|
| 244 | if [ $? -eq 0 ]; then ncks -O -x -v $v $2 $tmp ; mv $tmp $2; fi |
---|
| 245 | } |
---|
| 246 | #================================================================================== |
---|
| 247 | function get_date { |
---|
| 248 | # Assumes the following filename structure: *_${Yb}*-${Ye}*.* (Yb/e: 4 digits) |
---|
[3870] | 249 | # $1: varname |
---|
| 250 | # $2: datatype |
---|
| 251 | # $3: dirin |
---|
| 252 | # $4: dirin structure patch |
---|
| 253 | # $5...$N: files_in |
---|
| 254 | # [$N+1...]: <dset>:<var>=<val> to overwrite value of variables evaluated from parsing. |
---|
| 255 | local v_in dtyp d_in dstr f_in Yb Ye St a f first date dates files_in="" |
---|
| 256 | v_in=$1; shift; dtyp=$1; shift; d_in=$1; shift; dstr=$1; shift; f0=$1 |
---|
| 257 | while [ "$1" = "${1##*=}" ]; do files_in="$files_in $1"; shift; done |
---|
| 258 | for f_in in $files_in; do date=$(get_date_1 $v_in $dtyp $d_in $dstr $f_in $*) |
---|
| 259 | if [ $f_in = $f0 ]; then dates=$date; else dates="$dates $date"; fi |
---|
[3847] | 260 | done |
---|
| 261 | echo $dates |
---|
| 262 | } |
---|
| 263 | #================================================================================== |
---|
[3870] | 264 | function get_date_1 { |
---|
| 265 | # Assumes the following filename structure: *_${Yb}*-${Ye}*.* (Yb/e: 4 digits) |
---|
| 266 | # $1: varname |
---|
| 267 | # $2: datatype |
---|
| 268 | # $3: base directory for files |
---|
| 269 | # $4: dirin structure patch |
---|
| 270 | # $5: file_in |
---|
| 271 | # [$6...]: <dset>:<var>=<val> to overwrite value of variables evaluated from parsing. |
---|
| 272 | local v_in dtyp d_in d_str f_in Yb Ye St a f first |
---|
| 273 | v_in=$1; shift; dtyp=$1; shift; d_in=$1; shift; dstr=$1; shift; f_in=$1; shift |
---|
| 274 | parse_dir $f_in $dstr $*; Yb=1000000; Ye=0; first='t' |
---|
| 275 | for f in $(var=$v_in; Yb=????; Ye=????; datatype=$dtyp; eval ls $d_in/$f_in); do |
---|
| 276 | a=${f##*_}; if [ ${a::4} -le $Yb ]; then Yb=${a::4}; fi |
---|
| 277 | a=${a##*-}; if [ ${a::4} -ge $Ye ]; then Ye=${a::4}; fi |
---|
| 278 | if [ $first = 't' ]; then St=$((Ye-Yb+1)); first='f'; fi |
---|
| 279 | done |
---|
| 280 | echo $Yb-$Ye-$St |
---|
| 281 | } |
---|
| 282 | #================================================================================== |
---|
[3847] | 283 | function dim_len { |
---|
| 284 | local n |
---|
| 285 | if [ "$2" = "T" ]; then |
---|
| 286 | n=$(ncdump -h $1 | grep 'UNLIMITED'); n=${n#*// (}; echo ${n% currently*} |
---|
| 287 | else |
---|
| 288 | n=$(ncdump -h $1 | grep $2' = '); n=${n#* = }; echo ${n% ;*} |
---|
| 289 | fi |
---|
| 290 | } |
---|
| 291 | #================================================================================== |
---|
| 292 | function get_grid { |
---|
| 293 | # $1: filename $2: varname |
---|
| 294 | X=$(dim_nam $1 X); if [ $? -ne 0 ]; then X=""; else lX=$(dim_len $1 $X); fi |
---|
| 295 | Y=$(dim_nam $1 Y); if [ $? -ne 0 ]; then Y=""; else lY=$(dim_len $1 $Y); fi |
---|
| 296 | Z=$(dim_nam $1 Z); if [ $? -ne 0 ]; then Z=""; else lZ=$(dim_len $1 $Z); fi |
---|
| 297 | T=$(dim_nam $1 T); if [ $? -ne 0 ]; then T=""; else lT=$(dim_len $1 T); fi |
---|
| 298 | t=$(ncdump -h $1 | grep "double $2") |
---|
| 299 | if [ $? -ne 0 ]; then t=$(ncdump -h $1 | grep "float $2"); fi |
---|
| 300 | t=${t##*$2(}; t=${t%)*}; g=""; r="" |
---|
| 301 | while :; do s=${t##*, }; t=${t%,*} |
---|
| 302 | case $s in |
---|
| 303 | $X) g=${g}X; r=${r}x$lX ;; |
---|
| 304 | $Y) g=${g}Y; r=${r}x$lY ;; |
---|
| 305 | $Z) g=${g}Z; r=${r}x$lZ ;; |
---|
| 306 | $T) g=${g}T; r=${r}x$lT ;; |
---|
| 307 | esac |
---|
| 308 | if [ "$s" = "$t" ]; then break; fi |
---|
| 309 | done |
---|
| 310 | echo $g=${r:1:${#r}} |
---|
| 311 | } |
---|
| 312 | #================================================================================== |
---|
| 313 | |
---|