Source code for planetary_coverage.trajectory.mask_traj

"""Masked trajectory module."""
# pylint: disable=too-many-public-methods

from functools import wraps

import numpy as np

from .fovs import MaskedFovsCollection, SegmentedFovsCollection
from ..misc import Segment, cached_property


def trajectory_property(func):
    """Parent trajectory property decorator."""
    @property
    @wraps(func)
    def original_property(_self):
        traj = _self.traj
        prop = func.__name__

        if not hasattr(traj, prop):
            raise AttributeError(
                f'The original trajectory does not have a `{prop}` attribute.')

        return getattr(traj, prop)
    return original_property


def masked_trajectory_property(func):
    """Masked parent trajectory property decorator."""
    @property
    @wraps(func)
    def masked_property(_self):
        traj = _self.traj
        prop = func.__name__

        if not hasattr(traj, prop):
            raise AttributeError(
                f'The original trajectory does not have a `{prop}` attribute.')

        dtype, nan = (float, np.nan) if prop not in ['utc'] else \
            (np.datetime64, np.datetime64('NaT'))

        values = np.array(getattr(traj, prop), dtype=dtype)
        values[..., _self.mask] = nan

        return values

    return masked_property


def masked_trajectory_method(func):
    """Masked parent trajectory method decorator."""
    @wraps(func)
    def masked_method(_self, *args, **kwargs):
        traj = _self.traj
        method = func.__name__

        if not hasattr(traj, method):
            raise AttributeError(
                f'The original trajectory does not have a `{method}` method.')

        dtype, nan = (float, np.nan) if method not in ['utc_at'] else \
            (np.datetime64, np.datetime64('NaT'))

        values = np.array(getattr(traj, method)(*args, **kwargs), dtype=dtype)
        values[..., _self.mask] = nan

        return values

    return masked_method


def segment_trajectory_property(func):
    """Segment parent trajectory property decorator."""
    @property
    @wraps(func)
    def segment_property(_self):
        traj = _self.traj
        prop = func.__name__

        if not hasattr(traj, prop):
            raise AttributeError(
                f'The original trajectory does not have a `{prop}` attribute.')

        return np.array(getattr(traj, prop))[..., _self.seg]

    return segment_property


def segment_trajectory_method(func):
    """Segment parent trajectory method decorator."""
    @wraps(func)
    def segment_method(_self, *args, **kwargs):
        traj = _self.traj
        method = func.__name__

        if not hasattr(traj, method):
            raise AttributeError(
                f'The original trajectory does not have a `{method}` attribute.')

        return np.array(getattr(traj, method)(*args, **kwargs))[..., _self.seg]

    return segment_method


