def Ntubes_VDI(DBundle=None, Ntp=None, Do=None, pitch=None, angle=30.0):
    """A rough equation presented in the VDI Heat Atlas for estimating
    the number of tubes in a tube bundle of differing geometries and tube
    sizes. No accuracy estimation given.

    Parameters
    ----------
    DBundle : float
        Outer diameter of tube bundle, [m]
    Ntp : float
        Number of tube passes, [-]
    Do : float
        Tube outer diameter, [m]
    pitch : float
        Pitch; distance between two orthogonal tube centers, [m]
    angle : float
        The angle the tubes are positioned; 30, 45, 60 or 90, [degrees]

    Returns
    -------
    N : float
        Number of tubes, [-]

    Notes
    -----
    No coefficients for this method with Ntp=6 are available in [1]_. For
    consistency, estimated values were added to support 6 tube passes, f2 = 90..
    This equation is a rearranged form of that presented in [1]_.
    The calculated tube count is rounded down to an integer.

    Examples
    --------
    >>> Ntubes_VDI(DBundle=1.184, Ntp=2, Do=.028, pitch=.036, angle=30) 
    966

    References
    ----------
    .. [1] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.
       Berlin; New York:: Springer, 2010.
    """
    if Ntp == 1:
        f2 = 0.0
    elif Ntp == 2:
        f2 = 22.0
    elif Ntp == 4:
        f2 = 70.0
    elif Ntp == 8:
        f2 = 105.0
    elif Ntp == 6:
        f2 = 90.0
    else:
        raise Exception('Only 1, 2, 4 and 8 passes are supported')
    if angle == 30 or angle == 60:
        f1 = 1.1
    elif angle == 45 or angle == 90:
        f1 = 1.3
    else:
        raise Exception('Only 30, 60, 45 and 90 degree layouts are supported')
    DBundle, Do, pitch = DBundle * 1000, Do * 1000, pitch * 1000
    t = pitch
    Ntubes = (-(-4 * f1 * t ** 4 * f2 ** 2 * Do + 4 * f1 * t ** 4 * f2 ** 2 *
        DBundle ** 2 + t ** 4 * f2 ** 4) ** 0.5 - 2 * f1 * t ** 2 * Do + 2 *
        f1 * t ** 2 * DBundle ** 2 + t ** 2 * f2 ** 2) / (2 * f1 ** 2 * t ** 4)
    return int(Ntubes)
