From 11c1d312b5f2077adac1a519d83c8b7274b70902 Mon Sep 17 00:00:00 2001 From: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun, 9 Feb 2025 11:12:49 +0000 Subject: [PATCH 1/7] Create python-package.yml Add configuration for Python packaging. --- .github/workflows/python-package.yml | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/python-package.yml diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..1b85a0f --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,40 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python package + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest From b86c1ba0c09610555a89c7ff521e5a33a016e85a Mon Sep 17 00:00:00 2001 From: weasdown <34220924+weasdown@users.noreply.github.com> Date: Tue, 12 Aug 2025 09:39:39 +0100 Subject: [PATCH 2/7] feat: squash merge main --- .idea/GMAT-Python-simple.iml | 10 + .idea/inspectionProfiles/Project_Default.xml | 33 ++++ .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 10 + .../001_Creating_a_Spacecraft.xml | 25 +++ .../Tut01_SimulatingAnOrbit_py.xml | 25 +++ .../Tut02_SimpleOrbitTransfer.xml | 25 +++ ...ut03_Target_FiniteBurn_To_Raise_Apogee.xml | 25 +++ .../Tut04_Mars_B_Plane_Targeting.xml | 25 +++ .idea/runConfigurations/example_py.xml | 25 +++ .idea/vcs.xml | 12 ++ README.md | 2 + examples/scripts/example.script | 172 +++++++++--------- ...Tut03_Target_FiniteBurn_To_Raise_Apogee.py | 14 +- gmat_py_simple/burn.py | 26 ++- gmat_py_simple/orbit.py | 22 +-- load_gmat.py | 2 +- 17 files changed, 345 insertions(+), 114 deletions(-) create mode 100644 .idea/GMAT-Python-simple.iml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations/001_Creating_a_Spacecraft.xml create mode 100644 .idea/runConfigurations/Tut01_SimulatingAnOrbit_py.xml create mode 100644 .idea/runConfigurations/Tut02_SimpleOrbitTransfer.xml create mode 100644 .idea/runConfigurations/Tut03_Target_FiniteBurn_To_Raise_Apogee.xml create mode 100644 .idea/runConfigurations/Tut04_Mars_B_Plane_Targeting.xml create mode 100644 .idea/runConfigurations/example_py.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/GMAT-Python-simple.iml b/.idea/GMAT-Python-simple.iml new file mode 100644 index 0000000..aad402c --- /dev/null +++ b/.idea/GMAT-Python-simple.iml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..8bc1bfb --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,33 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..1f2a26a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/001_Creating_a_Spacecraft.xml b/.idea/runConfigurations/001_Creating_a_Spacecraft.xml new file mode 100644 index 0000000..dc39c0d --- /dev/null +++ b/.idea/runConfigurations/001_Creating_a_Spacecraft.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/Tut01_SimulatingAnOrbit_py.xml b/.idea/runConfigurations/Tut01_SimulatingAnOrbit_py.xml new file mode 100644 index 0000000..6ce2533 --- /dev/null +++ b/.idea/runConfigurations/Tut01_SimulatingAnOrbit_py.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/Tut02_SimpleOrbitTransfer.xml b/.idea/runConfigurations/Tut02_SimpleOrbitTransfer.xml new file mode 100644 index 0000000..828bd91 --- /dev/null +++ b/.idea/runConfigurations/Tut02_SimpleOrbitTransfer.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/Tut03_Target_FiniteBurn_To_Raise_Apogee.xml b/.idea/runConfigurations/Tut03_Target_FiniteBurn_To_Raise_Apogee.xml new file mode 100644 index 0000000..00730ba --- /dev/null +++ b/.idea/runConfigurations/Tut03_Target_FiniteBurn_To_Raise_Apogee.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/Tut04_Mars_B_Plane_Targeting.xml b/.idea/runConfigurations/Tut04_Mars_B_Plane_Targeting.xml new file mode 100644 index 0000000..98cc924 --- /dev/null +++ b/.idea/runConfigurations/Tut04_Mars_B_Plane_Targeting.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/example_py.xml b/.idea/runConfigurations/example_py.xml new file mode 100644 index 0000000..86a7366 --- /dev/null +++ b/.idea/runConfigurations/example_py.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..7ddfc9e --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index df24ffd..5ba30d3 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Due to the wrapper's extensive use of classes and methods rather than strings, i **This wrapper requires Python 3.10-3.12. It does not yet work with Python 3.13.** +**On 19/4/25, NASA released [GMAT-R2025a](https://sourceforge.net/projects/gmat/). This wrapper was developed and tested with R2022a, so while I expect everything to still work, I cannot guarantee it. If you find any parts that don't work with R2025a, please raise an [issue](https://github.com/weasdown/GMAT-Python-simple/issues).** + ## Examples To demonstrate the wrapper, tutorials will be added to the [examples](https://github.com/weasdown/GMAT-Python-simple/tree/main/examples)/[tutorials](https://github.com/weasdown/GMAT-Python-simple/tree/main/examples/tutorials) directory as the required feature level is reached. These tutorials will match those distributed with GMAT by default (in the \[GMAT root]/samples folder) and will demonstrate the power of the wrapper to create missions using very little code. diff --git a/examples/scripts/example.script b/examples/scripts/example.script index 1d60ff0..5297922 100644 --- a/examples/scripts/example.script +++ b/examples/scripts/example.script @@ -1,5 +1,5 @@ %General Mission Analysis Tool(GMAT) Script -%Created: 2024-01-19 14:31:25 +%Created: 2025-08-09 21:24:21 %---------------------------------------- @@ -7,109 +7,109 @@ %---------------------------------------- Create Spacecraft ExampleSat; -GMAT ExampleSat.DateFormat = UTCGregorian; -GMAT ExampleSat.Epoch = '01 Jan 2000 12:00:00.000'; -GMAT ExampleSat.CoordinateSystem = EarthMJ2000Eq; -GMAT ExampleSat.DisplayStateType = Keplerian; -GMAT ExampleSat.SMA = 83474.31799999907; -GMAT ExampleSat.ECC = 0.8965199999999991; -GMAT ExampleSat.INC = 12.4606; -GMAT ExampleSat.RAAN = 292.8362; -GMAT ExampleSat.AOP = 218.9805; -GMAT ExampleSat.TA = 181.0000000000006; -GMAT ExampleSat.DryMass = 850; -GMAT ExampleSat.Cd = 2.2; -GMAT ExampleSat.Cr = 1.8; -GMAT ExampleSat.DragArea = 15; -GMAT ExampleSat.SRPArea = 1; -GMAT ExampleSat.SPADDragScaleFactor = 1; -GMAT ExampleSat.SPADSRPScaleFactor = 1; -GMAT ExampleSat.AtmosDensityScaleFactor = 1; -GMAT ExampleSat.ExtendedMassPropertiesModel = 'None'; -GMAT ExampleSat.NAIFId = -10000001; -GMAT ExampleSat.NAIFIdReferenceFrame = -9000001; -GMAT ExampleSat.OrbitColor = Red; -GMAT ExampleSat.TargetColor = Teal; -GMAT ExampleSat.OrbitErrorCovariance = [ 1e+70 0 0 0 0 0 ; 0 1e+70 0 0 0 0 ; 0 0 1e+70 0 0 0 ; 0 0 0 1e+70 0 0 ; 0 0 0 0 1e+70 0 ; 0 0 0 0 0 1e+70 ]; -GMAT ExampleSat.CdSigma = 1e+70; -GMAT ExampleSat.CrSigma = 1e+70; -GMAT ExampleSat.Id = 'SatId'; -GMAT ExampleSat.Attitude = CoordinateSystemFixed; -GMAT ExampleSat.SPADSRPInterpolationMethod = Bilinear; -GMAT ExampleSat.SPADSRPScaleFactorSigma = 1e+70; -GMAT ExampleSat.SPADDragInterpolationMethod = Bilinear; -GMAT ExampleSat.SPADDragScaleFactorSigma = 1e+70; -GMAT ExampleSat.AtmosDensityScaleFactorSigma = 1e+70; -GMAT ExampleSat.ModelFile = 'aura.3ds'; -GMAT ExampleSat.ModelOffsetX = 0; -GMAT ExampleSat.ModelOffsetY = 0; -GMAT ExampleSat.ModelOffsetZ = 0; -GMAT ExampleSat.ModelRotationX = 0; -GMAT ExampleSat.ModelRotationY = 0; -GMAT ExampleSat.ModelRotationZ = 0; -GMAT ExampleSat.ModelScale = 1; -GMAT ExampleSat.AttitudeDisplayStateType = 'Quaternion'; -GMAT ExampleSat.AttitudeRateDisplayStateType = 'AngularVelocity'; -GMAT ExampleSat.AttitudeCoordinateSystem = EarthMJ2000Eq; -GMAT ExampleSat.EulerAngleSequence = '321'; +ExampleSat.DateFormat = UTCGregorian; +ExampleSat.Epoch = '01 Jan 2000 12:00:00.000'; +ExampleSat.CoordinateSystem = EarthMJ2000Eq; +ExampleSat.DisplayStateType = Keplerian; +ExampleSat.SMA = 83474.31799999907; +ExampleSat.ECC = 0.8965199999999991; +ExampleSat.INC = 12.4606; +ExampleSat.RAAN = 292.8362; +ExampleSat.AOP = 218.9805; +ExampleSat.TA = 181.0000000000006; +ExampleSat.DryMass = 850; +ExampleSat.Cd = 2.2; +ExampleSat.Cr = 1.8; +ExampleSat.DragArea = 15; +ExampleSat.SRPArea = 1; +ExampleSat.SPADDragScaleFactor = 1; +ExampleSat.SPADSRPScaleFactor = 1; +ExampleSat.AtmosDensityScaleFactor = 1; +ExampleSat.ExtendedMassPropertiesModel = 'None'; +ExampleSat.NAIFId = -10000001; +ExampleSat.NAIFIdReferenceFrame = -9000001; +ExampleSat.OrbitColor = Red; +ExampleSat.TargetColor = Teal; +ExampleSat.OrbitErrorCovariance = [ 1e+70 0 0 0 0 0 ; 0 1e+70 0 0 0 0 ; 0 0 1e+70 0 0 0 ; 0 0 0 1e+70 0 0 ; 0 0 0 0 1e+70 0 ; 0 0 0 0 0 1e+70 ]; +ExampleSat.CdSigma = 1e+70; +ExampleSat.CrSigma = 1e+70; +ExampleSat.Id = 'SatId'; +ExampleSat.Attitude = CoordinateSystemFixed; +ExampleSat.SPADSRPInterpolationMethod = Bilinear; +ExampleSat.SPADSRPScaleFactorSigma = 1e+70; +ExampleSat.SPADDragInterpolationMethod = Bilinear; +ExampleSat.SPADDragScaleFactorSigma = 1e+70; +ExampleSat.AtmosDensityScaleFactorSigma = 1e+70; +ExampleSat.ModelFile = 'aura.3ds'; +ExampleSat.ModelOffsetX = 0; +ExampleSat.ModelOffsetY = 0; +ExampleSat.ModelOffsetZ = 0; +ExampleSat.ModelRotationX = 0; +ExampleSat.ModelRotationY = 0; +ExampleSat.ModelRotationZ = 0; +ExampleSat.ModelScale = 1; +ExampleSat.AttitudeDisplayStateType = 'Quaternion'; +ExampleSat.AttitudeRateDisplayStateType = 'AngularVelocity'; +ExampleSat.AttitudeCoordinateSystem = EarthMJ2000Eq; +ExampleSat.EulerAngleSequence = '321'; %---------------------------------------- %---------- ForceModels %---------------------------------------- Create ForceModel LowEarthProp_ForceModel; -GMAT LowEarthProp_ForceModel.CentralBody = Earth; -GMAT LowEarthProp_ForceModel.PrimaryBodies = {Earth}; -GMAT LowEarthProp_ForceModel.PointMasses = {Luna, Sun}; -GMAT LowEarthProp_ForceModel.SRP = On; -GMAT LowEarthProp_ForceModel.RelativisticCorrection = Off; -GMAT LowEarthProp_ForceModel.ErrorControl = RSSStep; -GMAT LowEarthProp_ForceModel.GravityField.Earth.Degree = 10; -GMAT LowEarthProp_ForceModel.GravityField.Earth.Order = 10; -GMAT LowEarthProp_ForceModel.GravityField.Earth.StmLimit = 100; -GMAT LowEarthProp_ForceModel.GravityField.Earth.PotentialFile = 'JGM2.cof'; -GMAT LowEarthProp_ForceModel.GravityField.Earth.TideModel = 'None'; -GMAT LowEarthProp_ForceModel.SRP.Flux = 1367; -GMAT LowEarthProp_ForceModel.SRP.SRPModel = Spherical; -GMAT LowEarthProp_ForceModel.SRP.Nominal_Sun = 149597870.691; -GMAT LowEarthProp_ForceModel.Drag.AtmosphereModel = JacchiaRoberts; -GMAT LowEarthProp_ForceModel.Drag.HistoricWeatherSource = 'ConstantFluxAndGeoMag'; -GMAT LowEarthProp_ForceModel.Drag.PredictedWeatherSource = 'ConstantFluxAndGeoMag'; -GMAT LowEarthProp_ForceModel.Drag.CSSISpaceWeatherFile = 'SpaceWeather-All-v1.2.txt'; -GMAT LowEarthProp_ForceModel.Drag.SchattenFile = 'SchattenPredict.txt'; -GMAT LowEarthProp_ForceModel.Drag.F107 = 150; -GMAT LowEarthProp_ForceModel.Drag.F107A = 150; -GMAT LowEarthProp_ForceModel.Drag.MagneticIndex = 3; -GMAT LowEarthProp_ForceModel.Drag.SchattenErrorModel = 'Nominal'; -GMAT LowEarthProp_ForceModel.Drag.SchattenTimingModel = 'NominalCycle'; -GMAT LowEarthProp_ForceModel.Drag.DragModel = 'Spherical'; +LowEarthProp_ForceModel.CentralBody = Earth; +LowEarthProp_ForceModel.PrimaryBodies = {Earth}; +LowEarthProp_ForceModel.PointMasses = {Luna, Sun}; +LowEarthProp_ForceModel.SRP = On; +LowEarthProp_ForceModel.RelativisticCorrection = Off; +LowEarthProp_ForceModel.ErrorControl = RSSStep; +LowEarthProp_ForceModel.GravityField.Earth.Degree = 10; +LowEarthProp_ForceModel.GravityField.Earth.Order = 10; +LowEarthProp_ForceModel.GravityField.Earth.StmLimit = 100; +LowEarthProp_ForceModel.GravityField.Earth.PotentialFile = 'JGM2.cof'; +LowEarthProp_ForceModel.GravityField.Earth.TideModel = 'None'; +LowEarthProp_ForceModel.SRP.Flux = 1367; +LowEarthProp_ForceModel.SRP.SRPModel = Spherical; +LowEarthProp_ForceModel.SRP.Nominal_Sun = 149597870.691; +LowEarthProp_ForceModel.Drag.AtmosphereModel = JacchiaRoberts; +LowEarthProp_ForceModel.Drag.HistoricWeatherSource = 'ConstantFluxAndGeoMag'; +LowEarthProp_ForceModel.Drag.PredictedWeatherSource = 'ConstantFluxAndGeoMag'; +LowEarthProp_ForceModel.Drag.CSSISpaceWeatherFile = 'SpaceWeather-All-v1.2.txt'; +LowEarthProp_ForceModel.Drag.SchattenFile = 'SchattenPredict.txt'; +LowEarthProp_ForceModel.Drag.F107 = 150; +LowEarthProp_ForceModel.Drag.F107A = 150; +LowEarthProp_ForceModel.Drag.MagneticIndex = 3; +LowEarthProp_ForceModel.Drag.SchattenErrorModel = 'Nominal'; +LowEarthProp_ForceModel.Drag.SchattenTimingModel = 'NominalCycle'; +LowEarthProp_ForceModel.Drag.DragModel = 'Spherical'; %---------------------------------------- %---------- Propagators %---------------------------------------- Create Propagator LowEarthProp; -GMAT LowEarthProp.FM = LowEarthProp_ForceModel; -GMAT LowEarthProp.Type = RungeKutta89; -GMAT LowEarthProp.InitialStepSize = 60; -GMAT LowEarthProp.Accuracy = 9.999999999999999e-12; -GMAT LowEarthProp.MinStep = 0.001; -GMAT LowEarthProp.MaxStep = 2700; -GMAT LowEarthProp.MaxStepAttempts = 50; -GMAT LowEarthProp.StopIfAccuracyIsViolated = true; +LowEarthProp.FM = LowEarthProp_ForceModel; +LowEarthProp.Type = RungeKutta89; +LowEarthProp.InitialStepSize = 60; +LowEarthProp.Accuracy = 9.999999999999999e-12; +LowEarthProp.MinStep = 0; +LowEarthProp.MaxStep = 2700; +LowEarthProp.MaxStepAttempts = 50; +LowEarthProp.StopIfAccuracyIsViolated = true; %---------------------------------------- %---------- Burns %---------------------------------------- Create ImpulsiveBurn IB1; -GMAT IB1.CoordinateSystem = EarthMJ2000Eq; -GMAT IB1.Element1 = 0.2; -GMAT IB1.Element2 = 0; -GMAT IB1.Element3 = 0; -GMAT IB1.DecrementMass = false; -GMAT IB1.Isp = 300; -GMAT IB1.GravitationalAccel = 9.81; +IB1.CoordinateSystem = EarthMJ2000Eq; +IB1.Element1 = 0.2; +IB1.Element2 = 0; +IB1.Element3 = 0; +IB1.DecrementMass = false; +IB1.Isp = 300; +IB1.GravitationalAccel = 9.81; %---------------------------------------- diff --git a/examples/tutorials/Tut03_Target_FiniteBurn_To_Raise_Apogee.py b/examples/tutorials/Tut03_Target_FiniteBurn_To_Raise_Apogee.py index 2d6f034..967be91 100644 --- a/examples/tutorials/Tut03_Target_FiniteBurn_To_Raise_Apogee.py +++ b/examples/tutorials/Tut03_Target_FiniteBurn_To_Raise_Apogee.py @@ -7,15 +7,17 @@ import gmat_py_simple as gpy import os -log_path = os.path.normpath(f'{os.getcwd()}/examples/logs/GMAT-Tut03-Log.txt') -gmat.UseLogFile(log_path) -gmat.EchoLogFile(False) # set to True to view log output in console (e.g. live iteration results) +# # Uncomment to enable logging +# log_path = os.path.normpath(f'{os.getcwd()}/examples/logs/GMAT-Tut03-Log.txt') +# gmat.UseLogFile(log_path) +# gmat.EchoLogFile(False) # set to True to view log output in console (e.g. live iteration results) sat_params = { 'Name': 'DefaultSC', - 'Hardware': {'Tanks': {'chemical': [{'Name': 'ChemicalTank1'}], }, - 'Thrusters': {'chemical': [{'Name': 'ChemicalThruster1', 'Tanks': 'ChemicalTank1'}]}, - } + 'Hardware': { + 'ChemicalTanks': [{'Name': 'ChemicalTank1'}, ], + 'ChemicalThrusters': [{'Name': 'ChemicalThruster1', 'Tanks': 'ChemicalTank1'}, ], + } } sat = gpy.Spacecraft.from_dict(sat_params) diff --git a/gmat_py_simple/burn.py b/gmat_py_simple/burn.py index fd4d800..bbbff24 100644 --- a/gmat_py_simple/burn.py +++ b/gmat_py_simple/burn.py @@ -93,7 +93,8 @@ def EnableThrust(self): class ImpulsiveBurn(Burn): - def __init__(self, name, coord_sys: gpy.OrbitState.CoordinateSystem | dict | str = None, delta_v: list[int | float] = None, + def __init__(self, name, coord_sys: gpy.OrbitState.CoordinateSystem | dict | str = None, + delta_v: list[int | float] = None, decrement_mass: bool = False, tanks: gpy.Tank | list[gpy.Tank] | str = None, isp: int | float = 300, gravitational_accel: float = 9.81): super().__init__('ImpulsiveBurn', name) @@ -103,9 +104,9 @@ def __init__(self, name, coord_sys: gpy.OrbitState.CoordinateSystem | dict | str # Get default coordinate system from GMAT object self.coord_sys_name = self.GetStringParameter('CoordinateSystem') - self.origin: str = self.GetStringParameter('Origin') - self.axes: str = self.GetStringParameter('Axes') - self.origin = self.GetStringParameter('Origin') + self.origin_name: str = self.GetStringParameter('Origin') + self.origin_body: gmat.Planet = None + self.axes_name: str = self.GetStringParameter('Axes') # Update coordinate system if user has supplied one if coord_sys is not None: @@ -126,16 +127,22 @@ def __init__(self, name, coord_sys: gpy.OrbitState.CoordinateSystem | dict | str self.SetStringParameter('Origin', dict_origin) self.SetStringParameter('Axes', dict_axes) - elif isinstance(coord_sys, gpy.OrbitState.CoordinateSystem | gmat.CoordinateSystem): # coord_sys is a wrapper or GMAT CoordinateSystem object + elif isinstance(coord_sys, + gpy.OrbitState.CoordinateSystem | gmat.CoordinateSystem): # coord_sys is a wrapper or GMAT CoordinateSystem object coord_sys.Initialize() + + # Below avoids false positive type hint warning in PyCharm 2025.2. + # noinspection PyTypeHints coord_sys_new: gpy.OrbitState.CoordinateSystem | gmat.CoordinateSystem = coord_sys self.coord_sys_name = coord_sys_new.GetName() # Extract celestial body (e.g. Earth) and axes (e.g. MJ2000Eq) from CoordinateSystem if isinstance(coord_sys_new, gpy.OrbitState.CoordinateSystem): - self.origin: gmat.Planet = coord_sys_new.origin # obj for celestial body at coord sys origin + self.origin_body: gmat.Planet = coord_sys_new.origin # obj for celestial body at coord sys origin + self.origin_name: str = self.origin_body.GetName() self.axes: gpy.OrbitState.CoordinateSystem.Axes = coord_sys_new.axes self.axes_name: str = self.axes.name + elif isinstance(coord_sys_new, gmat.CoordinateSystem): # coord_sys is of type gmat.CoordinateSystem self.origin_name: str = coord_sys_new.GetField('Origin') @@ -150,10 +157,11 @@ def __init__(self, name, coord_sys: gpy.OrbitState.CoordinateSystem | dict | str # Attach CoordinateSystem's celestial body (Origin) to the ImpulsiveBurn self.SetStringParameter(2, self.origin_name) # 1 for CS, 2 for Origin, 3 for Axes - self.SetRefObject(self.origin, gmat.CELESTIAL_BODY, self.origin_name) + self.SetRefObject(self.origin_body, gmat.CELESTIAL_BODY, self.origin_name) - # Attach CoordinateSystem's Axes to the ImpulsiveBurn - self.SetStringParameter(3, self.axes_name) # 1 for CS, 2 for Origin, 3 for Axes + # Attach CoordinateSystem's Axes to the ImpulsiveBurn. param is 1 for CS, 2 for Origin, 3 for Axes + self.SetStringParameter(3, self.axes_name.replace('_', '').replace(self.origin_name, + '')) else: raise TypeError(f'CoordinateSystem type "{type(coord_sys).__name__}" not recognized in ' diff --git a/gmat_py_simple/orbit.py b/gmat_py_simple/orbit.py index ae15c49..fd56e94 100644 --- a/gmat_py_simple/orbit.py +++ b/gmat_py_simple/orbit.py @@ -1,9 +1,7 @@ from __future__ import annotations -import gmat_py_simple from load_gmat import gmat -import gmat_py_simple as gpy from gmat_py_simple.basics import GmatObject from gmat_py_simple.utils import * @@ -264,7 +262,7 @@ class PrimaryBody: # TODO: use fact that PrimaryBody is alias for GravityField - in init call GravityField.__init__ def __init__(self, fm: ForceModel, body: str = 'Earth', gravity: ForceModel.GravityField = None, - drag: ForceModel.DragForce | False = False): + drag: ForceModel.DragForce | bool = False): self._force_model = fm self._body = body if body else self._force_model.central_body self._gravity = gravity if gravity else ForceModel.GravityField() @@ -544,7 +542,8 @@ def __init__(self, name: str, origin: str = 'Earth', axes: str = 'MJ2000Eq', pri secondary: str = None, xaxis: str = None, yaxis: str = None, zaxis: str = None, epoch: str = None, alignment_vec_x: int = None, alignment_vec_y: int = None, alignment_vec_z: int = None, constraint_vec_x: int = None, constraint_vec_y: int = None, constraint_vec_z: int = None, - constraint_ref_vec_x: int = None, constraint_ref_vec_y: int = None, constraint_ref_vec_z: int = None, + constraint_ref_vec_x: int = None, constraint_ref_vec_y: int = None, + constraint_ref_vec_z: int = None, constraint_coord_sys: str = None, ref_object: str = None ): # TODO: remove kwargs if possible, if not document as another 2do @@ -607,22 +606,21 @@ def __init__(self, name: str, origin: str = 'Earth', axes: str = 'MJ2000Eq', pri raise AttributeError(f'Specified axes type "{axes}" is not recognized. Please specify one of the ' f'following:\n\t{self.allowed_values["Axes"]}') else: - self.axes: str = axes - if self.axes in list(self.allowed_values['AxesTypeSpecific'].keys()): - axes_specific_values = self.allowed_values['AxesTypeSpecific'][self.axes] + if axes in list(self.allowed_values['AxesTypeSpecific'].keys()): + axes_specific_values = self.allowed_values['AxesTypeSpecific'][axes] # TODO set params/ref objs for all axes types - if self.axes == 'ObjectReferenced': + if axes == 'ObjectReferenced': self.primary = primary self.secondary = secondary self.xaxis = xaxis self.yaxis = yaxis self.zaxis = zaxis - elif self.axes == 'TOE' or self.axes == 'MOE': + elif (axes == 'TOE') or (axes == 'MOE'): self.epoch = epoch - elif self.axes == 'LocalAlignedConstrained': + elif axes == 'LocalAlignedConstrained': self.alignment_vec_x = alignment_vec_x self.alignment_vec_y = alignment_vec_y self.alignment_vec_z = alignment_vec_z @@ -635,7 +633,7 @@ def __init__(self, name: str, origin: str = 'Earth', axes: str = 'MJ2000Eq', pri self.constraint_coord_sys = constraint_coord_sys self.ref_object = ref_object - self.axes = OrbitState.CoordinateSystem.Axes(axes, f'{origin}_{axes}') + self.axes: OrbitState.CoordinateSystem.Axes = OrbitState.CoordinateSystem.Axes(axes, f'{origin}_{axes}') self.SetRefObject(self.axes, gmat.AXIS_SYSTEM, self.axes.name) # gpy.Initialize() @@ -655,7 +653,7 @@ def from_sat(cls, sc: gpy.Spacecraft) -> OrbitState.CoordinateSystem: sc_cs_gmat_obj = sc.gmat_obj.GetRefObject(150, name) origin = sc_cs_gmat_obj.GetField('Origin') axes = sc_cs_gmat_obj.GetField('Axes') - coord_sys = cls(name=name, origin=origin, axes=axes, no_gmat_object=True) + coord_sys: OrbitState.CoordinateSystem = cls(name=name, origin=origin, axes=axes) return coord_sys @property diff --git a/load_gmat.py b/load_gmat.py index 571843a..27173da 100644 --- a/load_gmat.py +++ b/load_gmat.py @@ -9,7 +9,7 @@ from os import path apistartup = "api_startup_file.txt" -GmatInstall = "C:\\Users\\weasd\\Desktop\\GMAT\\gmat-win-R2022a\\GMAT" +GmatInstall = "C:\\Users\\weasd\\OneDrive\\Desktop\\GMAT\\gmat-win-R2025a" GmatBinPath = GmatInstall + "/bin" Startup = GmatBinPath + "/" + apistartup From af2d392ba14fb6110161d03361518a319bf1dbdb Mon Sep 17 00:00:00 2001 From: weasdown <34220924+weasdown@users.noreply.github.com> Date: Fri, 15 Aug 2025 22:26:12 +0100 Subject: [PATCH 3/7] feat: add pyproject.toml --- pyproject.toml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..6f67d03 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,23 @@ +[build-system] +requires = ["hatchling >= 1.26"] +build-backend = "hatchling.build" + +[project] +name = "GMAT-Python-simple" +version = "0.4.1" +authors = [ + { name="William Easdown Babb", email="weasdown99@gmail.com" }, +] +description = "An extra wrapper for the GMAT Python API to simplify setting up mission simulations." +readme = "README.md" +requires-python = ">=3.9" +classifiers = [ + "Programming Language :: Python :: 3", + "Operating System :: OS Independent", +] +license = "MIT" +license-files = ["LICEN[CS]E*"] + +[project.urls] +Homepage = "https://github.com/weasdown/GMAT-Python-simple/" +Issues = "https://github.com/weasdown/GMAT-Python-simple/issues/" \ No newline at end of file From 00d2bf69253b9b214435ed6dc2343a7d320add62 Mon Sep 17 00:00:00 2001 From: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun, 17 Aug 2025 17:07:25 +0100 Subject: [PATCH 4/7] Squashed commit of the following: commit 933c7ba5b0c118877c114661422ccfab18b59d8d Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:44:07 2025 +0100 docs: improve docstring for _gmat_path() commit 56078c4451647c65a594b8eadc6caedac7f6f428 Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:42:48 2025 +0100 style: remove prints commit a2baffd2d70a0752bec35fc4dee23d39f21e4ba3 Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:41:00 2025 +0100 feat: add IDE files commit 613a465fc8390e1cdaf3e7e9b6d3d67193b8cd23 Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:40:12 2025 +0100 fix: fix and tidy imports commit 667c4482aca9c457d772aa3748a538c1491bd8ec Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:36:19 2025 +0100 style: auto-formatting commit ddad61f51a001029f8e18705928f1953614b9fc6 Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:35:42 2025 +0100 fix: fix imports commit f71f1b4cc0842874794aa668868152e0ac912751 Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:33:54 2025 +0100 feat: make gmat library accessible package-wide commit fdd97f117257bc271b9ec0ca459d18c57dd4e1f3 Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:33:26 2025 +0100 feat: import gmat library as variable commit e9e22e2f445e7620b1a759f889700628cd36c6ea Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:22:49 2025 +0100 fix: add missing numpy dependency in pyproject.toml, update package version number commit acfca9225647bf160c1366b9db3caa14a1dc8bbe Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:21:14 2025 +0100 fix: add missing pyproject.toml from branch 9-python-packaging commit 0701d131a5ee6cf195d5edf5d63719b278edde00 Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:18:30 2025 +0100 refactor: rename load_gmat.py outside package to load_gmat_OLD.py, pending removal commit fed65b2137c05b0208d69cbc2cd93bb7bf06cd92 Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:18:06 2025 +0100 style: auto-formatting commit 997aa82d768f7f1ea09be70205310109edd5f9be Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:16:54 2025 +0100 refactor: import gmat from package load_gmat commit bbe162146073688a688ce7f69e4e5ced1c10a195 Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:10:55 2025 +0100 feat: add load_gmat.py inside package commit 1b49b59702f4692794b6f03ec6c051631e559291 Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 11:02:50 2025 +0100 docs: add TODO to remove commented code unrelated to branch issue commit 1269ae7225425397cd81504d02dc62870136c8a6 Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 10:55:15 2025 +0100 docs: add TODO to implement _gmat_path_from_config_file() commit a221d6253fc95491b5281a0763050b7ba08a256a Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 10:45:08 2025 +0100 feat: run import_lib.py at import commit 36565e6a96115ef1b277018f31542cd7ef4b185a Author: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun Aug 17 10:44:37 2025 +0100 feat: add import_lib.py --- .idea/dictionaries/project.xml | 7 ++ .idea/inspectionProfiles/Project_Default.xml | 36 +++++- .../inspectionProfiles/profiles_settings.xml | 3 +- .idea/vcs.xml | 3 - examples/example.py | 2 +- examples/minimum_propagate_using_defaults.py | 3 +- examples/tutorials/Tut01_SimulatingAnOrbit.py | 6 +- .../tutorials/Tut02_SimpleOrbitTransfer.py | 22 ++-- gmat_py_simple/__init__.py | 7 ++ gmat_py_simple/api_funcs.py | 3 +- gmat_py_simple/basics.py | 3 +- gmat_py_simple/burn.py | 2 +- gmat_py_simple/commands.py | 104 +++++++++--------- gmat_py_simple/executive.py | 12 +- gmat_py_simple/hardware.py | 2 +- gmat_py_simple/import_lib.py | 25 +++++ gmat_py_simple/interpreter.py | 4 +- gmat_py_simple/load_gmat.py | 26 +++++ gmat_py_simple/orbit.py | 2 +- gmat_py_simple/parameter.py | 3 +- gmat_py_simple/solver.py | 1 - gmat_py_simple/spacecraft.py | 9 +- gmat_py_simple/utils.py | 2 +- load_gmat.py => load_gmat_OLD.py | 0 pyproject.toml | 4 +- 25 files changed, 193 insertions(+), 98 deletions(-) create mode 100644 .idea/dictionaries/project.xml create mode 100644 gmat_py_simple/import_lib.py create mode 100644 gmat_py_simple/load_gmat.py rename load_gmat.py => load_gmat_OLD.py (100%) diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml new file mode 100644 index 0000000..966c379 --- /dev/null +++ b/.idea/dictionaries/project.xml @@ -0,0 +1,7 @@ + + + + gmatpy + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 8bc1bfb..a8498c3 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1,23 +1,49 @@ - - - \ No newline at end of file diff --git a/examples/example.py b/examples/example.py index e23cd53..65e8621 100644 --- a/examples/example.py +++ b/examples/example.py @@ -3,8 +3,8 @@ from __future__ import annotations import os -from load_gmat import gmat import gmat_py_simple as gpy +from gmat_py_simple import gmat as gmat # Set log and script options log_path = os.path.normpath(f'{os.getcwd()}/GMAT-Log-example.txt') diff --git a/examples/minimum_propagate_using_defaults.py b/examples/minimum_propagate_using_defaults.py index 1cc1866..78ff1bd 100644 --- a/examples/minimum_propagate_using_defaults.py +++ b/examples/minimum_propagate_using_defaults.py @@ -8,7 +8,8 @@ # Set log and script options log_path = os.path.normpath(f'{os.getcwd()}/GMAT-Log.txt') gmat.UseLogFile(log_path) -gmat.GmatGlobal.Instance().SetCommandEchoMode(True) # enables "CurrentCommand: [command generating string]" print out in log +gmat.GmatGlobal.Instance().SetCommandEchoMode( + True) # enables "CurrentCommand: [command generating string]" print out in log gmat.EchoLogFile(False) # set to True to have the log also print to the console as it's written # Shortcuts for later diff --git a/examples/tutorials/Tut01_SimulatingAnOrbit.py b/examples/tutorials/Tut01_SimulatingAnOrbit.py index badb050..c8ac8e8 100644 --- a/examples/tutorials/Tut01_SimulatingAnOrbit.py +++ b/examples/tutorials/Tut01_SimulatingAnOrbit.py @@ -2,10 +2,12 @@ # Written by William Easdown Babb from __future__ import annotations -from load_gmat import gmat -import gmat_py_simple as gpy + import os +import gmat_py_simple as gpy +from gmat_py_simple import gmat + log_path = os.path.normpath(f'{os.getcwd()}/GMAT-Log.txt') gmat.UseLogFile(log_path) echo_log = False diff --git a/examples/tutorials/Tut02_SimpleOrbitTransfer.py b/examples/tutorials/Tut02_SimpleOrbitTransfer.py index 952f6b0..67748ab 100644 --- a/examples/tutorials/Tut02_SimpleOrbitTransfer.py +++ b/examples/tutorials/Tut02_SimpleOrbitTransfer.py @@ -25,17 +25,17 @@ # Targeting sequence to adjust parameters of the two burns (TOI and GOI) to achieve desired final orbit tg1 = gpy.Target('Hohmann Transfer', dc1, exit_mode='SaveAndContinue', command_sequence=[ - # Vary the velocity of the TOI burn to achieve an apoapsis with RMAG = 42165 km - gpy.Vary('Vary TOI', dc1, f'{toi.name}.Element1'), - gpy.Maneuver('Perform TOI', toi, sat), - gpy.Propagate('Prop To Apoapsis', sat, prop, f'{sat.name}.Earth.Apoapsis'), - gpy.Achieve('Achieve RMAG = 42165', dc1, f'{sat.name}.Earth.RMAG', 42164.169, 0.1), - - # Vary the velocity of the GOI burn to achieve an eccentricity of 0.005 - gpy.Vary('Vary GOI', dc1, f'{goi.name}.Element1', max_step=0.2), - gpy.Maneuver('Perform GOI', goi, sat), - gpy.Achieve('Achieve ECC = 0.005', dc1, f'{sat.name}.Earth.ECC', 0.005, 0.0001) - ]) + # Vary the velocity of the TOI burn to achieve an apoapsis with RMAG = 42165 km + gpy.Vary('Vary TOI', dc1, f'{toi.name}.Element1'), + gpy.Maneuver('Perform TOI', toi, sat), + gpy.Propagate('Prop To Apoapsis', sat, prop, f'{sat.name}.Earth.Apoapsis'), + gpy.Achieve('Achieve RMAG = 42165', dc1, f'{sat.name}.Earth.RMAG', 42164.169, 0.1), + + # Vary the velocity of the GOI burn to achieve an eccentricity of 0.005 + gpy.Vary('Vary GOI', dc1, f'{goi.name}.Element1', max_step=0.2), + gpy.Maneuver('Perform GOI', goi, sat), + gpy.Achieve('Achieve ECC = 0.005', dc1, f'{sat.name}.Earth.ECC', 0.005, 0.0001) +]) # Mission Command Sequence mcs = [ diff --git a/gmat_py_simple/__init__.py b/gmat_py_simple/__init__.py index e5f1806..90ba41e 100644 --- a/gmat_py_simple/__init__.py +++ b/gmat_py_simple/__init__.py @@ -1,3 +1,10 @@ +from .import_lib import gmat_path + +from .load_gmat import * + +# GMAT's built-in library that interfaces to GMAT's source code. +gmat: types.ModuleType = load_gmat.gmat + from .api_funcs import * from .basics import * from .burn import * diff --git a/gmat_py_simple/api_funcs.py b/gmat_py_simple/api_funcs.py index 5758f04..2ed1d05 100644 --- a/gmat_py_simple/api_funcs.py +++ b/gmat_py_simple/api_funcs.py @@ -1,11 +1,12 @@ from __future__ import annotations -from load_gmat import gmat +from gmat_py_simple import gmat import gmat_py_simple as gpy import os.path +## TODO remove commented code # def GetObject(name: str) -> gmat.GmatBase: # try: # obj: gmat.GmatBase = gmat.GetObject(name) diff --git a/gmat_py_simple/basics.py b/gmat_py_simple/basics.py index 7a4b839..2c80552 100644 --- a/gmat_py_simple/basics.py +++ b/gmat_py_simple/basics.py @@ -1,7 +1,8 @@ from __future__ import annotations import gmat_py_simple as gpy -from load_gmat import gmat +# from gmat_py_simple import gmat +from gmat_py_simple.load_gmat import gmat from datetime import datetime diff --git a/gmat_py_simple/burn.py b/gmat_py_simple/burn.py index bbbff24..a95f64d 100644 --- a/gmat_py_simple/burn.py +++ b/gmat_py_simple/burn.py @@ -3,7 +3,7 @@ import gmat_py_simple as gpy from gmat_py_simple.basics import GmatObject -from load_gmat import gmat +from gmat_py_simple import gmat class Burn(GmatObject): diff --git a/gmat_py_simple/commands.py b/gmat_py_simple/commands.py index b799e26..7ee65de 100644 --- a/gmat_py_simple/commands.py +++ b/gmat_py_simple/commands.py @@ -1,7 +1,7 @@ from __future__ import annotations from math import pi -from load_gmat import gmat +from gmat_py_simple import gmat import gmat_py_simple as gpy from gmat_py_simple.utils import * @@ -211,54 +211,54 @@ def __init__(self, name: str, solver: gpy.DifferentialCorrector | gmat.Different # # param_type is the final element of the self.variable string, e.g. Periapsis for Sat.Earth.Periapsis # param_eles = self.variable.split('.') # param_type = param_eles[-1] - # new_param = gpy.Parameter(param_type, self.variable) - # for ele in param_eles: - # body = 'Earth' - # cs = 'EarthMJ2000Eq' - # if ele in gpy.CelestialBodies(): # a CelestialBody is given, so need to set it as a ref object - # # TODO: test this - # body = ele - # - # if ele in gpy.CoordSystems(): - # cs = ele - # - # pass - # new_param.SetRefObjectName(gmat.SPACE_POINT, body) - # new_param.SetRefObjectName(gmat.COORDINATE_SYSTEM, cs) - # new_param.Help() - # print(new_param.gmat_base.GetRefObjectTypeArray()) - # new_param.SetRefObjectName(gmat.CELESTIAL_BODY, ele) - - # if ele in gpy.CoordSystems(): # a CoordinateSystem is given, so need to set it as a ref object - # # TODO remove (debugging only) - # test_bddot = gmat.Construct('BdotT', 'TestBdotT') - # test_bddot.SetRefObjectName(gmat.SPACECRAFT, 'MAVEN') - # # test_bddot.SetReference(gmat.GetObject('MAVEN')) - # # print(gpy.Moderator().gmat_obj.GetListOfFactoryItems(gmat.PARAMETER)) - # # test_bddot.RenameRefObject(gmat.COORDINATE_SYSTEM, 'EarthMJ2000Eq', ele) - # test_bddot.SetRefObjectName(gmat.COORDINATE_SYSTEM, ele) - # cs = gmat.GetObject(ele) - # test_bddot.SetRefObject(cs, gmat.COORDINATE_SYSTEM, cs.GetName()) - # - # # test_bddot.SetRefObjectName(gmat.SPACECRAFT, 'MAVEN') - # test_bddot.SetRefObject(gmat.GetObject('MAVEN'), gmat.SPACECRAFT, 'MAVEN') - # - # test_bddot.SetSolarSystem(gmat.GetSolarSystem()) - # # gmat.Initialize() - # mod = gpy.Moderator().gmat_obj - # mod.SetParameterRefObject(test_bddot, 'BdotT', cs.GetName(), '', '', 1) - # test_bddot.Help() - # test_bddot.Initialize() - # - # new_param.SetRefObjectName(gmat.COORDINATE_SYSTEM, ele) - # # new_param.SetStringParameter(new_param.GetParameterID('CoordinateSystem'), ele) - # # new_param.SetRefObject(gmat.GetObject(ele), gmat.COORDINATE_SYSTEM) - # new_param.Help() - # pass - # - # for body in gpy.CelestialBodies(): - # if body in self.variable: - # new_param.SetRefObject(gmat.Planet(body), gmat.COORDINATE_SYSTEM) + # new_param = gpy.Parameter(param_type, self.variable) + # for ele in param_eles: + # body = 'Earth' + # cs = 'EarthMJ2000Eq' + # if ele in gpy.CelestialBodies(): # a CelestialBody is given, so need to set it as a ref object + # # TODO: test this + # body = ele + # + # if ele in gpy.CoordSystems(): + # cs = ele + # + # pass + # new_param.SetRefObjectName(gmat.SPACE_POINT, body) + # new_param.SetRefObjectName(gmat.COORDINATE_SYSTEM, cs) + # new_param.Help() + # print(new_param.gmat_base.GetRefObjectTypeArray()) + # new_param.SetRefObjectName(gmat.CELESTIAL_BODY, ele) + + # if ele in gpy.CoordSystems(): # a CoordinateSystem is given, so need to set it as a ref object + # # TODO remove (debugging only) + # test_bddot = gmat.Construct('BdotT', 'TestBdotT') + # test_bddot.SetRefObjectName(gmat.SPACECRAFT, 'MAVEN') + # # test_bddot.SetReference(gmat.GetObject('MAVEN')) + # # print(gpy.Moderator().gmat_obj.GetListOfFactoryItems(gmat.PARAMETER)) + # # test_bddot.RenameRefObject(gmat.COORDINATE_SYSTEM, 'EarthMJ2000Eq', ele) + # test_bddot.SetRefObjectName(gmat.COORDINATE_SYSTEM, ele) + # cs = gmat.GetObject(ele) + # test_bddot.SetRefObject(cs, gmat.COORDINATE_SYSTEM, cs.GetName()) + # + # # test_bddot.SetRefObjectName(gmat.SPACECRAFT, 'MAVEN') + # test_bddot.SetRefObject(gmat.GetObject('MAVEN'), gmat.SPACECRAFT, 'MAVEN') + # + # test_bddot.SetSolarSystem(gmat.GetSolarSystem()) + # # gmat.Initialize() + # mod = gpy.Moderator().gmat_obj + # mod.SetParameterRefObject(test_bddot, 'BdotT', cs.GetName(), '', '', 1) + # test_bddot.Help() + # test_bddot.Initialize() + # + # new_param.SetRefObjectName(gmat.COORDINATE_SYSTEM, ele) + # # new_param.SetStringParameter(new_param.GetParameterID('CoordinateSystem'), ele) + # # new_param.SetRefObject(gmat.GetObject(ele), gmat.COORDINATE_SYSTEM) + # new_param.Help() + # pass + # + # for body in gpy.CelestialBodies(): + # if body in self.variable: + # new_param.SetRefObject(gmat.Planet(body), gmat.COORDINATE_SYSTEM) self.value = value self.SetStringParameter('GoalValue', str(self.value)) @@ -280,7 +280,8 @@ def SetRefObject(self, obj, type_int: int, obj_name: str = '') -> bool: class BeginFiniteBurn(GmatCommand): - def __init__(self, burn: gpy.FiniteBurn | gmat.FiniteBurn, spacecraft: gpy.Spacecraft | gmat.Spacecraft, name: str = ''): + def __init__(self, burn: gpy.FiniteBurn | gmat.FiniteBurn, spacecraft: gpy.Spacecraft | gmat.Spacecraft, + name: str = ''): super().__init__('BeginFiniteBurn', name) # Assign the user-provided FiniteBurn to this command @@ -293,7 +294,8 @@ def __init__(self, burn: gpy.FiniteBurn | gmat.FiniteBurn, spacecraft: gpy.Space # self.spacecraft.Help() # print(type(self.spacecraft)) # self.burn.SetSpacecraftToManeuver(gpy.extract_gmat_obj(self.spacecraft)) # update FiniteBurn's associated Spacecraft - gpy.FiniteBurn.SetSpacecraftToManeuver(self.burn, gpy.extract_gmat_obj(self.spacecraft)) # update FiniteBurn's associated Spacecraft + gpy.FiniteBurn.SetSpacecraftToManeuver(self.burn, gpy.extract_gmat_obj( + self.spacecraft)) # update FiniteBurn's associated Spacecraft self.Initialize() diff --git a/gmat_py_simple/executive.py b/gmat_py_simple/executive.py index 5d27e34..b144361 100644 --- a/gmat_py_simple/executive.py +++ b/gmat_py_simple/executive.py @@ -1,13 +1,10 @@ from __future__ import annotations import gmat_py_simple as gpy -from load_gmat import gmat -from gmat_py_simple import GmatCommand +from gmat_py_simple import gmat -import sys - -def RunMission(mcs: list[GmatCommand]) -> int: +def RunMission(mcs: list[gpy.GmatCommand]) -> int: # Shortcut for running missions return gpy.Moderator().RunMission(mcs) @@ -199,13 +196,13 @@ def GetFirstCommand(self): def Initialize(self): self.gmat_obj.Initialize() - def InsertCommand(self, command_to_insert: GmatCommand, preceding_command: GmatCommand): + def InsertCommand(self, command_to_insert: gpy.GmatCommand, preceding_command: gpy.GmatCommand): return self.gmat_obj.InsertCommand(command_to_insert, preceding_command) def RemoveObject(self, obj_type: int, name: str, del_only_if_not_used: bool = True) -> bool: return self.gmat_obj.RemoveObject(obj_type, name, del_only_if_not_used) - def RunMission(self, mission_command_sequence: list[GmatCommand]) -> int: + def RunMission(self, mission_command_sequence: list[gpy.GmatCommand]) -> int: """ Run the mission command sequence @@ -214,6 +211,7 @@ def RunMission(self, mission_command_sequence: list[GmatCommand]) -> int: :param mission_command_sequence: :return: """ + def update_command_objs_post_run(command_sequence: list[gpy.GmatCommand | gmat.GmatCommand]): propagate_commands: list[gpy.Propagate] = [] # start a list of Propagates so their sats can be updated target_commands: list[gpy.Target] = [] # start a list of Targets for checking convergence diff --git a/gmat_py_simple/hardware.py b/gmat_py_simple/hardware.py index f431f99..e3bfc73 100644 --- a/gmat_py_simple/hardware.py +++ b/gmat_py_simple/hardware.py @@ -5,7 +5,7 @@ import numpy as np -from load_gmat import gmat +from gmat_py_simple import gmat import gmat_py_simple as gpy from gmat_py_simple import GmatObject diff --git a/gmat_py_simple/import_lib.py b/gmat_py_simple/import_lib.py new file mode 100644 index 0000000..6df288c --- /dev/null +++ b/gmat_py_simple/import_lib.py @@ -0,0 +1,25 @@ +import os + + +def _gmat_path(from_env: bool = True) -> str: + """Import GMAT's built-in gmat library.""" + return _gmat_path_from_env() if from_env else _gmat_path_from_config_file() + + +def _gmat_path_from_env() -> str: + """Gets the path to the GMAT directory from the "GMAT" environment variable.""" + try: + gmat_env: str = os.environ['GMAT'] + except KeyError: + raise ValueError('"GMAT" environment variable not set.') + + return gmat_env + + +def _gmat_path_from_config_file() -> str: + """Gets the path to the GMAT directory from a configuration file.""" + # TODO implement _gmat_path_from_config_file() + raise NotImplementedError + + +gmat_path: str = _gmat_path() diff --git a/gmat_py_simple/interpreter.py b/gmat_py_simple/interpreter.py index 82f67c4..f38b38c 100644 --- a/gmat_py_simple/interpreter.py +++ b/gmat_py_simple/interpreter.py @@ -1,7 +1,8 @@ from __future__ import annotations import gmat_py_simple as gpy -from load_gmat import gmat + +from gmat_py_simple import gmat class Validator: @@ -31,4 +32,3 @@ def SetSolarSystem(self, ss: gmat.SolarSystem = gmat.GetSolarSystem()) -> bool: def ValidateCommand(self, command: gpy.GmatCommand | gmat.GmatCommand): return gpy.extract_gmat_obj(self).ValidateCommand(gpy.extract_gmat_obj(command)) - diff --git a/gmat_py_simple/load_gmat.py b/gmat_py_simple/load_gmat.py new file mode 100644 index 0000000..a028ec4 --- /dev/null +++ b/gmat_py_simple/load_gmat.py @@ -0,0 +1,26 @@ +import errno +import os +import sys +import types + +from gmat_py_simple.import_lib import gmat_path + +api_startup = "api_startup_file.txt" +gmat_bin_path = gmat_path + "/bin" +startup = gmat_bin_path + "/" + api_startup + +if os.path.exists(startup): + print(f'Running GMAT in {gmat_path}') + + sys.path.insert(1, gmat_bin_path) + + gmat: types.ModuleType = __import__('gmatpy') + + gmat.Setup(startup) + +else: + message: str = ("Please set up a GMAT startup file named " + api_startup + + " in the " + gmat_bin_path + " folder.") + + raise FileNotFoundError( + errno.ENOENT, message, startup) diff --git a/gmat_py_simple/orbit.py b/gmat_py_simple/orbit.py index fd56e94..0158a9d 100644 --- a/gmat_py_simple/orbit.py +++ b/gmat_py_simple/orbit.py @@ -1,6 +1,6 @@ from __future__ import annotations -from load_gmat import gmat +from gmat_py_simple import gmat from gmat_py_simple.basics import GmatObject from gmat_py_simple.utils import * diff --git a/gmat_py_simple/parameter.py b/gmat_py_simple/parameter.py index 701026d..69fa16c 100644 --- a/gmat_py_simple/parameter.py +++ b/gmat_py_simple/parameter.py @@ -1,7 +1,8 @@ from __future__ import annotations import gmat_py_simple as gpy -from load_gmat import gmat + +from gmat_py_simple import gmat # def CreateParameter(param_type: str, name: str) -> Parameter: diff --git a/gmat_py_simple/solver.py b/gmat_py_simple/solver.py index bf74718..9028f08 100644 --- a/gmat_py_simple/solver.py +++ b/gmat_py_simple/solver.py @@ -1,6 +1,5 @@ from __future__ import annotations -from load_gmat import gmat import gmat_py_simple as gpy diff --git a/gmat_py_simple/spacecraft.py b/gmat_py_simple/spacecraft.py index 9fc20d8..08cf3ca 100644 --- a/gmat_py_simple/spacecraft.py +++ b/gmat_py_simple/spacecraft.py @@ -1,7 +1,7 @@ from __future__ import annotations import gmat_py_simple as gpy -from load_gmat import gmat +from gmat_py_simple import gmat from gmat_py_simple.basics import GmatObject from gmat_py_simple.orbit import OrbitState @@ -585,7 +585,8 @@ def from_dict(cls, ep_tank_dict: dict) -> gpy.ElectricTank | None: class Thruster(GmatObject): def __init__(self, fuel_type: str, name: str, tanks: str | gpy.Tank | gmat.Tank | list[gpy.Tank] | - list[gmat.FuelTank], mix_ratio: int | float | list[int | float] = None): + list[gmat.FuelTank], + mix_ratio: int | float | list[int | float] = None): self.fuel_type = fuel_type self.thruster_type = f'{self.fuel_type}Thruster' # 'ChemicalThruster' or 'ElectricThruster' super().__init__(self.thruster_type, name) @@ -673,7 +674,7 @@ def decrement_mass(self, true_false: bool): class ChemicalThruster(Thruster): def __init__(self, name: str, tanks: str | gpy.ChemicalTank | gmat.ChemicalTank | - list[gpy.ChemicalTank] | list[gmat.ChemicalTank]): + list[gpy.ChemicalTank] | list[gmat.ChemicalTank]): super().__init__('Chemical', name, tanks) self.Validate() @@ -691,7 +692,7 @@ def from_dict(cls, cp_thr_dict: dict) -> gpy.ChemicalThruster | None: class ElectricThruster(Thruster): def __init__(self, name: str, tanks: str | gpy.ElectricTank | gmat.ElectricTank | - list[gpy.ElectricTank] | list[gmat.ElectricTank]): + list[gpy.ElectricTank] | list[gmat.ElectricTank]): super().__init__('Electric', name, tanks) self.Initialize() diff --git a/gmat_py_simple/utils.py b/gmat_py_simple/utils.py index a892150..ef5ff59 100644 --- a/gmat_py_simple/utils.py +++ b/gmat_py_simple/utils.py @@ -1,7 +1,7 @@ from __future__ import annotations import gmat_py_simple as gpy -from load_gmat import gmat +from gmat_py_simple import gmat import sys from io import StringIO diff --git a/load_gmat.py b/load_gmat_OLD.py similarity index 100% rename from load_gmat.py rename to load_gmat_OLD.py diff --git a/pyproject.toml b/pyproject.toml index 6f67d03..bdb832e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [build-system] -requires = ["hatchling >= 1.26"] +requires = ["hatchling >= 1.26", "numpy >= 2.0.0"] build-backend = "hatchling.build" [project] name = "GMAT-Python-simple" -version = "0.4.1" +version = "0.4.3" authors = [ { name="William Easdown Babb", email="weasdown99@gmail.com" }, ] From 565694a71368c59ab93af284a252fa8e5f981ffc Mon Sep 17 00:00:00 2001 From: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun, 17 Aug 2025 17:12:05 +0100 Subject: [PATCH 5/7] Set GMAT path (#18) * feat: add import_lib.py * feat: run import_lib.py at import * docs: add TODO to implement _gmat_path_from_config_file() * docs: add TODO to remove commented code unrelated to branch issue * feat: add load_gmat.py inside package * refactor: import gmat from package load_gmat * style: auto-formatting * refactor: rename load_gmat.py outside package to load_gmat_OLD.py, pending removal * fix: add missing pyproject.toml from branch 9-python-packaging * fix: add missing numpy dependency in pyproject.toml, update package version number * feat: import gmat library as variable * feat: make gmat library accessible package-wide * fix: fix imports * style: auto-formatting * fix: fix and tidy imports * feat: add IDE files * style: remove prints * docs: improve docstring for _gmat_path() --- .idea/inspectionProfiles/Project_Default.xml | 27 ++++++-------------- .idea/vcs.xml | 3 +++ 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index a8498c3..26d0ee5 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1,17 +1,6 @@ - - - - - - - - + + + + + + + \ No newline at end of file From 714beddefda9100d13ea0ce8355ac37261562c4e Mon Sep 17 00:00:00 2001 From: weasdown <34220924+weasdown@users.noreply.github.com> Date: Sun, 17 Aug 2025 17:15:58 +0100 Subject: [PATCH 6/7] chore: updates to .idea files --- .idea/GMAT-Python-simple.iml | 3 --- .idea/inspectionProfiles/profiles_settings.xml | 1 - 2 files changed, 4 deletions(-) diff --git a/.idea/GMAT-Python-simple.iml b/.idea/GMAT-Python-simple.iml index aad402c..ec63674 100644 --- a/.idea/GMAT-Python-simple.iml +++ b/.idea/GMAT-Python-simple.iml @@ -4,7 +4,4 @@