def cooling_resource_activator(Q_thermal_req, T_district_cooling_supply_K,
                               T_district_cooling_return_K, Q_therm_Lake_W,
                               T_source_average_Lake_K, daily_storage_class,
                               T_ground_K, master_to_slave_variables,
                               absorption_chiller, CCGT_operation_data,
                               VCC_chiller):
    """

    :param Q_thermal_req:
    :param T_district_cooling_supply_K:
    :param T_district_cooling_return_K:
    :param Q_therm_Lake_W:
    :param T_source_average_Lake_K:
    :param daily_storage_class:
    :param T_ground_K:
    :param master_to_slave_variables:
    :param cea.technologies.chiller_absorption.AbsorptionChiller absorption_chiller:
    :param CCGT_operation_data:
    :return:
    """
    ## initializing unmet cooling load and requirements from daily storage for this hour
    Q_cooling_unmet_W = Q_thermal_req
    Q_DailyStorage_gen_directload_W = 0.0

    ## ACTIVATE THE TRIGEN
    if master_to_slave_variables.NG_Trigen_on == 1 and Q_cooling_unmet_W > 0.0 and not np.isclose(
            T_district_cooling_supply_K, T_district_cooling_return_K):
        size_trigen_W = master_to_slave_variables.NG_Trigen_ACH_size_W
        if Q_cooling_unmet_W > size_trigen_W:
            Q_Trigen_gen_W = size_trigen_W
        else:
            Q_Trigen_gen_W = Q_cooling_unmet_W

        # GET THE ABSORPTION CHILLER PERFORMANCE
        T_ACH_in_C = ACH_T_IN_FROM_CHP_K - 273
        Qc_CT_ACH_W, \
        Qh_CCGT_req_W, \
        E_ACH_req_W = calc_chiller_absorption_operation(Q_Trigen_gen_W,
                                                        T_district_cooling_return_K,
                                                        T_district_cooling_supply_K,
                                                        T_ACH_in_C,
                                                        T_ground_K,
                                                        absorption_chiller,
                                                        size_trigen_W)

        # operation of the CCGT
        Q_used_prim_CC_fn_W = CCGT_operation_data['q_input_fn_q_output_W']
        q_output_CC_min_W = CCGT_operation_data['q_output_min_W']
        Q_output_CC_max_W = CCGT_operation_data['q_output_max_W']
        eta_elec_interpol = CCGT_operation_data['eta_el_fn_q_input']

        # TODO: CONFIRM THAT THIS WORKS AS INTENDED
        if Qh_CCGT_req_W >= q_output_CC_min_W:
            if Q_cooling_unmet_W > size_trigen_W:
                Q_Trigen_NG_gen_directload_W = size_trigen_W
                Qc_Trigen_gen_storage_W = 0.0
                Qc_from_storage_W = daily_storage_class.discharge_storage(
                    Q_cooling_unmet_W - size_trigen_W)
                Q_Trigen_gen_W = Q_Trigen_NG_gen_directload_W + Qc_Trigen_gen_storage_W
            else:
                Q_Trigen_NG_gen_directload_W = Q_cooling_unmet_W
                Qc_Trigen_gen_storage_W = daily_storage_class.charge_storage(
                    size_trigen_W - Q_cooling_unmet_W)
                Qc_from_storage_W = 0.0
                Q_Trigen_gen_W = Q_Trigen_NG_gen_directload_W + Qc_Trigen_gen_storage_W

            T_ACH_in_C = ACH_T_IN_FROM_CHP_K - 273
            Qc_CT_ACH_W, \
            Qh_CCGT_req_W, \
            E_ACH_req_W = calc_chiller_absorption_operation(Q_Trigen_gen_W,
                                                            T_district_cooling_return_K,
                                                            T_district_cooling_supply_K,
                                                            T_ACH_in_C,
                                                            T_ground_K,
                                                            absorption_chiller,
                                                            size_trigen_W)
            # operation Possible if above minimal load
            if Qh_CCGT_req_W <= Q_output_CC_max_W:  # Normal operation Possible within partload regime
                Q_CHP_gen_W = float(Qh_CCGT_req_W)
                NG_Trigen_req_W = Q_used_prim_CC_fn_W(Q_CHP_gen_W)
                E_Trigen_NG_gen_W = np.float(
                    eta_elec_interpol(NG_Trigen_req_W)) * NG_Trigen_req_W

            else:  # Only part of the demand can be delivered as 100% load achieved
                Q_CHP_gen_W = Q_output_CC_max_W
                NG_Trigen_req_W = Q_used_prim_CC_fn_W(Q_CHP_gen_W)
                E_Trigen_NG_gen_W = np.float(
                    eta_elec_interpol(NG_Trigen_req_W)) * NG_Trigen_req_W
        else:
            Q_Trigen_gen_W = 0.0
            NG_Trigen_req_W = 0.0
            E_Trigen_NG_gen_W = 0.0
            Q_Trigen_NG_gen_directload_W = 0.0
            Qc_from_storage_W = 0.0

        # update unmet cooling load
        Q_cooling_unmet_W = Q_cooling_unmet_W - Q_Trigen_NG_gen_directload_W - Qc_from_storage_W
        Q_DailyStorage_gen_directload_W += Qc_from_storage_W
    else:
        Q_Trigen_gen_W = 0.0
        NG_Trigen_req_W = 0.0
        E_Trigen_NG_gen_W = 0.0
        Q_Trigen_NG_gen_directload_W = 0.0

    # Base VCC water-source
    if master_to_slave_variables.WS_BaseVCC_on == 1 and Q_cooling_unmet_W > 0.0 and T_source_average_Lake_K < VCC_T_COOL_IN and not np.isclose(
            T_district_cooling_supply_K, T_district_cooling_return_K):
        # Free cooling possible from the lake
        size_WS_BaseVCC_W = master_to_slave_variables.WS_BaseVCC_size_W
        if Q_cooling_unmet_W > min(
                size_WS_BaseVCC_W, Q_therm_Lake_W
        ):  # min funtion to deal with both constraints at the same time, limiting  factors being the size and the temal capacity of lake
            Q_BaseVCC_WS_gen_directload_W = min(size_WS_BaseVCC_W,
                                                Q_therm_Lake_W)
            Qc_BaseVCC_WS_gen_storage_W = 0.0
            Qc_from_storage_W = daily_storage_class.discharge_storage(
                Q_cooling_unmet_W - min(size_WS_BaseVCC_W, Q_therm_Lake_W))
            Q_BaseVCC_WS_gen_W = Q_BaseVCC_WS_gen_directload_W + Qc_BaseVCC_WS_gen_storage_W
        else:
            Q_BaseVCC_WS_gen_directload_W = Q_cooling_unmet_W
            Qc_BaseVCC_WS_gen_storage_W = daily_storage_class.charge_storage(
                min(size_WS_BaseVCC_W, Q_therm_Lake_W) - Q_cooling_unmet_W)
            Qc_from_storage_W = 0.0
            Q_BaseVCC_WS_gen_W = Q_BaseVCC_WS_gen_directload_W + Qc_BaseVCC_WS_gen_storage_W
        if (
                T_district_cooling_supply_K - DT_COOL
        ) < T_source_average_Lake_K < VCC_T_COOL_IN:  # if lake temperature lower than CT source, use compression chillers with lake water as source
            WS_BaseVCC_capacity = master_to_slave_variables.WS_BaseVCC_size_W
            Q_BaseVCC_WS_gen_W, \
            E_BaseVCC_WS_req_W = calc_vcc_operation(Q_BaseVCC_WS_gen_W,
                                                    T_district_cooling_return_K,
                                                    T_district_cooling_supply_K,
                                                    T_source_average_Lake_K,
                                                    WS_BaseVCC_capacity,
                                                    VCC_chiller)

            # Delta P from linearization after distribution optimization
            E_pump_WS_req_W = calc_water_body_uptake_pumping(
                Q_BaseVCC_WS_gen_W, T_district_cooling_return_K,
                T_district_cooling_supply_K)

            E_BaseVCC_WS_req_W += E_pump_WS_req_W

        elif T_source_average_Lake_K <= (
                T_district_cooling_supply_K - DT_COOL
        ):  # bypass, do not use chiller but use heat exchange to cool the water directly
            E_pump_WS_req_W = calc_water_body_uptake_pumping(
                Q_BaseVCC_WS_gen_W, T_district_cooling_return_K,
                T_district_cooling_supply_K)
            E_BaseVCC_WS_req_W = E_pump_WS_req_W
        else:
            print("no lake water source baseload VCC was used")
        Q_therm_Lake_W -= Q_BaseVCC_WS_gen_W  # discount availability
        Q_cooling_unmet_W = Q_cooling_unmet_W - Q_BaseVCC_WS_gen_W - Qc_from_storage_W + Qc_BaseVCC_WS_gen_storage_W  # the provided cooling equals the produced cooling plus the cooling from storage minus the stored cooling
        Q_DailyStorage_gen_directload_W += Qc_from_storage_W
    else:
        Q_BaseVCC_WS_gen_W = 0.0
        E_BaseVCC_WS_req_W = 0.0
        Q_BaseVCC_WS_gen_directload_W = 0.0

    # Peak VCC water-source
    if master_to_slave_variables.WS_PeakVCC_on == 1 and Q_cooling_unmet_W > 0.0 and T_source_average_Lake_K < VCC_T_COOL_IN and not np.isclose(
            T_district_cooling_supply_K, T_district_cooling_return_K):
        # Free cooling possible from the lake
        size_WS_PeakVCC_W = master_to_slave_variables.WS_PeakVCC_size_W
        if Q_cooling_unmet_W > min(size_WS_PeakVCC_W, Q_therm_Lake_W):
            Q_PeakVCC_WS_gen_directload_W = min(size_WS_PeakVCC_W,
                                                Q_therm_Lake_W)
            Qc_PeakVCC_WS_gen_storage_W = 0.0
            Qc_from_storage_W = daily_storage_class.discharge_storage(
                Q_cooling_unmet_W - min(size_WS_PeakVCC_W, Q_therm_Lake_W))
            Q_PeakVCC_WS_gen_W = Q_PeakVCC_WS_gen_directload_W + Qc_PeakVCC_WS_gen_storage_W
        else:
            Q_PeakVCC_WS_gen_directload_W = Q_cooling_unmet_W
            Qc_PeakVCC_WS_gen_storage_W = daily_storage_class.charge_storage(
                min(size_WS_PeakVCC_W, Q_therm_Lake_W) - Q_cooling_unmet_W)
            Qc_from_storage_W = 0.0
            Q_PeakVCC_WS_gen_W = Q_PeakVCC_WS_gen_directload_W + Qc_PeakVCC_WS_gen_storage_W

        if (T_district_cooling_supply_K -
                DT_COOL) < T_source_average_Lake_K < VCC_T_COOL_IN:
            WS_PeakVCC_capacity = master_to_slave_variables.WS_PeakVCC_size_W
            Q_PeakVCC_WS_gen_W, \
            E_PeakVCC_WS_req_W = calc_vcc_operation(Q_PeakVCC_WS_gen_W,
                                                    T_district_cooling_return_K,
                                                    T_district_cooling_supply_K,
                                                    T_source_average_Lake_K,
                                                    WS_PeakVCC_capacity,
                                                    VCC_chiller)
            E_pump_WS_req_W = calc_water_body_uptake_pumping(
                Q_PeakVCC_WS_gen_W, T_district_cooling_return_K,
                T_district_cooling_supply_K)

            E_PeakVCC_WS_req_W += E_pump_WS_req_W

        elif T_source_average_Lake_K <= (
                T_district_cooling_supply_K - DT_COOL
        ):  # bypass, do not use VCC but use heat exchange to cool the water directly
            E_pump_WS_req_W = calc_water_body_uptake_pumping(
                Q_PeakVCC_WS_gen_W, T_district_cooling_return_K,
                T_district_cooling_supply_K)
            E_PeakVCC_WS_req_W = E_pump_WS_req_W

        else:
            print("no lake water source baseload VCC was used")
        Q_therm_Lake_W -= Q_PeakVCC_WS_gen_W  # discount availability
        Q_cooling_unmet_W = Q_cooling_unmet_W - Q_PeakVCC_WS_gen_W - Qc_from_storage_W + Qc_PeakVCC_WS_gen_storage_W  # the provided cooling equals the produced cooling plus the cooling from storage minus
        Q_DailyStorage_gen_directload_W += Qc_from_storage_W

    else:
        Q_PeakVCC_WS_gen_directload_W = 0.0
        Q_PeakVCC_WS_gen_W = 0.0
        E_PeakVCC_WS_req_W = 0.0

    # Base VCC air-source with a cooling tower
    if master_to_slave_variables.AS_BaseVCC_on == 1 and Q_cooling_unmet_W > 0.0 and not np.isclose(
            T_district_cooling_supply_K, T_district_cooling_return_K):
        size_AS_BaseVCC_W = master_to_slave_variables.AS_BaseVCC_size_W
        if Q_cooling_unmet_W > size_AS_BaseVCC_W:
            Q_BaseVCC_AS_gen_directload_W = size_AS_BaseVCC_W
            Q_BaseVCC_AS_gen_storage_W = 0.0
            Qc_from_storage_W = daily_storage_class.discharge_storage(
                Q_cooling_unmet_W - size_AS_BaseVCC_W)
            Q_BaseVCC_AS_gen_W = Q_BaseVCC_AS_gen_directload_W + Q_BaseVCC_AS_gen_storage_W
        else:
            Q_BaseVCC_AS_gen_directload_W = Q_cooling_unmet_W
            Q_BaseVCC_AS_gen_storage_W = daily_storage_class.charge_storage(
                size_AS_BaseVCC_W - Q_cooling_unmet_W)
            Qc_from_storage_W = 0.0
            Q_BaseVCC_AS_gen_W = Q_BaseVCC_AS_gen_directload_W + Q_BaseVCC_AS_gen_storage_W

        Q_BaseVCC_AS_gen_W, \
        E_BaseVCC_AS_req_W = calc_vcc_CT_operation(Q_BaseVCC_AS_gen_W,
                                                   T_district_cooling_return_K,
                                                   T_district_cooling_supply_K,
                                                   VCC_T_COOL_IN,
                                                   size_AS_BaseVCC_W,
                                                   VCC_chiller)
        Q_cooling_unmet_W = Q_cooling_unmet_W - Q_BaseVCC_AS_gen_directload_W - Qc_from_storage_W
        Q_DailyStorage_gen_directload_W += Qc_from_storage_W
    else:
        Q_BaseVCC_AS_gen_W = 0.0
        E_BaseVCC_AS_req_W = 0.0
        Q_BaseVCC_AS_gen_directload_W = 0.0

    # Peak VCC air-source with a cooling tower
    if master_to_slave_variables.AS_PeakVCC_on == 1 and Q_cooling_unmet_W > 0.0 and not np.isclose(
            T_district_cooling_supply_K, T_district_cooling_return_K):
        size_AS_PeakVCC_W = master_to_slave_variables.AS_PeakVCC_size_W
        if Q_cooling_unmet_W > size_AS_PeakVCC_W:
            Q_PeakVCC_AS_gen_directload_W = size_AS_PeakVCC_W
            Q_PeakVCC_AS_gen_storage_W = 0.0
            Qc_from_storage_W = daily_storage_class.discharge_storage(
                Q_cooling_unmet_W - size_AS_PeakVCC_W)
            Q_PeakVCC_AS_gen_W = Q_PeakVCC_AS_gen_directload_W + Q_PeakVCC_AS_gen_storage_W
        else:
            Q_PeakVCC_AS_gen_directload_W = Q_cooling_unmet_W
            Q_PeakVCC_AS_gen_storage_W = daily_storage_class.charge_storage(
                size_AS_PeakVCC_W - Q_cooling_unmet_W)
            Qc_from_storage_W = 0.0
            Q_PeakVCC_AS_gen_W = Q_PeakVCC_AS_gen_directload_W + Q_PeakVCC_AS_gen_storage_W

        Q_PeakVCC_AS_gen_W, \
        E_PeakVCC_AS_req_W = calc_vcc_CT_operation(Q_PeakVCC_AS_gen_W,
                                                   T_district_cooling_return_K,
                                                   T_district_cooling_supply_K,
                                                   VCC_T_COOL_IN,
                                                   size_AS_PeakVCC_W,
                                                   VCC_chiller)

        Q_cooling_unmet_W = Q_cooling_unmet_W - Q_PeakVCC_AS_gen_directload_W - Qc_from_storage_W
        Q_DailyStorage_gen_directload_W += Qc_from_storage_W
    else:
        Q_PeakVCC_AS_gen_W = 0.0
        E_PeakVCC_AS_req_W = 0.0
        Q_BaseVCC_AS_gen_directload_W = 0.0
        Q_PeakVCC_AS_gen_directload_W = 0.0

    if Q_cooling_unmet_W > 1.0E-3:
        Q_BackupVCC_AS_gen_W = Q_cooling_unmet_W  # this will become the back-up chiller
        Q_BackupVCC_AS_directload_W = Q_cooling_unmet_W
    else:
        Q_BackupVCC_AS_gen_W = 0.0
        Q_BackupVCC_AS_directload_W = 0.0

    ## writing outputs
    electricity_output = {
        '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_Trigen_NG_gen_W': E_Trigen_NG_gen_W
    }

    thermal_output = {
        # cooling total
        'Q_Trigen_NG_gen_W': Q_Trigen_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_gen_W': Q_BackupVCC_AS_gen_W,

        # cooling to direct load
        'Q_DailyStorage_gen_directload_W': Q_DailyStorage_gen_directload_W,
        "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,
    }

    gas_output = {'NG_Trigen_req_W': NG_Trigen_req_W}

    return daily_storage_class, thermal_output, electricity_output, gas_output
