"""
MikoshiLang Extended Functions - Set 20
Fluid dynamics, computational fluid dynamics, and computational physics
"""
import sympy as sp
from sympy import symbols, sqrt, sin, cos, exp, log, pi

def get_rules():
    """Extended set 20: Fluid dynamics and computational physics (200 functions)"""
    x, y, z, t, rho, v, p = symbols('x y z t rho v p')
    
    return [
        # ===== FLUID DYNAMICS (60 functions) =====
        ('ContinuityEquation[rho_, v_]', lambda rho, v: sp.diff(rho, sp.Symbol('t')) + sp.diff(rho*v, sp.Symbol('x'))),
        ('MomentumEquation[rho_, v_, p_]', lambda rho, v, p: rho*sp.diff(v, sp.Symbol('t')) + rho*v*sp.diff(v, sp.Symbol('x')) + sp.diff(p, sp.Symbol('x'))),
        ('EulerEquation[rho_, v_, p_]', lambda rho, v, p: rho*(sp.diff(v, sp.Symbol('t')) + v*sp.diff(v, sp.Symbol('x'))) + sp.diff(p, sp.Symbol('x'))),
        ('NavierStokesEquation[v_, p_, mu_]', lambda v, p, mu: sp.diff(v, sp.Symbol('t')) + v*sp.diff(v, sp.Symbol('x')) - sp.diff(p, sp.Symbol('x'))/sp.Symbol('rho') + mu*sp.diff(v, sp.Symbol('x'), 2)),
        ('BernoulliEquation[p_, rho_, v_, h_]', lambda p, rho, v, h: p + sp.Rational(1,2)*rho*v**2 + rho*sp.Symbol('g')*h),
        ('DynamicPressure[rho_, v_]', lambda rho, v: sp.Rational(1,2)*rho*v**2),
        ('StaticPressure[total_, dynamic_]', lambda tot, dyn: tot - dyn),
        ('TotalPressure[static_, dynamic_]', lambda stat, dyn: stat + dyn),
        ('StagnationPressure[p_, rho_, v_]', lambda p, rho, v: p + sp.Rational(1,2)*rho*v**2),
        ('VelocityHead[v_, g_]', lambda v, g: v**2/(2*g)),
        ('PressureHead[p_, rho_, g_]', lambda p, rho, g: p/(rho*g)),
        ('ElevationHead[h_]', lambda h: h),
        ('HydraulicGradient[h1_, h2_, L_]', lambda h1, h2, L: (h1 - h2)/L),
        ('DarcyWeisbach[f_, L_, D_, v_, g_]', lambda f, L, D, v, g: f*L*v**2/(D*2*g)),
        ('HagenPoiseuille[mu_, L_, Q_, r_]', lambda mu, L, Q, r: 8*mu*L*Q/(pi*r**4)),
        ('ReynoldsNumberFluid[rho_, v_, L_, mu_]', lambda rho, v, L, mu: rho*v*L/mu),
        ('FroudeNumber[v_, g_, L_]', lambda v, g, L: v/sqrt(g*L)),
        ('WeberNumber[rho_, v_, L_, sigma_]', lambda rho, v, L, sig: rho*v**2*L/sig),
        ('CapillaryNumber[mu_, v_, sigma_]', lambda mu, v, sig: mu*v/sig),
        ('BondNumber[rho_, g_, L_, sigma_]', lambda rho, g, L, sig: rho*g*L**2/sig),
        ('EotvosNumber[rho_, g_, L_, sigma_]', lambda rho, g, L, sig: rho*g*L**2/sig),  # Same as Bond
        ('GrashofNumberFluid[g_, beta_, delta_T_, L_, nu_]', lambda g, beta, dT, L, nu: g*beta*dT*L**3/nu**2),
        ('RayleighNumberFluid[Gr_, Pr_]', lambda Gr, Pr: Gr*Pr),
        ('PrandtlNumberFluid[cp_, mu_, k_]', lambda cp, mu, k: cp*mu/k),
        ('SchmidtNumber[mu_, rho_, D_]', lambda mu, rho, D: mu/(rho*D)),
        ('SherwoodNumber[k_, L_, D_]', lambda k, L, D: k*L/D),
        ('PecletNumber[v_, L_, alpha_]', lambda v, L, alpha: v*L/alpha),
        ('StantonNumber[h_, rho_, v_, cp_]', lambda h, rho, v, cp: h/(rho*v*cp)),
        ('BiotNumber[h_, L_, k_]', lambda h, L, k: h*L/k),
        ('FourierNumber[alpha_, t_, L_]', lambda alpha, t, L: alpha*t/L**2),
        ('StrouhalNumber[f_, L_, v_]', lambda f, L, v: f*L/v),
        ('MachNumberFluid[v_, c_]', lambda v, c: v/c),
        ('KnudsenNumber[lambda_, L_]', lambda lam, L: lam/L),
        ('DeanNumber[Re_, R_, r_]', lambda Re, R, r: Re*sqrt(r/R)),
        ('RosbyNumber[v_, L_, omega_]', lambda v, L, omega: v/(L*omega)),
        ('EkmanNumber[nu_, L_, omega_]', lambda nu, L, omega: nu/(L**2*omega)),
        ('RichardsonNumber[g_, rho_, delta_rho_, v_, delta_z_]', lambda g, rho, drho, v, dz: g*drho*dz/(rho*v**2)),
        ('FrictionFactor[delta_p_, rho_, L_, D_, v_]', lambda dp, rho, L, D, v: dp*D/(sp.Rational(1,2)*rho*v**2*L)),
        ('MoodyDiagram[Re_, roughness_]', lambda Re, eps: 0.02),  # Simplified
        ('ColebrookEquation[epsilon_, D_, Re_]', lambda eps, D, Re: 1/sqrt(sp.Symbol('f')) == -2*log(eps/(3.7*D) + 2.51/(Re*sqrt(sp.Symbol('f'))))),
        ('SwameeFactor[epsilon_, D_, Re_]', lambda eps, D, Re: 0.25/(log(eps/(3.7*D) + 5.74/Re**0.9))**2),
        ('BlasisusEquation[Re_]', lambda Re: 0.316/Re**0.25),
        ('VonKarmanEquation[f_]', lambda f: 1/sqrt(f) == 2*log(Re*sqrt(f)) - 0.8),
        ('SkinFrictionCoefficient[tau_, rho_, v_]', lambda tau, rho, v: tau/(sp.Rational(1,2)*rho*v**2)),
        ('BoundaryLayerThickness[x_, Re_]', lambda x, Re: 5*x/sqrt(Re)),
        ('DisplacementThickness[u_, U_, y_]', lambda u, U, y: sp.integrate(1 - u/U, y)),
        ('MomentumThickness[u_, U_, y_]', lambda u, U, y: sp.integrate((u/U)*(1 - u/U), y)),
        ('ShapeFactorBoundaryLayer[delta_star_, theta_]', lambda dstar, theta: dstar/theta),
        ('LaminarBoundaryLayer[x_, Re_]', lambda x, Re: 5*x/sqrt(Re)),
        ('TurbulentBoundaryLayer[x_, Re_]', lambda x, Re: 0.37*x/Re**0.2),
        ('SeparationPointPrediction[pressure_gradient_]', lambda dp: dp > 0),
        ('VorticityMagnitude[omega_]', lambda omega: abs(omega)),
        ('CirculationKelvin[gamma_]', lambda gamma: gamma),
        ('StreamFunction[psi_]', lambda psi: psi),
        ('VelocityPotential[phi_]', lambda phi: phi),
        ('VorticityEquation[omega_, v_]', lambda omega, v: sp.diff(omega, sp.Symbol('t')) + v*sp.diff(omega, sp.Symbol('x'))),
        ('KelvinCirculationTheorem[gamma_]', lambda gamma: sp.diff(gamma, sp.Symbol('t'))),
        ('HelmholtzDecomposition[v_]', lambda v: (sp.Symbol('phi'), sp.Symbol('A'))),  # Potential + vector potential
        ('PoissonEquationPressure[rho_, v_]', lambda rho, v: sp.diff(sp.Symbol('p'), sp.Symbol('x'), 2)),
        ('LaplaceEquation[phi_]', lambda phi: sp.diff(phi, sp.Symbol('x'), 2) + sp.diff(phi, sp.Symbol('y'), 2)),
        ('WaveEquation[u_, c_]', lambda u, c: sp.diff(u, sp.Symbol('t'), 2) - c**2*sp.diff(u, sp.Symbol('x'), 2)),
        
        # ===== COMPUTATIONAL FLUID DYNAMICS (40 functions) =====
        ('FiniteDifferenceForward[f_, h_]', lambda f, h: (sp.Symbol('f(x+h)') - f)/h),
        ('FiniteDifferenceBackward[f_, h_]', lambda f, h: (f - sp.Symbol('f(x-h)'))/h),
        ('FiniteDifferenceCentral[f_, h_]', lambda f, h: (sp.Symbol('f(x+h)') - sp.Symbol('f(x-h)'))/(2*h)),
        ('SecondDerivativeFD[f_, h_]', lambda f, h: (sp.Symbol('f(x+h)') - 2*f + sp.Symbol('f(x-h)'))/h**2),
        ('UpwindScheme[v_, u_, dx_]', lambda v, u, dx: (u if v > 0 else sp.Symbol('u_next')) - u),
        ('LaxFriedrichs[u_, dx_, dt_]', lambda u, dx, dt: sp.Rational(1,2)*(sp.Symbol('u_left') + sp.Symbol('u_right')) - dt/(2*dx)*(sp.Symbol('F_right') - sp.Symbol('F_left'))),
        ('LaxWendroff[u_, dx_, dt_]', lambda u, dx, dt: u - dt/dx*(sp.Symbol('F_right') - sp.Symbol('F_left'))),
        ('MacCormackScheme[u_, F_, dx_, dt_]', lambda u, F, dx, dt: u - dt/dx*(sp.Symbol('F_pred') - F)),
        ('RungeKuttaFluid[u_, f_, dt_]', lambda u, f, dt: u + dt*f),  # RK1/Euler
        ('RungeKutta4Fluid[u_, f_, dt_]', lambda u, f, dt: u + dt/6*(sp.Symbol('k1') + 2*sp.Symbol('k2') + 2*sp.Symbol('k3') + sp.Symbol('k4'))),
        ('AdamsBashforth[u_, f_, dt_]', lambda u, f, dt: u + dt*(1.5*f - 0.5*sp.Symbol('f_prev'))),
        ('AdamsMoulton[u_, f_, dt_]', lambda u, f, dt: u + dt/2*(f + sp.Symbol('f_next'))),
        ('CrankNicolson[u_, alpha_, dx_, dt_]', lambda u, alpha, dx, dt: u + alpha*dt/(2*dx**2)*(sp.Symbol('u_xx_n') + sp.Symbol('u_xx_n1'))),
        ('ImplicitEuler[u_, f_, dt_]', lambda u, f, dt: u + dt*sp.Symbol('f_n1')),
        ('PredictorCorrector[u_, f_, dt_]', lambda u, f, dt: (u + dt*f, u + dt/2*(f + sp.Symbol('f_pred')))),
        ('CFLCondition[v_, dt_, dx_]', lambda v, dt, dx: v*dt/dx < 1),
        ('CourantNumber[v_, dt_, dx_]', lambda v, dt, dx: v*dt/dx),
        ('DiffusionNumber[alpha_, dt_, dx_]', lambda alpha, dt, dx: alpha*dt/dx**2),
        ('StabilityAnalysis[amplification_]', lambda amp: abs(amp) <= 1),
        ('VonNeumannStability[scheme_]', lambda s: s),
        ('LDUDecomposition[A_]', lambda A: (sp.Symbol('L'), sp.Symbol('D'), sp.Symbol('U'))),
        ('GaussSeidelIteration[A_, b_, x_]', lambda A, b, x: x),
        ('JacobiIteration[A_, b_, x_]', lambda A, b, x: x),
        ('SORIteration[A_, b_, x_, omega_]', lambda A, b, x, omega: x),
        ('ConjugateGradient[A_, b_]', lambda A, b: sp.Symbol('x')),
        ('BiCGSTAB[A_, b_]', lambda A, b: sp.Symbol('x')),
        ('GMRESMethod[A_, b_]', lambda A, b: sp.Symbol('x')),
        ('Multigrid[A_, b_, levels_]', lambda A, b, lev: sp.Symbol('x')),
        ('SIMPLEAlgorithm[p_, u_, v_]', lambda p, u, v: (p, u, v)),  # Pressure-velocity coupling
        ('PISOMAlgorithm[p_, u_, v_]', lambda p, u, v: (p, u, v)),
        ('FractionalStepMethod[u_, p_]', lambda u, p: (sp.Symbol('u_star'), p)),
        ('ProjectionMethod[u_, p_]', lambda u, p: (sp.Symbol('u_div_free'), p)),
        ('VorticityStreamFunction[omega_, psi_]', lambda omega, psi: sp.diff(psi, sp.Symbol('x'), 2) + sp.diff(psi, sp.Symbol('y'), 2) == -omega),
        ('PotentialFlowSolver[phi_, boundary_]', lambda phi, bc: phi),
        ('PanelMethod[geometry_]', lambda geo: 'potential solution'),
        ('VortexLatticeMethod[wing_]', lambda wing: 'lift distribution'),
        ('BoundaryElementMethod[surface_]', lambda surf: 'solution'),
        ('ImmersedBoundaryMethod[fluid_, solid_]', lambda fl, sol: fl),
        ('LevelSetMethod[interface_]', lambda interf: sp.diff(interf, sp.Symbol('t'))),
        ('VOFMethod[volume_fraction_]', lambda vf: vf),
        
        # ===== TURBULENCE MODELING (30 functions) =====
        ('TurbulentKineticEnergy[u_prime_]', lambda up: sp.Rational(1,2)*(up**2)),
        ('TurbulentDissipation[epsilon_]', lambda eps: eps),
        ('TurbulentViscosity[Cmu_, k_, epsilon_]', lambda Cmu, k, eps: Cmu*k**2/eps),
        ('KEpsilonModel[k_, epsilon_]', lambda k, eps: (sp.diff(k, sp.Symbol('t')), sp.diff(eps, sp.Symbol('t')))),
        ('KOmegaModel[k_, omega_]', lambda k, omega: (sp.diff(k, sp.Symbol('t')), sp.diff(omega, sp.Symbol('t')))),
        ('SSTModel[k_, omega_]', lambda k, omega: (k, omega)),  # Menter SST
        ('SpalartAllmaras[nu_tilde_]', lambda nut: sp.diff(nut, sp.Symbol('t'))),
        ('ReynoldsStressTensor[u_i_, u_j_]', lambda ui, uj: sp.Symbol('rho')*ui*uj),
        ('ReynoldsAveragedNS[u_, u_prime_]', lambda u, up: sp.diff(u, sp.Symbol('t')) + u*sp.diff(u, sp.Symbol('x'))),
        ('BoussinesqHypothesis[S_, mu_t_]', lambda S, mut: -2*mut*S),
        ('EdddyViscosity[l_, S_]', lambda l, S: l**2*abs(S)),
        ('MixingLength[y_, kappa_]', lambda y, kappa: kappa*y),
        ('SmagorinskyModel[Delta_, S_]', lambda Delta, S: (sp.Symbol('Cs')*Delta)**2*abs(S)),
        ('LargeEddySimulation[u_, u_resolved_]', lambda u, ures: ures),
        ('SubgridScaleModel[tau_sgs_]', lambda tau: tau),
        ('DirectNumericalSimulation[NS_]', lambda NS: NS),  # Fully resolved
        ('DetatechedEddySimulation[RANS_, LES_]', lambda RANS, LES: RANS + LES),
        ('TurbulenceIntensity[u_rms_, U_]', lambda urms, U: urms/U),
        ('TurbulentLengthScale[k_, epsilon_]', lambda k, eps: k**1.5/eps),
        ('TurbulentTimeScale[k_, epsilon_]', lambda k, eps: k/eps),
        ('TurbulentReynoldsNumber[k_, nu_]', lambda k, nu: k**2/(nu*sp.Symbol('epsilon'))),
        ('KolmogorovLengthScale[nu_, epsilon_]', lambda nu, eps: (nu**3/eps)**0.25),
        ('KolmogorovTimeScale[nu_, epsilon_]', lambda nu, eps: sqrt(nu/eps)),
        ('KolmogorovVelocityScale[nu_, epsilon_]', lambda nu, eps: (nu*eps)**0.25),
        ('TaylorMicroscale[u_rms_, du_dx_]', lambda urms, dudx: urms/sqrt(sp.Symbol('<(du/dx)^2>'))),
        ('IntegralLengthScale[autocorr_]', lambda ac: sp.integrate(ac, (sp.Symbol('r'), 0, sp.oo))),
        ('EnergySpectrumKolmogorov[k_wavenumber_]', lambda k: sp.Symbol('C')*sp.Symbol('epsilon')**sp.Rational(2,3)*k**sp.Rational(-5,3)),
        ('InertialSubrange[k_]', lambda k: k**sp.Rational(-5,3)),
        ('EnergyCascade[rate_]', lambda rate: rate),
        ('Intermittency[fluctuations_]', lambda fluct: fluct),
        
        # ===== MULTIPHASE FLOW (25 functions) =====
        ('TwoPhaseFlow[alpha_, rho1_, rho2_]', lambda alpha, rho1, rho2: alpha*rho1 + (1 - alpha)*rho2),
        ('VolumeFraction[V_phase_, V_total_]', lambda Vp, Vt: Vp/Vt),
        ('VoidFraction[V_gas_, V_total_]', lambda Vg, Vt: Vg/Vt),
        ('Slip Velocity[v1_, v2_]', lambda v1, v2: v1 - v2),
        ('Drift FluxModel[v_mixture_, j_]', lambda vm, j: vm + j),
        ('EulerEulerModel[alpha_, u_, p_]', lambda alpha, u, p: (sp.diff(alpha, sp.Symbol('t')), sp.diff(u, sp.Symbol('t')))),
        ('EulerLagrangeModel[particle_tracks_]', lambda tracks: tracks),
        ('DiscretePhaseModel[particles_]', lambda part: part),
        ('DragCoefficientSphere[Re_]', lambda Re: 24/Re if Re < 1 else 0.44),
        ('StokesLaw[mu_, r_, v_]', lambda mu, r, v: 6*pi*mu*r*v),
        ('TerminalVelocity[rho_p_, rho_f_, g_, r_, mu_]', lambda rhop, rhof, g, r, mu: 2*(rhop - rhof)*g*r**2/(9*mu)),
        ('SettlingVelocity[particle_]', lambda p: p),
        ('BubbleDiameter[We_, sigma_, rho_, v_]', lambda We, sig, rho, v: sig/(rho*v**2)*We),
        ('DropletBreakup[We_, critical_]', lambda We, Wec: We > Wec),
        ('CoalescenceRate[collisions_, efficiency_]', lambda col, eff: col*eff),
        ('SanitarySurface Tension[sigma_]', lambda sig: sig),
        ('ContactAngle[theta_]', lambda theta: theta),
        ('WettingCapillaryNumber[mu_, v_, sigma_]', lambda mu, v, sig: mu*v/sig),
        ('FilmThickness[Q_, width_, nu_]', lambda Q, w, nu: (3*nu*Q/w)**sp.Rational(1,3)),
        ('FallingFilm[Re_, Fr_]', lambda Re, Fr: Re*Fr),
        ('AnnularFlow[liquid_film_, gas_core_]', lambda liq, gas: (liq, gas)),
        ('SlugFlow[liquid_slug_, gas_bubble_]', lambda liq, gas: (liq, gas)),
        ('StratifiedFlow[h_interface_]', lambda h: h),
        ('ChurnFlow[mixing_]', lambda mix: mix),
        ('MistFlow[droplets_]', lambda drop: drop),
        
        # ===== HEAT TRANSFER IN FLUIDS (25 functions) =====
        ('ConvectiveHeatTransfer[h_, A_, delta_T_]', lambda h, A, dT: h*A*dT),
        ('NusseltCorrelation[Re_, Pr_]', lambda Re, Pr: 0.023*Re**0.8*Pr**0.4),
        ('DittusBoelter[Re_, Pr_, heating_]', lambda Re, Pr, heat: 0.023*Re**0.8*Pr**(0.4 if heat else 0.3)),
        ('SiederTate[Re_, Pr_, mu_ratio_]', lambda Re, Pr, mur: 0.027*Re**0.8*Pr**sp.Rational(1,3)*mur**0.14),
        ('GnielinkiCorrelation[Re_, Pr_, f_]', lambda Re, Pr, f: (f/8)*(Re - 1000)*Pr/(1 + 12.7*sqrt(f/8)*(Pr**sp.Rational(2,3) - 1))),
        ('ChurchillBernstein[Re_, Pr_]', lambda Re, Pr: 0.3 + 0.62*Re**0.5*Pr**sp.Rational(1,3)),
        ('RayleighNumber[g_, beta_, delta_T_, L_, alpha_, nu_]', lambda g, beta, dT, L, alpha, nu: g*beta*dT*L**3/(alpha*nu)),
        ('NaturalConvectionVerticalPlate[Ra_, Pr_]', lambda Ra, Pr: 0.59*Ra**0.25),
        ('NaturalConvectionHorizontalPlate[Ra_]', lambda Ra: 0.54*Ra**0.25),
        ('ForcedConvectionPipe[Re_, Pr_, D_, L_]', lambda Re, Pr, D, L: 0.023*Re**0.8*Pr**0.4),
        ('ThermalBoundaryLayer[x_, Pr_]', lambda x, Pr: x/Pr**sp.Rational(1,3)),
        ('ThermalEntryLength[Re_, Pr_, D_]', lambda Re, Pr, D: 0.05*Re*Pr*D),
        ('HydraulicDiameter[A_, P_]', lambda A, P: 4*A/P),
        ('EquivalentDiameter[non_circular_]', lambda nc: 4*sp.Symbol('A')/sp.Symbol('P')),
        ('BulkTemperature[T_, v_]', lambda T, v: sp.integrate(T*v, sp.Symbol('A'))/sp.integrate(v, sp.Symbol('A'))),
        ('FilmTemperature[T_surface_, T_bulk_]', lambda Ts, Tb: (Ts + Tb)/2),
        ('LogMeanTemperatureDifference[delta_T1_, delta_T2_]', lambda dT1, dT2: (dT1 - dT2)/log(dT1/dT2)),
        ('EffectivenessNTU[epsilon_, NTU_]', lambda eps, NTU: eps),
        ('NumberOfTransferUnits[UA_, Cmin_]', lambda UA, Cmin: UA/Cmin),
        ('HeatCapacityRateRatio[Cmin_, Cmax_]', lambda Cmin, Cmax: Cmin/Cmax),
        ('HeatExchangerEffectiveness[Q_actual_, Q_max_]', lambda Qa, Qm: Qa/Qm),
        ('CounterflowHX[NTU_, C_]', lambda NTU, C: (1 - exp(-NTU*(1 - C)))/(1 - C*exp(-NTU*(1 - C)))),
        ('ParallelFlowHX[NTU_, C_]', lambda NTU, C: (1 - exp(-NTU*(1 + C)))/(1 + C)),
        ('CrossFlowHX[NTU_, C_]', lambda NTU, C: 1 - exp(-NTU**0.22/C*(exp(-C*NTU**0.78) - 1))),
        ('BoilingHeatTransfer[h_, delta_T_]', lambda h, dT: h*dT**3),  # Simplified nucleate boiling
        ('CondensationFilmwise[k_, rho_, g_, h_fg_, mu_, delta_T_, L_]', lambda k, rho, g, hfg, mu, dT, L: 0.943*(rho**2*g*k**3*hfg/(mu*dT*L))**0.25),
        
        # ===== COMPRESSIBLE FLOW (20 functions) =====
        ('IsentropicFlow[gamma_, M_]', lambda gamma, M: (1 + (gamma - 1)/2*M**2)**(-gamma/(gamma - 1))),
        ('StagnationTemperature[T_, M_, gamma_]', lambda T, M, gamma: T*(1 + (gamma - 1)/2*M**2)),
        ('StagnationPressureCompressible[p_, M_, gamma_]', lambda p, M, gamma: p*(1 + (gamma - 1)/2*M**2)**(gamma/(gamma - 1))),
        ('CriticalPressureRatio[gamma_]', lambda gamma: (2/(gamma + 1))**(gamma/(gamma - 1))),
        ('ChokedFlow[M_]', lambda M: M >= 1),
        ('NormalShock[M1_, gamma_]', lambda M1, gamma: sqrt((1 + (gamma - 1)/2*M1**2)/(gamma*M1**2 - (gamma - 1)/2))),
        ('ObliqueShockAngle[M1_, beta_, gamma_]', lambda M1, beta, gamma: atan2(2*(M1**2*sin(beta)**2 - 1), (M1**2*(gamma + cos(2*beta)) + 2))),
        ('PrandtlMeyerFunction[M_, gamma_]', lambda M, gamma: sqrt((gamma + 1)/(gamma - 1))*atan2(sqrt((gamma - 1)/(gamma + 1)*(M**2 - 1)), 1) - atan2(sqrt(M**2 - 1), 1)),
        ('ExpansionWaveAngle[M1_, nu_]', lambda M1, nu: nu),
        ('RayleighFlow[M_, gamma_]', lambda M, gamma: (1 + gamma*M**2)/(1 + gamma)),
        ('FannoFlow[M_, gamma_]', lambda M, gamma: M*sqrt((gamma + 1)/(2 + (gamma - 1)*M**2))),
        ('AreaMachRelation[A_, A_star_, M_, gamma_]', lambda A, Astar, M, gamma: A/Astar == 1/M*((2 + (gamma - 1)*M**2)/(gamma + 1))**((gamma + 1)/(2*(gamma - 1)))),
        ('MassFluxChoked[rho0_, p0_, gamma_, R_, T0_]', lambda rho0, p0, gamma, R, T0: rho0*sqrt(gamma*R*T0)*(2/(gamma + 1))**((gamma + 1)/(2*(gamma - 1)))),
        ('SubsonicDiffuser[M1_, A1_, A2_]', lambda M1, A1, A2: M1*A1/A2),
        ('SupersonicNozzle[M_, A_throat_]', lambda M, At: M*At),
        ('LavalNozzle[p0_, pe_, gamma_]', lambda p0, pe, gamma: ((p0/pe)**((gamma - 1)/gamma) - 1)*2/(gamma - 1)),
        ('ShockTubeProblem[p4_, p1_, gamma_]', lambda p4, p1, gamma: sqrt(2*gamma/(gamma - 1)*((p4/p1)**((gamma - 1)/(2*gamma)) - 1))),
        ('ContactDiscontinuity[rho_, u_]', lambda rho, u: (rho, u)),
        ('RarefactionWave[characteristics_]', lambda char: char),
        ('SonicConditions[M_]', lambda M: M == 1),
    ]


def register():
    """Register all extended20 rules"""
    from .extended_helper import convert_rules
    return convert_rules(get_rules())
