Exemple #1
0
        // return the total environent radiation at position specified
        public static double Compute(Vessel v, Vector3d position, double gamma_transparency, double sunlight, out bool blackout,
                                     out bool magnetosphere, out bool inner_belt, out bool outer_belt, out bool interstellar, out double shieldedRadiation)
        {
            // prepare out parameters
            blackout          = false;
            magnetosphere     = false;
            inner_belt        = false;
            outer_belt        = false;
            interstellar      = false;
            shieldedRadiation = 0.0;

            // no-op when Radiation is disabled
            if (!Features.Radiation)
            {
                return(0.0);
            }

            // store stuff
            Space   gsm;
            Vector3 p;
            double  D;
            double  r;

            // accumulate radiation
            double        radiation = 0.0;
            CelestialBody body      = v.mainBody;

            while (body != null)
            {
                // Compute radiation values from overlapping 3d fields (belts + magnetospheres)

                RadiationBody  rb = Info(body);
                RadiationModel mf = rb.model;

                // activity is [-0.15..1.05]
                var activity = rb.SolarActivity(false);

                if (mf.Has_field())
                {
                    // transform to local space once
                    var scaled_position = ScaledSpace.LocalToScaledSpace(position);

                    // generate radii-normalized GSM space
                    gsm = Gsm_space(rb, true);

                    // move the point in GSM space
                    p = gsm.Transform_in(scaled_position);

                    // accumulate radiation and determine pause/belt flags
                    if (mf.has_inner)
                    {
                        D           = mf.Inner_func(p);
                        inner_belt |= D < 0;

                        // allow for radiation field to grow/shrink with solar activity
                        D         -= activity * 0.25 / mf.inner_radius;
                        r          = RadiationInBelt(D, mf.inner_radius, rb.radiation_inner_gradient);
                        radiation += r * rb.radiation_inner * (1 + activity * 0.3);
                    }
                    if (mf.has_outer)
                    {
                        D           = mf.Outer_func(p);
                        outer_belt |= D < 0;

                        // allow for radiation field to grow/shrink with solar activity
                        D         -= activity * 0.25 / mf.outer_radius;
                        r          = RadiationInBelt(D, mf.outer_radius, rb.radiation_outer_gradient);
                        radiation += r * rb.radiation_outer * (1 + activity * 0.3);
                    }
                    if (mf.has_pause)
                    {
                        gsm = Gsm_space(rb, false);
                        p   = gsm.Transform_in(scaled_position);
                        D   = mf.Pause_func(p);

                        radiation += Lib.Clamp(D / -0.1332f, 0.0f, 1.0f) * rb.RadiationPause();

                        magnetosphere |= D < 0.0f && !Lib.IsSun(rb.body); //< ignore heliopause
                        interstellar  |= D > 0.0f && Lib.IsSun(rb.body);  //< outside heliopause
                    }
                }

                if (rb.radiation_surface > 0 && body != v.mainBody)
                {
                    Vector3d direction;
                    double   distance;
                    if (Sim.IsBodyVisible(v, position, body, v.KerbalismData().EnvVisibleBodies, out direction, out distance))
                    {
                        var r0 = RadiationR0(rb);
                        var r1 = DistanceRadiation(r0, distance);

                        // clamp to max. surface radiation. when loading on a rescaled system, the vessel can appear to be within the sun for a few ticks
                        radiation += Math.Min(r1, rb.radiation_surface);
#if DEBUG_RADIATION
                        if (v.loaded)
                        {
                            Lib.Log("Radiation " + v + " from surface of " + body + ": " + Lib.HumanReadableRadiation(radiation) + " gamma: " + Lib.HumanReadableRadiation(r1));
                        }
#endif
                    }
                }

                // avoid loops in the chain
                body = (body.referenceBody != null && body.referenceBody.referenceBody == body) ? null : body.referenceBody;
            }

            // add extern radiation
            radiation += Settings.ExternRadiation / 3600.0;

#if DEBUG_RADIATION
            if (v.loaded)
            {
                Lib.Log("Radiation " + v + " extern: " + Lib.HumanReadableRadiation(radiation) + " gamma: " + Lib.HumanReadableRadiation(Settings.ExternRadiation));
            }
#endif

            // apply gamma transparency if inside atmosphere
            radiation *= gamma_transparency;

#if DEBUG_RADIATION
            if (v.loaded)
            {
                Lib.Log("Radiation " + v + " after gamma: " + Lib.HumanReadableRadiation(radiation) + " transparency: " + gamma_transparency);
            }
#endif
            // add surface radiation of the body itself
            if (Lib.IsSun(v.mainBody) && v.altitude < v.mainBody.Radius)
            {
                if (v.altitude > v.mainBody.Radius)
                {
                    radiation += DistanceRadiation(RadiationR0(Info(v.mainBody)), v.altitude);
                }
            }

#if DEBUG_RADIATION
            if (v.loaded)
            {
                Lib.Log("Radiation " + v + " from current main body: " + Lib.HumanReadableRadiation(radiation) + " gamma: " + Lib.HumanReadableRadiation(DistanceRadiation(RadiationR0(Info(v.mainBody)), v.altitude)));
            }
#endif

            shieldedRadiation = radiation;

            // if there is a storm in progress
            if (Storm.InProgress(v))
            {
                // inside a magnetopause (except heliosphere), blackout the signal
                // outside, add storm radiations modulated by sun visibility
                if (magnetosphere)
                {
                    blackout = true;
                }
                else
                {
                    var vd = v.KerbalismData();

                    var activity = Info(vd.EnvMainSun.SunData.body).SolarActivity(false) / 2.0;
                    var strength = PreferencesRadiation.Instance.StormRadiation * sunlight * (activity + 0.5);

                    radiation         += strength;
                    shieldedRadiation += vd.EnvHabitatInfo.AverageHabitatRadiation(strength);
                }
            }

            // add emitter radiation after atmosphere transparency
            var emitterRadiation = Emitter.Total(v);
            radiation         += emitterRadiation;
            shieldedRadiation += emitterRadiation;

#if DEBUG_RADIATION
            if (v.loaded)
            {
                Lib.Log("Radiation " + v + " after emitters: " + Lib.HumanReadableRadiation(radiation) + " shielded " + Lib.HumanReadableRadiation(shieldedRadiation));
            }
#endif

            // for EVAs, add the effect of nearby emitters
            if (v.isEVA)
            {
                var nearbyEmitters = Emitter.Nearby(v);
                radiation         += nearbyEmitters;
                shieldedRadiation += nearbyEmitters;
#if DEBUG_RADIATION
                if (v.loaded)
                {
                    Lib.Log("Radiation " + v + " nearby emitters " + Lib.HumanReadableRadiation(nearbyEmitters));
                }
#endif
            }

            var passiveShielding = PassiveShield.Total(v);
            shieldedRadiation -= passiveShielding;

#if DEBUG_RADIATION
            if (v.loaded)
            {
                Lib.Log("Radiation " + v + " passiveShielding " + Lib.HumanReadableRadiation(passiveShielding));
            }
            if (v.loaded)
            {
                Lib.Log("Radiation " + v + " before clamp: " + Lib.HumanReadableRadiation(radiation) + " shielded " + Lib.HumanReadableRadiation(shieldedRadiation));
            }
#endif

            // clamp radiation to positive range
            // note: we avoid radiation going to zero by using a small positive value
            radiation         = Math.Max(radiation, Nominal);
            shieldedRadiation = Math.Max(shieldedRadiation, Nominal);

#if DEBUG_RADIATION
            if (v.loaded)
            {
                Lib.Log("Radiation " + v + " after clamp: " + Lib.HumanReadableRadiation(radiation) + " shielded " + Lib.HumanReadableRadiation(shieldedRadiation));
            }
#endif
            // return radiation
            return(radiation);
        }
