def isothermal_gas(rho, fd, P1=None, P2=None, L=None, D=None, m=None):
    r'''Calculation function for dealing with flow of a compressible gas in a
    pipeline for the complete isothermal flow equation. Can calculate any of
    the following, given all other inputs:

    * Mass flow rate
    * Upstream pressure (numerical)
    * Downstream pressure (analytical or numerical if an overflow occurs)
    * Diameter of pipe (numerical)
    * Length of pipe

    A variety of forms of this equation have been presented, differing in their
    use of the ideal gas law and choice of gas constant. The form here uses
    density explicitly, allowing for non-ideal values to be used.

    .. math::
        \dot m^2 = \frac{\left(\frac{\pi D^2}{4}\right)^2 \rho_{avg}
        \left(P_1^2-P_2^2\right)}{P_1\left(f_d\frac{L}{D} + 2\ln\frac{P_1}{P_2}
        \right)}

    Parameters
    ----------
    rho : float
        Average density of gas in pipe, [kg/m^3]
    fd : float
        Darcy friction factor for flow in pipe [-]
    P1 : float, optional
        Inlet pressure to pipe, [Pa]
    P2 : float, optional
        Outlet pressure from pipe, [Pa]
    L : float, optional
        Length of pipe, [m]
    D : float, optional
        Diameter of pipe, [m]
    m : float, optional
        Mass flow rate of gas through pipe, [kg/s]

    Returns
    -------
    m, P1, P2, D, or L : float
        The missing input which was solved for [base SI]

    Notes
    -----
    The solution for P2 has the following closed form, derived using Maple:

    .. math::
        P_2={P_1 \left( {{ e}^{0.5\cdot{\frac {1}{{m}^{2}} \left( -C{m}^{2}
        +\text{ lambertW} \left(-{\frac {BP_1}{{m}^{2}}{{ e}^{-{\frac {-C{m}^{
        2}+BP_1}{{m}^{2}}}}}}\right){}{m}^{2}+BP_1 \right) }}} \right) ^{-1}}

    .. math::
       B = \frac{\pi^2 D^4}{4^2} \rho_{avg}

    .. math::
       C = f_d \frac{L}{D}

    A wide range of conditions are impossible due to choked flow. See
    `P_isothermal_critical_flow` for details. An exception is raised when
    they occur.

    The 2 multiplied by the logarithm is often shown  as a power of the
    pressure ratio; this is only the case when the pressure ratio is raised to
    the power of 2 before its logarithm is taken.
    
    A number of limitations exist for this model:
        
        * Density dependence is that of an ideal gas.
        * If calculating the pressure drop, the average gas density cannot
          be known immediately; iteration must be used to correct this.
        * The friction factor depends on both the gas density and velocity,
          so it should be solved for iteratively as well. It changes throughout
          the pipe as the gas expands and velocity increases.
        * The model is not easily adapted to include elevation effects due to 
          the acceleration term included in it.
        * As the gas expands, it will change temperature slightly, further
          altering the density and friction factor.
         
    There are many commercial packages which perform the actual direct 
    integration of the flow, such as OLGA Dynamic Multiphase Flow Simulator,
    or ASPEN Hydraulics.
    
    This expression has also been presented with the ideal gas assumption
    directly incorporated into it [4]_ (note R is the specific gas constant, in 
    units of J/kg/K):
        
    .. math::
        \dot m^2 = \frac{\left(\frac{\pi D^2}{4}\right)^2
        \left(P_1^2-P_2^2\right)}{RT\left(f_d\frac{L}{D} + 2\ln\frac{P_1}{P_2}
        \right)}

    Examples
    --------
    >>> isothermal_gas(rho=11.3, fd=0.00185, P1=1E6, P2=9E5, L=1000, D=0.5)
    145.4847572636031

    References
    ----------
    .. [1] Crane Co. Flow of Fluids Through Valves, Fittings, and Pipe. Crane,
       2009.
    .. [2] Kim, J. and Singh, N. "A Novel Equation for Isothermal Pipe Flow.".
       Chemical Engineering, June 2012, http://www.chemengonline.com/a-novel-equation-for-isothermal-pipe-flow/?printmode=1
    .. [3] Wilkes, James O. Fluid Mechanics for Chemical Engineers with
       Microfluidics and CFD. 2 edition. Upper Saddle River, NJ: Prentice Hall,
       2005.
    .. [4] Rennels, Donald C., and Hobart M. Hudson. Pipe Flow: A Practical
       and Comprehensive Guide. 1st edition. Hoboken, N.J: Wiley, 2012.
    '''
    if m is None and (None not in [P1, P2, L, D]):
        Pcf = P_isothermal_critical_flow(P=P1, fd=fd, D=D, L=L)
        if P2 < Pcf:
            raise Exception('Given outlet pressure is not physically possible \
due to the formation of choked flow at P2=%f, specified outlet pressure was %f' % (Pcf, P2))
        if P2 > P1:
            raise Exception('Specified outlet pressure is larger than the \
inlet pressure; fluid will flow backwards.')
        return (0.0625*pi*pi*D**4*rho/(P1*(fd*L/D + 2.0*log(P1/P2)))*(P1*P1 - P2*P2))**0.5
    elif L is None and (None not in [P1, P2, D, m]):
        return D*(pi*pi*D**4*rho*(P1*P1 - P2*P2) - 32.0*P1*m*m*log(P1/P2))/(16.0*P1*fd*m*m)
    elif P1 is None and (None not in [L, P2, D, m]):
        Pcf = P_upstream_isothermal_critical_flow(P=P2, fd=fd, D=D, L=L)

        def to_solve(P1):
            return m - isothermal_gas(rho, fd, P1=P1, P2=P2, L=L, D=D)
        try:
            # Use the explicit solution for P2 with different P1 guesses;
            # newton doesn't like solving for m.
            def to_solve_P2_basis(P1):
                return abs(P2 - isothermal_gas(rho, fd, m=m, P1=P1, P2=None, L=L, D=D))
            P1 = newton(to_solve_P2_basis, (P2+Pcf)/2.)
            assert P2 <= P1
            return P1
        except:
            try:
                return ridder(to_solve, a=P2, b=Pcf)
            except:
                m_max = isothermal_gas(rho, fd, P1=Pcf, P2=P2, L=L, D=D)
                raise Exception('The desired mass flow rate of %f kg/s cannot '
'be achieved with the specified downstream pressure; the maximum flowrate is '
'%f kg/s at an upstream pressure of %f Pa' %(m, m_max, Pcf))
    elif P2 is None and (None not in [L, P1, D, m]):
        try:
            Pcf = P_isothermal_critical_flow(P=P1, fd=fd, D=D, L=L)
            m_max = isothermal_gas(rho, fd, P1=P1, P2=Pcf, L=L, D=D)
            assert m <= m_max

            C = fd*L/D
            B = (pi/4*D**2)**2*rho
            arg = -B/m**2*P1*exp(-(-C*m**2+B*P1)/m**2)
            # Consider the two real branches of the lambertw function.
            # The k=-1 branch produces the higher P2 values; the k=0 branch is
            # physically impossible.
            lambert_ans = float(lambertw(arg, k=-1).real)
            # Large overflow problem here; also divide by zero problems!
            # Fail and try a numerical solution if it doesn't work.
            assert not math.isinf(lambert_ans)
            P2 = P1/exp((-C*m**2+lambert_ans*m**2+B*P1)/m**2/2.)
            assert P2 < P1
            return P2
        except:
            Pcf = P_isothermal_critical_flow(P=P1, fd=fd, D=D, L=L)
            def to_solve(P2):
                return m - isothermal_gas(rho, fd, P1=P1, P2=P2, L=L, D=D)
