source: TOOLS/CMIP6_FORCING/OZONE/tools.bash @ 3847

Last change on this file since 3847 was 3847, checked in by cugnet, 6 years ago

Simplifications and extensions for clims_CMIP6.bash:

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