Example #1
0
        // --------------------------------------------------------------------------
        // ATMOSPHERE
        // --------------------------------------------------------------------------

        // return proportion of flux not blocked by atmosphere
        // - position: sampling point
        // - sun_dir: normalized vector from sampling point to the sun
        public static double AtmosphereFactor(CelestialBody body, Vector3d position, Vector3d sun_dir)
        {
            // get up vector & altitude
            Vector3d up       = (position - body.position);
            double   altitude = up.magnitude;

            up       /= altitude;
            altitude -= body.Radius;
            altitude  = Math.Abs(altitude); //< deal with underwater & fp precision issues

            double static_pressure = body.GetPressure(altitude);

            if (static_pressure > 0.0)
            {
                double density = body.GetDensity(static_pressure, body.GetTemperature(altitude));

                // nonrefracting radially symmetrical atmosphere model [Schoenberg 1929]
                double Ra   = body.Radius + altitude;
                double Ya   = body.atmosphereDepth - altitude;
                double q    = Ra * Math.Max(0.0, Vector3d.Dot(up, sun_dir));
                double path = Math.Sqrt(q * q + 2.0 * Ra * Ya + Ya * Ya) - q;
                return(body.GetSolarPowerFactor(density) * Ya / path);
            }
            return(1.0);
        }
        public void SimulateAeroProperties(out Vector3 aeroForce, out Vector3 aeroTorque, Vector3 velocityWorldVector, double altitude)
        {
            // Rodhern: It seems that this method, 'SimulateAeroProperties', is only used in FARAPI, which in turn can be used by say KSPTrajectories.
            //          The parameter 'FARCenterQuery dummy' is from a code fix by Benjamin Chung (commit 18fbb9d29431679a4de9dfc22a443f400d2d4f8b).

            FARCenterQuery center = new FARCenterQuery();
            FARCenterQuery dummy  = new FARCenterQuery();

            float pressure;
            float density;
            float temperature;
            float speedOfSound;

            CelestialBody body = vessel.mainBody;      //Calculate main gas properties

            pressure     = (float)body.GetPressure(altitude);
            temperature  = (float)body.GetTemperature(altitude);
            density      = (float)body.GetDensity(pressure, temperature);
            speedOfSound = (float)body.GetSpeedOfSound(pressure, density);

            if (pressure <= 0 || temperature <= 0 || density <= 0 || speedOfSound <= 0)
            {
                aeroForce  = Vector3.zero;
                aeroTorque = Vector3.zero;
                return;
            }

            float     velocityMag         = velocityWorldVector.magnitude;
            float     machNumber          = velocityMag / speedOfSound;
            float     reynoldsNumber      = (float)FARAeroUtil.CalculateReynoldsNumber(density, Length, velocityMag, machNumber, temperature, body.atmosphereAdiabaticIndex);
            float     reynoldsPerLength   = reynoldsNumber / (float)Length;
            float     pseudoKnudsenNumber = machNumber / (reynoldsNumber + machNumber);
            float     skinFriction        = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber);
            FlightEnv fenv = FlightEnv.NewPredicted(vessel.mainBody, altitude, machNumber);

            if (_currentAeroSections != null)
            {
                for (int i = 0; i < _currentAeroSections.Count; i++)
                {
                    FARAeroSection curSection = _currentAeroSections[i];
                    if (curSection != null)
                    {
                        curSection.PredictionCalculateAeroForces(density, machNumber, reynoldsPerLength, pseudoKnudsenNumber, skinFriction, velocityWorldVector, center);
                    }
                }

                for (int i = 0; i < _legacyWingModels.Count; i++)
                {
                    FARWingAerodynamicModel curWing = _legacyWingModels[i];
                    if ((object)curWing != null)
                    {
                        Vector3d force = curWing.PrecomputeCenterOfLift(velocityWorldVector, fenv, dummy);
                        center.AddForce(curWing.transform.position, force);
                    }
                }
            }

            aeroForce  = center.force;
            aeroTorque = center.TorqueAt(vessel.CoM);
        }
Example #3
0
        /*
         * From Trajectories
         * Copyright 2014, Youen Toupin
         * This method is part of Trajectories, under MIT license.
         * StockAeroUtil by atomicfury
         */
        /// <summary>
        /// Gets the air density (rho) for the specified altitude on the specified body.
        /// This is an approximation, because actual calculations, taking sun exposure into account to compute air temperature, require to know the actual point on the body where the density is to be computed (knowing the altitude is not enough).
        /// However, the difference is small for high altitudes, so it makes very little difference for trajectory prediction.
        /// From StockAeroUtil.cs from Trajectories
        /// </summary>
        /// <param name="body"></param>
        /// <param name="altitude">Altitude above sea level (in meters)</param>
        /// <returns></returns>
        public static double GetDensity(this CelestialBody body, double altitude)
        {
            if (!body.atmosphere)
            {
                return(0);
            }

            if (altitude > body.atmosphereDepth)
            {
                return(0);
            }

            double pressure = body.GetPressure(altitude);

            // get an average day/night temperature at the equator
            double sunDot      = 0.5;
            float  sunAxialDot = 0;
            double atmosphereTemperatureOffset = (double)body.latitudeTemperatureBiasCurve.Evaluate(0)
                                                 + (double)body.latitudeTemperatureSunMultCurve.Evaluate(0) * sunDot
                                                 + (double)body.axialTemperatureSunMultCurve.Evaluate(sunAxialDot);
            double temperature = // body.GetFullTemperature(altitude, atmosphereTemperatureOffset);
                                 body.GetTemperature(altitude)
                                 + (double)body.atmosphereTemperatureSunMultCurve.Evaluate((float)altitude) * atmosphereTemperatureOffset;


            return(body.GetDensity(pressure, temperature));
        }
        protected void RunSimulation(object o)
        {
            try
            {
                CelestialBody simBody = HighLogic.LoadedSceneIsEditor ? editorBody : vessel.mainBody;

                double staticPressure = (HighLogic.LoadedSceneIsEditor || !liveSLT ? (simBody.atmosphere ? simBody.GetPressure(0) : 0) : vessel.staticPressurekPa) * PhysicsGlobals.KpaToAtmospheres;
                double atmDensity     = (HighLogic.LoadedSceneIsEditor || !liveSLT ? simBody.GetDensity(simBody.GetPressure(0), simBody.GetTemperature(0)) : vessel.atmDensity) / 1.225;
                double mach           = HighLogic.LoadedSceneIsEditor ? 1 : vessel.mach;

                //Run the simulation
                FuelFlowSimulation[]       sims         = (FuelFlowSimulation[])o;
                FuelFlowSimulation.Stats[] newAtmoStats = sims[0].SimulateAllStages(1.0f, staticPressure, atmDensity, mach);
                FuelFlowSimulation.Stats[] newVacStats  = sims[1].SimulateAllStages(1.0f, 0.0, 0.0, mach);
                atmoStats = newAtmoStats;
                vacStats  = newVacStats;
            }
            catch (Exception e)
            {
                print("Exception in MechJebModuleStageStats.RunSimulation(): " + e.StackTrace);
            }

            //see how long the simulation took
            stopwatch.Stop();
            long millisecondsToCompletion = stopwatch.ElapsedMilliseconds;

            stopwatch.Reset();

            //set the delay before the next simulation
            millisecondsBetweenSimulations = 2 * millisecondsToCompletion;

            //start the stopwatch that will count off this delay
            stopwatch.Start();
            simulationRunning = false;
        }
Example #5
0
        // return proportion of ionizing radiation not blocked by atmosphere
        public static double GammaTransparency(CelestialBody body, double altitude)
        {
            // deal with underwater & fp precision issues
            altitude = Math.Abs(altitude);

            // get pressure
            double static_pressure = body.GetPressure(altitude);

            if (static_pressure > 0.0)
            {
                // get density
                double density = body.GetDensity(static_pressure, body.GetTemperature(altitude));

                // math, you know
                double Ra     = body.Radius + altitude;
                double Ya     = body.atmosphereDepth - altitude;
                double path   = Math.Sqrt(Ra * Ra + 2.0 * Ra * Ya + Ya * Ya) - Ra;
                double factor = body.GetSolarPowerFactor(density) * Ya / path;

                // poor man atmosphere composition contribution
                if (body.atmosphereContainsOxygen || body.ocean)
                {
                    factor = 1.0 - Math.Pow(1.0 - factor, 0.015);
                }
                return(factor);
            }
            return(1.0);
        }
        // return proportion of ionizing radiation not blocked by atmosphere
        public static double GammaTransparency(CelestialBody body, double altitude)
        {
            // deal with underwater & fp precision issues
            altitude = Math.Abs(altitude);

            // get pressure
            var staticPressure = body.GetPressure(altitude);

            if (staticPressure > 0.0)
            {
                // get density
                var density = body.GetDensity(staticPressure, body.GetTemperature(altitude));

                // math, you know
                var radius = body.Radius + altitude;
                var depth  = body.atmosphereDepth - altitude;
                var path   = Math.Sqrt(radius * radius + 2.0 * radius * depth + depth * depth) - radius;
                var factor = body.GetSolarPowerFactor(density) * depth / path;

                // poor man atmosphere composition contribution
                if (body.atmosphereContainsOxygen || body.ocean)
                {
                    factor = 1.0 - Math.Pow(1.0 - factor, 0.015);
                }
                return(factor);
            }
            return(1.0);
        }