#                return abs(m - isothermal_gas(rho, fd, P1=P1, P2=P2, L=L, D=D))
#            return fminbound(to_solve, x1=Pcf, x2=P1)
            try:
                return ridder(to_solve, a=Pcf, b=P1)
#                m_max = isothermal_gas(rho, fd, P1=P1, P2=Pcf, L=L, D=D)
#                assert m < m_max
#                assert P > Pcv
#                return m
            except:
                m_max = isothermal_gas(rho, fd, P1=P1, P2=Pcf, L=L, D=D)
                raise Exception('The desired mass flow rate cannot be achieved '
'with the specified upstream pressure of %f Pa; the maximum flowrate is %f '
'kg/s at a downstream pressure of %f' %(P1, m_max, Pcf))
            # A solver which respects its boundaries is required here.
            # ridder cuts the time down from 2 ms to 200 mircoseconds.
            # Is is believed Pcf and P1 will always bracked the root, however
            # leave the commented code for testing
    elif D is None and (None not in [P2, P1, L, m]):
        def to_solve(D):
            return m - isothermal_gas(rho, fd, P1=P1, P2=P2, L=L, D=D)
        return newton(to_solve, 0.1)
    else:
        raise Exception('This function solves for either mass flow, upstream \
pressure, downstream pressure, diameter, or length; all other inputs \
must be provided.')