Пример #1
0
def test_demand_is_scaled(base_grid, raw_demand):
    base_demand = raw_demand[base_grid.id2zone.keys()]

    n_zone = param["n_zone_to_scale"]
    ct = ChangeTable(base_grid)
    ct.scale_demand(
        zone_id={
            z: f
            for z, f in zip(
                np.random.choice([i for i in base_grid.zone2id.values()],
                                 size=n_zone,
                                 replace=False),
                2 * np.random.random(size=n_zone),
            )
        })

    tg = TransformGrid(base_grid, ct.ct)
    transformed_grid = tg.get_grid()

    empty_scenario_info = {
    }  # scenario_info not needed since profile_input is mocked
    tp = TransformProfile(empty_scenario_info, transformed_grid, ct.ct)
    transformed_profile = tp.get_profile("demand")
    assert not base_demand.equals(transformed_profile)

    scaled_zone = list(ct.ct["demand"]["zone_id"].keys())
    unscaled_zone = set(base_grid.id2zone.keys()) - set(scaled_zone)
    factor = list(ct.ct["demand"]["zone_id"].values())
    assert transformed_profile[scaled_zone].equals(
        base_demand[scaled_zone].multiply(factor, axis=1))
    if unscaled_zone:
        assert transformed_profile[list(unscaled_zone)].equals(
            base_demand[list(unscaled_zone)])
Пример #2
0
    def prepare_profile(self, kind, profile_as=None):
        """Prepares profile for simulation.

        :param kind: one of *demand*, *'hydro'*, *'solar'* or *'wind'*.
        :param int/str/None profile_as: if given, copy profile from this scenario.
        """
        if profile_as is None:
            tp = TransformProfile(self._scenario_info, self.grid, self.ct)
            profile = tp.get_profile(kind)
            print(
                f"Writing scaled {kind} profile in {server_setup.LOCAL_DIR} on local machine"
            )
            file_name = "%s_%s.csv" % (self._scenario_info["id"], kind)
            profile.to_csv(os.path.join(server_setup.LOCAL_DIR, file_name))

            self._data_access.move_to(
                file_name, self.REL_TMP_DIR, change_name_to=f"{kind}.csv"
            )
        else:
            from_dir = posixpath.join(
                self.server_config.execute_dir(),
                f"scenario_{profile_as}",
            )
            to_dir = posixpath.join(
                self.server_config.execute_dir(), self.scenario_folder
            )
            _, _, stderr = self._data_access.copy(f"{from_dir}/{kind}.csv", to_dir)
            if len(stderr.readlines()) != 0:
                raise IOError(f"Failed to copy {kind}.csv on server")
Пример #3
0
    def get_demand(self, original=True):
        """Returns demand profiles.

        :param bool original: should the original demand profile or the
            potentially modified one be returned.
        :return: (*pandas.DataFrame*) -- data frame of demand (hour, zone).
        """
        profile = TransformProfile(self._scenario_info, self.get_grid(), self.get_ct())
        demand = profile.get_profile("demand")

        if original:
            return demand
        else:
            dates = pd.date_range(
                start=self._scenario_info["start_date"],
                end=self._scenario_info["end_date"],
                freq=self._scenario_info["interval"],
            )
            infeasibilities = self._parse_infeasibilities()
            if infeasibilities is None:
                print("No infeasibilities. Return original profile.")
                return demand
            else:
                for key, value in infeasibilities.items():
                    start = dates[key]
                    end = (
                        dates[key]
                        + pd.Timedelta(self._scenario_info["interval"])
                        - pd.Timedelta("1H")
                    )
                    demand[start:end] *= 1.0 - value / 100.0
                return demand
Пример #4
0
    def get_wind(self):
        """Returns wind profile

        :return: (*pandas.DataFrame*) -- data frame of wind energy output.
        """
        profile = TransformProfile(self._scenario_info, self.get_grid(), self.get_ct())
        return profile.get_profile("wind")
Пример #5
0
    def get_solar(self):
        """Returns solar profile

        :return: (*pandas.DataFrame*) -- data frame of solar energy output.
        """
        profile = TransformProfile(self._scenario_info, self.get_grid(), self.get_ct())
        return profile.get_profile("solar")
