Example #1
0
        // set boost parameters:
        // maximum MAP, the two boost pressures to maintain, the two rated altitudes (km),
        // the cost for the second boost mode, and the switch altitude (in km), or -1f for auto
        /// <summary>
        /// Set turbo/supercharger parameters
        /// </summary>
        /// <param name="wastegate">maximum MAP</param>
        /// <param name="boost0">boost mode 1 multiplier</param>
        /// <param name="boost1">boost mode 2 multiplier (or zero for 1-stage)</param>
        /// <param name="rated0">rated altitude in km for mode 1</param>
        /// <param name="rated1">rated altitude in km for mode 2</param>
        /// <param name="cost1">cost in HP for mode 2</param>
        /// <param name="switchAlt"></param>
        /// <param name="turbo"></param>
        /// <returns></returns>
        public bool SetBoostParams(double wastegate, double boost0, double boost1, double rated0, double rated1, double cost1, double switchAlt, bool turbo)
        {
            bool   retVal = false;
            double pres0, pres1, switchpres;

            // get pressure at rated alts
            CelestialBody body = FindHomeworld();

            if (body != null)
            {
                pres0      = body.GetPressure(rated0) * 1000;
                pres1      = body.GetPressure(rated1) * 1000;
                switchpres = body.GetPressure(switchAlt) * 1000;
            }
            else
            {
                pres0      = GetPressure(rated0);
                pres1      = GetPressure(rated1);
                switchpres = GetPressure(switchAlt);
            }

            if (boost0 > 0d)
            {
                _boostMults[0] = boost0 / pres0;
                _maxMP         = wastegate;
                retVal         = true;
            }
            if (boost1 > 0d)
            {
                _boostMults[1] = boost1 / pres1;
                _boostCosts[1] = cost1;
            }
            else
            {
                _boostMults[1] = 0d;
                _boostCosts[1] = 0d;
            }
            if (switchAlt >= 0d)
            {
                _boostSwitch = switchpres;
            }
            else
            {
                _boostSwitch = 0d;
            }
            MonoBehaviour.print("*AJE* Setting boost params. MaxMP = " + wastegate + ", boosts = " + _boostMults[0] + "/" + _boostMults[1] + ", switch " + _boostSwitch + " from " + boost0 + "@" + rated0 + ", " + boost1 + "@" + rated1);
            _hasSuper = !turbo && boost0 > 1.0d;
            return(retVal);
        }
Example #2
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);
        }
Example #3
0
        private List <DisplayItem> getAtmData(CelestialBody body)
        {
            var items = new List <DisplayItem>();

            if (!body.atmosphere)
            {
                return(items);
            }

            var maxHeight = DisplayItem.Create("Atmopshere Ends: ", body.atmosphereDepth.ToString("N0") + "m");

            items.Add(maxHeight);
            var oxygen = DisplayItem.Create("Oxygen?: ", body.atmosphereContainsOxygen ? "Yes" : "No");

            items.Add(oxygen);

            var kPAASL      = body.GetPressure(0d);
            var atmASL      = kPAASL * PhysicsGlobals.KpaToAtmospheres;
            var aslDisplay  = string.Format("{0}kPa ({1}atm)", kPAASL.ToString("F2"), atmASL.ToString("F2"));
            var aslPressure = DisplayItem.Create("Atm. ASL: ", aslDisplay);

            items.Add(aslPressure);

            var surfaceTemp = DisplayItem.Create("Surface Temp: ", body.GetTemperature(0.0).ToString("0.##") + "K");

            items.Add(surfaceTemp);

            return(items);
        }
Example #4
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 #5
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));
        }
Example #6
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 #7
0
        private void UpdateEditor()
        {
            UpdatePanels();

            if (!_updateSimulator)
            {
                return;
            }

            _updateSimulator = false;

            try
            {
                SimManager.Gravity = _currentBody.GeeASL * GRAVITY;

                if (Atmosphere)
                {
                    SimManager.Atmosphere = _currentBody.GetPressure(_atmosphereDepth) * PhysicsGlobals.KpaToAtmospheres;
                }
                else
                {
                    SimManager.Atmosphere = 0;
                }

                SimManager.Mach = _mach;

                SimManager.RequestSimulation();
                SimManager.TryStartSimulation();
            }
            catch (Exception e)
            {
                BasicLogger.Exception(e, "BasicDeltaV.Update()");
            }
        }
        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);
        }
        // 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 #10
0
        public static float ASLPressure(this CelestialBody body)
        {
            /* body.atmodspherePressureSeaLevel seems to fail sometimes for some reason,
             * for Laythe is 0.6 atm but sometimes it would be 0.8 atm. f**k me */
//            return (float)body.atmospherePressureSeaLevel;
            return((float)body.GetPressure(0));
        }
Example #11
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);
        }
Example #12
0
        public void Update()
        {
            // in editor and flight, update ui button label
            Events["Toggle"].guiName = Lib.StatusToggle(title, running ? "running" : "stopped");

            // if in flight, and the stock planet resource system is online
            if (Lib.IsFlight() && ResourceMap.Instance != null)
            {
                // shortcut
                CelestialBody body = vessel.mainBody;

                // determine if overall situation is valid for extraction
                bool valid = false;
                if (deployed)
                {
                    switch (type)
                    {
                    case 0: valid = vessel.Landed && GroundContact(); break;

                    case 1: valid = body.ocean && (vessel.Splashed || vessel.altitude < 0.0); break;

                    case 2: valid = body.atmosphere && vessel.altitude < body.atmosphereDepth; break;

                    case 3: valid = vessel.altitude > body.atmosphereDepth || !body.atmosphere; break;
                    }
                }

                // if situation is valid
                double abundance = 0.0;
                if (valid)
                {
                    // get abundance
                    AbundanceRequest request = new AbundanceRequest
                    {
                        ResourceType = (HarvestTypes)type,
                        ResourceName = resource,
                        BodyId       = body.flightGlobalsIndex,
                        Latitude     = vessel.latitude,
                        Longitude    = vessel.longitude,
                        Altitude     = vessel.altitude,
                        CheckForLock = false
                    };
                    abundance = ResourceMap.Instance.GetAbundance(request);
                }

                // determine if resources can be harvested
                // - invalid conditions
                // - abundance below threshold
                // - pressure below threshold
                starved = !valid || abundance <= min_abundance || (type == 2 && body.GetPressure(vessel.altitude) <= min_pressure);

                // update ui
                Events["Toggle"].guiActive    = valid;
                Fields["Abundance"].guiActive = valid;
                Fields["Abundance"].guiName   = Lib.BuildString(resource, " abundance");
                Abundance = abundance > double.Epsilon ? Lib.HumanReadablePerc(abundance, "F2") : "none";
            }
        }
        public static List <CrustalResource> GenerateCompositionFromCelestialBody(CelestialBody celestialBody) // generates Crustal composition based on Crustal characteristics
        {
            var bodyCrustalComposition = new List <CrustalResource>();                                         // instantiate a new list that this function will be returning

            try
            {
                // return empty if there's no crust
                if (!celestialBody.hasSolidSurface)
                {
                    return(bodyCrustalComposition);
                }

                // Lookup homeworld
                CelestialBody homeworld = FlightGlobals.Bodies.SingleOrDefault(b => b.isHomeWorld);

                if (homeworld == null)
                {
                    return(new List <CrustalResource>());
                }

                double pressureAtSurface = celestialBody.GetPressure(0);

                if (celestialBody.Mass < homeworld.Mass * 10 && pressureAtSurface < 1000)
                {
                    if (pressureAtSurface > 200)
                    {
                        // it is Venus-like/Eve-like, use Eve as a template
                        bodyCrustalComposition = GetCrustalCompositionForBody("Eve");
                    }
                    else if (celestialBody.Mass > (homeworld.Mass / 2) && celestialBody.Mass < homeworld.Mass && pressureAtSurface < 100) // it's at least half as big as the homeworld and has significant atmosphere
                    {
                        // it is Laythe-like, use Laythe as a template
                        bodyCrustalComposition = GetCrustalCompositionForBody("Laythe");
                    }
                    else if (celestialBody.atmosphereContainsOxygen)
                    {
                        // it is Earth-like, use Earth as a template
                        bool hasEarth = FlightGlobals.Bodies.Any(b => b.name == "Earth"); // is there a planet called Earth present in KSP?

                        bodyCrustalComposition = GetCrustalCompositionForBody(hasEarth ? "Earth" : "Kerbin");
                    }
                    else
                    {
                        // it is a Mars-like, use Mars as template
                        bool hasMars = FlightGlobals.Bodies.Any(b => b.name == "Mars"); // is there a planet called Mars present in KSP?

                        bodyCrustalComposition = GetCrustalCompositionForBody(hasMars ? "Mars" : "Duna");
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.LogError("[KSPI]: Exception while generating Crustal resource composition from celestial properties : " + ex.ToString());
            }

            return(bodyCrustalComposition);
        }
        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);
        }
        // return the reason why resource can't be harvested, or an empty string otherwise
        string DetectIssue(double abundance)
        {
            // shortcut
            CelestialBody body = vessel.mainBody;

            // check situation
            switch (type)
            {
            case 0:
                bool land_valid = vessel.Landed && GroundContact();
                if (!land_valid)
                {
                    return("no ground contact");
                }
                break;

            case 1:
                bool ocean_valid = body.ocean && (vessel.Splashed || vessel.altitude < 0.0);
                if (!ocean_valid)
                {
                    return("not in ocean");
                }
                break;

            case 2:
                bool atmo_valid = body.atmosphere && vessel.altitude < body.atmosphereDepth;
                if (!atmo_valid)
                {
                    return("not in atmosphere");
                }
                break;

            case 3:
                bool space_valid = vessel.altitude > body.atmosphereDepth || !body.atmosphere;
                if (!space_valid)
                {
                    return("not in space");
                }
                break;
            }

            // check against pressure
            if (type == 2 && body.GetPressure(vessel.altitude) < min_pressure)
            {
                return("pressure below threshold");
            }

            // check against abundance
            if (abundance < min_abundance)
            {
                return("abundance below threshold");
            }

            // all good
            return(string.Empty);
        }
