physics

package
v0.7.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package physics implements the spacecraft propagation layer: state vectors, integrators (Verlet + RK4), and patched-conic SOI handling.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Accel

func Accel(r orbital.Vec3, mu float64) orbital.Vec3

Accel returns the two-body gravitational acceleration on the spacecraft due to the primary with gravitational parameter mu. Direction is toward the primary (origin in the relative frame).

func GravityOnly

func GravityOnly(mu float64) func(r, v orbital.Vec3, t float64) orbital.Vec3

GravityOnly wraps Accel as an RK4-compatible accelFn closure.

func SOIRadius

func SOIRadius(body, primary bodies.CelestialBody) float64

SOIRadius returns the sphere-of-influence radius of `body` orbiting `primary`, in meters. SOI = a_body * (m_body / m_primary)^(2/5). Returns 0 for bodies without orbital data (e.g. the system primary itself).

func SemimajorAxis

func SemimajorAxis(s StateVector, mu float64) float64

SemimajorAxis returns the orbit's semimajor axis a = -μ/(2ε) for bound orbits; NaN for parabolic (ε≈0) and negative for hyperbolic trajectories.

func SpecificEnergy

func SpecificEnergy(s StateVector, mu float64) float64

SpecificEnergy returns the two-body orbital specific energy ε = v²/2 − μ/r (J/kg). Used as an invariant by energy-conservation tests.

func SurfaceGravity

func SurfaceGravity(b bodies.CelestialBody) float64

SurfaceGravity returns the magnitude of gravitational acceleration at the body's mean radius (m/s²). Diagnostic helper for tests.

Types

type Primary

type Primary struct {
	Body     bodies.CelestialBody
	Inertial orbital.Vec3
}

Primary captures which body the spacecraft is currently bound to and its inertial position at the relevant sim-time. Physics operates relative to the primary; world code looks this up every few ticks.

func FindPrimary

func FindPrimary(
	system bodies.System,
	rInertial orbital.Vec3,
	positions map[string]orbital.Vec3,
) Primary

FindPrimary picks the best primary for a spacecraft at inertial position rInertial. Rule: smallest SOI that contains the spacecraft wins; default to the system primary if none contain it.

Each body's SOI is computed against its actual parent (v0.5.0+): planets against the system primary, moons against their planet (per CelestialBody.ParentID). Pre-v0.5.0 every body's SOI was computed against the system primary, which silently treated moons as planets — a Luna at 384k km from Earth had its SOI sized as if it orbited the Sun at 384k km, an absurd value. Fixing this is what enables the Earth-and-Luna nested-SOI walk.

type StateVector

type StateVector struct {
	R orbital.Vec3 // position relative to primary
	V orbital.Vec3 // velocity relative to primary
	M float64      // current total mass (wet)
}

StateVector is the spacecraft's kinematic state relative to the current primary body (see patched-conic model in plan §Phase 1). All SI: position in m, velocity in m/s, mass in kg.

func KeplerStep added in v0.4.3

func KeplerStep(s StateVector, mu, dt float64) (StateVector, bool)

KeplerStep advances a state vector by dt using analytic Kepler propagation. Snapshots orbital elements, advances mean anomaly by n·dt, and reconstructs (r, v) from the new true anomaly. Exact (modulo Newton iteration tolerance in SolveKepler) — no numerical drift, regardless of dt size relative to orbital period.

Returns ok=false for hyperbolic / parabolic orbits (e ≥ 1) and degenerate inputs; the caller falls back to numerical integration (Verlet). Used for the v0.4.3 "warp lock": when warp > 1× and no active burn, integrateSpacecraft takes one KeplerStep per tick instead of looping Verlet sub-steps that drift eccentricity over many orbits.

SOI handling is the caller's responsibility: KeplerStep does not detect or rebase across primary boundaries. integrateSpacecraft guards against SOI crossings by checking apo < primary's SOI before taking the analytic path.

func Rebase

func Rebase(
	s StateVector,
	oldPrimaryInertial, newPrimaryInertial orbital.Vec3,
	dvInertial orbital.Vec3,
) StateVector

Rebase converts a state vector expressed relative to oldPrimary into one expressed relative to newPrimary. Both primaries' inertial positions are required. Velocity transforms by vector subtraction only if the primaries have non-zero relative velocity; in v0.1 planets are on fixed Keplerian tracks with velocities computed on demand, so we accept a relative-velocity parameter (dvInertial = v_oldPrimary - v_newPrimary).

func StepRK4

func StepRK4(
	s StateVector,
	dt float64,
	accelFn func(r, v orbital.Vec3, t float64) orbital.Vec3,
	t float64,
) StateVector

StepRK4 advances a StateVector by dt using classical 4th-order Runge-Kutta. Not symplectic — energy drifts over long horizons — but handles non- conservative forces (thrust during a finite burn, drag) cleanly, which Verlet does not. Parked for Phase 2 burns per plan §Phase 1 rationale; until then, Verlet is the default integrator.

accelFn(r, v, t) lets callers inject an applied thrust on top of two-body gravity. For pure gravity, pass a closure that computes Accel(r, μ).

func StepVerlet

func StepVerlet(s StateVector, mu, dt float64) StateVector

StepVerlet advances a StateVector by dt using the symplectic velocity- Verlet integrator. Single force evaluation per step (cheap under warp), conserves specific orbital energy over long horizons — see plan §Phase 1 rationale. Returns the new state; input is untouched.

The algorithm (for a = a(r) only, true for pure two-body gravity):

r' = r + v·dt + ½·a·dt²
a' = Accel(r')
v' = v + ½·(a + a')·dt

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL