From 76b8c629c5094eeb89a3282ebccb9b9cce8237b2 Mon Sep 17 00:00:00 2001 From: Joachim Moeyens Date: Wed, 5 Feb 2025 12:25:05 -0800 Subject: [PATCH] Add query_neocc (#141) * Add query_neocc * Remove try/except in query_neocc * Fix linting issues due to updated black (or ruff) versions * Fix timescale declaration in query_neocc --- src/adam_core/orbits/query/__init__.py | 2 + src/adam_core/orbits/query/neocc.py | 255 ++++++++++++++++++ .../orbits/query/tests/test_neocc.py | 211 +++++++++++++++ .../query/tests/testdata/neocc/2022OB5.ke0 | 36 +++ .../query/tests/testdata/neocc/2022OB5.ke1 | 36 +++ .../query/tests/testdata/neocc/2024YR4.ke0 | 36 +++ .../query/tests/testdata/neocc/2024YR4.ke1 | 36 +++ 7 files changed, 612 insertions(+) create mode 100644 src/adam_core/orbits/query/neocc.py create mode 100644 src/adam_core/orbits/query/tests/test_neocc.py create mode 100644 src/adam_core/orbits/query/tests/testdata/neocc/2022OB5.ke0 create mode 100644 src/adam_core/orbits/query/tests/testdata/neocc/2022OB5.ke1 create mode 100644 src/adam_core/orbits/query/tests/testdata/neocc/2024YR4.ke0 create mode 100644 src/adam_core/orbits/query/tests/testdata/neocc/2024YR4.ke1 diff --git a/src/adam_core/orbits/query/__init__.py b/src/adam_core/orbits/query/__init__.py index c7fc1337..1ca14b8c 100644 --- a/src/adam_core/orbits/query/__init__.py +++ b/src/adam_core/orbits/query/__init__.py @@ -1,3 +1,5 @@ # flake8: noqa: F401 from .horizons import query_horizons +from .neocc import query_neocc from .sbdb import query_sbdb +from .scout import query_scout diff --git a/src/adam_core/orbits/query/neocc.py b/src/adam_core/orbits/query/neocc.py new file mode 100644 index 00000000..9b250772 --- /dev/null +++ b/src/adam_core/orbits/query/neocc.py @@ -0,0 +1,255 @@ +from typing import Any, Dict, List, Literal, Union + +import numpy as np +import numpy.typing as npt +import quivr as qv +import requests + +from ...coordinates import CoordinateCovariances, KeplerianCoordinates, Origin +from ...orbits import Orbits +from ...time import Timestamp + + +def _upper_triangular_to_full( + upper_triangular: npt.NDArray[np.float64], +) -> npt.NDArray[np.float64]: + """ + Convert an upper triangular matrix containing 21 elements to a full 6x6 matrix. + """ + assert len(upper_triangular) == 21 + + full = np.zeros((6, 6)) + full[np.triu_indices(6)] = upper_triangular + full[np.tril_indices(6, -1)] = full.T[np.tril_indices(6, -1)] + return full + + +def _parse_oef(data: str) -> Dict[str, Any]: + """ + Parse a OEF file and return the stored orbital elements. + + Parameters + ---------- + data: str + The content of the OEF file. + + Returns + ------- + Dict[str, Any] + Dictionary containing the parsed orbital elements and metadata. + + + Examples + -------- + format = 'OEF2.0' ! file format + rectype = 'ML' ! record type (1L/ML) + refsys = ECLM J2000 ! default reference system + END_OF_HEADER + 2024YR4 + ! Keplerian elements: a, e, i, long. node, arg. peric., mean anomaly + KEP 2.5158127507489616E+00 6.6154036821914619E-01 3.4081393687180 271.3655954496424 134.3614240204325 4.0403920526717883E+01 + MJD 60800.000000000 TDT + MAG 23.876 0.150 + ! Non-gravitational parameters: model used, number of model parameters, dimension + LSP 0 0 6 + ! PERIHELION 8.5150105724807035E-01 + ! APHELION 4.1801244442498522E+00 + ! ANODE 1.6132920678553648E+00 + ! DNODE -1.6139338737144644E-02 + ! MOID 2.8281976977061222E-03 + ! PERIOD 1.4575246142278593E+03 + ! PHA F + ! VINFTY 14.2161102117779 + ! U_PAR 5.5 + ! ORB_TYPE Apollo + ! RMS 1.45945E-04 2.08511E-05 7.80533E-05 1.08159E-05 9.07220E-05 3.57225E-03 + COV 2.129990103626278E-08 3.043103695236090E-09 1.138994073085263E-08 + COV -1.297300567885438E-09 -1.321094812357632E-08 -5.213516734886736E-07 + COV 4.347664336862408E-10 1.627274457493249E-09 -1.853526029216412E-10 + COV -1.887473042074563E-09 -7.448518590163292E-08 6.092321667952164E-09 + COV -6.879908552449990E-10 -7.069797588501348E-09 -2.787885242390572E-07 + COV 1.169847013231039E-10 7.781995171805923E-10 3.175091792990313E-08 + COV 8.230474520730192E-09 3.233601008844550E-07 1.276097850815426E-05 + COR 1.000000000000000E+00 9.999998967955239E-01 9.998647520507938E-01 + COR -8.218400094356861E-01 -9.977753189147101E-01 -9.999999781092901E-01 + COR 9.999999999999999E-01 9.998650578225570E-01 -8.218757198089662E-01 + COR -9.977926872410703E-01 -9.999998019539900E-01 9.999999999999998E-01 + COR -8.149420314930980E-01 -9.983966836512449E-01 -9.998652884032685E-01 + COR 1.000000000000000E+00 7.930744967922404E-01 8.217690139449345E-01 + COR 1.000000000000000E+00 9.977735927640640E-01 1.000000000000000E+00 + + """ + lines = data.strip().split("\n") + result = {} + + # Parse header + header = {} + for line in lines: + line = line.strip() + if line == "END_OF_HEADER": + break + if "=" in line: + key, value = line.split("=", 1) + header[key.strip()] = value.split("!")[0].strip().strip("'") + result["header"] = header + + # Find object ID + for line in lines: + if not line.startswith( + ("!", " ", "format", "rectype", "refsys", "END_OF_HEADER") + ): + result["object_id"] = line.strip() + break + + # Parse Keplerian elements + for line in lines: + if line.strip().startswith("KEP"): + elements = line.split()[1:] + result["elements"] = { + "a": float(elements[0]), # semi-major axis + "e": float(elements[1]), # eccentricity + "i": float(elements[2]), # inclination + "node": float(elements[3]), # longitude of ascending node + "peri": float(elements[4]), # argument of perihelion + "M": float(elements[5]), # mean anomaly + } + + # Parse epoch + for line in lines: + if line.strip().startswith("MJD"): + result["epoch"] = float(line.split()[1]) + result["time_system"] = line.split()[2] + + # Parse magnitude + for line in lines: + if line.strip().startswith("MAG"): + mag_data = line.split()[1:] + result["magnitude"] = { + "value": float(mag_data[0]), + "uncertainty": float(mag_data[1]), + } + + # Parse derived parameters (marked with !) + derived = {} + for line in lines: + if line.strip().startswith("!") and len(line.split()) >= 3: + key = line.split()[1].lower() + try: + value = float(line.split()[2]) + derived[key] = value + except ValueError: + derived[key] = line.split()[2] + result["derived"] = derived + + # Parse covariance matrix + cov_matrix = [] + for line in lines: + if line.strip().startswith("COV"): + cov_matrix.extend([float(x) for x in line.split()[1:]]) + if cov_matrix: + # Upper triangular matrix with order + # (1,1) (1,2) (1,3) + # (1,4) (1,5) (1,6) + # (2,2) (2,3) (2,4) + # (2,5) (2,6) (3,3) + # (3,4) (3,5) (3,6) + # (4,4) (4,5) (4,6) + # (5,5) (5,6) (6,6) + result["covariance"] = _upper_triangular_to_full(np.array(cov_matrix)) + + # Parse correlation matrix + cor_matrix = [] + for line in lines: + if line.strip().startswith("COR"): + cor_matrix.extend([float(x) for x in line.split()[1:]]) + if cor_matrix: + result["correlation"] = _upper_triangular_to_full(np.array(cor_matrix)) + + return result + + +def query_neocc( + object_ids: Union[List, npt.ArrayLike], + orbit_type: Literal["ke", "eq"] = "ke", + orbit_epoch: Literal["middle", "present-day"] = "present-day", +) -> Orbits: + """ + Query ESA's Near-Earth Object Coordination Centre (NEOCC) database for orbital elements of the specified NEOs. + + Parameters + ---------- + object_ids : Union[List, npt.ArrayLike] + Object IDs / designations recognizable by NEOCC. + orbit_type : ["ke", "eq"] + Type of orbital elements to query. + orbit_epoch : ["middle", "present-day"] + Epoch of the orbital elements to query. + + Returns + ------- + orbits : `~adam_core.orbits.Orbits` + Orbits object containing the orbital elements of the specified NEOs. + """ + base_url = "https://neo.ssa.esa.int/PSDB-portlet/download" + + if orbit_type == "eq": + raise NotImplementedError("Equinoctial elements are not supported yet.") + + if orbit_epoch == "middle": + orbit_epoch = 0 + elif orbit_epoch == "present-day": + orbit_epoch = 1 + else: + raise ValueError(f"Invalid orbit epoch: {orbit_epoch}") + + orbits = Orbits.empty() + + for object_id in object_ids: + + # Clean object ID so that there are no spaces + object_id = object_id.replace(" ", "") + + params = {"file": f"{object_id}.{orbit_type}{orbit_epoch}"} + + response = requests.get(base_url, params=params) + response.raise_for_status() + + data = _parse_oef(response.text) + if orbit_type == "ke": + + time_scale = data["time_system"] + if time_scale == "TDT": + time_scale = "tt" + else: + raise ValueError(f"Unsupported time scale: {time_scale}") + + if data["header"]["refsys"] != "ECLM J2000": + raise ValueError( + f"Unsupported reference system: {data['header']['refsys']}" + ) + + orbit = Orbits.from_kwargs( + orbit_id=[data["object_id"]], + object_id=[data["object_id"]], + coordinates=KeplerianCoordinates.from_kwargs( + a=[data["elements"]["a"]], + e=[data["elements"]["e"]], + i=[data["elements"]["i"]], + raan=[data["elements"]["node"]], + ap=[data["elements"]["peri"]], + M=[data["elements"]["M"]], + time=Timestamp.from_mjd([data["epoch"]], scale=time_scale), + covariance=CoordinateCovariances.from_matrix( + data["covariance"].reshape( + 1, + 6, + 6, + ) + ), + frame="ecliptic", + origin=Origin.from_kwargs(code=["SUN"]), + ).to_cartesian(), + ) + orbits = qv.concatenate([orbits, orbit]) + + return orbits diff --git a/src/adam_core/orbits/query/tests/test_neocc.py b/src/adam_core/orbits/query/tests/test_neocc.py new file mode 100644 index 00000000..83ea55e6 --- /dev/null +++ b/src/adam_core/orbits/query/tests/test_neocc.py @@ -0,0 +1,211 @@ +from pathlib import Path + +import numpy as np + +from ..neocc import _parse_oef, _upper_triangular_to_full, query_neocc + +TESTDATA_DIR = Path(__file__).parent / "testdata" / "neocc" + + +def test__upper_triangular_to_full(): + # Test that we can reconstruct a full covariance matrix from an upper triangular matrix. + expected_array = np.array( + [ + [1, 2, 3, 4, 5, 6], + [2, 2, 3, 4, 5, 6], + [3, 3, 3, 4, 5, 6], + [4, 4, 4, 4, 5, 6], + [5, 5, 5, 5, 5, 6], + [6, 6, 6, 6, 6, 6], + ], + dtype=np.float64, + ) + + triangular_array = np.triu(expected_array)[np.triu_indices(6)].flatten() + + actual_array = _upper_triangular_to_full(triangular_array) + np.testing.assert_array_equal(actual_array, expected_array) + + +def test__parse_oef_2024YR4_ke0(): + with open(TESTDATA_DIR / "2024YR4.ke0", "r") as file: + data = file.read() + + result = _parse_oef(data) + + # Test header + assert result["header"]["format"] == "OEF2.0" + assert result["header"]["rectype"] == "ML" + assert result["header"]["refsys"] == "ECLM J2000" + + # Test object identification + assert result["object_id"] == "2024YR4" + + # Test Keplerian elements + assert result["elements"]["a"] == 2.5164332860625849 + assert result["elements"]["e"] == 0.66161845913486128 + assert result["elements"]["i"] == 3.4083351351535 + assert result["elements"]["node"] == 271.3684549331765 + assert result["elements"]["peri"] == 134.3639170929742 + assert result["elements"]["M"] == 12.947786309204405 + + # Test epoch and time system + assert result["epoch"] == 60688.865642464 + assert result["time_system"] == "TDT" + + # Test magnitude + assert result["magnitude"]["value"] == 23.876 + assert result["magnitude"]["uncertainty"] == 0.150 + + # Test derived parameters + assert abs(result["derived"]["perihelion"] - 0.85151457282218190) < 1e-14 + assert abs(result["derived"]["aphelion"] - 4.1813519993029882) < 1e-14 + assert abs(result["derived"]["period"] - 1458.0639039239943) < 1e-14 + assert result["derived"]["pha"] == "F" + assert result["derived"]["orb_type"] == "Apollo" + + # Test covariance and correlation matrices + assert result["covariance"].shape == (6, 6) + assert result["correlation"].shape == (6, 6) + + # Test matrix properties + assert np.allclose(result["covariance"], result["covariance"].T) # Symmetry + assert np.allclose(result["correlation"], result["correlation"].T) # Symmetry + assert np.allclose( + np.diagonal(result["correlation"]), 1.0 + ) # Diagonal elements should be 1 + + +def test__parse_oef_2022OB5_ke1(): + with open(TESTDATA_DIR / "2022OB5.ke1", "r") as file: + data = file.read() + + result = _parse_oef(data) + + # Test header + assert result["header"]["format"] == "OEF2.0" + assert result["header"]["rectype"] == "ML" + assert result["header"]["refsys"] == "ECLM J2000" + + # Test object identification + assert result["object_id"] == "2022OB5" + + # Test Keplerian elements + assert result["elements"]["a"] == 1.0088199810054714 + assert result["elements"]["e"] == 0.058593341916141808 + assert result["elements"]["i"] == 2.0599781391032 + assert result["elements"]["node"] == 302.6856493105631 + assert result["elements"]["peri"] == 105.7080782884594 + assert result["elements"]["M"] == 334.06138612130985 + + # Test epoch and time system + assert result["epoch"] == 60600.0 + assert result["time_system"] == "TDT" + + # Test magnitude + assert result["magnitude"]["value"] == 28.813 + assert result["magnitude"]["uncertainty"] == 0.150 + + # Test derived parameters + assert abs(result["derived"]["perihelion"] - 0.94970984692658189) < 1e-14 + assert abs(result["derived"]["aphelion"] - 1.0679301150843603) < 1e-14 + assert abs(result["derived"]["period"] - 370.09987635676049) < 1e-14 + assert result["derived"]["pha"] == "F" + assert result["derived"]["orb_type"] == "Apollo" + + # Test covariance and correlation matrices + assert result["covariance"].shape == (6, 6) + assert result["correlation"].shape == (6, 6) + + # Test matrix properties + assert np.allclose(result["covariance"], result["covariance"].T) # Symmetry + assert np.allclose(result["correlation"], result["correlation"].T) # Symmetry + assert np.allclose( + np.diagonal(result["correlation"]), 1.0 + ) # Diagonal elements should be 1 + + +def test_query_neocc(mocker): + """Test query_neocc with both present-day and middle epochs (using saved test data)""" + import requests + + # Setup mock responses for each test file + mock_responses = {} + for orbit_type in ["ke0", "ke1"]: + for obj in ["2024YR4", "2022OB5"]: + with open(TESTDATA_DIR / f"{obj}.{orbit_type}", "r") as f: + mock_responses[f"{obj}.{orbit_type}"] = f.read() + + # Create mock response + def mock_get(url, params): + mock = mocker.MagicMock() + mock.status_code = 200 + mock.text = mock_responses[params["file"]] + return mock + + # Patch requests.get + mocker.patch("requests.get", side_effect=mock_get) + + # Test querying multiple objects + object_ids = ["2024YR4", "2022OB5"] + orbits = query_neocc(object_ids, orbit_type="ke", orbit_epoch="present-day") + + # Verify the results + assert orbits is not None + assert len(orbits) == 2 + + assert orbits.orbit_id[0].as_py() == "2024YR4" + assert orbits.object_id[0].as_py() == "2024YR4" + assert orbits.orbit_id[1].as_py() == "2022OB5" + assert orbits.object_id[1].as_py() == "2022OB5" + assert orbits.coordinates.time.days[0].as_py() == 60800 + assert orbits.coordinates.time.days[1].as_py() == 60600 + assert orbits.coordinates.time.scale == "tt" + assert np.all(~np.isnan(orbits.coordinates.values)) + assert np.all(~np.isnan(orbits.coordinates.covariance.to_matrix())) + + # Verify the mock was called with correct parameters + requests.get.assert_has_calls( + [ + mocker.call( + "https://neo.ssa.esa.int/PSDB-portlet/download", + params={"file": "2024YR4.ke1"}, + ), + mocker.call( + "https://neo.ssa.esa.int/PSDB-portlet/download", + params={"file": "2022OB5.ke1"}, + ), + ] + ) + + # Test querying multiple objects + object_ids = ["2024YR4", "2022OB5"] + orbits = query_neocc(object_ids, orbit_type="ke", orbit_epoch="middle") + + # Verify the results + assert orbits is not None + assert len(orbits) == 2 + + assert orbits.orbit_id[0].as_py() == "2024YR4" + assert orbits.object_id[0].as_py() == "2024YR4" + assert orbits.orbit_id[1].as_py() == "2022OB5" + assert orbits.object_id[1].as_py() == "2022OB5" + assert orbits.coordinates.time.days[0].as_py() == 60688 + assert orbits.coordinates.time.days[1].as_py() == 59792 + assert orbits.coordinates.time.scale == "tt" + assert np.all(~np.isnan(orbits.coordinates.values)) + assert np.all(~np.isnan(orbits.coordinates.covariance.to_matrix())) + + # Verify the mock was called with correct parameters + requests.get.assert_has_calls( + [ + mocker.call( + "https://neo.ssa.esa.int/PSDB-portlet/download", + params={"file": "2024YR4.ke0"}, + ), + mocker.call( + "https://neo.ssa.esa.int/PSDB-portlet/download", + params={"file": "2022OB5.ke0"}, + ), + ] + ) diff --git a/src/adam_core/orbits/query/tests/testdata/neocc/2022OB5.ke0 b/src/adam_core/orbits/query/tests/testdata/neocc/2022OB5.ke0 new file mode 100644 index 00000000..115c9ea6 --- /dev/null +++ b/src/adam_core/orbits/query/tests/testdata/neocc/2022OB5.ke0 @@ -0,0 +1,36 @@ +format = 'OEF2.0' ! file format +rectype = 'ML' ! record type (1L/ML) +refsys = ECLM J2000 ! default reference system +END_OF_HEADER +2022OB5 +! Keplerian elements: a, e, i, long. node, arg. peric., mean anomaly + KEP 1.0239929945720563E+00 5.9531919032530821E-02 2.5390717058948 308.0742401418013 92.8788888034344 2.7523462240052027E+02 + MJD 59792.691344584 TDT + MAG 28.813 0.150 +! Non-gravitational parameters: model used, number of model parameters, dimension + LSP 0 0 6 +! PERIHELION 9.6303272652931382E-01 +! APHELION 1.0849532626147986E+00 +! ANODE 8.2660002607717435E-03 +! DNODE 3.1408129788216874E-02 +! MOID 5.3754815039091259E-03 +! PERIOD 3.7848084543206471E+02 +! PHA F +! VINFTY 2.1380637486204 +! U_PAR 4.1 +! ORB_TYPE Apollo +! RMS 1.85858E-06 3.81309E-06 1.76305E-04 2.58447E-05 9.65789E-04 1.38588E-03 + COV 3.454326662596819E-12 7.031100915165097E-12 3.261562318536510E-10 + COV 4.701150783527715E-11 -1.787692188802635E-09 2.574988407783582E-09 + COV 1.453965387620361E-11 6.716248073440527E-10 9.732571242635507E-11 + COV -3.597419282621802E-09 5.225343240323199E-09 3.108341144565231E-08 + COV 4.504403821738336E-09 -1.673681441974341E-07 2.425593621513732E-07 + COV 6.679462718535847E-10 -2.404980712839186E-08 3.493034951495819E-08 + COV 9.327484123086008E-07 -1.335567126468572E-06 1.920672076890530E-06 + COR 1.000000000000000E+00 9.921208915464224E-01 9.953587532900027E-01 + COR 9.787047889584983E-01 -9.959299226422499E-01 9.996937215627824E-01 + COR 9.999999999999999E-01 9.990457034713855E-01 9.875970689476337E-01 + COR -9.768587364744548E-01 9.888061939013633E-01 1.000000000000000E+00 + COR 9.885581356428432E-01 -9.829381760425833E-01 9.927207326067412E-01 + COR 1.000000000000000E+00 -9.635152071247277E-01 9.752266368270636E-01 + COR 1.000000000000000E+00 -9.978306739781621E-01 1.000000000000000E+00 diff --git a/src/adam_core/orbits/query/tests/testdata/neocc/2022OB5.ke1 b/src/adam_core/orbits/query/tests/testdata/neocc/2022OB5.ke1 new file mode 100644 index 00000000..1d9cc815 --- /dev/null +++ b/src/adam_core/orbits/query/tests/testdata/neocc/2022OB5.ke1 @@ -0,0 +1,36 @@ +format = 'OEF2.0' ! file format +rectype = 'ML' ! record type (1L/ML) +refsys = ECLM J2000 ! default reference system +END_OF_HEADER +2022OB5 +! Keplerian elements: a, e, i, long. node, arg. peric., mean anomaly + KEP 1.0088199810054714E+00 5.8593341916141808E-02 2.0599781391032 302.6856493105631 105.7080782884594 3.3406138612130985E+02 + MJD 60600.000000000 TDT + MAG 28.813 0.150 +! Non-gravitational parameters: model used, number of model parameters, dimension + LSP 0 0 6 +! PERIHELION 9.4970984692658189E-01 +! APHELION 1.0679301150843603E+00 +! ANODE 6.5000303171540126E-03 +! DNODE 6.6491005734343198E-03 +! MOID 3.6703277072839889E-03 +! PERIOD 3.7009987635676049E+02 +! PHA F +! VINFTY 2.0396462903870 +! U_PAR 4.0 +! ORB_TYPE Apollo +! RMS 1.54019E-06 3.37885E-06 2.52551E-04 1.70437E-03 2.55040E-03 2.32866E-03 + COV 2.372181619805195E-12 5.184561356100753E-12 3.887755709013494E-10 + COV 2.623340882901175E-09 -3.927838141277448E-09 -3.586065550274490E-09 + COV 1.141660480598333E-11 8.517071217049702E-10 5.750990724645152E-09 + COV -8.576343949021238E-09 -7.848552424260153E-09 6.378207690331209E-08 + COV 4.304107011819618E-07 -6.435563961746892E-07 -5.880256191167535E-07 + COV 2.904892412255057E-06 -4.342110988469157E-06 -3.968142415683946E-06 + COV 6.504554121408674E-06 5.936733812629100E-06 5.422676851323900E-06 + COR 1.000000000000000E+00 9.962528257225026E-01 9.994835969482515E-01 + COR 9.993456654460544E-01 -9.999328794731562E-01 -9.998558529235523E-01 + COR 9.999999999999999E-01 9.980963475358117E-01 9.986404590093775E-01 + COR -9.952333944108563E-01 -9.975030153470278E-01 1.000000000000000E+00 + COR 9.999279455579899E-01 -9.991449940550478E-01 -9.998619858385595E-01 + COR 1.000000000000000E+00 -9.989117653447538E-01 -9.998051329225822E-01 + COR 9.999999999999998E-01 9.996131222200630E-01 1.000000000000000E+00 diff --git a/src/adam_core/orbits/query/tests/testdata/neocc/2024YR4.ke0 b/src/adam_core/orbits/query/tests/testdata/neocc/2024YR4.ke0 new file mode 100644 index 00000000..bf8d2321 --- /dev/null +++ b/src/adam_core/orbits/query/tests/testdata/neocc/2024YR4.ke0 @@ -0,0 +1,36 @@ +format = 'OEF2.0' ! file format +rectype = 'ML' ! record type (1L/ML) +refsys = ECLM J2000 ! default reference system +END_OF_HEADER +2024YR4 +! Keplerian elements: a, e, i, long. node, arg. peric., mean anomaly + KEP 2.5164332860625849E+00 6.6161845913486128E-01 3.4083351351535 271.3684549331765 134.3639170929742 1.2947786309204405E+01 + MJD 60688.865642464 TDT + MAG 23.876 0.150 +! Non-gravitational parameters: model used, number of model parameters, dimension + LSP 0 0 6 +! PERIHELION 8.5151457282218190E-01 +! APHELION 4.1813519993029882E+00 +! ANODE 1.6158098389539370E+00 +! DNODE -1.5840554270114965E-02 +! MOID 2.7785886271125522E-03 +! PERIOD 1.4580639039239943E+03 +! PHA F +! VINFTY 14.2168543469435 +! U_PAR 5.5 +! ORB_TYPE Apollo +! RMS 1.46024E-04 2.08510E-05 7.80469E-05 1.09509E-05 9.05105E-05 1.18339E-03 + COV 2.132309431034840E-08 3.044754539891089E-09 1.139519830562004E-08 + COV -1.322015947926820E-09 -1.318719375737641E-08 -1.728035045410224E-07 + COV 4.347648602992980E-10 1.627137012958929E-09 -1.887805632452709E-10 + COV -1.883050918721391E-09 -2.467484932480712E-08 6.091314992114084E-09 + COV -7.007653075390621E-10 -7.052675566598593E-09 -9.234745627461765E-08 + COV 1.199214466204667E-10 7.911720695845702E-10 1.071094770286801E-08 + COV 8.192142461689422E-09 1.068691763405510E-07 1.400409464536380E-06 + COR 1.000000000000000E+00 9.999998969422654E-01 9.998647194887070E-01 + COR -8.267289597683575E-01 -9.977655968989192E-01 -9.999998006809782E-01 + COR 1.000000000000000E+00 9.998650259282418E-01 -8.267641385388432E-01 + COR -9.977829950739745E-01 -9.999994776953000E-01 1.000000000000000E+00 + COR -8.199146282139559E-01 -9.983886357849586E-01 -9.998662046276492E-01 + COR 9.999999999999998E-01 7.982221403925573E-01 8.265173047750388E-01 + COR 1.000000000000000E+00 9.977602443962413E-01 1.000000000000000E+00 diff --git a/src/adam_core/orbits/query/tests/testdata/neocc/2024YR4.ke1 b/src/adam_core/orbits/query/tests/testdata/neocc/2024YR4.ke1 new file mode 100644 index 00000000..c6a8126b --- /dev/null +++ b/src/adam_core/orbits/query/tests/testdata/neocc/2024YR4.ke1 @@ -0,0 +1,36 @@ +format = 'OEF2.0' ! file format +rectype = 'ML' ! record type (1L/ML) +refsys = ECLM J2000 ! default reference system +END_OF_HEADER +2024YR4 +! Keplerian elements: a, e, i, long. node, arg. peric., mean anomaly + KEP 2.5158127507489616E+00 6.6154036821914619E-01 3.4081393687180 271.3655954496424 134.3614240204325 4.0403920526717883E+01 + MJD 60800.000000000 TDT + MAG 23.876 0.150 +! Non-gravitational parameters: model used, number of model parameters, dimension + LSP 0 0 6 +! PERIHELION 8.5150105724807035E-01 +! APHELION 4.1801244442498522E+00 +! ANODE 1.6132920678553648E+00 +! DNODE -1.6139338737144644E-02 +! MOID 2.8281976977061222E-03 +! PERIOD 1.4575246142278593E+03 +! PHA F +! VINFTY 14.2161102117779 +! U_PAR 5.5 +! ORB_TYPE Apollo +! RMS 1.45945E-04 2.08511E-05 7.80533E-05 1.08159E-05 9.07220E-05 3.57225E-03 + COV 2.129990103626278E-08 3.043103695236090E-09 1.138994073085263E-08 + COV -1.297300567885438E-09 -1.321094812357632E-08 -5.213516734886736E-07 + COV 4.347664336862408E-10 1.627274457493249E-09 -1.853526029216412E-10 + COV -1.887473042074563E-09 -7.448518590163292E-08 6.092321667952164E-09 + COV -6.879908552449990E-10 -7.069797588501348E-09 -2.787885242390572E-07 + COV 1.169847013231039E-10 7.781995171805923E-10 3.175091792990313E-08 + COV 8.230474520730192E-09 3.233601008844550E-07 1.276097850815426E-05 + COR 1.000000000000000E+00 9.999998967955239E-01 9.998647520507938E-01 + COR -8.218400094356861E-01 -9.977753189147101E-01 -9.999999781092901E-01 + COR 9.999999999999999E-01 9.998650578225570E-01 -8.218757198089662E-01 + COR -9.977926872410703E-01 -9.999998019539900E-01 9.999999999999998E-01 + COR -8.149420314930980E-01 -9.983966836512449E-01 -9.998652884032685E-01 + COR 1.000000000000000E+00 7.930744967922404E-01 8.217690139449345E-01 + COR 1.000000000000000E+00 9.977735927640640E-01 1.000000000000000E+00