def setUp(self): data = [ 1, 4, 3, 2, 0, 1, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0.1, 5, ] self.rainfall = hydro.time_series(data, start_date=hydro.Date( 'M', '2001-01')) self.data = data
def test_wet_and_dry_spells(self): "Test wet and dry spells" data = self.data + [-3] rainfall = hydro.time_series(data, mask=24 * [0] + [1], start_date=hydro.Date("M", "2001-01")) threshold = 0.254 dspells = dry_spells(rainfall, threshold=threshold) wspells = wet_spells(rainfall, threshold=threshold) assert_equal(dspells.sum() + wspells.durations.sum(), rainfall.count())
def test_daily_random(self): "Test some PET models on some random daily data" (freq, base) = ('D', 365) wave = -10 * np.cos(np.arange(120) * (2. * np.pi) / base) tmin = hydro.time_series(5 + wave + np.random.rand(120) * 3, start_date=hydro.Date(freq, '1990-01-01')) tmax = hydro.time_series(10 + wave + np.random.rand(120) * 3, start_date=hydro.Date(freq, '1990-01-01')) ma.putmask(tmax, (tmax < tmin), tmin + 1) freeze = ((tmin + tmax) / 2. <= 0) PET = evapo.PotentialEvapoTranspiration(tmin, tmax, self.latitude) for d in self.defaults: err_msg = "Error w/ model '%s' : the PET should be masked" % d P = ma.masked_values(getattr(PET, d).__call__(), 0) if d in ['Hamon', 'Kharrufa', 'Turc']: assert_equal(ma.getmaskarray(P), freeze, err_msg=err_msg) else: assert (not ma.getmaskarray(P).any())
def test_daily_random(self): "Test some PET models on some random daily data" (freq, base) = ('D', 365) wave = -10 * np.cos(np.arange(120) * (2.*np.pi)/base) tmin = hydro.time_series(5 + wave + np.random.rand(120) * 3, start_date=hydro.Date(freq, '1990-01-01')) tmax = hydro.time_series(10 + wave + np.random.rand(120) * 3, start_date=hydro.Date(freq, '1990-01-01')) ma.putmask(tmax, (tmax < tmin), tmin+1) freeze = ((tmin + tmax)/2. <= 0) PET = evapo.PotentialEvapoTranspiration(tmin, tmax, self.latitude) for d in self.defaults: err_msg = "Error w/ model '%s' : the PET should be masked" % d P = ma.masked_values(getattr(PET, d).__call__(), 0) if d in ['Hamon', 'Kharrufa', 'Turc']: assert_equal(ma.getmaskarray(P), freeze, err_msg=err_msg) else: assert(not ma.getmaskarray(P).any())
def test_wet_and_dry_spells(self): "Test wet and dry spells" data = self.data + [-3] rainfall = hydro.time_series(data, mask=24 * [0] + [1], start_date=hydro.Date('M', '2001-01')) threshold = 0.254 dspells = dry_spells(rainfall, threshold=threshold) wspells = wet_spells(rainfall, threshold=threshold) assert_equal(dspells.sum() + wspells.durations.sum(), rainfall.count())
def dump_seasonal_averages(observations, dbname="coaps.sqlite", period="monthly", ensostr="ONI"): """ Dump seasonal averages of observations in a SQLite database. The database is named following the template ``avg%(observations)s.sdb``. For each season, there are four tables named following the template ``%(period)s_%(phase)s_%(ENSOindicator)``. Each table has N+1 columns: * Station COOP ID (format ``COOP%06i``) * ENSO indicator (used to define the phase): in ('ONI', 'JMAI', 'MEI') * ENSO phase : in ('A', 'C', 'N', 'W') * N values for each season Parameters ---------- observations: string String representing the observations to store. period : ('M', 'NDJ', 'DJF', 'JFM'), optional String representing the seasons. Use 'M' for monthly, 'DJF' for 'DJF,MAM,JJA,SON'... ensostr : ('ONI', 'JMAI', 'MEI'), optional String representing the ENSO indicator to define ENSO phases """ seasons = dict(monthly=['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC', ], JFM=['JFM', 'AMJ', 'JAS', 'OND'], DJF=['DJF', 'MAM', 'JJA', 'SON'], NDJ=['NDJ', 'FMA', 'MJJ', 'ASO']) # Get the seasonal frequency period = period.upper() period_to_freq = dict(M=hydro._c.FR_MTH, MONTHLY=hydro._c.FR_MTH, NDJ=hydro._c.FR_QTREOCT, DJF=hydro._c.FR_QTRENOV, JFM=hydro._c.FR_QTREDEC,) try: freq = period_to_freq[period] except KeyError: errmsg = "Invalid period '%s': should be in %s." raise ValueError(errmsg % (period, period_to_freq.keys())) # Get the names of the fields # fieldslist = ["COOPID text primary key", "ENSOI text", "phase text"] fieldslist = ["id integer primary key autoincrement", "COOPID text", "ENSOI text", "phase text"] if period in ("M", "MONTHLY"): period = "monthly" fieldslist += ["%s real" % _ for _ in seasons[period]] nbfields = len(fieldslist) # Get the conversion function: if freq == hydro._c.FR_MTH: conversion_func = None else: if observations == 'rain': conversion_func = ma.sum else: conversion_func = ma.mean # Load the ENSO information ensostr = ensostr.upper() if ensostr == 'ONI': ENSO = enso.load_oni() elif ensostr == 'JMAI': ENSO = enso.load_jma() elif ensostr == 'MEI': raise NotImplementedError else: errmsg = "Invalid ENSO indicator '%s': should be in ('ONI','JMAI','MEI')" raise ValueError(errmsg % ensostr) # Get the monthly series from the datatable and set the ENSO indicator tbname = "series_monthly_%s" % observations monthly = sql.tsfromsqlite(dbname, tbname, freq="M") monthly = enso.set_ensoindicator(monthly, ENSO) # Define dictionaries storing the averages avg_r = {} # Loop on the stations for station in monthly.dtype.names: # Get the current station current = monthly[station] # Get the season seasonal = current.convert(freq, func=conversion_func) if (observations == "rain") and (freq != hydro._c.FR_MTH): mask = hydro.time_series(current.mask, dates=current.dates) seasonal.mask = mask.convert(freq, func=ma.sum) # Get the values per phase coopid = station[-6:] avg_r[(coopid, ensostr, 'A')] = seasonal.convert("A").mean(0) avg_r[(coopid, ensostr, 'C')] = seasonal.cold.convert("A").mean(0) avg_r[(coopid, ensostr, 'N')] = seasonal.neutral.convert("A").mean(0) avg_r[(coopid, ensostr, 'W')] = seasonal.warm.convert("A").mean(0) # Get the database name detect_types = sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES connection = sqlite3.connect(dbname, detect_types=detect_types) # Define the creation/insertion lines tbname = "averages_%(period)s_%(observations)s" % locals() createstr = "create table %s (%s)" % (tbname, ", ".join(fieldslist)) insertstr_template = "insert into %s values (%s)" insertstr = insertstr_template % (tbname, ", ".join(['?']*nbfields)) # Create the table try: connection.execute(createstr) except sqlite3.OperationalError: pass # Define a generator for the values generator = ([None, ] + list(k) + list(v.astype(np.object).filled((None,))) for (k, v) in avg_r.items()) connection.executemany(insertstr, generator) connection.commit() connection.close()
def spi(rainfall, span=3, freq='monthly', start_reference=None, end_reference=None, distribution='gamma'): """ Computes the standardized precipitation index for the precipitation series at the given span. Parameters ---------- rainfall : TimeSeries Series of monthly cumulative precipitation. span : {3, int} optional Span, in months. freq : {'monthly','weekly'} optional Frequency start_reference : {None, Date} optional Starting date of the reference period. If None, use the first date of the series. end_reference : {None, Date} optional Ending date of the reference period. If None, use the last date of the series. distribution : {'gamma','normal'} optional Type of distribution for the data of each period. """ if not isinstance(rainfall, TimeSeries): raise TypeError,\ "The precipitation input should be a valid TimeSeries object!" _freq = freq.upper()[0] if _freq not in ['M', 'W']: raise ValueError,"Invalid frequency! Should be in ('Monthly','Weekly')"\ " (got '%s' instead)" % freq rain = rainfall.convert(_freq, func=ma.sum) dates = rain.dates # Convert to cumulative over span (mm) and as a Nx12 or Nx53 array... arain = mov_sum(rain, span).convert('A') # Define the reference period ................... if start_reference is None: startd = dates[0] elif not isinstance(start_reference, Date): startd = Date(_freq, start_reference) else: startd = start_reference.asfreq(_freq) if end_reference is None: endd = dates[-1] elif not isinstance(end_reference, Date): endd = Date(_freq, end_reference) else: endd = end_reference.asfreq(_freq) condition = time_series((dates < startd) | (dates > endd), dates=dates).convert('A') # Get the cumulative distribution try: cdffunc = _cdfdict[distribution] except KeyError: raise ValueError("Unrecognized distribution '%s':"\ "Should be in %s)" % (distribution, ','.join(_cdfdict.keys()))) cdf = cdffunc(arain, condition) # Get the corresponding normal scores zscores = ma.fix_invalid(ssd.norm.ppf(cdf)) zscores._mask |= ma.getmaskarray(arain) # Retransform to a regular time series if _freq == 'M': kwargs = {'month': 1} else: kwargs = {'week': 1} kwargs.update({'year': dates[0].year}) spi = time_series( zscores.ravel(), start_date=Date(_freq, **kwargs), ).view(type(rainfall)) return spi
def spi(rainfall, span=3, freq='monthly', start_reference=None, end_reference=None, distribution='gamma'): """ Computes the standardized precipitation index for the precipitation series at the given span. Parameters ---------- rainfall : TimeSeries Series of monthly cumulative precipitation. span : {3, int} optional Span, in months. freq : {'monthly','weekly'} optional Frequency start_reference : {None, Date} optional Starting date of the reference period. If None, use the first date of the series. end_reference : {None, Date} optional Ending date of the reference period. If None, use the last date of the series. distribution : {'gamma','normal'} optional Type of distribution for the data of each period. """ if not isinstance(rainfall, TimeSeries): raise TypeError,\ "The precipitation input should be a valid TimeSeries object!" _freq = freq.upper()[0] if _freq not in ['M','W']: raise ValueError,"Invalid frequency! Should be in ('Monthly','Weekly')"\ " (got '%s' instead)" % freq rain = rainfall.convert(_freq, func=ma.sum) dates = rain.dates # Convert to cumulative over span (mm) and as a Nx12 or Nx53 array... arain = mov_sum(rain, span).convert('A') # Define the reference period ................... if start_reference is None: startd = dates[0] elif not isinstance(start_reference, Date): startd = Date(_freq, start_reference) else: startd = start_reference.asfreq(_freq) if end_reference is None: endd = dates[-1] elif not isinstance(end_reference, Date): endd = Date(_freq, end_reference) else: endd = end_reference.asfreq(_freq) condition = time_series((dates < startd) | (dates > endd), dates=dates).convert('A') # Get the cumulative distribution try: cdffunc = _cdfdict[distribution] except KeyError: raise ValueError("Unrecognized distribution '%s':"\ "Should be in %s)" % (distribution, ','.join(_cdfdict.keys()))) cdf = cdffunc(arain, condition) # Get the corresponding normal scores zscores = ma.fix_invalid(ssd.norm.ppf(cdf)) zscores._mask |= ma.getmaskarray(arain) # Retransform to a regular time series if _freq == 'M': kwargs = {'month':1} else: kwargs = {'week':1} kwargs.update({'year':dates[0].year}) spi = time_series(zscores.ravel(), start_date=Date(_freq,**kwargs), ).view(type(rainfall)) return spi
def setUp(self): data = [1, 4, 3, 2, 0, 1, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0.1, 5] self.rainfall = hydro.time_series(data, start_date=hydro.Date("M", "2001-01")) self.data = data