asp-plot 1.19.0__tar.gz → 2.1.0__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.
- asp_plot-2.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- asp_plot-2.1.0/.github/ISSUE_TEMPLATE/problem-report.yml +44 -0
- asp_plot-2.1.0/.github/workflows/claude-code-review.yml +39 -0
- asp_plot-2.1.0/.github/workflows/claude.yml +49 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/.gitignore +3 -3
- {asp_plot-1.19.0 → asp_plot-2.1.0}/.readthedocs.yaml +1 -0
- asp_plot-2.1.0/AGENTS.md +81 -0
- asp_plot-1.19.0/AGENTS.md → asp_plot-2.1.0/ARCHITECTURE.md +47 -153
- {asp_plot-1.19.0 → asp_plot-2.1.0}/CHANGELOG.md +48 -0
- asp_plot-2.1.0/CLAUDE.md +1 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/PKG-INFO +5 -5
- {asp_plot-1.19.0 → asp_plot-2.1.0}/README.md +3 -3
- asp_plot-1.19.0/asp_plot/cli/asp_plot.py → asp_plot-2.1.0/asp_plot/cli/asp_report.py +2 -2
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/cli/request_planetary_altimetry.py +3 -3
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/cli/stereo_geom.py +16 -6
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/report.py +13 -5
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/report_captions.py +2 -2
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/report_pipeline.py +60 -41
- asp_plot-2.1.0/asp_plot/scenes.py +296 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/selections.py +1 -1
- asp_plot-2.1.0/asp_plot/sensors/__init__.py +298 -0
- asp_plot-2.1.0/asp_plot/sensors/aster.py +533 -0
- asp_plot-2.1.0/asp_plot/sensors/base.py +442 -0
- asp_plot-2.1.0/asp_plot/sensors/dimap.py +449 -0
- asp_plot-2.1.0/asp_plot/sensors/dimap_v1.py +610 -0
- asp_plot-2.1.0/asp_plot/sensors/rpc.py +653 -0
- asp_plot-1.19.0/asp_plot/sensors.py → asp_plot-2.1.0/asp_plot/sensors/worldview.py +77 -365
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/stereo.py +261 -99
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/stereo_geometry.py +366 -74
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/stereopair_metadata_parser.py +23 -7
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/utils.py +236 -58
- {asp_plot-1.19.0 → asp_plot-2.1.0}/conda-forge-recipe/meta.yaml +10 -5
- {asp_plot-1.19.0 → asp_plot-2.1.0}/pyproject.toml +5 -3
- asp_plot-1.19.0/asp_plot/scenes.py +0 -193
- {asp_plot-1.19.0 → asp_plot-2.1.0}/.flake8 +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/.github/workflows/release.yml +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/.github/workflows/run-tests.yml +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/.pre-commit-config.yaml +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/LICENSE +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/__init__.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/alignment.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/altimetry.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/altimetry_plots.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/altimetry_source.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/asp_log.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/bodies.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/bundle_adjust.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/cli/__init__.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/cli/csm_camera_plot.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/cli/gallery.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/csm_analysis.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/csm_camera.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/csm_io.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/gallery.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/icesat2_source.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/mapproject.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/planetary_source.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/asp_plot/processing_parameters.py +0 -0
- {asp_plot-1.19.0 → asp_plot-2.1.0}/environment.yml +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Problem report
|
|
2
|
+
description: Something in asp_plot is broken, wrong, or unclear
|
|
3
|
+
body:
|
|
4
|
+
- type: input
|
|
5
|
+
id: location
|
|
6
|
+
attributes:
|
|
7
|
+
label: Where did you hit this?
|
|
8
|
+
description: A docs page URL, a CLI command, an example notebook, or a module/function.
|
|
9
|
+
placeholder: e.g. `asp_report --directory ...`, or the stereo_geom example notebook
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: what-happened
|
|
14
|
+
attributes:
|
|
15
|
+
label: What happened?
|
|
16
|
+
description: What you did, what you expected, and what happened instead. Paste the full command and error output as text where possible.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: input
|
|
20
|
+
id: version
|
|
21
|
+
attributes:
|
|
22
|
+
label: asp_plot version
|
|
23
|
+
description: From `python -c "import asp_plot; print(asp_plot.__version__)"`.
|
|
24
|
+
placeholder: e.g. 1.1.0
|
|
25
|
+
validations:
|
|
26
|
+
required: false
|
|
27
|
+
- type: dropdown
|
|
28
|
+
id: install
|
|
29
|
+
attributes:
|
|
30
|
+
label: How did you install asp_plot?
|
|
31
|
+
options:
|
|
32
|
+
- conda-forge
|
|
33
|
+
- pip (PyPI)
|
|
34
|
+
- From source (git)
|
|
35
|
+
- Just reading the docs
|
|
36
|
+
validations:
|
|
37
|
+
required: false
|
|
38
|
+
- type: textarea
|
|
39
|
+
id: extra
|
|
40
|
+
attributes:
|
|
41
|
+
label: Anything else?
|
|
42
|
+
description: Screenshots, log files, links, ASP version.
|
|
43
|
+
validations:
|
|
44
|
+
required: false
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: Claude Code Review
|
|
2
|
+
|
|
3
|
+
# Runs once when a draft PR is marked ready for review.
|
|
4
|
+
# For further reviews, mention @claude in a PR comment (see claude.yml).
|
|
5
|
+
on:
|
|
6
|
+
pull_request:
|
|
7
|
+
types: [ready_for_review]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
claude-review:
|
|
11
|
+
# Optional: Filter by PR author
|
|
12
|
+
# if: |
|
|
13
|
+
# github.event.pull_request.user.login == 'external-contributor' ||
|
|
14
|
+
# github.event.pull_request.user.login == 'new-developer' ||
|
|
15
|
+
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
|
16
|
+
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
pull-requests: read
|
|
21
|
+
issues: read
|
|
22
|
+
id-token: write
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- name: Checkout repository
|
|
26
|
+
uses: actions/checkout@v4
|
|
27
|
+
with:
|
|
28
|
+
fetch-depth: 1
|
|
29
|
+
|
|
30
|
+
- name: Run Claude Code Review
|
|
31
|
+
id: claude-review
|
|
32
|
+
uses: anthropics/claude-code-action@v1
|
|
33
|
+
with:
|
|
34
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
35
|
+
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
|
|
36
|
+
plugins: 'code-review@claude-code-plugins'
|
|
37
|
+
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
|
|
38
|
+
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
|
39
|
+
# or https://code.claude.com/docs/en/cli-reference for available options
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: Claude Code
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issue_comment:
|
|
5
|
+
types: [created]
|
|
6
|
+
pull_request_review_comment:
|
|
7
|
+
types: [created]
|
|
8
|
+
issues:
|
|
9
|
+
types: [opened, assigned]
|
|
10
|
+
pull_request_review:
|
|
11
|
+
types: [submitted]
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
claude:
|
|
15
|
+
if: |
|
|
16
|
+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
17
|
+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
18
|
+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
|
19
|
+
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
pull-requests: read
|
|
24
|
+
issues: read
|
|
25
|
+
id-token: write
|
|
26
|
+
actions: read # Required for Claude to read CI results on PRs
|
|
27
|
+
steps:
|
|
28
|
+
- name: Checkout repository
|
|
29
|
+
uses: actions/checkout@v4
|
|
30
|
+
with:
|
|
31
|
+
fetch-depth: 1
|
|
32
|
+
|
|
33
|
+
- name: Run Claude Code
|
|
34
|
+
id: claude
|
|
35
|
+
uses: anthropics/claude-code-action@v1
|
|
36
|
+
with:
|
|
37
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
38
|
+
|
|
39
|
+
# This is an optional setting that allows Claude to read CI results on PRs
|
|
40
|
+
additional_permissions: |
|
|
41
|
+
actions: read
|
|
42
|
+
|
|
43
|
+
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
|
44
|
+
# prompt: 'Update the pull request description to include a summary of changes.'
|
|
45
|
+
|
|
46
|
+
# Optional: Add claude_args to customize behavior and configuration
|
|
47
|
+
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
|
48
|
+
# or https://code.claude.com/docs/en/cli-reference for available options
|
|
49
|
+
# claude_args: '--allowed-tools Bash(gh pr *)'
|
|
@@ -138,14 +138,14 @@ dmypy.json
|
|
|
138
138
|
scratch/
|
|
139
139
|
notebooks/**/*.parquet
|
|
140
140
|
notebooks/**/*.csv
|
|
141
|
-
CLAUDE
|
|
141
|
+
CLAUDE/
|
|
142
142
|
.claude/**
|
|
143
143
|
scripts/
|
|
144
144
|
/*.parquet
|
|
145
145
|
reports/regenerate_reports.sh
|
|
146
|
-
# Figure-selections sidecars written next to each report by `
|
|
146
|
+
# Figure-selections sidecars written next to each report by `asp_report`. These are
|
|
147
147
|
# regeneration byproducts that hardcode absolute local paths (dem_filename,
|
|
148
148
|
# parquet_cache), so they are not committed; a sanitized example is documented in
|
|
149
|
-
# docs/cli/
|
|
149
|
+
# docs/cli/asp_report.md instead.
|
|
150
150
|
reports/*_figure_selections.yml
|
|
151
151
|
*.csv
|
|
@@ -8,6 +8,7 @@ build:
|
|
|
8
8
|
pre_build:
|
|
9
9
|
- mkdir -p docs/examples/notebooks
|
|
10
10
|
- cp notebooks/WorldView/*.ipynb docs/examples/notebooks/
|
|
11
|
+
- cp notebooks/Pleiades/*.ipynb docs/examples/notebooks/
|
|
11
12
|
- cp notebooks/ASTER/*.ipynb docs/examples/notebooks/
|
|
12
13
|
- cp notebooks/LRO_NAC/*.ipynb docs/examples/notebooks/
|
|
13
14
|
- cp notebooks/Mars_MGS/*.ipynb docs/examples/notebooks/
|
asp_plot-2.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for AI coding agents (Claude Code and others) and new contributors. This file holds only what you can't infer from the code: commands, gotchas, external dependencies, and process. For the module-by-module codebase map and design rationale, read [ARCHITECTURE.md](ARCHITECTURE.md) on demand — and keep both files in sync with the code.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
`asp_plot` is a Python package for visualizing output from the NASA Ames Stereo Pipeline (ASP): diagnostic plots and comprehensive PDF reports covering stereo DEM results, bundle adjustment, CSM camera models, stereo acquisition geometry, DEM galleries, and altimetry comparison/alignment (ICESat-2 for Earth, LOLA for Moon, MOLA for Mars). Handles terrestrial and planetary sensors. Requires Python >= 3.11; published on PyPI and conda-forge. The version lives in `pyproject.toml` (exposed as `asp_plot.__version__`).
|
|
8
|
+
|
|
9
|
+
## Development Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Environment (installs the package editable with dev+docs extras)
|
|
13
|
+
conda env create -f environment.yml
|
|
14
|
+
conda activate asp_plot
|
|
15
|
+
pre-commit install # REQUIRED for development
|
|
16
|
+
|
|
17
|
+
# Tests
|
|
18
|
+
pytest # all tests; add -s to see print output
|
|
19
|
+
pytest tests/test_stereo.py::test_name # one file / one test
|
|
20
|
+
|
|
21
|
+
# Lint/format (pre-commit runs these on commit; manually:)
|
|
22
|
+
pre-commit run --all-files # black + flake8 + isort (profile: black)
|
|
23
|
+
|
|
24
|
+
# Rebuild after changing CLI tools or entry points
|
|
25
|
+
pip install -e ".[dev]"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Flake8 config is in `.flake8` (extends ignore: E203, E701); pre-commit further ignores E501, E722, E207.
|
|
29
|
+
|
|
30
|
+
To build the docs locally (Sphinx + MyST; hosted on ReadTheDocs, auto-built on push to `main`):
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# One-time: copy notebooks, reports, and figures for local preview
|
|
34
|
+
mkdir -p docs/examples/notebooks && cp notebooks/**/*.ipynb docs/examples/notebooks/
|
|
35
|
+
mkdir -p docs/_static/reports && cp reports/*.pdf docs/_static/reports/
|
|
36
|
+
mkdir -p docs/_extra/examples/figures && cp notebooks/figures/* docs/_extra/examples/figures/
|
|
37
|
+
|
|
38
|
+
sphinx-autobuild docs docs/_build/html --open-browser # or sphinx-build for a one-off
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Gotchas
|
|
42
|
+
|
|
43
|
+
- **ASP tools must be on PATH** for the workflows that wrap them: `stereo`/`parallel_stereo`, `bundle_adjust`, `point2dem`, `pc_align`, `geodiff`, `dg_mosaic` (called via `run_subprocess_command()`). **Append** the ASP bin directory to PATH rather than prepending: the ASP release bundles its own `python`, which would shadow your environment's interpreter and break imports.
|
|
44
|
+
- **Internet is required** for basemaps (contextily/Esri tiles), ICESat-2 requests (SlideRule), and ESA WorldCover sampling (public AWS S3 COGs). Tests must not depend on the network — basemap fetches are stubbed (#151).
|
|
45
|
+
- **Mars altimetry needs the `*_pts_csv.csv`** (with `PLANET_RAD`), never the `*_topo_csv.csv`: MOLA TOPOGRAPHY is referenced to the oblate areoid while ASP DEMs use the spherical IAU datum — a latitude-dependent offset up to ~10 km that pc_align cannot remove. The loader rejects the topo file with an explanatory error.
|
|
46
|
+
- **ASP's `mapproject` writes no log file**; its command is reconstructed from output GeoTIFF metadata (`mapproject.py`), not parsed from logs like the other tools.
|
|
47
|
+
- **Attribution vs sensor naming is deliberate**: copyright/attribution names the rights-holder (`detect_satellite_attribution()` → `"Vantor"` or `"Airbus DS"`), while readers in the `asp_plot/sensors/` package are named for the satellite family (WorldView, Pleiades). Don't reconcile them into one name (#137).
|
|
48
|
+
- **Package vs CLI naming is a deliberate split** (v2.0.0, #165): the *package* is `asp_plot` (`import asp_plot`, `pip install asp-plot`), the report *command* is `asp_report` (`asp_plot/cli/asp_report.py`). There is no `asp_plot` console script and no alias — don't "fix" either name to match the other. The other four CLIs (`stereo_geom`, `csm_camera_plot`, `request_planetary_altimetry`, `gallery`) are unprefixed and unchanged.
|
|
49
|
+
- **Airbus DIMAP quaternions are scalar-first** (`Q0` = scalar); they are reordered to the scalar-last `q1..q4` layout the roll/pitch/yaw code expects in `PleiadesMetadata.getAtt_df()`. Don't "fix" the reorder.
|
|
50
|
+
- **ASP multiview triangulation of mapprojected images needs `ISISROOT`** (observed with ASP 3.8.0-alpha, non-ISIS `-t pleiades` session): the joint triangulation aborts with an uncatchable `Isis::IException` (`$ISISROOT/IsisPreferences was not found`) that surfaces as a generic "Failed to run"/killed job. Workaround: `export ISISROOT=<ASP install root>` (the release bundles `IsisPreferences` there). Pair runs and raw-image multiview runs are unaffected; full write-up in a PR #155 comment.
|
|
51
|
+
|
|
52
|
+
## External Data Sources
|
|
53
|
+
|
|
54
|
+
- **ICESat-2 ATL06-SR** (Earth): requested through the SlideRule API; results cached as parquet next to the report.
|
|
55
|
+
- **LOLA (Moon) / MOLA (Mars)**: async queries to the ODE GDS REST API via the `request_planetary_altimetry` CLI — the user gets a download link by email, then passes the CSV to `asp_report --altimetry_csv`. Coordinates are east-positive 0–360 longitude, planetocentric latitude.
|
|
56
|
+
|
|
57
|
+
## Testing
|
|
58
|
+
|
|
59
|
+
Tests are in `tests/` with sample data in `tests/test_data/` (synthetic rasters, XML camera files, BA CSVs, ICESat-2 parquet, pc_align outputs, jitter data). Most modules have a matching `tests/test_<module>.py`; `test_imports.py` verifies everything imports. Some fixture derivatives (e.g. match-point CSVs next to `.match` files) are gitignored and regenerate during test runs — untracked files appearing under `tests/test_data/` after `pytest` are expected, don't commit them. Example notebooks in `notebooks/` are organized by sensor (WorldView, Pleiades, ASTER, LRO_NAC, Mars_MGS, Mars_MRO) — see ARCHITECTURE.md for what each demonstrates.
|
|
60
|
+
|
|
61
|
+
## Versioning and Release Process
|
|
62
|
+
|
|
63
|
+
Follow semantic versioning. To release:
|
|
64
|
+
1. Update version in `pyproject.toml`
|
|
65
|
+
2. Update `CHANGELOG.md` with version and date
|
|
66
|
+
3. Merge to `main`
|
|
67
|
+
|
|
68
|
+
The rest is automated: `release.yml` detects the version bump, creates a GitHub Release + tag, and publishes to PyPI via OIDC trusted publishing; conda-forge's autotick bot then opens a feedstock PR. PyPI trusted publishing and the conda-forge feedstock are already configured (reference recipe in `conda-forge-recipe/meta.yaml`).
|
|
69
|
+
|
|
70
|
+
**The autotick bot only bumps `version` and `sha256` — it never syncs dependencies or entry points.** So whenever you add/remove a runtime dependency in `pyproject.toml` or add/rename a `[project.scripts]` entry point, the feedstock's `recipe/meta.yaml` must be edited by hand in the same release (`requirements: run:` and `build: entry_points:` + the matching `test: commands:`). Otherwise the conda build *succeeds* and then fails its own test phase, conda-build moves the package to `broken/`, and **nothing is uploaded** — PyPI advances while conda-forge silently stalls on the last good version. This is not hypothetical: adding `pyyaml` in v1.16.0 (#121) went unmirrored and stalled conda-forge at 1.15.1 for five releases (1.16.0 → 1.19.0), with a red ✗ on the feedstock's default branch the whole time. After releasing, check <https://anaconda.org/conda-forge/asp-plot> actually advanced rather than assuming the bot handled it.
|
|
71
|
+
|
|
72
|
+
## Common File Patterns
|
|
73
|
+
|
|
74
|
+
ASP output files follow specific naming patterns (find them with the `glob_file()` utility):
|
|
75
|
+
- DEMs: `*-DEM.tif` or `*_dem.tif`
|
|
76
|
+
- Disparity: `*-F.tif`
|
|
77
|
+
- Match files: `*.match`
|
|
78
|
+
- Bundle adjust residuals: `*-initial_residuals_pointmap.csv`, `*-final_residuals_pointmap.csv`
|
|
79
|
+
- Log files: `*log-bundle_adjust*.txt`, `*log-stereo*.txt`, `*log-point2dem*.txt`
|
|
80
|
+
|
|
81
|
+
**Multi-view (>2 scene) runs** keep only the joint products (`*-PC.tif`, `*-DEM.tif`, `*-IntersectionErr.tif`) at the stereo-directory top level; the per-pair intermediates live one level down in `<prefix>-pairN/` (`N-L_sub.tif`, `N-R_sub.tif`, `N-D_sub.tif`, the `.match` file, `N-align-{L,R}.txt`, and an `N-stereo.default` config copy naming that pair's images). Discover them with `find_pair_directories()` rather than globbing — code that assumes the flat pair layout silently degrades to "missing files" placeholders (#160).
|