def __init__(self, locator, config, network_type):
     # store key variables
     self.locator = locator
     self.config = config
     self.network_type = network_type
     self.network_name = config.thermal_network_optimization.network_names
     # initialize optimization storage variables and dictionaries
     self.cost_info = ['capex', 'opex', 'total', 'el_network_MWh',
                       'opex_plant', 'opex_pump', 'opex_dis_loads', 'opex_dis_build', 'opex_hex',
                       'capex_chiller', 'capex_CT', 'capex_pump', 'capex_dis_loads', 'capex_dis_build', 'capex_hex',
                       'capex_network', 'network_length_m', 'avg_diam_m']
     self.generation_info = ['plant_buildings', 'number_of_plants', 'supplied_loads', 'disconnected_buildings',
                             'has_loops']
     self.supply_systems = SupplySystemsDatabase(locator)
     self.cost_storage = None
     self.building_names = None
     self.number_of_buildings_in_district = 0
     self.prices = None
     self.network_features = None
     self.layout = 0
     self.has_loops = None
     self.populations = {}
     self.generation_number = 0
     self.building_index = []
     self.individual_number = 0
     self.disconnected_buildings_index = []
     # list of all possible heating or cooling systems. used to compare which ones are centralized / decentralized
     self.full_heating_systems = ['ahu', 'aru', 'shu', 'ww']
     self.full_cooling_systems = ['ahu', 'aru',
                                  'scu']  # Todo: add 'data', 're' here once the are available disconnectedly
     self.substation_cooling_systems = config.thermal_network_optimization.substation_cooling_systems
     self.substation_heating_systems = config.thermal_network_optimization.substation_heating_systems
     self.__weather_data = None
def main(config):
    print('Running decentralized model for buildings with scenario = %s' % config.scenario)
    locator = cea.inputlocator.InputLocator(config.scenario)
    supply_systems = SupplySystemsDatabase(locator)
    total_demand = pd.read_csv(locator.get_total_demand())
    prices = Prices(supply_systems)
    lca = LcaCalculations(supply_systems)
    disconnected_building_main(locator=locator,  total_demand=total_demand,
                               config=config, prices=prices, lca=lca)
def disconnected_buildings_heating_main(locator, total_demand, building_names,
                                        config, prices, lca):
    """
    Computes the parameters for the operation of disconnected buildings
    output results in csv files.
    There is no optimization at this point. The different technologies are calculated and compared 1 to 1 to
    each technology. it is a classical combinatorial problem.
    :param locator: locator class
    :param building_names: list with names of buildings
    :type locator: class
    :type building_names: list
    :return: results of operation of buildings located in locator.get_optimization_decentralized_folder
    :rtype: Nonetype
    """
    t0 = time.perf_counter()
    prop_geometry = Gdf.from_file(locator.get_zone_geometry())
    geometry = pd.DataFrame({
        'Name': prop_geometry.Name,
        'Area': prop_geometry.area
    })
    geothermal_potential_data = dbf.dbf_to_dataframe(
        locator.get_building_supply())
    geothermal_potential_data = pd.merge(geothermal_potential_data,
                                         geometry,
                                         on='Name')
    geothermal_potential_data['Area_geo'] = geothermal_potential_data['Area']
    weather_path = locator.get_weather_file()
    weather_data = epwreader.epw_reader(weather_path)[[
        'year', 'drybulb_C', 'wetbulb_C', 'relhum_percent', 'windspd_ms',
        'skytemp_C'
    ]]

    T_ground_K = calc_ground_temperature(locator,
                                         weather_data['drybulb_C'],
                                         depth_m=10)
    supply_systems = SupplySystemsDatabase(locator)

    # This will calculate the substation state if all buildings where connected(this is how we study this)
    substation.substation_main_heating(locator, total_demand, building_names)

    n = len(building_names)
    cea.utilities.parallel.vectorize(disconnected_heating_for_building,
                                     config.get_number_of_processes())(
                                         building_names,
                                         repeat(supply_systems, n),
                                         repeat(T_ground_K, n),
                                         repeat(geothermal_potential_data, n),
                                         repeat(lca, n), repeat(locator, n),
                                         repeat(prices, n))

    print(time.perf_counter() - t0,
          "seconds process time for the Disconnected Building Routine \n")
