Study
lt.temporal.study(*, site, event, products, archive=None, box=...) returns a frozen
Study. It builds the Lunar ODE query, resolves the event to an event basis, obtains the source
pages and compiles the record with the unchanged v1 method.
Arguments
Section titled “Arguments”| Argument | Accepts | Rule |
|---|---|---|
site | (lat, lon) or a registered name such as "vikram" | The query box is the centre plus or minus box, rounded to 4 decimal places. |
event | "START/END" or a registered basis id | START and END are ISO UTC times ending in Z. END is exclusive. |
products | "IHID/IID/PT" | Exactly three non-empty parts. |
archive | None, a directory, or a packaged snapshot name | None fetches live. Anything else compiles offline. |
box | (dlat, dlon) | Half-widths in degrees. Default (0.005, 0.015). |
Coordinates are planetocentric, with east-positive longitude.
Site and box
Section titled “Site and box”A tuple and its registered name give the same query box. For Vikram the box is latitude -69.3791 to -69.3691 and longitude 32.305 to 32.335.
>>> import lunartrace as lt>>> call = dict(event="2023-08-23T12:33Z/12:35Z", products="LRO/LROC/CDRNAC4",... archive="vikram-2026-10-14")>>> by_tuple = lt.temporal.study(site=(-69.3741, 32.32), **call)>>> by_name = lt.temporal.study(site="vikram", **call)>>> by_tuple.digest == by_name.digestTrue>>> q = by_tuple.record["source"]["query"]>>> (q["min_lat"], q["max_lat"], q["west_lon"], q["east_lon"])(-69.3791, -69.3691, 32.305, 32.335)Event, and the event basis
Section titled “Event, and the event basis”The interval is half-open. END is not part of it, so 12:33Z/12:35Z is stored with
latest = 12:34:59.999999Z. The end may be just a clock time on the start date.
When the interval equals an event basis registered for the site, the study uses that basis with
its rationale, which cites the anchors (research/studies/vikram/ANCHORS.md). Vikram has four:
| Interval | Basis id |
|---|---|
2023-08-23T00:00Z/2023-08-24T00:00Z | vikram:utc-day |
2023-08-23T12:33Z/12:35Z | vikram:minute-envelope |
2023-08-23T12:33Z/12:34Z | vikram:nasa-dsn-minute |
2023-08-23T12:34Z/12:35Z | vikram:isro-minute |
You can pass the basis id as event instead of the interval. Any other interval is recorded
for what it is, an interval you supplied:
>>> import lunartrace as lt>>> call = dict(site="vikram", products="LRO/LROC/CDRNAC4", archive="vikram-2026-10-14")>>> by_id = lt.temporal.study(event="vikram:minute-envelope", **call)>>> by_interval = lt.temporal.study(event="2023-08-23T12:33Z/12:35Z", **call)>>> by_id.digest == by_interval.digestTrue>>> adhoc = lt.temporal.study(event="2023-08-23T12:00Z/13:00Z", **call)>>> adhoc.record["event_basis"]["basis_id"]'adhoc:2023-08-23T12:00Z/13:00Z'>>> adhoc.record["event_basis"]["rationale"]'Interval supplied by the caller.'Live and retained
Section titled “Live and retained”study.source_mode is "live" or "retained", and repr(study) prints it.
archive | Source | Network |
|---|---|---|
None | Lunar ODE now; the pages are kept in memory and can be saved | yes |
| a directory | the retained pages in it | no |
"vikram-2026-10-14" | the snapshot packaged with lunartrace | no |
A retained archive is checked before it is used: every page must match the SHA-256 in its receipt, and the receipt’s query must match the query you asked for. A live study is a new observation of a changing archive. It is never compared with the 14 October numbers.
import lunartrace as lt
live = lt.temporal.study(site=(-69.3741, 32.32), # no archive: fetches Lunar ODE now event="2023-08-23T12:33Z/12:35Z", products="LRO/LROC/CDRNAC4")live.source_mode # "live"live.save("live.study.json", sources=True)This is the only call on these pages that uses the network, and it asks the archive about the
present. The Vikram snapshot is the one to use when you want the numbers of 14 October 2026:
lt.temporal.packaged_archives() lists the snapshot names that ship with the package.
What raises
Section titled “What raises”Every refusal is a ValueError that says what was wrong.
>>> import lunartrace as lt>>> lt.temporal.study(site="vikram", event="2023-08-23T12:35Z/12:33Z",... products="LRO/LROC/CDRNAC4", archive="vikram-2026-10-14")Traceback (most recent call last): ...ValueError: event interval must end after it starts, got '2023-08-23T12:35Z/12:33Z'>>> lt.temporal.study(site="vikram", event="2023-08-23T12:33Z/12:35Z",... products="LRO/LROC", archive="vikram-2026-10-14")Traceback (most recent call last): ...ValueError: products must be 'IHID/IID/PT' with three non-empty parts, got 'LRO/LROC'Other refusals: a time without Z, a latitude outside -90 to 90, an unregistered site name, an
archive page whose bytes changed, and an archive fetched for a different query.