Skip to content

Performance: siderust-cpp sun::below_threshold bypasses optimized Sun-specific night/day path #1

Description

@VPRamon

Summary

Siderust-cpp exposes siderust::sun::below_threshold(...), but this wrapper currently goes through the generic FFI entry point siderust_below_threshold(...).

For Sun, this appears to bypass the optimized Rust-side solar period implementation and instead uses the generic altitude threshold search. In practice, computing Sun night periods for a 6-month interval takes around 12 seconds, which is unexpectedly slow for this use case.

Observed behavior

In a C++ consumer, this code is very slow for a 6-month period:

const auto nights = siderust::sun::below_threshold(
    geo,
    window,
    qtty::Degree(horizon)
);

Measured runtime: approximately 12 seconds for 6 months.

The caller then converts the returned periods:

for (const auto& night : nights) {
    const auto beginUtc = FromTtMjd(night.start());
    const auto endUtc   = FromTtMjd(night.end());

    const time::Period nightPeriod(beginUtc, endUtc);

    if (nightPeriod.Intersects(period)) {
        allNights.Add(nightPeriod.Intersection(period));
    }
}

Expected behavior

For solar night/day period queries, siderust-cpp should use the Sun-specific optimized path already available in Rust.

A 6-month Sun night-period query should not require tens of thousands of generic altitude evaluations when the solar module already has a coarser and safe Sun-specific scan strategy.

Current workaround

This is significantly faster because it reaches the body-specific altitude-period path:

const auto nights = siderust::sun::altitude_periods(
    geo,
    window,
    qtty::Degree(-90.0),
    qtty::Degree(horizon)
);

This workaround is not obvious to users because semantically sun::below_threshold(...) is the natural API for “night periods”.

Suspected root cause

The C++ wrapper:

siderust::sun::below_threshold(...)

calls the generic FFI function:

siderust_below_threshold(...)

which dispatches to the generic Rust function:

siderust::below_threshold(...)

That generic path computes:

let above = above_threshold_with_policy(...);
complement_within(window, &above)

and uses the generic altitude scan options.

For long periods, this means a default scan step around 10 minutes. For 6 months plus margins, that implies roughly:

184 days * 24 hours/day * 6 samples/hour ≈ 26,500 altitude evaluations

Each altitude evaluation for the Sun may involve VSOP87 / apparent-coordinate work, so the total runtime becomes large.

However, the Rust solar implementation already contains a Sun-specific path using a 2-hour scan step for solar altitude period detection. That is much more appropriate for sunrise/sunset/night intervals.

Proposed fix

Option A — Fix siderust-cpp wrapper only

Special-case the C++ Sun wrapper so that:

siderust::sun::below_threshold(obs, window, threshold)

internally calls:

siderust::sun::altitude_periods(
    obs,
    window,
    qtty::Degree(-90.0),
    threshold
);

This would preserve the public C++ API while routing Sun night queries through the optimized body-specific path.

Likewise:

siderust::sun::above_threshold(obs, window, threshold)

could call:

siderust::sun::altitude_periods(
    obs,
    window,
    threshold,
    qtty::Degree(90.0)
);

if that also triggers the optimized Rust solar fast path.

Option B — Fix the Rust FFI dispatch

Modify the Rust FFI/generic dispatch so that body-specific above_threshold / below_threshold calls use the AltitudePeriodsProvider trait method when available, instead of always going through the generic scan implementation.

For Sun, below_threshold should reach the equivalent of:

solar::find_night_periods(...)

and above_threshold should reach:

solar::find_day_periods(...)

This is probably the cleaner long-term fix because it benefits all language bindings, not only C++.

Acceptance criteria

  • siderust::sun::below_threshold(...) and siderust::sun::altitude_periods(..., -90°, threshold) return equivalent periods for representative locations and date ranges.

  • A 6-month Sun night-period query no longer takes around 12 seconds.

  • Add a regression benchmark or performance smoke test for:

    • 1 month
    • 6 months
    • 1 year
  • The benchmark should compare:

    • sun::below_threshold(...)
    • sun::altitude_periods(..., -90°, threshold)
  • The two APIs should have the same order of magnitude runtime.

  • Existing public C++ API remains source-compatible.

Suggested test case

Location: any fixed geodetic site, for example Greenwich or Roque de los Muchachos.

Period: 6 months.

Thresholds:

0°      ordinary night/day horizon
-6°     civil twilight
-12°    nautical twilight
-18°    astronomical twilight

Check that:

auto below = siderust::sun::below_threshold(
    geo,
    window,
    qtty::Degree(horizon)
);

auto range = siderust::sun::altitude_periods(
    geo,
    window,
    qtty::Degree(-90.0),
    qtty::Degree(horizon)
);

produce equivalent intervals within expected numerical tolerance.

Notes

This does not appear to be a debug/release build issue. The package build uses release-mode Rust FFI artifacts. The issue appears to be API dispatch: the intuitive C++ API path bypasses the optimized solar period implementation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions