| 1 | ## Python script to check model outputs within a given set of values from an external ASII file |
|---|
| 2 | # L. Fita, LMD. April 2015 |
|---|
| 3 | ## e.g. # checking_output.py -f histins.nc -v t2m -l 'limitsVariables.inf' |
|---|
| 4 | ## e.g. # python checking_output.py -f limit.nc -v SST,ALB -l 'limitsVariables.inf' |
|---|
| 5 | # NOTE: |
|---|
| 6 | # `nc_var_tools.py' set of python scripts is required |
|---|
| 7 | # can be found in subversion `http://svn.lmd.jussieu.fr/LMDZ_WRF/trunk/tools/nc_var_tools.py' |
|---|
| 8 | import numpy as np |
|---|
| 9 | from netCDF4 import Dataset as NetCDFFile |
|---|
| 10 | import os |
|---|
| 11 | import re |
|---|
| 12 | from optparse import OptionParser |
|---|
| 13 | import nc_var_tools as ncvar |
|---|
| 14 | |
|---|
| 15 | main = 'checking_output.py' |
|---|
| 16 | version = 0.1 |
|---|
| 17 | author = 'L. Fita' |
|---|
| 18 | institution = 'Laboratoire de Meteorologie Dynamique' |
|---|
| 19 | city = ' Paris' |
|---|
| 20 | country = 'France' |
|---|
| 21 | |
|---|
| 22 | errormsg = 'ERROR -- error -- ERROR -- error' |
|---|
| 23 | warnmsg = 'WARNING -- warning -- WARNING -- warning' |
|---|
| 24 | |
|---|
| 25 | fillValue = 1.e20 |
|---|
| 26 | |
|---|
| 27 | def compute_stddev(vals): |
|---|
| 28 | """ Function to compute standard deviation |
|---|
| 29 | vals= values |
|---|
| 30 | """ |
|---|
| 31 | fname = 'compute_stddev' |
|---|
| 32 | |
|---|
| 33 | mvals = np.mean(vals) |
|---|
| 34 | m2vals = np.mean(vals*vals) |
|---|
| 35 | |
|---|
| 36 | stddev = np.sqrt(m2vals - mvals*mvals) |
|---|
| 37 | |
|---|
| 38 | return stddev |
|---|
| 39 | |
|---|
| 40 | def checking(cn,valc,vern,lval,Vn): |
|---|
| 41 | """ Function to check a variable with |
|---|
| 42 | cn= checking name |
|---|
| 43 | valc= value to check |
|---|
| 44 | vern= verification value |
|---|
| 45 | lval= value to use for checking |
|---|
| 46 | Vn= variable name |
|---|
| 47 | """ |
|---|
| 48 | fname = 'checking' |
|---|
| 49 | |
|---|
| 50 | VerN = vern[0:1] |
|---|
| 51 | |
|---|
| 52 | good = True |
|---|
| 53 | if VerN == '<' and valc < lval: |
|---|
| 54 | print warnmsg |
|---|
| 55 | print ' ' + fname + " variable '" + vn + "' has a '" +cn+ "'",valc,vern,lval |
|---|
| 56 | good = False |
|---|
| 57 | elif VerN == '>' and valc > lval: |
|---|
| 58 | print warnmsg |
|---|
| 59 | print ' ' + fname + " variable '" + vn + "' has a '" +cn+ "'",valc,vern,lval |
|---|
| 60 | good = False |
|---|
| 61 | elif VerN == '%' and np.abs((valc-lval)*100./lval)>np.float(vern[1:len(vern)+1]): |
|---|
| 62 | print warnmsg |
|---|
| 63 | print ' ' + fname + " variable '" + vn + "' has a '" +cn+ "'", valc, '>', \ |
|---|
| 64 | VerN, np.float(vern[1:len(vern)+1]), 'than',lval |
|---|
| 65 | good = False |
|---|
| 66 | |
|---|
| 67 | return good |
|---|
| 68 | |
|---|
| 69 | |
|---|
| 70 | ####### ###### ##### #### ### ## # |
|---|
| 71 | |
|---|
| 72 | parser = OptionParser() |
|---|
| 73 | parser.add_option("-f", "--file", dest="ncfile", |
|---|
| 74 | help="file to check", metavar="FILE") |
|---|
| 75 | parser.add_option("-v", "--variable", dest="varns", |
|---|
| 76 | help="var to check (',' list of variables; 'all', for all variables)", metavar="VALUE") |
|---|
| 77 | parser.add_option("-l", "--ASCIIvarlimits", dest="lfile", |
|---|
| 78 | help="ASCII file with the limits for the variables (long explanation with -l h)", metavar="FILE") |
|---|
| 79 | |
|---|
| 80 | (opts, args) = parser.parse_args() |
|---|
| 81 | |
|---|
| 82 | ####### ####### |
|---|
| 83 | ## MAIN |
|---|
| 84 | ####### |
|---|
| 85 | |
|---|
| 86 | # Available statistics |
|---|
| 87 | Availablestats = ['min', 'max', 'mean', 'stddev'] |
|---|
| 88 | LAvailablestats = {'min':'minimum', 'max':'maximum', 'mean':'mean', \ |
|---|
| 89 | 'stddev':'standard deviation'} |
|---|
| 90 | |
|---|
| 91 | Availableverifs = ['<', '>', '%'] |
|---|
| 92 | SAvailableverifs = {'<':'lt', '>':'gt', '%':'percen'} |
|---|
| 93 | LAvailableverifs = {'<':'smaller', '>':'bigger', '%':'percentage'} |
|---|
| 94 | |
|---|
| 95 | ####### |
|---|
| 96 | ofile = 'wrongvariables.nc' |
|---|
| 97 | |
|---|
| 98 | if not os.path.isfile(opts.ncfile): |
|---|
| 99 | print errormsg |
|---|
| 100 | print ' ' + main + ": file '" + opts.ncfile + "' does not exist !!" |
|---|
| 101 | quit(-1) |
|---|
| 102 | |
|---|
| 103 | if opts.varns is None: |
|---|
| 104 | print warnmsg |
|---|
| 105 | print ' ' + main + ": no variables given!!" |
|---|
| 106 | print ' checking all' |
|---|
| 107 | varns = 'all' |
|---|
| 108 | else: |
|---|
| 109 | varns = opts.varns |
|---|
| 110 | |
|---|
| 111 | if opts.lfile is None: |
|---|
| 112 | print warnmsg |
|---|
| 113 | print ' ' + main + ": no ASCII file with limits for the variables is given!!" |
|---|
| 114 | quit(-1) |
|---|
| 115 | elif opts.lfile == 'h': |
|---|
| 116 | print 'HELP: ASCII limits of the variables_____________' |
|---|
| 117 | print 'First line: varname [stat1] [stat2] .... [statn]' |
|---|
| 118 | print 'Second line: - [verif1] [verif2] ... [verifn]' |
|---|
| 119 | print 'afterwards: [varname] [value1] [value2] ... [valuen]' |
|---|
| 120 | print ' [stat]: statistics/parameter to compute. Has to exist wihin the script' |
|---|
| 121 | print ' directly with an if or as function compute[stat]. Available ones are:' |
|---|
| 122 | print ' ',Availablestats |
|---|
| 123 | print ' [verif]: verification to make with the stat' |
|---|
| 124 | print ' <: Error if variable has values smaller than the limit' |
|---|
| 125 | print ' >: Error if variable has values bigger than the limit' |
|---|
| 126 | print ' %N: Error if variable has values +/- N % than the limit' |
|---|
| 127 | quit() |
|---|
| 128 | |
|---|
| 129 | ncobj = NetCDFFile(opts.ncfile, 'r') |
|---|
| 130 | filevars = ncobj.variables.keys() |
|---|
| 131 | |
|---|
| 132 | # Getting variables names |
|---|
| 133 | if varns == 'all': |
|---|
| 134 | vns = filevars |
|---|
| 135 | else: |
|---|
| 136 | vns = opts.varns.split(',') |
|---|
| 137 | |
|---|
| 138 | Nvars = len(vns) |
|---|
| 139 | print "From file '" + opts.ncfile + "' checking",Nvars,'variables...' |
|---|
| 140 | |
|---|
| 141 | # Getting ASCII file and its values |
|---|
| 142 | ## |
|---|
| 143 | # Assuming first line with something like varname min max mean stddev |
|---|
| 144 | # Continuted with a line for each variable and value like: |
|---|
| 145 | # t2m -70. 50. 20. 40. |
|---|
| 146 | # (...) |
|---|
| 147 | # It is required than this script some function called compute_[value] must be placed |
|---|
| 148 | # '#' for comment |
|---|
| 149 | olval = open(opts.lfile, 'r') |
|---|
| 150 | ili = 0 |
|---|
| 151 | statsverif = {} |
|---|
| 152 | limitvals = {} |
|---|
| 153 | |
|---|
| 154 | for line in olval: |
|---|
| 155 | linevals = ncvar.reduce_spaces(line) |
|---|
| 156 | if len(linevals) != 0 and linevals[0][0:0] != '#': |
|---|
| 157 | # print ili,linevals |
|---|
| 158 | if ili == 0: |
|---|
| 159 | NVals = len(linevals) - 1 |
|---|
| 160 | stats = linevals[1:NVals + 1] |
|---|
| 161 | elif ili == 1: |
|---|
| 162 | for ist in range(NVals): |
|---|
| 163 | statsverif[stats[ist]] = linevals[1+ist] |
|---|
| 164 | else: |
|---|
| 165 | limitvals[linevals[0]] = np.zeros((NVals), dtype=np.float) |
|---|
| 166 | for ist in range(NVals): |
|---|
| 167 | limitvals[linevals[0]][ist] = np.float(linevals[1+ist]) |
|---|
| 168 | |
|---|
| 169 | ili = ili + 1 |
|---|
| 170 | |
|---|
| 171 | # Checking stats to compute |
|---|
| 172 | for st in stats: |
|---|
| 173 | if not ncvar.searchInlist(Availablestats,st): |
|---|
| 174 | print errormsg |
|---|
| 175 | print ' ' + main + ": statistics/value '" + st + "' not ready!!" |
|---|
| 176 | print ' available parameters:', Availablestats |
|---|
| 177 | quit(-1) |
|---|
| 178 | |
|---|
| 179 | # Checking verifiaction to make |
|---|
| 180 | for st in stats: |
|---|
| 181 | verin = statsverif[st] |
|---|
| 182 | if not ncvar.searchInlist(Availableverifs,verin[0:1]): |
|---|
| 183 | print errormsg |
|---|
| 184 | print ' ' + main + ": verification '" + verin + "' not ready!!" |
|---|
| 185 | print ' available verifications:', Availableverifs |
|---|
| 186 | quit(-1) |
|---|
| 187 | |
|---|
| 188 | print 'Checking',NVals,'parameters:',stats,'verifyed as:',statsverif.values() |
|---|
| 189 | |
|---|
| 190 | # Creating output file |
|---|
| 191 | oobj = NetCDFFile(ofile, 'w') |
|---|
| 192 | |
|---|
| 193 | # Dimensinos |
|---|
| 194 | newdim = oobj.createDimension('stats', NVals) |
|---|
| 195 | newdim = oobj.createDimension('verif', NVals) |
|---|
| 196 | newdim = oobj.createDimension('checks', 2) |
|---|
| 197 | newdim = oobj.createDimension('Lstring', 50) |
|---|
| 198 | |
|---|
| 199 | # Variables with Dimensions values |
|---|
| 200 | newvar = oobj.createVariable('stats', 'c', ('stats', 'Lstring')) |
|---|
| 201 | newattr = ncvar.basicvardef(newvar, 'stats', 'statistics/parameters used to check', \ |
|---|
| 202 | '-') |
|---|
| 203 | newvals = ncvar.writing_str_nc(newvar, stats, 50) |
|---|
| 204 | |
|---|
| 205 | newvar = oobj.createVariable('verifs', 'c', ('stats', 'Lstring')) |
|---|
| 206 | newattr = ncvar.basicvardef(newvar, 'verifs', 'verifications used to check', '-') |
|---|
| 207 | newvals = ncvar.writing_str_nc(newvar, stats, 50) |
|---|
| 208 | |
|---|
| 209 | newvar = oobj.createVariable('checks', 'c', ('checks', 'Lstring')) |
|---|
| 210 | newattr = ncvar.basicvardef(newvar, 'checks', 'values used to check', '-') |
|---|
| 211 | newvals = ncvar.writing_str_nc(newvar, ['computed', 'limits'], 50) |
|---|
| 212 | |
|---|
| 213 | # Global attributes |
|---|
| 214 | newattr = ncvar.set_attribute(oobj, 'script', main) |
|---|
| 215 | newattr = ncvar.set_attribute(oobj, 'version', version) |
|---|
| 216 | newattr = ncvar.set_attribute(oobj, 'author', author) |
|---|
| 217 | newattr = ncvar.set_attribute(oobj, 'institution', institution) |
|---|
| 218 | newattr = ncvar.set_attribute(oobj, 'city', city) |
|---|
| 219 | newattr = ncvar.set_attribute(oobj, 'country', country) |
|---|
| 220 | |
|---|
| 221 | newattr = ncvar.set_attribute(oobj, 'description', 'Variables from ' + opts.ncfile + \ |
|---|
| 222 | ' with a wrong value according to ' + opts.lfile) |
|---|
| 223 | |
|---|
| 224 | oobj.sync() |
|---|
| 225 | |
|---|
| 226 | # Getting netCDF file and its values |
|---|
| 227 | ## |
|---|
| 228 | valsstats = np.zeros((NVals,Nvars), dtype = np.float) |
|---|
| 229 | wrongVars = {} |
|---|
| 230 | iv = 0 |
|---|
| 231 | for iv in range(Nvars): |
|---|
| 232 | vn = vns[iv] |
|---|
| 233 | print vn + '...' |
|---|
| 234 | if not ncvar.searchInlist(filevars, vn): |
|---|
| 235 | print errormsg |
|---|
| 236 | print ' ' + main + ": file '" + opts.ncfile + "' does not have variable '" +\ |
|---|
| 237 | vn + "' !!" |
|---|
| 238 | quit(-1) |
|---|
| 239 | |
|---|
| 240 | vals = ncobj.variables[vn][:] |
|---|
| 241 | wrongstats = [] |
|---|
| 242 | for ist in range(NVals): |
|---|
| 243 | stn = stats[ist] |
|---|
| 244 | Lstn = LAvailablestats[stn] |
|---|
| 245 | statpos = stats.index(stn) |
|---|
| 246 | limitval = limitvals[vn][statpos] |
|---|
| 247 | verif = statsverif[stn] |
|---|
| 248 | # print ' ', ist, stn, ':',limitval,verif |
|---|
| 249 | if stn == 'max': |
|---|
| 250 | valsstats[ist,iv] = np.max(vals) |
|---|
| 251 | elif stn == 'mean': |
|---|
| 252 | valsstats[ist,iv] = np.mean(vals) |
|---|
| 253 | elif stn == 'min': |
|---|
| 254 | valsstats[ist,iv] = np.min(vals) |
|---|
| 255 | elif stn == 'stddev': |
|---|
| 256 | valsstats[ist,iv] = compute_stddev(vals) |
|---|
| 257 | |
|---|
| 258 | # checks |
|---|
| 259 | if not checking(stn,valsstats[ist,iv],verif,limitval,vn): |
|---|
| 260 | vval = valsstats[ist,iv] |
|---|
| 261 | Sverif = SAvailableverifs[verif[0:1]] |
|---|
| 262 | Lverif = LAvailableverifs[verif[0:1]] |
|---|
| 263 | if verif[0:1] != '<' and verif[0:1] != '>': |
|---|
| 264 | Vverif = np.float(verif[1:len(verif)]) |
|---|
| 265 | VverifS = str(Vverif) |
|---|
| 266 | else: |
|---|
| 267 | VverifS = '' |
|---|
| 268 | |
|---|
| 269 | wrongstats.append(stn) |
|---|
| 270 | if not ncvar.searchInlist(oobj.variables.keys(), vn): |
|---|
| 271 | oobj.close() |
|---|
| 272 | ncvar.fvaradd(opts.ncfile + ':' + vn, ofile) |
|---|
| 273 | |
|---|
| 274 | oobj = NetCDFFile(ofile ,'a') |
|---|
| 275 | vobj = oobj.variables[vn] |
|---|
| 276 | if ncvar.searchInlist(vobj.ncattrs(),('units')): |
|---|
| 277 | vunits = vobj.getncattr('units') |
|---|
| 278 | else: |
|---|
| 279 | vunits = '-' |
|---|
| 280 | |
|---|
| 281 | dims = vobj.dimensions |
|---|
| 282 | # 1/0 Matrix with wrong values |
|---|
| 283 | if stn == 'max': |
|---|
| 284 | wrongvals = np.where(vals > limitval, 1, 0) |
|---|
| 285 | newvar = oobj.createVariable(vn+'Wrong'+stn+Sverif, 'i', dims) |
|---|
| 286 | newattr = ncvar.basicvardef(newvar, vn+'_wrong_'+stn+'_'+Sverif, \ |
|---|
| 287 | 'wrong ' + vn + ' ' + str(vval) + ' ' + Lstn + ' ' + VverifS + ' '+\ |
|---|
| 288 | Lverif + ' ' + str(limitval), vunits) |
|---|
| 289 | newvar[:] = wrongvals |
|---|
| 290 | elif stn == 'mean': |
|---|
| 291 | newattr = ncvar.set_attribute(vobj, 'wrong_'+stn+'_'+Sverif+VverifS, \ |
|---|
| 292 | 'wrong ' + vn + ' ' + str(vval) + ' ' + Lstn + ' ' + VverifS + ' '+\ |
|---|
| 293 | Lverif + ' ' + str(limitval)) |
|---|
| 294 | elif stn == 'min': |
|---|
| 295 | wrongvals = np.where(vals < limitval, 1, 0) |
|---|
| 296 | newvar = oobj.createVariable(vn+'Wrong'+stn+Sverif, 'i', dims) |
|---|
| 297 | newattr = ncvar.basicvardef(newvar, vn+'_wrong_'+stn+'_'+Sverif, \ |
|---|
| 298 | 'wrong ' + vn + ' ' + str(vval) + ' ' + Lstn + ' ' + VverifS + ' '+\ |
|---|
| 299 | Lverif + ' ' + str(limitval), vunits) |
|---|
| 300 | newvar[:] = wrongvals |
|---|
| 301 | elif stn == 'stddev': |
|---|
| 302 | newattr = ncvar.set_attribute(vobj, 'wrong_'+stn+'_'+Sverif+VverifS, \ |
|---|
| 303 | 'wrong ' + vn + ' ' + str(vval) + ' ' + Lstn + ' ' + VverifS + ' '+\ |
|---|
| 304 | Lverif + ' ' + str(limitval)) |
|---|
| 305 | |
|---|
| 306 | if len(wrongstats) != 0: wrongVars[vn] = wrongstats |
|---|
| 307 | newattr = ncvar.set_attribute(vobj, 'wrong', \ |
|---|
| 308 | ncvar.numVector_String(wrongVars[vn], ' ')) |
|---|
| 309 | |
|---|
| 310 | newvar = oobj.createVariable(vn + 'checks', 'f4', ('checks', 'stats')) |
|---|
| 311 | newattr = ncvar.basicvardef(newvar, vn + '_checks', vn + \ |
|---|
| 312 | ' computed/checked', vunits) |
|---|
| 313 | for ist in range(NVals): |
|---|
| 314 | newvar[:,ist] = [valsstats[ist,iv], limitvals[vn][ist]] |
|---|
| 315 | |
|---|
| 316 | oobj.sync() |
|---|
| 317 | oobj.close() |
|---|
| 318 | |
|---|
| 319 | # Results |
|---|
| 320 | ## |
|---|
| 321 | print ' Variables with Wrong results _______________________________________________' |
|---|
| 322 | print wrongVars |
|---|
| 323 | |
|---|
| 324 | print "succesfull writting of checking output file '" + ofile + "' !!" |
|---|