als-finder 0.0.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.
- als_finder-0.0.0/LICENSE +21 -0
- als_finder-0.0.0/MANIFEST.in +4 -0
- als_finder-0.0.0/PKG-INFO +447 -0
- als_finder-0.0.0/README.md +403 -0
- als_finder-0.0.0/setup.cfg +4 -0
- als_finder-0.0.0/setup.py +47 -0
- als_finder-0.0.0/src/als_finder/__init__.py +38 -0
- als_finder-0.0.0/src/als_finder/__main__.py +0 -0
- als_finder-0.0.0/src/als_finder/cli.py +1856 -0
- als_finder-0.0.0/src/als_finder/core/__init__.py +0 -0
- als_finder-0.0.0/src/als_finder/core/auth_manager.py +93 -0
- als_finder-0.0.0/src/als_finder/core/grid_manager.py +833 -0
- als_finder-0.0.0/src/als_finder/core/input_manager.py +95 -0
- als_finder-0.0.0/src/als_finder/core/local_catalog.py +101 -0
- als_finder-0.0.0/src/als_finder/core/quicklooks.py +219 -0
- als_finder-0.0.0/src/als_finder/core/stac_generator.py +163 -0
- als_finder-0.0.0/src/als_finder/core/standardization.py +765 -0
- als_finder-0.0.0/src/als_finder/data/__init__.py +0 -0
- als_finder-0.0.0/src/als_finder/data/ltbmu_boundary.gpkg +0 -0
- als_finder-0.0.0/src/als_finder/download.py +363 -0
- als_finder-0.0.0/src/als_finder/providers/__init__.py +111 -0
- als_finder-0.0.0/src/als_finder/providers/base.py +99 -0
- als_finder-0.0.0/src/als_finder/providers/earthdata.py +195 -0
- als_finder-0.0.0/src/als_finder/providers/gliht.py +237 -0
- als_finder-0.0.0/src/als_finder/providers/neon.py +257 -0
- als_finder-0.0.0/src/als_finder/providers/noaa.py +308 -0
- als_finder-0.0.0/src/als_finder/providers/opentopography.py +336 -0
- als_finder-0.0.0/src/als_finder/providers/usgs.py +218 -0
- als_finder-0.0.0/src/als_finder.egg-info/PKG-INFO +447 -0
- als_finder-0.0.0/src/als_finder.egg-info/SOURCES.txt +38 -0
- als_finder-0.0.0/src/als_finder.egg-info/dependency_links.txt +1 -0
- als_finder-0.0.0/src/als_finder.egg-info/entry_points.txt +2 -0
- als_finder-0.0.0/src/als_finder.egg-info/requires.txt +22 -0
- als_finder-0.0.0/src/als_finder.egg-info/top_level.txt +1 -0
- als_finder-0.0.0/tests/test_cli_tile.py +151 -0
- als_finder-0.0.0/tests/test_grid_manager.py +108 -0
- als_finder-0.0.0/tests/test_hierarchical_grid.py +162 -0
- als_finder-0.0.0/tests/test_provider_earthdata.py +48 -0
- als_finder-0.0.0/tests/test_provider_gliht.py +93 -0
- als_finder-0.0.0/tests/test_provider_neon.py +61 -0
als_finder-0.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jonathan Greenberg / University of Nevada, Reno
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: als-finder
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Summary: A high-performance, cloud-native CLI engine for discovering and parsing raw LiDAR point cloud metadata.
|
|
5
|
+
Home-page: https://github.com/cms-2024-hudak/als-finder
|
|
6
|
+
Author: Jonathan Greenberg
|
|
7
|
+
Author-email: jgreenberg@unr.edu
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: click
|
|
15
|
+
Requires-Dist: requests
|
|
16
|
+
Requires-Dist: geopandas
|
|
17
|
+
Requires-Dist: shapely
|
|
18
|
+
Requires-Dist: pyproj
|
|
19
|
+
Requires-Dist: python-dotenv
|
|
20
|
+
Requires-Dist: tqdm
|
|
21
|
+
Requires-Dist: pyogrio
|
|
22
|
+
Requires-Dist: pystac
|
|
23
|
+
Requires-Dist: stac-validator
|
|
24
|
+
Requires-Dist: psutil
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest; extra == "dev"
|
|
27
|
+
Requires-Dist: setuptools_scm; extra == "dev"
|
|
28
|
+
Requires-Dist: build; extra == "dev"
|
|
29
|
+
Provides-Extra: pdal
|
|
30
|
+
Requires-Dist: pdal; extra == "pdal"
|
|
31
|
+
Provides-Extra: all
|
|
32
|
+
Requires-Dist: pdal; extra == "all"
|
|
33
|
+
Dynamic: author
|
|
34
|
+
Dynamic: author-email
|
|
35
|
+
Dynamic: classifier
|
|
36
|
+
Dynamic: description
|
|
37
|
+
Dynamic: description-content-type
|
|
38
|
+
Dynamic: home-page
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
Dynamic: provides-extra
|
|
41
|
+
Dynamic: requires-dist
|
|
42
|
+
Dynamic: requires-python
|
|
43
|
+
Dynamic: summary
|
|
44
|
+
|
|
45
|
+
# als-finder
|
|
46
|
+
|
|
47
|
+
**A high-performance, cloud-native CLI engine for discovering, streaming, and partitioning raw LiDAR point cloud data across the globe.**
|
|
48
|
+
|
|
49
|
+
[](https://codespaces.new/cms-2024-hudak/als-finder)
|
|
50
|
+
|
|
51
|
+
`als-finder` gathers complete acquisition footprints (project boundaries), true WGS84 point densities, and metadata from **USGS 3DEP (EPT/COPC)**, **NOAA Digital Coast**, **NASA G-LiHT**, **NEON**, and **OpenTopography** into clean `.json` manifests, `QGIS`-ready `.gpkg` tables, and on-demand metric spatial tiles with automated Out-Of-Memory (OOM) protection.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 🚀 Quick Install
|
|
56
|
+
|
|
57
|
+
Because `als-finder` uses advanced C++ geospatial libraries (GDAL, PDAL, GEOS), **Conda** or **Docker** is the recommended installation method:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# 1. Create environment with all C++ and Python dependencies
|
|
61
|
+
conda create -n als-finder -c conda-forge python=3.11 geopandas pdal python-pdal pystac stac-validator psutil shapely pyproj tqdm pyogrio requests click python-dotenv laspy -y
|
|
62
|
+
|
|
63
|
+
# 2. Activate environment & install als-finder
|
|
64
|
+
conda activate als-finder
|
|
65
|
+
pip install git+https://github.com/cms-2024-hudak/als-finder.git
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
> [!TIP]
|
|
69
|
+
> 📖 **Full Installation Guide:** See [**docs/INSTALLATION.md**](docs/INSTALLATION.md) for Conda-Forge releases, Docker container runs, Singularity/Apptainer HPC setup, and Windows/WSL2 instructions.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 🧭 The Big-Data Architecture: The 4-Stage ALS Lifecycle
|
|
74
|
+
|
|
75
|
+
Traditional tools force researchers to download massive, multi-gigabyte survey archives before doing any work. `als-finder` is built from the ground up for **cloud-native lazy evaluation and HPC job arrays**:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
|
79
|
+
│ 1. DISCOVERY │ ──> │ 2. PLANNING │ ──> │ 3. ACQUISITION │ ──> │ 4. DERIVATIVE │
|
|
80
|
+
│ (search) │ │ (plan) │ │ (fetch) │ │ & MOSAIC │
|
|
81
|
+
└─────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘
|
|
82
|
+
• Federated APIs • Spatial tiling index • On-demand streaming • Crop buffers
|
|
83
|
+
• ROI & temporal • Memory risk audit • OOM auto-quadrants • gdalbuildvrt
|
|
84
|
+
• Provenance catalog • Slurm task lists • Sidecar crop bounds • Zero edge-effects
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## ⚡ Master Tutorial: End-to-End Walkthrough
|
|
90
|
+
|
|
91
|
+
This single, comprehensive tutorial walks through the complete lifecycle using a single workspace: `scratch/test_workspace`.
|
|
92
|
+
|
|
93
|
+
### Step 0: Extract the Bundled Example Area of Interest (AOI)
|
|
94
|
+
`als-finder` comes with a bundled Lake Tahoe Basin Management Unit (LTBMU) boundary polygon so you can follow along immediately:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Extract the example polygon (ltbmu_boundary.gpkg) to your current directory
|
|
98
|
+
als-finder get-example-roi
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### Step 1: Federated Discovery (`als-finder search`)
|
|
104
|
+
Search across all public LiDAR registries intersecting your AOI. Using `--cloud-native` filters exclusively for streaming-ready formats (USGS EPT / COPC), and `--dedup` eliminates duplicate survey records:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
als-finder search \
|
|
108
|
+
--roi ./ltbmu_boundary.gpkg \
|
|
109
|
+
--workspace scratch/test_workspace \
|
|
110
|
+
--cloud-native \
|
|
111
|
+
--dedup
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Console Output:**
|
|
115
|
+
```text
|
|
116
|
+
=================================================================================================================
|
|
117
|
+
LiDAR Data Search Results
|
|
118
|
+
=================================================================================================================
|
|
119
|
+
| Provider | Name | Date | Est (GB) | pts/m2 | Area km2 |
|
|
120
|
+
-----------------------------------------------------------------------------------------------------------------
|
|
121
|
+
| USGS_EPT | CA_SierraNevada_5_2022 | 2022-??-?? | 1380.20 | 29.1800 | 6347.47 |
|
|
122
|
+
| USGS_EPT | CA_SierraNevada_6_2022 | 2022-??-?? | 1136.46 | 26.2100 | 5819.74 |
|
|
123
|
+
| USGS_EPT | CA_SierraNevada_8_2022 | 2022-??-?? | 1171.62 | 25.1400 | 6255.39 |
|
|
124
|
+
| NASA_GLIHT | NASA G-LiHT Sierra Nevada / Lake Tahoe | 2022-07-18 | 30.73 | 32.5000 | 126.90 |
|
|
125
|
+
| USGS_EPT | NV_WestCentralEarthMRI_3_2020 | 2020-??-?? | 433.16 | 5.3400 | 10890.04 |
|
|
126
|
+
| USGS_EPT | CA_UpperSouthAmerican_Eldorado_2019 | 2019-??-?? | 2075.29 | 43.1600 | 6454.20 |
|
|
127
|
+
| NOAA_STAC | DigitalCoast_DAV:id_9452 | 2019-10-21 | 2075.29 | 46.7700 | 5954.91 |
|
|
128
|
+
| USGS_EPT | USGS_LPC_CA_NoCAL_Wildfires_B1_2018 | 2018-??-?? | 643.56 | 10.8900 | 7928.51 |
|
|
129
|
+
| NOAA_STAC | DigitalCoast_DAV:id_9036 | 2018-07-07 | 253.48 | 0.7800 | 43731.68 |
|
|
130
|
+
| USGS_EPT | USGS_LPC_NV_Reno_Carson_QL1_2017_LAS_2 | 2017-??-?? | 151.15 | 9.5400 | 2126.64 |
|
|
131
|
+
| USGS_EPT | CA_PlacerCo_2012 | 2012-??-?? | 36.96 | 3.9500 | 1254.54 |
|
|
132
|
+
=================================================================================================================
|
|
133
|
+
TOTAL DATASETS: 11 | ESTIMATED PAYLOAD: 9426.32 GB | QUERY TIME: 4.31s
|
|
134
|
+
-----------------------------------------------------------------------------------------------------------------
|
|
135
|
+
CATALOG TBL: scratch/test_workspace/catalog/catalog.gpkg
|
|
136
|
+
JSON METADATA: scratch/test_workspace/catalog/manifest.json
|
|
137
|
+
=================================================================================================================
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
> [!NOTE]
|
|
141
|
+
> **Zero Heavy Downloads:** Notice that 9.4 TB of data was discovered in 4 seconds. No heavy point cloud files were downloaded to your hard drive.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
### Step 2: Spatial Planning & Memory Risk Audit (`als-finder plan`)
|
|
146
|
+
Before launching jobs, use `als-finder plan` to inspect the study area's metric grid and audit memory safety against a target point budget (e.g. 4,000,000 points $\approx$ 4 GB RAM):
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
als-finder plan \
|
|
150
|
+
--workspace scratch/test_workspace \
|
|
151
|
+
--tile-size 500 \
|
|
152
|
+
--buffer-size 50 \
|
|
153
|
+
--max-points 4000000
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Console Output:**
|
|
157
|
+
```text
|
|
158
|
+
==================================================
|
|
159
|
+
ALS-FINDER SPATIAL PLANNING & GRID METRICS
|
|
160
|
+
==================================================
|
|
161
|
+
Master Tiles: 5,657
|
|
162
|
+
Total Leaf Tasks: 22,628
|
|
163
|
+
Tile ID Range: 0 to 5656
|
|
164
|
+
Tile Size: 500m (core)
|
|
165
|
+
Buffer Size: 50m (overlap)
|
|
166
|
+
Grid CRS: EPSG:32610
|
|
167
|
+
Target Tile ID: 0
|
|
168
|
+
Basename: CA_SierraNevada_5_2022_tile_E0737500_N4329500
|
|
169
|
+
Hive Directory: provider=USGS_EPT/dataset=CA_SierraNevada_5_2022/tilesize=500/buffer=50
|
|
170
|
+
Crop PDAL Bounds: ([737500.0, 738000.0], [4329000.0, 4329500.0])
|
|
171
|
+
Crop GDAL -te: 737500.0 4329000.0 738000.0 4329500.0
|
|
172
|
+
Grid File: scratch/test_workspace/catalog/grids/tilesize=500/buffer=50/grid.gpkg
|
|
173
|
+
--------------------------------------------------
|
|
174
|
+
MEMORY RISK AUDIT (PRE-FLIGHT):
|
|
175
|
+
Max Points Budget: 4,000,000
|
|
176
|
+
Est Points/Tile: 10,504,800
|
|
177
|
+
Subdivision: 5657 tiles exceed budget (split into 4 quadrants each)
|
|
178
|
+
Slurm Array Size: --array=1-22628
|
|
179
|
+
==================================================
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### Extracting Fields Directly for Shell Scripts (`--field` and `--format env`):
|
|
183
|
+
```bash
|
|
184
|
+
# Query exact scalar fields:
|
|
185
|
+
als-finder plan --workspace scratch/test_workspace --tile-size 500 --buffer-size 50 --field total_tiles
|
|
186
|
+
# Output: 5657
|
|
187
|
+
|
|
188
|
+
# Export full environment variables into your active shell:
|
|
189
|
+
eval $(als-finder plan --workspace scratch/test_workspace --tile-id 15 --tile-size 500 --buffer-size 50 --format env)
|
|
190
|
+
echo "Target Basename: $BASENAME"
|
|
191
|
+
echo "Crop Bounds: $CROP_GDAL_TE"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
> [!TIP]
|
|
195
|
+
> **Standardized Grid Alignment (1200m Core / 30m Buffer):**
|
|
196
|
+
> By default, `als-finder` generates $1200\,\text{m}$ core tiles with a $30\,\text{m}$ buffer. This geometry guarantees exact pixel integer divisibility across standard remote sensing raster resolutions—$30\,\text{m}$ ($40\,\text{px}$ core, $42\,\text{px}$ buffered), $10\,\text{m}$ ($120\,\text{px}$), and $1\,\text{m}$ ($1200\,\text{px}$)—completely preventing sub-pixel edge interpolation artifacts.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### Step 3: Generating HPC Slurm Task Lists & Manifests (`--tasks` / `--tasks-csv`)
|
|
201
|
+
When scheduling Slurm job arrays, you can output either a plain leaf tile list (`--tasks`) or a complete CSV manifest (`--tasks-csv`) with spatial coordinates, Hive paths, point counts, and recommended Slurm memory allocations:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# 1. Plain leaf task list for simple Slurm array indexes:
|
|
205
|
+
als-finder plan \
|
|
206
|
+
--workspace scratch/test_workspace \
|
|
207
|
+
--tasks > slurm_tasks.txt
|
|
208
|
+
|
|
209
|
+
# 2. Comprehensive CSV manifest for Slurm arrays, HPC job schedulers, and tracking:
|
|
210
|
+
als-finder plan \
|
|
211
|
+
--workspace scratch/test_workspace \
|
|
212
|
+
--tasks-csv slurm_manifest.csv
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Manifest Columns in `slurm_manifest.csv`:**
|
|
216
|
+
- `task_id`: Unique leaf task identifier (`0`, `15_NW`, etc.)
|
|
217
|
+
- `tile_id`: Parent master tile integer
|
|
218
|
+
- `basename`: Standardized spatial basename (`<dataset>_tile_E<easting>_N<northing>[_quad]`)
|
|
219
|
+
- `hive_dir` & `hive_path`: Deterministic Hive partition directory and destination file path
|
|
220
|
+
- `core_minx`, `core_miny`, `core_maxx`, `core_maxy`: Core bounding coordinates
|
|
221
|
+
- `point_density`, `est_points`: Acquisition point density ($pts/m^2$) and pre-flight point count
|
|
222
|
+
- `recommended_mem_gb`: Pre-calculated Slurm job memory allocation ($\approx 1.5 \times$ point payload)
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
### Step 4: On-Demand Point Cloud Streaming (`als-finder fetch tile`)
|
|
227
|
+
Acquire standard tile 15 directly over HTTP using clean positional syntax. Adding `--sidecar` writes a companion `.json` metadata file:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
als-finder fetch tile 15 \
|
|
231
|
+
--workspace scratch/test_workspace \
|
|
232
|
+
--tile-size 500 \
|
|
233
|
+
--buffer-size 50 \
|
|
234
|
+
--sidecar \
|
|
235
|
+
--overwrite
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Console Output:**
|
|
239
|
+
```text
|
|
240
|
+
Successfully streamed tile 15 to scratch/test_workspace/data/tiles/provider=USGS_EPT/dataset=CA_SierraNevada_5_2022/tilesize=500/buffer=50/CA_SierraNevada_5_2022_tile_E0738000_N4331000.laz
|
|
241
|
+
Wrote metadata sidecar to scratch/test_workspace/data/tiles/provider=USGS_EPT/dataset=CA_SierraNevada_5_2022/tilesize=500/buffer=50/CA_SierraNevada_5_2022_tile_E0738000_N4331000.json
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
### Step 5: Automatic OOM Protection & Quadrant Streaming
|
|
247
|
+
If a tile is hyper-dense and would exceed your RAM limit, passing `--max-points` causes `als-finder` to automatically bisect it into 4 safe quadrants:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
als-finder fetch tile 15 \
|
|
251
|
+
--workspace scratch/test_workspace \
|
|
252
|
+
--tile-size 500 \
|
|
253
|
+
--buffer-size 50 \
|
|
254
|
+
--max-points 4000000 \
|
|
255
|
+
--sidecar \
|
|
256
|
+
--overwrite
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Console Output:**
|
|
260
|
+
```text
|
|
261
|
+
Tile 15 exceeded budget. Subdivided into 4 quadrants:
|
|
262
|
+
- Streamed 15_NW to .../CA_SierraNevada_5_2022_tile_E0738000_N4331000_NW.laz
|
|
263
|
+
- Streamed 15_NE to .../CA_SierraNevada_5_2022_tile_E0738000_N4331000_NE.laz
|
|
264
|
+
- Streamed 15_SW to .../CA_SierraNevada_5_2022_tile_E0738000_N4331000_SW.laz
|
|
265
|
+
- Streamed 15_SE to .../CA_SierraNevada_5_2022_tile_E0738000_N4331000_SE.laz
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
> [!IMPORTANT]
|
|
269
|
+
> **Co-Located Subtiles & Constant Buffer:**
|
|
270
|
+
> 1. All quadrants sit directly in the parent Hive directory (`tilesize=500/buffer=50`), eliminating nested directory crawling.
|
|
271
|
+
> 2. The 50m buffer is **fully preserved** across all subdivisions, preventing edge-effect interpolation degradation.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
### Step 6: Multi-Tile Batch Streaming
|
|
276
|
+
Stream multiple tiles in a single concise command:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
als-finder fetch tile 14 16 \
|
|
280
|
+
--workspace scratch/test_workspace \
|
|
281
|
+
--tile-size 500 \
|
|
282
|
+
--buffer-size 50 \
|
|
283
|
+
--sidecar \
|
|
284
|
+
--overwrite
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Console Output:**
|
|
288
|
+
```text
|
|
289
|
+
Successfully processed 2 target tile(s) (2 file(s) generated):
|
|
290
|
+
- Tile 14 -> .../CA_SierraNevada_5_2022_tile_E0738000_N4330500.laz
|
|
291
|
+
- Tile 16 -> .../CA_SierraNevada_5_2022_tile_E0738000_N4331500.laz
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
### Step 7: Downstream Unbuffering & 1-Line Mosaicking
|
|
297
|
+
|
|
298
|
+
Because every `.laz` file includes a companion `.json` sidecar storing exact unbuffering crop parameters (`crop_gdal_te` / `crop_pdal_bounds`), downstream processing and mosaicking are completely automated:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
TILES_DIR="scratch/test_workspace/data/tiles/provider=USGS_EPT/dataset=CA_SierraNevada_5_2022/tilesize=500/buffer=50"
|
|
302
|
+
|
|
303
|
+
# 1. Process point clouds and crop away the 50m buffer
|
|
304
|
+
for LAZ in "$TILES_DIR"/*.laz; do
|
|
305
|
+
SIDECAR="${LAZ%.laz}.json"
|
|
306
|
+
CROP_BOX=$(jq -r '.crop_gdal_te' "$SIDECAR")
|
|
307
|
+
|
|
308
|
+
# Example: compute Canopy Height Model (CHM) with buffer, then crop to core:
|
|
309
|
+
# my_chm_tool "$LAZ" temp.tif
|
|
310
|
+
# gdal_translate -projwin $CROP_BOX temp.tif "${LAZ%.laz}_chm.tif"
|
|
311
|
+
done
|
|
312
|
+
|
|
313
|
+
# 2. Build a seamless mosaic across the entire study area (works for both 500m and 250m tiles):
|
|
314
|
+
# gdalbuildvrt full_study_area_chm.vrt "$TILES_DIR"/*_chm.tif
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
#### Native lidR (R) Integration & Buffer Point Tagging
|
|
318
|
+
Streamed `.laz` tiles embed a native LAS 1.4 `buffer` extra dimension (`buffer=0` for points inside the core tile, `buffer=1` for boundary buffer overlap points). In R using `lidR`, you can filter away buffer points after edge-artifact-free metric calculation with zero geometry math:
|
|
319
|
+
|
|
320
|
+
```r
|
|
321
|
+
library(lidR)
|
|
322
|
+
|
|
323
|
+
# Read LAS tile with extra dimensions:
|
|
324
|
+
las <- readLAS("tile.laz", select = "xyzc", filter = "")
|
|
325
|
+
|
|
326
|
+
# Compute metrics (e.g., CHM, canopy cover) with buffer points preventing edge voids:
|
|
327
|
+
# ...
|
|
328
|
+
|
|
329
|
+
# Instant zero-copy filter of core points only:
|
|
330
|
+
core_pts <- filter_poi(las, buffer == 0)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
### Step 8: High-Throughput Slurm Job Array Recipe
|
|
336
|
+
|
|
337
|
+
Here is the production Slurm script for running on-demand streaming across hundreds of HPC cores with zero OOM risk and instant scratch cleanup:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
#!/usr/bin/env bash
|
|
341
|
+
#SBATCH --job-name=als_tiles
|
|
342
|
+
#SBATCH --array=0-5656
|
|
343
|
+
#SBATCH --cpus-per-task=1
|
|
344
|
+
#SBATCH --mem=4G
|
|
345
|
+
#SBATCH --time=00:30:00
|
|
346
|
+
|
|
347
|
+
set -e
|
|
348
|
+
|
|
349
|
+
WORKSPACE="/shared/project/workspace"
|
|
350
|
+
FINAL_DIR="/shared/project/products/chm"
|
|
351
|
+
LOCAL_SCRATCH="$TMPDIR/als_work_${SLURM_ARRAY_TASK_ID}"
|
|
352
|
+
mkdir -p "$LOCAL_SCRATCH" "$FINAL_DIR"
|
|
353
|
+
|
|
354
|
+
# 1. Fetch on demand to local scratch (auto-subdivides if dense)
|
|
355
|
+
als-finder fetch tile "$SLURM_ARRAY_TASK_ID" \
|
|
356
|
+
--workspace "$WORKSPACE" \
|
|
357
|
+
--tile-size 500 \
|
|
358
|
+
--buffer-size 50 \
|
|
359
|
+
--max-points 4000000 \
|
|
360
|
+
--output "$LOCAL_SCRATCH" \
|
|
361
|
+
--sidecar \
|
|
362
|
+
--overwrite
|
|
363
|
+
|
|
364
|
+
# 2. Process all files in scratch (whether 1 tile or 4 quadrants)
|
|
365
|
+
for LAZ in "$LOCAL_SCRATCH"/*.laz; do
|
|
366
|
+
SIDECAR="${LAZ%.laz}.json"
|
|
367
|
+
BASENAME=$(basename "$LAZ" .laz)
|
|
368
|
+
CROP_BOX=$(jq -r '.crop_gdal_te' "$SIDECAR")
|
|
369
|
+
|
|
370
|
+
# Run point cloud metric tool
|
|
371
|
+
# compute_metric "$LAZ" "$LOCAL_SCRATCH/${BASENAME}_raw.tif"
|
|
372
|
+
|
|
373
|
+
# Crop off buffer to permanent storage
|
|
374
|
+
# gdal_translate -projwin $CROP_BOX "$LOCAL_SCRATCH/${BASENAME}_raw.tif" "$FINAL_DIR/${BASENAME}_chm.tif"
|
|
375
|
+
|
|
376
|
+
# Immediate cleanup of raw point cloud
|
|
377
|
+
rm -f "$LAZ" "$SIDECAR"
|
|
378
|
+
done
|
|
379
|
+
|
|
380
|
+
# Clean scratch
|
|
381
|
+
rm -rf "$LOCAL_SCRATCH"
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
### Step 9: Bulk Offline Survey Archiving (`als-finder fetch survey`)
|
|
387
|
+
For researchers who prefer to pre-download the entire raw dataset locally for air-gapped or offline processing:
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
als-finder fetch survey \
|
|
391
|
+
--workspace scratch/test_workspace \
|
|
392
|
+
--name "CA_SierraNevada_5_2022" \
|
|
393
|
+
--execute
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
### Step 10: Workspace Maintenance (`als-finder workspace`)
|
|
399
|
+
Update catalog filters or clean interim scratch files:
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
# Update catalog criteria (e.g. restrict to QL1):
|
|
403
|
+
als-finder workspace update --workspace scratch/test_workspace --density QL1
|
|
404
|
+
|
|
405
|
+
# Clean scratch workspace:
|
|
406
|
+
als-finder workspace clean --workspace scratch/test_workspace
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## 🐍 Programmatic Python API
|
|
412
|
+
|
|
413
|
+
You can also import and use `als_finder` directly in Python scripts and Jupyter Notebooks:
|
|
414
|
+
|
|
415
|
+
```python
|
|
416
|
+
import als_finder
|
|
417
|
+
|
|
418
|
+
# 1. Query tile specification and unbuffering bounds
|
|
419
|
+
spec = als_finder.get_tile_spec(
|
|
420
|
+
workspace="scratch/test_workspace",
|
|
421
|
+
tile_id=15,
|
|
422
|
+
tile_size=500,
|
|
423
|
+
buffer_size=50
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
print(f"Basename: {spec['basename']}")
|
|
427
|
+
print(f"Grid CRS: {spec['grid_crs']}")
|
|
428
|
+
print(f"Crop GDAL -te: {spec['crop_gdal_te']}")
|
|
429
|
+
|
|
430
|
+
# 2. Inspect Central Core Area vs Buffered Footprint
|
|
431
|
+
core = spec['core_poly']
|
|
432
|
+
buffered = spec['buffered_poly']
|
|
433
|
+
|
|
434
|
+
print(f"Core Tile Dimensions: {round(core.bounds[2] - core.bounds[0])}m x {round(core.bounds[3] - core.bounds[1])}m")
|
|
435
|
+
print(f"Buffer Extension: {round((buffered.bounds[2] - core.bounds[2]))}m on all sides")
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## 🏛️ Authorship & Citation
|
|
441
|
+
|
|
442
|
+
This software is released under the open-source **MIT License**. Copyright **Jonathan Greenberg**.
|
|
443
|
+
|
|
444
|
+
**Project Authors & Contributors:**
|
|
445
|
+
* **Jonathan Greenberg** (University of Nevada, Reno): Lead Developer and Core Project Architect.
|
|
446
|
+
* **Andrew Hudak** (US Forest Service): Advisory feedback and scientific computing grant alignment.
|
|
447
|
+
* **Antigravity (Google DeepMind)**: AI Software Engineering Partner.
|