def heating_source_activator(Q_therm_req_W, master_to_slave_vars,
                             Q_therm_GHP_W, TretGHPArray_K, TretLakeArray_K,
                             Q_therm_Lake_W, Q_therm_Sew_W, TretsewArray_K,
                             tdhsup_K, tdhret_req_K):
    """
    :param Q_therm_req_W:
    :param hour:
    :param context:
    :type Q_therm_req_W: float
    :type hour: int
    :type context: list
    :return: cost_data_centralPlant_op, source_info, Q_source_data, E_coldsource_data, E_PP_el_data, E_gas_data, E_wood_data, Q_excess
    :rtype:
    """

    ## initializing unmet heating load
    Q_heat_unmet_W = Q_therm_req_W

    # ACTIVATE THE COGEN
    if master_to_slave_vars.CC_on == 1 and Q_heat_unmet_W > 0.0:

        CC_op_cost_data = calc_cop_CCGT(master_to_slave_vars.CCGT_SIZE_W,
                                        tdhsup_K,
                                        "NG")  # create cost information
        Q_used_prim_CC_fn_W = CC_op_cost_data['q_input_fn_q_output_W']
        q_output_CC_min_W = CC_op_cost_data['q_output_min_W']
        Q_output_CC_max_W = CC_op_cost_data['q_output_max_W']
        eta_elec_interpol = CC_op_cost_data['eta_el_fn_q_input']

        if Q_heat_unmet_W >= q_output_CC_min_W:
            # operation Possible if above minimal load
            if Q_heat_unmet_W <= Q_output_CC_max_W:  # Normal operation Possible within partload regime
                Q_CHP_gen_W = Q_heat_unmet_W
                NG_CHP_req_W = Q_used_prim_CC_fn_W(Q_CHP_gen_W)
                E_CHP_gen_W = np.float(
                    eta_elec_interpol(NG_CHP_req_W)) * NG_CHP_req_W
            else:  # Only part of the demand can be delivered as 100% load achieved
                Q_CHP_gen_W = Q_output_CC_max_W
                NG_CHP_req_W = Q_used_prim_CC_fn_W(Q_CHP_gen_W)
                E_CHP_gen_W = np.float(
                    eta_elec_interpol(NG_CHP_req_W)) * NG_CHP_req_W
        else:
            NG_CHP_req_W = 0.0
            E_CHP_gen_W = 0.0
            Q_CHP_gen_W = 0.0
        Q_heat_unmet_W = Q_heat_unmet_W - Q_CHP_gen_W
    else:
        NG_CHP_req_W = 0.0
        E_CHP_gen_W = 0.0
        Q_CHP_gen_W = 0.0

    # WET FURNACE
    if master_to_slave_vars.Furnace_wet_on == 1 and Q_heat_unmet_W > 0.0:  # Activate Furnace if its there.
        # Operate only if its above minimal load
        if Q_heat_unmet_W > master_to_slave_vars.WBFurnace_Q_max_W:
            if Q_heat_unmet_W > master_to_slave_vars.WBFurnace_Q_max_W:
                Q_Furnace_wet_gen_W = master_to_slave_vars.WBFurnace_Q_max_W
                # scale down if above maximum load, Furnace operates at max. capacity
                DryBiomass_Furnace_req_W, E_Furnace_wet_gen_W = furnace_op_cost(
                    Q_Furnace_wet_gen_W,
                    master_to_slave_vars.WBFurnace_Q_max_W, tdhret_req_K,
                    "wet")

            else:  # Normal Operation Possible
                Q_Furnace_wet_gen_W = Q_heat_unmet_W
                DryBiomass_Furnace_req_W, E_Furnace_wet_gen_W = furnace_op_cost(
                    Q_Furnace_wet_gen_W,
                    master_to_slave_vars.WBFurnace_Q_max_W, tdhret_req_K,
                    "wet")
        else:
            E_Furnace_wet_gen_W = 0.0
            DryBiomass_Furnace_req_W = 0.0
            Q_Furnace_wet_gen_W = 0.0

        Q_heat_unmet_W = Q_heat_unmet_W - Q_Furnace_wet_gen_W

    else:
        E_Furnace_wet_gen_W = 0.0
        DryBiomass_Furnace_req_W = 0.0
        Q_Furnace_wet_gen_W = 0.0

    # DRY FURNACE
    if master_to_slave_vars.Furnace_dry_on == 1 and Q_heat_unmet_W > 0.0:  # Activate Furnace if its there.
        # Operate only if its above minimal load
        if Q_heat_unmet_W > master_to_slave_vars.DBFurnace_Q_max_W:
            if Q_heat_unmet_W > master_to_slave_vars.DBFurnace_Q_max_W:
                Q_Furnace_dry_gen_W = master_to_slave_vars.DBFurnace_Q_max_W
                # scale down if above maximum load, Furnace operates at max. capacity
                WetBiomass_Furnace_req_W, E_Furnace_dry_gen_W = furnace_op_cost(
                    Q_Furnace_dry_gen_W,
                    master_to_slave_vars.DBFurnace_Q_max_W, tdhret_req_K,
                    "dry")

            else:  # Normal Operation Possible
                Q_Furnace_dry_gen_W = Q_heat_unmet_W
                WetBiomass_Furnace_req_W, E_Furnace_dry_gen_W = furnace_op_cost(
                    Q_Furnace_dry_gen_W,
                    master_to_slave_vars.DBFurnace_Q_max_W, tdhret_req_K,
                    "dry")
        else:
            E_Furnace_dry_gen_W = 0.0
            WetBiomass_Furnace_req_W = 0.0
            Q_Furnace_dry_gen_W = 0.0

        Q_heat_unmet_W = Q_heat_unmet_W - Q_Furnace_dry_gen_W
    else:
        E_Furnace_dry_gen_W = 0.0
        WetBiomass_Furnace_req_W = 0.0
        Q_Furnace_dry_gen_W = 0.0

    if (master_to_slave_vars.HPSew_on
        ) == 1 and Q_heat_unmet_W > 0.0 and not np.isclose(
            tdhsup_K, tdhret_req_K):  # activate if its available

        if Q_heat_unmet_W > Q_therm_Sew_W:
            Q_HPSew_gen_W = Q_therm_Sew_W
            mdot_DH_to_Sew_kgpers = Q_HPSew_gen_W / (
                HEAT_CAPACITY_OF_WATER_JPERKGK * (tdhsup_K - tdhret_req_K))
        else:
            Q_HPSew_gen_W = Q_heat_unmet_W
            mdot_DH_to_Sew_kgpers = Q_HPSew_gen_W / (
                HEAT_CAPACITY_OF_WATER_JPERKGK * (tdhsup_K - tdhret_req_K))

        E_HPSew_req_W, \
        Q_coldsource_HPSew_W, \
        Q_HPSew_gen_W = HPSew_op_cost(mdot_DH_to_Sew_kgpers,
                                      tdhsup_K,
                                      tdhret_req_K,
                                      TretsewArray_K,
                                      Q_HPSew_gen_W
                                      )

        Q_heat_unmet_W = Q_heat_unmet_W - Q_HPSew_gen_W

    else:
        E_HPSew_req_W = 0.0
        Q_HPSew_gen_W = 0.0

    if (master_to_slave_vars.HPLake_on
        ) == 1 and Q_heat_unmet_W > 0.0 and not np.isclose(
            tdhsup_K, tdhret_req_K):
        if Q_heat_unmet_W > Q_therm_Lake_W:  # Scale down Load, 100% load achieved
            Q_HPLake_gen_W = Q_therm_Lake_W
        else:  # regular operation possible
            Q_HPLake_gen_W = Q_heat_unmet_W

        E_HPLake_req_W, Q_coldsource_HPLake_W, Q_HPLake_gen_W = HPLake_op_cost(
            Q_HPLake_gen_W, tdhsup_K, tdhret_req_K, TretLakeArray_K)
        E_pump_req_W = calc_water_body_uptake_pumping(Q_HPLake_gen_W,
                                                      tdhret_req_K, tdhsup_K)

        E_HPLake_req_W += E_pump_req_W

        Q_heat_unmet_W = Q_heat_unmet_W - Q_HPLake_gen_W

    else:
        E_HPLake_req_W = 0.0
        Q_HPLake_gen_W = 0.0

    if (master_to_slave_vars.GHP_on
        ) == 1 and Q_heat_unmet_W > 0.0 and not np.isclose(
            tdhsup_K, tdhret_req_K):
        if Q_heat_unmet_W > Q_therm_GHP_W:
            Q_GHP_gen_W = Q_therm_GHP_W
            mdot_DH_to_GHP_kgpers = Q_GHP_gen_W / (
                HEAT_CAPACITY_OF_WATER_JPERKGK * (tdhsup_K - tdhret_req_K))
        else:  # regular operation possible, demand is covered
            Q_GHP_gen_W = Q_heat_unmet_W
            mdot_DH_to_GHP_kgpers = Q_GHP_gen_W / (
                HEAT_CAPACITY_OF_WATER_JPERKGK * (tdhsup_K - tdhret_req_K))

        E_GHP_req_W, Q_coldsource_GHP_W, Q_GHP_gen_W = GHP_op_cost(
            mdot_DH_to_GHP_kgpers, tdhsup_K, tdhret_req_K, TretGHPArray_K,
            Q_GHP_gen_W)
        Q_heat_unmet_W = Q_heat_unmet_W - Q_GHP_gen_W

    else:
        E_GHP_req_W = 0.0
        Q_GHP_gen_W = 0.0

    if (master_to_slave_vars.Boiler_on) == 1 and Q_heat_unmet_W > 0:
        if Q_heat_unmet_W >= BOILER_MIN * master_to_slave_vars.Boiler_Q_max_W:  # Boiler can be activated?
            if Q_heat_unmet_W >= master_to_slave_vars.Boiler_Q_max_W:  # Boiler above maximum Load?
                Q_BaseBoiler_gen_W = master_to_slave_vars.Boiler_Q_max_W
            else:
                Q_BaseBoiler_gen_W = Q_heat_unmet_W

            NG_BaseBoiler_req_W, E_BaseBoiler_req_W = cond_boiler_op_cost(
                Q_BaseBoiler_gen_W, master_to_slave_vars.Boiler_Q_max_W,
                tdhret_req_K)
        else:
            Q_BaseBoiler_gen_W = 0.0
            NG_BaseBoiler_req_W = 0.0
            E_BaseBoiler_req_W = 0.0

        Q_heat_unmet_W = Q_heat_unmet_W - Q_BaseBoiler_gen_W

    else:
        Q_BaseBoiler_gen_W = 0.0
        NG_BaseBoiler_req_W = 0.0
        E_BaseBoiler_req_W = 0.0

    if master_to_slave_vars.BoilerPeak_on == 1 and Q_heat_unmet_W > 0:
        if Q_heat_unmet_W >= BOILER_MIN * master_to_slave_vars.BoilerPeak_Q_max_W:  # Boiler can be activated?
            if Q_heat_unmet_W > master_to_slave_vars.BoilerPeak_Q_max_W:  # Boiler above maximum Load?
                Q_PeakBoiler_gen_W = master_to_slave_vars.BoilerPeak_Q_max_W
            else:
                Q_PeakBoiler_gen_W = Q_heat_unmet_W

            NG_PeakBoiler_req_W, E_PeakBoiler_req_W = cond_boiler_op_cost(
                Q_PeakBoiler_gen_W, master_to_slave_vars.BoilerPeak_Q_max_W,
                tdhret_req_K)
        else:
            Q_PeakBoiler_gen_W = 0.0
            NG_PeakBoiler_req_W = 0
            E_PeakBoiler_req_W = 0.0

        Q_heat_unmet_W = Q_heat_unmet_W - Q_PeakBoiler_gen_W

    else:
        Q_PeakBoiler_gen_W = 0.0
        NG_PeakBoiler_req_W = 0
        E_PeakBoiler_req_W = 0.0

    if Q_heat_unmet_W > 1.0E-3:
        Q_uncovered_W = Q_heat_unmet_W  # this will become the back-up boiler
    else:
        Q_uncovered_W = 0.0

    return Q_HPSew_gen_W, \
           Q_HPLake_gen_W, \
           Q_GHP_gen_W, \
           Q_CHP_gen_W, \
           Q_Furnace_dry_gen_W, \
           Q_Furnace_wet_gen_W, \
           Q_BaseBoiler_gen_W, \
           Q_PeakBoiler_gen_W, \
           Q_uncovered_W, \
           E_HPSew_req_W, \
           E_HPLake_req_W, \
           E_BaseBoiler_req_W, \
           E_PeakBoiler_req_W, \
           E_GHP_req_W, \
           E_CHP_gen_W, \
           E_Furnace_dry_gen_W, \
           E_Furnace_wet_gen_W, \
           NG_CHP_req_W, \
           NG_BaseBoiler_req_W, \
           NG_PeakBoiler_req_W, \
           WetBiomass_Furnace_req_W, \
           DryBiomass_Furnace_req_W