Example #7
0
        protected override Vector3 UpdatePosition()
        {
            if (EditorLogic.RootPart == null)
            {
                /* DragCubes can get NaNed without this check */
                return(Vector3.zero);
            }
            if (RCSBuildAid.Mode != PluginMode.Parachutes)
            {
                return(Vector3.zero);
            }

            hasParachutes = RCSBuildAid.Parachutes.Count > 0;
            body          = Settings.selected_body;
            altitude      = MenuParachutes.altitude;
            temperature   = body.GetTemperature(altitude);
            pressure      = body.GetPressure(altitude);
            density       = body.GetDensity(pressure, temperature);
            mach          = (float)(speed / body.GetSpeedOfSound(pressure, density));
            gravity       = body.gravity(altitude);

            findCenterOfDrag();
            speed = Vt = calculateTerminalVelocity();

            /* unless I go at mach speeds I don't care about this
             * reynolds = (float)(density * speed);
             * reynoldsDragMult = PhysicsGlobals.DragCurvePseudoReynolds.Evaluate (reynolds);
             */
            dragForce.Vector = calculateDragForce();

            return(position);
        }
Example #8
0
        protected override Vector3 UpdatePosition()
        {
            if (EditorLogic.RootPart == null) {
                /* DragCubes can get NaNed without this check */
                return Vector3.zero;
            }
            if (RCSBuildAid.Mode != PluginMode.Parachutes) {
                return Vector3.zero;
            }

            hasParachutes = RCSBuildAid.Parachutes.Count > 0;
            body = Settings.selected_body;
            altitude = MenuParachutes.altitude;
            temperature = body.GetTemperature (altitude);
            pressure = body.GetPressure (altitude);
            density = body.GetDensity (pressure, temperature);
            mach = (float)(speed / body.GetSpeedOfSound(pressure, density));
            gravity = body.gravity(altitude);

            findCenterOfDrag();
            speed = Vt = calculateTerminalVelocity ();
            /* unless I go at mach speeds I don't care about this
            reynolds = (float)(density * speed);
            reynoldsDragMult = PhysicsGlobals.DragCurvePseudoReynolds.Evaluate (reynolds);
            */
            dragForce.Vector = calculateDragForce ();

            return position;
        }
        public void SimulateAeroProperties(out Vector3 aeroForce, out Vector3 aeroTorque, Vector3 velocityWorldVector, double altitude)
        {
            FARCenterQuery center = new FARCenterQuery();

            float pressure;
            float density;
            float temperature;
            float speedOfSound;

            CelestialBody body = vessel.mainBody;      //Calculate main gas properties

            pressure     = (float)body.GetPressure(altitude);
            temperature  = (float)body.GetTemperature(altitude);
            density      = (float)body.GetDensity(pressure, temperature);
            speedOfSound = (float)body.GetSpeedOfSound(pressure, density);

            if (pressure <= 0 || temperature <= 0 || density <= 0 || speedOfSound <= 0)
            {
                aeroForce  = Vector3.zero;
                aeroTorque = Vector3.zero;
                return;
            }

            float velocityMag    = velocityWorldVector.magnitude;
            float machNumber     = velocityMag / speedOfSound;
            float reynoldsNumber = (float)FARAeroUtil.CalculateReynoldsNumber(density, Length, velocityMag, machNumber, temperature, body.atmosphereAdiabaticIndex);

            float reynoldsPerLength = reynoldsNumber / (float)Length;
            float skinFriction      = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber);

            float pseudoKnudsenNumber = machNumber / (reynoldsNumber + machNumber);

            if (_currentAeroSections != null)
            {
                for (int i = 0; i < _currentAeroSections.Count; i++)
                {
                    FARAeroSection curSection = _currentAeroSections[i];
                    if (curSection != null)
                    {
                        curSection.PredictionCalculateAeroForces(density, machNumber, reynoldsPerLength, pseudoKnudsenNumber, skinFriction, velocityWorldVector, center);
                    }
                }

                for (int i = 0; i < _legacyWingModels.Count; i++)
                {
                    FARWingAerodynamicModel curWing = _legacyWingModels[i];
                    if ((object)curWing != null)
                    {
                        curWing.PrecomputeCenterOfLift(velocityWorldVector, machNumber, density, center);
                    }
                }
            }

            aeroForce  = center.force;
            aeroTorque = center.TorqueAt(vessel.CoM);
        }
Example #10
0
        // determine average atmospheric absorption factor over the daylight period (not the whole day)
        // - by doing an average of values at midday, sunrise and an intermediate value
        // - using the current sun direction at the given position to approximate
        //   the influence of high latitudes and of the inclinaison of the body orbit
        public static double AtmosphereFactorAnalytic(CelestialBody body, Vector3d position, Vector3d sun_dir)
        {
            // only for atmospheric bodies whose rotation period is less than 120 hours
            if (body.rotationPeriod > 432000.0)
            {
                return(AtmosphereFactor(body, position, sun_dir));
            }

            // get up vector & altitude
            Vector3d radialOut = position - body.position;
            double   altitude  = radialOut.magnitude;

            radialOut /= altitude;             // normalize
            altitude  -= body.Radius;
            altitude   = Math.Abs(altitude);   //< deal with underwater & fp precision issues

            double static_pressure = body.GetPressure(altitude);

            if (static_pressure > 0.0)
            {
                Vector3d[] sunDirs = new Vector3d[3];

                // east - sunrise
                sunDirs[0] = body.getRFrmVel(position).normalized;
                // perpendicular vector
                Vector3d sunUp = Vector3d.Cross(sunDirs[0], sun_dir).normalized;
                // midday vector (along the radial plane + an angle depending on the original vesselSundir)
                sunDirs[1] = Vector3d.Cross(sunUp, sunDirs[0]).normalized;
                // invert midday vector if it's pointing toward the ground (checking against radial-out vector)
                if (Vector3d.Dot(sunDirs[1], radialOut) < 0.0)
                {
                    sunDirs[1] *= -1.0;
                }
                // get an intermediate vector between sunrise and midday
                sunDirs[2] = (sunDirs[0] + sunDirs[1]).normalized;

                double density = body.GetDensity(static_pressure, body.GetTemperature(altitude));

                // nonrefracting radially symmetrical atmosphere model [Schoenberg 1929]
                double Ra = body.Radius + altitude;
                double Ya = body.atmosphereDepth - altitude;
                double atmo_factor_analytic = 0.0;
                for (int i = 0; i < 3; i++)
                {
                    double q    = Ra * Math.Max(0.0, Vector3d.Dot(radialOut, sunDirs[i]));
                    double path = Math.Sqrt(q * q + 2.0 * Ra * Ya + Ya * Ya) - q;
                    atmo_factor_analytic += body.GetSolarPowerFactor(density) * Ya / path;
                }
                atmo_factor_analytic /= 3.0;
                return(atmo_factor_analytic);
            }
            return(1.0);
        }
        public void CalculateConstants(CelestialBody body, float speed, double altitude)
        {
            double atmosphereTemperatureOffset = 0;

            atmoTemp            = body.GetFullTemperature(altitude, atmosphereTemperatureOffset);
            density             = body.GetDensity(staticPressurekPa, atmoTemp);
            mach                = CalculateMachNumber(body, speed, staticPressurekPa, density);
            staticPressurekPa   = body.GetPressure(altitude);
            convectiveMachScale = Math.Pow(UtilMath.Clamp01(
                                               (mach - PhysicsGlobals.NewtonianMachTempLerpStartMach) / (PhysicsGlobals.NewtonianMachTempLerpEndMach - PhysicsGlobals.NewtonianMachTempLerpStartMach)),
                                           PhysicsGlobals.NewtonianMachTempLerpExponent);
        }
Example #12
0
        // return proportion of flux not blocked by atmosphere
        // note: this one assume the receiver is on the ground
        // - cos_a: cosine of angle between zenith and sun, in [0..1] range
        //          to get an average for stats purpose, use 0.7071
        public static double AtmosphereFactor(CelestialBody body, double cos_a)
        {
            double static_pressure = body.GetPressure(0.0);

            if (static_pressure > 0.0)
            {
                double density = body.GetDensity(static_pressure, body.GetTemperature(0.0));
                body.GetSolarAtmosphericEffects(cos_a, density, out _, out double stockFluxFactor);
                return(stockFluxFactor);
            }
            return(1.0);
        }
Example #13
0
 public AtmosphereParams(CelestialBody body, double altitude)
 {
     Alt  = altitude;
     Body = body;
     if (!Body.atmosphere)
     {
         return;
     }
     P     = Body.GetPressure(Alt);
     T     = Body.GetTemperature(Alt);
     Rho   = Body.GetDensity(P, T);
     Mach1 = Body.GetSpeedOfSound(P, Rho);
 }
Example #14
0
        public static double GetDensity(Vector3d position, CelestialBody body)
        {
            if (!body.atmosphere)
                return 0;

            double altitude = (position - body.position).magnitude - body.Radius;
            if (altitude > body.atmosphereDepth)
                return 0;

            double pressure = body.GetPressure(altitude);
            double temperature = GetTemperature(position, body);

            return body.GetDensity(pressure, temperature);
        }
