digest2 2.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. digest2-2.2.1/MANIFEST.in +7 -0
  2. digest2-2.2.1/PKG-INFO +418 -0
  3. digest2-2.2.1/README.md +384 -0
  4. digest2-2.2.1/digest2/common.c +144 -0
  5. digest2-2.2.1/digest2/common.h +17 -0
  6. digest2-2.2.1/digest2/d2ades.c +279 -0
  7. digest2-2.2.1/digest2/d2ades.h +49 -0
  8. digest2-2.2.1/digest2/d2cli.c +424 -0
  9. digest2-2.2.1/digest2/d2lib.c +372 -0
  10. digest2-2.2.1/digest2/d2lib.h +68 -0
  11. digest2-2.2.1/digest2/d2math.c +1256 -0
  12. digest2-2.2.1/digest2/d2model.c +262 -0
  13. digest2-2.2.1/digest2/d2model.h +32 -0
  14. digest2-2.2.1/digest2/d2modelio.c +263 -0
  15. digest2-2.2.1/digest2/d2mpc.c +249 -0
  16. digest2-2.2.1/digest2/digest2.c +639 -0
  17. digest2-2.2.1/digest2/digest2.h +236 -0
  18. digest2-2.2.1/population/MPC.config +158 -0
  19. digest2-2.2.1/population/digest2.model.csv +3 -0
  20. digest2-2.2.1/pyproject.toml +43 -0
  21. digest2-2.2.1/setup.cfg +4 -0
  22. digest2-2.2.1/setup.py +46 -0
  23. digest2-2.2.1/src/digest2/__init__.py +39 -0
  24. digest2-2.2.1/src/digest2/_extension.c +351 -0
  25. digest2-2.2.1/src/digest2/core.py +341 -0
  26. digest2-2.2.1/src/digest2/data/MPC.config +158 -0
  27. digest2-2.2.1/src/digest2/data/digest2.model.csv +3 -0
  28. digest2-2.2.1/src/digest2/filters.py +162 -0
  29. digest2-2.2.1/src/digest2/model.py +125 -0
  30. digest2-2.2.1/src/digest2/observation.py +359 -0
  31. digest2-2.2.1/src/digest2/population.py +726 -0
  32. digest2-2.2.1/src/digest2/result.py +74 -0
  33. digest2-2.2.1/src/digest2.egg-info/PKG-INFO +418 -0
  34. digest2-2.2.1/src/digest2.egg-info/SOURCES.txt +41 -0
  35. digest2-2.2.1/src/digest2.egg-info/dependency_links.txt +1 -0
  36. digest2-2.2.1/src/digest2.egg-info/requires.txt +16 -0
  37. digest2-2.2.1/src/digest2.egg-info/top_level.txt +1 -0
  38. digest2-2.2.1/tests/test_core.py +496 -0
  39. digest2-2.2.1/tests/test_digest2_cli.py +56 -0
  40. digest2-2.2.1/tests/test_extension.py +170 -0
  41. digest2-2.2.1/tests/test_filters.py +88 -0
  42. digest2-2.2.1/tests/test_observation.py +157 -0
  43. digest2-2.2.1/tests/test_population.py +444 -0
