Source code for sasktran2.viewinggeo.ecef
from __future__ import annotations
import numpy as np
import pandas as pd
import sasktran2 as sk
[docs]
def ecef_to_sasktran2_ray(
observer: np.array,
look_vector: np.array,
time: pd.Timestamp,
geoid: sk.Geodetic | None = None,
solar_handler: sk.SolarGeometryHandlerBase | None = None,
ground_elevation: float = 0.0,
) -> sk.ViewingGeometry:
"""
Converts an observer, look vector in ECEF coordinates and time to a sasktran2 viewing ray object
Parameters
----------
observer : np.array
Observer position in ECEF (ITRF) coordinates
look_vector : np.array
Local lok vector in ECEF (ITRF) coordinates
time: pd.Timestamp
Time of the observation. Used to lookup the sun position if applicable.
geoid : sk.Geodetic
Geodetic object to use for the internal calculations. Defaults to WGS84
solar_handler : sk.solar.SolarGeometryHandlerBase
Object used to lookup the solar angles for each ray. Defaults to None in which case a SolarHandlerForced object is used with 0 solar zenith and 0 solar azimuth
Returns
-------
sk.ViewingGeometryBase
"""
if solar_handler is None:
solar_handler = sk.SolarGeometryHandlerForced(0, 0)
if geoid is None:
geoid = sk.WGS84()
# Start by determining the observer's geodetic coordinates
geoid.from_xyz(observer)
# obs_lat = geoid.latitude
# obs_lon = geoid.longitude
obs_alt = geoid.altitude
# Now start by checking if this is a limb viewing ray
geoid.from_tangent_point(observer, look_vector)
if geoid.altitude > ground_elevation:
# Limb viewing
solar_zenith, solar_azimuth = solar_handler.target_solar_angles(
geoid.latitude, geoid.longitude, geoid.altitude, time
)
# Get the viewing azimuth angle
viewing_azimuth = -np.rad2deg(
np.arctan2(
np.dot(look_vector, geoid.local_west),
-np.dot(look_vector, geoid.local_south),
)
)
return sk.TangentAltitudeSolar(
geoid.altitude,
np.deg2rad(solar_azimuth - viewing_azimuth),
obs_alt,
np.cos(np.deg2rad(solar_zenith)),
)
# ground viewing
geoid.from_xyz(
geoid.altitude_intercepts(ground_elevation, observer, look_vector)[0]
)
solar_zenith, solar_azimuth = solar_handler.target_solar_angles(
geoid.latitude, geoid.longitude, geoid.altitude, time
)
cos_viewing_zenith = np.dot(look_vector, geoid.local_up)
if np.abs(cos_viewing_zenith) > (1 - 1e-8):
# Basically nadir viewing and so we can't get an observer azimuth
viewing_azimuth = 0.0
else:
# Get the viewing azimuth angle
viewing_azimuth = -np.arctan2(
np.dot(look_vector, geoid.local_west),
-np.dot(look_vector, geoid.local_south),
)
return sk.GroundViewingSolar(
np.cos(np.deg2rad(solar_zenith)),
np.deg2rad(solar_azimuth - viewing_azimuth),
cos_viewing_zenith,
obs_alt,
)