Example #15
0
        // determine average atmospheric absorption factor over the daylight period (not the whole day)
        // - by doing an average of values at midday, sunrise and an intermediate value
        // - using the current sun direction at the given position to approximate
        //   the influence of high latitudes and of the inclinaison of the body orbit
        public static double AtmosphereFactorAnalytic(CelestialBody body, Vector3d position, Vector3d sun_dir)
        {
            // only for atmospheric bodies whose rotation period is less than 120 hours
            if (body.rotationPeriod > 432000.0)
            {
                return(AtmosphereFactor(body, position, sun_dir));
            }

            // get up vector & altitude
            Vector3d radialOut = position - body.position;
            double   altitude  = radialOut.magnitude;

            radialOut /= altitude;             // normalize
            altitude  -= body.Radius;
            altitude   = Math.Abs(altitude);   //< deal with underwater & fp precision issues

            double static_pressure = body.GetPressure(altitude);

            if (static_pressure > 0.0)
            {
                Vector3d[] sunDirs = new Vector3d[3];

                // east - sunrise
                sunDirs[0] = body.getRFrmVel(position).normalized;
                // perpendicular vector
                Vector3d sunUp = Vector3d.Cross(sunDirs[0], sun_dir).normalized;
                // midday vector (along the radial plane + an angle depending on the original vesselSundir)
                sunDirs[1] = Vector3d.Cross(sunUp, sunDirs[0]).normalized;
                // invert midday vector if it's pointing toward the ground (checking against radial-out vector)
                if (Vector3d.Dot(sunDirs[1], radialOut) < 0.0)
                {
                    sunDirs[1] *= -1.0;
                }
                // get an intermediate vector between sunrise and midday
                sunDirs[2] = (sunDirs[0] + sunDirs[1]).normalized;

                double density = body.GetDensity(static_pressure, body.GetTemperature(altitude));
                double atmo_factor_analytic = 0.0;
                for (int i = 0; i < 3; i++)
                {
                    body.GetSolarAtmosphericEffects(Vector3d.Dot(radialOut, sunDirs[i]), density, out _, out double stockFluxFactor);
                    atmo_factor_analytic += stockFluxFactor;
                }
                atmo_factor_analytic /= 3.0;
                return(atmo_factor_analytic);
            }
            return(1.0);
        }
Example #16
0
        //Function to estimate the final velocity given a stage's mass and parachute info
        public static double VelocityEstimate(double mass, double chuteAreaTimesCd)
        {
            if (chuteAreaTimesCd <= 0)
            {
                return(200);
            }
            if (mass <= 0)
            {
                return(0);
            }

            CelestialBody home = Planetarium.fetch.Home;

            return(Math.Sqrt((2000 * mass * 9.81) / (home.GetDensity(home.GetPressure(0), home.GetTemperature(0)) * chuteAreaTimesCd)));
            //This is according to the formulas used by Stupid_Chris in the Real Chute drag calculator program included with Real Chute. Source: https://github.com/StupidChris/RealChute/blob/master/Drag%20Calculator/RealChute%20drag%20calculator/RCDragCalc.cs
        }
Example #17
0
        // return proportion of flux not blocked by atmosphere
        // note: this one assume the receiver is on the ground
        // - cos_a: cosine of angle between zenith and sun, in [0..1] range
        //          to get an average for stats purpose, use 0.7071
        public static double AtmosphereFactor(CelestialBody body, double cos_a)
        {
            double static_pressure = body.GetPressure(0.0);

            if (static_pressure > 0.0)
            {
                double density = body.GetDensity(static_pressure, body.GetTemperature(0.0));

                // nonrefracting radially symmetrical atmosphere model [Schoenberg 1929]
                double Ra   = body.Radius;
                double Ya   = body.atmosphereDepth;
                double q    = Ra * cos_a;
                double path = Math.Sqrt(q * q + 2.0 * Ra * Ya + Ya * Ya) - q;
                return(body.GetSolarPowerFactor(density) * Ya / path);
            }
            return(1.0);
        }
Example #18
0
        static void setup_qrys(float AoA, float sideslip)
        {
            CelestialBody home = Planetarium.fetch.Home;

            pressure    = home.GetPressure(Math.Max(0.0, altitude));
            density     = home.GetDensity(pressure, home.GetTemperature(altitude));
            sound_speed = home.GetSpeedOfSound(pressure, density);
            mach        = (float)(Mathf.Abs(speed) / sound_speed);

            qry.refAirDensity     = density;
            qry.refStaticPressure = pressure;
            qry.refAltitude       = altitude;
            qry.refVector         = Quaternion.AngleAxis(AoA, EditorLogic.RootPart.partTransform.right) *
                                    Quaternion.AngleAxis(sideslip, EditorLogic.RootPart.partTransform.forward) *
                                    EditorLogic.RootPart.partTransform.up;
            qry.refVector *= speed;
        }
Example #19
0
        /// <summary>
        /// Gets the air density (rho) for the specified altitude on the specified body.
        /// This is an approximation, because actual calculations, taking sun exposure into account to compute air temperature, require to know the actual point on the body where the density is to be computed (knowing the altitude is not enough).
        /// However, the difference is small for high altitudes, so it makes very little difference for trajectory prediction.
        /// </summary>
        /// <param name="altitude">Altitude above sea level (in meters)</param>
        /// <param name="body"></param>
        /// <returns></returns>
        public static double GetDensity(double altitude, CelestialBody body)
        {
            if (!body.atmosphere)
                return 0;

            if (altitude > body.atmosphereDepth)
                return 0;

            double pressure = body.GetPressure(altitude);

            // get an average day/night temperature at the equator
            double sunDot = 0.5;
            float sunAxialDot = 0;
            double atmosphereTemperatureOffset = (double)body.latitudeTemperatureBiasCurve.Evaluate(0) + (double)body.latitudeTemperatureSunMultCurve.Evaluate(0) * sunDot + (double)body.axialTemperatureSunMultCurve.Evaluate(sunAxialDot);
            double temperature = body.GetTemperature(altitude) + (double)body.atmosphereTemperatureSunMultCurve.Evaluate((float)altitude) * atmosphereTemperatureOffset;

            return body.GetDensity(pressure, temperature);
        }
Example #20
0
        public static double GetDensity(Vector3d position, CelestialBody body)
        {
            if (!body.atmosphere)
            {
                return(0);
            }

            double altitude = (position - body.position).magnitude - body.Radius;

            if (altitude > body.atmosphereDepth)
            {
                return(0);
            }

            double pressure    = body.GetPressure(altitude);
            double temperature = GetTemperature(position, body);

            return(body.GetDensity(pressure, temperature));
        }
Example #21
0
        /// <summary>
        /// Gets the air density (rho) for the specified altitude (above sea level, in meters) on the specified body.
        /// This is an approximation, because actual calculations, taking sun exposure into account to compute air
        /// temperature, require to know the actual point on the body where the density is to be computed
        /// (knowing the altitude is not enough).
        /// However, the difference is small for high altitudes, so it makes very little difference
        /// for trajectory prediction.
        /// </summary>
        public static double GetDensity(double altitude, CelestialBody body)
        {
            if (!body.atmosphere)
            {
                return(0);
            }
            if (altitude > body.atmosphereDepth)
            {
                return(0);
            }
            var pressure = body.GetPressure(altitude);
            // get an average day/night temperature at the equator
            var sunDot      = 0.5;
            var sunAxialDot = 0f;
            var atmosphereTemperatureOffset = body.latitudeTemperatureBiasCurve.Evaluate(0) + body.latitudeTemperatureSunMultCurve.Evaluate(0) * sunDot + body.axialTemperatureSunMultCurve.Evaluate(sunAxialDot);
            var temperature = body.GetTemperature(altitude) + body.atmosphereTemperatureSunMultCurve.Evaluate((float)altitude) * atmosphereTemperatureOffset;

            return(body.GetDensity(pressure, temperature));
        }
Example #22
0
        // return proportion of flux not blocked by atmosphere
        // - position: sampling point
        // - sun_dir: normalized vector from sampling point to the sun
        public static double AtmosphereFactor(CelestialBody body, Vector3d position, Vector3d sun_dir)
        {
            // get up vector & altitude
            Vector3d up       = position - body.position;
            double   altitude = up.magnitude;

            up       /= altitude;
            altitude -= body.Radius;
            altitude  = Math.Abs(altitude);            //< deal with underwater & fp precision issues

            double static_pressure = body.GetPressure(altitude);

            if (static_pressure > 0.0)
            {
                double density = body.GetDensity(static_pressure, body.GetTemperature(altitude));
                body.GetSolarAtmosphericEffects(Vector3d.Dot(up, sun_dir), density, out _, out double stockFluxFactor);
                return(stockFluxFactor);
            }
            return(1.0);
        }
Example #23
0
        public static float ComputeCutoffAlt(CelestialBody body, float cutoffDensity, float stepSize = 100)
        {
            //This unfortunately doesn't seem to be coming up with the right altitude for Kerbin (~23km, it finds ~27km)
            double dens = 0;
            float  alt  = (float)body.atmosphereDepth;

            while (alt > 0)
            {
                dens = body.GetDensity(FlightGlobals.getStaticPressure(alt, body), body.atmosphereTemperatureCurve.Evaluate(alt)); //body.atmospherePressureCurve.Evaluate(alt)
                //Debug.Log("[SR] Alt: " + alt + " Pres: " + dens);
                if (dens < cutoffDensity)
                {
                    alt -= stepSize;
                }
                else
                {
                    break;
                }
            }
            return(alt);
        }
        protected override bool updateMessage(ref atmoConditionStruct message)
        {
            message.atmoCharacteristics = 0;

            Vessel vessel = FlightGlobals.ActiveVessel;

            if (vessel == null)
            {
                return(false);
            }

            CelestialBody body = FlightGlobals.ActiveVessel.mainBody;

            if (body == null)
            {
                return(false);
            }

            if (body.atmosphere)
            {
                message.atmoCharacteristics |= AtmoConditionsBits.hasAtmosphere;
                if (body.atmosphereContainsOxygen)
                {
                    message.atmoCharacteristics |= AtmoConditionsBits.hasOxygen;
                }
                if (body.atmosphereDepth >= vessel.altitude)
                {
                    message.atmoCharacteristics |= AtmoConditionsBits.isVesselInAtmosphere;
                }

                message.temperature = (float)body.GetTemperature(vessel.altitude);
                message.pressure    = (float)body.GetPressure(vessel.altitude);
                message.airDensity  = (float)body.GetDensity(body.GetPressure(vessel.altitude), body.GetTemperature(vessel.altitude));
            }

            FlightGlobals.ActiveVessel.mainBody.GetFullTemperature(FlightGlobals.ActiveVessel.CoMD);

            return(false);
        }
