<commit_before>"""
Absorption chillers
"""
from __future__ import division, print_function
import cea.config
import cea.inputlocator
import pandas as pd
import numpy as np
from math import log, ceil
import sympy
from cea.constants import HEAT_CAPACITY_OF_WATER_JPERKGK

__author__ = "<NAME>"
__copyright__ = "Copyright 2015, Architecture and Building Systems - ETH Zurich"
__credits__ = ["<NAME>"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "<NAME>"
__email__ = "<EMAIL>"
__status__ = "Production"


# technical model

def calc_chiller_main(mdot_chw_kgpers, T_chw_sup_K, T_chw_re_K, T_hw_in_C, T_ground_K, chiller_prop):
    """
    This model calculates the operation conditions of the absorption chiller given the chilled water loads in
    evaporators and the hot water inlet temperature in the generator (desorber).
    This is an empirical model using characteristic equation method developed by _[<NAME>. & <NAME>., 2005].
    The parameters of each absorption chiller can be derived from experiments or performance curves from manufacturer's
    catalog, more details are described in _[Puig-Arnavat M. et al, 2010].
    Assumptions: constant external flow rates (chilled water at the evaporator, cooling water at the condenser and
    absorber, hot water at the generator).
    :param mdot_chw_kgpers: required chilled water flow rate
    :type mdot_chw_kgpers: float
    :param T_chw_sup_K: required chilled water supply temperature (outlet from the evaporator)
    :type T_chw_sup_K: float
    :param T_chw_re_K: required chilled water return temperature (inlet to the evaporator)
    :type T_chw_re_K: float
    :param T_hw_in_C: hot water inlet temperature to the generator
    :type T_hw_in_C: float
    :param T_ground_K: ground temperature
    :type T_ground_K: float
    :param locator: locator class
    :return:
    ..[<NAME>. & <NAME>., 2005] Operational results of a 10kW absorption chiller and adaptation of the characteristic
    equation. In: Proceedings of the interantional conference solar air conditioning. Bad Staffelstein, Germany: 2005.
    ..[<NAME> al, 2010] Analysis and parameter identification for characteristic equations of single- and
    double-effect absorption chillers by means of multivariable regression. Int J Refrig: 2010.
    """
    chiller_prop = chiller_prop.chiller_prop #get data from the class
    # create a dict of input operating conditions
    input_conditions = {'T_chw_sup_K': T_chw_sup_K,
                        'T_chw_re_K': T_chw_re_K,
                        'T_hw_in_C': T_hw_in_C,
                        'T_ground_K': T_ground_K}
    mcp_chw_WperK = mdot_chw_kgpers * HEAT_CAPACITY_OF_WATER_JPERKGK
    q_chw_total_W = mcp_chw_WperK * (T_chw_re_K - T_chw_sup_K)

    if np.isclose(q_chw_total_W, 0.0):
        wdot_W = 0.0
        q_cw_W = 0.0
        q_hw_W = 0.0
        T_hw_out_C = np.nan
        EER = 0.0
        input_conditions['q_chw_W'] = 0.0
    else:
        min_chiller_size_W = min(chiller_prop['cap_min'].values)
        max_chiller_size_W = max(chiller_prop['cap_max'].values)
        # get chiller properties and input conditions according to load
        if q_chw_total_W < min_chiller_size_W:
            # get chiller property according to load
            chiller_prop = chiller_prop[chiller_prop['cap_min'] == min_chiller_size_W]
            # operate at minimum load
            number_of_chillers_activated = 1.0  # only activate one chiller
            input_conditions['q_chw_W'] = chiller_prop['cap_min'].values  # minimum load
        elif q_chw_total_W <= max_chiller_size_W:
            # get chiller property according to load
            chiller_prop = chiller_prop[(chiller_prop['cap_min'] <= q_chw_total_W) &
                                        (chiller_prop['cap_max'] >= q_chw_total_W)]
            # operate one chiller at the cooling load
            number_of_chillers_activated = 1.0  # only activate one chiller
            input_conditions['q_chw_W'] = q_chw_total_W # operate at the chilled water load
        else:
            # get chiller property according to load
            chiller_prop = chiller_prop[chiller_prop['cap_max'] == max_chiller_size_W]
            # distribute loads to multiple chillers
            number_of_chillers_activated = q_chw_total_W / max_chiller_size_W
            # operate at maximum load
            input_conditions['q_chw_W'] = max(chiller_prop['cap_max'].values)

        # calculate operating conditions at given input conditions
        operating_conditions = calc_operating_conditions(chiller_prop, input_conditions)
        # calculate chiller outputs
        wdot_W = calc_power_demand(input_conditions['q_chw_W'], chiller_prop) * number_of_chillers_activated
        q_cw_W = operating_conditions['q_cw_W'] * number_of_chillers_activated
        q_hw_W = operating_conditions['q_hw_W'] * number_of_chillers_activated
        T_hw_out_C = operating_conditions['T_hw_out_C']
        EER = q_chw_total_W / (q_hw_W + wdot_W)

        if T_hw_out_C < 0.0 :
            print ('T_hw_out_C = ', T_hw_out_C, ' incorrect condition, check absorption chiller script.')

    chiller_operation = {'wdot_W': wdot_W, 'q_cw_W': q_cw_W, 'q_hw_W': q_hw_W, 'T_hw_out_C': T_hw_out_C,
                         'q_chw_W': q_chw_total_W, 'EER': EER}

    return chiller_operation


def calc_operating_conditions(chiller_prop, input_conditions):
    """
    Calculates chiller operating conditions at given input conditions by solving the characteristic equations and the
    energy balance equations. This method is adapted from _[<NAME>. & <NAME>., 2005].
    The heat rejection to cooling tower is approximated with the energy balance:
    Q(condenser) + Q(absorber) = Q(generator) + Q(evaporator)
    :param chiller_prop: parameters in the characteristic equations and the external flow rates.
    :type chiller_prop: dict
    :param input_conditions:
    :type input_conditions: dict
    :return: a dict with operating conditions of the chilled water, cooling water and hot water loops in a absorption
    chiller.
    ..[<NAME>. & <NAME>., 2005] Operational results of a 10kW absorption chiller and adaptation of the characteristic
    equation. In: Proceedings of the interantional conference solar air conditioning. Bad Staffelstein, Germany: 2005.
    """
    # external water circuits (e: chilled water, ac: cooling water, d: hot water)
    T_cw_in_C = input_conditions['T_ground_K'] - 273.0  # condenser water inlet temperature
    T_chw_in_C = input_conditions['T_chw_re_K'] - 273.0  # inlet to the evaporator
    T_chw_out_C = input_conditions['T_chw_sup_K'] - 273.0  # outlet from the evaporator
    q_chw_kW = input_conditions['q_chw_W'] / 1000  # cooling load ata the evaporator
    m_cw_kgpers = chiller_prop['m_cw'].values[0]  # external flow rate of cooling water at the condenser and absorber
    m_hw_kgpers = chiller_prop['m_hw'].values[0]  # external flow rate of hot water at the generator
    mcp_cw_kWperK = m_cw_kgpers * HEAT_CAPACITY_OF_WATER_JPERKGK/1000
    mcp_hw_kWperK = m_hw_kgpers * HEAT_CAPACITY_OF_WATER_JPERKGK/1000

    # chiller_props (these are constants from the Absorption_chiller sheet in systems.xls)
    s_e = chiller_prop['s_e'].values[0]
    r_e = chiller_prop['r_e'].values[0]
    s_g = chiller_prop['s_g'].values[0]
    r_g = chiller_prop['r_g'].values[0]
    a_e = chiller_prop['a_e'].values[0]
    e_e = chiller_prop['e_e'].values[0]
    a_g = chiller_prop['a_g'].values[0]
    e_g = chiller_prop['e_g'].values[0]



    # variables to solve
    T_hw_out_C, T_cw_out_C, q_hw_kW = sympy.symbols('T_hw_out_C T_cw_out_C q_hw_kW')

    # characteristic temperature differences
    T_hw_mean_C = (input_conditions['T_hw_in_C'] + T_hw_out_C) / 2
    T_cw_mean_C = (T_cw_in_C + T_cw_out_C) / 2
    T_chw_mean_C = (T_chw_in_C + T_chw_out_C) / 2
    ddt_e = T_hw_mean_C + a_e * T_cw_mean_C + e_e * T_chw_mean_C
    ddt_g = T_hw_mean_C + a_g * T_cw_mean_C + e_g * T_chw_mean_C

    # systems of equations to solve
    eq_e = s_e * ddt_e + r_e - q_chw_kW
    eq_g = s_g * ddt_g + r_g - q_hw_kW
    eq_bal_g = (input_conditions['T_hw_in_C'] - T_hw_out_C) - q_hw_kW / mcp_hw_kWperK

    # solve the system of equations with sympy
    eq_sys = [eq_e, eq_g, eq_bal_g]
    unknown_variables = (T_hw_out_C, T_cw_out_C, q_hw_kW)
    (T_hw_out_C, T_cw_out_C, q_hw_kW) = tuple(*sympy.linsolve(eq_sys, unknown_variables))

    # calculate results
    q_cw_kW = q_hw_kW + q_chw_kW # Q(condenser) + Q(absorber)
    T_hw_out_C = input_conditions['T_hw_in_C'] - q_hw_kW / mcp_hw_kWperK
    T_cw_out_C = T_cw_in_C + q_cw_kW / mcp_cw_kWperK  # TODO: set upper bound of the chiller operation

    return {'T_hw_out_C': T_hw_out_C,
            'T_cw_out_C': T_cw_out_C,
            'q_chw_W': q_chw_kW * 1000,
            'q_hw_W': q_hw_kW * 1000,
            'q_cw_W': q_cw_kW * 1000}


def calc_operating_conditions_matrix(chiller_prop, input_conditions):
    """
    Calculates chiller operating conditions at given input conditions by solving the characteristic equations and the
    energy balance equations. This method is adapted from _[<NAME>. & <NAME>., 2005].
    The heat rejection to cooling tower is approximated with the energy balance:
    Q(condenser) + Q(absorber) = Q(generator) + Q(evaporator)
    :param chiller_prop: parameters in the characteristic equations and the external flow rates.
    :type chiller_prop: dict
    :param input_conditions:
    :type input_conditions: dict
    :return: a dict with operating conditions of the chilled water, cooling water and hot water loops in a absorption
    chiller.
    ..[<NAME>. & <NAME>., 2005] Operational results of a 10kW absorption chiller and adaptation of the characteristic
    equation. In: Proceedings of the interantional conference solar air conditioning. Bad Staffelstein, Germany: 2005.
    """
    # external water circuits (e: chilled water, ac: cooling water, d: hot water)
    T_hw_in_C = input_conditions['T_hw_in_C']
    T_cw_in_C = input_conditions['T_ground_K'] - 273.0  # condenser water inlet temperature
    T_chw_in_C = input_conditions['T_chw_re_K'] - 273.0  # inlet to the evaporator
    T_chw_out_C = input_conditions['T_chw_sup_K'] - 273.0  # outlet from the evaporator
    q_chw_kW = input_conditions['q_chw_W'] / 1000  # cooling load ata the evaporator
    m_cw_kgpers = chiller_prop['m_cw'].values[0]  # external flow rate of cooling water at the condenser and absorber
    m_hw_kgpers = chiller_prop['m_hw'].values[0]  # external flow rate of hot water at the generator
    mcp_cw_kWperK = m_cw_kgpers * HEAT_CAPACITY_OF_WATER_JPERKGK/1000
    mcp_hw_kWperK = m_hw_kgpers * HEAT_CAPACITY_OF_WATER_JPERKGK/1000

    # chiller_props (these are constants from the Absorption_chiller sheet in systems.xls)
    s_e = chiller_prop['s_e'].values[0]
    r_e = chiller_prop['r_e'].values[0]
    s_g = chiller_prop['s_g'].values[0]
    r_g = chiller_prop['r_g'].values[0]
    a_e = chiller_prop['a_e'].values[0]
    e_e = chiller_prop['e_e'].values[0]
    a_g = chiller_prop['a_g'].values[0]
    e_g = chiller_prop['e_g'].values[0]

    # variables to solve
    T_hw_out_C, T_cw_out_C, q_hw_kW, ddt_e, ddt_g = sympy.symbols('T_hw_out_C T_cw_out_C q_hw_kW , ddt_e, ddt_g')

    # systems of equations to solve
    eq_e = chiller_prop['s_e'].values[0] * ddt_e + chiller_prop['r_e'].values[0] - q_chw_kW
    eq_ddt_e = (input_conditions['T_hw_in_C'] + T_hw_out_C) / 2 + \
               chiller_prop['a_e'].values[0] * (T_cw_in_C + T_cw_out_C) / 2 + \
               chiller_prop['e_e'].values[0] * (T_chw_in_C + T_chw_out_C) / 2 - ddt_e
    eq_g = chiller_prop['s_g'].values[0] * ddt_g + chiller_prop['r_g'].values[0] - q_hw_kW
    eq_ddt_g = (input_conditions['T_hw_in_C'] + T_hw_out_C) / 2 + \
               chiller_prop['a_g'].values[0] * (T_cw_in_C + T_cw_out_C) / 2 + \
               chiller_prop['e_g'].values[0] * (T_chw_in_C + T_chw_out_C) / 2 - ddt_g
    eq_bal_g = (input_conditions['T_hw_in_C'] - T_hw_out_C) - q_hw_kW / mcp_hw_kWperK

    # solve the system of equations with sympy
    eq_sys = [eq_e, eq_g, eq_bal_g, eq_ddt_e, eq_ddt_g]
    unknown_variables = (T_hw_out_C, T_cw_out_C, q_hw_kW, ddt_e, ddt_g)
    (T_hw_out_C, T_cw_out_C, q_hw_kW, ddt_e, ddt_g) = tuple(*sympy.linsolve(eq_sys, unknown_variables))

    # calculate results
    q_cw_kW = q_hw_kW + q_chw_kW # Q(condenser) + Q(absorber)
    T_hw_out_C = T_hw_in_C - q_hw_kW / mcp_hw_kWperK
    T_cw_out_C = T_cw_in_C + q_cw_kW / mcp_cw_kWperK  # TODO: set upper bound of the chiller operation

    return {'T_hw_out_C': T_hw_out_C,
            'T_cw_out_C': T_cw_out_C,
            'q_chw_W': q_chw_kW * 1000,
            'q_hw_W': q_hw_kW * 1000,
            'q_cw_W': q_cw_kW * 1000}
<commit_msg>new version of calc_operating_conditions using pre-solved expression for q_hw_kW<commit_after>"""
Absorption chillers
"""
from __future__ import division, print_function
import cea.config
import cea.inputlocator
import pandas as pd
import numpy as np
from math import log, ceil
import sympy
from cea.constants import HEAT_CAPACITY_OF_WATER_JPERKGK

__author__ = "<NAME>"
__copyright__ = "Copyright 2015, Architecture and Building Systems - ETH Zurich"
__credits__ = ["<NAME>"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "<NAME>"
__email__ = "<EMAIL>"
__status__ = "Production"


# technical model

def calc_chiller_main(mdot_chw_kgpers, T_chw_sup_K, T_chw_re_K, T_hw_in_C, T_ground_K, chiller_prop):
    """
    This model calculates the operation conditions of the absorption chiller given the chilled water loads in
    evaporators and the hot water inlet temperature in the generator (desorber).
    This is an empirical model using characteristic equation method developed by _[<NAME>. & <NAME>., 2005].
    The parameters of each absorption chiller can be derived from experiments or performance curves from manufacturer's
    catalog, more details are described in _[Puig-Arnavat M. et al, 2010].
    Assumptions: constant external flow rates (chilled water at the evaporator, cooling water at the condenser and
    absorber, hot water at the generator).
    :param mdot_chw_kgpers: required chilled water flow rate
    :type mdot_chw_kgpers: float
    :param T_chw_sup_K: required chilled water supply temperature (outlet from the evaporator)
    :type T_chw_sup_K: float
    :param T_chw_re_K: required chilled water return temperature (inlet to the evaporator)
    :type T_chw_re_K: float
    :param T_hw_in_C: hot water inlet temperature to the generator
    :type T_hw_in_C: float
    :param T_ground_K: ground temperature
    :type T_ground_K: float
    :param locator: locator class
    :return:
    ..[<NAME>. & <NAME>., 2005] Operational results of a 10kW absorption chiller and adaptation of the characteristic
    equation. In: Proceedings of the interantional conference solar air conditioning. Bad Staffelstein, Germany: 2005.
    ..[<NAME> al, 2010] Analysis and parameter identification for characteristic equations of single- and
    double-effect absorption chillers by means of multivariable regression. Int J Refrig: 2010.
    """
    chiller_prop = chiller_prop.chiller_prop #get data from the class
    # create a dict of input operating conditions
    input_conditions = {'T_chw_sup_K': T_chw_sup_K,
                        'T_chw_re_K': T_chw_re_K,
                        'T_hw_in_C': T_hw_in_C,
                        'T_ground_K': T_ground_K}
    mcp_chw_WperK = mdot_chw_kgpers * HEAT_CAPACITY_OF_WATER_JPERKGK
    q_chw_total_W = mcp_chw_WperK * (T_chw_re_K - T_chw_sup_K)

    if np.isclose(q_chw_total_W, 0.0):
        wdot_W = 0.0
        q_cw_W = 0.0
        q_hw_W = 0.0
        T_hw_out_C = np.nan
        EER = 0.0
        input_conditions['q_chw_W'] = 0.0
    else:
        min_chiller_size_W = min(chiller_prop['cap_min'].values)
        max_chiller_size_W = max(chiller_prop['cap_max'].values)
        # get chiller properties and input conditions according to load
        if q_chw_total_W < min_chiller_size_W:
            # get chiller property according to load
            chiller_prop = chiller_prop[chiller_prop['cap_min'] == min_chiller_size_W]
            # operate at minimum load
            number_of_chillers_activated = 1.0  # only activate one chiller
            input_conditions['q_chw_W'] = chiller_prop['cap_min'].values  # minimum load
        elif q_chw_total_W <= max_chiller_size_W:
            # get chiller property according to load
            chiller_prop = chiller_prop[(chiller_prop['cap_min'] <= q_chw_total_W) &
                                        (chiller_prop['cap_max'] >= q_chw_total_W)]
            # operate one chiller at the cooling load
            number_of_chillers_activated = 1.0  # only activate one chiller
            input_conditions['q_chw_W'] = q_chw_total_W # operate at the chilled water load
        else:
            # get chiller property according to load
            chiller_prop = chiller_prop[chiller_prop['cap_max'] == max_chiller_size_W]
            # distribute loads to multiple chillers
            number_of_chillers_activated = q_chw_total_W / max_chiller_size_W
            # operate at maximum load
            input_conditions['q_chw_W'] = max(chiller_prop['cap_max'].values)

        # calculate operating conditions at given input conditions
        operating_conditions = calc_operating_conditions(chiller_prop, input_conditions)
        operating_conditions_new = calc_operating_conditions_new(chiller_prop, input_conditions)

        for key in operating_conditions.keys():
            assert np.isclose(float(operating_conditions[key]), operating_conditions_new[key])
            # print("All same: {0:.2f} == {1:.2f}".format(float(operating_conditions[key]), operating_conditions_new[key]))

        # calculate chiller outputs
        wdot_W = calc_power_demand(input_conditions['q_chw_W'], chiller_prop) * number_of_chillers_activated
        q_cw_W = operating_conditions['q_cw_W'] * number_of_chillers_activated
        q_hw_W = operating_conditions['q_hw_W'] * number_of_chillers_activated
        T_hw_out_C = operating_conditions['T_hw_out_C']
        EER = q_chw_total_W / (q_hw_W + wdot_W)

        if T_hw_out_C < 0.0 :
            print ('T_hw_out_C = ', T_hw_out_C, ' incorrect condition, check absorption chiller script.')

    chiller_operation = {'wdot_W': wdot_W, 'q_cw_W': q_cw_W, 'q_hw_W': q_hw_W, 'T_hw_out_C': T_hw_out_C,
                         'q_chw_W': q_chw_total_W, 'EER': EER}

    return chiller_operation


def calc_operating_conditions(chiller_prop, input_conditions):
    """
    Calculates chiller operating conditions at given input conditions by solving the characteristic equations and the
    energy balance equations. This method is adapted from _[<NAME>. & <NAME>., 2005].
    The heat rejection to cooling tower is approximated with the energy balance:
    Q(condenser) + Q(absorber) = Q(generator) + Q(evaporator)
    :param chiller_prop: parameters in the characteristic equations and the external flow rates.
    :type chiller_prop: dict
    :param input_conditions:
    :type input_conditions: dict
    :return: a dict with operating conditions of the chilled water, cooling water and hot water loops in a absorption
    chiller.
    ..[<NAME>. & <NAME>., 2005] Operational results of a 10kW absorption chiller and adaptation of the characteristic
    equation. In: Proceedings of the interantional conference solar air conditioning. Bad Staffelstein, Germany: 2005.
    """
    # external water circuits (e: chilled water, ac: cooling water, d: hot water)
    T_cw_in_C = input_conditions['T_ground_K'] - 273.0  # condenser water inlet temperature
    T_chw_in_C = input_conditions['T_chw_re_K'] - 273.0  # inlet to the evaporator
    T_chw_out_C = input_conditions['T_chw_sup_K'] - 273.0  # outlet from the evaporator
    q_chw_kW = input_conditions['q_chw_W'] / 1000  # cooling load ata the evaporator
    m_cw_kgpers = chiller_prop['m_cw'].values[0]  # external flow rate of cooling water at the condenser and absorber
    m_hw_kgpers = chiller_prop['m_hw'].values[0]  # external flow rate of hot water at the generator
    mcp_cw_kWperK = m_cw_kgpers * HEAT_CAPACITY_OF_WATER_JPERKGK/1000
    mcp_hw_kWperK = m_hw_kgpers * HEAT_CAPACITY_OF_WATER_JPERKGK/1000

    # chiller_props (these are constants from the Absorption_chiller sheet in systems.xls)
    s_e = chiller_prop['s_e'].values[0]
    r_e = chiller_prop['r_e'].values[0]
    s_g = chiller_prop['s_g'].values[0]
    r_g = chiller_prop['r_g'].values[0]
    a_e = chiller_prop['a_e'].values[0]
    e_e = chiller_prop['e_e'].values[0]
    a_g = chiller_prop['a_g'].values[0]
    e_g = chiller_prop['e_g'].values[0]



    # variables to solve
    T_hw_out_C, T_cw_out_C, q_hw_kW = sympy.symbols('T_hw_out_C T_cw_out_C q_hw_kW')

    # characteristic temperature differences
    T_hw_mean_C = (input_conditions['T_hw_in_C'] + T_hw_out_C) / 2
    T_cw_mean_C = (T_cw_in_C + T_cw_out_C) / 2
    T_chw_mean_C = (T_chw_in_C + T_chw_out_C) / 2
    ddt_e = T_hw_mean_C + a_e * T_cw_mean_C + e_e * T_chw_mean_C
    ddt_g = T_hw_mean_C + a_g * T_cw_mean_C + e_g * T_chw_mean_C

    # systems of equations to solve
    eq_e = s_e * ddt_e + r_e - q_chw_kW
    eq_g = s_g * ddt_g + r_g - q_hw_kW
    eq_bal_g = (input_conditions['T_hw_in_C'] - T_hw_out_C) - q_hw_kW / mcp_hw_kWperK

    # solve the system of equations with sympy
    eq_sys = [eq_e, eq_g, eq_bal_g]
    unknown_variables = (T_hw_out_C, T_cw_out_C, q_hw_kW)
    (T_hw_out_C, T_cw_out_C, q_hw_kW) = tuple(*sympy.linsolve(eq_sys, unknown_variables))

    # calculate results
    q_cw_kW = q_hw_kW + q_chw_kW # Q(condenser) + Q(absorber)
    T_hw_out_C = input_conditions['T_hw_in_C'] - q_hw_kW / mcp_hw_kWperK
    T_cw_out_C = T_cw_in_C + q_cw_kW / mcp_cw_kWperK  # TODO: set upper bound of the chiller operation

    return {'T_hw_out_C': T_hw_out_C,
            'T_cw_out_C': T_cw_out_C,
            'q_chw_W': q_chw_kW * 1000,
            'q_hw_W': q_hw_kW * 1000,
            'q_cw_W': q_cw_kW * 1000}


def calc_operating_conditions_new(chiller_prop, input_conditions):
    """
    Calculates chiller operating conditions at given input conditions by solving the characteristic equations and the
    energy balance equations. This method is adapted from _[<NAME>. & <NAME>., 2005].
    The heat rejection to cooling tower is approximated with the energy balance:
    Q(condenser) + Q(absorber) = Q(generator) + Q(evaporator)
    :param chiller_prop: parameters in the characteristic equations and the external flow rates.
    :type chiller_prop: dict
    :param input_conditions:
    :type input_conditions: dict
    :return: a dict with operating conditions of the chilled water, cooling water and hot water loops in a absorption
    chiller.
    ..[<NAME>. & <NAME>., 2005] Operational results of a 10kW absorption chiller and adaptation of the characteristic
    equation. In: Proceedings of the interantional conference solar air conditioning. Bad Staffelstein, Germany: 2005.
    """
    # external water circuits (e: chilled water, ac: cooling water, d: hot water)
    T_hw_in_C = input_conditions['T_hw_in_C']
    T_cw_in_C = input_conditions['T_ground_K'] - 273.0  # condenser water inlet temperature
    T_chw_in_C = input_conditions['T_chw_re_K'] - 273.0  # inlet to the evaporator
    T_chw_out_C = input_conditions['T_chw_sup_K'] - 273.0  # outlet from the evaporator
    q_chw_kW = input_conditions['q_chw_W'] / 1000  # cooling load ata the evaporator
    m_cw_kgpers = chiller_prop['m_cw'].values[0]  # external flow rate of cooling water at the condenser and absorber
    m_hw_kgpers = chiller_prop['m_hw'].values[0]  # external flow rate of hot water at the generator
    mcp_cw_kWperK = m_cw_kgpers * HEAT_CAPACITY_OF_WATER_JPERKGK / 1000
    mcp_hw_kWperK = m_hw_kgpers * HEAT_CAPACITY_OF_WATER_JPERKGK / 1000

    # chiller_props (these are constants from the Absorption_chiller sheet in systems.xls)
    s_e = chiller_prop['s_e'].values[0]
    r_e = chiller_prop['r_e'].values[0]
    s_g = chiller_prop['s_g'].values[0]
    r_g = chiller_prop['r_g'].values[0]
    a_e = chiller_prop['a_e'].values[0]
    e_e = chiller_prop['e_e'].values[0]
    a_g = chiller_prop['a_g'].values[0]
    e_g = chiller_prop['e_g'].values[0]

    # variables to solve
    # T_hw_out_C, T_cw_out_C, q_hw_kW, ddt_e, ddt_g = sympy.symbols('T_hw_out_C T_cw_out_C q_hw_kW , ddt_e, ddt_g')
    #
    # # systems of equations to solve
    # eq_e = s_e * ddt_e + r_e - q_chw_kW
    # eq_ddt_e = ((T_hw_in_C + T_hw_out_C) / 2.0 + a_e * (T_cw_in_C + T_cw_out_C) / 2.0 + e_e * (T_chw_in_C + T_chw_out_C) / 2.0 - ddt_e)
    # eq_g = s_g * ddt_g + r_g - q_hw_kW
    # eq_ddt_g = ((T_hw_in_C + T_hw_out_C) / 2.0 + a_g * (T_cw_in_C + T_cw_out_C) / 2.0 + e_g * (T_chw_in_C + T_chw_out_C) / 2.0- ddt_g)
    # eq_bal_g = (T_hw_in_C - T_hw_out_C) - q_hw_kW / mcp_hw_kWperK
    #
    # # solve the system of equations with sympy
    # eq_sys = [eq_e, eq_g, eq_bal_g, eq_ddt_e, eq_ddt_g]
    # unknown_variables = (T_hw_out_C, T_cw_out_C, q_hw_kW, ddt_e, ddt_g)
    # (T_hw_out_C, T_cw_out_C, q_hw_kW, ddt_e, ddt_g) = tuple(*sympy.linsolve(eq_sys, unknown_variables))

    # a = np.array([
    #     [0, 0, 0, s_e, 0],
    #     [0, 0, -1, 0, s_g],
    #     [-1, 0, -1 / mcp_hw_kWperK, 0, 0],
    #     [0.5, 0, 0, -1, 0],
    #     [0.5, 0, 0, 0, -1]])
    # b = np.array([
    #     [q_chw_kW - r_e],
    #     [-r_g],
    #     [-T_hw_in_C],
    #     [-0.5 * T_hw_in_C - 0.5 * e_e * (T_chw_in_C + T_chw_out_C)],
    #     [-0.5 * T_hw_in_C - 0.5 * e_g * (T_chw_in_C + T_chw_out_C)]])

    # the below equation for q_hw_kW was created with sympy.linsolve using symbols for all the variables.
    q_hw_kW = ((r_g * s_e * (0.5 * a_e * mcp_hw_kWperK + 0.25 * s_g * (a_e - a_g)) + s_g * (
                0.5 * a_g * mcp_hw_kWperK * (q_chw_kW - r_e) + s_e * (0.5 * mcp_hw_kWperK * (a_e * (
                    0.5 * T_chw_in_C * e_g + 0.5 * T_chw_out_C * e_g + 0.5 * T_cw_in_C * a_g + 1.0 * T_hw_in_C) - a_g * (
                                                                                                         0.5 * T_chw_in_C * e_e + 0.5 * T_chw_out_C * e_e + 0.5 * T_cw_in_C * a_e + 1.0 * T_hw_in_C)) - 0.25 * r_g * (
                                                                                  a_e - a_g)))) / (
                           s_e * (0.5 * a_e * mcp_hw_kWperK + 0.25 * s_g * (a_e - a_g))))

    # calculate results
    q_cw_kW = q_hw_kW + q_chw_kW  # Q(condenser) + Q(absorber)
    T_hw_out_C = T_hw_in_C - q_hw_kW / mcp_hw_kWperK
    T_cw_out_C = T_cw_in_C + q_cw_kW / mcp_cw_kWperK  # TODO: set upper bound of the chiller operation

    return {'T_hw_out_C': T_hw_out_C,
            'T_cw_out_C': T_cw_out_C,
            'q_chw_W': q_chw_kW * 1000,
            'q_hw_W': q_hw_kW * 1000,
            'q_cw_W': q_cw_kW * 1000}

{'fraction_non_alphanumeric': 0.09039484946596703, 'fraction_numerical': 0.01644895984518626, 'mean_word_length': 3.3015847606851287, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 11, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6598088', 'n_tokens_mistral': 10561, 'n_tokens_neox': 10039, 'n_words': 2397}