Known limitations¶
The list below captures behaviour that surprises users often enough to warrant
a heads-up. Most items are intentional — they fall out of the underlying
gmatpy runtime or the GMAT script semantics — and gmat-run does not try to
paper over them.
gmatpy single-init constraint¶
gmatpy cannot be cleanly reinitialised once it has been loaded into a Python
interpreter. gmat_run.bootstrap (and therefore
Mission.load) caches the loaded module and the
GmatInstall it was bound to; a second call requesting
a different install raises GmatLoadError. Calling
again with the same install is a no-op and returns the cached module.
Practical implications:
- A single Python process is bound to one GMAT install for its lifetime. If you need to compare missions across GMAT releases, run them in separate processes (subprocess, pytest workers, multiprocessing).
gmat-runintegration tests that touch the runtime cannot forkxdistworkers within the same process; spawn them.
Supported Python versions¶
gmatpy ships per-Python-minor shared libraries inside the GMAT install's
bin/gmatpy/ directory. If your interpreter's minor version does not match
one of the prebuilt wheels in the install, bootstrap
raises GmatLoadError at import time.
R2026a ships builds for Python 3.10, 3.11, and 3.12. Older Python interpreters
or 3.13+ are not supported by the bundled gmatpy and cannot be made to work
without rebuilding GMAT from source.
Output paths must be set via Filename, not OUTPUT_PATH¶
FileManager.OUTPUT_PATH and GmatGlobal.SetOutputPath look like the right
knobs for redirecting ReportFile / EphemerisFile / ContactLocator
output, but they only take effect at parse time. Once
Mission.load has parsed a script, every subscriber
has its absolute output path resolved and cached internally; later changes to
the global OUTPUT_PATH are ignored at write time.
Mission.run handles this for you by rewriting each
subscriber's Filename field to an absolute path inside the run workspace.
If you bypass Mission.run and drive
gmat.RunScript() yourself, you need to do the same rewrite — set
<Subscriber>.Filename to an absolute path before calling RunScript.
GMAT R2026a does not write CCSDS-AEM¶
GMAT's EphemerisFile writer supports CCSDS-OEM, SPK, Code-500, and
STK-TimePosVel only — there is no FileFormat = CCSDS-AEM. Attitude history
in GMAT is a reader-side concept: a Spacecraft resource consumes an
external AEM file via its AttitudeFileName field. gmat-run surfaces those
input files via Mission.attitude_inputs
and parses them with gmat_run.parsers.aem_ephemeris.parse,
but you cannot ask GMAT to emit an AEM trace of a propagated spacecraft.
Parser format restrictions¶
The parsers in gmat_run.parsers cover the formats
GMAT actually emits in v0.2; uncommon variants are rejected with
GmatOutputParseError rather than silently
guessed at.
- CCSDS-OEM ephemeris: covariance blocks (
COVARIANCE_START…COVARIANCE_STOP) are skipped; acceleration columns past the mandatory six state components are rejected. - STK-TimePosVel ephemeris: the
EphemerisTimePosVelAcc(with acceleration) andEphemerisTimePos(position-only) data-section variants are rejected. - CCSDS-AEM attitude: only
QUATERNIONandEULER_ANGLEsegment types parse. Rate/derivative/spin variants (QUATERNION/DERIVATIVE,QUATERNION/RATE,EULER_ANGLE/RATE,SPIN,SPIN/NUTATION) are rejected, and multi-segment files mixing differentATTITUDE_TYPEvalues are rejected (the column shapes are not concatenable). - SPK ephemeris: the parser assumes one spacecraft per file (which matches GMAT's writer behaviour). Multi-target SPKs are rejected.
- Code-500 binary ephemeris: not implemented. GMAT does not run any of its stock R2026a sample missions through this format, and no public tooling decodes it; out of scope unless a user need surfaces.
Epoch promotion is not a time-scale conversion¶
gmat_run.parsers.epoch.promote_epochs
turns the ten {scale}{format} GMAT epoch columns into
datetime64[ns] with the time scale recorded on df.attrs["epoch_scales"].
It does not apply leap-second-correct conversion between scales: a
TAIModJulian column becomes a datetime64[ns] representing the TAI instant,
labelled "TAI". Aligning across scales (UTC ↔ TAI ↔ TT ↔ TDB) is deferred
to a future astropy-extra release.