163 lines
4.9 KiB
Go
163 lines
4.9 KiB
Go
|
|
package occultationgeo
|
||
|
|
|
||
|
|
import (
|
||
|
|
"math"
|
||
|
|
"sync"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"b612.me/astro/basic"
|
||
|
|
"b612.me/astro/internal/geodata"
|
||
|
|
)
|
||
|
|
|
||
|
|
var (
|
||
|
|
saturn20250105Once sync.Once
|
||
|
|
saturn20250105Paths []basic.PlanetOccultationPath
|
||
|
|
)
|
||
|
|
|
||
|
|
func saturn20250105Path(tb testing.TB) basic.PlanetOccultationPath {
|
||
|
|
tb.Helper()
|
||
|
|
saturn20250105Once.Do(func() {
|
||
|
|
zone := time.FixedZone("UTC+8", 8*60*60)
|
||
|
|
start := time.Date(2025, time.January, 5, 0, 0, 0, 0, zone)
|
||
|
|
paths, err := basic.FindPlanetOccultationPaths(
|
||
|
|
start, start.Add(24*time.Hour), basic.OccultationSaturn,
|
||
|
|
basic.OccultationPathOptions{
|
||
|
|
Step: 20 * time.Minute, TargetSpacingKM: 900,
|
||
|
|
DisableFootprints: true, IncludeFootprintTimeline: true,
|
||
|
|
FootprintTimelineStep: 5 * time.Minute, RiseSetStep: time.Minute,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
if err != nil || len(paths) != 1 {
|
||
|
|
tb.Fatalf("FindPlanetOccultationPaths() paths=%d err=%v", len(paths), err)
|
||
|
|
}
|
||
|
|
saturn20250105Paths = paths
|
||
|
|
})
|
||
|
|
return saturn20250105Paths[0]
|
||
|
|
}
|
||
|
|
|
||
|
|
func BenchmarkVisibleBandPolygonsSaturn20250105(b *testing.B) {
|
||
|
|
path := saturn20250105Path(b)
|
||
|
|
b.ResetTimer()
|
||
|
|
for iteration := 0; iteration < b.N; iteration++ {
|
||
|
|
if _, _, err := VisibleBandPolygonsFromContours(
|
||
|
|
path.PartialBandFootprints, path.PartialBandContours,
|
||
|
|
path.NorthernLimit, path.SouthernLimit, path.RiseSetCurves,
|
||
|
|
); err != nil {
|
||
|
|
b.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func BenchmarkVisibleBandPolygonsAnalyticSaturn20250105(b *testing.B) {
|
||
|
|
path := saturn20250105Path(b)
|
||
|
|
b.ResetTimer()
|
||
|
|
for iteration := 0; iteration < b.N; iteration++ {
|
||
|
|
if _, _, err := VisibleBandPolygonsFromAnalyticContours(
|
||
|
|
path.PartialBandFootprints, path.PartialBandContours, path.PartialVisibilityContours,
|
||
|
|
path.NorthernLimit, path.SouthernLimit, path.RiseSetCurves,
|
||
|
|
); err != nil {
|
||
|
|
b.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func BenchmarkFootprintSweepPolygonsSaturn20250105(b *testing.B) {
|
||
|
|
path := saturn20250105Path(b)
|
||
|
|
b.ResetTimer()
|
||
|
|
for iteration := 0; iteration < b.N; iteration++ {
|
||
|
|
if _, err := footprintSweepPolygons(
|
||
|
|
path.PartialBandFootprints, path.NorthernLimit, path.SouthernLimit,
|
||
|
|
); err != nil {
|
||
|
|
b.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func BenchmarkFootprintOpenSweepSaturn20250105(b *testing.B) {
|
||
|
|
path := saturn20250105Path(b)
|
||
|
|
b.ResetTimer()
|
||
|
|
for iteration := 0; iteration < b.N; iteration++ {
|
||
|
|
if _, err := footprintOpenSweepPolygons(path.PartialBandFootprints); err != nil {
|
||
|
|
b.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func BenchmarkFootprintVisibleUnionSaturn20250105(b *testing.B) {
|
||
|
|
path := saturn20250105Path(b)
|
||
|
|
b.ResetTimer()
|
||
|
|
for iteration := 0; iteration < b.N; iteration++ {
|
||
|
|
if polygons := footprintVisibleUnionPolygons(path.PartialBandFootprints); len(polygons) == 0 {
|
||
|
|
b.Fatal("empty visible union")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func occultationBenchChainPolygons(count, points int) [][]geodata.GeoPoint {
|
||
|
|
polygons := make([][]geodata.GeoPoint, 0, count)
|
||
|
|
for index := 0; index < count; index++ {
|
||
|
|
center := geodata.GeoPoint{
|
||
|
|
Longitude: -0.5 + float64(index)*1.5,
|
||
|
|
Latitude: 40,
|
||
|
|
}
|
||
|
|
ring := make([]geodata.GeoPoint, 0, points+1)
|
||
|
|
for step := 0; step <= points; step++ {
|
||
|
|
angle := 2 * math.Pi * float64(step) / float64(points)
|
||
|
|
ring = append(ring, geodata.GeoPoint{
|
||
|
|
Longitude: center.Longitude + 0.5*math.Cos(angle),
|
||
|
|
Latitude: center.Latitude + 0.5*math.Sin(angle),
|
||
|
|
})
|
||
|
|
}
|
||
|
|
polygons = append(polygons, ring)
|
||
|
|
}
|
||
|
|
return polygons
|
||
|
|
}
|
||
|
|
|
||
|
|
func BenchmarkMergeTouchingVisiblePolygonsChain(b *testing.B) {
|
||
|
|
b.Run("count=12/points=16", func(b *testing.B) {
|
||
|
|
for iteration := 0; iteration < b.N; iteration++ {
|
||
|
|
polygons := occultationBenchChainPolygons(12, 16)
|
||
|
|
if merged := mergeTouchingVisiblePolygons(polygons); len(merged) != 1 {
|
||
|
|
b.Fatalf("merged=%d, want one face", len(merged))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
})
|
||
|
|
b.Run("count=24/points=16", func(b *testing.B) {
|
||
|
|
for iteration := 0; iteration < b.N; iteration++ {
|
||
|
|
polygons := occultationBenchChainPolygons(24, 16)
|
||
|
|
if merged := mergeTouchingVisiblePolygons(polygons); len(merged) != 1 {
|
||
|
|
b.Fatalf("merged=%d, want one face", len(merged))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func occultationBenchConstrainInput(points int) (parent, child [][]geodata.GeoPoint) {
|
||
|
|
ring := make([]geodata.GeoPoint, 0, points+1)
|
||
|
|
childRing := make([]geodata.GeoPoint, 0, points+1)
|
||
|
|
for step := 0; step <= points; step++ {
|
||
|
|
angle := 2 * math.Pi * float64(step) / float64(points)
|
||
|
|
longitude := -70 + 20*math.Cos(angle)
|
||
|
|
latitude := -40 + 8*math.Sin(angle)
|
||
|
|
ring = append(ring, geodata.GeoPoint{Longitude: longitude, Latitude: latitude})
|
||
|
|
childRing = append(childRing, geodata.GeoPoint{
|
||
|
|
Longitude: longitude + 0.02*math.Cos(angle),
|
||
|
|
Latitude: latitude + 0.02*math.Sin(angle),
|
||
|
|
})
|
||
|
|
}
|
||
|
|
return [][]geodata.GeoPoint{ring}, [][]geodata.GeoPoint{childRing}
|
||
|
|
}
|
||
|
|
|
||
|
|
func BenchmarkConstrainPolygonsWithinSmallBreach(b *testing.B) {
|
||
|
|
b.Run("points=512", func(b *testing.B) {
|
||
|
|
parent, child := occultationBenchConstrainInput(512)
|
||
|
|
b.ResetTimer()
|
||
|
|
for iteration := 0; iteration < b.N; iteration++ {
|
||
|
|
if repaired := ConstrainPolygonsWithin(parent, child); len(repaired) == 0 {
|
||
|
|
b.Fatal("empty repair")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|