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#

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 = {'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()

    # Run a new optimization with the capacity of PV and electrical heater fixed with the size of the first optimization
    reho.df_fix_Units = reho.results['totex'][0]["df_Unit"]  # load data on the capacity of units
    reho.fix_units_list = ['PV', 'ElectricalHeater_DHW', 'ElectricalHeater_SH']  # select the ones being fixed
    reho.scenario['Objective'] = 'CAPEX'
    reho.scenario['name'] = 'fixed'
    reho.method['fix_units'] = True  # select the method fixing the unit sizes
    reho.single_optimization()

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

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#

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 Isolation
    scenario['name'] = 'Isolation'
    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

    # Isolation costs and impact
    isolation_cost = 5.4  # CHF/m2/yr (already annualized for 50 years)
    isolation_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],
                        'isolation': [0, 0, 0, 0, isolation_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],
                      'isolation': [0, 0, 0, 0, isolation_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('Suisse')
    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()

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).

Hydrogen and biomethane 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"]
    scenario['enforce_units'] = ["rSOC", "MTR", "CO2_storage_IP", "CH4_storage_IP"]

    # 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': {},
                                             'NaturalGas': {},
                                             '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", "CO2_storage_IP", "CH4_storage_IP"]
    scenario['enforce_units'] = ["rSOC"]

    # 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': {},
                                             'NaturalGas': {},
                                             'Hydrogen': {"Cost_supply_cst": 0.45, "Cost_demand_cst": 0.15}, # 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)
    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()