Skip to content

Using the Python package

The lunartrace package is the numerical authority of the project. Downstream readers consume its results and validated projections; they do not reimplement its rules. This guide shows how to call the public functions. Every signature, argument and raised exception is in the generated Python API reference, which is built from the source docstrings.

Run scripts with the project environment, for example uv run --frozen python my_script.py. The slope-quality functions are imported from Python. The one console script, lunartrace, belongs to the temporal Study.

The temporal PRE/POST Study has its own section. lt.temporal.study(...) compiles it in one call, and its frontiers, why answers, saved files and replay are covered in The one-call Study.

NeedUseAPI page
Evaluate grids you already hold in memoryslope_quality.evaluateslope_quality
Evaluate from files, with optional frozen-hash checksslope_quality.run_pathsslope_quality
Run the frozen Site01 study with CAS verification and a receiptstudy.run_studystudy
Build a summary projection from canonical result bytesstudy.build_projectionstudy
Emit per-cell raster sidecarsraster_projection.emit_from_manifestraster_projection
Compile a temporal PRE/POST Study, screen its frontiers, save and replay itlunartrace.temporal.studyThe one-call Study
Model the cross-client contractslunartrace.projectionprojection
Read the standing levelslunartrace.standingstanding

evaluate is the in-memory interface. It assumes that its Grid and RoiSet inputs are already verified. Construct a Grid from an array, an affine transform, a CRS and a label, and an RoiSet from closed polygons:

from lunartrace.science import slope_quality as sq
slope = sq.Grid(slope_array, transform, crs, "my-slope")
rms = sq.Grid(rms_array, transform, crs, "my-rms")
rois = sq.RoiSet((polygon,), "my-rois")
result = sq.evaluate(slope, rms, rois, taus=(0.5, 2.0))
for row in result.rows:
print(row.roi, row.tau, row.joint_cells, row.included_cells, row.included_fraction)

Each Row carries the ROI and τ, the ROI, joint and included cell counts, the valid-cell fraction, slope quantiles and mean, and the histogram. The label "union" is the union of all ROIs. A None mean or quantile means that no cell was included. Do not treat a None as zero.

When the inputs come from files, use run_paths. It loads them and can check caller-supplied SHA-256 values against the bytes:

from pathlib import Path
from lunartrace.science import slope_quality as sq
frozen = {"slope": "<sha256>", "slope_rms": "<sha256>", "roi_shp": "<sha256>"}
result = sq.run_paths(
Path("slope.tif"), Path("slope_rms.tif"), Path("roi.shp"), frozen=frozen
)

The hashes you supply are caller identity. run_paths checks them, but it does not establish that the bytes came from a frozen source. For that, use STUDY.

run_study is the path with custody. It reads a source-witness manifest, resolves each role blob from the local content-addressed store, re-hashes every blob, and writes result.json and an execution receipt:

import os
from pathlib import Path
from lunartrace.science.study import run_study
receipt = run_study(
Path("research/sources/pgda78-site01.manifest.json"),
Path(os.environ["LUNARTRACE_SOURCE_STORE"]),
Path(".build/site01-study"),
)
print(receipt["status"], receipt["result_sha256"])

The receipt’s status is METHOD_EXECUTED. Its bytes differ between runs because it records timestamps and the environment. The result.json bytes are deterministic and match the documented result hash for the same inputs. Read the workflows guide for what a receipt does and does not establish.

load_manifest and resolve_inputs expose the same manifest and CAS resolution steps separately, if you need them without running the method.

build_projection wraps canonical result bytes with provenance from the witness and validates the typed projection model. The model classes live in lunartrace.projection. They are frozen Pydantic models with extra fields forbidden, so a misspelled field is an error, not a silently dropped value.

The Standing type is a literal union of METHOD_EXECUTED, NUMERIC_REPRODUCED, SCIENCE_VERTICAL_QUALIFIED and BLOCKED. A client must not raise the evidence level. Choosing a standing is the caller’s assertion, and it has to match the evidence that exists.

Per-cell raster projections are built by raster_projection. encode_layers applies the same validity and inclusion rules and encodes slope values as little-endian float32 only when that conversion is lossless. write_projection validates the manifest and writes the JSON with its binary sidecars.

Inputs outside the method’s preconditions raise MethodInputError, a subclass of ValueError. Examples are a non-finite or negative τ, or grids that are not compatible with one another. Cell-level rules are applied as data rules rather than errors: a slope outside 0 to 90 degrees, or a non-positive slope RMS, makes that cell invalid and it is excluded from the denominator. Nothing is clipped or interpolated. Catch this exception only to report or to choose a different input; do not catch it to substitute a default.

  • Angles are degrees. τ is a slope-RMS cutoff in degrees, not propagated uncertainty.
  • Counts and included_fraction are cells and fractions of jointly valid cells. Neither is a physical area.
  • The histogram uses 2° bins from 0 to 90 degrees.
  • A standing is a label, not a computed property. Admission, landing safety and physical area are not established by these functions.
  • Method: the cell rules these functions implement.
  • Provenance: what the witness, CAS and receipt establish.
  • Command line: the same operations as module entry points.