ISCE_INSAR/components/isceobj/Planet/Planet.py

234 lines
7.1 KiB
Python
Raw Normal View History

2019-01-16 19:40:08 +00:00
#!/usr/bin/env python3
from __future__ import print_function
import math
from iscesys.Component.Component import Component
import isceobj.Planet.AstronomicalHandbook as AstronomicalHandbook
from isceobj.Planet.Ellipsoid import Ellipsoid
from iscesys.Component.Configurable import SELF
PNAME = Component.Parameter(
'pname',
public_name='PNAME',
default='Earth',
type=str,
mandatory=True,
intent='input',
doc='Planet name'
)
ELLIPSOID_MODEL = Component.Parameter(
'ellipsoidModel',
public_name='ELLIPSOID_MODEL',
default=None,
type=str,
mandatory=False,
intent='input',
doc='Ellipsoid model'
)
class Planet(Component):
"""
A class to represent a planet.
The parameters maintained internally are the following:
elp = an ellipsoid model of class Ellipsoid
GM = Planet mass in units of acceleration * distance**2 ---
dividing by distance**2 from the center of the planet gives the
gravitational acceleration at that distance and
dividing by the distance gives the gravitational potential field
monopole term at that distance
spin = radian frequency of the planet's spin
"""
parameter_list = (
PNAME,
ELLIPSOID_MODEL
)
family = 'planet'
#modified the constructor so it takes the ellipsoid model. this way it
#does not to be hardcoded to WGS-84.
#also ellipsoid as been modified so it has the model attribute
def __init__(self,family='', name='',pname='', ellipsoidModel=None):
super(Planet, self).__init__(family if family else self.__class__.family, name=name)
self._pname = pname
self._ellipsoidModel = ellipsoidModel
#Before all the initialization done in _configure was done here but now we want that
#to be triggered also during the initialization of Configurable. By putting it into
# _configure() we reach the goal
#Call configure() for backward compatibility.
self._configure()
return None
#put all the initialization
def _configure(self):
if self._ellipsoidModel is None:
if self._pname == 'Earth':
self._ellipsoidModel = 'WGS-84'
else:
self._ellipsoidModel = 'default'
########## TO BE DONE in AstronomicalHandbook.py:
# define a generic model called
# default that just maps the name of the planet to the corresponding
# axis and eccentricity
#######################
print(
'At the moment there is no default ellipsoid defined for the planet',
self._pname)
raise NotImplementedError
pass
if self._pname in AstronomicalHandbook.PlanetsData.names:
self._ellipsoid = (
Ellipsoid(
a=AstronomicalHandbook.PlanetsData.ellipsoid[
self._pname
][self._ellipsoidModel].a,e2=AstronomicalHandbook.PlanetsData.ellipsoid[
self._pname
][self._ellipsoidModel].e2,
model=self._ellipsoidModel)
)
self.GM = AstronomicalHandbook.PlanetsData.GM[self._pname]
self.spin = (
2.0*math.pi/
AstronomicalHandbook.PlanetsData.rotationPeriod[self._pname]
)
else:
self._ellipsoid = Ellipsoid()
self.GM = 1.0
self.spin = 1.0
pass
@property
def pname(self):
"""Name of the planet"""
return self._pname
@pname.setter
def pname(self, pname):
self._pname = pname
return None
def set_name(self,pname):
if not isinstance(pname,basestring):
raise ValueError("attempt to instantiate a planet with a name %s that is not a string" % pname)
self.pname = pname
return None
def get_name(self):
return self.pname
@property
def ellipsoid(self):
"""Ellipsoid model of the planet. See Ellipsoid class."""
return self._ellipsoid
@ellipsoid.setter
def ellipsoid(self, elp):
self._ellipsoid = elp
return None
def get_elp(self):
return self.ellipsoid
@property
def GM(self):
"""Mass of planet times Newton's gravitational constant in m**3/s**2"""
return self._GM
@GM.setter
def GM(self, GM):
try:
self._GM = float(GM)
except (TypeError, ValueError):
raise ValueError(
"invalid use of non-numeric object %s to set GM value "
%
str(GM)
)
return None
def get_GM(self):
return self.GM
def set_GM(self, GM):
self.GM = GM
pass
@property
def spin(self):
return self._spin
@spin.setter
def spin(self, spin):
try:
self._spin = float(spin)
except (ValueError, TypeError):
raise ValueError(
"invalid use of non-numeric object %s to set spin " % spin
)
pass
def get_spin(self):
return self.spin
def set_spin(self, spin):
self.spin = spin
@property
def polar_axis(self):
return self._polar_axis
@polar_axis.setter
def polar_axis(self, vector):
"""Give me a vector that is parallel to my spin axis"""
from isceobj.Util.geo.euclid import Vector
if not isinstance(vector, Vector):
try:
vector = Vector(*vector)
except Exception:
raise ValueError(
"polar axis must a Vector or length 3 container"
)
pass
self._polar_axis = vector.hat()
return None
@property
def ortho_axis(self):
return self._ortho_axis
@property
def primary_axis(self):
return self._primary_axis
@primary_axis.setter
def primary_axis(self, vector):
"""Give me a vector in your coordinates that is orthogonal to my polar
axis"""
from isceobj.Util.geo.euclid import Vector
if not isinstance(vector, Vector):
try:
vector = Vector(*vector)
except Exception:
raise ValueError(
"primary axis must a Vector or length 3 container"
)
pass
self._primary_axis = vector.hat()
try:
if self.polar_axis*self._primary_axis > 1.e-10:
raise ValueError(
"polar_axis and primary_axis are not orthogonal"
)
except AttributeError:
class RaceHazard(Exception):
"""The outer class has methods that must be called in order.
Should you fail to do so, this Exception shall be raised"""
pass
raise RuntimeError("You must set planet's polar axis first")
self._ortho_axis = self.primary_axis.cross(self.polar_axis)
pass
pass