Exemple #2
0
            /// <summary>
            /// Update the 'sunsInfo' list and the 'mainSun', 'solarFluxTotal' variables.
            /// Uses discrete or analytic (for high timewarp speeds) evaluation methods based on the isAnalytic bool.
            /// Require the 'visibleBodies' variable to be set.
            /// </summary>
            // at the two highest timewarp speed, the number of sun visibility samples drop to the point that
            // the quantization error first became noticeable, and then exceed 100%, to solve this :
            // - we switch to an analytical estimation of the sunlight/shadow period
            // - atmo_factor become an average atmospheric absorption factor over the daylight period (not the whole day)
            public static void UpdateSunsInfo(VesselData vd, Vector3d vesselPosition)
            {
                Vessel v             = vd.Vessel;
                double lastSolarFlux = 0.0;

                vd.sunsInfo          = new List <SunInfo>(Sim.suns.Count);
                vd.solarFluxTotal    = 0.0;
                vd.rawSolarFluxTotal = 0.0;

                foreach (Sim.SunData sunData in Sim.suns)
                {
                    SunInfo sunInfo = new SunInfo(sunData);

                    if (vd.isAnalytic)
                    {
                        // get sun direction and distance
                        Lib.DirectionAndDistance(vesselPosition, sunInfo.sunData.body, out sunInfo.direction, out sunInfo.distance);
                        // analytical estimation of the portion of orbit that was in sunlight, current limitations :
                        // - the result is dependant on the vessel altitude at the time of evaluation,
                        //   consequently it gives inconsistent behavior with highly eccentric orbits
                        // - this totally ignore the orbit inclinaison, polar orbits will be treated as equatorial orbits
                        sunInfo.sunlightFactor = 1.0 - Sim.ShadowPeriod(v) / Sim.OrbitalPeriod(v);
                        // get atmospheric absorbtion
                        // for atmospheric bodies whose rotation period is less than 120 hours,
                        // determine analytic atmospheric absorption over a single body revolution instead
                        // of using a discrete value that would be unreliable at large timesteps :
                        if (vd.inAtmosphere)
                        {
                            sunInfo.atmoFactor = Sim.AtmosphereFactorAnalytic(v.mainBody, vesselPosition, sunInfo.direction);
                        }
                        else
                        {
                            sunInfo.atmoFactor = 1.0;
                        }
                    }
                    else
                    {
                        // determine if in sunlight, calculate sun direction and distance
                        sunInfo.sunlightFactor = Sim.IsBodyVisible(v, vesselPosition, sunData.body, vd.visibleBodies, out sunInfo.direction, out sunInfo.distance) ? 1.0 : 0.0;
                        // get atmospheric absorbtion
                        sunInfo.atmoFactor = Sim.AtmosphereFactor(v.mainBody, vesselPosition, sunInfo.direction);
                    }

                    // get resulting solar flux in W/m²
                    sunInfo.rawSolarFlux = sunInfo.sunData.SolarFlux(sunInfo.distance);
                    sunInfo.solarFlux    = sunInfo.rawSolarFlux * sunInfo.sunlightFactor * sunInfo.atmoFactor;
                    // increment total flux from all stars
                    vd.rawSolarFluxTotal += sunInfo.rawSolarFlux;
                    vd.solarFluxTotal    += sunInfo.solarFlux;
                    // add the star to the list
                    vd.sunsInfo.Add(sunInfo);
                    // the most powerful star will be our "default" sun. Uses raw flux before atmo / sunlight factor
                    if (sunInfo.rawSolarFlux > lastSolarFlux)
                    {
                        lastSolarFlux = sunInfo.rawSolarFlux;
                        vd.mainSun    = sunInfo;
                    }
                }

                vd.sunlightFactor = 0.0;
                foreach (SunInfo sunInfo in vd.sunsInfo)
                {
                    sunInfo.fluxProportion = sunInfo.rawSolarFlux / vd.rawSolarFluxTotal;
                    vd.sunlightFactor     += sunInfo.SunlightFactor * sunInfo.fluxProportion;
                }
                // avoid rounding errors
                if (vd.sunlightFactor > 0.99)
                {
                    vd.sunlightFactor = 1.0;
                }
            }
