geopyv-dev 0.1.15__tar.gz → 0.2.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.
Files changed (142) hide show
  1. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/.readthedocs.yaml +1 -1
  2. geopyv_dev-0.2.0/CLAUDE.md +134 -0
  3. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/Cargo.lock +3 -3
  4. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/Cargo.toml +1 -1
  5. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/PKG-INFO +1 -1
  6. geopyv_dev-0.2.0/geopyv_dev/__init__.py +794 -0
  7. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv_dev/plots.py +296 -29
  8. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv_dev/wrappers.py +2 -1
  9. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/pyproject.toml +1 -1
  10. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/Cargo.toml +1 -1
  11. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_field.rs +13 -17
  12. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_image.rs +18 -1
  13. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_mask.rs +12 -4
  14. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_mesh.rs +425 -6
  15. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_particle.rs +212 -4
  16. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_sequence.rs +78 -6
  17. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_speckle.rs +41 -5
  18. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_subset.rs +33 -0
  19. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/field.rs +209 -26
  20. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/geometry/mod.rs +1 -0
  21. geopyv_dev-0.2.0/src/geometry/rasterize.rs +674 -0
  22. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/image.rs +60 -40
  23. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/io.rs +636 -17
  24. geopyv_dev-0.2.0/src/masks.rs +573 -0
  25. geopyv_dev-0.2.0/src/mesh.rs +3574 -0
  26. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/particle.rs +982 -20
  27. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/sequence.rs +35 -1
  28. geopyv_dev-0.2.0/src/speckle.rs +1523 -0
  29. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/subset.rs +650 -72
  30. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/validation.rs +5 -0
  31. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/image/test_image.py +44 -37
  32. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/io/test_io.py +2 -1
  33. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/plots/test_plots.py +346 -1
  34. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/sequence/test_sequence.py +191 -0
  35. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/subset/test_subset.py +113 -16
  36. geopyv_dev-0.1.15/geopyv_dev/__init__.py +0 -409
  37. geopyv_dev-0.1.15/src/masks.rs +0 -301
  38. geopyv_dev-0.1.15/src/mesh.rs +0 -1714
  39. geopyv_dev-0.1.15/src/speckle.rs +0 -696
  40. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/.github/workflows/release.yml +0 -0
  41. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/.gitignore +0 -0
  42. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/LICENSE +0 -0
  43. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/Makefile +0 -0
  44. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/README.md +0 -0
  45. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/basictest.py +0 -0
  46. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/_static/gifs/intro_hero.gif +0 -0
  47. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/_static/gifs/quad_deformation.gif +0 -0
  48. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/_static/gifs/region_motion.gif +0 -0
  49. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/_static/gifs/sequence_distortion.gif +0 -0
  50. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/_static/gifs/subset_shape_order.gif +0 -0
  51. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/_static/img/c2_subset.png +0 -0
  52. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/_static/img/combined_25_standard_error.png +0 -0
  53. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/_static/img/mask_local_vs_global.png +0 -0
  54. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/_static/img/mesh_solve_flow.png +0 -0
  55. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/_static/img/sequence_solve_flow.png +0 -0
  56. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/_static/img/subset_quality.png +0 -0
  57. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/api/index.rst +0 -0
  58. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/conf.py +0 -0
  59. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/index.rst +0 -0
  60. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/installation.rst +0 -0
  61. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/requirements-docs.txt +0 -0
  62. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/scripts/build_images_assets.py +0 -0
  63. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/scripts/build_intro_gif.py +0 -0
  64. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/scripts/build_mesh_flow.py +0 -0
  65. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/scripts/build_region_motion_gif.py +0 -0
  66. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/scripts/build_sequence_distortion_gif.py +0 -0
  67. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/scripts/build_sequence_flow.py +0 -0
  68. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/scripts/build_subset_assets.py +0 -0
  69. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/scripts/common.py +0 -0
  70. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/tutorials/00_introduction.rst +0 -0
  71. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/tutorials/01_images_and_masks.rst +0 -0
  72. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/tutorials/02_subset.rst +0 -0
  73. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/tutorials/03_mesh.rst +0 -0
  74. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/tutorials/04_sequence.rst +0 -0
  75. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/tutorials/05_particle.rst +0 -0
  76. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/tutorials/06_field.rst +0 -0
  77. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/tutorials/07_validation.rst +0 -0
  78. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/tutorials/08_calibration.rst +0 -0
  79. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/docs/tutorials/index.rst +0 -0
  80. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/00_introduction.ipynb +0 -0
  81. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/01_images_and_masks.ipynb +0 -0
  82. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/02_subset.ipynb +0 -0
  83. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/03_mesh.ipynb +0 -0
  84. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/04_sequence.ipynb +0 -0
  85. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/05_particle_and_field.ipynb +0 -0
  86. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/data/sequence/seq_0.jpg +0 -0
  87. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/data/sequence/seq_1.jpg +0 -0
  88. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/data/sequence/seq_2.jpg +0 -0
  89. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/data/sequence/seq_3.jpg +0 -0
  90. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/data/sequence/seq_4.jpg +0 -0
  91. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/data/single/intro_0.jpg +0 -0
  92. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv-dev-tutorials/data/single/intro_1.jpg +0 -0
  93. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/geopyv_dev/calibration.py +0 -0
  94. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/SB/SB_0.jpg +0 -0
  95. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/SB/SB_1.jpg +0 -0
  96. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/SB/SB_2.jpg +0 -0
  97. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/SB/SB_3.jpg +0 -0
  98. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/SB/SB_4.jpg +0 -0
  99. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/SB/SB_5.jpg +0 -0
  100. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/SB/speckle_SB.pyv +0 -0
  101. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/comp/compression_0.jpg +0 -0
  102. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/comp/compression_1.jpg +0 -0
  103. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/comp/compression_10.jpg +0 -0
  104. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/comp/compression_2.jpg +0 -0
  105. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/comp/compression_3.jpg +0 -0
  106. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/comp/compression_4.jpg +0 -0
  107. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/comp/compression_5.jpg +0 -0
  108. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/comp/compression_6.jpg +0 -0
  109. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/comp/compression_7.jpg +0 -0
  110. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/comp/compression_8.jpg +0 -0
  111. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/comp/compression_9.jpg +0 -0
  112. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/quality/quality_speckle.jpg +0 -0
  113. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/shear/shear_0.jpg +0 -0
  114. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/shear/shear_1.jpg +0 -0
  115. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/shear/shear_2.jpg +0 -0
  116. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/shear/shear_3.jpg +0 -0
  117. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/shear/shear_4.jpg +0 -0
  118. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/images/shear/speckle_shear.pyv +0 -0
  119. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/geopyv-dev/__init__.py +0 -0
  120. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/lib.rs +0 -0
  121. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_calibration.rs +0 -0
  122. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_geometry.rs +0 -0
  123. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_io.rs +0 -0
  124. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/py_validation.rs +0 -0
  125. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/python/src/utils.rs +0 -0
  126. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/calibration.rs +0 -0
  127. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/error.rs +0 -0
  128. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/geometry/meshing.rs +0 -0
  129. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/geometry/region.rs +0 -0
  130. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/geometry/triangulation.rs +0 -0
  131. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/geometry/utilities.rs +0 -0
  132. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/src/lib.rs +0 -0
  133. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/calibration/test_calibration.py +0 -0
  134. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/field/test_field.py +0 -0
  135. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/geometry/test_geometry.py +0 -0
  136. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/mesh/test_mesh.py +0 -0
  137. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/particle/test_particle.py +0 -0
  138. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/plots/__init__.py +0 -0
  139. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/plots/conftest.py +0 -0
  140. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/templates/test_templates.py +0 -0
  141. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/validation/test_validation.py +0 -0
  142. {geopyv_dev-0.1.15 → geopyv_dev-0.2.0}/tests/python/validation/test_validation_solve.py +0 -0