Пример #6
0
    def get_hydro(self):
        """Returns hydro profile

        :return: (*pandas.DataFrame*) -- data frame of hydro energy output.
        """
        profile = TransformProfile(self._scenario_info, self.get_grid(), self.get_ct())
        return profile.get_profile("hydro")
Пример #7
0
    def get_profile(self, kind):
        """Returns demand, hydro, solar or wind  profile.

        :param str kind: either *'demand'*, *'hydro'*, *'solar'*, *'wind'*.
        :return: (*pandas.DataFrame*) -- profile.
        """
        profile = TransformProfile(self._scenario_info, self.get_grid(),
                                   self.get_ct())
        return profile.get_profile(kind)
Пример #8
0
    def get_profile(self, kind):
        """Returns demand, hydro, solar or wind  profile.

        :param str kind: either *'demand'*, *'hydro'*, *'solar'*, *'wind'*.
        :return: (*pandas.DataFrame*) -- profile.
        """
        if getattr(self, kind):
            profile = TransformProfile(
                {
                    "grid_model": self.grid_model,
                    "base_%s" % kind: getattr(self, kind),
                },
                self.get_grid(),
                self.get_ct(),
            )
            return profile.get_profile(kind)
        else:
            raise Exception("%s profile version not set" % kind)
Пример #9
0
def _check_plants_are_scaled(ct, base_grid, profile_info, raw_profile, resource):
    plant_id_type = get_plant_with_resource(base_grid, resource)

    base_profile = (
        raw_profile[plant_id_type] * base_grid.plant.loc[plant_id_type, "Pmax"]
    )

    tg = TransformGrid(base_grid, ct)
    transformed_grid = tg.get_grid()

    tp = TransformProfile(profile_info, transformed_grid, ct)
    transformed_profile = tp.get_profile(resource)

    scaled_plant_id = []
    scaling_factor_plant = []
    if "zone_id" in ct[resource].keys():
        for z, f in ct[resource]["zone_id"].items():
            plant_id_zone = (
                base_grid.plant.groupby(["zone_id", "type"])
                .get_group((z, resource))
                .index.tolist()
            )
            scaled_plant_id += plant_id_zone
            scaling_factor_plant += [f] * len(plant_id_zone)
    if "plant_id" in ct[resource].keys():
        for i, f in ct[resource]["plant_id"].items():
            if i in scaled_plant_id:
                scaling_factor_plant[scaled_plant_id.index(i)] *= f
            else:
                scaled_plant_id.append(i)
                scaling_factor_plant.append(f)

    assert not base_profile.equals(transformed_profile)
    assert_almost_equal(
        transformed_profile[scaled_plant_id].values,
        base_profile[scaled_plant_id].multiply(scaling_factor_plant, axis=1).values,
    )

    unscaled_plant_id = set(plant_id_type) - set(scaled_plant_id)
    if unscaled_plant_id:
        assert transformed_profile[unscaled_plant_id].equals(
            base_profile[unscaled_plant_id]
        )
    return transformed_profile