Example #25
0
        public void SimulateAeroProperties(out Vector3 aeroForce, out Vector3 aeroTorque, Vector3 velocityWorldVector, double altitude)
        {
            FARCenterQuery center = new FARCenterQuery();

            float pressure;
            float density;
            float temperature;
            float speedOfSound;

            CelestialBody body = _vessel.mainBody;      //Calculate main gas properties

            pressure     = (float)body.GetPressure(altitude);
            temperature  = (float)body.GetTemperature(altitude);
            density      = (float)body.GetDensity(pressure, temperature);
            speedOfSound = (float)body.GetSpeedOfSound(pressure, density);

            float velocityMag    = velocityWorldVector.magnitude;
            float machNumber     = velocityMag / speedOfSound;
            float reynoldsNumber = (float)FARAeroUtil.CalculateReynoldsNumber(density, Length, velocityMag, machNumber, temperature, body.atmosphereAdiabaticIndex);

            float reynoldsPerLength = reynoldsNumber / (float)Length;
            float skinFriction      = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber);

            float pseudoLanchesterNumber = machNumber / (reynoldsNumber + machNumber);

            for (int i = 0; i < _currentAeroSections.Count; i++)
            {
                _currentAeroSections[i].PredictionCalculateAeroForces(density, machNumber, reynoldsPerLength, pseudoLanchesterNumber, skinFriction, velocityWorldVector, center);
            }

            for (int i = 0; i < _legacyWingModels.Count; i++)
            {
                _legacyWingModels[i].PrecomputeCenterOfLift(velocityWorldVector, machNumber, density, center);
            }

            aeroForce  = center.force;
            aeroTorque = center.TorqueAt(_vessel.CoM);
        }
Example #26
0
            public void setup(CenterOfLiftQuery qry)
            {
                CelestialBody home = Planetarium.fetch.Home;

                pressure    = home.GetPressure(altitude);
                density     = home.GetDensity(pressure, home.GetTemperature(altitude));
                sound_speed = home.GetSpeedOfSound(pressure, density);
                mach        = (float)(speed / sound_speed);

                qry.refAirDensity     = density;
                qry.refStaticPressure = pressure;
                qry.refAltitude       = altitude;
                qry.refVector         = Quaternion.AngleAxis(AoA, EditorLogic.RootPart.partTransform.right) * EditorLogic.VesselRotation * Vector3.up;
                qry.refVector        *= speed;

                qry.lift = 0.0f;
                qry.dir  = Vector3.zero;
                qry.pos  = Vector3.zero;

                local_qry.refAirDensity     = qry.refAirDensity;
                local_qry.refAltitude       = qry.refAltitude;
                local_qry.refStaticPressure = qry.refStaticPressure;
                local_qry.refVector         = qry.refVector;
            }
Example #27
0
 public static float density(this CelestialBody body, float altitude)
 {
     return((float)body.GetDensity(body.GetPressure(altitude), 300));
 }
        public void Display()
        {
            //stabDerivHelp = GUILayout.Toggle(stabDerivHelp, "?", ButtonStyle, GUILayout.Width(200));

            GUILayout.Label("Flight Condition:");
            GUILayout.BeginHorizontal();
            GUILayout.Label("Planet:");
            _bodySettingDropdown.GUIDropDownDisplay();

            GUILayout.Label("Altitude (km):");
            altitude = GUILayout.TextField(altitude, GUILayout.ExpandWidth(true));

            GUILayout.Label("Mach Number: ");
            machNumber = GUILayout.TextField(machNumber, GUILayout.ExpandWidth(true));

            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Flap Setting: ");
            _flapSettingDropdown.GUIDropDownDisplay();
            GUILayout.Label("Spoilers:");
            spoilersDeployed = GUILayout.Toggle(spoilersDeployed, spoilersDeployed ? "Deployed" : "Retracted", GUILayout.Width(100));
            GUILayout.EndHorizontal();

            if (GUILayout.Button("Calculate Stability Derivatives", GUILayout.Width(250.0F), GUILayout.Height(25.0F)))
            {
                CelestialBody body = _bodySettingDropdown.ActiveSelection;
                FARAeroUtil.UpdateCurrentActiveBody(body);
                //atm_temp_str = Regex.Replace(atm_temp_str, @"[^-?[0-9]*(\.[0-9]*)?]", "");
                //rho_str = Regex.Replace(rho_str, @"[^-?[0-9]*(\.[0-9]*)?]", "");
                machNumber = Regex.Replace(machNumber, @"[^-?[0-9]*(\.[0-9]*)?]", "");

                altitude = Regex.Replace(altitude, @"[^-?[0-9]*(\.[0-9]*)?]", "");
                double altitudeDouble = Convert.ToDouble(altitude);
                altitudeDouble *= 1000;


                double temp     = body.GetTemperature(altitudeDouble);
                double pressure = body.GetPressure(altitudeDouble);
                if (pressure > 0)
                {
                    //double temp = Convert.ToSingle(atm_temp_str);
                    double machDouble = Convert.ToSingle(machNumber);
                    machDouble = FARMathUtil.Clamp(machDouble, 0.001, float.PositiveInfinity);

                    double density = body.GetDensity(pressure, temp);

                    double sspeed = body.GetSpeedOfSound(pressure, density);
                    double vel    = sspeed * machDouble;

                    //UpdateControlSettings();

                    double q = vel * vel * density * 0.5f;

                    stabDerivOutput        = simManager.StabDerivCalculator.CalculateStabilityDerivs(vel, q, machDouble, 0, 0, 0, _flapSettingDropdown.ActiveSelection, spoilersDeployed, body, altitudeDouble);
                    simManager.vehicleData = stabDerivOutput;
                    SetAngleVectors(stabDerivOutput.stableAoA);
                }
                else
                {
                    PopupDialog.SpawnPopupDialog("Error!", "Altitude was above atmosphere", "OK", false, HighLogic.Skin);
                }
            }
            GUILayout.BeginHorizontal();
            GUILayout.Label("Aircraft Properties", GUILayout.Width(180));
            GUILayout.Label("Moments of Inertia", GUILayout.Width(160));
            GUILayout.Label("Products of Inertia", GUILayout.Width(160));
            GUILayout.Label("Level Flight", GUILayout.Width(140));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.BeginVertical(GUILayout.Width(180));
            GUILayout.Label("Ref Area: " + stabDerivOutput.area.ToString("G3") + " m²");
            GUILayout.Label("Scaled Chord: " + stabDerivOutput.MAC.ToString("G3") + " m");
            GUILayout.Label("Scaled Span: " + stabDerivOutput.b.ToString("G3") + " m");
            GUILayout.EndVertical();


            GUILayout.BeginVertical(GUILayout.Width(160));
            GUILayout.Label(new GUIContent("Ixx: " + stabDerivOutput.stabDerivs[0].ToString("G6") + " kg * m²", "Inertia about X-axis due to rotation about X-axis"));
            GUILayout.Label(new GUIContent("Iyy: " + stabDerivOutput.stabDerivs[1].ToString("G6") + " kg * m²", "Inertia about Y-axis due to rotation about Y-axis"));
            GUILayout.Label(new GUIContent("Izz: " + stabDerivOutput.stabDerivs[2].ToString("G6") + " kg * m²", "Inertia about Z-axis due to rotation about Z-axis"));
            GUILayout.EndVertical();

            GUILayout.BeginVertical(GUILayout.Width(160));
            GUILayout.Label(new GUIContent("Ixy: " + stabDerivOutput.stabDerivs[24].ToString("G6") + " kg * m²", "Inertia about X-axis due to rotation about Y-axis; is equal to inertia about Y-axis due to rotation about X-axis"));
            GUILayout.Label(new GUIContent("Iyz: " + stabDerivOutput.stabDerivs[25].ToString("G6") + " kg * m²", "Inertia about Y-axis due to rotation about Z-axis; is equal to inertia about Z-axis due to rotation about Y-axis"));
            GUILayout.Label(new GUIContent("Ixz: " + stabDerivOutput.stabDerivs[26].ToString("G6") + " kg * m²", "Inertia about X-axis due to rotation about Z-axis; is equal to inertia about Z-axis due to rotation about X-axis"));
            GUILayout.EndVertical();

            GUILayout.BeginVertical(GUILayout.Width(140));
            GUILayout.Label(new GUIContent("u0: " + stabDerivOutput.nominalVelocity.ToString("G6") + " m/s", "Air speed based on this mach number and temperature."));
            GUILayout.BeginHorizontal();
            GUILayout.Label(new GUIContent("Cl: " + stabDerivOutput.stableCl.ToString("G3"), "Required lift coefficient at this mass, speed and air density."));
            GUILayout.Label(new GUIContent("Cd: " + stabDerivOutput.stableCd.ToString("G3"), "Resulting drag coefficient at this mass, speed and air density."));
            GUILayout.EndHorizontal();
            GUILayout.Label(new GUIContent("AoA: " + stabDerivOutput.stableAoAState + stabDerivOutput.stableAoA.ToString("G6") + " deg", "Angle of attack required to achieve the necessary lift force."));
            GUILayout.EndVertical();

            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Longitudinal Derivatives", GUILayout.Width(160));
            GUILayout.EndHorizontal();

            GUIStyle BackgroundStyle = new GUIStyle(GUI.skin.box);

            BackgroundStyle.hover = BackgroundStyle.active = BackgroundStyle.normal;

            GUILayout.BeginVertical(BackgroundStyle);
            GUILayout.BeginHorizontal();
            GUILayout.Label("Down Vel Derivatives", GUILayout.Width(160));
            GUILayout.Label("Fwd Vel Derivatives", GUILayout.Width(160));
            GUILayout.Label("Pitch Rate Derivatives", GUILayout.Width(160));
            GUILayout.Label("Pitch Ctrl Derivatives", GUILayout.Width(160));
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            StabilityLabel("Zw: ", stabDerivOutput.stabDerivs[3], " s⁻¹", "Change in Z-direction acceleration with respect to Z-direction velocity; should be negative", 160, -1);
            StabilityLabel("Zu: ", stabDerivOutput.stabDerivs[6], " s⁻¹", "Change in Z-direction acceleration with respect to X-direction velocity; should be negative", 160, -1);
            StabilityLabel("Zq: ", stabDerivOutput.stabDerivs[9], " m/s", "Change in Z-direction acceleration with respect to pitch-up rate; sign unimportant", 160, 0);
            StabilityLabel("Zδe: ", stabDerivOutput.stabDerivs[12], " m/s²", "Change in Z-direction acceleration with respect to pitch control input; should be negative", 160, 0);
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            StabilityLabel("Xw: ", stabDerivOutput.stabDerivs[4], " s⁻¹", "Change in X-direction acceleration with respect to Z-direction velocity; sign unimportant", 160, 0);
            StabilityLabel("Xu: ", stabDerivOutput.stabDerivs[7], " s⁻¹", "Change in X-direction acceleration with respect to X-direction velocity; should be negative", 160, -1);
            StabilityLabel("Xq: ", stabDerivOutput.stabDerivs[10], " m/s", "Change in X-direction acceleration with respect to pitch-up rate; sign unimportant", 160, 0);
            StabilityLabel("Xδe: ", stabDerivOutput.stabDerivs[13], " m/s²", "Change in X-direction acceleration with respect to pitch control input; sign unimportant", 160, 0);
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            StabilityLabel("Mw: ", stabDerivOutput.stabDerivs[5], " (m * s)⁻¹", "Change in pitch-up angular acceleration with respect to Z-direction velocity; should be negative", 160, -1);
            StabilityLabel("Mu: ", stabDerivOutput.stabDerivs[8], " (m * s)⁻¹", "Change in pitch-up angular acceleration acceleration with respect to X-direction velocity; sign unimportant", 160, 0);
            StabilityLabel("Mq: ", stabDerivOutput.stabDerivs[11], " s⁻¹", "Change in pitch-up angular acceleration acceleration with respect to pitch-up rate; should be negative", 160, -1);
            StabilityLabel("Mδe: ", stabDerivOutput.stabDerivs[14], " s⁻²", "Change in pitch-up angular acceleration acceleration with respect to pitch control input; should be positive", 160, 1);
            GUILayout.EndHorizontal();
            GUILayout.EndVertical();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Lateral Derivatives", GUILayout.Width(160));
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            GUILayout.Label("Sideslip Derivatives", GUILayout.Width(160));
            GUILayout.Label("Roll Rate Derivatives", GUILayout.Width(160));
            GUILayout.Label("Yaw Rate Derivatives", GUILayout.Width(160));
            GUILayout.EndHorizontal();
            GUILayout.BeginVertical(BackgroundStyle);
            GUILayout.BeginHorizontal();
            StabilityLabel("Yβ: ", stabDerivOutput.stabDerivs[15], " m/s²", "Change in Y-direction acceleration with respect to sideslip angle β; should be negative", 160, -1);
            StabilityLabel("Yp: ", stabDerivOutput.stabDerivs[18], " m/s", "Change in Y-direction acceleration with respect to roll-right rate; sign unimportant", 160, 0);
            StabilityLabel("Yr: ", stabDerivOutput.stabDerivs[21], " m/s", "Change in Y-direction acceleration with respect to yaw-right rate; should be positive", 160, 1);
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            StabilityLabel("Lβ: ", stabDerivOutput.stabDerivs[16], " s⁻²", "Change in roll-right angular acceleration with respect to sideslip angle β; should be negative", 160, -1);
            StabilityLabel("Lp: ", stabDerivOutput.stabDerivs[19], " s⁻¹", "Change in roll-right angular acceleration with respect to roll-right rate; should be negative", 160, -1);
            StabilityLabel("Lr: ", stabDerivOutput.stabDerivs[22], " s⁻¹", "Change in roll-right angular acceleration with respect to yaw-right rate; should be positive", 160, 1);
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            StabilityLabel("Nβ: ", stabDerivOutput.stabDerivs[17], " s⁻²", "Change in yaw-right angular acceleration with respect to sideslip angle β; should be positive", 160, 1);
            StabilityLabel("Np: ", stabDerivOutput.stabDerivs[20], " s⁻¹", "Change in yaw-right angular acceleration with respect to roll-right rate; sign unimportant", 160, 0);
            StabilityLabel("Nr: ", stabDerivOutput.stabDerivs[23], " s⁻¹", "Change in yaw-right angular acceleration with respect to yaw-right rate; should be negative", 160, -1);
            GUILayout.EndHorizontal();
            GUILayout.EndVertical();

            DrawTooltip();
        }
