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