Source code for isofit.core.geometry

#! /usr/bin/env python3
#
#  Copyright 2018 California Institute of Technology
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#
# ISOFIT: Imaging Spectrometer Optimal FITting
# Author: David R Thompson, david.r.thompson@jpl.nasa.gov
#

import logging
from datetime import datetime
import scipy as s

from .sunposition import sunpos


[docs]class Geometry: """The geometry of the observation, all we need to calculate sensor, surface, and solar positions.""" def __init__(self, obs=None, glt=None, loc=None, ds=None, esd=None, pushbroom_column=None): # Set some benign defaults... self.earth_sun_file = None self.observer_zenith = 0 self.observer_azimuth = 0 self.observer_altitude_km = None self.surface_elevation_km = None self.datetime = None self.day_of_year = None self.latitude = None self.longitude = None self.longitudeE = None self.gmtime = None self.earth_sun_distance = None self.OBSZEN = 180.0 self.RELAZ = 0.0 self.TRUEAZ = 0.0 self.umu = 1.0 self.pushbroom_column = pushbroom_column # The 'obs' object is observation metadata that follows a historical # AVIRIS-NG format. It arrives to our initializer in the form of # a list-like object... if obs is not None: self.path_length = obs[0] self.observer_azimuth = obs[1] # 0 to 360 clockwise from N self.observer_zenith = obs[2] # 0 to 90 from zenith self.solar_azimuth = obs[3] # 0 to 360 clockwise from N self.solar_zenith = obs[4] # 0 to 90 from zenith self.OBSZEN = 180.0 - abs(obs[2]) # MODTRAN convention? self.RELAZ = obs[1] - obs[3] + 180.0 self.TRUEAZ = obs[1] # MODTRAN convention? self.umu = s.cos(obs[2]/360.0*2.0*s.pi) # Libradtran # The 'loc' object is a list-like object that optionally contains # latitude and longitude information about the surface being # observed. if loc is not None: self.GNDALT = loc[2] / 1000.0 self.altitude = loc[2] self.surface_elevation_km = loc[2] / 1000.0 self.latitude = loc[1] self.longitude = loc[0] self.longitudeE = -loc[0] if self.longitude < 0: self.longitude = 360.0 - self.longitude logging.debug('Geometry lat: %f lon: %f' % (self.latitude, self.longitude)) logging.debug('Geometry observer OBSZEN: %f RELAZ: %f GNDALT: %f' % (self.OBSZEN, self.RELAZ, self.GNDALT)) # The ds object is an optional date object, defining the time of # the observation. if ds is not None: self.datetime = datetime.strptime(ds, '%Y%m%dt%H%M%S') self.day_of_year = self.datetime.timetuple().tm_yday # Finally, the earth sun distance is an array that maps the day of the # year (zero-indexed!) onto the mean-relative distance to the sun. if esd is not None: self.earth_sun_distance = esd.copy()
[docs] def coszen(self): """ Return the cosine of the solar zenith.""" self.dt = self.datetime az, zen, ra, dec, h = sunpos(self.datetime, self.latitude, self.longitudeE, self.surface_elevation_km * 1000.0, radians=True) return s.cos(zen)
[docs] def sundist(self): '''Return the mean-relative distance to the sun as defined by the day of the year. Note that we use zero-indexed table, offset by one from the actual cardenality, per Python conventions...''' return float(self.earth_sun_distance[self.day_of_year-1, 1])