Example #29
0
        protected void RunSimulation(object o)
        {
            try
            {
                CelestialBody simBody = HighLogic.LoadedSceneIsEditor ? editorBody : vessel.mainBody;

                double staticPressureKpa = (HighLogic.LoadedSceneIsEditor || !liveSLT ? (simBody.atmosphere ? simBody.GetPressure(altSLT) : 0) : vessel.staticPressurekPa);
                double atmDensity        = (HighLogic.LoadedSceneIsEditor || !liveSLT ? simBody.GetDensity(simBody.GetPressure(altSLT), simBody.GetTemperature(0)) : vessel.atmDensity) / 1.225;
                double mach = HighLogic.LoadedSceneIsEditor ? this.mach : vessel.mach;

                //Run the simulation
                newAtmoStats = sims[0].SimulateAllStages(1.0f, staticPressureKpa, atmDensity, mach);
                newVacStats  = sims[1].SimulateAllStages(1.0f, 0.0, 0.0, mach);
            }
            catch (Exception e)
            {
                Log.err(e, "Exception in MechJebModuleStageStats.RunSimulation(): {0}", e.Message);
            }

            //see how long the simulation took
            stopwatch.Stop();
            long millisecondsToCompletion = stopwatch.ElapsedMilliseconds;

            stopwatch.Reset();

            //set the delay before the next simulation
            millisecondsBetweenSimulations = 2 * millisecondsToCompletion;

            //start the stopwatch that will count off this delay
            stopwatch.Start();
            resultReady       = true;
            simulationRunning = false;
        }
