''' '''
'''
ISC License
Copyright (c) 2016, Autonomous Vehicle Systems Lab, University of Colorado at Boulder
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
'''
from Basilisk.simulation import gravityEffector
from Basilisk.simulation.gravityEffector import gravCoeffOps
from Basilisk.simulation import spice_interface
from Basilisk.simulation.gravityEffector import gravCoeffOps
from Basilisk.utilities import unitTestSupport
class gravBodyFactory(object):
def __init__(self, bodyNames=None):
self.spicePlanetNames = []
self.gravBodies = {}
self.spiceObject = None
self.spiceKernelFileNames = []
if bodyNames:
self.createBodies(bodyNames)
def createBodies(self, bodyNames):
"""
A convenience function to create multiple typical solar system bodies.
Parameters
----------
bodyNames : array_like
Planet name strings. Each planet name must be a valid SPICE celestial body string.
Returns
-------
gravBodies : array_like
A list of gravity body objects held by the gravity factory.
"""
for name in bodyNames:
if name == 'mercury':
self.createMercury()
elif name == 'venus':
self.createVenus()
elif name == "earth":
self.createEarth()
elif name == "moon":
self.createMoon()
elif name == "mars":
self.createMars()
elif name == "mars barycenter":
self.createMarsBarycenter()
elif name == "jupiter barycenter":
self.createJupiter()
elif name == "saturn":
self.createSaturn()
elif name == 'uranus':
self.createUranus()
elif name == 'neptune':
self.createNeptune()
elif name == "sun":
self.createSun()
else:
print("gravBody " + name + " not found in gravBodyUtilities.py")
return self.gravBodies
def createSun(self):
sun = gravityEffector.GravBodyData()
sun.bodyInMsgName = "sun_planet_data"
sun.outputMsgName = "sun_display_frame_data"
sun.mu = 1.32712440018E20 # meters^3/s^2
sun.radEquator = 695508000.0 # meters
sun.isCentralBody = False
sun.useSphericalHarmParams = False
self.gravBodies['sun'] = sun
sun.this.disown()
return sun
def createMercury(self):
mercury = gravityEffector.GravBodyData()
mercury.bodyInMsgName = "mercury_planet_data"
mercury.outputMsgName = "mercury_display_frame_data"
mercury.mu = 4.28283100e13 # meters^3/s^2
mercury.radEquator = 2439700.0 # meters
mercury.isCentralBody = False
mercury.useSphericalHarmParams = False
self.gravBodies['mercury'] = mercury
mercury.this.disown()
return mercury
def createVenus(self):
venus = gravityEffector.GravBodyData()
venus.bodyInMsgName = "venus_planet_data"
venus.outputMsgName = "venus_display_frame_data"
venus.mu = 3.24858599e14 # meters^3/s^2
venus.radEquator = 6051800.0 # meters
venus.isCentralBody = False
venus.useSphericalHarmParams = False
self.gravBodies['venus'] = venus
venus.this.disown()
return venus
def createEarth(self):
earth = gravityEffector.GravBodyData()
earth.bodyInMsgName = "earth_planet_data"
earth.outputMsgName = "earth_display_frame_data"
earth.mu = 0.3986004415E+15 # meters^3/s^2
earth.radEquator = 6378136.6 # meters
earth.isCentralBody = False
earth.useSphericalHarmParams = False
self.gravBodies['earth'] = earth
earth.this.disown()
return earth
def createMoon(self):
moon = gravityEffector.GravBodyData()
moon.bodyInMsgName = "moon_planet_data"
moon.outputMsgName = "moon_display_frame_data"
moon.mu = 4.902799E12 # meters^3/s^2
moon.radEquator = 1738100.0 # meters
moon.isCentralBody = False
moon.useSphericalHarmParams = False
self.gravBodies['moon'] = moon
moon.this.disown()
return moon
def createMars(self):
mars = gravityEffector.GravBodyData()
mars.bodyInMsgName = "mars_planet_data"
mars.outputMsgName = "mars_display_frame_data"
mars.mu = 4.28283100e13 # meters^3/s^2
mars.radEquator = 3396190 # meters
mars.isCentralBody = False
mars.useSphericalHarmParams = False
self.gravBodies['mars'] = mars
mars.this.disown()
return mars
def createMarsBarycenter(self):
mars_barycenter = gravityEffector.GravBodyData()
mars_barycenter.bodyInMsgName = "mars barycenter_planet_data"
mars_barycenter.outputMsgName = "mars_barycenter_display_frame_data"
mars_barycenter.mu = 4.28283100e13 # meters^3/s^2
mars_barycenter.radEquator = 3396190 # meters
mars_barycenter.isCentralBody = False
mars_barycenter.useSphericalHarmParams = False
self.gravBodies['mars barycenter'] = mars_barycenter
mars_barycenter.this.disown()
return mars_barycenter
def createJupiter(self):
jupiter = gravityEffector.GravBodyData()
jupiter.bodyInMsgName = "jupiter barycenter_planet_data"
jupiter.outputMsgName = "jupiter_display_frame_data"
jupiter.mu = 1.266865349093058E17 # meters^3/s^2
jupiter.radEquator = 71492000.0 # meters
jupiter.isCentralBody = False
jupiter.useSphericalHarmParams = False
self.gravBodies['jupiter barycenter'] = jupiter
jupiter.this.disown()
return jupiter
def createSaturn(self):
saturn = gravityEffector.GravBodyData()
saturn.bodyInMsgName = "saturn barycenter_planet_data"
saturn.outputMsgName = "saturn_display_frame_data"
saturn.mu = 3.79395000E16 # meters^3/s^2
saturn.radEquator = 60268000.0 # meters
saturn.isCentralBody = False
saturn.useSphericalHarmParams = False
self.gravBodies['saturn'] = saturn
saturn.this.disown()
return saturn
def createUranus(self):
uranus = gravityEffector.GravBodyData()
uranus.bodyInMsgName = "uranus barycenter_planet_data"
uranus.outputMsgName = "uranus_display_frame_data"
uranus.mu = 5.79396566E15 # meters^3/s^2
uranus.radEquator = 25559000.0 # meters
uranus.isCentralBody = False
uranus.useSphericalHarmParams = False
self.gravBodies['uranus'] = uranus
uranus.this.disown()
return uranus
def createNeptune(self):
neptune = gravityEffector.GravBodyData()
neptune.bodyInMsgName = "neptune barycenter_planet_data"
neptune.outputMsgName = "neptune_display_frame_data"
neptune.mu = 6.83509920E15 # meters^3/s^2
neptune.radEquator = 24764000.0 # meters
neptune.isCentralBody = False
neptune.useSphericalHarmParams = False
self.gravBodies['neptune'] = neptune
neptune.this.disown()
return neptune
def createSpiceInterface(self, path, time, **kwargs):
"""
A convenience function to configure a NAIF Spice module for the simulation.
Parameters
----------
path : string
The absolute path to the Basilisk source directory (default '').
time : string
The time string.
Other Parameters
----------------
kwargs :
spiceKernalFileNames : array_like
A list of spice kernel file names including file extension.
spicePlanetNames : array_like
A list of planet names whose Spice data is loaded, overriding the gravBodies list.
Returns
-------
spiceObject : Basilisk spice module
A configured Basilisk spice module.
"""
if 'spiceKernalFileNames' in kwargs:
try:
for fileName in kwargs['spiceKernalFileNames']:
self.spiceKernelFileNames.append(fileName)
except(TypeError):
raise TypeError('spiceKernalFileNames expects a list')
else:
self.spiceKernelFileNames.extend(['de430.bsp', 'naif0012.tls', 'de-403-masses.tpc', 'pck00010.tpc'])
self.spicePlanetNames = []
if 'spicePlanetNames' in kwargs:
try:
for planetName in kwargs['spicePlanetNames']:
self.spicePlanetNames.append(planetName)
except(TypeError):
raise TypeError('spicePlanetNames expects a list')
else:
self.spicePlanetNames = list(self.gravBodies.keys())
self.spiceObject = spice_interface.SpiceInterface()
self.spiceObject.ModelTag = "SpiceInterfaceData"
self.spiceObject.SPICEDataPath = path
self.spiceObject.outputBufferCount = 10000
self.spiceObject.planetNames = spice_interface.StringVector(self.spicePlanetNames)
self.spiceObject.UTCCalInit = time
for fileName in self.spiceKernelFileNames:
self.spiceObject.loadSpiceKernel(fileName, path)
self.spiceObject.SPICELoaded = True
if 'epochInMsgName' in kwargs:
epMsgName = kwargs['epochInMsgName']
if not isinstance(epMsgName, str):
print('ERROR: epochInMsgName must be a string argument')
exit(1)
self.spiceObject.epochInMsgName = epMsgName
epochMsg = unitTestSupport.timeStringToGregorianUTCMsg(time, dataPath = path)
return self.spiceObject, epochMsg
return self.spiceObject
def unloadSpiceKernels(self):
for fileName in self.spiceKernelFileNames:
self.spiceObject.unloadSpiceKernel(self.spiceObject.SPICEDataPath, fileName)
return
[docs]def loadGravFromFile(fileName, spherHarm, maxDeg=2):
"""
Load the gravitational body spherical harmonics coefficients from a file.
Parameters
----------
fileName : string
The full path to the specified data file.
spherHarm:
The spherical harmonics container of the gravity body.
maxDeg : integer
maximum degree of spherical harmonics to load
Notes
-----
This function is a convenience utility for loading in the spherical harmonics
coefficients from a data file. The default harmonic degree is 2 unless specified.
Note that this function calls the gravityEffector function loadGravFromFile().
"""
gravCoeffOps.loadGravFromFile(fileName, spherHarm, maxDeg)