Пример #10
0
def test_flexible_demand_profiles_are_trimmed(base_grid,
                                              raw_demand_flexibility_up,
                                              raw_demand_flexibility_dn,
                                              monkeypatch):
    monkeypatch.setattr(Context, "get_data_access",
                        MockContext().get_data_access)
    data_access = Context.get_data_access()

    # Specify the fake demand flexibility profiles from MockInputData
    zone_keys = [f"zone.{z}" for z in base_grid.id2zone.keys()]
    base_demand_flexibility_up = raw_demand_flexibility_up[zone_keys]
    base_demand_flexibility_dn = raw_demand_flexibility_dn[zone_keys]

    # Create fake files in the expected directory path
    exp_path = f"raw/{base_grid.grid_model}"

    for csv_file in (
            "demand_flexibility_up_Test.csv",
            "demand_flexibility_dn_Test.csv",
    ):
        with data_access.write(exp_path + "/" + csv_file) as f:
            pd.DataFrame().to_csv(f)

    # Specify the change table
    ct = ChangeTable(base_grid)
    ct.add_demand_flexibility({
        "demand_flexibility_up": "Test",
        "demand_flexibility_dn": "Test",
        "demand_flexibility_duration": 6,
    })

    # Transform the grid object accordingly
    tg = TransformGrid(base_grid, ct.ct)
    transformed_grid = tg.get_grid()

    # Test that the demand flexibility profiles are pruned
    empty_scenario_info = {"grid_model": base_grid.grid_model}
    tp = TransformProfile(empty_scenario_info, transformed_grid, ct.ct)
    transformed_demand_flexibility_up = tp.get_profile("demand_flexibility_up")
    transformed_demand_flexibility_dn = tp.get_profile("demand_flexibility_dn")
    assert base_demand_flexibility_up.equals(transformed_demand_flexibility_up)
    assert base_demand_flexibility_dn.equals(transformed_demand_flexibility_dn)
Пример #11
0
    def get_profile(self, kind):
        """Returns demand, hydro, solar or wind  profile.

        :param str kind: either *'demand'*, *'hydro'*, *'solar'*, *'wind'*.
        :return: (*pandas.DataFrame*) -- profile.
        :raises Exception: if :attr:`builder` has not been assigned yet through
            meth:`set_builder` or if :meth:`_Builder.set_base_profile` has not been
            called yet.
        """
        if getattr(self.builder, kind):
            profile = TransformProfile(
                {
                    "grid_model": getattr(self.builder, "grid_model"),
                    "base_%s" % kind: getattr(self.builder, kind),
                },
                self.get_grid(),
                self.get_ct(),
            )
            return profile.get_profile(kind)
        else:
            raise Exception("%s profile version not set" % kind)
Пример #12
0
    def prepare_profile(self, kind, profile_as=None, slice=False):
        """Prepares profile for simulation.

        :param kind: one of *demand*, *'hydro'*, *'solar'*, *'wind'*,
            *'demand_flexibility_up'*, *'demand_flexibility_dn'*,
            *'demand_flexibility_cost_up'*, or *'demand_flexibility_cost_dn'*.
        :param int/str profile_as: if given, copy profile from this scenario.
        :param bool slice: whether to slice the profiles by the Scenario's time range.
        """
        file_name = f"{kind}.csv"
        dest_path = "/".join([self.REL_TMP_DIR, file_name])
        if profile_as is None:
            tp = TransformProfile(self._scenario_info, self.grid, self.ct, slice)
            profile = tp.get_profile(kind)
            print(f"Writing scaled {kind} profile to {dest_path}")
            with self._data_access.write(dest_path, save_local=False) as f:
                profile.to_csv(f)
        else:
            from_dir = self._data_access.tmp_folder(profile_as)
            src = "/".join([from_dir, file_name])
            self._data_access.fs.copy(src, dest_path)
Пример #13
0
def export_transformed_profile(kind,
                               scenario_info,
                               grid,
                               ct,
                               filepath,
                               slice=True):
    """Apply transformation to the given kind of profile and save the result locally.

    :param str kind: which profile to export. This parameter is passed to
        :meth:`TransformProfile.get_profile`.
    :param dict scenario_info: a dict containing the profile version, with
        key in the form base_{kind}
    :param powersimdata.input.grid.Grid grid: a Grid object previously
        transformed.
    :param dict ct: change table.
    :param str filepath: path to save the result, including the filename
    :param bool slice: whether to slice the profiles by the Scenario's time range.
    """
    tp = TransformProfile(scenario_info, grid, ct, slice)
    profile = tp.get_profile(kind)
    print(f"Writing scaled {kind} profile to {filepath} on local machine")
    profile.to_csv(filepath)