Example #30
0
 public double GetDensity(double altitude)
 {
     return(CelestialBody.GetDensity(GetPressure(altitude), GetTemperature(altitude)));
 }
        public StabilityDerivExportOutput CalculateStabilityDerivs(CelestialBody body, double alt, double machNumber, int flapSetting, bool spoilers, double alpha, double beta, double phi)
        {
            double pressure    = body.GetPressure(alt);
            double temperature = body.GetTemperature(alt);
            double density     = body.GetDensity(pressure, temperature);
            double sspeed      = body.GetSpeedOfSound(pressure, density);
            double u0          = sspeed * machNumber;
            double q           = u0 * u0 * density * 0.5f;

            StabilityDerivOutput          stabDerivOutput = new StabilityDerivOutput();
            StabilityDerivExportVariables stabDerivExport = new StabilityDerivExportVariables();

            stabDerivOutput.nominalVelocity = u0;
            stabDerivOutput.altitude        = alt;
            stabDerivOutput.body            = body;

            Vector3d CoM  = Vector3d.zero;
            double   mass = 0;

            double MAC  = 0;
            double b    = 0;
            double area = 0;

            double Ix  = 0;
            double Iy  = 0;
            double Iz  = 0;
            double Ixy = 0;
            double Iyz = 0;
            double Ixz = 0;

            InstantConditionSimInput  input = new InstantConditionSimInput(alpha, beta, phi, 0, 0, 0, machNumber, 0, flapSetting, spoilers);
            InstantConditionSimOutput nominalOutput;
            InstantConditionSimOutput pertOutput = new InstantConditionSimOutput();

            _instantCondition.GetClCdCmSteady(input, out nominalOutput, true);

            List <Part> partsList = EditorLogic.SortedShipList;

            for (int i = 0; i < partsList.Count; i++)
            {
                Part p = partsList[i];

                if (FARAeroUtil.IsNonphysical(p))
                {
                    continue;
                }
                double partMass = p.mass;
                if (p.Resources.Count > 0)
                {
                    partMass += p.GetResourceMass();
                }

                //partMass += p.GetModuleMass(p.mass);
                // If you want to use GetModuleMass, you need to start from p.partInfo.mass, not p.mass
                CoM  += partMass * (Vector3d)p.transform.TransformPoint(p.CoMOffset);
                mass += partMass;
                FARWingAerodynamicModel w = p.GetComponent <FARWingAerodynamicModel>();
                if (w != null)
                {
                    if (w.isShielded)
                    {
                        continue;
                    }

                    area += w.S;
                    MAC  += w.GetMAC() * w.S;
                    b    += w.Getb_2() * w.S;
                    if (w is FARControllableSurface)
                    {
                        (w as FARControllableSurface).SetControlStateEditor(CoM, p.transform.up, 0, 0, 0, input.flaps, input.spoilers);
                    }
                }
            }
            if (area.NearlyEqual(0))
            {
                area = _instantCondition._maxCrossSectionFromBody;
                MAC  = _instantCondition._bodyLength;
                b    = 1;
            }
            MAC  /= area;
            b    /= area;
            CoM  /= mass;
            mass *= 1000;

            stabDerivOutput.b    = b;
            stabDerivOutput.MAC  = MAC;
            stabDerivOutput.area = area;

            for (int i = 0; i < partsList.Count; i++)
            {
                Part p = partsList[i];

                if (p == null || FARAeroUtil.IsNonphysical(p))
                {
                    continue;
                }
                //This section handles the parallel axis theorem
                Vector3 relPos = p.transform.TransformPoint(p.CoMOffset) - CoM;
                double  x2, y2, z2, x, y, z;
                x2 = relPos.z * relPos.z;
                y2 = relPos.x * relPos.x;
                z2 = relPos.y * relPos.y;
                x  = relPos.z;
                y  = relPos.x;
                z  = relPos.y;

                double partMass = p.mass;
                if (p.Resources.Count > 0)
                {
                    partMass += p.GetResourceMass();
                }

                //partMass += p.GetModuleMass(p.mass);
                // If you want to use GetModuleMass, you need to start from p.partInfo.mass, not p.mass

                Ix += (y2 + z2) * partMass;
                Iy += (x2 + z2) * partMass;
                Iz += (x2 + y2) * partMass;

                Ixy += -x * y * partMass;
                Iyz += -z * y * partMass;
                Ixz += -x * z * partMass;

                //And this handles the part's own moment of inertia
                Vector3    principalInertia = p.Rigidbody.inertiaTensor;
                Quaternion prncInertRot     = p.Rigidbody.inertiaTensorRotation;

                //The rows of the direction cosine matrix for a quaternion
                Vector3 Row1 = new Vector3(prncInertRot.x * prncInertRot.x - prncInertRot.y * prncInertRot.y - prncInertRot.z * prncInertRot.z + prncInertRot.w * prncInertRot.w,
                                           2 * (prncInertRot.x * prncInertRot.y + prncInertRot.z * prncInertRot.w),
                                           2 * (prncInertRot.x * prncInertRot.z - prncInertRot.y * prncInertRot.w));

                Vector3 Row2 = new Vector3(2 * (prncInertRot.x * prncInertRot.y - prncInertRot.z * prncInertRot.w),
                                           -prncInertRot.x * prncInertRot.x + prncInertRot.y * prncInertRot.y - prncInertRot.z * prncInertRot.z + prncInertRot.w * prncInertRot.w,
                                           2 * (prncInertRot.y * prncInertRot.z + prncInertRot.x * prncInertRot.w));

                Vector3 Row3 = new Vector3(2 * (prncInertRot.x * prncInertRot.z + prncInertRot.y * prncInertRot.w),
                                           2 * (prncInertRot.y * prncInertRot.z - prncInertRot.x * prncInertRot.w),
                                           -prncInertRot.x * prncInertRot.x - prncInertRot.y * prncInertRot.y + prncInertRot.z * prncInertRot.z + prncInertRot.w * prncInertRot.w);


                //And converting the principal moments of inertia into the coordinate system used by the system
                Ix += principalInertia.x * Row1.x * Row1.x + principalInertia.y * Row1.y * Row1.y + principalInertia.z * Row1.z * Row1.z;
                Iy += principalInertia.x * Row2.x * Row2.x + principalInertia.y * Row2.y * Row2.y + principalInertia.z * Row2.z * Row2.z;
                Iz += principalInertia.x * Row3.x * Row3.x + principalInertia.y * Row3.y * Row3.y + principalInertia.z * Row3.z * Row3.z;

                Ixy += principalInertia.x * Row1.x * Row2.x + principalInertia.y * Row1.y * Row2.y + principalInertia.z * Row1.z * Row2.z;
                Ixz += principalInertia.x * Row1.x * Row3.x + principalInertia.y * Row1.y * Row3.y + principalInertia.z * Row1.z * Row3.z;
                Iyz += principalInertia.x * Row2.x * Row3.x + principalInertia.y * Row2.y * Row3.y + principalInertia.z * Row2.z * Row3.z;
            }
            Ix *= 1000;
            Iy *= 1000;
            Iz *= 1000;

            stabDerivOutput.stabDerivs[0] = Ix;
            stabDerivOutput.stabDerivs[1] = Iy;
            stabDerivOutput.stabDerivs[2] = Iz;

            stabDerivOutput.stabDerivs[24] = Ixy;
            stabDerivOutput.stabDerivs[25] = Iyz;
            stabDerivOutput.stabDerivs[26] = Ixz;


            double effectiveG = _instantCondition.CalculateAccelerationDueToGravity(body, alt); //This is the effect of gravity

            effectiveG -= u0 * u0 / (alt + body.Radius);                                        //This is the effective reduction of gravity due to high velocity
            double neededCl = mass * effectiveG / (q * area);


            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);
            //Longitudinal Mess
            _instantCondition.SetState(machNumber, neededCl, CoM, 0, input.flaps, input.spoilers);

            alpha         = FARMathUtil.SelectedSearchMethod(machNumber, _instantCondition.FunctionIterateForAlpha);
            input.alpha   = alpha;
            nominalOutput = _instantCondition.iterationOutput;
            //alpha_str = (alpha * Mathf.PI / 180).ToString();

            input.alpha = (alpha + 2);

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            stabDerivOutput.stableCl       = neededCl;
            stabDerivOutput.stableCd       = nominalOutput.Cd;
            stabDerivOutput.stableAoA      = alpha;
            stabDerivOutput.stableAoAState = "";
            if (Math.Abs((nominalOutput.Cl - neededCl) / neededCl) > 0.1)
            {
                stabDerivOutput.stableAoAState = ((nominalOutput.Cl > neededCl) ? "<" : ">");
            }

            FARLogger.Info("Cl needed: " + neededCl + ", AoA: " + alpha + ", Cl: " + nominalOutput.Cl + ", Cd: " + nominalOutput.Cd);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / (2 * FARMathUtil.deg2rad);                   //vert vel derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / (2 * FARMathUtil.deg2rad);
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / (2 * FARMathUtil.deg2rad);

            pertOutput.Cl += nominalOutput.Cd;
            pertOutput.Cd -= nominalOutput.Cl;

            pertOutput.Cl *= -q * area / (mass * u0);
            pertOutput.Cd *= -q * area / (mass * u0);
            pertOutput.Cm *= q * area * MAC / (Iy * u0);

            stabDerivOutput.stabDerivs[3] = pertOutput.Cl;  //Zw
            stabDerivOutput.stabDerivs[4] = pertOutput.Cd;  //Xw
            stabDerivOutput.stabDerivs[5] = pertOutput.Cm;  //Mw

            // Rodhern: The motivation for the revised stability derivatives sign interpretations of Zq, Xq, Ze and Xe
            //  is to align the sign conventions used for Zu, Zq, Ze, Xu, Xq and Xe. Further explanation can be found
            //  here: https://forum.kerbalspaceprogram.com/index.php?/topic/109098-official-far-craft-repository/&do=findComment&comment=2425057

            input.alpha      = alpha;
            input.machNumber = machNumber + 0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05 * machNumber;                   //fwd vel derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.05 * machNumber;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.05 * machNumber;

            pertOutput.Cl += 2 * nominalOutput.Cl;
            pertOutput.Cd += 2 * nominalOutput.Cd;

            pertOutput.Cl *= -q * area / (mass * u0);
            pertOutput.Cd *= -q * area / (mass * u0);
            pertOutput.Cm *= q * area * MAC / (u0 * Iy);

            stabDerivOutput.stabDerivs[6] = pertOutput.Cl;  //Zu
            stabDerivOutput.stabDerivs[7] = pertOutput.Cd;  //Xu
            stabDerivOutput.stabDerivs[8] = pertOutput.Cm;  //Mu

            input.machNumber = machNumber;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.alphaDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05;                   //pitch rate derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.05;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.05;

            pertOutput.Cl *= -q * area * MAC / (2 * u0 * mass); // Rodhern: Replaced 'q' by '-q', so that formulas
            pertOutput.Cd *= -q * area * MAC / (2 * u0 * mass); //  for Zq and Xq match those for Zu and Xu.
            pertOutput.Cm *= q * area * MAC * MAC / (2 * u0 * Iy);

            stabDerivOutput.stabDerivs[9]  = pertOutput.Cl; //Zq
            stabDerivOutput.stabDerivs[10] = pertOutput.Cd; //Xq
            stabDerivOutput.stabDerivs[11] = pertOutput.Cm; //Mq

            input.alphaDot   = 0;
            input.pitchValue = 0.1;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.1;                   //elevator derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.1;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.1;

            pertOutput.Cl *= -q * area / mass; // Rodhern: Replaced 'q' by '-q', so that formulas
            pertOutput.Cd *= -q * area / mass; //  for Ze and Xe match those for Zu and Xu.
            pertOutput.Cm *= q * area * MAC / Iy;

            stabDerivOutput.stabDerivs[12] = pertOutput.Cl; //Ze
            stabDerivOutput.stabDerivs[13] = pertOutput.Cd; //Xe
            stabDerivOutput.stabDerivs[14] = pertOutput.Cm; //Me

            //Lateral Mess

            input.pitchValue = 0;
            input.beta       = (beta + 2);

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);
            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / (2 * FARMathUtil.deg2rad);               //sideslip angle derivs
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / (2 * FARMathUtil.deg2rad);
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / (2 * FARMathUtil.deg2rad);

            pertOutput.Cy     *= q * area / mass;
            pertOutput.Cn     *= q * area * b / Iz;
            pertOutput.C_roll *= q * area * b / Ix;

            stabDerivOutput.stabDerivs[15] = pertOutput.Cy;     //Yb
            stabDerivOutput.stabDerivs[17] = pertOutput.Cn;     //Nb
            stabDerivOutput.stabDerivs[16] = pertOutput.C_roll; //Lb

            input.beta = beta;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.phiDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / 0.05;               //roll rate derivs
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / 0.05;
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / 0.05;

            pertOutput.Cy     *= q * area * b / (2 * mass * u0);
            pertOutput.Cn     *= q * area * b * b / (2 * Iz * u0);
            pertOutput.C_roll *= q * area * b * b / (2 * Ix * u0);

            stabDerivOutput.stabDerivs[18] = pertOutput.Cy;     //Yp
            stabDerivOutput.stabDerivs[20] = pertOutput.Cn;     //Np
            stabDerivOutput.stabDerivs[19] = pertOutput.C_roll; //Lp


            input.phiDot = 0;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.betaDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false); pertOutput.Cy = (pertOutput.Cy - nominalOutput.Cy) / 0.05f;                   //yaw rate derivs
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / 0.05f;
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / 0.05f;

            pertOutput.Cy     *= q * area * b / (2 * mass * u0);
            pertOutput.Cn     *= q * area * b * b / (2 * Iz * u0);
            pertOutput.C_roll *= q * area * b * b / (2 * Ix * u0);

            stabDerivOutput.stabDerivs[21] = pertOutput.Cy;     //Yr
            stabDerivOutput.stabDerivs[23] = pertOutput.Cn;     //Nr
            stabDerivOutput.stabDerivs[22] = pertOutput.C_roll; //Lr

            // Assign values to export variables
            stabDerivExport.craftmass      = mass;
            stabDerivExport.envpressure    = pressure;
            stabDerivExport.envtemperature = temperature;
            stabDerivExport.envdensity     = density;
            stabDerivExport.envsoundspeed  = sspeed;
            stabDerivExport.envg           = _instantCondition.CalculateAccelerationDueToGravity(body, alt);
            stabDerivExport.sitmach        = machNumber;
            stabDerivExport.sitdynpres     = q;
            stabDerivExport.siteffg        = effectiveG;

            return(new StabilityDerivExportOutput(stabDerivOutput, stabDerivExport));
        }
        public void Display()
        {
            //stabDerivHelp = GUILayout.Toggle(stabDerivHelp, "?", ButtonStyle, GUILayout.Width(200));

            GUILayout.Label(Localizer.Format("FAREditorStabDerivFlightCond"));
            GUILayout.BeginHorizontal();
            GUILayout.Label(Localizer.Format("FAREditorStabDerivPlanet"));
            _bodySettingDropdown.GUIDropDownDisplay();

            GUILayout.Label(Localizer.Format("FAREditorStabDerivAlt"));
            altitude = GUILayout.TextField(altitude, GUILayout.ExpandWidth(true));

            GUILayout.Label(Localizer.Format("FAREditorStabDerivMach"));
            machNumber = GUILayout.TextField(machNumber, GUILayout.ExpandWidth(true));

            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label(Localizer.Format("FAREditorStabDerivFlap"));
            _flapSettingDropdown.GUIDropDownDisplay();
            GUILayout.Label(Localizer.Format("FAREditorStabDerivSpoiler"));
            spoilersDeployed = GUILayout.Toggle(spoilersDeployed, spoilersDeployed ? Localizer.Format("FAREditorStabDerivSDeploy") : Localizer.Format("FAREditorStabDerivSRetract"), GUILayout.Width(100));
            GUILayout.EndHorizontal();

            if (GUILayout.Button(Localizer.Format("FAREditorStabDerivCalcButton"), GUILayout.Width(250.0F), GUILayout.Height(25.0F)))
            {
                CelestialBody body = _bodySettingDropdown.ActiveSelection;
                FARAeroUtil.UpdateCurrentActiveBody(body);
                //atm_temp_str = Regex.Replace(atm_temp_str, @"[^-?[0-9]*(\.[0-9]*)?]", "");
                //rho_str = Regex.Replace(rho_str, @"[^-?[0-9]*(\.[0-9]*)?]", "");
                machNumber = Regex.Replace(machNumber, @"[^-?[0-9]*(\.[0-9]*)?]", "");

                altitude = Regex.Replace(altitude, @"[^-?[0-9]*(\.[0-9]*)?]", "");
                double altitudeDouble = Convert.ToDouble(altitude);
                altitudeDouble *= 1000;


                double temp     = body.GetTemperature(altitudeDouble);
                double pressure = body.GetPressure(altitudeDouble);
                if (pressure > 0)
                {
                    //double temp = Convert.ToSingle(atm_temp_str);
                    double machDouble = Convert.ToSingle(machNumber);
                    machDouble = FARMathUtil.Clamp(machDouble, 0.001, float.PositiveInfinity);

                    double density = body.GetDensity(pressure, temp);

                    double sspeed = body.GetSpeedOfSound(pressure, density);
                    double vel    = sspeed * machDouble;

                    //UpdateControlSettings();

                    double q = vel * vel * density * 0.5f;

                    stabDerivOutput        = simManager.StabDerivCalculator.CalculateStabilityDerivs(vel, q, machDouble, 0, 0, 0, _flapSettingDropdown.ActiveSelection, spoilersDeployed, body, altitudeDouble);
                    simManager.vehicleData = stabDerivOutput;
                    SetAngleVectors(stabDerivOutput.stableAoA);
                }
                else
                {
                    PopupDialog.SpawnPopupDialog(new Vector2(0, 0), new Vector2(0, 0), "FARStabDerivError", Localizer.Format("FAREditorStabDerivError"), Localizer.Format("FAREditorStabDerivErrorExp"), Localizer.Format("FARGUIOKButton "), true, HighLogic.UISkin);
                }
            }
            GUILayout.BeginHorizontal();
            GUILayout.Label(Localizer.Format("FAREditorStabDerivAirProp"), GUILayout.Width(180));
            GUILayout.Label(Localizer.Format("FAREditorStabDerivMoI"), GUILayout.Width(160));
            GUILayout.Label(Localizer.Format("FAREditorStabDerivPoI"), GUILayout.Width(160));
            GUILayout.Label(Localizer.Format("FAREditorStabDerivLvlFl"), GUILayout.Width(140));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.BeginVertical(GUILayout.Width(180));
            GUILayout.Label(Localizer.Format("FAREditorStabDerivRefArea") + stabDerivOutput.area.ToString("G3") + " " + Localizer.Format("FARUnitMSq"));
            GUILayout.Label(Localizer.Format("FAREditorStabDerivScaledChord") + stabDerivOutput.MAC.ToString("G3") + " " + Localizer.Format("FARUnitM"));
            GUILayout.Label(Localizer.Format("FAREditorStabDerivScaledSpan") + stabDerivOutput.b.ToString("G3") + " " + Localizer.Format("FARUnitM"));
            GUILayout.EndVertical();


            GUILayout.BeginVertical(GUILayout.Width(160));
            GUILayout.Label(new GUIContent(Localizer.Format("FAREditorStabDerivIxx") + stabDerivOutput.stabDerivs[0].ToString("G6") + " " + Localizer.Format("FARUnitKgMSq"), Localizer.Format("FAREditorStabDerivIxxExp")));
            GUILayout.Label(new GUIContent(Localizer.Format("FAREditorStabDerivIyy") + stabDerivOutput.stabDerivs[1].ToString("G6") + " " + Localizer.Format("FARUnitKgMSq"), Localizer.Format("FAREditorStabDerivIyyExp")));
            GUILayout.Label(new GUIContent(Localizer.Format("FAREditorStabDerivIzz") + stabDerivOutput.stabDerivs[2].ToString("G6") + " " + Localizer.Format("FARUnitKgMSq"), Localizer.Format("FAREditorStabDerivIzzExp")));
            GUILayout.EndVertical();

            GUILayout.BeginVertical(GUILayout.Width(160));
            GUILayout.Label(new GUIContent(Localizer.Format("FAREditorStabDerivIxy") + stabDerivOutput.stabDerivs[24].ToString("G6") + " " + Localizer.Format("FARUnitKgMSq"), Localizer.Format("FAREditorStabDerivIxyExp")));
            GUILayout.Label(new GUIContent(Localizer.Format("FAREditorStabDerivIyz") + stabDerivOutput.stabDerivs[25].ToString("G6") + " " + Localizer.Format("FARUnitKgMSq"), Localizer.Format("FAREditorStabDerivIyzExp")));
            GUILayout.Label(new GUIContent(Localizer.Format("FAREditorStabDerivIxz") + stabDerivOutput.stabDerivs[26].ToString("G6") + " " + Localizer.Format("FARUnitKgMSq"), Localizer.Format("FAREditorStabDerivIxzExp")));
            GUILayout.EndVertical();

            GUILayout.BeginVertical(GUILayout.Width(140));
            GUILayout.Label(new GUIContent(Localizer.Format("FAREditorStabDerivu0") + stabDerivOutput.nominalVelocity.ToString("G6") + " " + Localizer.Format("FARUnitMPerSec"), Localizer.Format("FAREditorStabDerivu0Exp")));
            GUILayout.BeginHorizontal();
            GUILayout.Label(new GUIContent(Localizer.Format("FARAbbrevCl") + ": " + stabDerivOutput.stableCl.ToString("G3"), Localizer.Format("FAREditorStabDerivClExp")));
            GUILayout.Label(new GUIContent(Localizer.Format("FARAbbrevCd") + ": " + stabDerivOutput.stableCd.ToString("G3"), Localizer.Format("FAREditorStabDerivCdExp")));
            GUILayout.EndHorizontal();
            GUILayout.Label(new GUIContent(Localizer.Format("FARAbbrevAoA") + ": " + stabDerivOutput.stableAoAState + stabDerivOutput.stableAoA.ToString("G6") + " " + Localizer.Format("FARUnitDeg"), Localizer.Format("FAREditorStabDerivAoAExp")));
            GUILayout.EndVertical();

            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label(Localizer.Format("FAREditorLongDeriv"), GUILayout.Width(160));
            GUILayout.EndHorizontal();

            GUIStyle BackgroundStyle = new GUIStyle(GUI.skin.box);

            BackgroundStyle.hover = BackgroundStyle.active = BackgroundStyle.normal;

            GUILayout.BeginVertical(BackgroundStyle);
            GUILayout.BeginHorizontal();
            GUILayout.Label(Localizer.Format("FAREditorDownVelDeriv"), GUILayout.Width(160));
            GUILayout.Label(Localizer.Format("FAREditorFwdVelDeriv"), GUILayout.Width(160));
            GUILayout.Label(Localizer.Format("FAREditorPitchRateDeriv"), GUILayout.Width(160));
            GUILayout.Label(Localizer.Format("FAREditorPitchCtrlDeriv"), GUILayout.Width(160));
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            StabilityLabel(Localizer.Format("FAREditorZw"), stabDerivOutput.stabDerivs[3], " " + Localizer.Format("FARUnitInvSec"), Localizer.Format("FAREditorZwExp"), 160, -1);
            StabilityLabel(Localizer.Format("FAREditorZu"), stabDerivOutput.stabDerivs[6], " " + Localizer.Format("FARUnitInvSec"), Localizer.Format("FAREditorZuExp"), 160, -1);
            StabilityLabel(Localizer.Format("FAREditorZq"), stabDerivOutput.stabDerivs[9], " " + Localizer.Format("FARUnitMPerSec"), Localizer.Format("FAREditorZqExp"), 160, 0);
            StabilityLabel(Localizer.Format("FAREditorZDeltae"), stabDerivOutput.stabDerivs[12], " " + Localizer.Format("FARUnitMPerSecSq"), Localizer.Format("FAREditorZDeltaeExp"), 160, 0);
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            StabilityLabel(Localizer.Format("FAREditorXw"), stabDerivOutput.stabDerivs[4], " " + Localizer.Format("FARUnitInvSec"), Localizer.Format("FAREditorXwExp"), 160, 0);
            StabilityLabel(Localizer.Format("FAREditorXu"), stabDerivOutput.stabDerivs[7], " " + Localizer.Format("FARUnitInvSec"), Localizer.Format("FAREditorXuExp"), 160, -1);
            StabilityLabel(Localizer.Format("FAREditorXq"), stabDerivOutput.stabDerivs[10], " " + Localizer.Format("FARUnitMPerSec"), Localizer.Format("FAREditorXqExp"), 160, 0);
            StabilityLabel(Localizer.Format("FAREditorXDeltae"), stabDerivOutput.stabDerivs[13], " " + Localizer.Format("FARUnitMPerSecSq"), Localizer.Format("FAREditorXDeltaeExp"), 160, 0);
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            StabilityLabel(Localizer.Format("FAREditorMw"), stabDerivOutput.stabDerivs[5], " " + Localizer.Format("FARUnitInvMSec"), Localizer.Format("FAREditorMwExp"), 160, -1);
            StabilityLabel(Localizer.Format("FAREditorMu"), stabDerivOutput.stabDerivs[8], " " + Localizer.Format("FARUnitInvMSec"), Localizer.Format("FAREditorMuExp"), 160, 0);
            StabilityLabel(Localizer.Format("FAREditorMq"), stabDerivOutput.stabDerivs[11], " " + Localizer.Format("FARUnitInvSec"), Localizer.Format("FAREditorMqExp"), 160, -1);
            StabilityLabel(Localizer.Format("FAREditorMDeltae"), stabDerivOutput.stabDerivs[14], " " + Localizer.Format("FARUnitInvSecSq"), Localizer.Format("FAREditorMDeltaeExp"), 160, 1);
            GUILayout.EndHorizontal();
            GUILayout.EndVertical();

            GUILayout.BeginHorizontal();
            GUILayout.Label(Localizer.Format("FAREditorLatDeriv"), GUILayout.Width(160));
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            GUILayout.Label(Localizer.Format("FAREditorSideslipDeriv"), GUILayout.Width(160));
            GUILayout.Label(Localizer.Format("FAREditorRollRateDeriv"), GUILayout.Width(160));
            GUILayout.Label(Localizer.Format("FAREditorYawRateDeriv"), GUILayout.Width(160));
            GUILayout.EndHorizontal();
            GUILayout.BeginVertical(BackgroundStyle);
            GUILayout.BeginHorizontal();
            StabilityLabel(Localizer.Format("FAREditorYβ"), stabDerivOutput.stabDerivs[15], " " + Localizer.Format("FARUnitMPerSecSq"), Localizer.Format("FAREditorYβExp"), 160, -1);
            StabilityLabel(Localizer.Format("FAREditorYp"), stabDerivOutput.stabDerivs[18], " " + Localizer.Format("FARUnitMPerSec"), Localizer.Format("FAREditorYpExp"), 160, 0);
            StabilityLabel(Localizer.Format("FAREditorYr"), stabDerivOutput.stabDerivs[21], " " + Localizer.Format("FARUnitMPerSec"), Localizer.Format("FAREditorYrExp"), 160, 1);
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            StabilityLabel(Localizer.Format("FAREditorLβ"), stabDerivOutput.stabDerivs[16], " " + Localizer.Format("FARUnitInvSecSq"), Localizer.Format("FAREditorLβExp"), 160, -1);
            StabilityLabel(Localizer.Format("FAREditorLp"), stabDerivOutput.stabDerivs[19], " " + Localizer.Format("FARUnitInvSec"), Localizer.Format("FAREditorLpExp"), 160, -1);
            StabilityLabel(Localizer.Format("FAREditorLr"), stabDerivOutput.stabDerivs[22], " " + Localizer.Format("FARUnitInvSec"), Localizer.Format("FAREditorLrExp"), 160, 1);
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            StabilityLabel(Localizer.Format("FAREditorNβ"), stabDerivOutput.stabDerivs[17], " " + Localizer.Format("FARUnitInvSecSq"), Localizer.Format("FAREditorNβExp"), 160, 1);
            StabilityLabel(Localizer.Format("FAREditorNp"), stabDerivOutput.stabDerivs[20], " " + Localizer.Format("FARUnitInvSec"), Localizer.Format("FAREditorNpExp"), 160, 0);
            StabilityLabel(Localizer.Format("FAREditorNr"), stabDerivOutput.stabDerivs[23], " " + Localizer.Format("FARUnitInvSec"), Localizer.Format("FAREditorNrExp"), 160, -1);
            GUILayout.EndHorizontal();
            GUILayout.EndVertical();

            DrawTooltip();
        }
