from typing import Literal
import astropy.units as u # type: ignore[import-untyped]
import numpy as np
import numpy.typing as npt
from astropy.coordinates import SkyCoord # type: ignore[import-untyped]
from astropy.time import Time # type: ignore[import-untyped]
from pydantic import Field
from ...core.enums import ConstraintType
from ...ephemeris import Ephemeris
from ..catalogs import get_bright_stars
from .base import ConstraintABC
[docs]
class BrightStarConstraint(ConstraintABC):
"""
Constraint that avoids observing too close to bright stars.
Bright stars can cause detector saturation, blooming, or scattered light
issues. This constraint ensures observations are conducted at sufficient
angular distance from bright stars.
Parameters
----------
min_separation : float
Minimum angular separation (degrees) required from bright stars.
Observations closer than this to bright stars will be constrained.
magnitude_limit : float
Magnitude limit for bright stars to avoid. Stars brighter than this
magnitude will be considered for avoidance. Default is 6.0 (naked eye visible).
Methods
-------
__call__(time, ephemeris, coordinate)
Checks if the coordinate is too close to any bright star.
"""
[docs]
name: Literal[ConstraintType.BRIGHT_STAR] = ConstraintType.BRIGHT_STAR
[docs]
short_name: Literal["Bright Star"] = "Bright Star"
[docs]
min_separation: float = Field(
default=5.0, gt=0, description="Minimum angular separation (degrees) from bright stars"
)
[docs]
magnitude_limit: float = Field(
default=6.0, description="Magnitude limit for stars to avoid (brighter than this)"
)
[docs]
def __call__(self, time: Time, ephemeris: Ephemeris, coordinate: SkyCoord) -> npt.NDArray[np.bool_]:
"""
Check if the coordinate is too close to any bright star.
Parameters
----------
time : Time
The time (not used for star positions).
ephemeris : Ephemeris
The ephemeris (not used for star positions).
coordinate : SkyCoord
The coordinate to check.
Returns
-------
npt.NDArray[np.bool_]
Boolean array where True indicates the coordinate violates the constraint
(is too close to a bright star).
"""
# Get bright stars from catalog filtered by magnitude limit
bright_stars = get_bright_stars(magnitude_limit=self.magnitude_limit)
# Check separation from each bright star
min_separation_rad = self.min_separation * u.deg
in_constraint = np.zeros(len(time), dtype=bool)
for star, _ in bright_stars:
separation = coordinate.separation(star)
# Note: magnitude is already filtered by get_bright_stars()
in_constraint |= separation < min_separation_rad
return in_constraint