Пример #14
0
def test_demand_is_scaled(base_grid):
    input_data = InputData()
    demand_info = {
        "interconnect": "_".join(interconnect),
        "grid_model": "usa_tamu",
        "base_demand": param["demand"],
    }
    raw_demand = input_data.get_data(demand_info, "demand")
    base_demand = raw_demand[base_grid.id2zone.keys()]

    n_zone = param["n_zone_to_scale"]
    ct = ChangeTable(base_grid)
    ct.scale_demand(
        zone_id={
            z: f
            for z, f in zip(
                np.random.choice(
                    [i for i in base_grid.zone2id.values()], size=n_zone, replace=False
                ),
                2 * np.random.random(size=n_zone),
            )
        }
    )

    tg = TransformGrid(base_grid, ct.ct)
    transformed_grid = tg.get_grid()

    tp = TransformProfile(demand_info, transformed_grid, ct.ct)
    transformed_profile = tp.get_profile("demand")
    assert not base_demand.equals(transformed_profile)

    scaled_zone = list(ct.ct["demand"]["zone_id"].keys())
    unscaled_zone = set(base_grid.id2zone.keys()) - set(scaled_zone)
    factor = list(ct.ct["demand"]["zone_id"].values())
    assert transformed_profile[scaled_zone].equals(
        base_demand[scaled_zone].multiply(factor, axis=1)
    )
    if unscaled_zone:
        assert transformed_profile[unscaled_zone].equals(base_demand[unscaled_zone])
Пример #15
0
def _check_new_plants_are_added(ct, base_grid, raw_profile, resource):
    n_plant = param["n_plant_to_add"]
    plant_id_type = (base_grid.plant.isin(
        profile_type[resource]).query("type == True").index)
    base_profile = (raw_profile[plant_id_type] *
                    base_grid.plant.loc[plant_id_type, "Pmax"])

    tg = TransformGrid(base_grid, ct)
    transformed_grid = tg.get_grid()

    empty_scenario_info = {
    }  # scenario_info not needed since profile_input is mocked
    tp = TransformProfile(empty_scenario_info, transformed_grid, ct)
    transformed_profile = tp.get_profile(resource)

    assert not transformed_profile.equals(base_profile)
    assert not len(base_profile.columns) == len(transformed_profile.columns)
    assert len(set(transformed_profile.columns) -
               set(base_profile.columns)) == n_plant
    assert set(transformed_profile.columns) - set(base_profile.columns) == set(
        transformed_grid.plant.index[-n_plant:])

    return transformed_profile.drop(base_profile.columns, axis=1)
def construct_load_shed(scenario_info, grid, ct, infeasibilities=None):
    """Constructs load_shed dataframe from relevant scenario/grid data.

    :param dict scenario_info: info attribute of Scenario object.
    :param powersimdata.input.grid.Grid grid: grid to construct load_shed for.
    :param dict ct: ChangeTable dictionary.
    :param dict/None infeasibilities: dictionary of
        {interval (int): load shed percentage (int)}, or None.
    :return: (*pandas.DataFrame*) -- data frame of load_shed.
    """
    hours = pd.date_range(start=scenario_info["start_date"],
                          end=scenario_info["end_date"],
                          freq="1H").tolist()
    buses = grid.bus.index
    if infeasibilities is None:
        print("No infeasibilities, constructing DataFrame")
        load_shed_data = coo_matrix((len(hours), len(buses)))
        load_shed = pd.DataFrame.sparse.from_spmatrix(load_shed_data)
    else:
        print("Infeasibilities, constructing DataFrame")
        zone_demand = TransformProfile(scenario_info, grid, ct)
        bus_demand = distribute_demand_from_zones_to_buses(
            zone_demand, grid.bus)
        load_shed = np.zeros((len(hours), len(buses)))
        # Convert '24H' to 24
        interval = int(scenario_info["interval"][:-1])
        for i, v in infeasibilities.items():
            start = i * interval
            end = (i + 1) * interval
            base_demand = bus_demand.iloc[start:end, :].to_numpy()
            shed_demand = base_demand * (v / 100)
            load_shed[start:end, :] = shed_demand
        load_shed = pd.DataFrame(load_shed, columns=buses, index=hours)
        load_shed = load_shed.astype(pd.SparseDtype("float", 0))
    load_shed.index = hours
    load_shed.index.name = "UTC"
    load_shed.columns = buses

    return load_shed