Examples#

This section reproduces the examples provided in the repository (these examples scripts are available in IPESE/REHO).

They should give you a brief overview of REHO’s capabilities and to test the various features of the tool.

Note

Since the content of the scripts/examples/ subfolder is git-tracked, you should not modify these files directly, but rather copy their contents into any other subfolder of scripts/ that you have yourself created. The content there (code, data, results, and figures) will be ignored by the git versioning.

1. Building-scale#

Single-optimization#

from reho.model.reho import *
from reho.plotting import plotting

if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=1)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Set method options
    method = {'building-scale': True}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    plotting.plot_sankey(reho.results['totex'][0], label='EN_long', color='ColorPastel', title="Sankey diagram").show()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='1a')

Pareto curve#

from reho.model.reho import *
from reho.plotting import plotting


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=1)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = ['OPEX', 'CAPEX']  # for multi-objective optimization two objectives are needed
    scenario['nPareto'] = 2  # number of points per objective (total number of optimizations = nPareto * 2 + 2)
    scenario['name'] = 'pareto'
    scenario['exclude_units'] = ['OIL_Boiler', 'ThermalSolar']
    scenario['enforce_units'] = []

    # Set method options
    method = {'building-scale': True}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.generate_pareto_curve()  # multi-objective optimization

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='1b')

    # Performance plot : costs and gwp
    plotting.plot_performance(reho.results, plot='costs', indexed_on='Pareto_ID', label='EN_long', title="Economical performance").show()
    plotting.plot_performance(reho.results, plot='gwp', indexed_on='Pareto_ID', label='EN_long', title="Environmental performance").show()

    # Sankey diagram
    for key in reho.results['pareto'].keys():
        plotting.plot_sankey(reho.results['pareto'][key], label='EN_long', color='ColorPastel', title="Sankey diagram").show()

2. District-scale#

Single-optimization#

from reho.model.reho import *


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, egid=['1017073/1017074', '1017109', '1017079', '1030377/1030380'])

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Set method options
    method = {'district-scale': True}
    DW_params = {'max_iter': 2}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, DW_params=DW_params, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='2a')

Pareto curve#

from reho.model.reho import *


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=2)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = ['OPEX', 'CAPEX']
    scenario['nPareto'] = 2
    scenario['name'] = 'pareto'
    scenario['exclude_units'] = ['OIL_Boiler']
    scenario['enforce_units'] = []

    # Set method options
    method = {'district-scale': True}
    DW_params = {'max_iter': 2}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, DW_params=DW_params, solver="gurobi")
    reho.generate_pareto_curve()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='2b')

3. Specific features#

Load buildings from a .csv file#

from reho.model.reho import *


if __name__ == '__main__':

    buildings_filename = str(Path(__file__).parent / 'data' / 'buildings.csv')

    # Set building parameters
    # Load your buildings from a csv file instead of reading the database
    reader = QBuildingsReader()
    qbuildings_data = reader.read_csv(buildings_filename=buildings_filename, nb_buildings=2)

    # Select clustering options for weather data
    cluster = {'Location': 'Sion', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Set method options
    method = {'building-scale': True}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3a')

Add diverse energy layers#

from reho.model.reho import *


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, egid=['1017073/1017074', '1017109', '1017079', '1030377/1030380'])

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Initialize available units and grids
    # You can add more resources layers besides electricity and natural gas, and adapt their prices
    # - directly within the script
    # - or through a custom csv file based on the default values from data/infrastructure/layers.csv
    grids = infrastructure.initialize_grids({'Electricity': {"Cost_supply_cst": 0.30, "Cost_demand_cst": 0.16},
                                             'NaturalGas': {"Cost_supply_cst": 0.15},
                                             'Wood': {},
                                             'Oil': {},
                                             })

    # Set method options
    method = {'building-scale': True}

    # Units specifications can also be adapted through a custom csv file based on the default values from data/infrastructure/building_units.csv
    # You can simply create a new file and specify the path to it in the initialize_units function
    path_to_custom_units = str(Path(__file__).parent / 'data' / 'custom_building_units.csv')
    units = infrastructure.initialize_units(scenario, grids, building_data=path_to_custom_units)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3b')

Change heat pump temperature#

from reho.model.reho import *


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, egid=['1017073/1017074', '1017109', '1017079', '1030377/1030380'])
    n_buildings = len(qbuildings_data['buildings_data'])

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Set method options
    method = {'building-scale': True}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Set specific parameters
    # Heat pump can have different sources such as air, lake, geothermal
    parameters = {"T_source": np.repeat({"Geothermal": 17.0}, n_buildings)}

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, parameters=parameters, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3c')

