Code Base

Following section display the code snippets that were used to create the TransC/E results and diagrams.

System-Model-Scenario-Combination Creation Code

Following code snippet shows how to create the TransC/E combinations

import os

import numpy as np
import pandas as pd

import tessif.frused.namedtuples as nts
from tessif.frused.paths import example_dir
from tessif.model import components, energy_system


def create_losslc_es(periods=24,):
    """
    Create the TransCnE system model scenarios combinations.

    Parameters
    ----------
    periods : int, default=24
        Number of time steps of the evaluated timeframe (one time step is one
        hour)

    Note
    ----
    Changes compared to `Hanke Project Thesis
    <https://tore.tuhh.de/handle/11420/11759>`_:

        1. Rename ``"[High/Mid/Low] Voltage Powerline"`` to ``"[High/Mid/Low]
           Voltage Grid"``
        2. Rename ``"[High/Low] Voltage Transformator"`` to ``"[High/Low]
           Voltage Transfer Grid"``

    Return
    ------
    es: :class:`tessif.model.energy_system.AbstractEnergySystem`
        Tessif energy system.
    """
    # 2. Create a simulation time frame as a :class:`pandas.DatetimeIndex`:
    timeframe = pd.date_range('10/13/2030', periods=periods, freq='H')

    # 3. Parse csv files with the demand and renewables load data:
    d = os.path.join(example_dir, 'data', 'tsf', 'load_profiles')

    # solar:
    pv = pd.read_csv(os.path.join(d, 'Renewable_Energy.csv'),
                     index_col=0, sep=';')
    pv = pv['pv_load'].values.flatten()[0:periods]
    max_pv = np.max(pv)

    # wind onshore:
    w_on = pd.read_csv(os.path.join(
        d, 'Renewable_Energy.csv'), index_col=0, sep=';')
    w_on = w_on['won_load'].values.flatten()[0:periods]
    max_w_on = np.max(w_on)

    # wind offshore:
    w_off = pd.read_csv(os.path.join(
        d, 'Renewable_Energy.csv'), index_col=0, sep=';')
    w_off = w_off['woff_load'].values.flatten()[0:periods]
    max_w_off = np.max(w_off)

    # solar thermal:
    s_t = pd.read_csv(os.path.join(
        d, 'Renewable_Energy.csv'), index_col=0, sep=';')
    s_t = s_t['st_load'].values.flatten()[0:periods]
    max_s_t = np.max(s_t)

    # household demand
    h_d = pd.read_csv(os.path.join(d, 'Loads.csv'), index_col=0, sep=';')
    h_d = h_d['household_demand'].values.flatten()[0:periods]
    max_h_d = np.max(h_d)

    # industrial demand
    i_d = pd.read_csv(os.path.join(d, 'Loads.csv'), index_col=0, sep=';')
    i_d = i_d['industrial_demand'].values.flatten()[0:periods]
    max_i_d = np.max(i_d)

    # commercial demand
    c_d = pd.read_csv(os.path.join(d, 'Loads.csv'), index_col=0, sep=';')
    c_d = c_d['commercial_demand'].values.flatten()[0:periods]
    max_c_d = np.max(c_d)

    # district heating demand
    dh_d = pd.read_csv(os.path.join(d, 'Loads.csv'), index_col=0, sep=';')
    dh_d = dh_d['heat_demand'].values.flatten()[0:periods]
    max_dh_d = np.max(dh_d)

    # car charging demand
    cc_d = pd.read_csv(os.path.join(d, 'Car_Charging.csv'),
                       index_col=0, sep=';')
    cc_d = cc_d['cc_demand'].values.flatten()[0:periods]
    max_cc_d = np.max(cc_d)

    # 4. Create the individual energy system components:
    global_constraints = {
        'name': 'default',
        'emissions': float('+inf'),
    }

    # -------------Low Voltage and heat ------------------

    solar_panel = components.Source(
        name='Solar Panel',
        outputs=('electricity',),
        # Minimum number of arguments required
        sector='Power',
        carrier='Electricity',
        node_type='Renewable',
        flow_rates={'electricity': nts.MinMax(min=0, max=max_pv)},
        flow_costs={'electricity': 60.85},
        flow_emissions={'electricity': 0},
        timeseries={'electricity': nts.MinMax(min=pv, max=pv)},

    )

    biogas_supply = components.Source(
        name='Biogas plant',
        outputs=('fuel',),
        # Minimum number of arguments required
        sector='Coupled',
        carrier='Gas',
        node_type='source',
        flow_rates={'fuel': nts.MinMax(min=0, max=25987.87879)},
        flow_costs={'fuel': 0},
        flow_emissions={'fuel': 0},
    )

    bhkw_generator = components.Transformer(
        name='BHKW',
        inputs=('fuel',),
        outputs=('electricity', 'heat'),
        conversions={('fuel', 'electricity'): 0.33, ('fuel', 'heat'): 0.52},
        # Minimum number of arguments required
        sector='Coupled',
        carrier='electricity',
        node_type='transformer',
        flow_rates={
            'fuel': nts.MinMax(min=0, max=25987.87879),
            'electricity': nts.MinMax(min=0, max=8576),
            'heat': nts.MinMax(min=0, max=13513.69697)},
        flow_costs={'fuel': 0, 'electricity': 124.4, 'heat': 31.1},
        flow_emissions={'fuel': 0, 'electricity': 0.1573, 'heat': 0.0732},
    )

    household_demand = components.Sink(
        name='Household Demand',
        inputs=('electricity',),
        # Minimum number of arguments required
        sector='Power',
        carrier='electricity',
        node_type='demand',
        flow_rates={'electricity': nts.MinMax(min=0, max=max_h_d)},
        flow_costs={'electricity': 0},
        flow_emissions={'electricity': 0},
        timeseries={'electricity': nts.MinMax(min=h_d, max=h_d)},
    )

    commercial_demand = components.Sink(
        name='Commercial Demand',
        inputs=('electricity',),
        # Minimum number of arguments required
        sector='Power',
        carrier='electricity',
        node_type='demand',
        flow_rates={'electricity': nts.MinMax(min=0, max=max_c_d)},
        flow_costs={'electricity': 0},
        flow_emissions={'electricity': 0},
        timeseries={'electricity': nts.MinMax(min=c_d, max=c_d)},
    )

    heat_demand = components.Sink(
        name='District Heating Demand',
        inputs=('heat',),
        # Minimum number of arguments required
        sector='Heat',
        carrier='hot Water',
        node_type='demand',
        flow_rates={'heat': nts.MinMax(min=0, max=max_dh_d)},
        flow_costs={'heat': 0},
        flow_emissions={'heat': 0},
        timeseries={'heat': nts.MinMax(min=dh_d, max=dh_d)},
    )

    gas_supply_line = components.Bus(
        name='Gaspipeline',
        inputs=('Gas Station.fuel',),
        outputs=('GuD.fuel',),
        # Minimum number of arguments required
        sector='Power',
        carrier='gas',
        node_type='bus',
    )

    biogas_supply_line = components.Bus(
        name='Biogas',
        inputs=('Biogas plant.fuel',),
        outputs=('BHKW.fuel',),
        # Minimum number of arguments required
        sector='Coupled',
        carrier='gas',
        node_type='bus',
    )

    low_electricity_line = components.Bus(
        name='Low Voltage Powerline',
        inputs=(
            'BHKW.electricity',
            'Battery.electricity',
            'Solar Panel.electricity',
        ),
        outputs=(
            'Household Demand.electricity',
            'Commercial Demand.electricity',
            'Battery.electricity',
        ),
        # Minimum number of arguments required
        sector='Power',
        carrier='electricity',
        node_type='bus',
    )

    heat_line = components.Bus(
        name='District Heating',
        inputs=(
            'BHKW.heat',
            'Solar Thermal.heat',
            'Heat Storage.heat',
            'Power to Heat.heat',
            'HKW.heat',
        ),
        outputs=(
            'District Heating Demand.heat',
            'Heat Storage.heat',
        ),
        # Minimum number of arguments required
        sector='Heat',
        carrier='hot Water',
        node_type='bus',
    )

    # ----- -------Medium Voltage and Heat ------------------

    onshore_wind_power = components.Source(
        name='Onshore Wind Power',
        outputs=('electricity',),
        # Minimum number of arguments required
        sector='Power',
        carrier='Electricity',
        node_type='Renewable',
        flow_rates={'electricity': nts.MinMax(min=0, max=max_w_on)},
        flow_costs={'electricity': 61.1},
        flow_emissions={'electricity': 0},
        timeseries={'electricity': nts.MinMax(min=w_on, max=w_on)},
    )

    solar_thermal = components.Source(
        name='Solar Thermal',
        outputs=('heat',),
        # Minimum number of arguments required
        sector='Heat',
        carrier='Hot Water',
        node_type='Renewable',
        flow_rates={'heat': nts.MinMax(min=0, max=max_s_t)},
        flow_costs={'heat': 73},
        flow_emissions={'heat': 0},
        timeseries={'heat': nts.MinMax(min=s_t, max=s_t)},
    )

    industrial_demand = components.Sink(
        name='Industrial Demand',
        inputs=('electricity',),
        # Minimum number of arguments required
        sector='Power',
        carrier='electricity',
        node_type='demand',
        flow_rates={'electricity': nts.MinMax(min=0, max=max_i_d)},
        flow_costs={'electricity': 0},
        flow_emissions={'electricity': 0},
        timeseries={'electricity': nts.MinMax(min=i_d, max=i_d)},
    )

    car_charging_station_demand = components.Sink(
        name='Car charging Station',
        inputs=('electricity',),
        # Minimum number of arguments required
        sector='Power',
        carrier='electricity',
        node_type='demand',
        flow_rates={'electricity': nts.MinMax(min=0, max=max_cc_d)},
        flow_costs={'electricity': 0},
        flow_emissions={'electricity': 0},
        timeseries={'electricity': nts.MinMax(min=cc_d, max=cc_d)},
    )

    power_to_heat = components.Transformer(
        name='Power to Heat',
        inputs=('electricity',),
        outputs=('heat',),
        conversions={('electricity', 'heat'): 1.00},
        # Minimum number of arguments required
        carrier='Hot Water',
        node_type='transformer',
        flow_rates={
            'electricity': nts.MinMax(min=0, max=50000),
            'heat': nts.MinMax(min=0, max=50000),
        },
        flow_costs={'electricity': 0, 'heat': 0},
        flow_emissions={'electricity': 0, 'heat': 0},
    )

    medium_electricity_line = components.Bus(
        name='Medium Voltage Grid',
        inputs=('Onshore Wind Power.electricity',),
        outputs=(
            'Car charging Station.electricity',
            'Industrial Demand.electricity',
            'Power to Heat.electricity',
        ),
        # Minimum number of arguments required
        sector='Power',
        carrier='electricity',
        node_type='bus',
    )

    low_medium_transformator = components.Connector(
        name='Low Voltage Transfer Grid',
        interfaces=(
            'Medium Voltage Grid',
            'Low Voltage Powerline'),
        conversions={
            ('Medium Voltage Grid', 'Low Voltage Powerline'): 1,
            ('Low Voltage Powerline', 'Medium Voltage Grid'): 1,
        },
        node_type='connector',
    )

    # ----------------- High Voltage -------------------------

    offshore_wind_power = components.Source(
        name='Offshore Wind Power',
        outputs=('electricity',),
        # Minimum number of arguments required
        sector='Power',
        carrier='Electricity',
        node_type='Renewable',
        flow_rates={'electricity': nts.MinMax(min=0, max=max_w_off)},
        flow_costs={'electricity': 106.4},
        flow_emissions={'electricity': 0},
        timeseries={'electricity': nts.MinMax(min=w_off, max=w_off)},
    )

    coal_supply = components.Source(
        name='Coal Supply',
        outputs=('fuel',),
        # Minimum number of arguments required
        sector='Coupled',
        carrier='Coal',
        node_type='source',
        flow_rates={'fuel': nts.MinMax(min=0, max=102123.3)},
        flow_costs={'fuel': 0},
        flow_emissions={'fuel': 0},
    )

    gas_supply = components.Source(
        name='Gas Station',
        outputs=('fuel',),
        # Minimum number of arguments required
        sector='Power',
        carrier='Gas',
        node_type='source',
        flow_rates={'fuel': nts.MinMax(min=0, max=float('+inf'))},
        flow_costs={'fuel': 0},
        flow_emissions={'fuel': 0},
    )

    hkw_generator = components.Transformer(
        name='HKW',
        inputs=('fuel',),
        outputs=('electricity', 'heat'),
        conversions={('fuel', 'electricity'): 0.24, ('fuel', 'heat'): 0.6},
        # Minimum number of arguments required
        sector='Coupled',
        carrier='electricity',
        node_type='transformer',
        flow_rates={
            'fuel': nts.MinMax(min=0, max=102123.3),
            'electricity': nts.MinMax(min=0, max=24509.6),
            'heat': nts.MinMax(min=0, max=61273.96)},
        flow_costs={'fuel': 0, 'electricity': 80.65, 'heat': 20.1625},
        flow_emissions={'fuel': 0, 'electricity': 0.5136, 'heat': 0.293},
    )

    hkw_generator_2 = components.Transformer(
        name='HKW2',
        inputs=('fuel',),
        outputs=('electricity',),
        conversions={('fuel', 'electricity'): 0.43},
        # Minimum number of arguments required
        sector='Power',
        carrier='electricity',
        node_type='connector',
        flow_rates={
            'fuel': nts.MinMax(min=0, max=102123.3),
            'electricity': nts.MinMax(min=0, max=43913)},
        flow_costs={'fuel': 0, 'electricity': 80.65},
        flow_emissions={'fuel': 0, 'electricity': 0.5136},
    )

    gud_generator = components.Transformer(
        name='GuD',
        inputs=('fuel',),
        outputs=('electricity',),
        conversions={('fuel', 'electricity'): 0.59},
        # Minimum number of arguments required
        sector='Power',
        carrier='electricity',
        node_type='transformer',
        flow_rates={
            'fuel': nts.MinMax(min=0, max=45325.42373),
            'electricity': nts.MinMax(min=0, max=26742)},
        flow_costs={'fuel': 0, 'electricity': 88.7},
        flow_emissions={'fuel': 0, 'electricity': 0.3366},
    )

    coal_supply_line = components.Bus(
        name='Coal Supply Line',
        inputs=('Coal Supply.fuel',),
        outputs=('HKW.fuel', 'HKW2.fuel'),
        # Minimum number of arguments required
        sector='Coupled',
        carrier='Coal',
        node_type='bus',
    )

    high_electricity_line = components.Bus(
        name='High Voltage Grid',
        inputs=(
            'Offshore Wind Power.electricity',
            'GuD.electricity',
            'HKW.electricity',
            'HKW2.electricity',
        ),
        outputs=('Power Sink.electricity',),
        # Minimum number of arguments required
        sector='Power',
        carrier='electricity',
        node_type='bus',
    )

    high_medium_transformator = components.Connector(
        name='High Voltage Transfer Grid',
        interfaces=(
            'Medium Voltage Grid',
            'High Voltage Grid',
        ),
        conversions={
            ('Medium Voltage Grid', 'High Voltage Grid'): 1,
            ('High Voltage Grid', 'Medium Voltage Grid'): 1,
        },
        node_type='connector',
    )

    # 4. Create the actual energy system:
    es = energy_system.AbstractEnergySystem(
        uid="LossLC",
        busses=(
            gas_supply_line,
            low_electricity_line,
            heat_line,
            medium_electricity_line,
            high_electricity_line,
            coal_supply_line,
            biogas_supply_line,
        ),
        sinks=(
            household_demand,
            commercial_demand,
            heat_demand,
            industrial_demand,
            car_charging_station_demand,
        ),
        sources=(
            solar_panel,
            gas_supply,
            onshore_wind_power,
            offshore_wind_power,
            coal_supply,
            solar_thermal,
            biogas_supply,
        ),
        transformers=(
            bhkw_generator,
            power_to_heat,
            gud_generator,
            hkw_generator,
            hkw_generator_2,
        ),
        connectors=(
            low_medium_transformator,
            high_medium_transformator,
        ),
        timeframe=timeframe,
        global_constraints=global_constraints,
    )

    return es

