def simple_run_demo(): """Simple demo using HBV time-series and similar model-values """ # 1. Setup the time-axis for our simulation normal_calendar = Calendar(3600) # we need UTC+1, since day-boundaries in day series in SmG is at UTC+1 t_start = normal_calendar.time(2010, 9, 1) # we start at t_end = normal_calendar.add(t_start,Calendar.YEAR,5) # 5 years period for simulation time_axis = Timeaxis(t_start, model_dt, normal_calendar.diff_units(t_start,t_end,model_dt)) # 2. Create the shyft model from the HBV model-repository shyft_model = create_kjela_model(PTHSKModel, kjela.geo_ts_repository) # 3. establish the initial state # using the *pattern* of distribution after one year (so hbv-zone 1..10 get approximate distribution of discharge) # *and* the observed discharge at the start time t_start # t_burnin = normal_calendar.add(t_start,Calendar.YEAR,1) # use one year to get distribution between hbvzones burnin_time_axis = Timeaxis(t_start, model_dt, normal_calendar.diff_units(t_start, t_burnin, model_dt)) q_obs_m3s_ts = observed_kjela_discharge(time_axis.total_period()) # get out the observation ts q_obs_m3s_at_t_start= q_obs_m3s_ts(t_start) # get the m3/s at t_start initial_state = burn_in_state(shyft_model,burnin_time_axis, q_obs_m3s_at_t_start) # 4. now run the model with the established state # that will start out with the burn in state shyft_model.run(time_axis, initial_state) # 5. display results etc. goes here plot_results(shyft_model, q_obs_m3s_ts) plt.show()
def test_dtss_partition_by_average(self): """ This test illustrates use of partition_by client and server-side. The main point here is to ensure that the evaluate period covers both the historical and evaluation peri """ with tempfile.TemporaryDirectory() as c_dir: # setup data to be calculated utc = Calendar() d = deltahours(1) t = utc.time(2000, 1, 1) n = utc.diff_units(t, utc.add(t, Calendar.YEAR, 10), d) ta = TimeAxis(t, d, n) td = TimeAxis(t, d * 24, n // 24) n_ts = 1 store_tsv = TsVector() # something we store at server side for i in range(n_ts): pts = TimeSeries( ta, np.sin( np.linspace(start=0, stop=1.0 * (i + 1), num=ta.size())), point_fx.POINT_AVERAGE_VALUE) ts_id = shyft_store_url(f"{i}") store_tsv.append(TimeSeries( ts_id, pts)) # generate a bound pts to store # start dtss server dtss = DtsServer() cache_on_write = True port_no = find_free_port() host_port = 'localhost:{0}'.format(port_no) dtss.set_auto_cache(True) dtss.set_listening_port(port_no) dtss.set_container( "test", c_dir ) # notice we set container 'test' to point to c_dir directory dtss.start_async( ) # the internal shyft time-series will be stored to that container # create dts client c = DtsClient( host_port, auto_connect=False) # demonstrate object life-time connection c.store_ts(store_tsv, overwrite_on_write=True, cache_on_write=cache_on_write) t_0 = utc.time(2018, 1, 1) tax = TimeAxis(t_0, Calendar.DAY, 365) ts_h1 = TimeSeries(shyft_store_url(f'{0}')) ts_h2 = store_tsv[0] ts_p1 = ts_h1.partition_by(utc, t, Calendar.YEAR, 10, t_0).average(tax) ts_p2 = ts_h2.partition_by(utc, t, Calendar.YEAR, 10, t_0).average(tax)
def period_percentiles_tsv( ts: TimeSeries, period: UtcPeriod, average_dt: int, percentile_period: UtcPeriod, percentiles: Sequence[int], client: DtsClient, calendar: Calendar ) -> TsVector: """Compute percentiles from a part of a time-series and generate a TsVector of percentile time-series spanning a possibly different time period. Args: ts: TimeSeries to compute percentile time-series for. period: Time period the output time-series should span. average_dt: Period to average values by when partitioning the input time-series. percentile_period: Period from ts to compute percentiles for. percentiles: Percentiles to compute. Values should be in the range ``0..100``. client: DtsClient to use for performing the partitioning. calendar: Calendar to to for interpreting time and partitioning the input time-series. Returns: A TsVector with one TimeSeries for each value in percentiles, all spanning period. """ periods = int((percentile_period.end - percentile_period.start)//average_dt) n_avg = calendar.diff_units(period.start, period.end, average_dt) if n_avg*average_dt < period.end - period.start: n_avg += 1 tsv = client.evaluate( ts.average(TimeAxis(period.start, average_dt, n_avg)) .partition_by(calendar, period.start, average_dt, periods, period.start), period ) tsv_p = tsv.percentiles(TimeAxis(period.start, average_dt, 1), percentiles) tsv = TsVector() ta = TimeAxis(period.start, period.end - period.start, 1) for ts_p in tsv_p: tsv.append(TimeSeries(ta, [ts_p.values[0]], POINT_AVERAGE_VALUE)) return tsv
def windowed_percentiles_tsv( ts: TimeSeries, period: UtcPeriod, average_dt: int, percentile_dt: int, percentiles: Sequence[int], client: DtsClient, calendar: Calendar ) -> TsVector: """Compute percentiles for a time-series in a gliding window fashion. The input time-series is partitioned and averaged using ``ts.partition_by`` such that each value is included in percentile computations spanning percentile_dt time from the value occurrence. Args: ts: TimeSeries to compute percentile time-series for. period: Period to generate percentile time-series for. average_dt: Period to average values by when partitioning the input time-series. This is the time-step of the time-series in the output TsVector. percentile_dt: Time span for a value to contribute to percentile computations. percentiles: Percentiles to compute. Values should be in the range ``0..100``. client: DtsClient to use for performing the partitioning. calendar: Calendar to to for interpreting time and partitioning the input time-series. Returns: A TsVector with one TimeSeries for each value in percentiles, all spanning period. """ periods = int(percentile_dt//average_dt) n_avg = calendar.diff_units(period.start, period.end, average_dt) if n_avg*average_dt < period.end - period.start: n_avg += 1 tsv = client.evaluate( ts.average(TimeAxis(period.start, average_dt, n_avg)) .partition_by(calendar, period.start, average_dt, periods, period.start) .time_shift(periods*average_dt), period ) return tsv.percentiles(TimeAxis(period.start, average_dt, n_avg), percentiles)
def selector_ts( ts: TimeSeries, period: UtcPeriod, average_dt: int, threshold_tss: Sequence[TimeSeries], tss: Sequence[TimeSeries], mask_point_fx: point_interpretation_policy, client: DtsClient, calendar: Calendar ) -> TimeSeries: """Select values from different time-series based on values from a single time-series when compared to a set of threshold time-series. Args: ts: TimeSeries to base selections on. period: Period to select values in. average_dt: Time step to use for the internal masking series. An average of the input ts together with the threshold time-series in threshold_tss is used to generate the masks. threshold_tss: Threshold time-series. Should be one less than the number of time-series to choose from. tss: TimeSeries to choose values from. mask_point_fx: Point interpretation to use for the mask time-series. If equal to POINT_INSTANT_VALUE the boundaries between different selection regions is smoothed. If equal to POINT_AVERAGE_VALUE the boundaries are sharp. client: DtsClient use for computations and data retrieval. calendar: Calendar used to interpret time. Returns: A TimeSeries that is the selection of values from tss. """ assert len(threshold_tss) == len(tss) - 1, ('the number of thresholds should be one less ' 'than the number of time-series') # setup averaging for mask tsv = TsVector() # ---------- n = calendar.diff_units(period.start, period.end, average_dt) if n * average_dt < period.end - period.start: n += 1 ta_avg = TimeAxis(period.start, average_dt, n) tsv.append(ts.average(ta_avg)) # ---------- tsv: TsVector = client.evaluate(tsv, period) # ---------- avg_ts = tsv[0] del tsv # compute mask masks: List[DoubleVector] = [] for avg_p, avg_v in zip(avg_ts.get_time_axis(), avg_ts.values): added_mask = False for i in range(len(tss)): if i == len(masks): masks.append(DoubleVector()) if not added_mask: # determine period threshold if i == 0: min_threshold = -1_000_000_000 max_threshold = threshold_tss[0](avg_p.start) elif i == len(tss) - 1: min_threshold = threshold_tss[-1](avg_p.start) max_threshold = 1_000_000_000 else: min_threshold = threshold_tss[i - 1](avg_p.start) max_threshold = threshold_tss[i](avg_p.start) # set mask value if min_threshold <= avg_v < max_threshold: added_mask = True masks[i].append(1.0) else: masks[i].append(0.0) else: masks[i].append(0.0) # construct final ts computed_ts = None for i, ts_expr in enumerate(tss): if computed_ts is not None: computed_ts += ts_expr * TimeSeries(ta_avg, masks[i], mask_point_fx) else: computed_ts = ts_expr * TimeSeries(ta_avg, masks[i], mask_point_fx) return computed_ts