Include electric vehicles#

from reho.plotting import plotting
from reho.model.reho import *

if __name__ == '__main__':
    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, egid=['1017073/1017074', '1017109', '1017079', '1030377/1030380'])

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = ['Battery', 'Bike_district', 'ICE_district', 'ElectricBike_district']
    scenario['enforce_units'] = []

    parameters = dict()

    # Initialize available units and grids
    grids = infrastructure.initialize_grids({'Electricity': {},
                                             'NaturalGas': {},
                                             'Gasoline': {},
                                             'Mobility': {},
                                             })
    units = infrastructure.initialize_units(scenario, grids, district_data=True)

    # Set method options
    method = {'building-scale': True}

    # Set specific parameters
    parameters = {}

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, parameters=parameters, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3d')

    # Plot results
    plotting.plot_performance(reho.results, plot='costs', indexed_on='Scn_ID', label='EN_long', title="Economical performance").show()

Integrate a district heating network#

from reho.model.reho import *
from reho.plotting import plotting


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=4)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = ['HeatPump_DHN']
    scenario["specific"] = ["enforce_DHN"]

    # Set method options
    # You can specify if the DHN is based on CO2. If not, a water DHN is assumed.
    method = {'building-scale': True, 'DHN_CO2': True}

    # Set specific parameters
    # Specify the temperature of the DHN
    parameters = {'T_DHN_supply_cst': np.repeat(20.0, 4), "T_DHN_return_cst": np.repeat(15.0, 4)}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids({'Electricity': {},
                                             'NaturalGas': {},
                                             'Heat': {}})

    units = infrastructure.initialize_units(scenario, grids, district_data=True)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, parameters=parameters, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.get_DHN_costs()  # run one optimization forcing DHN to find costs DHN connection per house
    reho.single_optimization()  # run optimization with DHN costs

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3e')

    # Plot results
    plotting.plot_performance(reho.results, plot='costs', indexed_on='Scn_ID', label='EN_long', title="Economical performance").show()
    plotting.plot_sankey(reho.results['totex'][0], label='EN_long', color='ColorPastel', title="Sankey diagram").show()

Use custom profiles#

from reho.model.reho import *


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, egid=['1017073/1017074', '1017109', '1017079', '1030377/1030380'])

    # Select clustering options for weather data, with custom profiles
    custom_weather_profile = str(Path(__file__).parent / 'data' / 'profiles' / 'Geneva.csv')
    cluster = {'custom_weather': custom_weather_profile, 'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Set method options
    # You can provide here a profile for domestic electricity, domestic hot water, or building occupancy
    custom_elec_profile = str(Path(__file__).parent / 'data' / 'profiles' / 'electricity.csv')
    method = {'building-scale': True, 'use_custom_profiles': {'electricity': custom_elec_profile}}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids=grids)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3f')

Include stochasticity into profiles#

from reho.model.reho import *
from reho.model.preprocessing.QBuildings import *


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, egid=['1017073/1017074', '1017109', '1017079', '1030377/1030380'])

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Set method options
    # Add stochasticity in the demand profiles given by the SIA standards, tunable with:
    # - standard deviation on the peak demand
    # - standard deviation on the time-shift
    method = {'building-scale': True, 'include_stochasticity': True, 'sd_stochasticity': [0.1, 2]}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3g')

Fix units size#

The example shows the use of two methods:

  • enforcing the size of specific units (method fix_units)

  • considering existing units capacity in the optimization using the parameter Units_Ext

from reho.model.reho import *
from reho.plotting import plotting


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, egid=['1017073/1017074', '1017109', '1017079', '1030377/1030380'])

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Set method options
    method = {'building-scale': True, 'fix_units': True}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Scenario 1: min TOTEX
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    # Scenario 2: min TOTEX with fixed units
    # Give dataframe to fix Units_Mult and Units_Use. The index of the dataframe contains the units being fixed !
    reho.scenario['name'] = 'units_fixed'
    df_fix_units = pd.DataFrame([15, 15, 15, 15], index=["PV_Building" + str(i) for i in range(1, 5)], columns=["Units_Mult"])
    df_fix_units["Units_Use"] = 1
    reho.df_fix_Units = df_fix_units
    reho.single_optimization()

    # Scenario 3: min TOTEX with existing units
    # Run optimization with units already installed (PV), but the optimization can install more capacity
    # The index of the dataframe contains the units being fixed !
    reho.method["fix_units"] = False
    reho.scenario["name"] = "units_ext"
    reho.parameters["Units_Ext"] = pd.DataFrame([15, 15, 15, 15], index=["PV_Building" + str(i) for i in range(1, 5)], columns=["Units_Ext"])
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3h')
    plotting.plot_performance(reho.results, plot='costs', indexed_on='Scn_ID', label='EN_long', title="Economical performance").show()