Generic Graph

The LossLC Generic Graph image was crated using following code snippet:

import matplotlib.pyplot as plt

import tessif.visualize.dcgrph as dcv
import tessif.examples.data.tsf.py_hard as tsf_py


tsf_es = tsf_py.create_losslc_es()
# grph = tsf_es.to_nxgrph()
app = dcv.draw_generic_graph(
    energy_system=tsf_es,
    color_group={
        'Coal Supply': '#666666',
        'Coal Supply Line': '#666666',
        'HKW': '#666666',
        'HKW2': '#666666',
        'Solar Thermal': '#b30000',
        'Heat Storage': '#cc0033',
        'District Heating': 'Red',
        'District Heating Demand': 'Red',
        'Power to Heat': '#b30000',
        'Biogas plant': '#006600',
        'Biogas': '#006600',
        'BHKW': '#006600',
        'Onshore Wind Power': '#99ccff',
        'Offshore Wind Power': '#00ccff',
        'Gas Station': '#336666',
        'Gaspipeline': '#336666',
        'GuD': '#336666',
        'Solar Panel': '#ffe34d',
        'Commercial Demand': '#ffe34d',
        'Household Demand': '#ffe34d',
        'Industrial Demand': '#ffe34d',
        'Car charging Station': '#669999',
        'Low Voltage Grid': '#ffcc00',
        'Medium Voltage Grid': '#ffcc00',
        'High Voltage Grid': '#ffcc00',
        'High Voltage Transfer Grid': 'yellow',
        'Low Voltage Transfer Grid': 'yellow',
    },
    node_size={
        'High Voltage Transfer Grid': 150,
        'Low Voltage Transfer Grid': 150,
        'District Heating': 150
    },
    title='Lossless Power Grid Example Energy System Graph',
)

