def _obj_to_create(self, filename): """ open file, read a few lines to determine if it is an ossm file or a shio file """ # mode 'U' means universal newline support fh = open(filename, 'rU') lines = [fh.readline() for i in range(4)] if len(lines[1]) == 0: # look for \r for lines instead of \n lines = string.split(lines[0], '\r', 4) if len(lines[1]) == 0: # if this is still 0, then throw an error! raise ValueError('This does not appear to be a valid file format ' 'that can be read by OSSM or Shio to get ' 'tide information') # look for following keywords to determine if it is a Shio or OSSM file shio_file = ['[StationInfo]', 'Type=', 'Name=', 'Latitude='] if all([shio_file[i] == (lines[i])[:len(shio_file[i])] for i in range(4)]): return CyShioTime(filename) elif len(string.split(lines[3], ',')) == 7: # maybe log / display a warning that v=0 for tide file and will be # ignored # if float( string.split(lines[3],',')[-1]) != 0.0: return CyOSSMTime(filename, file_contains=tsformat('uv')) else: raise ValueError('This does not appear to be a valid file format ' 'that can be read by OSSM or Shio to get ' 'tide information')
def _obj_to_create(self, filename): """ open file, read a few lines to determine if it is an ossm file or a shio file """ # mode 'U' means universal newline support fh = open(filename, 'rU') lines = [fh.readline() for i in range(4)] if len(lines[1]) == 0: # look for \r for lines instead of \n lines = string.split(lines[0], '\r', 4) if len(lines[1]) == 0: # if this is still 0, then throw an error! raise ValueError('This does not appear to be a valid file format ' 'that can be read by OSSM or Shio to get ' 'tide information') # look for following keywords to determine if it is a Shio or OSSM file shio_file = ['[StationInfo]', 'Type=', 'Name=', 'Latitude='] if all([shio_file[i] == (lines[i])[:len(shio_file[i])] for i in range(4)]): return CyShioTime(filename) elif len(string.split(lines[3], ',')) == 7: # maybe log / display a warning that v=0 for tide file and will be # ignored # if float( string.split(lines[3],',')[-1]) != 0.0: return CyTimeseries(filename, file_format=tsformat('uv')) else: raise ValueError('This does not appear to be a valid file format ' 'that can be read by OSSM or Shio to get ' 'tide information')
def __init__(self, timeseries=None, filename=None, format='uv'): """ Initializes a timeseries object from either a timeseries or datafile containing the timeseries. If both timeseries and file are given, it will read data from the file If neither are given, timeseries gets initialized as: timeseries = np.zeros((1,), dtype=basic_types.datetime_value_2d) If user provides timeseries, the default format is 'uv'. The C++ stores the data in 'uv' format - transformations are done in this Python code (set_timeseries(), get_timeseries()). C++ code only transforms the data from 'r-theta' to 'uv' format if data is read from file. And this happens during initialization because C++ stores data in 'uv' format internally. Units option are not included - let derived classes manage units since the units for CyTimeseries (OSSMTimeValue_c) are limited. No unit conversion is performed when get_timeseries, set_timeseries is invoked. It does, however convert between 'uv' and 'r-theta' depending on format specified. Choose format='uv' if no transformation is desired. .. note:: For the Wind datafiles, the units will get read from the file. These are stored in ossm.user_units. It would be ideal to remove units and unit conversion from here, but can't completely do away with it since C++ file reading uses/sets it. But, managing units is responsibility of derived objects. All other keywords are optional :param timeseries: numpy array containing time_value_pair :type timeseries: numpy.ndarray containing basic_types.datetime_value_2d or basic_types.datetime_value_1d. It gets converted to an array containging basic_types.time_value_pair datatype since that's what the C++ code expects :param filename: path to a timeseries file from which to read data. Datafile must contain either a 3 line or a 5 line header with following info: 1. Station Name: name of the station as a string 2. (long, lat, z): station location as tuple containing floats 3. units: for wind this is knots, meteres per second or miles per hour. For datafile containing something other than velocity, this should be 'undefined' Optional parameters (kwargs): :param format: (Optional) default timeseries format is magnitude direction: 'r-theta' :type format: string 'r-theta' or 'uv'. Default is 'r-theta'. Converts string to integer defined by gnome.basic_types.ts_format.* TODO: 'format' is a python builtin keyword. We should not use it as an argument name """ if (timeseries is None and filename is None): timeseries = np.array([(sec_to_date(zero_time()), [0.0, 0.0])], dtype=basic_types.datetime_value_2d) self._filename = filename if filename is None: # will raise an Exception if it fails self._check_timeseries(timeseries) datetime_value_2d = self._xform_input_timeseries(timeseries) time_value_pair = to_time_value_pair(datetime_value_2d, format) self.ossm = CyTimeseries(timeseries=time_value_pair) else: ts_format = tsformat(format) self.ossm = CyTimeseries(filename=self._filename, file_format=ts_format)
def __init__(self, timeseries=None, filename=None, format='uv'): """ Initializes a timeseries object from either a timeseries or datafile containing the timeseries. If both timeseries and file are given, it will read data from the file If neither are given, timeseries gets initialized as: timeseries = np.zeros((1,), dtype=basic_types.datetime_value_2d) If user provides timeseries, the default format is 'uv'. The C++ stores the data in 'uv' format - transformations are done in this Python code (set_timeseries(), get_timeseries()). C++ code only transforms the data from 'r-theta' to 'uv' format if data is read from file. And this happens during initialization because C++ stores data in 'uv' format internally. Units option are not included - let derived classes manage units since the units for CyTimeseries (OSSMTimeValue_c) are limited. No unit conversion is performed when get_timeseries, set_timeseries is invoked. It does, however convert between 'uv' and 'r-theta' depending on format specified. Choose format='uv' if no transformation is desired. .. note:: For the Wind datafiles, the units will get read from the file. These are stored in ossm.user_units. It would be ideal to remove units and unit conversion from here, but can't completely do away with it since C++ file reading uses/sets it. But, managing units is responsibility of derived objects. All other keywords are optional :param timeseries: numpy array containing time_value_pair :type timeseries: numpy.ndarray containing basic_types.datetime_value_2d or basic_types.datetime_value_1d. It gets converted to an array containging basic_types.time_value_pair datatype since that's what the C++ code expects :param filename: path to a timeseries file from which to read data. Datafile must contain either a 3 line or a 5 line header with following info: 1. Station Name: name of the station as a string 2. (long, lat, z): station location as tuple containing floats 3. units: for wind this is knots, meteres per second or miles per hour. For datafile containing something other than velocity, this should be 'undefined' Optional parameters (kwargs): :param format: (Optional) default timeseries format is magnitude direction: 'r-theta' :type format: string 'r-theta' or 'uv'. Default is 'r-theta'. Converts string to integer defined by gnome.basic_types.ts_format.* TODO: 'format' is a python builtin keyword. We should not use it as an argument name """ if (timeseries is None and filename is None): timeseries = np.array([(sec_to_date(zero_time()), [0.0, 0.0])], dtype=basic_types.datetime_value_2d) self._filename = filename if filename is None: if self._check_timeseries(timeseries): datetime_value_2d = self._xform_input_timeseries(timeseries) time_value_pair = to_time_value_pair(datetime_value_2d, format) self.ossm = CyTimeseries(timeseries=time_value_pair) else: raise ValueError('Bad timeseries as input') else: ts_format = tsformat(format) self.ossm = CyTimeseries(filename=self._filename, file_format=ts_format)
def __init__(self, timeseries=None, units=None, filename=None, format='r-theta', latitude=None, longitude=None, **kwargs): """ Initializes a wind object from timeseries or datafile If both are given, it will read data from the file If neither are given, timeseries gets initialized as: timeseries = np.zeros((1,), dtype=basic_types.datetime_value_2d) units = 'mps' If user provides timeseries, they *must* also provide units All other keywords are optional. Optional parameters (kwargs): :param timeseries: numpy array containing time_value_pair :type timeseries: numpy.ndarray[basic_types.time_value_pair, ndim=1] :param filename: path to a long wind file from which to read wind data :param units: units associated with the timeseries data. If 'filename' is given, then units are read in from the file. get_timeseries() will use these as default units to output data, unless user specifies otherwise. These units must be valid as defined in the hazpy unit_conversion module: unit_conversion.GetUnitNames('Velocity') :type units: string, for example: 'knot', 'meter per second', 'mile per hour' etc. Default units for input/output timeseries data :param format: (Optional) default timeseries format is magnitude direction: 'r-theta' :type format: string 'r-theta' or 'uv'. Default is 'r-theta'. Converts string to integer defined by gnome.basic_types.ts_format.* TODO: 'format' is a python builtin keyword. We should not use it as an argument name :param name: (Optional) human readable string for wind object name. Default is filename if data is from file or "Wind Object" :param source_type: (Optional) Default is undefined, but can be one of the following: ['buoy', 'manual', 'undefined', 'file', 'nws'] If data is read from file, then it is 'file' :param latitude: (Optional) latitude of station or location where wind data is obtained from NWS :param longitude: (Optional) longitude of station or location where wind data is obtained from NWS """ if (timeseries is None and filename is None): timeseries = np.zeros((1,), dtype=basic_types.datetime_value_2d) units = 'mps' self._filename = None if not filename: time_value_pair = self._convert_to_time_value_pair(timeseries, units, format) # this has same scope as CyWindMover object # # TODO: move this as a class attribute if we can. # I can see that we are instantiating the class, # but maybe we can find a way to not have to # pickle this attribute when we pickle a Wind instance # self.ossm = CyOSSMTime(timeseries=time_value_pair) self._user_units = units self.source_type = (kwargs.pop('source_type') if kwargs.get('source_type') in basic_types.wind_datasource._attr else 'undefined') self.name = kwargs.pop('name', self.__class__.__name__) else: ts_format = tsformat(format) self._filename = filename self.ossm = CyOSSMTime(filename=self._filename, file_contains=ts_format) self._user_units = self.ossm.user_units self.source_type = 'file' # this must be file self.name = kwargs.pop('name', os.path.split(self.filename)[1]) self.updated_at = kwargs.pop('updated_at', None) self.source_id = kwargs.pop('source_id', 'undefined') self.longitude = longitude self.latitude = latitude self.description = kwargs.pop('description', 'Wind Object') super(Wind, self).__init__(**kwargs)
def __init__(self, **kwargs): """ Initializes a wind object. It only takes keyword arguments as input, these are defined below. Invokes super(Wind,self).__init__(\*\*kwargs) for parent class initialization It requires one of the following to initialize: 1. 'timeseries' along with 'units' or 2. a 'filename' containing a header that defines units amongst other meta data All other keywords are optional. Optional parameters (kwargs): :param timeseries: (Required) numpy array containing time_value_pair :type timeseries: numpy.ndarray[basic_types.time_value_pair, ndim=1] :param filename: path to a long wind file from which to read wind data :param units: units associated with the timeseries data. If 'filename' is given, then units are read in from the file. get_timeseries() will use these as default units to output data, unless user specifies otherwise. These units must be valid as defined in the hazpy unit_conversion module: unit_conversion.GetUnitNames('Velocity') :type units: string, for example: 'knot', 'meter per second', 'mile per hour' etc. Default units for input/output timeseries data :param format: (Optional) default timeseries format is magnitude direction: 'r-theta' :type format: string 'r-theta' or 'uv'. Converts string to integer defined by gnome.basic_types.ts_format.* TODO: 'format' is a python builtin keyword :param name: (Optional) human readable string for wind object name. Default is filename if data is from file or "Wind Object" :param source_type: (Optional) Default is undefined, but can be one of the following: ['buoy', 'manual', 'undefined', 'file', 'nws'] If data is read from file, then it is 'file' :param latitude: (Optional) latitude of station or location where wind data is obtained from NWS :param longitude: (Optional) longitude of station or location where wind data is obtained from NWS Remaining kwargs ('id' if present) are passed onto Environment's __init__ using super. See base class documentation for remaining valid kwargs. """ if 'timeseries' in kwargs and 'filename' in kwargs: raise TypeError('Cannot instantiate Wind object with both timeseries and file as input' ) if 'timeseries' not in kwargs and 'filename' not in kwargs: raise TypeError('Either provide a timeseries or a wind file with a header, containing wind data' ) # default lat/long - can these be set from reading data in the file? self.longitude = None self.latitude = None # format of data 'uv' or 'r-theta'. Default is 'r-theta' # TODO: 'format' is a python builtin keyword format = kwargs.pop('format', 'r-theta') self.description = kwargs.pop('description', 'Wind Object') if 'timeseries' in kwargs: if 'units' not in kwargs: raise TypeError("Provide 'units' argument with the 'timeseries' input" ) timeseries = kwargs.pop('timeseries') units = kwargs.pop('units') self._check_units(units) self._check_timeseries(timeseries, units) timeseries['value'] = self._convert_units(timeseries['value' ], format, units, 'meter per second') # ts_format is checked during conversion time_value_pair = convert.to_time_value_pair(timeseries, format) # this has same scope as CyWindMover object self.ossm = CyOSSMTime(timeseries=time_value_pair) # do not set ossm.user_units since that only has a subset of # possible units self._user_units = units self.name = kwargs.pop('name', 'Wind Object') self.source_type = (kwargs.pop('source_type' ) if kwargs.get('source_type') in basic_types.wind_datasource._attr else 'undefined' ) else: ts_format = convert.tsformat(format) self.ossm = CyOSSMTime(filename=kwargs.pop('filename'), file_contains=ts_format) self._user_units = self.ossm.user_units self.name = kwargs.pop('name', os.path.split(self.ossm.filename)[1]) self.source_type = 'file' # this must be file # For default: if read from file and filename exists, # then use last modified time of file # else # default to datetime.datetime.now # not sure if this should be datetime or string self.updated_at = kwargs.pop('updated_at', (time_utils.sec_to_date(os.path.getmtime(self.ossm.filename)) if self.ossm.filename else datetime.datetime.now())) self.source_id = kwargs.pop('source_id', 'undefined') self.longitude = kwargs.pop('longitude', self.longitude) self.latitude = kwargs.pop('latitude', self.latitude) super(Wind, self).__init__(**kwargs)
def __init__( self, filename=None, timeseries=None, yeardata=os.path.join(os.path.dirname(gnome.__file__), 'data', 'yeardata'), **kwargs ): """ Tide information can be obtained from a filename or set as a timeseries (timeseries is NOT TESTED YET) Invokes super(Tides,self).__init__(\*\*kwargs) for parent class initialization It requires one of the following to initialize: 1. 'timeseries' assumed to be in 'uv' format (NOT TESTED/IMPLEMENTED OR USED YET) 2. a 'filename' containing a header that defines units amongst other meta data :param timeseries: numpy array containing datetime_value_2d, ts_format is always 'uv' :type timeseries: numpy.ndarray[basic_types.time_value_pair, ndim=1] :param units: units associated with the timeseries data. If 'filename' is given, then units are read in from the filename. unit_conversion - NOT IMPLEMENTED YET :type units: (Optional) string, for example: 'knot', 'meter per second', 'mile per hour' etc Default is None for now :param filename: path to a long wind filename from which to read wind data :param yeardata: (Optional) path to yeardata used for Shio data filenames. Default location is gnome/data/yeardata/ Remaining kwargs ('id' if present) are passed onto Environment's __init__ using super. See base class documentation for remaining valid kwargs. """ # define locally so it is available even for OSSM files, # though not used by OSSM files self._yeardata = None if timeseries is None and filename is None: raise ValueError('Either provide timeseries or a valid filename containing Tide data' ) if timeseries is not None: # if units is None: # raise ValueError("Provide valid units as string or unicode " \ # "for timeseries") # will probably need to move this function out # self._check_timeseries(timeseries, units) # data_format is checked during conversion time_value_pair = convert.to_time_value_pair(timeseries, convert.tsformat('uv')) # this has same scope as CyWindMover object self.cy_obj = CyOSSMTime(timeseries=time_value_pair) # not sure what these should be self._user_units = kwargs.pop('units', None) else: # self.filename = os.path.abspath( filename) self.cy_obj = self._obj_to_create(filename) # self.yeardata = os.path.abspath( yeardata ) # set yeardata self.yeardata = yeardata # set yeardata super(Tide, self).__init__(**kwargs)
def test_ts_format(format_): if format_ == 'uv': assert tsformat(format_) == ts_format.uv else: assert tsformat(format_) == ts_format.r_theta