Connect to ELCOM database for electricity prices#

from reho.model.reho import *
from reho.model.preprocessing import electricity_prices


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, egid=['1017073/1017074', '1017109', '1017079', '1030377/1030380'])

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Set method options
    method = {'building-scale': True}

    # Initialize available units and grids
    # You can use prices coming from the ELCOM public database
    prices = electricity_prices.get_prices_from_elcom_by_city(city=reader, category='H4')
    grids = infrastructure.initialize_grids({'Electricity': {"Cost_supply_cst": prices['finalcosts'][0], "Cost_demand_cst": 0.16},
                                             'NaturalGas': {"Cost_supply_cst": 0.15},
                                             })
    units = infrastructure.initialize_units(scenario, grids)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3i')

Include capacities of networks for imports and exports#

from reho.model.reho import *

if __name__ == '__main__':
    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=6)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids, district_data=True)

    grids["Electricity"]["ReinforcementOfNetwork"] = np.array([100, 150, 200, 250])  # available new capacities for Electricity network considering reinforecment
    parameters = {'Network_ext': np.array([100, 1000])}  # existing capacities of networks [Electricity, NaturalGas]

    # Set method options
    method = {'district-scale': True}
    DW_params = {'max_iter': 4}

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, parameters=parameters, method=method, DW_params=DW_params, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3j')

Include buildings renovation options#

The “renovation” method consists in a list of renovation options. Each option contains building elements to renovate. The order does not matter. The buildings elements are: window, facade, roof and footprint. For each option, an additional SP is run with the U-value of the renovated building, calculated based on the file infrastructure/U_values.csv. The MP will receive at each iteration one solution with non-renovated buildings and one solution per renovated option. To keep consistency, the non-renovated U-value of the buildings should be taken using the functions reader.read_db or read_csv with the option correct_Uh=True. This option uses the values in infrastructure/U_values.csv instead of the U-values from QBuildings. Investment costs and embodied emissions are calculated based on the file infrastructure/renovation.csv.

from reho.model.reho import *
from reho.plotting import plotting

if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=6, correct_Uh=True)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # The "renovation" method consists in a list of renovation options.
    # Each option contains building elements to renovate. The order does not matter.
    method = {'building-scale': True, "renovation": ["window/facade/roof/footprint", "window/facade", "roof"]}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    additional_data = {"renovation": reho.results["totex"][0]["df_Performance"].xs("Network")["Costs_ins"]}
    plotting.plot_performance(reho.results, plot='costs', indexed_on='Pareto_ID', label='EN_long', title="Economical performance", additional_costs=additional_data).show()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3k')

Data centers and Organic Rankine Cycles#

Liquid cooled data centers (direct-on-chip cooling) produce heat at a temperature of 60-75 °C, which can be used for district heating networks or valorized with Organic Rankine Cycles. This example shows how the demand for data can be set through an average known value of electricity consumption of data centers in an urban energy hub and how the waste heat from such district-level data centers can be used through an Organic Rankine Cycle. Assuming a temperature of 75°C, a cycle efficiency is used to abstract the model.

from reho.model.reho import *
from reho.plotting import plotting


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=1)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'GWP'
    scenario['name'] = 'gwp'
    scenario['exclude_units'] = ["Battery", "Battery_district", "DataHeat_DHW", "DataHeat_SH"]


    # Set method options
    method = {'district-scale': True}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids({'Electricity': {},
                                             'Data': {},
                                             'Heat': {}
                                             })
    units = infrastructure.initialize_units(scenario, grids, district_data=True)

    # Set parameters
    parameters = {'Network_ext': np.array([500, 500, 0]), 'data_EUD_avg': 50}  # existing capacities of networks in alphabetical order

    DW_params = {'max_iter': 2}

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, parameters=parameters, cluster=cluster, scenario=scenario, method=method,
                DW_params=DW_params, solver="gurobi")

    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='3l')

    # Plot results
    plotting.plot_performance(reho.results, plot='costs', indexed_on='Scn_ID', label='EN_long', title="Economical performance").show()
    plotting.plot_sankey(reho.results['gwp'][0], label='EN_long', color='ColorPastel', title="Sankey diagram").show()

4. Global features#

Compare various scenarios#

