[GRASS-git] [OSGeo/grass-addons] 9b0a4c: i.hyper: major upgrade with metadata, atmospheric ...

the-tomazz noreply at github.com
Wed Sep 16 05:50:14 PDT 2026


  Branch: refs/heads/grass8
  Home:   https://github.com/OSGeo/grass-addons
  Commit: 9b0a4cb558447a91cfe9f598fe6f0f1a20013b93
      https://github.com/OSGeo/grass-addons/commit/9b0a4cb558447a91cfe9f598fe6f0f1a20013b93
  Author: the-tomazz <the-tomazz at users.noreply.github.com>
  Date:   2026-09-16 (Wed, 16 Sep 2026)

  Changed paths:
    M .gitignore
    M pyproject.toml
    M src/imagery/i.hyper/CMakeLists.txt
    M src/imagery/i.hyper/Makefile
    A src/imagery/i.hyper/i.hyper.atcorr/CMakeLists.txt
    A src/imagery/i.hyper/i.hyper.atcorr/Makefile
    A src/imagery/i.hyper/i.hyper.atcorr/README.md
    A src/imagery/i.hyper/i.hyper.atcorr/i.hyper.atcorr.html
    A src/imagery/i.hyper/i.hyper.atcorr/i.hyper.atcorr.md
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/.gitignore
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/INSTALL.md
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/LICENSE
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/Makefile
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/README.md
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/debian/changelog
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/debian/control
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/debian/copyright
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/debian/libsixsv-dev.install
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/debian/libsixsv.pc.in
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/debian/libsixsv2.install
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/debian/libsixsv2.symbols
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/debian/rules
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/debian/watch
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/Makefile
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/_support.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/data/6sv21_extended_parity.json
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/data/6sv21_satellite_continental.json
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/generate_6sv21_extended_reference.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/generate_6sv21_reference.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/patches/6sv21-print-precision.patch
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/test_6sv21_extended_parity.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/test_6sv21_pipeline_parity.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/test_6sv_compat.f90
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/test_fortran_compat.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/test_lut.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/test_openmp.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/developer_tests/test_solar.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/01_basic_lut.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/01_basic_lut.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/02_scene_correction.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/02_scene_correction.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/03_retrievals.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/03_retrievals.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/04_brdf.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/04_brdf.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/05_spatial_filters.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/05_spatial_filters.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/06_full_pipeline.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/06_full_pipeline.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/Makefile
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/examples/README.md
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/adjacency.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/aerosol_tables.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/atcorr.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/brdf.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/gas_tables.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/oe_invert.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/retrieve.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/sixs_ctx.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/solar_table.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/spatial.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/spectral_brdf.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/surface_model.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/terrain.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/include/uncertainty.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/adjacency.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/aeroprof.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/aerosol.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/aerosol_polar_tables.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/aerosol_tables.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/atcorr.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/atmosphere.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/brdf.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/chand.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/correct.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/csalbr.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/discom.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/discre.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/discre.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/enviro.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/gas_abs.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/gas_tables.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/gauss.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/gauss.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/interp.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/interp.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/kernel.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/kernel.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/kernelpol.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/kernelpol.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/lut.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/mie.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/oe_invert.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/ospol.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/ospol.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/polglit.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/polglit.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/possol.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/pressure.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/rayleigh.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/rayleigh.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/retrieve.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/rt.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/rt.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/scatra.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/scatra.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/solar.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/solar_table.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/spatial.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/spectral_brdf.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/srf_conv.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/surface_model.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/terrain.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/trunca.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/trunca.h
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/src/uncertainty.c
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/tools/extract_aerosol_polar_tables.py
    A src/imagery/i.hyper/i.hyper.atcorr/libsixsv/tools/extract_gas_tables.py
    A src/imagery/i.hyper/i.hyper.atcorr/main.c
    M src/imagery/i.hyper/i.hyper.composite/i.hyper.composite.py
    M src/imagery/i.hyper/i.hyper.explore/i.hyper.explore.html
    M src/imagery/i.hyper/i.hyper.explore/i.hyper.explore.md
    M src/imagery/i.hyper/i.hyper.explore/i.hyper.explore.py
    M src/imagery/i.hyper/i.hyper.export/i.hyper.export.py
    M src/imagery/i.hyper/i.hyper.html
    M src/imagery/i.hyper/i.hyper.import/i.hyper.import.html
    M src/imagery/i.hyper/i.hyper.import/i.hyper.import.md
    M src/imagery/i.hyper/i.hyper.import/i.hyper.import.py
    M src/imagery/i.hyper/i.hyper.md
    M src/imagery/i.hyper/i.hyper.metadata/extended_metadata_unification.md
    M src/imagery/i.hyper/i.hyper.metadata/i.hyper.metadata.html
    M src/imagery/i.hyper/i.hyper.metadata/i.hyper.metadata.md
    M src/imagery/i.hyper/i.hyper.metadata/i.hyper.metadata.py
    A src/imagery/i.hyper/i.hyper.metadata/testsuite/test_metadata_unit.py
    M src/imagery/i.hyper/i.hyper.preproc/i.hyper.preproc.html
    M src/imagery/i.hyper/i.hyper.preproc/i.hyper.preproc.md
    M src/imagery/i.hyper/i.hyper.preproc/i.hyper.preproc.py
    A src/imagery/i.hyper/i.hyper.specresamp/CMakeLists.txt
    A src/imagery/i.hyper/i.hyper.specresamp/Makefile
    A src/imagery/i.hyper/i.hyper.specresamp/i.hyper.specresamp.html
    A src/imagery/i.hyper/i.hyper.specresamp/i.hyper.specresamp.md
    A src/imagery/i.hyper/i.hyper.specresamp/i.hyper.specresamp.py
    M src/imagery/i.hyper/i_hyper_lib/CMakeLists.txt
    M src/imagery/i.hyper/i_hyper_lib/Makefile
    A src/imagery/i.hyper/i_hyper_lib/check_proj.py
    A src/imagery/i.hyper/i_hyper_lib/emit.py
    M src/imagery/i.hyper/i_hyper_lib/enmap.py
    M src/imagery/i.hyper/i_hyper_lib/hyper_meta.py
    M src/imagery/i.hyper/i_hyper_lib/prisma.py
    M src/imagery/i.hyper/i_hyper_lib/prisma_reader.py
    A src/imagery/i.hyper/i_hyper_lib/specresamp.py
    M src/imagery/i.hyper/i_hyper_lib/tanager.py
    M src/imagery/i.hyper/i_hyper_lib/tanager_reader.py

  Log Message:
  -----------
  i.hyper: major upgrade with metadata, atmospheric correction, spectral resampling, and export formats (#1844)

* i.hyper.import: support EnMAP BSQ products

* fix enmap L1 products import, closes #16

* i.hyper.import: reject missing radiometric calibration

* i.hyper.specresamp: new addon for spectral resampling of hyperspectral 3D rasters

* i.hyper.import: document product import behavior

* i.hyper.preproc: fix -q interpolation import bug and clarify behavior

- Move scipy.interpolate.interp1d import to module level (fixes NameError)
- Update -q flag description: specify linear interpolation with extrapolation
- Add Interpolation to pipeline steps display (fixes misleading 'No operations selected')
- Fix typo 'Interpolaties' in docs
- Update docs to clarify -q uses linear interpolation with extrapolation

Closes #19

* i.hyper.preproc: remove aspirational steps= docs that were never implemented

fixes #14

* i.hyper.import: add -p product guidance

* emit: finalize importer with CRS reprojection and L1B support

- Add get_emit_proj_info() for check_proj.py -p flag support
- Register emit in check_proj.py (_load_proj_module + _FUNC_NAMES)
- Implement auto-reprojection of EMIT EPSG:4326 grid corners
  to location CRS using pyproj when CRS differs
- Add L1B radiance detection (fallback when 'reflectance' not found)
- Handle missing good_wavelengths in L1B data
- Set correct radiometric quantity/units for L1B vs L2A
- Register emit in i.hyper.import.py options and PRODUCT_MODULE_MAP
- Register emit.py in Makefile and CMakeLists.txt

* emit: fix import_behavior/project_requirements strings and add EMIT to metadata spec

- import_behavior: describes GLT orthorectification, no CRS leak
- project_requirements: matching CRS best, any projected CRS works
- Add EMIT source mappings to extended_metadata_unification.md
  (Tables A and B subsections, emit. namespace in Section C)

* i.hyper.metadata: copy metadata from source cube

* i.hyper.metadata: fix copy initialization and validation

* i.hyper.import: reject direct-grid CRS mismatch

* emit: replace corner-transform with forward bilinear splatting (Tanager BASIC pattern)

- Corner-transform caused rotated output when CRS differed
- Now uses per-pixel lon/lat arrays (like Tanager BASIC) + pyproj transform
  + bilinear splat accumulation onto target CRS grid
- Splat plan (indices + weights) built once before band loop
- When CRS matches EPSG:4326 → direct write (no splat overhead)
- Updated project_requirements string

* emit: expand 1D lon/lat to 2D meshgrid at read time

EMIT stores lon/lat as 1D arrays matching ortho_cols/ortho_rows.
The splat plan builder indexes with the 2D glt_valid mask, which
requires 2D arrays. Expanding at read time keeps downstream code
simple.

* emit: use geotransform-derived pixel positions for splat (matching Tanager ORTHO pattern)

EMIT stores lon/lat as 1D arrays that may differ in length from GLT grid
dimensions. Compute pixel centers from the geotransform instead:
  lon = west + (c + 0.5) * ewres
  lat = north - (r + 0.5) * nsres
This always matches the GLT grid and aligns with Tanager ORTHO's approach.

* metadata spec: add EMIT column to Tables A and B

* i.hyper.import: warn on direct-grid CRS mismatch

* i.hyper.atcorr: initial C addon with bundled libsixsv library

Seeded from YannChemin/i.hyper.atcorr 71404b4 and
YannChemin/libsixsv c75c1d8.

Architecture follows the established GRASS addon library pattern
(i.pr/PRLIB, r.pi/r.pi.library):

  i.hyper/libsixsv/       — Lib.make-based C library
  i.hyper/i.hyper.atcorr/ — Module.make-based C addon linking -lgrass_sixsv

Contains:
- main.c (2687 lines): LUT generation, Raster3D correction, ISOFIT
  improvements (per-pixel AOD/H2O, adjacency, MAP prior, uncertainty,
  terrain, NBAR, FlexBRDF, DASF)
- libsixsv: 6SV2.1 RT physics library (~40 .c files, 14 public headers)
- Documentation: HTML + Markdown manuals, install guide, README
- Tests: Fortran compat (6SV2.1 -> C), LUT, solar, retrievals,
  BRDF, GRASS module integration
- python/atcorr.py: ctypes bindings to libgrass_sixsv

License: Unlicense (public domain)

* issue 23 -i.hyper.export: handle D:M:S resolution strings from r3.info in lat/lon locations

* libsixsv/Makefile: add LIBSRCS and MOD_OBJS for src/ subdirectory sources

Without these, Lib.make has no source files to compile.
Fixes build failure when running make from the i.hyper/ parent level.

* i.hyper.atcorr: single-executable build (cmake-friendly)

Compile libsixsv sources directly into the i.hyper.atcorr binary
instead of building a separate shared library. This enables:

- g.extension on any GRASS installation (binary or source)
- Compatible with both cmake and traditional make build systems
- No separate library build/install step

Changes:
- libsixsv/: source-only directory (no Makefile/CMakeLists.txt)
- i.hyper.atcorr/Makefile: Module.make + vpath to ../libsixsv/src/
- i.hyper.atcorr/CMakeLists.txt: lists all 39 libsixsv .c sources
- i.hyper/Makefile: simplified SUBDIRS (no separate libsixsv build)
- i.hyper/CMakeLists.txt: removed add_subdirectory(libsixsv)

* i.hyper.atcorr: remove python, tests, testsuite, INSTALL.md

These are not part of the C addon module. Available upstream at
YannChemin/i.hyper.atcorr.

* libsixsv: remove manual seed, prepare for subtree

* Squashed 'src/imagery/i.hyper/libsixsv/' content from commit c75c1d824

git-subtree-dir: src/imagery/i.hyper/libsixsv
git-subtree-split: c75c1d82486b942ccddca8052f90bc1d276bbba4

* AGENTS.md: update architecture, add subtree sync instructions, remove outdated paths

* i.hyper.atcorr: add proper attribution (Yann Chemin, Tomaž Žagar)

* i.hyper.atcorr: add affiliations, remove LICENSE (align with other i.hyper submodules)

* i.hyper.atcorr: remove stale docs referencing deleted files (python/, testsuite/, INSTALL.md, LICENSE)

* i.hyper.atcorr: point SEE ALSO links to GitHub (outside OSGeo addons)

* libsixsv: remove from i.hyper/ level (moving inside i.hyper.atcorr/)

* Squashed 'src/imagery/i.hyper/i.hyper.atcorr/libsixsv/' content from commit c75c1d824

git-subtree-dir: src/imagery/i.hyper/i.hyper.atcorr/libsixsv
git-subtree-split: c75c1d82486b942ccddca8052f90bc1d276bbba4

* i.hyper.atcorr: move libsixsv/ inside module, update build paths and docs

libsixsv is now vendored via git subtree inside i.hyper.atcorr/
instead of at the i.hyper/ level. This makes the module
self-contained for g.extension compatibility (no more broken
../libsixsv/ relative paths when g.extension copies the module).

- Makefile: ../libsixsv/ -> libsixsv/
- CMakeLists.txt: ../libsixsv/ -> libsixsv/
- README.md: updated architecture tree + subtree pull --prefix
- AGENTS.md: updated architecture tree + subtree pull --prefix

* i.hyper.atcorr.html: fix charset iso-8859-1 -> utf-8

Fixes mojibake of Slovenian letters (ž, š, č) and other
non-ASCII characters in the manual page.

* i.hyper.atcorr: add metadata fallback chain (CLI → hyper.json → defaults)

C-side (main.c):
  - Add #include <grass/spawn.h> for G_popen_read / G_vspawn_ex
  - Add HyperMeta struct and JSON scanner helpers for reading
    extended_metadata from i.hyper.metadata JSON output
  - Add read_hyperjson_meta() — tries G_popen_read('i.hyper.metadata')
    first, falls back to direct hyper.json file read
  - Add resolve_float_opt / resolve_str_opt for CLI → metadata → default chain
  - Mark 11 overridable options with '(overrides metadata)' label suffix
  - Change sza to required=NO (no hardcoded default, fatal if missing
    from both CLI and metadata)
  - Add derive call via G_vspawn_ex after correct_raster3d() to write
    output metadata

Python-side (i.hyper.metadata.py):
  - Add operation=derive option + overrides= and command= options
  - Implement generic _derive_output_metadata() — loads source metadata,
    applies top-level overrides (e.g. radiometric_quantity) and merges
    extended_metadata from overrides JSON via merge_extended_metadata()
  - Wire operation=derive into main()

Documentation:
  - i.hyper.metadata.html + .md: document derive operation, overrides=
    and command= options

* i.hyper.atcorr: add metadata fallback chain (CLI → hyper.json → defaults)

C-side (main.c):
  - Add #include <grass/spawn.h> for G_popen_read / G_vspawn_ex
  - Add HyperMeta struct and JSON scanner helpers for reading
    extended_metadata from i.hyper.metadata JSON output
  - Add read_hyperjson_meta() — tries G_popen_read('i.hyper.metadata')
    first, falls back to direct hyper.json file read
  - Add resolve_float_opt / resolve_str_opt for CLI → metadata → default chain
  - Mark 11 overridable options with '(overrides metadata)' label suffix
  - Change sza to required=NO (no hardcoded default, fatal if missing
    from both CLI and metadata)
  - Call merge-overrides + add-history via G_vspawn_ex after
    correct_raster3d() to write output metadata

Python-side (i.hyper.metadata.py):
  - Add merge-overrides operation: applies top-level keys and merges
    extended_metadata from overrides= JSON into an existing map
  - Add add-history operation: appends a processing_history entry
    using source_map= and command=
  - Add overrides= and command= options

Documentation:
  - i.hyper.metadata.html + .md: document merge-overrides and
    add-history operations

* i.hyper.atcorr: add metadata fallback chain (CLI → hyper.json → defaults)

C-side (main.c):
  - Add #include <grass/spawn.h> for G_popen_read / G_vspawn_ex
  - Add HyperMeta struct and JSON scanner helpers for reading
    extended_metadata from i.hyper.metadata JSON output
  - Add read_hyperjson_meta() — tries G_popen_read('i.hyper.metadata')
    first, falls back to direct hyper.json file read
  - Add resolve_float_opt / resolve_str_opt for CLI → metadata → default chain
  - Mark 11 overridable options with '(overrides metadata)' label suffix
  - Change sza to required=NO (no hardcoded default, fatal if missing
    from both CLI and metadata)
  - Call merge-overrides + add-history via G_vspawn_ex after
    correct_raster3d() to write output metadata
  - Use CMDLINE env var for add-history command string instead of
    hardcoded 'i.hyper.atcorr'

Python-side (i.hyper.metadata.py):
  - Add merge-overrides operation: applies top-level keys and merges
    extended_metadata from overrides= JSON into an existing map
  - Add add-history operation: appends a processing_history entry
    using source_map= and command=
  - Add overrides= and command= options

Documentation:
  - i.hyper.metadata.html + .md: document merge-overrides and
    add-history operations

* i.hyper.atcorr: update docs for sza optional with metadata fallback

- i.hyper.atcorr.html: synopsis now shows [sza=float] (optional),
  description updated to note metadata fallback
- i.hyper.atcorr/README.md: add note at top of Options Reference
  explaining CLI → metadata → default resolution chain

* i.hyper.atcorr: copy input metadata to output before merge-overrides

Creates hyper.json for the output map by copying metadata from the input
map via i.hyper.metadata operation=copy, so that subsequent
merge-overrides and add-history operations have a metadata sidecar to
work with.

Previously the C-level Rast3d_open_new_opt_tile_size() created only the
raw 3D raster file without the hyper.json JSON metadata sidecar, causing
i.hyper.metadata merge-overrides and add-history to fail with
'JSON metadata file not found'.

* i.hyper.metadata: fix input_datasets_metadata collection for derived datasets

The root_produced_ids filter in collect_input_datasets_metadata() was
built from ALL processing history step outputs, which caused ancestor
dataset_ids to be incorrectly excluded when they were also outputs of
earlier steps (e.g., the import step's output referenced as input by
the copy step). This left input_datasets_metadata empty for derived
datasets with multi-step processing history.

Changed root_produced_ids to only exclude the root dataset's own ID
(self-reference guard), and updated the save() call site to pass
dataset_id into root_data so the filter works correctly.

This makes derived metadata truly self-contained: HyperMetadata.load()
can resolve inherited values (e.g. bands.wavelength) from embedded
input_datasets_metadata snapshots, fixing failures in downstream
consumers like i.hyper.composite.

* i.hyper.atcorr: clean up processing history and record full command line

Two changes:

1. Remove metadata-tooling noise from processing history:
   Added -q flag to i.hyper.metadata operation=copy that suppresses the
   copy history entry. i.hyper.atcorr passes this flag so the processing
   history only shows scientific steps (import -> atcorr), not the
   metadata plumbing.

2. Record full atcorr command line in processing history:
   Replaced getenv(CMDLINE) fallback (which always produced bare
   'i.hyper.atcorr') with a snapshot of argv captured before G_parser(),
   preserving the exact invocation with all parameters.

* git: remove top-level .gitignore

* i.hyper.metadata: clear processing history in quiet copy mode

When record_history=False (-q flag), clear the source's processing
history instead of carrying it forward. This matches the preproc
pattern where only the current processing step appears in the main
history, with ancestor steps stored exclusively in
input_datasets_metadata.

* emit: add -p flag to i.colors.enhance for RGB composite (matching prisma/tanager/enmap)

* Restore top-level .gitignore

* i.hyper.import: add -u flag to update region

* i.hyper.atcorr: fix radiance unit mismatch for EnMAP L1C (nm→µm ×1000)

* i.hyper.import: stop creating composites by default

* Stop tracking AGENTS.md

* i.hyper.atcorr: fix radiance unit mismatch for EnMAP L1C (nm→µm ×1000)

* Stop tracking AGENTS.md

* i.hyper.atcorr: fix CLI defaults blocking metadata fallback

Remove hardcoded ->answer assignments from options that have
metadata equivalents (vza, raa, altitude, ozone, doy, aod_val,
h2o_val, sun_azimuth). The hardcoded defaults were returned by
resolve_float_opt() before metadata was ever checked, breaking
the documented CLI \u2192 metadata \u2192 default priority chain.

* i.hyper.atcorr: document code defaults in labels and HTML docs

- Remove misleading (overrides metadata) from atmosphere/aerosol (dead code)
- Add default values to labels for all 9 resolve_float_opt parameters
- Add default values to CLI-default-only parameter descriptions
- Add (overrides metadata) annotations to relevant HTML entries

* i.hyper.atcorr: GUI tab reorg, Raster3D->3D raster, wavelengths in nm

- Rename 'Correction' tab to 'Main' (first tab)
- Move atmosphere/aerosol to Main tab
- Move custom Mie params to Atmosphere tab
- Move DOY/Scene AOD/Column water vapour to Atmosphere tab
- Move DEM raster to Terrain tab
- Replace 'Raster3D' with '3D raster' in all user-facing strings
- Wavelength input changed to nm (internally converted to um via /1000)
- Update docs to match

* i.hyper.atcorr: rename RM -> RM_OFF in kernelpol.c to fix macro redefinition warning

The local RM(j) macro in sixs_kernelpol() collided with the RM(ctx, i)
macro defined in sixs_ctx.h (included via kernelpol.h). Renaming to
RM_OFF avoids the redefinition warning during compilation.

* i.hyper.atcorr: suppress CMake RPATH conflict warning

Disable CMAKE_INSTALL_RPATH_USE_LINK_PATH to prevent CMake from
warning about libgomp.so.1 path collision between the conda
environment and the system GCC directory.

* i.hyper.atcorr: suppress CMake RPATH conflict warning via target property

Replace the variable-based approach (which was ineffective due to
function scope isolation in build_addon.cmake) with a direct
set_target_properties call on the target after build_addon() creates it.

* i.hyper.atcorr: explicitly set BUILD_RPATH/INSTALL_RPATH to suppress CMake RPATH conflict warning

CMake warns when a linked library (libgomp from conda) exists in both
an RPATH candidate directory and an implicit system directory. Neither
INSTALL_RPATH_USE_LINK_PATH (variable nor target property) suppresses
this check. Explicitly setting both BUILD_RPATH and INSTALL_RPATH to
GISBASE/lib prevents CMake from computing the RPATH and triggering
the conflict detection. libgomp is resolved from the system GCC path
at runtime.

* validity branch: full physical spectral axis for all products

Key differences from i.hyper branch:

- Always preserve the full physical source-band axis during import.
  Invalid/provider-rejected bands are written as all-NULL raster slices
  and marked validity=False in metadata. Removed -n flag (previously
  toggled between physical and compact layout); physical is now the
  only mode. bands.count always equals cube depth; bands.count_valid
  records usable bands.

- hyper_meta.resolve_band_axis() maps between source axis and raster
  depth, supporting both physical (depth == count) and legacy compact
  (depth == count_valid) cubes for backward compat. save() always
  writes bands.count/count_valid even when inherited. validate_strict()
  merges full bands dict from input lineage for derived spectral datasets.

- get_wavelengths_array()/get_fwhm_array() accept valid_only flag.
  find_nearest_band() considers validity. select_bands_by_wavelength()
  uses full axis.

- enmap.py: sort band entries by wavelength (not global_band number),
  fixing VNIR/SWIR overlap ordering. All source bands written; invalid
  ones get per-band NULL mapcalc + no gain/offset. Composite band
  selection uses valid_band_indices resolved from valid wavelengths.

- prisma_reader.py BandInfo stores full band list (not just flagged).
  concatenate_hyperspectral preserves full axis, returns validity mask,
  sorts by wavelength. Zero-wavelength HDF5 reserved slots kept as
  NULL slices (validity=False).

- prisma.py/emit.py/tanager.py: removed import_null parameter.
  Invalid bands set to NaN in data cube. Composite band indices
  resolved from valid_band_indices/valid_wavelengths.

- specresamp.py: NaN-safe Gaussian resampling (finite-weight
  normalization). Linear resampling handles exact-match and edge cases.

- i.hyper.preproc: operates on valid bands only (via resolve_band_axis),
  reinserts into full NaN output array. Interpolation moved before
  filtering for correct NaN handling.

- i.hyper.specresamp: uses resolve_band_axis(), writes out_validity
  to output metadata.

- i.hyper.metadata copy: always generates fresh dataset_id; output
  history entry always includes id; depth check compares source raster
  depth (not metadata bands.count).

- i.hyper.explore/composite: updated for axis-resolved validity-aware
  band selection.

* fix shebangs: python -> python3 for i.hyper.export and i.hyper.preproc

* i.hyper.atcorr: replace find_OpenMP() with -fopenmp flags to suppress CMake RPATH warning

find_OpenMP() resolves libgomp to a full path (conda's
libgomp.so). CMake detects a conflict between that path and the
implicit system GCC directory, emitting a warning regardless of
RPATH settings.

Using -fopenmp flags directly avoids CMake tracking any library
path, eliminating the conflict check entirely. The compiler/linker
resolves -fopenmp against whatever libgomp is on the active
toolchain's search path (conda or system), producing the same
binary either way.

* i.hyper.atcorr: fix plain vs keyword signature conflict in target_link_libraries

build_addon.cmake uses the plain signature of
target_link_libraries, so subsequent calls for the same target
must also be plain (no PRIVATE/INTERFACE/PUBLIC keyword).

* i.hyper.atcorr: extend RPATH to conda base lib for consistent libgomp resolution

The binary's RPATH previously only pointed at GISBASE/lib, so
libgomp resolved from the system path instead of the conda
environment. Extending RPATH to include GISBASE/../../lib
(conda base lib/) makes all GCC runtime libs resolve from
the same source. The -fopenmp flag approach (no CMake-tracked
library path) keeps the CMake warning suppressed.

* i.hyper: fix PLW0717 via refactoring, format & lint

* i.hyper: fix missing bands.wavelength regression from validity-branch save optimization

The validity branch save() writes only bands.count/count_valid for
derived datasets, omitting wavelength/fwhm/validity. The inherited
value from resolve_inherited_value() is the same minimal bands dict
because it finds the key in the root data. Fix by looking up the
full source bands directly via input_datasets_metadata when local
bands lacks wavelength, then merging local overrides on top.

i.hyper.composite map=test3_sr at PERMANENT output=test3_sr composites=rgb now succeeds.

* atcorr:wip

* i.hyper.atcorr: tolerate wavelength endpoint rounding

* libsixsv: restore 6SV2.1 pipeline parity

* i.hyper.atcorr: effective-coefficient LUT, SRF guard, extended parity

- Full-column satellite pipeline now returns gas-weighted effective
  coefficients; s_alb coupling uses directional-hemispherical albedo.
- SRF gas correction stays guarded off (direction-only factors are
  incompatible with effective path-gas coefficients).
- Add polarized 6SV2.1 extended-parity fixtures (ground observer,
  gas-weighted 940 nm, 3.75 um continuum) and generator script.
- Rename Debian packaging to libsixsv2; add libsixsv.pc.in.
- Fix doy range (1-366), black-sky albedo naming, examples T_scat, and
  stale docs/comments across the module and libsixsv.

* libsixsv: fix DISCOM angular quadrature for full 6SV2.1 parity

setup_rm_gb built the RT quadrature from a 24-point Gauss-Legendre rule on
[0,1], while the pinned Fortran feeds gauss(-1,1,anglem,weightm,mu2) with
mu2_p=48 and maps rm(1..24)=anglem(48..25), rm(-1..-24)=anglem(1..24).
This systematically shifted s_alb and the transmittances by ~1e-3.

Switch to the 48-point rule on [-1,1] with the Fortran index mapping;
s_alb now matches the full-precision reference to 1e-7..1e-9 in every
case, and recovered surface reflectance is 0.200001..0.200013.

Also regenerate both fixtures with the full-precision print patch
(committed under testsuite/patches), tighten the parity tolerances toward
1e-5 (keeping documented gas/continuum exceptions), and update the
pipeline parity tables.

* i.hyper.atcorr: fix -Wformat-truncation on overrides metadata arg

Size ovrarg relative to the overrides buffer so the 'overrides=' prefix
cannot overflow the 4096-byte destination when the metadata JSON is near
its maximum length.

* libsixsv: fix ozone continuum column scaling for EnMAP RGB parity

Fortran ABSTRA.f uses uud=uu/xmus with uu the profile-integrated ozone in
atm-cm scaled by rat(4)=uo3/uo3us (uo3us=0.344), not the flat user column.
Reproduce that in the down, plane, and total gas paths so C matches 6SV2.1
to ~1e-6 at the EnMAP RGB bands.  H2O/O3 k-band scaling stays on the
absolute-column contract (profile-normalised), so ground-sensor and
cross-profile normalisation tests remain consistent.

Also add EnMAP RGB (478/572/660 nm) cases to the extended reference
generator (snapped to 6SV's 0.0025-um grid) and regenerate the parity
fixture: 15/15 pass.

* metadata handling

* bugfix

* i.hyper.atcorr: fix pressure parity and metadata handling

* i.hyper.atcorr: documentation

* i.hyper.atcorr: document quality output category values

* i.hyper.atcorr: null quality mask outside footprint; add categories

* i.hyper.metadata: Resolve inherited band metadata

* i.hyper.explore: Visualize uncertainty 3D raster maps

* i.hyper.atcorr: Add Alen Mangafić to authors

* i.hyper: Update roadmap

* i.hyper.atcorr: Use ASCII author names in HTML

* i.hyper.atcorr: Move standalone developer tests

* i.hyper.atcorr: Preserve developer script modes

* i.hyper.metadata: Expect fatal validation errors

* i.hyper.atcorr: Format example build commands

---------

Co-authored-by: tomazz <tomazz at localhost>
Co-authored-by: mazingaro <amangaf at gmail.com>
Co-authored-by: matjazkrebs <matjazkrebs at matjazkrebs.geod>
Co-authored-by: tomazz <tomazz>



To unsubscribe from these emails, change your notification settings at https://github.com/OSGeo/grass-addons/settings/notifications


More information about the grass-commit mailing list