r'''Returns the number of transfer units of a TEMA E 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:
        
    * 1-1 TEMA E, shell fluid mixed
    * 1-2 TEMA E, shell fluid mixed (this configuration is symmetric)
    * 1-2 TEMA E, shell fluid split into two steams individually mixed
    * 1-3 TEMA E, shell and tube fluids mixed, one parallel pass and two 
      counterflow passes (efficient)
    * 1-3 TEMA E, shell and tube fluids mixed, two parallel passes and one 
      counteflow pass (inefficient)
    * 1-N TEMA E, shall and tube fluids mixed, efficient counterflow 
      orientation, N an even number
      
    Two of these cases have analytical solutions; the rest use numerical 
    solvers of varying quality.
    
    The analytical solution to 1-1 TEMA E, shell fluid mixed (the same as pure
    counterflow):
        
    .. math::
        NTU_1 = - \frac{1}{R_{1} - 1} \log{\left (\frac{P_{1} R_{1} - 1}{P_{1} 
        - 1} \right )}
    
    1-2 TEMA E, shell fluid mixed:
        
    .. math::
        NTU_1 = \frac{2}{\sqrt{R_{1}^{2} + 1}} \log{\left (\sqrt{\frac{P_{1} 
        R_{1} - P_{1} \sqrt{R_{1}^{2} + 1} + P_{1} - 2}{P_{1} R_{1} + P_{1} 
        \sqrt{R_{1}^{2} + 1} + P_{1} - 2}} \right )}
        
    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, 2, 3, 4, or an even number [-]
    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, [-]

    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 odd numbers of tube passes greater than 3, an exception is raised. 
    
    For the 2 pass, unoptimal case, a bounded solver is used with NTU1 between
    1E-11 and 100; the solution to any feasible P1 was found to lie in there.
    For the 4 or a higher even number of pass case, the upper limit on NTU1
    is 1000; this solver works pretty well, but as NTU1 reaches its limit the
    change in P1 is so small a smaller but also correct solution is often 
    returned.
    
    For both the optimal and unoptimal 3 tube pass case, a solution is only
    returned if NTU1 is between 1E-11 and 10. These functions are extremely
    mathematically frustrating, and as NTU1 rises above 10 catastrophic 
    cancellation quickly results in this expression finding a ZeroDivisionError.
    The use of arbitrary prevision helps little - quickly 1000 digits are needed,
    and then 1000000 digits, and so one. Using SymPy's rational number support
    works better but is extremely slow for these complicated solutions.
    Nevertheless, so long as a solution is between 1E-11 and 10, the solver is
    quite robust.

    Examples
    --------
    >>> NTU_from_P_E(P1=.58, R1=1/3., Ntp=2)
    1.0381979240816719

def NTU_from_P_E(P1, R1, Ntp, optimal=True):
    r'''Returns the number of transfer units of a TEMA E 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:
        
    * 1-1 TEMA E, shell fluid mixed
    * 1-2 TEMA E, shell fluid mixed (this configuration is symmetric)
    * 1-2 TEMA E, shell fluid split into two steams individually mixed
    * 1-3 TEMA E, shell and tube fluids mixed, one parallel pass and two 
      counterflow passes (efficient)
    * 1-3 TEMA E, shell and tube fluids mixed, two parallel passes and one 
      counteflow pass (inefficient)
    * 1-N TEMA E, shall and tube fluids mixed, efficient counterflow 
      orientation, N an even number
      
    Two of these cases have analytical solutions; the rest use numerical 
    solvers of varying quality.
    
    The analytical solution to 1-1 TEMA E, shell fluid mixed (the same as pure
    counterflow):
        
    .. math::
        NTU_1 = - \frac{1}{R_{1} - 1} \log{\left (\frac{P_{1} R_{1} - 1}{P_{1} 
        - 1} \right )}
    
    1-2 TEMA E, shell fluid mixed:
        
    .. math::
        NTU_1 = \frac{2}{\sqrt{R_{1}^{2} + 1}} \log{\left (\sqrt{\frac{P_{1} 
        R_{1} - P_{1} \sqrt{R_{1}^{2} + 1} + P_{1} - 2}{P_{1} R_{1} + P_{1} 
        \sqrt{R_{1}^{2} + 1} + P_{1} - 2}} \right )}
        
    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, 2, 3, 4, or an even number [-]
    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, [-]

    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 odd numbers of tube passes greater than 3, an exception is raised. 
    
    For the 2 pass, unoptimal case, a bounded solver is used with NTU1 between
    1E-11 and 100; the solution to any feasible P1 was found to lie in there.
    For the 4 or a higher even number of pass case, the upper limit on NTU1
    is 1000; this solver works pretty well, but as NTU1 reaches its limit the
    change in P1 is so small a smaller but also correct solution is often 
    returned.
    
    For both the optimal and unoptimal 3 tube pass case, a solution is only
    returned if NTU1 is between 1E-11 and 10. These functions are extremely
    mathematically frustrating, and as NTU1 rises above 10 catastrophic 
    cancellation quickly results in this expression finding a ZeroDivisionError.
    The use of arbitrary prevision helps little - quickly 1000 digits are needed,
    and then 1000000 digits, and so one. Using SymPy's rational number support
    works better but is extremely slow for these complicated solutions.
    Nevertheless, so long as a solution is between 1E-11 and 10, the solver is
    quite robust.

    Examples
    --------
    >>> NTU_from_P_E(P1=.58, R1=1/3., Ntp=2)
    1.0381979240816719

    '''
    NTU_min = 1E-11
    function = temperature_effectiveness_TEMA_E
    if Ntp == 1:
        return NTU_from_P_basic(P1, R1, subtype='counterflow')
    elif Ntp == 2 and optimal:
        # Nice analytical solution is available
        # There are actualy two roots but one of them is complex
        x1 = R1*R1 + 1.
        return 2.*log(((P1*R1 - P1*x1**0.5 + P1 - 2.)/(P1*R1 + P1*x1**0.5 + P1 - 2.))**0.5)*(x1)**-.5
    elif Ntp == 2 and not optimal:
        NTU_max = 1E2 
        # Can't find anywhere it needs to go above 70 to reach the maximum
    elif Ntp == 3 and optimal:
        # no pade could be found, just about the worst-conditioned problem
        # I've ever found
        # Higher starting values result in errors
        NTU_max = 10
    elif Ntp == 3 and not optimal:
        # no pade could be found, just about the worst-conditioned problem
        # I've ever found
        NTU_max = 10
    elif Ntp == 4 or Ntp %2 == 0:
        NTU_max = 1E3
    else:
        raise Exception('For TEMA E shells with an odd number of tube passes more than 3, no solution is implemented.')
    return _NTU_from_P_solver(P1, R1, NTU_min, NTU_max, function, Ntp=Ntp, optimal=optimal)