Exemple #1
0
    def __init__(self,
                 building,
                 zones,
                 lambda_val,
                 start,
                 end,
                 forecasting_horizon,
                 window,
                 tstats,
                 non_contrallable_data=None):
        """

        :param building:
        :param zones:
        :param lambda_val:
        :param start: datetime with timezone
        :param end: datetime with timezone
        :param forecasting_horizon:
        :param window:
        :param tstats:
        :param non_contrallable_data:
        """
        assert xsg.get_window_in_sec(
            forecasting_horizon) % xsg.get_window_in_sec(window) == 0

        self.building = building
        self.zones = zones
        self.window = window
        self.lambda_val = lambda_val

        self.forecasting_horizon = forecasting_horizon
        self.delta_forecasting_horizon = datetime.timedelta(
            seconds=xsg.get_window_in_sec(forecasting_horizon))

        self.delta_window = datetime.timedelta(
            seconds=xsg.get_window_in_sec(window))

        # Simulation end is when current_time reaches end and end will become the end of our data.
        self.simulation_end = end
        end += self.delta_forecasting_horizon

        self.DataManager = DataManager(building, zones, start, end, window,
                                       non_contrallable_data)

        self.tstats = tstats  # dictionary of simulator object with key zone. has functions: current_temperature, next_temperature(action)

        self.current_time = start
        self.current_time_step = 0

        self.actions = {iter_zone: []
                        for iter_zone in self.zones}  # {zone: [ints]}
        self.temperatures = {
            iter_zone: [self.tstats[iter_zone].temperature]
            for iter_zone in self.zones
        }  # {zone: [floats]}
Exemple #2
0
def get_actions(request, all_buildings, all_zones):
    """Returns temperatures for a given request or None.
    Guarantees that no Nan values in returned data exist."""
    logging.info("received request:", request.building, request.zones,
                 request.start, request.end, request.window,
                 request.lambda_val, request.starting_temperatures,
                 request.unit)

    duration = xsg.get_window_in_sec(request.window)

    request_length = [
        len(request.building),
        len(request.zones), request.start, request.end,
        len(request.starting_temperatures), duration
    ]

    if request.building not in all_buildings:
        return None, "invalid request, building name is not valid."
    if any(v == 0 for v in request_length):
        return None, "invalid request, empty params"
    if request.end > int(time.time() * 1e9):
        return None, "invalid request, end date is in the future."
    if request.start >= request.end:
        return None, "invalid request, start date is after end date."
    if request.start < 0 or request.end < 0:
        return None, "invalid request, negative dates."
    if request.start + (duration * 1e9) > request.end:
        return None, "invalid request, start date + window is greater than end date."
    if request.unit != "F":
        return None, "invalid request, only Fahrenheit is supported as a unit."
    if not 0 <= request.lambda_val <= 1:
        return None, "invalid request, lambda_val needs to be between 0 and 1."
    if not all([
            iter_zone in request.starting_temperatures
            for iter_zone in all_zones[request.building]
    ]):
        return None, "invalid request, missing zones in starting_temperatures."

    d_start = datetime.utcfromtimestamp(float(request.start /
                                              1e9)).replace(tzinfo=pytz.utc)
    d_end = datetime.utcfromtimestamp(float(request.end /
                                            1e9)).replace(tzinfo=pytz.utc)

    MPC_instance = MPC(request.building, request.zones, d_start, d_end,
                       request.window, request.lambda_val)
    actions, err = MPC_instance.advise(request.starting_temperatures)
    if actions is None:
        return None, err

    return optimizer_pb2.Reply(actions=actions), None