[docs]class MaskedTrajectory: """Generic masked trajectory object."""
[docs]class MaskedSpacecraftTrajectory(MaskedTrajectory): """Masked spacecraft trajectory object. Parameters ---------- traj: Original trajectory. mask: numpy.ndarray Bool list of the points to mask. """ def __init__(self, traj, mask): self.traj = traj self.mask = mask self.seg = Segment(np.invert(mask)) def __repr__(self): return ( f'<{self.__class__.__name__}> ' f'Observer: {self.observer} | ' f'Target: {self.target}' f'\n - First UTC start time: {self.start}' f'\n - Last UTC stop time: {self.stop}' f'\n - Nb of pts: {len(self):,d} (+{self.nb_masked:,d} masked)' f'\n - Nb of segments: {self.nb_segments}' ) def __len__(self): """Number of point in the trajectory.""" return len(self.traj) - self.nb_masked def __and__(self, other): """And ``&`` operator.""" return self.traj.mask( self.traj.intersect(other) | self.mask ) def __xor__(self, other): """Hat ``^`` operator.""" return self.traj.mask( self.traj.intersect(other, outside=True) | self.mask ) def __getitem__(self, _): raise ReferenceError( 'Change of target or observer should be performed ' 'on the original trajectory not on the masked trajectory.' ) def __iter__(self): for seg in self.seg: yield SegmentedSpacecraftTrajectory(self.traj, seg) @property def nb_masked(self): """Number of point masked.""" return np.sum(self.mask) @property def nb_segments(self): """Number of segment(s).""" return len(self.seg) @property def starts(self): """UTC start time segments.""" return self.utc[self.seg.istarts] @property def stops(self): """UTC stop time segments.""" return self.utc[self.seg.istops] @property def start(self): """UTC start time of the initial segment.""" return self.starts[0] if len(self) != 0 else np.datetime64('NaT') @property def stop(self): """UTC stop time of the last segment.""" return self.stops[-1] if len(self) != 0 else np.datetime64('NaT') @property def windows(self): """Segmented windows (UTC start and stop times).""" return np.vstack([self.starts, self.stops]).T @trajectory_property def observer(self): """Observer SPICE reference for the trajectory.""" @trajectory_property def target(self): """Target SPICE reference for the trajectory.""" @masked_trajectory_property def ets(self): """Masked ephemeris times.""" @masked_trajectory_property def utc(self): """Masked UTC times.""" @masked_trajectory_property def lon_e(self): """Masked sub-observer ground track east longitudes (degree).""" @masked_trajectory_property def lat(self): """Masked sub-observer ground track east latitudes (degree).""" @masked_trajectory_property def lonlat(self): """Masked sub-observer ground track east longitudes and latitudes (degree).""" @masked_trajectory_property def local_time(self): """Masked sub-observer local time (decimal hours).""" @masked_trajectory_property def inc(self): """Masked sub-observer incidence angle (degree).""" @masked_trajectory_property def emi(self): """Masked sub-observer emission angle (degree).""" @masked_trajectory_property def phase(self): """Masked sub-observer phase angle (degree).""" @masked_trajectory_property def day(self): """Masked day side.""" @masked_trajectory_property def night(self): """Masked night side.""" @masked_trajectory_property def dist(self): """Masked spacecraft distance to target body center (km).""" @masked_trajectory_property def alt(self): """Masked spacecraft altitude to the sub-observer point (km).""" @masked_trajectory_property def target_size(self): """Masked target angular size (degrees).""" @masked_trajectory_property def slant(self): """Masked spacecraft line-of-sight distance to the sub-observer point (km).""" @masked_trajectory_property def quaternions(self): """Masked observer quaternions (degree).""" @masked_trajectory_property def ra(self): """Masked boresight right ascension pointing (degree).""" @masked_trajectory_property def dec(self): """Masked boresight declination pointing (degree).""" @masked_trajectory_property def radec(self): """Masked boresight RA/DEC pointing (degree).""" @masked_trajectory_property def sun_lonlat(self): """Masked sub-solar ground track coordinates (degree).""" @masked_trajectory_property def solar_zenith_angle(self): """Masked sub-observer solar zenith angle (degree).""" @masked_trajectory_property def solar_longitude(self): """Masked target seasonal solar longitude (degree).""" @masked_trajectory_property def true_anomaly(self): """Masked target orbital true anomaly (degree).""" @masked_trajectory_property def groundtrack_velocity(self): """Masked groundtrack velocity (km/s)."""
[docs] @masked_trajectory_method def distance_to(self, *args, **kwargs): """Masked distance to a target body (km)."""
[docs] @masked_trajectory_method def ets_at(self, *args, **kwargs): """Masked ephemeris time at target location with light-time corrections."""
[docs] @masked_trajectory_method def utc_at(self, *args, **kwargs): """Masked UTC time at target location with light-time corrections."""
[docs] @masked_trajectory_method def angular_size(self, *args, **kwargs): """Masked Angle size of a given target seen from the spacecraft (degrees)."""
[docs] @masked_trajectory_method def angle_between(self, *args, **kwargs): """Masked angle between 2 rays in spacecraft frame (degrees)."""
[docs] @masked_trajectory_method def station_azel(self, *args, **kwargs): """Masked spacecraft azimuth and elevation seen from a tracking station."""
[docs] @masked_trajectory_method def target_separation(self, *args, **kwargs): """Masked angular target separation (degrees)."""
[docs]class MaskedInstrumentTrajectory(MaskedSpacecraftTrajectory): """Masked instrument trajectory.""" def __iter__(self): for seg in self.seg: yield SegmentedInstrumentTrajectory(self.traj, seg) @masked_trajectory_property def lon_e(self): """Masked instrument surface intersect east longitudes (degree).""" @masked_trajectory_property def lat(self): """Masked instrument surface intersect east latitudes (degree).""" @masked_trajectory_property def lonlat(self): """Masked instrument surface intersect east longitudes and latitudes (degree).""" @masked_trajectory_property def local_time(self): """Masked instrument surface intersect local time (decimal hours).""" @masked_trajectory_property def inc(self): """Masked instrument surface intersect incidence angle (degree).""" @masked_trajectory_property def emi(self): """Masked instrument surface intersect emission angle (degree).""" @masked_trajectory_property def phase(self): """Masked instrument surface intersect phase angle (degree).""" @masked_trajectory_property def slant(self): """Masked line-of-sight distance to the boresight surface intersection (km).""" @masked_trajectory_property def solar_zenith_angle(self): """Masked instrument surface intersect solar zenith angle (degree).""" @masked_trajectory_property def pixel_scale(self): """Masked instrument pixel scale (km/pix).""" @cached_property def fovs(self): """Masked instrument field of view paths collection.""" return MaskedFovsCollection(self.traj.fovs, self.mask)
[docs]class SegmentedTrajectory: """Generic segmented trajectory object."""
[docs]class SegmentedSpacecraftTrajectory(SegmentedTrajectory): """Segmented spacecraft trajectory object. Parameters ---------- traj: Original trajectory. segment: slice Segment to extract. """ def __init__(self, traj, segment): self.traj = traj self.seg = segment self.mask = np.full(len(self.traj), True) self.mask[self.seg] = False def __repr__(self): return ( f'<{self.__class__.__name__}> ' f'Observer: {self.observer} | ' f'Target: {self.target}' f'\n - First UTC start time: {self.start}' f'\n - Last UTC stop time: {self.stop}' f'\n - Nb of pts: {len(self):,d}' ) def __len__(self): """Number of point in the trajectory.""" return len(self.ets) def __and__(self, other): """And ``&`` operator.""" return self.traj.mask( self.traj.intersect(other) | self.mask ) def __xor__(self, other): """Hat ``^`` operator.""" return self.traj.mask( self.traj.intersect(other, outside=True) | self.mask ) def __getitem__(self, _): raise ReferenceError( 'Change of target or observer should be performed ' 'on the original trajectory not on the segmented trajectory.' ) def __iter__(self): yield self def __hash__(self): """Kernels hash.""" return hash(self.traj) @trajectory_property def kernels(self): """Trajectory required kernels.""" @trajectory_property def observer(self): """Observer SPICE reference for the trajectory.""" @trajectory_property def target(self): """Target SPICE reference for the trajectory.""" @trajectory_property def abcorr(self): """Trajectory aberration correction.""" @segment_trajectory_property def ets(self): """Segment Ephemeris Times.""" @segment_trajectory_property def utc(self): """Segment UTC times.""" @property def start(self): """Segment UTC start time.""" return self.utc[0] @property def stop(self): """Segment UTC stop time.""" return self.utc[-1] @segment_trajectory_property def lon_e(self): """Segment sub-observer ground track east longitudes (degree).""" @segment_trajectory_property def lat(self): """Segment sub-observer ground track east latitudes (degree).""" @segment_trajectory_property def lonlat(self): """Segment sub-observer ground track coordinates (degree).""" @segment_trajectory_property def local_time(self): """Segment sub-observer local time (decimal hours).""" @segment_trajectory_property def inc(self): """Segment sub-observer incidence angle (degree).""" @segment_trajectory_property def emi(self): """Segment sub-observer emission angle (degree).""" @segment_trajectory_property def phase(self): """Segment sub-observer phase angle (degree).""" @segment_trajectory_property def day(self): """Segment day side.""" @segment_trajectory_property def night(self): """Segment night side.""" @segment_trajectory_property def dist(self): """Segment spacecraft distance to target body center (km).""" @segment_trajectory_property def alt(self): """Segment spacecraft altitude to the sub-observer point (km).""" @segment_trajectory_property def target_size(self): """Segment target angular size (degrees).""" @segment_trajectory_property def slant(self): """Segment spacecraft line-of-sight distance to the sub-observer point (km).""" @segment_trajectory_property def quaternions(self): """Segment observer quaternions (degree).""" @segment_trajectory_property def ra(self): """Segment boresight right ascension pointing (degree).""" @segment_trajectory_property def dec(self): """Segment boresight declination pointing (degree).""" @segment_trajectory_property def radec(self): """Segment boresight RA/DEC pointing (degree).""" @segment_trajectory_property def sun_lonlat(self): """Segment sub-solar ground track coordinates (degree).""" @segment_trajectory_property def solar_zenith_angle(self): """Segment sub-observer solar zenith angle (degree).""" @segment_trajectory_property def solar_longitude(self): """Segment target seasonal solar longitude (degree).""" @segment_trajectory_property def true_anomaly(self): """Segment target orbital true anomaly (degree).""" @segment_trajectory_property def groundtrack_velocity(self): """Segment groundtrack velocity (km/s)."""
[docs] @segment_trajectory_method def distance_to(self, *args, **kwargs): """Segment distance to a target body (km)."""
[docs] @segment_trajectory_method def ets_at(self, *args, **kwargs): """Segment ephemeris time at target location with light-time corrections."""
[docs] @segment_trajectory_method def utc_at(self, *args, **kwargs): """Segment UTC time at target location with light-time corrections."""
[docs] @segment_trajectory_method def angular_size(self, *args, **kwargs): """Segment Angle size of a given target seen from the spacecraft (degrees)."""
[docs] @segment_trajectory_method def angle_between(self, *args, **kwargs): """Segment angle between 2 rays in spacecraft frame (degrees)."""
[docs] @segment_trajectory_method def station_azel(self, *args, **kwargs): """Segment spacecraft azimuth and elevation seen from a tracking station."""
[docs] @segment_trajectory_method def target_separation(self): """Segment angular target separation (degrees)."""
[docs]class SegmentedInstrumentTrajectory(SegmentedSpacecraftTrajectory): """Segmented instrument trajectory.""" @segment_trajectory_property def lon_e(self): """Segment instrument surface intersect east longitudes (degree).""" @segment_trajectory_property def lat(self): """Segment instrument surface intersect east latitudes (degree).""" @segment_trajectory_property def lonlat(self): """Segment instrument surface intersect east longitudes and latitudes (degree).""" @segment_trajectory_property def local_time(self): """Segment instrument surface intersect local time (decimal hours).""" @segment_trajectory_property def inc(self): """Segment instrument surface intersect incidence angle (degree).""" @segment_trajectory_property def emi(self): """Segment instrument surface intersect emission angle (degree).""" @segment_trajectory_property def phase(self): """Segment instrument surface intersect phase angle (degree).""" @segment_trajectory_property def slant(self): """Segment line-of-sight distance to the boresight surface intersection (km).""" @segment_trajectory_property def solar_zenith_angle(self): """Segment instrument surface intersect solar zenith angle (degree).""" @segment_trajectory_property def pixel_scale(self): """Segment instrument pixel scale (km/pix).""" @cached_property def fovs(self): """Segment instrument field of view paths collection.""" return SegmentedFovsCollection(self)