Example #16
0
 public StabilityDerivExportOutput CalculateStabilityDerivs(CelestialBody body, double alt, double machNumber, int flapSetting, bool spoilers)
 {
     if (body.GetPressure(alt) > 0)
     {
         return(CalculateStabilityDerivs(body, alt, machNumber, flapSetting, spoilers, 0, 0));
     }
     else
     {
         return(null);
     }
 }
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));
                body.GetSolarAtmosphericEffects(cos_a, density, out _, out double stockFluxFactor);
                return(stockFluxFactor);
            }
            return(1.0);
        }
Example #18
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);
        }
Example #19
0
 /// <summary>
 /// Gets the air pressure (in Pascals) for the specified altitude (above sea level, in meters) on the specified body.
 /// </summary>
 public static double GetPressure(double altitude, CelestialBody body)
 {
     if (!body.atmosphere)
     {
         return(0);
     }
     if (altitude > body.atmosphereDepth)
     {
         return(0);
     }
     return(body.GetPressure(altitude) * 1000d);
 }
        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);
        }
        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 #22
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 #23
0
        // return true if a vessel is inside a breathable atmosphere
        public static bool Breathable(Vessel v, bool underwater)
        {
            // a vessel is inside a breathable atmosphere if:
            // - it is inside an atmosphere
            // - the atmospheric pressure is above 25kPA
            // - the body atmosphere is flagged as containing oxygen
            // - it isn't underwater
            CelestialBody body = v.mainBody;

            return(body.atmosphereContainsOxygen &&
                   body.GetPressure(v.altitude) > 25.0 &&
                   !underwater);
        }