Exemple #3
0
def get_train_test(building,
                   zone,
                   start,
                   end,
                   prediction_window,
                   raw_data_granularity,
                   train_ratio,
                   is_second_order,
                   use_occupancy,
                   curr_action_timesteps,
                   prev_action_timesteps,
                   check_data=True):
    """Create data set to train with.

    :param building: (string) building name
    :param zone: (string) zone name
    :param start: (datetime timezone aware) start of the dataset used
    :param end: (datetime timezone aware) start of the dataset used
    :param prediction_window: (str) number of seconds between predictions
    :param raw_data_granularity: (str) the window size of the raw data. needs to be less than prediction_window.
    :param train_ratio: (float) in (0, 1). the ratio in which to split train and test set from the given dataset. The train set comes before test set in time.
    :param is_second_order: (bool) Whether we are using second order in temperature.
    :param curr_action_timesteps: (int) The order of the current action. Set 0 if there should only be one action.
    :param prev_action_timesteps: (int) The order of the previous action. Set 0 if there should only be one prev action.
        Set -1 if it should not be used at all.
    :param method: (str) ["OLS", "random_forest", "LSTM"] are the available methods so far
    :param rmse_series: np.array the rmse of the forecasting procedure.
    :param num_forecasts: (int) The number of forecasts which contributed to the RMSE.
    :param forecasting_horizon: (int seconds) The horizon used when forecasting.
    :param check_data: If True (default), will enforce that training data has the right start/end times (recommended).
        If False, then data will be returns if it exists;
        However, the times may be different (allows model to be created faster by using previously prepocessed data)
        – useful when prototyping since the preprocessing does not have to be repeated.
    :return: trained sklearn.LinearRegression object.

    """
    seconds_prediction_window = xsg.get_window_in_sec(prediction_window)

    # Get data
    # TODO add check that the data we have stored is at least as long and has right prediction_window
    # TODO Fix how we deal with nan's. some zone temperatures might get set to -1.
    loaded_data = load_data(building, zone)
    err = xsg.check_data(loaded_data,
                         start,
                         end,
                         prediction_window,
                         check_nan=True)
    if (loaded_data is None) or ((err is not None) and check_data):
        processed_data, err = pid.get_preprocessed_data(
            building, zone, start, end, prediction_window,
            raw_data_granularity)
        if err is not None:
            return None, None, None, None, err
        store_data(processed_data, building, zone)
    else:
        processed_data = loaded_data.loc[start:end]

    # add features
    processed_data = pid.indoor_data_cleaning(processed_data)
    if is_second_order:
        processed_data = pid.add_feature_last_temperature(processed_data)
    if curr_action_timesteps > 0 or prev_action_timesteps > 0:
        processed_data = pid.convert_categorical_action(
            processed_data,
            num_start=curr_action_timesteps,
            num_end=prev_action_timesteps,
            interval_thermal=seconds_prediction_window)

    # split data into training and test sets
    N = processed_data.shape[0]  # number of datapoints
    train_data = processed_data.iloc[:int(N * train_ratio)]
    test_data = processed_data.iloc[int(N * train_ratio):]

    # which columns to drop for training and testing
    columns_to_drop = ["dt", "action_duration"]
    if curr_action_timesteps != 0:
        columns_to_drop.append("action")
    if prev_action_timesteps != 0 or prev_action_timesteps == -1:
        columns_to_drop.append(
            "action_prev"
        )  # TODO we might want to use this as a feature. so don't set to -1...
    if not use_occupancy:
        columns_to_drop.append("occ")

    # train data
    train_data = train_data[train_data["dt"] == seconds_prediction_window]
    train_data = train_data.drop(columns_to_drop, axis=1)
    if train_data.isna().values.any():
        return None, None, None, None, "Nan values detected in training data."

    train_y = train_data[
        "t_next"]  # Note: We now assume that there are no Nan values in data.
    train_X = train_data.drop(["t_next"], axis=1)

    # test data
    if test_data.isna().values.any():
        return None, None, None, None, "Nan values detected in test data."
    test_data = test_data[test_data["dt"] == seconds_prediction_window]
    test_data = test_data.drop(columns_to_drop, axis=1)

    test_y = test_data["t_next"]
    test_X = test_data.drop(["t_next"], axis=1)

    if train_X.shape[0] == 0:
        return None, None, None, None, "Not enough data to train the model."

    return train_X, train_y, test_X, test_y, None
    def __init__(self, building, zones, start, end, window, non_controllable_data={}):
        """Exposes:
            - self.comfortband
            - self.do_not_exceed
            - self.occupancy
            - self.outdoor_temperature
            - self.discomfort_stub
            - self.hvac_consumption
            - self.price
            - self.all_zone_temperatures: pd.df with columns being zone names and values being F temperatures

            - self.start
            - self.unix_start
            - self.end
            - self.unix_end
            - self.window

            - self.building
            - self.zones


        :param building:
        :param zones:
        :param start:
        :param end:
        :param window:
        :param non_controllable_data: possible keys:
                ["comfortband", "do_not_exceed", "occupancy", "outdoor_temperature"]
                for each key the value needs to be a dictionary with {zone: data} for all zones in self.zones.
                Outdoor temperature is just data since it is data for the whole building.
        """

        self.start = start
        self.unix_start = start.timestamp() * 1e9
        self.end = end
        self.unix_end = end.timestamp() * 1e9
        self.window = window  # timedelta string

        self.building = building
        self.zones = zones

        if non_controllable_data is None:
            non_controllable_data = {}
        # TODO add error checking. check that the right zones are given in non_controllable_data and that the start/end/window are right.

        # Documentation: All data here is in timeseries starting exactly at start and every step corresponds to one
        # interval. The end is not inclusive.

        # temperature band
        temperature_band_stub = xsg.get_temperature_band_stub()

        if "comfortband" not in non_controllable_data:
            self.comfortband = {
            iter_zone: xsg.get_comfortband(temperature_band_stub, self.building, iter_zone, self.start, self.end,
                                           self.window)
            for iter_zone in self.zones}
        else:
            self.comfortband = non_controllable_data["comfortband"]
        err = check_data_zones(self.zones, self.comfortband, start, end, window)
        if err is not None:
            raise Exception("Bad comfortband given. " + err)

        if "do_not_exceed" not in non_controllable_data:
            self.do_not_exceed = {
            iter_zone: xsg.get_do_not_exceed(temperature_band_stub, self.building, iter_zone, self.start, self.end,
                                             self.window)
            for iter_zone in self.zones}
        else:
            self.do_not_exceed = non_controllable_data["do_not_exceed"]
        err = check_data_zones(self.zones, self.do_not_exceed, start, end, window)
        if err is not None:
            raise Exception("Bad DoNotExceed given. " + err)

        # occupancy
        if "occupancy" not in non_controllable_data:
            occupancy_stub = xsg.get_occupancy_stub()
            self.occupancy = {
            iter_zone: xsg.get_occupancy(occupancy_stub, self.building, iter_zone, self.start, self.end, self.window)["occupancy"]
            for iter_zone in self.zones}
        else:
            self.occupancy = non_controllable_data["occupancy"]
        err = check_data_zones(self.zones, self.occupancy, start, end, window)
        if err is not None:
            raise Exception("Bad occupancy given. " + err)

        # outdoor temperatures
        if "outdoor_temperature" not in non_controllable_data:
            outdoor_historic_stub = xsg.get_outdoor_temperature_historic_stub()
            self.outdoor_temperature = xsg.get_preprocessed_outdoor_temperature(outdoor_historic_stub, self.building,
                                                                            self.start, self.end, self.window)["temperature"]
        else:
            self.outdoor_temperature = non_controllable_data["outdoor_temperature"]
        err = xsg.check_data(self.outdoor_temperature, start, end, window, check_nan=True)
        if err is not None:
            raise Exception("Bad outdoor temperature given. " + err)
        #         outdoor_prediction_channel = grpc.insecure_channel(OUTSIDE_PREDICTION)
        #         outdoor_prediction_stub = outdoor_temperature_prediction_pb2_grpc.OutdoorTemperatureStub(outdoor_prediction_channel)

        #         self.outdoor_temperatures = get_outside_temperature(
        #             outdoor_historic_stub, outdoor_prediction_stub, self.building, self.start, self.end, self.window)

        # discomfort channel
        # self.discomfort_stub = xsg.get_discomfort_stub(secure=False)

        # HVAC Consumption TODO ERROR CHECK?
        hvac_consumption_stub = xsg.get_hvac_consumption_stub()
        self.hvac_consumption = {iter_zone: xsg.get_hvac_consumption(hvac_consumption_stub, building, iter_zone)
                                 for iter_zone in self.zones}

        if "energy_price" not in non_controllable_data:
            price_stub = xsg.get_price_stub()
            self.energy_price = xsg.get_price(price_stub, building, "ENERGY", start, end, window)
        else:
            self.energy_price = non_controllable_data["energy_price"]
        err = xsg.check_data(self.energy_price, start, end, window, check_nan=True)
        if err is not None:
            raise Exception("Bad energy prices given. " + err)

        self.indoor_temperature_prediction_stub = xsg.get_indoor_temperature_prediction_stub()
        indoor_historic_stub = xsg.get_indoor_historic_stub()

        # TEMPORARY --------

        self.indoor_temperature_prediction = ThermalModel()

        # ------------

        # +++++++++++++ TODO other zone temps uncomment when wanting to use real thermal model and delete uncommented section
        #
        # # get indoor temperature for other zones.
        # if "all_zone_temperature_data" not in non_controllable_data:
        #     building_zone_names_stub = xsg.get_building_zone_names_stub()
        #     all_zones = xsg.get_zones(building_zone_names_stub, building)
        #     self.all_zone_temperature_data = {}
        #     for iter_zone in all_zones:
        #         # TODO there is an error with the indoor historic service where it doesn't return the full lenght of data.
        #         zone_temperature = xsg.get_indoor_temperature_historic(indoor_historic_stub, building, iter_zone, start, end + datetime.timedelta(seconds=xsg.get_window_in_sec(window)),
        #                                                                  window)
        #         assert zone_temperature['unit'].values[0] == "F"
        #         zone_temperature = zone_temperature["temperature"].squeeze()
        #         self.all_zone_temperature_data[iter_zone] = zone_temperature.interpolate("time")
        #     self.all_zone_temperature_data = pd.DataFrame(self.all_zone_temperature_data)
        # else:
        #     self.all_zone_temperature_data = non_controllable_data["all_zone_temperature_data"]
        # err = check_data_zones(zones, self.all_zone_temperature_data, start, end, window, check_nan=True)
        # if err is not None:
        #     if "Is missing zone" in err:
        #         raise Exception("Bad indoor temperature data given. " + err)
        #     else:
        #         for iter_zone in zones:
        #             err = xsg.check_data(self.all_zone_temperature_data[iter_zone], start, end, window, True)
        #             if "Nan values in data." in err:
        #                 self.all_zone_temperature_data[iter_zone][:] = 70 # TODO only doing this if interpolation above does not work because everything is nan
        #             else:
        #                 raise Exception("Bad indoor temperature data given. " + err)

        building_zone_names_stub = xsg.get_building_zone_names_stub()
        all_zones = xsg.get_zones(building_zone_names_stub, building)
        temp_pd = pd.Series(data=0, index = pd.date_range(start, end, freq=str(xsg.get_window_in_sec(window)) + "S"))
        self.all_zone_temperature_data = {iter_zone: temp_pd for iter_zone in all_zones}

        err = check_data_zones(zones, self.all_zone_temperature_data, start, end, window, check_nan=True)

        if err is not None:
            raise Exception("Bad indoor temperature data given. " + err)

        self.all_zone_temperature_data = pd.DataFrame(self.all_zone_temperature_data)
