Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding bus to parametrized elements iterative #35

Merged
merged 5 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion data_adapter_oemof/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def get_default_parameters(
"type": cls.type,
}
# Add mapped attributes
mapped_values = mapper.get_default_mappings(cls, struct)
mapped_values = mapper.get_default_mappings(struct)
defaults.update(mapped_values)
# Add additional attributes
attributes = {
Expand Down
49 changes: 24 additions & 25 deletions data_adapter_oemof/build_datapackage.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from data_adapter import core
from data_adapter.preprocessing import Adapter
from data_adapter_oemof.adapters import FACADE_ADAPTERS
from data_adapter_oemof.mappings import PROCESS_TYPE_MAP
from data_adapter_oemof.mappings import PROCESS_TYPE_MAP, Mapper


def refactor_timeseries(timeseries: pd.DataFrame):
Expand Down Expand Up @@ -63,28 +63,6 @@ def refactor_timeseries(timeseries: pd.DataFrame):

return df_timeseries

def add_bus_to_element_dict(elements_dict):
"""
Takes a sequence dict of processes with sequence data and searches for busses in columns that contain `bus`
:param elements_dict:
:return: Updated Sequence with additional entry "bus" that contains all occurring bus entries as balanced busses.
"""
unique_entries = set()
for element in elements_dict.values():
bus_occourences = [col for col in element.columns if "bus" in col]
for bus_category_name in bus_occourences:
unique_entries.update(element[bus_category_name].unique())

unique_entries = pd.unique(list(unique_entries))
elements_dict["bus"] = pd.DataFrame(
{
"name": unique_entries,
"type": ["bus" for i in unique_entries],
"balanced": [True for i in unique_entries],
}
)

return elements_dict

@dataclasses.dataclass
class DataPackage:
Expand Down Expand Up @@ -133,21 +111,36 @@ def build_datapackage(cls, adapter: Adapter):

"""
es_structure = adapter.get_structure()
parametrized_elements = {}
parametrized_elements = {"bus": []}
parametrized_sequences = {}
foreign_keys = {}
# Iterate Elements
for process_name, struct in es_structure.items():
process_data = adapter.get_process(process_name)
timeseries = refactor_timeseries(process_data.timeseries)
facade_adapter_name: str = PROCESS_TYPE_MAP[process_name]
facade_adapter = FACADE_ADAPTERS[facade_adapter_name]
components = []

# Build class from adapter with Mapper and add up for each component within the Element
for component_data in process_data.scalars.to_dict(orient="records"):
component = facade_adapter.parametrize_dataclass(
process_name, component_data, timeseries, struct
)
components.append(component.as_dict())

# Fill bus.csv with all busses occurring
parametrized_elements["bus"] += list(
Mapper(
adapter=facade_adapter,
process_name=process_name,
data=component_data,
timeseries=timeseries,
)
.get_busses(struct)
.values()
)

scalars = pd.DataFrame(components)

# check if facade_adapter already exists
Expand All @@ -163,7 +156,13 @@ def build_datapackage(cls, adapter: Adapter):
parametrized_elements[facade_adapter_name] = scalars

parametrized_sequences = {process_name: timeseries}
parametrized_elements = add_bus_to_element_dict(parametrized_elements)
parametrized_elements["bus"] = pd.DataFrame(
{
"name": pd.unique(parametrized_elements["bus"]),
"type": ["bus" for i in pd.unique(parametrized_elements["bus"])],
"blanced": [True for i in pd.unique(parametrized_elements["bus"])],
FelixMau marked this conversation as resolved.
Show resolved Hide resolved
}
)
return cls(
parametrized_elements=parametrized_elements,
parametrized_sequences=parametrized_sequences,
Expand Down
28 changes: 15 additions & 13 deletions data_adapter_oemof/mappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def get(self, key, field_type: Optional[Type] = None):
mapped_key = self.map_key(key)
return self.get_data(mapped_key, field_type)

def get_busses(self, cls, struct):
def get_busses(self, struct):
"""
Identify mentioned buses in the facade.
Determine if each bus in the facade is classified as an "input"/"output".
Expand All @@ -137,38 +137,41 @@ def get_busses(self, cls, struct):
Between the structure CSV and the adapter's buses take name from the structure.

:param parameter: paramter for mapping different parameters within a process
:param cls: Child from Adapter class
:param struct: dict
:return: dictionary with tabular like Busses
"""
bus_occurrences_in_fields = [
field.name for field in dataclasses.fields(cls) if "bus" in field.name
field.name
for field in dataclasses.fields(self.adapter)
if "bus" in field.name
]
if len(bus_occurrences_in_fields) == 0:
logger.warning(
f"No busses found in facades fields for Dataadapter {cls.__name__}"
f"No busses found in facades fields for Dataadapter {self.adapter.__name__}"
)
# { input: [], output :[]}
# {default: {},
# co2:{}}}
bus_dict = {}
for bus in bus_occurrences_in_fields: # emission_bus
for bus in bus_occurrences_in_fields: # emission_bus
# 1. Check for existing mappings
try:
bus_dict[bus] = self.bus_map[cls.__name__][bus]
bus_dict[bus] = self.bus_map[self.adapter.__name__][bus]
continue
except KeyError:
pass

#TODO: Make use of Parameter [stuct.csv]?
# TODO: Make use of Parameter [stuct.csv]?
# Do we need parameter specific Bus structure? Maybe for multiple in/output?
if len(struct.keys()) == 1:
struct = list(struct.values())[0]
elif "default" in struct.keys():
struct = struct["default"]
else:
warnings.warn("Please check structure and provide either one set of inputs/outputs or specify as default"
"Parameter specific busses not implemented yet")
warnings.warn(
"Please check structure and provide either one set of inputs/outputs or specify as default"
"Parameter specific busses not implemented yet"
)

# 2. Check for default busses
if bus in ("bus", "from_bus", "to_bus"):
Expand Down Expand Up @@ -201,20 +204,19 @@ def get_busses(self, cls, struct):

return bus_dict

def get_default_mappings(self, cls, struct):
def get_default_mappings(self, struct):
"""
:param struct: dict
:param cls: Data-adapter which is inheriting from oemof.tabular facade
:param mapper: Mapper to map oemof.tabular data names to Project naming
:return: Dictionary for all fields that the facade can take and matching data
"""

mapped_all_class_fields = {
field.name: value
for field in dataclasses.fields(cls)
for field in dataclasses.fields(self.adapter)
if (value := self.get(field.name, field.type)) is not None
}
mapped_all_class_fields.update(self.get_busses(cls, struct))
mapped_all_class_fields.update(self.get_busses(struct))
return mapped_all_class_fields

@staticmethod
Expand Down
10 changes: 6 additions & 4 deletions tests/test_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def test_get_busses():
}
}

struct = {"default":{"inputs": ["ch4"], "outputs": ["electricity", "heat"]}}
struct = {"default": {"inputs": ["ch4"], "outputs": ["electricity", "heat"]}}

expected = {"electricity_bus": "electricity", "heat_bus": "heat", "fuel_bus": "ch4"}

Expand Down Expand Up @@ -135,7 +135,9 @@ def test_default_bus_mapping():
"custom_capacity": 100.0,
}

struct = {"default":{"inputs": ["electricity_bus_1"], "outputs": ["electricity_bus_2"]}}
struct = {
"default": {"inputs": ["electricity_bus_1"], "outputs": ["electricity_bus_2"]}
}

expected = {
"from_bus": "electricity_bus_1",
Expand All @@ -158,7 +160,7 @@ def test_default_bus_mapping():
"custom_capacity": 100.0,
}

struct = {"default":{"inputs": [], "outputs": ["electricity"]}}
struct = {"default": {"inputs": [], "outputs": ["electricity"]}}

expected = {"bus": "electricity"}

Expand Down Expand Up @@ -187,7 +189,7 @@ def test_get_matched_busses():

bus_map = {}

struct = {"default":{"inputs": ["ch4fuel"], "outputs": ["elec", "heating"]}}
struct = {"default": {"inputs": ["ch4fuel"], "outputs": ["elec", "heating"]}}

expected = {"electricity_bus": "elec", "heat_bus": "heating", "fuel_bus": "ch4fuel"}

Expand Down