Example #24
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 #25
0
        // return true if inside a breathable atmosphere
        public static bool Breathable(Vessel v, bool underwater)
        {
            // atmosphere is breathable if:
            // - vessel body is the home body
            // - the body has an atmosphere, and it contain oxygen
            // - the pressure is above 25kPA
            // - the vessel is not underwater
            CelestialBody body = v.mainBody;

            return(body == FlightGlobals.GetHomeBody() &&
                   body.atmosphereContainsOxygen &&
                   body.GetPressure(v.altitude) > 25.0 &&
                   !underwater);
        }
        private static void SupplementWithHelium3(IDictionary <string, AtmosphericResource> bodyAtmosphericComposition, CelestialBody body)
        {
            // if helium3 is undefined, but liquid helium is, derive it
            if (!bodyAtmosphericComposition.ContainsKey(KITResourceSettings.Helium3Lqd) &&
                bodyAtmosphericComposition.TryGetValue(KITResourceSettings.Helium4Lqd, out var heliumLqd))
            {
                var helium3Abundance = body.GetPressure(0) > 1000
                    ? heliumLqd.ResourceAbundance * 0.001
                    : heliumLqd.ResourceAbundance * 1.38e-6;

                Debug.Log("[KSPI]: Added helium-3 to atmosphere either abundance " + helium3Abundance);
                bodyAtmosphericComposition.Add(KITResourceSettings.Helium3Lqd,
                                               new AtmosphericResource(KITResourceSettings.Helium3Lqd, helium3Abundance, "Helium-3"));
            }
            // if helium3 is undefined, but helium gas is, derive it
            else if (!bodyAtmosphericComposition.ContainsKey(KITResourceSettings.Helium3Lqd) &&
                     bodyAtmosphericComposition.TryGetValue(KITResourceSettings.Helium4Gas, out var heliumGas))
            {
                var helium3Abundance = body.GetPressure(0) > 1000
                    ? heliumGas.ResourceAbundance * 0.001
                    : heliumGas.ResourceAbundance * 1.38e-6;

                Debug.Log("[KSPI]: Added helium-3 to atmosphere either abundance " + helium3Abundance);
                bodyAtmosphericComposition.Add(KITResourceSettings.Helium3Lqd,
                                               new AtmosphericResource(KITResourceSettings.Helium3Lqd, helium3Abundance, "Helium-3"));
            }
            else if (bodyAtmosphericComposition.ContainsKey(KITResourceSettings.Helium3Lqd))
            {
                Debug.Log("[KSPI]: Helium-3 is already present in atmosphere specification at " +
                          bodyAtmosphericComposition[KITResourceSettings.Helium3Lqd].ResourceAbundance);
            }
            else
            {
                Debug.Log("[KSPI]: No Helium is present in atmosphere specification, helium-4 will not be added");
            }
        }
Example #27
0
        // vessel.staticPressurekPa * PhysicsGlobals.KpaToAtmospheres

        protected void StartSimulation()
        {
            simBody            = HighLogic.LoadedSceneIsEditor ? editorBody ?? Planetarium.fetch.Home : vessel.mainBody;
            SimManager.Gravity = 9.81 * simBody.GeeASL;

            SimManager.Atmosphere     = simBody.atmosphere ? simBody.GetPressure(0) : 0; // TODO : use the current atmo ?
            SimManager.Mach           = HighLogic.LoadedSceneIsEditor ? 1 : vessel.mach;
            SimManager.vectoredThrust = dVLinearThrust;

            Profiler.BeginSample("MechJebModuleStageStats.StartSimulation()");

            SimManager.RequestSimulation();
            SimManager.TryStartSimulation();
            Profiler.EndSample();
        }
Example #28
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 #29
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 #30
0
        private void GenerateHighlightingData(ShipConstruct ship, CelestialBody body, float altitude, float speed, float aoa)
        {
            float mach, atmDensity;

            lock (body)
            {
                atmDensity = (float)Extensions.KSPClassExtensions.GetDensity(body, altitude);
                mach       = speed / (float)body.GetSpeedOfSound(body.GetPressure(altitude), atmDensity);
            }

            int count = ship.parts.Count;

            highlightingData = new PartAeroData[count];

            Vector3 inflow = AeroPredictor.InflowVect(aoa);

            float pseudoReDragMult;

            lock (PhysicsGlobals.DragCurvePseudoReynolds)
                pseudoReDragMult = PhysicsGlobals.DragCurvePseudoReynolds.Evaluate(atmDensity * speed);

            for (int i = 0; i < count; i++)
            {
                if (WindTunnelSettings.HighlightIgnoresLiftingSurfaces && ship.parts[i].HasModuleImplementing <ModuleLiftingSurface>())
                {
                    highlightingData[i] = new PartAeroData(0, 0, ship.parts[i].mass);
                    continue;
                }

                VesselCache.SimulatedPart simPart = VesselCache.SimulatedPart.Borrow(ship.parts[i], null);
                Vector3 partForce = simPart.GetAero(inflow, mach, pseudoReDragMult);

                ModuleLiftingSurface liftingSurface = ship.parts[i].FindModuleImplementing <ModuleLiftingSurface>();
                if (liftingSurface != null)
                {
                    VesselCache.SimulatedLiftingSurface simLiftSurf = VesselCache.SimulatedLiftingSurface.Borrow(liftingSurface, simPart);
                    partForce += simLiftSurf.GetForce(inflow, mach);
                    simLiftSurf.Release();
                }
                simPart.Release();
                //Vector3 partForce = highlightingVessel.parts[i].GetAero(inflow, mach, pseudoReDragMult);
                //Vector3 partForce = StockAeroUtil.SimAeroForce(body, new ShipConstruct("test", "", new List<Part>() { EditorLogic.fetch.ship.parts[i] }), inflow * speed, altitude);
                partForce = AeroPredictor.ToFlightFrame(partForce, aoa);  // (Quaternion.AngleAxis((aoa * 180 / Mathf.PI), Vector3.left) * partForce);

                highlightingData[i] = new PartAeroData(Math.Abs(partForce.z), Math.Abs(partForce.y), ship.parts[i].mass);
            }
        }
