def setup_and_check(self): # {{{ """ Perform steps to set up the analysis and check for errors in the setup. """ # Authors # ------- # Xylar Asay-Davis # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.runDirectory , self.historyDirectory, self.plotsDirectory, # self.namelist, self.runStreams, self.historyStreams, # self.calendar super(ComputeAnomalySubtask, self).setup_and_check() startDate = self.config.get('timeSeries', 'startDate') endDate = self.config.get('timeSeries', 'endDate') delta = MpasRelativeDelta(string_to_datetime(endDate), string_to_datetime(startDate), calendar=self.calendar) months = delta.months + 12*delta.years if months <= self.movingAveragePoints: raise ValueError('Cannot meaninfully perform a rolling mean ' 'because the time series is too short.') self.mpasTimeSeriesTask.add_variables(variableList=self.variableList) self.inputFile = self.mpasTimeSeriesTask.outputFile
def string_to_relative_delta(dateString, calendar='gregorian'): # {{{ """ Given a date string and a calendar, returns an instance of ``MpasRelativeDelta`` Parameters ---------- dateString : str A date and time in one of the following formats:: YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh.mm.ss YYYY-MM-DD SSSSS DDD hh:mm:ss DDD hh.mm.ss DDD SSSSS hh.mm.ss hh:mm:ss YYYY-MM-DD YYYY-MM SSSSS Note: either underscores or spaces can be used to separate the date from the time portion of the string. calendar: {'gregorian', 'gregorian_noleap'}, optional The name of one of the calendars supported by MPAS cores Returns ------- relativedelta : An ``MpasRelativeDelta`` object Raises ------ ValueError If an invalid ``dateString`` is supplied. """ # Authors # ------- # Xylar Asay-Davis (years, months, days, hours, minutes, seconds) = \ _parse_date_string(dateString, isInterval=True) return MpasRelativeDelta(years=years, months=months, days=days, hours=hours, minutes=minutes, seconds=seconds, calendar=calendar)
def setup_and_check(self): # {{{ ''' Perform steps to set up the analysis and check for errors in the setup. ''' # Authors # ------- # Xylar Asay-Davis # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.runDirectory , self.historyDirectory, self.plotsDirectory, # self.namelist, self.runStreams, self.historyStreams, # self.calendar super(IndexNino34, self).setup_and_check() startDate = self.config.get('index', 'startDate') endDate = self.config.get('index', 'endDate') delta = MpasRelativeDelta(string_to_datetime(endDate), string_to_datetime(startDate), calendar=self.calendar) months = delta.months + 12 * delta.years if months <= 12: raise ValueError('Cannot meaninfully analyze El Nino climate ' 'index because the time series is too short.') self.variableList = \ ['timeMonthly_avg_avgValueWithinOceanRegion_avgSurfaceTemperature'] self.mpasTimeSeriesTask.add_variables(variableList=self.variableList) self.inputFile = self.mpasTimeSeriesTask.outputFile mainRunName = self.config.get('runs', 'mainRunName') config = self.config regionToPlot = config.get('indexNino34', 'region') if regionToPlot not in ['nino3.4', 'nino3', 'nino4']: raise ValueError( 'Unexpectes El Nino Index region {}'.format(regionToPlot)) ninoIndexNumber = regionToPlot[4:] self.xmlFileNames = [] for filePrefix in [ 'nino{}_{}'.format(ninoIndexNumber, mainRunName), 'nino{}_spectra_{}'.format(ninoIndexNumber, mainRunName) ]: self.xmlFileNames.append('{}/{}.xml'.format( self.plotsDirectory, filePrefix))
def test_timekeeping(self): # test each possible format: # YYYY-MM-DD_hh:mm:ss # YYYY-MM-DD_hh.mm.ss # YYYY-MM-DD_SSSSS # DDD_hh:mm:ss # DDD_hh.mm.ss # DDD_SSSSS # hh.mm.ss # hh:mm:ss # YYYY-MM-DD # SSSSS for calendar in ['gregorian', 'gregorian_noleap']: # test datetime.datetime # YYYY-MM-DD_hh:mm:ss date1 = string_to_datetime('0001-01-01_00:00:00') date2 = datetime.datetime(year=1, month=1, day=1, hour=0, minute=0, second=0) self.assertEqual(date1, date2) delta1 = string_to_relative_delta('0001-00-00_00:00:00', calendar=calendar) delta2 = MpasRelativeDelta(years=1, months=0, days=0, hours=0, minutes=0, seconds=0, calendar=calendar) self.assertEqual(delta1, delta2) # YYYY-MM-DD_hh.mm.ss date1 = string_to_datetime('0001-01-01_00.00.00') date2 = datetime.datetime(year=1, month=1, day=1, hour=0, minute=0, second=0) self.assertEqual(date1, date2) # YYYY-MM-DD_SSSSS date1 = string_to_datetime('0001-01-01_00002') date2 = datetime.datetime(year=1, month=1, day=1, hour=0, minute=0, second=2) self.assertEqual(date1, date2) # DDD_hh:mm:ss delta1 = string_to_relative_delta('0001_00:00:01', calendar=calendar) delta2 = MpasRelativeDelta(years=0, months=0, days=1, hours=0, minutes=0, seconds=1, calendar=calendar) self.assertEqual(delta1, delta2) # DDD_hh.mm.ss delta1 = string_to_relative_delta('0002_01.00.01', calendar=calendar) delta2 = MpasRelativeDelta(years=0, months=0, days=2, hours=1, minutes=0, seconds=1, calendar=calendar) self.assertEqual(delta1, delta2) # DDD_SSSSS delta1 = string_to_relative_delta('0002_00003', calendar=calendar) delta2 = MpasRelativeDelta(years=0, months=0, days=2, hours=0, minutes=0, seconds=3, calendar=calendar) self.assertEqual(delta1, delta2) # hh:mm:ss date1 = string_to_datetime('00:00:01') date2 = datetime.datetime(year=1, month=1, day=1, hour=0, minute=0, second=1) self.assertEqual(date1, date2) # hh.mm.ss delta1 = string_to_relative_delta('00.00.01', calendar=calendar) delta2 = MpasRelativeDelta(years=0, months=0, days=0, hours=0, minutes=0, seconds=1, calendar=calendar) self.assertEqual(delta1, delta2) # YYYY-MM-DD date1 = string_to_datetime('0001-01-01') date2 = datetime.datetime(year=1, month=1, day=1, hour=0, minute=0, second=0) self.assertEqual(date1, date2) # SSSSS delta1 = string_to_relative_delta('00005', calendar=calendar) delta2 = MpasRelativeDelta(years=0, months=0, days=0, hours=0, minutes=0, seconds=5, calendar=calendar) self.assertEqual(delta1, delta2) date1 = string_to_datetime('1996-01-15') delta = string_to_relative_delta('0005-00-00', calendar=calendar) date2 = date1-delta self.assertEqual(date2, string_to_datetime('1991-01-15')) date1 = string_to_datetime('1996-01-15') delta = string_to_relative_delta('0000-02-00', calendar=calendar) date2 = date1-delta self.assertEqual(date2, string_to_datetime('1995-11-15')) date1 = string_to_datetime('1996-01-15') delta = string_to_relative_delta('0000-00-20', calendar=calendar) date2 = date1-delta self.assertEqual(date2, string_to_datetime('1995-12-26'))
def test_MpasRelativeDeltaOps(self): # test if the calendars behave as they should close to leap day # also, test addition and subtraction of the form # datetime.datetime +/- MpasRelativeDelta above # both calendars with adding one day for calendar, expected in zip(['gregorian', 'gregorian_noleap'], ['2016-02-29', '2016-03-01']): self.assertEqual(string_to_datetime('2016-02-28') + string_to_relative_delta('0000-00-01', calendar=calendar), string_to_datetime(expected)) # both calendars with subtracting one day for calendar, expected in zip(['gregorian', 'gregorian_noleap'], ['2016-02-29', '2016-02-28']): self.assertEqual(string_to_datetime('2016-03-01') - string_to_relative_delta('0000-00-01', calendar=calendar), string_to_datetime(expected)) # both calendars with adding one month for calendar, expected in zip(['gregorian', 'gregorian_noleap'], ['2016-02-29', '2016-02-28']): self.assertEqual(string_to_datetime('2016-01-31') + string_to_relative_delta('0000-01-00', calendar=calendar), string_to_datetime(expected)) # both calendars with subtracting one month for calendar, expected in zip(['gregorian', 'gregorian_noleap'], ['2016-02-29', '2016-02-28']): self.assertEqual(string_to_datetime('2016-03-31') - string_to_relative_delta('0000-01-00', calendar=calendar), string_to_datetime(expected)) for calendar in ['gregorian', 'gregorian_noleap']: delta1 = string_to_relative_delta('0000-01-00', calendar=calendar) delta2 = string_to_relative_delta('0000-00-01', calendar=calendar) deltaSum = string_to_relative_delta('0000-01-01', calendar=calendar) # test MpasRelativeDelta + MpasRelativeDelta self.assertEqual(delta1 + delta2, deltaSum) # test MpasRelativeDelta - MpasRelativeDelta self.assertEqual(deltaSum - delta2, delta1) # test MpasRelativeDelta(date1, date2) date1 = string_to_datetime('0002-02-02') date2 = string_to_datetime('0001-01-01') delta = string_to_relative_delta('0001-01-01', calendar=calendar) self.assertEqual(MpasRelativeDelta(dt1=date1, dt2=date2, calendar=calendar), delta) # test MpasRelativeDelta + datetime.datetime (an odd order but # it's allowed...) date1 = string_to_datetime('0001-01-01') delta = string_to_relative_delta('0001-01-01', calendar=calendar) date2 = string_to_datetime('0002-02-02') self.assertEqual(delta + date1, date2) # test multiplication/division by scalars delta1 = string_to_relative_delta('0001-01-01', calendar=calendar) delta2 = string_to_relative_delta('0002-02-02', calendar=calendar) self.assertEqual(2*delta1, delta2) self.assertEqual(delta2/2, delta1) # make sure there's an error when we try to add MpasRelativeDeltas # with different calendars with self.assertRaisesRegexp(ValueError, 'MpasRelativeDelta objects can only be ' 'added if their calendars match.'): delta1 = string_to_relative_delta('0000-01-00', calendar='gregorian') delta2 = string_to_relative_delta('0000-00-01', calendar='gregorian_noleap') deltaSum = delta1 + delta2
def _replicate_cycle(self, ds, dsToReplicate, calendar): # {{{ """ Replicates a periodic time series `dsToReplicate` to cover the timeframe of the dataset `ds`. Parameters ---------- ds : dataset used to find the start and end time of the replicated cycle dsToReplicate : dataset to replicate. The period of the cycle is the length of dsToReplicate plus the time between the first two time values (typically one year total). calendar : {'gregorian', 'gregorian_noleap'} The name of one of the calendars supported by MPAS cores Returns: -------- dsShift : a cyclicly repeated version of `dsToReplicte` covering the range of time of `ds`. """ # Authors # ------- # Xylar Asay-Davis, Milena Veneziani dsStartTime = days_to_datetime(ds.Time.min(), calendar=calendar) dsEndTime = days_to_datetime(ds.Time.max(), calendar=calendar) repStartTime = days_to_datetime(dsToReplicate.Time.min(), calendar=calendar) repEndTime = days_to_datetime(dsToReplicate.Time.max(), calendar=calendar) repSecondTime = days_to_datetime(dsToReplicate.Time.isel(Time=1), calendar=calendar) period = (MpasRelativeDelta(repEndTime, repStartTime) + MpasRelativeDelta(repSecondTime, repStartTime)) startIndex = 0 while(dsStartTime > repStartTime + (startIndex + 1) * period): startIndex += 1 endIndex = 0 while(dsEndTime > repEndTime + endIndex * period): endIndex += 1 dsShift = dsToReplicate.copy() times = days_to_datetime(dsShift.Time, calendar=calendar) dsShift.coords['Time'] = ('Time', datetime_to_days(times + startIndex * period, calendar=calendar)) # replicate cycle: for cycleIndex in range(startIndex, endIndex): dsNew = dsToReplicate.copy() dsNew.coords['Time'] = \ ('Time', datetime_to_days(times + (cycleIndex + 1) * period, calendar=calendar)) dsShift = xr.concat([dsShift, dsNew], dim='Time') # clip dsShift to the range of ds dsStartTime = dsShift.Time.sel(Time=ds.Time.min(), method=str('nearest')).values dsEndTime = dsShift.Time.sel(Time=ds.Time.max(), method=str('nearest')).values dsShift = dsShift.sel(Time=slice(dsStartTime, dsEndTime)) return dsShift # }}}