from reho.model.reho import *
from reho.plotting import plotting


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, egid=['1017073/1017074', '1017109', '1017079', '1030377/1030380'])

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['EMOO'] = {}
    scenario['specific'] = []

    # Set method options
    method = {'building-scale': True}

    # Set specific parameters
    parameters = {}

    # Scenario 1 Oil boiler
    scenario['name'] = 'Oil'
    scenario['exclude_units'] = ['ThermalSolar', 'HeatPump', 'ElectricalHeater', 'PV']
    scenario['enforce_units'] = []
    grids = infrastructure.initialize_grids({'Electricity': {}, 'Oil': {}})
    units = infrastructure.initialize_units(scenario, grids)

    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, parameters=parameters, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    # Scenario 2 HP + PV
    scenario['name'] = 'HP + PV'
    scenario['exclude_units'] = ['ThermalSolar', 'OIL_Boiler']
    scenario['enforce_units'] = []
    units = infrastructure.initialize_units(scenario, grids)

    reho.scenario = scenario
    reho.units = units
    reho.infrastructure = infrastructure.Infrastructure(qbuildings_data, units, grids)
    reho.build_infrastructure_SP()
    for b in qbuildings_data['buildings_data']:
        reho.buildings_data[b]['Th_supply_0'] = 45
        reho.buildings_data[b]['Th_return_0'] = 35
    reho.single_optimization()

    # Scenario 3 EV
    scenario['name'] = 'EV'
    scenario['exclude_units'] = ['ThermalSolar', 'OIL_Boiler', 'Bike_district', 'ICE_district', 'ElectricBike_district']
    scenario['enforce_units'] = ['EV_district']

    grids = infrastructure.initialize_grids({'Electricity': {}, 'Oil': {}, 'Gasoline': {}, 'Mobility': {}})
    units = infrastructure.initialize_units(scenario, grids, district_data=True)

    reho.scenario = scenario
    reho.units = units
    reho.infrastructure = infrastructure.Infrastructure(qbuildings_data, units, grids)
    reho.build_infrastructure_SP()
    reho.single_optimization()

    # Scenario 4 ICT
    scenario['name'] = 'ICT'
    scenario['exclude_units'] = ['ThermalSolar', 'OIL_Boiler', 'Bike_district', 'ICE_district', 'ElectricBike_district', 'DataHeat_SH']
    scenario['enforce_units'] = ['EV_district', 'DataHeat_DHW']

    grids = infrastructure.initialize_grids({'Electricity': {}, 'Oil': {}, 'Gasoline': {}, 'Mobility': {},
                                             'Data': {"Cost_demand_cst": 1, "GWP_demand_cst": 0}})
    units = infrastructure.initialize_units(scenario, grids, district_data=True)

    reho.scenario = scenario
    reho.units = units
    reho.infrastructure = infrastructure.Infrastructure(qbuildings_data, units, grids)
    reho.build_infrastructure_SP()
    reho.single_optimization()

    # Scenario 5 renovation
    scenario['name'] = 'renovation'
    for b in qbuildings_data['buildings_data']:
        reho.buildings_data[b]['U_h'] = 0.4 * qbuildings_data['buildings_data'][b]['U_h']

    reho.scenario = scenario
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='4a')

    # Additional data
    era = reho.results['Oil'][0]['df_Buildings'].ERA.sum()

    # Gasoline avoided costs = EV_consumption * 4 (efficiency ratio ICE/EV) * gasoline_price
    gasoline_price = 0.24  # CHF/kWh
    gasoline_gwp = 0.32  # kgCO2/kWh
    EV_consumption = reho.results['EV'][0]['df_Annuals'].loc[("Electricity", "EV_charger_district"), "Demand_MWh"] - reho.results['EV'][0]['df_Annuals'].loc[("Electricity", "EV_charger_district"), "Supply_MWh"]
    gasoline_cost = 1000 * EV_consumption * 4 * gasoline_price / era
    gasoline_impact = 1000 * EV_consumption * 4 * gasoline_gwp / era

    # ICT avoided costs = ICT_consumption * 1.3 (mean PUE for Switzerland) * electricity_price
    electricity_price = 0.33  # CHF/kWh
    electricity_gwp = 0.13  # kgCO2/kWh
    ict_cost = 1000 * reho.results['ICT'][0]['df_Annuals'].loc[("Data", "Network"), "Demand_MWh"] * 1.3 * electricity_price / era
    ict_impact = 1000 * reho.results['ICT'][0]['df_Annuals'].loc[("Data", "Network"), "Demand_MWh"] * 1.3 * electricity_gwp / era

    # renovation costs and impact
    renovation_cost = 5.4  # CHF/m2/yr (already annualized for 50 years)
    renovation_impact = 0.076  # kgCO2/m2/yr (already annualized for 50 years)

    additional_costs = {'mobility': [gasoline_cost, gasoline_cost, 0, 0, 0],
                        'ict': [ict_cost, ict_cost, ict_cost, 0, 0],
                        'renovation': [0, 0, 0, 0, renovation_cost]}
    additional_costs['no_ict_profit'] = False  # data processing profits can be included in the costs or not

    additional_gwp = {'mobility': [gasoline_impact, gasoline_impact, 0, 0, 0],
                      'ict': [ict_impact, ict_impact, ict_impact, 0, 0],
                      'renovation': [0, 0, 0, 0, renovation_impact]}

    # Plot results
    plotting.plot_performance(reho.results, plot='costs', per_m2=True, additional_costs=additional_costs, title="Economical performance").show()
    plotting.plot_performance(reho.results, plot='gwp', per_m2=True, additional_gwp=additional_gwp, title="Environmental performance").show()