app.run_server(debug=False)

Optimization Results

Shown below, is the code to generate the LossLC results. Use the PERIODS constant to adjust the simulated time span. Results displayed were created using PERIODS = 24.

Optimize and Post Process via Tessif

Following script uses the LossLC creation skript above to generate and tessif internally post-process the optimization results, ready for further analysis.

import pandas as pd

import json
import importlib
import os
from pathlib import Path

from tessif.analyze import ComparativeResultier
from tessif.frused.paths import doc_dir
import tessif.examples.data.tsf.py_hard as tsf_examples
import tessif.simulate as optimize
from tessif.transform.es2mapping import compile_result_data_representation

# Change this to 8760 and "exp_results" for the full results.
# (Takes about 30min - 1h)
PERIODS = 24
FOLDER = "results"
FOLDER = "losslc_results"

PARENT = os.path.join(
    doc_dir,
    "source",
    "getting_started",
    "examples",
    "application",
    "phd",
    "field_study",
    "LossLC",
)


# create dispatch problem aka LossLC combination
tessif_LossLC = tsf_examples.create_losslc_es(periods=PERIODS)

# define the softwares to be used
SOFTWARES = ['cllp', 'fine', 'omf', 'ppsa', ]
# use this in case you are just testing out the water
# SOFTWARES = ['cllp', ]