Beispiel #4
0
def main(config):
    """
    run the whole preprocessing routine
    """
    from cea.optimization.prices import Prices as Prices
    print("Running decentralized model for buildings with scenario = %s" %
          config.scenario)

    locator = cea.inputlocator.InputLocator(scenario=config.scenario)
    supply_systems = SupplySystemsDatabase(locator)
    total_demand = pd.read_csv(locator.get_total_demand())
    building_names = total_demand.Name
    prices = Prices(supply_systems)
    lca = LcaCalculations(supply_systems)
    disconnected_buildings_cooling_main(locator, building_names, total_demand,
                                        config, prices, lca)

    print("test_decentralized_buildings_cooling() succeeded")
Beispiel #5
0
def disconnected_buildings_cooling_main(locator, building_names, total_demand,
                                        config, prices, lca):
    """
    Computes the parameters for the operation of disconnected buildings output results in csv files.
    There is no optimization at this point. The different cooling energy supply system configurations are calculated
    and compared 1 to 1 to each other. it is a classical combinatorial problem.
    The six supply system configurations include:
    (VCC: Vapor Compression Chiller, ACH: Absorption Chiller, CT: Cooling Tower, Boiler)
    (AHU: Air Handling Units, ARU: Air Recirculation Units, SCU: Sensible Cooling Units)
    - config 0: Direct Expansion / Mini-split units (NOTE: this configuration is not fully built yet)
    - config 1: VCC_to_AAS (AHU + ARU + SCU) + CT
    - config 2: FP + single-effect ACH_to_AAS (AHU + ARU + SCU) + Boiler + CT
    - config 3: ET + single-effect ACH_to_AAS (AHU + ARU + SCU) + Boiler + CT
    - config 4: VCC_to_AA (AHU + ARU) + VCC_to_S (SCU) + CT
    - config 5: VCC_to_AA (AHU + ARU) + single effect ACH_S (SCU) + CT + Boiler

    Note:
    1. Only cooling supply configurations are compared here. The demand for electricity is supplied from the grid,
    and the demand for domestic hot water is supplied from electric boilers.
    2. Single-effect chillers are coupled with flat-plate solar collectors, and the double-effect chillers are coupled
    with evacuated tube solar collectors.
    :param locator: locator class with paths to input/output files
    :param building_names: list with names of buildings
    :param config: cea.config
    :param prices: prices class
    :return: one .csv file with results of operations of disconnected buildings; one .csv file with operation of the
    best configuration (Cost, CO2, Primary Energy)
    """

    t0 = time.perf_counter()
    supply_systems = SupplySystemsDatabase(locator)

    n = len(building_names)

    cea.utilities.parallel.vectorize(disconnected_cooling_for_building,
                                     config.get_number_of_processes())(
                                         building_names,
                                         repeat(supply_systems, n),
                                         repeat(lca, n), repeat(locator, n),
                                         repeat(prices, n),
                                         repeat(total_demand, n))

    print(time.perf_counter() - t0,
          "seconds process time for the decentralized Building Routine \n")
