-- pg_orrery 0.16.0 -> 0.17.0: solar elongation, planet phase, satellite eclipse, -- observing night quality, lunar libration -- ============================================================ -- Solar elongation (1) -- ============================================================ CREATE FUNCTION solar_elongation(int4, timestamptz) RETURNS float8 AS 'MODULE_PATHNAME', 'solar_elongation' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION solar_elongation(int4, timestamptz) IS 'Sun-Earth-Planet angle in degrees [0, 180]. How far a planet appears from the Sun. Body IDs 1-8.'; -- ============================================================ -- Planet phase fraction (1) -- ============================================================ CREATE FUNCTION planet_phase(int4, timestamptz) RETURNS float8 AS 'MODULE_PATHNAME', 'planet_phase' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION planet_phase(int4, timestamptz) IS 'Illuminated fraction of a planet disk as seen from Earth [0.0, 1.0]. Body IDs 1-8.'; -- ============================================================ -- Satellite eclipse prediction (4) -- ============================================================ CREATE FUNCTION satellite_is_eclipsed(tle, timestamptz) RETURNS bool AS 'MODULE_PATHNAME', 'satellite_is_eclipsed' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION satellite_is_eclipsed(tle, timestamptz) IS 'True if the satellite is in Earth cylindrical shadow at the given time.'; CREATE FUNCTION satellite_next_eclipse_entry(tle, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'satellite_next_eclipse_entry' LANGUAGE C STABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION satellite_next_eclipse_entry(tle, timestamptz) IS 'Next time the satellite enters Earth shadow (up to 7-day search). NULL if none found.'; CREATE FUNCTION satellite_next_eclipse_exit(tle, timestamptz) RETURNS timestamptz AS 'MODULE_PATHNAME', 'satellite_next_eclipse_exit' LANGUAGE C STABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION satellite_next_eclipse_exit(tle, timestamptz) IS 'Next time the satellite exits Earth shadow (up to 7-day search). NULL if none found.'; CREATE FUNCTION satellite_eclipse_fraction(tle, timestamptz, timestamptz) RETURNS float8 AS 'MODULE_PATHNAME', 'satellite_eclipse_fraction' LANGUAGE C STABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION satellite_eclipse_fraction(tle, timestamptz, timestamptz) IS 'Fraction of the given time window the satellite spends in eclipse [0.0, 1.0].'; -- ============================================================ -- Observing night quality (1) -- ============================================================ CREATE FUNCTION observing_night_quality(observer, timestamptz DEFAULT NOW()) RETURNS text AS $$ DECLARE astro_dusk timestamptz; astro_dawn timestamptz; dark_hours float8; illum float8; moon_up bool; score int := 100; BEGIN -- Astronomical darkness window astro_dusk := sun_astronomical_dusk($1, $2); IF astro_dusk IS NULL THEN RETURN 'poor'; -- No astronomical darkness (polar summer) END IF; astro_dawn := sun_astronomical_dawn($1, astro_dusk); IF astro_dawn IS NULL THEN RETURN 'poor'; END IF; dark_hours := extract(epoch FROM astro_dawn - astro_dusk) / 3600.0; -- Short dark window penalty IF dark_hours < 2.0 THEN score := score - 40; ELSIF dark_hours < 4.0 THEN score := score - 20; ELSIF dark_hours < 6.0 THEN score := score - 10; END IF; -- Moon illumination penalty illum := moon_illumination(astro_dusk); IF illum > 0.75 THEN -- Check if Moon is above horizon during darkness moon_up := topo_elevation(moon_observe($1, astro_dusk)) > 0 OR topo_elevation(moon_observe($1, astro_dusk + (astro_dawn - astro_dusk) / 2)) > 0; IF moon_up THEN score := score - (illum * 30)::int; -- Up to -30 for full moon END IF; END IF; -- Classify IF score >= 80 THEN RETURN 'excellent'; ELSIF score >= 60 THEN RETURN 'good'; ELSIF score >= 40 THEN RETURN 'fair'; ELSE RETURN 'poor'; END IF; END; $$ LANGUAGE plpgsql STABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION observing_night_quality(observer, timestamptz) IS 'Composite observing quality assessment: excellent/good/fair/poor based on darkness duration and Moon interference.'; -- ============================================================ -- Lunar libration (5) -- ============================================================ CREATE FUNCTION moon_libration_longitude(timestamptz) RETURNS float8 AS 'MODULE_PATHNAME', 'moon_libration_longitude' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION moon_libration_longitude(timestamptz) IS 'Optical libration in longitude (degrees, typically [-8, +8]). Meeus Ch. 53.'; CREATE FUNCTION moon_libration_latitude(timestamptz) RETURNS float8 AS 'MODULE_PATHNAME', 'moon_libration_latitude' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION moon_libration_latitude(timestamptz) IS 'Optical libration in latitude (degrees, typically [-7, +7]). Meeus Ch. 53.'; CREATE FUNCTION moon_libration_position_angle(timestamptz) RETURNS float8 AS 'MODULE_PATHNAME', 'moon_libration_position_angle' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION moon_libration_position_angle(timestamptz) IS 'Position angle of the Moon axis (degrees, [0, 360)). Meeus Ch. 53.'; CREATE FUNCTION moon_libration(timestamptz, OUT l float8, OUT b float8, OUT p float8) RETURNS record AS 'MODULE_PATHNAME', 'moon_libration' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION moon_libration(timestamptz) IS 'All three libration values: longitude (l), latitude (b), position angle (p) in degrees.'; CREATE FUNCTION moon_subsolar_longitude(timestamptz) RETURNS float8 AS 'MODULE_PATHNAME', 'moon_subsolar_longitude' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION moon_subsolar_longitude(timestamptz) IS 'Selenographic longitude of the sub-solar point (degrees, [0, 360)). Determines the lunar terminator position.';