Exemplo n.º 1
0
        public static double Graviolis(Vessel v)
        {
            double dist = Vector3d.Distance(v.GetWorldPos3D(), Lib.GetParentSun(v.mainBody).position);
            double au   = dist / FlightGlobals.GetHomeBody().orbit.semiMajorAxis;

            return(1.0 - Math.Min(AU, 1.0));            // 0 at 1AU -> 1 at sun position
        }
Exemplo n.º 2
0
        // ctor: deserialize
        public RadiationBody(ConfigNode node, Dictionary <string, RadiationModel> models, CelestialBody body)
        {
            name                     = Lib.ConfigValue(node, "name", "");
            radiation_inner          = Lib.ConfigValue(node, "radiation_inner", 0.0) / 3600.0;
            radiation_inner_gradient = Lib.ConfigValue(node, "radiation_inner_gradient", 3.3);
            radiation_outer          = Lib.ConfigValue(node, "radiation_outer", 0.0) / 3600.0;
            radiation_outer_gradient = Lib.ConfigValue(node, "radiation_outer_gradient", 2.2);
            radiation_pause          = Lib.ConfigValue(node, "radiation_pause", 0.0) / 3600.0;
            radiation_surface        = Lib.ConfigValue(node, "radiation_surface", -1.0) / 3600.0;
            solar_cycle              = Lib.ConfigValue(node, "solar_cycle", -1.0);
            solar_cycle_offset       = Lib.ConfigValue(node, "solar_cycle_offset", 0.0);
            geomagnetic_pole_lat     = Lib.ConfigValue(node, "geomagnetic_pole_lat", 90.0f);
            geomagnetic_pole_lon     = Lib.ConfigValue(node, "geomagnetic_pole_lon", 0.0f);
            geomagnetic_offset       = Lib.ConfigValue(node, "geomagnetic_offset", 0.0f);
            reference                = Lib.ConfigValue(node, "reference", Lib.GetParentSun(body).flightGlobalsIndex);

            // get the radiation environment
            if (!models.TryGetValue(Lib.ConfigValue(node, "radiation_model", ""), out model))
            {
                model = RadiationModel.none;
            }

            // get the body
            this.body = body;

            float lat = (float)(geomagnetic_pole_lat * Math.PI / 180.0);
            float lon = (float)(geomagnetic_pole_lon * Math.PI / 180.0);

            float x = Mathf.Cos(lat) * Mathf.Cos(lon);
            float y = Mathf.Sin(lat);
            float z = Mathf.Cos(lat) * Mathf.Sin(lon);

            geomagnetic_pole = new Vector3(x, y, z).normalized;

            if (Lib.IsSun(body))
            {
                // suns without a solar cycle configuration default to a cycle of 6 years
                // (set to 0 if you really want none)
                if (solar_cycle < 0)
                {
                    solar_cycle = Lib.HoursInDay * 3600 * Lib.DaysInYear * 6;
                }

                // add a rather nominal surface radiation for suns that have no config
                // for comparison: the stock kerbin sun has a surface radiation of 47 rad/h, which gives 0.01 rad/h near Kerbin
                // (set to 0 if you really want none)
                if (radiation_surface < 0)
                {
                    radiation_surface = 10.0 * 3600.0;
                }
            }

            // calculate point emitter strength r0 at center of body
            if (radiation_surface > 0)
            {
                radiation_r0 = radiation_surface * 4 * Math.PI * body.Radius * body.Radius;
            }
        }
Exemplo n.º 3
0
        /// <summary>Estimated solar flux from the first parent sun of the given body, including other neighbouring stars/suns (binary systems handling)</summary>
        /// <param name="body"></param>
        /// <param name="worstCase">if true, we use the largest distance between the body and the sun</param>
        /// <param name="mainSun"></param>
        /// <param name="mainSunDirection"></param>
        /// <param name="mainSunDistance"></param>
        /// <returns></returns>
        public static double SolarFluxAtBody(CelestialBody body, bool worstCase, out CelestialBody mainSun, out Vector3d mainSunDirection, out double mainSunDistance)
        {
            // get first parent sun
            mainSun = Lib.GetParentSun(body);

            // get direction and distance
            mainSunDirection = (mainSun.position - body.position).normalized;
            if (worstCase)
            {
                mainSunDistance = Sim.Apoapsis(Lib.GetParentPlanet(body)) - mainSun.Radius - body.Radius;
            }
            else
            {
                mainSunDistance = Sim.SunDistance(body.position, mainSun);
            }

            // get solar flux
            int mainSunIndex = mainSun.flightGlobalsIndex;

            Sim.SunData mainSunData = Sim.suns.Find(pr => pr.bodyIndex == mainSunIndex);
            double      solarFlux   = mainSunData.SolarFlux(mainSunDistance);

            // multiple suns handling (binary systems...)
            foreach (Sim.SunData otherSun in Sim.suns)
            {
                if (otherSun.body == mainSun)
                {
                    continue;
                }
                Vector3d otherSunDir = (otherSun.body.position - body.position).normalized;
                double   otherSunDist;
                if (worstCase)
                {
                    otherSunDist = Sim.Apoapsis(Lib.GetParentPlanet(body)) - otherSun.body.Radius;
                }
                else
                {
                    otherSunDist = Sim.SunDistance(body.position, otherSun.body);
                }
                // account only for other suns that have approximatively the same direction (+/- 30°), discard the others
                if (Vector3d.Angle(otherSunDir, mainSunDirection) > 30.0)
                {
                    continue;
                }
                solarFlux += otherSun.SolarFlux(otherSunDist);
            }
            return(solarFlux);
        }