Conduct a sensitivity analysis#

from reho.model.postprocessing.sensitivity_analysis import *
from reho.plotting import plotting


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=1)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Set method options
    method = {'building-scale': True}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Run sensitivity analysis
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    SA = SensitivityAnalysis(reho, SA_type="Monte_Carlo", sampling_parameters=8)

    SA_parameters = {'Elec_retail': [0.2, 0.45], 'Elec_feedin': [0.0, 0.15], 'NG_retail': [0.2, 0.4]}
    SA.build_SA(unit_parameter=['Cost_inv1', 'Cost_inv2'], SA_parameters=SA_parameters)
    SA.run_SA()

    # Save results
    plotting.plot_performance(reho.results, plot='costs', indexed_on='Pareto_ID', label='EN_long', title="Economical performance").show()
    reho.save_results(format=['xlsx', 'pickle'], filename='4b')

5. Photovoltaics#

Consider roofs orientation#

from reho.model.reho import *


if __name__ == '__main__':

    # Set building parameters
    # Roofs orientation for PV can be considered
    reader = QBuildingsReader(load_roofs=True)
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=2, nb_buildings=2)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Set method options
    method = {'use_pv_orientation': True}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='5a')

Include photovoltaics on facades#

from reho.model.reho import *


if __name__ == '__main__':

    # Set building parameters
    # PV on facades can be considered
    reader = QBuildingsReader(load_facades=True, load_roofs=True)

    # # Warning: to connect to QBuildings-Suisse (database including facades data), you need to be within EPFL intranet.
    # reader.establish_connection('Suisse')
    # qbuildings_data = reader.read_db(district_id=3658, nb_buildings=2)

    # Alternatively, roof orientations and facades can be loaded from csv files
    buildings_filename = str(Path(__file__).parent / 'data' / 'buildings.csv')
    facades_filename = str(Path(__file__).parent / 'data' / 'facades.csv')
    roofs_filename = str(Path(__file__).parent / 'data' / 'roofs.csv')
    qbuildings_data = reader.read_csv(buildings_filename=buildings_filename, nb_buildings=2,
                                      facades_filename=facades_filename, roofs_filename=roofs_filename)

    # Select clustering options for weather data
    cluster = {'Location': 'Sion', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = []
    scenario['enforce_units'] = []

    # Set method options
    method = {'use_pv_orientation': True, 'use_facades': True, 'building-scale': True}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='5b')

6. Mobility#

Add Mobility Layer#

The Layer Mobility differs slightly from the other Layers in REHO as this energy carrier is expressed in passenger-kilometers (\(pkm\)) rather than \(kWh\). The mobility demand is represented through an hourly passenger-kilometer (\(pkm\)) profile for each typical day, similarly to the other end-use demand profiles. The transport units represented in the model include EVs, ICEs, bikes, electric bikes and public transport. The model can optimize between the different transport modes. However, it is for now recommended to constrain the modal split, as the optimization based on cost does not reflect typical usage of the different transport modes. The FSO reports can be used to find suitable modal split data.

from reho.model.reho import *
from reho.plotting import plotting