# dynamically access the tessif transform utilities based on requested
# softwares above. Store them in a dictionairy for
# ease of access.
transformers = {}
for software in SOFTWARES:
    transformers[software] = importlib.import_module(
        '.'.join(['tessif.transform.es2es', software]))

# Do the tessif -> software transformations and store them in a dictionairy for
# ease of access
transformed_LossLC_combinations = {}
for software in SOFTWARES:
    transformed_LossLC_combinations[software] = transformers[software].transform(
        tessif_LossLC)


# Perform the software specific optimizations
optimized_LossLC_combinations = {}
for software in SOFTWARES:
    optimizer = getattr(optimize, "_".join([software, "from_es"]))
    optimized_LossLC_combinations[software] = optimizer(
        transformed_LossLC_combinations[software])

# post process the allresultiers:
all_resultiers = {}
for software in SOFTWARES:
    post_processor = importlib.import_module(
        '.'.join(['tessif.transform.es2mapping', software]))
    all_resultiers[software] = post_processor.AllResultier(
        optimized_LossLC_combinations[software])

# post process the comparative results using the constructed all-resultiers:
comparatier = ComparativeResultier(all_resultiers)


data_storage_path = os.path.join(PARENT, FOLDER)

# store the all_loads results
for software in SOFTWARES:

    result_id = f"{software}_all_loads"
    storage_location = os.path.join(data_storage_path, result_id)
    result_df = comparatier.all_loads[software]
    result_df.to_csv(".".join([storage_location, "csv"]))

