Repository navigation
Conversation
ea24a8d to
a1ea23f
Compare
|
@ReeceHumphreys @suhaslord, I Started working on a comparison, if you want to take a look. It is leading to several changes though, it could be better to split them in several PRs, what do you think @schaubh ? On another note, It would be great if someone with experience on GMAT and Orekit could review their setups. Leaving this in draft as it could still change significantly and probably isn't at the top of the priorities. |
dc6ce4d to
7208276
Compare
schaubh
left a comment
There was a problem hiding this comment.
Requesting changes to address the four inline findings below: consistent epochs for midpoint extrapolation, aligned inertial frames in the comparison, complete rate-mismatch detection, and reference-file provenance. Reviewed commit 7208276.
| for(long unsigned int c = 0; c<this->scStateInMsgs.size(); c++){ | ||
| bool tmpScRead; | ||
| scMsg = this->scStateInMsgs.at(c)(); | ||
| scMsg = this->scStateExtrapolation.apply(c, |
There was a problem hiding this comment.
[P2] Midpoint extrapolation mixes spacecraft and planet epochs
The new code advances the spacecraft to the interval midpoint, then updateRelativePos() subtracts the planet's unadjusted position. This is incorrect when the planet translates in the simulation frame. I reproduced it with a spacecraft and planet moving together at 30 km/s: a 10-second interval introduced a 150 km altitude error despite constant physical separation. Planet orientation and time-dependent environment inputs also remain at the current epoch.
Please evaluate the relevant inputs at one consistent epoch, or explicitly restrict the supported configuration, and add a regression test with a translating planet. The same timing assumption should be checked in the other environment modules adopting this helper.
| outDir.mkdir(parents=True, exist_ok=True) | ||
| mu = spec["mu_m3_s2"] # [m^3/s^2] | ||
| ae = spec["equatorial_radius_m"] # [m] | ||
| eme2000 = FramesFactory.getEME2000() |
There was a problem hiding this comment.
[P2] The comparison does not align the inertial frames
Orekit initializes and exports states in EME2000. Basilisk uses SPICE's default J2000, which, for the selected DE430 and high-precision Earth kernels, means ICRF axes. The scripts assign identical numerical initial coordinates and subtract outputs without accounting for the rotation between these frames. That matters when interpreting meter-level differences.
This conclusion follows from the code and the documented frame definitions; I have not measured its contribution to each published result. Please use a consistent frame for initial conditions, environment data, attitudes, and output across the tools, then regenerate the affected comparisons.
References: NAIF's ICRF versus J2000 explanation and Orekit 13.1's EME2000 frame-bias implementation.
| this->rewritten[index] = true; | ||
| this->lastWriteNanos[index] = timeWrittenNanos; | ||
| } | ||
| if (this->rewritten[index] && timeWrittenNanos < previousUpdateNanos && !this->warned) { |
There was a problem hiding this comment.
[P2] The rate-mismatch warning misses a common mismatch
This condition only detects messages older than the previous environment update. When the spacecraft runs faster than the environment, its message is newer, so the warning never fires. I reproduced this with spacecraft updates every second and environment updates every ten seconds: at environment times 10, 20, and 30 s, spacecraft messages written at 9, 19, and 29 s are extrapolated without a warning.
The option therefore continues extrapolating silently outside its documented scheduling assumptions. Please add coverage for both directions of rate mismatch and either disable unsupported extrapolation or report it reliably.
| raise ValueError(f"{where} has {len(reference)} samples but Basilisk produced {len(bsk)}. Regenerate it with " | ||
| f"generate_{tool}_reference.py using the same cases.json, or use a shorter --duration-days.") | ||
| reference = reference[:len(bsk)] | ||
| timeError = np.abs(reference[:, 0] - bsk[:, 0]).max() # [s] |
There was a problem hiding this comment.
[P2] Reference files cannot establish which experiment they represent
The validation checks shape, length, and elapsed sample times, but the reference CSVs carry no epoch, configuration hash, frame, tool version, or data provenance. For example, generating Orekit references with --oblate-shadow overwrites the same filenames, and a later default comparison accepts them without identifying the changed physics. Changing an epoch in cases.json is similarly undetectable because elapsed sample times still match.
Please add a reference manifest that records the effective case configuration, generator options, frame, tool versions, and external-data identifiers/checksums, and validate it before running Basilisk. Intentional alternative configurations should be identified explicitly in the results rather than silently appearing as the default reference.
| unextrapolated on successive steps, and the module input jumps by about ``v * dt / 2``. A spacecraft with a | ||
| variable step, such as a variable-step integrator or a changing task period, has the same problem, because the | ||
| message age no longer matches the interval the spacecraft integrates. A warning is logged once if a different |
There was a problem hiding this comment.
[P2] Distinguish task periods from adaptive integrator substeps
This warning conflates task periods with adaptive integrator substeps. It says variable-step integrators invalidate extrapolation, yet the comparison itself uses adaptive RKF78. Internal adaptive substeps still cover the requested spacecraft update interval.
Please explain the scheduling requirement precisely and record Basilisk's integration tolerances in the accuracy-comparison documentation.
schaubh
left a comment
There was a problem hiding this comment.
Posted some feedback. Thanks for taking a stab at this.
I would not include the "Run Time" section of the benchmark comparison as it really is not apples-to-apples comparison. The tools have different features as you point out. If BSK has a 1Hz task rate, we force updates every 1s even if larger steps would be possible from an orbital mechanics point of view.
I would add a note at the top that these comparison are meant as a rough comparison. These are not auto-generated, so this page will become out of date with new releases of all tools!
You try hard to compare with MSIS drag included. There are a lot of factors here how this model is setup. Are you sure this is apples-and-apples at this point? Would it make more sense to just include a basic exponential density model to avoid these issues?
…ation extrapolation, environment-module step lag and MSIS altitude/solar time; add docs
…ation on solar time doc
…d flag for nrlmsise
…hereBase and inertial frame alignment
7208276 to
24c9d8c
Compare
|
Thank you! Yes, you are right. It would be great to compare everything, but it is better to start with the basics. I changed to exponential density and worked on your comments. I'll push a few changes in a bit |
…hereBase and inertial frame alignment
24c9d8c to
e3fd30a
Compare
… wind step extrapolation in comparison
… warning, add boundary tests
… equation of time before 1970
Description
Adds the documentation page requested in #1456,
Support/User/accuracyComparison.rst, which compares Basilisk orbit propagation with GMAT and Orekit, together with the scripts and a guide to reproduce it. Seventeen cases add the perturbations one at a time (two-body, zonal and tesseral gravity up to degree and order 70, Sun and Moon, SRP, drag), so a disagreement can be traced to a single effect. They cover LEO, sun-synchronous, Molniya, GTO and GEO orbits, and faceted drag and SRP of a box spacecraft with a fixed and with a spinning attitude (compared with Orekit). All tools propagate in the ICRF axes (GCRFin Orekit,EarthICRFin GMAT,J2000of the DE430 kernels in Basilisk), and the drag cases use a single-scale exponential atmosphere, which all three tools can model identically.The comparison exposed a few Basilisk behaviours that are touched by this PR:
Planet orientation in
gravityEffector(gravityEffector.cpp): the orientation of a SPICE-driven planet was advanced withDCM + DCM_dot * dt, which is not a rotation. It scales the evaluated field by a relative error of order (omega dt)^2 and distorts even a point-mass field. It is now advanced as a rotation about the planet angular velocity, with the newplanetSpin()andadvanceDcm()ofstateExtrapolation.h, which are shared with the environment modules.gravityEffectorderives the planet angular velocity once per planet message (planetSpin(), cached inGravBodyData) and only applies the rotation (advanceDcm()) at each integrator stage.advanceDcmDot()advancesJ20002Pfix_dotconsistently with the advanced orientation, both inextrapolatePlanetStateToEpoch()(so the angular velocity reconstructed byWindBasefrom the extrapolated planet state is unchanged) and ingravityEffector, which now stores the advancedJ20002PfixandJ20002Pfix_dotof the same epoch. These two state properties are stored as[PN]and[PN_dot], as documented ingravityEffector.h; they were the transposed[NP]after the first update, while their initial value was[PN].One-step lag of the environment modules (new
architecture/utilities/stateExtrapolation.h;AtmosphereBase,WindBase,MagneticFieldBase,Eclipse,SolarFlux): these modules run before the spacecraft, so they read its state from the previous step. They can now use the position extrapolated to the middle of the interval the next spacecraft update integrates. The extrapolation is off by default and is enabled withsetExtrapolateScStateToStepMidpoint(True).applyPlanet(),extrapolatePlanetStateToEpoch()), so a translating planet does not bias the relative position. This matters for the Sun inSolarFluxand for planet-fixed frames inAtmosphereBase.ScStateExtrapolation::prepare()(with a reusable write-time buffer,writeTimesBuffer()) makes one decision per module update for all spacecraft and the shared planets: if there is no spacecraft, or any spacecraft message was not written at the previous module update (stale, or a spacecraft that runs slower or faster than the module, as seen from its write interval), nothing is extrapolated and a warning is logged once (mismatchDetected()). This keeps every spacecraft and the planets at one epoch. A task period mismatch is not always detectable from the write times: a message written at the current module update (for example by a faster spacecraft that runs before the module) is used as written and gives no warning, but a message that is not the output of the previous module update is never extrapolated.WindBasereads and extrapolates the planet state only when both the spacecraft and the planet messages were written.MSIS altitude and solar time (
AtmosphereBase,MsisAtmosphere), both opt-in so existing results are unchanged:setPlanetPolarRadius()gives the geodetic altitude (also used byExponentialAtmospherein the comparison);setUseApparentSolarTime()adds the equation of time to the local solar time (epochs before 1970 raise aBSK_ERROR).Time zone dependence of the environment modules (new
architecture/utilities/utcTime.h;AtmosphereBase,MsisAtmosphere,WindBase,MagneticFieldBase,MagneticFieldWMM): the UTC epoch was normalized withmktime, which uses the time zone of the computer. On a computer in a time zone with daylight saving time, the local solar time ofMsisAtmospherewas one hour wrong once a simulation crossed a transition. The epoch is now normalized as UTC withtimegm(_mkgmtimeon Windows). Simulations that did not cross a transition are unchanged.Solar flux of
FacetSRPDynamicEffector(facetSRPDynamicEffector.cpp): the module used1368 W/m^2at 1 AU whileRadiationPressureusesSOLAR_FLUX_EARTH(1361 W/m^2). Both now useSOLAR_FLUX_EARTH(1361 W/m^2), and the module takes the astronomical unit and the speed of light fromastroConstants.h(AU2M,SPEED_LIGHT) instead of local constants. The two Python tests that recompute the force use the same values.MSIS 3-hour Ap history (
MsisAtmosphere), opt-in so existing results are unchanged:setUseApHistory()sets switch 9 of NRLMSISE-00 to -1, so the model uses the 3-hour Ap array that the module already builds from messages 1 to 20 instead of the daily Ap of message 0. The default is the daily Ap, as before.PCPF2LLA()at a pole: the altitude was wrong for a position exactly at a pole of an oblate planet, where the equatorial component is zero.test_radiationPressureIntegratedTestfailed after the gravity-orientation fix because its stored truth contained the old orientation error. The truth is replaced with an independent scipy integration.Notes for reviewers:
MsisAtmospherewith their own unit tests.compare_with_basilisk.pycompares the altitude and density that each tool computes at nine Earth-fixed probe points (density_probeincases.json, files<tool>_density_probe.csvwritten by the generators, with a manifest entry) against Basilisk, and stops if the altitude definition or the density differ beyond the tolerances there.compare_with_basilisk.pyvalidates it before running Basilisk and rejects a stale or mismatched reference with a message naming the field.benchmarks/and is not an automated test. The rotating-Earth cases use the high-precisionearth_000101_260711_260415.bpcandearth_assoc_itrf93.tfkernels, which are not in the support-data registry or this repository; the script looks for them with--kernel-dir, inbenchmarks/accuracyComparison/data/spice, or in the support-data cache.--oblate-shadowand--max-stepselect the Orekit default (such references get a variant label and are rejected by a default comparison unless--orekit-variantis given).Verification
utcTime, polar radius, MSIS apparent solar time and Ap history.benchmarks/tests/test_accuracy_comparison_manifest.py), and two-spacecraft tests of the all-or-nothing extrapolation (C++ and Python), and tests of messages written at the module update by a faster or slower spacecraft (C++ and Python).compare_with_basilisk.pyenables the step extrapolation on the atmosphere, the wind and the eclipse modules.astroConstants.h.Documentation
Support/User/accuracyComparison.rst(linked fromSupport/User.rstand the validation bullet inindex.rst) with static tables, SVG figures, and a "Reproducing the Results" guide.gravityEffector,atmosphereBase,windBase,magneticFieldBase,eclipse,solarFlux,msisAtmosphere,facetSRPDynamicEffector.bskKnownIssues.rstentries.Future work
stateExtrapolation.h. Option 2: handle a spacecraft period that differs from the module period instead of disabling the extrapolation.ScStateExtrapolationalready observes the spacecraft period from the message write times, so the position could be extrapolated to the middle of the next spacecraft integration interval.planetRadiationBase/albedo/earth radiation,dentonFluxModel, charging).compare_with_basilisk.py(only the manifest and probe validation are tested now).