Exemplo n.º 4
0
        private static void RadiationLevels(CelestialBody body, out string inner, out string outer, out string pause, out double activity, out double cycle)
        {
            // TODO cache this information somewhere

            var    rb    = Radiation.Info(body);
            double rad   = Settings.ExternRadiation / 3600.0;
            var    rbSun = Radiation.Info(Lib.GetParentSun(body));

            rad += rbSun.radiation_pause;

            if (rb.inner_visible)
            {
                inner = rb.model.has_inner ? "~" + Lib.HumanReadableRadiation(Math.Max(0, rad + rb.radiation_inner)) : "n/a";
            }
            else
            {
                inner = "unknown";
            }

            if (rb.outer_visible)
            {
                outer = rb.model.has_outer ? "~" + Lib.HumanReadableRadiation(Math.Max(0, rad + rb.radiation_outer)) : "n/a";
            }
            else
            {
                outer = "unknown";
            }

            if (rb.pause_visible)
            {
                pause = rb.model.has_pause ? "∆" + Lib.HumanReadableRadiation(Math.Abs(rb.radiation_pause)) : "n/a";
            }
            else
            {
                pause = "unknown";
            }

            activity = -1;
            cycle    = rb.solar_cycle;
            if (cycle > 0)
            {
                activity = rb.SolarActivity();
            }
        }
Exemplo n.º 5
0
        // calculate irradiance in W/m2 from solar flux reflected on a celestial body in direction of the vessel
        public static double AlbedoFlux(CelestialBody body, Vector3d pos)
        {
            CelestialBody sun      = Lib.GetParentSun(body);
            Vector3d      sun_dir  = sun.position - body.position;
            double        sun_dist = sun_dir.magnitude;

            sun_dir  /= sun_dist;
            sun_dist -= sun.Radius;

            Vector3d body_dir  = pos - body.position;
            double   body_dist = body_dir.magnitude;

            body_dir  /= body_dist;
            body_dist -= body.Radius;

            // used to scale with distance
            double d = Math.Min((body.Radius + body.atmosphereDepth) / (body.Radius + body_dist), 1.0);

            return(suns.Find(p => p.body == sun).SolarFlux(sun_dist)                    // solar radiation
                   * body.albedo                                                        // reflected
                   * Math.Max(0.0, Vector3d.Dot(sun_dir, body_dir))                     // clamped cosine
                   * d * d);                                                            // scale with distance
        }
Exemplo n.º 6
0
        internal static void CreateStorm(StormData bd, CelestialBody body, double distanceToSun)
        {
            // do nothing if storms are disabled
            if (!Features.SpaceWeather)
            {
                return;
            }

            var now = Planetarium.GetUniversalTime();

            if (bd.storm_generation < now)
            {
                var sun         = Lib.GetParentSun(body);
                var avgDuration = PreferencesRadiation.Instance.AvgStormDuration;

                // retry after 3 * average storm duration + jitter (to avoid recalc spikes)
                bd.storm_generation = now + avgDuration * 3 + avgDuration * Lib.RandomDouble();

                var rb       = Radiation.Info(sun);
                var activity = rb.solar_cycle > 0 ? rb.SolarActivity() : 1.0;

                if (Lib.RandomDouble() < activity * PreferencesRadiation.Instance.stormFrequency)
                {
                    // storm duration depends on current solar activity
                    bd.storm_duration = avgDuration / 2.0 + avgDuration * activity * 2;

                    // if further out, the storm lasts longer (but is weaker)
                    bd.storm_duration /= Storm_frequency(distanceToSun);

                    // set a start time to give enough time for warning
                    bd.storm_time = now + Time_to_impact(distanceToSun);

                    // delay next storm generation by duration of this one
                    bd.storm_generation += bd.storm_duration;

                    // add a random error to the estimated storm duration if we don't observe the sun too well
                    var error = bd.storm_duration * 3 * Lib.RandomDouble() * (1 - sun_observation_quality);
                    bd.displayed_duration = bd.storm_duration + error;

                    // show warning message only if you're lucky...
                    bd.display_warning = Lib.RandomFloat() < sun_observation_quality;


#if DEBUG_RADIATION
                    Lib.Log("Storm on " + body + " will start in " + Lib.HumanReadableDuration(bd.storm_time - now) + " and last for " + Lib.HumanReadableDuration(bd.storm_duration));
                }
                else
                {
                    Lib.Log("No storm on " + body + ", will retry in " + Lib.HumanReadableDuration(bd.storm_generation - now));
#endif
                }
            }

            if (bd.storm_time + bd.storm_duration < now)
            {
                // storm is over
                bd.Reset();
            }
            else if (bd.storm_time < now && bd.storm_time + bd.storm_duration > now)
            {
                // storm in progress
                bd.storm_state = 2;
            }
            else if (bd.storm_time > now)
            {
                // storm incoming
                bd.storm_state = 1;
            }
        }
