function parse_dir { # Syntax: parse_dir [] # $1: directory to parse # $2: directory structure # [$3...]: := patches # Purpose: parse directory with structure and export all variables. # If $dataset = $dset, the value of obtain with parsing is replaced with . local d s d=$1; shift; s=$1; shift while :; do $(eval echo "export ${s%%/*}=${d%%/*}") s=${s#*/}; d=${d#*/} if [ "$s" = "${s#*/}" ]; then break; fi done while [ $# -ge 1 ]; do if [ $dataset = ${1%:*} ]; then eval export ${1#*:}; fi; shift; done unset d s } #================================================================================== function replace_1 { # $1: string $2: = local out=$1 while [ "${out%${2%=*}*}" != "$out" ]; do out=${out%${2%=*}*}"${2#*=}"${out##*${2#=*}*}; done echo $out; unset out; return 0 } #================================================================================== function replace { # same as "replace_1", but with several = arguments. local out=$1; shift while [ $# -ne 0 ]; do out=$(replace_1 $out "$1"); shift; done echo $out; unset out; return 0 } #================================================================================== function addc { local s="$1"; while [ ${#s} -lt $2 ]; do s="_$s"; done ; echo "$s"; unset s } #================================================================================== function progress_bar { # $1: iteration $2: iterations number $3: length of the bar local n bar bar=`echo "scale=1 ; (100*$1)/$2" | bc` bar="`addc "$bar" 5`% [" n=`echo "scale=0 ; ($3*$1)/$2" | bc` if [ $n -ne 0 ]; then bar="$bar"`eval "printf '='%.0s {1..$n}"`; fi n=$(($3-$n)) if [ $n -ne 0 ]; then bar="$bar"`eval "printf '.'%.0s {1..$n}"`']\r'; fi echo -ne $bar; if [ $2 -eq $1 ]; then echo; fi unset n bar } #================================================================================== function extract { # Input arguments: # $1: v_in,v_ou (input/output variable names) # $2: f_in,f_ou (input/output files names) # $3: Ymin,Ymax,dY (min/max available years, years/file number) # $4: nmrg (number of additional months before and after) # # Purpose: # * Extract year $Y for variable $v_in from files $f_in containing data from # $Ymin to $Ymax, where each input file contains $dY years # * Outputs are stored in file $f_ou, and variable renamed $v_ou. # * Optionally, add before/after the 12 months the $nmrg previous/next months. # - Y=Ymin (missing Ymin-1) => $nmrg last months of year $Y used instead. # - Y=Ymax (missing Ymax+1) => $nmrg first months of year $Y used instead. # # Remark: First record of first file has to be january $Ymin. # 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 v_in="${1%%,*}"; v_ou="${1#*,}"; shift f_in="${1%%,*}"; f_ou="${1#*,}"; shift Ymin="${1%%,*}"; Ymax="${1#*,}"; dY="${Ymax#*,}"; Ymax="${Ymax%%,*}"; shift Y=$1; shift; if [ $# -eq 1 ]; then nmrg=$1; else nmrg=0; fi if [ $dY -eq $((Ymax-Ymin+1)) ]; then dY=0; fi #--- SINGLE FILE ff=actu_${v_in}_${Y}.nc; fm=""; fp="" #--- INITIAL AND FINAL YEAR OF FILE CONTAINING CURRENT YEAR if [ $dY -eq 0 ]; then Yb=$Ymin; Ye=$Ymax else Yb=$((Ymin+dY*((Y-Ymin)/dY))); Ye=$((Yb+dY-1)) Ye=$(($Ye>$Ymax?$Ymax:$Ye)) fi nbm=$((12*(Ye-Yb+1)-1)) #--- MONTHS NUMBER OF CURRENT FILE it=$((12*(Y-Yb))) #--- JANUARY INDEX IN CURRENT FILE fin=`var=$v_in; Yb=$Yb; Ye=$Ye; eval echo $f_in` #--- CURRENT FILE NAME fou=`var=$v_ou; Y=$Y; eval echo $f_ou` #--- OUTPUT FILE NAME ib=$(($it<=nmrg?0:$((it-nmrg)))) #--- INDEX OF FIRST USED MONTH ie=$(($((it+11+mrg))>=$nbm?$nbm:$((it+11+nmrg)))) #--- INDEX OF LAST USED MONTHF rm -f $ff ; rm -f $ff ; ncks -d time,$ib,$ie $fin $ff #--- MISSING PREVIOUS YEAR LAST MONTHS => CURRENT YEAR INSTEAD if [ $it -lt $nmrg ]; then fm="prev_${v_in}_${Y}.nc"; rm -f $fm if [[ $Y -eq $Ymin || $dY -eq 0 ]]; then ncks -d time,$((it-nmrg+12)),11 $fin $fm else Yb=$((dY*((Y-1)/dY))); Ye=$((Yb+dY-1)); Ye=$(($Ye>$Ymax?$Ymax:$Ye)) 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 fi fi #--- MISSING FOLLOWING YEAR FIRST MONTHS => CURRENT YEAR INSTEAD if [ $((it+nmrg+11)) -gt $nbm ]; then fp="next_${v_in}_${Y}.nc"; rm -f $fp if [[ $Y -eq $Ymax || $dY -eq 0 ]]; then ncks -d time,$((nbm-11)),$((it+nmrg-1)) $fin $fp else Yb=$((dY*((Y+1)/dY))); Ye=$((Yb+dY-1)); Ye=$(($Ye>$Ymax?$Ymax:$Ye)) ncks -d time,0,$((nmrg-1)) `var=$v_in; Yb=$Yb; Ye=$Ye; eval echo $f_in` $fp fi fi if [ ! -d ${fou%/*} ]; then mkdir -p ${fou%/*}; fi if [[ "$fm" != "" || "$fp" != "" ]]; then rm -f $fou ; ncrcat $fm $ff $fp $fou ; rm -f $fm $ff $fp else mv $ff $fou fi if [ "$v_in" != "$v_ou" ]; then ncrename -v $v_in,$v_ou $fou > /dev/null 2>&1 fi } #================================================================================== function make_clim { # Input arguments: # $1: variable name $2: input files name # $3: beg-end years $4: index for january (optional, starting from 0) # # Purpose: # Create a 12 months climatology for a variable using 1-year monthly files. # # Remark: # Files with additional months are usable if the index for january is given (default: 0) # local f_ou f0 Yb Ye ib ie M MM Yb="${3%%-*}"; Ye="${3#*-}" if [ $# -eq 4 ]; then ib=$4; else ib=0; fi; ie=$((ib+11)) #=== INDEX $ib FOR JANUARY for M in $(eval echo {$ib..$ie}); do MM=$((M+1-ib)); if [ $MM -le 9 ]; then MM=0$MM; fi for Y in `eval echo {${Yb}..${Ye}}`; do f_ou=$(var=$1; Y=$Y; eval echo $2) rm -f ${1}_$Y$MM.nc ; ncks -d time,$M $(var=$1; Y=$Y; eval echo $f_ou) ${1}_$Y$MM.nc done rm -f ${1}_$MM.nc ; ncra ${1}_????$MM.nc ${1}_$MM.nc ; rm -f ${1}_????$MM.nc progress_bar $((M+1-ib)) $((ie-ib+1)) 50 done f_ou=$(var=$1; Y=${Yb}_${Ye}_clim; eval echo $2) if [ ! -p ${f_ou%/*} ]; then mkdir -p ${f_ou%/*}; fi rm -f $f_ou ; ncrcat ${1}_??.nc $f_ou ; rm -f ${1}_??.nc f0=`var=$1; Y='YYYY'; eval echo $2`; f0=$(var=$1; Y='YYYY'; eval echo $f0); f0=${f0##*/} ncatted -a comment,global,a,c,"\nClimatology from $Yb to $Ye using file(s) $f0" $f_ou } #================================================================================== function str2ascii() { LC_CTYPE=C printf '%d' "'$1" } #================================================================================== function deblank { #--- REMOVE UNEXPECTED CHARACTERS (IN PARTICULAR THOSE WEIRD ASCII(0) CHARS) local a a=$1; while [ `str2ascii ${a:0:1}` -lt 32 ]; do a=${a:1:${#a}}; done; echo $a } #================================================================================== function dim_nam { #--- GET DIMENSION $2 (X/Y/Z/T) NAME FOR FILE $1 #--- SPECIAL CASE: RETURN 'Seasons' IF "$2" = "S". local a v Units case $2 in X) Units='degrees_east degree_east degree_e degrees_e "degrees east" "degree east" degreee degreese' ;; Y) Units='degrees_north degree_north degree_n degrees_n "degrees north" "degree north" degreen degreesn' ;; Z) Units='pa pascal pascals hpa millibar millibars mbar mbars mb bar bars atm atms atmosphere atmospheres' ;; T) Units=' since' ;; S) echo Seasons; return 0 ;; *) echo "error in dim_nam: unrecognized axis $2"; return 1 ;; esac for u in $Units; do case $2 in X|Y|Z) a=`ncdump -h $1 | grep -i ':units = "'"$u"'"'` ;; T) a=`ncdump -h $1 | grep -i $u | grep ':units = "'` ;; esac if [ "$a" != "" ]; then if [ "$2" = "Z" ]; then v=${a%%:*}; v=`deblank $v` if [ "`ncdump -h $1 | grep -i "$v($v)"`" != "" ]; then break; fi else break fi fi done if [[ "$a" = "" && "$2" = "Z" ]]; then a=`ncdump -h $1 | grep -i ':positive = "'`; fi if [ "$a" = "" ]; then echo "error in dim_nam: unable to recognize axis $2"; return 1; fi echo ${a%%:*}; return 0 } #================================================================================== function test_var { # Input arguments: # $1: file name $2: variable name ncdump -h $1 | grep "double $2" > /dev/null; if [ $? -eq 0 ]; then return 0; fi ncdump -h $1 | grep "float $2" > /dev/null; return $? } #================================================================================== function get_boundsvar { # Input arguments: # $1: file name $2: variable name local a=$(ncdump -h $1 | grep -P "\t$2:bounds") if [ "$a" != "${a#*\"}" ]; then a=${a#*\"}; echo ${a%\"*}; else echo ""; fi } #================================================================================== function rename_bounds { # Input arguments: # $1: file name $2: variable name $3: new variable name # returns: $old_var,$old_boundvar,$new_boundvar local vin=$(get_boundsvar $1 $2) beg end vou if [ "$vin" = "" ]; then return 1; fi beg=${vin##*$2}; if [ "$beg" = "$vin" ]; then beg=$vin; fi beg=${vin%%$2*}; if [ "$end" = "$vin" ]; then end=$vin; fi if [[ "$beg" = "" && "$end" = "" ]]; then return 1; fi vou=$beg$3$end echo "$2,$vin,$vou" } #================================================================================== function rename_dims { # Input arguments: # $1: file name $2...: : (axis=X,Y,Z or T) # # Purpose: # Rename dimensions, dimensional variables. # In case of boundary grid variables with bounds_ names are available, # they are renamed together with the corresponding "bounds" attributes. local vio f=$1 att="" ren="" nam_in nam_ou shift while [ $# -ge 1 ]; do nam_ou=${1##*:}; nam_in=$(dim_nam $f ${1%:*}); shift if [ "$nam_in" != "$nam_ou" ]; then ren="$ren -d $nam_in,$nam_ou -v $nam_in,$nam_ou" #--- CHECK WETHER "bounds" ATTRIBUTE IS THERE vio="$(rename_bounds $f $nam_in $nam_ou)" if [ "$vio" != "" ]; then att="$att -a bounds,$nam_ou,m,c,${vio##*,}"; ren="$ren -v ${vio#*,}" fi fi done if [ "$ren" != "" ]; then ncrename $ren $f 2>&1 > /dev/null ; fi if [ "$att" != "" ]; then ncatted $att $f 2>&1 > /dev/null ; fi } #================================================================================== function zonal_mean { # Input arguments: # $1: input file $2: output file local tmp=tmp.$$.nc if [ ! -d ${2%/*} ]; then mkdir -p ${2%/*}; fi ncwa -a longitude $1 $tmp ; mv $tmp $2 #--- Zonal mean ncks -O -x -v longitude $2 $tmp ; mv $tmp $2 #--- Remove longitude v="bounds_longitude"; test_var $2 $v #--- Remove bounds vars if [ $? -eq 0 ]; then ncks -O -x -v $v $2 $tmp ; mv $tmp $2; fi } #================================================================================== function get_date { # Call get_date1 one time each input file. # $1: varname $2: datatype $3: dirin $4: patch $5...$N: # [$N+1...]: := to overwrite value of variables evaluated from parsing. local v_in dtyp d_in dstr f_in Yb Ye St a f first date dates files_in="" v_in=$1; shift; dtyp=$1; shift; d_in=$1; shift; dstr=$1; shift; f0=$1 while [ "$1" = "${1##*=}" ]; do files_in="$files_in $1"; shift; done for f_in in $files_in; do date=$(get_date_1 $v_in $dtyp $d_in $dstr $f_in $*) if [ $f_in = $f0 ]; then dates=$date; else dates="$dates $date"; fi done echo $dates } #================================================================================== function get_date_1 { # Assumes the following filename structure: *_${Yb}*-${Ye}*.* (Yb/e: 4 digits) # Returns ${FirstYear}-${LastYear}-${IntervalsLengths} # $1: varname $2: datatype $3: dirin $4: patch $5: # [$6...]: := to overwrite value of variables evaluated from parsing. local v_in dtyp d_in d_str f_in Yb Ye St a f first v_in=$1; shift; dtyp=$1; shift; d_in=$1; shift; dstr=$1; shift; f_in=$1; shift parse_dir $f_in $dstr $*; Yb=1000000; Ye=0; first='t' for f in $(var=$v_in; Yb=????; Ye=????; datatype=$dtyp; eval ls $d_in/$f_in); do a=${f##*_}; ymn=${a::4}; if [ $ymn -le $Yb ]; then Yb=$ymn; fi a=${a##*-}; ymx=${a::4}; if [ $ymx -ge $Ye ]; then Ye=$ymx; fi if [ $first != 't' ]; then St=${St}-; fi; first='f'; St=${St}$((ymx-ymn+1)) done echo $Yb-$Ye-$St } #================================================================================== function dim_len { local n if [ "$2" = "T" ]; then n=$(ncdump -h $1 | grep 'UNLIMITED'); n=${n#*// (}; echo ${n% currently*} else n=$(ncdump -h $1 | grep $2' = '); n=${n#* = }; echo ${n% ;*} fi } #================================================================================== function get_grid { # $1: filename $2: varname X=$(dim_nam $1 X); if [ $? -ne 0 ]; then X=""; else lX=$(dim_len $1 $X); fi Y=$(dim_nam $1 Y); if [ $? -ne 0 ]; then Y=""; else lY=$(dim_len $1 $Y); fi Z=$(dim_nam $1 Z); if [ $? -ne 0 ]; then Z=""; else lZ=$(dim_len $1 $Z); fi T=$(dim_nam $1 T); if [ $? -ne 0 ]; then T=""; else lT=$(dim_len $1 T); fi t=$(ncdump -h $1 | grep "double $2") if [ $? -ne 0 ]; then t=$(ncdump -h $1 | grep "float $2"); fi t=${t##*$2(}; t=${t%)*}; g=""; r="" while :; do s=${t##*, }; t=${t%,*} case $s in $X) g=${g}X; r=${r}x$lX ;; $Y) g=${g}Y; r=${r}x$lY ;; $Z) g=${g}Z; r=${r}x$lZ ;; $T) g=${g}T; r=${r}x$lT ;; esac if [ "$s" = "$t" ]; then break; fi done echo $g=${r:1:${#r}} } #================================================================================== function is_int { # $1: string to be checked set +vx if [[ $1 =~ ^[0-9]+$ ]]; then return 0; else return 1; fi set -vx } #================================================================================== function remove_version { # $1: variable name local out=$1 while `is_int ${out##*-}`; do out=${out%-*}; done; echo $out; return 1 }