using System;

namespace FluidSim.Core
{
    /// <summary>
    /// Compressible flow through an orifice, modelled as an isentropic nozzle.
    /// The caller provides the upstream stagnation state (pUp, rhoUp, TUp),
    /// downstream pressure, orifice area, discharge coefficient, and gas properties.
    /// Returns the face state and mass flow from upstream to downstream.
    /// </summary>
    public static class IsentropicOrifice
    {
        public static void Compute(
            double pUp, double rhoUp, double TUp,  // upstream stagnation
            double pDown,                           // downstream back pressure
            double gamma, double R, double area, double Cd,
            out double mdot, out double rhoFace, out double uFace, out double pFace)
        {
            mdot = 0; rhoFace = rhoUp; uFace = 0; pFace = pUp;

            if (area <= 0 || pUp <= 0 || rhoUp <= 0 || TUp <= 0)
                return;

            double pr = pDown / pUp;
            if (pr < 1e-6) pr = 1e-6;

            double prCrit = Math.Pow(2.0 / (gamma + 1.0), gamma / (gamma - 1.0));
            if (pr < prCrit) pr = prCrit;   // choked flow

            double exponent = (gamma - 1.0) / gamma;
            double M = Math.Sqrt((2.0 / (gamma - 1.0)) * (Math.Pow(pr, -exponent) - 1.0));
            if (double.IsNaN(M)) M = 0;

            double aUp = Math.Sqrt(gamma * R * TUp);
            uFace = M * aUp;
            rhoFace = rhoUp * Math.Pow(pr, 1.0 / gamma);
            pFace = pUp * pr;
            mdot = rhoFace * uFace * area * Cd;    // positive from upstream to downstream
        }
    }
}