Fix GPU bugs, restore aspect viz, fix anomaly mask, revert flow_acc to vectorized D8

GPU: num_gpus() returns real count via _gpu_candidates (was always 0/1),
available_gpu_ids() added. Pipeline: round-robin on real GPU host indices
instead of file enumerate index. _process_file_standalone signature simplified.

Restore generate_aspect using SharedDEM gradient (dy, dx). Colormap twilight
0-360 fixed range. VIZ_STEPS back to 16.

Flow accumulation: revert to vectorized numpy D8 direction + module-level
numba accumulator (cached, top-down sort) with Python fallback. Priority-flood
NaN-aware. Log1p transform.

Anomaly mask: replace RMS+fixed 2sigma threshold (was blank) with weighted
sum of |z-score| + adaptive percentile threshold. Absolute z-score captures
both positive and negative deviations. 6% signal detected vs 0% before.
This commit is contained in:
Antoine Jacquin
2026-06-01 23:03:19 +02:00
parent 618cd620e3
commit 8478106e51
5 changed files with 418 additions and 213 deletions

View File

@ -144,6 +144,14 @@ COLORMAPS = {
'vmin_mode': 'fixed', 'vmin_val': 0,
'vmax_mode': 'percentile', 'vmax_pct': 97,
},
'aspect': {
'cmap': 'twilight',
'title': 'Aspect (Direction des pentes)',
'legend': 'Direction vers laquelle le terrain descend\nCycle continu : Nord→Est→Sud→Ouest→Nord\nCouleurs perceptuellement uniformes (pas de saut de teinte)',
'description': 'Orientation des pentes — utile pour distinguer structures des formes naturelles',
'vmin_mode': 'fixed', 'vmin_val': 0,
'vmax_mode': 'fixed', 'vmax_val': 360,
},
'roughness': {
'cmap': 'plasma',
'title': 'Rugosité Multi-Échelle (3m + 15m)',
@ -154,11 +162,10 @@ COLORMAPS = {
},
'wavelet': {
'cmap': 'cividis',
'title': 'Ondelette Mexican Hat + Gabor directionnelle (multi-échelle)',
'legend': 'Réponse RMS combinée Mexican Hat (circulaire) + Gabor (linéaire)\nÉchelles adaptées à la résolution\n4 orientations Gabor : 0°, 45°, 90°, 135°\n\nClair = Structure détectée\nSombre = Pas de structure',
'description': 'Mexican Hat pour tumulus/enclos + Gabor pour chemins/murs/fossés',
'vmin_mode': 'fixed', 'vmin_val': 0,
'vmax_mode': 'percentile', 'vmax_pct': 98,
'title': 'Ondelette Mexican Hat (CWT multi-échelle)',
'legend': 'Réponse de la transformée en ondelette\nÉchelles adaptées à la résolution\n\nClair = Structure détectée à cette échelle\nSombre = Pas de structure\n\nOptimisé pour formes circulaires:\ntumulus, enclos, fossés annulaires',
'description': 'Transformée en ondelette 2D — excellente pour détecter structures circulaires',
'vmin_mode': 'symmetric', 'sym_pct': (2, 98),
},
'flow_acc': {
'cmap': 'YlGn',
@ -176,6 +183,14 @@ COLORMAPS = {
'vmin_mode': 'fixed', 'vmin_val': 0,
'vmax_mode': 'fixed', 'vmax_val': 1,
},
'solar': {
'cmap': 'gray',
'title': 'Éclairage Solaire',
'legend': "Illumination solaire (azimut 90°, altitude 30°)\nClair = Face éclairée | Sombre = Zone d'ombre",
'description': "Simulation de l'éclairage solaire matinal",
'vmin_mode': 'fixed', 'vmin_val': 0,
'vmax_mode': 'fixed', 'vmax_val': 1,
},
}
# RGB entries (ortho/topo) are handled specially
@ -822,7 +837,7 @@ def generate_pdf_report(basename, vis_dir, pdf_dir, resolution):
# Sort analysis files by archaeological priority
order = ['mslrm', 'svf', 'negative_openness',
'positive_openness', 'aniso_open', 'sailore', 'hillshade_multi',
'flow_acc', 'slope', 'roughness', 'wavelet']
'flow_acc', 'solar', 'slope', 'roughness', 'wavelet']
def sort_key(f):
name = f.stem.lower()