|
| 1 | +#!/bin/bash |
| 2 | +# Meteorological Data Processing Workflow |
| 3 | +# Copyright (C) 2022, University of Saskatchewan |
| 4 | +# |
| 5 | +# This file is part of Meteorological Data Processing Workflow |
| 6 | +# |
| 7 | +# This program is free software: you can redistribute it and/or modify |
| 8 | +# it under the terms of the GNU General Public License as published by |
| 9 | +# the Free Software Foundation, either version 3 of the License, or |
| 10 | +# (at your option) any later version. |
| 11 | +# |
| 12 | +# This program is distributed in the hope that it will be useful, |
| 13 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | +# GNU General Public License for more details. |
| 16 | +# |
| 17 | +# You should have received a copy of the GNU General Public License |
| 18 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | + |
| 20 | +# ========================= |
| 21 | +# Credits and contributions |
| 22 | +# ========================= |
| 23 | +# 1. Parts of the code are taken from https://www.shellscript.sh/tips/getopt/index.html |
| 24 | + |
| 25 | + |
| 26 | +# ================ |
| 27 | +# General comments |
| 28 | +# ================ |
| 29 | +# * All variables are camelCased for distinguishing from function names; |
| 30 | +# * function names are all in lower_case with words seperated by underscore for legibility; |
| 31 | +# * shell style is based on Google Open Source Projects' |
| 32 | +# Style Guide: https://google.github.io/styleguide/shellguide.html |
| 33 | + |
| 34 | + |
| 35 | +# =============== |
| 36 | +# Usage Functions |
| 37 | +# =============== |
| 38 | +short_usage() { |
| 39 | + echo "usage: $(basename $0) [-cio DIR] [-v VARS] [-se DATE] [-t CHAR] [-ln REAL,REAL] [-p STR]" |
| 40 | +} |
| 41 | + |
| 42 | + |
| 43 | +# argument parsing using getopt - WORKS ONLY ON LINUX BY DEFAULT |
| 44 | +parsedArguments=$(getopt -a -n wfdei_gem_capa -o i:v:o:s:e:t:l:n:p:c:m: --long dataset-dir:,variables:,output-dir:,start-date:,end-date:,time-scale:,lat-lims:,lon-lims:,prefix:,cache:,ensemble: -- "$@") |
| 45 | +validArguments=$? |
| 46 | +if [ "$validArguments" != "0" ]; then |
| 47 | + short_usage; |
| 48 | + exit 1; |
| 49 | +fi |
| 50 | + |
| 51 | +# check if no options were passed |
| 52 | +if [ $# -eq 0 ]; then |
| 53 | + echo "$(basename $0): ERROR! arguments missing"; |
| 54 | + exit 1; |
| 55 | +fi |
| 56 | + |
| 57 | +# check long and short options passed |
| 58 | +eval set -- "$parsedArguments" |
| 59 | +while : |
| 60 | +do |
| 61 | + case "$1" in |
| 62 | + -i | --dataset-dir) datasetDir="$2" ; shift 2 ;; # required |
| 63 | + -v | --variables) variables="$2" ; shift 2 ;; # required |
| 64 | + -o | --output-dir) outputDir="$2" ; shift 2 ;; # required |
| 65 | + -s | --start-date) startDate="$2" ; shift 2 ;; # required |
| 66 | + -e | --end-date) endDate="$2" ; shift 2 ;; # required |
| 67 | + -t | --time-scale) timeScale="$2" ; shift 2 ;; # redundant - added for compatibility |
| 68 | + -l | --lat-lims) latLims="$2" ; shift 2 ;; # required |
| 69 | + -n | --lon-lims) lonLims="$2" ; shift 2 ;; # required |
| 70 | + -p | --prefix) prefix="$2" ; shift 2 ;; # optional |
| 71 | + -c | --cache) cache="$2" ; shift 2 ;; # required |
| 72 | + -m | --ensemble) ensemble="$2" ; shift 2 ;; # redundant - added for compatibility |
| 73 | + |
| 74 | + # -- means the end of the arguments; drop this, and break out of the while loop |
| 75 | + --) shift; break ;; |
| 76 | + |
| 77 | + # in case of invalid option |
| 78 | + *) |
| 79 | + echo "$(basename $0): ERROR! invalid option '$1'"; |
| 80 | + short_usage; exit 1 ;; |
| 81 | + esac |
| 82 | +done |
| 83 | + |
| 84 | +# raise error in case --ensemble argument are provided |
| 85 | +if [[ -n "$ensemble" ]]; then |
| 86 | + echo "$(basename $0): ERROR! invalid option '--ensemble'" |
| 87 | + exit 1 |
| 88 | +fi |
| 89 | + |
| 90 | +# make array of variable names |
| 91 | +IFS=',' read -ra variablesArr <<< "$(echo "$variables")" |
| 92 | + |
| 93 | +# check the prefix of not set |
| 94 | +if [[ -z $prefix ]]; then |
| 95 | + prefix="data" |
| 96 | +fi |
| 97 | + |
| 98 | + |
| 99 | +# ===================== |
| 100 | +# Necessary Assumptions |
| 101 | +# ===================== |
| 102 | +# TZ to be set to UTC to avoid invalid dates due to Daylight Saving |
| 103 | +alias date='TZ=UTC date' |
| 104 | + |
| 105 | +# expand aliases for the one stated above |
| 106 | +shopt -s expand_aliases |
| 107 | + |
| 108 | + |
| 109 | +# ========================== |
| 110 | +# Necessary Global Variables |
| 111 | +# ========================== |
| 112 | +# the structure of file names is as follows: "%var__WFDEI_GEM_1979_2016.Feb29.nc" |
| 113 | +format="%Y-%m-%dT%H:%M:%S" # date format |
| 114 | +fileStruct="_WFDEI_GEM_1979_2016.Feb29.nc" # source dataset files' suffix constant |
| 115 | + |
| 116 | +latVar="lat" |
| 117 | +lonVar="lon" |
| 118 | +timeVar="time" |
| 119 | + |
| 120 | + |
| 121 | +# =================== |
| 122 | +# Necessary Functions |
| 123 | +# =================== |
| 124 | +# Modules below available on Compute Canada (CC) Graham Cluster Server |
| 125 | +load_core_modules () { |
| 126 | + module -q load cdo/2.0.4 |
| 127 | + module -q load nco/5.0.6 |
| 128 | +} |
| 129 | +load_core_modules |
| 130 | + |
| 131 | + |
| 132 | +####################################### |
| 133 | +# useful one-liners |
| 134 | +####################################### |
| 135 | +#calcualte Unix EPOCH time in seconds from 1970-01-01 00:00:00 |
| 136 | +unix_epoch () { date --date="$@" +"%s"; } |
| 137 | + |
| 138 | +#check whether the input is float or real |
| 139 | +check_real () { if [[ "$1" == *'.'* ]]; then echo 'float'; else echo 'int'; fi; } |
| 140 | + |
| 141 | +#convert to float if the number is 'int' |
| 142 | +to_float () { if [[ $(check_real $1) == 'int' ]]; then printf "%.1f" "$1"; echo; else printf "$1"; echo; fi; } |
| 143 | + |
| 144 | +#join array element by the specified delimiter |
| 145 | +join_by () { local IFS="$1"; shift; echo "$*"; } |
| 146 | + |
| 147 | +#to_float the latLims and lonLims, real numbers delimited by ',' |
| 148 | +lims_to_float () { IFS=',' read -ra l <<< $@; f_arr=(); for i in "${l[@]}"; do f_arr+=($(to_float $i)); done; echo $(join_by , "${f_arr[@]}"); } |
| 149 | + |
| 150 | + |
| 151 | +# =============== |
| 152 | +# Data Processing |
| 153 | +# =============== |
| 154 | +# display info |
| 155 | +echo "$(basename $0): processing CCRN WFDEI-GEM_CaPA..." |
| 156 | + |
| 157 | +# make the output directory |
| 158 | +echo "$(basename $0): creating output directory under $outputDir" |
| 159 | +mkdir -p "$outputDir" |
| 160 | + |
| 161 | +# reformat $startDate and $endDate |
| 162 | +startDateFormated="$(date --date="$startDate" +"$format")" # startDate |
| 163 | +endDateFormated="$(date --date="$endDate" +"$format")" # endDate |
| 164 | + |
| 165 | +# extract $startYear and $endYear |
| 166 | +startYear="$(date --date="$startDate" +"%Y")" |
| 167 | +endYear="$(date --date="$endDate" +"%Y")" |
| 168 | + |
| 169 | +# making the output directory |
| 170 | +mkdir -p "$outputDir" |
| 171 | + |
| 172 | +# loop over variables |
| 173 | +for var in "${variablesArr[@]}"; do |
| 174 | + ncks -O -d "$latVar",$(lims_to_float "$latLims") \ |
| 175 | + -d "$lonVar",$(lims_to_float "$lonLims") \ |
| 176 | + -d "$timeVar","$startDateFormated","$endDateFormated" \ |
| 177 | + "$datasetDir/${var}${fileStruct}" "$outputDir/${prefix}${var}_WFDEI_GEM_${startYear}_${endYear}.Feb29.nc" |
| 178 | + |
| 179 | +done |
| 180 | + |
| 181 | +# wait to assure the loop is over |
| 182 | +wait |
| 183 | + |
| 184 | +echo "$(basename $0): results are produced under $outputDir." |
| 185 | + |
0 commit comments