def preproccessing(locator, total_demand, buildings_heating_demand, buildings_cooling_demand,
                   weather_file, district_heating_network, district_cooling_network):
    """
    This function aims at preprocessing all data for the optimization.

    :param locator: path to locator function
    :param total_demand: dataframe with total demand and names of all building in the area
    :param building_names: dataframe with names of all buildings in the area
    :param weather_file: path to wather file
    :type locator: class
    :type total_demand: list
    :type building_names: list
    :type weather_file: string
    :return:
        - extraCosts: extra pareto optimal costs due to electricity and process heat (
            these are treated separately and not considered inside the optimization)
        - extraCO2: extra pareto optimal emissions due to electricity and process heat (
            these are treated separately and not considered inside the optimization)
        - extraPrim: extra pareto optimal primary energy due to electricity and process heat (
            these are treated separately and not considered inside the optimization)
        - solar_features: extraction of solar features form the results of the solar technologies
            calculation.

    :rtype: float, float, float, float

    """
    print("PRE-PROCESSING 0/4: initialize directory")
    shutil.rmtree(locator.get_optimization_master_results_folder())
    shutil.rmtree(locator.get_optimization_network_results_folder())
    shutil.rmtree(locator.get_optimization_slave_results_folder())
    shutil.rmtree(locator.get_optimization_substations_folder())

    print("PRE-PROCESSING 1/4: weather features")  # at first estimate a distribution with all the buildings connected
    weather_features = WeatherFeatures(weather_file, locator)

    print("PRE-PROCESSING 2/4: conversion systems database")  # at first estimate a distribution with all the buildings connected
    supply_systems = SupplySystemsDatabase(locator)

    print("PRE-PROCESSING 3/4: feedstocks systems database")  # at first estimate a distribution with all the buildings connected
    prices = Prices(supply_systems)
    lca = LcaCalculations(supply_systems)

    print("PRE-PROCESSING 4/4: network features")  # at first estimate a distribution with all the buildings connected
    if district_heating_network:
        num_tot_buildings = len(buildings_heating_demand)
        DHN_barcode = ''.join(str(1) for e in range(num_tot_buildings))
        substation.substation_main_heating(locator, total_demand, buildings_heating_demand,
                                           DHN_barcode=DHN_barcode)

        summarize_network.network_main(locator, buildings_heating_demand, weather_features.ground_temp, num_tot_buildings, "DH",
                                       DHN_barcode)
        # "_all" key for all buildings
    if district_cooling_network:
        num_tot_buildings = len(buildings_cooling_demand)
        DCN_barcode = ''.join(str(1) for e in range(num_tot_buildings))
        substation.substation_main_cooling(locator, total_demand, buildings_cooling_demand, DCN_barcode=DCN_barcode)

        summarize_network.network_main(locator, buildings_cooling_demand,
                                       weather_features.ground_temp, num_tot_buildings, "DC",
                                       DCN_barcode)  # "_all" key for all buildings

    network_features = NetworkOptimizationFeatures(district_heating_network, district_cooling_network, locator)

    return weather_features, network_features, prices, lca