# store the all_socs results
result_id = f"all_socs"
storage_location = os.path.join(data_storage_path, result_id)
result_df = comparatier.all_socs

if not result_df.empty:
    result_df.to_csv(".".join([storage_location, "csv"]))

# store the rest of the all_* results:
for rtype in [
        "all_capacities",
        "all_original_capacities",
        "all_net_energy_flows",
        "all_costs_incurred",
        "all_emissions_caused",
]:
    result_id = rtype
    storage_location = os.path.join(data_storage_path, result_id)
    result_df = getattr(comparatier, rtype)
    result_df.to_csv(".".join([storage_location, "csv"]))

result_types = ['Load', 'Capacity', 'IntegratedGlobal']
post_processed_data = {}
for software in SOFTWARES:
    post_processor = importlib.import_module(
        '.'.join(['tessif.transform.es2mapping', software]))
    post_processed_data[software] = {}
    for result_type in result_types:
        post_processed_data[software][result_type] = getattr(
            post_processor, "".join([result_type, "Resultier"]))(
                optimized_LossLC_combinations[software])

wanted_results = {
    'Load': 'node_load',
    'Capacity': 'node_installed_capacity',
    'IntegratedGlobal': 'global_results',
}
nodes_of_interest = {
    'Load': [
        'High Voltage Grid',
        "Medium Voltage Grid",
        "Low Voltage Grid",
        'District Heating',
    ],
    'Capacity': [],
    'IntegratedGlobal': [],
}