@@ -0,0 +1,7 @@
1
+ include README.md
2
+ include digest2/*.c
3
+ include digest2/*.h
4
+ recursive-include src/digest2 *.c *.py
5
+ recursive-include src/digest2/data *
6
+ include population/digest2.model.csv
7
+ include population/MPC.config
digest2-2.2.1/PKG-INFO ADDED
@@ -0,0 +1,418 @@
1
+ Metadata-Version: 2.4
2
+ Name: digest2
3
+ Version: 2.2.1
4
+ Summary: NEO orbit classification from short-arc astrometric tracklets
5
+ Author: Minor Planet Center
6
+ License: Public Domain
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Science/Research
9
+ Classifier: License :: Public Domain
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: C
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Scientific/Engineering :: Astronomy
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: numpy
22
+ Requires-Dist: astropy
23
+ Provides-Extra: filters
24
+ Requires-Dist: pandas; extra == "filters"
25
+ Provides-Extra: test
26
+ Requires-Dist: pytest; extra == "test"
27
+ Requires-Dist: numpy; extra == "test"
28
+ Requires-Dist: astropy; extra == "test"
29
+ Provides-Extra: all
30
+ Requires-Dist: pandas; extra == "all"
31
+ Requires-Dist: pytest; extra == "all"
32
+ Requires-Dist: numpy; extra == "all"
33
+ Requires-Dist: astropy; extra == "all"
34
+
35
+ # digest2
36
+
37
+ NEO orbit classification from short-arc astrometric tracklets.
38
+ Available as both a C command-line tool and a pip-installable Python package.
39
+
40
+ digest2 is a fast short-arc orbit classifier for minor planets, primarily used to identify Near-Earth Object (NEO) candidates from astrometric tracklets (groups of 2+ observations of the same object over a short time). It has been in operational use at the Minor Planet Center for over 15 years and is a key component of the NEO discovery workflow.
41
+
42
+ Given a set of observations, digest2 outputs a score (0-100) for each of 14 orbit classes, representing the pseudo-probability that the object belongs to that class. Objects scoring D2 >= 65 for the NEO class are posted to the NEO Confirmation Page (NEOCP) for follow-up.
43
+
44
+ **References:**
45
+ - Keys et al. 2019, "The digest2 NEO Classification Code" (PASP 131, 064501) -- [arXiv:1904.09188](https://arxiv.org/abs/1904.09188)
46
+ - Shober, Cloete, Veres 2023, "Improvement of digest2 NEO Classification Code" -- [arXiv:2309.16407](https://arxiv.org/abs/2309.16407)
47
+
48
+ **Authors:** Sonia Keys (original), with contributions from Carl Hergenrother, Robert McNaught, David Asher. ADES support added by Richard Cloete and Peter Veres.
49
+
50
+ **License:** Public domain.
51
+
52
+ ---
53
+
54
+ ## Python Package (recommended)
55
+
56
+ ```bash
57
+ pip install digest2
58
+ ```
59
+
60
+ ```python
61
+ from digest2 import Digest2
62
+
63
+ with Digest2() as d2:
64
+ results = d2.classify_file("observations.obs")
65
+ for r in results:
66
+ print(r.designation, r.noid.NEO, r.noid.MB1)
67
+ ```
68
+
69
+ The `digest2` Python package wraps a C scoring engine.
70
+ Pre-built wheels are available on PyPI for common platforms
71
+ (Linux, macOS, Windows), so most users get a ready-to-use binary with `pip install digest2`.
72
+ If no wheel matches your platform or Python version,
73
+ pip will automatically compile the C code from the source distribution -
74
+ this requires a local C compiler (e.g., gcc or clang) but no external C libraries such as libxml2.
75
+
76
+
77
+ ### Python API
78
+
79
+ - **`Digest2(model_path=None, config_path=None, obscodes_path=None, repeatable=True, no_threshold=False)`** -- Stateful classifier; auto-discovers bundled model data. Set `no_threshold=True` to disable per-observation RMS ceiling clamping.
80
+ - **`d2.classify_tracklet(observations)`** -- Classify a list of `Observation` objects. Returns `ClassificationResult`.
81
+ - **`d2.classify_file(filepath)`** -- Classify all tracklets in an MPC 80-col or ADES XML file. Returns `List[ClassificationResult]`.
82
+ - **`classify(input, ...)`** -- One-shot convenience function.
83
+ - **`parse_mpc80(line)`** / **`parse_mpc80_file(path)`** -- Parse MPC 80-column observations.
84
+ - **`parse_ades_xml(path)`** -- Parse ADES XML observations.
85
+ - **`digest2.filters`** -- NEOCP threshold filtering tools (requires `pip install digest2[filters]`).
86
+
87
+ ### Development Setup
88
+
89
+ ```bash
90
+ cd digest2
91
+ pip install -e '.[test]'
92
+
93
+ # Download observatory codes (one-time)
94
+ curl -o digest2/digest2.obscodes https://minorplanetcenter.net/iau/lists/ObsCodes.html
95
+
96
+ # Run tests
97
+ pytest tests/ -v
98
+ ```
99
+
100
+ ### Releasing to PyPI
101
+
102
+ Three GitHub Actions workflows handle CI and publishing for the Python package:
103
+
104
+ 1. **Tests** (`digest2-python-test.yml`) -- Runs `pytest` on every pull request and on pushes to `main` that modify `digest2/` files.
105
+
106
+ 2. **TestPyPI** (`digest2-python-testpypi.yml`) -- On every push to a PR branch that modifies `digest2/`, wheels and an sdist are built for Linux, macOS, and Windows, version-suffixed with `.devN`, and published to [TestPyPI](https://test.pypi.org/project/digest2/). Reviewers can install a pre-release build with:
107
+ ```bash
108
+ pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ digest2
109
+ ```
110
+
111
+ 3. **PyPI release** (`digest2-python-release.yml`) -- Triggered when a GitHub Release is published with a tag matching `digest2-v*`. Builds production wheels and sdist, then publishes to [PyPI](https://pypi.org/project/digest2/).
112
+
113
+ **To release a new version:**
114
+
115
+ 1. Update the version in `pyproject.toml` (e.g., `version = "2.2.0"`).
116
+ 2. Open a PR with the version bump (and any other changes) and merge it into `main`.
117
+ 3. Go to the repository's [Releases page](https://github.com/Smithsonian/mpc-public/releases) and create a new release:
118
+ - **Tag:** `digest2-v2.2.0` (must start with `digest2-v`)
119
+ - **Target:** `main`
120
+ - **Title/notes:** Describe what changed in this release.
121
+ 4. Publishing the release automatically triggers the workflow, which builds wheels for all platforms and uploads them to PyPI.
122
+
123
+ ### Python Package Structure
124
+
125
+ ```
126
+ src/digest2/
127
+ ├── __init__.py # Package init, imports Digest2, classify, Scores, ClassificationResult
128
+ ├── _extension.c # CPython C extension (low-level bindings to d2lib)
129
+ ├── core.py # High-level API: Digest2 class, classify() function
130
+ ├── result.py # ClassificationResult and Scores dataclasses
131
+ ├── observation.py # Observation dataclass, MPC80/ADES parsers
132
+ ├── model.py # Model/obscodes/config path resolution
133
+ ├── filters.py # NEOCP filter tools (from NEOCP_filters/)
134
+ └── data/
135
+ └── MPC.config # Bundled per-site observatory errors
136
+ ```
137
+
138
+ ### C Library API (d2lib)
139
+
140
+ The files `d2lib.h` / `d2lib.c` provide a clean, non-threaded library interface used by the Python extension:
141
+
142
+ - `d2_init(model_csv, obscodes)` -- Load model and observatory data
143
+ - `d2_score_observations(obs, n, classes, n_classes, is_ades)` -- Score a tracklet
144
+ - `d2_cleanup()` -- Release resources
145
+ - `d2_configure()` -- Set observatory errors, repeatable mode, noThreshold flag
146
+ - No libxml2 or pthreads dependency (XML parsing done in Python)
147
+
148
+ ### Key Design Decisions
149
+
150
+ - **Existing CLI is unchanged.** `make` in `digest2/digest2/` still builds the same binary.
151
+ - **Preprocessor guards** (`D2_NO_LIBXML`, `D2_NO_REGEX`) allow building without libxml2/regex.
152
+ - **Global state is managed** by `d2_init()`/`d2_cleanup()` -- single-threaded library mode.
153
+ - **Band correction** matches C code exactly (common.c `updateMagnitude`).
154
+ - **MJD calculation** uses C-style truncation-toward-zero integer division.
155
+
156
+ ---
157
+
158
+ ## C Command-Line Tool
159
+
160
+ ### Building from Source
161
+
162
+ Requirements:
163
+ - C99-capable C compiler (e.g., `gcc` or `clang`)
164
+ - `make`
165
+ - `libxml2` development headers (`libxml2-dev` or `libxml2-devel`)
166
+ - Optional: internet connection to download latest observatory codes from the MPC website.
167
+
168
+ ```bash
169
+ cd digest2/digest2
170
+ make # Produces the `digest2` executable
171
+ ```
172
+
173
+ Ensure the runtime data files are alongside the executable:
174
+ - `digest2.model` (or `digest2.model.csv`), and `MPC.config` (found under `digest2/population/`; updated versions can be copied in when available).
175
+
176
+ Platform notes:
177
+ - The provided `Makefile` is minimal and may require small tweaks for non-Linux platforms (see `digest2/digest2/BUILDING.md` for details).
178
+ - **libxml2** is required for ADES XML parsing. Install the development package for your platform:
179
+ - Debian/Ubuntu: `sudo apt-get install libxml2 libxml2-dev`
180
+ - RHEL/CentOS/Fedora: `sudo dnf install libxml2 libxml2-devel`
181
+ - macOS: `brew install libxml2` (ensure headers are on your include path via `pkg-config`)
182
+
183
+ ### Usage
184
+
185
+ ```bash
186
+ # MPC 80-column format
187
+ ./digest2 sample.obs
188
+
189
+ # ADES XML format
190
+ ./digest2 sample.xml
191
+
192
+ # With config file (per-observatory errors)
193
+ ./digest2 -c MPC.config sample.obs
194
+
195
+ # From stdin
196
+ cat sample.obs | ./digest2 -
197
+
198
+ # Generate binary model from CSV (faster subsequent loads)
199
+ ./digest2 -m digest2.model
200
+ ```
201
+
202
+ Run `./digest2 sample.obs` to verify the build. Expected output (small differences may occur):
203
+ ```
204
+ Desig. RMS Int NEO N22 N18 Other Possibilities
205
+ K16S99K 0.73 0 2 1 0 (MC 2) (MB1 93) (MB2 3) (JFC <1)
206
+ ```
207
+
208
+ Notes:
209
+ - If you have an internet connection, `digest2` will download the latest observatory parallax data from the Minor Planet Center. Otherwise, download `ObsCodes.html` and place it in the current directory as `digest2.obscodes`.
210
+ - To execute from a different directory, use the `-p` option: `./digest2 some.obs -p '/path/to/data'`.
211
+ - Run `./digest2 --help` for full command-line help.
212
+ - More detailed options can be found in [digest2/OPERATION.md](digest2/OPERATION.md).
213
+
214
+ ### Input Formats
215
+
216
+ 1. **MPC 80-column** (`.obs`): Fixed-width format with packed designation, date, RA/Dec, magnitude, observatory code
217
+ 2. **ADES XML** (`.xml`): Rich format with per-observation uncertainties (rmsRA, rmsDec), roving/satellite observer support
218
+
219
+ ### Config File Keywords
220
+
221
+ | Keyword | Description |
222
+ |---------|-------------|
223
+ | `headings`/`noheadings` | Toggle column headers in output |
224
+ | `rms` | Output great-circle RMS of tracklet |
225
+ | `rmsPrime` | Output RMS from ADES-provided uncertainties |
226
+ | `raw` | Output raw population scores |
227
+ | `noid` | Output no-ID scores (default) |
228
+ | `repeatable`/`random` | Deterministic vs stochastic Monte Carlo seeding |
229
+ | `obserr` | Default observational error (arcsec), default 1.0 |
230
+ | `obserrXXX` | Per-observatory error (e.g., `obserrF51=0.3`) |
231
+ | `poss` | Show "Other Possibilities" column |
232
+ | `noThreshold` | Accept ADES uncertainties without floor/ceiling clamping |
233
+
234
+ ---
235
+
236
+ ## Algorithm Overview
237
+
238
+ 1. **Motion vector & photometry:** Computes a motion vector from the first and last observation, and a composite V magnitude from available photometry (default 21 if none).
239
+
240
+ 2. **Statistical ranging:** Generates many trial orbits consistent with the observed motion, each with an absolute magnitude (H) consistent with the apparent brightness.
241
+
242
+ 3. **Histogram binning:** Each trial orbit is located in a 4D binned model of the Solar System (dimensions: q, e, i, H). Bins are tagged as "reachable" for each orbit class.
243
+
244
+ 4. **Iterative search:** Orbits are generated to explore the full solution space, terminating when diminishing returns in discovering new bins.
245
+
246
+ 5. **Population scoring (raw):** The population of tagged bins for a given class, divided by the total population of all tagged bins, gives the raw score (x100).
247
+
248
+ 6. **No-ID scoring (noid):** Same as raw, but uses the estimated *undiscovered* population (total minus known objects with sky uncertainty < 1 arcmin). This is the default score and represents the probability that an *unidentified* tracklet belongs to a class.
249
+
250
+ ### Model Dimensions
251
+
252
+ The population histogram is binned in 4 dimensions:
253
+ - **q** (perihelion): 29 bins
254
+ - **e** (eccentricity): 8 bins
255
+ - **i** (inclination): 11 bins
256
+ - **H** (absolute magnitude): 18 bins
257
+
258
+ Total: 29 x 8 x 11 x 18 = 45,936 bins per class, times 15 classes.
259
+
260
+ ### Orbit Classes (14 + "MPC Interest")
261
+
262
+ | Abbr | Description |
263
+ |------|-------------|
264
+ | Int | MPC Interest (q<1.3 OR e>0.5 OR i>=40 OR Q>10) |
265
+ | NEO | Near-Earth Object (q < 1.3 AU) |
266
+ | N22 | NEO with H <= 22 |
267
+ | N18 | NEO with H <= 18 |
268
+ | MC | Mars Crosser |
269
+ | Hun | Hungaria group |
270
+ | Pho | Phocaea group |
271
+ | MB1 | Inner Main Belt |
272
+ | Pal | Pallas group |
273
+ | Han | Hansa group |
274
+ | MB2 | Middle Main Belt |
275
+ | MB3 | Outer Main Belt |
276
+ | Hil | Hilda group |
277
+ | JTr | Jupiter Trojan |
278
+ | JFC | Jupiter Family Comet |
279
+
280
+ ---
281
+
282
+ ## NEOCP Filters
283
+
284
+ Post-processing tools that apply threshold-based filtering to digest2 output to separate likely NEOs from non-NEOs, using the methods documented in [Veres et al. (2025)](https://arxiv.org/abs/2505.11910).
285
+
286
+ **Requirements:** Python 3.6+, pandas (`pip install pandas` or `pip install digest2[filters]`)
287
+
288
+ **Tools:**
289
+ - `find_filter.py` -- Trains optimal per-class thresholds from labeled NEOCP data. Reads a digest2 CSV and produces `optimal_thresholds.json`.
290
+ - `neocp_filter.py` -- Applies thresholds to new digest2 output to flag likely non-NEOs for removal from NEOCP.
291
+
292
+ **Sample data:**
293
+ - `digest_data_19-24.csv` -- Training data (2019-2023 NEOCP)
294
+ - `digest_data_24.csv` -- Test data (2024 NEOCP)
295
+ - `optimal_thresholds.json` -- Pre-computed thresholds
296
+
297
+ ### End-to-End Example
298
+
299
+ 1. Create a config file `digest2.conf` in the directory where the `digest2` binary lives:
300
+
301
+ ```
302
+ repeatable
303
+ norms
304
+ raw
305
+ noid
306
+ Int
307
+ NEO
308
+ MC
309
+ Hun
310
+ Pho
311
+ MB1
312
+ Pal
313
+ Han
314
+ MB2
315
+ MB3
316
+ Hil
317
+ JTr
318
+ JFC
319
+ ```
320
+
321
+ 2. Run `digest2` on an ADES XML file and save the output:
322
+
323
+ ```bash
324
+ ./digest2 sample.xml -c digest2.conf > sample.digest2
325
+ ```
326
+
327
+ 3. Convert the output to the CSV format expected by the filter tools:
328
+
329
+ ```python
330
+ with open("sample.digest2", "r") as infile:
331
+ lines = infile.readlines()[2:] # skip header lines
332
+
333
+ output_lines = []
334
+ for line in lines:
335
+ fields = line.strip().split()
336
+ fields.append("0") # Add class column (placeholder)
337
+ output_lines.append(",".join(fields))
338
+
339
+ with open("sample.digest2.csv", "w") as outfile:
340
+ outfile.write("trksub,Int1,Int2,Neo1,Neo2,MC1,MC2,Hun1,Hun2,Pho1,Pho2,"
341
+ "MB1_1,MB1_2,Pal1,Pal2,Han1,Han2,MB2_1,MB2_2,MB3_1,MB3_2,"
342
+ "Hil1,Hil2,JTr1,JTr2,JFC1,JFC2,class\n")
343
+ for line in output_lines:
344
+ outfile.write(line + "\n")
345
+ ```
346
+
347
+ 4. Apply the filter:
348
+
349
+ ```bash
350
+ python NEOCP_filters/neocp_filter.py sample.digest2.csv NEOCP_filters/optimal_thresholds.json
351
+ ```
352
+
353
+ If the input contains non-NEO tracklets, `neocp_filter.py` will output those flagged as likely non-NEOs. NEO tracklets produce no output.
354
+
355
+ ---
356
+
357
+ ## Directory Structure
358
+
359
+ ```
360
+ digest2/
361
+ ├── digest2/ # C source code and build system
362
+ │ ├── Makefile # Build: `make` produces `digest2` executable
363
+ │ ├── digest2.c # Main program: CLI, threading, I/O orchestration
364
+ │ ├── d2math.c # Core algorithm: orbit generation, scoring, statistical ranging
365
+ │ ├── d2cli.c # Command-line parsing and config file reading
366
+ │ ├── d2model.c # Population model: orbit class definitions, bin partitions
367
+ │ ├── d2modelio.c # Model I/O: read CSV, read/write binary model
368
+ │ ├── d2mpc.c # MPC 80-column format parser, observatory code loading
369
+ │ ├── d2ades.c # ADES XML format parser (uses libxml2)
370
+ │ ├── common.c # Shared utilities (obscode parsing, magnitude conversion)
371
+ │ ├── digest2.h # Main header: observation, tracklet, perClass structs
372
+ │ ├── d2model.h # Model dimensions: QX=29, EX=8, IX=11, HX=18; 15 classes
373
+ │ ├── d2ades.h # ADES optical observation struct
374
+ │ ├── common.h # Shared function declarations
375
+ │ ├── ALGORITHM.md # Algorithm description
376
+ │ ├── BUILDING.md # Build instructions
377
+ │ ├── OPERATION.md # Usage, config file format, orbit class list
378
+ │ ├── sample.obs # Sample MPC 80-column input
379
+ │ ├── sample.xml # Sample ADES XML input
380
+ │ └── MPC.config -> ../population/MPC.config
381
+
382
+ ├── population/ # Solar System population model data
383
+ │ ├── digest2.model.csv # 4D histogram of SS populations (q, e, i, H bins)
384
+ │ ├── MPC.config # Config with per-observatory observational errors
385
+ │ ├── README.md
386
+ │ └── make_population/ # Tools to regenerate model from SSM + astorb.dat
387
+ │ ├── s3mbin.c # Processes Pan-STARRS Synthetic Solar System Model
388
+ │ ├── muk.c # Combines s3m.dat + astorb.dat -> digest2.model.csv
389
+ │ └── README.md
390
+
391
+ ├── NEOCP_filters/ # Post-processing filters for NEO/non-NEO classification
392
+ │ ├── find_filter.py # Derives optimal thresholds from labeled digest2 output
393
+ │ ├── neocp_filter.py # Applies thresholds to flag likely non-NEOs
394
+ │ ├── optimal_thresholds.json # Pre-computed thresholds
395
+ │ ├── digest_data_19-24.csv # Training data (2019-2023 NEOCP)
396
+ │ ├── digest_data_24.csv # Test data (2024 NEOCP)
397
+ │ ├── MPC.config
398
+ │ └── README.md
399
+
400
+ ├── src/digest2/ # Python package source
401
+ ├── tests/ # Python package tests
402
+ ├── pyproject.toml # Python package build configuration
403
+ └── README.md # This file
404
+ ```
405
+
406
+ ## Key Data Structures (C)
407
+
408
+ - **`observation`** -- Single astrometric observation: MJD, RA/Dec (radians), V magnitude, site index, rmsRA/rmsDec
409
+ - **`tracklet`** -- Group of observations of one object: designation, observation list, motion vector, scoring arrays, per-class results
410
+ - **`perClass`** -- Per-class scoring data: raw/noID scores, tagged bin arrays, population sums
411
+ - **`site`** -- Observatory parallax constants and observational error
412
+
413
+ ## Dependencies
414
+
415
+ - **C CLI:** C99 compiler, `libxml2` (for ADES XML parsing), pthreads, math library
416
+ - **Python package:** Python >= 3.8, C99 compiler for building from source (no libxml2 or pthreads needed)
417
+ - **Filters (optional):** pandas
418
+ - **Runtime data:** `digest2.model.csv`, `MPC.config`, `digest2.obscodes` (auto-downloaded from MPC)