def NTU_from_P_basic(P1, R1, subtype='crossflow'):
    r'''Returns the number of transfer units of a basic heat exchanger type
    with a specified (for side 1) thermal effectiveness `P1`, and heat capacity 
    ratio `R1`. The supported cases are as follows:
        
    * Counterflow (ex. double-pipe) [analytical]
    * Parallel (ex. double pipe inefficient configuration) [analytical]
    * Crossflow, single pass, fluids unmixed [numerical]
    * Crossflow, single pass, fluid 1 mixed, fluid 2 unmixed [analytical]
    * Crossflow, single pass, fluid 2 mixed, fluid 1 unmixed [analytical]
    * Crossflow, single pass, both fluids mixed [numerical]
    
    The analytical solutions, for those cases they are available, are as 
    follows:
        
    Counterflow:
        
    .. math::
        NTU_1 = - \frac{1}{R_{1} - 1} \log{\left (\frac{P_{1} R_{1} - 1}{P_{1} 
        - 1} \right )}
    
    Parallel:
    
    .. math::
        NTU_1 = \frac{1}{R_{1} + 1} \log{\left (- \frac{1}{P_{1} \left(R_{1} 
        + 1\right) - 1} \right )}
    
    Crossflow, single pass, fluid 1 mixed, fluid 2 unmixed:
        
    .. math::
        NTU_1 = - \frac{1}{R_{1}} \log{\left (R_{1} \log{\left (- \left(P_{1}
        - 1\right) e^{\frac{1}{R_{1}}} \right )} \right )}
    
    Crossflow, single pass, fluid 2 mixed, fluid 1 unmixed
    
    .. math::
        NTU_1 = - \log{\left (\frac{1}{R_{1}} \log{\left (- \left(P_{1} R_{1}
        - 1\right) e^{R_{1}} \right )} \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 [-]
    subtype : float
        The type of heat exchanger; one of 'counterflow', 'parallel', 
        'crossflow', 'crossflow approximate', 'crossflow, mixed 1', 
        'crossflow, mixed 2', 'crossflow, mixed 1&2'.
        
    Returns
    -------
    NTU1 : float
        Thermal number of transfer units of the heat exchanger in the P-NTU 
        method, calculated with respect to stream 1 [-]

    Notes
    -----
    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 when this occurs, although not always a helpful one.
    
    >>> NTU_from_P_basic(P1=.99, R1=.1, subtype='parallel')
    Traceback (most recent call last):
    ValueError: math domain error
            
    For the 'crossflow approximate' solution the function is monotonic, and a
    bounded solver is used within the range of NTU1 from 1E-11 to 1E5. 
    
    For the full correct 'crossflow' solution, the initial guess for newton's
    method is obtained by the 'crossflow approximate' solution; the function
    may not converge because of inaccuracy performing the numerical integral 
    involved.

    For the 'crossflow, mixed 1&2' 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_basic(P1=.975, R1=.1, subtype='counterflow')
    3.984769850376482
    '''
    NTU_min = 1E-11
    function = temperature_effectiveness_basic
    if subtype == 'counterflow':
        return -log((P1*R1 - 1.)/(P1 - 1.))/(R1 - 1.)
    elif subtype == 'parallel':
        return log(-1./(P1*(R1 + 1.) - 1.))/(R1 + 1.)
    elif subtype == 'crossflow, mixed 1':
        return -log(R1*log(-(P1 - 1.)*exp(1./R1)))/R1
    elif subtype == 'crossflow, mixed 2':
        return -log(log(-(P1*R1 - 1.)*exp(R1))/R1)
    elif subtype == 'crossflow, mixed 1&2':
        NTU_max = _NTU_max_for_P_solver(NTU_from_P_basic_crossflow_mixed_12, R1)        
    elif subtype == 'crossflow approximate':
        # These are tricky but also easy because P1 can always be 1
        NTU_max = 1E5
    elif subtype == 'crossflow':
        guess = NTU_from_P_basic(P1, R1, subtype='crossflow approximate')
        to_solve = lambda NTU1 : _NTU_from_P_objective(NTU1, R1, P1, function, subtype='crossflow')
        return newton(to_solve, guess)
    else:
        raise Exception('Subtype not recognized.')
    return _NTU_from_P_solver(P1, R1, NTU_min, NTU_max, function, subtype=subtype)