From 4303137c0a7e3cb3278dbf6c93c1acdfa986cc78 Mon Sep 17 00:00:00 2001 From: Don Cross Date: Sun, 22 May 2022 09:41:44 -0400 Subject: [PATCH] PY gravsim: initial coding completed Finished coding the Python version of the gravity simulator. No unit tests have been written yet. Cleaned up documentation in the other languages. Made some functions static that did not need to be members. --- README.md | 2 +- demo/browser/astronomy.browser.js | 36 ++-- demo/nodejs/astronomy.js | 36 ++-- demo/nodejs/calendar/astronomy.ts | 36 ++-- demo/python/astronomy.py | 128 +++++++++++++- generate/template/astronomy.c | 5 +- generate/template/astronomy.cs | 5 +- generate/template/astronomy.kt | 5 +- generate/template/astronomy.py | 128 +++++++++++++- generate/template/astronomy.ts | 36 ++-- source/c/README.md | 2 +- source/c/astronomy.c | 5 +- source/csharp/README.md | 2 +- source/csharp/astronomy.cs | 5 +- source/js/README.md | 7 +- source/js/astronomy.browser.js | 36 ++-- source/js/astronomy.browser.min.js | 166 +++++++++--------- source/js/astronomy.d.ts | 10 +- source/js/astronomy.js | 36 ++-- source/js/astronomy.min.js | 18 +- source/js/astronomy.ts | 36 ++-- source/js/esm/astronomy.js | 36 ++-- source/kotlin/doc/-gravity-simulator/index.md | 2 +- .../kotlin/doc/-gravity-simulator/update.md | 4 +- .../github/cosinekitty/astronomy/astronomy.kt | 5 +- source/python/README.md | 35 +++- source/python/astronomy/astronomy.py | 128 +++++++++++++- 27 files changed, 681 insertions(+), 269 deletions(-) diff --git a/README.md b/README.md index 000a811d..c3c54da1 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ of complexity. So I decided to create Astronomy Engine with the following engine - Support JavaScript, C, C#, and Python with the same algorithms, and verify them to produce identical results. (Kotlin support was added in 2022.) - No external dependencies! The code must not require anything outside the standard library for each language. -- Minified JavaScript code less than 120K. (The current size is 113612 bytes.) +- Minified JavaScript code less than 120K. (The current size is 113559 bytes.) - Accuracy always within 1 arcminute of results from NOVAS. - It would be well documented, relatively easy to use, and support a wide variety of common use cases. diff --git a/demo/browser/astronomy.browser.js b/demo/browser/astronomy.browser.js index 31baed39..7130abaa 100644 --- a/demo/browser/astronomy.browser.js +++ b/demo/browser/astronomy.browser.js @@ -8824,7 +8824,7 @@ class GravitySimulator { // We just need the stub to put into `this.curr`. const smallBodyList = []; // Calculate the states of the Sun and planets. - const largeBodyDict = this.CalcSolarSystem(time); + const largeBodyDict = GravitySimulator.CalcSolarSystem(time); this.curr = new GravSimEndpoint(time, largeBodyDict, smallBodyList); // Convert origin-centric bodyStates vectors into barycentric body_grav_calc_t array. const o = this.InternalBodyState(originBody); @@ -8852,7 +8852,7 @@ class GravitySimulator { return this.curr.time; } /** - * Advances a gravity simulation by a small time step. + * Advances the gravity simulation by a small time step. * * Updates the simulation of the user-supplied small bodies * to the time indicated by the `date` parameter. @@ -8871,9 +8871,11 @@ class GravitySimulator { * Generally, bodies that stay in the outer Solar System and move slowly can * use larger time steps. Bodies that pass into the inner Solar System and * move faster will need a smaller time step to maintain accuracy. - * Some experimentation may be necessary to find a good value. * The `date` value may be after or before the current simulation time * to move forward or backward in time. + * + * @return {StateVector[]} + * An array of state vectors, one for each simulated small body. */ Update(date) { const time = MakeTime(date); @@ -8890,9 +8892,9 @@ class GravitySimulator { this.Swap(); // Update the current time. this.curr.time = time; - // Now that the time is set, it is safe to update the Solar System. - this.curr.gravitators = this.CalcSolarSystem(time); - // Estimate the position of each small body as if their existing + // Calculate the positions and velocities of the Sun and planets at the given time. + this.curr.gravitators = GravitySimulator.CalcSolarSystem(time); + // Estimate the positions of the small bodies as if their existing // accelerations apply across the whole time interval. for (let i = 0; i < this.curr.bodies.length; ++i) { const p = this.prev.bodies[i]; @@ -8993,7 +8995,7 @@ class GravitySimulator { return bstate; throw `Invalid body: ${body}`; } - CalcSolarSystem(time) { + static CalcSolarSystem(time) { const dict = {}; // Start with the SSB at zero position and velocity. const ssb = new body_state_t(time.tt, TerseVector.zero(), TerseVector.zero()); @@ -9020,18 +9022,18 @@ class GravitySimulator { // Calculate the gravitational acceleration experienced by the simulated small bodies. for (let b of this.curr.bodies) { b.a = TerseVector.zero(); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Sun].r, SUN_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mercury].r, MERCURY_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Venus].r, VENUS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Earth].r, EARTH_GM + MOON_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mars].r, MARS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Jupiter].r, JUPITER_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Saturn].r, SATURN_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Uranus].r, URANUS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Neptune].r, NEPTUNE_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Sun].r, SUN_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mercury].r, MERCURY_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Venus].r, VENUS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Earth].r, EARTH_GM + MOON_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mars].r, MARS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Jupiter].r, JUPITER_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Saturn].r, SATURN_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Uranus].r, URANUS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Neptune].r, NEPTUNE_GM); } } - AddAcceleration(acc, smallPos, majorPos, gm) { + static AddAcceleration(acc, smallPos, majorPos, gm) { const dx = majorPos.x - smallPos.x; const dy = majorPos.y - smallPos.y; const dz = majorPos.z - smallPos.z; diff --git a/demo/nodejs/astronomy.js b/demo/nodejs/astronomy.js index 1dc16d38..faaedf0e 100644 --- a/demo/nodejs/astronomy.js +++ b/demo/nodejs/astronomy.js @@ -8823,7 +8823,7 @@ class GravitySimulator { // We just need the stub to put into `this.curr`. const smallBodyList = []; // Calculate the states of the Sun and planets. - const largeBodyDict = this.CalcSolarSystem(time); + const largeBodyDict = GravitySimulator.CalcSolarSystem(time); this.curr = new GravSimEndpoint(time, largeBodyDict, smallBodyList); // Convert origin-centric bodyStates vectors into barycentric body_grav_calc_t array. const o = this.InternalBodyState(originBody); @@ -8851,7 +8851,7 @@ class GravitySimulator { return this.curr.time; } /** - * Advances a gravity simulation by a small time step. + * Advances the gravity simulation by a small time step. * * Updates the simulation of the user-supplied small bodies * to the time indicated by the `date` parameter. @@ -8870,9 +8870,11 @@ class GravitySimulator { * Generally, bodies that stay in the outer Solar System and move slowly can * use larger time steps. Bodies that pass into the inner Solar System and * move faster will need a smaller time step to maintain accuracy. - * Some experimentation may be necessary to find a good value. * The `date` value may be after or before the current simulation time * to move forward or backward in time. + * + * @return {StateVector[]} + * An array of state vectors, one for each simulated small body. */ Update(date) { const time = MakeTime(date); @@ -8889,9 +8891,9 @@ class GravitySimulator { this.Swap(); // Update the current time. this.curr.time = time; - // Now that the time is set, it is safe to update the Solar System. - this.curr.gravitators = this.CalcSolarSystem(time); - // Estimate the position of each small body as if their existing + // Calculate the positions and velocities of the Sun and planets at the given time. + this.curr.gravitators = GravitySimulator.CalcSolarSystem(time); + // Estimate the positions of the small bodies as if their existing // accelerations apply across the whole time interval. for (let i = 0; i < this.curr.bodies.length; ++i) { const p = this.prev.bodies[i]; @@ -8992,7 +8994,7 @@ class GravitySimulator { return bstate; throw `Invalid body: ${body}`; } - CalcSolarSystem(time) { + static CalcSolarSystem(time) { const dict = {}; // Start with the SSB at zero position and velocity. const ssb = new body_state_t(time.tt, TerseVector.zero(), TerseVector.zero()); @@ -9019,18 +9021,18 @@ class GravitySimulator { // Calculate the gravitational acceleration experienced by the simulated small bodies. for (let b of this.curr.bodies) { b.a = TerseVector.zero(); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Sun].r, SUN_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mercury].r, MERCURY_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Venus].r, VENUS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Earth].r, EARTH_GM + MOON_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mars].r, MARS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Jupiter].r, JUPITER_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Saturn].r, SATURN_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Uranus].r, URANUS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Neptune].r, NEPTUNE_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Sun].r, SUN_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mercury].r, MERCURY_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Venus].r, VENUS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Earth].r, EARTH_GM + MOON_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mars].r, MARS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Jupiter].r, JUPITER_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Saturn].r, SATURN_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Uranus].r, URANUS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Neptune].r, NEPTUNE_GM); } } - AddAcceleration(acc, smallPos, majorPos, gm) { + static AddAcceleration(acc, smallPos, majorPos, gm) { const dx = majorPos.x - smallPos.x; const dy = majorPos.y - smallPos.y; const dz = majorPos.z - smallPos.z; diff --git a/demo/nodejs/calendar/astronomy.ts b/demo/nodejs/calendar/astronomy.ts index 45059812..6394f626 100644 --- a/demo/nodejs/calendar/astronomy.ts +++ b/demo/nodejs/calendar/astronomy.ts @@ -9266,7 +9266,7 @@ export class GravitySimulator { const smallBodyList: body_grav_calc_t[] = []; // Calculate the states of the Sun and planets. - const largeBodyDict = this.CalcSolarSystem(time); + const largeBodyDict = GravitySimulator.CalcSolarSystem(time); this.curr = new GravSimEndpoint(time, largeBodyDict, smallBodyList); // Convert origin-centric bodyStates vectors into barycentric body_grav_calc_t array. @@ -9300,7 +9300,7 @@ export class GravitySimulator { } /** - * Advances a gravity simulation by a small time step. + * Advances the gravity simulation by a small time step. * * Updates the simulation of the user-supplied small bodies * to the time indicated by the `date` parameter. @@ -9319,9 +9319,11 @@ export class GravitySimulator { * Generally, bodies that stay in the outer Solar System and move slowly can * use larger time steps. Bodies that pass into the inner Solar System and * move faster will need a smaller time step to maintain accuracy. - * Some experimentation may be necessary to find a good value. * The `date` value may be after or before the current simulation time * to move forward or backward in time. + * + * @return {StateVector[]} + * An array of state vectors, one for each simulated small body. */ public Update(date: FlexibleDateTime): StateVector[] { const time = MakeTime(date); @@ -9339,10 +9341,10 @@ export class GravitySimulator { // Update the current time. this.curr.time = time; - // Now that the time is set, it is safe to update the Solar System. - this.curr.gravitators = this.CalcSolarSystem(time); + // Calculate the positions and velocities of the Sun and planets at the given time. + this.curr.gravitators = GravitySimulator.CalcSolarSystem(time); - // Estimate the position of each small body as if their existing + // Estimate the positions of the small bodies as if their existing // accelerations apply across the whole time interval. for (let i = 0; i < this.curr.bodies.length; ++i) { const p = this.prev.bodies[i]; @@ -9462,7 +9464,7 @@ export class GravitySimulator { throw `Invalid body: ${body}`; } - private CalcSolarSystem(time: AstroTime): BodyStateTable { + private static CalcSolarSystem(time: AstroTime): BodyStateTable { const dict: BodyStateTable = {}; // Start with the SSB at zero position and velocity. @@ -9495,19 +9497,19 @@ export class GravitySimulator { // Calculate the gravitational acceleration experienced by the simulated small bodies. for (let b of this.curr.bodies) { b.a = TerseVector.zero(); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Sun ].r, SUN_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mercury].r, MERCURY_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Venus ].r, VENUS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Earth ].r, EARTH_GM + MOON_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mars ].r, MARS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Jupiter].r, JUPITER_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Saturn ].r, SATURN_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Uranus ].r, URANUS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Neptune].r, NEPTUNE_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Sun ].r, SUN_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mercury].r, MERCURY_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Venus ].r, VENUS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Earth ].r, EARTH_GM + MOON_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mars ].r, MARS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Jupiter].r, JUPITER_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Saturn ].r, SATURN_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Uranus ].r, URANUS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Neptune].r, NEPTUNE_GM); } } - private AddAcceleration(acc: TerseVector, smallPos: TerseVector, majorPos: TerseVector, gm: number): void { + private static AddAcceleration(acc: TerseVector, smallPos: TerseVector, majorPos: TerseVector, gm: number): void { const dx = majorPos.x - smallPos.x; const dy = majorPos.y - smallPos.y; const dz = majorPos.z - smallPos.z; diff --git a/demo/python/astronomy.py b/demo/python/astronomy.py index 7fc0c54d..0920370e 100644 --- a/demo/python/astronomy.py +++ b/demo/python/astronomy.py @@ -9840,6 +9840,7 @@ def LagrangePointFast(point, major_state, major_mass, minor_state, minor_mass): scale = (x - r1) / R return StateVector(scale*dx, scale*dy, scale*dz, scale*vx, scale*vy, scale*vz, major_state.t) +#-------------------------------------------------------------------------------------------------- class GravitySimulator: """A simulation of zero or more small bodies moving through the Solar System. @@ -9884,7 +9885,7 @@ class GravitySimulator: All the times embedded within the state vectors must exactly match `time`, or this constructor will throw an exception. """ - self.originBody = originBody + self._originBody = originBody # Verify that the state vectors have matching times. for b in bodyStates: if b.t.tt != time.tt: @@ -9915,9 +9916,123 @@ class GravitySimulator: self.prev = self._Duplicate() def Time(self): - """The time represented by the current step of the gravity simulation.""" + """The time represented by the current step of the gravity simulation. + + Returns + ------- + Time + """ return self.curr.time + def OriginBody(self): + """The origin of the reference frame. See constructor for more info. + + Returns + ------- + Body + """ + return self._originBody + + def Update(self, time): + """Advances the gravity simulation by a small time step. + + Updates the simulation of the user-supplied small bodies + to the time indicated by the `time` parameter. + Returns an array of state vectors for the simulated bodies. + The array is in the same order as the original array that + was used to construct this simulator object. + The positions and velocities in the returned array are + referenced to the `originBody` that was used to construct + this simulator. + + Parameters + ---------- + time : Time + A time that is a small increment away from the current simulation time. + It is up to the developer to figure out an appropriate time increment. + Depending on the trajectories, a smaller or larger increment + may be needed for the desired accuracy. Some experimentation may be needed. + Generally, bodies that stay in the outer Solar System and move slowly can + use larger time steps. Bodies that pass into the inner Solar System and + move faster will need a smaller time step to maintain accuracy. + The `time` value may be after or before the current simulation time + to move forward or backward in time. + + Returns + ------- + StateVector[] + An array of state vectors, one for each small body. + """ + dt = time.tt - self.curr.time.tt + if dt == 0.0: + # Special case: the time has not changed, so skip the usual physics calculations. + # This allows another way for the caller to query the current body states. + # It is also necessary to avoid dividing by `dt` if `dt` is zero. + # To prepare for a possible swap operation, duplicate the current state into the previous state. + self.prev = self._Duplicate() + else: + # Exchange the current state with the previous state. Then calculate the new current state. + self.Swap() + + # Update the current time + self.curr.time = time + + # Calculate the positions and velocities of the Sun and planets at the given time. + self.curr.gravitators = _CalcSolarSystem(time) + + # Estimate the positions of the small bodies as if their existing + # existing accelerations apply across the whole time interval. + nbodies = len(self.curr.bodies) + for i in range(nbodies): + p = self.prev.bodies[i] + c = self.curr.bodies[i] + c.r = _UpdatePosition(dt, p.r, p.v, p.a) + + # Calculate the acceleration experienced by the small bodies at + # their respective approximate next locations. + self._CalcBodyAccelerations() + + for i in range(nbodies): + # Calculate the average of the acceleration vectors + # experienced by the previous body positions and + # their estimated next positions. + # These become estimates of the mean effective accelerations + # over the whole interval. + p = self.prev.bodies[i] + c = self.curr.bodies[i] + acc = p.a.mean(c.a) + # Refine the estimates of position and velocity at the next time step, + # using the mean acceleration as a better approximation of the + # continuously changing acceleration acting on each body. + c.tt = time.tt + c.r = _UpdatePosition(dt, p.r, p.v, acc) + c.v = _UpdateVelocity(dt, p.v, acc) + + # Re-calculate accelerations experienced by each body. + # These will be needed for the next simulation step (if any). + # Also, they will be potentially useful if some day we add + # a function to query the acceleration vectors for the bodies. + self._CalcBodyAccelerations() + + # Translate our internal calculations of body positions and velocities + # into state vectors that the caller can understand. + # We have to convert the internal type _body_grav_calc_t to the public type StateVector. + # Also convert from barycentric coordinates to coordinates based on the selected origin body. + bodyStates = [] + ostate = self._InternalBodyState(self._originBody) + for bcalc in self.curr.bodies: + bodyStates.append(StateVector( + bcalc.r.x - ostate.r.x, + bcalc.r.y - ostate.r.y, + bcalc.r.z - ostate.r.z, + bcalc.v.x - ostate.v.x, + bcalc.v.y - ostate.v.y, + bcalc.v.z - ostate.v.z, + time + )) + return bodyStates + + def Swap(self): """Exchange the current time step with the previous time step. @@ -9962,9 +10077,14 @@ class GravitySimulator: ---------- body : Body The Sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, or Neptune. + + Returns + ------- + StateVector + The state vector of the requested Solar System body. """ bstate = self._InternalBodyState(body) - ostate = self._InternalBodyState(self.originBody) + ostate = self._InternalBodyState(self._originBody) return _ExportState(bstate - ostate, self.curr.time) def _InternalBodyState(self, body): @@ -10039,3 +10159,5 @@ def _AddAcceleration(acc, smallPos, majorPos, gm): acc.x += dx * pull acc.y += dy * pull acc.z += dz * pull + +#-------------------------------------------------------------------------------------------------- diff --git a/generate/template/astronomy.c b/generate/template/astronomy.c index a17f9b82..82950896 100644 --- a/generate/template/astronomy.c +++ b/generate/template/astronomy.c @@ -2991,7 +2991,6 @@ fail: * Generally, bodies that stay in the outer Solar System and move slowly can * use larger time steps. Bodies that pass into the inner Solar System and * move faster will need a smaller time step to maintain accuracy. - * Some experimentation may be necessary to find a good value. * The `time` value may be after or before the current simulation time * to move forward or backward in time. * @@ -3058,8 +3057,8 @@ astro_status_t Astronomy_GravSimUpdate( for (i = 0; i < numBodies; ++i) { /* - Estimate the position of each small body as if the - current acceleration applies across the whole time interval. + Estimate the positions of the small bodies as if their + current accelerations apply across the whole time interval. approx_pos = pos1 + vel1*dt + (1/2)acc*dt^2 */ body_grav_calc_t *prev = &sim->prev->bodies[i]; diff --git a/generate/template/astronomy.cs b/generate/template/astronomy.cs index ecd91fee..dad9cecf 100644 --- a/generate/template/astronomy.cs +++ b/generate/template/astronomy.cs @@ -2272,7 +2272,6 @@ $ASTRO_ADDSOL() /// Generally, bodies that stay in the outer Solar System and move slowly can /// use larger time steps. Bodies that pass into the inner Solar System and /// move faster will need a smaller time step to maintain accuracy. - /// Some experimentation may be necessary to find a good value. /// The `time` value may be after or before the current simulation time /// to move forward or backward in time. /// @@ -2311,7 +2310,7 @@ $ASTRO_ADDSOL() // Now that the time is set, it is safe to update the Solar System. CalcSolarSystem(); - // Estimate the position of each small body as if their existing + // Estimate the positions of the small bodies as if their existing // accelerations apply across the whole time interval. for (int i = 0; i < nbodies; ++i) curr.bodies[i].r = Astronomy.UpdatePosition(dt, prev.bodies[i].r, prev.bodies[i].v, prev.bodies[i].a); @@ -2484,7 +2483,7 @@ $ASTRO_ADDSOL() } } - private TerseVector Acceleration(TerseVector smallPos, TerseVector majorPos, double gm) + private static TerseVector Acceleration(TerseVector smallPos, TerseVector majorPos, double gm) { double dx = majorPos.x - smallPos.x; double dy = majorPos.y - smallPos.y; diff --git a/generate/template/astronomy.kt b/generate/template/astronomy.kt index 92c78f5c..f256d70a 100644 --- a/generate/template/astronomy.kt +++ b/generate/template/astronomy.kt @@ -7955,7 +7955,7 @@ class GravitySimulator { /** - * Advances a gravity simulation by a small time step. + * Advances the gravity simulation by a small time step. * * Updates the simulation of the user-supplied small bodies * to the time indicated by the `time` parameter. @@ -7971,7 +7971,6 @@ class GravitySimulator { * Generally, bodies that stay in the outer Solar System and move slowly can * use larger time steps. Bodies that pass into the inner Solar System and * move faster will need a smaller time step to maintain accuracy. - * Some experimentation may be necessary to find a good value. * The `time` value may be after or before the current simulation time * to move forward or backward in time. */ @@ -7993,7 +7992,7 @@ class GravitySimulator { // Now that the time is set, it is safe to update the Solar System. calcSolarSystem() - // Estimate the position of each small body as if their existing + // Estimate the positions of the small bodies as if their existing // accelerations apply across the whole time interval. prev.bodies.forEachIndexed { i, p -> curr.bodies[i].r = updatePosition(dt, p.r, p.v, p.a) diff --git a/generate/template/astronomy.py b/generate/template/astronomy.py index 1bc9cc14..2d006a3a 100644 --- a/generate/template/astronomy.py +++ b/generate/template/astronomy.py @@ -7347,6 +7347,7 @@ def LagrangePointFast(point, major_state, major_mass, minor_state, minor_mass): scale = (x - r1) / R return StateVector(scale*dx, scale*dy, scale*dz, scale*vx, scale*vy, scale*vz, major_state.t) +#-------------------------------------------------------------------------------------------------- class GravitySimulator: """A simulation of zero or more small bodies moving through the Solar System. @@ -7391,7 +7392,7 @@ class GravitySimulator: All the times embedded within the state vectors must exactly match `time`, or this constructor will throw an exception. """ - self.originBody = originBody + self._originBody = originBody # Verify that the state vectors have matching times. for b in bodyStates: if b.t.tt != time.tt: @@ -7422,9 +7423,123 @@ class GravitySimulator: self.prev = self._Duplicate() def Time(self): - """The time represented by the current step of the gravity simulation.""" + """The time represented by the current step of the gravity simulation. + + Returns + ------- + Time + """ return self.curr.time + def OriginBody(self): + """The origin of the reference frame. See constructor for more info. + + Returns + ------- + Body + """ + return self._originBody + + def Update(self, time): + """Advances the gravity simulation by a small time step. + + Updates the simulation of the user-supplied small bodies + to the time indicated by the `time` parameter. + Returns an array of state vectors for the simulated bodies. + The array is in the same order as the original array that + was used to construct this simulator object. + The positions and velocities in the returned array are + referenced to the `originBody` that was used to construct + this simulator. + + Parameters + ---------- + time : Time + A time that is a small increment away from the current simulation time. + It is up to the developer to figure out an appropriate time increment. + Depending on the trajectories, a smaller or larger increment + may be needed for the desired accuracy. Some experimentation may be needed. + Generally, bodies that stay in the outer Solar System and move slowly can + use larger time steps. Bodies that pass into the inner Solar System and + move faster will need a smaller time step to maintain accuracy. + The `time` value may be after or before the current simulation time + to move forward or backward in time. + + Returns + ------- + StateVector[] + An array of state vectors, one for each small body. + """ + dt = time.tt - self.curr.time.tt + if dt == 0.0: + # Special case: the time has not changed, so skip the usual physics calculations. + # This allows another way for the caller to query the current body states. + # It is also necessary to avoid dividing by `dt` if `dt` is zero. + # To prepare for a possible swap operation, duplicate the current state into the previous state. + self.prev = self._Duplicate() + else: + # Exchange the current state with the previous state. Then calculate the new current state. + self.Swap() + + # Update the current time + self.curr.time = time + + # Calculate the positions and velocities of the Sun and planets at the given time. + self.curr.gravitators = _CalcSolarSystem(time) + + # Estimate the positions of the small bodies as if their existing + # existing accelerations apply across the whole time interval. + nbodies = len(self.curr.bodies) + for i in range(nbodies): + p = self.prev.bodies[i] + c = self.curr.bodies[i] + c.r = _UpdatePosition(dt, p.r, p.v, p.a) + + # Calculate the acceleration experienced by the small bodies at + # their respective approximate next locations. + self._CalcBodyAccelerations() + + for i in range(nbodies): + # Calculate the average of the acceleration vectors + # experienced by the previous body positions and + # their estimated next positions. + # These become estimates of the mean effective accelerations + # over the whole interval. + p = self.prev.bodies[i] + c = self.curr.bodies[i] + acc = p.a.mean(c.a) + # Refine the estimates of position and velocity at the next time step, + # using the mean acceleration as a better approximation of the + # continuously changing acceleration acting on each body. + c.tt = time.tt + c.r = _UpdatePosition(dt, p.r, p.v, acc) + c.v = _UpdateVelocity(dt, p.v, acc) + + # Re-calculate accelerations experienced by each body. + # These will be needed for the next simulation step (if any). + # Also, they will be potentially useful if some day we add + # a function to query the acceleration vectors for the bodies. + self._CalcBodyAccelerations() + + # Translate our internal calculations of body positions and velocities + # into state vectors that the caller can understand. + # We have to convert the internal type _body_grav_calc_t to the public type StateVector. + # Also convert from barycentric coordinates to coordinates based on the selected origin body. + bodyStates = [] + ostate = self._InternalBodyState(self._originBody) + for bcalc in self.curr.bodies: + bodyStates.append(StateVector( + bcalc.r.x - ostate.r.x, + bcalc.r.y - ostate.r.y, + bcalc.r.z - ostate.r.z, + bcalc.v.x - ostate.v.x, + bcalc.v.y - ostate.v.y, + bcalc.v.z - ostate.v.z, + time + )) + return bodyStates + + def Swap(self): """Exchange the current time step with the previous time step. @@ -7469,9 +7584,14 @@ class GravitySimulator: ---------- body : Body The Sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, or Neptune. + + Returns + ------- + StateVector + The state vector of the requested Solar System body. """ bstate = self._InternalBodyState(body) - ostate = self._InternalBodyState(self.originBody) + ostate = self._InternalBodyState(self._originBody) return _ExportState(bstate - ostate, self.curr.time) def _InternalBodyState(self, body): @@ -7546,3 +7666,5 @@ def _AddAcceleration(acc, smallPos, majorPos, gm): acc.x += dx * pull acc.y += dy * pull acc.z += dz * pull + +#-------------------------------------------------------------------------------------------------- diff --git a/generate/template/astronomy.ts b/generate/template/astronomy.ts index b4cd896e..08f282a3 100644 --- a/generate/template/astronomy.ts +++ b/generate/template/astronomy.ts @@ -7809,7 +7809,7 @@ export class GravitySimulator { const smallBodyList: body_grav_calc_t[] = []; // Calculate the states of the Sun and planets. - const largeBodyDict = this.CalcSolarSystem(time); + const largeBodyDict = GravitySimulator.CalcSolarSystem(time); this.curr = new GravSimEndpoint(time, largeBodyDict, smallBodyList); // Convert origin-centric bodyStates vectors into barycentric body_grav_calc_t array. @@ -7843,7 +7843,7 @@ export class GravitySimulator { } /** - * Advances a gravity simulation by a small time step. + * Advances the gravity simulation by a small time step. * * Updates the simulation of the user-supplied small bodies * to the time indicated by the `date` parameter. @@ -7862,9 +7862,11 @@ export class GravitySimulator { * Generally, bodies that stay in the outer Solar System and move slowly can * use larger time steps. Bodies that pass into the inner Solar System and * move faster will need a smaller time step to maintain accuracy. - * Some experimentation may be necessary to find a good value. * The `date` value may be after or before the current simulation time * to move forward or backward in time. + * + * @return {StateVector[]} + * An array of state vectors, one for each simulated small body. */ public Update(date: FlexibleDateTime): StateVector[] { const time = MakeTime(date); @@ -7882,10 +7884,10 @@ export class GravitySimulator { // Update the current time. this.curr.time = time; - // Now that the time is set, it is safe to update the Solar System. - this.curr.gravitators = this.CalcSolarSystem(time); + // Calculate the positions and velocities of the Sun and planets at the given time. + this.curr.gravitators = GravitySimulator.CalcSolarSystem(time); - // Estimate the position of each small body as if their existing + // Estimate the positions of the small bodies as if their existing // accelerations apply across the whole time interval. for (let i = 0; i < this.curr.bodies.length; ++i) { const p = this.prev.bodies[i]; @@ -8005,7 +8007,7 @@ export class GravitySimulator { throw `Invalid body: ${body}`; } - private CalcSolarSystem(time: AstroTime): BodyStateTable { + private static CalcSolarSystem(time: AstroTime): BodyStateTable { const dict: BodyStateTable = {}; // Start with the SSB at zero position and velocity. @@ -8038,19 +8040,19 @@ export class GravitySimulator { // Calculate the gravitational acceleration experienced by the simulated small bodies. for (let b of this.curr.bodies) { b.a = TerseVector.zero(); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Sun ].r, SUN_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mercury].r, MERCURY_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Venus ].r, VENUS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Earth ].r, EARTH_GM + MOON_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mars ].r, MARS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Jupiter].r, JUPITER_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Saturn ].r, SATURN_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Uranus ].r, URANUS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Neptune].r, NEPTUNE_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Sun ].r, SUN_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mercury].r, MERCURY_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Venus ].r, VENUS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Earth ].r, EARTH_GM + MOON_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mars ].r, MARS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Jupiter].r, JUPITER_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Saturn ].r, SATURN_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Uranus ].r, URANUS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Neptune].r, NEPTUNE_GM); } } - private AddAcceleration(acc: TerseVector, smallPos: TerseVector, majorPos: TerseVector, gm: number): void { + private static AddAcceleration(acc: TerseVector, smallPos: TerseVector, majorPos: TerseVector, gm: number): void { const dx = majorPos.x - smallPos.x; const dy = majorPos.y - smallPos.y; const dz = majorPos.z - smallPos.z; diff --git a/source/c/README.md b/source/c/README.md index 21f6c2f8..3caacb2a 100644 --- a/source/c/README.md +++ b/source/c/README.md @@ -925,7 +925,7 @@ Usually this function will be called immediately after a matching call to [`Astr | Type | Parameter | Description | | --- | --- | --- | | astro_grav_sim_t * | `sim` | A simulation object that was created by a prior call to [`Astronomy_GravSimInit`](#Astronomy_GravSimInit). | -| [`astro_time_t`](#astro_time_t) | `time` | A time that is a small increment away from the current simulation time. It is up to the developer to figure out an appropriate time increment. Depending on the trajectories, a smaller or larger increment may be needed for the desired accuracy. Some experimentation may be needed. Generally, bodies that stay in the outer Solar System and move slowly can use larger time steps. Bodies that pass into the inner Solar System and move faster will need a smaller time step to maintain accuracy. Some experimentation may be necessary to find a good value. The `time` value may be after or before the current simulation time to move forward or backward in time. | +| [`astro_time_t`](#astro_time_t) | `time` | A time that is a small increment away from the current simulation time. It is up to the developer to figure out an appropriate time increment. Depending on the trajectories, a smaller or larger increment may be needed for the desired accuracy. Some experimentation may be needed. Generally, bodies that stay in the outer Solar System and move slowly can use larger time steps. Bodies that pass into the inner Solar System and move faster will need a smaller time step to maintain accuracy. The `time` value may be after or before the current simulation time to move forward or backward in time. | | `int` | `numBodies` | The number of bodies whose state vectors are to be updated. This is the number of elements in the `bodyStateArray`. This parameter is passed as a sanity check, and must be equal to the value passed to [`Astronomy_GravSimInit`](#Astronomy_GravSimInit) when `sim` was created. | | astro_state_vector_t * | `bodyStateArray` | An array big enough to hold `numBodies` state vectors, to receive the updated positions and velocities of the simulated small bodies. Alternatively, `bodyStateArray` may be NULL if the output of this simulation step is not needed. This makes the call slightly faster. | diff --git a/source/c/astronomy.c b/source/c/astronomy.c index 60ecd478..aa7bb6f9 100644 --- a/source/c/astronomy.c +++ b/source/c/astronomy.c @@ -4003,7 +4003,6 @@ fail: * Generally, bodies that stay in the outer Solar System and move slowly can * use larger time steps. Bodies that pass into the inner Solar System and * move faster will need a smaller time step to maintain accuracy. - * Some experimentation may be necessary to find a good value. * The `time` value may be after or before the current simulation time * to move forward or backward in time. * @@ -4070,8 +4069,8 @@ astro_status_t Astronomy_GravSimUpdate( for (i = 0; i < numBodies; ++i) { /* - Estimate the position of each small body as if the - current acceleration applies across the whole time interval. + Estimate the positions of the small bodies as if their + current accelerations apply across the whole time interval. approx_pos = pos1 + vel1*dt + (1/2)acc*dt^2 */ body_grav_calc_t *prev = &sim->prev->bodies[i]; diff --git a/source/csharp/README.md b/source/csharp/README.md index c31f1313..08ce07ac 100644 --- a/source/csharp/README.md +++ b/source/csharp/README.md @@ -2702,7 +2702,7 @@ to the `originBody` that was used to construct this simulator. | Type | Parameter | Description | | --- | --- | --- | -| [`AstroTime`](#AstroTime) | `time` | A time that is a small increment away from the current simulation time. It is up to the developer to figure out an appropriate time increment. Depending on the trajectories, a smaller or larger increment may be needed for the desired accuracy. Some experimentation may be needed. Generally, bodies that stay in the outer Solar System and move slowly can use larger time steps. Bodies that pass into the inner Solar System and move faster will need a smaller time step to maintain accuracy. Some experimentation may be necessary to find a good value. The `time` value may be after or before the current simulation time to move forward or backward in time. | +| [`AstroTime`](#AstroTime) | `time` | A time that is a small increment away from the current simulation time. It is up to the developer to figure out an appropriate time increment. Depending on the trajectories, a smaller or larger increment may be needed for the desired accuracy. Some experimentation may be needed. Generally, bodies that stay in the outer Solar System and move slowly can use larger time steps. Bodies that pass into the inner Solar System and move faster will need a smaller time step to maintain accuracy. The `time` value may be after or before the current simulation time to move forward or backward in time. | | [`StateVector[]`](#StateVector[]) | `bodyStates` | If this array is not null, it must contain exactly the same number of elements as the number of small bodies that were added when this simulator was created. The non-null array receives updated state vectors for the simulated small bodies. If `bodyStates` is null, the simulation is updated but without returning the state vectors. | --- diff --git a/source/csharp/astronomy.cs b/source/csharp/astronomy.cs index 19187629..57430f49 100644 --- a/source/csharp/astronomy.cs +++ b/source/csharp/astronomy.cs @@ -2377,7 +2377,6 @@ namespace CosineKitty /// Generally, bodies that stay in the outer Solar System and move slowly can /// use larger time steps. Bodies that pass into the inner Solar System and /// move faster will need a smaller time step to maintain accuracy. - /// Some experimentation may be necessary to find a good value. /// The `time` value may be after or before the current simulation time /// to move forward or backward in time. /// @@ -2416,7 +2415,7 @@ namespace CosineKitty // Now that the time is set, it is safe to update the Solar System. CalcSolarSystem(); - // Estimate the position of each small body as if their existing + // Estimate the positions of the small bodies as if their existing // accelerations apply across the whole time interval. for (int i = 0; i < nbodies; ++i) curr.bodies[i].r = Astronomy.UpdatePosition(dt, prev.bodies[i].r, prev.bodies[i].v, prev.bodies[i].a); @@ -2589,7 +2588,7 @@ namespace CosineKitty } } - private TerseVector Acceleration(TerseVector smallPos, TerseVector majorPos, double gm) + private static TerseVector Acceleration(TerseVector smallPos, TerseVector majorPos, double gm) { double dx = majorPos.x - smallPos.x; double dy = majorPos.y - smallPos.y; diff --git a/source/js/README.md b/source/js/README.md index b78802ae..9c65c54a 100644 --- a/source/js/README.md +++ b/source/js/README.md @@ -856,8 +856,8 @@ time steps. -### gravitySimulator.Update(date) -Advances a gravity simulation by a small time step. +### gravitySimulator.Update(date) ⇒ [Array.<StateVector>](#StateVector) +Advances the gravity simulation by a small time step. Updates the simulation of the user-supplied small bodies to the time indicated by the `date` parameter. @@ -869,10 +869,11 @@ referenced to the `originBody` that was used to construct this simulator. **Kind**: instance method of [GravitySimulator](#GravitySimulator) +**Returns**: [Array.<StateVector>](#StateVector) - An array of state vectors, one for each simulated small body. | Param | Type | Description | | --- | --- | --- | -| date | [FlexibleDateTime](#FlexibleDateTime) | A time that is a small increment away from the current simulation time. It is up to the developer to figure out an appropriate time increment. Depending on the trajectories, a smaller or larger increment may be needed for the desired accuracy. Some experimentation may be needed. Generally, bodies that stay in the outer Solar System and move slowly can use larger time steps. Bodies that pass into the inner Solar System and move faster will need a smaller time step to maintain accuracy. Some experimentation may be necessary to find a good value. The `date` value may be after or before the current simulation time to move forward or backward in time. | +| date | [FlexibleDateTime](#FlexibleDateTime) | A time that is a small increment away from the current simulation time. It is up to the developer to figure out an appropriate time increment. Depending on the trajectories, a smaller or larger increment may be needed for the desired accuracy. Some experimentation may be needed. Generally, bodies that stay in the outer Solar System and move slowly can use larger time steps. Bodies that pass into the inner Solar System and move faster will need a smaller time step to maintain accuracy. The `date` value may be after or before the current simulation time to move forward or backward in time. | * * * diff --git a/source/js/astronomy.browser.js b/source/js/astronomy.browser.js index 31baed39..7130abaa 100644 --- a/source/js/astronomy.browser.js +++ b/source/js/astronomy.browser.js @@ -8824,7 +8824,7 @@ class GravitySimulator { // We just need the stub to put into `this.curr`. const smallBodyList = []; // Calculate the states of the Sun and planets. - const largeBodyDict = this.CalcSolarSystem(time); + const largeBodyDict = GravitySimulator.CalcSolarSystem(time); this.curr = new GravSimEndpoint(time, largeBodyDict, smallBodyList); // Convert origin-centric bodyStates vectors into barycentric body_grav_calc_t array. const o = this.InternalBodyState(originBody); @@ -8852,7 +8852,7 @@ class GravitySimulator { return this.curr.time; } /** - * Advances a gravity simulation by a small time step. + * Advances the gravity simulation by a small time step. * * Updates the simulation of the user-supplied small bodies * to the time indicated by the `date` parameter. @@ -8871,9 +8871,11 @@ class GravitySimulator { * Generally, bodies that stay in the outer Solar System and move slowly can * use larger time steps. Bodies that pass into the inner Solar System and * move faster will need a smaller time step to maintain accuracy. - * Some experimentation may be necessary to find a good value. * The `date` value may be after or before the current simulation time * to move forward or backward in time. + * + * @return {StateVector[]} + * An array of state vectors, one for each simulated small body. */ Update(date) { const time = MakeTime(date); @@ -8890,9 +8892,9 @@ class GravitySimulator { this.Swap(); // Update the current time. this.curr.time = time; - // Now that the time is set, it is safe to update the Solar System. - this.curr.gravitators = this.CalcSolarSystem(time); - // Estimate the position of each small body as if their existing + // Calculate the positions and velocities of the Sun and planets at the given time. + this.curr.gravitators = GravitySimulator.CalcSolarSystem(time); + // Estimate the positions of the small bodies as if their existing // accelerations apply across the whole time interval. for (let i = 0; i < this.curr.bodies.length; ++i) { const p = this.prev.bodies[i]; @@ -8993,7 +8995,7 @@ class GravitySimulator { return bstate; throw `Invalid body: ${body}`; } - CalcSolarSystem(time) { + static CalcSolarSystem(time) { const dict = {}; // Start with the SSB at zero position and velocity. const ssb = new body_state_t(time.tt, TerseVector.zero(), TerseVector.zero()); @@ -9020,18 +9022,18 @@ class GravitySimulator { // Calculate the gravitational acceleration experienced by the simulated small bodies. for (let b of this.curr.bodies) { b.a = TerseVector.zero(); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Sun].r, SUN_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mercury].r, MERCURY_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Venus].r, VENUS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Earth].r, EARTH_GM + MOON_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mars].r, MARS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Jupiter].r, JUPITER_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Saturn].r, SATURN_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Uranus].r, URANUS_GM); - this.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Neptune].r, NEPTUNE_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Sun].r, SUN_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mercury].r, MERCURY_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Venus].r, VENUS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Earth].r, EARTH_GM + MOON_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Mars].r, MARS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Jupiter].r, JUPITER_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Saturn].r, SATURN_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Uranus].r, URANUS_GM); + GravitySimulator.AddAcceleration(b.a, b.r, this.curr.gravitators[Body.Neptune].r, NEPTUNE_GM); } } - AddAcceleration(acc, smallPos, majorPos, gm) { + static AddAcceleration(acc, smallPos, majorPos, gm) { const dx = majorPos.x - smallPos.x; const dy = majorPos.y - smallPos.y; const dz = majorPos.z - smallPos.z; diff --git a/source/js/astronomy.browser.min.js b/source/js/astronomy.browser.min.js index 5a664ede..9d75d097 100644 --- a/source/js/astronomy.browser.min.js +++ b/source/js/astronomy.browser.min.js @@ -32,23 +32,23 @@ $jscomp.getGlobal=function(r){r=["object"==typeof globalThis&&globalThis,r,"obje $jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(r,u,e){if(r==Array.prototype||r==Object.prototype)return r;r[u]=e.value;return r};$jscomp.IS_SYMBOL_NATIVE="function"===typeof Symbol&&"symbol"===typeof Symbol("x");$jscomp.TRUST_ES6_POLYFILLS=!$jscomp.ISOLATE_POLYFILLS||$jscomp.IS_SYMBOL_NATIVE;$jscomp.polyfills={};$jscomp.propertyToPolyfillSymbol={}; $jscomp.POLYFILL_PREFIX="$jscp$";var $jscomp$lookupPolyfilledValue=function(r,u){var e=$jscomp.propertyToPolyfillSymbol[u];if(null==e)return r[u];e=r[e];return void 0!==e?e:r[u]};$jscomp.polyfill=function(r,u,e,C){u&&($jscomp.ISOLATE_POLYFILLS?$jscomp.polyfillIsolated(r,u,e,C):$jscomp.polyfillUnisolated(r,u,e,C))}; $jscomp.polyfillUnisolated=function(r,u,e,C){e=$jscomp.global;r=r.split(".");for(C=0;Carguments.length)return arguments.length?Math.abs(arguments[0]):0;var e,C,A;for(e=A=0;eA){if(!A)return A;for(e=C=0;eu?-e:e}},"es6","es3"); -(function(r){"object"===typeof exports&&"undefined"!==typeof module?module.exports=r():"function"===typeof define&&define.amd?define([],r):("undefined"!==typeof window?window:"undefined"!==typeof global?global:"undefined"!==typeof self?self:this).Astronomy=r()})(function(){return function(){function r(u,e,C){function A(O,Q){if(!e[O]){if(!u[O]){var Ea="function"==typeof require&&require;if(!Q&&Ea)return Ea(O,!0);if(x)return x(O,!0);Q=Error("Cannot find module '"+O+"'");throw Q.code="MODULE_NOT_FOUND", -Q;}Q=e[O]={exports:{}};u[O][0].call(Q.exports,function(v){return A(u[O][1][v]||v)},Q,Q.exports,r,u,e,C)}return e[O].exports}for(var x="function"==typeof require&&require,N=0;NMath.abs(c))throw"AngleBetween: first vector is too short.";var d=b.x*b.x+b.y*b.y+b.z*b.z;if(1E-8>Math.abs(d))throw"AngleBetween: second vector is too short.";a=(a.x*b.x+a.y*b.y+a.z*b.z)/Math.sqrt(c*d);return-1>=a?180:1<=a?0:e.RAD2DEG*Math.acos(a)}function Q(a){var b=2E3+(a-14)/365.24217;if(-500>b)return a=(b-1820)/100,-20+32*a*a;if(500>b){a=b/100;b=a*a;var c=a*b;return 10583.6-1014.41*a+33.78311*b-5.952053*c-.1798452*b*b+.022174192* +(function(r){"object"===typeof exports&&"undefined"!==typeof module?module.exports=r():"function"===typeof define&&define.amd?define([],r):("undefined"!==typeof window?window:"undefined"!==typeof global?global:"undefined"!==typeof self?self:this).Astronomy=r()})(function(){return function(){function r(u,e,C){function A(P,R){if(!e[P]){if(!u[P]){var Ea="function"==typeof require&&require;if(!R&&Ea)return Ea(P,!0);if(x)return x(P,!0);R=Error("Cannot find module '"+P+"'");throw R.code="MODULE_NOT_FOUND", +R;}R=e[P]={exports:{}};u[P][0].call(R.exports,function(v){return A(u[P][1][v]||v)},R,R.exports,r,u,e,C)}return e[P].exports}for(var x="function"==typeof require&&require,O=0;OMath.abs(c))throw"AngleBetween: first vector is too short.";var d=b.x*b.x+b.y*b.y+b.z*b.z;if(1E-8>Math.abs(d))throw"AngleBetween: second vector is too short.";a=(a.x*b.x+a.y*b.y+a.z*b.z)/Math.sqrt(c*d);return-1>=a?180:1<=a?0:e.RAD2DEG*Math.acos(a)}function R(a){var b=2E3+(a-14)/365.24217;if(-500>b)return a=(b-1820)/100,-20+32*a*a;if(500>b){a=b/100;b=a*a;var c=a*b;return 10583.6-1014.41*a+33.78311*b-5.952053*c-.1798452*b*b+.022174192* b*c+.0090316521*c*c}if(1600>b)return a=(b-1E3)/100,b=a*a,c=a*b,1574.2-556.01*a+71.23472*b+.319781*c-.8503463*b*b-.005050998*b*c+.0083572073*c*c;if(1700>b)return a=b-1600,b=a*a,120-.9808*a-.01532*b+a*b/7129;if(1800>b)return a=b-1700,b=a*a,8.83+.1603*a-.0059285*b+1.3336E-4*a*b-b*b/1174E3;if(1860>b){a=b-1800;b=a*a;c=a*b;var d=b*b;return 13.72-.332447*a+.0068612*b+.0041116*c-3.7436E-4*d+1.21272E-5*b*c-1.699E-7*c*c+8.75E-10*c*d}if(1900>b)return a=b-1860,b=a*a,c=a*b,7.62+.5737*a-.251754*b+.01680668*c-4.473624E-4* b*b+b*c/233174;if(1920>b)return a=b-1900,b=a*a,-2.79+1.494119*a-.0598939*b+.0061966*a*b-1.97E-4*b*b;if(1941>b)return a=b-1920,b=a*a,21.2+.84493*a-.0761*b+.0020936*a*b;if(1961>b)return a=b-1950,b=a*a,29.07+.407*a-b/233+a*b/2547;if(1986>b)return a=b-1975,b=a*a,45.45+1.067*a-b/260-a*b/718;if(2005>b)return a=b-2E3,b=a*a,c=a*b,63.86+.3345*a-.060374*b+.0017275*c+6.51814E-4*b*b+2.373599E-5*b*c;if(2050>b)return a=b-2E3,62.92+.32217*a+.005589*a*a;if(2150>b)return a=(b-1820)/100,-20+32*a*a-.5628*(2150-b);a= -(b-1820)/100;return-20+32*a*a}function Ea(a){return a+Ub(a)/86400}function v(a){return a instanceof P?a:new P(a)}function Vb(a){a=a.tt/36525;return(((((-4.34E-8*a-5.76E-7)*a+.0020034)*a-1.831E-4)*a-46.836769)*a+84381.406)/3600}function Za(a){var b;if(!$a||1E-6=F;++F)0!==D[F]&&g(K.x,K.y,c(y,D[F],F),c(w,D[F],F), -function(pa,qa){return K.x=pa,K.y=qa});return K}function h(D,F,M,ca,K,pa,qa,rb){K=l(K,pa,qa,rb);q+=D*K.y;t+=F*K.y;ab+=M*K.x;ra+=ca*K.x}++e.CalcMoonCount;a=a.tt/36525;var m,n,q,t,y=b(-6,6,1,4),w=b(-6,6,1,4);var z=a*a;var ab=t=q=0;var ra=3422.7;var ia=k(.19833+.05611*a);var da=k(.27869+.04508*a);var T=k(.16827-.36903*a);var Z=k(.34734-5.37261*a);var Fa=k(.10498-5.37899*a);var bb=k(.42681-.41855*a),bd=k(.14943-5.37511*a);var cb=.84*ia+.31*da+14.27*T+7.26*Z+.28*Fa+.24*bb;var tb=2.94*ia+.31*da+14.27*T+ -9.34*Z+1.12*Fa+.83*bb;var db=-6.4*ia-1.89*bb;da=.21*ia+.31*da+14.27*T-88.7*Z-15.3*Fa+.24*bb-1.86*bd;T=cb-db;ia=-3.332E-6*k(.59734-5.37261*a)-5.39E-7*k(.35498-5.37899*a)-6.4E-8*k(.39943-5.37511*a);cb=R*N(.60643382+1336.85522467*a-3.13E-6*z)+cb/ea;tb=R*N(.37489701+1325.55240982*a+2.565E-5*z)+tb/ea;db=R*N(.99312619+99.99735956*a-4.4E-7*z)+db/ea;da=R*N(.25909118+1342.2278298*a-8.92E-6*z)+da/ea;Fa=R*N(.82736186+1236.85308708*a-3.97E-6*z)+T/ea;for(m=1;4>=m;++m){switch(m){case 1:T=tb;z=4;Z=1.000002208;break; -case 2:T=db;z=3;Z=.997504612-.002495388*a;break;case 3:T=da;z=4;Z=1.000002708+139.978*ia;break;case 4:T=Fa;z=6;Z=1;break;default:throw"Internal error: I = "+m;}d(0,m,1);d(1,m,Math.cos(T)*Z);f(0,m,0);f(1,m,Math.sin(T)*Z);for(n=2;n<=z;++n)g(c(y,n-1,m),c(w,n-1,m),c(y,1,m),c(w,1,m),function(D,F){return d(n,m,D),f(n,m,F)});for(n=1;n<=z;++n)d(-n,m,c(y,n,m)),f(-n,m,-c(w,n,m))}h(13.902,14.06,-.001,.2607,0,0,0,4);h(.403,-4.01,.394,.0023,0,0,0,3);h(2369.912,2373.36,.601,28.2333,0,0,0,2);h(-125.154,-112.79, +(b-1820)/100;return-20+32*a*a}function Ea(a){return a+Ub(a)/86400}function v(a){return a instanceof Q?a:new Q(a)}function Vb(a){a=a.tt/36525;return(((((-4.34E-8*a-5.76E-7)*a+.0020034)*a-1.831E-4)*a-46.836769)*a+84381.406)/3600}function Za(a){var b;if(!$a||1E-6=F;++F)0!==D[F]&&g(L.x,L.y,c(y,D[F],F),c(w,D[F],F), +function(pa,qa){return L.x=pa,L.y=qa});return L}function h(D,F,N,ca,L,pa,qa,rb){L=l(L,pa,qa,rb);q+=D*L.y;t+=F*L.y;ab+=N*L.x;ra+=ca*L.x}++e.CalcMoonCount;a=a.tt/36525;var m,n,q,t,y=b(-6,6,1,4),w=b(-6,6,1,4);var z=a*a;var ab=t=q=0;var ra=3422.7;var ia=k(.19833+.05611*a);var da=k(.27869+.04508*a);var U=k(.16827-.36903*a);var Z=k(.34734-5.37261*a);var Fa=k(.10498-5.37899*a);var bb=k(.42681-.41855*a),bd=k(.14943-5.37511*a);var cb=.84*ia+.31*da+14.27*U+7.26*Z+.28*Fa+.24*bb;var tb=2.94*ia+.31*da+14.27*U+ +9.34*Z+1.12*Fa+.83*bb;var db=-6.4*ia-1.89*bb;da=.21*ia+.31*da+14.27*U-88.7*Z-15.3*Fa+.24*bb-1.86*bd;U=cb-db;ia=-3.332E-6*k(.59734-5.37261*a)-5.39E-7*k(.35498-5.37899*a)-6.4E-8*k(.39943-5.37511*a);cb=S*O(.60643382+1336.85522467*a-3.13E-6*z)+cb/ea;tb=S*O(.37489701+1325.55240982*a+2.565E-5*z)+tb/ea;db=S*O(.99312619+99.99735956*a-4.4E-7*z)+db/ea;da=S*O(.25909118+1342.2278298*a-8.92E-6*z)+da/ea;Fa=S*O(.82736186+1236.85308708*a-3.97E-6*z)+U/ea;for(m=1;4>=m;++m){switch(m){case 1:U=tb;z=4;Z=1.000002208;break; +case 2:U=db;z=3;Z=.997504612-.002495388*a;break;case 3:U=da;z=4;Z=1.000002708+139.978*ia;break;case 4:U=Fa;z=6;Z=1;break;default:throw"Internal error: I = "+m;}d(0,m,1);d(1,m,Math.cos(U)*Z);f(0,m,0);f(1,m,Math.sin(U)*Z);for(n=2;n<=z;++n)g(c(y,n-1,m),c(w,n-1,m),c(y,1,m),c(w,1,m),function(D,F){return d(n,m,D),f(n,m,F)});for(n=1;n<=z;++n)d(-n,m,c(y,n,m)),f(-n,m,-c(w,n,m))}h(13.902,14.06,-.001,.2607,0,0,0,4);h(.403,-4.01,.394,.0023,0,0,0,3);h(2369.912,2373.36,.601,28.2333,0,0,0,2);h(-125.154,-112.79, -.725,-.9781,0,0,0,1);h(1.979,6.98,-.445,.0433,1,0,0,4);h(191.953,192.72,.029,3.0861,1,0,0,2);h(-8.466,-13.51,.455,-.1093,1,0,0,1);h(22639.5,22609.07,.079,186.5398,1,0,0,0);h(18.609,3.59,-.094,.0118,1,0,0,-1);h(-4586.465,-4578.13,-.077,34.3117,1,0,0,-2);h(3.215,5.44,.192,-.0386,1,0,0,-3);h(-38.428,-38.64,.001,.6008,1,0,0,-4);h(-.393,-1.43,-.092,.0086,1,0,0,-6);h(-.289,-1.59,.123,-.0053,0,1,0,4);h(-24.42,-25.1,.04,-.3,0,1,0,2);h(18.023,17.93,.007,.1494,0,1,0,1);h(-668.146,-126.98,-1.302,-.3997,0,1, 0,0);h(.56,.32,-.001,-.0037,0,1,0,-1);h(-165.145,-165.06,.054,1.9178,0,1,0,-2);h(-1.877,-6.46,-.416,.0339,0,1,0,-4);h(.213,1.02,-.074,.0054,2,0,0,4);h(14.387,14.78,-.017,.2833,2,0,0,2);h(-.586,-1.2,.054,-.01,2,0,0,1);h(769.016,767.96,.107,10.1657,2,0,0,0);h(1.75,2.01,-.018,.0155,2,0,0,-1);h(-211.656,-152.53,5.679,-.3039,2,0,0,-2);h(1.225,.91,-.03,-.0088,2,0,0,-3);h(-30.773,-34.07,-.308,.3722,2,0,0,-4);h(-.57,-1.4,-.074,.0109,2,0,0,-6);h(-2.921,-11.75,.787,-.0484,1,1,0,2);h(1.267,1.52,-.022,.0164, 1,1,0,1);h(-109.673,-115.18,.461,-.949,1,1,0,0);h(-205.962,-182.36,2.056,1.4437,1,1,0,-2);h(.233,.36,.012,-.0025,1,1,0,-3);h(-4.391,-9.66,-.471,.0673,1,1,0,-4);h(.283,1.53,-.111,.006,1,-1,0,4);h(14.577,31.7,-1.54,.2302,1,-1,0,2);h(147.687,138.76,.679,1.1528,1,-1,0,0);h(-1.089,.55,.021,0,1,-1,0,-1);h(28.475,23.59,-.443,-.2257,1,-1,0,-2);h(-.276,-.38,-.006,-.0036,1,-1,0,-3);h(.636,2.27,.146,-.0102,1,-1,0,-4);h(-.189,-1.68,.131,-.0028,0,2,0,2);h(-7.486,-.66,-.037,-.0086,0,2,0,0);h(-8.096,-16.35,-.74, @@ -56,70 +56,70 @@ case 2:T=db;z=3;Z=.997504612-.002495388*a;break;case 3:T=da;z=4;Z=1.000002708+13 2,1,0,-2);h(-2.74,-2.54,.022,.0324,2,1,0,-4);h(1.181,3.32,-.212,.0213,2,-1,0,2);h(9.703,11.67,-.151,.1268,2,-1,0,0);h(-.352,-.37,.001,-.0028,2,-1,0,-1);h(-2.494,-1.17,-.003,-.0017,2,-1,0,-2);h(.36,.2,-.012,-.0043,2,-1,0,-4);h(-1.167,-1.25,.008,-.0106,1,2,0,0);h(-7.412,-6.12,.117,.0484,1,2,0,-2);h(-.311,-.65,-.032,.0044,1,2,0,-4);h(.757,1.82,-.105,.0112,1,-2,0,2);h(2.58,2.32,.027,.0196,1,-2,0,0);h(2.533,2.4,-.014,-.0212,1,-2,0,-2);h(-.344,-.57,-.025,.0036,0,3,0,-2);h(-.992,-.02,0,0,1,0,2,2);h(-45.099, -.02,0,-.001,1,0,2,0);h(-.179,-9.52,0,-.0833,1,0,2,-2);h(-.301,-.33,0,.0014,1,0,2,-4);h(-6.382,-3.37,0,-.0481,1,0,-2,2);h(39.528,85.13,0,-.7136,1,0,-2,0);h(9.366,.71,0,-.0112,1,0,-2,-2);h(.202,.02,0,0,1,0,-2,-4);h(.415,.1,0,.0013,0,1,2,0);h(-2.152,-2.26,0,-.0066,0,1,2,-2);h(-1.44,-1.3,0,.0014,0,1,-2,2);h(.384,-.04,0,0,0,1,-2,-2);h(1.938,3.6,-.145,.0401,4,0,0,0);h(-.952,-1.58,.052,-.013,4,0,0,-2);h(-.551,-.94,.032,-.0097,3,1,0,0);h(-.482,-.57,.005,-.0045,3,1,0,-2);h(.681,.96,-.026,.0115,3,-1,0,0); h(-.297,-.27,.002,-9E-4,2,2,0,-2);h(.254,.21,-.003,0,2,-2,0,-2);h(-.25,-.22,.004,.0014,1,3,0,-2);h(-3.996,0,0,4E-4,2,0,2,0);h(.557,-.75,0,-.009,2,0,2,-2);h(-.459,-.38,0,-.0053,2,0,-2,2);h(-1.298,.74,0,4E-4,2,0,-2,0);h(.538,1.14,0,-.0141,2,0,-2,-2);h(.263,.02,0,0,1,1,2,0);h(.426,.07,0,-6E-4,1,1,-2,-2);h(-.304,.03,0,3E-4,1,-1,2,0);h(-.372,-.19,0,-.0027,1,-1,-2,2);h(.418,0,0,0,0,0,4,0);h(-.33,-.04,0,0,3,0,2,0);z=-526.069*l(0,0,1,-2).y;z+=-3.352*l(0,0,1,-4).y;z+=44.297*l(1,0,1,-2).y;z+=-6*l(1,0,1,-4).y; -z+=20.599*l(-1,0,1,0).y;z+=-30.598*l(-1,0,1,-2).y;z+=-24.649*l(-2,0,1,0).y;z+=-2*l(-2,0,1,-2).y;z+=-22.571*l(0,1,1,-2).y;z+=10.985*l(0,-1,1,-2).y;q+=.82*k(.7736-62.5512*a)+.31*k(.0466-125.1025*a)+.35*k(.5785-25.1042*a)+.66*k(.4591+1335.8075*a)+.64*k(.313-91.568*a)+1.14*k(.148+1331.2898*a)+.21*k(.5918+1056.5859*a)+.44*k(.5784+1322.8595*a)+.24*k(.2275-5.7374*a)+.28*k(.2965+2.6929*a)+.33*k(.3132+6.3368*a);a=da+t/ea;a=(1.000002708+139.978*ia)*(18518.511+1.189+ab)*Math.sin(a)-6.24*Math.sin(3*a)+z;return{geo_eclip_lon:R* -N((cb+q/ea)/R),geo_eclip_lat:Math.PI/648E3*a,distance_au:ea*cd/(.999953253*ra)}}function Zb(a,b){return[a.rot[0][0]*b[0]+a.rot[1][0]*b[1]+a.rot[2][0]*b[2],a.rot[0][1]*b[0]+a.rot[1][1]*b[1]+a.rot[2][1]*b[2],a.rot[0][2]*b[0]+a.rot[1][2]*b[1]+a.rot[2][2]*b[2]]}function Ga(a,b,c){b=Ha(b,c);return Zb(b,a)}function Ha(a,b){a=a.tt/36525;var c=84381.406,d=((((3.337E-7*a-4.67E-7)*a-.00772503)*a+.0512623)*a-.025754)*a+c;c*=4.84813681109536E-6;var f=((((-9.51E-8*a+1.32851E-4)*a-.00114045)*a-1.0790069)*a+5038.481507)* -a*4.84813681109536E-6;d*=4.84813681109536E-6;var g=((((-5.6E-8*a+1.70663E-4)*a-.00121197)*a-2.3814292)*a+10.556403)*a*4.84813681109536E-6;a=Math.sin(c);c=Math.cos(c);var k=Math.sin(-f);f=Math.cos(-f);var l=Math.sin(-d);d=Math.cos(-d);var h=Math.sin(g),m=Math.cos(g);g=m*f-k*h*d;var n=m*k*c+h*d*f*c-a*h*l,q=m*k*a+h*d*f*a+c*h*l,t=-h*f-k*m*d,y=-h*k*c+m*d*f*c-a*m*l;h=-h*k*a+m*d*f*a+c*m*l;k*=l;m=-l*f*c-a*d;a=-l*f*a+d*c;if(b===G.Into2000)return new L([[g,n,q],[t,y,h],[k,m,a]]);if(b===G.From2000)return new L([[g, +z+=20.599*l(-1,0,1,0).y;z+=-30.598*l(-1,0,1,-2).y;z+=-24.649*l(-2,0,1,0).y;z+=-2*l(-2,0,1,-2).y;z+=-22.571*l(0,1,1,-2).y;z+=10.985*l(0,-1,1,-2).y;q+=.82*k(.7736-62.5512*a)+.31*k(.0466-125.1025*a)+.35*k(.5785-25.1042*a)+.66*k(.4591+1335.8075*a)+.64*k(.313-91.568*a)+1.14*k(.148+1331.2898*a)+.21*k(.5918+1056.5859*a)+.44*k(.5784+1322.8595*a)+.24*k(.2275-5.7374*a)+.28*k(.2965+2.6929*a)+.33*k(.3132+6.3368*a);a=da+t/ea;a=(1.000002708+139.978*ia)*(18518.511+1.189+ab)*Math.sin(a)-6.24*Math.sin(3*a)+z;return{geo_eclip_lon:S* +O((cb+q/ea)/S),geo_eclip_lat:Math.PI/648E3*a,distance_au:ea*cd/(.999953253*ra)}}function Zb(a,b){return[a.rot[0][0]*b[0]+a.rot[1][0]*b[1]+a.rot[2][0]*b[2],a.rot[0][1]*b[0]+a.rot[1][1]*b[1]+a.rot[2][1]*b[2],a.rot[0][2]*b[0]+a.rot[1][2]*b[1]+a.rot[2][2]*b[2]]}function Ga(a,b,c){b=Ha(b,c);return Zb(b,a)}function Ha(a,b){a=a.tt/36525;var c=84381.406,d=((((3.337E-7*a-4.67E-7)*a-.00772503)*a+.0512623)*a-.025754)*a+c;c*=4.84813681109536E-6;var f=((((-9.51E-8*a+1.32851E-4)*a-.00114045)*a-1.0790069)*a+5038.481507)* +a*4.84813681109536E-6;d*=4.84813681109536E-6;var g=((((-5.6E-8*a+1.70663E-4)*a-.00121197)*a-2.3814292)*a+10.556403)*a*4.84813681109536E-6;a=Math.sin(c);c=Math.cos(c);var k=Math.sin(-f);f=Math.cos(-f);var l=Math.sin(-d);d=Math.cos(-d);var h=Math.sin(g),m=Math.cos(g);g=m*f-k*h*d;var n=m*k*c+h*d*f*c-a*h*l,q=m*k*a+h*d*f*a+c*h*l,t=-h*f-k*m*d,y=-h*k*c+m*d*f*c-a*m*l;h=-h*k*a+m*d*f*a+c*m*l;k*=l;m=-l*f*c-a*d;a=-l*f*a+d*c;if(b===G.Into2000)return new M([[g,n,q],[t,y,h],[k,m,a]]);if(b===G.From2000)return new M([[g, t,k],[n,y,m],[q,h,a]]);throw"Invalid precess direction";}function aa(a){if(!eb||eb.tt!==a.tt){var b=a.tt/36525,c=15*Za(a).ee,d=(.779057273264+.00273781191135448*a.ut+a.ut%1)%1*360;0>d&&(d+=360);b=((c+.014506+((((-3.68E-8*b-2.9956E-5)*b-4.4E-7)*b+1.3915817)*b+4612.156534)*b)/3600+d)%360/15;0>b&&(b+=24);eb={tt:a.tt,st:b}}return eb.st}function ub(a,b){var c=a.latitude*e.DEG2RAD,d=Math.sin(c);c=Math.cos(c);var f=1/Math.hypot(c,.996647180302104*d),g=a.height/1E3,k=6378.1366*f+g;b=(15*b+a.longitude)*e.DEG2RAD; a=Math.sin(b);b=Math.cos(b);return{pos:[k*c*b/e.KM_PER_AU,k*c*a/e.KM_PER_AU,(6335.438815127603*f+g)*d/e.KM_PER_AU],vel:[-7.292115E-5*k*c*a*86400/e.KM_PER_AU,7.292115E-5*k*c*b*86400/e.KM_PER_AU,0]}}function fb(a,b,c){b=Ia(b,c);return Zb(b,a)}function Ia(a,b){a=Za(a);var c=a.mobl*e.DEG2RAD,d=a.tobl*e.DEG2RAD,f=4.84813681109536E-6*a.dpsi;a=Math.cos(c);c=Math.sin(c);var g=Math.cos(d),k=Math.sin(d);d=Math.cos(f);var l=Math.sin(f);f=-l*a;var h=-l*c,m=l*g,n=d*a*g+c*k,q=d*c*g-a*k;l*=k;var t=d*a*k-c*g;a=d* -c*k+a*g;if(b===G.From2000)return new L([[d,m,l],[f,n,t],[h,q,a]]);if(b===G.Into2000)return new L([[d,f,h],[m,n,q],[l,t,a]]);throw"Invalid precess direction";}function gb(a,b,c){return c===G.Into2000?Ga(fb(a,b,c),b,c):fb(Ga(a,b,c),b,c)}function $b(a,b){var c=aa(a);b=ub(b,c).pos;return gb(b,a,G.Into2000)}function dd(a){if(!(a instanceof Array)||3!==a.length)return!1;for(var b=0;3>b;++b){if(!(a[b]instanceof Array)||3!==a[b].length)return!1;for(var c=0;3>c;++c)if(!Number.isFinite(a[b][c]))return!1}return!0} +c*k+a*g;if(b===G.From2000)return new M([[d,m,l],[f,n,t],[h,q,a]]);if(b===G.Into2000)return new M([[d,f,h],[m,n,q],[l,t,a]]);throw"Invalid precess direction";}function gb(a,b,c){return c===G.Into2000?Ga(fb(a,b,c),b,c):fb(Ga(a,b,c),b,c)}function $b(a,b){var c=aa(a);b=ub(b,c).pos;return gb(b,a,G.Into2000)}function dd(a){if(!(a instanceof Array)||3!==a.length)return!1;for(var b=0;3>b;++b){if(!(a[b]instanceof Array)||3!==a[b].length)return!1;for(var c=0;3>c;++c)if(!Number.isFinite(a[b][c]))return!1}return!0} function ac(a,b){b=new E(a[0],a[1],a[2],b);var c=b.x*b.x+b.y*b.y,d=Math.sqrt(c+b.z*b.z);if(0===c){if(0===b.z)throw"Indeterminate sky coordinates";return new hb(0,0>b.z?-90:90,d,b)}var f=e.RAD2HOUR*Math.atan2(b.y,b.x);0>f&&(f+=24);return new hb(f,e.RAD2DEG*Math.atan2(a[2],Math.sqrt(c)),d,b)}function sa(a,b){var c=a*e.DEG2RAD;a=Math.cos(c);c=Math.sin(c);return[a*b[0]+c*b[1],a*b[1]-c*b[0],b[2]]}function Ja(a,b,c,d,f){a=v(a);ta(b);x(c);x(d);var g=Math.sin(b.latitude*e.DEG2RAD),k=Math.cos(b.latitude*e.DEG2RAD), l=Math.sin(b.longitude*e.DEG2RAD),h=Math.cos(b.longitude*e.DEG2RAD);b=Math.sin(d*e.DEG2RAD);var m=Math.cos(d*e.DEG2RAD),n=Math.sin(c*e.HOUR2RAD),q=Math.cos(c*e.HOUR2RAD),t=[k*h,k*l,g];g=[-g*h,-g*l,k];l=[l,-h,0];k=-15*aa(a);a=sa(k,t);t=sa(k,g);l=sa(k,l);b=[m*q,m*n,b];n=b[0]*a[0]+b[1]*a[1]+b[2]*a[2];m=b[0]*t[0]+b[1]*t[1]+b[2]*t[2];t=b[0]*l[0]+b[1]*l[1]+b[2]*l[2];q=Math.hypot(m,t);0m&&(m+=360)):m=0;n=e.RAD2DEG*Math.atan2(q,n);q=d;if(f&&(d=n,f=Ka(f,90-n),n-=f,0l;++l)f.push((b[l]-d*a[l])/t*c+a[l]*q);q=Math.hypot(f[0],f[1]);0c&&(c+=24)):c=0;q=e.RAD2DEG*Math.atan2(f[2],q)}return new bc(m,90-n,c,q)}function ta(a){if(!(a instanceof vb))throw"Not an instance of the Observer class: "+a;x(a.latitude);x(a.longitude);x(a.height);if(-90>a.latitude||90b&&(b+=360));g=e.RAD2DEG*Math.atan2(c,g);a=new E(d,f,c,a.t);return new ec(a,g,b)}function Ma(a){void 0===ib&&(ib=e.DEG2RAD*Za(v(wb)).mobl,fc=Math.cos(ib),gc=Math.sin(ib));return dc(a,fc,gc)}function W(a){a=v(a);var b=ba(a),c=b.distance_au*Math.cos(b.geo_eclip_lat);b=[c*Math.cos(b.geo_eclip_lon),c*Math.sin(b.geo_eclip_lon),b.distance_au*Math.sin(b.geo_eclip_lat)];var d=Vb(a)*e.DEG2RAD;c=Math.cos(d);d=Math.sin(d);b=Ga([b[0],b[1]*c-b[2]*d,b[1]*d+b[2]*c],a,G.Into2000); -return new E(b[0],b[1],b[2],a)}function jb(a){a=v(a);a=ba(a);return new Na(a.geo_eclip_lat*e.RAD2DEG,a.geo_eclip_lon*e.RAD2DEG,a.distance_au)}function Oa(a){a=v(a);var b=a.AddDays(-1E-5),c=a.AddDays(1E-5);b=W(b);c=W(c);return new I((b.x+c.x)/2,(b.y+c.y)/2,(b.z+c.z)/2,(c.x-b.x)/2E-5,(c.y-b.y)/2E-5,(c.z-b.z)/2E-5,a)}function xb(a){a=v(a);var b=Oa(a);return new I(b.x/82.30056,b.y/82.30056,b.z/82.30056,b.vx/82.30056,b.vy/82.30056,b.vz/82.30056,a)}function ja(a,b,c){var d=1,f=0;a=$jscomp.makeIterator(a); -for(var g=a.next();!g.done;g=a.next()){var k=0;g=$jscomp.makeIterator(g.value);for(var l=g.next();!l.done;l=g.next()){var h=$jscomp.makeIterator(l.value);l=h.next().value;var m=h.next().value;h=h.next().value;k+=l*Math.cos(m+b*h)}k*=d;c&&(k%=R);f+=k;d*=b}return f}function yb(a,b){var c=1,d=0,f=0,g=0;a=$jscomp.makeIterator(a);for(var k=a.next();!k.done;k=a.next()){var l=0,h=0;k=$jscomp.makeIterator(k.value);for(var m=k.next();!m.done;m=k.next()){var n=$jscomp.makeIterator(m.value);m=n.next().value; -var q=n.next().value;n=n.next().value;q+=b*n;l+=m*n*Math.sin(q);0b&&(b+=360));g=e.RAD2DEG*Math.atan2(c,g);a=new E(d,f,c,a.t);return new ec(a,g,b)}function Ma(a){void 0===ib&&(ib=e.DEG2RAD*Za(v(wb)).mobl,fc=Math.cos(ib),gc=Math.sin(ib));return dc(a,fc,gc)}function X(a){a=v(a);var b=ba(a),c=b.distance_au*Math.cos(b.geo_eclip_lat);b=[c*Math.cos(b.geo_eclip_lon),c*Math.sin(b.geo_eclip_lon),b.distance_au*Math.sin(b.geo_eclip_lat)];var d=Vb(a)*e.DEG2RAD;c=Math.cos(d);d=Math.sin(d);b=Ga([b[0],b[1]*c-b[2]*d,b[1]*d+b[2]*c],a,G.Into2000); +return new E(b[0],b[1],b[2],a)}function jb(a){a=v(a);a=ba(a);return new Na(a.geo_eclip_lat*e.RAD2DEG,a.geo_eclip_lon*e.RAD2DEG,a.distance_au)}function Oa(a){a=v(a);var b=a.AddDays(-1E-5),c=a.AddDays(1E-5);b=X(b);c=X(c);return new J((b.x+c.x)/2,(b.y+c.y)/2,(b.z+c.z)/2,(c.x-b.x)/2E-5,(c.y-b.y)/2E-5,(c.z-b.z)/2E-5,a)}function xb(a){a=v(a);var b=Oa(a);return new J(b.x/82.30056,b.y/82.30056,b.z/82.30056,b.vx/82.30056,b.vy/82.30056,b.vz/82.30056,a)}function ja(a,b,c){var d=1,f=0;a=$jscomp.makeIterator(a); +for(var g=a.next();!g.done;g=a.next()){var k=0;g=$jscomp.makeIterator(g.value);for(var l=g.next();!l.done;l=g.next()){var h=$jscomp.makeIterator(l.value);l=h.next().value;var m=h.next().value;h=h.next().value;k+=l*Math.cos(m+b*h)}k*=d;c&&(k%=S);f+=k;d*=b}return f}function yb(a,b){var c=1,d=0,f=0,g=0;a=$jscomp.makeIterator(a);for(var k=a.next();!k.done;k=a.next()){var l=0,h=0;k=$jscomp.makeIterator(k.value);for(var m=k.next();!m.done;m=k.next()){var n=$jscomp.makeIterator(m.value);m=n.next().value; +var q=n.next().value;n=n.next().value;q+=b*n;l+=m*n*Math.sin(q);0a?0:a>=b?b-1:a}function Cb(a){var b= -$jscomp.makeIterator(a);a=b.next().value;var c=$jscomp.makeIterator(b.next().value);var d=c.next().value;var f=c.next().value;c=c.next().value;var g=$jscomp.makeIterator(b.next().value);b=g.next().value;var k=g.next().value;g=g.next().value;d=new V(a,new B(d,f,c),new B(b,k,g));a=new va(d.tt);f=d.r.add(a.Sun.r);c=d.v.add(a.Sun.v);b=a.Acceleration(f);d=new Ra(d.tt,f,c,b);return new ic(a,d)}function kc(a,b,c){a=Cb(a);for(var d=Math.ceil((b-a.grav.tt)/c),f=0;fka[50][0])c=null;else{c=jc((c-d)/29200,50);if(!Eb[c]){d=Eb[c]=[];d[0]=Cb(ka[c]).grav;d[200]=Cb(ka[c+1]).grav;var f,g=d[0].tt;for(f=1;200>f;++f)d[f]=Bb(g+=146,d[f-1]).grav;g=d[200].tt;var k=[];k[200]=d[200];for(f=199;0d[1]&&(d[1]+=R);f=$jscomp.makeIterator(b.z);for(g=f.next();!g.done;g=f.next())k=$jscomp.makeIterator(g.value),g=k.next().value,l=k.next().value,k=k.next().value,l+=c*k,d[2]+=g* +146,200);c=d[f];g=d[f+1];var l=c.a.mean(g.a);f=ua(a.tt-c.tt,c.r,c.v,l);d=Ab(a.tt-c.tt,c.v,l);k=ua(a.tt-g.tt,g.r,g.v,l);g=Ab(a.tt-g.tt,g.v,l);l=(a.tt-c.tt)/146;c=f.mul(1-l).add(k.mul(l));d=d.mul(1-l).add(g.mul(l))}else{var h=a.ttd[1]&&(d[1]+=S);f=$jscomp.makeIterator(b.z);for(g=f.next();!g.done;g=f.next())k=$jscomp.makeIterator(g.value),g=k.next().value,l=k.next().value,k=k.next().value,l+=c*k,d[2]+=g* Math.cos(l),d[3]+=g*Math.sin(l);f=$jscomp.makeIterator(b.zeta);for(g=f.next();!g.done;g=f.next())k=$jscomp.makeIterator(g.value),g=k.next().value,l=k.next().value,k=k.next().value,l+=c*k,d[4]+=g*Math.cos(l),d[5]+=g*Math.sin(l);f=d[0];k=d[1];g=d[2];l=d[3];c=d[4];d=d[5];var h=Math.sqrt(b.mu/(f*f*f));b=k+g*Math.sin(k)-l*Math.cos(k);do{var m=Math.cos(b);var n=Math.sin(b);m=(k-b+g*n-l*m)/(1-g*m-l*n);b+=m}while(1E-12<=Math.abs(m));m=Math.cos(b);n=Math.sin(b);k=l*m-g*n;var q=-g*m-l*n,t=1/(1+q),y=1/(1+Math.sqrt(1- -g*g-l*l));b=f*(m-g-y*l*k);k=f*(n-l+y*g*k);l=h*t*f*(-n-y*l*q);f=h*t*f*(+m+y*g*q);g=2*Math.sqrt(1-c*c-d*d);h=1-2*d*d;m=1-2*c*c;n=2*d*c;a=new I(b*h+k*n,b*n+k*m,(c*k-b*d)*g,l*h+f*n,l*n+f*m,(c*f-l*d)*g,a);return wa(ed,a)}function Sa(a,b){b=v(b);if(a in H)return U(H[a],b);if(a===p.Pluto)return a=Db(b,!0),new E(a.x,a.y,a.z,b);if(a===p.Sun)return new E(0,0,0,b);if(a===p.Moon){a=U(H.Earth,b);var c=W(b);return new E(a.x+c.x,a.y+c.y,a.z+c.z,b)}if(a===p.EMB)return a=U(H.Earth,b),c=W(b),new E(a.x+c.x/82.30056, -a.y+c.y/82.30056,a.z+c.z/82.30056,b);if(a===p.SSB)return a=new E(0,0,0,b),kb(a,b,p.Jupiter,2.825345909524226E-7),kb(a,b,p.Saturn,8.459715185680659E-8),kb(a,b,p.Uranus,1.292024916781969E-8),kb(a,b,p.Neptune,1.524358900784276E-8),a;throw'HelioVector: Unknown body "'+a+'"';}function la(a,b){b=v(b);return a in H?ja(H[a][2],b.tt/365250,!1):Sa(a,b).Length()}function fa(a,b,c){A(c);b=v(b);if(a===p.Moon)return W(b);if(a===p.Earth)return new E(0,0,0,b);for(var d=null,f,g=0,k=b,l=0;10>l;++l){f=Sa(a,k);c?d= -U(H.Earth,k):d||(d=U(H.Earth,b));f=new E(f.x-d.x,f.y-d.y,f.z-d.z,b);var h=b.AddDays(-f.Length()/e.C_AUDAY);g=Math.abs(h.tt-k.tt);if(1E-9>g)return f;k=h}throw"Light-travel time solver did not converge: dt="+g;}function ma(a,b){return new I(a.r.x,a.r.y,a.r.z,a.v.x,a.v.y,a.v.z,b)}function Fb(a,b){b=v(b);switch(a){case p.Sun:return new I(0,0,0,0,0,0,b);case p.SSB:return a=new va(b.tt),new I(-a.Sun.r.x,-a.Sun.r.y,-a.Sun.r.z,-a.Sun.v.x,-a.Sun.v.y,-a.Sun.v.z,b);case p.Mercury:case p.Venus:case p.Earth:case p.Mars:case p.Jupiter:case p.Saturn:case p.Uranus:case p.Neptune:return a= -Pa(H[a],b.tt),ma(a,b);case p.Pluto:return Db(b,!0);case p.Moon:case p.EMB:var c=Pa(H.Earth,b.tt);a=a==p.Moon?Oa(b):xb(b);return new I(a.x+c.r.x,a.y+c.r.y,a.z+c.r.z,a.vx+c.v.x,a.vy+c.v.y,a.vz+c.v.z,b);default:throw'HelioState: Unsupported body "'+a+'"';}}function fd(a,b,c,d,f){var g=(f+c)/2-d;c=(f-c)/2;if(0==g){if(0==c)return null;d=-d/c;if(-1>d||1=d)return null;f=Math.sqrt(d);d=(-c+f)/(2*g);f=(-c-f)/(2*g);if(-1<=d&&1>=d){if(-1<=f&&1>=f)return null}else if(-1<= -f&&1>=f)d=f;else return null}return{x:d,t:a+d*b,df_dt:(2*g*d+c)/b}}function J(a,b,c,d){var f=x(d&&d.dt_tolerance_seconds||1);f=Math.abs(f/86400);var g=d&&d.init_f1||a(b),k=d&&d.init_f2||a(c),l=NaN,h=0;d=d&&d.iter_limit||20;for(var m=!0;;){if(++h>d)throw"Excessive iteration in Search()";var n=new P(b.ut+.5*(c.ut-b.ut)),q=n.ut-b.ut;if(Math.abs(q)(q.ut-b.ut)*(q.ut-c.ut)&&0>(y.ut-b.ut)*(y.ut-c.ut))){t=a(q);var z=a(y);if(0>t&&0<=z){g=t;k=z;b=q;c=y;l=w;m=!1;continue}}}}if(0>g&&0<=l)c=n,k=l;else if(0>l&&0<=k)b=n,g=l;else return null}}function xa(a){for(;-180>=a;)a+=360;for(;180a;)a+=360;for(;360<=a;)a-=360;return a}function lc(a,b,c){x(a);x(c);b=v(b);c=b.AddDays(c);return J(function(d){d=cc(d);return xa(d.elon-a)},b,c,{dt_tolerance_seconds:.01})}function Gb(a, -b,c){if(a===p.Earth||b===p.Earth)throw"The Earth does not have a longitude as seen from itself.";c=v(c);a=fa(a,c,!1);a=Ma(a);b=fa(b,c,!1);b=Ma(b);return ya(a.elon-b.elon)}function za(a,b){if(a==p.Earth)throw"The Earth does not have an angle as seen from itself.";var c=v(b);b=fa(p.Sun,c,!0);a=fa(a,c,!0);return O(b,a)}function na(a,b){if(a===p.Sun)throw"Cannot calculate heliocentric longitude of the Sun.";a=Sa(a,b);return Ma(a).elon}function mb(a,b){if(a===p.Earth)throw"The illumination of the Earth is not defined."; -var c=v(b),d=U(H.Earth,c);if(a===p.Sun){var f=new E(-d.x,-d.y,-d.z,c);b=new E(0,0,0,c);d=0}else a===p.Moon?(f=W(c),b=new E(d.x+f.x,d.y+f.y,d.z+f.z,c)):(b=Sa(a,b),f=new E(b.x-d.x,b.y-d.y,b.z-d.z,c)),d=O(f,b);var g=f.Length(),k=b.Length();if(a===p.Sun)var l=gd+5*Math.log10(g);else if(a===p.Moon)a=d*e.DEG2RAD,l=a*a,a=-12.717+1.49*Math.abs(a)+.0431*l*l,l=a+=5*Math.log10(g/(385000.6/e.KM_PER_AU)*k);else if(a===p.Saturn){var h=d;a=Ma(f);l=28.06*e.DEG2RAD;var m=e.DEG2RAD*a.elat;a=Math.asin(Math.sin(m)*Math.cos(l)- +g*g-l*l));b=f*(m-g-y*l*k);k=f*(n-l+y*g*k);l=h*t*f*(-n-y*l*q);f=h*t*f*(+m+y*g*q);g=2*Math.sqrt(1-c*c-d*d);h=1-2*d*d;m=1-2*c*c;n=2*d*c;a=new J(b*h+k*n,b*n+k*m,(c*k-b*d)*g,l*h+f*n,l*n+f*m,(c*f-l*d)*g,a);return wa(ed,a)}function Sa(a,b){b=v(b);if(a in I)return V(I[a],b);if(a===p.Pluto)return a=Db(b,!0),new E(a.x,a.y,a.z,b);if(a===p.Sun)return new E(0,0,0,b);if(a===p.Moon){a=V(I.Earth,b);var c=X(b);return new E(a.x+c.x,a.y+c.y,a.z+c.z,b)}if(a===p.EMB)return a=V(I.Earth,b),c=X(b),new E(a.x+c.x/82.30056, +a.y+c.y/82.30056,a.z+c.z/82.30056,b);if(a===p.SSB)return a=new E(0,0,0,b),kb(a,b,p.Jupiter,2.825345909524226E-7),kb(a,b,p.Saturn,8.459715185680659E-8),kb(a,b,p.Uranus,1.292024916781969E-8),kb(a,b,p.Neptune,1.524358900784276E-8),a;throw'HelioVector: Unknown body "'+a+'"';}function la(a,b){b=v(b);return a in I?ja(I[a][2],b.tt/365250,!1):Sa(a,b).Length()}function fa(a,b,c){A(c);b=v(b);if(a===p.Moon)return X(b);if(a===p.Earth)return new E(0,0,0,b);for(var d=null,f,g=0,k=b,l=0;10>l;++l){f=Sa(a,k);c?d= +V(I.Earth,k):d||(d=V(I.Earth,b));f=new E(f.x-d.x,f.y-d.y,f.z-d.z,b);var h=b.AddDays(-f.Length()/e.C_AUDAY);g=Math.abs(h.tt-k.tt);if(1E-9>g)return f;k=h}throw"Light-travel time solver did not converge: dt="+g;}function ma(a,b){return new J(a.r.x,a.r.y,a.r.z,a.v.x,a.v.y,a.v.z,b)}function Fb(a,b){b=v(b);switch(a){case p.Sun:return new J(0,0,0,0,0,0,b);case p.SSB:return a=new va(b.tt),new J(-a.Sun.r.x,-a.Sun.r.y,-a.Sun.r.z,-a.Sun.v.x,-a.Sun.v.y,-a.Sun.v.z,b);case p.Mercury:case p.Venus:case p.Earth:case p.Mars:case p.Jupiter:case p.Saturn:case p.Uranus:case p.Neptune:return a= +Pa(I[a],b.tt),ma(a,b);case p.Pluto:return Db(b,!0);case p.Moon:case p.EMB:var c=Pa(I.Earth,b.tt);a=a==p.Moon?Oa(b):xb(b);return new J(a.x+c.r.x,a.y+c.r.y,a.z+c.r.z,a.vx+c.v.x,a.vy+c.v.y,a.vz+c.v.z,b);default:throw'HelioState: Unsupported body "'+a+'"';}}function fd(a,b,c,d,f){var g=(f+c)/2-d;c=(f-c)/2;if(0==g){if(0==c)return null;d=-d/c;if(-1>d||1=d)return null;f=Math.sqrt(d);d=(-c+f)/(2*g);f=(-c-f)/(2*g);if(-1<=d&&1>=d){if(-1<=f&&1>=f)return null}else if(-1<= +f&&1>=f)d=f;else return null}return{x:d,t:a+d*b,df_dt:(2*g*d+c)/b}}function K(a,b,c,d){var f=x(d&&d.dt_tolerance_seconds||1);f=Math.abs(f/86400);var g=d&&d.init_f1||a(b),k=d&&d.init_f2||a(c),l=NaN,h=0;d=d&&d.iter_limit||20;for(var m=!0;;){if(++h>d)throw"Excessive iteration in Search()";var n=new Q(b.ut+.5*(c.ut-b.ut)),q=n.ut-b.ut;if(Math.abs(q)(q.ut-b.ut)*(q.ut-c.ut)&&0>(y.ut-b.ut)*(y.ut-c.ut))){t=a(q);var z=a(y);if(0>t&&0<=z){g=t;k=z;b=q;c=y;l=w;m=!1;continue}}}}if(0>g&&0<=l)c=n,k=l;else if(0>l&&0<=k)b=n,g=l;else return null}}function xa(a){for(;-180>=a;)a+=360;for(;180a;)a+=360;for(;360<=a;)a-=360;return a}function lc(a,b,c){x(a);x(c);b=v(b);c=b.AddDays(c);return K(function(d){d=cc(d);return xa(d.elon-a)},b,c,{dt_tolerance_seconds:.01})}function Gb(a, +b,c){if(a===p.Earth||b===p.Earth)throw"The Earth does not have a longitude as seen from itself.";c=v(c);a=fa(a,c,!1);a=Ma(a);b=fa(b,c,!1);b=Ma(b);return ya(a.elon-b.elon)}function za(a,b){if(a==p.Earth)throw"The Earth does not have an angle as seen from itself.";var c=v(b);b=fa(p.Sun,c,!0);a=fa(a,c,!0);return P(b,a)}function na(a,b){if(a===p.Sun)throw"Cannot calculate heliocentric longitude of the Sun.";a=Sa(a,b);return Ma(a).elon}function mb(a,b){if(a===p.Earth)throw"The illumination of the Earth is not defined."; +var c=v(b),d=V(I.Earth,c);if(a===p.Sun){var f=new E(-d.x,-d.y,-d.z,c);b=new E(0,0,0,c);d=0}else a===p.Moon?(f=X(c),b=new E(d.x+f.x,d.y+f.y,d.z+f.z,c)):(b=Sa(a,b),f=new E(b.x-d.x,b.y-d.y,b.z-d.z,c)),d=P(f,b);var g=f.Length(),k=b.Length();if(a===p.Sun)var l=gd+5*Math.log10(g);else if(a===p.Moon)a=d*e.DEG2RAD,l=a*a,a=-12.717+1.49*Math.abs(a)+.0431*l*l,l=a+=5*Math.log10(g/(385000.6/e.KM_PER_AU)*k);else if(a===p.Saturn){var h=d;a=Ma(f);l=28.06*e.DEG2RAD;var m=e.DEG2RAD*a.elat;a=Math.asin(Math.sin(m)*Math.cos(l)- Math.cos(m)*Math.sin(l)*Math.sin(e.DEG2RAD*a.elon-e.DEG2RAD*(169.51+3.82E-5*c.tt)));l=Math.sin(Math.abs(a));h=-9+.044*h+l*(-2.6+1.2*l)+5*Math.log10(k*g);a*=e.RAD2DEG;l=h;h=a}else{var n=m=l=0;switch(a){case p.Mercury:a=-.6;l=4.98;m=-4.88;n=3.02;break;case p.Venus:163.6>d?(a=-4.47,l=1.03,m=.57,n=.13):(a=.98,l=-1.02);break;case p.Mars:a=-1.52;l=1.6;break;case p.Jupiter:a=-9.4;l=.5;break;case p.Uranus:a=-7.19;l=.25;break;case p.Neptune:a=-6.87;break;case p.Pluto:a=-1;l=4;break;default:throw"VisualMagnitude: unsupported body "+ a;}var q=d/100;l=a+q*(l+q*(m+q*n))+5*Math.log10(k*g)}return new mc(c,l,d,k,g,f,b,h)}function Ta(a){if(a===p.Earth)throw"The Earth does not have a synodic period as seen from itself.";if(a===p.Moon)return 29.530588;var b=ha[a];if(!b)throw"Not a valid planet name: "+a;a=ha.Earth.OrbitalPeriod;return Math.abs(a/(a/b.OrbitalPeriod-1))}function Aa(a,b,c){function d(m){var n=na(a,m);m=na(p.Earth,m);return xa(g*(m-n)-b)}x(b);var f=ha[a];if(!f)throw"Cannot search relative longitude because body is not a planet: "+ a;if(a===p.Earth)throw"Cannot search relative longitude for the Earth (it is always 0)";var g=f.OrbitalPeriod>ha.Earth.OrbitalPeriod?1:-1;f=Ta(a);c=v(c);var k=d(c);0l;++l){var h=-k/360*f;c=c.AddDays(h);if(1>86400*Math.abs(h))return c;h=k;k=d(c);30>Math.abs(h)&&h!==k&&(h/=h-k,.5h&&(f*=h))}throw"Relative longitude search failed to converge for "+a+" near "+c.toString()+" (error_angle = "+k+").";}function Hb(a){return Gb(p.Moon,p.Sun,a)}function Ua(a,b,c){function d(k){k= -Hb(k);return xa(k-a)}x(a);x(c);b=v(b);var f=d(b);0c)return null;c=Math.min(c,g+1.5);f=b.AddDays(f);b=b.AddDays(c);return J(d,f,b)}function nc(a){var b=Hb(a);b=(Math.floor(b/90)+1)%4;a=Ua(90*b,a,10);if(!a)throw"Cannot find moon quarter";return new oc(b,a)}function pc(a,b,c,d,f,g){ta(b);x(f);if(0>=f)throw"Invalid value for limitDays: "+f;if(a===p.Earth)throw"Cannot find altitude event for the Earth.";if(1===c){c=12;var k=0}else if(-1===c)c=0,k=12;else throw"Invalid direction parameter "+ -c+" -- must be +1 or -1";d=v(d);var l=g(d);var h;if(0=l&&0=d.ut+f)return null;m=l.time;l=g(l.time);h=g(n.time)}}function Va(a,b,c,d){ta(b);d=v(d);var f=0;if(a===p.Earth)throw"Cannot search for hour angle of the Earth.";x(c);if(0>c||24<=c)throw"Invalid hour angle "+c;for(;;){++f;var g=aa(d),k=La(a,d,b,!0,!0); +Hb(k);return xa(k-a)}x(a);x(c);b=v(b);var f=d(b);0c)return null;c=Math.min(c,g+1.5);f=b.AddDays(f);b=b.AddDays(c);return K(d,f,b)}function nc(a){var b=Hb(a);b=(Math.floor(b/90)+1)%4;a=Ua(90*b,a,10);if(!a)throw"Cannot find moon quarter";return new oc(b,a)}function pc(a,b,c,d,f,g){ta(b);x(f);if(0>=f)throw"Invalid value for limitDays: "+f;if(a===p.Earth)throw"Cannot find altitude event for the Earth.";if(1===c){c=12;var k=0}else if(-1===c)c=0,k=12;else throw"Invalid direction parameter "+ +c+" -- must be +1 or -1";d=v(d);var l=g(d);var h;if(0=l&&0=d.ut+f)return null;m=l.time;l=g(l.time);h=g(n.time)}}function Va(a,b,c,d){ta(b);d=v(d);var f=0;if(a===p.Earth)throw"Cannot search for hour angle of the Earth.";x(c);if(0>c||24<=c)throw"Invalid hour angle "+c;for(;;){++f;var g=aa(d),k=La(a,d,b,!0,!0); g=(c+k.ra-b.longitude/15-g)%24;1===f?0>g&&(g+=24):-12>g?g+=24:123600*Math.abs(g))return a=Ja(d,b,k.ra,k.dec,"normal"),new qc(d,a);d=d.AddDays(g/24*.9972695717592592)}}function rc(a,b){b=v(b);var c=Gb(a,p.Sun,b);if(1805*f;++f){var g= -a.AddDays(5),k=b(g);if(0>=d*k){if(0>d||0k){a=J(c,a,g,{init_f1:-d,init_f2:-k});if(!a)throw"SearchLunarApsis INTERNAL ERROR: apogee search failed!";d=ba(a).distance_au;return new Wa(a,1,d)}throw"SearchLunarApsis INTERNAL ERROR: cannot classify apsis event!";}a=g;d=k}throw"SearchLunarApsis INTERNAL ERROR: could not find apsis within 2 synodic months of start date."; +a.AddDays(5),k=b(g);if(0>=d*k){if(0>d||0k){a=K(c,a,g,{init_f1:-d,init_f2:-k});if(!a)throw"SearchLunarApsis INTERNAL ERROR: apogee search failed!";d=ba(a).distance_au;return new Wa(a,1,d)}throw"SearchLunarApsis INTERNAL ERROR: cannot classify apsis event!";}a=g;d=k}throw"SearchLunarApsis INTERNAL ERROR: could not find apsis within 2 synodic months of start date."; }function uc(a,b,c,d){for(var f=b===Ba.Apocenter?1:-1;;){d/=9;if(d<1/1440)return c=c.AddDays(d/2),a=la(a,c),new Wa(c,b,a);for(var g=-1,k=0,l=0;10>l;++l){var h=c.AddDays(l*d);h=f*la(a,h);if(0==l||h>k)g=l,k=h}c=c.AddDays((g-1)*d);d*=2}}function hd(a,b){var c=b.AddDays(-30/360*ha[a].OrbitalPeriod),d=b.AddDays(.75*ha[a].OrbitalPeriod),f=c,g=c,k=-1,l=-1;d=(d.ut-c.ut)/99;for(var h=0;100>h;++h){var m=c.AddDays(h*d),n=la(a,m);0===h?l=k=n:(n>l&&(l=n,g=m),n=b.tt)return a.time.tt>=b.tt&&a.time.tt=b.tt)return a;throw"Internal error: failed to find Neptune apsis.";}function vc(a,b){function c(n){var q=n.AddDays(-5E-4);n=n.AddDays(5E-4);q=la(a,q);return(la(a,n)-q)/.001}function d(n){return-c(n)}b=v(b);if(a===p.Neptune||a===p.Pluto)return hd(a,b);for(var f=ha[a].OrbitalPeriod,g=f/6,k=c(b),l=0;l*g<2*f;++l){var h=b.AddDays(g),m=c(h);if(0>=k*m){f=g=void 0;if(0>k||0m)g=d,f=Ba.Apocenter;else throw"Internal error with slopes in SearchPlanetApsis";b=J(g,b,h);if(!b)throw"Failed to find slope transition in planetary apsis search.";k=la(a,b);return new Wa(b,f,k)}b=h;k=m}throw"Internal error: should have found planetary apsis within 2 orbital periods.";}function Ca(a){return new L([[a.rot[0][0],a.rot[1][0],a.rot[2][0]],[a.rot[0][1],a.rot[1][1],a.rot[2][1]],[a.rot[0][2],a.rot[1][2],a.rot[2][2]]])}function Da(a,b){return new L([[b.rot[0][0]*a.rot[0][0]+b.rot[1][0]* +k||0>m)g=d,f=Ba.Apocenter;else throw"Internal error with slopes in SearchPlanetApsis";b=K(g,b,h);if(!b)throw"Failed to find slope transition in planetary apsis search.";k=la(a,b);return new Wa(b,f,k)}b=h;k=m}throw"Internal error: should have found planetary apsis within 2 orbital periods.";}function Ca(a){return new M([[a.rot[0][0],a.rot[1][0],a.rot[2][0]],[a.rot[0][1],a.rot[1][1],a.rot[2][1]],[a.rot[0][2],a.rot[1][2],a.rot[2][2]]])}function Da(a,b){return new M([[b.rot[0][0]*a.rot[0][0]+b.rot[1][0]* a.rot[0][1]+b.rot[2][0]*a.rot[0][2],b.rot[0][1]*a.rot[0][0]+b.rot[1][1]*a.rot[0][1]+b.rot[2][1]*a.rot[0][2],b.rot[0][2]*a.rot[0][0]+b.rot[1][2]*a.rot[0][1]+b.rot[2][2]*a.rot[0][2]],[b.rot[0][0]*a.rot[1][0]+b.rot[1][0]*a.rot[1][1]+b.rot[2][0]*a.rot[1][2],b.rot[0][1]*a.rot[1][0]+b.rot[1][1]*a.rot[1][1]+b.rot[2][1]*a.rot[1][2],b.rot[0][2]*a.rot[1][0]+b.rot[1][2]*a.rot[1][1]+b.rot[2][2]*a.rot[1][2]],[b.rot[0][0]*a.rot[2][0]+b.rot[1][0]*a.rot[2][1]+b.rot[2][0]*a.rot[2][2],b.rot[0][1]*a.rot[2][0]+b.rot[1][1]* a.rot[2][1]+b.rot[2][1]*a.rot[2][2],b.rot[0][2]*a.rot[2][0]+b.rot[1][2]*a.rot[2][1]+b.rot[2][2]*a.rot[2][2]]])}function Ib(a,b){b=v(b);var c=a.lat*e.DEG2RAD,d=a.lon*e.DEG2RAD,f=a.dist*Math.cos(c);return new E(f*Math.cos(d),f*Math.sin(d),a.dist*Math.sin(c),b)}function Jb(a){var b=Kb(a);return new hb(b.lon/15,b.lat,b.dist,a)}function Kb(a){var b=a.x*a.x+a.y*a.y,c=Math.sqrt(b+a.z*a.z);if(0===b){if(0===a.z)throw"Zero-length vector not allowed.";var d=0;a=0>a.z?-90:90}else d=e.RAD2DEG*Math.atan2(a.y,a.x), 0>d&&(d+=360),a=e.RAD2DEG*Math.atan2(a.z,Math.sqrt(b));return new Na(a,d,c)}function wc(a){a=360-a;360<=a?a-=360:0>a&&(a+=360);return a}function Ka(a,b){x(b);if(-90>b||90c&&(c=-1);c=1.02/Math.tan((c+10.3/(c+5.11))*e.DEG2RAD)/60;"normal"===a&&-1>b&&(c*=(b+90)/89)}else{if(a)throw"Invalid refraction option: "+a;c=0}return c}function xc(a,b){if(-90>b||90Math.abs(d))return c-b;c-=d}}function Xa(a, -b){return new E(a.rot[0][0]*b.x+a.rot[1][0]*b.y+a.rot[2][0]*b.z,a.rot[0][1]*b.x+a.rot[1][1]*b.y+a.rot[2][1]*b.z,a.rot[0][2]*b.x+a.rot[1][2]*b.y+a.rot[2][2]*b.z,b.t)}function wa(a,b){return new I(a.rot[0][0]*b.x+a.rot[1][0]*b.y+a.rot[2][0]*b.z,a.rot[0][1]*b.x+a.rot[1][1]*b.y+a.rot[2][1]*b.z,a.rot[0][2]*b.x+a.rot[1][2]*b.y+a.rot[2][2]*b.z,a.rot[0][0]*b.vx+a.rot[1][0]*b.vy+a.rot[2][0]*b.vz,a.rot[0][1]*b.vx+a.rot[1][1]*b.vy+a.rot[2][1]*b.vz,a.rot[0][2]*b.vx+a.rot[1][2]*b.vy+a.rot[2][2]*b.vz,b.t)}function yc(){return new L([[1, -0,0],[0,.9174821430670688,-.3977769691083922],[0,.3977769691083922,.9174821430670688]])}function Lb(a){a=v(a);var b=Ha(a,G.From2000);a=Ia(a,G.From2000);return Da(b,a)}function Mb(a){a=v(a);var b=Ia(a,G.Into2000);a=Ha(a,G.Into2000);return Da(b,a)}function Nb(a,b){a=v(a);var c=Math.sin(b.latitude*e.DEG2RAD),d=Math.cos(b.latitude*e.DEG2RAD),f=Math.sin(b.longitude*e.DEG2RAD),g=Math.cos(b.longitude*e.DEG2RAD);b=[d*g,d*f,c];c=[-c*g,-c*f,d];f=[f,-g,0];a=-15*aa(a);b=sa(a,b);c=sa(a,c);a=sa(a,f);return new L([[c[0], +b){return new E(a.rot[0][0]*b.x+a.rot[1][0]*b.y+a.rot[2][0]*b.z,a.rot[0][1]*b.x+a.rot[1][1]*b.y+a.rot[2][1]*b.z,a.rot[0][2]*b.x+a.rot[1][2]*b.y+a.rot[2][2]*b.z,b.t)}function wa(a,b){return new J(a.rot[0][0]*b.x+a.rot[1][0]*b.y+a.rot[2][0]*b.z,a.rot[0][1]*b.x+a.rot[1][1]*b.y+a.rot[2][1]*b.z,a.rot[0][2]*b.x+a.rot[1][2]*b.y+a.rot[2][2]*b.z,a.rot[0][0]*b.vx+a.rot[1][0]*b.vy+a.rot[2][0]*b.vz,a.rot[0][1]*b.vx+a.rot[1][1]*b.vy+a.rot[2][1]*b.vz,a.rot[0][2]*b.vx+a.rot[1][2]*b.vy+a.rot[2][2]*b.vz,b.t)}function yc(){return new M([[1, +0,0],[0,.9174821430670688,-.3977769691083922],[0,.3977769691083922,.9174821430670688]])}function Lb(a){a=v(a);var b=Ha(a,G.From2000);a=Ia(a,G.From2000);return Da(b,a)}function Mb(a){a=v(a);var b=Ia(a,G.Into2000);a=Ha(a,G.Into2000);return Da(b,a)}function Nb(a,b){a=v(a);var c=Math.sin(b.latitude*e.DEG2RAD),d=Math.cos(b.latitude*e.DEG2RAD),f=Math.sin(b.longitude*e.DEG2RAD),g=Math.cos(b.longitude*e.DEG2RAD);b=[d*g,d*f,c];c=[-c*g,-c*f,d];f=[f,-g,0];a=-15*aa(a);b=sa(a,b);c=sa(a,c);a=sa(a,f);return new M([[c[0], a[0],b[0]],[c[1],a[1],b[1]],[c[2],a[2],b[2]]])}function zc(a,b){a=Nb(a,b);return Ca(a)}function Ac(a,b){a=v(a);b=zc(a,b);a=Mb(a);return Da(b,a)}function Bc(a){a=Mb(a);var b=yc();return Da(a,b)}function Cc(a){a=Bc(a);return Ca(a)}function Dc(a,b){a=v(a);var c=Cc(a);a=Nb(a,b);return Da(c,a)}function Ya(a,b,c,d){var f=(d.x*c.x+d.y*c.y+d.z*c.z)/(d.x*d.x+d.y*d.y+d.z*d.z);return new id(b,f,e.KM_PER_AU*Math.hypot(f*d.x-c.x,f*d.y-c.y,f*d.z-c.z),695700-(1+f)*(695700-a),-695700+(1+f)*(695700+a),c,d)}function nb(a){var b= -U(H.Earth,a),c=W(a);return Ya(6459,a,c,b)}function Ec(a){var b=U(H.Earth,a),c=W(a),d=new E(-c.x,-c.y,-c.z,c.t);c.x+=b.x;c.y+=b.y;c.z+=b.z;return Ya(1737.4,a,d,c)}function Ob(a,b){var c=$b(a,b);b=U(H.Earth,a);var d=W(a);c=new E(c[0]-d.x,c[1]-d.y,c[2]-d.z,a);d.x+=b.x;d.y+=b.y;d.z+=b.z;return Ya(1737.4,a,c,d)}function ob(a,b,c){a=fa(a,c,!1);var d=fa(p.Sun,c,!1),f=new E(a.x-d.x,a.y-d.y,a.z-d.z,c);d.x=-a.x;d.y=-a.y;d.z=-a.z;return Ya(b,c,d,f)}function Pb(a,b){var c=1/86400,d=b.AddDays(-c);b=b.AddDays(+c); -d=a(d);return(a(b).r-d.r)/c}function jd(a){var b=a.AddDays(-.03);a=a.AddDays(.03);b=J(function(c){return Pb(nb,c)},b,a);if(!b)throw"Failed to find peak Earth shadow time.";return nb(b)}function kd(a){var b=a.AddDays(-.03);a=a.AddDays(.03);b=J(function(c){return Pb(Ec,c)},b,a);if(!b)throw"Failed to find peak Moon shadow time.";return Ec(b)}function ld(a,b,c){var d=c.AddDays(-1);c=c.AddDays(1);d=J(function(f){var g=1/86400,k=ob(a,b,f.AddDays(-g));return(ob(a,b,f.AddDays(+g)).r-k.r)/g},d,c);if(!d)throw"Failed to find peak planet shadow time."; -return ob(a,b,d)}function md(a,b){function c(g){return Ob(g,b)}var d=a.AddDays(-.2),f=a.AddDays(.2);d=J(function(g){return Pb(c,g)},d,f);if(!d)throw"PeakLocalMoonShadow: search failure for search_center_time = "+a;return Ob(d,b)}function Qb(a,b,c){var d=c/1440;c=a.AddDays(-d);d=a.AddDays(+d);c=J(function(f){return-(nb(f).r-b)},c,a);a=J(function(f){return+(nb(f).r-b)},a,d);if(!c||!a)throw"Failed to find shadow semiduration";return 720*(a.ut-c.ut)}function Rb(a){a=ba(a);return e.RAD2DEG*a.geo_eclip_lat} -function Fc(a){a=v(a);for(var b=0;12>b;++b){var c=Ua(180,a,40);if(!c)throw"Cannot find full moon.";a=Rb(c);if(1.8>Math.abs(a)&&(a=jd(c),a.rb;++b){var c=Ua(0,a,40);if(!c)throw"Cannot find new moon"; -a=Rb(c);if(1.8>Math.abs(a)&&(a=kd(c),a.r=d?d+=360:180a.r)throw"Unexpected shadow distance from geoid intersection = "+a.r;g=.014Math.abs(c)){var d=md(a,b);if(d.rza(a,d)&&(b=ld(a,c,d),b.r=c.lat*f.lat){a.$jscomp$loop$prop$kind$33=f.lat>c.lat?oa.Ascending:oa.Descending;b=J(function(g){return function(k){return g.$jscomp$loop$prop$kind$33* +V(I.Earth,a),c=X(a);return Ya(6459,a,c,b)}function Ec(a){var b=V(I.Earth,a),c=X(a),d=new E(-c.x,-c.y,-c.z,c.t);c.x+=b.x;c.y+=b.y;c.z+=b.z;return Ya(1737.4,a,d,c)}function Ob(a,b){var c=$b(a,b);b=V(I.Earth,a);var d=X(a);c=new E(c[0]-d.x,c[1]-d.y,c[2]-d.z,a);d.x+=b.x;d.y+=b.y;d.z+=b.z;return Ya(1737.4,a,c,d)}function ob(a,b,c){a=fa(a,c,!1);var d=fa(p.Sun,c,!1),f=new E(a.x-d.x,a.y-d.y,a.z-d.z,c);d.x=-a.x;d.y=-a.y;d.z=-a.z;return Ya(b,c,d,f)}function Pb(a,b){var c=1/86400,d=b.AddDays(-c);b=b.AddDays(+c); +d=a(d);return(a(b).r-d.r)/c}function jd(a){var b=a.AddDays(-.03);a=a.AddDays(.03);b=K(function(c){return Pb(nb,c)},b,a);if(!b)throw"Failed to find peak Earth shadow time.";return nb(b)}function kd(a){var b=a.AddDays(-.03);a=a.AddDays(.03);b=K(function(c){return Pb(Ec,c)},b,a);if(!b)throw"Failed to find peak Moon shadow time.";return Ec(b)}function ld(a,b,c){var d=c.AddDays(-1);c=c.AddDays(1);d=K(function(f){var g=1/86400,k=ob(a,b,f.AddDays(-g));return(ob(a,b,f.AddDays(+g)).r-k.r)/g},d,c);if(!d)throw"Failed to find peak planet shadow time."; +return ob(a,b,d)}function md(a,b){function c(g){return Ob(g,b)}var d=a.AddDays(-.2),f=a.AddDays(.2);d=K(function(g){return Pb(c,g)},d,f);if(!d)throw"PeakLocalMoonShadow: search failure for search_center_time = "+a;return Ob(d,b)}function Qb(a,b,c){var d=c/1440;c=a.AddDays(-d);d=a.AddDays(+d);c=K(function(f){return-(nb(f).r-b)},c,a);a=K(function(f){return+(nb(f).r-b)},a,d);if(!c||!a)throw"Failed to find shadow semiduration";return 720*(a.ut-c.ut)}function Rb(a){a=ba(a);return e.RAD2DEG*a.geo_eclip_lat} +function Fc(a){a=v(a);for(var b=0;12>b;++b){var c=Ua(180,a,40);if(!c)throw"Cannot find full moon.";a=Rb(c);if(1.8>Math.abs(a)&&(a=jd(c),a.rb;++b){var c=Ua(0,a,40);if(!c)throw"Cannot find new moon"; +a=Rb(c);if(1.8>Math.abs(a)&&(a=kd(c),a.r=d?d+=360:180a.r)throw"Unexpected shadow distance from geoid intersection = "+a.r;g=.014Math.abs(c)){var d=md(a,b);if(d.rza(a,d)&&(b=ld(a,c,d),b.r=c.lat*f.lat){a.$jscomp$loop$prop$kind$33=f.lat>c.lat?oa.Ascending:oa.Descending;b=K(function(g){return function(k){return g.$jscomp$loop$prop$kind$33* jb(k).lat}}(a),b,d);if(!b)throw"Could not find moon node.";return new Tc(a.$jscomp$loop$prop$kind$33,b)}b=d;c=f}}function Uc(a,b,c,d,f){if(1>a||5=c)throw"Major mass must be a positive number.";if(!Number.isFinite(f)||0>=f)throw"Minor mass must be a negative number.";var g=d.x-b.x,k=d.y-b.y,l=d.z-b.z,h=g*g+k*k+l*l,m=Math.sqrt(h),n=d.vx-b.vx,q=d.vy-b.vy;d=d.vz-b.vz;if(4===a||5===a){h=k*d-l*q;c=l*n-g*d;var t=g*q-k*n,y=c*l-t*k;t=t*g-h*l;h= -h*k-c*g;c=Math.sqrt(y*y+t*t+h*h);y/=c;t/=c;h/=c;g/=m;k/=m;l/=m;a=4==a?.8660254037844386:-.8660254037844386;c=.5*g+a*y;f=.5*k+a*t;var w=.5*l+a*h,z=n*g+q*k+d*l;n=n*y+q*t+d*h;b=new I(m*c,m*f,m*w,z*c+n*(.5*y-a*g),z*f+n*(.5*t-a*k),z*w+n*(.5*h-a*l),b.t)}else{y=f/(c+f)*-m;t=c/(c+f)*+m;h=(c+f)/(h*m);if(1===a||2===a)w=c/(c+f)*Math.cbrt(f/(3*c)),c=-c,1==a?(w=1-w,a=+f):(w=1+w,a=-f);else if(3===a)w=(7/12*f-c)/(f+c),c=+c,a=+f;else throw"Invalid Langrage point "+a+". Must be an integer 1..5.";f=m*w-y;do w=f-y, -z=f-t,w=(h*f+c/(w*w)+a/(z*z))/(h-2*c/(w*w*w)-2*a/(z*z*z)),f-=w;while(1E-14Math.abs(c))return b; -b=b.AddDays(c)}};P.prototype.toString=function(){return this.date.toISOString()};P.prototype.AddDays=function(a){return new P(this.ut+a)};e.AstroTime=P;e.MakeTime=v;var Wb=[[[0,0,0,0,1],[-172064161,-174666,33386,92052331,9086,15377]],[[0,0,2,-2,2],[-13170906,-1675,-13696,5730336,-3015,-4587]],[[0,0,2,0,2],[-2276413,-234,2796,978459,-485,1374]],[[0,0,0,0,2],[2074554,207,-698,-897492,470,-291]],[[0,1,0,0,0],[1475877,-3633,11817,73871,-184,-1924]],[[0,1,2,-2,2],[-516821,1226,-524,224386,-677,-174]], +5.18592878704,1.4844727083],[.0053776051,4.52113935896,35.1640902212],[.00495725141,1.5710564165,491.5579294568],[.00274571975,1.84552258866,175.1660598002],[1.201232E-4,1.92059384991,1021.2488945514],[.00121801746,5.79754470298,76.2660712756],[.00100896068,.3770272493,73.297125859],[.00135134092,3.37220609835,39.6175083461],[7.571796E-5,1.07149207335,388.4651552382]]]]};e.DeltaT_EspenakMeeus=R;e.DeltaT_JplHorizons=function(a){return R(Math.min(a,17*365.24217))};var Ub=R;e.SetDeltaTFunction=function(a){Ub= +a};var Q=function(a){if(a instanceof Q)this.date=a.date,this.ut=a.ut,this.tt=a.tt;else if(a instanceof Date&&Number.isFinite(a.getTime()))this.date=a,this.ut=(a.getTime()-wb.getTime())/864E5,this.tt=Ea(this.ut);else if(Number.isFinite(a))this.date=new Date(wb.getTime()+864E5*a),this.ut=a,this.tt=Ea(this.ut);else throw"Argument must be a Date object, an AstroTime object, or a numeric UTC Julian date.";};Q.FromTerrestrialTime=function(a){for(var b=new Q(a);;){var c=a-b.tt;if(1E-12>Math.abs(c))return b; +b=b.AddDays(c)}};Q.prototype.toString=function(){return this.date.toISOString()};Q.prototype.AddDays=function(a){return new Q(this.ut+a)};e.AstroTime=Q;e.MakeTime=v;var Wb=[[[0,0,0,0,1],[-172064161,-174666,33386,92052331,9086,15377]],[[0,0,2,-2,2],[-13170906,-1675,-13696,5730336,-3015,-4587]],[[0,0,2,0,2],[-2276413,-234,2796,978459,-485,1374]],[[0,0,0,0,2],[2074554,207,-698,-897492,470,-291]],[[0,1,0,0,0],[1475877,-3633,11817,73871,-184,-1924]],[[0,1,2,-2,2],[-516821,1226,-524,224386,-677,-174]], [[1,0,0,0,0],[711159,73,-872,-6750,0,358]],[[0,0,2,0,1],[-387298,-367,380,200728,18,318]],[[1,0,2,0,2],[-301461,-36,816,129025,-63,367]],[[0,-1,2,-2,2],[215829,-494,111,-95929,299,132]],[[0,0,2,-2,1],[128227,137,181,-68982,-9,39]],[[-1,0,2,0,2],[123457,11,19,-53311,32,-4]],[[-1,0,0,2,0],[156994,10,-168,-1235,0,82]],[[1,0,0,0,1],[63110,63,27,-33228,0,-9]],[[-1,0,0,0,1],[-57976,-63,-189,31429,0,-75]],[[-1,0,2,2,2],[-59641,-11,149,25543,-11,66]],[[1,0,2,0,1],[-51613,-42,129,26366,0,78]],[[-2,0,2,0,1], [45893,50,31,-24236,-10,20]],[[0,0,0,2,0],[63384,11,-150,-1220,0,29]],[[0,0,2,2,2],[-38571,-1,158,16452,-11,68]],[[0,-2,2,-2,2],[32481,0,0,-13870,0,0]],[[-2,0,0,2,0],[-47722,0,-18,477,0,-25]],[[2,0,2,0,2],[-31046,-1,131,13238,-11,59]],[[1,0,2,-2,2],[28593,0,-1,-12338,10,-3]],[[-1,0,2,0,1],[20441,21,10,-10758,0,-3]],[[2,0,0,0,0],[29243,0,-74,-609,0,13]],[[0,0,2,0,0],[25887,0,-66,-550,0,11]],[[0,1,0,0,1],[-14053,-25,79,8551,-2,-45]],[[-1,0,0,2,1],[15164,10,11,-8001,0,-1]],[[0,2,2,-2,2],[-15794,72,-16, 6850,-42,-5]],[[0,0,-2,2,0],[21783,0,13,-167,0,13]],[[1,0,0,-2,1],[-12873,-10,-37,6953,0,-14]],[[0,-1,0,0,1],[-12654,11,63,6415,0,26]],[[-1,0,2,2,1],[-10204,0,25,5222,0,15]],[[0,2,0,0,0],[16707,-85,-10,168,-1,10]],[[1,0,2,2,2],[-7691,0,44,3268,0,19]],[[-2,0,2,0,0],[-11024,0,-14,104,0,2]],[[0,1,2,0,2],[7566,-21,-11,-3250,0,-5]],[[0,0,2,2,1],[-6637,-11,25,3353,0,14]],[[0,-1,2,0,2],[-7141,21,8,3070,0,4]],[[0,0,0,2,1],[-6302,-11,2,3272,0,4]],[[1,0,2,-2,1],[5800,10,2,-3045,0,-1]],[[2,0,2,-2,2],[6443,0, @@ -170,11 +170,11 @@ g.geo_eclip_lat;g=g.distance_au*e.KM_PER_AU;var l=1.543*e.DEG2RAD,h=e.DEG2RAD*ya Math.sin(k)*Math.sin(l),Math.cos(t)*Math.cos(k));var y=xa(e.RAD2DEG*(f-h));l=Math.asin(-Math.sin(t)*Math.cos(k)*Math.sin(l)-Math.sin(k)*Math.cos(l));t=-.02752*Math.cos(q)+-.02245*Math.sin(h)+.00684*Math.cos(q-2*h)+-.00293*Math.cos(2*h)+-8.5E-4*Math.cos(2*h-2*d)+-5.4E-4*Math.cos(q-2*d)+-2E-4*Math.sin(q+h)+-2E-4*Math.cos(q+2*h)+-2E-4*Math.cos(q-h)+1.4E-4*Math.cos(q+2*h-2*d);var w=-.02816*Math.sin(q)+.02244*Math.cos(h)+-.00682*Math.sin(q-2*h)+-.00279*Math.sin(2*h)+-8.3E-4*Math.sin(2*h-2*d)+6.9E-4*Math.sin(q- 2*d)+4E-4*Math.cos(q+h)+-2.5E-4*Math.sin(2*q)+-2.3E-4*Math.sin(q+2*h)+2E-4*Math.cos(q-h)+1.9E-4*Math.sin(q-h)+1.3E-4*Math.sin(q+2*h-2*d)+-1E-4*Math.cos(q-3*h);return new Vc(e.RAD2DEG*l+(w*Math.cos(f)-t*Math.sin(f)),y+(-(.0252*c*Math.sin(n)+.00473*Math.sin(2*q-2*h)+-.00467*Math.sin(q)+.00396*Math.sin(e.DEG2RAD*(119.75+131.849*a))+.00276*Math.sin(2*q-2*d)+.00196*Math.sin(m)+-.00183*Math.cos(q-h)+.00115*Math.sin(q-2*d)+-9.6E-4*Math.sin(q-d)+4.6E-4*Math.sin(2*h-2*d)+-3.9E-4*Math.sin(q-h)+-3.2E-4*Math.sin(q- n-d)+2.7E-4*Math.sin(2*q-n-2*d)+2.3E-4*Math.sin(e.DEG2RAD*(72.56+20.186*a))+-1.4E-4*Math.sin(2*d)+1.4E-4*Math.cos(2*q-2*h)+-1.2E-4*Math.sin(q-2*h)+-1.2E-4*Math.sin(2*q)+1.1E-4*Math.sin(2*q-2*n-2*d))+(t*Math.cos(f)+w*Math.sin(f))*Math.tan(l)),e.RAD2DEG*k,e.RAD2DEG*b,g,2*e.RAD2DEG*Math.atan(1737.4/Math.sqrt(g*g-1737.4*1737.4)))};var eb;e.SiderealTime=function(a){a=v(a);return aa(a)};var E=function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.t=d};E.prototype.Length=function(){return Math.hypot(this.x,this.y, -this.z)};e.Vector=E;var I=function(a,b,c,d,f,g,k){this.x=a;this.y=b;this.z=c;this.vx=d;this.vy=f;this.vz=g;this.t=k};e.StateVector=I;var Na=function(a,b,c){this.lat=x(a);this.lon=x(b);this.dist=x(c)};e.Spherical=Na;var hb=function(a,b,c,d){this.ra=x(a);this.dec=x(b);this.dist=x(c);this.vec=d};e.EquatorialCoordinates=hb;var L=function(a){this.rot=a};e.RotationMatrix=L;e.MakeRotation=function(a){if(!dd(a))throw"Argument must be a [3][3] array of numbers";return new L(a)};var bc=function(a,b,c,d){this.azimuth= -x(a);this.altitude=x(b);this.ra=x(c);this.dec=x(d)};e.HorizontalCoordinates=bc;var ec=function(a,b,c){this.vec=a;this.elat=x(b);this.elon=x(c)};e.EclipticCoordinates=ec;e.Horizon=Ja;var vb=function(a,b,c){this.latitude=a;this.longitude=b;this.height=c;ta(this)};e.Observer=vb;e.SunPosition=cc;e.Equator=La;e.ObserverVector=function(a,b,c){a=v(a);var d=aa(a);b=ub(b,d).pos;c||(b=gb(b,a,G.Into2000));return new E(b[0],b[1],b[2],a)};e.ObserverState=function(a,b,c){a=v(a);var d=aa(a);b=ub(b,d);b=new I(b.pos[0], +this.z)};e.Vector=E;var J=function(a,b,c,d,f,g,k){this.x=a;this.y=b;this.z=c;this.vx=d;this.vy=f;this.vz=g;this.t=k};e.StateVector=J;var Na=function(a,b,c){this.lat=x(a);this.lon=x(b);this.dist=x(c)};e.Spherical=Na;var hb=function(a,b,c,d){this.ra=x(a);this.dec=x(b);this.dist=x(c);this.vec=d};e.EquatorialCoordinates=hb;var M=function(a){this.rot=a};e.RotationMatrix=M;e.MakeRotation=function(a){if(!dd(a))throw"Argument must be a [3][3] array of numbers";return new M(a)};var bc=function(a,b,c,d){this.azimuth= +x(a);this.altitude=x(b);this.ra=x(c);this.dec=x(d)};e.HorizontalCoordinates=bc;var ec=function(a,b,c){this.vec=a;this.elat=x(b);this.elon=x(c)};e.EclipticCoordinates=ec;e.Horizon=Ja;var vb=function(a,b,c){this.latitude=a;this.longitude=b;this.height=c;ta(this)};e.Observer=vb;e.SunPosition=cc;e.Equator=La;e.ObserverVector=function(a,b,c){a=v(a);var d=aa(a);b=ub(b,d).pos;c||(b=gb(b,a,G.Into2000));return new E(b[0],b[1],b[2],a)};e.ObserverState=function(a,b,c){a=v(a);var d=aa(a);b=ub(b,d);b=new J(b.pos[0], b.pos[1],b.pos[2],b.vel[0],b.vel[1],b.vel[2],a);return c?b:(c=G.Into2000,c===G.Into2000?(d=Ia(a,c),b=wa(d,b),a=Ha(a,c),a=wa(a,b)):(d=Ha(a,c),b=wa(d,b),a=Ia(a,c),a=wa(a,b)),a)};e.VectorObserver=function(a,b){var c=aa(a.t),d=[a.x,a.y,a.z];b||(d=Ga(d,a.t,G.From2000),d=fb(d,a.t,G.From2000));b=d[0]*e.KM_PER_AU;var f=d[1]*e.KM_PER_AU;d=d[2]*e.KM_PER_AU;a=Math.hypot(b,f);if(1E-6>a){c=0;var g=0=c;)c+=360;for(;180Math.abs(n))break;g-=n/(-42.69778487239616*((l-h)/k-h*l*-.006694397995865464/(-42.69778487239616*m))+d*f+a*b)}g*=e.RAD2DEG;k=6378.1366/k;d=Math.abs(f)>Math.abs(b)?d/f-.9933056020041345*k:a/b-k}return new vb(g,c,1E3*d)};e.ObserverGravity=function(a,b){a=Math.sin(a*e.DEG2RAD);a*=a;return 9.7803253359*(1+.00193185265241*a)/Math.sqrt(1-.00669437999013* -a)*(1-(3.15704E-7-2.10269E-9*a)*b+7.37452E-14*b*b)};e.Ecliptic=Ma;e.GeoMoon=W;e.EclipticGeoMoon=jb;e.GeoMoonState=Oa;e.GeoEmbState=xb;var ka=[[-73E4,[-26.118207232108,-14.376168177825,3.384402515299],[.0016339372163656,-.0027861699588508,-.0013585880229445]],[-700800,[41.974905202127,-.448502952929,-12.770351505989],[7.3458569351457E-4,.0022785014891658,4.8619778602049E-4]],[-671600,[14.706930780744,44.269110540027,9.353698474772],[-.00210001479998,2.2295915939915E-4,7.0143443551414E-4]],[-642400, +a)*(1-(3.15704E-7-2.10269E-9*a)*b+7.37452E-14*b*b)};e.Ecliptic=Ma;e.GeoMoon=X;e.EclipticGeoMoon=jb;e.GeoMoonState=Oa;e.GeoEmbState=xb;var ka=[[-73E4,[-26.118207232108,-14.376168177825,3.384402515299],[.0016339372163656,-.0027861699588508,-.0013585880229445]],[-700800,[41.974905202127,-.448502952929,-12.770351505989],[7.3458569351457E-4,.0022785014891658,4.8619778602049E-4]],[-671600,[14.706930780744,44.269110540027,9.353698474772],[-.00210001479998,2.2295915939915E-4,7.0143443551414E-4]],[-642400, [-29.441003929957,-6.43016153057,6.858481011305],[8.4495803960544E-4,-.0030783914758711,-.0012106305981192]],[-613200,[39.444396946234,-6.557989760571,-13.913760296463],[.0011480029005873,.0022400006880665,3.5168075922288E-4]],[-584E3,[20.2303809507,43.266966657189,7.382966091923],[-.0019754081700585,5.3457141292226E-4,7.5929169129793E-4]],[-554800,[-30.65832536462,2.093818874552,9.880531138071],[6.1010603013347E-5,-.0031326500935382,-9.9346125151067E-4]],[-525600,[35.737703251673,-12.587706024764, -14.677847247563],[.0015802939375649,.0021347678412429,1.9074436384343E-4]],[-496400,[25.466295188546,41.367478338417,5.216476873382],[-.0018054401046468,8.328308359951E-4,8.0260156912107E-4]],[-467200,[-29.847174904071,10.636426313081,12.297904180106],[-6.3257063052907E-4,-.0029969577578221,-7.4476074151596E-4]],[-438E3,[30.774692107687,-18.236637015304,-14.945535879896],[.0020113162005465,.0019353827024189,-2.0937793168297E-6]],[-408800,[30.243153324028,38.656267888503,2.938501750218],[-.0016052508674468, .0011183495337525,8.3333973416824E-4]],[-379600,[-27.288984772533,18.643162147874,14.023633623329],[-.0011856388898191,-.0027170609282181,-4.9015526126399E-4]],[-350400,[24.519605196774,-23.245756064727,-14.626862367368],[.0024322321483154,.0016062008146048,-2.3369181613312E-4]],[-321200,[34.505274805875,35.125338586954,.557361475637],[-.0013824391637782,.0013833397561817,8.4823598806262E-4]],[-292E3,[-23.275363915119,25.818514298769,15.055381588598],[-.0016062295460975,-.0023395961498533,-2.4377362639479E-4]], @@ -187,10 +187,10 @@ a)*(1-(3.15704E-7-2.10269E-9*a)*b+7.37452E-14*b*b)};e.Ecliptic=Ma;e.GeoMoon=W;e. [496400,[31.375957451819,38.050372720763,2.433138343754],[-.0015546055556611,.0011699815465629,8.3565439266001E-4]],[525600,[-26.360071336928,20.662505904952,14.414696258958],[-.0013142373118349,-.0026236647854842,-4.2542017598193E-4]],[554800,[22.599441488648,-24.508879898306,-14.484045731468],[.0025454108304806,.0014917058755191,-3.0243665086079E-4]],[584E3,[35.877864013014,33.894226366071,-.224524636277],[-.0012941245730845,.0014560427668319,8.4762160640137E-4]],[613200,[-21.538149762417,28.204068269761, 15.321973799534],[-.001731211740901,-.0021939631314577,-1.631691327518E-4]],[642400,[13.971521374415,-28.339941764789,-13.083792871886],[.0029334630526035,9.1860931752944E-4,-5.9939422488627E-4]],[671600,[39.526942044143,28.93989736011,-2.872799527539],[-.0010068481658095,.001702113288809,8.3578230511981E-4]],[700800,[-15.576200701394,34.399412961275,15.466033737854],[-.0020098814612884,-.0017191109825989,7.0414782780416E-5]],[73E4,[4.24325283709,-30.118201690825,-10.707441231349],[.0031725847067411, 1.609846120227E-4,-9.0672150593868E-4]]],B=function(a,b,c){this.x=a;this.y=b;this.z=c};B.prototype.clone=function(){return new B(this.x,this.y,this.z)};B.prototype.ToAstroVector=function(a){return new E(this.x,this.y,this.z,a)};B.zero=function(){return new B(0,0,0)};B.prototype.quadrature=function(){return this.x*this.x+this.y*this.y+this.z*this.z};B.prototype.add=function(a){return new B(this.x+a.x,this.y+a.y,this.z+a.z)};B.prototype.sub=function(a){return new B(this.x-a.x,this.y-a.y,this.z-a.z)}; -B.prototype.incr=function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z};B.prototype.decr=function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z};B.prototype.mul=function(a){return new B(a*this.x,a*this.y,a*this.z)};B.prototype.div=function(a){return new B(this.x/a,this.y/a,this.z/a)};B.prototype.mean=function(a){return new B((this.x+a.x)/2,(this.y+a.y)/2,(this.z+a.z)/2)};B.prototype.neg=function(){return new B(-this.x,-this.y,-this.z)};var V=function(a,b,c){this.tt=a;this.r=b;this.v=c};V.prototype.clone=function(){return new V(this.tt, -this.r,this.v)};V.prototype.sub=function(a){return new V(this.tt,this.r.sub(a.r),this.v.sub(a.v))};var va=function(a){var b=new V(a,new B(0,0,0),new B(0,0,0));this.Jupiter=S(b,a,p.Jupiter,2.825345909524226E-7);this.Saturn=S(b,a,p.Saturn,8.459715185680659E-8);this.Uranus=S(b,a,p.Uranus,1.292024916781969E-8);this.Neptune=S(b,a,p.Neptune,1.524358900784276E-8);this.Jupiter.r.decr(b.r);this.Jupiter.v.decr(b.v);this.Saturn.r.decr(b.r);this.Saturn.v.decr(b.v);this.Uranus.r.decr(b.r);this.Uranus.v.decr(b.v); -this.Neptune.r.decr(b.r);this.Neptune.v.decr(b.v);this.Sun=new V(a,b.r.mul(-1),b.v.mul(-1))};va.prototype.Acceleration=function(a){var b=Qa(a,2.959122082855911E-4,this.Sun.r);b.incr(Qa(a,2.825345909524226E-7,this.Jupiter.r));b.incr(Qa(a,8.459715185680659E-8,this.Saturn.r));b.incr(Qa(a,1.292024916781969E-8,this.Uranus.r));b.incr(Qa(a,1.524358900784276E-8,this.Neptune.r));return b};var Ra=function(a,b,c,d){this.tt=a;this.r=b;this.v=c;this.a=d};Ra.prototype.clone=function(){return new Ra(this.tt,this.r.clone(), -this.v.clone(),this.a.clone())};var ic=function(a,b){this.bary=a;this.grav=b},Eb=[],ed=new L([[.999432765338654,-.0336771074697641,0],[.0303959428906285,.902057912352809,.430543388542295],[-.0144994559663353,-.430299169409101,.902569881273754]]),qb=[{mu:2.82489428433814E-7,al:[1.446213296021224,3.5515522861824],a:[[.0028210960212903,0,0]],l:[[-1.925258348666E-4,4.9369589722645,.01358483658305],[-9.70803596076E-5,4.3188796477322,.01303413843243],[-8.988174165E-5,1.9080016428617,.00305064867158],[-5.53101050262E-5, +B.prototype.incr=function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z};B.prototype.decr=function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z};B.prototype.mul=function(a){return new B(a*this.x,a*this.y,a*this.z)};B.prototype.div=function(a){return new B(this.x/a,this.y/a,this.z/a)};B.prototype.mean=function(a){return new B((this.x+a.x)/2,(this.y+a.y)/2,(this.z+a.z)/2)};B.prototype.neg=function(){return new B(-this.x,-this.y,-this.z)};var W=function(a,b,c){this.tt=a;this.r=b;this.v=c};W.prototype.clone=function(){return new W(this.tt, +this.r,this.v)};W.prototype.sub=function(a){return new W(this.tt,this.r.sub(a.r),this.v.sub(a.v))};var va=function(a){var b=new W(a,new B(0,0,0),new B(0,0,0));this.Jupiter=T(b,a,p.Jupiter,2.825345909524226E-7);this.Saturn=T(b,a,p.Saturn,8.459715185680659E-8);this.Uranus=T(b,a,p.Uranus,1.292024916781969E-8);this.Neptune=T(b,a,p.Neptune,1.524358900784276E-8);this.Jupiter.r.decr(b.r);this.Jupiter.v.decr(b.v);this.Saturn.r.decr(b.r);this.Saturn.v.decr(b.v);this.Uranus.r.decr(b.r);this.Uranus.v.decr(b.v); +this.Neptune.r.decr(b.r);this.Neptune.v.decr(b.v);this.Sun=new W(a,b.r.mul(-1),b.v.mul(-1))};va.prototype.Acceleration=function(a){var b=Qa(a,2.959122082855911E-4,this.Sun.r);b.incr(Qa(a,2.825345909524226E-7,this.Jupiter.r));b.incr(Qa(a,8.459715185680659E-8,this.Saturn.r));b.incr(Qa(a,1.292024916781969E-8,this.Uranus.r));b.incr(Qa(a,1.524358900784276E-8,this.Neptune.r));return b};var Ra=function(a,b,c,d){this.tt=a;this.r=b;this.v=c;this.a=d};Ra.prototype.clone=function(){return new Ra(this.tt,this.r.clone(), +this.v.clone(),this.a.clone())};var ic=function(a,b){this.bary=a;this.grav=b},Eb=[],ed=new M([[.999432765338654,-.0336771074697641,0],[.0303959428906285,.902057912352809,.430543388542295],[-.0144994559663353,-.430299169409101,.902569881273754]]),qb=[{mu:2.82489428433814E-7,al:[1.446213296021224,3.5515522861824],a:[[.0028210960212903,0,0]],l:[[-1.925258348666E-4,4.9369589722645,.01358483658305],[-9.70803596076E-5,4.3188796477322,.01303413843243],[-8.988174165E-5,1.9080016428617,.00305064867158],[-5.53101050262E-5, 1.4936156681569,.01293892891155]],z:[[.0041510849668155,4.089939635545,-.01290686414666],[6.260521444113E-4,1.446188898627,3.5515522949802],[3.52747346169E-5,2.1256287034578,1.2727416567E-4]],zeta:[[3.142172466014E-4,2.7964219722923,-.002315096098],[9.04169207946E-5,1.0477061879627,-5.6920638196E-4]]},{mu:2.82483274392893E-7,al:[-.3735263437471362,1.76932271112347],a:[[.0044871037804314,0,0],[4.324367498E-7,1.819645606291,1.7822295777568]],l:[[8.576433172936E-4,4.3188693178264,.01303413830805],[4.549582875086E-4, 1.4936531751079,.01293892881962],[3.248939825174E-4,1.8196494533458,1.7822295777568],[-3.074250079334E-4,4.9377037005911,.01358483286724],[1.982386144784E-4,1.907986905476,.00305101212869],[1.834063551804E-4,2.1402853388529,.00145009789338],[-1.434383188452E-4,5.622214036663,.89111478887838],[-7.71939140944E-5,4.300272437235,2.6733443704266]],z:[[-.0093589104136341,4.0899396509039,-.01290686414666],[2.988994545555E-4,5.9097265185595,1.7693227079462],[2.13903639035E-4,2.1256289300016,1.2727418407E-4], [1.980963564781E-4,2.743516829265,6.7797343009E-4],[1.210388158965E-4,5.5839943711203,3.20566149E-5],[8.37042048393E-5,1.6094538368039,-.90402165808846],[8.23525166369E-5,1.4461887708689,3.5515522949802]],zeta:[[.0040404917832303,1.0477063169425,-5.692064054E-4],[2.200421034564E-4,3.3368857864364,-1.2491307307E-4],[1.662544744719E-4,2.4134862374711,0],[5.90282470983E-5,5.9719930968366,-3.056160225E-5]]},{mu:2.82498184184723E-7,al:[.2874089391143348,.878207923589328],a:[[.0071566594572575,0,0],[1.393029911E-6, @@ -198,21 +198,21 @@ this.v.clone(),this.a.clone())};var ic=function(a,b){this.bary=a;this.grav=b},Eb [7.71093122676E-4,5.5836330003496,3.20643411E-5],[5.925911780766E-4,4.0899396636448,-.01290686414666],[2.045597496146E-4,5.2713683670372,-.12523544076106],[1.785118648258E-4,.28743156721063,.8782079244252],[1.131999784893E-4,1.4462127277818,3.5515522949802],[-6.5877816921E-5,2.2702423990985,-1.7951364394537],[4.97058888328E-5,5.9096792204858,1.7693227129285]],zeta:[[.0015932721570848,3.3368862796665,-1.2491307058E-4],[8.533093128905E-4,2.4133881688166,0],[3.513347911037E-4,5.9720789850127,-3.056101771E-5], [-1.441929255483E-4,1.0477061764435,-5.6920632124E-4]]},{mu:2.82492144889909E-7,al:[-.3620341291375704,.376486233433828],a:[[.0125879701715314,0,0],[3.595204947E-6,.64965776007116,.50172168165034],[2.7580210652E-6,1.808423578151,3.1750660413359]],l:[[5.586040123824E-4,2.1404207189815,.00145009793231],[-3.805813868176E-4,2.7358844897853,2.972965062E-5],[2.205152863262E-4,.649796525964,.5017216724358],[1.877895151158E-4,1.8084787604005,3.1750660413359],[7.66916975242E-5,6.2720114319755,1.3928364636651], [7.47056855106E-5,1.2995916202344,1.0034433456729]],z:[[.0073755808467977,5.5836071576084,3.206509914E-5],[2.065924169942E-4,5.9209831565786,.37648624194703],[1.589869764021E-4,.28744006242623,.8782079244252],[-1.561131605348E-4,2.1257397865089,1.2727441285E-4],[1.486043380971E-4,1.4462134301023,3.5515522949802],[6.35073108731E-5,5.9096803285954,1.7693227129285],[5.99351698525E-5,4.1125517584798,-2.7985797954589],[5.40660842731E-5,5.5390350845569,.00286834082283],[-4.89596900866E-5,4.6218149483338, --.62695712529519]],zeta:[[.0038422977898495,2.4133922085557,0],[.0022453891791894,5.9721736773277,-3.056125525E-5],[-2.604479450559E-4,3.3368746306409,-1.2491309972E-4],[3.3211214323E-5,5.5604137742337,.00290037688507]]}],Wc=function(a,b,c,d){this.io=a;this.europa=b;this.ganymede=c;this.callisto=d};e.JupiterMoonsInfo=Wc;e.JupiterMoons=function(a){a=new P(a);return new Wc(lb(a,qb[0]),lb(a,qb[1]),lb(a,qb[2]),lb(a,qb[3]))};e.HelioVector=Sa;e.HelioDistance=la;e.GeoVector=fa;e.BaryState=function(a,b){b= -v(b);if(a===p.SSB)return new I(0,0,0,0,0,0,b);if(a===p.Pluto)return Db(b,!1);var c=new va(b.tt);switch(a){case p.Sun:return ma(c.Sun,b);case p.Jupiter:return ma(c.Jupiter,b);case p.Saturn:return ma(c.Saturn,b);case p.Uranus:return ma(c.Uranus,b);case p.Neptune:return ma(c.Neptune,b);case p.Moon:case p.EMB:var d=Pa(H[p.Earth],b.tt);a=a===p.Moon?Oa(b):xb(b);return new I(a.x+c.Sun.r.x+d.r.x,a.y+c.Sun.r.y+d.r.y,a.z+c.Sun.r.z+d.r.z,a.vx+c.Sun.v.x+d.v.x,a.vy+c.Sun.v.y+d.v.y,a.vz+c.Sun.v.z+d.v.z,b)}if(a in -H)return a=Pa(H[a],b.tt),new I(c.Sun.r.x+a.r.x,c.Sun.r.y+a.r.y,c.Sun.r.z+a.r.z,c.Sun.v.x+a.v.x,c.Sun.v.y+a.v.y,c.Sun.v.z+a.v.z,b);throw'BaryState: Unsupported body "'+a+'"';};e.HelioState=Fb;e.Search=J;e.SearchSunLongitude=lc;e.PairLongitude=Gb;e.AngleFromSun=za;e.EclipticLongitude=na;var mc=function(a,b,c,d,f,g,k,l){this.time=a;this.mag=b;this.phase_angle=c;this.helio_dist=d;this.geo_dist=f;this.gc=g;this.hc=k;this.ring_tilt=l;this.phase_fraction=(1+Math.cos(e.DEG2RAD*c))/2};e.IlluminationInfo=mc; +-.62695712529519]],zeta:[[.0038422977898495,2.4133922085557,0],[.0022453891791894,5.9721736773277,-3.056125525E-5],[-2.604479450559E-4,3.3368746306409,-1.2491309972E-4],[3.3211214323E-5,5.5604137742337,.00290037688507]]}],Wc=function(a,b,c,d){this.io=a;this.europa=b;this.ganymede=c;this.callisto=d};e.JupiterMoonsInfo=Wc;e.JupiterMoons=function(a){a=new Q(a);return new Wc(lb(a,qb[0]),lb(a,qb[1]),lb(a,qb[2]),lb(a,qb[3]))};e.HelioVector=Sa;e.HelioDistance=la;e.GeoVector=fa;e.BaryState=function(a,b){b= +v(b);if(a===p.SSB)return new J(0,0,0,0,0,0,b);if(a===p.Pluto)return Db(b,!1);var c=new va(b.tt);switch(a){case p.Sun:return ma(c.Sun,b);case p.Jupiter:return ma(c.Jupiter,b);case p.Saturn:return ma(c.Saturn,b);case p.Uranus:return ma(c.Uranus,b);case p.Neptune:return ma(c.Neptune,b);case p.Moon:case p.EMB:var d=Pa(I[p.Earth],b.tt);a=a===p.Moon?Oa(b):xb(b);return new J(a.x+c.Sun.r.x+d.r.x,a.y+c.Sun.r.y+d.r.y,a.z+c.Sun.r.z+d.r.z,a.vx+c.Sun.v.x+d.v.x,a.vy+c.Sun.v.y+d.v.y,a.vz+c.Sun.v.z+d.v.z,b)}if(a in +I)return a=Pa(I[a],b.tt),new J(c.Sun.r.x+a.r.x,c.Sun.r.y+a.r.y,c.Sun.r.z+a.r.z,c.Sun.v.x+a.v.x,c.Sun.v.y+a.v.y,c.Sun.v.z+a.v.z,b);throw'BaryState: Unsupported body "'+a+'"';};e.HelioState=Fb;e.Search=K;e.SearchSunLongitude=lc;e.PairLongitude=Gb;e.AngleFromSun=za;e.EclipticLongitude=na;var mc=function(a,b,c,d,f,g,k,l){this.time=a;this.mag=b;this.phase_angle=c;this.helio_dist=d;this.geo_dist=f;this.gc=g;this.hc=k;this.ring_tilt=l;this.phase_fraction=(1+Math.cos(e.DEG2RAD*c))/2};e.IlluminationInfo=mc; e.Illumination=mb;e.SearchRelativeLongitude=Aa;e.MoonPhase=Hb;e.SearchMoonPhase=Ua;var oc=function(a,b){this.quarter=a;this.time=b};e.MoonQuarter=oc;e.SearchMoonQuarter=nc;e.NextMoonQuarter=function(a){a=new Date(a.time.date.getTime()+5184E5);return nc(a)};e.SearchRiseSet=function(a,b,c,d,f){a:switch(a){case p.Sun:var g=nd;break a;case p.Moon:g=od;break a;default:g=0}return pc(a,b,c,d,f,function(k){var l=La(a,k,b,!0,!0);k=Ja(k,b,l.ra,l.dec).altitude+g/l.dist*e.RAD2DEG+pd;return c*k})};e.SearchAltitude= function(a,b,c,d,f,g){if(!Number.isFinite(g)||-90>g||90=++f;){var g=na(a,b),k=na(p.Earth,b),l=xa(g-k),h=g=k=void 0;l>=-d.s1&&l<+d.s1?(h=0,k=+d.s1,g=+d.s2):l>=+d.s2||l<-d.s2?(h=0,k=-d.s2,g=-d.s1):0<=l?(h=-Ta(a)/4,k=+d.s1,g=+d.s2):(h=-Ta(a)/4,k=-d.s2,g=-d.s1);l=b.AddDays(h);k=Aa(a,k,l);g=Aa(a,g,k);l=c(k);if(0<=l)throw"SearchMaxElongation: internal error: m1 = "+ -l;h=c(g);if(0>=h)throw"SearchMaxElongation: internal error: m2 = "+h;l=J(c,k,g,{init_f1:l,init_f2:h,dt_tolerance_seconds:10});if(!l)throw"SearchMaxElongation: failed search iter "+f+" (t1="+k.toString()+", t2="+g.toString()+")";if(l.tt>=b.tt)return rc(a,l);b=g.AddDays(1)}throw"SearchMaxElongation: failed to find event after 2 tries.";};e.SearchPeakMagnitude=function(a,b){function c(h){var m=h.AddDays(-.005);h=h.AddDays(.005);m=mb(a,m).mag;return(mb(a,h).mag-m)/.01}if(a!==p.Venus)throw"SearchPeakMagnitude currently works for Venus only."; -b=v(b);for(var d=0;2>=++d;){var f=na(a,b),g=na(p.Earth,b),k=xa(f-g),l=f=g=void 0;-10<=k&&10>k?(l=0,g=10,f=30):30<=k||-30>k?(l=0,g=-30,f=-10):0<=k?(l=-Ta(a)/4,g=10,f=30):(l=-Ta(a)/4,g=-30,f=-10);k=b.AddDays(l);g=Aa(a,g,k);f=Aa(a,f,g);k=c(g);if(0<=k)throw"SearchPeakMagnitude: internal error: m1 = "+k;l=c(f);if(0>=l)throw"SearchPeakMagnitude: internal error: m2 = "+l;k=J(c,g,f,{init_f1:k,init_f2:l,dt_tolerance_seconds:10});if(!k)throw"SearchPeakMagnitude: failed search iter "+d+" (t1="+g.toString()+ +l;h=c(g);if(0>=h)throw"SearchMaxElongation: internal error: m2 = "+h;l=K(c,k,g,{init_f1:l,init_f2:h,dt_tolerance_seconds:10});if(!l)throw"SearchMaxElongation: failed search iter "+f+" (t1="+k.toString()+", t2="+g.toString()+")";if(l.tt>=b.tt)return rc(a,l);b=g.AddDays(1)}throw"SearchMaxElongation: failed to find event after 2 tries.";};e.SearchPeakMagnitude=function(a,b){function c(h){var m=h.AddDays(-.005);h=h.AddDays(.005);m=mb(a,m).mag;return(mb(a,h).mag-m)/.01}if(a!==p.Venus)throw"SearchPeakMagnitude currently works for Venus only."; +b=v(b);for(var d=0;2>=++d;){var f=na(a,b),g=na(p.Earth,b),k=xa(f-g),l=f=g=void 0;-10<=k&&10>k?(l=0,g=10,f=30):30<=k||-30>k?(l=0,g=-30,f=-10):0<=k?(l=-Ta(a)/4,g=10,f=30):(l=-Ta(a)/4,g=-30,f=-10);k=b.AddDays(l);g=Aa(a,g,k);f=Aa(a,f,g);k=c(g);if(0<=k)throw"SearchPeakMagnitude: internal error: m1 = "+k;l=c(f);if(0>=l)throw"SearchPeakMagnitude: internal error: m2 = "+l;k=K(c,g,f,{init_f1:k,init_f2:l,dt_tolerance_seconds:10});if(!k)throw"SearchPeakMagnitude: failed search iter "+d+" (t1="+g.toString()+ ", t2="+f.toString()+")";if(k.tt>=b.tt)return mb(a,k);b=f.AddDays(1)}throw"SearchPeakMagnitude: failed to find event after 2 tries.";};var Ba;(function(a){a[a.Pericenter=0]="Pericenter";a[a.Apocenter=1]="Apocenter"})(Ba=e.ApsisKind||(e.ApsisKind={}));var Wa=function(a,b,c){this.time=a;this.kind=b;this.dist_au=c;this.dist_km=c*e.KM_PER_AU};e.Apsis=Wa;e.SearchLunarApsis=tc;e.NextLunarApsis=function(a){var b=tc(a.time.AddDays(11));if(1!==b.kind+a.kind)throw"NextLunarApsis INTERNAL ERROR: did not find alternating apogee/perigee: prev="+ -a.kind+" @ "+a.time.toString()+", next="+b.kind+" @ "+b.time.toString();return b};e.SearchPlanetApsis=vc;e.NextPlanetApsis=function(a,b){if(b.kind!==Ba.Pericenter&&b.kind!==Ba.Apocenter)throw"Invalid apsis kind: "+b.kind;var c=b.time.AddDays(.25*ha[a].OrbitalPeriod);a=vc(a,c);if(1!==a.kind+b.kind)throw"Internal error: previous apsis was "+b.kind+", but found "+a.kind+" for next apsis.";return a};e.InverseRotation=Ca;e.CombineRotation=Da;e.IdentityMatrix=function(){return new L([[1,0,0],[0,1,0],[0, -0,1]])};e.Pivot=function(a,b,c){if(0!==b&&1!==b&&2!==b)throw"Invalid axis "+b+". Must be [0, 1, 2].";var d=x(c)*e.DEG2RAD;c=Math.cos(d);d=Math.sin(d);var f=(b+1)%3,g=(b+2)%3,k=[[0,0,0],[0,0,0],[0,0,0]];k[f][f]=c*a.rot[f][f]-d*a.rot[f][g];k[f][g]=d*a.rot[f][f]+c*a.rot[f][g];k[f][b]=a.rot[f][b];k[g][f]=c*a.rot[g][f]-d*a.rot[g][g];k[g][g]=d*a.rot[g][f]+c*a.rot[g][g];k[g][b]=a.rot[g][b];k[b][f]=c*a.rot[b][f]-d*a.rot[b][g];k[b][g]=d*a.rot[b][f]+c*a.rot[b][g];k[b][b]=a.rot[b][b];return new L(k)};e.VectorFromSphere= -Ib;e.EquatorFromVector=Jb;e.SphereFromVector=Kb;e.HorizonFromVector=function(a,b){a=Kb(a);a.lon=wc(a.lon);a.lat+=Ka(b,a.lat);return a};e.VectorFromHorizon=function(a,b,c){b=v(b);var d=wc(a.lon);c=a.lat+xc(c,a.lat);a=new Na(c,d,a.dist);return Ib(a,b)};e.Refraction=Ka;e.InverseRefraction=xc;e.RotateVector=Xa;e.RotateState=wa;e.Rotation_EQJ_ECL=yc;e.Rotation_ECL_EQJ=function(){return new L([[1,0,0],[0,.9174821430670688,.3977769691083922],[0,-.3977769691083922,.9174821430670688]])};e.Rotation_EQJ_EQD= -Lb;e.Rotation_EQD_EQJ=Mb;e.Rotation_EQD_HOR=Nb;e.Rotation_HOR_EQD=zc;e.Rotation_HOR_EQJ=Ac;e.Rotation_EQJ_HOR=function(a,b){a=Ac(a,b);return Ca(a)};e.Rotation_EQD_ECL=Bc;e.Rotation_ECL_EQD=Cc;e.Rotation_ECL_HOR=Dc;e.Rotation_HOR_ECL=function(a,b){a=Dc(a,b);return Ca(a)};e.Rotation_EQJ_GAL=function(){return new L([[-.0548624779711344,.4941095946388765,-.8676668813529025],[-.8734572784246782,-.4447938112296831,-.1980677870294097],[-.483800052994852,.7470034631630423,.4559861124470794]])};e.Rotation_GAL_EQJ= -function(){return new L([[-.0548624779711344,-.8734572784246782,-.483800052994852],[.4941095946388765,-.4447938112296831,.7470034631630423],[-.8676668813529025,-.1980677870294097,.4559861124470794]])};var qd=[["And","Andromeda"],["Ant","Antila"],["Aps","Apus"],["Aql","Aquila"],["Aqr","Aquarius"],["Ara","Ara"],["Ari","Aries"],["Aur","Auriga"],["Boo","Bootes"],["Cae","Caelum"],["Cam","Camelopardis"],["Cap","Capricornus"],["Car","Carina"],["Cas","Cassiopeia"],["Cen","Centaurus"],["Cep","Cepheus"],["Cet", +a.kind+" @ "+a.time.toString()+", next="+b.kind+" @ "+b.time.toString();return b};e.SearchPlanetApsis=vc;e.NextPlanetApsis=function(a,b){if(b.kind!==Ba.Pericenter&&b.kind!==Ba.Apocenter)throw"Invalid apsis kind: "+b.kind;var c=b.time.AddDays(.25*ha[a].OrbitalPeriod);a=vc(a,c);if(1!==a.kind+b.kind)throw"Internal error: previous apsis was "+b.kind+", but found "+a.kind+" for next apsis.";return a};e.InverseRotation=Ca;e.CombineRotation=Da;e.IdentityMatrix=function(){return new M([[1,0,0],[0,1,0],[0, +0,1]])};e.Pivot=function(a,b,c){if(0!==b&&1!==b&&2!==b)throw"Invalid axis "+b+". Must be [0, 1, 2].";var d=x(c)*e.DEG2RAD;c=Math.cos(d);d=Math.sin(d);var f=(b+1)%3,g=(b+2)%3,k=[[0,0,0],[0,0,0],[0,0,0]];k[f][f]=c*a.rot[f][f]-d*a.rot[f][g];k[f][g]=d*a.rot[f][f]+c*a.rot[f][g];k[f][b]=a.rot[f][b];k[g][f]=c*a.rot[g][f]-d*a.rot[g][g];k[g][g]=d*a.rot[g][f]+c*a.rot[g][g];k[g][b]=a.rot[g][b];k[b][f]=c*a.rot[b][f]-d*a.rot[b][g];k[b][g]=d*a.rot[b][f]+c*a.rot[b][g];k[b][b]=a.rot[b][b];return new M(k)};e.VectorFromSphere= +Ib;e.EquatorFromVector=Jb;e.SphereFromVector=Kb;e.HorizonFromVector=function(a,b){a=Kb(a);a.lon=wc(a.lon);a.lat+=Ka(b,a.lat);return a};e.VectorFromHorizon=function(a,b,c){b=v(b);var d=wc(a.lon);c=a.lat+xc(c,a.lat);a=new Na(c,d,a.dist);return Ib(a,b)};e.Refraction=Ka;e.InverseRefraction=xc;e.RotateVector=Xa;e.RotateState=wa;e.Rotation_EQJ_ECL=yc;e.Rotation_ECL_EQJ=function(){return new M([[1,0,0],[0,.9174821430670688,.3977769691083922],[0,-.3977769691083922,.9174821430670688]])};e.Rotation_EQJ_EQD= +Lb;e.Rotation_EQD_EQJ=Mb;e.Rotation_EQD_HOR=Nb;e.Rotation_HOR_EQD=zc;e.Rotation_HOR_EQJ=Ac;e.Rotation_EQJ_HOR=function(a,b){a=Ac(a,b);return Ca(a)};e.Rotation_EQD_ECL=Bc;e.Rotation_ECL_EQD=Cc;e.Rotation_ECL_HOR=Dc;e.Rotation_HOR_ECL=function(a,b){a=Dc(a,b);return Ca(a)};e.Rotation_EQJ_GAL=function(){return new M([[-.0548624779711344,.4941095946388765,-.8676668813529025],[-.8734572784246782,-.4447938112296831,-.1980677870294097],[-.483800052994852,.7470034631630423,.4559861124470794]])};e.Rotation_GAL_EQJ= +function(){return new M([[-.0548624779711344,-.8734572784246782,-.483800052994852],[.4941095946388765,-.4447938112296831,.7470034631630423],[-.8676668813529025,-.1980677870294097,.4559861124470794]])};var qd=[["And","Andromeda"],["Ant","Antila"],["Aps","Apus"],["Aql","Aquila"],["Aqr","Aquarius"],["Ara","Ara"],["Ari","Aries"],["Aur","Auriga"],["Boo","Bootes"],["Cae","Caelum"],["Cam","Camelopardis"],["Cap","Capricornus"],["Car","Carina"],["Cas","Cassiopeia"],["Cen","Centaurus"],["Cep","Cepheus"],["Cet", "Cetus"],["Cha","Chamaeleon"],["Cir","Circinus"],["CMa","Canis Major"],["CMi","Canis Minor"],["Cnc","Cancer"],["Col","Columba"],["Com","Coma Berenices"],["CrA","Corona Australis"],["CrB","Corona Borealis"],["Crt","Crater"],["Cru","Crux"],["Crv","Corvus"],["CVn","Canes Venatici"],["Cyg","Cygnus"],["Del","Delphinus"],["Dor","Dorado"],["Dra","Draco"],["Equ","Equuleus"],["Eri","Eridanus"],["For","Fornax"],["Gem","Gemini"],["Gru","Grus"],["Her","Hercules"],["Hor","Horologium"],["Hya","Hydra"],["Hyi","Hydrus"], ["Ind","Indus"],["Lac","Lacerta"],["Leo","Leo"],["Lep","Lepus"],["Lib","Libra"],["LMi","Leo Minor"],["Lup","Lupus"],["Lyn","Lynx"],["Lyr","Lyra"],["Men","Mensa"],["Mic","Microscopium"],["Mon","Monoceros"],["Mus","Musca"],["Nor","Norma"],["Oct","Octans"],["Oph","Ophiuchus"],["Ori","Orion"],["Pav","Pavo"],["Peg","Pegasus"],["Per","Perseus"],["Phe","Phoenix"],["Pic","Pictor"],["PsA","Pisces Austrinus"],["Psc","Pisces"],["Pup","Puppis"],["Pyx","Pyxis"],["Ret","Reticulum"],["Scl","Sculptor"],["Sco","Scorpius"], ["Sct","Scutum"],["Ser","Serpens"],["Sex","Sextans"],["Sge","Sagitta"],["Sgr","Sagittarius"],["Tau","Taurus"],["Tel","Telescopium"],["TrA","Triangulum Australe"],["Tri","Triangulum"],["Tuc","Tucana"],["UMa","Ursa Major"],["UMi","Ursa Minor"],["Vel","Vela"],["Vir","Virgo"],["Vol","Volans"],["Vul","Vulpecula"]],rd=[[83,0,8640,2112],[83,2880,5220,2076],[83,7560,8280,2068],[83,6480,7560,2064],[15,0,2880,2040],[10,3300,3840,1968],[15,0,1800,1920],[10,3840,5220,1920],[83,6300,6480,1920],[33,7260,7560,1920], @@ -229,8 +229,8 @@ function(){return new L([[-.0548624779711344,-.8734572784246782,-.48380005299485 -1032],[67,2880,3012,-1032],[35,1230,1392,-1056],[71,5911.5,6420,-1092],[24,6420,6900,-1092],[76,6900,7320,-1092],[53,7320,7680,-1092],[35,1080,1230,-1104],[9,1620,1740,-1116],[49,5520,5640,-1152],[63,0,840,-1156],[35,960,1080,-1176],[40,1470,1536,-1176],[9,1536,1620,-1176],[38,7680,7920,-1200],[67,2160,2880,-1218],[84,2880,2940,-1218],[35,870,960,-1224],[40,1380,1470,-1224],[63,0,660,-1236],[12,2160,2220,-1260],[84,2940,3042,-1272],[40,1260,1380,-1276],[32,1380,1440,-1276],[63,0,570,-1284],[35,780, 870,-1296],[64,1620,1800,-1296],[49,5418,5520,-1296],[84,3042,3180,-1308],[12,2220,2340,-1320],[14,4260,4620,-1320],[49,5100,5418,-1320],[56,5418,5520,-1320],[32,1440,1560,-1356],[84,3180,3960,-1356],[14,3960,4050,-1356],[5,6300,6480,-1368],[78,6480,7320,-1368],[38,7920,8400,-1368],[40,1152,1260,-1380],[64,1800,1980,-1380],[12,2340,2460,-1392],[63,0,480,-1404],[35,480,780,-1404],[63,8400,8640,-1404],[32,1560,1650,-1416],[56,5520,5911.5,-1440],[43,7320,7680,-1440],[64,1980,2160,-1464],[18,5460,5520, -1464],[5,5911.5,5970,-1464],[18,5370,5460,-1526],[5,5970,6030,-1526],[64,2160,2460,-1536],[12,2460,3252,-1536],[14,4050,4260,-1536],[27,4260,4620,-1536],[14,4620,5232,-1536],[18,4860,4920,-1560],[5,6030,6060,-1560],[40,780,1152,-1620],[69,1152,1650,-1620],[18,5310,5370,-1620],[5,6060,6300,-1620],[60,6300,6480,-1620],[81,7920,8400,-1620],[32,1650,2370,-1680],[18,4920,5310,-1680],[79,5310,6120,-1680],[81,0,480,-1800],[42,1260,1650,-1800],[86,2370,3252,-1800],[12,3252,4050,-1800],[55,4050,4920,-1800], -[60,6480,7680,-1800],[43,7680,8400,-1800],[81,8400,8640,-1800],[81,270,480,-1824],[42,0,1260,-1980],[17,2760,4920,-1980],[2,4920,6480,-1980],[52,1260,2760,-2040],[57,0,8640,-2160]],Sb,Yc,Zc=function(a,b,c,d){this.symbol=a;this.name=b;this.ra1875=c;this.dec1875=d};e.ConstellationInfo=Zc;e.Constellation=function(a,b){x(a);x(b);if(-90>b||90a&&(a+=24);Sb||(Sb=Lb(new P(-45655.74141261017)),Yc=new P(0));a=new Na(b,15*a,1);a=Ib(a,Yc);a=Xa(Sb, -a);a=Jb(a);b=10/240;for(var c=b/15,d=$jscomp.makeIterator(rd),f=d.next();!f.done;f=d.next()){f=f.value;var g=f[1]*c,k=f[2]*c;if(f[3]*b<=a.dec&&g<=a.ra&&a.rab||90a&&(a+=24);Sb||(Sb=Lb(new Q(-45655.74141261017)),Yc=new Q(0));a=new Na(b,15*a,1);a=Ib(a,Yc);a=Xa(Sb, +a);a=Jb(a);b=10/240;for(var c=b/15,d=$jscomp.makeIterator(rd),f=d.next();!f.done;f=d.next()){f=f.value;var g=f[1]*c,k=f[2]*c;if(f[3]*b<=a.dec&&g<=a.ra&&a.raa||5=c)throw"Major mass must be a positive number.";if(!Number.isFinite(e)||0>=e)throw"Minor mass must be a negative number.";var f=d.x-b.x,g=d.y-b.y,k=d.z-b.z,h=f*f+g*g+k*k,l=Math.sqrt(h),m=d.vx-b.vx,n=d.vy-b.vy;d=d.vz-b.vz;if(4===a||5===a){h=g*d-k*n;c=k*m-f*d;var p=f*n-g*m,r=c*k-p*g;p=p*f-h*k;h=h*g-c*f;c=Math.sqrt(r*r+p*p+h*h);r/=c;p/=c;h/=c;f/=l;g/=l;k/=l;a=4==a?.8660254037844386:-.8660254037844386; c=.5*f+a*r;e=.5*g+a*p;var q=.5*k+a*h,t=m*f+n*g+d*k;m=m*r+n*p+d*h;b=new StateVector(l*c,l*e,l*q,t*c+m*(.5*r-a*f),t*e+m*(.5*p-a*g),t*q+m*(.5*h-a*k),b.t)}else{r=e/(c+e)*-l;p=c/(c+e)*+l;h=(c+e)/(h*l);if(1===a||2===a)q=c/(c+e)*Math.cbrt(e/(3*c)),c=-c,1==a?(q=1-q,a=+e):(q=1+q,a=-e);else if(3===a)q=(7/12*e-c)/(e+c),c=+c,a=+e;else throw"Invalid Langrage point "+a+". Must be an integer 1..5.";e=l*q-r;do q=e-r,t=e-p,q=(h*e+c/(q*q)+a/(t*t))/(h-2*c/(q*q*q)-2*a/(t*t*t)),e-=q;while(1E-14fun [solarSystemBodyState](solar-system-body-state.md)(body: [Body](../-body/index.md)): [StateVector](../-state-vector/index.md)
Get the position and velocity of a Solar System body included in the simulation. | | [swap](swap.md)
fun [swap](swap.md)()
Exchange the current time step with the previous time step. | | [time](time.md)
fun [time](time.md)(): [Time](../-time/index.md)
Returns the time of the current simulation step. | -| [update](update.md)
fun [update](update.md)(time: [Time](../-time/index.md)): [Array](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/index.html)<[StateVector](../-state-vector/index.md)>
Advances a gravity simulation by a small time step. | +| [update](update.md)
fun [update](update.md)(time: [Time](../-time/index.md)): [Array](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/index.html)<[StateVector](../-state-vector/index.md)>
Advances the gravity simulation by a small time step. | ## Properties diff --git a/source/kotlin/doc/-gravity-simulator/update.md b/source/kotlin/doc/-gravity-simulator/update.md index eedf66b4..d0feab55 100644 --- a/source/kotlin/doc/-gravity-simulator/update.md +++ b/source/kotlin/doc/-gravity-simulator/update.md @@ -4,7 +4,7 @@ fun [update](update.md)(time: [Time](../-time/index.md)): [Array](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/index.html)<[StateVector](../-state-vector/index.md)> -Advances a gravity simulation by a small time step. +Advances the gravity simulation by a small time step. Updates the simulation of the user-supplied small bodies to the time indicated by the time parameter. Retuns an updated array of state vectors for the small bodies. The positions and velocities in the returned array are referenced to the originBody that was used to construct this simulator. @@ -12,4 +12,4 @@ Updates the simulation of the user-supplied small bodies to the time indicated b | | | |---|---| -| time | A time that is a small increment away from the current simulation time. It is up to the developer to figure out an appropriate time increment. Depending on the trajectories, a smaller or larger increment may be needed for the desired accuracy. Some experimentation may be needed. Generally, bodies that stay in the outer Solar System and move slowly can use larger time steps. Bodies that pass into the inner Solar System and move faster will need a smaller time step to maintain accuracy. Some experimentation may be necessary to find a good value. The time value may be after or before the current simulation time to move forward or backward in time. | +| time | A time that is a small increment away from the current simulation time. It is up to the developer to figure out an appropriate time increment. Depending on the trajectories, a smaller or larger increment may be needed for the desired accuracy. Some experimentation may be needed. Generally, bodies that stay in the outer Solar System and move slowly can use larger time steps. Bodies that pass into the inner Solar System and move faster will need a smaller time step to maintain accuracy. The time value may be after or before the current simulation time to move forward or backward in time. | diff --git a/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt b/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt index 8c7b3c76..5f22bf76 100644 --- a/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt +++ b/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt @@ -7955,7 +7955,7 @@ class GravitySimulator { /** - * Advances a gravity simulation by a small time step. + * Advances the gravity simulation by a small time step. * * Updates the simulation of the user-supplied small bodies * to the time indicated by the `time` parameter. @@ -7971,7 +7971,6 @@ class GravitySimulator { * Generally, bodies that stay in the outer Solar System and move slowly can * use larger time steps. Bodies that pass into the inner Solar System and * move faster will need a smaller time step to maintain accuracy. - * Some experimentation may be necessary to find a good value. * The `time` value may be after or before the current simulation time * to move forward or backward in time. */ @@ -7993,7 +7992,7 @@ class GravitySimulator { // Now that the time is set, it is safe to update the Solar System. calcSolarSystem() - // Estimate the position of each small body as if their existing + // Estimate the positions of the small bodies as if their existing // accelerations apply across the whole time interval. prev.bodies.forEachIndexed { i, p -> curr.bodies[i].r = updatePosition(dt, p.r, p.v, p.a) diff --git a/source/python/README.md b/source/python/README.md index b1386f75..d551df65 100644 --- a/source/python/README.md +++ b/source/python/README.md @@ -462,6 +462,13 @@ time steps. | [`Time`](#Time) | `time` | The initial time at which to start the simulation. | | [`StateVector[]`](#StateVector[]) | `bodyStates` | An array of zero or more initial state vectors (positions and velocities) of the small bodies to be simulated. The caller must know the positions and velocities of the small bodies at an initial moment in time. Their positions and velocities are expressed with respect to `originBody`, using equatorial J2000 orientation (EQJ). Positions are expressed in astronomical units (AU). Velocities are expressed in AU/day. All the times embedded within the state vectors must exactly match `time`, or this constructor will throw an exception. | + +### GravitySimulator.OriginBody(self) + +**The origin of the reference frame. See constructor for more info.** + +### Returns: [`Body`](#Body) + ### GravitySimulator.SolarSystemBodyState(self, body) @@ -480,6 +487,9 @@ of the `originBody` parameter that was passed to this object's constructor. | --- | --- | --- | | [`Body`](#Body) | `body` | The Sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, or Neptune. | +### Returns: [`StateVector`](#StateVector) +The state vector of the requested Solar System body. + ### GravitySimulator.Swap(self) @@ -506,7 +516,30 @@ that has not yet been updated by a call to [`GravitySimulator`](#GravitySimulato ### GravitySimulator.Time(self) -The time represented by the current step of the gravity simulation. +**The time represented by the current step of the gravity simulation.** + +### Returns: [`Time`](#Time) + + +### GravitySimulator.Update(self, time) + +**Advances the gravity simulation by a small time step.** + +Updates the simulation of the user-supplied small bodies +to the time indicated by the `time` parameter. +Returns an array of state vectors for the simulated bodies. +The array is in the same order as the original array that +was used to construct this simulator object. +The positions and velocities in the returned array are +referenced to the `originBody` that was used to construct +this simulator. + +| Type | Parameter | Description | +| --- | --- | --- | +| [`Time`](#Time) | `time` | A time that is a small increment away from the current simulation time. It is up to the developer to figure out an appropriate time increment. Depending on the trajectories, a smaller or larger increment may be needed for the desired accuracy. Some experimentation may be needed. Generally, bodies that stay in the outer Solar System and move slowly can use larger time steps. Bodies that pass into the inner Solar System and move faster will need a smaller time step to maintain accuracy. The `time` value may be after or before the current simulation time to move forward or backward in time. | + +### Returns: [`StateVector[]`](#StateVector[]) +An array of state vectors, one for each small body. --- diff --git a/source/python/astronomy/astronomy.py b/source/python/astronomy/astronomy.py index 7fc0c54d..0920370e 100644 --- a/source/python/astronomy/astronomy.py +++ b/source/python/astronomy/astronomy.py @@ -9840,6 +9840,7 @@ def LagrangePointFast(point, major_state, major_mass, minor_state, minor_mass): scale = (x - r1) / R return StateVector(scale*dx, scale*dy, scale*dz, scale*vx, scale*vy, scale*vz, major_state.t) +#-------------------------------------------------------------------------------------------------- class GravitySimulator: """A simulation of zero or more small bodies moving through the Solar System. @@ -9884,7 +9885,7 @@ class GravitySimulator: All the times embedded within the state vectors must exactly match `time`, or this constructor will throw an exception. """ - self.originBody = originBody + self._originBody = originBody # Verify that the state vectors have matching times. for b in bodyStates: if b.t.tt != time.tt: @@ -9915,9 +9916,123 @@ class GravitySimulator: self.prev = self._Duplicate() def Time(self): - """The time represented by the current step of the gravity simulation.""" + """The time represented by the current step of the gravity simulation. + + Returns + ------- + Time + """ return self.curr.time + def OriginBody(self): + """The origin of the reference frame. See constructor for more info. + + Returns + ------- + Body + """ + return self._originBody + + def Update(self, time): + """Advances the gravity simulation by a small time step. + + Updates the simulation of the user-supplied small bodies + to the time indicated by the `time` parameter. + Returns an array of state vectors for the simulated bodies. + The array is in the same order as the original array that + was used to construct this simulator object. + The positions and velocities in the returned array are + referenced to the `originBody` that was used to construct + this simulator. + + Parameters + ---------- + time : Time + A time that is a small increment away from the current simulation time. + It is up to the developer to figure out an appropriate time increment. + Depending on the trajectories, a smaller or larger increment + may be needed for the desired accuracy. Some experimentation may be needed. + Generally, bodies that stay in the outer Solar System and move slowly can + use larger time steps. Bodies that pass into the inner Solar System and + move faster will need a smaller time step to maintain accuracy. + The `time` value may be after or before the current simulation time + to move forward or backward in time. + + Returns + ------- + StateVector[] + An array of state vectors, one for each small body. + """ + dt = time.tt - self.curr.time.tt + if dt == 0.0: + # Special case: the time has not changed, so skip the usual physics calculations. + # This allows another way for the caller to query the current body states. + # It is also necessary to avoid dividing by `dt` if `dt` is zero. + # To prepare for a possible swap operation, duplicate the current state into the previous state. + self.prev = self._Duplicate() + else: + # Exchange the current state with the previous state. Then calculate the new current state. + self.Swap() + + # Update the current time + self.curr.time = time + + # Calculate the positions and velocities of the Sun and planets at the given time. + self.curr.gravitators = _CalcSolarSystem(time) + + # Estimate the positions of the small bodies as if their existing + # existing accelerations apply across the whole time interval. + nbodies = len(self.curr.bodies) + for i in range(nbodies): + p = self.prev.bodies[i] + c = self.curr.bodies[i] + c.r = _UpdatePosition(dt, p.r, p.v, p.a) + + # Calculate the acceleration experienced by the small bodies at + # their respective approximate next locations. + self._CalcBodyAccelerations() + + for i in range(nbodies): + # Calculate the average of the acceleration vectors + # experienced by the previous body positions and + # their estimated next positions. + # These become estimates of the mean effective accelerations + # over the whole interval. + p = self.prev.bodies[i] + c = self.curr.bodies[i] + acc = p.a.mean(c.a) + # Refine the estimates of position and velocity at the next time step, + # using the mean acceleration as a better approximation of the + # continuously changing acceleration acting on each body. + c.tt = time.tt + c.r = _UpdatePosition(dt, p.r, p.v, acc) + c.v = _UpdateVelocity(dt, p.v, acc) + + # Re-calculate accelerations experienced by each body. + # These will be needed for the next simulation step (if any). + # Also, they will be potentially useful if some day we add + # a function to query the acceleration vectors for the bodies. + self._CalcBodyAccelerations() + + # Translate our internal calculations of body positions and velocities + # into state vectors that the caller can understand. + # We have to convert the internal type _body_grav_calc_t to the public type StateVector. + # Also convert from barycentric coordinates to coordinates based on the selected origin body. + bodyStates = [] + ostate = self._InternalBodyState(self._originBody) + for bcalc in self.curr.bodies: + bodyStates.append(StateVector( + bcalc.r.x - ostate.r.x, + bcalc.r.y - ostate.r.y, + bcalc.r.z - ostate.r.z, + bcalc.v.x - ostate.v.x, + bcalc.v.y - ostate.v.y, + bcalc.v.z - ostate.v.z, + time + )) + return bodyStates + + def Swap(self): """Exchange the current time step with the previous time step. @@ -9962,9 +10077,14 @@ class GravitySimulator: ---------- body : Body The Sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, or Neptune. + + Returns + ------- + StateVector + The state vector of the requested Solar System body. """ bstate = self._InternalBodyState(body) - ostate = self._InternalBodyState(self.originBody) + ostate = self._InternalBodyState(self._originBody) return _ExportState(bstate - ostate, self.curr.time) def _InternalBodyState(self, body): @@ -10039,3 +10159,5 @@ def _AddAcceleration(acc, smallPos, majorPos, gm): acc.x += dx * pull acc.y += dy * pull acc.z += dz * pull + +#--------------------------------------------------------------------------------------------------