Exemple #5
0
 def timestep_to_datetime(self, timestep):
     return self.start + timestep * datetime.timedelta(
         seconds=xsg.get_window_in_sec(self.window))
Exemple #6
0
def get_preprocessed_data(building, zone, start, end, window, raw_data_granularity="1m"):
    """Get training data to use for indoor temperature prediction.

    :param building: (str) building name
    :param zone: (str) zone name
    :param start: (datetime timezone aware)
    :param end: (datetime timezone aware)
    :param window: (str) the intervals in which to split data.
    :param raw_data_granularity: (str) the intervals in which to get raw indoor data.
    :return: pd.df index= start (inclusive) to end (not inclusive) with frequency given by window.
            col=["t_in", "action",  "t_out", "t_next", "occ", "action_duration", "action_prev",
            "temperature_zone_...", "dt"]. TODO explain meaning of each feature somewhere.

    """
    # get indoor temperature and action for current zone
    indoor_historic_stub = xsg.get_indoor_historic_stub()
    indoor_temperatures = _get_indoor_temperature_historic(indoor_historic_stub, building, zone, start, end,
                                                             raw_data_granularity)
    assert indoor_temperatures['unit'].values[0] == "F"
    indoor_temperatures = indoor_temperatures["temperature"].squeeze()

    indoor_actions = _get_action_historic(indoor_historic_stub, building, zone, start, end, raw_data_granularity)
    indoor_actions = indoor_actions["action"].squeeze()

    # get indoor temperature for other zones.
    building_zone_names_stub = xsg.get_building_zone_names_stub()
    all_zones = xsg.get_zones(building_zone_names_stub, building)
    all_other_zone_temperature_data = {}
    for iter_zone in all_zones:
        if iter_zone != zone:
            other_zone_temperature = _get_indoor_temperature_historic(indoor_historic_stub,
                                                                 building, iter_zone, start, end, window)
            assert other_zone_temperature['unit'].values[0] == "F"
            other_zone_temperature = other_zone_temperature["temperature"].squeeze()
            all_other_zone_temperature_data[iter_zone] = other_zone_temperature

    # Preprocessing indoor data putting temperature and action data together.
    indoor_data = pd.concat([indoor_temperatures.to_frame(name="t_in"), indoor_actions.to_frame(name="action")], axis=1)
    preprocessed_data = preprocess_indoor_data(indoor_data, xsg.get_window_in_sec(window))
    if preprocessed_data is None:
        return None, "No data left after preprocessing."

    # get historic outdoor temperatures
    outdoor_historic_stub = xsg.get_outdoor_temperature_historic_stub()
    outdoor_historic_temperatures = xsg.get_outdoor_temperature_historic(outdoor_historic_stub, building, start, end, window)

    # getting occupancy
    # get occupancy
    occupancy_stub = xsg.get_occupancy_stub()
    occupancy = xsg.get_occupancy(occupancy_stub, building, zone, start, end, window)

    # add outdoor and occupancy and other zone temperatures
    preprocessed_data["t_out"] = [outdoor_historic_temperatures.loc[
                              idx: idx + datetime.timedelta(seconds=xsg.get_window_in_sec(window))].mean() for idx in
                                  preprocessed_data.index]

    preprocessed_data["occ"] = [occupancy.loc[
                              idx: idx + datetime.timedelta(seconds=xsg.get_window_in_sec(window))].mean() for idx in
                            preprocessed_data.index]

    for iter_zone, iter_data in all_other_zone_temperature_data.items():
        preprocessed_data["temperature_zone_" + iter_zone] = [
            iter_data.loc[idx: idx + datetime.timedelta(seconds=xsg.get_window_in_sec(window))].mean() for idx in
            preprocessed_data.index]

    # TODO check if we should drop nan values... or at least where they are coming from
    preprocessed_data = preprocessed_data.dropna(axis=0)

    return preprocessed_data, None