Example #31
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);
        }
        /// <summary>
        /// Initialize standard conditions
        /// Standard pressure is 101325 Pa, temperature is 288.15 K
        /// </summary>
        /// <param name="usePlanetarium">If true (and planeterium available), will get conditions from sea level at home body</param>
        public static EngineThermodynamics StandardConditions(bool usePlanetarium = false)
        {
            double P = 101325d;
            double T = 288.15d;

            if (usePlanetarium && Planetarium.fetch != null)
            {
                CelestialBody home = Planetarium.fetch.Home;
                if (home != null)
                {
                    P = home.GetPressure(0d) * 1000d;
                    T = home.GetTemperature(0d);
                }
            }

            return(new EngineThermodynamics(P: P, T: T));
        }
Example #33
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);
        }
        //redraw the picture of the planned flight path
        public static void UpdateAtmoTexture(Texture2D texture, CelestialBody mainBody, double maxAltitude, bool realAtmo = false)
        {
            double scale = maxAltitude / texture.height; //meters per pixel

            double maxAtmosphereAltitude = mainBody.RealMaxAtmosphereAltitude();
            double pressureSeaLevel = mainBody.atmospherePressureSeaLevel;

            for (int y = 0; y < texture.height; y++)
            {
                double alt = scale * y;

                if (realAtmo)
                {
                    alt = mainBody.GetPressure(alt) / pressureSeaLevel;
                }
                else
                {
                    alt = 1.0 - alt / maxAtmosphereAltitude;
                }

                float v = (float)(mainBody.atmosphere ? alt : 0.0F);
                Color c = new Color(0.0F, 0.0F, v);

                for (int x = 0; x < texture.width; x++)
                {
                    texture.SetPixel(x, y, c);

                    if (mainBody.atmosphere && (int)(maxAtmosphereAltitude / scale) == y)
                        texture.SetPixel(x, y, XKCDColors.LightGreyBlue);
                }
            }

            texture.Apply();
        }
        protected void StartSimulation()
        {
            simBody = HighLogic.LoadedSceneIsEditor ? editorBody ?? Planetarium.fetch.Home : vessel.mainBody;
            SimManager.Gravity = 9.81 * simBody.GeeASL;

            SimManager.Atmosphere = (HighLogic.LoadedSceneIsEditor ? (simBody.atmosphere ? simBody.GetPressure(0) : 0) : vessel.staticPressurekPa) * PhysicsGlobals.KpaToAtmospheres;
            SimManager.Mach = HighLogic.LoadedSceneIsEditor ? 1 : vessel.mach;
            SimManager.vectoredThrust = dVLinearThrust;
            SimManager.Body = simBody;

            Profiler.BeginSample("MechJebModuleStageStats.StartSimulation()");

            SimManager.RequestSimulation();
            SimManager.TryStartSimulation();
            Profiler.EndSample();
        }
