qgis-tem-loader

qgis plugin for loading TEM geophysical inversion XYZ files as 3D objects
git clone git://src.adamsgaard.dk/qgis-tem-loader # fast
git clone https://src.adamsgaard.dk/qgis-tem-loader.git # slow
Log | Files | Refs | README | LICENSE Back to index

AGENTS.md (3935B)


      1 # TEM Loader Plugin
      2 
      3 QGIS 3.40+ plugin for loading Time-Domain Electromagnetic (TEM) inversion XYZ files as styled 3D vector layers. Python; the only third-party dependency is numpy, which ships with QGIS. Tests and CI must install numpy.
      4 
      5 ## Commands
      6 
      7 ```sh
      8 make test      # run the unittest suite
      9 python3 -m unittest discover -s test -p 'test_*.py'  # same test runner without Make
     10 python3 -m unittest test.test_core.ProcessXYZTests.test_temimage_4_0_4_6_fixture  # single test
     11 make package   # build tem_loader.zip for installation
     12 make clean     # remove the zip
     13 ```
     14 
     15 CI runs `make test` on Python 3.12; the GitLab pipeline also produces `tem_loader.zip` as an artifact.
     16 
     17 ## Boundaries
     18 
     19 **Allowed without asking:**
     20 - Read any file, list directories, run single-file type checks and tests
     21 - Create or edit files in `tem_loader/`, `test/`, and `tem_loader/styles/`
     22 
     23 **Ask first:**
     24 - Installing new Python dependencies (project has none)
     25 - Deleting test fixtures from `test/data/`
     26 - Pushing to git (`git-push.sh` pushes to origin, own, and geus remotes)
     27 
     28 **Never touch:**
     29 - `.env`, secrets, or credentials
     30 - Binary video files (`*.mov`, `*.mp4`) — they are demos, not code
     31 - Large XYZ fixture data in the project root (development samples only)
     32 
     33 ## Architecture
     34 
     35 - `tem_loader/core.py` — XYZ parsing, CSV writing, resistivity color mapping. No QGIS dependency; fully unit-testable.
     36 - `tem_loader/interpolate.py` — Vectorized (numpy) IDW interpolation core: `GridSpec`, `axis_count`/`axis_cell_size`, `samples_from_layers`, `idw`, `interpolate_voxels`. Depends on numpy but has no QGIS dependency; fully unit-testable (numpy must be installed for tests).
     37 - `tem_loader/mean_resistivity.py` — Mean resistivity maps per elevation interval: per-sounding thickness-weighted log10 interval mean (`interval_mean`), vectorized 2D IDW (`idw_grid`), and `mean_resistivity_maps`. numpy only; no QGIS dependency.
     38 - `tem_loader/geotiff.py` — GeoTIFF writer using `osgeo.gdal` (ships with QGIS). `test/test_geotiff.py` skips when GDAL is not installed, as in CI.
     39 - `tem_loader/tem_loader.py` — QGIS plugin glue: dialogs, layer creation, CRS resolution, styling, group organization.
     40 - `tem_loader/styles/*.qml` — QGIS layer style files for points, DOI, layers, and voxels (supports 3D renderer with dynamic color), and the raster style for mean resistivity maps (mirrors `core.RESISTIVITY_COLOR_RAMP`).
     41 - `test/data/` — fixture XYZ files for the three supported export families: TEMImage, Aarhus Workbench, and SCI Workbench.
     42 
     43 ## Conventions
     44 
     45 - Fallible operations raise `ValueError` with descriptive messages; callers catch and present them to the user (not swallowed).
     46 - Multiple file processing continues after errors per-file, collecting failures into a single warning dialog.
     47 - CRS resolution: source EPSG from file metadata > project CRS > EPSG:4326 fallback.
     48 - Test fixtures live in `test/data/`; tests assert counts, specific field values, and QXML structure (for style verification).
     49 
     50 ## Git
     51 
     52 - Commit messages follow conventional commits, for example `feat(parser): ...`, `fix(qgis): ...`, `build: ...`, and `chore(release): ...`.
     53 - Do not push without approval; `git-push.sh` pushes to `origin`, `own`, and `geus`.
     54 
     55 ## Gotchas
     56 
     57 - `core.py` must remain free of QGIS imports — it is the only module tested without a running QGIS instance.
     58 - The SCI Workbench format aggregates per-layer rows into soundings at parse time; its code path diverges from the other two formats.
     59 - XYZ files with an extra leading index column (pandas-style) must be handled by dropping the first value before zipping.
     60 - `tem_loader.py` imports `geotiff.py` (and thus `osgeo`) at module level; the plugin tests in `test_core.py` stub `osgeo` alongside `qgis` so they run in CI without GDAL.
     61 - `test_fixture_doi_values_fit_fixed_scale` parses every `test/data/*.xyz`, including untracked files; keep unsupported local samples in the project root.