Exemple #3
0
            /// <summary>
            /// Update the 'sunsInfo' list and the 'mainSun', 'solarFluxTotal' variables.
            /// Uses discrete or analytic (for high timewarp speeds) evaluation methods based on the isAnalytic bool.
            /// Require the 'visibleBodies' variable to be set.
            /// </summary>
            // at the two highest timewarp speed, the number of sun visibility samples drop to the point that
            // the quantization error first became noticeable, and then exceed 100%, to solve this:
            // - we switch to an analytical estimation of the sunlight/shadow period
            // - atmo_factor become an average atmospheric absorption factor over the daylight period (not the whole day)
            public static void UpdateSunsInfo(VesselData vd, Vector3d vesselPosition, double elapsedSeconds)
            {
                Vessel v             = vd.Vessel;
                double lastSolarFlux = 0.0;

                vd.sunsInfo          = new List <SunInfo>(Sim.suns.Count);
                vd.solarFluxTotal    = 0.0;
                vd.rawSolarFluxTotal = 0.0;

                foreach (Sim.SunData sunData in Sim.suns)
                {
                    SunInfo sunInfo = new SunInfo(sunData);

                    if (vd.isAnalytic)
                    {
                        // get sun direction and distance
                        Lib.DirectionAndDistance(vesselPosition, sunInfo.sunData.body, out sunInfo.direction, out sunInfo.distance);
                        // analytical estimation of the portion of orbit that was in sunlight.
                        // it has some limitations, see the comments on Sim.ShadowPeriod

                        if (Settings.UseSamplingSunFactor)
                        {
                            // sampling estimation of the portion of orbit that is in sunlight
                            // until we will calculate again
                            sunInfo.sunlightFactor = Sim.SampleSunFactor(v, elapsedSeconds);
                        }

                        else
                        {
                            // analytical estimation of the portion of orbit that was in sunlight.
                            // it has some limitations, see the comments on Sim.ShadowPeriod
                            sunInfo.sunlightFactor = 1.0 - Sim.ShadowPeriod(v) / Sim.OrbitalPeriod(v);
                        }


                        // get atmospheric absorbtion
                        // for atmospheric bodies whose rotation period is less than 120 hours,
                        // determine analytic atmospheric absorption over a single body revolution instead
                        // of using a discrete value that would be unreliable at large timesteps :
                        if (vd.inAtmosphere)
                        {
                            sunInfo.atmoFactor = Sim.AtmosphereFactorAnalytic(v.mainBody, vesselPosition, sunInfo.direction);
                        }
                        else
                        {
                            sunInfo.atmoFactor = 1.0;
                        }
                    }
                    else
                    {
                        // determine if in sunlight, calculate sun direction and distance
                        sunInfo.sunlightFactor = Sim.IsBodyVisible(v, vesselPosition, sunData.body, vd.visibleBodies, out sunInfo.direction, out sunInfo.distance) ? 1.0 : 0.0;
                        // get atmospheric absorbtion
                        sunInfo.atmoFactor = Sim.AtmosphereFactor(v.mainBody, vesselPosition, sunInfo.direction);
                    }

                    // get resulting solar flux in W/m²
                    sunInfo.rawSolarFlux = sunInfo.sunData.SolarFlux(sunInfo.distance);
                    sunInfo.solarFlux    = sunInfo.rawSolarFlux * sunInfo.sunlightFactor * sunInfo.atmoFactor;
                    // increment total flux from all stars
                    vd.rawSolarFluxTotal += sunInfo.rawSolarFlux;
                    vd.solarFluxTotal    += sunInfo.solarFlux;
                    // add the star to the list
                    vd.sunsInfo.Add(sunInfo);
                    // the most powerful star will be our "default" sun. Uses raw flux before atmo / sunlight factor
                    if (sunInfo.rawSolarFlux > lastSolarFlux)
                    {
                        lastSolarFlux = sunInfo.rawSolarFlux;
                        vd.mainSun    = sunInfo;
                    }
                }

                vd.sunlightFactor = 0.0;
                foreach (SunInfo sunInfo in vd.sunsInfo)
                {
                    sunInfo.fluxProportion = sunInfo.rawSolarFlux / vd.rawSolarFluxTotal;
                    vd.sunlightFactor     += sunInfo.SunlightFactor * sunInfo.fluxProportion;
                }
                // avoid rounding errors
                if (vd.sunlightFactor > 0.99)
                {
                    vd.sunlightFactor = 1.0;
                }
            }