if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=2)

    # Select weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['I', 'T', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['EMOO'] = {}
    scenario['exclude_units'] = []
    scenario['enforce_units'] = ['EV_district']

    # Initialize available units and grids
    grids = infrastructure.initialize_grids({'Electricity': {},
                                             'NaturalGas': {},
                                             'Gasoline': {},
                                             'Mobility': {},
                                             })
    units = infrastructure.initialize_units(scenario, grids, district_data=True)

    # Set method options
    method = {'building-scale': True}

    # SCENARIO 1: Flexible charging profile
    scenario['name'] = 'totex'

    # Set parameters
    era = np.sum([qbuildings_data["buildings_data"][b]['ERA'] for b in qbuildings_data["buildings_data"]])

    # here Population is scaled to the number of buildings being optimized (CH : 46m²/cap on average )
    # 35 km/cap/day, 2 categories of distance (D0 : short and D1 : long)
    parameters = {"Population": era / 46, "DailyDist": {'D0': 25, 'D1': 10}}

    # min max share for each mobility mode and each distance
    modal_split = pd.DataFrame({"min_D0": [0, 0, 0.4, 0.3], "max_D0": [0.1, 0.3, 0.7, 0.7],
                                "min_D1": [0, 0.2, 0.4, 0.3], "max_D1": [0, 0.4, 0.7, 0.7]},
                               index=['MD', 'PT', 'cars', 'EV_district'])

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, parameters=parameters, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.modal_split = modal_split # give modal_split as attribute
    reho.single_optimization()

    # SCENARIO 2: Fixed charging profile
    scenario['name'] = 'totex_profile'

    # Activate the constraint forcing the charging profile of electric vehicles. 
    scenario['specific'] = ['EV_chargingprofile1', "EV_chargingprofile2"]

    # Run optimization
    reho.scenario = scenario
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='6a')

    # Plot results
    plotting.plot_performance(reho.results, plot='costs', indexed_on='Scn_ID', label='EN_long', title="Economical performance").show()
    plotting.plot_sankey(reho.results['totex'][0], label='EN_long', color='ColorPastel', title="Sankey diagram").show()


Co-optimization#

Multiple districts can be optimized together in order to calculate EV charging exchanges between districts. This feature can be used to conduct analyses on EV fleets at the city scale. Example 6b demonstrates how to use this feature step by step. Only one district is optimized with external charging option available. The optimized district is also parameterized with a load on EV charger representing incoming EVs from other districts.

7. Interperiod storage#

Investigate interperiod storage units in a building facing grid constraints (e.g. a building with limited import or export capacity).

Hybrid biomethane/CO2 storage#

from reho.model.reho import *
from reho.plotting import plotting

if __name__ == '__main__':
    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=5, egid=['2034144/2034143/2749579/2034146/2034145'])

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = ["FC", "ETZ", "Battery_IP", "rSOC", "H2_storage_IP", "HeatPump_Geothermal"]
    scenario['enforce_units'] = []

    # Set method options
    method = {'interperiod_storage': True}

    # Initialize available units and grids
    # WARNING: necessary to define all 3 layers Hydrogen / Biomethane / CO2 to enable rSOC or Methanator unit
    grids = infrastructure.initialize_grids({'Electricity': {},
                                             'Hydrogen': {},
                                             'Biomethane': {},
                                             'CO2': {},
                                             })

    grids["Electricity"]["ReinforcementOfNetwork"] = np.array([5])  # limit the 2000 kW default value (from layers.csv) for export or import electricity
    grids["Hydrogen"]["ReinforcementOfNetwork"] = np.array([0])  # keep the 0 kW default value (from layers.csv) for export or import hydrogen

    units = infrastructure.initialize_units(scenario, grids, interperiod_data=True)  # enable interperiod storage

    # Set parameters
    parameters = {}

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, parameters=parameters, cluster=cluster, scenario=scenario, method=method,
                solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='7a')

    # Plot results
    plotting.plot_performance(reho.results, plot='costs', indexed_on='Scn_ID', label='EN_long', title="Economical performance").show()
    plotting.plot_sankey(reho.results['totex'][0], label='EN_long', color='ColorPastel', title="Sankey diagram").show()
    plotting.plot_electricity_flows(reho.results['totex'][0], color='ColorPastel', day_of_the_year=40, time_range='2 weeks', label='EN_long').show()
    plotting.plot_storage_profile(reho.results['totex'][0], resolution='hourly').show()

Hydrogen production and export#

from reho.model.reho import *
from reho.plotting import plotting