Exemplo n.º 7
0
        // return irradiance from the surface of a body in W/m2
        public static double BodyFlux(CelestialBody body, double altitude)
        {
            CelestialBody sun      = Lib.GetParentSun(body);
            Vector3d      sun_dir  = sun.position - body.position;
            double        sun_dist = sun_dir.magnitude;

            sun_dir  /= sun_dist;
            sun_dist -= sun.Radius;

            // heat capacities, in J/(g K)
            const double water_k      = 4.181;
            const double regolith_k   = 0.67;
            const double hydrogen_k   = 14.300;
            const double helium_k     = 5.193;
            const double oxygen_k     = 0.918;
            const double silicum_k    = 0.703;
            const double aluminium_k  = 0.897;
            const double iron_k       = 0.412;
            const double co2_k        = 0.839;
            const double nitrogen_k   = 1.040;
            const double argon_k      = 0.520;
            const double earth_surf_k = oxygen_k * 0.54 + silicum_k * 0.31 + aluminium_k * 0.09 + iron_k * 0.06;
            const double earth_atmo_k = nitrogen_k * 0.78 + oxygen_k * 0.21 + argon_k * 0.01;
            const double hell_atmo_k  = co2_k * 0.96 + nitrogen_k * 0.04;
            const double gas_giant_k  = hydrogen_k * 0.75 + helium_k * 0.25;

            // proportion of flux not absorbed by atmosphere
            double atmo_factor = AtmosphereFactor(body, 0.7071);

            // try to determine if this is a gas giant
            // - old method: density less than 20% of home planet
            bool is_gas_giant = !body.hasSolidSurface;

            // try to determine if this is a runaway greenhouse planet
            bool is_hell = atmo_factor < 0.5;

            // store heat capacity coefficients
            double surf_k = 0.0;
            double atmo_k = 0.0;

            // deduce surface and atmosphere heat capacity coefficients
            if (is_gas_giant)
            {
                surf_k = gas_giant_k;
                atmo_k = gas_giant_k;
            }
            else
            {
                if (body.atmosphere)
                {
                    surf_k = !body.ocean ? earth_surf_k : earth_surf_k * 0.29 + water_k * 0.71;
                    atmo_k = !is_hell ? earth_atmo_k : hell_atmo_k;
                }
                else
                {
                    surf_k = !body.ocean ? regolith_k : regolith_k * 0.5 + water_k * 0.5;
                }
            }

            // how much flux a part of surface is able to store, in J
            double surf_capacity = surf_k                 // heat capacity, in J/(g K)
                                   * body.Radius / 6000.0 // volume of ground considered, 1x1xN m (100 m^3 at kerbin)
                                   * body.Density         // convert to grams
                                   / 4.0;                 // lighter matter on surface compared to overall density

            // how much flux the atmosphere is able to store, in J
            double atmo_capacity = atmo_k
                                   * body.atmospherePressureSeaLevel
                                   * 1000.0
                                   * SurfaceGravity(body);

            // solar flux striking the body
            double solar_flux = suns.Find(p => p.body == sun).SolarFlux(sun_dist);

            // duration of lit and unlit periods
            double half_day = body.solarDayLength * 0.5;

            // flux stored by surface during daylight, and re-emitted during whole day
            double surf_flux = Math.Min
                               (
                solar_flux                              // incoming flux
                * (1.0 - body.albedo)                   // not reflected
                * atmo_factor                           // not absorbed by atmosphere
                * 0.7071                                // clamped cosine average
                * half_day,                             // accumulated during daylight period
                surf_capacity                           // clamped to storage capacity
                               ) / body.solarDayLength; // released during whole day

            // flux stored by atmosphere during daylight, and re-emitted during whole day
            double atmo_flux = Math.Min
                               (
                solar_flux                              // incoming flux
                * (1.0 - body.albedo)                   // not reflected
                * (1.0 - atmo_factor)                   // absorbed by atmosphere
                * half_day,                             // accumulated during daylight period
                atmo_capacity                           // clamped to storage capacity
                               ) / body.solarDayLength; // released during whole day

            // used to scale with distance
            double d = Math.Min((body.Radius + body.atmosphereDepth) / (body.Radius + altitude), 1.0);

            // return radiative cooling flux from the body
            return((surf_flux + atmo_flux) * d * d);
        }