111 lines
3.6 KiB
Go
111 lines
3.6 KiB
Go
|
|
package basic
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"os"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
type planetRiseSetBaselineSample struct {
|
||
|
|
Body string `json:"body"`
|
||
|
|
Site string `json:"site"`
|
||
|
|
InputUTC string `json:"input_utc"`
|
||
|
|
Longitude float64 `json:"longitude"`
|
||
|
|
Latitude float64 `json:"latitude"`
|
||
|
|
RiseUTC string `json:"rise_utc"`
|
||
|
|
TransitUTC string `json:"transit_utc"`
|
||
|
|
SetUTC string `json:"set_utc"`
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPlanetRiseSetMatchesHorizonsBaseline(t *testing.T) {
|
||
|
|
data, err := os.ReadFile("testdata/planet_rise_set_baseline.json")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("read baseline: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
var samples []planetRiseSetBaselineSample
|
||
|
|
if err := json.Unmarshal(data, &samples); err != nil {
|
||
|
|
t.Fatalf("decode baseline: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
type observationCase struct {
|
||
|
|
rise func(float64, float64, float64, float64, float64, float64) (float64, error)
|
||
|
|
transit func(float64, float64, float64) float64
|
||
|
|
set func(float64, float64, float64, float64, float64, float64) (float64, error)
|
||
|
|
}
|
||
|
|
|
||
|
|
cases := map[string]observationCase{
|
||
|
|
"mercury": {rise: MercuryRiseTime, transit: MercuryCulminationTime, set: MercurySetTime},
|
||
|
|
"venus": {rise: VenusRiseTime, transit: VenusCulminationTime, set: VenusSetTime},
|
||
|
|
"mars": {rise: MarsRiseTime, transit: MarsCulminationTime, set: MarsSetTime},
|
||
|
|
"jupiter": {rise: JupiterRiseTime, transit: JupiterCulminationTime, set: JupiterSetTime},
|
||
|
|
"saturn": {rise: SaturnRiseTime, transit: SaturnCulminationTime, set: SaturnSetTime},
|
||
|
|
"uranus": {rise: UranusRiseTime, transit: UranusCulminationTime, set: UranusSetTime},
|
||
|
|
"neptune": {rise: NeptuneRiseTime, transit: NeptuneCulminationTime, set: NeptuneSetTime},
|
||
|
|
}
|
||
|
|
|
||
|
|
const tolerance = 2 * time.Minute
|
||
|
|
var maxRiseDiff time.Duration
|
||
|
|
var maxTransitDiff time.Duration
|
||
|
|
var maxSetDiff time.Duration
|
||
|
|
|
||
|
|
for _, sample := range samples {
|
||
|
|
tc, ok := cases[sample.Body]
|
||
|
|
if !ok {
|
||
|
|
t.Fatalf("unknown body %q", sample.Body)
|
||
|
|
}
|
||
|
|
|
||
|
|
inputTime, err := time.Parse(time.RFC3339, sample.InputUTC)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("parse input time %q: %v", sample.InputUTC, err)
|
||
|
|
}
|
||
|
|
jd := Date2JDE(inputTime.UTC())
|
||
|
|
|
||
|
|
riseJD, err := tc.rise(jd, sample.Longitude, sample.Latitude, 0, 1, 0)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("%s %s rise error: %v", sample.Body, sample.Site, err)
|
||
|
|
}
|
||
|
|
riseDiff := assertEventTimeClose(t, sample.Body+"."+sample.Site+".rise", riseJD, sample.RiseUTC, tolerance)
|
||
|
|
if riseDiff > maxRiseDiff {
|
||
|
|
maxRiseDiff = riseDiff
|
||
|
|
}
|
||
|
|
|
||
|
|
transitJD := tc.transit(jd, sample.Longitude, 0)
|
||
|
|
transitDiff := assertEventTimeClose(t, sample.Body+"."+sample.Site+".transit", transitJD, sample.TransitUTC, tolerance)
|
||
|
|
if transitDiff > maxTransitDiff {
|
||
|
|
maxTransitDiff = transitDiff
|
||
|
|
}
|
||
|
|
|
||
|
|
setJD, err := tc.set(jd, sample.Longitude, sample.Latitude, 0, 1, 0)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("%s %s set error: %v", sample.Body, sample.Site, err)
|
||
|
|
}
|
||
|
|
setDiff := assertEventTimeClose(t, sample.Body+"."+sample.Site+".set", setJD, sample.SetUTC, tolerance)
|
||
|
|
if setDiff > maxSetDiff {
|
||
|
|
maxSetDiff = setDiff
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
t.Logf("planet rise/set max diff: rise=%v transit=%v set=%v", maxRiseDiff, maxTransitDiff, maxSetDiff)
|
||
|
|
}
|
||
|
|
|
||
|
|
func assertEventTimeClose(t *testing.T, name string, gotJD float64, wantUTC string, tolerance time.Duration) time.Duration {
|
||
|
|
t.Helper()
|
||
|
|
|
||
|
|
wantTime, err := time.Parse(time.RFC3339, wantUTC)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("parse %s baseline time %q: %v", name, wantUTC, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
gotTime := JDE2DateByZone(gotJD, time.UTC, false)
|
||
|
|
diff := gotTime.Sub(wantTime)
|
||
|
|
if diff < 0 {
|
||
|
|
diff = -diff
|
||
|
|
}
|
||
|
|
if diff > tolerance {
|
||
|
|
t.Fatalf("%s mismatch: got %s want %s tolerance %v", name, gotTime.Format(time.RFC3339), wantUTC, tolerance)
|
||
|
|
}
|
||
|
|
return diff
|
||
|
|
}
|