for software in SOFTWARES:
    for rtype in result_types:
        if nodes_of_interest[rtype]:
            for node in nodes_of_interest[rtype]:
                result_id = f"{software}_{rtype}_{node}"
                storage_location = os.path.join(data_storage_path, result_id)
                res = getattr(post_processed_data[software][rtype], wanted_results[rtype])[
                    node]
                if rtype == 'Load':
                    res = res.sum()
                    res.name = result_id
                    res.to_json(
                        ".".join([storage_location, "json"]), orient="split")

        else:
            result_id = f"{software}_{rtype}"
            storage_location = os.path.join(data_storage_path, result_id)
            res = getattr(
                post_processed_data[software][rtype], wanted_results[rtype])
            res = pd.Series(res.values(), index=res.keys())
            res.name = result_id
            res.to_json(
                ".".join([storage_location, "json"]), orient="split")

# Use this in case you want to see the result representation of certain nodes
# rdrs = {}
# for software in SOFTWARES:
#     rdrs[software] = compile_result_data_representation(
#         optimized_es=optimized_LossLC_combinations[software],
#         software=software,
#         node="Heatline",
#     )
# # print(rdrs['fine'])

Aggregate, Compare, and Store Representative Results

Following script takes the stored and post processed results from the optimization process above and turns them into representative csv files shown in the results section.

import pandas as pd
from numpy import int_

import os
from collections import defaultdict
import numbers

from tessif.frused.paths import doc_dir

FOLDER = "results"

# locate the storage directory
cp = os.path.join(
    doc_dir, "source", "getting_started", "examples", "application",
    "phd", "model_scenario_combinations", "LossLC", FOLDER
)

softwares = ['cllp', 'fine', 'omf', 'ppsa', ]
# use this in case you are just testing out the water
# softwares = ['fine', ]
load_nodes = [
    'High Voltage Grid',
    "Medium Voltage Grid",
    "Low Voltage Grid",
    'District Heating',
]

# Result dicts for convenience access
globalesque_results = {}
load_results = {}
for software in softwares:
    load_results[software] = {}
    for node in load_nodes:
        load_result_file = f"{software}_Load_{node}"
        storage_path = os.path.join(cp, ".".join([load_result_file, "json"]))
        ser = pd.read_json(
            storage_path, orient="split", typ="series")
        ser.name = load_result_file
        load_results[software][node] = ser

    globalesque_results[software] = {}
    for rtype in ["Capacity", "IntegratedGlobal"]:
        result_file = f"{software}_{rtype}"
        storage_path = os.path.join(cp, ".".join([result_file, "json"]))
        ser = pd.read_json(
            storage_path, orient="split", typ="series")
        ser.name = result_file
        globalesque_results[software][rtype] = ser

# flatten capacity and igr results for better readability:
capacity_results = {}
integrated_global_results = {}
for software in softwares:
    capacity_results[software] = globalesque_results[software]["Capacity"]
    integrated_global_results[software] = globalesque_results[software]["IntegratedGlobal"]

# aggregate software results into one dataframe for ease of comparison
load_by_node = defaultdict(dict)
for software in softwares:
    for node in load_nodes:
        load_by_node[node][software] = load_results[software][node]

labels = ["Capacity", "IGR", "Load-High Voltage Grid",
          "Load-Medium Voltage Grid", "Load-Low Voltage Grid", "Load-District Heating"]
dimensions = ["MW or MWh", "€ or t_CO2", "MW", "MW", "MW", "MW"]
for pos, dct in enumerate([
    capacity_results,
    integrated_global_results,
    load_by_node["High Voltage Grid"],
    load_by_node["Medium Voltage Grid"],
    load_by_node["Low Voltage Grid"],
    load_by_node["District Heating"],
]):

    df = pd.concat(
        dct.values(),
        keys=dct.keys(),
        axis='columns')
    # give dataframe a name for higher recognition value
    df.index.name = labels[pos] + f" [{dimensions[pos]}]"
    # sort dataframe for index
    df = df.sort_index()

    # change None to "variable" since that is what it means
    df = df.fillna("variable")
    # cast values into integers, since they are deemed to provide enough
    # information
    df = df.applymap(
        lambda x: int_(x) if isinstance(x, numbers.Number) else x,
        # na_action="ignore",
    )

    # dynamically create the filename using the df.index name
    storage_path = os.path.join(cp, ".".join([labels[pos], "csv"]))

    # store the result dfs as csv for convenient access
    df.to_csv(storage_path)

IGR Bar Plot Code

The Integrated Global Result bar plots from above are created using following code:

import pandas as pd


from pathlib import Path

from tessif.frused.paths import doc_dir
from tessif.visualize import igr

mpl_config = {
    "title": "Integrated Global Results Relative to 'Oemof'",
    "ylabel": "",
    "xlabel": "Result Values",
    "rot": 0,
}

for result in ["results", ]:
    igr_results_csv_path = (
        Path(doc_dir)
        / "source"
        / "getting_started"
        / "examples"
        / "application"
        / "phd"
        / "model_scenario_combinations"
        / "LossLC"
        / result
        / "IGR.csv"
    )

    result_df = pd.read_csv(igr_results_csv_path, index_col=0)

    # make results relative to oemof
    result_df = result_df.div(result_df['omf'], axis='index')
    # mpl_config["ylim"] = [
    #     math.floor(10*result_df.min().min())/10,
    #     math.ceil(10*result_df.max().max())/10,
    # ]

    handle = igr.plot(
        igr_df=result_df,
        plt_config=mpl_config,
        ptype="bar",
    )

    for category in ["costs", "non_costs"]:
        figure_storage_path = igr_results_csv_path.parents[0] / "_".join(
            [category, "IGR.png"])

        handle[category].savefig(figure_storage_path)

    # handle["costs"].show()
    # handle["non_costs"].show()


plexp_config = {
    "title": "Integrated Global Results Relative to 'Oemof (omf)'",
    "barmode": "group",
    "text_auto": True,
}


handle = igr.plot(
    igr_df=result_df,
    plt_config=plexp_config,
    ptype="bar",
    draw_util="plexp",
)
handle["costs"].show()
handle["non_costs"].show()

Comutational Ressources

Computational Ressources Estimation Code

The computational ressources bar plots from above are created using following code:

# change spellings_logging_level to debug to declutter output
import tessif.analyze
import tessif.frused.configurations as configurations  # nopep8
configurations.spellings_logging_level = 'debug'


import tessif.examples.data.tsf.py_hard as tsf_examples  # nopep8

# Import path settings
from tessif.frused.paths import doc_dir  # nopep8
import os  # nopep8


PERIODS = 24
FOLDER = "results"
# EXPANSION = True
SOFTWARES = ('cllp', 'fine', 'omf', 'ppsa', )
# SOFTWARES = ('cllp',)
HOOK_PYPSA = False

# locate the storage directory
current_path = os.path.join(
    doc_dir, "source", "getting_started", "examples", "application",
    "phd", "model_scenario_combinations", "LossLC", FOLDER
)


