// return the surface radiation for the body specified (used by body info panel) public static double ComputeSurface(CelestialBody b, double gamma_transparency) { // store stuff Space gsm; Vector3 p; float D; // transform to local space once Vector3d position = ScaledSpace.LocalToScaledSpace(b.position); // accumulate radiation double radiation = 0.0; CelestialBody body = b; while (body != null) { RadiationBody rb = Info(body); RadiationModel mf = rb.model; if (mf.Has_field()) { // generate radii-normalized GSM space gsm = Gsm_space(rb.body, FlightGlobals.Bodies[rb.reference]); // move the poing in GSM space p = gsm.Transform_in(position); // accumulate radiation and determine pause/belt flags if (mf.has_inner) { D = mf.Inner_func(p); radiation += Lib.Clamp(D / -0.0666f, 0.0f, 1.0f) * rb.radiation_inner; } if (mf.has_outer) { D = mf.Outer_func(p); radiation += Lib.Clamp(D / -0.0333f, 0.0f, 1.0f) * rb.radiation_outer; } if (mf.has_pause) { D = mf.Pause_func(p); radiation += Lib.Clamp(D / -0.1332f, 0.0f, 1.0f) * rb.radiation_pause; } } // avoid loops in the chain body = (body.referenceBody != null && body.referenceBody.referenceBody == body) ? null : body.referenceBody; } // add extern radiation radiation += Settings.ExternRadiation; // clamp radiation to positive range // note: we avoid radiation going to zero by using a small positive value radiation = Math.Max(radiation, Nominal); // return radiation, scaled by gamma transparency if inside atmosphere return(radiation * gamma_transparency); }
// 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) { // prepare out parameters blackout = false; magnetosphere = false; inner_belt = false; outer_belt = false; interstellar = false; // no-op when Radiation is disabled if (!Features.Radiation) { return(0.0); } // store stuff Space gsm; Vector3 p; float D; // transform to local space once position = ScaledSpace.LocalToScaledSpace(position); // accumulate radiation double radiation = 0.0; CelestialBody body = v.mainBody; while (body != null) { RadiationBody rb = Info(body); RadiationModel mf = rb.model; if (mf.Has_field()) { // generate radii-normalized GSM space gsm = Gsm_space(rb.body, FlightGlobals.Bodies[rb.reference]); // move the poing in GSM space p = gsm.Transform_in(position); // accumulate radiation and determine pause/belt flags if (mf.has_inner) { D = mf.Inner_func(p); radiation += Lib.Clamp(D / -0.0666f, 0.0f, 1.0f) * rb.radiation_inner; inner_belt |= D < 0.0f; } if (mf.has_outer) { D = mf.Outer_func(p); radiation += Lib.Clamp(D / -0.0333f, 0.0f, 1.0f) * rb.radiation_outer; outer_belt |= D < 0.0f; } if (mf.has_pause) { D = mf.Pause_func(p); radiation += Lib.Clamp(D / -0.1332f, 0.0f, 1.0f) * rb.radiation_pause; magnetosphere |= D < 0.0f && rb.body.flightGlobalsIndex != 0; //< ignore heliopause interstellar |= D > 0.0f && rb.body.flightGlobalsIndex == 0; //< outside heliopause } } // avoid loops in the chain body = (body.referenceBody != null && body.referenceBody.referenceBody == body) ? null : body.referenceBody; } // add extern radiation radiation += PreferencesStorm.Instance.ExternRadiation; // add emitter radiation radiation += Emitter.Total(v); // 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 { radiation += PreferencesStorm.Instance.StormRadiation * sunlight; } } // clamp radiation to positive range // note: we avoid radiation going to zero by using a small positive value radiation = Math.Max(radiation, Nominal); // return radiation, scaled by gamma transparency if inside atmosphere return(radiation * gamma_transparency); }
// return the surface radiation for the body specified (used by body info panel) public static double ComputeSurface(CelestialBody b, double gamma_transparency) { if (!Features.Radiation) { return(0.0); } // store stuff Space gsm; Vector3 p; double D; // transform to local space once Vector3d position = ScaledSpace.LocalToScaledSpace(b.position); // accumulate radiation double radiation = 0.0; CelestialBody body = b; while (body != null) { RadiationBody rb = Info(body); RadiationModel mf = rb.model; var activity = rb.SolarActivity(false); if (mf.Has_field()) { // generate radii-normalized GSM space gsm = Gsm_space(rb, true); // move the poing in GSM space p = gsm.Transform_in(position); // accumulate radiation and determine pause/belt flags if (mf.has_inner) { D = mf.Inner_func(p); // allow for radiation field to grow/shrink with solar activity D -= activity * 0.25 / mf.inner_radius; var 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); // allow for radiation field to grow/shrink with solar activity D -= activity * 0.25 / mf.outer_radius; var 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(position); D = mf.Pause_func(p); radiation += Lib.Clamp(D / -0.1332f, 0.0f, 1.0f) * rb.RadiationPause(); } } if (rb.radiation_surface > 0 && body != b) { // add surface radiation emitted from other body double distance = (b.position - body.position).magnitude; var r0 = RadiationR0(rb); var r1 = DistanceRadiation(r0, distance); // Lib.Log("Surface radiation on " + b + " from " + body + ": " + Lib.HumanReadableRadiation(r1) + " distance " + 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); } // avoid loops in the chain body = (body.referenceBody != null && body.referenceBody.referenceBody == body) ? null : body.referenceBody; } // add extern radiation radiation += Settings.ExternRadiation / 3600.0; // Lib.Log("Radiation subtotal on " + b + ": " + Lib.HumanReadableRadiation(radiation) + ", gamma " + gamma_transparency); // scale radiation by gamma transparency if inside atmosphere radiation *= gamma_transparency; // Lib.Log("srf scaled on " + b + ": " + Lib.HumanReadableRadiation(radiation)); // add surface radiation of the body itself RadiationBody bodyInfo = Info(b); // clamp to max. bodyInfo.radiation_surface to avoid extreme radiation effects while loading a vessel on rescaled systems radiation += Math.Min(bodyInfo.radiation_surface, DistanceRadiation(RadiationR0(bodyInfo), b.Radius)); // Lib.Log("Radiation on " + b + ": " + Lib.HumanReadableRadiation(radiation) + ", own surface radiation " + Lib.HumanReadableRadiation(DistanceRadiation(RadiationR0(Info(b)), b.Radius))); // Lib.Log("radiation " + radiation + " nominal " + Nominal); // clamp radiation to positive range // note: we avoid radiation going to zero by using a small positive value radiation = Math.Max(radiation, Nominal); return(radiation); }
// 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); }