Example #36
0
        //*******************************************************
		public static Vector3 SimAeroForce(List<Part> parts, CelestialBody body, Vector3 v_wrld_vel, double altitude, double latitude = 0.0)
        {
            double pressure = body.GetPressure(altitude);
            // Lift and drag for force accumulation.
            Vector3d total_lift = Vector3d.zero;
            Vector3d total_drag = Vector3d.zero;

            // dynamic pressure for standard drag equation
            double rho = GetDensity(altitude, body);
            double dyn_pressure = 0.0005 * rho * v_wrld_vel.sqrMagnitude;

            if (rho <= 0)
            {
                return Vector3.zero;
            }

            double soundSpeed = body.GetSpeedOfSound(pressure, rho);
            double mach = v_wrld_vel.magnitude / soundSpeed;
            if (mach > 25.0) { mach = 25.0; }

            // Loop through all parts, accumulating drag and lift.
			foreach(Part p in parts)
            {
                // need checks on shielded components
                if (p.ShieldedFromAirstream || p.Rigidbody == null)
                {
                    continue;
                }
                
                // Get Drag
                Vector3 sim_dragVectorDir = v_wrld_vel.normalized;
                Vector3 sim_dragVectorDirLocal = -(p.transform.InverseTransformDirection(sim_dragVectorDir));

                Vector3 liftForce = new Vector3(0, 0, 0);

                switch(p.dragModel)
                {
                    case Part.DragModel.DEFAULT:
                    case Part.DragModel.CUBE:
					SmartDragCubeList cubes = new SmartDragCubeList(p, parts);

                        DragCubeList.CubeData p_drag_data;

                        float drag;
                        if (cubes.None) // since 1.0.5, some parts don't have drag cubes (for example fuel lines and struts)
                        {
                            drag = p.maximum_drag;
                        }
                        else
                        {
                            p_drag_data = cubes.AddSurfaceDragDirection(-sim_dragVectorDirLocal, (float)mach);

                            drag = p_drag_data.areaDrag * PhysicsGlobals.DragCubeMultiplier;

                            liftForce = p_drag_data.liftForce;
                        }

                        double sim_dragScalar = dyn_pressure * (double)drag * PhysicsGlobals.DragMultiplier;
                        total_drag += -(Vector3d)sim_dragVectorDir * sim_dragScalar;

                        break;

                    case Part.DragModel.SPHERICAL:
                        total_drag += -(Vector3d)sim_dragVectorDir * (double)p.maximum_drag;
                        break;

                    case Part.DragModel.CYLINDRICAL:
                        total_drag += -(Vector3d)sim_dragVectorDir * (double)Mathf.Lerp(p.minimum_drag, p.maximum_drag, Mathf.Abs(Vector3.Dot(p.partTransform.TransformDirection(p.dragReferenceVector), sim_dragVectorDir)));
                        break;

                    case Part.DragModel.CONIC:
                        total_drag += -(Vector3d)sim_dragVectorDir * (double)Mathf.Lerp(p.minimum_drag, p.maximum_drag, Vector3.Angle(p.partTransform.TransformDirection(p.dragReferenceVector), sim_dragVectorDir) / 180f);
                        break;

                    default:
                        // no drag to apply
                        break;
                }

                // If it isn't a wing or lifter, get body lift.
                if (!p.hasLiftModule)
                {
                    float simbodyLiftScalar = p.bodyLiftMultiplier * PhysicsGlobals.BodyLiftMultiplier * (float)dyn_pressure;
                    simbodyLiftScalar *= PhysicsGlobals.GetLiftingSurfaceCurve("BodyLift").liftMachCurve.Evaluate((float)mach);
                    Vector3 bodyLift = p.transform.rotation * (simbodyLiftScalar * liftForce);
                    bodyLift = Vector3.ProjectOnPlane(bodyLift, sim_dragVectorDir);
                    // Only accumulate forces for non-LiftModules
                    total_lift += bodyLift;
                }

                // Find ModuleLifingSurface for wings and liftforce.
                // Should catch control surface as it is a subclass
				foreach (var m in p.Modules.OfType<ModuleLiftingSurface>())
                {
                    float mcs_mod = 1.0f;
                    double liftQ = dyn_pressure * 1000;
                    ModuleLiftingSurface wing = (ModuleLiftingSurface)m;
                    Vector3 nVel = Vector3.zero;
                    Vector3 liftVector = Vector3.zero;
                    float liftdot;
                    float absdot;
                    wing.SetupCoefficients(v_wrld_vel, out nVel, out liftVector, out liftdot, out absdot);

                    float simLiftScalar = Mathf.Sign(liftdot) * wing.liftCurve.Evaluate(absdot) * wing.liftMachCurve.Evaluate((float)mach);
                    simLiftScalar *= wing.deflectionLiftCoeff;
                    simLiftScalar = (float)(liftQ * (double)(PhysicsGlobals.LiftMultiplier * simLiftScalar));

                    float simdragScalar = wing.dragCurve.Evaluate(absdot) * wing.dragMachCurve.Evaluate((float)mach);
                    simdragScalar *= wing.deflectionLiftCoeff;
                    simdragScalar = (float)(liftQ * (double)(simdragScalar * PhysicsGlobals.LiftDragMultiplier));

                    Vector3 local_lift = mcs_mod * wing.GetLiftVector(liftVector, liftdot, absdot, liftQ, (float)mach);
                    Vector3 local_drag = mcs_mod * wing.GetDragVector(nVel, absdot, liftQ);

                    total_lift += local_lift;
                    total_drag += local_drag;
                }

            }
            // RETURN STUFF
            Vector3 force = total_lift + total_drag;
            return 1000 * force;
        }