r'''Returns the number of transfer units of a TEMA G type heat exchanger
    with a specified (for side 1) thermal effectiveness `P1`, heat capacity 
    ratio `R1`, the number of tube passes `Ntp`, and for the two-pass case
    whether or not the inlets are arranged optimally. The supported cases are 
    as follows:
        
    * One tube pass (tube fluid split into two streams individually mixed,  
      shell fluid mixed)
    * Two tube passes (shell and tube exchanger with shell and tube fluids  
      mixed in each pass at the cross section), counterflow arrangement
    * Two tube passes (shell and tube exchanger with shell and tube fluids  
      mixed in each pass at the cross section), parallelflow arrangement
                
    Parameters
    ----------
    P1 : float
        Thermal effectiveness of the heat exchanger in the P-NTU method,
        calculated with respect to stream 1 [-]
    R1 : float
        Heat capacity ratio of the heat exchanger in the P-NTU method,
        calculated with respect to stream 1 (shell side = 1, tube side = 2) [-]
    Ntp : int
        Number of tube passes, 1 or 2 [-]
    optimal : bool, optional
        Whether or not the arrangement is configured to give more of a
        countercurrent and efficient (True) case or an inefficient parallel
        case (only applies for two passes), [-]

    Returns
    -------
    NTU1 : float
        Thermal number of transfer units of the heat exchanger in the P-NTU 
        method, calculated with respect to stream 1 (shell side = 1, tube side
        = 2) [-]

    Notes
    -----
    For numbers of tube passes greater than 1 or 2, an exception is raised.
    
    Although this function allows the thermal effectiveness desired to be
    specified, it does not mean such a high value can be obtained. An exception
    is raised which shows the maximum possible effectiveness obtainable at the
    specified `R1` and configuration.
    
    >>> NTU_from_P_G(P1=1, R1=1/3., Ntp=2)
    Traceback (most recent call last):
    ValueError: No solution possible gives such a high P1; maximum P1=0.954545 at NTU1=10000.000000
    
    Of the three configurations, 1 pass and the optimal 2 pass have monotonic 
    functions which allow for a bounded solver to work smoothly. In both cases
    a solution is searched for between NTU1 values of 1E-11 and 1E-4.
    
    For the 2 pass unoptimal solution, a bounded solver is first use, but
    the upper bound on P1 and the upper NTU1 limit is calculated from a pade
    approximation performed with mpmath. 

    Examples
    --------
    >>> NTU_from_P_G(P1=.573, R1=1/3., Ntp=1)
    0.9999513707769526

def NTU_from_P_G(P1, R1, Ntp, optimal=True):
    r'''Returns the number of transfer units of a TEMA G type heat exchanger
    with a specified (for side 1) thermal effectiveness `P1`, heat capacity 
    ratio `R1`, the number of tube passes `Ntp`, and for the two-pass case
    whether or not the inlets are arranged optimally. The supported cases are 
    as follows:
        
    * One tube pass (tube fluid split into two streams individually mixed,  
      shell fluid mixed)
    * Two tube passes (shell and tube exchanger with shell and tube fluids  
      mixed in each pass at the cross section), counterflow arrangement
    * Two tube passes (shell and tube exchanger with shell and tube fluids  
      mixed in each pass at the cross section), parallelflow arrangement
                
    Parameters
    ----------
    P1 : float
        Thermal effectiveness of the heat exchanger in the P-NTU method,
        calculated with respect to stream 1 [-]
    R1 : float
        Heat capacity ratio of the heat exchanger in the P-NTU method,
        calculated with respect to stream 1 (shell side = 1, tube side = 2) [-]
    Ntp : int
        Number of tube passes, 1 or 2 [-]
    optimal : bool, optional
        Whether or not the arrangement is configured to give more of a
        countercurrent and efficient (True) case or an inefficient parallel
        case (only applies for two passes), [-]

    Returns
    -------
    NTU1 : float
        Thermal number of transfer units of the heat exchanger in the P-NTU 
        method, calculated with respect to stream 1 (shell side = 1, tube side
        = 2) [-]

    Notes
    -----
    For numbers of tube passes greater than 1 or 2, an exception is raised.
    
    Although this function allows the thermal effectiveness desired to be
    specified, it does not mean such a high value can be obtained. An exception
    is raised which shows the maximum possible effectiveness obtainable at the
    specified `R1` and configuration.
    
    >>> NTU_from_P_G(P1=1, R1=1/3., Ntp=2)
    Traceback (most recent call last):
    ValueError: No solution possible gives such a high P1; maximum P1=0.954545 at NTU1=10000.000000
    
    Of the three configurations, 1 pass and the optimal 2 pass have monotonic 
    functions which allow for a bounded solver to work smoothly. In both cases
    a solution is searched for between NTU1 values of 1E-11 and 1E-4.
    
    For the 2 pass unoptimal solution, a bounded solver is first use, but
    the upper bound on P1 and the upper NTU1 limit is calculated from a pade
    approximation performed with mpmath. 

    Examples
    --------
    >>> NTU_from_P_G(P1=.573, R1=1/3., Ntp=1)
    0.9999513707769526
    '''
    NTU_min = 1E-11
    function = temperature_effectiveness_TEMA_G
    if Ntp == 1 or (Ntp == 2 and optimal):
        NTU_max = 1E4
        # We could fit a curve to determine the NTU where the floating point
        # does not allow NTU to increase though, but that would be another
        # binary bisection process, different from the current pipeline
    elif Ntp == 2 and not optimal:
        NTU_max = _NTU_max_for_P_solver(NTU_from_G_2_unoptimal, R1)
    else:
        raise Exception('Supported numbers of tube passes are 1 or 2.')
    return _NTU_from_P_solver(P1, R1, NTU_min, NTU_max, function, Ntp=Ntp, optimal=optimal)