Source code for powersimdata.input.changes.bus

import copy


[docs]def add_bus(obj, info): """Sets parameters of new bus(es) in change table. :param powersimdata.input.change_table.ChangeTable obj: change table :param list info: each entry is a dictionary. The dictionary gathers the information needed to create a new bus. Required keys: "lat", "lon", ["zone_id" XOR "zone_name"]. Optional key: "Pd", "baseKV". :raises TypeError: if ``info`` is not a list. :raises ValueError: if any new bus doesn't have appropriate keys/values. """ if not isinstance(info, list): raise TypeError("Argument enclosing new bus(es) must be a list") info = copy.deepcopy(info) new_buses = [] required = {"lat", "lon"} xor_sets = {("zone_id", "zone_name")} defaults = {"Pd": 0, "baseKV": 230} for i, new_bus in enumerate(info): obj._check_entry_keys( new_bus, i, "new_bus", required, xor_sets, defaults.keys() ) for l in {"lat", "lon"}: if not isinstance(new_bus[l], (int, float)): raise ValueError(f"{l} must be numeric (int/float)") if abs(new_bus["lat"]) > 90: raise ValueError("'lat' must be between -90 and +90") if abs(new_bus["lon"]) > 180: raise ValueError("'lon' must be between -180 and +180") if "zone_id" in new_bus and new_bus["zone_id"] not in obj.grid.id2zone: zone_id = new_bus["zone_id"] raise ValueError(f"zone_id {zone_id} not present in Grid") if "zone_name" in new_bus: try: new_bus["zone_id"] = obj.grid.zone2id[new_bus["zone_name"]] except KeyError: zone_name = new_bus["zone_name"] raise ValueError(f"zone_name {zone_name} not present in Grid") del new_bus["zone_name"] if "Pd" in new_bus: if not isinstance(new_bus["Pd"], (int, float)): raise ValueError("Pd must be numeric (int/float)") else: new_bus["Pd"] = defaults["Pd"] if "baseKV" in new_bus: if not isinstance(new_bus["baseKV"], (int, float)): raise ValueError("baseKV must be numeric (int/float)") if new_bus["baseKV"] <= 0: raise ValueError("baseKV must be positive") else: new_bus["baseKV"] = defaults["baseKV"] new_buses.append(new_bus) if "new_bus" not in obj.ct: obj.ct["new_bus"] = [] obj.ct["new_bus"] += new_buses
[docs]def remove_bus(obj, info): """Remove one or more buses. :param powersimdata.input.change_table.ChangeTable obj: change table :param int/iterable info: iterable of bus indices, or a single bus index. :raises ValueError: if ``info`` contains one or more entries not present in the bus table index. """ if isinstance(info, int): info = {info} # Check whether all buses to be removed are present in the grid diff = set(info) - set(obj._get_transformed_df("bus").index) if len(diff) != 0: raise ValueError(f"No bus with the following id(s): {sorted(diff)}") # Check whether there exist any plants with non-zero capacity at these buses anticipated_plant = obj._get_transformed_df("plant").query("Pmax > 0") plants_at_removal_buses = set(info) & set(anticipated_plant.bus_id) if len(plants_at_removal_buses) > 0: raise ValueError( f"Generators exist at bus id(s): {sorted(plants_at_removal_buses)}" ) # Check whether storage exists at these buses anticipated_storage = obj._get_transformed_df("storage_gen") storage_at_removal_buses = set(info) & set(anticipated_storage.bus_id) if len(storage_at_removal_buses) > 0: raise ValueError( f"Storage units exist at bus id(s): {sorted(storage_at_removal_buses)}" ) # Check whether there exist branches or DC lines at these buses for table in ("branch", "dcline"): anticipated = obj._get_transformed_df(table) overlap = anticipated.query("from_bus_id in @info or to_bus_id in @info") if len(overlap) > 0: raise ValueError( f"These {table} IDs connect to a bus to be removed: {overlap.index}" ) # All checks have passed, and we can add this to the change table if "remove_bus" not in obj.ct: obj.ct["remove_bus"] = set() obj.ct["remove_bus"] |= set(info)