def test_load_variable_non_0001_refdate(load_variable_data_loader, year): def preprocess(ds, **kwargs): # This function converts our testing data (encoded with a units # attribute with a reference data of 0001-01-01) to one # with a reference data of 0004-01-01 (to do so we also need # to offset the raw time values by three years). three_yrs = 1095. ds['time'] = ds['time'] - three_yrs ds['time'].attrs['units'] = 'days since 0004-01-01 00:00:00' ds['time'].attrs['calendar'] = 'noleap' ds['time_bounds'] = ds['time_bounds'] - three_yrs ds['time_bounds'].attrs['units'] = 'days since 0004-01-01 00:00:00' ds['time_bounds'].attrs['calendar'] = 'noleap' return ds load_variable_data_loader.preprocess_func = preprocess result = load_variable_data_loader.load_variable( condensation_rain, DatetimeNoLeap(year, 1, 1), DatetimeNoLeap(year, 12, 31), intvl_in='monthly') filepath = os.path.join( os.path.split(ROOT_PATH)[0], 'netcdf', '000{}0101.precip_monthly.nc'.format(year)) expected = xr.open_dataset(filepath)['condensation_rain'] np.testing.assert_allclose(result.values, expected.values)
def test_load_variable_preprocess(load_variable_data_loader): def preprocess(ds, **kwargs): if kwargs['start_date'] == DatetimeNoLeap(5, 1, 1): ds['condensation_rain'] = 10. * ds['condensation_rain'] return ds load_variable_data_loader.preprocess_func = preprocess result = load_variable_data_loader.load_variable(condensation_rain, DatetimeNoLeap(5, 1, 1), DatetimeNoLeap(5, 12, 31), intvl_in='monthly') filepath = os.path.join( os.path.split(ROOT_PATH)[0], 'netcdf', '00050101.precip_monthly.nc') expected = 10. * xr.open_dataset(filepath)['condensation_rain'] np.testing.assert_allclose(result.values, expected.values) result = load_variable_data_loader.load_variable(condensation_rain, DatetimeNoLeap(4, 1, 1), DatetimeNoLeap(4, 12, 31), intvl_in='monthly') filepath = os.path.join( os.path.split(ROOT_PATH)[0], 'netcdf', '00040101.precip_monthly.nc') expected = xr.open_dataset(filepath)['condensation_rain'] np.testing.assert_allclose(result.values, expected.values)
def test_recursively_compute_grid_attr_error(load_variable_data_loader): # Should fail because zsurf is not provided to the example_model object zsurf = Var(name=ZSURF_STR, def_time=False, def_vert=False, def_lon=True, def_lat=True) with pytest.raises(AttributeError): load_variable_data_loader.recursively_compute_variable( zsurf, DatetimeNoLeap(5, 1, 1), DatetimeNoLeap(5, 12, 31), model=example_model, intvl_in='monthly')
def test_recursively_compute_grid_attr(load_variable_data_loader): result = load_variable_data_loader.recursively_compute_variable( bk, DatetimeNoLeap(5, 1, 1), DatetimeNoLeap(5, 12, 31), model=example_model, intvl_in='monthly') filepath = os.path.join(os.path.split(ROOT_PATH)[0], 'netcdf', '00060101.sphum_monthly.nc') expected = _open_ds_catch_warnings(filepath)['bk'] np.testing.assert_array_equal(result.values, expected.values)
def test_recursively_compute_variable_native(load_variable_data_loader): result = load_variable_data_loader.recursively_compute_variable( condensation_rain, DatetimeNoLeap(5, 1, 1), DatetimeNoLeap(5, 12, 31), intvl_in='monthly') filepath = os.path.join(os.path.split(ROOT_PATH)[0], 'netcdf', '00050101.precip_monthly.nc') expected = _open_ds_catch_warnings(filepath)['condensation_rain'] np.testing.assert_array_equal(result.values, expected.values)
def test_recursively_compute_variable_one_level(load_variable_data_loader): one_level = Var( name='one_level', variables=(condensation_rain, condensation_rain), func=lambda x, y: x + y) result = load_variable_data_loader.recursively_compute_variable( one_level, DatetimeNoLeap(5, 1, 1), DatetimeNoLeap(5, 12, 31), intvl_in='monthly') filepath = os.path.join(os.path.split(ROOT_PATH)[0], 'netcdf', '00050101.precip_monthly.nc') expected = 2. * _open_ds_catch_warnings(filepath)['condensation_rain'] np.testing.assert_array_equal(result.values, expected.values)
def test_recursively_compute_grid_attr_multi_level(load_variable_data_loader): one_level = Var(name='one_level', variables=(bk, ), func=lambda x: 2 * x) multi_level = Var(name='multi_level', variables=(one_level, bk), func=lambda x, y: x + y) result = load_variable_data_loader.recursively_compute_variable( multi_level, DatetimeNoLeap(5, 1, 1), DatetimeNoLeap(5, 12, 31), model=example_model, intvl_in='monthly') filepath = os.path.join( os.path.split(ROOT_PATH)[0], 'netcdf', '00060101.sphum_monthly.nc') expected = 3 * xr.open_dataset(filepath)['bk'] np.testing.assert_array_equal(result.values, expected.values)
def __init__(self, ncpath1, ncpath2, tim1, tim2, ppt1, ppt2): mpersec_to_mmperday = 86400000. self.tim1 = tim1 self.tim2 = tim2 # open as xarray dataset self.ncmod1 = xr.open_dataset(ncpath1) self.ncmod2 = xr.open_dataset(ncpath2) var_ppt1 = self.ncmod1[ppt1] var_ppt2 = self.ncmod2[ppt2] self.var = (var_ppt1 + var_ppt2) * mpersec_to_mmperday # modify time coordinate for CESM (1 month backwards) oldtime = self.var['time'] newtime_beg = DatetimeNoLeap(oldtime.dt.year[0], oldtime.dt.month[0] - 1, oldtime.dt.day[0]) newtime = xr.cftime_range(start=newtime_beg, periods=np.shape(oldtime)[0], freq='MS', calendar='noleap') self.var = self.var.assign_coords(time=newtime) # time subset # this subsetting allows for DJF mean that includes only D of the firt year and JF of the last year plus one self.vtsub = self.var.sel( time=slice(str(self.tim1) + '-03-01', str(self.tim2) + '-02-01'))
def __init__(self, ncpath, tim1, tim2, varcode, zm=False): self.tim1 = tim1 self.tim2 = tim2 # open as xarray dataset self.ncmod = xr.open_dataset(ncpath) self.var = self.ncmod[varcode] # modify time coordinate for CESM (1 month backwards) oldtime = self.var['time'] newtime_beg = DatetimeNoLeap(oldtime.dt.year[0], oldtime.dt.month[0] - 1, oldtime.dt.day[0]) newtime = xr.cftime_range(start=newtime_beg, periods=np.shape(oldtime)[0], freq='MS', calendar='noleap') self.var = self.var.assign_coords(time=newtime) # time subset # this subsetting allows for DJF mean that includes only D of the firt year and JF of the last year plus one self.vtsub = self.var.sel( time=slice(str(self.tim1) + '-03-01', str(self.tim2) + '-02-01')) # if zonal mean if zm: self.vtsub = self.vtsub.isel(lon=0) # fill in missing values self.vtsub = self.vtsub.fillna(0)
def test_parse_array_of_cftime_strings(): from cftime import DatetimeNoLeap strings = np.array(['2000-01-01', '2000-01-02']) expected = np.array( [DatetimeNoLeap(2000, 1, 1), DatetimeNoLeap(2000, 1, 2)]) result = _parse_array_of_cftime_strings(strings, DatetimeNoLeap) np.testing.assert_array_equal(result, expected) # Test scalar array case strings = np.array('2000-01-01') expected = np.array(DatetimeNoLeap(2000, 1, 1)) result = _parse_array_of_cftime_strings(strings, DatetimeNoLeap) np.testing.assert_array_equal(result, expected)
def test_load_variable_mask_and_scale(load_variable_data_loader): def convert_all_to_missing_val(ds, **kwargs): ds['condensation_rain'] = 0. * ds['condensation_rain'] + 1.0e20 ds['condensation_rain'].attrs['_FillValue'] = 1.0e20 return ds load_variable_data_loader.preprocess_func = convert_all_to_missing_val data = load_variable_data_loader.load_variable(condensation_rain, DatetimeNoLeap(5, 1, 1), DatetimeNoLeap(5, 12, 31), intvl_in='monthly') num_non_missing = np.isfinite(data).sum().item() expected_num_non_missing = 0 assert num_non_missing == expected_num_non_missing
def test_parse_array_of_cftime_strings(): from cftime import DatetimeNoLeap strings = np.array([["2000-01-01", "2000-01-02"], ["2000-01-03", "2000-01-04"]]) expected = np.array( [ [DatetimeNoLeap(2000, 1, 1), DatetimeNoLeap(2000, 1, 2)], [DatetimeNoLeap(2000, 1, 3), DatetimeNoLeap(2000, 1, 4)], ] ) result = _parse_array_of_cftime_strings(strings, DatetimeNoLeap) np.testing.assert_array_equal(result, expected) # Test scalar array case strings = np.array("2000-01-01") expected = np.array(DatetimeNoLeap(2000, 1, 1)) result = _parse_array_of_cftime_strings(strings, DatetimeNoLeap) np.testing.assert_array_equal(result, expected)
def setUp(self): self.date1_365_day = DatetimeNoLeap(-5000, 1, 2, 12) self.date2_365_day = DatetimeNoLeap(-5000, 1, 3, 12) self.date3_gregorian = DatetimeGregorian(1969, 7, 20, 12) # last day of the Julian calendar in the mixed Julian/Gregorian calendar self.date4_gregorian = DatetimeGregorian(1582, 10, 4) # first day of the Gregorian calendar in the mixed Julian/Gregorian calendar self.date5_gregorian = DatetimeGregorian(1582, 10, 15) self.date6_proleptic_gregorian = DatetimeProlepticGregorian( 1582, 10, 15) self.date7_360_day = Datetime360Day(2000, 1, 1) self.date8_julian = DatetimeJulian(1582, 10, 4) # a datetime.datetime instance (proleptic Gregorian calendar) self.datetime_date1 = datetime(1969, 7, 21, 12) self.delta = timedelta(hours=25)
def preprocess(filename, varcode, tim1, tim2, vertical=False): # extract variable var = xr.open_dataset(filename)[varcode] # modify time coordinate for CESM (1 month backwards) oldtime = var['time'] newtime_beg = DatetimeNoLeap(oldtime.dt.year[0], oldtime.dt.month[0] - 1, oldtime.dt.day[0]) newtime = xr.cftime_range(start=newtime_beg, periods=np.shape(oldtime)[0], freq='MS', calendar='noleap') var = var.assign_coords(time=newtime) # time subset - start in March, end in February var = var.sel(time=slice(str(tim1) + '-03-01', str(tim2) + '-02-01')) # Adjust lon values to make sure they are within (-180, 180) lon_name = 'lon' var['_longitude_adjusted'] = xr.where(var[lon_name] > 180, var[lon_name] - 360, var[lon_name]) # reassign the new coords to as the main lon coords # and sort DataArray using new coordinate values var = (var.swap_dims({ lon_name: '_longitude_adjusted' }).sel(**{ '_longitude_adjusted': sorted(var._longitude_adjusted) }).drop(lon_name)) var = var.rename({'_longitude_adjusted': lon_name}) # latitude subset #var = var.sel(lat=slice(20,80), lon=slice(-90,40)) # convert variable and dimensions to numpy arrays npvar = var.values nptime = var['time'].values nplat = var['lat'].values nplon = var['lon'].values if vertical: nplev = var['level'].values # for cos latitude weighting later coslat = np.cos(np.deg2rad(nplat)) return (npvar, nptime, nplev, nplat, nplon, coslat) if vertical else (npvar, nptime, nplat, nplon, coslat)
def rm_leap(data: xr.DataArray) -> xr.DataArray: """Remove lear days and replace time axis with cftime.DatetimeNoLeap.""" february = 2 leap_day = 29 data = data.sel( time=~((data.time.dt.month == february) & (data.time.dt.day == leap_day)), ) days_since_first = np.cumsum( np.append(data.time[1:].values - data.time[:-1].values, timedelta(1)), ) data["time"] = [ DatetimeNoLeap(*data.time[0].values.tolist().timetuple()) + dt for dt in days_since_first ] return data
def test_fieldset_nonstandardtime(calendar, tmpdir, filename='test_nonstandardtime.nc', xdim=4, ydim=6): from cftime import DatetimeNoLeap, Datetime360Day filepath = tmpdir.join(filename) if calendar == 'noleap': dates = [DatetimeNoLeap(0, m, 1) for m in range(1, 13)] else: dates = [Datetime360Day(0, m, 1) for m in range(1, 13)] da = xr.DataArray(np.random.rand(12, xdim, ydim), coords=[dates, range(xdim), range(ydim)], dims=['time', 'lon', 'lat'], name='U') da.to_netcdf(str(filepath)) dims = {'lon': 'lon', 'lat': 'lat', 'time': 'time'} field = Field.from_netcdf(filepath, 'U', dims) assert field.grid.time_origin.calendar == 'cftime'
def __init__(self, ncpath='', tim1='', tim2='', var=''): self.tim1 = tim1 self.tim2 = tim2 # open as xarray dataset self.ncmod = xr.open_dataset(ncpath) self.var = self.ncmod[var] # modify time coordinate for CESM (1 month backwards) oldtime = self.var['time'] newtime_beg = DatetimeNoLeap(oldtime.dt.year[0],oldtime.dt.month[0]-1,oldtime.dt.day[0]) newtime = xr.cftime_range(start=newtime_beg, periods=np.shape(oldtime)[0], freq='MS', calendar='noleap') self.var = self.var.assign_coords(time=newtime) #self.var, self.dimdict = basic_functions.extract_var_dims(ncpath, varname='TREFHT', xlonname='lon', xlatname='lat', xtimname='time') #self.var = self.var.isel(lat=slice(0,2), lon=slice(0,2)) yr_to_dec = 10
def __init__(self, ncpath1, ncpath2, tim1, tim2, ppt1, ppt2): mpersec_to_mmperday = 86400000. self.tim1 = tim1 self.tim2 = tim2 # open as xarray dataset self.ncmod1 = xr.open_dataset(ncpath1) self.ncmod2 = xr.open_dataset(ncpath2) var_ppt1 = self.ncmod1[ppt1] var_ppt2 = self.ncmod2[ppt2] self.var = (var_ppt1 + var_ppt2)*mpersec_to_mmperday # modify time coordinate for CESM (1 month backwards) oldtime = self.var['time'] newtime_beg = DatetimeNoLeap(oldtime.dt.year[0],oldtime.dt.month[0]-1,oldtime.dt.day[0]) newtime = xr.cftime_range(start=newtime_beg, periods=np.shape(oldtime)[0], freq='MS', calendar='noleap') self.var = self.var.assign_coords(time=newtime)
def setUp(self): self.date1_365_day = DatetimeNoLeap(-5000, 1, 2, 12) self.date2_365_day = DatetimeNoLeap(-5000, 1, 3, 12) self.date3_gregorian = DatetimeGregorian(1969, 7, 20, 12) # last day of the Julian calendar in the mixed Julian/Gregorian calendar self.date4_gregorian = DatetimeGregorian(1582, 10, 4) # first day of the Gregorian calendar in the mixed Julian/Gregorian calendar self.date5_gregorian = DatetimeGregorian(1582, 10, 15) self.date6_proleptic_gregorian = DatetimeProlepticGregorian(1582, 10, 15) self.date7_360_day = Datetime360Day(2000, 1, 1) self.date8_julian = DatetimeJulian(1582, 10, 4) # a datetime.datetime instance (proleptic Gregorian calendar) self.datetime_date1 = datetime(1969, 7, 21, 12) self.delta = timedelta(hours=25)
def __init__(self, ncpath='', tim1='', tim2='', var=''): self.tim1 = tim1 self.tim2 = tim2 # open as xarray dataset self.ncmod = xr.open_dataset(ncpath) self.var = self.ncmod[var] # zonal mean - choose single longitude self.var = self.var.isel(lon=0) # modify time coordinate for CESM (1 month backwards) oldtime = self.var['time'] newtime_beg = DatetimeNoLeap(oldtime.dt.year[0],oldtime.dt.month[0]-1,oldtime.dt.day[0]) newtime = xr.cftime_range(start=newtime_beg, periods=np.shape(oldtime)[0], freq='MS', calendar='noleap') self.var = self.var.assign_coords(time=newtime) self.var = self.var.fillna(0) self.trend_scaling = 30.
class DateTime(unittest.TestCase): def setUp(self): self.date1_365_day = DatetimeNoLeap(-5000, 1, 2, 12) self.date2_365_day = DatetimeNoLeap(-5000, 1, 3, 12) self.date3_gregorian = DatetimeGregorian(1969, 7, 20, 12) # last day of the Julian calendar in the mixed Julian/Gregorian calendar self.date4_gregorian = DatetimeGregorian(1582, 10, 4) # first day of the Gregorian calendar in the mixed Julian/Gregorian calendar self.date5_gregorian = DatetimeGregorian(1582, 10, 15) self.date6_proleptic_gregorian = DatetimeProlepticGregorian(1582, 10, 15) self.date7_360_day = Datetime360Day(2000, 1, 1) self.date8_julian = DatetimeJulian(1582, 10, 4) # a datetime.datetime instance (proleptic Gregorian calendar) self.datetime_date1 = datetime(1969, 7, 21, 12) self.delta = timedelta(hours=25) def test_add(self): dt = self.date1_365_day # datetime + timedelta self.assertEqual(dt + self.delta, # add 25 hours dt.replace(day=dt.day + 1, hour=dt.hour + 1)) # timedelta + datetime self.assertEqual(self.delta + dt, # add 25 hours dt.replace(day=dt.day + 1, hour=dt.hour + 1)) # test the Julian/Gregorian transition self.assertEqual(self.date4_gregorian + self.delta, DatetimeGregorian(1582, 10, 15, 1)) # The Julian calendar has no invalid dates self.assertEqual(self.date8_julian + self.delta, DatetimeJulian(1582, 10, 5, 1)) # Test going over the year boundary. self.assertEqual(DatetimeGregorian(2000, 11, 1) + timedelta(days=30 + 31), DatetimeGregorian(2001, 1, 1)) # Year 2000 is a leap year. self.assertEqual(DatetimeGregorian(2000, 1, 1) + timedelta(days=31 + 29), DatetimeGregorian(2000, 3, 1)) # Test the 366_day calendar. self.assertEqual(DatetimeAllLeap(1, 1, 1) + timedelta(days=366 * 10 + 31), DatetimeAllLeap(11, 2, 1)) # The Gregorian calendar has no year zero. self.assertEqual(DatetimeGregorian(-1, 12, 31) + self.delta, DatetimeGregorian(1, 1, 1, 1)) def invalid_add_1(): self.date1_365_day + 1 def invalid_add_2(): 1 + self.date1_365_day for func in [invalid_add_1, invalid_add_2]: self.assertRaises(TypeError, func) def test_sub(self): # subtracting a timedelta previous_day = self.date1_365_day - self.delta self.assertEqual(previous_day.day, self.date1_365_day.day - 1) def total_seconds(td): """Equivalent to td.total_seconds() on Python >= 2.7. See https://docs.python.org/2/library/datetime.html#datetime.timedelta.total_seconds """ return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6 # sutracting two netcdftime.datetime instances delta = self.date2_365_day - self.date1_365_day # date1 and date2 are exactly one day apart self.assertEqual(total_seconds(delta), 86400) # subtracting netcdftime.datetime from datetime.datetime delta = self.datetime_date1 - self.date3_gregorian # real_date2 and real_date1 are exactly one day apart self.assertEqual(total_seconds(delta), 86400) # subtracting datetime.datetime from netcdftime.datetime delta = self.date3_gregorian - self.datetime_date1 # real_date2 and real_date1 are exactly one day apart self.assertEqual(total_seconds(delta), -86400) # Test the Julian/Gregorian transition. self.assertEqual(self.date5_gregorian - self.delta, DatetimeGregorian(1582, 10, 3, 23)) # The proleptic Gregorian calendar does not have invalid dates. self.assertEqual(self.date6_proleptic_gregorian - self.delta, DatetimeProlepticGregorian(1582, 10, 13, 23)) # The Gregorian calendar has no year zero. self.assertEqual(DatetimeGregorian(1, 1, 1) - self.delta, DatetimeGregorian(-1, 12, 30, 23)) # The 360_day calendar has year zero. self.assertEqual(self.date7_360_day - timedelta(days=2000 * 360), Datetime360Day(0, 1, 1)) # Test going over the year boundary. self.assertEqual(DatetimeGregorian(2000, 3, 1) - timedelta(days=29 + 31 + 31), DatetimeGregorian(1999, 12, 1)) # Year 2000 is a leap year. self.assertEqual(DatetimeGregorian(2000, 3, 1) - self.delta, DatetimeGregorian(2000, 2, 28, 23)) def invalid_sub_1(): self.date1_365_day - 1 def invalid_sub_2(): 1 - self.date1_365_day def invalid_sub_3(): self.date1_365_day - self.datetime_date1 def invalid_sub_4(): self.datetime_date1 - self.date1_365_day def invalid_sub_5(): self.date3_gregorian - self.date1_365_day for func in [invalid_sub_1, invalid_sub_2]: self.assertRaises(TypeError, func) for func in [invalid_sub_3, invalid_sub_4, invalid_sub_5]: self.assertRaises(ValueError, func) def test_replace(self): self.assertEqual(self.date1_365_day.replace(year=4000).year, 4000) self.assertEqual(self.date1_365_day.replace(month=3).month, 3) self.assertEqual(self.date1_365_day.replace(day=3).day, 3) self.assertEqual(self.date1_365_day.replace(hour=3).hour, 3) self.assertEqual(self.date1_365_day.replace(minute=3).minute, 3) self.assertEqual(self.date1_365_day.replace(second=3).second, 3) self.assertEqual(self.date1_365_day.replace(microsecond=3).microsecond, 3) self.assertEqual(self.date1_365_day.replace(dayofwk=3).dayofwk, 3) self.assertEqual(self.date1_365_day.replace(dayofyr=3).dayofyr, 3) def test_pickling(self): "Test reversibility of pickling." import pickle date = Datetime360Day(year=1, month=2, day=3, hour=4, minute=5, second=6, microsecond=7) self.assertEqual(date, pickle.loads(pickle.dumps(date))) def test_misc(self): "Miscellaneous tests." # make sure repr succeeds repr(self.date1_365_day) # make sure strftime without a format string works self.assertEqual(self.date3_gregorian.strftime(None), "1969-07-20 12:00:00") def invalid_year(): DatetimeGregorian(0, 1, 1) + self.delta def invalid_month(): DatetimeGregorian(1, 13, 1) + self.delta def invalid_day(): DatetimeGregorian(1, 1, 32) + self.delta def invalid_gregorian_date(): DatetimeGregorian(1582, 10, 5) + self.delta for func in [invalid_year, invalid_month, invalid_day, invalid_gregorian_date]: self.assertRaises(ValueError, func) def test_richcmp(self): # compare datetime and datetime self.assertTrue(self.date1_365_day == self.date1_365_day) self.assertFalse(self.date1_365_day == self.date2_365_day) self.assertTrue(self.date1_365_day < self.date2_365_day) self.assertFalse(self.date1_365_day < self.date1_365_day) self.assertTrue(self.date2_365_day > self.date1_365_day) self.assertFalse(self.date1_365_day > self.date2_365_day) # compare real_datetime and datetime self.assertTrue(self.datetime_date1 > self.date3_gregorian) # compare datetime and real_datetime self.assertFalse(self.date3_gregorian > self.datetime_date1) def not_comparable_1(): "compare two datetime instances with different calendars" self.date1_365_day > self.date3_gregorian def not_comparable_2(): "compare a datetime instance with a non-standard calendar to real_datetime" self.date2_365_day > self.datetime_date1 def not_comparable_3(): "compare datetime.datetime to netcdftime.datetime with a non-gregorian calendar" self.datetime_date1 > self.date2_365_day def not_comparable_4(): "compare a datetime instance to something other than a datetime" self.date1_365_day > 0 for func in [not_comparable_1, not_comparable_2, not_comparable_3, not_comparable_4]: self.assertRaises(TypeError, func)
[datetime(2020, 3, 21, 12, 0, 0), 0.0, 0.0, 1.0], [datetime(2020, 3, 21, 18, 0, 0), -90.0, 0.0, 1.0], [datetime(2020, 3, 21, 18, 0, 0), 270.0, 0.0, 1.0], [datetime(2020, 7, 6, 12, 0, 0), -90.0, 0.0, -0.0196310], [datetime(2020, 7, 6, 9, 0, 0), 40.0, 40.0, 0.9501915], [datetime(2020, 7, 6, 12, 0, 0), 0.0, 90.0, 0.3843733], ), ) def test__sun_zenith_angle(time, lon, lat, expected): assert cos_zenith_angle(time, lon, lat) == pytest.approx(expected, abs=1e-3) @pytest.mark.parametrize( "invalid_time", ( DatetimeNoLeap(2000, 1, 1), np.array([DatetimeNoLeap(2000, 1, 1), DatetimeNoLeap(2000, 2, 1)]), ), ids=["scalar", "array"], ) def test__sun_zenith_angle_invalid_time(invalid_time): with pytest.raises(ValueError, match="model_time has an invalid date type"): cos_zenith_angle(invalid_time, 0.0, 0.0) def test_cos_zenith_angle_dataarray(): time = DatetimeJulian(2020, 3, 21, 12, 0, 0) lat = 0 lon = 0 dataset = xr.Dataset( {"time": ([], time), "lat": (["x"], [lat]), "lon": (["x"], [lon])}
'snw_day_CESM2_historical_r11i1p1f1_gn_20000101-20150101.nc', # 6 'ts_Amon_CESM2_historical_r11i1p1f1_gn_200001-201412.nc', # 7 'tsl_Lmon_CESM2_historical_r11i1p1f1_gn_200001-201412.nc', # 8 'soil_mon_ERA5_2015.nc', # 9 'landmask_CESM2.nc', # 10 'phis_CESM2.nc' ] # 11 chdir(nc_path) dss = [] for nc in ncs: ds = open_dataset(nc) dss.append(ds) start_date = DatetimeNoLeap(start_year, start_month, start_day) end_date = DatetimeNoLeap(end_year, end_month, end_day) dates = [] date = start_date while date <= end_date: dates.append(date) date += timedelta(hours=6) for date in dates: # datetime tnum = date.year, date.month, date.day, date.hour t6hr = DatetimeNoLeap(tnum[0], tnum[1], tnum[2], tnum[3]) tday = DatetimeNoLeap(tnum[0], tnum[1], tnum[2]) + timedelta(days=1) if tnum[1] is 2: mid_day = 14 else:
import numpy as np import pytest import xarray as xr from aospy.internal_names import ( LON_STR, TIME_STR, TIME_BOUNDS_STR, BOUNDS_STR, ) _DATE_RANGES = { 'datetime': (datetime.datetime(2000, 1, 1), datetime.datetime(2002, 12, 31)), 'datetime64': (np.datetime64('2000-01-01'), np.datetime64('2002-12-31')), 'cftime': (DatetimeNoLeap(2000, 1, 1), DatetimeNoLeap(2002, 12, 31)), 'str': ('2000', '2002') } @pytest.fixture() def alt_lat_str(): return 'LATITUDE' @pytest.fixture() def var_name(): return 'a' @pytest.fixture
) @pytest.mark.parametrize(('input_dtype', 'expected_dtype'), [(np.float32, np.float64), (np.int, np.int)]) def test_maybe_cast_to_float64(input_dtype, expected_dtype): da = xr.DataArray(np.ones(3, dtype=input_dtype)) result = _maybe_cast_to_float64(da).dtype assert result == expected_dtype _DATE_RANGES = { 'datetime': (datetime.datetime(2000, 1, 1), datetime.datetime(2002, 12, 31)), 'datetime64': (np.datetime64('2000-01-01'), np.datetime64('2002-12-31')), 'cftime': (DatetimeNoLeap(2000, 1, 1), DatetimeNoLeap(2002, 12, 31)), 'str': ('2000', '2002') } @pytest.fixture(params=_DATE_RANGES.values(), ids=list(_DATE_RANGES.keys())) def generate_file_set_args(request): start_date, end_date = request.param return dict(var=condensation_rain, start_date=start_date, end_date=end_date, domain='atmos', intvl_in='monthly', dtype_in_vert='sigma', dtype_in_time='ts', intvl_out=None)
def preprocess(ds, **kwargs): if kwargs['start_date'] == DatetimeNoLeap(5, 1, 1): ds['condensation_rain'] = 10. * ds['condensation_rain'] return ds
class DateTime(unittest.TestCase): def setUp(self): self.date1_365_day = DatetimeNoLeap(-5000, 1, 2, 12) self.date2_365_day = DatetimeNoLeap(-5000, 1, 3, 12) self.date3_gregorian = DatetimeGregorian(1969, 7, 20, 12) # last day of the Julian calendar in the mixed Julian/Gregorian calendar self.date4_gregorian = DatetimeGregorian(1582, 10, 4) # first day of the Gregorian calendar in the mixed Julian/Gregorian calendar self.date5_gregorian = DatetimeGregorian(1582, 10, 15) self.date6_proleptic_gregorian = DatetimeProlepticGregorian( 1582, 10, 15) self.date7_360_day = Datetime360Day(2000, 1, 1) self.date8_julian = DatetimeJulian(1582, 10, 4) # a datetime.datetime instance (proleptic Gregorian calendar) self.datetime_date1 = datetime(1969, 7, 21, 12) self.delta = timedelta(hours=25) def test_add(self): dt = self.date1_365_day # datetime + timedelta self.assertEqual( dt + self.delta, # add 25 hours dt.replace(day=dt.day + 1, hour=dt.hour + 1)) # timedelta + datetime self.assertEqual( self.delta + dt, # add 25 hours dt.replace(day=dt.day + 1, hour=dt.hour + 1)) # test the Julian/Gregorian transition self.assertEqual(self.date4_gregorian + self.delta, DatetimeGregorian(1582, 10, 15, 1)) # The Julian calendar has no invalid dates self.assertEqual(self.date8_julian + self.delta, DatetimeJulian(1582, 10, 5, 1)) # Test going over the year boundary. self.assertEqual( DatetimeGregorian(2000, 11, 1) + timedelta(days=30 + 31), DatetimeGregorian(2001, 1, 1)) # Year 2000 is a leap year. self.assertEqual( DatetimeGregorian(2000, 1, 1) + timedelta(days=31 + 29), DatetimeGregorian(2000, 3, 1)) # Test the 366_day calendar. self.assertEqual( DatetimeAllLeap(1, 1, 1) + timedelta(days=366 * 10 + 31), DatetimeAllLeap(11, 2, 1)) # The Gregorian calendar has no year zero. self.assertEqual( DatetimeGregorian(-1, 12, 31) + self.delta, DatetimeGregorian(1, 1, 1, 1)) def invalid_add_1(): self.date1_365_day + 1 def invalid_add_2(): 1 + self.date1_365_day for func in [invalid_add_1, invalid_add_2]: self.assertRaises(TypeError, func) def test_sub(self): # subtracting a timedelta previous_day = self.date1_365_day - self.delta self.assertEqual(previous_day.day, self.date1_365_day.day - 1) def total_seconds(td): """Equivalent to td.total_seconds() on Python >= 2.7. See https://docs.python.org/2/library/datetime.html#datetime.timedelta.total_seconds """ return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6 # sutracting two netcdftime.datetime instances delta = self.date2_365_day - self.date1_365_day # date1 and date2 are exactly one day apart self.assertEqual(total_seconds(delta), 86400) # subtracting netcdftime.datetime from datetime.datetime delta = self.datetime_date1 - self.date3_gregorian # real_date2 and real_date1 are exactly one day apart self.assertEqual(total_seconds(delta), 86400) # subtracting datetime.datetime from netcdftime.datetime delta = self.date3_gregorian - self.datetime_date1 # real_date2 and real_date1 are exactly one day apart self.assertEqual(total_seconds(delta), -86400) # Test the Julian/Gregorian transition. self.assertEqual(self.date5_gregorian - self.delta, DatetimeGregorian(1582, 10, 3, 23)) # The proleptic Gregorian calendar does not have invalid dates. self.assertEqual(self.date6_proleptic_gregorian - self.delta, DatetimeProlepticGregorian(1582, 10, 13, 23)) # The Gregorian calendar has no year zero. self.assertEqual( DatetimeGregorian(1, 1, 1) - self.delta, DatetimeGregorian(-1, 12, 30, 23)) # The 360_day calendar has year zero. self.assertEqual(self.date7_360_day - timedelta(days=2000 * 360), Datetime360Day(0, 1, 1)) # Test going over the year boundary. self.assertEqual( DatetimeGregorian(2000, 3, 1) - timedelta(days=29 + 31 + 31), DatetimeGregorian(1999, 12, 1)) # Year 2000 is a leap year. self.assertEqual( DatetimeGregorian(2000, 3, 1) - self.delta, DatetimeGregorian(2000, 2, 28, 23)) def invalid_sub_1(): self.date1_365_day - 1 def invalid_sub_2(): 1 - self.date1_365_day def invalid_sub_3(): self.date1_365_day - self.datetime_date1 def invalid_sub_4(): self.datetime_date1 - self.date1_365_day def invalid_sub_5(): self.date3_gregorian - self.date1_365_day for func in [invalid_sub_1, invalid_sub_2]: self.assertRaises(TypeError, func) for func in [invalid_sub_3, invalid_sub_4, invalid_sub_5]: self.assertRaises(ValueError, func) def test_replace(self): self.assertEqual(self.date1_365_day.replace(year=4000).year, 4000) self.assertEqual(self.date1_365_day.replace(month=3).month, 3) self.assertEqual(self.date1_365_day.replace(day=3).day, 3) self.assertEqual(self.date1_365_day.replace(hour=3).hour, 3) self.assertEqual(self.date1_365_day.replace(minute=3).minute, 3) self.assertEqual(self.date1_365_day.replace(second=3).second, 3) self.assertEqual( self.date1_365_day.replace(microsecond=3).microsecond, 3) self.assertEqual(self.date1_365_day.replace(dayofwk=3).dayofwk, 3) self.assertEqual(self.date1_365_day.replace(dayofyr=3).dayofyr, 3) def test_pickling(self): "Test reversibility of pickling." import pickle date = Datetime360Day(year=1, month=2, day=3, hour=4, minute=5, second=6, microsecond=7) self.assertEqual(date, pickle.loads(pickle.dumps(date))) def test_misc(self): "Miscellaneous tests." # make sure repr succeeds repr(self.date1_365_day) # make sure strftime without a format string works self.assertEqual(self.date3_gregorian.strftime(None), "1969-07-20 12:00:00") def invalid_year(): DatetimeGregorian(0, 1, 1) + self.delta def invalid_month(): DatetimeGregorian(1, 13, 1) + self.delta def invalid_day(): DatetimeGregorian(1, 1, 32) + self.delta def invalid_gregorian_date(): DatetimeGregorian(1582, 10, 5) + self.delta for func in [ invalid_year, invalid_month, invalid_day, invalid_gregorian_date ]: self.assertRaises(ValueError, func) def test_richcmp(self): # compare datetime and datetime self.assertTrue(self.date1_365_day == self.date1_365_day) self.assertFalse(self.date1_365_day == self.date2_365_day) self.assertTrue(self.date1_365_day < self.date2_365_day) self.assertFalse(self.date1_365_day < self.date1_365_day) self.assertTrue(self.date2_365_day > self.date1_365_day) self.assertFalse(self.date1_365_day > self.date2_365_day) # compare real_datetime and datetime self.assertTrue(self.datetime_date1 > self.date3_gregorian) # compare datetime and real_datetime self.assertFalse(self.date3_gregorian > self.datetime_date1) def not_comparable_1(): "compare two datetime instances with different calendars" self.date1_365_day > self.date3_gregorian def not_comparable_2(): "compare a datetime instance with a non-standard calendar to real_datetime" self.date2_365_day > self.datetime_date1 def not_comparable_3(): "compare datetime.datetime to netcdftime.datetime with a non-gregorian calendar" self.datetime_date1 > self.date2_365_day def not_comparable_4(): "compare a datetime instance to something other than a datetime" self.date1_365_day > 0 for func in [ not_comparable_1, not_comparable_2, not_comparable_3, not_comparable_4 ]: self.assertRaises(TypeError, func)
os.path.split(ROOT_PATH)[0], 'netcdf', '000[4-6]0101.precip_monthly.nc') sphum_files = os.path.join( os.path.split(ROOT_PATH)[0], 'netcdf', '00060101.sphum_monthly.nc') file_map = { 'monthly': { 'condensation_rain': precip_files, 'convection_rain': precip_files, 'sphum': sphum_files, 'ps': sphum_files } } example_run = Run( name='example_run', description=('Control simulation of the idealized moist model'), data_loader=NestedDictDataLoader(file_map), default_start_date=DatetimeNoLeap(4, 1, 1), default_end_date=DatetimeNoLeap(6, 12, 31)) example_model = Model(name='example_model', grid_file_paths=((os.path.join( os.path.split(ROOT_PATH)[0], 'netcdf', '00060101.sphum_monthly.nc'), os.path.join( os.path.split(ROOT_PATH)[0], 'netcdf', 'im.landmask.nc')), ), runs=[example_run], load_grid_data=True, grid_attrs={ LAND_MASK_STR: 'custom_land_mask', LON_STR: 'custom_lon' })