234 lines
7.1 KiB
Python
234 lines
7.1 KiB
Python
#!/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
|
|
|
|
|
|
|