def district_cooling_network(locator,
                             master_to_slave_variables,
                             config,
                             prices,
                             network_features):
    """
    Computes the parameters for the cooling of the complete DCN

    :param cea.inputlocator.InputLocator locator: path to res folder
    :param network_features: network features
    :param prices: Prices imported from the database
    :type network_features: class
    :type prices: class
    :return: costs, co2, prim
    :rtype: tuple
    """

    if master_to_slave_variables.DCN_exists:
        # THERMAL STORAGE + NETWORK
        # Import Temperatures from Network Summary:
        Q_thermal_req_W, \
        T_district_cooling_return_K, \
        T_district_cooling_supply_K, \
        mdot_kgpers = calc_network_summary_DCN(master_to_slave_variables)

        # Initialize daily storage calss
        T_ground_K = calculate_ground_temperature(locator)
        daily_storage = LoadLevelingDailyStorage(master_to_slave_variables.Storage_cooling_on,
                                                 master_to_slave_variables.Storage_cooling_size_W,
                                                 min(T_district_cooling_supply_K) - DT_COOL,
                                                 max(T_district_cooling_return_K) - DT_COOL,
                                                 T_TANK_FULLY_DISCHARGED_K,
                                                 np.mean(T_ground_K)
                                                 )

        # Import Data - potentials lake heat
        if master_to_slave_variables.WS_BaseVCC_on == 1 or master_to_slave_variables.WS_PeakVCC_on == 1:
            HPlake_Data = pd.read_csv(locator.get_water_body_potential())
            Q_therm_Lake = np.array(HPlake_Data['QLake_kW']) * 1E3
            total_WS_VCC_installed = master_to_slave_variables.WS_BaseVCC_size_W + master_to_slave_variables.WS_PeakVCC_size_W
            Q_therm_Lake_W = [x if x < total_WS_VCC_installed else total_WS_VCC_installed for x in Q_therm_Lake]
            T_source_average_Lake_K = np.array(HPlake_Data['Ts_C']) + 273
        else:
            Q_therm_Lake_W = np.zeros(HOURS_IN_YEAR)
            T_source_average_Lake_K = np.zeros(HOURS_IN_YEAR)

        # get properties of technology used in this script
        absorption_chiller = AbsorptionChiller(pd.read_excel(locator.get_database_conversion_systems(), sheet_name="Absorption_chiller"), 'double')
        CCGT_prop = calc_cop_CCGT(master_to_slave_variables.NG_Trigen_ACH_size_W, ACH_T_IN_FROM_CHP_K, "NG")

        VCC_database = pd.read_excel(locator.get_database_conversion_systems(), sheet_name="Chiller")
        technology_type = VCC_CODE_CENTRALIZED
        VCC_database = VCC_database[VCC_database['code'] == technology_type]
        max_VCC_capacity = int(VCC_database['cap_max'])
        min_VCC_capacity = int(VCC_database['cap_min'])
        # G_VALUE = VCC_database['ISENTROPIC_EFFICIENCY'] # create vessel to carry down gvalue and max_VCC_capacity, min_VCC_capacity to VCC module

        # initialize variables
        Q_Trigen_NG_gen_W = np.zeros(HOURS_IN_YEAR)
        Q_BaseVCC_WS_gen_W = np.zeros(HOURS_IN_YEAR)
        Q_PeakVCC_WS_gen_W = np.zeros(HOURS_IN_YEAR)
        Q_BaseVCC_AS_gen_W = np.zeros(HOURS_IN_YEAR)
        Q_PeakVCC_AS_gen_W = np.zeros(HOURS_IN_YEAR)
        Q_DailyStorage_gen_directload_W = np.zeros(HOURS_IN_YEAR)

        E_Trigen_NG_gen_W = np.zeros(HOURS_IN_YEAR)
        E_BaseVCC_AS_req_W = np.zeros(HOURS_IN_YEAR)
        E_PeakVCC_AS_req_W = np.zeros(HOURS_IN_YEAR)
        E_BaseVCC_WS_req_W = np.zeros(HOURS_IN_YEAR)
        E_PeakVCC_WS_req_W = np.zeros(HOURS_IN_YEAR)
        NG_Trigen_req_W = np.zeros(HOURS_IN_YEAR)
        Q_BackupVCC_AS_gen_W = np.zeros(HOURS_IN_YEAR)

        Q_Trigen_NG_gen_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_BaseVCC_WS_gen_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_PeakVCC_WS_gen_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_BaseVCC_AS_gen_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_PeakVCC_AS_gen_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_BackupVCC_AS_directload_W = np.zeros(HOURS_IN_YEAR)

        for hour in range(HOURS_IN_YEAR):  # cooling supply for all buildings excluding cooling loads from data centers
            if Q_thermal_req_W[hour] > 0.0:  # only if there is a cooling load!
                daily_storage, \
                thermal_output, \
                electricity_output, \
                gas_output = cooling_resource_activator(Q_thermal_req_W[hour],
                                                        T_district_cooling_supply_K[hour],
                                                        T_district_cooling_return_K[hour],
                                                        Q_therm_Lake_W[hour],
                                                        T_source_average_Lake_K[hour],
                                                        daily_storage,
                                                        T_ground_K[hour],
                                                        master_to_slave_variables,
                                                        absorption_chiller,
                                                        CCGT_prop,
                                                        min_VCC_capacity,
                                                        max_VCC_capacity)

                Q_DailyStorage_gen_directload_W[hour] = thermal_output['Q_DailyStorage_gen_directload_W']
                Q_Trigen_NG_gen_directload_W[hour] = thermal_output['Q_Trigen_NG_gen_directload_W']
                Q_BaseVCC_WS_gen_directload_W[hour] = thermal_output['Q_BaseVCC_WS_gen_directload_W']
                Q_PeakVCC_WS_gen_directload_W[hour] = thermal_output['Q_PeakVCC_WS_gen_directload_W']
                Q_BaseVCC_AS_gen_directload_W[hour] = thermal_output['Q_BaseVCC_AS_gen_directload_W']
                Q_PeakVCC_AS_gen_directload_W[hour] = thermal_output['Q_PeakVCC_AS_gen_directload_W']
                Q_BackupVCC_AS_directload_W[hour] = thermal_output['Q_BackupVCC_AS_directload_W']

                Q_Trigen_NG_gen_W[hour] = thermal_output['Q_Trigen_NG_gen_W']
                Q_BaseVCC_WS_gen_W[hour] = thermal_output['Q_BaseVCC_WS_gen_W']
                Q_PeakVCC_WS_gen_W[hour] = thermal_output['Q_PeakVCC_WS_gen_W']
                Q_BaseVCC_AS_gen_W[hour] = thermal_output['Q_BaseVCC_AS_gen_W']
                Q_PeakVCC_AS_gen_W[hour] = thermal_output['Q_PeakVCC_AS_gen_W']
                Q_BackupVCC_AS_gen_W[hour] = thermal_output['Q_BackupVCC_AS_gen_W']

                E_BaseVCC_WS_req_W[hour] = electricity_output['E_BaseVCC_WS_req_W']
                E_PeakVCC_WS_req_W[hour] = electricity_output['E_PeakVCC_WS_req_W']
                E_BaseVCC_AS_req_W[hour] = electricity_output['E_BaseVCC_AS_req_W']
                E_PeakVCC_AS_req_W[hour] = electricity_output['E_PeakVCC_AS_req_W']
                E_Trigen_NG_gen_W[hour] = electricity_output['E_Trigen_NG_gen_W']

                NG_Trigen_req_W[hour] = gas_output['NG_Trigen_req_W']

        #calculate the electrical capacity as a function of the peak produced by the turbine
        master_to_slave_variables.NG_Trigen_CCGT_size_electrical_W = E_Trigen_NG_gen_W.max()

        # BACK-UPP VCC - AIR SOURCE
        scale = 'DISTRICT'
        master_to_slave_variables.AS_BackupVCC_size_W = np.amax(Q_BackupVCC_AS_gen_W)
        size_chiller_CT = master_to_slave_variables.AS_BackupVCC_size_W
        if master_to_slave_variables.AS_BackupVCC_size_W != 0.0:
            master_to_slave_variables.AS_BackupVCC_on = 1
            Q_BackupVCC_AS_gen_W, E_BackupVCC_AS_req_W = np.vectorize(calc_vcc_CT_operation)(Q_BackupVCC_AS_gen_W,
                                                                                             T_district_cooling_return_K,
                                                                                             T_district_cooling_supply_K,
                                                                                             VCC_T_COOL_IN,
                                                                                             size_chiller_CT,
                                                                                             min_VCC_capacity,
                                                                                             max_VCC_capacity,
                                                                                             scale)
        else:
            E_BackupVCC_AS_req_W = np.zeros(HOURS_IN_YEAR)

        # CAPEX (ANNUAL, TOTAL) AND OPEX (FIXED, VAR, ANNUAL) GENERATION UNITS
        supply_systems = SupplySystemsDatabase(locator)
        mdotnMax_kgpers = np.amax(mdot_kgpers)
        performance_costs_generation, \
        district_cooling_capacity_installed = cost_model.calc_generation_costs_capacity_installed_cooling(locator,
                                                                                                          master_to_slave_variables,
                                                                                                          supply_systems,
                                                                                                          mdotnMax_kgpers
                                                                                                          )
        # CAPEX (ANNUAL, TOTAL) AND OPEX (FIXED, VAR, ANNUAL) STORAGE UNITS
        performance_costs_storage = cost_model.calc_generation_costs_cooling_storage(locator,
                                                                                     master_to_slave_variables,
                                                                                     config,
                                                                                     daily_storage
                                                                                     )

        # CAPEX (ANNUAL, TOTAL) AND OPEX (FIXED, VAR, ANNUAL) NETWORK
        performance_costs_network, \
        E_used_district_cooling_network_W = cost_model.calc_network_costs_cooling(locator,
                                                                                  master_to_slave_variables,
                                                                                  network_features,
                                                                                  "DC",
                                                                                  prices)

        # MERGE COSTS AND EMISSIONS IN ONE FILE
        performance = dict(performance_costs_generation, **performance_costs_storage)
        district_cooling_costs = dict(performance, **performance_costs_network)
    else:
        Q_thermal_req_W = np.zeros(HOURS_IN_YEAR)
        Q_DailyStorage_gen_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_Trigen_NG_gen_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_BaseVCC_WS_gen_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_PeakVCC_WS_gen_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_BaseVCC_AS_gen_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_PeakVCC_AS_gen_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_BackupVCC_AS_directload_W = np.zeros(HOURS_IN_YEAR)
        Q_Trigen_NG_gen_W = np.zeros(HOURS_IN_YEAR)
        Q_BaseVCC_WS_gen_W = np.zeros(HOURS_IN_YEAR)
        Q_PeakVCC_WS_gen_W = np.zeros(HOURS_IN_YEAR)
        Q_BaseVCC_AS_gen_W = np.zeros(HOURS_IN_YEAR)
        Q_PeakVCC_AS_gen_W = np.zeros(HOURS_IN_YEAR)
        Q_BackupVCC_AS_gen_W = np.zeros(HOURS_IN_YEAR)
        E_Trigen_NG_gen_W = np.zeros(HOURS_IN_YEAR)
        E_used_district_cooling_network_W = np.zeros(HOURS_IN_YEAR)
        E_BaseVCC_WS_req_W = np.zeros(HOURS_IN_YEAR)
        E_PeakVCC_WS_req_W = np.zeros(HOURS_IN_YEAR)
        E_BaseVCC_AS_req_W = np.zeros(HOURS_IN_YEAR)
        E_PeakVCC_AS_req_W = np.zeros(HOURS_IN_YEAR)
        E_BackupVCC_AS_req_W = np.zeros(HOURS_IN_YEAR)
        NG_Trigen_req_W = np.zeros(HOURS_IN_YEAR)
        district_cooling_costs = {}
        district_cooling_capacity_installed = {}

    # SAVE
    district_cooling_generation_dispatch = {
        # demand of the network
        "Q_districtcooling_sys_req_W": Q_thermal_req_W,

        # ENERGY GENERATION TO DIRECT LOAD
        # from storage
        "Q_DailyStorage_gen_directload_W": Q_DailyStorage_gen_directload_W,
        # cooling
        "Q_Trigen_NG_gen_directload_W": Q_Trigen_NG_gen_directload_W,
        "Q_BaseVCC_WS_gen_directload_W": Q_BaseVCC_WS_gen_directload_W,
        "Q_PeakVCC_WS_gen_directload_W": Q_PeakVCC_WS_gen_directload_W,
        "Q_BaseVCC_AS_gen_directload_W": Q_BaseVCC_AS_gen_directload_W,
        "Q_PeakVCC_AS_gen_directload_W": Q_PeakVCC_AS_gen_directload_W,
        "Q_BackupVCC_AS_directload_W": Q_BackupVCC_AS_directload_W,

        # ENERGY GENERATION TOTAL
        # cooling
        "Q_Trigen_NG_gen_W": Q_Trigen_NG_gen_W,
        "Q_BaseVCC_WS_gen_W": Q_BaseVCC_WS_gen_W,
        "Q_PeakVCC_WS_gen_W": Q_PeakVCC_WS_gen_W,
        "Q_BaseVCC_AS_gen_W": Q_BaseVCC_AS_gen_W,
        "Q_PeakVCC_AS_gen_W": Q_PeakVCC_AS_gen_W,
        "Q_BackupVCC_AS_W": Q_BackupVCC_AS_gen_W,

        # electricity
        "E_Trigen_NG_gen_W": E_Trigen_NG_gen_W
    }

    district_cooling_electricity_requirements_dispatch = {
        # ENERGY REQUIREMENTS
        # Electricity
        "E_DCN_req_W": E_used_district_cooling_network_W,
        "E_BaseVCC_WS_req_W": E_BaseVCC_WS_req_W,
        "E_PeakVCC_WS_req_W": E_PeakVCC_WS_req_W,
        "E_BaseVCC_AS_req_W": E_BaseVCC_AS_req_W,
        "E_PeakVCC_AS_req_W": E_PeakVCC_AS_req_W,
        "E_BackupVCC_AS_req_W": E_BackupVCC_AS_req_W,
    }

    district_cooling_fuel_requirements_dispatch = {
        # fuels
        "NG_Trigen_req_W": NG_Trigen_req_W
    }

    # PLOT RESULTS

    return district_cooling_costs, \
           district_cooling_generation_dispatch, \
           district_cooling_electricity_requirements_dispatch, \
           district_cooling_fuel_requirements_dispatch, \
           district_cooling_capacity_installed