r'''Calculates the outer diameter of a tube bundle containing a specified
    number of tubes.
    The tube count is effected by the pitch, number of tube passes, and angle.
    
    The result is an exact number of tubes and is calculated by a very accurate
    method using number theory by default. This method is available only up to
    100,000 tubes.
    
    Parameters
    ----------
    N : int
        Total number of tubes that fit in the heat exchanger, [-]
    Do : float
        Tube outer diameter, [m]
    pitch : float
        Pitch; distance between two orthogonal tube centers, [m]
    Ntp : int, optional
        Number of tube passes, [-]
    angle : float, optional
        The angle the tubes are positioned; 30, 45, 60 or 90, [degrees]

    Returns
    -------
    DBundle : float
        Outer diameter of tube bundle, [m]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to calculate the tube count

    Other Parameters
    ----------------
    Method : string, optional
        One of 'Phadkeb', 'HEDH', 'VDI' or 'Perry'
    AvailableMethods : bool, optional
        If True, function will consider which methods which can be used to
        calculate the tube count with the given inputs

    See Also
    --------
    Ntubes
    DBundle_for_Ntubes_Phadkeb
    D_for_Ntubes_VDI
    DBundle_for_Ntubes_HEDH
    
    Notes
    -----
    The 'Perry' method is solved with a numerical solver and is very unreliable.
    
    Examples
    --------
    >>> size_bundle_from_tubecount(N=1285, Do=0.025, pitch=0.03125)
    1.1985676402390355

def size_bundle_from_tubecount(N, Do, pitch, Ntp=1, angle=30, Method=None,
                               AvailableMethods=False):
    r'''Calculates the outer diameter of a tube bundle containing a specified
    number of tubes.
    The tube count is effected by the pitch, number of tube passes, and angle.
    
    The result is an exact number of tubes and is calculated by a very accurate
    method using number theory by default. This method is available only up to
    100,000 tubes.
    
    Parameters
    ----------
    N : int
        Total number of tubes that fit in the heat exchanger, [-]
    Do : float
        Tube outer diameter, [m]
    pitch : float
        Pitch; distance between two orthogonal tube centers, [m]
    Ntp : int, optional
        Number of tube passes, [-]
    angle : float, optional
        The angle the tubes are positioned; 30, 45, 60 or 90, [degrees]

    Returns
    -------
    DBundle : float
        Outer diameter of tube bundle, [m]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to calculate the tube count

    Other Parameters
    ----------------
    Method : string, optional
        One of 'Phadkeb', 'HEDH', 'VDI' or 'Perry'
    AvailableMethods : bool, optional
        If True, function will consider which methods which can be used to
        calculate the tube count with the given inputs

    See Also
    --------
    Ntubes
    DBundle_for_Ntubes_Phadkeb
    D_for_Ntubes_VDI
    DBundle_for_Ntubes_HEDH
    
    Notes
    -----
    The 'Perry' method is solved with a numerical solver and is very unreliable.
    
    Examples
    --------
    >>> size_bundle_from_tubecount(N=1285, Do=0.025, pitch=0.03125)
    1.1985676402390355
    '''
    def list_methods():
        methods = ['Phadkeb']
        if Ntp == 1:
            methods.append('HEDH')
        if Ntp in [1, 2, 4, 8]:
            methods.append('VDI')
        if Ntp in [1, 2, 4, 6]:
             # Also restricted to 1.25 pitch ratio but not hard coded
            methods.append('Perry')
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = 'Phadkeb'
        
    if Method == 'Phadkeb':
        return DBundle_for_Ntubes_Phadkeb(Ntubes=N, Ntp=Ntp, Do=Do, pitch=pitch, angle=angle)
    elif Method == 'VDI':
        return D_for_Ntubes_VDI(N=N, Ntp=Ntp, Do=Do, pitch=pitch, angle=angle)
    elif Method == 'HEDH':
        return DBundle_for_Ntubes_HEDH(N=N, Do=Do, pitch=pitch, angle=angle)
    elif Method == 'Perry':
        to_solve = lambda D : Ntubes_Perrys(DBundle=D, Do=Do, Ntp=Ntp, angle=angle) - N
        return ridder(to_solve, Do*5, 1000*Do)
    else:
        raise Exception('Method not recognized; allowable methods are '
                        '"Phadkeb", "HEDH", "VDI", and "Perry"')