Exemple #7
0
                    best_action[iter_zone]))
            self.actions[iter_zone].append(best_action[iter_zone])

        return root

    def run(self):
        while self.current_time < self.simulation_end:
            self.step()


if __name__ == "__main__":
    forecasting_horizon = "4h"

    end = datetime.datetime.utcnow().replace(
        tzinfo=pytz.utc) - datetime.timedelta(
            seconds=xsg.get_window_in_sec(forecasting_horizon))
    end = end.replace(microsecond=0)
    start = end - datetime.timedelta(hours=6)

    print(start)
    print(start.timestamp())
    building = "avenal-animal-shelter"
    zones = ["hvac_zone_shelter_corridor"]
    window = "15m"
    lambda_val = 0.995
    tstats = {iter_zone: Tstat(building, iter_zone, 75) for iter_zone in zones}

    simulation = SimulationMPC(building, zones, lambda_val, start, end,
                               forecasting_horizon, window, tstats)

    t = time.time()
def _create_timeseries_feature(data, aggregation_window, aggregation_type,
                               forward_shifts, backward_shifts):
    """
    Creates some features available to a generic time series:
    - For every datapoint, will aggregate the non-nan values within it's time plus aggregation_window by aggregation type.
    - Creates higher orders of the data. Shifts the aggregated data according to forward_shifts and backward_shifts. Will append to column name "+/-i" for an i forward/backward shift.
    :param data: (pd.series) with equally spaced timeseries Index.
    :param aggregation_window: (str) The timeframe length for which to aggregate.
    :param aggregation_type: (str) ["mean", "max", "min", "None"]. None does nothing to the data (as if aggregated assuming first value of aggregation window is constant throughout.)
    :param forward_shifts: (int, positive) Number of forward shifts. Shift window is the timedelta of the input data timeseries.
    :param backward_shifts: (int, positive) Number of backward shifts. Shift window is the timedelta of the input data timeseries.
    :return: (pd.df) columns=orginal_col_name+["_+/-i"] *same pd.df index* as given in data input.
    """
    if not aggregation_type in ["mean", "max", "min"]:
        raise ValueError("Aggregation Type {} not valid/implemented.".format(
            aggregation_type))

    assert forward_shifts >= 0
    assert backward_shifts >= 0

    # timeseries checks
    if isinstance(data, pd.DataFrame):
        if len(data.columns) != 1:
            raise ValueError(
                "Data with type pd.DataFrame is expected to have exactly one column."
            )
    elif isinstance(data, pd.Series):
        data = pd.DataFrame(data, columns=[""])
    else:
        raise ValueError(
            "Data is expected to be of time pd.Dataframe or pd.Series.")

    # check if equally spaced timeseries

    # TODO how long should the data be. Should we check that?

    # aggregation step
    if (aggregation_type != "None") and (data.shape[0] > 1):

        df_sec = (data.index[1] - data.index[0]).seconds
        agg_sec = xsg.get_window_in_sec(aggregation_window)

        if agg_sec % df_sec != 0:
            raise ValueError(
                "Aggregation window of {}S is not evenly divided by the time length of {}S between data points in the data."
                .format(agg_sec, df_sec))
        if 24 * 60 * 60 % agg_sec != 0:
            raise ValueError(
                "Aggregation window of {}S does not evenly divide a day.".
                format(agg_sec))

        resample_dfs = []
        curr_base = 0

        while curr_base < agg_sec:
            resample_dfs.append(
                data.resample("{}S".format(agg_sec), base=curr_base))
            curr_base += df_sec

        if aggregation_type == "mean":
            aggregated_dfs = [
                resample_df.mean() for resample_df in resample_dfs
            ]
        elif aggregation_type == "max":
            aggregated_dfs = [
                resample_df.max() for resample_df in resample_dfs
            ]
        elif aggregation_type == "min":
            aggregated_dfs = [
                resample_df.min() for resample_df in resample_dfs
            ]

        data = pd.concat(aggregated_dfs).sort_index().loc[data.index]

    # shift step
    data_name = data.columns[0]

    shifted_data = data.copy()
    shifted_data.columns = [data_name + "_0"]

    for i in range(1, forward_shifts + 1):
        shifted_data[data_name +
                     "_+{}".format(i)] = shifted_data[data_name +
                                                      "_0"].shift(periods=-i)
    for i in range(1, backward_shifts + 1):
        shifted_data[data_name +
                     "_-{}".format(i)] = shifted_data[data_name +
                                                      "_0"].shift(periods=+i)

    data = shifted_data

    return data
