Ignore:
Timestamp:
Aug 2, 2005, 4:48:56 PM (20 years ago)
Author:
ole
Message:

Moved old file function stuff out and re-tested.
File_function is now all in one function which is based on NetCDF

File:
1 edited

Legend:

Unmodified
Added
Removed
  • inundation/ga/storm_surge/pyvolution/util.py

    r1670 r1671  
    66
    77#FIXME: Move polygon stuff out
    8 #FIXME: Finish Interpolation function and get rid of File_function_ASCII
    9 
    108
    119def angle(v):
     
    135133
    136134
    137 def file_function(filename, domain=None, quantities = None, interpolation_points = None, verbose = False):
    138     """If domain is specified, don't specify quantites as they are automatically derived
     135def file_function(filename,
     136                  domain = None,
     137                  quantities = None,
     138                  interpolation_points = None, verbose = False):
     139    """If quantities is not specified, derive them from domain
     140    (if that is specified)
    139141    """
    140142
     
    157159    fid.close()
    158160
    159     if domain is not None:
    160         quantities = domain.conserved_quantities
    161     else:
    162         quantities = None
     161    if quantities is None:
     162        if domain is not None:
     163            quantities = domain.conserved_quantities
     164
    163165
    164166
     
    167169                                        interpolation_points, verbose = verbose)
    168170    else:
    169         #FIXME Should be phased out
    170         return File_function_ASCII(filename, domain, quantities,
    171                                    interpolation_points)
    172    
    173    
    174 
    175 
    176 
    177 
    178 
     171        raise 'Must be a NetCDF File'
    179172
    180173
     
    215208
    216209    if quantity_names is None or len(quantity_names) < 1:
    217         msg = 'ERROR: At least one independent value must be specified'
    218         raise msg
     210        #Get quantities from file
     211        quantity_names = []
     212        for name in fid.variables.keys():
     213            if name not in ['x', 'y', 'time']:
     214                quantity_names.append(name)
     215               
     216        #msg = 'ERROR: At least one independent value must be specified'
     217        #raise msg
    219218
    220219    missing = []
    221     for quantity in ['x', 'y', 'time'] + quantity_names:
     220       
     221    for quantity in ['time'] + quantity_names:
    222222        if not fid.variables.has_key(quantity):
    223223            missing.append(quantity)
     
    226226        msg = 'Quantities %s could not be found in file %s'\
    227227              %(str(missing), filename)
     228        fid.close()
    228229        raise msg
     230
     231    #Decide whether this data has a spatial dimension
     232    spatial = True
     233    for quantity in ['x', 'y']:
     234        if not fid.variables.has_key(quantity):
     235            spatial = False
     236
    229237
    230238
     
    236244        raise msg
    237245
    238     #Get origin
    239     xllcorner = fid.xllcorner[0]
    240     yllcorner = fid.yllcorner[0]
    241 
    242 
    243246    #Get variables
    244     if verbose: print 'Get variables'
    245     x = fid.variables['x'][:]
    246     y = fid.variables['y'][:]
    247     triangles = fid.variables['volumes'][:]
    248     time = fid.variables['time'][:]
    249 
    250     x = reshape(x, (len(x),1))
    251     y = reshape(y, (len(y),1))
    252     vertex_coordinates = concatenate((x,y), axis=1) #m x 2 array
     247    if verbose: print 'Get variables'   
     248    time = fid.variables['time'][:]   
     249
     250    if spatial:
     251        #Get origin
     252        xllcorner = fid.xllcorner[0]
     253        yllcorner = fid.yllcorner[0]
     254
     255        x = fid.variables['x'][:]
     256        y = fid.variables['y'][:]
     257        triangles = fid.variables['volumes'][:]
     258
     259        x = reshape(x, (len(x),1))
     260        y = reshape(y, (len(y),1))
     261        vertex_coordinates = concatenate((x,y), axis=1) #m x 2 array
     262
    253263
    254264    if domain is not None:
     
    277287        print '  References:'
    278288        #print '    Datum ....' #FIXME
    279         print '    Lower left corner: [%f, %f]'\
    280               %(xllcorner, yllcorner)
     289        if spatial:
     290            print '    Lower left corner: [%f, %f]'\
     291                  %(xllcorner, yllcorner)
    281292        print '    Start time:   %f' %starttime               
    282293       
     
    292303
    293304    from least_squares import Interpolation_function
     305
     306    if not spatial:
     307        vertex_coordinates = triangles = interpolation_points = None         
     308       
    294309    return Interpolation_function(time,
    295310                                  quantities,
     
    299314                                  interpolation_points,
    300315                                  verbose = verbose)
    301 
    302 
    303 
    304 
    305 
    306 
    307 
    308 
    309 
    310 
    311 
    312 
    313 
    314 
    315 #FIXME Obsolete
    316 class File_function_NetCDF:
    317     """Read time history of spatial data from NetCDF sww file and
    318     return a callable object f(t,x,y)
    319     which will return interpolated values based on the input file.
    320 
    321     x, y may be either scalars or vectors
    322 
    323     #FIXME: More about format, interpolation and order of quantities
    324 
    325     The quantities returned by the callable objects are specified by
    326     the list quantities which must contain the names of the
    327     quantities to be returned and also reflect the order, e.g. for
    328     the shallow water wave equation, on would have
    329     quantities = ['stage', 'xmomentum', 'ymomentum']
    330 
    331     interpolation_points decides at which points interpolated
    332     quantities are to be computed whenever object is called.
    333     If None, return average value
    334     """
    335 
    336     def  __init__(self, filename, domain=None, quantities=None,
    337                   interpolation_points=None, verbose = False):
    338         """Initialise callable object from a file.
    339 
    340         If domain is specified, model time (domain.starttime)
    341         will be checked and possibly modified
    342 
    343         All times are assumed to be in UTC
    344         """
    345 
    346         #FIXME: Check that model origin is the same as file's origin
    347         #(both in UTM coordinates)
    348         #If not - modify those from file to match domain
    349         #Take this code from e.g. dem2pts in data_manager.py
    350         #FIXME: Use geo_reference to read and write xllcorner...
    351        
    352 
    353         import time, calendar
    354         from config import time_format
    355         from Scientific.IO.NetCDF import NetCDFFile
    356 
    357         #Open NetCDF file
    358         if verbose: print 'Reading', filename
    359         fid = NetCDFFile(filename, 'r')
    360 
    361         if quantities is None or len(quantities) < 1:
    362             msg = 'ERROR: At least one independent value must be specified'
    363             raise msg
    364 
    365         missing = []
    366         for quantity in ['x', 'y', 'time'] + quantities:
    367              if not fid.variables.has_key(quantity):
    368                  missing.append(quantity)
    369 
    370         if len(missing) > 0:
    371             msg = 'Quantities %s could not be found in file %s'\
    372                   %(str(missing), filename)
    373             raise msg
    374 
    375 
    376         #Get first timestep
    377         try:
    378             self.starttime = fid.starttime[0]
    379         except ValueError:
    380             msg = 'Could not read starttime from file %s' %filename
    381             raise msg
    382 
    383         #Get origin
    384         self.xllcorner = fid.xllcorner[0]
    385         self.yllcorner = fid.yllcorner[0]
    386 
    387         self.number_of_values = len(quantities)
    388         self.fid = fid
    389         self.filename = filename
    390         self.quantities = quantities
    391         self.domain = domain
    392         self.interpolation_points = interpolation_points
    393 
    394         if domain is not None:
    395             msg = 'WARNING: Start time as specified in domain (%f)'\
    396                   %domain.starttime
    397             msg += ' is earlier than the starttime of file %s (%f).'\
    398                      %(self.filename, self.starttime)
    399             msg += ' Modifying domain starttime accordingly.'
    400             if self.starttime > domain.starttime:
    401                 if verbose: print msg
    402                 domain.starttime = self.starttime #Modifying model time
    403                 if verbose: print 'Domain starttime is now set to %f'\
    404                    %domain.starttime
    405 
    406         #Read all data in and produce values for desired data points at
    407         #each timestep
    408         self.spatial_interpolation(interpolation_points, verbose = verbose)
    409         fid.close()
    410 
    411     def spatial_interpolation(self, interpolation_points, verbose = False):
    412         """For each timestep in fid: read surface,
    413         interpolate to desired points and store values for use when
    414         object is called.
    415         """
    416 
    417         from Numeric import array, zeros, Float, alltrue, concatenate, reshape
    418 
    419         from config import time_format
    420         from least_squares import Interpolation
    421         import time, calendar
    422 
    423         fid = self.fid
    424 
    425         #Get variables
    426         if verbose: print 'Get variables'
    427         x = fid.variables['x'][:]
    428         y = fid.variables['y'][:]
    429         #z = fid.variables['elevation'][:]
    430         triangles = fid.variables['volumes'][:]
    431         time = fid.variables['time'][:]
    432 
    433         #Check
    434         msg = 'File %s must list time as a monotonuosly ' %self.filename
    435         msg += 'increasing sequence'
    436         assert alltrue(time[1:] - time[:-1] > 0 ), msg
    437 
    438 
    439         if interpolation_points is not None:
    440 
    441             try:
    442                 P = ensure_numeric(interpolation_points)
    443             except:
    444                 msg = 'Interpolation points must be an N x 2 Numeric array or a list of points\n'
    445                 msg += 'I got: %s.' %( str(interpolation_points)[:60] + '...')
    446                 raise msg
    447 
    448 
    449             self.T = time[:]  #Time assumed to be relative to starttime
    450             self.index = 0    #Initial time index
    451 
    452             self.values = {}
    453             for name in self.quantities:
    454                 self.values[name] = zeros( (len(self.T),
    455                                             len(interpolation_points)),
    456                                             Float)
    457 
    458             #Build interpolator
    459             if verbose: print 'Build interpolation matrix'
    460             x = reshape(x, (len(x),1))
    461             y = reshape(y, (len(y),1))
    462             vertex_coordinates = concatenate((x,y), axis=1) #m x 2 array
    463 
    464             interpol = Interpolation(vertex_coordinates,
    465                                      triangles,
    466                                      point_coordinates = P,
    467                                      alpha = 0,
    468                                      verbose = verbose)
    469 
    470 
    471             if verbose: print 'Interpolate'
    472             for i, t in enumerate(self.T):
    473                 #Interpolate quantities at this timestep
    474                 if verbose: print ' time step %d of %d' %(i, len(self.T))
    475                 for name in self.quantities:
    476                     self.values[name][i, :] =\
    477                     interpol.interpolate(fid.variables[name][i,:])
    478 
    479             #Report
    480             if verbose:
    481                 print '------------------------------------------------'
    482                 print 'File_function statistics:'
    483                 print '  Name: %s' %self.filename
    484                 print '  References:'
    485                 #print '    Datum ....' #FIXME
    486                 print '    Lower left corner: [%f, %f]'\
    487                       %(self.xllcorner, self.yllcorner)
    488                 print '    Start time:   %f' %self.starttime               
    489                 #print '    Start time (file):   %f' %self.starttime
    490                 #print '    Start time (domain): %f' %domain.starttime
    491                 print '  Extent:'
    492                 print '    x in [%f, %f], len(x) == %d'\
    493                       %(min(x.flat), max(x.flat), len(x.flat))
    494                 print '    y in [%f, %f], len(y) == %d'\
    495                       %(min(y.flat), max(y.flat), len(y.flat))
    496                 print '    t in [%f, %f], len(t) == %d'\
    497                       %(min(self.T), max(self.T), len(self.T))
    498                 print '  Quantities:'
    499                 for name in self.quantities:
    500                     q = fid.variables[name][:].flat
    501                     print '    %s in [%f, %f]' %(name, min(q), max(q))
    502 
    503 
    504                 print '  Interpolation points (xi, eta):'\
    505                       'number of points == %d ' %P.shape[0]
    506                 print '    xi in [%f, %f]' %(min(P[:,0]), max(P[:,0]))
    507                 print '    eta in [%f, %f]' %(min(P[:,1]), max(P[:,1]))
    508                 print '  Interpolated quantities (over all timesteps):'
    509                 for name in self.quantities:
    510                     q = self.values[name][:].flat
    511                     print '    %s at interpolation points in [%f, %f]'\
    512                           %(name, min(q), max(q))
    513                 print '------------------------------------------------'
    514         else:
    515             msg = 'File_function_NetCDF must be invoked with '
    516             msg += 'a list of interpolation points'
    517             raise msg
    518             #FIXME: Should not be an error.
    519             #__call__ could return an average or in case of time series only
    520             #no point s are needed
    521 
    522 
    523     def __repr__(self):
    524         return 'File function'
    525 
    526     def __call__(self, t, x=None, y=None, point_id = None):
    527         """Evaluate f(t, point_id)
    528 
    529         Inputs:
    530           t: time - Model time (tau = domain.starttime-self.starttime+t)
    531                     must lie within existing timesteps
    532           point_id: index of one of the preprocessed points.
    533                     If point_id is None all preprocessed points are computed
    534 
    535           FIXME: point_id could also be a slice
    536           FIXME: One could allow arbitrary x, y coordinates
    537           (requires computation of a new interpolator)
    538           Maybe not,.,.
    539           FIXME: What if x and y are vectors?
    540         """
    541 
    542         from math import pi, cos, sin, sqrt
    543         from Numeric import zeros, Float
    544 
    545 
    546         if point_id is None:
    547             msg = 'NetCDF File function needs a point_id when invoked'
    548             raise msg
    549 
    550 
    551         #Find time tau such that
    552         #
    553         # domain.starttime + t == self.starttime + tau
    554 
    555         if self.domain is not None:
    556             tau = self.domain.starttime-self.starttime+t
    557         else:
    558             tau = t
    559 
    560 
    561         msg = 'Time interval derived from file %s [%s:%s]'\
    562               %(self.filename, self.T[0], self.T[1])
    563         msg += ' does not match model time: %s\n' %tau
    564         msg += 'Domain says its starttime == %f' %(self.domain.starttime)
    565 
    566         if tau < self.T[0]: raise msg
    567         if tau > self.T[-1]: raise msg
    568 
    569 
    570         oldindex = self.index #Time index
    571 
    572         #Find time slot
    573         while tau > self.T[self.index]: self.index += 1
    574         while tau < self.T[self.index]: self.index -= 1
    575 
    576 
    577         if tau == self.T[self.index]:
    578             #Protect against case where tau == T[-1] (last time)
    579             # - also works in general when tau == T[i]
    580             ratio = 0
    581         else:
    582             #t is now between index and index+1
    583             ratio = (tau - self.T[self.index])/\
    584                     (self.T[self.index+1] - self.T[self.index])
    585 
    586 
    587 
    588 
    589         #Compute interpolated values
    590         q = zeros( len(self.quantities), Float)
    591 
    592         for i, name in enumerate(self.quantities):
    593             Q = self.values[name]
    594 
    595             if ratio > 0:
    596                 q[i] = Q[self.index, point_id] +\
    597                        ratio*(Q[self.index+1, point_id] -\
    598                               Q[self.index, point_id])
    599             else:
    600                 q[i] = Q[self.index, point_id]
    601 
    602 
    603 
    604         #Return vector of interpolated values
    605         return q
    606 
    607 #FIXME Obsolete
    608 class File_function_ASCII:
    609     """Read time series from file and return a callable object:
    610     f(t,x,y)
    611     which will return interpolated values based on the input file.
    612 
    613     The file format is assumed to be either two fields separated by a comma:
    614 
    615         time [DD/MM/YY hh:mm:ss], value0 value1 value2 ...
    616 
    617     or four comma separated fields
    618 
    619         time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ...
    620 
    621     In either case, the callable object will return a tuple of
    622     interpolated values, one each value stated in the file.
    623 
    624 
    625     E.g
    626 
    627       31/08/04 00:00:00, 1.328223 0 0
    628       31/08/04 00:15:00, 1.292912 0 0
    629 
    630     will provide a time dependent function f(t,x=None,y=None),
    631     ignoring x and y, which returns three values per call.
    632 
    633 
    634     NOTE: At this stage the function is assumed to depend on
    635     time only, i.e  no spatial dependency!!!!!
    636     When that is needed we can use the least_squares interpolation.
    637 
    638     #FIXME: This should work with netcdf (e.g. sww) and thus render the
    639     #spatio-temporal boundary condition in shallow water fully general
    640 
    641     #FIXME: Specified quantites not used here -
    642     #always return whatever is in the file
    643     """
    644 
    645 
    646     def __init__(self, filename, domain=None, quantities = None, interpolation_points=None):
    647         """Initialise callable object from a file.
    648         See docstring for class File_function
    649 
    650         If domain is specified, model time (domain,starttime)
    651         will be checked and possibly modified
    652 
    653         All times are assumed to be in UTC
    654         """
    655 
    656         import time, calendar
    657         from Numeric import array
    658         from config import time_format
    659 
    660         fid = open(filename)
    661         line = fid.readline()
    662         fid.close()
    663 
    664         fields = line.split(',')
    665         msg = 'File %s must have the format date, value0 value1 value2 ...'
    666         msg += ' or date, x, y, value0 value1 value2 ...'
    667         mode = len(fields)
    668         assert mode in [2,4], msg
    669 
    670         #time.strptime(fields[0], time_format)
    671         try:
    672             starttime = calendar.timegm(time.strptime(fields[0], time_format))
    673         except ValueError:
    674             msg = 'First field in file %s must be' %filename
    675             msg += ' date-time with format %s.\n' %time_format
    676             msg += 'I got %s instead.' %fields[0]
    677             raise msg
    678 
    679 
    680         #Split values
    681         values = []
    682         for value in fields[mode-1].split():
    683             values.append(float(value))
    684 
    685         q = ensure_numeric(values)
    686 
    687         msg = 'ERROR: File must contain at least one independent value'
    688         assert len(q.shape) == 1, msg
    689 
    690         self.number_of_values = len(q)
    691 
    692         self.filename = filename
    693         self.starttime = starttime
    694         self.domain = domain
    695 
    696         if domain is not None:
    697             msg = 'WARNING: Start time as specified in domain (%s)'\
    698                   %domain.starttime
    699             msg += ' is earlier than the starttime of file %s: %s.'\
    700                      %(self.filename, self.starttime)
    701             msg += 'Modifying starttime accordingly.'
    702             if self.starttime > domain.starttime:
    703                 #FIXME: Print depending on some verbosity setting
    704                 ##if verbose: print msg
    705                 domain.starttime = self.starttime #Modifying model time
    706 
    707             #if domain.starttime is None:
    708             #    domain.starttime = self.starttime
    709             #else:
    710             #    msg = 'WARNING: Start time as specified in domain (%s)'\
    711             #          %domain.starttime
    712             #    msg += ' is earlier than the starttime of file %s: %s.'\
    713             #             %(self.filename, self.starttime)
    714             #    msg += 'Modifying starttime accordingly.'
    715             #    if self.starttime > domain.starttime:
    716             #        #FIXME: Print depending on some verbosity setting
    717             #        #print msg
    718             #        domain.starttime = self.starttime #Modifying model time
    719 
    720         if mode == 2:
    721             self.read_times() #Now read all times in.
    722         else:
    723             raise 'x,y dependency not yet implemented'
    724 
    725 
    726     def read_times(self):
    727         """Read time and values
    728         """
    729         from Numeric import zeros, Float, alltrue
    730         from config import time_format
    731         import time, calendar
    732 
    733         fid = open(self.filename)
    734         lines = fid.readlines()
    735         fid.close()
    736 
    737         N = len(lines)
    738         d = self.number_of_values
    739 
    740         T = zeros(N, Float)       #Time
    741         Q = zeros((N, d), Float)  #Values
    742 
    743         for i, line in enumerate(lines):
    744             fields = line.split(',')
    745             realtime = calendar.timegm(time.strptime(fields[0], time_format))
    746 
    747             T[i] = realtime - self.starttime
    748 
    749             for j, value in enumerate(fields[1].split()):
    750                 Q[i, j] = float(value)
    751 
    752         msg = 'File %s must list time as a monotonuosly ' %self.filename
    753         msg += 'increasing sequence'
    754         assert alltrue( T[1:] - T[:-1] > 0 ), msg
    755 
    756         self.T = T     #Time
    757         self.Q = Q     #Values
    758         self.index = 0 #Initial index
    759 
    760 
    761     def __repr__(self):
    762         return 'File function'
    763 
    764     def __call__(self, t, x=None, y=None, point_id=None):
    765         """Evaluate f(t,x,y)
    766 
    767         FIXME: x, y dependency not yet implemented except that
    768         result is a vector of same length as x and y
    769         FIXME: Naaaa
    770 
    771         FIXME: Rethink semantics when x,y are vectors.
    772         """
    773 
    774         from math import pi, cos, sin, sqrt
    775 
    776 
    777         #Find time tau such that
    778         #
    779         # domain.starttime + t == self.starttime + tau
    780 
    781         if self.domain is not None:
    782             tau = self.domain.starttime-self.starttime+t
    783         else:
    784             tau = t
    785 
    786 
    787         msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\
    788               %(self.filename, self.T[0], self.T[1], tau)
    789         if tau < self.T[0]: raise msg
    790         if tau > self.T[-1]: raise msg
    791 
    792         oldindex = self.index
    793 
    794         #Find slot
    795         while tau > self.T[self.index]: self.index += 1
    796         while tau < self.T[self.index]: self.index -= 1
    797 
    798         #t is now between index and index+1
    799         ratio = (tau - self.T[self.index])/\
    800                 (self.T[self.index+1] - self.T[self.index])
    801 
    802         #Compute interpolated values
    803         q = self.Q[self.index,:] +\
    804             ratio*(self.Q[self.index+1,:] - self.Q[self.index,:])
    805 
    806         #Return vector of interpolated values
    807         if x == None and y == None:
    808             return q
    809         else:
    810             try:
    811                 N = len(x)
    812             except:
    813                 return q
    814             else:
    815                 from Numeric import ones, Float
    816                 #x is a vector - Create one constant column for each value
    817                 N = len(x)
    818                 assert len(y) == N, 'x and y must have same length'
    819 
    820                 res = []
    821                 for col in q:
    822                     res.append(col*ones(N, Float))
    823 
    824                 return res
    825 
    826 
    827 #FIXME: TEMP
    828 class File_function_copy:
    829     """Read time series from file and return a callable object:
    830     f(t,x,y)
    831     which will return interpolated values based on the input file.
    832 
    833     The file format is assumed to be either two fields separated by a comma:
    834 
    835         time [DD/MM/YY hh:mm:ss], value0 value1 value2 ...
    836 
    837     or four comma separated fields
    838 
    839         time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ...
    840 
    841     In either case, the callable object will return a tuple of
    842     interpolated values, one each value stated in the file.
    843 
    844 
    845     E.g
    846 
    847       31/08/04 00:00:00, 1.328223 0 0
    848       31/08/04 00:15:00, 1.292912 0 0
    849 
    850     will provide a time dependent function f(t,x=None,y=None),
    851     ignoring x and y, which returns three values per call.
    852 
    853 
    854     NOTE: At this stage the function is assumed to depend on
    855     time only, i.e  no spatial dependency!!!!!
    856     When that is needed we can use the least_squares interpolation.
    857 
    858     #FIXME: This should work with netcdf (e.g. sww) and thus render the
    859     #spatio-temporal boundary condition in shallow water fully general
    860     """
    861 
    862 
    863     def __init__(self, filename, domain=None):
    864         """Initialise callable object from a file.
    865         See docstring for class File_function
    866 
    867         If domain is specified, model time (domain,starttime)
    868         will be checked and possibly modified
    869 
    870         All times are assumed to be in UTC
    871         """
    872 
    873         import time, calendar
    874         from Numeric import array
    875         from config import time_format
    876 
    877         assert type(filename) == type(''),\
    878                'First argument to File_function must be a string'
    879 
    880 
    881         try:
    882             fid = open(filename)
    883         except Exception, e:
    884             msg = 'File "%s" could not be opened: Error="%s"'\
    885                   %(filename, e)
    886             raise msg
    887 
    888 
    889         line = fid.readline()
    890         fid.close()
    891         fields = line.split(',')
    892         msg = 'File %s must have the format date, value0 value1 value2 ...'
    893         msg += ' or date, x, y, value0 value1 value2 ...'
    894         mode = len(fields)
    895         assert mode in [2,4], msg
    896 
    897         try:
    898             starttime = calendar.timegm(time.strptime(fields[0], time_format))
    899         except ValueError:
    900             msg = 'First field in file %s must be' %filename
    901             msg += ' date-time with format %s.\n' %time_format
    902             msg += 'I got %s instead.' %fields[0]
    903             raise msg
    904 
    905 
    906         #Split values
    907         values = []
    908         for value in fields[mode-1].split():
    909             values.append(float(value))
    910 
    911         q = ensure_numeric(values)
    912 
    913         msg = 'ERROR: File must contain at least one independent value'
    914         assert len(q.shape) == 1, msg
    915 
    916         self.number_of_values = len(q)
    917 
    918         self.filename = filename
    919         self.starttime = starttime
    920         self.domain = domain
    921 
    922         if domain is not None:
    923             if domain.starttime is None:
    924                 domain.starttime = self.starttime
    925             else:
    926                 msg = 'WARNING: Start time as specified in domain (%s)'\
    927                       %domain.starttime
    928                 msg += ' is earlier than the starttime of file %s: %s.'\
    929                          %(self.filename, self.starttime)
    930                 msg += 'Modifying starttime accordingly.'
    931                 if self.starttime > domain.starttime:
    932                     #FIXME: Print depending on some verbosity setting
    933                     #print msg
    934                     domain.starttime = self.starttime #Modifying model time
    935 
    936         if mode == 2:
    937             self.read_times() #Now read all times in.
    938         else:
    939             raise 'x,y dependency not yet implemented'
    940 
    941 
    942     def read_times(self):
    943         """Read time and values
    944         """
    945         from Numeric import zeros, Float, alltrue
    946         from config import time_format
    947         import time, calendar
    948 
    949         fid = open(self.filename)
    950         lines = fid.readlines()
    951         fid.close()
    952 
    953         N = len(lines)
    954         d = self.number_of_values
    955 
    956         T = zeros(N, Float)       #Time
    957         Q = zeros((N, d), Float)  #Values
    958 
    959         for i, line in enumerate(lines):
    960             fields = line.split(',')
    961             realtime = calendar.timegm(time.strptime(fields[0], time_format))
    962 
    963             T[i] = realtime - self.starttime
    964 
    965             for j, value in enumerate(fields[1].split()):
    966                 Q[i, j] = float(value)
    967 
    968         msg = 'File %s must list time as a monotonuosly ' %self.filename
    969         msg += 'increasing sequence'
    970         assert alltrue( T[1:] - T[:-1] > 0 ), msg
    971 
    972         self.T = T     #Time
    973         self.Q = Q     #Values
    974         self.index = 0 #Initial index
    975 
    976 
    977     def __repr__(self):
    978         return 'File function'
    979 
    980 
    981 
    982     def __call__(self, t, x=None, y=None):
    983         """Evaluate f(t,x,y)
    984 
    985         FIXME: x, y dependency not yet implemented except that
    986         result is a vector of same length as x and y
    987         FIXME: Naaaa
    988         """
    989 
    990         from math import pi, cos, sin, sqrt
    991 
    992 
    993         #Find time tau such that
    994         #
    995         # domain.starttime + t == self.starttime + tau
    996 
    997         if self.domain is not None:
    998             tau = self.domain.starttime-self.starttime+t
    999         else:
    1000             tau = t
    1001 
    1002 
    1003         msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\
    1004               %(self.filename, self.T[0], self.T[1], tau)
    1005         if tau < self.T[0]: raise msg
    1006         if tau > self.T[-1]: raise msg
    1007 
    1008         oldindex = self.index
    1009 
    1010         #Find slot
    1011         while tau > self.T[self.index]: self.index += 1
    1012         while tau < self.T[self.index]: self.index -= 1
    1013 
    1014         #t is now between index and index+1
    1015         ratio = (tau - self.T[self.index])/\
    1016                 (self.T[self.index+1] - self.T[self.index])
    1017 
    1018         #Compute interpolated values
    1019         q = self.Q[self.index,:] +\
    1020             ratio*(self.Q[self.index+1,:] - self.Q[self.index,:])
    1021 
    1022         #Return vector of interpolated values
    1023         if x == None and y == None:
    1024             return q
    1025         else:
    1026             try:
    1027                 N = len(x)
    1028             except:
    1029                 return q
    1030             else:
    1031                 from Numeric import ones, Float
    1032                 #x is a vector - Create one constant column for each value
    1033                 N = len(x)
    1034                 assert len(y) == N, 'x and y must have same length'
    1035 
    1036                 res = []
    1037                 for col in q:
    1038                     res.append(col*ones(N, Float))
    1039 
    1040                 return res
     316   
     317
     318
    1041319
    1042320
     
    1052330    """
    1053331    #FIXME: Probably obsoleted by similar function in load_ASCII
    1054     #FIXE: Name read_data_points (or see 'load' in pylab)
     332    #FIXME: Name read_data_points (or see 'load' in pylab)
    1055333
    1056334    from Scientific.IO.NetCDF import NetCDFFile
     
    1512790    to check if a tsh/msh file 'looks' good.
    1513791    """
     792
     793    #FIXME Move to data_manager
    1514794    from shallow_water import Domain
    1515795    from pmesh2domain import pmesh_to_domain_instance
     
    1596876
    1597877
    1598 
    1599 
    1600 #OBSOLETED STUFF
    1601 def inside_polygon_old(point, polygon, closed = True, verbose = False):
    1602     #FIXME Obsoleted
    1603     """Determine whether points are inside or outside a polygon
    1604 
    1605     Input:
    1606        point - Tuple of (x, y) coordinates, or list of tuples
    1607        polygon - list of vertices of polygon
    1608        closed - (optional) determine whether points on boundary should be
    1609        regarded as belonging to the polygon (closed = True)
    1610        or not (closed = False)
    1611 
    1612     Output:
    1613        If one point is considered, True or False is returned.
    1614        If multiple points are passed in, the function returns indices
    1615        of those points that fall inside the polygon
    1616 
    1617     Examples:
    1618        U = [[0,0], [1,0], [1,1], [0,1]] #Unit square
    1619        inside_polygon( [0.5, 0.5], U)
    1620        will evaluate to True as the point 0.5, 0.5 is inside the unit square
    1621 
    1622        inside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U)
    1623        will return the indices [0, 2] as only the first and the last point
    1624        is inside the unit square
    1625 
    1626     Remarks:
    1627        The vertices may be listed clockwise or counterclockwise and
    1628        the first point may optionally be repeated.
    1629        Polygons do not need to be convex.
    1630        Polygons can have holes in them and points inside a hole is
    1631        regarded as being outside the polygon.
    1632 
    1633 
    1634     Algorithm is based on work by Darel Finley,
    1635     http://www.alienryderflex.com/polygon/
    1636 
    1637     """
    1638 
    1639     from Numeric import array, Float, reshape
    1640 
    1641 
    1642     #Input checks
    1643     try:
    1644         point = array(point).astype(Float)
    1645     except:
    1646         msg = 'Point %s could not be converted to Numeric array' %point
    1647         raise msg
    1648 
    1649     try:
    1650         polygon = array(polygon).astype(Float)
    1651     except:
    1652         msg = 'Polygon %s could not be converted to Numeric array' %polygon
    1653         raise msg
    1654 
    1655     assert len(polygon.shape) == 2,\
    1656        'Polygon array must be a 2d array of vertices: %s' %polygon
    1657 
    1658 
    1659     assert polygon.shape[1] == 2,\
    1660        'Polygon array must have two columns: %s' %polygon
    1661 
    1662 
    1663     if len(point.shape) == 1:
    1664         one_point = True
    1665         points = reshape(point, (1,2))
    1666     else:
    1667         one_point = False
    1668         points = point
    1669 
    1670     N = polygon.shape[0] #Number of vertices in polygon
    1671     M = points.shape[0]  #Number of points
    1672 
    1673     px = polygon[:,0]
    1674     py = polygon[:,1]
    1675 
    1676     #Used for an optimisation when points are far away from polygon
    1677     minpx = min(px); maxpx = max(px)
    1678     minpy = min(py); maxpy = max(py)
    1679 
    1680 
    1681     #Begin main loop (FIXME: It'd be crunchy to have this written in C:-)
    1682     indices = []
    1683     for k in range(M):
    1684 
    1685         if verbose:
    1686             if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M)
    1687 
    1688         #for each point
    1689         x = points[k, 0]
    1690         y = points[k, 1]
    1691 
    1692         inside = False
    1693 
    1694         #Optimisation
    1695         if x > maxpx or x < minpx: continue
    1696         if y > maxpy or y < minpy: continue
    1697 
    1698         #Check polygon
    1699         for i in range(N):
    1700             j = (i+1)%N
    1701 
    1702             #Check for case where point is contained in line segment
    1703             if point_on_line(x, y, px[i], py[i], px[j], py[j]):
    1704                 if closed:
    1705                     inside = True
    1706                 else:
    1707                     inside = False
    1708                 break
    1709             else:
    1710                 #Check if truly inside polygon
    1711                 if py[i] < y and py[j] >= y or\
    1712                    py[j] < y and py[i] >= y:
    1713                     if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x:
    1714                         inside = not inside
    1715 
    1716         if inside: indices.append(k)
    1717 
    1718     if one_point:
    1719         return inside
    1720     else:
    1721         return indices
    1722 
    1723 
    1724 #def remove_from(A, B):
    1725 #    """Assume that A
    1726 #    """
    1727 #    from Numeric import search_sorted##
    1728 #
    1729 #    ind = search_sorted(A, B)
    1730 
    1731 
    1732 
    1733 def outside_polygon_old(point, polygon, closed = True, verbose = False):
    1734     #OBSOLETED
    1735     """Determine whether points are outside a polygon
    1736 
    1737     Input:
    1738        point - Tuple of (x, y) coordinates, or list of tuples
    1739        polygon - list of vertices of polygon
    1740        closed - (optional) determine whether points on boundary should be
    1741        regarded as belonging to the polygon (closed = True)
    1742        or not (closed = False)
    1743 
    1744     Output:
    1745        If one point is considered, True or False is returned.
    1746        If multiple points are passed in, the function returns indices
    1747        of those points that fall outside the polygon
    1748 
    1749     Examples:
    1750        U = [[0,0], [1,0], [1,1], [0,1]] #Unit square
    1751        outside_polygon( [0.5, 0.5], U )
    1752        will evaluate to False as the point 0.5, 0.5 is inside the unit square
    1753 
    1754        ouside_polygon( [1.5, 0.5], U )
    1755        will evaluate to True as the point 1.5, 0.5 is outside the unit square
    1756 
    1757        outside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U )
    1758        will return the indices [1] as only the first and the last point
    1759        is inside the unit square
    1760     """
    1761 
    1762     #FIXME: This is too slow
    1763 
    1764     res  = inside_polygon(point, polygon, closed, verbose)
    1765 
    1766     if res is True or res is False:
    1767         return not res
    1768 
    1769     #Now invert indices
    1770     from Numeric import arrayrange, compress
    1771     outside_indices = arrayrange(len(point))
    1772     for i in res:
    1773         outside_indices = compress(outside_indices != i, outside_indices)
    1774     return outside_indices
    1775 
    1776 def inside_polygon_c(point, polygon, closed = True, verbose = False):
    1777     #FIXME: Obsolete
    1778     """Determine whether points are inside or outside a polygon
    1779 
    1780     C-wrapper
    1781     """
    1782 
    1783     from Numeric import array, Float, reshape, zeros, Int
    1784 
    1785 
    1786     if verbose: print 'Checking input to inside_polygon'
    1787     #Input checks
    1788     try:
    1789         point = array(point).astype(Float)
    1790     except:
    1791         msg = 'Point %s could not be converted to Numeric array' %point
    1792         raise msg
    1793 
    1794     try:
    1795         polygon = array(polygon).astype(Float)
    1796     except:
    1797         msg = 'Polygon %s could not be converted to Numeric array' %polygon
    1798         raise msg
    1799 
    1800     assert len(polygon.shape) == 2,\
    1801        'Polygon array must be a 2d array of vertices: %s' %polygon
    1802 
    1803 
    1804     assert polygon.shape[1] == 2,\
    1805        'Polygon array must have two columns: %s' %polygon
    1806 
    1807 
    1808     if len(point.shape) == 1:
    1809         one_point = True
    1810         points = reshape(point, (1,2))
    1811     else:
    1812         one_point = False
    1813         points = point
    1814 
    1815     from util_ext import inside_polygon
    1816 
    1817     if verbose: print 'Allocating array for indices'
    1818 
    1819     indices = zeros( points.shape[0], Int )
    1820 
    1821     if verbose: print 'Calling C-version of inside poly'
    1822     count = inside_polygon(points, polygon, indices,
    1823                            int(closed), int(verbose))
    1824 
    1825     if one_point:
    1826         return count == 1 #Return True if the point was inside
    1827     else:
    1828         if verbose: print 'Got %d points' %count
    1829 
    1830         return indices[:count]   #Return those indices that were inside
Note: See TracChangeset for help on using the changeset viewer.