def reparam_ppsa(tessif_es):
    reparameterized_es = reparameterize_components(
        es=tessif_es,
        components={
            'Hard Coal CHP': {
                'flow_emissions': {'Hard_Coal': 0, 'electricity': 0, 'hot_water': 0},
            },
            'Hard Coal Supply': {
                'flow_emissions': {'Hard_Coal': 0.8 * 0.4 + 0.06 * 0.4},
            },
            'Biogas CHP': {
                'flow_emissions': {'biogas': 0, 'electricity': 0, 'hot_water': 0},
            },
            'Biogas Supply': {
                'flow_emissions': {'biogas': 0.25 * 0.4 + 0.01875 * 0.5},
            },

        },

    )
    return reparameterized_es


hook = None
if HOOK_PYPSA:
    hook = reparam_ppsa

# Choose the underlying energy system
tsf_es = tsf_examples.create_component_es(periods=PERIODS)

# write it to disk, so the comparatier can read it out
import os  # nopep8
from tessif.frused.paths import write_dir  # nopep8

output_msg = tsf_es.to_hdf5(
    directory=os.path.join(write_dir, 'tsf'),
    filename='es_to_compare.hdf5',
)
# let the comparatier do the auto comparison:

import tessif.parse  # nopep8
import functools  # nopep8
from tessif.frused.hooks.tsf import reparameterize_components  # nopep8
import pandas as pd  # nopep8


memory_results = {}
for software in SOFTWARES:
    dct = tessif.analyze.trace_memory(
        path=os.path.join(write_dir, 'tsf', 'es_to_compare.hdf5'),
        parser=tessif.parse.hdf5,
        model=software,
        hook=hook,
    )

    memory_df = pd.DataFrame(
        data=dct.values(), index=dct.keys(), columns=(software,))
    memory_df = memory_df.divide(1e6).round(0)
    memory_df.index.name = "Memory [MB]"
    memory_df.rename(index={'simulation': 'optimization'}, inplace=True)
    csv_path = os.path.join(current_path, "_".join(
        [software, "memory_results.csv"]))
    memory_df.to_csv(csv_path)

print("memory results obtianed")

timing_results = {}
for software in SOFTWARES:
    dct = tessif.analyze.stop_time(
        path=os.path.join(write_dir, 'tsf', 'es_to_compare.hdf5'),
        parser=tessif.parse.hdf5,
        model=software,
        measurement='wall',
        hook=hook,
    )

    timings_df = pd.DataFrame(
        data=dct.values(), index=dct.keys(), columns=(software,))
    timings_df = timings_df.round(1)
    timings_df.index.name = "Timings [s]"
    timings_df.rename(index={'simulation': 'optimization'}, inplace=True)
    csv_path = os.path.join(current_path, "_".join(
        [software, "timings_results.csv"]))
    timings_df.to_csv(csv_path)

print("timing results obtianed")

Computational Ressources Plots

The computational ressources bar plots from above are created using following code:

from tessif.frused.paths import doc_dir  # nopep8
import os  # nopep8
import pandas as pd  # nopep8


FOLDER = "results"
# SOFTWARES = ('cllp', 'fine', 'ppsa', 'omf',)
SOFTWARES = ('cllp', 'fine', 'ppsa', 'omf',)

# locate the storage directory
current_path = os.path.join(
    doc_dir, "source", "getting_started", "examples", "application",
    "phd", "model_scenario_combinations", "LossLC", FOLDER
)

memory_results = {}
for software in SOFTWARES:
    csv_path = os.path.join(current_path, "_".join(
        [software, "memory_results.csv"]))
    memory_results[software] = pd.read_csv(
        csv_path, index_col=0).to_dict()[software]

memory_df = pd.DataFrame(memory_results)
memory_df.index.name = "Memory [MB]"
csv_path = os.path.join(current_path, "memory_results.csv")
plot_path = os.path.join(current_path, "memory_results.png")
memory_df.to_csv(csv_path)
memory_df.plot(kind="bar", rot=0, figsize=(10, 5)).figure.savefig(plot_path)

timings_results = {}
for software in SOFTWARES:
    csv_path = os.path.join(current_path, "_".join(
        [software, "timings_results.csv"]))
    timings_results[software] = pd.read_csv(
        csv_path, index_col=0).to_dict()[software]

timings_df = pd.DataFrame(timings_results)
timings_df.index.name = "Time [s]"
csv_path = os.path.join(current_path, "timings_results.csv")
plot_path = os.path.join(current_path, "timings_results.png")
timings_df.to_csv(csv_path)
timings_df.plot(kind="bar", rot=0, figsize=(10, 5)).figure.savefig(plot_path)