if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=5, egid=['2034144/2034143/2749579/2034146/2034145'])

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = ["FC", "ETZ", "Battery_IP", "Battery", "HeatPump_Geothermal"]
    scenario['enforce_units'] = []

    # Set method options
    method = {'interperiod_storage': True}

    # Initialize available units and grids
    # WARNING: necessary to define all 3 layers Hydrogen / Biomethane / CO2 to enable rSOC or Methanator unit
    grids = infrastructure.initialize_grids({'Electricity': {},
                                             'Hydrogen': {"Cost_supply_cst": 0.45, "Cost_demand_cst": 0.2},  # default export price = 0.15 CHF/kWh (5 CHF/kg H2)
                                             'Biomethane': {},
                                             'CO2': {},
                                             })

    grids["Electricity"]["ReinforcementOfNetwork"] = np.array([15])  # limit the 2000 kW default value (from layers.csv) for export or import electricity
    grids["Hydrogen"]["ReinforcementOfNetwork"] = np.array([100])  # update the 0 kW default value (from layers.csv) for export or import hydrogen

    units = infrastructure.initialize_units(scenario, grids, interperiod_data=True)  # enable interperiod storage

    # Set parameters
    parameters = {}

    # Annual hydrogen export can be forced in the parameters
    # parameters['HydrogenAnnualExport'] = 20e3  # kWh
    # scenario['specific'] = ['forced_H2_annual_export']

    # A continuous daily hydrogen export can be forced (value is a variable in the optimization) it can be 0 actually if not attractive
    scenario['specific'] = ['forced_H2_fixed_daily_export']

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, parameters=parameters, cluster=cluster, scenario=scenario, method=method, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='7b')

    # Plot results
    plotting.plot_performance(reho.results, plot='costs', indexed_on='Scn_ID', label='EN_long', title="Economical performance").show()
    plotting.plot_sankey(reho.results['totex'][0], label='EN_long', color='ColorPastel', title="Sankey diagram").show()
    plotting.plot_electricity_flows(reho.results['totex'][0], color='ColorPastel', day_of_the_year=40, time_range='2 weeks', label='EN_long').show()
    plotting.plot_storage_profile(reho.results['totex'][0], resolution='weekly').show()

District-scale rSOC with IP storage#

from reho.model.reho import *
from reho.plotting import plotting

if __name__ == '__main__':
    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=4)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['name'] = 'totex'
    scenario['exclude_units'] = ["FC", "ETZ", "Battery", "Battery_district", "Battery_IP", "Battery_IP_district",
                                 "H2_storage_IP_district", "rSOC", "MTR", "DHN_hex"]

    # scenario['enforce_units'] = ['HeatPump_DHN']
    # scenario["specific"] = ["enforce_DHN"]

    # Set method options
    method = {
        'interperiod_storage': True,
        'district-scale': True
    }

    # Initialize available units and grids
    # WARNING: necessary to define all 3 layers Hydrogen / Biomethane / CO2 to enable rSOC or Methanator unit
    grids = infrastructure.initialize_grids({'Electricity': {},
                                             'Hydrogen': {},
                                             'Biomethane': {},
                                             'CO2': {},
                                             'Heat': {}
                                             })

    grids["Biomethane"]["ReinforcementOfNetwork"] = np.array([0])  # keep the 0 kW default value (from layers.csv) for export or import hydrogen
    grids["CO2"]["ReinforcementOfNetwork"] = np.array([0])  # keep the 0 kW default value (from layers.csv) for export or import hydrogen
    grids["Electricity"]["ReinforcementOfNetwork"] = np.array([15])  # limit the 2000 kW default value (from layers.csv) for export or import electricity
    grids["Heat"]["ReinforcementOfNetwork"] = np.array([10])  # keep the 0 kW default value (from layers.csv) for export or import hydrogen
    grids["Hydrogen"]["ReinforcementOfNetwork"] = np.array([0])  # keep the 0 kW default value (from layers.csv) for export or import hydrogen

    # enable district units, interperiod storage units for both (True), district only ('district') or building only ('building')
    units = infrastructure.initialize_units(scenario, grids, district_data=True, interperiod_data='district')

    # Set parameters
    parameters = {'Network_ext': np.array([0, 0, 15, 10, 0])}  # existing capacities of networks [Electricity, Heat]

    DW_params = {'max_iter': 2}

    # Run optimization
    reho = REHO(qbuildings_data=qbuildings_data, units=units, grids=grids, parameters=parameters, cluster=cluster, scenario=scenario, method=method,
                DW_params=DW_params, solver="gurobi")
    reho.single_optimization()

    # Save results
    reho.save_results(format=['xlsx', 'pickle'], filename='7c')

    # Plot results
    plotting.plot_performance(reho.results, plot='costs', indexed_on='Scn_ID', label='EN_long', title="Economical performance").show()
    plotting.plot_sankey(reho.results['totex'][0], label='EN_long', color='ColorPastel', title="Sankey diagram").show()
    plotting.plot_electricity_flows(reho.results['totex'][0], color='ColorPastel', day_of_the_year=40, time_range='2 weeks', label='EN_long').show()
    plotting.plot_storage_profile(reho.results['totex'][0], resolution='hourly').show()

