Source code for test_orb_elem_convert

''' '''
'''
 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.

'''
import pytest
import os
import inspect
import matplotlib.pyplot as plt
import math
import numpy
#
# orb_elem_convert Unit Test
#
# Purpose:  Test the precision of the orb_elem_convert module. Functionality
#           is tested by comparing input/output data as well as calculated
#           conversions.
# Author:   Gabriel Chapel
# Creation Date:  July 27, 2017
#

filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))
splitPath = path.split('simulation')

# @cond DOXYGEN_IGNORE
from Basilisk.utilities import SimulationBaseClass
from Basilisk.simulation import orb_elem_convert
from Basilisk.utilities import macros
from Basilisk.utilities import macros as mc
from Basilisk.utilities import unitTestSupport
# @endcond

# Class in order to plot using data accross the different paramatrized scenarios
class DataStore:
    def __init__(self):
        self.Date = [] # replace these with appropriate containers for the data to be stored for plotting
        self.MarsPosErr = []
        self.EarthPosErr = []
        self.SunPosErr = []


[docs]@pytest.mark.parametrize("a, e, i, AN, AP, f, mu, name", [ # Inclined Elliptical Orbit Varying e (10000000.0, 0.01, 33.3*mc.D2R, 48.2*mc.D2R, 347.8*mc.D2R, 85.3*mc.D2R, 0.3986004415E+15, 'IncEllip_e_1'), (10000000.0, 0.10, 33.3*mc.D2R, 48.2*mc.D2R, 347.8*mc.D2R, 85.3*mc.D2R, 0.3986004415E+15, 0), (10000000.0, 0.25, 33.3*mc.D2R, 48.2*mc.D2R, 347.8*mc.D2R, 85.3*mc.D2R, 0.3986004415E+15, 0), (10000000.0, 0.50, 33.3*mc.D2R, 48.2*mc.D2R, 347.8*mc.D2R, 85.3*mc.D2R, 0.3986004415E+15, 0), (10000000.0, 0.75, 33.3*mc.D2R, 48.2*mc.D2R, 347.8*mc.D2R, 85.3*mc.D2R, 0.3986004415E+15, 'IncEllip_e_2'), # Inclined Elliptical Orbit Varying a (10000000.0, 0.50, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'IncEllip_a_1'), (100000.0, 0.50, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (10000.0, 0.50, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (1000.0, 0.50, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (100.0, 0.50, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (10.0, 0.50, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'IncEllip_a_2'), # Equatorial Elliptical Orbit Varying e (10000000.0, 0.01, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'EquEllip_e_1'), (10000000.0, 0.10, 0.0, 0.0, 347.8*mc.D2R, 85.3*mc.D2R, 0.3986004415E+15, 0), (10000000.0, 0.25, 0.0, 0.0, 347.8*mc.D2R, 85.3*mc.D2R, 0.3986004415E+15, 0), (10000000.0, 0.50, 0.0, 0.0, 347.8*mc.D2R, 85.3*mc.D2R, 0.3986004415E+15, 0), (10000000.0, 0.75, 0.0, 0.0, 347.8*mc.D2R, 85.3*mc.D2R, 0.3986004415E+15, 'EquEllip_e_2'), # Equatorial Elliptical Orbit Varying a (10000000.0, 0.50, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'EquEllip_a_1'), # For i=0 => AN=0 (100000.0, 0.50, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (10000.0, 0.50, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (1000.0, 0.50, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (100.0, 0.50, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (10.0, 0.50, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'EquEllip_a_2'), # Inclined Circular Orbit (10000000.0, 0.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 'IncCirc_1'), (1000000.0, 0.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 0), (100000.0, 0.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 0), (10000.0, 0.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 0), (1000.0, 0.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 0), (100.0, 0.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 0), (10.0, 0.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 'IncCirc_2'), # Equatorial Circular Orbit (10000000.0, 0.0, 0.0, 0.0, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 'EquCirc_1'), (1000000.0, 0.0, 0.0, 0.0, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 0), (100000.0, 0.0, 0.0, 0.0, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 0), (10000.0, 0.0, 0.0, 0.0, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 0), (1000.0, 0.0, 0.0, 0.0, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 0), (100.0, 0.0, 0.0, 0.0, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 0), (10.0, 0.0, 0.0, 0.0, 0.0, 85.3 * mc.D2R, 0.3986004415E+15, 'EquCirc_2'), # Inclined Parabolic Orbit (-10.0, 1.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'IncPara_1'), # For input of -a, (-100.0, 1.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), # must have e= 1.0 (-1000.0, 1.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), # or e >1.0 (-10000.0, 1.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-100000.0, 1.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'IncPara_2'), # Equatorial Parabolic Orbit (-10.0, 1.0, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'EquPara_1'), # For input of -a, (-100.0, 1.0, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), # must have e= 1.0 (-1000.0, 1.0, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), # or e >1.0 (-10000.0, 1.0, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-100000.0, 1.0, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'EquPara_2'), # Inclined Hyperbolic Orbit varying a (-10.0, 1.3, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'IncHyp_a_1'), (-100.0, 1.3, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-1000.0, 1.3, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-10000.0, 1.3, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-100000.0, 1.3, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'IncHyp_a_2'), # Inclined Hyperbolic Orbit varying e (-100000.0, 1.1, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'IncHyp_e_1'), (-100000.0, 1.2, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-100000.0, 1.3, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-100000.0, 1.4, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-100000.0, 1.5, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'IncHyp_e_2'), # Equatorial Hyperbolic Orbit varying a (-10.0, 1.3, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'EquHyp_a_1'), (-100.0, 1.3, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-1000.0, 1.3, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-10000.0, 1.3, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-100000.0, 1.3, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'EquHyp_a_2'), # Equatorial Hyperbolic Orbit varying e (-100000.0, 1.1, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'EquHyp_e_1'), (-100000.0, 1.2, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-100000.0, 1.3, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-100000.0, 1.4, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 0), (-100000.0, 1.5, 0.0, 0.0, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15, 'EquHyp_e_2'), # # Approaching circular orbit # (100000.0, 0.000001, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15), # These don't work # (10000000.0, 1.0, 33.3 * mc.D2R, 48.2 * mc.D2R, 347.8 * mc.D2R, 85.3 * mc.D2R, 0.3986004415E+15), # or e >1.0 # (-10, 0.9, 33.3*mc.D2R, 48.2*mc.D2R, 347.8*mc.D2R, 85.3*mc.D2R, 0.3986004415E+15) ]) # provide a unique test method name, starting with test_ def test_orb_elem_convert(a, e, i, AN, AP, f, mu, name, DispPlot=False): """Module Unit Test""" # each test method requires a single assert method to be called [testResults, testMessage] = orbElem(a, e, i, AN, AP, f, mu, name, DispPlot) assert testResults < 1, testMessage
# Run unit test def orbElem(a, e, i, AN, AP, f, mu, name, DispPlot): # Elem2RV testFailCount1 = 0 # zero unit test result counter testMessages = [] # create empty array to store test log messages # Create a sim module as an empty container unitTaskName = "unitTask" # arbitrary name (don't change) unitProcessName = "TestProcess" # arbitrary name (don't change) # Create a sim module as an empty container TotalSim = SimulationBaseClass.SimBaseClass() DynUnitTestProc = TotalSim.CreateNewProcess(unitProcessName) # # create the dynamics task and specify the integration update time testProcessRate = macros.sec2nano(1.0) DynUnitTestProc.addTask(TotalSim.CreateNewTask(unitTaskName, testProcessRate)) # Initialize the modules that we are using. orb_elemObject = orb_elem_convert.OrbElemConvert() orb_elemObject.ModelTag = "OrbElemConvertData" # Add Model To Task TotalSim.AddModelToTask(unitTaskName, orb_elemObject) # Set element values epsDiff = 0.0000001 orb_elemObject.mu = mu orb_elemObject.Elements2Cart = True orb_elemObject.inputsGood = True orb_elemObject.ReinitSelf = True orb_elemObject.useEphemFormat = True ###### ELEM2RV ###### TotalSim.AddVariableForLogging('OrbElemConvertData.r_N', testProcessRate, 0, 2, 'double') TotalSim.AddVariableForLogging('OrbElemConvertData.v_N', testProcessRate, 0, 2, 'double') TotalSim.AddVariableForLogging('OrbElemConvertData.ReinitSelf') orb_elemObject.StateString = "ClassicElemString" ElemMessage = orb_elem_convert.classicElements() inputMessageSize = ElemMessage.getStructSize() # Create and write messages TotalSim.TotalSim.CreateNewMessage(unitProcessName, orb_elemObject.StateString, inputMessageSize, 2) # number of buffers (leave at 2 as default, don't make zero) if e == 1.0: ElemMessage.a = 0.0 ElemMessage.rPeriap = -a else: ElemMessage.a = a # meters ElemMessage.e = e ElemMessage.i = i ElemMessage.Omega = AN ElemMessage.omega = AP ElemMessage.f = f TotalSim.TotalSim.WriteMessageData(orb_elemObject.StateString, inputMessageSize, 0, ElemMessage) # Log Message to test WriteOutputMessage() TotalSim.TotalSim.logThisMessage(orb_elemObject.OutputDataString) # Execute simulation TotalSim.ConfigureStopTime(int(1E9)) TotalSim.InitializeSimulation() TotalSim.ExecuteSimulation() # Get r and v from sim vSim = TotalSim.GetLogVariableData('OrbElemConvertData.v_N') vSim = numpy.delete(vSim[-1], 0, axis=0) rSim = TotalSim.GetLogVariableData('OrbElemConvertData.r_N') rSim = numpy.delete(rSim[-1], 0, axis=0) # Get r and v from message if orb_elemObject.useEphemFormat: rMsgPlanet = TotalSim.pullMessageLogData(orb_elemObject.OutputDataString + '.PositionVector', list(range(3))) rMsgPlanet = numpy.delete(rMsgPlanet[-1], 0, axis=0) vMsgPlanet = TotalSim.pullMessageLogData(orb_elemObject.OutputDataString + '.VelocityVector', list(range(3))) vMsgPlanet = numpy.delete(vMsgPlanet[-1], 0, axis=0) rMsgPlanetDiff = numpy.subtract(rSim, rMsgPlanet) for g in range(3): if abs(rMsgPlanetDiff[g]) > 0: testMessages.append(" FAILED: Planet Position Message, column " + str(g)) testFailCount1 += 1 vMsgPlanetDiff = numpy.subtract(vSim, vMsgPlanet) for g in range(3): if abs(vMsgPlanetDiff[g]) > 0: testMessages.append(" FAILED: Planet Velocity Message, column " + str(g)) testFailCount1 += 1 else: rMsgSC = TotalSim.pullMessageLogData(orb_elemObject.OutputDataString + '.r_BN_N', list(range(3))) rMsgSC = numpy.delete(rMsgSC[-1], 0, axis=0) vMsgSC = TotalSim.pullMessageLogData(orb_elemObject.OutputDataString + '.v_BN_N', list(range(3))) vMsgSC = numpy.delete(vMsgSC[-1], 0, axis=0) rMsgSCDiff = numpy.subtract(rSim, rMsgSC) for g in range(3): if abs(rMsgSCDiff[g]) > 0: testMessages.append(" FAILED: Spacecraft Position Message, column " + str(g)) testFailCount1 += 1 vMsgSCDiff = numpy.subtract(vSim, vMsgSC) for g in range(3): if abs(vMsgSCDiff[g]) > 0: testMessages.append(" FAILED: Spacecraft Velocity Message, column " + str(g)) testFailCount1 += 1 ReinitSelf = TotalSim.GetLogVariableData('OrbElemConvertData.ReinitSelf') ReinitSelf = numpy.delete(ReinitSelf[-1], 0, axis=0) if ReinitSelf: testMessages.append(" FAILED: ReinitSelf") testFailCount1 += 1 # Calculation of elem2rv if e == 1.0 and a > 0.0: # rectilinear elliptic orbit case Ecc = f # f is treated as ecc.anomaly r = a * (1 - e * math.cos(Ecc)) # orbit radius v = math.sqrt(2 * mu / r - mu / a) ir = numpy.zeros(3) ir[0] = math.cos(AN) * math.cos(AP) - math.sin(AN) * math.sin(AP) * math.cos(i) ir[1] = math.sin(AN) * math.cos(AP) + math.cos(AN) * math.sin(AP) * math.cos(i) ir[2] = math.sin(AP) * math.sin(i) rTruth = numpy.multiply(r, ir) if math.sin(Ecc) > 0: vTruth = numpy.multiply(-v, ir) else: vTruth = numpy.multiply(v, ir) else: if e == 1 and a < 0: # parabolic case rp = -a # radius at periapses p = 2 * rp # semi-latus rectum a = 0.0 else: # elliptic and hyperbolic cases p = a * (1 - e * e) # semi-latus rectum r = p / (1 + e * math.cos(f)) # orbit radius theta = AP + f # true latitude angle h = math.sqrt(mu * p) # orbit ang.momentum mag. rTruth = numpy.zeros(3) rTruth[0] = r * (math.cos(AN) * math.cos(theta) - math.sin(AN) * math.sin(theta) * math.cos(i)) rTruth[1] = r * (math.sin(AN) * math.cos(theta) + math.cos(AN) * math.sin(theta) * math.cos(i)) rTruth[2] = r * (math.sin(theta) * math.sin(i)) vTruth = numpy.zeros(3) vTruth[0] = -mu / h * (math.cos(AN) * (math.sin(theta) + e * math.sin(AP)) + math.sin(AN) * (math.cos( theta) + e * math.cos(AP)) * math.cos(i)) vTruth[1] = -mu / h * (math.sin(AN) * (math.sin(theta) + e * math.sin(AP)) - math.cos(AN) * (math.cos( theta) + e * math.cos(AP)) * math.cos(i)) vTruth[2] = -mu / h * (-(math.cos(theta) + e * math.cos(AP)) * math.sin(i)) # Position and Velocity Diff Checks rDiff = numpy.subtract(rSim, rTruth) vDiff = numpy.subtract(vSim, vTruth) rDiffcsv = numpy.asarray(rDiff) vDiffcsv = numpy.asarray(vDiff) for g in range(3): if abs(rDiff[g]) > epsDiff: testMessages.append(" FAILED: Position Vector, column " + str(g)) testFailCount1 += 1 for g in range(3): if abs(vDiff[g]) > epsDiff: testMessages.append(" FAILED: Velocity Vector, column " + str(g)) testFailCount1 += 1 if name != 0: if testFailCount1 == 0: colorText = 'ForestGreen' passFailMsg = "" # "Passed: " + name + "." passedText = r'\textcolor{' + colorText + '}{' + "PASSED" + '}' else: colorText = 'Red' passFailMsg = "Failed: " + name + "." testMessages.append(passFailMsg) testMessages.append(" | ") passedText = r'\textcolor{' + colorText + '}{' + "FAILED" + '}' # Write some snippets for AutoTex snippetName = name + "PassedText1" snippetContent = passedText unitTestSupport.writeTeXSnippet(snippetName, snippetContent, path) snippetName = name + "PassFailMsg1" snippetContent = passFailMsg unitTestSupport.writeTeXSnippet(snippetName, snippetContent, path) ###### RV2ELEM ###### # RV2Elem testFailCount2 = 0 # zero unit test result counter testMessages = [] # create empty array to store test log messages for g in range(2): TotalSim = SimulationBaseClass.SimBaseClass() DynUnitTestProc = TotalSim.CreateNewProcess(unitProcessName) # # create the dynamics task and specify the integration update time testProcessRate = macros.sec2nano(1.0) DynUnitTestProc.addTask(TotalSim.CreateNewTask(unitTaskName, testProcessRate)) # Initialize the modules that we are using. orb_elemObject = orb_elem_convert.OrbElemConvert() orb_elemObject.ModelTag = "OrbElemConvertData" # Add Model To Task TotalSim.AddModelToTask(unitTaskName, orb_elemObject) # Log Variables TotalSim.AddVariableForLogging('OrbElemConvertData.CurrentElem.a') TotalSim.AddVariableForLogging('OrbElemConvertData.CurrentElem.e') TotalSim.AddVariableForLogging('OrbElemConvertData.CurrentElem.i') TotalSim.AddVariableForLogging('OrbElemConvertData.CurrentElem.Omega') TotalSim.AddVariableForLogging('OrbElemConvertData.CurrentElem.omega') TotalSim.AddVariableForLogging('OrbElemConvertData.CurrentElem.f') TotalSim.AddVariableForLogging('OrbElemConvertData.Elements2Cart') TotalSim.AddVariableForLogging('OrbElemConvertData.inputsGood') TotalSim.AddVariableForLogging('OrbElemConvertData.r_N', testProcessRate, 0, 2, 'double') TotalSim.AddVariableForLogging('OrbElemConvertData.v_N', testProcessRate, 0, 2, 'double') orb_elemObject.Elements2Cart = False orb_elemObject.inputsGood = True orb_elemObject.mu = mu if g == 0: orb_elemObject.useEphemFormat = False CartMessage = orb_elem_convert.SCPlusStatesSimMsg() CartMessage.r_BN_N = rSim CartMessage.v_BN_N = vSim else: orb_elemObject.useEphemFormat = True CartMessage = orb_elem_convert.SpicePlanetStateSimMsg() CartMessage.PositionVector = rSim CartMessage.VelocityVector = vSim orb_elemObject.StateString = "inertial_state_output" inputMessageSize = CartMessage.getStructSize() # Create and write messages TotalSim.TotalSim.CreateNewMessage(unitProcessName, orb_elemObject.StateString, inputMessageSize, 2) # number of buffers (leave at 2 as default, don't make zero) TotalSim.TotalSim.WriteMessageData(orb_elemObject.StateString, inputMessageSize, 0, CartMessage) TotalSim.TotalSim.logThisMessage(orb_elemObject.OutputDataString) # Execute simulation TotalSim.ConfigureStopTime(int(1E9)) TotalSim.InitializeSimulation() TotalSim.ExecuteSimulation() aOut = TotalSim.GetLogVariableData('OrbElemConvertData.CurrentElem.a') aOut = numpy.delete(aOut[-1], 0, axis=0) eOut = TotalSim.GetLogVariableData('OrbElemConvertData.CurrentElem.e') eOut = numpy.delete(eOut[-1], 0, axis=0) iOut = TotalSim.GetLogVariableData('OrbElemConvertData.CurrentElem.i') iOut = numpy.delete(iOut[-1], 0, axis=0) ANOut = TotalSim.GetLogVariableData('OrbElemConvertData.CurrentElem.Omega') ANOut = numpy.delete(ANOut[-1], 0, axis=0) APOut = TotalSim.GetLogVariableData('OrbElemConvertData.CurrentElem.omega') APOut = numpy.delete(APOut[-1], 0, axis=0) fOut = TotalSim.GetLogVariableData('OrbElemConvertData.CurrentElem.f') fOut = numpy.delete(fOut[-1], 0, axis=0) # Element Diff Check ElemDiff = [(a - aOut), (e - eOut), (i - iOut), (AN - ANOut), (AP - APOut), (f - fOut)] ElemDiffcsv = numpy.asarray(ElemDiff) for g in range(6): if abs(ElemDiff[g]) > epsDiff: testMessages.append(" FAILED: Sim Orbital Element " + str(g)) testFailCount2 += 1 aMsg = TotalSim.pullMessageLogData(orb_elemObject.OutputDataString + ".a", list(range(1))) aMsg = numpy.delete(aMsg[-1], 0, axis=0) eMsg = TotalSim.pullMessageLogData(orb_elemObject.OutputDataString + ".e", list(range(1))) eMsg = numpy.delete(eMsg[-1], 0, axis=0) iMsg = TotalSim.pullMessageLogData(orb_elemObject.OutputDataString + ".i", list(range(1))) iMsg = numpy.delete(iMsg[-1], 0, axis=0) ANMsg = TotalSim.pullMessageLogData(orb_elemObject.OutputDataString + ".Omega", list(range(1))) ANMsg = numpy.delete(ANMsg[-1], 0, axis=0) APMsg = TotalSim.pullMessageLogData(orb_elemObject.OutputDataString + ".omega", list(range(1))) APMsg = numpy.delete(APMsg[-1], 0, axis=0) fMsg = TotalSim.pullMessageLogData(orb_elemObject.OutputDataString + ".f", list(range(1))) fMsg = numpy.delete(fMsg[-1], 0, axis=0) ElemMsgDiff = [(aOut - aMsg), (eOut - eMsg), (iOut - iMsg), (ANOut - ANMsg), (APOut - APMsg), (fOut - fMsg)] for g in range(6): if abs(ElemMsgDiff[g]) > 0: testMessages.append(" FAILED: Orbital Element Message " + str(g)) testFailCount2 += 1 ######### Calculate rv2elem ######### # Calculate the specific angular momentum and its magnitude epsConv = 0.0000000001 hVec = numpy.cross(rTruth, vTruth) h = numpy.linalg.norm(hVec) p = h * h / mu # Calculate the line of nodes v3 = numpy.array([0.0, 0.0, 1.0]) nVec = numpy.cross(v3, hVec) n = numpy.linalg.norm(nVec) # Orbit eccentricity and energy r = numpy.linalg.norm(rTruth) v = numpy.linalg.norm(vTruth) eVec = numpy.multiply(v * v / mu - 1.0 / r, rTruth) v3 = numpy.multiply(numpy.dot(rTruth, vTruth) / mu, vTruth) eVec = numpy.subtract(eVec, v3) eO = numpy.linalg.norm(eVec) rmag = r rPeriap = p / (1.0 + eO) # compute semi - major axis alpha = 2.0 / r - v * v / mu if (math.fabs(alpha) > epsConv): # elliptic or hyperbolic case aO = 1.0 / alpha rApoap = p / (1.0 - eO) else: # parabolic case rp = p / 2.0 aO = 0.0 # a is not defined for parabola, so -rp is returned instead rApoap = 0.0 # Calculate the inclination iO = math.acos(hVec[2] / h) # Calculate AP, AN, and True anomaly if eO >= 1e-11 and iO >= 1e-11: # Case 1: Non - circular, inclined orbit Omega = math.acos(nVec[0] / n) if (nVec[1] < 0.0): Omega = 2.0 * math.pi - Omega omega = math.acos(numpy.dot(nVec, eVec) / n / eO) if eVec[2] < 0.0: omega = 2.0 * math.pi - omega fO = math.acos(numpy.dot(eVec, rTruth) / eO / r) if numpy.dot(rTruth, vTruth) < 0.0: fO = 2.0 * math.pi - fO elif eO >= 1e-11 and iO < 1e-11: # Case 2: Non - circular, equatorial orbit # Equatorial orbit has no ascending node Omega = 0.0 # True longitude of periapsis, omegatilde_true omega = math.acos(eVec[0] / eO) if eVec[1] < 0.0: omega = 2.0 * math.pi - omega fO = math.acos(numpy.dot(eVec, rTruth) / eO / r) if numpy.dot(rTruth, vTruth) < 0.0: fO = 2.0 * math.pi - fO elif eO < 1e-11 and iO >= 1e-11: # Case 3: Circular, inclined orbit Omega = math.acos(nVec[0] / n) if (nVec[1] < 0.0): Omega = 2.0 * math.pi - Omega omega = 0.0 # Argument of latitude, u = omega + f * / fO = math.acos(numpy.dot(nVec, rTruth) / n / r) if rTruth[2] < 0.0: fO = 2.0 * math.pi - fO elif eO < 1e-11 and iO < 1e-11: # Case 4: Circular, equatorial orbit Omega = 0.0 omega = 0.0 # True longitude, lambda_true fO = math.acos(rTruth[0] / r) if rTruth[1] < 0: fO = 2.0 * math.pi - fO else: print("Error: rv2elem couldn't identify orbit type.\n") if (eO >= 1.0 and math.fabs(fO) > math.pi): twopiSigned = math.copysign(2.0 * math.pi, fO) fO -= twopiSigned # Element Diff Check ElemCalcDiff = [(aO - aOut), (eO - eOut), (iO - iOut), (Omega - ANOut), (omega - APOut), (fOut - fOut)] ElemCalcDiffcsv = numpy.asarray(ElemCalcDiff) for g in range(6): if abs(ElemCalcDiff[g]) > epsDiff: testMessages.append(" FAILED: Calculated Orbital Element " + str() + str(g)) testFailCount2 += 1 # create plot # txt = 'e = ' + str(e) + ' and a = ' + str(a) + 'km' fact = (len(str(abs(a)))-3.0) plt.figure(1,figsize=(7, 5), dpi=80, facecolor='w', edgecolor='k') plt.clf() # fig1.text(.5, .05, txt, ha='center') ax1 = plt.subplot(211) ax1.cla() index = numpy.arange(3) bar_width = 0.35 opacity = 0.8 rects1 = ax1.bar(index, rSim, bar_width, alpha=opacity, color='b', label='Simulated Position') rects2 = ax1.bar(index + bar_width, rTruth, bar_width, alpha=opacity, color='g', label='Calculated Position') ax1.spines['left'].set_position('zero') ax1.spines['right'].set_color('none') ax1.spines['bottom'].set_position('zero') ax1.spines['top'].set_color('none') ax1.spines['left'].set_smart_bounds(False) ax1.spines['bottom'].set_smart_bounds(False) for xtick in ax1.get_xticklabels(): xtick.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.5)) ax1.xaxis.set_ticks_position('bottom') ax1.yaxis.set_ticks_position('left') plt.ylabel('Position (m)') plt.xticks(index + bar_width, ('X', 'Y', 'Z')) plt.legend(loc='lower right') ax2 = plt.subplot(212) ax2.cla() rects1 = ax2.bar(index, vSim, bar_width, alpha=opacity, color='b', label='Simulated Velocity') rects2 = ax2.bar(index + bar_width, vTruth, bar_width, alpha=opacity, color='g', label='Calculated Velocity') ax2.spines['left'].set_position('zero') ax2.spines['right'].set_color('none') ax2.spines['bottom'].set_position('zero') ax2.spines['top'].set_color('none') ax2.spines['left'].set_smart_bounds(False) ax2.spines['bottom'].set_smart_bounds(False) for xtick in ax2.get_xticklabels(): xtick.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.5)) ax2.xaxis.set_ticks_position('bottom') ax2.yaxis.set_ticks_position('left') plt.ylabel('Velocity (m/s)') plt.xticks(index + bar_width, ('X', 'Y', 'Z')) plt.legend(loc='lower right') if name != 0: unitTestSupport.writeFigureLaTeX(name, "$e = " + str(e) + "$ and $a = 10^" + str(int(fact)) + "$km", plt, 'height=0.7\\textwidth, keepaspectratio', path) if testFailCount2 == 0: colorText = 'ForestGreen' passFailMsg = "" # "Passed: " + name + "." passedText = r'\textcolor{' + colorText + '}{' + "PASSED" + '}' else: colorText = 'Red' passFailMsg = "Failed: " + name + "." testMessages.append(passFailMsg) testMessages.append(" | ") passedText = r'\textcolor{' + colorText + '}{' + "FAILED" + '}' # Write some snippets for AutoTex snippetName = name + "PassedText2" snippetContent = passedText unitTestSupport.writeTeXSnippet(snippetName, snippetContent, path) snippetName = name + "PassFailMsg2" snippetContent = passFailMsg unitTestSupport.writeTeXSnippet(snippetName, snippetContent, path) if DispPlot: plt.show() plt.close() testFailCount = testFailCount1+testFailCount2 return [testFailCount, ''.join(testMessages)] if __name__ == "__main__": test_orb_elem_convert(10000000.0, 0.01, 33.3*mc.D2R, 48.2*mc.D2R, 347.8*mc.D2R, 85.3*mc.D2R, 0.3986004415E+15, 0 )