[21341] | 1 | import numpy as np
|
---|
[12842] | 2 | import os
|
---|
[17806] | 3 | from pairoptions import pairoptions
|
---|
| 4 | import MatlabFuncs as m
|
---|
[12842] | 5 |
|
---|
[17806] | 6 | def checkfield(md,*args):
|
---|
[12842] | 7 | """
|
---|
| 8 | CHECKFIELD - check field consistency
|
---|
| 9 |
|
---|
[17806] | 10 | Used to check model consistency.,
|
---|
[23189] | 11 | Requires:
|
---|
| 12 | 'field' or 'fieldname' option. If 'fieldname' is provided, it will retrieve it from the model md. (md.(fieldname))
|
---|
[17806] | 13 | If 'field' is provided, it will assume the argument following 'field' is a numeric array.
|
---|
| 14 |
|
---|
[12943] | 15 | Available options:
|
---|
| 16 | - NaN: 1 if check that there is no NaN
|
---|
| 17 | - size: [lines cols], NaN for non checked dimensions
|
---|
| 18 | - >: greater than provided value
|
---|
| 19 | - >=: greater or equal to provided value
|
---|
| 20 | - <: smallerthan provided value
|
---|
| 21 | - <=: smaller or equal to provided value
|
---|
| 22 | - < vec: smallerthan provided values on each vertex
|
---|
[19105] | 23 | - timeseries: 1 if check time series consistency (size and time)
|
---|
[12943] | 24 | - values: cell of strings or vector of acceptable values
|
---|
| 25 | - numel: list of acceptable number of elements
|
---|
| 26 | - cell: 1 if check that is cell
|
---|
| 27 | - empty: 1 if check that non empty
|
---|
| 28 | - message: overloaded error message
|
---|
[12842] | 29 |
|
---|
[12943] | 30 | Usage:
|
---|
| 31 | md = checkfield(md,fieldname,options);
|
---|
[12842] | 32 | """
|
---|
| 33 |
|
---|
| 34 | #get options
|
---|
| 35 | options=pairoptions(*args)
|
---|
| 36 |
|
---|
| 37 | #get field from model
|
---|
[17806] | 38 | if options.exist('field'):
|
---|
| 39 | field=options.getfieldvalue('field')
|
---|
| 40 | fieldname=options.getfieldvalue('fieldname','no fieldname')
|
---|
| 41 | else:
|
---|
[23189] | 42 | fieldname=options.getfieldvalue('fieldname')
|
---|
[21341] | 43 | exec("field=md.{}".format(fieldname))
|
---|
[17806] | 44 |
|
---|
[13043] | 45 | if isinstance(field,(bool,int,long,float)):
|
---|
[21341] | 46 | field=np.array([field])
|
---|
[12842] | 47 |
|
---|
| 48 | #check empty
|
---|
[12943] | 49 | if options.exist('empty'):
|
---|
[12842] | 50 | if not field:
|
---|
| 51 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 52 | "field '%s' is empty" % fieldname))
|
---|
| 53 |
|
---|
| 54 | #Check size
|
---|
[12943] | 55 | if options.exist('size'):
|
---|
[12842] | 56 | fieldsize=options.getfieldvalue('size')
|
---|
[21341] | 57 | if len(fieldsize) == 1:
|
---|
| 58 | if np.isnan(fieldsize[0]):
|
---|
[13023] | 59 | pass
|
---|
[21341] | 60 | elif np.ndim(field)==1:
|
---|
| 61 | if not np.size(field)==fieldsize[0]:
|
---|
| 62 | md = md.checkmessage(options.getfieldvalue('message',"field {} size should be {}".format(fieldname,fieldsize[0])))
|
---|
| 63 | else:
|
---|
| 64 | try:
|
---|
| 65 | exec("md.{}=field[:,0]".format(fieldname))
|
---|
| 66 | print('{} had a bad dimension, we fixed it but you should check it'.format(fieldname))
|
---|
| 67 | except IndexError:
|
---|
| 68 | md = md.checkmessage(options.getfieldvalue('message',"field {} should have {} dimension".format(fieldname,len(fieldsize))))
|
---|
[12943] | 69 | elif len(fieldsize) == 2:
|
---|
[21341] | 70 | if np.isnan(fieldsize[0]):
|
---|
| 71 | if not np.size(field,1)==fieldsize[1]:
|
---|
[21729] | 72 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have %d columns" % (fieldname,fieldsize[1])))
|
---|
[21341] | 73 | elif np.isnan(fieldsize[1]):
|
---|
| 74 | if not np.size(field,0)==fieldsize[0]:
|
---|
[21729] | 75 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have %d lines" % (fieldname,fieldsize[0])))
|
---|
| 76 | elif fieldsize[1]==1:
|
---|
| 77 | if (not np.size(field,0)==fieldsize[0]):
|
---|
| 78 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' size should be %d x %d" % (fieldname,fieldsize[0],fieldsize[1])))
|
---|
[12943] | 79 | else:
|
---|
[21341] | 80 | if (not np.size(field,0)==fieldsize[0]) or (not np.size(field,1)==fieldsize[1]):
|
---|
[21729] | 81 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' size should be %d x %d" % (fieldname,fieldsize[0],fieldsize[1])))
|
---|
[23189] | 82 |
|
---|
[12842] | 83 | #Check numel
|
---|
[12943] | 84 | if options.exist('numel'):
|
---|
[12842] | 85 | fieldnumel=options.getfieldvalue('numel')
|
---|
[22758] | 86 | if (type(fieldnumel) == int and np.size(field) != fieldnumel) or (type(fieldnumel) == list and np.size(field) not in fieldnumel):
|
---|
[12842] | 87 | if len(fieldnumel)==1:
|
---|
| 88 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 89 | "field '%s' size should be %d" % (fieldname,fieldnumel)))
|
---|
| 90 | elif len(fieldnumel)==2:
|
---|
| 91 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 92 | "field '%s' size should be %d or %d" % (fieldname,fieldnumel[0],fieldnumel[1])))
|
---|
| 93 | else:
|
---|
| 94 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 95 | "field '%s' size should be %s" % (fieldname,fieldnumel)))
|
---|
| 96 |
|
---|
| 97 | #check NaN
|
---|
| 98 | if options.getfieldvalue('NaN',0):
|
---|
[21341] | 99 | if np.any(np.isnan(field)):
|
---|
[12842] | 100 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 101 | "NaN values found in field '%s'" % fieldname))
|
---|
| 102 |
|
---|
[22758] | 103 |
|
---|
[20500] | 104 | #check Inf
|
---|
| 105 | if options.getfieldvalue('Inf',0):
|
---|
[21341] | 106 | if np.any(np.isinf(field)):
|
---|
[20500] | 107 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 108 | "Inf values found in field '%s'" % fieldname))
|
---|
| 109 |
|
---|
[22758] | 110 |
|
---|
[12842] | 111 | #check cell
|
---|
| 112 | if options.getfieldvalue('cell',0):
|
---|
| 113 | if not isinstance(field,(tuple,list,dict)):
|
---|
| 114 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 115 | "field '%s' should be a cell" % fieldname))
|
---|
| 116 |
|
---|
| 117 | #check values
|
---|
[12943] | 118 | if options.exist('values'):
|
---|
[12842] | 119 | fieldvalues=options.getfieldvalue('values')
|
---|
[17806] | 120 | if False in m.ismember(field,fieldvalues):
|
---|
[12842] | 121 | if len(fieldvalues)==1:
|
---|
| 122 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 123 | "field '%s' value should be '%s'" % (fieldname,fieldvalues[0])))
|
---|
| 124 | elif len(fieldvalues)==2:
|
---|
| 125 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 126 | "field '%s' values should be '%s' or '%s'" % (fieldname,fieldvalues[0],fieldvalues[1])))
|
---|
| 127 | else:
|
---|
| 128 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 129 | "field '%s' should have values in %s" % (fieldname,fieldvalues)))
|
---|
| 130 |
|
---|
| 131 | #check greater
|
---|
[12943] | 132 | if options.exist('>='):
|
---|
[22758] | 133 | lowerbound = options.getfieldvalue('>=')
|
---|
[23189] | 134 | if np.size(lowerbound)>1: #checking elementwise
|
---|
| 135 | if any(field<upperbound):
|
---|
| 136 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have values below %d" % (fieldname,upperbound)))
|
---|
| 137 | else:
|
---|
| 138 | minval=np.nanmin(field)
|
---|
| 139 | if options.getfieldvalue('timeseries',0):
|
---|
| 140 | minval=np.nanmin(field[:-1])
|
---|
| 141 | elif options.getfieldvalue('singletimeseries',0):
|
---|
| 142 | if np.size(field)==1: #some singletimeseries are just one value
|
---|
| 143 | minval=field
|
---|
| 144 | else:
|
---|
| 145 | minval=np.nanmin(field[0])
|
---|
[22758] | 146 |
|
---|
[23189] | 147 | if minval<lowerbound:
|
---|
| 148 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have values above %d" % (fieldname,lowerbound)))
|
---|
[22758] | 149 |
|
---|
[12943] | 150 | if options.exist('>'):
|
---|
[12842] | 151 | lowerbound=options.getfieldvalue('>')
|
---|
[23189] | 152 | if np.size(lowerbound)>1: #checking elementwise
|
---|
| 153 | if any(field<=upperbound):
|
---|
| 154 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have values below %d" % (fieldname,upperbound)))
|
---|
| 155 | else:
|
---|
| 156 | minval=np.nanmin(field)
|
---|
| 157 | if options.getfieldvalue('timeseries',0) :
|
---|
| 158 | minval=np.nanmin(field[:-1])
|
---|
| 159 | elif options.getfieldvalue('singletimeseries',0):
|
---|
| 160 | if np.size(field)==1: #some singletimeseries are just one value
|
---|
| 161 | minval=field
|
---|
| 162 | else:
|
---|
| 163 | minval=np.nanmin(field[0])
|
---|
[22758] | 164 |
|
---|
[23189] | 165 | if minval<=lowerbound:
|
---|
| 166 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have values above %d" % (fieldname,lowerbound)))
|
---|
[22758] | 167 |
|
---|
[12842] | 168 | #check smaller
|
---|
[12943] | 169 | if options.exist('<='):
|
---|
[12842] | 170 | upperbound=options.getfieldvalue('<=')
|
---|
[23189] | 171 | if np.size(upperbound)>1: #checking elementwise
|
---|
| 172 | if any(field>upperbound):
|
---|
| 173 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have values below %d" % (fieldname,upperbound)))
|
---|
| 174 | else:
|
---|
| 175 | maxval=np.nanmax(field)
|
---|
| 176 | if options.getfieldvalue('timeseries',0):
|
---|
| 177 | maxval=np.nanmax(field[:-1])
|
---|
| 178 | elif options.getfieldvalue('singletimeseries',0):
|
---|
| 179 | if np.size(field)==1: #some singletimeseries are just one value
|
---|
| 180 | maxval=field
|
---|
| 181 | else:
|
---|
| 182 | maxval=np.nanmax(field[0])
|
---|
| 183 | if maxval>upperbound:
|
---|
| 184 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have values below %d" % (fieldname,upperbound)))
|
---|
[22758] | 185 |
|
---|
[12943] | 186 | if options.exist('<'):
|
---|
[12842] | 187 | upperbound=options.getfieldvalue('<')
|
---|
[23189] | 188 | if np.size(upperbound)>1: #checking elementwise
|
---|
| 189 | if any(field>=upperbound):
|
---|
| 190 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have values below %d" % (fieldname,upperbound)))
|
---|
[22758] | 191 |
|
---|
[23189] | 192 | else:
|
---|
| 193 | maxval=np.nanmax(field)
|
---|
| 194 | if options.getfieldvalue('timeseries',0):
|
---|
| 195 | maxval=np.nanmax(field[:-1])
|
---|
| 196 | elif options.getfieldvalue('singletimeseries',0):
|
---|
| 197 | if np.size(field)==1: #some singletimeseries are just one value
|
---|
| 198 | maxval=field.copy()
|
---|
| 199 | else:
|
---|
| 200 | maxval=np.nanmax(field[0])
|
---|
[22758] | 201 |
|
---|
[23189] | 202 | if maxval>=upperbound:
|
---|
| 203 | md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have values below %d" % (fieldname,upperbound)))
|
---|
[12842] | 204 |
|
---|
| 205 | #check file
|
---|
| 206 | if options.getfieldvalue('file',0):
|
---|
| 207 | if not os.path.exists(field):
|
---|
| 208 | md = md.checkmessage("file provided in '%s': '%s' does not exist" % (fieldname,field))
|
---|
| 209 |
|
---|
[16560] | 210 | #Check row of strings
|
---|
| 211 | if options.exist('stringrow'):
|
---|
| 212 | if not isinstance(field,list):
|
---|
| 213 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 214 | "field '%s' should be a list" %fieldname))
|
---|
| 215 |
|
---|
[12842] | 216 | #Check forcings (size and times)
|
---|
[19105] | 217 | if options.getfieldvalue('timeseries',0):
|
---|
[22758] | 218 | if np.size(field,0)==md.mesh.numberofvertices or np.size(field,0)==md.mesh.numberofelements:
|
---|
[21341] | 219 | if np.ndim(field)>1 and not np.size(field,1)==1:
|
---|
[12842] | 220 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 221 | "field '%s' should have only one column as there are md.mesh.numberofvertices lines" % fieldname))
|
---|
[22758] | 222 | elif np.size(field,0)==md.mesh.numberofvertices+1 or np.size(field,0)==md.mesh.numberofelements+1:
|
---|
| 223 | if np.ndim(field) > 1 and not all(field[-1,:]==np.sort(field[-1,:])):
|
---|
[12842] | 224 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 225 | "field '%s' columns should be sorted chronologically" % fieldname))
|
---|
[22758] | 226 | if np.ndim(field) > 1 and any(field[-1,0:-1]==field[-1,1:]):
|
---|
[12842] | 227 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 228 | "field '%s' columns must not contain duplicate timesteps" % fieldname))
|
---|
| 229 | else:
|
---|
| 230 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 231 | "field '%s' should have md.mesh.numberofvertices or md.mesh.numberofvertices+1 lines" % fieldname))
|
---|
| 232 |
|
---|
[20500] | 233 | #Check single value forcings (size and times)
|
---|
| 234 | if options.getfieldvalue('singletimeseries',0):
|
---|
[21341] | 235 | if np.size(field,0)==2:
|
---|
| 236 | if not all(field[-1,:]==np.sort(field[-1,:])):
|
---|
[20500] | 237 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 238 | "field '%s' columns should be sorted chronologically" % fieldname))
|
---|
| 239 | if any(field[-1,0:-1]==field[-1,1:]):
|
---|
| 240 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 241 | "field '%s' columns must not contain duplicate timesteps" % fieldname))
|
---|
[22758] | 242 | elif np.size(field,0) == 1:
|
---|
| 243 | if np.ndim(field) > 1 and not np.size(field,1) == 1:
|
---|
| 244 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
| 245 | "field '%s' should be either a scalar or have 2 lines" % fieldname))
|
---|
[20500] | 246 | else:
|
---|
| 247 | md = md.checkmessage(options.getfieldvalue('message',\
|
---|
[22758] | 248 | "field '%s' should have 2 lines or be a scalar" % fieldname))
|
---|
[20500] | 249 |
|
---|
[12842] | 250 | return md
|
---|