diff --git a/doc/source/math/basic.rst b/doc/source/math/basic.rst index c42d2c92c..e3af8ed54 100644 --- a/doc/source/math/basic.rst +++ b/doc/source/math/basic.rst @@ -22,7 +22,9 @@ constants about the universe that you may find handy in your math operations. P - Description * - :global:`G` - - Newton's Gravitational Constant + - Newton's Gravitational Constant. + * - :global:`g0 + - gravity acceleration (m/s^2) at sea level on Earth. * - :global:`E` - Base of the natural log (Euler's number) * - :global:`PI` @@ -41,7 +43,63 @@ constants about the universe that you may find handy in your math operations. P .. global:: Constant:G - Newton's Gravitational Constant, 6.67384E-11:: + Newton's Gravitational Constant that the game's planetary + bodies are implying in their configuration data. + (6.67384E-11 as of the last update to these documents). + + Note, the stock KSP game never technically records a value + for G in its data. kOS derives this value by calculating it + based on the Sun's Mass and its Gravitational Parameter. It + is possible for a mod (or perhaps a future release of KSP, if + mistakes were made) to define a universe in which Newton's + Gravitational Constant, G, isn't actually constant at all + within that game universe, and instead varies from one sphere + of influence to the next. Such a universe would be breaking + some laws of physics by a lot, but it is technically possible + in the game's data model. Due to this strange misfeature in + the game's data model, it is probably safer to always have + your scripts use the body's Mu in your formulas instead of + explicitly doing mass*G to derive it. + + Do NOT confuse this with ``Constant:g0`` below. + + Example:: + + PRINT "Gravitational parameter of Kerbin, calculated:". + PRINT constant:G * Kerbin:Mass. + PRINT "Gravitational parameter of Kerbin, hardcoded:". + PRINT Kerbin:Mu. + PRINT "The above two numbers had *better* agree.". + PRINT "If they do not, then your solar system is badly configured.". + +.. global:: Constant:g0 + + Standard value the game uses for acceleration due to + gravity at sea level on Earth. (9.80655 m/s^2 as + of the last update to these documents). + + Do NOT confuse this with ``Constant:G`` above. + + The place where this matters the most is in ISP + calculations. The rocket equation using ISP + contains an inherent conversion from mass to weight + that basically means, "what would this mass of fuel + have weighed at g0?". Some kind of official standard + value of g0 is needed to use ISP to predict truly + accurately how much fuel will be burned in a scenario. + + In pretty much any other calculation other than using + ISP in the Rocketry Equation, you should probably + not use g0 and instead calculate your local gravity + more precisely based on your actual radius to the body + center. Not only because this is more accurate, but + because the g0 you see here is NOT the g0 you would + actually have on Kerbin's sea level. It's the g0 on + Earth, which is what the game's ISP numbers are using. + Kerbin's sea level g0 is ever so slightly different + from Earth's g0 (but not by much.) + + :: PRINT "Gravitational parameter of Kerbin is:". PRINT constant:G * Kerbin:Mass. diff --git a/src/kOS.Safe/Encapsulation/ConstantValue.cs b/src/kOS.Safe/Encapsulation/ConstantValue.cs index 9ced6ee95..20dee765a 100644 --- a/src/kOS.Safe/Encapsulation/ConstantValue.cs +++ b/src/kOS.Safe/Encapsulation/ConstantValue.cs @@ -26,10 +26,18 @@ public static double GravConst get { return gravConstBeingUsed; } set { gravConstBeingUsed = value; } } + + private static double g0 = 9.80665; // Typically accepted Earth value. Will override with KSP game value. + public static double G0 + { + get { return g0; } + set { g0 = value; } + } static ConstantValue() { AddGlobalSuffix("G", new StaticSuffix(() => GravConst)); + AddGlobalSuffix("G0", new StaticSuffix(() => G0)); AddGlobalSuffix("E", new StaticSuffix(() => Math.E)); AddGlobalSuffix("PI", new StaticSuffix(() => Math.PI)); AddGlobalSuffix("C", new StaticSuffix(() => 299792458.0, "Speed of light in m/s")); diff --git a/src/kOS/Module/kOSProcessor.cs b/src/kOS/Module/kOSProcessor.cs index 7336e95b7..8c4498a84 100644 --- a/src/kOS/Module/kOSProcessor.cs +++ b/src/kOS/Module/kOSProcessor.cs @@ -15,6 +15,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using kOS.Safe.Execution; using UnityEngine; using kOS.Safe.Encapsulation; @@ -427,7 +428,7 @@ public void InitObjects() } objectsInitialized = true; - CalcGravConstFromKSP(); + CalcConstsFromKSP(); shared = new SharedObjects(); @@ -504,13 +505,33 @@ public void InitObjects() InitProcessorTracking(); } - // The official value of "G" changes over time as standards bodies re-calculate it. - // This code below ensures we're using whatever value KSP itself is using. (KSP updated - // it once in the past, so hardcoding it as a literal in kOS code isn't such a good idea.) + // The official value of some physics constants change over time as standards bodies re-calculate them. + // This code below ensures we're using whatever value KSP itself is using. // The reason this code is *here* not in ConstantValue is because ConstantValue can't call // the KSP API. It's in kOS.Safe. - private void CalcGravConstFromKSP() - { + private void CalcConstsFromKSP() + { + // GravitationalAcceleration did not exist in PhysicsGlobals prior to KSP 1.6.x. + // This code has to use reflection to avoid calling it on older backports: + Type physGlobType = typeof(PhysicsGlobals); + if (physGlobType != null) + { + // KSP often changes its mind whether a member is a Field or Property, so let's write this + // to future-proof against them changing which it is by trying both ways: + FieldInfo asField = (physGlobType.GetField("GravitationalAcceleration", BindingFlags.Public | BindingFlags.Static)); + if (asField != null) + ConstantValue.G0 = (double) asField.GetValue(null); + else + { + PropertyInfo asProperty = (physGlobType.GetProperty("GravitationalAcceleration", BindingFlags.Public | BindingFlags.Static)); + if (asProperty != null) + ConstantValue.G0 = (double)asProperty.GetValue(null, null); + } + } + // Fallback: Note if none of the above work, G0 still does have a reasonable value because we + // hardcode it to a literal in ConstantValue before doing any of the above work. + + // Cannot find anything in KSP's API exposing their value of G, so this indirect means // of calculating it from an arbitrary body is used: CelestialBody anyBody = FlightGlobals.fetch.bodies.FirstOrDefault();