8. Actor model#

Investigate the boundaries of stakeholders in a district energy system and how they influence the optimal design of the system.

Including building upfront cost#

Landlords may consider the upfront cost of building by charging a fixed rent from tenants. Tenants’ expenses thus include both the energy cost and the fixed rent.

from reho.model.actors_problem import *


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader(load_roofs=True)
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=40, correct_Uh=True)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['EMOO'] = {}
    scenario['specific'] = ['no_ElectricalHeater_without_HP', 'Owner_Link_Subsidy_to_renovation','Renter_noSub', 'Rent_fix_absolute']
    # Rent_fix2 calculates based on absolute values of the building costs
    # if Rent_fix_increase  is active, the rent increase is considered. and parameter 'Costs_House_upfront_m2_MP' has to be set in parameters to 0

    scenario["name"] = "actors"

    # Choose energy system structure options
    scenario['exclude_units'] = ['ThermalSolar', 'NG_Cogeneration', 'Battery']
    scenario['enforce_units'] = []

    # Set method options
    method = {'actors_problem': True, "renovation": ["window/facade/roof/footprint"], 'use_pv_orientation': True,
              "include_all_solutions": True, "save_streams": False,
              "save_timeseries": False, 'print_logs': True, "save_data_input": True, 'parallel_computation': False}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Define maximum rent affordable
    reho = ActorsProblem(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, DW_params={'max_iter': 4}, solver="gurobiasl")
    reho.parameters['renter_expense_max'] = actors.generate_renter_expense_max(method='absolute', qbuildings_data=qbuildings_data, income=70000)

    # Set value / sampling range for actors epsilon
    bounds = {"Owners": [0.0, 0], "Utility": [0.0, 0.0]}
    reho.sample_actors_epsilon(bounds=bounds, n_samples=1, ins_target=[0])

    #Run actor-based optimization
    reho.actor_decomposition_optimization()

    # Save results
    reho.save_results(format=["pickle"], filename='8a')

Considering only rent increase#

Due to regulations, landlords may increase the rent after renovating the building. In this case, tenants’ expenses are limited by the pre-renovation expenses to avoid unacceptable rent increases.

from reho.model.actors_problem import *


if __name__ == '__main__':

    # Set building parameters
    reader = QBuildingsReader()
    reader.establish_connection('Geneva')
    qbuildings_data = reader.read_db(district_id=234, nb_buildings=40)

    # Select clustering options for weather data
    cluster = {'Location': 'Geneva', 'Attributes': ['T', 'I', 'W'], 'Periods': 10, 'PeriodDuration': 24}

    # Set scenario
    scenario = dict()
    scenario['Objective'] = 'TOTEX'
    scenario['EMOO'] = {}
    scenario['specific'] = ['no_ElectricalHeater_without_HP', 'Owner_Link_Subsidy_to_renovation','Renter_noSub', 'Rent_fix_increase']

    scenario["name"] = "actors"

    # Choose energy system structure options
    scenario['exclude_units'] = ['ThermalSolar', 'NG_Cogeneration', 'Battery']
    scenario['enforce_units'] = []

    # Set method options
    method = {'actors_problem': True, "renovation": ["window/facade/roof/footprint"], 'use_pv_orientation': True,
              "include_all_solutions": True, "save_streams": False,
              "save_timeseries": False, 'print_logs': True, "save_data_input": True, 'parallel_computation': False}

    # Initialize available units and grids
    grids = infrastructure.initialize_grids()
    units = infrastructure.initialize_units(scenario, grids)

    # Define maximum rent affordable
    reho = ActorsProblem(qbuildings_data=qbuildings_data, units=units, grids=grids, cluster=cluster, scenario=scenario, method=method, DW_params={'max_iter': 8}, solver="gurobiasl")
    reho.parameters['renter_expense_max'] = actors.generate_renter_expense_max(method='increase', reho_model=reho)
    reho.parameters['Costs_House_upfront_m2_MP'] = 0.0

    # Set value / sampling range for actors epsilon
    bounds = {"Owners": [0.0, 0.0], "Utility": [0.0, 0.0]}
    reho.sample_actors_epsilon(bounds=bounds, n_samples=1, ins_target=[0])

    #Run actor-based optimization
    reho.actor_decomposition_optimization()

    # Save results
    reho.save_results(format=["pickle"], filename='8b')