Exemple #9
0
    def __init__(self, env_config):

        self.DataManager = DataManager(env_config["building"],
                                       env_config["zones"],
                                       env_config["start"], env_config["end"],
                                       env_config["window"])

        self.start = start
        self.unix_start = start.timestamp() * 1e9
        self.end = end
        self.unix_end = end.timestamp() * 1e9
        self.window = window  # timedelta string

        self.building = building
        self.zones = zones

        self.lambda_val = env_config["lambda_val"]

        # assert self.zones == all zones in building. this is because of the thermal model needing other zone temperatures.

        self.curr_timestep = 0

        self.indoor_starting_temperatures = env_config[
            "indoor_starting_temperatures"]  # to get starting temperatures [last, current]
        self.outdoor_starting_temperature = env_config[
            "outdoor_starting_temperature"]

        self.tstats = {}
        for iter_zone in self.zones:
            self.tstats[iter_zone] = Tstat(
                self.building,
                iter_zone,
                self.indoor_starting_temperatures[iter_zone]["current"],
                last_temperature=self.indoor_starting_temperatures[iter_zone]
                ["last"])

        assert 60 * 60 % xsg.get_window_in_sec(
            self.window) == 0  # window divides an hour
        assert (self.end - self.start).total_seconds() % xsg.get_window_in_sec(
            self.window) == 0  # window divides the timeframe

        # the number of timesteps
        self.num_timesteps = int((self.end - self.start).total_seconds() /
                                 xsg.get_window_in_sec(self.window))

        self.unit = env_config["unit"]
        assert self.unit == "F"

        # all zones current and last temperature = 2*num_zones
        # building outside temperature -> make a class for how this behaves = 1
        # timestep -> do one hot encoding of week, day, hour, window  \approx 4 + 7 + 24 + 60*60 / window
        low_bound = [32] * 2 * len(
            self.zones
        )  # we could use parametric temperature bounds... for now we will give negative inft reward
        low_bound += [-100]  # for outside temperature we cannot gurantee much

        high_bound = [100] * 2 * len(self.zones)
        high_bound += [200]  # for outside temperature we cannot gurantee much

        low_bound += [0] * (
            self.num_timesteps + 1
        )  # total timesteps plus the final timestep which wont be executed
        high_bound += [1] * (
            self.num_timesteps + 1
        )  # total timesteps plus the final timestep which wont be executed

        self.observation_space = Box(low=np.array(low_bound),
                                     high=np.array(high_bound),
                                     dtype=np.float32)

        self.action_space = Tuple((Discrete(3), ) * len(self.zones))

        self.reset()
