Changeset 623
- Timestamp:
- Nov 24, 2004, 4:43:40 PM (20 years ago)
- Location:
- inundation/ga/storm_surge/pyvolution
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
inundation/ga/storm_surge/pyvolution/generic_boundary_conditions.py
r566 r623 115 115 return self.f(self.domain.time) 116 116 117 117 118 class File_boundary(Boundary): 118 119 """Boundary values obtained from file and interpolated. … … 125 126 126 127 127 def __init__(self, domain = None, filename = None):128 def __init__(self, filename, domain): 128 129 import time 129 130 from Numeric import array 130 131 from config import time_format 131 132 Boundary.__init__(self) 133 134 135 try: 136 fid = open(filename) 137 except Exception, e: 138 msg = 'Boundary file %s could not be opened: %s\n' %(filename, e) 139 raise msg 140 141 142 line = fid.readline() 143 fid.close() 144 fields = line.split(',') 145 msg = 'File %s must have the format date, values' 146 assert len(fields) == 2, msg 147 148 try: 149 starttime = time.mktime(time.strptime(fields[0], time_format)) 150 except ValueError: 151 msg = 'First field in file %s must be' %filename 152 msg += ' date-time with format %s.\n' %time_format 153 msg += 'I got %s instead.' %fields[0] 154 raise msg 155 156 #Split values 157 values = [] 158 for value in fields[1].split(): 159 values.append(float(value)) 160 161 q = array(values) 162 163 msg = 'ERROR: File boundary function must return a 1d list or array ' 164 assert len(q.shape) == 1, msg 165 132 from util import File_function 133 134 Boundary.__init__(self) 135 136 self.F = File_function(filename, domain) 137 self.domain = domain 138 139 #Test 140 q = self.F(0) 141 166 142 d = len(domain.conserved_quantities) 167 143 msg = 'Values specified in file must be a list or an array of length %d' %d 168 144 assert len(q) == d, msg 169 145 170 self.filename = filename171 self.domain = domain172 self.starttime = starttime173 174 if domain.starttime is None:175 domain.starttime = starttime176 else:177 msg = 'Start time as specified in domain (%s) is earlier '178 'than the starttime of file %s: %s'\179 %(domain.starttime, self.filename, self.starttime)180 if self.starttime > domain.starttime:181 raise msg182 183 self.read_time_boundary() #Now read all times in.184 185 186 def read_time_boundary(self):187 from Numeric import zeros, Float, alltrue188 from config import time_format189 import time190 191 fid = open(self.filename)192 lines = fid.readlines()193 fid.close()194 195 N = len(lines)196 d = len(self.domain.conserved_quantities)197 198 T = zeros(N, Float)199 Q = zeros((N, d), Float)200 201 202 for i, line in enumerate(lines):203 fields = line.split(',')204 real_time = time.mktime(time.strptime(fields[0], time_format))205 206 T[i] = real_time - self.starttime207 208 209 for j, value in enumerate(fields[1].split()):210 Q[i, j] = float(value)211 212 msg = 'Time boundary must list time as a monotonuosly '213 msg += 'increasing sequence'214 215 assert alltrue( T[1:] - T[:-1] > 0 ), msg216 217 self.T = T #Time218 self.Q = Q #Boundary values219 self.index = 0 #Initial index220 221 146 222 147 def __repr__(self): … … 225 150 def evaluate(self, vol_id=None, edge_id=None): 226 151 """Return linearly interpolated values based on domain.time 152 153 vol_id and edge_id are ignored 227 154 """ 228 155 229 156 t = self.domain.time 230 231 msg = 'Time given in File boundary does not match model time' 232 if t < self.T[0]: raise msg 233 if t > self.T[-1]: raise msg 234 235 oldindex = self.index 236 237 #Find slot 238 while t > self.T[self.index]: self.index += 1 239 while t < self.T[self.index]: self.index -= 1 240 241 #if oldindex != self.index: 242 # print 'Changing from %d to %d' %(oldindex, self.index) 243 244 245 #t is now between index and index+1 246 ratio = (t - self.T[self.index])/\ 247 (self.T[self.index+1] - self.T[self.index]) 248 249 return self.Q[self.index,:] +\ 250 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 157 return self.F(t) 251 158 252 159 … … 344 251 self.domain.time) 345 252 346 347 348 253 254 255 256 257 class File_boundary_old(Boundary): 258 """Boundary values obtained from file and interpolated. 259 conserved quantities as a function of time. 260 261 Assumes that file contains a time series. 262 263 No spatial info assumed. 264 """ 265 266 267 def __init__(self, domain = None, filename = None): 268 import time 269 from Numeric import array 270 from config import time_format 271 272 Boundary.__init__(self) 273 274 275 try: 276 fid = open(filename) 277 except Exception, e: 278 msg = 'Boundary file %s could not be opened: %s\n' %(filename, e) 279 raise msg 280 281 282 line = fid.readline() 283 fid.close() 284 fields = line.split(',') 285 msg = 'File %s must have the format date, values' 286 assert len(fields) == 2, msg 287 288 try: 289 starttime = time.mktime(time.strptime(fields[0], time_format)) 290 except ValueError: 291 msg = 'First field in file %s must be' %filename 292 msg += ' date-time with format %s.\n' %time_format 293 msg += 'I got %s instead.' %fields[0] 294 raise msg 295 296 #Split values 297 values = [] 298 for value in fields[1].split(): 299 values.append(float(value)) 300 301 q = array(values) 302 303 msg = 'ERROR: File boundary function must return a 1d list or array ' 304 assert len(q.shape) == 1, msg 305 306 d = len(domain.conserved_quantities) 307 msg = 'Values specified in file must be a list or an array of length %d' %d 308 assert len(q) == d, msg 309 310 self.filename = filename 311 self.domain = domain 312 self.starttime = starttime 313 314 if domain.starttime is None: 315 domain.starttime = starttime 316 else: 317 msg = 'Start time as specified in domain (%s) is earlier ' 318 'than the starttime of file %s: %s'\ 319 %(domain.starttime, self.filename, self.starttime) 320 if self.starttime > domain.starttime: 321 raise msg 322 323 self.read_time_boundary() #Now read all times in. 324 325 326 def read_time_boundary(self): 327 from Numeric import zeros, Float, alltrue 328 from config import time_format 329 import time 330 331 fid = open(self.filename) 332 lines = fid.readlines() 333 fid.close() 334 335 N = len(lines) 336 d = len(self.domain.conserved_quantities) 337 338 T = zeros(N, Float) 339 Q = zeros((N, d), Float) 340 341 342 for i, line in enumerate(lines): 343 fields = line.split(',') 344 real_time = time.mktime(time.strptime(fields[0], time_format)) 345 346 T[i] = real_time - self.starttime 347 348 349 for j, value in enumerate(fields[1].split()): 350 Q[i, j] = float(value) 351 352 msg = 'Time boundary must list time as a monotonuosly ' 353 msg += 'increasing sequence' 354 355 assert alltrue( T[1:] - T[:-1] > 0 ), msg 356 357 self.T = T #Time 358 self.Q = Q #Boundary values 359 self.index = 0 #Initial index 360 361 362 def __repr__(self): 363 return 'File boundary' 364 365 def evaluate(self, vol_id=None, edge_id=None): 366 """Return linearly interpolated values based on domain.time 367 """ 368 369 t = self.domain.time 370 371 msg = 'Time given in File boundary does not match model time' 372 if t < self.T[0]: raise msg 373 if t > self.T[-1]: raise msg 374 375 oldindex = self.index 376 377 #Find slot 378 while t > self.T[self.index]: self.index += 1 379 while t < self.T[self.index]: self.index -= 1 380 381 #if oldindex != self.index: 382 # print 'Changing from %d to %d' %(oldindex, self.index) 383 384 385 #t is now between index and index+1 386 ratio = (t - self.T[self.index])/\ 387 (self.T[self.index+1] - self.T[self.index]) 388 389 return self.Q[self.index,:] +\ 390 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 391 392 393 394 395 -
inundation/ga/storm_surge/pyvolution/shallow_water.py
r620 r623 518 518 """ 519 519 520 #FIXME: Experimental 520 #FIXME: Experimental (from old version). Not in use at the moment 521 521 522 522 #Shortcuts … … 560 560 xmomc[k] = ymomc[k] = 0.0 561 561 562 #FIXME: Delete 562 563 #From 'newstyle 563 564 #if hc[k] < domain.minimum_allowed_height: … … 901 902 def check_forcefield(f): 902 903 """Check that f is either 903 1: a callable object of x,y,t, where x and y are vectors904 1: a callable object f(t,x,y), where x and y are vectors 904 905 and that it returns an array or a list of same length 905 906 as x and y … … 915 916 y = ones(3, Float) 916 917 try: 917 q = f( x, y, 1.0)918 q = f(1.0, x, y) 918 919 except Exception, e: 919 920 msg = 'Function %s could not be executed:\n%s' %(f, e) … … 943 944 944 945 class Wind_stress: 945 """Apply wind stress to water momentum 946 """Apply wind stress to water momentum in terms of 947 wind speed [m/s] and wind direction [degrees] 946 948 """ 947 949 … … 959 961 map from True north to grid north. 960 962 961 Arguments can also be Python functions of x,y,tas in962 963 def speed( x,y,t):963 Arguments can also be Python functions of t,x,y as in 964 965 def speed(t,x,y): 964 966 ... 965 967 return s 966 968 967 def angle( x,y,t):969 def angle(t,x,y): 968 970 ... 969 971 return phi … … 978 980 forcing_terms as in 979 981 982 Alternatively, one vector valued function for (speed, angle) 983 can be applied, providing both quantities simultaneously. 984 FIXME: Not yet implemented 985 980 986 domain.forcing_terms.append(W) 981 982 987 """ 983 988 … … 1006 1011 if callable(self.speed): 1007 1012 xc = domain.get_centroid_coordinates() 1008 s_vec = self.speed( xc[:,0], xc[:,1], t)1013 s_vec = self.speed(t, xc[:,0], xc[:,1]) 1009 1014 else: 1010 1015 #Assume s is a scalar … … 1019 1024 if callable(self.phi): 1020 1025 xc = domain.get_centroid_coordinates() 1021 phi_vec = self.phi( xc[:,0], xc[:,1], t)1026 phi_vec = self.phi(t, xc[:,0], xc[:,1]) 1022 1027 else: 1023 1028 #Assume phi is a scalar … … 1057 1062 ymom_update[k] += S*v 1058 1063 1059 1060 class Wind_stress_from_file:1061 """Apply wind stress read from a file to water momentum1062 1063 At this stage the wind field is assumed to depend on time only, i.e1064 no spatial dependency.1065 1066 FIXME: This class may be incorporated in the generic Wind_stress class1067 Superseded1068 """1069 1070 1071 def __init__(self, filename):1072 """Initialise windfield from a file with the following format1073 1074 time [DD/MM/YY hh:mm:ss], speed [m/s] direction [degrees]1075 1076 e.g.1077 1078 03/09/04 19:15:00, 9.53 391079 1080 domain.forcing_terms.append(W)1081 1082 """1083 1084 import time1085 from Numeric import array1086 from config import time_format1087 1088 1089 from config import rho_a, rho_w, eta_w1090 self.const = eta_w*rho_a/rho_w1091 1092 1093 try:1094 fid = open(filename)1095 except Exception, e:1096 msg = 'Wind stress file %s could not be opened: %s\n'\1097 %(filename, e)1098 raise msg1099 1100 1101 line = fid.readline()1102 fid.close()1103 fields = line.split(',')1104 msg = 'File %s must have the format date, values'1105 assert len(fields) == 2, msg1106 1107 try:1108 starttime = time.mktime(time.strptime(fields[0], time_format))1109 except ValueError:1110 msg = 'First field in file %s must be' %filename1111 msg += ' date-time with format %s.\n' %time_format1112 msg += 'I got %s instead.' %fields[0]1113 raise msg1114 1115 #Split values1116 values = []1117 for value in fields[1].split():1118 values.append(float(value))1119 1120 q = array(values)1121 1122 msg = 'ERROR: File function must return a 1d list or array '1123 assert len(q.shape) == 1, msg1124 1125 1126 msg = 'Values specified in file must convert to an array of length 2'1127 assert len(q) == 2, msg1128 1129 self.filename = filename1130 self.domain = domain1131 self.starttime = starttime1132 1133 1134 if domain.starttime is None:1135 domain.starttime = starttime1136 else:1137 msg = 'Start time as specified in domain (%s) is earlier '1138 'than the starttime of file %s: %s'\1139 %(domain.starttime, self.filename, self.starttime)1140 if self.starttime > domain.starttime:1141 raise msg1142 1143 1144 self.read_times() #Now read all times in.1145 1146 1147 def read_times(self):1148 from Numeric import zeros, Float, alltrue1149 from config import time_format1150 import time1151 1152 fid = open(self.filename)1153 lines = fid.readlines()1154 fid.close()1155 1156 N = len(lines)1157 1158 T = zeros(N, Float) #Time1159 Q = zeros((N, 2), Float) #Wind field (s, phi)1160 1161 for i, line in enumerate(lines):1162 fields = line.split(',')1163 real_time = time.mktime(time.strptime(fields[0], time_format))1164 1165 T[i] = real_time - self.start_time1166 1167 for j, value in enumerate(fields[1].split()):1168 Q[i, j] = float(value)1169 1170 msg = 'File %s must list time as a monotonuosly ' %self.filename1171 msg += 'increasing sequence'1172 assert alltrue( T[1:] - T[:-1] > 0 ), msg1173 1174 self.T = T #Time1175 self.Q = Q #Windfied1176 self.index = 0 #Initial index1177 1178 1179 def __repr__(self):1180 return 'Wind field from file'1181 1182 1183 1184 def __call__(self, domain):1185 """Evaluate windfield based on values found in domain1186 """1187 1188 from math import pi, cos, sin, sqrt1189 1190 xmom_update = domain.quantities['xmomentum'].explicit_update1191 ymom_update = domain.quantities['ymomentum'].explicit_update1192 1193 N = domain.number_of_elements1194 t = self.domain.time1195 1196 msg = 'Time given in File %s does not match model time'\1197 %self.filename1198 1199 if t < self.T[0]: raise msg1200 if t > self.T[-1]: raise msg1201 1202 oldindex = self.index1203 1204 #Find slot1205 while t > self.T[self.index]: self.index += 11206 while t < self.T[self.index]: self.index -= 11207 1208 #t is now between index and index+11209 ratio = (t - self.T[self.index])/\1210 (self.T[self.index+1] - self.T[self.index])1211 1212 #Compute interpolated values for s and phi1213 q = self.Q[self.index,:] +\1214 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:])1215 1216 s = q[0]1217 1218 #Convert to radians1219 phi = q[1]*pi/1801220 1221 #Compute velocity vector (u, v)1222 u = s*cos(phi)1223 v = s*sin(phi)1224 1225 #Compute wind stress for this time step1226 S = self.const * sqrt(u**2 + v**2)1227 xmom_update += S*u1228 ymom_update += S*v1229 1230 1231 1232 1064 1233 1065 -
inundation/ga/storm_surge/pyvolution/test_generic_boundary_conditions.py
r324 r623 144 144 t_string = time.strftime(time_format, time.gmtime(t)) 145 145 146 147 146 fid.write('%s,%f %f\n' %(t_string, 1.0*i, sin(i*2*pi/10))) 148 147 fid.close() 149 148 150 149 151 F = File_boundary( domain, filename)150 F = File_boundary(filename, domain) 152 151 153 152 from config import default_boundary_tag … … 164 163 165 164 os.remove(filename) 165 166 167 168 def test_fileboundary_exception(self): 169 """Test that boundary object complians if number of 170 conserved quantities are wrong 171 """ 172 173 from domain import Domain 174 from quantity import Quantity 175 import time, os 176 from math import sin, pi 177 from config import time_format 178 179 a = [0.0, 0.0] 180 b = [0.0, 2.0] 181 c = [2.0,0.0] 182 d = [0.0, 4.0] 183 e = [2.0, 2.0] 184 f = [4.0,0.0] 185 186 points = [a, b, c, d, e, f] 187 188 #bac, bce, ecf, dbe 189 elements = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4] ] 190 191 domain = Domain(points, elements) 192 domain.conserved_quantities = ['level', 'xmomentum', 'ymomentum'] 193 domain.quantities['level'] =\ 194 Quantity(domain, [[1,2,3], [5,5,5], 195 [0,0,9], [-6, 3, 3]]) 196 197 domain.quantities['xmomentum'] =\ 198 Quantity(domain, [[2,3,4], [5,5,5], 199 [0,0,9], [-6, 3, 3]]) 200 domain.quantities['ymomentum'] =\ 201 Quantity(domain, [[2,3,4], [5,5,5], 202 [0,0,9], [-6, 3, 3]]) 203 204 domain.check_integrity() 205 206 #Write file (with only two values) 207 filename = 'boundarytest' + str(time.time()) 208 fid = open(filename, 'w') 209 start = time.mktime(time.strptime('2000', '%Y')) 210 dt = 5*60 #Five minute intervals 211 for i in range(10): 212 t = start + i*dt 213 t_string = time.strftime(time_format, time.gmtime(t)) 214 215 fid.write('%s,%f %f\n' %(t_string, 1.0*i, sin(i*2*pi/10))) 216 fid.close() 217 218 219 try: 220 F = File_boundary(filename, domain) 221 except AssertionError: 222 pass 223 else: 224 raise 'Should have raised an exception' 225 226 os.remove(filename) 227 228 166 229 167 230 #------------------------------------------------------------- -
inundation/ga/storm_surge/pyvolution/test_shallow_water.py
r612 r623 11 11 12 12 #Variable windfield implemented using functions 13 def speed( x,y,t):13 def speed(t,x,y): 14 14 """Large speeds halfway between center and edges 15 15 Low speeds at center and edges … … 32 32 33 33 34 def scalar_func( x,y,t):34 def scalar_func(t,x,y): 35 35 """Function that returns a scalar. 36 36 Used to test error message when Numeric array is expected … … 40 40 41 41 42 def angle( x,y,t):42 def angle(t,x,y): 43 43 """Rotating field 44 44 """ … … 814 814 x = xc[:,0] 815 815 y = xc[:,1] 816 s_vec = speed( x,y,t)817 phi_vec = angle( x,y,t)816 s_vec = speed(t,x,y) 817 phi_vec = angle(t,x,y) 818 818 819 819 -
inundation/ga/storm_surge/pyvolution/test_util.py
r258 r623 138 138 139 139 140 141 def test_file_function_time(self): 142 """Test that File function interpolates correctly 143 between given times. No x,y dependency here. 144 """ 145 146 #Write file 147 import os, time 148 from config import time_format 149 from math import sin, pi 150 151 finaltime = 1200 152 filename = 'test_file_function.txt' 153 fid = open(filename, 'w') 154 start = time.mktime(time.strptime('2000', '%Y')) 155 dt = 60 #One minute intervals 156 t = 0.0 157 while t <= finaltime: 158 t_string = time.strftime(time_format, time.gmtime(t+start)) 159 fid.write('%s, %f %f %f\n' %(t_string, 2*t, t**2, sin(t*pi/600))) 160 t += dt 161 162 fid.close() 163 164 F = File_function(filename) 165 166 #Now try interpolation 167 for i in range(20): 168 t = i*10 169 q = F(t) 170 171 #Exact linear intpolation 172 assert allclose(q[0], 2*t) 173 if i%6 == 0: 174 assert allclose(q[1], t**2) 175 assert allclose(q[2], sin(t*pi/600)) 176 177 #Check non-exact 178 179 t = 90 #Halfway between 60 and 120 180 q = F(t) 181 assert allclose( (120**2 + 60**2)/2, q[1] ) 182 assert allclose( (sin(120*pi/600) + sin(60*pi/600))/2, q[2] ) 183 184 185 t = 100 #Two thirds of the way between between 60 and 120 186 q = F(t) 187 assert allclose( 2*120**2/3 + 60**2/3, q[1] ) 188 assert allclose( 2*sin(120*pi/600)/3 + sin(60*pi/600)/3, q[2] ) 189 190 191 192 193 def test_file_function_time_with_domain(self): 194 """Test that File function interpolates correctly 195 between given times. No x,y dependency here. 196 Use domain with starttime 197 """ 198 199 #Write file 200 import os, time, calendar 201 from config import time_format 202 from math import sin, pi 203 from domain import Domain 204 205 finaltime = 1200 206 filename = 'test_file_function.txt' 207 fid = open(filename, 'w') 208 start = time.mktime(time.strptime('2000', '%Y')) 209 dt = 60 #One minute intervals 210 t = 0.0 211 while t <= finaltime: 212 t_string = time.strftime(time_format, time.gmtime(t+start)) 213 fid.write('%s, %f %f %f\n' %(t_string, 2*t, t**2, sin(t*pi/600))) 214 t += dt 215 216 fid.close() 217 218 a = [0.0, 0.0] 219 b = [4.0, 0.0] 220 c = [0.0, 3.0] 221 222 points = [a, b, c] 223 vertices = [[0,1,2]] 224 domain = Domain(points, vertices) 225 226 #Check that domain.starttime is updated if non-existing 227 F = File_function(filename, domain) 228 assert allclose(domain.starttime, start) 229 230 #Check that domain.starttime is updated if too early 231 domain.starttime = start - 1 232 F = File_function(filename, domain) 233 assert allclose(domain.starttime, start) 234 235 #Check that domain.starttime isn't updated if later 236 domain.starttime = start + 1 237 F = File_function(filename, domain) 238 assert allclose(domain.starttime, start+1) 239 240 241 242 #Now try interpolation 243 for i in range(20): 244 t = i*10 245 q = F(t) 246 247 #Exact linear intpolation 248 assert allclose(q[0], 2*t) 249 if i%6 == 0: 250 assert allclose(q[1], t**2) 251 assert allclose(q[2], sin(t*pi/600)) 252 253 #Check non-exact 254 255 t = 90 #Halfway between 60 and 120 256 q = F(t) 257 assert allclose( (120**2 + 60**2)/2, q[1] ) 258 assert allclose( (sin(120*pi/600) + sin(60*pi/600))/2, q[2] ) 259 260 261 t = 100 #Two thirds of the way between between 60 and 120 262 q = F(t) 263 assert allclose( 2*120**2/3 + 60**2/3, q[1] ) 264 assert allclose( 2*sin(120*pi/600)/3 + sin(60*pi/600)/3, q[2] ) 265 140 266 141 267 #------------------------------------------------------------- -
inundation/ga/storm_surge/pyvolution/util.py
r274 r623 46 46 return sum(x)/len(x) 47 47 48 49 50 51 #FIXME: Maybe move to util as this is quite general 52 class File_function: 53 """Read time series from file and return a callable object: 54 f(t,x,y) 55 which will return interpolated values based on the input file. 56 57 The file format is assumed to be either two fields separated by a comma: 58 59 time [DD/MM/YY hh:mm:ss], value0 value1 value2 ... 60 61 or four comma separated fields 62 63 time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ... 64 65 In either case, the callable obejct will return a tuple of 66 interpolated values, one each value stated in the file. 67 68 69 E.g 70 71 31/08/04 00:00:00, 1.328223 0 0 72 31/08/04 00:15:00, 1.292912 0 0 73 74 will provide a time dependent function f(t,x=None,y=None), 75 ignoring x and y, which returns three values per call. 76 77 78 NOTE: At this stage the function is assumed to depend on 79 time only, i.e no spatial dependency!!!!! 80 When that is need we can use the least_squares interpolation. 81 """ 82 83 84 def __init__(self, filename, domain=None): 85 """Initialise callable object from a file. 86 See docstring for class File_function 87 88 If domain is specified, model time (domain,starttime) 89 will be checked and possibly modified 90 91 ALl times are assumed to be in UTC 92 """ 93 94 import time, calendar 95 from Numeric import array 96 from config import time_format 97 98 try: 99 fid = open(filename) 100 except Exception, e: 101 msg = 'File %s could not be opened: %s\n'\ 102 %(filename, e) 103 raise msg 104 105 106 line = fid.readline() 107 fid.close() 108 fields = line.split(',') 109 msg = 'File %s must have the format date, value0 value1 value2 ...' 110 msg += ' or date, x, y, value0 value1 value2 ...' 111 mode = len(fields) 112 assert mode in [2,4], msg 113 114 try: 115 starttime = calendar.timegm(time.strptime(fields[0], time_format)) 116 except ValueError: 117 msg = 'First field in file %s must be' %filename 118 msg += ' date-time with format %s.\n' %time_format 119 msg += 'I got %s instead.' %fields[0] 120 raise msg 121 122 123 #Split values 124 values = [] 125 for value in fields[mode-1].split(): 126 values.append(float(value)) 127 128 q = array(values) 129 130 msg = 'ERROR: File must contain at least one independent value' 131 assert len(q.shape) == 1, msg 132 133 self.number_of_values = len(q) 134 135 self.filename = filename 136 self.starttime = starttime 137 138 139 if domain is not None: 140 if domain.starttime is None: 141 domain.starttime = starttime 142 else: 143 msg = 'WARNING: Start time as specified in domain (%s)'\ 144 %domain.starttime 145 msg += ' is earlier than the starttime of file %s: %s.'\ 146 %(self.filename, self.starttime) 147 msg += 'Modifying starttime accordingly.' 148 if self.starttime > domain.starttime: 149 #FIXME: Print depending on some verbosity setting 150 #print msg 151 domain.starttime = self.starttime #Modifying model time 152 153 if mode == 2: 154 self.read_times() #Now read all times in. 155 else: 156 raise 'x,y dependecy not yet implemented' 157 158 159 def read_times(self): 160 """Read time and values 161 """ 162 from Numeric import zeros, Float, alltrue 163 from config import time_format 164 import time, calendar 165 166 fid = open(self.filename) 167 lines = fid.readlines() 168 fid.close() 169 170 N = len(lines) 171 d = self.number_of_values 172 173 T = zeros(N, Float) #Time 174 Q = zeros((N, d), Float) #Values 175 176 for i, line in enumerate(lines): 177 fields = line.split(',') 178 realtime = calendar.timegm(time.strptime(fields[0], time_format)) 179 180 T[i] = realtime - self.starttime 181 182 for j, value in enumerate(fields[1].split()): 183 Q[i, j] = float(value) 184 185 msg = 'File %s must list time as a monotonuosly ' %self.filename 186 msg += 'increasing sequence' 187 assert alltrue( T[1:] - T[:-1] > 0 ), msg 188 189 self.T = T #Time 190 self.Q = Q #Values 191 self.index = 0 #Initial index 192 193 194 def __repr__(self): 195 return 'File function' 196 197 198 199 def __call__(self, t, x=None, y=None): 200 """Evaluate f(t,x,y) 201 202 FIXME: x, y dependency not yet implemented 203 """ 204 205 from math import pi, cos, sin, sqrt 206 207 208 msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\ 209 %(self.filename, self.T[0], self.T[1], t) 210 if t < self.T[0]: raise msg 211 if t > self.T[-1]: raise msg 212 213 oldindex = self.index 214 215 #Find slot 216 while t > self.T[self.index]: self.index += 1 217 while t < self.T[self.index]: self.index -= 1 218 219 #t is now between index and index+1 220 ratio = (t - self.T[self.index])/\ 221 (self.T[self.index+1] - self.T[self.index]) 222 223 #Compute interpolated values for values 224 q = self.Q[self.index,:] +\ 225 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 226 227 #Return vector of interpolated values 228 return q 229 230 231 232 48 233 #################################################################### 49 234 #Python versions of function that are also implemented in util_gateway.c
Note: See TracChangeset
for help on using the changeset viewer.