File size: 5,195 Bytes
cd5e31d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4ecb57a
 
cd5e31d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4ecb57a
cd5e31d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
---
license: cc-by-4.0
language:
  - en
tags:
  - lunar
  - digital-elevation-model
  - shape-from-shading
  - self-supervised
  - remote-sensing
  - planetary-science
  - pytorch
pipeline_tag: image-to-image
---

# gnomon

1 m height maps of 26 lunar south-polar landing sites, solved from LRO photos lit from thirty directions. This repository holds the network weights, the scores, and the site list. The maps themselves (GeoTIFFs, 1 m) are in a separate dataset repository.

<p align="center"><img src="img/sun_sweep.gif" width="900"></p>

<sub>700 m of the IM-2 landing site, sun 3° above the horizon and circling. Left, NASA's 10 m map. Right, ours.</sub>

The polar sun circles the horizon, so a shadow cast from thirty directions is a thirty-way constraint on the ground. A differentiable renderer casts shadows from a height map; a self-supervised UNet is trained with that renderer as its only loss, no labels, no NASA elevation products. The only external height input is the LOLA 10 m laser grid, which anchors the low frequencies.

<p align="center"><img src="img/photo_lola_ours.jpg" width="1000"></p>

<sub>A photo the network never saw. LOLA rendered under that sun. Ours rendered under that sun.</sub>

## Files

| path | contents |
|---|---|
| `weights/<site>/unet/<run>/net.pt` | UNet state dict, PyTorch. 198 checkpoints: 7 to 8 seeds per 6 km site (`unet1` …), 3 per 16 km site, one `long` run, 20 MB each |
| `weights/<site>/unet/<run>/params.json` | the per-sun-bin exposure and floor fitted with that network |
| `weights/<site>/split.json` | the frozen train/test split of sun bins for that site |
| `weights/<site>/sun_fit.csv` | sun direction per bin, nominal and refined |
| `results/<site>.csv` | held-out scores for every map at that site, plain column names |
| `sites.csv` | every site: place, mission, coordinates, box size, status |

**The weights are site-specific.** The network input is the stack of that site's training sun bins plus the LOLA base, so the channel count differs between sites and a checkpoint cannot be applied to another site. Each one reproduces its site's map from the public inputs; it is not a general lunar terrain model.

## Scores

Every fifth sun direction was hidden before fitting. Sixteen 300 m blocks of laser heights were removed from the fit. One site has an independent stereo DTM.

| | LOLA 10 m | NASA 5 m SfS | ours 1 m |
|---|---|---|---|
| correlation with hidden photos, NASA's 16 km tile | 0.68 | 0.81 | 0.90 |
| shadow overlap (IoU), same tile | 0.82 | 0.82 | 0.86 |
| relative brightness error, same tile (lower is better) | 0.277 | 0.203 | 0.205 |
| RMSE against the stereo DTM, IM-2 | 0.50 m | | 0.40 m |
| sites beating LOLA on hidden photos | | | 26 of 26, median gain 0.23 |

<p align="center">
<img src="img/shadow_test.jpg" width="49%">
<img src="img/stereo_truth.jpg" width="49%">
</p>

<sub>Left: two hidden suns from opposite sides of the sky. Right: height error against the stereo DTM, and a 4 m crater LOLA draws as a flat line.</sub>

## Using a checkpoint

Reproduce a site's map from the public inputs with the pipeline in the code repository:

```
export MOONDEM_DATA=data/sites/haworth MOONDEM_BOX=haworth
python pipeline/step1_cut_photos.py && python pipeline/step2_get_laser_heights.py && python pipeline/step3_check_sun_angles.py
cp weights/haworth/split.json $MOONDEM_DATA/
python pipeline/step5_fit_terrain_network.py --infer-only weights/haworth/unet/unet1/net.pt --tag from_checkpoint
```

The architecture is a five-level UNet (widths 32, 64, 128, 256, 256) that takes 2·N+1 channels (N training bins, their valid masks, the LOLA base) and outputs a height residual scaled by 5 m. Input stacks, LOLA windows and the solver are in the code repository.

## Not proven

- Only one site has independent truth, a 4 m-post stereo DTM at IM-2 that is band-limited near 20 m.
- Hidden suns have trained neighbours about 15° away. The two-sun shadow test is what rules out appearance interpolation.
- The correlation metric is close to what the network optimises. NASA's 5 m map keeps lower brightness error at one site and is closer at the LOLA points it was fit to.
- The sun-bin filter was applied before the split, so it touched the test bins.
- Fine relief is in the right places but about a third too strong: the renderer has no albedo term. Slopes at baselines under 20 m are an upper bound until an albedo refit.
- Permanently shadowed floors produce no map.
- Multi-image shape-from-shading is an established method, run at 1 to 2 m on some sites by NASA Ames. What is new here is scale and cost (26 sites, one night, about $150), the held-out validation, the self-supervised network, and full release.

## Training data

LROC controlled NAC south-polar mosaics (PDS type BDRNPL), 1 m per pixel, one mosaic per 10° of sub-solar longitude, 23 to 36 per tile. LOLA 10 m south-polar DEM from PGDA. Evaluation only: LROC NAC stereo DTM NOBILE03 and NASA PGDA 5 m shape-from-shading DEM of the Leibnitz Beta plateau.

## Citation

```
@misc{gnomon2026, title={gnomon: 1 m height maps of lunar south-polar landing sites from multi-sun photos}, year={2026}, howpublished={Hugging Face}}
```