Exemple #10
0
def get_simulation(request, all_buildings, all_zones):
    """Returns simulation temperatures and actions."""
    print("received request:", request.building, request.zones, request.start,
          request.end, request.window, request.forecasting_horizon,
          request.lambda_val, request.starting_temperatures, request.unit,
          request.num_runs)

    duration = xsg.get_window_in_sec(request.window)
    forecasting_horizon = xsg.get_window_in_sec(request.forecasting_horizon)

    request_length = [
        len(request.building),
        len(request.zones), request.start, request.end,
        len(request.starting_temperatures), duration
    ]

    if request.building not in all_buildings:
        return None, "invalid request, building name is not valid."
    if any(v == 0 for v in request_length):
        return None, "invalid request, empty params"
    if request.end > int(time.time() * 1e9):
        return None, "invalid request, end date is in the future."
    if request.start >= request.end:
        return None, "invalid request, start date is after end date."
    if request.start < 0 or request.end < 0:
        return None, "invalid request, negative dates."
    if request.start + (duration * 1e9) > request.end:
        return None, "invalid request, start date + window is greater than end date."
    if request.start + (forecasting_horizon * 1e9) > request.end:
        return None, "invalid request, start date + forecasting_horizon is greater than end date."
    if request.unit != "F":
        return None, "invalid request, only Fahrenheit is supported as a unit."
    if not 0 <= request.lambda_val <= 1:
        return None, "invalid request, lambda_val needs to be between 0 and 1."
    if not all([
            iter_zone in request.starting_temperatures
            for iter_zone in all_zones[request.building]
    ]):
        return None, "invalid request, missing zones in starting_temperatures."

    d_start = datetime.utcfromtimestamp(float(request.start /
                                              1e9)).replace(tzinfo=pytz.utc)
    d_end = datetime.utcfromtimestamp(float(request.end /
                                            1e9)).replace(tzinfo=pytz.utc)

    if request.num_runs != 1:
        return None, "invalid request, NotImplementedError: variables num_runs not working. Set num_runs to 1."

    # somewhat inefficient since this could be stored as class var...
    tstats = {
        iter_zone: Tstat(request.building,
                         iter_zone,
                         request.starting_temperatures[iter_zone],
                         suppress_not_enough_data_error=True)
        for iter_zone in request.zones
    }

    Simulation_instance = SimulationMPC(request.building, request.zones,
                                        request.lambda_val, d_start, d_end,
                                        request.forecasting_horizon,
                                        request.window, tstats)

    Simulation_instance.run()
    actions = Simulation_instance.actions
    temperatures = Simulation_instance.temperatures

    if actions is None or temperatures is None:
        return None, "Unable to Simulate. Simulation returns None."

    print(actions)
    actions = {
        iter_zone: optimizer_pb2.ActionList(actions=actions[iter_zone])
        for iter_zone in request.zones
    }
    temperatures = {
        iter_zone:
        optimizer_pb2.TemperatureList(temperatures=temperatures[iter_zone])
        for iter_zone in request.zones
    }

    return optimizer_pb2.SimulationReply(simulation_results=[
        optimizer_pb2.ActionTemperatureReply(actions=actions,
                                             temperatures=temperatures)
    ]), None