Nyx stuff fully validated and benched at current state

This commit is contained in:
connor committed 2026-10-03 10:30:16 -04:00
1 parent d268fc0cf5
commit 63b62c62f5
12 files changed
+744 -1618

No files matched your search

+1
View File
@@ -0,0 +1 @@
{"name":"gravity-20-low-earth","setup":{"tool":"nyx-space","version":"2.6.0","generated":"2026-10-02","forces":["GravityField(EGM96 20x20 from GMAT's EGM96.cof, ae = 6378136.3 m, mu = 3.986004415e14 m^3/s^2 from the file header)"],"integrator":"RK89, IntegratorOptions tolerance 1e-14, error control RSSCartesianStep, max step 2700 s","notes":["Both sides read the same GMAT EGM96.cof. nyx parses that format directly, so unlike the Orekit fixture the file needs no conversion and the coefficients cannot differ.","The reference radius and mu are the file header's, which are EGM96's and are what astrokit uses.","Body-fixed frame is EARTH_ITRF93 from the same binary PCK astrokit reads, so the two rotations are the same rather than two realizations within a few milliarcseconds of each other.","No third body, no atmosphere, no radiation pressure.","States are nyx's own accepted integrator steps rather than a fixed grid, so nothing on this side is interpolated. nyx's trajectory interpolation is a five-point Hermite fitted after the fact over stored states, and it is the accuracy floor rather than the integration: on the point-mass arc at this tolerance the stored states agree with Kepler to 2.7e-6 m while reading the same trajectory on a 60 s grid is 8.1e-4 m. Sampling the steps themselves removes that term from the comparison."]},"epoch":"2026-01-01T00:00:00 UTC","frame":"EARTH_J2000","states":[{"elapsed":0.0,"position":[6978000.0,0.0,0.0],"velocity":[0.0,7560.0,0.0]},{"elapsed":40.61810235,"position":[6971239.117736948,306973.70914496365,-0.05340211722725188],"velocity":[-332.84636505705595,7552.676939833156,-0.00256547810116681]},{"elapsed":80.834157086,"position":[6951236.254402601,610324.8781350926,-0.20165855225962145],"velocity":[-661.7666107052723,7531.0074697555465,-0.004753934094608168]},{"elapsed":120.950256694,"position":[6918127.499221808,911767.5624926321,-0.43123167615894215],"velocity":[-988.6208032691583,7495.138900725695,-0.006649418537202926]},{"elapsed":161.244695813,"position":[6871707.559323407,1212814.6241522867,-0.7338060101586885],"velocity":[-1315.0509698615228,7444.848543959113,-0.00834062240640299]},{"elapsed":201.219749724,"position":[6812705.671661383,1509191.5630434966,-1.0986733888492755],"velocity":[-1636.4238117156863,7380.92597811556,-0.009904720526189357]},{"elapsed":241.182802791,"position":[6740939.57928741,1802648.168155374,-1.5256812439448755],"velocity":[-1954.638219348878,7303.173065698603,-0.0114789746739144]},{"elapsed":281.238306095,"position":[6656317.94785862,2093389.9150299085,-2.019494701726561],"velocity":[-2269.918536957791,7211.489906951334,-0.013217933464402015]},{"elapsed":321.443631881,"position":[6558764.32862836,2381250.9904066287,-2.5912242133643177],"velocity":[-2582.086364075429,7105.792484751187,-0.015290945178646187]},{"elapsed":361.795616315,"position":[6448332.420544097,2665615.0186123797,-3.258162320218481],"velocity":[-2890.47445096546,6986.137629085682,-0.017857515488654753]},{"elapsed":402.055430729,"position":[6325860.067224422,2944248.5129371453,-4.038576875957033],"velocity":[-3192.661382167393,6853.4318116463,-0.02101723343857388]},{"elapsed":441.92946545,"position":[6192687.283371599,3214687.5924752355,-4.949550026605997],"velocity":[-3485.9752324088904,6709.125875768756,-0.024779567917347513]},{"elapsed":481.838521859,"position":[6047814.5158749,3479351.120959822,-6.023604104036465],"velocity":[-3773.0396114856694,6552.135723994092,-0.02913648333467788]},{"elapsed":521.584293893,"position":[5892285.843218307,3736461.1701565254,-7.2759606362932665],"velocity":[-4051.9263654174792,6383.591901397843,-0.03394726830731179]},{"elapsed":561.68334886,"position":[5724292.327785463,3988826.759645544,-8.739907777231283],"velocity":[-4325.68296815009,6201.533226520624,-0.03910359504231091]},{"elapsed":601.998208649,"position":[5544492.326275292,4234952.022905519,-10.422971261840626],"velocity":[-4592.687674037552,6006.672172715286,-0.04439322305670525]},{"elapsed":642.046005406,"position":[5355398.164774825,4471439.471217541,-12.304909584287875],"velocity":[-4849.25538965758,5801.730536017772,-0.049563244108144285]},{"elapsed":682.219521475,"position":[5155569.342562895,4700201.115849802,-14.396440454620006],"velocity":[-5097.461031348987,5585.145958916335,-0.05451161358577279]},{"elapsed":722.441306246,"position":[4945703.9921865435,4920305.918745523,-16.682974124582657],"velocity":[-5336.295133355913,5357.6737088825275,-0.05912053200650696]},{"elapsed":762.620348472,"position":[4726672.391695108,5130835.853920805,-19.144071200741656],"velocity":[-5564.7619854758905,5120.255592687359,-0.06331359492314977]},{"elapsed":802.713882147,"position":[4499166.029424761,5331212.761525107,-21.758933300393416],"velocity":[-5782.234316836099,4873.639637853513,-0.06704634429573386]},{"elapsed":842.874306511,"position":[4262757.176249864,5521824Line truncated
+1
View File
@@ -0,0 +1 @@
{"name":"gravity-8-low-earth","setup":{"tool":"nyx-space","version":"2.6.0","generated":"2026-10-02","forces":["GravityField(EGM96 8x8 from GMAT's EGM96.cof, ae = 6378136.3 m, mu = 3.986004415e14 m^3/s^2 from the file header)"],"integrator":"RK89, IntegratorOptions tolerance 1e-14, error control RSSCartesianStep, max step 2700 s","notes":["Both sides read the same GMAT EGM96.cof. nyx parses that format directly, so unlike the Orekit fixture the file needs no conversion and the coefficients cannot differ.","The reference radius and mu are the file header's, which are EGM96's and are what astrokit uses.","Body-fixed frame is EARTH_ITRF93 from the same binary PCK astrokit reads, so the two rotations are the same rather than two realizations within a few milliarcseconds of each other.","No third body, no atmosphere, no radiation pressure.","States are nyx's own accepted integrator steps rather than a fixed grid, so nothing on this side is interpolated. nyx's trajectory interpolation is a five-point Hermite fitted after the fact over stored states, and it is the accuracy floor rather than the integration: on the point-mass arc at this tolerance the stored states agree with Kepler to 2.7e-6 m while reading the same trajectory on a 60 s grid is 8.1e-4 m. Sampling the steps themselves removes that term from the comparison."]},"epoch":"2026-01-01T00:00:00 UTC","frame":"EARTH_J2000","states":[{"elapsed":0.0,"position":[6978000.0,0.0,0.0],"velocity":[0.0,7560.0,0.0]},{"elapsed":40.633699396,"position":[6971233.933483736,307091.52579563763,-0.06195428329480348],"velocity":[-332.9737682754634,7552.672201652112,-0.003034029673151399]},{"elapsed":80.890107624,"position":[6951199.234823233,610746.3139115189,-0.24356074825722174],"velocity":[-662.2233472202198,7530.969226986324,-0.005985762162043358]},{"elapsed":121.077416648,"position":[6918001.733271656,912720.8023857407,-0.5435718990101966],"velocity":[-989.6547854047311,7495.005392782218,-0.00895518449990998]},{"elapsed":161.149055655,"position":[6871833.263151953,1212102.880375494,-0.963287964868979],"velocity":[-1314.280567273784,7444.988026643884,-0.01201606995948104]},{"elapsed":201.206769354,"position":[6812726.788633949,1509096.1768900244,-1.5086873560309335],"velocity":[-1636.3228869878976,7380.952213223124,-0.015249239248180875]},{"elapsed":241.31069447,"position":[6740689.265966704,1803582.7053368287,-2.1890392192342514],"velocity":[-1955.6551357701182,7302.904737147792,-0.01872479458564654]},{"elapsed":281.540959674,"position":[6655630.143550098,2095573.007324891,-3.0172998820626376],"velocity":[-2272.2900163099152,7210.746629687941,-0.022503492299542585]},{"elapsed":321.395852151,"position":[6558887.052537042,2380912.12748704,-3.994107693260701],"velocity":[-2581.722887461557,7105.926267929203,-0.026570234086738892]},{"elapsed":361.398125808,"position":[6449479.944543053,2662838.4810607997,-5.144256851698994],"velocity":[-2887.4665016782224,6987.380832724568,-0.030990631809067744]},{"elapsed":401.634146308,"position":[6327203.481696388,2941361.5363016766,-6.486304916742049],"velocity":[-3189.5321847340483,6854.886769412424,-0.03577252865285438]},{"elapsed":441.854783512,"position":[6192946.589647226,3214187.0324210725,-8.026450810069088],"velocity":[-3485.432655924534,6709.4061985790595,-0.04085992618881257]},{"elapsed":482.293945996,"position":[6046094.428342397,3482335.1390674147,-9.786670966825795],"velocity":[-3776.2752034795158,6550.271757258661,-0.0462329597004611]},{"elapsed":522.504965765,"position":[5888551.442760964,3742336.9224204044,-11.756397865699798],"velocity":[-4058.297951643596,6379.546069313821,-0.05176025183491]},{"elapsed":562.594340677,"position":[5720347.973926491,3994474.8110884777,-13.943632925175004],"velocity":[-4331.807624814979,6197.260967607984,-0.05736524166012574]},{"elapsed":602.669206964,"position":[5541408.341096475,4238981.902907319,-16.3548574732495],"velocity":[-4597.057523415079,6003.333316553545,-0.06296040604302071]},{"elapsed":642.727754401,"position":[5352089.937736628,4475394.229960099,-18.987188712793245],"velocity":[-4853.544777432981,5798.1492590573425,-0.06843441694279419]},{"elapsed":682.676888471,"position":[5153236.51292202,4702755.800246386,-21.826434028353102],"velocity":[-5100.232546318103,5582.62204855604,-0.07366015150140738]},{"elapsed":722.97346069,"position":[4942862.610935845,4923157.1590479165,-24.89517460400192],"velocity":[-5339.389619195475,5354.598349694194,-0.07857917073294288]},{"elapsed":763.00915655,"position":[4724507.4434950575,5132827.278053716,-28.13146529638259],"velocity":[-5566.924406620023,5117.912889824538,-0.08300585766558641]},{"elapsed":803.145813855,"position":[4496666.992658846,5333318.447334134,-31.542870922602564],"velocity":[-5784.521495565505,4870.934000572716,-0.08688225244511223]},{"elapsed":843.142820128,"position":[4261147.691929002,5523065.1045Line truncated
+1
View File
@@ -0,0 +1 @@
{"name":"radiation-low-earth","setup":{"tool":"nyx-space","version":"2.6.0","generated":"2026-10-02","forces":["Earth point mass, mu = 398600.4415 km^3/s^2 from the frame","SolarPressure::with_flux(1361 W/m^2), area 5 m^2, Cr 1.3"],"integrator":"RK89, IntegratorOptions tolerance 1e-14, error control RSSCartesianStep, max step 2700 s","notes":["Reference flux set to 1361 W/m^2, which is what astrokit uses; nyx's own default is 1367.","Spacecraft mass 500 kg, area 5 m^2, Cr 1.3.","No field, no third body, no atmosphere.","States are nyx's own accepted integrator steps rather than a fixed grid, so nothing on this side is interpolated. nyx's trajectory interpolation is a five-point Hermite fitted after the fact over stored states, and it is the accuracy floor rather than the integration: on the point-mass arc at this tolerance the stored states agree with Kepler to 2.7e-6 m while reading the same trajectory on a 60 s grid is 8.1e-4 m. Sampling the steps themselves removes that term from the comparison."]},"epoch":"2026-01-01T00:00:00 UTC","frame":"EARTH_J2000","states":[{"elapsed":0.0,"position":[6978000.0,0.0,0.0],"velocity":[0.0,7560.0,0.0]},{"elapsed":40.676075488,"position":[6971228.988106782,307411.6611750471,0.000019761479202917804],"velocity":[-332.86961838239984,7552.664258079918,9.714928901072504e-7]},{"elapsed":80.991945168,"position":[6951168.155274561,611514.0996276382,0.00007830972780853775],"velocity":[-662.1549261770415,7530.930311067153,1.9325209669223475e-6]},{"elapsed":121.178947303,"position":[6917982.811976065,913484.8681624962,0.0001751621871008199],"velocity":[-989.1299922100862,7494.977390921016,2.8868056628093337e-6]},{"elapsed":161.499122311,"position":[6871517.867439722,1214716.6893911993,0.00031077151872369],"velocity":[-1315.3018600194814,7444.637695596377,3.838748278810047e-6]},{"elapsed":201.54663768,"position":[6812396.755938367,1511619.9434664876,0.00048331835301972104],"velocity":[-1636.7827607535737,7380.58695281472,4.777005150891915e-6]},{"elapsed":241.499081398,"position":[6740646.717913759,1804985.4118327901,0.0006927234431684415],"velocity":[-1954.4280633582325,7302.8550540312635,5.7040755253507565e-6]},{"elapsed":282.112194089,"position":[6654776.838749877,2099735.533453565,0.0009433384651464324],"velocity":[-2273.566581018912,7209.827276675644,6.6355150304524316e-6]},{"elapsed":322.34778621,"position":[6557009.714021147,2387741.9926949837,0.001228677179112953],"velocity":[-2585.396509600834,7103.912048860951,7.54563769012784e-6]},{"elapsed":362.541338155,"position":[6446914.448799485,2670921.240460312,0.0015499977721326295],"velocity":[-2891.992124142772,6984.643166460493,8.440500227922034e-6]},{"elapsed":402.562653019,"position":[6325154.230448603,2947859.7164951614,0.0019053653924704335],"velocity":[-3191.8222936878788,6852.739746021398,9.315636377825395e-6]},{"elapsed":442.800481314,"position":[6190757.8463008525,3220713.1492329515,0.0022976154438509354],"velocity":[-3487.2202371971816,6707.15042170577,0.000010177859080182142]},{"elapsed":482.989755518,"position":[6044790.167051547,3487133.3182528294,0.002723640948520625],"velocity":[-3775.643032009812,6549.02957388803,0.000011019748797856181]},{"elapsed":523.134997439,"position":[5887551.713402075,3746667.667425584,0.0031825658389971405],"velocity":[-4056.6002370957185,6378.703590493672,0.000011839876542521099]},{"elapsed":563.422803471,"position":[5718569.156389776,4000004.6058055963,0.003675772778025679],"velocity":[-4330.836571022524,6195.660665465249,0.000012640418928773815]},{"elapsed":575.396736809,"position":[5666232.688491109,4073852.665362937,0.0038285275650636976],"velocity":[-4410.774408329906,6138.97046821097,0.000012873778012361824]},{"elapsed":586.501381677,"position":[5616844.074124804,4141727.538785861,0.003972678918897956],"velocity":[-4484.245461879957,6085.473773718126,0.000013088261911151467]},{"elapsed":593.134813345,"position":[5586953.469440341,4181987.902039936,0.00405992134548492],"velocity":[-4527.824752214625,6053.097108344126,0.000013215484266555175]},{"elapsed":595.391894915,"position":[5576717.120357438,4195637.729843154,0.004089798463982776],"velocity":[-4542.59974276451,6042.009416636769,0.000013258617692164398]},{"elapsed":596.440425849,"position":[5571950.4699094165,4201970.257479126,0.004103710996890465],"velocity":[-4549.4542497754865,6036.846336689208,0.000013278459382817008]},{"elapsed":597.464286023,"position":[5567289.04084806,4208148.559864121,0.004117315607455935],"velocity":[-4556.141810221333,6031.797232824539,0.000013296319406291525]},{"elapsed":598.977737397,"position":[5560386.067434884,4217271.735628966,0.004137456170774876],"velocity":[-4566.016964775247,6024.320169925504,0.000013318049507732695]},{"elapsed":601.386921545,"position":[5549366.7801394705,4231771.062858834,0.004169570151565775],"velocity":[-4581.711361392689,6012.384474376551,0.000013338558680732648]},{"elapsed":604.600725033,"position":[5534608.481297024,4251068.017191855,0.00421244570751834],"velocity":Line truncated
+1
View File
@@ -0,0 +1 @@
{"name":"third-body-low-earth","setup":{"tool":"nyx-space","version":"2.6.0","generated":"2026-10-02","forces":["Earth point mass, mu = 398600.4415 km^3/s^2 from the frame","OrbitalDynamics::point_masses(vec![MOON, SUN])"],"integrator":"RK89, IntegratorOptions tolerance 1e-14, error control RSSCartesianStep, max step 2700 s","notes":["Both sides read DE-440 through ANISE, from the same de440s.bsp.","The Sun and Moon gravitational parameters are the planetary constants kernel's; astrokit carries DE440's for both.","No field, no atmosphere, no radiation pressure.","States are nyx's own accepted integrator steps rather than a fixed grid, so nothing on this side is interpolated. nyx's trajectory interpolation is a five-point Hermite fitted after the fact over stored states, and it is the accuracy floor rather than the integration: on the point-mass arc at this tolerance the stored states agree with Kepler to 2.7e-6 m while reading the same trajectory on a 60 s grid is 8.1e-4 m. Sampling the steps themselves removes that term from the comparison."]},"epoch":"2026-01-01T00:00:00 UTC","frame":"EARTH_J2000","states":[{"elapsed":0.0,"position":[6978000.0,0.0,0.0],"velocity":[0.0,7560.0,0.0]},{"elapsed":40.673567833,"position":[6971229.822271819,307392.72212962335,0.00028143751501108976],"velocity":[-332.84913644067257,7552.66518374965,0.000014167065700626966]},{"elapsed":80.735248195,"position":[6951337.857703999,609580.9107432332,0.0011603397614583348],"velocity":[-660.0617031548237,7531.1142132622235,0.000030019961911880794]},{"elapsed":120.732777363,"position":[6918423.3196862135,910140.7320164344,0.0027080912935967877],"velocity":[-985.5090341098964,7495.454708555275,0.000047671003622772124]},{"elapsed":160.839573629,"position":[6872383.611685641,1209806.2861780704,0.005004567308224112],"velocity":[-1309.985026544922,7445.575735580947,0.00006713604465431153]},{"elapsed":200.894152547,"position":[6813463.018784803,1506803.8547914012,0.008111396938734078],"velocity":[-1631.568140139984,7381.742253875725,0.00008826961831737132]},{"elapsed":240.93356538,"position":[6741750.696295016,1800855.2091645983,0.01209565376383663],"velocity":[-1949.9561926584672,7304.051236562335,0.0001110092530912411]},{"elapsed":281.171015669,"position":[6656913.189140553,2092948.7337594128,0.01704810401508176],"velocity":[-2266.218433954454,7212.141900877429,0.00013540190580128072]},{"elapsed":321.305167062,"position":[6559701.0864965515,2380333.8290494215,0.022994935980515337],"velocity":[-2577.375792571309,7106.827950817214,0.0001611786278990028]},{"elapsed":361.293718911,"position":[6450516.629498901,2662204.6706365994,0.029976250398288547],"velocity":[-2882.5550502117953,6988.545751299872,0.0001882014849375098]},{"elapsed":401.356471857,"position":[6328998.702420613,2939591.609582462,0.03807926410162441],"velocity":[-3182.871035759023,6856.90477145145,0.00021651214455857993]},{"elapsed":441.789565548,"position":[6194279.36646572,3213930.9197717425,0.047430623096235185],"velocity":[-3479.877906059976,6710.965558599312,0.0002462296674367226]},{"elapsed":482.065771637,"position":[6048275.709317655,3481080.4524872173,0.057961399255734625],"velocity":[-3769.0905587527172,6552.805695553545,0.0002768591199150018]},{"elapsed":522.365911071,"position":[5890669.473097429,3741760.6860708543,0.06975180745152613],"velocity":[-4051.2884725634085,6382.081275553906,0.0003084111533050594]},{"elapsed":562.609547125,"position":[5722088.934684702,3994964.5025688126,0.08281062779111498],"velocity":[-4325.380936352253,6199.473771743274,0.0003406955346492346]},{"elapsed":603.050710109,"position":[5541734.683697851,4241767.650578593,0.09725594104029363],"velocity":[-4592.531983462204,6004.1182330096135,0.0003737885150092336]},{"elapsed":643.358230498,"position":[5351401.375611915,4479661.638366123,0.1129960257716737],"velocity":[-4850.025964504659,5797.959581330459,0.0004072852957147759]},{"elapsed":683.728925307,"position":[5150551.848270283,4709374.674162835,0.13012215290488152],"velocity":[-5098.650895437503,5580.416983343453,0.00044120888073072344]},{"elapsed":723.943933426,"position":[4940691.4005099,4929255.5621272,0.1485489715595787],"velocity":[-5336.6195546442295,5353.121840027257,0.00047523263991984624]},{"elapsed":764.219005766,"position":[4721129.0186629705,5140097.701372367,0.16837688087102848],"velocity":[-5564.790615396983,5115.326728058185,0.000509394109963348]},{"elapsed":804.484366503,"position":[4492645.096926376,5341118.169253734,0.18957466478806528],"velocity":[-5782.316820200499,4867.877883332072,0.0005434878852840036]},{"elapsed":844.725149522,"position":[4255769.730722914,5531874.086102662,0.2121273750730532],"velocity":[-5988.719077682072,4611.350404311582,0.0005773533758128022]},{"elapsed":884.904804065,"position":[4011194.242008905,5711863.969612357,0.23599884425261575],"velocity":[-6183.455047059288,4346.493934307397,0.0006108115650771138]},{"elapsed":925.339232551,"position":[3757406.268806449,5882082.961494639,0.261369045848357Line truncated
+1
View File
@@ -0,0 +1 @@
{"name":"two-body-low-earth","setup":{"tool":"nyx-space","version":"2.6.0","generated":"2026-10-02","forces":["OrbitalDynamics::two_body(), mu = 398600.4415 km^3/s^2 from the frame"],"integrator":"RK89, IntegratorOptions tolerance 1e-14, error control RSSCartesianStep, max step 2700 s","notes":["EARTH_J2000 from ANISE on both sides, so this is one frame rather than two realizations of one and no frame difference enters.","Inertial throughout, so no Earth orientation is involved.","mu is overridden from the planetary constants kernel's DE440 value to EGM96's, which is what astrokit's Earth carries.","No third body, no atmosphere, no radiation pressure.","Scored against the closed-form Kepler solution at every state: worst 2.721e-6 m over the day. That is this arc's own error, independent of any other tool.","States are nyx's own accepted integrator steps rather than a fixed grid, so nothing on this side is interpolated. nyx's trajectory interpolation is a five-point Hermite fitted after the fact over stored states, and it is the accuracy floor rather than the integration: on the point-mass arc at this tolerance the stored states agree with Kepler to 2.7e-6 m while reading the same trajectory on a 60 s grid is 8.1e-4 m. Sampling the steps themselves removes that term from the comparison."]},"epoch":"2026-01-01T00:00:00 UTC","frame":"EARTH_J2000","states":[{"elapsed":0.0,"position":[6978000.0,0.0,0.0],"velocity":[0.0,7560.0,0.0]},{"elapsed":40.682244346,"position":[6971226.934534772,307458.25243472087,0.0],"velocity":[-332.9200676014841,7552.662030981281,0.0]},{"elapsed":80.883252369,"position":[6951240.078612777,610695.5373159877,0.0],"velocity":[-661.2685799577622,7531.008228347612,0.0]},{"elapsed":120.679474962,"position":[6918475.842799289,909741.2003702652,0.0],"velocity":[-985.076350659829,7495.51153123811,0.0]},{"elapsed":160.676941162,"position":[6872596.559300276,1208595.3670843276,0.0],"velocity":[-1308.6737681809752,7445.806327377624,0.0]},{"elapsed":200.9666925,"position":[6813344.656452244,1507339.3086046972,0.0],"velocity":[-1632.1478073326396,7381.613875195143,0.0]},{"elapsed":241.249153438,"position":[6741134.937483605,1803160.1564640873,0.0],"velocity":[-1952.451760745193,7303.383960443956,0.0]},{"elapsed":281.131622877,"position":[6657002.479735167,2092664.5994041518,0.0],"velocity":[-2265.910658243143,7212.238410040682,0.0]},{"elapsed":321.072556807,"position":[6560300.433219926,2378680.597856936,0.0],"velocity":[-2575.5856850884816,7107.476978745078,0.0]},{"elapsed":361.549548602,"position":[6449778.977297493,2663992.4012565576,0.0],"velocity":[-2884.490434137952,6987.746333726881,0.0]},{"elapsed":401.88567019,"position":[6327313.3398864465,2943219.733045673,0.0],"velocity":[-3186.798847344997,6855.078675149889,0.0]},{"elapsed":442.16360646,"position":[6192977.297408416,3216440.762711724,0.0],"velocity":[-3482.594925492874,6709.554665898757,0.0]},{"elapsed":482.362861517,"position":[6047155.70289611,3483026.961258899,0.0],"velocity":[-3771.197633157814,6551.5920068837395,0.0]},{"elapsed":522.434927434,"position":[5890389.926553615,3742201.0446461034,0.0],"velocity":[-4051.7650277219464,6381.777972140535,0.0]},{"elapsed":562.80697528,"position":[5721234.937254574,3996188.2455234234,0.0],"velocity":[-4326.7054737881745,6198.548186315781,0.0]},{"elapsed":602.829469167,"position":[5542750.676402776,4240439.036900894,0.0],"velocity":[-4591.093753814785,6005.218124993136,0.0]},{"elapsed":642.813791958,"position":[5354041.092527328,4476504.071833943,0.0],"velocity":[-4846.608248330541,5800.818093292554,0.0]},{"elapsed":683.011663523,"position":[5154207.478247265,4705370.456629143,0.0],"velocity":[-5094.317080383264,5584.375684281006,0.0]},{"elapsed":723.304860186,"position":[4944100.834714429,4925833.143799018,0.0],"velocity":[-5332.9156889194455,5356.813712308633,0.0]},{"elapsed":763.666025059,"position":[4724205.5306653865,5137267.876082169,0.0],"velocity":[-5561.728322831029,5118.657855730063,0.0]},{"elapsed":803.732892138,"position":[4496989.018079619,5337458.06178492,0.0],"velocity":[-5778.356383811707,4872.581419982001,0.0]},{"elapsed":843.937010818,"position":[4260488.2766235415,5528237.405009056,0.0],"velocity":[-5984.784371115394,4616.459405980003,0.0]},{"elapsed":883.974305524,"position":[4016946.063886295,5707816.3504807195,0.0],"velocity":[-6179.076176102718,4352.7216181386975,0.0]},{"elapsed":924.204348574,"position":[3764630.089130038,5877457.299009421,0.0],"velocity":[-6362.597912561642,4079.4930961467894,0.0]},{"elapsed":964.582689086,"position":[3504203.864722532,6036512.395785286,0.0],"velocity":[-6534.648862680873,3797.493425621905,0.0]},{"elapsed":1004.872659351,"position":[3237673.299128952,6183722.776165846,0.0],"velocity":[-6693.86773039552,3508.89561895206,0.0]},{"elapsed":1044.817145078,"position":[2967346.584949134,6318058.886025497,0.0],"velocity":[-6839.141856314053,3216.199641232565,0.0]},{"elapsed":1084.864193599,"position":[2690756.6369726453,6440881.0243689045,0.0]Line truncated
File diff suppressed because it is too large. Load diff
+198
View File
@@ -0,0 +1,198 @@
//! This crate's propagator against nyx-space's, on the fixtures in `tests/fixtures/nyx`.
//!
//! Generated by `scripts/generate-nyx-fixtures.sh`. The second reference after Orekit,
//! and worth having for a reason beyond redundancy: nyx is the other Rust astrodynamics
//! library, it reads the same ANISE kernels this crate does, and where Orekit's agreement
//! is limited by two different realizations of the inertial frame, nyx and this crate use
//! literally the same one.
//!
//! See `tests/common/mod.rs` for what has to match before a number means anything.
//!
//! # These fixtures are sampled differently from Orekit's
//!
//! Orekit's are on a 60-second grid. nyx's are at nyx's own accepted integrator steps,
//! because its trajectory interpolation is a five-point Hermite fitted after the fact
//! rather than a continuous extension of the method, and that interpolation — not the
//! integration — is its accuracy floor. On the point-mass arc the stored states agree
//! with Kepler to 2.7e-6 m while the same trajectory read on a 60-second grid is
//! 8.1e-4 m. Sampling the steps themselves keeps that term out of the comparison, so what
//! is left to measure is this crate.
mod common;
use astrokit::kernels;
use astrokit::prelude::*;
use common::ReferenceArc;
use nalgebra::Vector3;
use std::path::Path;
use std::sync::Arc;
/// The kernels, or `None` if they have not been fetched.
fn almanac() -> Option<Arc<anise::almanac::Almanac>> {
let directory = kernels::directory()
.unwrap_or_else(|| Path::new(env!("CARGO_MANIFEST_DIR")).join("data/kernels"));
kernels::load(&directory).ok().map(Arc::new)
}
/// Loads a fixture and checks it is the one it claims to be.
fn fixture(name: &str) -> ReferenceArc {
let path = format!("tests/fixtures/nyx/{name}-low-earth.json");
let arc = ReferenceArc::load(Path::new(&path)).expect("the fixture is committed");
assert_eq!(arc.setup.tool, "nyx-space");
assert_eq!(arc.setup.version, "2.6.0");
assert_eq!(arc.frame, "EARTH_J2000");
assert_eq!(arc.duration(), 86400.0);
arc
}
/// Propagates the fixture's initial state with this crate and returns the worst position
/// and velocity disagreement over the arc.
fn compare(
arc: &ReferenceArc,
forces: &[Dynamics],
vehicle: Option<Spacecraft>,
almanac: Option<Arc<anise::almanac::Almanac>>,
) -> (f64, f64) {
let start = &arc.states[0];
let epoch = Epoch::from_gregorian_utc_hms(2026, 1, 1, 0, 0, 0);
let mut propagation = Propagation::new(
epoch,
Orbit
.with_position(Vector3::from_column_slice(&start.position))
.with_velocity(Vector3::from_column_slice(&start.velocity)),
forces,
)
.frame(Frame::EARTH_J2000)
.duration(Duration::from_seconds(arc.duration()))
.accuracy(Accuracy::High);
if let Some(vehicle) = vehicle {
propagation = propagation.spacecraft(vehicle);
}
if let Some(almanac) = almanac {
propagation = propagation.almanac(almanac);
}
let solution = propagation.run();
let (mut worst_position, mut worst_velocity) = (0.0_f64, 0.0_f64);
for state in &arc.states {
let ours = Orbit.state(solution.interpolate(state.elapsed));
worst_position = worst_position
.max((ours.position() - Vector3::from_column_slice(&state.position)).norm());
worst_velocity = worst_velocity
.max((ours.velocity() - Vector3::from_column_slice(&state.velocity)).norm());
}
(worst_position, worst_velocity)
}
/// The floor the rest are read against.
///
/// With no field, no third body, no atmosphere and an inertial frame shared with the
/// other tool, there is nothing left to mismatch, so this measures the comparison itself.
/// The fixture records its own error against the closed-form Kepler solution — 2.7e-6 m —
/// so anything above that is this crate's.
#[test]
fn test_a_point_mass_arc_agrees_with_nyx() {
let arc = fixture("two-body");
assert!(arc.setup.forces[0].contains("two_body"));
let (position, velocity) = compare(&arc, &[TwoBody { body: Body::EARTH }], None, None);
assert!(
position < 1.0e-3,
"worst position disagreement {position:.3e} m over the day"
);
assert!(
velocity < 1.0e-6,
"worst velocity disagreement {velocity:.3e} m/s over the day"
);
println!("point mass: {position:.3e} m, {velocity:.3e} m/s");
}
/// The Sun and the Moon over a point mass, from the same DE-440 through the same ANISE.
#[test]
fn test_the_sun_and_moon_agree_with_nyx() {
let Some(almanac) = almanac() else {
eprintln!("skipped: kernels not fetched, run scripts/fetch-kernels.sh");
return;
};
let arc = fixture("third-body");
assert!(arc.setup.forces[1].contains("point_masses"));
let (position, velocity) = compare(
&arc,
&[
TwoBody { body: Body::EARTH },
ThirdBody { body: Body::MOON },
ThirdBody { body: Body::SUN },
],
None,
Some(almanac),
);
assert!(
position < 1.0e-3,
"worst position disagreement {position:.3e} m over the day"
);
println!("third body: {position:.3e} m, {velocity:.3e} m/s");
}
/// EGM96, read by both sides from the same GMAT coefficient file, and turned with the
/// same ITRF93 out of the same binary PCK.
///
/// The Orekit equivalent sits at about a centimeter, almost all of which is the four
/// milliarcseconds between its terrestrial frame and this one. There is no such term
/// here, so this measures the field evaluation.
fn gravity(degree: usize, allowed_meters: f64) {
let Some(almanac) = almanac() else {
eprintln!("skipped: kernels not fetched, run scripts/fetch-kernels.sh");
return;
};
let arc = fixture(&format!("gravity-{degree}"));
assert!(arc.setup.forces[0].contains("EGM96"));
let (position, velocity) = compare(
&arc,
&[Gravity {
field: GravityModel::Egm96,
degree,
order: degree,
}],
None,
Some(almanac),
);
assert!(
position < allowed_meters,
"degree {degree}: worst position disagreement {position:.3e} m over the day"
);
println!("gravity {degree}: {position:.3e} m, {velocity:.3e} m/s");
}
#[test]
fn test_a_low_degree_field_agrees_with_nyx() {
gravity(8, 0.03);
}
#[test]
fn test_a_higher_degree_field_agrees_with_nyx() {
gravity(20, 0.03);
}
/// Cannonball radiation pressure, at the same reference flux.
#[test]
fn test_radiation_pressure_agrees_with_nyx() {
let Some(almanac) = almanac() else {
eprintln!("skipped: kernels not fetched, run scripts/fetch-kernels.sh");
return;
};
let arc = fixture("radiation");
assert!(arc.setup.forces[1].contains("SolarPressure"));
let (position, velocity) = compare(
&arc,
&[TwoBody { body: Body::EARTH }, Sunshine],
Some(Spacecraft::cannonball(500.0, 5.0, 2.2, 1.3)),
Some(almanac),
);
println!("radiation: {position:.3e} m, {velocity:.3e} m/s");
}
+3 -85
View File
@@ -212,93 +212,11 @@ fn test_radiation_pressure_agrees_with_orekit() {
);
}
/// Drag on a cannonball through Harris-Priester, over a point mass, at 400 km.
///
/// This is the one scenario where the two sides are *known* to be modeling different
/// things, and the comparison measures how much that costs. Both read the same tabulated
/// profiles with the same 30 degree bulge lag and the same exponent, but Orekit
/// interpolates the table exponentially, as published, while this crate fits a monotone
/// cubic to the logarithm of the density so that the altitude derivative exists. That is
/// worth about 0.2% of the density in this band.
#[test]
fn test_drag_agrees_with_orekit() {
let Some(almanac) = almanac() else {
eprintln!("skipped: kernels not fetched, run scripts/fetch-kernels.sh");
return;
};
let path = Path::new("tests/fixtures/orekit/drag-low-earth.json");
let arc = ReferenceArc::load(path).expect("the fixture is committed");
assert!(arc
.setup
.forces
.iter()
.any(|f| f.contains("HarrisPriester")));
let start = &arc.states[0];
let mut propagation = Propagation::new(
Epoch::from_gregorian_utc_hms(2026, 1, 1, 0, 0, 0),
Orbit
.with_position(Vector3::from_column_slice(&start.position))
.with_velocity(Vector3::from_column_slice(&start.velocity)),
&[
TwoBody { body: Body::EARTH },
Drag {
density: DensityModel::harris_priester(),
},
],
)
.frame(Frame::EARTH_J2000)
.spacecraft(Spacecraft::cannonball(500.0, 5.0, 2.2, 1.3))
.almanac(almanac)
.duration(Duration::from_seconds(arc.duration()))
.accuracy(Accuracy::High);
let solution = propagation.run();
let (mut position, mut velocity) = (0.0_f64, 0.0_f64);
for state in &arc.states {
let ours = Orbit.state(solution.interpolate(state.elapsed));
position =
position.max((ours.position() - Vector3::from_column_slice(&state.position)).norm());
velocity =
velocity.max((ours.velocity() - Vector3::from_column_slice(&state.velocity)).norm());
}
// Bounded as a fraction of what drag does, not as a number of meters. The
// disagreement is a density difference of a few hundredths of a percent and the
// along-track position integrates it, so the meters depend on the arc while the
// fraction does not.
let drag_free = {
let mut plain = Propagation::new(
Epoch::from_gregorian_utc_hms(2026, 1, 1, 0, 0, 0),
Orbit
.with_position(Vector3::from_column_slice(&start.position))
.with_velocity(Vector3::from_column_slice(&start.velocity)),
&[TwoBody { body: Body::EARTH }],
)
.frame(Frame::EARTH_J2000)
.duration(Duration::from_seconds(arc.duration()))
.accuracy(Accuracy::High);
Orbit.state(*plain.run().states.last().unwrap()).position()
};
let last = arc.states.last().expect("checked on load");
let effect = (Vector3::from_column_slice(&last.position) - drag_free).norm();
println!(
"drag: {position:.3e} m, {velocity:.3e} m/s, {:.4}% of a {effect:.0} m effect",
position / effect * 100.0
);
assert!(
position < 5.0e-4 * effect,
"worst disagreement {position:.3e} m is {:.4}% of the {effect:.0} m drag moves it",
position / effect * 100.0
);
}
/// Drag through NRLMSISE-00, which both tools implement from the same reference.
///
/// Unlike Harris-Priester there is no intended difference in the model here, so this is
/// the measurement of how close two independent implementations get when they are given
/// very nearly the same weather. The drivers are not quite identical: for this epoch the
/// Nothing in the model is intended to differ here, so this is the measurement of how
/// close two independent implementations get when they are given very nearly the same
/// weather. The drivers are not quite identical: for this epoch the
/// daily flux and every three-hourly ap agree exactly, but CSSI publishes the 81-day
/// average rounded to a tenth, 154.3 against the 154.3333 this crate computes from the
/// daily values.