def wind_ts(rq_wind): """ setup a wind timeseries - uses the rq_wind fixture to get the wind values used for conversions - returns a dict with the expected datetime_rq, datetime_uv and time_value_pair objects """ date_times = ([sec_to_date(zero_time())] * len(rq_wind['rq'])) dtv_rq = (np.array(zip(date_times, rq_wind['rq']), dtype=datetime_value_2d) .view(dtype=np.recarray)) date_times = ([sec_to_date(zero_time())] * len(rq_wind['uv'])) dtv_uv = (np.array(zip(date_times, rq_wind['uv']), dtype=datetime_value_2d) .view(dtype=np.recarray)) date_times = ([zero_time()] * len(rq_wind['uv'])) tv = (np.array(zip(date_times, rq_wind['uv']), dtype=time_value_pair) .view(dtype=np.recarray)) print 'Test Case - actual values:' print 'datetime_value_2d: datetime, (r, theta):' print dtv_rq.time print dtv_rq.value print '----------' print 'datetime_value_2d: datetime, (u, v):' print dtv_uv.time print dtv_uv.value print '----------' print 'time_value_pair: time, (u, v):' print tv.time print tv.value.reshape(len(tv.value), -1) return {'dtv_rq': dtv_rq, 'dtv_uv': dtv_uv, 'tv': tv}
def test_variable_wind_after_model_time(self): ''' test to make sure the wind mover is behaving properly with out-of-bounds winds. A variable wind should not extrapolate if it is out of bounds, so prepare_for_model_step() should fail with an exception in this case. ''' wind_time = datetime(2012, 8, 21, 13) # one day after model time time_series = (np.zeros((3, ), dtype=datetime_value_2d) .view(dtype=np.recarray)) time_series.time = [sec_to_date(date_to_sec(wind_time) + self.time_step * i) for i in range(3)] time_series.value = np.array(((2., 25.), (2., 25.), (2., 25.))) wind = Wind(timeseries=time_series.reshape(3), units='meter per second') wm = WindMover(wind) wm.prepare_for_model_run() for ix in range(2): curr_time = sec_to_date(date_to_sec(self.model_time) + self.time_step * ix) with raises(RuntimeError): wm.prepare_for_model_step(self.sc, self.time_step, curr_time)
def _convert(x): """ helper method for the next 4 tests """ y = date_to_sec(x) return sec_to_date(y)
def test_get_move_exceptions(self): curr_time = sec_to_date(date_to_sec(self.model_time) + self.time_step) tmp_windages = self.sc._data_arrays['windages'] del self.sc._data_arrays['windages'] with pytest.raises(KeyError): self.wm.get_move(self.sc, self.time_step, curr_time) self.sc._data_arrays['windages'] = tmp_windages
def test_prepare_for_model_step(): """ explicitly test to make sure windages are being updated for persistence != 0 and windages are not being changed for persistance == -1 """ time_step = 15 * 60 # seconds model_time = datetime(2012, 8, 20, 13) # yyyy/month/day/hr/min/sec sc = sample_sc_release(5, (3., 6., 0.), model_time) sc['windage_persist'][:2] = -1 wind = Wind(timeseries=np.array((model_time, (2., 25.)), dtype=datetime_value_2d).reshape(1), units='meter per second') wm = WindMover(wind) wm.prepare_for_model_run() for ix in range(2): curr_time = sec_to_date(date_to_sec(model_time) + time_step * ix) old_windages = np.copy(sc['windages']) wm.prepare_for_model_step(sc, time_step, curr_time) mask = [sc['windage_persist'] == -1] assert np.all(sc['windages'][mask] == old_windages[mask]) mask = [sc['windage_persist'] > 0] assert np.all(sc['windages'][mask] != old_windages[mask])
def to_datetime_value_1d(time_value_pair): ''' converts a numpy array containing basic_types.time_value_pair to a numpy array containing basic_types.datetime_value_1d. It simply drops the 2nd component of value: eg: time_value_pair[0] = ((datetime), (val_0, val_1)) becomes: output = ((datetime), (val_0,)) This is partly used for timeseries for Tide data and in this case, the v-component of velocity (u, v) is 0.0 This function does not perform a check to see if 2nd component is 0.0, it simply drops it. :param time_value_pair: numpy array of type basic_types.time_value_pair ''' if time_value_pair.dtype != basic_types.time_value_pair: raise ValueError('Method expects a numpy array containing ' 'basic_types.time_value_pair') datetime_value_1d = np.zeros((len(time_value_pair), ), dtype=basic_types.datetime_value_1d) datetime_value_1d['time'] = time_utils.sec_to_date(time_value_pair['time']) datetime_value_1d['value'][:] = time_value_pair['value']['u'] return datetime_value_1d
def test_default_init(): wind = Wind() assert wind.timeseries == np.array([(sec_to_date(zero_time()), [0.0, 0.0])], dtype=datetime_value_2d) assert wind.units == 'mps'
def test_get_move(self): """ Test the get_move(...) results in WindMover match the expected delta """ for ix in range(2): curr_time = sec_to_date(date_to_sec(self.model_time) + self.time_step * ix) self.wm.prepare_for_model_step(self.sc, self.time_step, curr_time) delta = self.wm.get_move(self.sc, self.time_step, curr_time) actual = self._expected_move() # the results should be independent of model time tol = 1e-8 msg = ('{0} is not within a tolerance of ' '{1}'.format('WindMover.get_move()', tol)) np.testing.assert_allclose(delta, actual, tol, tol, msg, 0) assert self.wm.active ts = date_to_sec(curr_time) - date_to_sec(self.model_time) print ('Time step [sec]:\t{0}' 'C++ delta-move:\n{1}' 'Expected delta-move:\n{2}' ''.format(ts, delta, actual)) self.wm.model_step_is_done()
def test_constant_wind_after_model_time(self): ''' test to make sure the wind mover is behaving properly with out-of-bounds winds. A constant wind should extrapolate if it is out of bounds, so prepare_for_model_step() should not fail. We are testing that the wind extrapolates properly, so the windages should be updated in the same way as the in-bounds test ''' wind_time = datetime(2012, 8, 21, 13) # one day after model time wind = Wind(timeseries=np.array((wind_time, (2., 25.)), dtype=datetime_value_2d).reshape(1), units='meter per second') wm = WindMover(wind) wm.prepare_for_model_run() for ix in range(2): curr_time = sec_to_date(date_to_sec(self.model_time) + self.time_step * ix) print 'curr_time = ', curr_time old_windages = np.copy(self.sc['windages']) wm.prepare_for_model_step(self.sc, self.time_step, curr_time) mask = self.sc['windage_persist'] == -1 assert np.all(self.sc['windages'][mask] == old_windages[mask]) mask = self.sc['windage_persist'] > 0 assert np.all(self.sc['windages'][mask] != old_windages[mask])
def _convert(x): """ helper method for the next 4 tests """ y = time_utils.date_to_sec(x) return time_utils.sec_to_date(y)
def test_to_date_dst_transition_fall(): seconds = [1478419200, 1478421000, 1478422800, 1478424600, 1478426400, 1478428200] dates = sec_to_date(seconds) diff = np.diff(dates).astype(np.int64) # checks that the interval is constant -- i.e. no repeated or skipped times assert not np.any(np.diff(diff))
def to_datetime_value_2d(time_value_pair, out_ts_format): """ converts a numpy array containing basic_types.time_value_pair to a numpy array containing basic_types.datetime_value_2d in user specified basic_types.ts_format :param time_value_pair: numpy array of type basic_types.time_value_pair :param out_ts_format: desired format of the array defined by one of the options given in basic_types.ts_format """ if time_value_pair.dtype != basic_types.time_value_pair: raise ValueError('Method expects a numpy array containing basic_types.time_value_pair' ) datetime_value_2d = np.zeros((len(time_value_pair), ), dtype=basic_types.datetime_value_2d) if isinstance(out_ts_format, basestring): out_ts_format = tsformat(out_ts_format) # convert time_value_pair to datetime_value_2d in desired output format if out_ts_format == basic_types.ts_format.magnitude_direction: datetime_value_2d['time'] = \ time_utils.sec_to_date(time_value_pair['time']) uv = np.zeros((len(time_value_pair), 2), dtype=np.double) uv[:, 0] = time_value_pair['value']['u'] uv[:, 1] = time_value_pair['value']['v'] datetime_value_2d['value'] = transforms.uv_to_r_theta_wind(uv) elif out_ts_format == basic_types.ts_format.uv: datetime_value_2d['time'] = \ time_utils.sec_to_date(time_value_pair['time']) datetime_value_2d['value'][:, 0] = time_value_pair['value']['u'] datetime_value_2d['value'][:, 1] = time_value_pair['value']['v'] else: raise ValueError('out_ts_format is not one of the two supported types: basic_types.ts_format.magnitude_direction, basic_types.ts_format.uv' ) return datetime_value_2d
def test_to_time_value_pair_from_1d(): length_of_dim1 = 4 zero_times = [sec_to_date(zero_time())] * length_of_dim1 rand_data = np.random.uniform(1, 10, length_of_dim1) data = np.array(zip(zero_times, rand_data), dtype=datetime_value_1d) out_tv = to_time_value_pair(data) assert np.all(out_tv['value']['v'] == 0.0) assert np.all(out_tv['value']['u'] == data['value'])
def to_datetime_value_2d(time_value_pair, out_ts_format): """ converts a numpy array containing basic_types.time_value_pair to a numpy array containing basic_types.datetime_value_2d in user specified basic_types.ts_format :param time_value_pair: numpy array of type basic_types.time_value_pair :param out_ts_format: desired format of the array defined by one of the options given in basic_types.ts_format """ if time_value_pair.dtype != basic_types.time_value_pair: raise ValueError('Method expects a numpy array containing ' 'basic_types.time_value_pair') datetime_value_2d = np.zeros((len(time_value_pair), ), dtype=basic_types.datetime_value_2d) if isinstance(out_ts_format, basestring): out_ts_format = tsformat(out_ts_format) # convert time_value_pair to datetime_value_2d in desired output format if out_ts_format == basic_types.ts_format.magnitude_direction: datetime_value_2d['time'] = \ time_utils.sec_to_date(time_value_pair['time']) uv = np.zeros((len(time_value_pair), 2), dtype=np.double) uv[:, 0] = time_value_pair['value']['u'] uv[:, 1] = time_value_pair['value']['v'] datetime_value_2d['value'] = transforms.uv_to_r_theta_wind(uv) elif out_ts_format == basic_types.ts_format.uv: datetime_value_2d['time'] = \ time_utils.sec_to_date(time_value_pair['time']) datetime_value_2d['value'][:, 0] = time_value_pair['value']['u'] datetime_value_2d['value'][:, 1] = time_value_pair['value']['v'] else: raise ValueError('out_ts_format is not one of the two supported ' 'types: ' 'basic_types.ts_format.magnitude_direction, ' 'basic_types.ts_format.uv') return datetime_value_2d
def test_to_date_dst_transition_spring(): # these are hard coded from what was generated by date_to_sec # they cross the spring transition, and caused a problem. seconds = np.array([1457857800, 1457859600, 1457861400, 1457863200, 1457865000, 1457866800], dtype=np.uint32) dates = sec_to_date(seconds) diff = np.diff(dates).astype(np.int64) # checks that the interval is constant -- i.e. no repeated or skipped times assert not np.any(np.diff(diff))
def test_sec_to_date(self): """ Uses time_utils.secondsToDate_noDST to convert the time in seconds back to a datetime object and make """ tgt = time_utils.round_time(dt=self.now, roundTo=1) act = time_utils.sec_to_date(self.pySec) print print 'expected:\t' + str(tgt) print 'actual: \t' + str(act) assert tgt == act
def test_variable_wind_after_model_time_with_extrapolation(self): ''' test to make sure the wind mover is behaving properly with out-of-bounds winds. A variable wind can extrapolate if it is configured to do so, so prepare_for_model_step() should succeed in this case. We are testing that the wind extrapolates properly, so the windages should be updated in the same way as the in-bounds test ''' wind_time = datetime(2012, 8, 21, 13) # one day after model time time_series = (np.zeros((3, ), dtype=datetime_value_2d) .view(dtype=np.recarray)) time_series.time = [sec_to_date(date_to_sec(wind_time) + self.time_step * i) for i in range(3)] time_series.value = np.array(((2., 25.), (2., 25.), (2., 25.))) wind = Wind(timeseries=time_series.reshape(3), extrapolation_is_allowed=True, units='meter per second') wm = WindMover(wind) wm.prepare_for_model_run() for ix in range(2): curr_time = sec_to_date(date_to_sec(self.model_time) + self.time_step * ix) old_windages = np.copy(self.sc['windages']) wm.prepare_for_model_step(self.sc, self.time_step, curr_time) mask = self.sc['windage_persist'] == -1 assert np.all(self.sc['windages'][mask] == old_windages[mask]) mask = self.sc['windage_persist'] > 0 assert np.all(self.sc['windages'][mask] != old_windages[mask])
def wind_ts(rq_wind): """ setup a wind timeseries - uses the rq_wind fixture to get the wind values used for conversions - returns a dict with the expected datetime_rq, datetime_uv and time_value_pair objects """ date_times = ([sec_to_date(zero_time())] * len(rq_wind['rq'])) dtv_rq = (np.array(zip(date_times, rq_wind['rq']), dtype=datetime_value_2d).view(dtype=np.recarray)) date_times = ([sec_to_date(zero_time())] * len(rq_wind['uv'])) dtv_uv = (np.array(zip(date_times, rq_wind['uv']), dtype=datetime_value_2d).view(dtype=np.recarray)) date_times = ([zero_time()] * len(rq_wind['uv'])) values = zip(date_times, (tuple(w) for w in rq_wind['uv'])) tv = (np.array(values, dtype=time_value_pair).view(dtype=np.recarray)) # print 'Test Case - actual values:' # print 'datetime_value_2d: datetime, (r, theta):' # print dtv_rq.time # print dtv_rq.value # print '----------' # print 'datetime_value_2d: datetime, (u, v):' # print dtv_uv.time # print dtv_uv.value # print '----------' # print 'time_value_pair: time, (u, v):' # print tv.time # print tv.value.reshape(len(tv.value), -1) return {'dtv_rq': dtv_rq, 'dtv_uv': dtv_uv, 'tv': tv}
def __init__(self, wind=None, timeseries=None, past_hours_to_average=3, **kwargs): """ Initializes a running average object from a wind and past hours to average If no wind is given, timeseries gets initialized as: timeseries = np.zeros((1,), dtype=basic_types.datetime_value_2d) units = 'mps' (note: probably should be an error) All other keywords are optional. Optional parameters (kwargs): :param past_hours_to_average: default is 3 """ self.units = 'mps' self.format = 'uv' self._past_hours_to_average = past_hours_to_average self.wind = wind if (wind is None and timeseries is None): mvg_timeseries = np.array([(sec_to_date(zero_time()), [0.0, 0.0])], dtype=basic_types.datetime_value_2d) moving_timeseries = self._convert_to_time_value_pair(mvg_timeseries) else: if wind is not None: moving_timeseries = wind.ossm.create_running_average(self._past_hours_to_average) else: self.wind = Wind(timeseries, units='mps', format='uv') moving_timeseries = self.wind.ossm.create_running_average(self._past_hours_to_average) # print "moving_timeseries" # print moving_timeseries self.ossm = CyTimeseries(timeseries=moving_timeseries) super(RunningAverage, self).__init__(**kwargs)
def __init__(self, wind=None, timeseries=None, past_hours_to_average=3, **kwargs): """ Initializes a running average object from a wind and past hours to average If no wind is given, timeseries gets initialized as: timeseries = np.zeros((1,), dtype=basic_types.datetime_value_2d) units = 'mps' (note: probably should be an error) All other keywords are optional. Optional parameters (kwargs): :param past_hours_to_average: default is 3 """ self.units = 'mps' self.format = 'uv' self._past_hours_to_average = past_hours_to_average self.wind = wind if (wind is None and timeseries is None): mvg_timeseries = np.array([(sec_to_date(zero_time()), [0.0, 0.0])], dtype=basic_types.datetime_value_2d) moving_ts = self._convert_to_time_value_pair(mvg_timeseries) elif wind is not None: moving_ts = (wind.ossm .create_running_average(self._past_hours_to_average)) else: self.wind = Wind(timeseries, units='mps', coord_sys='uv') moving_ts = (self.wind.ossm .create_running_average(self._past_hours_to_average)) self.ossm = CyTimeseries(timeseries=moving_ts) super(RunningAverage, self).__init__(**kwargs)
def test_get_move(self): """ Test the get_move(...) results in WindMover match the expected delta """ self.wm.prepare_for_model_step(self.sc, self.time_step, self.model_time) for ix in range(2): curr_time = sec_to_date(date_to_sec(self.model_time) + self.time_step * ix) delta = self.wm.get_move(self.sc, self.time_step, curr_time) actual = self._expected_move() # the results should be independent of model time tol = 1e-8 msg = '{0} is not within a tolerance of {1}' np.testing.assert_allclose( delta, actual, tol, tol, msg.format('WindMover.get_move()', tol), 0, ) assert self.wm.active == True ts = date_to_sec(curr_time) - date_to_sec(self.model_time) print 'Time step [sec]:\t%s' % ts print 'C++ delta-move:\n%s' % str(delta) print 'Expected delta-move:\n%s' % str(actual) self.wm.model_step_is_done()
def test_windages_updated(self): ''' explicitly test to make sure: - windages are being updated for persistence != 0 and - windages are not being changed for persistance == -1 ''' wind = Wind(timeseries=np.array((self.model_time, (2., 25.)), dtype=datetime_value_2d).reshape(1), units='meter per second') wm = WindMover(wind) wm.prepare_for_model_run() for ix in range(2): curr_time = sec_to_date(date_to_sec(self.model_time) + self.time_step * ix) old_windages = np.copy(self.sc['windages']) wm.prepare_for_model_step(self.sc, self.time_step, curr_time) mask = self.sc['windage_persist'] == -1 assert np.all(self.sc['windages'][mask] == old_windages[mask]) mask = self.sc['windage_persist'] > 0 assert np.all(self.sc['windages'][mask] != old_windages[mask])
assert unknown not in refs # check __contains__ ''' Run the following save/load test on multiple pygnome objects so collect tests here and parametrize it by the objects ''' base_dir = os.path.dirname(__file__) # For WindMover test_save_load in test_wind_mover g_objects = (environment.Tide(testdata['CatsMover']['tide']), environment.Wind(filename=testdata['ComponentMover']['wind']), environment.Wind(timeseries=(sec_to_date(24 * 60 * 60), (0, 0)), units='mps'), environment.Water(temperature=273), movers.random_movers.RandomMover(), movers.CatsMover(testdata['CatsMover']['curr']), movers.CatsMover(testdata['CatsMover']['curr'], tide=environment.Tide(testdata['CatsMover']['tide'])), movers.ComponentMover(testdata['ComponentMover']['curr']), movers.ComponentMover(testdata['ComponentMover']['curr'], wind=environment.Wind(filename=testdata['ComponentMover']['wind'])), movers.RandomVerticalMover(), movers.SimpleMover(velocity=(10.0, 10.0, 0.0)), map.MapFromBNA(testdata['MapFromBNA']['testmap'], 6), outputters.NetCDFOutput(os.path.join(base_dir, u'xtemp.nc')), outputters.Renderer(testdata['Renderer']['bna_sample'], os.path.join(base_dir, 'output_dir')),
def test_default_init(): av = RunningAverage() assert av.timeseries == np.array([(sec_to_date(zero_time()), [0.0, 0.0])], dtype=datetime_value_2d) assert av.units == 'mps'
''' Run the following save/load test on multiple pygnome objects so collect tests here and parametrize it by the objects ''' base_dir = os.path.dirname(__file__) # For WindMover test_save_load in test_wind_mover g_objects = ( GridCurrent.from_netCDF(testdata['GridCurrentMover']['curr_tri']), Tide(testdata['CatsMover']['tide']), Wind(filename=testdata['ComponentMover']['wind']), Wind(timeseries=(sec_to_date(24 * 60 * 60), (0, 0)), units='mps'), Water(temperature=273), RandomMover(), CatsMover(testdata['CatsMover']['curr']), CatsMover(testdata['CatsMover']['curr'], tide=Tide(testdata['CatsMover']['tide'])), ComponentMover(testdata['ComponentMover']['curr']), ComponentMover(testdata['ComponentMover']['curr'], wind=Wind(filename=testdata['ComponentMover']['wind'])), RandomVerticalMover(), SimpleMover(velocity=(10.0, 10.0, 0.0)), map.MapFromBNA(testdata['MapFromBNA']['testmap'], 6), NetCDFOutput(os.path.join(base_dir, u'xtemp.nc')),
def test_round_trip_dst(dt): # does it round-trip? assert dt == sec_to_date(date_to_sec(dt))
nw = ShipDriftMover(wind_file, topology_file, grid_type=2) print print '======================' print 'repr(ShipDriftMover): ' print repr(nw) print print 'str(ShipDriftMover): ' print str(nw) assert True num_le = 4 start_pos = (-123.57152, 37.369436, 0.0) rel_time = datetime.datetime(2006, 3, 31, 21, 0) time_step = 30 * 60 # seconds model_time = time_utils.sec_to_date(time_utils.date_to_sec(rel_time)) def test_loop(): """ test one time step with no uncertainty on the spill checks there is non-zero motion. also checks the motion is same for all LEs """ pSpill = sample_sc_release(num_le, start_pos, rel_time) wind = ShipDriftMover(wind_file, topology_file, grid_type=2) delta = _certain_loop(pSpill, wind) _assert_move(delta)
''' Run the following save/load test on multiple pygnome objects so collect tests here and parametrize it by the objects ''' base_dir = os.path.dirname(__file__) # For WindMover test_save_load in test_wind_mover g_objects = ( environment.environment_objects.GridCurrent.from_netCDF( testdata['GridCurrentMover']['curr_tri']), environment.Tide(testdata['CatsMover']['tide']), environment.Wind(filename=testdata['ComponentMover']['wind']), environment.Wind(timeseries=(sec_to_date(24 * 60 * 60), (0, 0)), units='mps'), environment.Water(temperature=273), movers.random_movers.RandomMover(), movers.CatsMover(testdata['CatsMover']['curr']), movers.CatsMover(testdata['CatsMover']['curr'], tide=environment.Tide(testdata['CatsMover']['tide'])), movers.ComponentMover(testdata['ComponentMover']['curr']), movers.ComponentMover( testdata['ComponentMover']['curr'], wind=environment.Wind(filename=testdata['ComponentMover']['wind'])), movers.RandomVerticalMover(), movers.SimpleMover(velocity=(10.0, 10.0, 0.0)), map.MapFromBNA(testdata['MapFromBNA']['testmap'], 6), outputters.NetCDFOutput(os.path.join(base_dir, u'xtemp.nc')), outputters.Renderer(testdata['Renderer']['bna_sample'],
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 test_default_init(): wind = Wind() assert wind.timeseries == np.array( [(sec_to_date(zero_time()), [0.0, 0.0])], dtype=datetime_value_2d) assert wind.units == 'mps'
assert unknown not in refs # check __contains__ ''' Run the following save/load test on multiple pygnome objects so collect tests here and parametrize it by the objects ''' base_dir = os.path.dirname(__file__) # For WindMover test_save_load in test_wind_mover g_objects = ( GridCurrent.from_netCDF(testdata['GridCurrentMover']['curr_tri']), Tide(testdata['CatsMover']['tide']), Wind(filename=testdata['ComponentMover']['wind']), Wind(timeseries=(sec_to_date(24 * 60 * 60), (0, 0)), units='mps'), Water(temperature=273), RandomMover(), CatsMover(testdata['CatsMover']['curr']), CatsMover(testdata['CatsMover']['curr'], tide=Tide(testdata['CatsMover']['tide'])), ComponentMover(testdata['ComponentMover']['curr']), ComponentMover(testdata['ComponentMover']['curr'], wind=Wind(filename=testdata['ComponentMover']['wind'])), RandomMover3D(), SimpleMover(velocity=(10.0, 10.0, 0.0)), map.MapFromBNA(testdata['MapFromBNA']['testmap'], 6), NetCDFOutput(os.path.join(base_dir, u'xtemp.nc')), Renderer(testdata['Renderer']['bna_sample'], os.path.join(base_dir, 'output_dir')), WeatheringOutput(),
def __init__(self, timeseries=None, units=None, filename=None, coord_sys='r-theta', latitude=None, longitude=None, speed_uncertainty_scale=0.0, extrapolation_is_allowed=False, **kwargs): """ todo: update docstrings! """ self._timeseries = np.array([(sec_to_date(zero_time()), [0.0, 0.0])], dtype=datetime_value_2d) 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') self.speed_uncertainty_scale = speed_uncertainty_scale # TODO: the way we are doing this, super() is not being used # effectively. We should tailor kwargs in a way that we can # just pass it into the base __init__() function. # As it is, we are losing arguments that we then need to # explicitly handle. if filename is not None: self.source_type = kwargs.pop('source_type', 'file') super(Wind, self).__init__(filename=filename, coord_sys=coord_sys, **kwargs) self.name = kwargs.pop('name', os.path.split(self.filename)[1]) # set _user_units attribute to match user_units read from file. self._user_units = self.ossm.user_units self._timeseries = self.get_wind_data(units=self._user_units) if units is not None: self.units = units else: if kwargs.get('source_type') in wind_datasources._attr: self.source_type = kwargs.pop('source_type') else: self.source_type = 'undefined' # either timeseries is given or nothing is given # create an empty default object super(Wind, self).__init__(coord_sys=coord_sys, **kwargs) self.units = 'mps' # units for default object if timeseries is not None: if units is None: raise TypeError('Units must be provided with timeseries') self.units = units self.new_set_timeseries(timeseries, coord_sys) self.extrapolation_is_allowed = extrapolation_is_allowed self.time = kwargs.pop('time', None)
# # file does not exist # IceMover(os.path.join('./', 'ChesBay.CUR')) # # with pytest.raises(OSError): # IceMover(testdata['CurrentCycleMover']['curr_bad_file']) # # with pytest.raises(TypeError): # IceMover(curr_file, topology_file=10) # num_le = 4 start_pos = (-164.01696, 72.921024, 0) rel_time = datetime.datetime(2015, 5, 14, 0) time_step = 15 * 60 # seconds test_time = time_utils.date_to_sec(rel_time) model_time = time_utils.sec_to_date(time_utils.date_to_sec(rel_time)) def test_loop(): """ test one time step with no uncertainty on the spill checks there is non-zero motion. also checks the motion is same for all LEs """ pSpill = sample_sc_release(num_le, start_pos, rel_time) ice_mover = IceMover(ice_file, topology_file) delta = _certain_loop(pSpill, ice_mover) _assert_move(delta)
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)