Example #33
0
        protected string GetThrustInfo()
        {
            string output = "";

            if (engineSolver == null || !(engineSolver is SolverRF))
            {
                CreateEngine();
            }
            rfSolver.SetPropellantStatus(true, true);
            // get stats
            double pressure = 101.325d, temperature = 288.15d, density = 1.225d;

            if (Planetarium.fetch != null)
            {
                CelestialBody home = Planetarium.fetch.Home;
                if (home != null)
                {
                    pressure    = home.GetPressure(0d);
                    temperature = home.GetTemperature(0d);
                    density     = home.GetDensity(pressure, temperature);
                }
            }
            ambientTherm = new EngineThermodynamics();
            ambientTherm.FromAmbientConditions(pressure, temperature, density);
            inletTherm = new EngineThermodynamics();
            inletTherm.CopyFrom(ambientTherm);
            currentThrottle        = 1f;
            lastPropellantFraction = 1d;
            bool oldE = EngineIgnited;

            EngineIgnited = true;
            bool oldIg = ignited;

            ignited = true;

            rfSolver.UpdateThrustRatio(1d);
            rfSolver.SetPropellantStatus(true, true);

            UpdateSolver(ambientTherm, 0d, Vector3d.zero, 0d, true, true, false);
            double thrustASL = (engineSolver.GetThrust() * 0.001d);

            if (atmChangeFlow) // If it's a jet
            {
                output += "<b>Static Thrust: </b>" + (thrustASL).ToString("0.0##") + " kN" + ThrottleString();
                if (useVelCurve) // if thrust changes with mach
                {
                    float vMin, vMax, tMin, tMax;
                    velCurve.FindMinMaxValue(out vMin, out vMax, out tMin, out tMax); // get the max mult, and thus report maximum thrust possible.
                    output += "\n<b>Max. Thrust: </b>" + (thrustASL * vMax).ToString("0.0##") + " kN Mach " + tMax.ToString("0.#");
                }
            }
            else
            {
                // get stats again
                double spaceHeight = 131000d;
                pressure = 0d;
                density  = 0d;
                if (Planetarium.fetch != null)
                {
                    CelestialBody home = Planetarium.fetch.Home;
                    if (home != null)
                    {
                        temperature = home.GetTemperature(home.atmosphereDepth + 1d);
                        spaceHeight = home.atmosphereDepth + 1000d;
                    }
                }
                else
                {
                    temperature = PhysicsGlobals.SpaceTemperature;
                }
                ambientTherm.FromAmbientConditions(pressure, temperature, density);
                UpdateSolver(ambientTherm, spaceHeight, Vector3d.zero, 0d, true, true, false);
                double thrustVac = (engineSolver.GetThrust() * 0.001d);

                if (thrustASL != thrustVac)
                {
                    output += (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust (Vac.): </b>" + (thrustVac).ToString("0.0##") + " kN" + ThrottleString()
                              + "\n" + (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust (ASL): </b>" + (thrustASL).ToString("0.0##") + " kN";
                }
                else
                {
                    output += (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust: </b>" + (thrustVac).ToString("0.0##") + " kN" + ThrottleString();
                }
            }
            output       += "\n";
            EngineIgnited = oldE;
            ignited       = oldIg;
            return(output);
        }
 public static float ComputeCutoffAlt(CelestialBody body, float cutoffDensity, float stepSize=100)
 {
     //This unfortunately doesn't seem to be coming up with the right altitude for Kerbin (~23km, it finds ~27km)
     double dens = 0;
     float alt = (float)body.atmosphereDepth;
     while (alt > 0)
     {
         dens = body.GetDensity(FlightGlobals.getStaticPressure(alt, body), body.atmosphereTemperatureCurve.Evaluate(alt)); //body.atmospherePressureCurve.Evaluate(alt)
         //Debug.Log("[SR] Alt: " + alt + " Pres: " + dens);
         if (dens < cutoffDensity)
             alt -= stepSize;
         else
             break;
     }
     return alt;
 }