@@ -4,7 +4,7 @@ build:
4
4
  os: ubuntu-22.04
5
5
  tools:
6
6
  python: "3.12"
7
- rust: "1.86"
7
+ rust: "1.91"
8
8
 
9
9
  sphinx:
10
10
  configuration: docs/conf.py
@@ -0,0 +1,134 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ### Build & develop
8
+
9
+ ```bash
10
+ # Build the Rust core library only
11
+ cargo build
12
+
13
+ # Build the Python extension (debug)
14
+ cargo build -p geopyv-dev-python
15
+
16
+ # Build and install the Python package into the venv (required after any Rust change)
17
+ source .venv/bin/activate
18
+ maturin develop --manifest-path python/Cargo.toml
19
+
20
+ # Run all Rust unit tests
21
+ cargo test
22
+
23
+ # Run a single Rust test by name
24
+ cargo test test_solve_icgn_order1_golden
25
+
26
+ # Run Python tests
27
+ source .venv/bin/activate
28
+ pytest tests/python/
29
+
30
+ # Run a single Python test file
31
+ pytest tests/python/mesh/test_mesh.py
32
+
33
+ # Run the integration smoke-test (requires images/ directory)
34
+ source .venv/bin/activate && python basictest.py
35
+ ```
36
+
37
+ ### Build the GUI (separate binary crate)
38
+
39
+ ```bash
40
+ cargo build -p geopyv-gui
41
+ cargo run -p geopyv-gui
42
+ ```
43
+
44
+ ### Publishing a release to PyPI
45
+
46
+ The `.github/workflows/release.yml` workflow triggers **only on version tags** — pushing a branch does nothing. Steps:
47
+
48
+ 1. Update the version string in all three places (they must match):
49
+ - `Cargo.toml` (workspace root) — `version = "x.y.z"`
50
+ - `pyproject.toml` — `version = "x.y.z"`
51
+ - `python/Cargo.toml` — `version = "x.y.z"`
52
+
53
+ 2. Commit the version bump and push the branch:
54
+ ```bash
55
+ git add Cargo.toml pyproject.toml python/Cargo.toml
56
+ git commit -m "Bump version to x.y.z"
57
+ git push origin <branch>
58
+ ```
59
+
60
+ 3. Create and push the version tag:
61
+ ```bash
62
+ git tag vx.y.z
63
+ git push origin vx.y.z
64
+ ```
65
+
66
+ The tag push triggers the workflow: it builds manylinux + aarch64 + Windows wheels and an sdist, then publishes everything to PyPI via trusted publishing (no API token needed).
67
+
68
+ ## Architecture
69
+
70
+ ### Three-crate workspace
71
+
72
+ ```
73
+ geopyv-dev/ ← workspace root
74
+ src/ ← Rust core library (crate: geopyv-dev)
75
+ python/src/ ← PyO3 extension (crate: geopyv-dev-python → _geopyv_dev.so)
76
+ geopyv-gui/src/ ← egui desktop app (crate: geopyv-gui)
77
+ geopyv_dev/ ← Python package (imports .so + adds wrappers/plots)
78
+ tests/python/ ← pytest suite for the Python API
79
+ ```
80
+
81
+ The Python package that users import (`geopyv_dev`) is **not** the `.so` directly. It lives in `geopyv_dev/` and consists of:
82
+ - `__init__.py` — re-exports `_geopyv_dev.*`, then shadows the raw Rust classes (`Subset`, `Mesh`, `Sequence`, `Field`, `Particle`) with thin Python wrappers that add `.solve()`, `.inspect()`, `.convergence()`, `.contour()`.
83
+ - `wrappers.py` — `MeshWrapper`, `SequenceSolutionWrapper`, `FieldWrapper`, `ParticleWrapper`, `SubsetWrapper` — returned by `.solve()` on the wrapper classes.
84
+ - `plots.py` — all matplotlib visualisation functions.
85
+ - `_geopyv_dev.cpython-*.so` — the compiled Rust extension.
86
+
87
+ The installed `.so` is also shadowed: `maturin` writes to `geopyv_dev/_geopyv_dev.so` directly, which means `maturin develop` + the existing `geopyv_dev/` package are the runtime. There is a `python/geopyv-dev/` stub that is only used during the maturin build and can be ignored.
88
+
89
+ ### Rust core → PyO3 boundary
90
+
91
+ Each domain module in `src/` has a corresponding `python/src/py_*.rs` wrapper:
92
+
93
+ | Core (`src/`) | Wrapper (`python/src/`) | Python class |
94
+ |---|---|---|
95
+ | `image.rs` | `py_image.rs` | `Image` |
96
+ | `templates.rs` | `py_templates.rs` | `Template` |
97
+ | `geometry/` | `py_geometry.rs` | `CircleRegion`, `PathRegion`, free fns |
98
+ | `subset.rs` | `py_subset.rs` | `Subset` |
99
+ | `mesh.rs` | `py_mesh.rs` | `Mesh`, `MeshSolution` |
100
+ | `sequence.rs` | `py_sequence.rs` | `Sequence`, `SequenceSolution` |
101
+ | `particle.rs` | `py_particle.rs` | `Particle`, `ParticleSolution` |
102
+ | `field.rs` | `py_field.rs` | `Field`, `FieldSolution` |
103
+ | `io.rs` | `py_io.rs` | `save`, `load` |
104
+ | `validation.rs` | `py_validation.rs` | free validation fns |
105
+
106
+ Error bridging: `geopyv_dev::Error` cannot implement `From<PyErr>` directly (orphan rule). The `python/src/lib.rs` newtype `Error(geopyv_dev::Error)` bridges via two `From` impls. Every wrapper method uses `.map_err(Error::from)?`.
107
+
108
+ ### Data flow: DIC solve
109
+
110
+ `Image::from_file` → FFT → B-spline coefficients (QCQT matrix, stored on `Image`) → `Subset::new` takes QCQT + template coordinates + centre → computes `f`, `f_m`, `delta_f`, `grad_f` → `solve_icgn` / `solve_fagn` takes target QCQT + initial warp → returns `SolveResult`.
111
+
112
+ At the Python level: `gp.Image(filepath=...)` → `gp.Template(...)` → `gp.Subset(coord, template, f_img)` → `subset.solve(g_img, p_0)`.
113
+
114
+ ### Mesh pipeline
115
+
116
+ `Mesh.generate(borders, segments, curves, ...)` calls `spade` (Delaunay/CDT) internally. `borders`/`segments`/`curves` are produced by `define_roi` (in `geometry/meshing.rs` / `py_geometry.rs`), which takes raw boundary nodes and exclusion-region node arrays and computes the constraint topology. `Mesh.solve(f_img, g_img, template, seed_coord, seed_warp)` runs reliability-guided propagation across all nodes, calling `Subset::new` + `solve_icgn/fagn` per node.
117
+
118
+ ### Serialisation
119
+
120
+ `.pyv` files: 4-byte magic `GPYV` + 1-byte version `0x01` + bincode-v2 encoded `GeopyvObject` (a serde enum over `MeshSolution`, `FieldSolution`, `SequenceSolution`, `SubsetSolution`, `ParticleSolution`). Incompatible with the Python `geopyv` pickle format.
121
+
122
+ ### Coordinate convention
123
+
124
+ `coord[0]` = x (column), `coord[1]` = y (row). `bspline_eval` uses `coords[:,0]` as the column index and `coords[:,1]` as the row index. This matches `_subset.cpp` in the original Python package.
125
+
126
+ ### Tolerance tiers (used in test names and comments)
127
+
128
+ - **Tier A** `atol = 1e-12` — pure matrix algebra, no floating-point chains.
129
+ - **Tier B** `rtol = 1e-8` — FFT / B-spline coefficient computation.
130
+ - **Tier C** `rtol = 1e-5` — solver outputs (ZNCC, converged warp).
131
+
132
+ ### Original Python package reference
133
+
134
+ The Rust code is a rewrite of `geopyv` (Python). C++ extension functions (`_subset.cpp`, etc.) are the numerical ground-truth. Comments throughout `src/` note which Python/C++ function each Rust function matches (e.g. `// Matches _intensity in _subset.cpp`). Golden test values come from running the Python package on the same inputs. The Python test images live at `geopyv/tests/ref.jpg` and `tar.jpg` relative to `CARGO_MANIFEST_DIR`; integration tests skip gracefully if the files are absent.
@@ -1531,7 +1531,7 @@ dependencies = [
1531
1531
 
1532
1532
  [[package]]
1533
1533
  name = "geopyv-dev"
1534
- version = "0.1.15"
1534
+ version = "0.2.0"
1535
1535
  dependencies = [
1536
1536
  "bincode",
1537
1537
  "image",
@@ -1550,7 +1550,7 @@ dependencies = [
1550
1550
 
1551
1551
  [[package]]
1552
1552
  name = "geopyv-dev-python"
1553
- version = "0.1.15"
1553
+ version = "0.2.0"
1554
1554
  dependencies = [
1555
1555
  "geopyv-dev",
1556
1556
  "ndarray",
@@ -1560,7 +1560,7 @@ dependencies = [
1560
1560
 
1561
1561
  [[package]]
1562
1562
  name = "geopyv-gui"
1563
- version = "0.1.13"
1563
+ version = "0.2.0"
1564
1564
  dependencies = [
1565
1565
  "dirs",
1566
1566
  "eframe",
@@ -4,7 +4,7 @@ resolver = "2"
4
4
 
5
5
  [package]
6
6
  name = "geopyv-dev"
7
- version = "0.1.15"
7
+ version = "0.2.0"
8
8
  edition = "2024"
9
9
 
10
10
  [dependencies]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geopyv_dev
3
- Version: 0.1.15
3
+ Version: 0.2.0
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)