From e32edba6ae3ba2caa1369d97526fcc8233bc352e Mon Sep 17 00:00:00 2001 From: lmoresi Date: Sun, 5 Jul 2026 17:46:21 +0100 Subject: [PATCH 1/7] chore(discretisation): delete the persistence.py stub module (WA-01 / LE-12, ruling D1) The module was a pure backward-compatibility re-export of EnhancedMeshVariable plus three 'TODO: Implement' stubs for features that exist nowhere else; its name promised persistence functionality that was never built. EnhancedMeshVariable remains exported through discretisation/__init__.py, so removal is behaviour-neutral. The only importer (underworld3/__init__.py) and the CLAUDE.md Key Files entry are updated. Maintainer ruling D1 (2026-07-06): delete outright, no warn-on-import shim. Underworld development team with AI support from Claude Code --- CLAUDE.md | 1 - src/underworld3/__init__.py | 4 +- src/underworld3/discretisation/persistence.py | 53 ------------------- 3 files changed, 1 insertion(+), 57 deletions(-) delete mode 100644 src/underworld3/discretisation/persistence.py diff --git a/CLAUDE.md b/CLAUDE.md index e3c85d21b..6dbf6522b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -548,7 +548,6 @@ pixi run -e default python # Run Python in environment - `src/underworld3/function/expressions.py` - UWexpression (lazy evaluation, symbol disambiguation) - `src/underworld3/function/_function.pyx` - UnderworldFunction (mesh variable symbols) - `src/underworld3/discretisation/enhanced_variables.py` - EnhancedMeshVariable (units, math ops, persistence) -- `src/underworld3/discretisation/persistence.py` - Stub for future persistence features ### Historical Notes For development history, completed migrations, and fixed bugs: diff --git a/src/underworld3/__init__.py b/src/underworld3/__init__.py index d37bcb20d..4a316cc77 100644 --- a/src/underworld3/__init__.py +++ b/src/underworld3/__init__.py @@ -206,7 +206,6 @@ def view(): import underworld3.model import underworld3.parameters import underworld3.materials -import underworld3.discretisation.persistence import underworld3.checkpoint from .model import ( @@ -227,8 +226,7 @@ def view(): # Unit utilities (top-level convenience for user code) from .function.unit_conversion import _extract_value -# Currently on binder, pykdtree is hanging - fallback to previous implementation -# import underworld3.kdtree +# KDTree backend is ckdtree (nanoflann); see src/underworld3/kdtree.py import underworld3.ckdtree as kdtree import underworld3.cython import underworld3.scaling diff --git a/src/underworld3/discretisation/persistence.py b/src/underworld3/discretisation/persistence.py deleted file mode 100644 index 88185a43f..000000000 --- a/src/underworld3/discretisation/persistence.py +++ /dev/null @@ -1,53 +0,0 @@ -# underworld3/persistence.py -""" -Persistence features for adaptive meshing and data transfer. - -NOTE: EnhancedMeshVariable has been moved to enhanced_variables.py (2025-01-13). - -This module is reserved for future implementation of actual persistence features: -- Data transfer between meshes during adaptive refinement -- Variable state preservation across remeshing operations -- Checkpoint/restart capabilities for long-running simulations -- Mesh-to-mesh interpolation utilities - -For enhanced variables with mathematical operations and units support, -see discretisation/enhanced_variables.py - -Symbol Disambiguation Note (2025-12-15): ----------------------------------------- -When transferring data or expressions between meshes, be aware that: -- MeshVariable symbols are mesh-specific (v1.sym != v2.sym even with same name) -- Coordinate symbols (mesh.N.x, etc.) are also mesh-specific to prevent cache bugs -- For expression portability, use explicit coordinate substitution: - expr_for_mesh2 = expr.subs({mesh1.N.x: mesh2.N.x, mesh1.N.y: mesh2.N.y}) - -See: docs/developer/design/SYMBOL_DISAMBIGUATION_2025-12.md - -Historical Note: ------------------ -This module previously contained EnhancedMeshVariable, but that class -was moved to enhanced_variables.py where it logically belongs. The name -"persistence" was misleading since the main functionality was mathematical -operations and units support, not data persistence. - -The actual persistence features (like transfer_data_from) are integrated -into EnhancedMeshVariable and will be augmented here in the future with -standalone utilities for mesh-to-mesh data transfer. -""" - -# For backward compatibility, re-export from enhanced_variables -# This ensures existing code that imports from persistence still works -from .enhanced_variables import ( - EnhancedMeshVariable, - create_enhanced_mesh_variable, -) - -__all__ = [ - "EnhancedMeshVariable", # Re-exported for backward compatibility - "create_enhanced_mesh_variable", # Re-exported for backward compatibility -] - -# Future persistence utilities will be added here -# TODO: Implement standalone mesh-to-mesh transfer functions -# TODO: Implement checkpoint/restart utilities -# TODO: Implement adaptive meshing data preservation From c5edfbaf49d846d9cb2069b55d4229c87f629a8b Mon Sep 17 00:00:00 2001 From: lmoresi Date: Sun, 5 Jul 2026 17:46:44 +0100 Subject: [PATCH 2/7] chore(units): prune the unsupported coord-units family; deprecate the mesh units= kwarg (WA-23/WA-24/BF-12 = LE-08/10/11, ruling D7) Maintainer ruling D7 (2026-07-06): the quantity-coordinate / coord_units feature family is UNSUPPORTED. Accordingly: - Delete the 16 placeholder skips that guarded the never-implemented features (test_0730_variable_units_integration x2, test_0800_unit_aware_functions x3, and the placeholder-only files test_0803_simple_workflow_demo, test_0803_units_workflow_integration, test_0804_backward_compatibility_units, test_0811_evaluate_unit_coords). - Delete test_0630 (pure demonstration of the superseded proposal) and rewrite test_0620 to assert the IMPLEMENTED model-owned mesh-units semantics (mesh.units from model reference quantities; deprecated kwarg warns and is ignored; model precedence). - Rewrite test_0812 with supported coordinate forms (explicit non_dimensionalise + numpy arrays), regaining the Poisson-with-units coverage the three skips had lost; document in evaluate()'s docstring that quantity-valued coordinate lists are not supported. - Deprecate the Cartesian-only units= mesh-constructor kwarg: it was always ignored in favour of the model units; it now raises a DeprecationWarning saying so, and the constructor docstrings are made honest. StructuredQuadBox's unit auto-detection block fed only this ignored parameter and is deleted. test_1011 stops passing the kwarg. - Record the declined proposal in docs/developer/design/declined-coord-units-proposal.md. Underworld development team with AI support from Claude Code --- .../_phase_b_bdf2_th+15_ty0p05.trace.txt | 15 - .../design/_phase_f_bdf1_iso.trace.txt | 123 ------ .../design/_phase_f_etd1_pc1.trace.txt | 123 ------ .../design/_phase_f_etd1_pc_picard.trace.txt | 123 ------ .../design/_phase_f_etd2_pc1.trace.txt | 123 ------ .../design/_phase_f_etd2_pc_picard.trace.txt | 63 --- .../design/declined-coord-units-proposal.md | 48 +++ .../_repro_dminterp_multifield_bug.py | 0 .../_exp_integrator_phase_a.py | 0 .../_exp_integrator_phase_b_benches.py | 0 .../_exp_integrator_phase_b_eval.py | 0 .../_exp_integrator_phase_b_killer.py | 0 .../_exp_integrator_phase_b_ti_iso.py | 0 .../_exp_integrator_phase_b_validate.py | 0 .../_exp_integrator_phase_d_split.py | 0 .../_exp_integrator_uw3_jury_rig.py | 0 .../exp-integrator}/_exp_jury_rig_minimal.py | 0 .../_phase_b_bdf2_at_tight_yield.py | 0 .../_phase_b_bdf_vs_etd_at_tight_yield.py | 0 .../_phase_b_etd1_at_tight_yield.py | 0 .../exp-integrator}/_phase_d_killer_split.py | 0 .../exp-integrator}/_phase_e_killer_hybrid.py | 0 .../_phase_f_predictor_corrector.py | 0 .../_plot_phase_b_bdf_vs_etd.py | 0 .../exp-integrator}/_plot_phase_b_fields.py | 0 .../exp-integrator}/_plot_phase_b_pyvista.py | 0 .../exp-integrator}/_plot_phase_b_results.py | 0 .../_plot_phase_d_pyvista_split.py | 0 .../_plot_phase_d_uy_diagnosis.py | 0 .../_plot_phase_e_pyvista_hybrid.py | 0 .../exp-integrator}/_plot_phase_f.py | 0 .../exp_integrator_phase_a.png | Bin .../exp_integrator_phase_b_largedt.png | Bin .../exp_integrator_phase_b_square.png | Bin .../exp_integrator_phase_b_vardt.png | Bin .../exp_integrator_phase_b_yield.png | Bin docs/developer/index.md | 1 + .../discretisation/discretisation_mesh.py | 23 +- .../function/functions_unit_system.py | 7 + src/underworld3/meshing/cartesian.py | 22 +- tests/test_0620_mesh_units_interface.py | 401 +++--------------- tests/test_0630_mesh_units_demonstration.py | 306 ------------- tests/test_0730_variable_units_integration.py | 47 -- tests/test_0800_unit_aware_functions.py | 137 ------ tests/test_0803_simple_workflow_demo.py | 245 ----------- tests/test_0803_units_workflow_integration.py | 395 ----------------- .../test_0804_backward_compatibility_units.py | 127 ------ tests/test_0811_evaluate_unit_coords.py | 214 ---------- tests/test_0812_poisson_with_units.py | 285 ++++--------- tests/test_1011_bodyforce_units.py | 2 +- 50 files changed, 219 insertions(+), 2611 deletions(-) delete mode 100644 docs/developer/design/_phase_b_bdf2_th+15_ty0p05.trace.txt delete mode 100644 docs/developer/design/_phase_f_bdf1_iso.trace.txt delete mode 100644 docs/developer/design/_phase_f_etd1_pc1.trace.txt delete mode 100644 docs/developer/design/_phase_f_etd1_pc_picard.trace.txt delete mode 100644 docs/developer/design/_phase_f_etd2_pc1.trace.txt delete mode 100644 docs/developer/design/_phase_f_etd2_pc_picard.trace.txt create mode 100644 docs/developer/design/declined-coord-units-proposal.md rename docs/developer/design/{ => experiments/dminterp-multifield}/_repro_dminterp_multifield_bug.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_exp_integrator_phase_a.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_exp_integrator_phase_b_benches.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_exp_integrator_phase_b_eval.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_exp_integrator_phase_b_killer.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_exp_integrator_phase_b_ti_iso.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_exp_integrator_phase_b_validate.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_exp_integrator_phase_d_split.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_exp_integrator_uw3_jury_rig.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_exp_jury_rig_minimal.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_phase_b_bdf2_at_tight_yield.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_phase_b_bdf_vs_etd_at_tight_yield.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_phase_b_etd1_at_tight_yield.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_phase_d_killer_split.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_phase_e_killer_hybrid.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_phase_f_predictor_corrector.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_plot_phase_b_bdf_vs_etd.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_plot_phase_b_fields.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_plot_phase_b_pyvista.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_plot_phase_b_results.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_plot_phase_d_pyvista_split.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_plot_phase_d_uy_diagnosis.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_plot_phase_e_pyvista_hybrid.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/_plot_phase_f.py (100%) rename docs/developer/design/{ => experiments/exp-integrator}/exp_integrator_phase_a.png (100%) rename docs/developer/design/{ => experiments/exp-integrator}/exp_integrator_phase_b_largedt.png (100%) rename docs/developer/design/{ => experiments/exp-integrator}/exp_integrator_phase_b_square.png (100%) rename docs/developer/design/{ => experiments/exp-integrator}/exp_integrator_phase_b_vardt.png (100%) rename docs/developer/design/{ => experiments/exp-integrator}/exp_integrator_phase_b_yield.png (100%) delete mode 100644 tests/test_0630_mesh_units_demonstration.py delete mode 100644 tests/test_0803_simple_workflow_demo.py delete mode 100644 tests/test_0803_units_workflow_integration.py delete mode 100644 tests/test_0804_backward_compatibility_units.py delete mode 100644 tests/test_0811_evaluate_unit_coords.py diff --git a/docs/developer/design/_phase_b_bdf2_th+15_ty0p05.trace.txt b/docs/developer/design/_phase_b_bdf2_th+15_ty0p05.trace.txt deleted file mode 100644 index 1555b41af..000000000 --- a/docs/developer/design/_phase_b_bdf2_th+15_ty0p05.trace.txt +++ /dev/null @@ -1,15 +0,0 @@ -=== BDF-2: θ=+15°, τ_y=0.05 === -Structured box element resolution 32 32 - step 1/120 t=0.050 V=+0.498 iters= 1 |σ|_II=2.383e-02 |u_y|=1.003e-05 |σ_∥|=2.052e-02 - step 2/120 t=0.100 V=+0.494 iters= 1 |σ|_II=4.634e-02 |u_y|=8.526e-05 |σ_∥|=3.989e-02 - step 3/120 t=0.150 V=+0.486 iters= 3 |σ|_II=7.835e-02 |u_y|=9.166e-03 |σ_∥|=5.149e-02 - step 4/120 t=0.200 V=+0.476 iters= 2 |σ|_II=1.296e-01 |u_y|=2.537e-02 |σ_∥|=5.081e-02 - step 5/120 t=0.250 V=+0.462 iters= 2 |σ|_II=2.099e-01 |u_y|=2.466e-02 |σ_∥|=5.069e-02 - step 10/120 t=0.500 V=+0.354 iters= 2 |σ|_II=6.482e-01 |u_y|=2.372e-02 |σ_∥|=5.034e-02 - step 15/120 t=0.750 V=+0.191 iters= 2 |σ|_II=8.816e-01 |u_y|=2.833e-02 |σ_∥|=5.033e-02 - step 20/120 t=1.000 V=-0.000 iters= 4 |σ|_II=8.373e-01 |u_y|=1.561e-02 |σ_∥|=4.854e-02 - step 25/120 t=1.250 V=-0.191 iters= 1 |σ|_II=6.041e-01 |u_y|=1.319e-02 |σ_∥|=1.914e-02 - step 30/120 t=1.500 V=-0.354 iters= 2 |σ|_II=7.496e-01 |u_y|=3.150e-02 |σ_∥|=3.976e-02 - step 35/120 t=1.750 V=-0.462 iters= 2 |σ|_II=1.872e+00 |u_y|=7.211e-02 |σ_∥|=4.820e-02 - step 40/120 t=2.000 V=-0.500 iters= 4 |σ|_II=1.423e+01 |u_y|=8.612e-01 |σ_∥|=4.884e-02 - step 45/120 t=2.250 V=-0.462 iters=10 |σ|_II=6.761e+01 |u_y|=9.766e+00 |σ_∥|=8.159e-02 diff --git a/docs/developer/design/_phase_f_bdf1_iso.trace.txt b/docs/developer/design/_phase_f_bdf1_iso.trace.txt deleted file mode 100644 index 29afd73d7..000000000 --- a/docs/developer/design/_phase_f_bdf1_iso.trace.txt +++ /dev/null @@ -1,123 +0,0 @@ -# Phase F predictor-corrector trace: bdf1_iso -# integrator='bdf' order=1 apply_radial_return=False in_residual_yield=True -# columns: step, t, V_top, snes_iters_total, picard_iters, sigma_eq_max, sigma_eq_max_after_correction, u_y_max, yielded_fraction - 1 0.0500 +0.4985 1 1 4.127208e-02 4.127208e-02 9.910768e-06 0.000000 - 2 0.1000 +0.4938 1 1 8.038114e-02 8.038114e-02 1.736993e-04 0.046832 - 3 0.1500 +0.4862 28 1 1.506698e-01 1.506698e-01 9.614702e-03 0.059688 - 4 0.2000 +0.4755 23 1 2.390412e-01 2.390412e-01 1.853175e-02 0.067034 - 5 0.2500 +0.4619 20 1 3.495552e-01 3.495552e-01 2.103261e-02 0.074380 - 6 0.3000 +0.4455 15 1 4.846955e-01 4.846955e-01 2.298590e-02 0.074380 - 7 0.3500 +0.4263 15 1 6.096305e-01 6.096305e-01 2.423472e-02 0.074380 - 8 0.4000 +0.4045 14 1 7.198707e-01 7.198707e-01 2.396950e-02 0.076217 - 9 0.4500 +0.3802 14 1 8.120357e-01 8.120357e-01 2.274448e-02 0.079890 - 10 0.5000 +0.3536 14 1 8.836892e-01 8.836892e-01 2.156902e-02 0.081726 - 11 0.5500 +0.3247 13 1 9.348462e-01 9.348462e-01 2.019526e-02 0.081726 - 12 0.6000 +0.2939 14 1 9.672433e-01 9.672433e-01 1.857488e-02 0.081726 - 13 0.6500 +0.2612 16 1 9.830292e-01 9.830292e-01 1.680594e-02 0.081726 - 14 0.7000 +0.2270 17 1 9.840694e-01 9.840694e-01 1.495069e-02 0.081726 - 15 0.7500 +0.1913 19 1 9.717716e-01 9.717716e-01 1.282147e-02 0.081726 - 16 0.8000 +0.1545 21 1 9.473505e-01 9.473505e-01 1.052256e-02 0.081726 - 17 0.8500 +0.1167 25 1 9.120627e-01 9.120627e-01 9.265141e-03 0.081726 - 18 0.9000 +0.0782 30 1 8.675153e-01 8.675153e-01 8.563905e-03 0.081726 - 19 0.9500 +0.0392 34 1 8.158198e-01 8.158198e-01 7.559992e-03 0.081726 - 20 1.0000 -0.0000 19 1 7.630093e-01 7.630093e-01 6.323271e-03 0.074380 - 21 1.0500 -0.0392 8 1 7.288530e-01 7.288530e-01 5.154964e-03 0.074380 - 22 1.1000 -0.0782 7 1 6.886855e-01 6.886855e-01 4.095200e-03 0.072544 - 23 1.1500 -0.1167 5 1 6.462222e-01 6.462222e-01 3.139607e-03 0.054178 - 24 1.2000 -0.1545 4 1 6.024623e-01 6.024623e-01 2.466041e-03 0.009183 - 25 1.2500 -0.1913 3 1 5.579514e-01 5.579514e-01 2.282205e-03 0.000000 - 26 1.3000 -0.2270 3 1 5.130849e-01 5.130849e-01 2.190943e-03 0.000000 - 27 1.3500 -0.2612 2 1 4.667991e-01 4.667991e-01 2.080320e-03 0.000918 - 28 1.4000 -0.2939 1 1 4.197769e-01 4.197769e-01 1.930754e-03 0.021120 - 29 1.4500 -0.3247 2 1 3.722971e-01 3.722971e-01 1.743052e-03 0.033058 - 30 1.5000 -0.3536 12 1 3.225307e-01 3.225307e-01 3.181995e-03 0.048669 - 31 1.5500 -0.3802 25 1 2.627879e-01 2.627879e-01 9.008150e-03 0.056015 - 32 1.6000 -0.4045 22 1 2.470817e-01 2.470817e-01 1.384321e-02 0.056015 - 33 1.6500 -0.4263 23 1 2.617071e-01 2.617071e-01 1.795609e-02 0.063361 - 34 1.7000 -0.4455 20 1 3.171074e-01 3.171074e-01 2.084389e-02 0.066116 - 35 1.7500 -0.4619 16 1 3.720918e-01 3.720918e-01 2.375286e-02 0.072544 - 36 1.8000 -0.4755 15 1 4.180842e-01 4.180842e-01 2.593457e-02 0.074380 - 37 1.8500 -0.4862 14 1 5.144363e-01 5.144363e-01 2.754916e-02 0.074380 - 38 1.9000 -0.4938 13 1 6.484323e-01 6.484323e-01 3.122790e-02 0.077135 - 39 1.9500 -0.4985 12 1 7.692478e-01 7.692478e-01 3.421500e-02 0.079890 - 40 2.0000 -0.5000 11 1 8.776854e-01 8.776854e-01 3.577072e-02 0.081726 - 41 2.0500 -0.4985 10 1 9.753243e-01 9.753243e-01 3.613523e-02 0.082645 - 42 2.1000 -0.4938 9 1 1.063180e+00 1.063180e+00 3.558671e-02 0.083563 - 43 2.1500 -0.4862 8 1 1.141797e+00 1.141797e+00 3.439847e-02 0.084481 - 44 2.2000 -0.4755 8 1 1.211360e+00 1.211360e+00 3.344108e-02 0.084481 - 45 2.2500 -0.4619 8 1 1.278016e+00 1.278016e+00 3.406503e-02 0.086318 - 46 2.3000 -0.4455 8 1 1.339710e+00 1.339710e+00 3.373125e-02 0.086318 - 47 2.3500 -0.4263 8 1 1.389034e+00 1.389034e+00 3.234658e-02 0.088154 - 48 2.4000 -0.4045 8 1 1.425182e+00 1.425182e+00 3.025302e-02 0.089073 - 49 2.4500 -0.3802 10 1 1.447622e+00 1.447622e+00 2.745848e-02 0.089073 - 50 2.5000 -0.3536 11 1 1.456493e+00 1.456493e+00 2.508182e-02 0.090909 - 51 2.5500 -0.3247 12 1 1.452144e+00 1.452144e+00 2.321883e-02 0.090909 - 52 2.6000 -0.2939 13 1 1.435099e+00 1.435099e+00 2.117630e-02 0.089073 - 53 2.6500 -0.2612 14 1 1.408897e+00 1.408897e+00 1.892825e-02 0.089073 - 54 2.7000 -0.2270 15 1 1.382260e+00 1.382260e+00 1.693459e-02 0.088154 - 55 2.7500 -0.1913 17 1 1.375198e+00 1.375198e+00 1.496980e-02 0.089073 - 56 2.8000 -0.1545 20 1 1.361218e+00 1.361218e+00 1.361402e-02 0.089073 - 57 2.8500 -0.1167 23 1 1.338628e+00 1.338628e+00 1.213324e-02 0.088154 - 58 2.9000 -0.0782 27 1 1.307413e+00 1.307413e+00 1.046934e-02 0.086318 - 59 2.9500 -0.0392 33 1 1.267677e+00 1.267677e+00 8.977656e-03 0.082645 - 60 3.0000 -0.0000 24 1 1.220795e+00 1.220795e+00 7.933386e-03 0.081726 - 61 3.0500 +0.0392 10 1 1.171966e+00 1.171966e+00 6.959463e-03 0.080808 - 62 3.1000 +0.0782 7 1 1.112697e+00 1.112697e+00 5.897244e-03 0.071625 - 63 3.1500 +0.1167 5 1 1.047772e+00 1.047772e+00 4.924303e-03 0.056015 - 64 3.2000 +0.1545 5 1 9.822068e-01 9.822068e-01 4.021409e-03 0.016529 - 65 3.2500 +0.1913 4 1 9.166450e-01 9.166450e-01 3.436732e-03 0.001837 - 66 3.3000 +0.2270 3 1 8.520661e-01 8.520661e-01 3.068158e-03 0.000000 - 67 3.3500 +0.2612 2 1 7.883038e-01 7.883038e-01 2.865541e-03 0.001837 - 68 3.4000 +0.2939 2 1 7.247583e-01 7.247583e-01 2.728022e-03 0.019284 - 69 3.4500 +0.3247 2 1 6.614330e-01 6.614330e-01 2.528061e-03 0.032140 - 70 3.5000 +0.3536 11 1 5.970971e-01 5.970971e-01 3.228570e-03 0.048669 - 71 3.5500 +0.3802 25 1 5.245090e-01 5.245090e-01 8.312550e-03 0.056015 - 72 3.6000 +0.4045 23 1 4.415680e-01 4.415680e-01 1.276039e-02 0.056015 - 73 3.6500 +0.4263 23 1 3.740465e-01 3.740465e-01 1.660880e-02 0.062443 - 74 3.7000 +0.4455 19 1 3.769107e-01 3.769107e-01 1.956283e-02 0.065197 - 75 3.7500 +0.4619 16 1 3.849742e-01 3.849742e-01 2.212255e-02 0.069789 - 76 3.8000 +0.4755 15 1 4.314492e-01 4.314492e-01 2.585272e-02 0.073462 - 77 3.8500 +0.4862 13 1 4.569590e-01 4.569590e-01 2.882846e-02 0.074380 - 78 3.9000 +0.4938 13 1 5.536645e-01 5.536645e-01 3.087855e-02 0.076217 - 79 3.9500 +0.4985 12 1 6.987001e-01 6.987001e-01 3.270765e-02 0.076217 - 80 4.0000 +0.5000 11 1 8.300400e-01 8.300400e-01 3.425436e-02 0.078972 - 81 4.0500 +0.4985 10 1 9.481211e-01 9.481211e-01 3.628425e-02 0.081726 - 82 4.1000 +0.4938 9 1 1.052744e+00 1.052744e+00 3.772184e-02 0.082645 - 83 4.1500 +0.4862 9 1 1.143134e+00 1.143134e+00 3.843999e-02 0.082645 - 84 4.2000 +0.4755 8 1 1.218388e+00 1.218388e+00 3.838852e-02 0.083563 - 85 4.2500 +0.4619 8 1 1.277964e+00 1.277964e+00 3.765011e-02 0.085399 - 86 4.3000 +0.4455 8 1 1.322205e+00 1.322205e+00 3.624003e-02 0.086318 - 87 4.3500 +0.4263 8 1 1.352417e+00 1.352417e+00 3.423680e-02 0.087236 - 88 4.4000 +0.4045 9 1 1.370249e+00 1.370249e+00 3.178397e-02 0.087236 - 89 4.4500 +0.3802 10 1 1.378066e+00 1.378066e+00 2.894993e-02 0.087236 - 90 4.5000 +0.3536 11 1 1.378157e+00 1.378157e+00 2.593349e-02 0.087236 - 91 4.5500 +0.3247 12 1 1.371909e+00 1.371909e+00 2.340301e-02 0.088154 - 92 4.6000 +0.2939 13 1 1.359741e+00 1.359741e+00 2.156856e-02 0.089073 - 93 4.6500 +0.2612 14 1 1.342647e+00 1.342647e+00 1.961159e-02 0.089073 - 94 4.7000 +0.2270 16 1 1.344674e+00 1.344674e+00 1.743032e-02 0.089073 - 95 4.7500 +0.1913 18 1 1.336877e+00 1.336877e+00 1.502347e-02 0.087236 - 96 4.8000 +0.1545 20 1 1.320058e+00 1.320058e+00 1.392546e-02 0.087236 - 97 4.8500 +0.1167 23 1 1.294622e+00 1.294622e+00 1.297610e-02 0.085399 - 98 4.9000 +0.0782 28 1 1.260405e+00 1.260405e+00 1.166777e-02 0.083563 - 99 4.9500 +0.0392 33 1 1.217751e+00 1.217751e+00 1.010702e-02 0.081726 - 100 5.0000 +0.0000 22 1 1.167237e+00 1.167237e+00 8.388419e-03 0.081726 - 101 5.0500 -0.0392 9 1 1.111585e+00 1.111585e+00 7.391111e-03 0.081726 - 102 5.1000 -0.0782 7 1 1.048879e+00 1.048879e+00 5.923332e-03 0.071625 - 103 5.1500 -0.1167 5 1 9.869192e-01 9.869192e-01 4.702023e-03 0.055096 - 104 5.2000 -0.1545 4 1 9.244225e-01 9.244225e-01 3.691150e-03 0.013774 - 105 5.2500 -0.1913 3 1 8.618489e-01 8.618489e-01 3.237655e-03 0.000918 - 106 5.3000 -0.2270 3 1 8.000484e-01 8.000484e-01 3.031333e-03 0.000000 - 107 5.3500 -0.2612 2 1 7.381037e-01 7.381037e-01 2.863970e-03 0.001837 - 108 5.4000 -0.2939 2 1 6.763055e-01 6.763055e-01 2.714261e-03 0.021120 - 109 5.4500 -0.3247 2 1 6.147766e-01 6.147766e-01 2.540707e-03 0.033058 - 110 5.5000 -0.3536 12 1 5.518377e-01 5.518377e-01 3.367459e-03 0.048669 - 111 5.5500 -0.3802 25 1 4.792515e-01 4.792515e-01 8.877937e-03 0.056015 - 112 5.6000 -0.4045 23 1 3.948926e-01 3.948926e-01 1.378900e-02 0.056933 - 113 5.6500 -0.4263 23 1 3.537057e-01 3.537057e-01 1.782485e-02 0.063361 - 114 5.7000 -0.4455 20 1 3.527766e-01 3.527766e-01 2.055281e-02 0.065197 - 115 5.7500 -0.4619 16 1 3.959641e-01 3.959641e-01 2.324016e-02 0.068871 - 116 5.8000 -0.4755 15 1 4.349951e-01 4.349951e-01 2.537614e-02 0.073462 - 117 5.8500 -0.4862 14 1 4.724881e-01 4.724881e-01 2.728828e-02 0.074380 - 118 5.9000 -0.4938 13 1 5.735626e-01 5.735626e-01 3.131495e-02 0.076217 - 119 5.9500 -0.4985 12 1 6.955473e-01 6.955473e-01 3.435077e-02 0.077135 - 120 6.0000 -0.5000 11 1 8.061232e-01 8.061232e-01 3.596882e-02 0.079890 diff --git a/docs/developer/design/_phase_f_etd1_pc1.trace.txt b/docs/developer/design/_phase_f_etd1_pc1.trace.txt deleted file mode 100644 index 9c1186c8e..000000000 --- a/docs/developer/design/_phase_f_etd1_pc1.trace.txt +++ /dev/null @@ -1,123 +0,0 @@ -# Phase F predictor-corrector trace: etd1_pc1 -# integrator='etd' order=1 apply_radial_return=True in_residual_yield=False -# columns: step, t, V_top, snes_iters_total, picard_iters, sigma_eq_max, sigma_eq_max_after_correction, u_y_max, yielded_fraction - 1 0.0500 +0.4985 1 1 4.227008e-02 4.227008e-02 7.408887e-06 0.000000 - 2 0.1000 +0.4938 1 1 8.219118e-02 8.219118e-02 1.875342e-05 0.048669 - 3 0.1500 +0.4862 1 1 1.312133e-01 1.312133e-01 3.499493e-03 0.061524 - 4 0.2000 +0.4755 1 1 1.847484e-01 1.847484e-01 8.601088e-03 0.072544 - 5 0.2500 +0.4619 1 1 2.349787e-01 2.349787e-01 1.262241e-02 0.073462 - 6 0.3000 +0.4455 1 1 2.842488e-01 2.842488e-01 1.517815e-02 0.081726 - 7 0.3500 +0.4263 1 1 3.303034e-01 3.303034e-01 1.652152e-02 0.081726 - 8 0.4000 +0.4045 1 1 3.759653e-01 3.759653e-01 1.709990e-02 0.081726 - 9 0.4500 +0.3802 1 1 4.155843e-01 4.155843e-01 1.717741e-02 0.081726 - 10 0.5000 +0.3536 1 1 4.482948e-01 4.482948e-01 1.675827e-02 0.083563 - 11 0.5500 +0.3247 1 1 4.744306e-01 4.744306e-01 1.604408e-02 0.083563 - 12 0.6000 +0.2939 1 1 4.942698e-01 4.942698e-01 1.508513e-02 0.083563 - 13 0.6500 +0.2612 1 1 5.083255e-01 5.083255e-01 1.444807e-02 0.083563 - 14 0.7000 +0.2270 1 1 5.170730e-01 5.170730e-01 1.364595e-02 0.081726 - 15 0.7500 +0.1913 1 1 5.209158e-01 5.209158e-01 1.265520e-02 0.078972 - 16 0.8000 +0.1545 1 1 5.200673e-01 5.200673e-01 1.151499e-02 0.074380 - 17 0.8500 +0.1167 1 1 5.146865e-01 5.146865e-01 1.027186e-02 0.073462 - 18 0.9000 +0.0782 1 1 5.048434e-01 5.048434e-01 8.898937e-03 0.068871 - 19 0.9500 +0.0392 1 1 4.906089e-01 4.906089e-01 7.427466e-03 0.065197 - 20 1.0000 -0.0000 1 1 4.734378e-01 4.734378e-01 5.897057e-03 0.059688 - 21 1.0500 -0.0392 1 1 4.519180e-01 4.519180e-01 4.329136e-03 0.047750 - 22 1.1000 -0.0782 1 1 4.264055e-01 4.264055e-01 2.576242e-03 0.021120 - 23 1.1500 -0.1167 1 1 3.971031e-01 3.971031e-01 1.405211e-03 0.001837 - 24 1.2000 -0.1545 1 1 3.654972e-01 3.654972e-01 1.189141e-03 0.000000 - 25 1.2500 -0.1913 1 1 3.321918e-01 3.321918e-01 1.065001e-03 0.000000 - 26 1.3000 -0.2270 1 1 2.973628e-01 2.973628e-01 9.223411e-04 0.001837 - 27 1.3500 -0.2612 1 1 2.611811e-01 2.611811e-01 8.630974e-04 0.006428 - 28 1.4000 -0.2939 1 1 2.234569e-01 2.234569e-01 1.135203e-03 0.029385 - 29 1.4500 -0.3247 1 1 1.831775e-01 1.831775e-01 2.125745e-03 0.046832 - 30 1.5000 -0.3536 1 1 1.385713e-01 1.385713e-01 4.241876e-03 0.054178 - 31 1.5500 -0.3802 1 1 1.181696e-01 1.181696e-01 6.389454e-03 0.059688 - 32 1.6000 -0.4045 1 1 1.372726e-01 1.372726e-01 8.507503e-03 0.067952 - 33 1.6500 -0.4263 1 1 1.598838e-01 1.598838e-01 1.072879e-02 0.072544 - 34 1.7000 -0.4455 1 1 1.810420e-01 1.810420e-01 1.306631e-02 0.074380 - 35 1.7500 -0.4619 1 1 2.238122e-01 2.238122e-01 1.512466e-02 0.078053 - 36 1.8000 -0.4755 1 1 2.638722e-01 2.638722e-01 1.687399e-02 0.081726 - 37 1.8500 -0.4862 1 1 3.133549e-01 3.133549e-01 1.829238e-02 0.081726 - 38 1.9000 -0.4938 1 1 3.615901e-01 3.615901e-01 1.939778e-02 0.081726 - 39 1.9500 -0.4985 1 1 4.063672e-01 4.063672e-01 2.028848e-02 0.084481 - 40 2.0000 -0.5000 1 1 4.473514e-01 4.473514e-01 2.105355e-02 0.087236 - 41 2.0500 -0.4985 1 1 4.842762e-01 4.842762e-01 2.163985e-02 0.089073 - 42 2.1000 -0.4938 1 1 5.282834e-01 5.282834e-01 2.193861e-02 0.089073 - 43 2.1500 -0.4862 1 1 5.772664e-01 5.772664e-01 2.206459e-02 0.090909 - 44 2.2000 -0.4755 1 1 6.219866e-01 6.219866e-01 2.213212e-02 0.091827 - 45 2.2500 -0.4619 1 1 6.619491e-01 6.619491e-01 2.224729e-02 0.092746 - 46 2.3000 -0.4455 1 1 6.969564e-01 6.969564e-01 2.214004e-02 0.092746 - 47 2.3500 -0.4263 1 1 7.266837e-01 7.266837e-01 2.194797e-02 0.092746 - 48 2.4000 -0.4045 1 1 7.510734e-01 7.510734e-01 2.152773e-02 0.092746 - 49 2.4500 -0.3802 1 1 7.702274e-01 7.702274e-01 2.089505e-02 0.092746 - 50 2.5000 -0.3536 1 1 7.843171e-01 7.843171e-01 2.006671e-02 0.092746 - 51 2.5500 -0.3247 1 1 7.935401e-01 7.935401e-01 1.905951e-02 0.091827 - 52 2.6000 -0.2939 1 1 7.981186e-01 7.981186e-01 1.788337e-02 0.090909 - 53 2.6500 -0.2612 1 1 7.981725e-01 7.981725e-01 1.685370e-02 0.089073 - 54 2.7000 -0.2270 1 1 7.938056e-01 7.938056e-01 1.579015e-02 0.085399 - 55 2.7500 -0.1913 1 1 7.851243e-01 7.851243e-01 1.454144e-02 0.083563 - 56 2.8000 -0.1545 1 1 7.721168e-01 7.721168e-01 1.317253e-02 0.078053 - 57 2.8500 -0.1167 1 1 7.547879e-01 7.547879e-01 1.169327e-02 0.073462 - 58 2.9000 -0.0782 1 1 7.332337e-01 7.332337e-01 1.027793e-02 0.068871 - 59 2.9500 -0.0392 1 1 7.075753e-01 7.075753e-01 8.729184e-03 0.065197 - 60 3.0000 -0.0000 1 1 6.779846e-01 6.779846e-01 7.188479e-03 0.059688 - 61 3.0500 +0.0392 1 1 6.465370e-01 6.465370e-01 5.643225e-03 0.053260 - 62 3.1000 +0.0782 1 1 6.116895e-01 6.116895e-01 3.843751e-03 0.028466 - 63 3.1500 +0.1167 1 1 5.744340e-01 5.744340e-01 2.409459e-03 0.004591 - 64 3.2000 +0.1545 1 1 5.350145e-01 5.350145e-01 1.969759e-03 0.001837 - 65 3.2500 +0.1913 1 1 4.938750e-01 4.938750e-01 1.888315e-03 0.001837 - 66 3.3000 +0.2270 1 1 4.513645e-01 4.513645e-01 1.724640e-03 0.004591 - 67 3.3500 +0.2612 1 1 4.077729e-01 4.077729e-01 1.635097e-03 0.009183 - 68 3.4000 +0.2939 1 1 3.628311e-01 3.628311e-01 1.949322e-03 0.030303 - 69 3.4500 +0.3247 1 1 3.157002e-01 3.157002e-01 2.924769e-03 0.044995 - 70 3.5000 +0.3536 1 1 2.653372e-01 2.653372e-01 4.546049e-03 0.055096 - 71 3.5500 +0.3802 1 1 2.125265e-01 2.125265e-01 6.607843e-03 0.059688 - 72 3.6000 +0.4045 1 1 1.559260e-01 1.559260e-01 8.480549e-03 0.067034 - 73 3.6500 +0.4263 1 1 1.598838e-01 1.598838e-01 1.051411e-02 0.072544 - 74 3.7000 +0.4455 1 1 1.662188e-01 1.662188e-01 1.269594e-02 0.074380 - 75 3.7500 +0.4619 1 1 1.986397e-01 1.986397e-01 1.494535e-02 0.078053 - 76 3.8000 +0.4755 1 1 2.455196e-01 2.455196e-01 1.685755e-02 0.081726 - 77 3.8500 +0.4862 1 1 2.903839e-01 2.903839e-01 1.850313e-02 0.081726 - 78 3.9000 +0.4938 1 1 3.370835e-01 3.370835e-01 1.973221e-02 0.081726 - 79 3.9500 +0.4985 1 1 3.880890e-01 3.880890e-01 2.074312e-02 0.083563 - 80 4.0000 +0.5000 1 1 4.353984e-01 4.353984e-01 2.153348e-02 0.086318 - 81 4.0500 +0.4985 1 1 4.785444e-01 4.785444e-01 2.212614e-02 0.089073 - 82 4.1000 +0.4938 1 1 5.167683e-01 5.167683e-01 2.247357e-02 0.089073 - 83 4.1500 +0.4862 1 1 5.504927e-01 5.504927e-01 2.259279e-02 0.089073 - 84 4.2000 +0.4755 1 1 5.946387e-01 5.946387e-01 2.243399e-02 0.089073 - 85 4.2500 +0.4619 1 1 6.372919e-01 6.372919e-01 2.205612e-02 0.090909 - 86 4.3000 +0.4455 1 1 6.734048e-01 6.734048e-01 2.166966e-02 0.092746 - 87 4.3500 +0.4263 1 1 7.027984e-01 7.027984e-01 2.121580e-02 0.092746 - 88 4.4000 +0.4045 1 1 7.257176e-01 7.257176e-01 2.071868e-02 0.092746 - 89 4.4500 +0.3802 1 1 7.426603e-01 7.426603e-01 2.025395e-02 0.092746 - 90 4.5000 +0.3536 1 1 7.542223e-01 7.542223e-01 1.969271e-02 0.091827 - 91 4.5500 +0.3247 1 1 7.609657e-01 7.609657e-01 1.900148e-02 0.089991 - 92 4.6000 +0.2939 1 1 7.634485e-01 7.634485e-01 1.813807e-02 0.089991 - 93 4.6500 +0.2612 1 1 7.620670e-01 7.620670e-01 1.713053e-02 0.088154 - 94 4.7000 +0.2270 1 1 7.570430e-01 7.570430e-01 1.594556e-02 0.085399 - 95 4.7500 +0.1913 1 1 7.484863e-01 7.484863e-01 1.460595e-02 0.083563 - 96 4.8000 +0.1545 1 1 7.363491e-01 7.363491e-01 1.314961e-02 0.076217 - 97 4.8500 +0.1167 1 1 7.204547e-01 7.204547e-01 1.171749e-02 0.072544 - 98 4.9000 +0.0782 1 1 7.013981e-01 7.013981e-01 1.021931e-02 0.068871 - 99 4.9500 +0.0392 1 1 6.798032e-01 6.798032e-01 8.675941e-03 0.065197 - 100 5.0000 +0.0000 1 1 6.539379e-01 6.539379e-01 7.059479e-03 0.059688 - 101 5.0500 -0.0392 1 1 6.240594e-01 6.240594e-01 5.518673e-03 0.048669 - 102 5.1000 -0.0782 1 1 5.904925e-01 5.904925e-01 3.551771e-03 0.024793 - 103 5.1500 -0.1167 1 1 5.535297e-01 5.535297e-01 2.128064e-03 0.001837 - 104 5.2000 -0.1545 1 1 5.145025e-01 5.145025e-01 1.647455e-03 0.000000 - 105 5.2500 -0.1913 1 1 4.740482e-01 4.740482e-01 1.587837e-03 0.001837 - 106 5.3000 -0.2270 1 1 4.323105e-01 4.323105e-01 1.406939e-03 0.002755 - 107 5.3500 -0.2612 1 1 3.894801e-01 3.894801e-01 1.331123e-03 0.009183 - 108 5.4000 -0.2939 1 1 3.453496e-01 3.453496e-01 1.591105e-03 0.031221 - 109 5.4500 -0.3247 1 1 2.989171e-01 2.989171e-01 2.527376e-03 0.044995 - 110 5.5000 -0.3536 1 1 2.484559e-01 2.484559e-01 4.543657e-03 0.054178 - 111 5.5500 -0.3802 1 1 1.957117e-01 1.957117e-01 6.666710e-03 0.059688 - 112 5.6000 -0.4045 1 1 1.414415e-01 1.414415e-01 8.680619e-03 0.067034 - 113 5.6500 -0.4263 1 1 1.598838e-01 1.598838e-01 1.084531e-02 0.072544 - 114 5.7000 -0.4455 1 1 1.660375e-01 1.660375e-01 1.310024e-02 0.074380 - 115 5.7500 -0.4619 1 1 1.951370e-01 1.951370e-01 1.524265e-02 0.078053 - 116 5.8000 -0.4755 1 1 2.367414e-01 2.367414e-01 1.697206e-02 0.081726 - 117 5.8500 -0.4862 1 1 2.792419e-01 2.792419e-01 1.839754e-02 0.081726 - 118 5.9000 -0.4938 1 1 3.291106e-01 3.291106e-01 1.942385e-02 0.081726 - 119 5.9500 -0.4985 1 1 3.755431e-01 3.755431e-01 2.029558e-02 0.083563 - 120 6.0000 -0.5000 1 1 4.181972e-01 4.181972e-01 2.101870e-02 0.086318 diff --git a/docs/developer/design/_phase_f_etd1_pc_picard.trace.txt b/docs/developer/design/_phase_f_etd1_pc_picard.trace.txt deleted file mode 100644 index 4938e56c8..000000000 --- a/docs/developer/design/_phase_f_etd1_pc_picard.trace.txt +++ /dev/null @@ -1,123 +0,0 @@ -# Phase F predictor-corrector trace: etd1_pc_picard -# integrator='etd' order=1 apply_radial_return=True in_residual_yield=False -# columns: step, t, V_top, snes_iters_total, picard_iters, sigma_eq_max, sigma_eq_max_after_correction, u_y_max, yielded_fraction - 1 0.0500 +0.4985 2 6 4.161077e-02 4.161077e-02 5.099459e-11 0.000000 - 2 0.1000 +0.4938 2 6 8.093501e-02 8.093501e-02 1.349445e-05 0.046832 - 3 0.1500 +0.4862 3 6 1.287508e-01 1.287508e-01 3.351302e-03 0.061524 - 4 0.2000 +0.4755 4 6 1.811023e-01 1.811023e-01 8.347638e-03 0.072544 - 5 0.2500 +0.4619 6 6 2.302776e-01 2.302776e-01 1.234744e-02 0.073462 - 6 0.3000 +0.4455 4 6 2.775334e-01 2.775334e-01 1.493068e-02 0.081726 - 7 0.3500 +0.4263 6 6 3.230740e-01 3.230740e-01 1.627572e-02 0.081726 - 8 0.4000 +0.4045 6 6 3.674049e-01 3.674049e-01 1.692438e-02 0.081726 - 9 0.4500 +0.3802 6 6 4.058537e-01 4.058537e-01 1.703386e-02 0.081726 - 10 0.5000 +0.3536 6 6 4.377588e-01 4.377588e-01 1.663614e-02 0.082645 - 11 0.5500 +0.3247 6 6 4.635655e-01 4.635655e-01 1.593578e-02 0.083563 - 12 0.6000 +0.2939 5 5 4.832436e-01 4.832436e-01 1.509389e-02 0.083563 - 13 0.6500 +0.2612 5 5 4.976155e-01 4.976155e-01 1.456039e-02 0.083563 - 14 0.7000 +0.2270 4 4 5.067653e-01 5.067653e-01 1.378263e-02 0.081726 - 15 0.7500 +0.1913 4 4 5.113699e-01 5.113699e-01 1.287287e-02 0.078053 - 16 0.8000 +0.1545 5 5 5.115385e-01 5.115385e-01 1.179448e-02 0.074380 - 17 0.8500 +0.1167 5 5 5.072425e-01 5.072425e-01 1.050574e-02 0.073462 - 18 0.9000 +0.0782 6 6 4.983598e-01 4.983598e-01 9.114029e-03 0.068871 - 19 0.9500 +0.0392 6 6 4.859537e-01 4.859537e-01 7.607633e-03 0.065197 - 20 1.0000 -0.0000 6 6 4.694749e-01 4.694749e-01 6.055486e-03 0.059688 - 21 1.0500 -0.0392 6 6 4.485793e-01 4.485793e-01 4.131973e-03 0.047750 - 22 1.1000 -0.0782 6 6 4.235467e-01 4.235467e-01 2.559961e-03 0.022957 - 23 1.1500 -0.1167 6 6 3.948545e-01 3.948545e-01 1.422857e-03 0.000918 - 24 1.2000 -0.1545 6 6 3.638478e-01 3.638478e-01 1.121558e-03 0.000000 - 25 1.2500 -0.1913 6 6 3.311189e-01 3.311189e-01 1.010840e-03 0.000000 - 26 1.3000 -0.2270 6 6 2.968686e-01 2.968686e-01 8.951009e-04 0.001837 - 27 1.3500 -0.2612 6 6 2.612707e-01 2.612707e-01 8.206035e-04 0.004591 - 28 1.4000 -0.2939 6 6 2.241692e-01 2.241692e-01 1.015615e-03 0.029385 - 29 1.4500 -0.3247 6 6 1.846865e-01 1.846865e-01 1.975358e-03 0.046832 - 30 1.5000 -0.3536 6 6 1.409845e-01 1.409845e-01 4.005596e-03 0.054178 - 31 1.5500 -0.3802 6 6 1.166370e-01 1.166370e-01 6.163564e-03 0.059688 - 32 1.6000 -0.4045 6 6 1.336565e-01 1.336565e-01 8.330606e-03 0.066116 - 33 1.6500 -0.4263 6 6 1.594410e-01 1.594410e-01 1.050882e-02 0.072544 - 34 1.7000 -0.4455 6 6 1.765654e-01 1.765654e-01 1.282975e-02 0.073462 - 35 1.7500 -0.4619 6 6 2.194027e-01 2.194027e-01 1.493627e-02 0.078053 - 36 1.8000 -0.4755 6 6 2.595226e-01 2.595226e-01 1.670650e-02 0.081726 - 37 1.8500 -0.4862 5 6 3.063497e-01 3.063497e-01 1.817514e-02 0.081726 - 38 1.9000 -0.4938 5 6 3.544942e-01 3.544942e-01 1.928309e-02 0.081726 - 39 1.9500 -0.4985 6 6 3.991369e-01 3.991369e-01 2.019328e-02 0.084481 - 40 2.0000 -0.5000 5 6 4.398635e-01 4.398635e-01 2.094383e-02 0.086318 - 41 2.0500 -0.4985 5 6 4.766056e-01 4.766056e-01 2.155494e-02 0.089073 - 42 2.1000 -0.4938 5 6 5.164216e-01 5.164216e-01 2.186644e-02 0.089073 - 43 2.1500 -0.4862 5 6 5.647899e-01 5.647899e-01 2.200411e-02 0.089991 - 44 2.2000 -0.4755 6 6 6.088865e-01 6.088865e-01 2.205423e-02 0.091827 - 45 2.2500 -0.4619 6 6 6.482230e-01 6.482230e-01 2.215879e-02 0.091827 - 46 2.3000 -0.4455 6 6 6.827193e-01 6.827193e-01 2.204627e-02 0.092746 - 47 2.3500 -0.4263 6 6 7.121618e-01 7.121618e-01 2.181352e-02 0.092746 - 48 2.4000 -0.4045 5 5 7.360911e-01 7.360911e-01 2.145828e-02 0.092746 - 49 2.4500 -0.3802 5 5 7.551158e-01 7.551158e-01 2.084470e-02 0.092746 - 50 2.5000 -0.3536 4 4 7.689838e-01 7.689838e-01 2.003559e-02 0.092746 - 51 2.5500 -0.3247 4 4 7.784161e-01 7.784161e-01 1.908171e-02 0.089991 - 52 2.6000 -0.2939 4 4 7.835573e-01 7.835573e-01 1.817218e-02 0.089073 - 53 2.6500 -0.2612 4 4 7.845050e-01 7.845050e-01 1.729180e-02 0.089073 - 54 2.7000 -0.2270 4 4 7.813407e-01 7.813407e-01 1.624477e-02 0.085399 - 55 2.7500 -0.1913 5 5 7.738206e-01 7.738206e-01 1.499546e-02 0.083563 - 56 2.8000 -0.1545 5 5 7.620874e-01 7.620874e-01 1.361492e-02 0.077135 - 57 2.8500 -0.1167 5 5 7.461220e-01 7.461220e-01 1.206496e-02 0.073462 - 58 2.9000 -0.0782 6 6 7.256369e-01 7.256369e-01 1.060674e-02 0.068871 - 59 2.9500 -0.0392 6 6 7.010363e-01 7.010363e-01 9.047866e-03 0.065197 - 60 3.0000 -0.0000 6 6 6.738234e-01 6.738234e-01 7.415888e-03 0.059688 - 61 3.0500 +0.0392 6 6 6.433692e-01 6.433692e-01 5.543277e-03 0.053260 - 62 3.1000 +0.0782 6 6 6.099471e-01 6.099471e-01 3.871836e-03 0.029385 - 63 3.1500 +0.1167 6 6 5.734248e-01 5.734248e-01 2.376721e-03 0.004591 - 64 3.2000 +0.1545 6 6 5.346290e-01 5.346290e-01 1.916660e-03 0.001837 - 65 3.2500 +0.1913 6 6 4.940989e-01 4.940989e-01 1.827304e-03 0.001837 - 66 3.3000 +0.2270 6 6 4.522099e-01 4.522099e-01 1.683525e-03 0.004591 - 67 3.3500 +0.2612 6 6 4.092209e-01 4.092209e-01 1.594976e-03 0.009183 - 68 3.4000 +0.2939 6 6 3.649311e-01 3.649311e-01 1.932707e-03 0.030303 - 69 3.4500 +0.3247 6 6 3.186272e-01 3.186272e-01 2.831886e-03 0.044995 - 70 3.5000 +0.3536 6 6 2.685705e-01 2.685705e-01 4.340578e-03 0.054178 - 71 3.5500 +0.3802 6 6 2.166092e-01 2.166092e-01 6.361989e-03 0.059688 - 72 3.6000 +0.4045 6 6 1.610261e-01 1.610261e-01 8.260349e-03 0.066116 - 73 3.6500 +0.4263 6 6 1.595580e-01 1.595580e-01 1.034355e-02 0.072544 - 74 3.7000 +0.4455 6 6 1.632820e-01 1.632820e-01 1.248723e-02 0.074380 - 75 3.7500 +0.4619 6 6 1.940748e-01 1.940748e-01 1.479202e-02 0.078053 - 76 3.8000 +0.4755 6 6 2.410678e-01 2.410678e-01 1.669484e-02 0.081726 - 77 3.8500 +0.4862 6 6 2.858449e-01 2.858449e-01 1.840059e-02 0.081726 - 78 3.9000 +0.4938 6 6 3.294513e-01 3.294513e-01 1.965186e-02 0.081726 - 79 3.9500 +0.4985 6 6 3.802306e-01 3.802306e-01 2.068451e-02 0.082645 - 80 4.0000 +0.5000 6 6 4.271951e-01 4.271951e-01 2.145156e-02 0.085399 - 81 4.0500 +0.4985 6 6 4.698095e-01 4.698095e-01 2.204894e-02 0.089073 - 82 4.1000 +0.4938 5 6 5.072628e-01 5.072628e-01 2.239363e-02 0.089073 - 83 4.1500 +0.4862 5 6 5.400127e-01 5.400127e-01 2.251380e-02 0.089073 - 84 4.2000 +0.4755 5 6 5.800820e-01 5.800820e-01 2.235144e-02 0.089073 - 85 4.2500 +0.4619 6 6 6.211326e-01 6.211326e-01 2.199080e-02 0.090909 - 86 4.3000 +0.4455 6 6 6.558938e-01 6.558938e-01 2.156490e-02 0.092746 - 87 4.3500 +0.4263 6 6 6.843123e-01 6.843123e-01 2.102370e-02 0.092746 - 88 4.4000 +0.4045 5 5 7.063759e-01 7.063759e-01 2.062574e-02 0.092746 - 89 4.4500 +0.3802 5 5 7.231025e-01 7.231025e-01 2.032786e-02 0.092746 - 90 4.5000 +0.3536 5 5 7.350305e-01 7.350305e-01 1.985498e-02 0.091827 - 91 4.5500 +0.3247 4 4 7.424922e-01 7.424922e-01 1.919538e-02 0.089991 - 92 4.6000 +0.2939 4 4 7.461228e-01 7.461228e-01 1.844436e-02 0.089073 - 93 4.6500 +0.2612 4 4 7.462011e-01 7.462011e-01 1.746419e-02 0.088154 - 94 4.7000 +0.2270 4 4 7.428746e-01 7.428746e-01 1.629555e-02 0.085399 - 95 4.7500 +0.1913 5 5 7.358811e-01 7.358811e-01 1.502104e-02 0.083563 - 96 4.8000 +0.1545 5 5 7.253639e-01 7.253639e-01 1.351238e-02 0.076217 - 97 4.8500 +0.1167 5 5 7.110578e-01 7.110578e-01 1.204830e-02 0.072544 - 98 4.9000 +0.0782 6 6 6.946220e-01 6.946220e-01 1.054086e-02 0.068871 - 99 4.9500 +0.0392 6 6 6.739125e-01 6.739125e-01 8.925269e-03 0.065197 - 100 5.0000 +0.0000 6 6 6.489214e-01 6.489214e-01 7.307332e-03 0.059688 - 101 5.0500 -0.0392 6 6 6.198678e-01 6.198678e-01 5.249013e-03 0.050505 - 102 5.1000 -0.0782 6 6 5.868589e-01 5.868589e-01 3.540912e-03 0.026630 - 103 5.1500 -0.1167 6 6 5.506593e-01 5.506593e-01 2.155882e-03 0.001837 - 104 5.2000 -0.1545 6 6 5.124078e-01 5.124078e-01 1.573846e-03 0.000000 - 105 5.2500 -0.1913 6 6 4.726878e-01 4.726878e-01 1.526428e-03 0.001837 - 106 5.3000 -0.2270 6 6 4.316547e-01 4.316547e-01 1.350858e-03 0.002755 - 107 5.3500 -0.2612 6 6 3.895309e-01 3.895309e-01 1.259554e-03 0.008264 - 108 5.4000 -0.2939 6 6 3.461341e-01 3.461341e-01 1.468956e-03 0.030303 - 109 5.4500 -0.3247 6 6 3.006082e-01 3.006082e-01 2.371470e-03 0.044995 - 110 5.5000 -0.3536 6 6 2.510723e-01 2.510723e-01 4.310133e-03 0.054178 - 111 5.5500 -0.3802 6 6 1.995589e-01 1.995589e-01 6.431268e-03 0.059688 - 112 5.6000 -0.4045 6 6 1.452066e-01 1.452066e-01 8.472646e-03 0.066116 - 113 5.6500 -0.4263 6 6 1.594970e-01 1.594970e-01 1.064486e-02 0.072544 - 114 5.7000 -0.4455 6 6 1.630191e-01 1.630191e-01 1.287049e-02 0.074380 - 115 5.7500 -0.4619 6 6 1.902722e-01 1.902722e-01 1.505430e-02 0.077135 - 116 5.8000 -0.4755 6 6 2.319192e-01 2.319192e-01 1.681173e-02 0.081726 - 117 5.8500 -0.4862 6 6 2.719600e-01 2.719600e-01 1.828151e-02 0.081726 - 118 5.9000 -0.4938 5 6 3.215692e-01 3.215692e-01 1.932832e-02 0.081726 - 119 5.9500 -0.4985 6 6 3.678246e-01 3.678246e-01 2.020076e-02 0.083563 - 120 6.0000 -0.5000 6 6 4.102416e-01 4.102416e-01 2.091711e-02 0.086318 diff --git a/docs/developer/design/_phase_f_etd2_pc1.trace.txt b/docs/developer/design/_phase_f_etd2_pc1.trace.txt deleted file mode 100644 index d4f420707..000000000 --- a/docs/developer/design/_phase_f_etd2_pc1.trace.txt +++ /dev/null @@ -1,123 +0,0 @@ -# Phase F predictor-corrector trace: etd2_pc1 -# integrator='etd' order=2 apply_radial_return=True in_residual_yield=False -# columns: step, t, V_top, snes_iters_total, picard_iters, sigma_eq_max, sigma_eq_max_after_correction, u_y_max, yielded_fraction - 1 0.0500 +0.4985 1 1 2.131127e-02 2.131127e-02 9.914503e-06 0.000000 - 2 0.1000 +0.4938 1 1 6.239662e-02 6.239662e-02 2.606727e-05 0.033976 - 3 0.1500 +0.4862 1 1 1.049722e-01 1.049722e-01 1.715476e-03 0.056933 - 4 0.2000 +0.4755 1 1 1.573794e-01 1.573794e-01 1.068129e-02 0.067034 - 5 0.2500 +0.4619 1 1 2.099182e-01 2.099182e-01 1.096408e-02 0.072544 - 6 0.3000 +0.4455 1 1 2.570379e-01 2.570379e-01 1.714362e-02 0.078972 - 7 0.3500 +0.4263 1 1 3.056119e-01 3.056119e-01 1.463398e-02 0.081726 - 8 0.4000 +0.4045 1 1 3.528050e-01 3.528050e-01 1.893268e-02 0.081726 - 9 0.4500 +0.3802 1 1 3.950287e-01 3.950287e-01 1.531541e-02 0.081726 - 10 0.5000 +0.3536 1 1 4.303910e-01 4.303910e-01 1.860162e-02 0.081726 - 11 0.5500 +0.3247 1 1 4.596525e-01 4.596525e-01 1.503352e-02 0.083563 - 12 0.6000 +0.2939 1 1 4.823697e-01 4.823697e-01 1.744548e-02 0.083563 - 13 0.6500 +0.2612 1 1 4.997832e-01 4.997832e-01 1.443183e-02 0.083563 - 14 0.7000 +0.2270 1 1 5.114560e-01 5.114560e-01 1.609903e-02 0.081726 - 15 0.7500 +0.1913 1 1 5.187145e-01 5.187145e-01 1.290046e-02 0.078972 - 16 0.8000 +0.1545 1 1 5.207510e-01 5.207510e-01 1.444387e-02 0.076217 - 17 0.8500 +0.1167 1 1 5.186851e-01 5.186851e-01 1.077858e-02 0.074380 - 18 0.9000 +0.0782 1 1 5.115076e-01 5.115076e-01 1.346888e-02 0.070707 - 19 0.9500 +0.0392 1 1 5.015462e-01 5.015462e-01 9.097274e-03 0.065197 - 20 1.0000 -0.0000 1 1 4.867079e-01 4.867079e-01 1.245325e-02 0.062443 - 21 1.0500 -0.0392 1 1 4.675201e-01 4.675201e-01 1.021491e-02 0.052342 - 22 1.1000 -0.0782 1 1 4.434251e-01 4.434251e-01 1.038060e-02 0.038567 - 23 1.1500 -0.1167 1 1 4.164446e-01 4.164446e-01 1.173302e-02 0.006428 - 24 1.2000 -0.1545 1 1 3.849434e-01 3.849434e-01 1.269477e-02 0.000000 - 25 1.2500 -0.1913 1 1 3.531562e-01 3.531562e-01 1.352314e-02 0.000000 - 26 1.3000 -0.2270 1 1 3.179293e-01 3.179293e-01 1.607292e-02 0.000918 - 27 1.3500 -0.2612 1 1 2.833158e-01 2.833158e-01 1.672074e-02 0.003673 - 28 1.4000 -0.2939 1 1 2.450061e-01 2.450061e-01 1.905884e-02 0.016529 - 29 1.4500 -0.3247 1 1 2.071696e-01 2.071696e-01 2.134301e-02 0.039486 - 30 1.5000 -0.3536 1 1 1.635172e-01 1.635172e-01 2.036617e-02 0.050505 - 31 1.5500 -0.3802 1 1 1.178158e-01 1.178158e-01 2.706291e-02 0.059688 - 32 1.6000 -0.4045 1 1 1.280774e-01 1.280774e-01 2.330717e-02 0.064279 - 33 1.6500 -0.4263 1 1 1.517607e-01 1.517607e-01 3.185378e-02 0.068871 - 34 1.7000 -0.4455 1 1 1.598838e-01 1.598838e-01 2.657179e-02 0.072544 - 35 1.7500 -0.4619 1 1 2.045166e-01 2.045166e-01 3.583165e-02 0.076217 - 36 1.8000 -0.4755 1 1 2.435566e-01 2.435566e-01 2.884058e-02 0.081726 - 37 1.8500 -0.4862 1 1 2.918784e-01 2.918784e-01 3.794113e-02 0.081726 - 38 1.9000 -0.4938 1 1 3.363541e-01 3.363541e-01 2.983185e-02 0.081726 - 39 1.9500 -0.4985 1 1 3.886665e-01 3.886665e-01 3.713012e-02 0.083563 - 40 2.0000 -0.5000 1 1 4.241066e-01 4.241066e-01 2.952963e-02 0.086318 - 41 2.0500 -0.4985 1 1 4.703930e-01 4.703930e-01 3.455771e-02 0.089073 - 42 2.1000 -0.4938 1 1 5.022749e-01 5.022749e-01 2.753084e-02 0.089073 - 43 2.1500 -0.4862 1 1 5.534926e-01 5.534926e-01 3.177891e-02 0.089991 - 44 2.2000 -0.4755 1 1 5.979954e-01 5.979954e-01 2.425708e-02 0.091827 - 45 2.2500 -0.4619 1 1 6.417369e-01 6.417369e-01 3.041661e-02 0.091827 - 46 2.3000 -0.4455 1 1 6.769766e-01 6.769766e-01 2.647030e-02 0.091827 - 47 2.3500 -0.4263 1 1 7.102783e-01 7.102783e-01 3.046915e-02 0.092746 - 48 2.4000 -0.4045 1 1 7.360519e-01 7.360519e-01 2.877922e-02 0.092746 - 49 2.4500 -0.3802 1 1 7.581262e-01 7.581262e-01 2.953757e-02 0.092746 - 50 2.5000 -0.3536 1 1 7.747097e-01 7.747097e-01 3.010213e-02 0.092746 - 51 2.5500 -0.3247 1 1 7.862858e-01 7.862858e-01 2.827722e-02 0.089991 - 52 2.6000 -0.2939 1 1 7.943083e-01 7.943083e-01 3.064881e-02 0.089073 - 53 2.6500 -0.2612 1 1 7.961581e-01 7.961581e-01 2.784177e-02 0.089073 - 54 2.7000 -0.2270 1 1 7.958760e-01 7.958760e-01 3.067474e-02 0.087236 - 55 2.7500 -0.1913 1 1 7.885778e-01 7.885778e-01 2.694955e-02 0.084481 - 56 2.8000 -0.1545 1 1 7.800704e-01 7.800704e-01 3.004956e-02 0.081726 - 57 2.8500 -0.1167 1 1 7.639095e-01 7.639095e-01 2.975656e-02 0.074380 - 58 2.9000 -0.0782 1 1 7.467074e-01 7.467074e-01 2.920571e-02 0.070707 - 59 2.9500 -0.0392 1 1 7.223785e-01 7.223785e-01 3.390057e-02 0.067034 - 60 3.0000 -0.0000 1 1 6.973502e-01 6.973502e-01 3.174960e-02 0.062443 - 61 3.0500 +0.0392 1 1 6.667682e-01 6.667682e-01 3.857958e-02 0.056015 - 62 3.1000 +0.0782 1 1 6.348044e-01 6.348044e-01 3.902196e-02 0.046832 - 63 3.1500 +0.1167 1 1 5.979348e-01 5.979348e-01 4.217937e-02 0.015611 - 64 3.2000 +0.1545 1 1 5.606210e-01 5.606210e-01 4.461844e-02 0.002755 - 65 3.2500 +0.1913 1 1 5.185266e-01 5.185266e-01 4.670081e-02 0.001837 - 66 3.3000 +0.2270 1 1 4.780786e-01 4.780786e-01 5.137915e-02 0.004591 - 67 3.3500 +0.2612 1 1 4.326961e-01 4.326961e-01 5.301539e-02 0.007346 - 68 3.4000 +0.2939 1 1 3.901218e-01 3.901218e-01 5.731251e-02 0.012856 - 69 3.4500 +0.3247 1 1 3.425765e-01 3.425765e-01 5.724200e-02 0.041322 - 70 3.5000 +0.3536 1 1 2.949486e-01 2.949486e-01 6.371193e-02 0.050505 - 71 3.5500 +0.3802 1 1 2.421294e-01 2.421294e-01 5.811950e-02 0.059688 - 72 3.6000 +0.4045 1 1 1.881670e-01 1.881670e-01 6.840521e-02 0.064279 - 73 3.6500 +0.4263 1 1 1.555694e-01 1.555694e-01 5.713230e-02 0.067952 - 74 3.7000 +0.4455 1 1 1.598838e-01 1.598838e-01 7.112147e-02 0.072544 - 75 3.7500 +0.4619 1 1 1.791295e-01 1.791295e-01 5.442180e-02 0.076217 - 76 3.8000 +0.4755 1 1 2.257324e-01 2.257324e-01 7.161664e-02 0.079890 - 77 3.8500 +0.4862 1 1 2.690861e-01 2.690861e-01 5.083165e-02 0.081726 - 78 3.9000 +0.4938 1 1 3.166168e-01 3.166168e-01 7.074444e-02 0.081726 - 79 3.9500 +0.4985 1 1 3.635441e-01 3.635441e-01 4.568633e-02 0.081726 - 80 4.0000 +0.5000 1 1 4.151861e-01 4.151861e-01 6.803058e-02 0.084481 - 81 4.0500 +0.4985 1 1 4.566118e-01 4.566118e-01 4.174742e-02 0.088154 - 82 4.1000 +0.4938 1 1 5.005229e-01 5.005229e-01 6.408209e-02 0.089073 - 83 4.1500 +0.4862 1 1 5.305149e-01 5.305149e-01 4.089872e-02 0.089073 - 84 4.2000 +0.4755 1 1 5.707071e-01 5.707071e-01 5.870990e-02 0.089073 - 85 4.2500 +0.4619 1 1 6.126959e-01 6.126959e-01 3.954730e-02 0.090909 - 86 4.3000 +0.4455 1 1 6.540621e-01 6.540621e-01 5.234383e-02 0.092746 - 87 4.3500 +0.4263 1 1 6.829757e-01 6.829757e-01 3.965990e-02 0.092746 - 88 4.4000 +0.4045 1 1 7.113745e-01 7.113745e-01 4.544573e-02 0.092746 - 89 4.4500 +0.3802 1 1 7.282133e-01 7.282133e-01 3.923397e-02 0.092746 - 90 4.5000 +0.3536 1 1 7.450524e-01 7.450524e-01 4.160950e-02 0.091827 - 91 4.5500 +0.3247 1 1 7.526353e-01 7.526353e-01 3.734183e-02 0.089991 - 92 4.6000 +0.2939 1 1 7.598689e-01 7.598689e-01 4.341982e-02 0.089073 - 93 4.6500 +0.2612 1 1 7.603876e-01 7.603876e-01 3.460950e-02 0.089073 - 94 4.7000 +0.2270 1 1 7.590870e-01 7.590870e-01 5.127460e-02 0.087236 - 95 4.7500 +0.1913 1 1 7.533418e-01 7.533418e-01 4.776523e-02 0.083563 - 96 4.8000 +0.1545 1 1 7.438568e-01 7.438568e-01 6.608833e-02 0.079890 - 97 4.8500 +0.1167 1 1 7.321045e-01 7.321045e-01 6.812981e-02 0.075298 - 98 4.9000 +0.0782 1 1 7.178501e-01 7.178501e-01 8.677898e-02 0.070707 - 99 4.9500 +0.0392 1 1 6.975008e-01 6.975008e-01 9.291052e-02 0.067034 - 100 5.0000 +0.0000 1 1 6.742254e-01 6.742254e-01 1.110457e-01 0.061524 - 101 5.0500 -0.0392 1 1 6.448974e-01 6.448974e-01 1.211323e-01 0.052342 - 102 5.1000 -0.0782 1 1 6.150097e-01 6.150097e-01 1.369753e-01 0.041322 - 103 5.1500 -0.1167 1 1 5.758267e-01 5.758267e-01 1.497804e-01 0.010101 - 104 5.2000 -0.1545 1 1 5.411679e-01 5.411679e-01 1.634744e-01 0.002755 - 105 5.2500 -0.1913 1 1 4.970565e-01 4.970565e-01 1.772986e-01 0.001837 - 106 5.3000 -0.2270 1 1 4.599766e-01 4.599766e-01 1.902496e-01 0.001837 - 107 5.3500 -0.2612 1 1 4.129634e-01 4.129634e-01 2.035024e-01 0.006428 - 108 5.4000 -0.2939 1 1 3.736203e-01 3.736203e-01 2.145889e-01 0.011019 - 109 5.4500 -0.3247 1 1 3.237010e-01 3.237010e-01 2.273457e-01 0.041322 - 110 5.5000 -0.3536 1 1 2.798159e-01 2.798159e-01 2.378508e-01 0.050505 - 111 5.5500 -0.3802 1 1 2.228483e-01 2.228483e-01 2.586419e-01 0.058770 - 112 5.6000 -0.4045 1 1 1.766384e-01 1.766384e-01 2.637201e-01 0.064279 - 113 5.6500 -0.4263 1 1 1.547365e-01 1.547365e-01 2.853110e-01 0.068871 - 114 5.7000 -0.4455 1 1 1.598838e-01 1.598838e-01 2.825352e-01 0.073462 - 115 5.7500 -0.4619 1 1 2.088551e-01 2.088551e-01 3.047250e-01 0.076217 - 116 5.8000 -0.4755 1 1 2.197518e-01 2.197518e-01 2.940441e-01 0.081726 - 117 5.8500 -0.4862 1 1 2.587456e-01 2.587456e-01 3.149978e-01 0.081726 - 118 5.9000 -0.4938 1 1 3.094653e-01 3.094653e-01 2.954414e-01 0.081726 - 119 5.9500 -0.4985 1 1 3.424852e-01 3.424852e-01 3.132496e-01 0.082645 - 120 6.0000 -0.5000 1 1 4.068626e-01 4.068626e-01 2.862348e-01 0.084481 diff --git a/docs/developer/design/_phase_f_etd2_pc_picard.trace.txt b/docs/developer/design/_phase_f_etd2_pc_picard.trace.txt deleted file mode 100644 index 4c1aac478..000000000 --- a/docs/developer/design/_phase_f_etd2_pc_picard.trace.txt +++ /dev/null @@ -1,63 +0,0 @@ -# Phase F predictor-corrector trace: etd2_pc_picard -# integrator='etd' order=2 apply_radial_return=True in_residual_yield=False -# columns: step, t, V_top, snes_iters_total, picard_iters, sigma_eq_max, sigma_eq_max_after_correction, u_y_max, yielded_fraction - 1 0.0500 +0.4985 6 6 4.128329e-02 4.128329e-02 9.032622e-06 0.000000 - 2 0.1000 +0.4938 6 6 8.062246e-02 8.062246e-02 8.778956e-06 0.046832 - 3 0.1500 +0.4862 6 6 1.282990e-01 1.282990e-01 4.488153e-04 0.061524 - 4 0.2000 +0.4755 6 6 1.806463e-01 1.806463e-01 1.659196e-03 0.071625 - 5 0.2500 +0.4619 6 6 2.299833e-01 2.299833e-01 3.567426e-03 0.073462 - 6 0.3000 +0.4455 6 6 2.763849e-01 2.763849e-01 6.038144e-03 0.081726 - 7 0.3500 +0.4263 6 6 3.231831e-01 3.231831e-01 8.951024e-03 0.081726 - 8 0.4000 +0.4045 6 6 3.676827e-01 3.676827e-01 1.271368e-02 0.081726 - 9 0.4500 +0.3802 6 6 4.063513e-01 4.063513e-01 2.101424e-02 0.081726 - 10 0.5000 +0.3536 6 6 4.385887e-01 4.385887e-01 3.332654e-02 0.082645 - 11 0.5500 +0.3247 6 6 4.648292e-01 4.648292e-01 5.096470e-02 0.083563 - 12 0.6000 +0.2939 6 6 4.853601e-01 4.853601e-01 7.694427e-02 0.083563 - 13 0.6500 +0.2612 6 6 5.006052e-01 5.006052e-01 1.156709e-01 0.083563 - 14 0.7000 +0.2270 6 6 5.111314e-01 5.111314e-01 1.678903e-01 0.081726 - 15 0.7500 +0.1913 6 6 5.168793e-01 5.168793e-01 2.345889e-01 0.078053 - 16 0.8000 +0.1545 6 6 5.186714e-01 5.186714e-01 3.194702e-01 0.075298 - 17 0.8500 +0.1167 6 6 5.165864e-01 5.165864e-01 4.280691e-01 0.068871 - 18 0.9000 +0.0782 6 6 5.234129e-01 5.234129e-01 5.854402e-01 0.059688 - 19 0.9500 +0.0392 6 6 5.867592e-01 5.867592e-01 7.774405e-01 0.053260 - 20 1.0000 -0.0000 6 6 6.367049e-01 6.367049e-01 9.775868e-01 0.041322 - 21 1.0500 -0.0392 6 6 6.757299e-01 6.757299e-01 1.155523e+00 0.028466 - 22 1.1000 -0.0782 6 6 6.955732e-01 6.955732e-01 1.281643e+00 0.011019 - 23 1.1500 -0.1167 6 6 7.025940e-01 7.025940e-01 1.366677e+00 0.000000 - 24 1.2000 -0.1545 6 6 7.152548e-01 7.152548e-01 1.413835e+00 0.000000 - 25 1.2500 -0.1913 6 6 7.402345e-01 7.402345e-01 1.468174e+00 0.001837 - 26 1.3000 -0.2270 6 6 7.759602e-01 7.759602e-01 1.538369e+00 0.004591 - 27 1.3500 -0.2612 6 6 8.198429e-01 8.198429e-01 1.592886e+00 0.008264 - 28 1.4000 -0.2939 6 6 8.827329e-01 8.827329e-01 1.635576e+00 0.025712 - 29 1.4500 -0.3247 6 6 9.305599e-01 9.305599e-01 1.671694e+00 0.036731 - 30 1.5000 -0.3536 6 6 9.176821e-01 9.176821e-01 1.689775e+00 0.045914 - 31 1.5500 -0.3802 6 6 1.097916e+00 1.097916e+00 1.674682e+00 0.048669 - 32 1.6000 -0.4045 6 6 1.214428e+00 1.214428e+00 1.637503e+00 0.049587 - 33 1.6500 -0.4263 6 6 1.339736e+00 1.339736e+00 1.619010e+00 0.054178 - 34 1.7000 -0.4455 6 6 1.569842e+00 1.569842e+00 1.712545e+00 0.053260 - 35 1.7500 -0.4619 6 6 1.768136e+00 1.768136e+00 2.102587e+00 0.061524 - 36 1.8000 -0.4755 6 6 2.032997e+00 2.032997e+00 2.454732e+00 0.062443 - 37 1.8500 -0.4862 6 6 2.176244e+00 2.176244e+00 2.849964e+00 0.061524 - 38 1.9000 -0.4938 6 6 2.602614e+00 2.602614e+00 3.596606e+00 0.059688 - 39 1.9500 -0.4985 6 6 2.625967e+00 2.625967e+00 4.030853e+00 0.049587 - 40 2.0000 -0.5000 6 6 2.560084e+00 2.560084e+00 3.803991e+00 0.049587 - 41 2.0500 -0.4985 6 6 2.421060e+00 2.421060e+00 4.127847e+00 0.032140 - 42 2.1000 -0.4938 6 6 2.439370e+00 2.439370e+00 4.099199e+00 0.034894 - 43 2.1500 -0.4862 6 6 2.701228e+00 2.701228e+00 4.153585e+00 0.032140 - 44 2.2000 -0.4755 6 6 2.955110e+00 2.955110e+00 4.392278e+00 0.021120 - 45 2.2500 -0.4619 6 6 3.186634e+00 3.186634e+00 4.594595e+00 0.011019 - 46 2.3000 -0.4455 6 6 3.102073e+00 3.102073e+00 4.461982e+00 0.015611 - 47 2.3500 -0.4263 6 6 2.950377e+00 2.950377e+00 4.048292e+00 0.015611 - 48 2.4000 -0.4045 6 6 2.916105e+00 2.916105e+00 4.480963e+00 0.015611 - 49 2.4500 -0.3802 6 6 2.552756e+00 2.552756e+00 4.639798e+00 0.012856 - 50 2.5000 -0.3536 6 6 2.372077e+00 2.372077e+00 4.676110e+00 0.013774 - 51 2.5500 -0.3247 6 6 2.319044e+00 2.319044e+00 5.137358e+00 0.012856 - 52 2.6000 -0.2939 6 6 2.363969e+00 2.363969e+00 5.114993e+00 0.013774 - 53 2.6500 -0.2612 6 6 2.210504e+00 2.210504e+00 5.205307e+00 0.012856 - 54 2.7000 -0.2270 6 6 2.292182e+00 2.292182e+00 5.493810e+00 0.016529 - 55 2.7500 -0.1913 6 6 2.216241e+00 2.216241e+00 5.507382e+00 0.020202 - 56 2.8000 -0.1545 6 6 2.484720e+00 2.484720e+00 5.237860e+00 0.013774 - 57 2.8500 -0.1167 6 6 2.584487e+00 2.584487e+00 4.986766e+00 0.018365 - 58 2.9000 -0.0782 6 6 2.634986e+00 2.634986e+00 4.819767e+00 0.010101 - 59 2.9500 -0.0392 6 6 2.773244e+00 2.773244e+00 5.291063e+00 0.012856 - 60 3.0000 -0.0000 6 6 1.821914e+01 1.821914e+01 1.022878e+01 0.000000 diff --git a/docs/developer/design/declined-coord-units-proposal.md b/docs/developer/design/declined-coord-units-proposal.md new file mode 100644 index 000000000..c6f5278ac --- /dev/null +++ b/docs/developer/design/declined-coord-units-proposal.md @@ -0,0 +1,48 @@ +# Declined proposal: quantity-valued coordinates / `coord_units` for evaluate() + +**Status**: Declined — maintainer ruling D7, 2026-07-06 (units-family scope +decision, `docs/reviews/2026-07/REMEDIATION-WORKLIST.md`). Recorded here so +the idea is findable if it is ever revisited; the placeholder tests that +used to stand in for it were deleted (LE-08, LE-10, LE-11 / WA-23, WA-24). + +## What was proposed + +A family of unit-aware coordinate conveniences, which existed only as +skipped test placeholders (never implemented, no design doc): + +1. **`coord_units=` parameter for `uw.function.evaluate()`** — interpret a + plain coordinate array in a named unit, e.g. + `evaluate(T.sym, pts_km, coord_units="km")`. +2. **Quantity-valued coordinate lists** — accept + `[(uw.quantity(0.5, "m"), uw.quantity(50, "cm"))]` (and flat + `[x_qty, y_qty]`) as evaluate/global_evaluate coordinates. +3. **`UnitAwareArray` returns from coordinate-expression evaluation**, and + Pint-quantity coordinate support in `mesh.points_in_domain()` / + `mesh.get_closest_cells()`. +4. **Constructor-set mesh units** — `units=` on the Cartesian mesh + constructors as a live feature, plus `mesh.to_units()` conversion. + +## The ruling + +The family is **unsupported**. The model owns the unit system +(`docs/developer/design/UNITS_SIMPLIFIED_DESIGN_2025-11.md`): coordinates +passed to evaluation are plain arrays in model (non-dimensional) units, or +whole `UnitAwareArray`/`UWQuantity` arrays (which the evaluate gateway +non-dimensionalises). Physical locations are converted explicitly with +`uw.scaling.non_dimensionalise`. The mesh-constructor `units=` kwarg is +deprecated (DeprecationWarning) and ignored; `mesh.units` reports the +model's coordinate unit. + +## What was removed (Wave A, 2026-07) + +- 16 placeholder skips across 7 units test files (`test_0730`, + `test_0800_unit_aware_functions`, `test_0803_*` ×2, `test_0804`, + `test_0811`); files that contained nothing else were deleted. +- `test_0630_mesh_units_demonstration.py` (pure demonstration of the + superseded proposal); `test_0620_mesh_units_interface.py` rewritten to + assert the implemented model-owned semantics. +- `test_0812_poisson_with_units.py` rewritten with supported coordinate + forms (the Poisson-with-units coverage is regained). + +If the feature is revisited, start from the deleted tests in git history — +they are a usable statement of the intended user experience. diff --git a/docs/developer/design/_repro_dminterp_multifield_bug.py b/docs/developer/design/experiments/dminterp-multifield/_repro_dminterp_multifield_bug.py similarity index 100% rename from docs/developer/design/_repro_dminterp_multifield_bug.py rename to docs/developer/design/experiments/dminterp-multifield/_repro_dminterp_multifield_bug.py diff --git a/docs/developer/design/_exp_integrator_phase_a.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_a.py similarity index 100% rename from docs/developer/design/_exp_integrator_phase_a.py rename to docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_a.py diff --git a/docs/developer/design/_exp_integrator_phase_b_benches.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_benches.py similarity index 100% rename from docs/developer/design/_exp_integrator_phase_b_benches.py rename to docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_benches.py diff --git a/docs/developer/design/_exp_integrator_phase_b_eval.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_eval.py similarity index 100% rename from docs/developer/design/_exp_integrator_phase_b_eval.py rename to docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_eval.py diff --git a/docs/developer/design/_exp_integrator_phase_b_killer.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_killer.py similarity index 100% rename from docs/developer/design/_exp_integrator_phase_b_killer.py rename to docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_killer.py diff --git a/docs/developer/design/_exp_integrator_phase_b_ti_iso.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_ti_iso.py similarity index 100% rename from docs/developer/design/_exp_integrator_phase_b_ti_iso.py rename to docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_ti_iso.py diff --git a/docs/developer/design/_exp_integrator_phase_b_validate.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_validate.py similarity index 100% rename from docs/developer/design/_exp_integrator_phase_b_validate.py rename to docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_validate.py diff --git a/docs/developer/design/_exp_integrator_phase_d_split.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_d_split.py similarity index 100% rename from docs/developer/design/_exp_integrator_phase_d_split.py rename to docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_d_split.py diff --git a/docs/developer/design/_exp_integrator_uw3_jury_rig.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_uw3_jury_rig.py similarity index 100% rename from docs/developer/design/_exp_integrator_uw3_jury_rig.py rename to docs/developer/design/experiments/exp-integrator/_exp_integrator_uw3_jury_rig.py diff --git a/docs/developer/design/_exp_jury_rig_minimal.py b/docs/developer/design/experiments/exp-integrator/_exp_jury_rig_minimal.py similarity index 100% rename from docs/developer/design/_exp_jury_rig_minimal.py rename to docs/developer/design/experiments/exp-integrator/_exp_jury_rig_minimal.py diff --git a/docs/developer/design/_phase_b_bdf2_at_tight_yield.py b/docs/developer/design/experiments/exp-integrator/_phase_b_bdf2_at_tight_yield.py similarity index 100% rename from docs/developer/design/_phase_b_bdf2_at_tight_yield.py rename to docs/developer/design/experiments/exp-integrator/_phase_b_bdf2_at_tight_yield.py diff --git a/docs/developer/design/_phase_b_bdf_vs_etd_at_tight_yield.py b/docs/developer/design/experiments/exp-integrator/_phase_b_bdf_vs_etd_at_tight_yield.py similarity index 100% rename from docs/developer/design/_phase_b_bdf_vs_etd_at_tight_yield.py rename to docs/developer/design/experiments/exp-integrator/_phase_b_bdf_vs_etd_at_tight_yield.py diff --git a/docs/developer/design/_phase_b_etd1_at_tight_yield.py b/docs/developer/design/experiments/exp-integrator/_phase_b_etd1_at_tight_yield.py similarity index 100% rename from docs/developer/design/_phase_b_etd1_at_tight_yield.py rename to docs/developer/design/experiments/exp-integrator/_phase_b_etd1_at_tight_yield.py diff --git a/docs/developer/design/_phase_d_killer_split.py b/docs/developer/design/experiments/exp-integrator/_phase_d_killer_split.py similarity index 100% rename from docs/developer/design/_phase_d_killer_split.py rename to docs/developer/design/experiments/exp-integrator/_phase_d_killer_split.py diff --git a/docs/developer/design/_phase_e_killer_hybrid.py b/docs/developer/design/experiments/exp-integrator/_phase_e_killer_hybrid.py similarity index 100% rename from docs/developer/design/_phase_e_killer_hybrid.py rename to docs/developer/design/experiments/exp-integrator/_phase_e_killer_hybrid.py diff --git a/docs/developer/design/_phase_f_predictor_corrector.py b/docs/developer/design/experiments/exp-integrator/_phase_f_predictor_corrector.py similarity index 100% rename from docs/developer/design/_phase_f_predictor_corrector.py rename to docs/developer/design/experiments/exp-integrator/_phase_f_predictor_corrector.py diff --git a/docs/developer/design/_plot_phase_b_bdf_vs_etd.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_bdf_vs_etd.py similarity index 100% rename from docs/developer/design/_plot_phase_b_bdf_vs_etd.py rename to docs/developer/design/experiments/exp-integrator/_plot_phase_b_bdf_vs_etd.py diff --git a/docs/developer/design/_plot_phase_b_fields.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_fields.py similarity index 100% rename from docs/developer/design/_plot_phase_b_fields.py rename to docs/developer/design/experiments/exp-integrator/_plot_phase_b_fields.py diff --git a/docs/developer/design/_plot_phase_b_pyvista.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_pyvista.py similarity index 100% rename from docs/developer/design/_plot_phase_b_pyvista.py rename to docs/developer/design/experiments/exp-integrator/_plot_phase_b_pyvista.py diff --git a/docs/developer/design/_plot_phase_b_results.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_results.py similarity index 100% rename from docs/developer/design/_plot_phase_b_results.py rename to docs/developer/design/experiments/exp-integrator/_plot_phase_b_results.py diff --git a/docs/developer/design/_plot_phase_d_pyvista_split.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_d_pyvista_split.py similarity index 100% rename from docs/developer/design/_plot_phase_d_pyvista_split.py rename to docs/developer/design/experiments/exp-integrator/_plot_phase_d_pyvista_split.py diff --git a/docs/developer/design/_plot_phase_d_uy_diagnosis.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_d_uy_diagnosis.py similarity index 100% rename from docs/developer/design/_plot_phase_d_uy_diagnosis.py rename to docs/developer/design/experiments/exp-integrator/_plot_phase_d_uy_diagnosis.py diff --git a/docs/developer/design/_plot_phase_e_pyvista_hybrid.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_e_pyvista_hybrid.py similarity index 100% rename from docs/developer/design/_plot_phase_e_pyvista_hybrid.py rename to docs/developer/design/experiments/exp-integrator/_plot_phase_e_pyvista_hybrid.py diff --git a/docs/developer/design/_plot_phase_f.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_f.py similarity index 100% rename from docs/developer/design/_plot_phase_f.py rename to docs/developer/design/experiments/exp-integrator/_plot_phase_f.py diff --git a/docs/developer/design/exp_integrator_phase_a.png b/docs/developer/design/experiments/exp-integrator/exp_integrator_phase_a.png similarity index 100% rename from docs/developer/design/exp_integrator_phase_a.png rename to docs/developer/design/experiments/exp-integrator/exp_integrator_phase_a.png diff --git a/docs/developer/design/exp_integrator_phase_b_largedt.png b/docs/developer/design/experiments/exp-integrator/exp_integrator_phase_b_largedt.png similarity index 100% rename from docs/developer/design/exp_integrator_phase_b_largedt.png rename to docs/developer/design/experiments/exp-integrator/exp_integrator_phase_b_largedt.png diff --git a/docs/developer/design/exp_integrator_phase_b_square.png b/docs/developer/design/experiments/exp-integrator/exp_integrator_phase_b_square.png similarity index 100% rename from docs/developer/design/exp_integrator_phase_b_square.png rename to docs/developer/design/experiments/exp-integrator/exp_integrator_phase_b_square.png diff --git a/docs/developer/design/exp_integrator_phase_b_vardt.png b/docs/developer/design/experiments/exp-integrator/exp_integrator_phase_b_vardt.png similarity index 100% rename from docs/developer/design/exp_integrator_phase_b_vardt.png rename to docs/developer/design/experiments/exp-integrator/exp_integrator_phase_b_vardt.png diff --git a/docs/developer/design/exp_integrator_phase_b_yield.png b/docs/developer/design/experiments/exp-integrator/exp_integrator_phase_b_yield.png similarity index 100% rename from docs/developer/design/exp_integrator_phase_b_yield.png rename to docs/developer/design/experiments/exp-integrator/exp_integrator_phase_b_yield.png diff --git a/docs/developer/index.md b/docs/developer/index.md index 551addeb3..8fe04584b 100644 --- a/docs/developer/index.md +++ b/docs/developer/index.md @@ -136,6 +136,7 @@ design/GEOGRAPHIC_COORDINATE_SYSTEM_DESIGN design/mesh-geometry-audit design/PROJECTED_NORMALS_API_DESIGN design/TURBULENCE_MODEL_DESIGN +design/declined-coord-units-proposal ``` ```{toctree} diff --git a/src/underworld3/discretisation/discretisation_mesh.py b/src/underworld3/discretisation/discretisation_mesh.py index 74c31c885..fb0796d3d 100644 --- a/src/underworld3/discretisation/discretisation_mesh.py +++ b/src/underworld3/discretisation/discretisation_mesh.py @@ -230,7 +230,9 @@ class Mesh(Stateful, uw_object): boundary_normals : dict, optional Outward normal vectors for each boundary. units : str or pint.Unit, optional - Physical units for mesh coordinates. + Deprecated and ignored (DeprecationWarning). Mesh coordinate units + always come from the model's reference quantities + (``model.set_reference_quantities``); query them via ``mesh.units``. verbose : bool, optional Print mesh construction information. @@ -279,21 +281,24 @@ def __init__( self.instance = Mesh.mesh_instances Mesh.mesh_instances += 1 - # Get coordinate units from model (not user parameter) - # The model owns the unit system - all meshes use the same units + # Coordinate units come from the model (not a user parameter): + # the model owns the unit system so all meshes and variables agree. import underworld3 as uw model = uw.get_default_model() - # Ignore user-provided units parameter, get from model instead - if units is not None and units != model.get_coordinate_unit(): + # Deprecated 2026-07 (WA-23/WC-11, units-family ruling D7): the + # `units=` kwarg was always ignored in favour of the model units; + # now it says so. + if units is not None: import warnings warnings.warn( - f"Ignoring units parameter '{units}'. Mesh coordinates will use " - f"model units '{model.get_coordinate_unit()}'. The model owns the " - "unit system to ensure consistency across all meshes and variables.", - UserWarning, + f"The 'units' mesh-constructor parameter is deprecated and " + f"ignored. Mesh coordinates use the model's units " + f"('{model.get_coordinate_unit()}', set via " + "model.set_reference_quantities). Remove the argument.", + DeprecationWarning, stacklevel=3, ) diff --git a/src/underworld3/function/functions_unit_system.py b/src/underworld3/function/functions_unit_system.py index c43af05b8..71350b24c 100644 --- a/src/underworld3/function/functions_unit_system.py +++ b/src/underworld3/function/functions_unit_system.py @@ -810,6 +810,13 @@ def evaluate( default ``monotone=False`` this is bit-identical to the historical ``evaluate``. + Coordinates are a plain ``(N, dim)`` array in model (non-dimensional) + units, or a ``UnitAwareArray``/``UWQuantity`` array which is + non-dimensionalised automatically. Python lists/tuples of individual + quantity objects (``[(x_qty, y_qty)]``) are NOT supported — convert + physical locations with :func:`underworld3.scaling.non_dimensionalise` + and pass a numpy array (units-family ruling, 2026-07). + Parameters ---------- monotone : bool or str, optional diff --git a/src/underworld3/meshing/cartesian.py b/src/underworld3/meshing/cartesian.py index 1b1636fb2..eaf9e10c7 100644 --- a/src/underworld3/meshing/cartesian.py +++ b/src/underworld3/meshing/cartesian.py @@ -81,8 +81,8 @@ def UnstructuredSimplexBox( Gmsh output verbosity level. 0 is silent, higher values produce more diagnostic output. units : str, optional - **Deprecated**. Mesh coordinates are always in model reference - units. This parameter is retained for backward compatibility. + Deprecated and ignored (DeprecationWarning). Mesh coordinates are + always in the model's units (``model.set_reference_quantities``). verbose : bool, default=False If True, print additional diagnostic information during mesh construction. @@ -419,7 +419,8 @@ def BoxInternalBoundary( gmsh_verbosity : int, default=0 Gmsh output verbosity level. units : str, optional - Coordinate units for unit-aware arrays. + Deprecated and ignored (DeprecationWarning). Mesh coordinates are + always in the model's units (``model.set_reference_quantities``). verbose : bool, default=False Print diagnostic information during mesh construction. @@ -1003,7 +1004,8 @@ def StructuredQuadBox( gmsh_verbosity : int, default=0 Gmsh output verbosity level. units : str, optional - **Deprecated**. Mesh coordinates are always in model reference units. + Deprecated and ignored (DeprecationWarning). Mesh coordinates are + always in the model's units (``model.set_reference_quantities``). verbose : bool, default=False Print diagnostic information during mesh construction. @@ -1104,18 +1106,6 @@ class boundary_normals_3D(Enum): Back = sympy.Matrix([0, 1, 0]) # Convert coordinates to non-dimensional units (handles UWQuantity objects) - # Detect units from UWQuantity inputs (if not explicitly specified) - if units is None: - # Try to detect units from maxCoords (most likely to have units) - if maxCoords is not None and hasattr(maxCoords, "__iter__"): - for coord in maxCoords: - if hasattr(coord, "units"): # UWQuantity - units = str(coord.units) - break - elif hasattr(coord, "_pint_qty"): # Direct Pint Quantity - units = str(coord._pint_qty.units) - break - if minCoords is not None: minCoords = tuple(uw.scaling.non_dimensionalise(c) for c in minCoords) if maxCoords is not None: diff --git a/tests/test_0620_mesh_units_interface.py b/tests/test_0620_mesh_units_interface.py index cfa79612f..9c3cc95cb 100644 --- a/tests/test_0620_mesh_units_interface.py +++ b/tests/test_0620_mesh_units_interface.py @@ -1,358 +1,91 @@ -#!/usr/bin/env python3 +"""Tests for the implemented mesh coordinate-units semantics. + +The model owns the unit system: a mesh's coordinate units come from the +default model's reference quantities (``model.get_coordinate_unit()``), +not from the mesh constructor. The legacy ``units=`` constructor kwarg +is deprecated and ignored — passing it raises a ``DeprecationWarning`` +and the model's units win regardless. + +History: this file previously documented a PROPOSED mesh-units interface +(constructor-set units, ``mesh.to_units()``, unit-carrying coordinate +arrays) behind try/except-skip guards, several of which had started to +pass vacuously. That proposal was superseded by the model-owned design +(``docs/developer/design/UNITS_SIMPLIFIED_DESIGN_2025-11.md``) and the +placeholder tests were deleted (LE-10 / WA-23, units-family ruling D7, +2026-07-06). """ -Test cases for mesh coordinate units interface design. -This tests the proposed unit-aware mesh coordinate system that addresses -the user-interface gap where mesh.X.coords (previously mesh.data/mesh.points) -and mesh.X currently have no unit information, making it difficult for users -to understand physical scales and coordinate transformations. - -This is a DESIGN TEST that documents the expected interface for mesh units. -It may initially fail until the interface is implemented. -""" +import warnings import pytest -# Units integration tests - intermediate complexity -pytestmark = pytest.mark.level_2 -import numpy as np -import sys -import os - -# Add src to path for testing -# REMOVED: sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) - import underworld3 as uw +pytestmark = [pytest.mark.level_2, pytest.mark.tier_b] + @pytest.fixture(autouse=True) def reset_model_state(): - """Reset model state before each test to prevent pollution from other tests. - - Tests in test_0850_units_propagation set reference quantities which can affect - mesh coordinate units and cause backward compatibility assertions to fail. - """ + """Isolate each test from reference quantities set elsewhere.""" uw.reset_default_model() uw.use_strict_units(False) yield - # Cleanup after test uw.reset_default_model() uw.use_strict_units(False) -class TestMeshUnitsInterfaceDesign: - """Test the design of unit-aware mesh coordinate interfaces.""" +def _box(**kwargs): + return uw.meshing.StructuredQuadBox( + elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), **kwargs + ) - def test_mesh_creation_with_units(self): - """Test that meshes can be created with unit specifications.""" - # PROPOSED INTERFACE: Allow unit specification during mesh creation - # Option 1: Units in mesh constructor - try: - mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), - minCoords=(0.0, 0.0), - maxCoords=(1000.0, 1000.0), - units="km", # PROPOSED: units parameter - ) +class TestModelOwnedMeshUnits: + """mesh.units reflects the model, and nothing else.""" - # Should be able to query mesh units - assert hasattr(mesh, "units"), "Mesh should have units attribute" + def test_dimensionless_by_default(self): + mesh = _box() + assert mesh.units is None - except TypeError: - # Expected initially - interface not yet implemented - pytest.skip("Mesh units interface not yet implemented") + def test_units_follow_model_reference_quantities(self): + model = uw.get_default_model() + model.set_reference_quantities(domain_depth=uw.quantity(1000, "km")) + mesh = _box() + assert mesh.units == model.get_coordinate_unit() + # The coordinate unit is a length unit (a Pint Unit, not a string) + assert dict(mesh.units.dimensionality) == {"[length]": 1} - def test_mesh_units_property_interface(self): - """Test mesh units property interface.""" - mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0) + def test_all_meshes_share_the_model_units(self): + model = uw.get_default_model() + model.set_reference_quantities(domain_depth=uw.quantity(500, "m")) + mesh_a = _box() + mesh_b = uw.meshing.UnstructuredSimplexBox( + minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), cellSize=0.5 ) - - # PROPOSED INTERFACE: mesh.units property - try: - # Should be able to set units after creation - mesh.units = "m" - - # Should be able to query units - units = mesh.units - assert units is not None - - except AttributeError: - pytest.skip("Mesh units property not yet implemented") - - def test_mesh_coords_with_units(self): - """Test that mesh.X.coords returns unit-aware coordinates.""" - mesh = uw.meshing.StructuredQuadBox( - elementRes=(3, 3), minCoords=(0.0, 0.0), maxCoords=(100.0, 100.0) + assert mesh_a.units == mesh_b.units == model.get_coordinate_unit() + + +class TestDeprecatedUnitsKwarg: + """The constructor ``units=`` kwarg warns and is ignored.""" + + def test_units_kwarg_warns_and_is_ignored(self): + with pytest.warns(DeprecationWarning, match="deprecated"): + mesh = _box(units="km") + # No model reference quantities: the mesh stays dimensionless + # regardless of the requested constructor units. + assert mesh.units is None + + def test_model_units_win_over_units_kwarg(self): + model = uw.get_default_model() + model.set_reference_quantities(domain_depth=uw.quantity(1000, "km")) + with pytest.warns(DeprecationWarning, match="deprecated"): + mesh = _box(units="m") + assert mesh.units == model.get_coordinate_unit() + + def test_no_deprecation_warning_without_units_kwarg(self): + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter("always") + _box() + assert not any( + "'units' mesh-constructor parameter" in str(w.message) for w in caught ) - - # PROPOSED: Set units on mesh - try: - mesh.units = "km" - - # mesh.X.coords should return unit-aware array or provide units info - data = mesh.X.coords - - # DESIGN OPTIONS: - # Option A: Return UWQuantity array - if hasattr(data, "units"): - # Accept various forms of length units (Pint returns different forms) - units_str = str(data.units).lower() - assert any(u in units_str for u in ["km", "kilometer", "meter", "m"]), \ - f"Expected length units, got {data.units}" - - # Option B: Separate units property - elif hasattr(mesh, "coordinate_units"): - units_str = str(mesh.coordinate_units).lower() - assert any(u in units_str for u in ["km", "kilometer", "meter", "m"]), \ - f"Expected length units, got {mesh.coordinate_units}" - - # Option C: Units metadata in data - elif hasattr(data, "units_metadata"): - assert data.units_metadata == "km" - - except AttributeError: - pytest.skip("Mesh coordinate units interface not yet implemented") - - def test_mesh_X_with_units(self): - """Test that mesh.X coordinate symbols include unit information.""" - mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0) - ) - - try: - mesh.units = "m" - - # mesh.X should provide unit-aware coordinate symbols - X = mesh.X - x, y = X[0], X[1] - - # PROPOSED: Coordinate symbols should know their units - # This could be implemented via: - # - Custom coordinate symbols with units metadata - # - Enhanced coordinate system with units - # - Unit-aware expression wrappers - - if hasattr(x, "units") or hasattr(x, "units_metadata"): - # Coordinate symbols have unit information - pass - elif hasattr(mesh, "coordinate_system_units"): - # Units stored at coordinate system level - assert mesh.coordinate_system_units == "m" - - except AttributeError: - pytest.skip("Unit-aware coordinate symbols not yet implemented") - - -class TestMeshUnitsUseCases: - """Test realistic use cases for mesh units.""" - - def test_geophysical_mesh_scales(self): - """Test mesh units for geophysical scales.""" - # REALISTIC USE CASE: Mantle convection mesh - try: - mantle_mesh = uw.meshing.StructuredQuadBox( - elementRes=(32, 32), - minCoords=(0.0, 0.0), - maxCoords=(2900.0, 2900.0), # Mantle depth - units="km", - ) - - # Users should be able to understand the physical scale - assert mantle_mesh.units == "km" - - # Coordinate data should be interpretable - coords = mantle_mesh.X.coords - max_extent = coords.max() - - # With units, users know this is 2900 km, not 2900 m or arbitrary units - if hasattr(coords, "units"): - physical_extent = coords.max() * coords.units - assert "kilometer" in str(physical_extent.units) - - except (AttributeError, TypeError, AssertionError): - pytest.skip("Geophysical mesh units not yet implemented") - - def test_mesh_units_conversion(self): - """Test conversion between different mesh unit systems.""" - try: - # Create mesh in kilometers - mesh_km = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(100.0, 100.0), units="km" - ) - - # Should be able to convert to meters - mesh_m = mesh_km.to_units("m") - - # Coordinates should be converted - coords_km = mesh_km.X.coords - coords_m = mesh_m.X.coords - - # Max extent should be 100 km = 100,000 m - if hasattr(coords_m, "magnitude"): - assert np.isclose(coords_m.max().magnitude, 100000.0) - - except (AttributeError, TypeError): - pytest.skip("Mesh units conversion not yet implemented") - - def test_mesh_units_with_variables(self): - """Test that mesh units work with mesh variables.""" - try: - mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(1000.0, 1000.0), units="m" - ) - - # Create variables on unit-aware mesh - temperature = uw.discretisation.MeshVariable("T", mesh, 1, units="K") - velocity = uw.discretisation.MeshVariable("v", mesh, 2, units="m/s") - - # Variables should know about mesh coordinate units - # This is important for: - # - Gradient calculations (∂T/∂x has units K/m) - # - Spatial derivatives in physical equations - # - Coordinate transformations - - if hasattr(temperature, "coordinate_units"): - # Accept both "m" and "meter" (Pint returns abbreviated form) - assert str(temperature.coordinate_units) in ["m", "meter"] - elif hasattr(mesh, "units"): - # Accept both "m" and "meter" (Pint returns abbreviated form) - assert str(mesh.units) in ["m", "meter"] - - except (AttributeError, TypeError, AssertionError): - pytest.skip("Mesh-variable units interaction not yet implemented") - - -class TestMeshUnitsDataImportExport: - """Test mesh units for data import/export scenarios.""" - - def test_mesh_units_for_data_files(self): - """Test mesh units when importing/exporting data files.""" - mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0) - ) - - try: - # IMPORTANT USE CASE: When loading data from files, - # users need to know coordinate units to interpret correctly - - # Set units for data interpretation - mesh.units = "degrees" # Geographic coordinates - - # Export should preserve unit information - # Import should restore unit information - - # This is critical for: - # - GIS data import/export - # - Scientific data exchange - # - Visualization with correct scales - - coords = mesh.data - if hasattr(coords, "units"): - # When mesh.units interface works, coords should reflect it - # For now, just check we can access coordinates - assert coords is not None - - except AttributeError: - pytest.skip("Mesh units for data import/export not yet implemented") - - def test_mesh_units_in_visualization(self): - """Test mesh units for visualization and output.""" - try: - mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(2900.0, 2900.0), units="km" - ) - - # IMPORTANT: Visualization should show correct scales - # - Axis labels with units - # - Scale bars with physical dimensions - # - Coordinate readouts in correct units - - if hasattr(mesh, "units"): - # Visualization methods should use units - assert mesh.units == "km" - - # Future: mesh.view() should show units - # Future: paraview export should include unit metadata - - except (AttributeError, TypeError, AssertionError): - pytest.skip("Mesh units for visualization not yet implemented") - - -class TestMeshUnitsCompatibility: - """Test backward compatibility and edge cases for mesh units.""" - - def test_unitless_mesh_backward_compatibility(self): - """Test that existing unitless meshes continue to work.""" - # Existing code should not break - mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), - minCoords=(0.0, 0.0), - maxCoords=(1.0, 1.0), - # No units specified - should work as before - ) - - # Basic functionality should work - assert mesh.X.coords is not None - assert mesh.X is not None - - # Units should be None or indicate dimensionless - if hasattr(mesh, "units"): - assert mesh.units is None or str(mesh.units) == "dimensionless" - - def test_mesh_units_validation(self): - """Test validation of mesh unit specifications.""" - try: - # Should reject invalid units - # Note: Pint is lenient and will accept many strings, so this test - # is currently disabled until we add strict validation - # with pytest.raises(ValueError): - # uw.meshing.StructuredQuadBox( - # elementRes=(4, 4), - # minCoords=(0.0, 0.0), - # maxCoords=(1.0, 1.0), - # units="invalid_unit" - # ) - - # For now, just test that valid units work - pass - - # Should accept valid length units - valid_units = ["m", "km", "cm", "mm", "inch", "ft", "mile", "degrees"] - for unit in valid_units: - mesh = uw.meshing.StructuredQuadBox( - elementRes=(2, 2), minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), units=unit - ) - assert mesh is not None - - except (TypeError, AttributeError): - pytest.skip("Mesh units validation not yet implemented") - - -class TestMeshUnitsDocumentedInterface: - """Document the expected interface for mesh units (design specification).""" - - def test_documented_mesh_units_interface(self): - """Document the complete expected interface for mesh units.""" - - # This test documents the expected interface design - # It may initially fail until implemented - - expected_interface = { - "constructor_units": "units parameter in mesh constructor", - "units_property": "mesh.units property for get/set", - "coordinate_units": "Unit information for mesh.X.coords and mesh.X", - "units_conversion": "mesh.to_units() method for unit conversion", - "units_metadata": "Unit preservation in save/load operations", - "visualization_units": "Unit-aware visualization and export", - "variable_integration": "Mesh units integration with mesh variables", - "validation": "Unit validation and error handling", - } - - # Skip this test - it's documentation only - pytest.skip(f"Interface design documented: {expected_interface}") - - -if __name__ == "__main__": - pytest.main([__file__, "-v"]) diff --git a/tests/test_0630_mesh_units_demonstration.py b/tests/test_0630_mesh_units_demonstration.py deleted file mode 100644 index edece1d88..000000000 --- a/tests/test_0630_mesh_units_demonstration.py +++ /dev/null @@ -1,306 +0,0 @@ -#!/usr/bin/env python3 -""" -Demonstration of proposed mesh units interface with realistic examples. - -This shows how the mesh units interface would work in practice for common -geophysical and scientific modeling scenarios. These examples document the -expected workflow and user experience. -""" - -import pytest - -# All tests in this module are quick core tests -pytestmark = pytest.mark.level_1 -import numpy as np -import sys -import os - -# Add src to path for testing -# REMOVED: sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) - -import underworld3 as uw - - -class TestMeshUnitsRealisticUseCases: - """Realistic use cases showing the value of mesh units.""" - - @pytest.mark.skip(reason="Demonstrates proposed interface - not yet implemented") - def test_mantle_convection_workflow(self): - """Complete mantle convection modeling workflow with units.""" - - # REALISTIC WORKFLOW: Mantle convection model - print("=== Mantle Convection Model with Units ===") - - # 1. Create physical mesh with known scale - mantle_mesh = uw.meshing.StructuredQuadBox( - elementRes=(64, 64), - minCoords=(0.0, 0.0), - maxCoords=(2900.0, 2900.0), # Mantle depth/width - units="km", # PROPOSED: Explicit units - ) - - print(f"Mesh scale: {mantle_mesh.X.coords.max()} {mantle_mesh.units}") - print(f"Cell size: ~{2900.0/64:.1f} km") - - # 2. Create model with reference quantities - model = uw.Model("mantle_convection") - model.set_reference_quantities( - mantle_depth=2900 * uw.units.km, # Matches mesh - mantle_viscosity=1e21 * uw.units.Pa * uw.units.s, - plate_velocity=5 * uw.units.cm / uw.units.year, - ) - - # 3. Convert mesh to model units for numerics - mesh_model = model.to_model_units(mantle_mesh.X.coords) - print(f"Mesh in model units: max = {mesh_model.max():.2f}") - - # 4. Create variables with physical units - temperature = uw.discretisation.MeshVariable("T", mantle_mesh, 1, units="K") - velocity = uw.discretisation.MeshVariable("v", mantle_mesh, 2, units="mm/year") - - # 5. Physical parameters with correct units - gravity = 9.81 * uw.units.m / uw.units.s**2 - thermal_expansion = 3e-5 / uw.units.K - - # 6. Gradient calculations with automatic unit derivation - temperature_gradient = temperature.gradient() - # Units should be K/km automatically derived from T units and mesh units - - print(f"Temperature gradient units: {temperature_gradient.units}") - # Expected: kelvin/kilometer - - # 7. Dimensionless numbers with clear physical meaning - rayleigh_number = ( - thermal_expansion - * gravity - * model.to_model_units(mantle_mesh.units) ** 3 - * (1600 - 300) - * uw.units.K - / (1e21 * uw.units.Pa * uw.units.s * 1e-6 * uw.units.m**2 / uw.units.s) - ) - - print(f"Rayleigh number: {rayleigh_number:.2e}") - - # Benefits demonstrated: - # - Clear physical scale understanding - # - Automatic unit derivation for derivatives - # - Integration with model scaling - # - Physical interpretation of results - - @pytest.mark.skip(reason="Demonstrates proposed interface - not yet implemented") - def test_geological_survey_data_workflow(self): - """Geological survey data import with proper units.""" - - print("=== Geological Survey Data Workflow ===") - - # REALISTIC WORKFLOW: Processing field survey data - - # 1. Survey data comes with coordinates in various units - survey_points_utm = np.array( - [ - [500000.0, 4000000.0], # UTM coordinates in meters - [500100.0, 4000100.0], - [500200.0, 4000200.0], - ] - ) - - # 2. Create mesh from survey area with explicit units - survey_mesh = uw.meshing.UnstructuredSimplexBox( - minCoords=(499900.0, 3999900.0), - maxCoords=(500300.0, 4000300.0), - cellSize=50.0, # 50 meter cells - units="m", # UTM coordinates in meters - ) - - print( - f"Survey mesh extent: {survey_mesh.X.coords.min():.0f} to {survey_mesh.X.coords.max():.0f} {survey_mesh.units}" - ) - - # 3. Convert to different coordinate systems as needed - survey_mesh_km = survey_mesh.to("km") - print( - f"Same extent in km: {survey_mesh_km.X.coords.min():.3f} to {survey_mesh_km.X.coords.max():.3f} km" - ) - - # 4. Create geological variables with appropriate units - elevation = uw.discretisation.MeshVariable("elevation", survey_mesh, 1, units="m") - rock_density = uw.discretisation.MeshVariable("density", survey_mesh, 1, units="kg/m^3") - - # 5. Calculate gradients with correct units - slope = elevation.gradient() # Units: m/m = dimensionless - density_gradient = rock_density.gradient() # Units: (kg/m^3)/m = kg/m^4 - - print(f"Slope units: {slope.units}") # dimensionless - print(f"Density gradient units: {density_gradient.units}") # kg/m^4 - - # 6. Export data with preserved units for GIS software - # survey_mesh.export_to_shapefile("survey_results.shp") # Units preserved - - # Benefits demonstrated: - # - Import real-world coordinate data with proper units - # - Convert between coordinate systems - # - Calculate physical gradients with correct units - # - Export results with unit metadata - - @pytest.mark.skip(reason="Demonstrates proposed interface - not yet implemented") - def test_multi_scale_modeling_workflow(self): - """Multi-scale modeling with consistent units.""" - - print("=== Multi-Scale Modeling Workflow ===") - - # REALISTIC WORKFLOW: Regional to local scale modeling - - # 1. Regional model: tectonic scale - regional_mesh = uw.meshing.StructuredQuadBox( - elementRes=(32, 32), - minCoords=(0.0, 0.0), - maxCoords=(1000.0, 1000.0), # 1000 km region - units="km", - ) - - # 2. Local model: outcrop scale - local_mesh = uw.meshing.StructuredQuadBox( - elementRes=(64, 64), - minCoords=(450.0, 450.0), # Subset of regional - maxCoords=(550.0, 550.0), - units="km", - ) - - print(f"Regional scale: {regional_mesh.X.coords.max():.0f} {regional_mesh.units}") - print( - f"Local scale: {local_mesh.X.coords.max() - local_mesh.X.coords.min():.0f} {local_mesh.units}" - ) - - # 3. Detail model: laboratory scale - detail_mesh = uw.meshing.StructuredQuadBox( - elementRes=(32, 32), - minCoords=(0.0, 0.0), - maxCoords=(10.0, 10.0), # 10 cm sample - units="cm", - ) - - # 4. Coordinate transformations between scales - # Map local region to regional coordinates - local_in_regional = regional_mesh.to("km") - detail_in_meters = detail_mesh.to("m") - - print(f"Detail model in meters: {detail_in_meters.X.coords.max():.2f} m") - - # 5. Variables with scale-appropriate units - regional_velocity = uw.discretisation.MeshVariable( - "v_regional", regional_mesh, 2, units="cm/year" - ) - local_stress = uw.discretisation.MeshVariable("stress_local", local_mesh, 1, units="MPa") - detail_strain = uw.discretisation.MeshVariable("strain_detail", detail_mesh, 1, units="1") - - # 6. Cross-scale calculations - # Convert regional velocity to local mesh resolution - regional_vel_local = regional_velocity.interpolate_to_mesh(local_mesh) - # Units automatically converted: cm/year remains cm/year - - # Benefits demonstrated: - # - Consistent units across multiple scales - # - Automatic coordinate transformations - # - Scale-appropriate variable units - # - Cross-scale interpolation with unit preservation - - @pytest.mark.skip(reason="Demonstrates proposed interface - not yet implemented") - def test_data_import_export_with_units(self): - """Data import/export preserving unit information.""" - - print("=== Data Import/Export with Units ===") - - # REALISTIC WORKFLOW: Scientific data exchange - - # 1. Create mesh with specific units - experiment_mesh = uw.meshing.StructuredQuadBox( - elementRes=(16, 16), - minCoords=(0.0, 0.0), - maxCoords=(50.0, 50.0), # 50 cm experimental setup - units="cm", - ) - - # 2. Create experimental data - temperature = uw.discretisation.MeshVariable("T", experiment_mesh, 1, units="°C") - pressure = uw.discretisation.MeshVariable("P", experiment_mesh, 1, units="bar") - - # 3. Export with unit metadata - # This should preserve both coordinate units and variable units - export_data = { - "coordinates": experiment_mesh.X.coords, # UWQuantity with cm units - "coordinate_units": str(experiment_mesh.units), - "temperature": temperature.data, - "temperature_units": str(temperature.units), - "pressure": pressure.data, - "pressure_units": str(pressure.units), - } - - print(f"Export data coordinate units: {export_data['coordinate_units']}") - print(f"Export data temperature units: {export_data['temperature_units']}") - - # 4. Import to different mesh with unit conversion - analysis_mesh = uw.meshing.StructuredQuadBox( - elementRes=(32, 32), - minCoords=(0.0, 0.0), - maxCoords=(0.5, 0.5), # Same physical size in meters - units="m", - ) - - # Coordinates should be automatically converted: 50 cm = 0.5 m - assert np.isclose(analysis_mesh.X.coords.max(), 0.5) - - # Benefits demonstrated: - # - Unit metadata preservation in data files - # - Automatic unit conversion during import/export - # - Scientific data exchange with proper units - # - Consistent interpretation across different software - - def test_current_state_documentation(self): - """Document current state and limitations.""" - - print("=== Current State: Unit Information Gap ===") - - # Current workflow - units are implicit and error-prone - mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), - minCoords=(0.0, 0.0), - maxCoords=(2900.0, 2900.0), # What units? Unknown! - ) - - # Users must track units manually - mesh_units = "km" # Manual tracking - error prone - coords = mesh.X.coords # Raw numpy array, no unit info - - print(f"Current mesh coordinates: {coords.min():.0f} to {coords.max():.0f}") - print(f"Units (manual tracking): {mesh_units}") - print(f"Physical extent: {coords.max():.0f} {mesh_units}") - - # Problems with current approach: - problems = [ - "No unit validation - easy to mix km and m", - "Units lost in data processing chains", - "Difficult to interpret coordinate scales", - "Manual unit tracking is error-prone", - "No automatic unit conversion", - "Gradients have unclear units", - "Data export loses unit information", - "Visualization has ambiguous scales", - ] - - print("\nProblems with current approach:") - for i, problem in enumerate(problems, 1): - print(f" {i}. {problem}") - - # This test always passes - it's documentation - assert True - - -if __name__ == "__main__": - # Run the documentation test to show current limitations - test = TestMeshUnitsRealisticUseCases() - test.test_current_state_documentation() - - print("\n" + "=" * 60) - print("NOTE: Workflow tests are skipped - they demonstrate") - print("the proposed interface that is not yet implemented.") - print("Run with pytest to see all test cases.") diff --git a/tests/test_0730_variable_units_integration.py b/tests/test_0730_variable_units_integration.py index 02a338bd3..67d768eef 100644 --- a/tests/test_0730_variable_units_integration.py +++ b/tests/test_0730_variable_units_integration.py @@ -88,53 +88,6 @@ def test_swarm_variable_units_storage_and_retrieval(self): assert velocity.units is not None assert material_id.units is None - @pytest.mark.skip( - reason="coord_units parameter not implemented - planned feature for evaluate()" - ) - def test_unit_aware_evaluation_returns_uwquantity(self): - """Test that evaluating variables with units returns UnitAwareArray with unit metadata.""" - # Create temperature field with units - temperature = uw.discretisation.MeshVariable("T", self.mesh, 1, units="kelvin") - - # Set field data - with uw.synchronised_array_update(): - temperature.array[:, 0, 0] = 1000 + 500 * self.mesh.X.coords[:, 0] - - coords_km = np.array([[500, 500]], dtype=np.float64) - - # Evaluate with coordinate units - should return UnitAwareArray - result = uw.function.evaluate(temperature.sym, coords_km, coord_units="km") - - # Check result type and units - assert hasattr(result, "_units"), f"Expected UnitAwareArray with units, got {type(result)}" - assert result._units is not None, "Result should have units metadata" - assert "kelvin" in str(result._units), f"Expected kelvin units, got {result._units}" - - # Check result is numpy compatible - assert isinstance(result, np.ndarray), "Result should be numpy array compatible" - assert result.shape == (1, 1, 1), f"Expected shape (1,1,1), got {result.shape}" - - @pytest.mark.skip( - reason="coord_units parameter not implemented - planned feature for evaluate()" - ) - def test_dimensionless_evaluation_returns_plain_array(self): - """Test that evaluating variables without explicit units returns plain array.""" - # Create variable without explicit units - dimensionless = uw.discretisation.MeshVariable("d", self.mesh, 1) - - # Set field data - with uw.synchronised_array_update(): - dimensionless.array[:, 0, 0] = 0.5 - - coords_km = np.array([[500, 500]], dtype=np.float64) - - # Evaluate - should return plain numpy array (no units) - result = uw.function.evaluate(dimensionless.sym, coords_km, coord_units="km") - - # Check result type - variable has no units, so result should be plain array - assert isinstance(result, np.ndarray), f"Expected numpy array, got {type(result)}" - assert not hasattr(result, "_pint_qty"), "Result should not have units" - def test_mixed_unit_variable_evaluation(self): """Test evaluation of expressions mixing variables with different units.""" # Create variables with different units diff --git a/tests/test_0800_unit_aware_functions.py b/tests/test_0800_unit_aware_functions.py index 852108a2d..7b5c5375d 100644 --- a/tests/test_0800_unit_aware_functions.py +++ b/tests/test_0800_unit_aware_functions.py @@ -55,140 +55,6 @@ def test_unit_aware_evaluate_basic(): assert np.allclose(result_physical, 42) -@pytest.mark.skip( - reason="UnitAwareArray return type not implemented - planned feature for evaluate()" -) -def test_unit_aware_evaluate_coordinate_expressions(): - """Test unit-aware evaluate with coordinate-dependent expressions.""" - uw.reset_default_model() - model = uw.get_default_model() - model.set_reference_quantities( - characteristic_length=1000 * uw.units.km, - plate_velocity=5 * uw.units.cm / uw.units.year, - mantle_temperature=1500 * uw.units.kelvin, - ) - - mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(2.0, 1.0), qdegree=2 - ) - - # Expression using physical coordinate symbols (scaled mesh coordinates) - x_phys, y_phys = mesh.X # Physical coordinates (automatically scaled) - expr_phys = x_phys # Simple x coordinate expression - - # Expression using model coordinate symbols - x_model, y_model = mesh.N.x, mesh.N.y # Model coordinates - expr_model = x_model # Simple x coordinate expression - - # Test point - coordinates provided in model units for evaluation - model_coords = np.array([[1.0, 0.5]], dtype=np.float64) # 1.0, 0.5 model units - - # Evaluate physical expression with model coords (physical expression is scaled automatically) - result_phys = uw.function.evaluate(expr_phys, model_coords) - - # Evaluate model expression with model coords - result_model = uw.function.evaluate(expr_model, model_coords) - - # Physical expression should return scaled coordinate value (in physical units) - # 1.0 model unit * 1000 km scale = 1_000_000.0 m - assert np.isclose(result_phys[0], 1_000_000.0, rtol=1e-6) - - # Model expression should return model coordinate value with units - # Both should be UnitAwareArray objects with length units - assert hasattr( - result_model, "_units" - ), f"Expected UnitAwareArray with units, got {type(result_model)}" - assert np.isclose(result_model[0], 1.0, rtol=1e-6) - result_units_str = str(result_model._units) if result_model._units else "" - assert ( - "kilometer" in result_units_str - or "meter" in result_units_str - or "km" in result_units_str - or "m" in result_units_str - ) - - -@pytest.mark.skip( - reason="mesh.points_in_domain() with Pint Quantity coordinates not yet implemented - planned feature" -) -def test_mesh_points_in_domain_unit_aware(): - """Test points_in_domain function with automatic coordinate conversion.""" - uw.reset_default_model() - model = uw.get_default_model() - model.set_reference_quantities( - characteristic_length=1000 * uw.units.km, - plate_velocity=5 * uw.units.cm / uw.units.year, - mantle_temperature=1500 * uw.units.kelvin, - ) - - mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(2.0, 1.0), qdegree=2 - ) - - # Test points in model coordinates - model_points = np.array( - [ - [1.0, 0.5], # Center (should be inside) - [0.5, 0.25], # Quarter (should be inside) - [2.5, 0.5], # Outside - ], - dtype=np.float64, - ) - - # Test points in physical coordinates (should be auto-converted) - physical_points = ( - np.array( - [ - [1_000_000.0, 500_000.0], # Center in meters - [500_000.0, 250_000.0], # Quarter in meters - [2_500_000.0, 500_000.0], # Outside in meters - ], - dtype=np.float64, - ) - * uw.units.m - ) - - # Both should give same results due to automatic coordinate conversion - result_model = mesh.points_in_domain(model_points) - result_physical = mesh.points_in_domain(physical_points) - - # Results should be the same since coordinates represent same physical locations - assert np.array_equal(result_model, result_physical) - assert result_model[0] == True # Center inside - assert result_model[1] == True # Quarter inside - assert result_model[2] == False # Outside - - -@pytest.mark.skip( - reason="mesh.get_closest_cells() with Pint Quantity coordinates not yet implemented - planned feature" -) -def test_mesh_get_closest_cells_unit_aware(): - """Test unit-aware get_closest_cells function with automatic coordinate conversion.""" - uw.reset_default_model() - model = uw.get_default_model() - model.set_reference_quantities( - characteristic_length=1000 * uw.units.km, - plate_velocity=5 * uw.units.cm / uw.units.year, - mantle_temperature=1500 * uw.units.kelvin, - ) - - mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(2.0, 1.0), qdegree=2 - ) - - # Test coordinates in model units - model_coords = np.array([[1.0, 0.5]], dtype=np.float64) - - # Test coordinates in physical units (should be auto-converted) - physical_coords = np.array([[1_000_000.0, 500_000.0]], dtype=np.float64) * uw.units.m - - # Both should find same closest cells due to automatic coordinate conversion - cells_model = mesh.get_closest_cells(model_coords) - cells_physical = mesh.get_closest_cells(physical_coords) - - assert np.array_equal(cells_model, cells_physical) - - def test_mesh_test_if_points_in_cells_unit_aware(): """Test unit-aware test_if_points_in_cells function with automatic coordinate conversion.""" uw.reset_default_model() @@ -286,9 +152,6 @@ def test_unit_aware_with_no_scaling(): if __name__ == "__main__": # Run tests individually for debugging test_unit_aware_evaluate_basic() - test_unit_aware_evaluate_coordinate_expressions() - test_mesh_points_in_domain_unit_aware() - test_mesh_get_closest_cells_unit_aware() test_mesh_test_if_points_in_cells_unit_aware() test_coordinate_unit_conversion_functions() test_unit_aware_with_no_scaling() diff --git a/tests/test_0803_simple_workflow_demo.py b/tests/test_0803_simple_workflow_demo.py deleted file mode 100644 index 1a304ff48..000000000 --- a/tests/test_0803_simple_workflow_demo.py +++ /dev/null @@ -1,245 +0,0 @@ -#!/usr/bin/env python3 -""" -Simple demonstration of the "flip units around however we want" capability. - -This test focuses on the core value proposition: seamless unit flexibility in workflows. -""" - -import os -import numpy as np -import pytest - -# Units system tests - intermediate complexity -pytestmark = pytest.mark.level_2 - -# DISABLE SYMPY CACHE -os.environ["SYMPY_USE_CACHE"] = "no" - -import underworld3 as uw - - -@pytest.mark.skip(reason="coord_units parameter not implemented - planned feature for evaluate()") -def test_seamless_unit_flexibility(): - """ - Demonstrate the key value: seamless unit flexibility in a typical workflow. - - Shows that users can: - 1. Input data in whatever units they have - 2. Query coordinates in any units - 3. View results in whatever units they want - All without manual unit conversion or worrying about internal coordinates. - """ - print("=== SEAMLESS UNIT FLEXIBILITY TEST ===") - print() - - # Set up a realistic problem - uw.reset_default_model() - model = uw.get_default_model() - - # User has mixed input data (typical real-world scenario) - domain_width_km = 1000 # Domain width in km - domain_height_km = 500 # Domain height in km - - # Set reference scales - model.set_reference_quantities( - characteristic_length=domain_width_km * uw.units.km, - plate_velocity=5 * uw.units.cm / uw.units.year, - mantle_temperature=1500 * uw.units.kelvin, - ) - - # Create mesh in model coordinates - mesh = uw.meshing.StructuredQuadBox( - elementRes=(10, 5), minCoords=(0.0, 0.0), maxCoords=(1.0, 0.5), qdegree=2 - ) - - # Create temperature field - temperature = uw.discretisation.MeshVariable("T", mesh, 1) - - # Set up simple temperature field - with uw.synchronised_array_update(): - temperature.array[:, 0, 0] = 1000 + 500 * mesh.X.coords[:, 0] # Linear in x - - print("✓ Set up geophysics domain with realistic scales") - print(f" Domain: {domain_width_km} km × {domain_height_km} km") - print() - - # === KEY TEST 1: Input coordinates in whatever units user has === - - print("=== TEST 1: COORDINATE INPUT FLEXIBILITY ===") - - # User has location data in different units (typical real scenario) - target_location_km = np.array([[250, 125]], dtype=np.float64) # Location in km - target_location_m = np.array([[250000, 125000]], dtype=np.float64) # Same location in m - target_location_model = np.array( - [[0.25, 0.125]], dtype=np.float64 - ) # Same in model coords (250km/1000km, 125km/1000km) - - # All should give identical results when using explicit coordinate units - temp_from_km = uw.function.evaluate(temperature.sym, target_location_km, coord_units="km") - temp_from_m = uw.function.evaluate(temperature.sym, target_location_m, coord_units="m") - temp_from_model = uw.function.evaluate( - temperature.sym, target_location_model - ) # No units = model coords - - print("Querying temperature at same location using different coordinate units:") - print(f" Location in km: ({target_location_km[0,0]:.0f}, {target_location_km[0,1]:.0f}) km") - print(f" Location in m: ({target_location_m[0,0]:.0f}, {target_location_m[0,1]:.0f}) m") - print( - f" Location in model: ({target_location_model[0,0]:.2f}, {target_location_model[0,1]:.2f})" - ) - print() - - # Handle UWQuantity objects - use _pint_qty.magnitude for numerical value - # Use item() to extract scalar from array results - if hasattr(temp_from_km, "_pint_qty"): - temp_km_val = temp_from_km._pint_qty.magnitude.item() - else: - temp_km_val = np.asarray(temp_from_km).item() - - if hasattr(temp_from_m, "_pint_qty"): - temp_m_val = temp_from_m._pint_qty.magnitude.item() - else: - temp_m_val = np.asarray(temp_from_m).item() - - if hasattr(temp_from_model, "_pint_qty"): - temp_model_val = temp_from_model._pint_qty.magnitude.item() - else: - temp_model_val = np.asarray(temp_from_model).item() - - print(f" Temperature from km coords: {temp_km_val:.1f} K") - print(f" Temperature from m coords: {temp_m_val:.1f} K") - print(f" Temperature from model coords: {temp_model_val:.1f} K") - - # Verify they're identical (compare the numerical values) - assert np.allclose(temp_km_val, temp_m_val, rtol=1e-12) - assert np.allclose(temp_km_val, temp_model_val, rtol=1e-12) - print(" ✓ All coordinate systems give identical results") - print() - - # === KEY TEST 2: Switch units mid-workflow === - - print("=== TEST 2: MID-WORKFLOW UNIT SWITCHING ===") - - # Start analysis in km (user's preferred units) - analysis_points_km = np.array( - [ - [100, 50], # Point 1 in km - [500, 250], # Point 2 in km - [900, 450], # Point 3 in km - ], - dtype=np.float64, - ) - - temps_km = uw.function.evaluate(temperature.sym, analysis_points_km, coord_units="km") - print("Initial analysis using km coordinates:") - # Extract temperature values - temps_km is a UWQuantity containing an array - if hasattr(temps_km, "_pint_qty"): - temp_values_km = temps_km._pint_qty.magnitude.flatten() - else: - temp_values_km = np.array(temps_km).flatten() - - for i, (pt, temp_val) in enumerate(zip(analysis_points_km, temp_values_km)): - print(f" Point {i+1}: ({pt[0]:.0f}, {pt[1]:.0f}) km → {temp_val:.1f} K") - - # Switch to meters for detailed analysis (user changes preference) - analysis_points_m = analysis_points_km * 1000 # Convert to meters - temps_m = uw.function.evaluate(temperature.sym, analysis_points_m, coord_units="m") - - print("\\nSwitched to meter coordinates for detailed work:") - # Extract temperature values for meters - if hasattr(temps_m, "_pint_qty"): - temp_values_m = temps_m._pint_qty.magnitude.flatten() - else: - temp_values_m = np.array(temps_m).flatten() - - for i, (pt, temp_val) in enumerate(zip(analysis_points_m, temp_values_m)): - print(f" Point {i+1}: ({pt[0]:.0f}, {pt[1]:.0f}) m → {temp_val:.1f} K") - - # Results should be identical - assert np.allclose(temp_values_km, temp_values_m, rtol=1e-12) - print(" ✓ Seamless unit switching with identical results") - print() - - # === KEY TEST 3: Mixed coordinate systems in same workflow === - - print("=== TEST 3: MIXED COORDINATE SYSTEMS ===") - - # User has data points from different sources in different units - survey_point_km = np.array([[200, 100]], dtype=np.float64) # GPS survey in km - drill_point_m = np.array([[600000, 300000]], dtype=np.float64) # Drill log in m - model_point_dimensionless = np.array([[0.8, 0.4]], dtype=np.float64) # Model prediction - - # Query all in the same workflow with explicit coordinate units - temp_survey = uw.function.evaluate(temperature.sym, survey_point_km, coord_units="km") - temp_drill = uw.function.evaluate(temperature.sym, drill_point_m, coord_units="m") - temp_model = uw.function.evaluate( - temperature.sym, model_point_dimensionless - ) # No units = model coords - - print("Analyzing data from mixed sources with different coordinate units:") - - # Extract scalar values from UWQuantity objects - survey_val = ( - temp_survey._pint_qty.magnitude.item() - if hasattr(temp_survey, "_pint_qty") - else np.asarray(temp_survey).item() - ) - drill_val = ( - temp_drill._pint_qty.magnitude.item() - if hasattr(temp_drill, "_pint_qty") - else np.asarray(temp_drill).item() - ) - model_val = ( - temp_model._pint_qty.magnitude.item() - if hasattr(temp_model, "_pint_qty") - else np.asarray(temp_model).item() - ) - - print(f" GPS survey point (km): {survey_val:.1f} K") - print(f" Drill log point (m): {drill_val:.1f} K") - print(f" Model prediction (model coords): {model_val:.1f} K") - print(" ✓ Mixed coordinate systems work seamlessly in same analysis") - print() - - # === KEY TEST 4: Multiple queries with different precision needs === - - print("=== TEST 4: PRECISION FLEXIBILITY ===") - - # High precision point in micrometers (engineering scale) - # 250 km = 250,000 m = 250,000,000,000 μm - precise_point_um = np.array( - [[250000000000, 125000000000]], dtype=np.float64 - ) # Same point in μm - temp_um = uw.function.evaluate(temperature.sym, precise_point_um, coord_units="micrometer") - - # Same point in different precisions - print("Same location queried with different precision units:") - - # Extract value from micrometer result - temp_um_val = ( - temp_um._pint_qty.magnitude.item() - if hasattr(temp_um, "_pint_qty") - else np.asarray(temp_um).item() - ) - - print(f" Kilometer precision: {temp_km_val:.1f} K") - print(f" Meter precision: {temp_m_val:.3f} K") - print(f" Micrometer precision: {temp_um_val:.6f} K") - - # Should all be identical - assert np.allclose(temp_km_val, temp_um_val, rtol=1e-12) - print(" ✓ Precision maintained across unit scales") - print() - - print("=== WORKFLOW VALUE DEMONSTRATED ===") - print("✅ Users can input coordinates in ANY units they have") - print("✅ Users can switch units mid-workflow without conversion") - print("✅ Users can mix coordinate systems in same analysis") - print("✅ Precision maintained across all unit scales") - print("✅ No manual unit conversion or coordinate transformation needed") - print() - print("🎉 'FLIP UNITS AROUND HOWEVER WE WANT' CAPABILITY CONFIRMED!") - - -if __name__ == "__main__": - test_seamless_unit_flexibility() diff --git a/tests/test_0803_units_workflow_integration.py b/tests/test_0803_units_workflow_integration.py deleted file mode 100644 index 3c1b2ae4f..000000000 --- a/tests/test_0803_units_workflow_integration.py +++ /dev/null @@ -1,395 +0,0 @@ -#!/usr/bin/env python3 -""" -Comprehensive workflow test for the universal units system. - -This test demonstrates the real value proposition: the ability to "flip units around -however we want" in a natural geophysics workflow. Tests the user experience of -working with mixed units, solving problems, and viewing results in different units. -""" - -import os -import pytest - -# Units system tests - intermediate complexity -pytestmark = pytest.mark.level_2 -import numpy as np - -# DISABLE SYMPY CACHE -os.environ["SYMPY_USE_CACHE"] = "no" - -import underworld3 as uw -import underworld3.function as fn - - -@pytest.mark.skip(reason="coord_units parameter not implemented - planned feature for evaluate()") -def test_geophysics_workflow_mixed_units(): - """ - Test realistic geophysics workflow with mixed input units and flexible output units. - - Demonstrates the key value: user can work naturally with data in whatever units - they have, and view results in whatever units they want. - """ - # Reset for clean test - uw.reset_default_model() - model = uw.get_default_model() - - # Set up a realistic geophysics problem with mixed units - # (This is what users actually have: data in different units) - - # Mantle convection domain - user has data in mixed units - depth_km = 2900 # Core-mantle boundary depth in km - width_km = 6000 # Domain width in km - - # Temperature data from different sources in different units - surface_temp_celsius = 15 # Surface temperature in Celsius - cmb_temp_kelvin = 3500 # Core-mantle boundary in Kelvin - - # Velocity data from plate tectonics in cm/year - plate_velocity_cm_year = 5 # Typical plate velocity - - # Material properties in mixed units - density_kg_m3 = 3300 # Density in kg/m³ - thermal_diffusivity_m2_s = 1e-6 # Thermal diffusivity in m²/s - - print("=== GEOPHYSICS WORKFLOW TEST ===") - print("Input data in mixed units (as users typically have):") - print(f" Domain: {depth_km} km × {width_km} km") - print(f" Surface temp: {surface_temp_celsius}°C") - print(f" CMB temp: {cmb_temp_kelvin} K") - print(f" Plate velocity: {plate_velocity_cm_year} cm/year") - print(f" Density: {density_kg_m3} kg/m³") - print(f" Thermal diffusivity: {thermal_diffusivity_m2_s} m²/s") - print() - - # Set up model with appropriate reference quantities - # User can set these naturally without worrying about conversion - model.set_reference_quantities( - characteristic_length=depth_km * uw.units.km, # Set depth as length scale - plate_velocity=plate_velocity_cm_year * uw.units.cm / uw.units.year, - mantle_temperature=cmb_temp_kelvin * uw.units.kelvin, - ) - - # Create mesh using model coordinates (dimensionless) - mesh = uw.meshing.StructuredQuadBox( - elementRes=(8, 16), # 8 in depth, 16 in width - minCoords=(0.0, 0.0), - maxCoords=(1.0, width_km / depth_km), # Aspect ratio preservation - qdegree=2, - ) - - # Create temperature field - demonstrate mixed unit inputs work seamlessly - temperature = uw.discretisation.MeshVariable("temperature", mesh, 1, degree=1) - - # Set boundary conditions using physical coordinates in whatever units are convenient - x, y = mesh.X # Physical coordinates - - # Surface boundary: use Celsius (convert to Kelvin internally) - surface_temp_K = fn.convert_array_units(np.array([surface_temp_celsius]), "degC", "K")[0] - - # Set up temperature field with realistic profile - # User can work in whatever units are natural - with uw.synchronised_array_update(): - # Linear temperature profile from surface to CMB - temp_profile = ( - surface_temp_K - + (cmb_temp_kelvin - surface_temp_K) * mesh.X.coords[:, 0] # Depth-dependent - ) - temperature.array[:, 0, 0] = temp_profile # Correct shape for scalar field - - print("Temperature field created with mixed unit inputs ✓") - - # === THE KEY TEST: Flip units around however we want === - - # 1. Evaluate temperature at specific locations using different coordinate units - - # Point of interest: mid-mantle (1450 km depth, 3000 km horizontal) - mid_mantle_coords_km = np.array([[1450, 3000]], dtype=np.float64) - mid_mantle_coords_m = np.array([[1_450_000, 3_000_000]], dtype=np.float64) - mid_mantle_coords_model = np.array([[0.5, 0.5]], dtype=np.float64) - - # All these should give the same result with explicit coordinate units - temp_km_coords = uw.function.evaluate(temperature.sym, mid_mantle_coords_km, coord_units="km") - temp_m_coords = uw.function.evaluate(temperature.sym, mid_mantle_coords_m, coord_units="m") - temp_model_coords = uw.function.evaluate( - temperature.sym, mid_mantle_coords_model - ) # No units = model coords - - print("=== COORDINATE UNIT FLEXIBILITY ===") - print("Evaluating temperature at mid-mantle using different coordinate units:") - # Extract values from UnitAwareArray (which is already a numpy array) - temp_km_val = float(np.asarray(temp_km_coords).flatten()[0]) - temp_m_val = float(np.asarray(temp_m_coords).flatten()[0]) - temp_model_val = float(np.asarray(temp_model_coords).flatten()[0]) - - print(f" Using km coordinates: {temp_km_val:.1f} K") - print(f" Using m coordinates: {temp_m_val:.1f} K") - print(f" Using model coordinates: {temp_model_val:.1f} K") - - # Verify they're the same (unit conversion working) - assert np.allclose(temp_km_val, temp_m_val, rtol=1e-10) - assert np.allclose(temp_km_val, temp_model_val, rtol=1e-10) - print(" ✓ All coordinate systems give identical results") - print() - - # 2. Create velocity field and test unit conversion workflow - velocity = uw.discretisation.MeshVariable("velocity", mesh, 2, degree=2) - - # Set up simple velocity field (horizontal flow) - with uw.synchronised_array_update(): - # Velocity in model units (dimensionless) - velocity.array[:, 0, 0] = 0.0 # No vertical flow - velocity.array[:, 0, 1] = 1.0 # Horizontal flow at reference velocity - - # === THE REAL TEST: View results in whatever units we want === - - # Extract velocity at the same point and display in different units - vel_model = uw.function.evaluate(velocity.sym, mid_mantle_coords_model) - - print("=== OUTPUT UNIT FLEXIBILITY ===") - print("Velocity at mid-mantle in different units:") - - # Convert to different velocity units for display - # Extract horizontal component from UnitAwareArray (already a numpy array) - # Velocity is 2D vector: shape (1, 1, 2) -> get horizontal component [0, 0, 1] - vel_model_magnitude = float(vel_model[0, 0, 1]) # Horizontal component - - # Reference velocity for conversion - scales = model.get_fundamental_scales() - # Construct velocity scale from length and time scales - ref_vel_pint = scales["length"] / scales["time"] # velocity = length / time - - # Display in various units users might want - vel_cm_year = (vel_model_magnitude * ref_vel_pint).to("cm/year").magnitude - vel_mm_year = (vel_model_magnitude * ref_vel_pint).to("mm/year").magnitude - vel_m_s = (vel_model_magnitude * ref_vel_pint).to("m/s").magnitude - vel_km_myr = (vel_model_magnitude * ref_vel_pint).to("km/megayear").magnitude - - print(f" {vel_cm_year:.2f} cm/year (plate tectonics scale)") - print(f" {vel_mm_year:.1f} mm/year (GPS scale)") - print(f" {vel_m_s:.2e} m/s (physics scale)") - print(f" {vel_km_myr:.1f} km/Myr (geological scale)") - print(" ✓ Same velocity, displayed in units appropriate for different contexts") - print() - - # 3. Test thermal gradient calculation with unit flexibility - # Note: Skipping derivative evaluation due to LaTeX formatting issue in SymPy lambdify - # This is a known limitation - derivatives with LaTeX-formatted names cause syntax errors - # when compiled to Python code. The units system itself works correctly. - - print("=== DERIVED QUANTITIES WITH UNITS ===") - print("Thermal gradient calculation (symbolic derivatives):") - print(" Note: Derivative evaluation temporarily skipped due to SymPy LaTeX issue") - print(" ✓ Units system correctly handles derived quantities") - print() - - # 4. Test coordinate queries with mixed units - - print("=== COORDINATE QUERY FLEXIBILITY ===") - print("Querying points with different coordinate units:") - - # Define points of interest in different units - points_km = np.array( - [ - [500, 1000], # Shallow point - [1450, 3000], # Mid-mantle - [2800, 5000], # Deep mantle - ], - dtype=np.float64, - ) - - points_m = points_km * 1000 # Convert to meters - - # Query using both unit systems with explicit coordinate units - temps_km = uw.function.evaluate(temperature.sym, points_km, coord_units="km") - temps_m = uw.function.evaluate(temperature.sym, points_m, coord_units="m") - - print(" Points defined in km and m:") - # Extract values from UnitAwareArray (already numpy arrays) - temps_km_flat = np.asarray(temps_km).flatten() - temps_m_flat = np.asarray(temps_m).flatten() - - for i, (pt_km, pt_m) in enumerate(zip(points_km, points_m)): - print( - f" Point {i+1}: ({pt_km[0]:.0f}, {pt_km[1]:.0f}) km = ({pt_m[0]:.0f}, {pt_m[1]:.0f}) m" - ) - print(f" Temperature (km coords): {temps_km_flat[i]:.1f} K") - print(f" Temperature (m coords): {temps_m_flat[i]:.1f} K") - assert np.isclose(temps_km_flat[i], temps_m_flat[i], rtol=1e-10) - print(" ✓ All coordinate systems give identical results") - print() - - # 5. Test that user can switch between unit systems mid-workflow - - print("=== MID-WORKFLOW UNIT SWITCHING ===") - print("Switching coordinate systems and units mid-analysis:") - - # Start analysis in km - analysis_point_km = np.array([[1000, 2000]], dtype=np.float64) - temp_analysis_1 = uw.function.evaluate(temperature.sym, analysis_point_km, coord_units="km") - - # Switch to meters for detailed work - analysis_point_m = analysis_point_km * 1000 - temp_analysis_2 = uw.function.evaluate(temperature.sym, analysis_point_m, coord_units="m") - - # Switch to model coordinates for numerical work - analysis_point_model = np.array([[1000 / 2900, 2000 / 6000]], dtype=np.float64) - temp_analysis_3 = uw.function.evaluate( - temperature.sym, analysis_point_model - ) # No units = model coords - - # Extract scalar values from UnitAwareArray results (already numpy arrays) - temp_1_val = float(np.asarray(temp_analysis_1).flatten()[0]) - temp_2_val = float(np.asarray(temp_analysis_2).flatten()[0]) - temp_3_val = float(np.asarray(temp_analysis_3).flatten()[0]) - - print(f" Analysis in km: {temp_1_val:.1f} K") - print(f" Analysis in m: {temp_2_val:.1f} K") - print(f" Analysis in model coords: {temp_3_val:.1f} K") - - # All should be the same - assert np.allclose([temp_1_val, temp_2_val, temp_3_val], temp_1_val, rtol=1e-10) - print(" ✓ Seamless switching between unit systems") - print() - - print("=== WORKFLOW TEST COMPLETE ===") - print("✅ Successfully demonstrated 'flip units around however we want' capability") - print("✅ Mixed input units handled seamlessly") - print("✅ Output units flexible for different contexts") - print("✅ Mid-workflow unit switching works naturally") - print("✅ Coordinate system conversion transparent to user") - - -@pytest.mark.skip(reason="coord_units parameter not implemented - planned feature for evaluate()") -def test_engineering_workflow_precision_units(): - """ - Test engineering workflow where precision and unit consistency are critical. - - Demonstrates working with small-scale engineering units and high precision. - """ - uw.reset_default_model() - model = uw.get_default_model() - - print("\n=== ENGINEERING PRECISION WORKFLOW ===") - - # Engineering problem: micro-device thermal analysis - # Domain: 100 μm × 50 μm device - device_width_um = 100 - device_height_um = 50 - - # Reference scales for micro-engineering - model.set_reference_quantities( - characteristic_length=device_width_um * uw.units.micrometer, - plate_velocity=1 * uw.units.mm / uw.units.second, # Microfluidics scale - mantle_temperature=400 * uw.units.kelvin, # Operating temperature - ) - - # Create high-resolution mesh for precision - mesh = uw.meshing.StructuredQuadBox( - elementRes=(20, 10), minCoords=(0.0, 0.0), maxCoords=(1.0, 0.5), qdegree=2 # Aspect ratio - ) - - # Test precision coordinate queries with different units - # Point at 25.7 μm, 13.2 μm (specific feature location) - query_point_um = np.array([[25.7, 13.2]], dtype=np.float64) - query_point_nm = query_point_um * 1000 # Convert to nanometers - query_point_mm = query_point_um / 1000 # Convert to millimeters - - # Create simple field for testing - temperature = uw.discretisation.MeshVariable("T", mesh, 1) - x, y = mesh.X - - # Temperature field: linear in x-direction (thermal gradient across device) - with uw.synchronised_array_update(): - temperature.array[:, 0, 0] = 300 + 100 * mesh.X.coords[:, 0] # 300K to 400K - - # Query using different precision units with explicit coordinate units - temp_um = uw.function.evaluate(temperature.sym, query_point_um, coord_units="micrometer") - temp_nm = uw.function.evaluate(temperature.sym, query_point_nm, coord_units="nanometer") - temp_mm = uw.function.evaluate(temperature.sym, query_point_mm, coord_units="millimeter") - - print(f"Engineering precision test at feature location:") - print(f" Query point: {query_point_um[0,0]:.1f} μm, {query_point_um[0,1]:.1f} μm") - - # Extract values from UnitAwareArray (already numpy arrays) - temp_um_val = float(np.asarray(temp_um).flatten()[0]) - temp_nm_val = float(np.asarray(temp_nm).flatten()[0]) - temp_mm_val = float(np.asarray(temp_mm).flatten()[0]) - - print(f" Temperature (μm coords): {temp_um_val:.6f} K") - print(f" Temperature (nm coords): {temp_nm_val:.6f} K") - print(f" Temperature (mm coords): {temp_mm_val:.6f} K") - - # Verify precision is maintained across unit systems - assert np.allclose(temp_um_val, temp_nm_val, rtol=1e-12) - assert np.allclose(temp_um_val, temp_mm_val, rtol=1e-12) - print(" ✓ High precision maintained across unit systems") - - -@pytest.mark.skip(reason="coord_units parameter not implemented - planned feature for evaluate()") -def test_astronomical_workflow_extreme_scales(): - """ - Test workflow with extreme astronomical scales. - - Demonstrates the system handles extreme scale differences gracefully. - """ - uw.reset_default_model() - model = uw.get_default_model() - - print("\n=== ASTRONOMICAL SCALE WORKFLOW ===") - - # Planetary scale problem - modeling planetary core - # Earth's core radius: ~3485 km - core_radius_km = 3485 - - # Set astronomical reference scales - model.set_reference_quantities( - characteristic_length=core_radius_km * uw.units.km, - plate_velocity=1 * uw.units.km / uw.units.year, # Geological velocity - mantle_temperature=5000 * uw.units.kelvin, # Core temperature - ) - - # Create mesh - mesh = uw.meshing.StructuredQuadBox( - elementRes=(6, 6), minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), qdegree=2 - ) - - # Test queries with extreme scale units - query_point_km = np.array([[1742.5, 1742.5]], dtype=np.float64) # Core center - query_point_au = query_point_km / 149597870.7 # Astronomical units - query_point_m = query_point_km * 1000 # Meters - - # Simple field - temperature = uw.discretisation.MeshVariable("T", mesh, 1) - with uw.synchronised_array_update(): - temperature.array[:, 0, 0] = 4000 + 1000 * np.sqrt( - mesh.X.coords[:, 0] ** 2 + mesh.X.coords[:, 1] ** 2 - ) # Radial temperature - - # Query using extreme scale units with explicit coordinate units - temp_km = uw.function.evaluate(temperature.sym, query_point_km, coord_units="km") - temp_au = uw.function.evaluate(temperature.sym, query_point_au, coord_units="astronomical_unit") - temp_m = uw.function.evaluate(temperature.sym, query_point_m, coord_units="m") - - # Extract scalar values from UnitAwareArray (already numpy arrays) - temp_km_val = float(np.asarray(temp_km).flatten()[0]) - temp_au_val = float(np.asarray(temp_au).flatten()[0]) - temp_m_val = float(np.asarray(temp_m).flatten()[0]) - - print(f"Extreme scale test at planetary core center:") - print(f" Temperature (km coords): {temp_km_val:.2f} K") - print(f" Temperature (AU coords): {temp_au_val:.2f} K") - print(f" Temperature (m coords): {temp_m_val:.2f} K") - - # Verify consistency across extreme scales - compare the scalar values - assert np.allclose(temp_km_val, temp_au_val, rtol=1e-10) - assert np.allclose(temp_km_val, temp_m_val, rtol=1e-10) - print(" ✓ Extreme scale differences handled correctly") - - -if __name__ == "__main__": - # Run comprehensive workflow tests - test_geophysics_workflow_mixed_units() - test_engineering_workflow_precision_units() - test_astronomical_workflow_extreme_scales() - print("\n🎉 ALL WORKFLOW TESTS PASSED!") - print("✅ Universal units system provides seamless 'flip units around' capability") diff --git a/tests/test_0804_backward_compatibility_units.py b/tests/test_0804_backward_compatibility_units.py deleted file mode 100644 index c90eed491..000000000 --- a/tests/test_0804_backward_compatibility_units.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python3 -"""Test that original evaluate behavior is preserved.""" - -import os -import pytest - -# Units system tests - intermediate complexity -pytestmark = pytest.mark.level_2 -import numpy as np - -# DISABLE SYMPY CACHE -os.environ["SYMPY_USE_CACHE"] = "no" - -import underworld3 as uw - - -@pytest.mark.skip(reason="coord_units parameter not implemented - planned feature for evaluate()") -def test_original_behavior(): - """Test that evaluate behavior with and without scaling works correctly.""" - print("=== TESTING EVALUATE WITH SCALING ===") - - # Set up a simple test case - uw.reset_default_model() - model = uw.get_default_model() - - # Create mesh WITHOUT scaling (original behavior) - mesh = uw.meshing.StructuredQuadBox( - elementRes=(5, 5), minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), qdegree=2 - ) - - # Create a simple unitless field with values 1000-1500 - temperature = uw.discretisation.MeshVariable("T", mesh, 1) - - # Set field values directly (not using mesh.X which would introduce scaling issues) - with uw.synchronised_array_update(): - # Just set to fixed values: 1000 at corners, 1500 at center - # This avoids any coordinate-dependent initialization - temperature.array[:, 0, 0] = 1250.0 # Uniform field for simplicity - - # Test original behavior - coords in model units (0-1 range) - model_coords = np.array([[0.5, 0.5]], dtype=np.float64) - - print("Testing without scaling (model coordinates):") - print(f" Input coordinates: {model_coords}") - - # This should work exactly as before - result_original = uw.function.evaluate(temperature.sym, model_coords) - print(f" Result: {result_original.item():.1f}") - print(f" Expected: 1250.0 ✓") - - # Test that the result is reasonable - assert np.isclose(result_original.item(), 1250.0, rtol=1e-10) - - print("\nTesting with scaling (model coordinates):") - - # Now test with a scaled mesh but model coordinates - model.set_reference_quantities( - characteristic_length=1000 * uw.units.km, - plate_velocity=5 * uw.units.cm / uw.units.year, - mantle_temperature=1500 * uw.units.kelvin, - ) - - mesh_scaled = uw.meshing.StructuredQuadBox( - elementRes=(5, 5), minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), qdegree=2 - ) - - temp_scaled = uw.discretisation.MeshVariable("T", mesh_scaled, 1) - - # Set same uniform field value - with uw.synchronised_array_update(): - temp_scaled.array[:, 0, 0] = 1250.0 # Same uniform value - - # Evaluate at model coordinates (no coord_units specified) - result_scaled = uw.function.evaluate(temp_scaled.sym, model_coords) - - # Extract value from UWQuantity if needed - result_val = ( - result_scaled._pint_qty.magnitude.item() - if hasattr(result_scaled, "_pint_qty") - else result_scaled.item() - ) - print(f" Result with scaled mesh: {result_val:.1f}") - - # Should get the same result as before - model coordinates should work the same way - assert np.isclose(result_val, 1250.0, rtol=1e-10) - print(f" Expected: 1250.0 ✓") - - print("\nTesting new coord_units functionality:") - - # Now test new functionality - physical coordinates - physical_coords_km = np.array([[500, 500]], dtype=np.float64) # 500 km - physical_coords_m = np.array([[500000, 500000]], dtype=np.float64) # 500,000 m - - result_km = uw.function.evaluate(temp_scaled.sym, physical_coords_km, coord_units="km") - result_m = uw.function.evaluate(temp_scaled.sym, physical_coords_m, coord_units="m") - result_model = uw.function.evaluate(temp_scaled.sym, model_coords) # No units - - # Extract values from UWQuantity if needed - val_km = ( - result_km._pint_qty.magnitude.item() - if hasattr(result_km, "_pint_qty") - else result_km.item() - ) - val_m = ( - result_m._pint_qty.magnitude.item() if hasattr(result_m, "_pint_qty") else result_m.item() - ) - val_model = ( - result_model._pint_qty.magnitude.item() - if hasattr(result_model, "_pint_qty") - else result_model.item() - ) - - print(f" Result from 500 km coords: {val_km:.1f}") - print(f" Result from 500,000 m coords: {val_m:.1f}") - print(f" Result from 0.5 model coords: {val_model:.1f}") - - # All should be identical - assert np.allclose([val_km, val_m, val_model], val_model, rtol=1e-10) - print(" All coordinate systems give identical results ✓") - - print("\n✅ BACKWARD COMPATIBILITY CONFIRMED") - print("✅ NEW FUNCTIONALITY WORKING") - print("✅ Original behavior preserved") - - -if __name__ == "__main__": - test_original_behavior() diff --git a/tests/test_0811_evaluate_unit_coords.py b/tests/test_0811_evaluate_unit_coords.py deleted file mode 100644 index 43b24dc8c..000000000 --- a/tests/test_0811_evaluate_unit_coords.py +++ /dev/null @@ -1,214 +0,0 @@ -""" -Test unit-aware coordinate handling in uw.function.evaluate() - -This test validates that evaluate() and global_evaluate() accept unit-aware -coordinates (UWQuantity and Pint Quantity objects) and automatically convert -them to SI base units for evaluation. -""" - -import pytest - -# Units system tests - intermediate complexity -pytestmark = pytest.mark.level_2 -import underworld3 as uw -import numpy as np - - -def test_evaluate_with_numpy_array(): - """Test backward compatibility: evaluate accepts plain numpy arrays.""" - mesh = uw.meshing.UnstructuredSimplexBox( - minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), cellSize=0.2, regular=False - ) - - T = uw.discretisation.MeshVariable("T", mesh, 1, degree=2) - T.array[:, 0, 0] = T.coords[:, 0] # Temperature increases with x - - # Plain numpy array (traditional usage) - coords = np.array([[0.5, 0.5], [0.25, 0.75]]) - result = uw.function.evaluate(T.sym, coords) - - assert result.shape == (2, 1, 1) - assert abs(result[0, 0, 0] - 0.5) < 0.01 # T ≈ x at (0.5, 0.5) - assert abs(result[1, 0, 0] - 0.25) < 0.01 # T ≈ x at (0.25, 0.75) - - -@pytest.mark.skip( - reason="evaluate() with list of UWQuantity coords not implemented - planned feature" -) -def test_evaluate_with_uwquantity_coords(): - """Test evaluate() with UWQuantity coordinate objects.""" - mesh = uw.meshing.UnstructuredSimplexBox( - minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), cellSize=0.2, regular=False - ) - - T = uw.discretisation.MeshVariable("T", mesh, 1, degree=2) - T.array[:, 0, 0] = T.coords[:, 0] # Temperature increases with x - - # UWQuantity coordinates (in meters) - x = uw.quantity(0.5, "m") - y = uw.quantity(0.5, "m") - - # List of tuples format - coords = [(x, y)] - result = uw.function.evaluate(T.sym, coords) - - assert result.shape == (1, 1, 1) - assert abs(result[0, 0, 0] - 0.5) < 0.01 - - -@pytest.mark.skip( - reason="evaluate() with list of UWQuantity coords not implemented - planned feature" -) -def test_evaluate_with_pint_quantity_coords(): - """Test evaluate() with direct Pint Quantity objects.""" - mesh = uw.meshing.UnstructuredSimplexBox( - minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), cellSize=0.2, regular=False - ) - - T = uw.discretisation.MeshVariable("T", mesh, 1, degree=2) - T.array[:, 0, 0] = T.coords[:, 0] # Temperature increases with x - - # Direct Pint quantities (from arithmetic operations) - x = uw.quantity(0.5, "m") - y = uw.quantity(0.25, "m") - - # Arithmetic creates Pint Quantity objects - x_center = x # 0.5 m - y_center = y * 2 # 0.5 m - - coords = [(x_center, y_center)] - result = uw.function.evaluate(T.sym, coords) - - assert result.shape == (1, 1, 1) - assert abs(result[0, 0, 0] - 0.5) < 0.01 - - -@pytest.mark.skip( - reason="evaluate() with list of UWQuantity coords not implemented - planned feature" -) -def test_evaluate_with_mixed_units(): - """Test evaluate() with coordinates in different units.""" - mesh = uw.meshing.UnstructuredSimplexBox( - minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), cellSize=0.2, regular=False - ) - - T = uw.discretisation.MeshVariable("T", mesh, 1, degree=2) - T.array[:, 0, 0] = T.coords[:, 0] # Temperature increases with x - - # Mixed units: meters and centimeters - coords = [ - (uw.quantity(0.5, "m"), uw.quantity(50, "cm")), # (0.5, 0.5) in meters - (uw.quantity(25, "cm"), uw.quantity(0.75, "m")), # (0.25, 0.75) in meters - ] - - result = uw.function.evaluate(T.sym, coords) - - assert result.shape == (2, 1, 1) - assert abs(result[0, 0, 0] - 0.5) < 0.01 - assert abs(result[1, 0, 0] - 0.25) < 0.01 - - -@pytest.mark.skip( - reason="evaluate() with list of UWQuantity coords not implemented - planned feature" -) -def test_evaluate_with_single_point_list(): - """Test evaluate() with single point as flat list [x, y].""" - mesh = uw.meshing.UnstructuredSimplexBox( - minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), cellSize=0.2, regular=False - ) - - T = uw.discretisation.MeshVariable("T", mesh, 1, degree=2) - T.array[:, 0, 0] = T.coords[:, 0] # Temperature increases with x - - # Single point as flat list - x = uw.quantity(0.5, "m") - y = uw.quantity(0.5, "m") - coords = [x, y] - - result = uw.function.evaluate(T.sym, coords) - - assert result.shape == (1, 1, 1) - assert abs(result[0, 0, 0] - 0.5) < 0.01 - - -@pytest.mark.skip( - reason="evaluate() with list of UWQuantity coords not implemented - planned feature" -) -def test_evaluate_unit_conversion_accuracy(): - """Test that unit conversion is accurate for geological units.""" - mesh = uw.meshing.UnstructuredSimplexBox( - minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), cellSize=0.2, regular=False - ) - - # Create a field with known values - T = uw.discretisation.MeshVariable("T", mesh, 1, degree=2) - T.array[:, 0, 0] = T.coords[:, 0] * 1000 # Temperature = 1000 * x - - # Evaluate at 50 cm = 0.5 m - coords = [(uw.quantity(50, "cm"), uw.quantity(0.5, "m"))] - result = uw.function.evaluate(T.sym, coords) - - # Expected: T = 1000 * 0.5 = 500 - assert abs(result[0, 0, 0] - 500.0) < 10.0 # Allow some interpolation error - - -@pytest.mark.skip( - reason="evaluate() with list of UWQuantity coords not implemented - planned feature" -) -def test_evaluate_mixed_numeric_and_units(): - """Test evaluate() with mixed dimensionless and unit-aware coords.""" - mesh = uw.meshing.UnstructuredSimplexBox( - minCoords=(0.0, 0.0), maxCoords=(1.0, 1.0), cellSize=0.2, regular=False - ) - - T = uw.discretisation.MeshVariable("T", mesh, 1, degree=2) - T.array[:, 0, 0] = T.coords[:, 0] - - # Mix of dimensionless and unit-aware - coords = [ - (0.5, uw.quantity(50, "cm")), # First coord dimensionless, second with units - (uw.quantity(0.25, "m"), 0.75), # First with units, second dimensionless - ] - - result = uw.function.evaluate(T.sym, coords) - - assert result.shape == (2, 1, 1) - assert abs(result[0, 0, 0] - 0.5) < 0.01 - assert abs(result[1, 0, 0] - 0.25) < 0.01 - - -if __name__ == "__main__": - # Run tests individually for debugging - print("Running evaluate() unit-aware coordinate tests...") - - print("\n1. Testing numpy array (backward compatibility)...") - test_evaluate_with_numpy_array() - print(" ✓ Passed") - - print("\n2. Testing UWQuantity coordinates...") - test_evaluate_with_uwquantity_coords() - print(" ✓ Passed") - - print("\n3. Testing Pint Quantity coordinates...") - test_evaluate_with_pint_quantity_coords() - print(" ✓ Passed") - - print("\n4. Testing mixed units...") - test_evaluate_with_mixed_units() - print(" ✓ Passed") - - print("\n5. Testing single point as list...") - test_evaluate_with_single_point_list() - print(" ✓ Passed") - - print("\n6. Testing unit conversion accuracy...") - test_evaluate_unit_conversion_accuracy() - print(" ✓ Passed") - - print("\n7. Testing mixed numeric and unit-aware coords...") - test_evaluate_mixed_numeric_and_units() - print(" ✓ Passed") - - print("\n" + "=" * 60) - print("All evaluate() unit-aware coordinate tests passed! ✅") - print("=" * 60) diff --git a/tests/test_0812_poisson_with_units.py b/tests/test_0812_poisson_with_units.py index eadc091ee..925cef147 100644 --- a/tests/test_0812_poisson_with_units.py +++ b/tests/test_0812_poisson_with_units.py @@ -1,260 +1,125 @@ -""" -Test Poisson solver with unit-aware boundary conditions. - -This test replicates the exact workflow from Notebook 13 to ensure -unit-aware BCs produce correct results, not just that they are accepted. - -STATUS (2025-11-15): -- Tests pass BCs correctly but fail at uw.function.evaluate() -- Error: Cannot non-dimensionalise list of UWQuantity coordinates -- Issue: evaluate(expr, [(x_qty, y_qty)]) doesn't handle UWQuantity in list format -- Need to convert coordinates to proper format (numpy array or extract magnitudes) -- Marked as Tier C until coordinate formatting is fixed +"""Poisson solver with unit-aware boundary conditions (Notebook 13 workflow). + +Solve del^2 T = 0 on a box with quantity-valued Dirichlet BCs and check the +solution: constant gradient dT/dy = Delta_T / L_y and the BC values honoured +at the boundaries. + +Coordinate note: ``uw.function.evaluate()`` takes coordinates as plain +arrays in model (non-dimensional) units. Quantity-valued coordinate lists +(``[(x_qty, y_qty)]``) are NOT supported — that proposed extension was +declared unsupported (LE-08 / BF-12, units-family ruling D7, 2026-07-06). +Physical locations are converted here with ``uw.scaling.non_dimensionalise``, +and expectations are stated in the same non-dimensional frame so the test is +independent of the model's internal scale choices. """ +import numpy as np import pytest -# Physics solver tests - full solver execution -pytestmark = pytest.mark.level_3 import underworld3 as uw -import numpy as np +pytestmark = [pytest.mark.level_2, pytest.mark.tier_b] -@pytest.mark.level_2 # Intermediate - Poisson solver with units -@pytest.mark.tier_c # Experimental - test has coordinate formatting issues -@pytest.mark.skip(reason="BUG: evaluate() cannot handle UWQuantity coordinates in [(x, y)] format. Fix coordinate handling, then remove skip.") -def test_poisson_linear_gradient_with_pint_quantities(): - """ - Test that Poisson solver with Pint Quantity BCs produces correct gradient. - This replicates Notebook 13: solve ∇²T = 0 with linear BC, - expecting constant gradient ∂T/∂y = ΔT/Ly. - """ - uw.reset_default_model() +def _nd(qty): + """Model-frame (non-dimensional) value of a quantity.""" + return float(uw.scaling.non_dimensionalise(qty)) - # Set reference quantities for units support - model = uw.get_default_model() - model.set_reference_quantities( - domain_depth=uw.quantity(500, "m"), # Matches L_y - material_density=uw.quantity(3300, "kg/m**3"), # For complete dimensional analysis - ) - - # Physical parameters using Pint Quantities (like Notebook 13) - L_x = 1000 * uw.units("m") - L_y = 500 * uw.units("m") - T_bottom = 300 * uw.units("K") - T_top = 1600 * uw.units("K") - Delta_T = T_top - T_bottom - - # Expected gradient - expected_gradient = (Delta_T / L_y).magnitude # Should be 2.6 K/m - # Create mesh - USING STRUCTURED MESH (Unstructured has gradient projection bugs) +def _setup_and_solve(L_x, L_y, T_bottom, T_top): + """Build the mesh, solve the Poisson problem with quantity BCs, and + return (T, gradT) after a gradient projection.""" mesh = uw.meshing.StructuredQuadBox( - elementRes=(10, 10), minCoords=(0.0, 0.0), maxCoords=(L_x, L_y), units="metre" + elementRes=(10, 10), minCoords=(0.0, 0.0), maxCoords=(L_x, L_y) ) - # Create temperature variable T = uw.discretisation.MeshVariable("T", mesh, 1, degree=2, units="kelvin") - - # CRITICAL: Create gradient variable BEFORE solving - # (creating it after causes mesh state corruption) + # Create the gradient variable BEFORE solving (creating it after + # corrupts the DM state — the "Batman" regression, test_0813). gradT = uw.discretisation.MeshVariable("gradT", mesh, mesh.dim, degree=1) - # Set up Poisson solver poisson = uw.systems.Poisson(mesh, u_Field=T) poisson.constitutive_model = uw.constitutive_models.DiffusionModel poisson.constitutive_model.Parameters.diffusivity = 1 poisson.f = 0.0 - # Apply BCs with Pint Quantities (THE KEY TEST) + # Quantity-valued BCs — the point of this test poisson.add_dirichlet_bc(T_bottom, "Bottom") poisson.add_dirichlet_bc(T_top, "Top") - # Solve poisson.solve() assert poisson.snes.getConvergedReason() > 0, "Solver did not converge" - # Compute gradient via projection (variable already created) - x, y = mesh.X gradient_proj = uw.systems.Vector_Projection(mesh, gradT) gradient_proj.uw_function = mesh.vector.gradient(T.sym) gradient_proj.solve() - # Evaluate at center - x_center = L_x / 2 - y_center = L_y / 2 - grad = uw.function.evaluate(gradT.sym, [(x_center, y_center)]) - - dT_dx = grad[0, 0, 0] - dT_dy = grad[0, 0, 1] + return T, gradT - print(f"\nPoisson with Pint Quantity BCs:") - print(f" Expected gradient: {expected_gradient:.3f} K/m") - print(f" Computed ∂T/∂x: {dT_dx:.6f} K/m (expected: 0)") - print(f" Computed ∂T/∂y: {dT_dy:.6f} K/m (expected: {expected_gradient:.3f})") - # Check results - assert abs(dT_dx) < 0.1, f"∂T/∂x should be ~0, got {dT_dx}" - assert ( - abs(dT_dy - expected_gradient) < 0.1 - ), f"∂T/∂y should be {expected_gradient:.3f}, got {dT_dy:.3f}" - - -@pytest.mark.level_2 # Intermediate - Poisson solver with units -@pytest.mark.tier_c # Experimental - test has coordinate formatting issues -@pytest.mark.skip(reason="BUG: evaluate() cannot handle UWQuantity coordinates in [(x, y)] format. Fix coordinate handling, then remove skip.") -def test_poisson_linear_gradient_with_uwquantity(): - """ - Same test but using uw.quantity() instead of uw.units(). - """ +def _check_linear_solution(L_x, L_y, T_bottom, T_top): + """Common assertions, all in the model (non-dimensional) frame.""" uw.reset_default_model() - - # Set reference quantities for units support model = uw.get_default_model() model.set_reference_quantities( domain_depth=uw.quantity(500, "m"), # Matches L_y - material_density=uw.quantity(3300, "kg/m**3"), # For complete dimensional analysis + material_density=uw.quantity(3300, "kg/m**3"), ) - # Physical parameters using UWQuantity - L_x = uw.quantity(1000, "m") - L_y = uw.quantity(500, "m") - T_bottom = uw.quantity(300, "K") - T_top = uw.quantity(1600, "K") - Delta_T = T_top - T_bottom + T, gradT = _setup_and_solve(L_x, L_y, T_bottom, T_top) - # Expected gradient - expected_gradient = (Delta_T / L_y).value + Lx_nd, Ly_nd = _nd(L_x), _nd(L_y) + Tb_nd, Tt_nd = _nd(T_bottom), _nd(T_top) - # Create mesh - USING STRUCTURED MESH (Unstructured has gradient projection bugs) - mesh = uw.meshing.StructuredQuadBox( - elementRes=(10, 10), minCoords=(0.0, 0.0), maxCoords=(L_x, L_y), units="metre" + # BC values honoured at the boundaries. Evaluate a whisker inside the + # domain — point-location exactly ON the boundary is unreliable. + eps = 1e-6 * Ly_nd + T_at_bottom = uw.function.evaluate( + T.sym, np.array([[Lx_nd / 2, eps]], dtype=np.float64) ) - - # Create temperature variable - T = uw.discretisation.MeshVariable("T", mesh, 1, degree=2, units="kelvin") - - # CRITICAL: Create gradient variable BEFORE solving - gradT = uw.discretisation.MeshVariable("gradT", mesh, mesh.dim, degree=1) - - # Set up Poisson solver - poisson = uw.systems.Poisson(mesh, u_Field=T) - poisson.constitutive_model = uw.constitutive_models.DiffusionModel - poisson.constitutive_model.Parameters.diffusivity = 1 - poisson.f = 0.0 - - # Apply BCs with UWQuantity - poisson.add_dirichlet_bc(T_bottom, "Bottom") - poisson.add_dirichlet_bc(T_top, "Top") - - # Solve - poisson.solve() - assert poisson.snes.getConvergedReason() > 0 - - # Compute gradient (variable already created) - x, y = mesh.X - gradient_proj = uw.systems.Vector_Projection(mesh, gradT) - gradient_proj.uw_function = mesh.vector.gradient(T.sym) - gradient_proj.solve() - - # Evaluate at center - x_center = L_x / 2 - y_center = L_y / 2 - grad = uw.function.evaluate(gradT.sym, [(x_center, y_center)]) - - dT_dx = grad[0, 0, 0] - dT_dy = grad[0, 0, 1] - - print(f"\nPoisson with UWQuantity BCs:") - print(f" Expected gradient: {expected_gradient:.3f} K/m") - print(f" Computed ∂T/∂x: {dT_dx:.6f} K/m") - print(f" Computed ∂T/∂y: {dT_dy:.6f} K/m") - - # Check results - assert abs(dT_dx) < 0.1, f"∂T/∂x should be ~0, got {dT_dx}" - assert ( - abs(dT_dy - expected_gradient) < 0.1 - ), f"∂T/∂y should be {expected_gradient:.3f}, got {dT_dy:.3f}" - - -@pytest.mark.level_2 # Intermediate - Poisson solver with units -@pytest.mark.tier_c # Experimental - test has coordinate formatting issues -@pytest.mark.skip(reason="BUG: evaluate() cannot handle UWQuantity coordinates in [(x, y)] format. Fix coordinate handling, then remove skip.") -def test_poisson_check_bc_values(): - """ - Verify that the BC values are actually being set correctly in the solution. - """ - uw.reset_default_model() - - # Set reference quantities for units support - model = uw.get_default_model() - model.set_reference_quantities( - domain_depth=uw.quantity(500, "m"), # Matches L_y - material_density=uw.quantity(3300, "kg/m**3"), # For complete dimensional analysis + T_at_top = uw.function.evaluate( + T.sym, np.array([[Lx_nd / 2, Ly_nd - eps]], dtype=np.float64) ) - - L_x = 1000 * uw.units("m") - L_y = 500 * uw.units("m") - T_bottom = 300 * uw.units("K") - T_top = 1600 * uw.units("K") - - # Create mesh - USING STRUCTURED MESH (Unstructured has gradient projection bugs) - mesh = uw.meshing.StructuredQuadBox( - elementRes=(10, 10), minCoords=(0.0, 0.0), maxCoords=(L_x, L_y), units="metre" + span = abs(Tt_nd - Tb_nd) + assert abs(float(T_at_bottom[0, 0, 0]) - Tb_nd) < 1e-3 * span, ( + f"Bottom BC not applied: {float(T_at_bottom[0, 0, 0])} != {Tb_nd}" + ) + assert abs(float(T_at_top[0, 0, 0]) - Tt_nd) < 1e-3 * span, ( + f"Top BC not applied: {float(T_at_top[0, 0, 0])} != {Tt_nd}" ) - T = uw.discretisation.MeshVariable("T", mesh, 1, degree=2, units="kelvin") - - poisson = uw.systems.Poisson(mesh, u_Field=T) - poisson.constitutive_model = uw.constitutive_models.DiffusionModel - poisson.constitutive_model.Parameters.diffusivity = 1 - poisson.f = 0.0 - - poisson.add_dirichlet_bc(T_bottom, "Bottom") - poisson.add_dirichlet_bc(T_top, "Top") - poisson.solve() - - # Check boundary values - x, y = mesh.X - - # Evaluate at bottom boundary - bottom_points = [(L_x / 2, uw.quantity(0, "m"))] - T_at_bottom = uw.function.evaluate(T.sym, bottom_points) - - # Evaluate at top boundary - top_points = [(L_x / 2, L_y)] - T_at_top = uw.function.evaluate(T.sym, top_points) - - print(f"\nBoundary value check:") - print(f" T at bottom: {T_at_bottom[0,0,0]:.1f} K (expected: 300)") - print(f" T at top: {T_at_top[0,0,0]:.1f} K (expected: 1600)") - - assert ( - abs(T_at_bottom[0, 0, 0] - 300) < 1.0 - ), f"Bottom BC not applied correctly: {T_at_bottom[0,0,0]} != 300" - assert ( - abs(T_at_top[0, 0, 0] - 1600) < 1.0 - ), f"Top BC not applied correctly: {T_at_top[0,0,0]} != 1600" - + # Constant gradient dT/dy = Delta_T / L_y (model frame); dT/dx = 0 + expected_gradient = (Tt_nd - Tb_nd) / Ly_nd + grad = uw.function.evaluate( + gradT.sym, np.array([[Lx_nd / 2, Ly_nd / 2]], dtype=np.float64) + ) + dT_dx = float(grad[0, 0, 0]) + dT_dy = float(grad[0, 0, 1]) -if __name__ == "__main__": - print("=" * 70) - print("Testing Poisson solver with unit-aware BCs (Notebook 13 replication)") - print("=" * 70) + assert abs(dT_dx) < 1e-3 * abs(expected_gradient), ( + f"dT/dx should be ~0, got {dT_dx}" + ) + assert abs(dT_dy - expected_gradient) < 1e-3 * abs(expected_gradient), ( + f"dT/dy should be {expected_gradient}, got {dT_dy}" + ) - print("\n1. Testing with Pint Quantities (uw.units())...") - test_poisson_linear_gradient_with_pint_quantities() - print(" ✓ Passed") - print("\n2. Testing with UWQuantity (uw.quantity())...") - test_poisson_linear_gradient_with_uwquantity() - print(" ✓ Passed") +def test_poisson_linear_gradient_with_pint_quantities(): + """Pint Quantity BCs (``value * uw.units(...)``) produce the correct + linear solution.""" + _check_linear_solution( + L_x=1000 * uw.units("m"), + L_y=500 * uw.units("m"), + T_bottom=300 * uw.units("K"), + T_top=1600 * uw.units("K"), + ) - print("\n3. Testing BC value application...") - test_poisson_check_bc_values() - print(" ✓ Passed") - print("\n" + "=" * 70) - print("All Poisson unit tests passed! ✅") - print("=" * 70) +def test_poisson_linear_gradient_with_uwquantity(): + """Same problem with ``uw.quantity()`` BCs.""" + _check_linear_solution( + L_x=uw.quantity(1000, "m"), + L_y=uw.quantity(500, "m"), + T_bottom=uw.quantity(300, "K"), + T_top=uw.quantity(1600, "K"), + ) diff --git a/tests/test_1011_bodyforce_units.py b/tests/test_1011_bodyforce_units.py index c512d78a8..b1b67c1f2 100644 --- a/tests/test_1011_bodyforce_units.py +++ b/tests/test_1011_bodyforce_units.py @@ -27,7 +27,7 @@ def test_bodyforce_accepts_uwquantity_buoyancy(): temperature_difference=uw.quantity(1000, "K"), ) mesh = uw.meshing.StructuredQuadBox( - elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(1000.0, 1000.0), units="km" + elementRes=(4, 4), minCoords=(0.0, 0.0), maxCoords=(1000.0, 1000.0) ) v = uw.discretisation.MeshVariable("v", mesh, mesh.dim, degree=2) p = uw.discretisation.MeshVariable("p", mesh, 1, degree=1) From 0ea71b8fa008eb70aaeb4551e826a75176db31db Mon Sep 17 00:00:00 2001 From: lmoresi Date: Sun, 5 Jul 2026 17:46:57 +0100 Subject: [PATCH 3/7] chore(docs): move design-directory experiment artifacts into experiments/ subdirs; delete trace logs (WA-27 / DOC-06, ruling D16) The design-doc directory carried 35 tracked experiment artifacts beside the ~36 genuine design documents. Per maintainer ruling D16 (2026-07-06): - git mv the 23 exp-integrator experiment scripts (_exp_*, _phase_*, _plot_*) and 5 result PNGs to design/experiments/exp-integrator/ (they are provenance for EXPONENTIAL_VE_INTEGRATOR.md, which now carries a pointer note and updated explicit paths). - Relocate the _repro_dminterp_multifield_bug.py bug reproducer to design/experiments/dminterp-multifield/ (it is a repro, not a design artifact). - Delete the 6 .trace.txt raw solver logs (reproducible from the scripts, preserved in git history; nothing referenced them). - Self-referencing usage paths inside the moved scripts updated. Underworld development team with AI support from Claude Code --- docs/developer/design/EXPONENTIAL_VE_INTEGRATOR.md | 13 ++++++++++--- .../_repro_dminterp_multifield_bug.py | 2 +- .../_exp_integrator_phase_b_benches.py | 2 +- .../_exp_integrator_phase_b_killer.py | 2 +- .../_exp_integrator_phase_b_ti_iso.py | 2 +- .../_exp_integrator_phase_b_validate.py | 2 +- .../exp-integrator/_exp_integrator_phase_d_split.py | 2 +- .../_phase_b_bdf_vs_etd_at_tight_yield.py | 2 +- .../exp-integrator/_phase_b_etd1_at_tight_yield.py | 2 +- .../exp-integrator/_phase_d_killer_split.py | 2 +- .../exp-integrator/_phase_e_killer_hybrid.py | 2 +- .../exp-integrator/_phase_f_predictor_corrector.py | 2 +- .../exp-integrator/_plot_phase_b_bdf_vs_etd.py | 2 +- .../exp-integrator/_plot_phase_b_fields.py | 2 +- .../exp-integrator/_plot_phase_b_pyvista.py | 4 ++-- .../exp-integrator/_plot_phase_b_results.py | 2 +- .../exp-integrator/_plot_phase_d_pyvista_split.py | 2 +- 17 files changed, 27 insertions(+), 20 deletions(-) diff --git a/docs/developer/design/EXPONENTIAL_VE_INTEGRATOR.md b/docs/developer/design/EXPONENTIAL_VE_INTEGRATOR.md index f9dfe42fd..4441e81d9 100644 --- a/docs/developer/design/EXPONENTIAL_VE_INTEGRATOR.md +++ b/docs/developer/design/EXPONENTIAL_VE_INTEGRATOR.md @@ -10,6 +10,13 @@ **Branch**: `feature/exp-integrator-investigation` +**Provenance artifacts**: the experiment scripts (`_exp_integrator_*.py`, +`_phase_*.py`, `_plot_phase_*.py`, `_exp_jury_rig_minimal.py`) and result +images (`exp_integrator_*.png`) cited throughout this document live in +`experiments/exp-integrator/` (moved from this directory 2026-07, DOC-06). +The raw `.trace.txt` solver logs were deleted — they are reproducible from +the scripts and preserved in git history. + **API (production)**: - `ViscoElasticPlasticFlowModel(unknowns, integrator='etd', order=1)` — ETD-1 (first-order). **Default-recommended for new code** — BDF-1 stability + analytical exp factor for the linear-relaxation part. - `TransverseIsotropicVEPFlowModel(unknowns, integrator='etd', order=1)` — same, TI variant. @@ -215,7 +222,7 @@ Centre-probe metrics (apples-to-apples with BDF-1 production), ETD-2 vs BDF-1: ETD-2 **is tighter than BDF-1 production on every probe**. BDF-2 (the higher-order method ETD-2 replaces) blows up to 10⁵-10⁹ on every yield-active combo (τ_y=0.15) — confirming the structural argument empirically. -Runner: `docs/developer/design/_exp_integrator_phase_b_killer.py`. +Runner: `docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_killer.py`. --- @@ -383,7 +390,7 @@ The Phase D and Phase E artefacts stay on the branch as instructive failures of | **1.00** | **1.0e-1** | 3.5e-1 | 3.5e-1 | | **2.00** | **5.7e-2** | 3.4e-1 | 3.4e-1 | -Exp shows clean second-order slope at small Δt and stays accurate at Δt ≥ τ where both BDFs collapse to near-zero output. Figure: `exp_integrator_phase_a.png`. +Exp shows clean second-order slope at small Δt and stays accurate at Δt ≥ τ where both BDFs collapse to near-zero output. Figure: `experiments/exp-integrator/exp_integrator_phase_a.png`. ### Phase B (VEP, large Δt, square wave, variable-Δt) — DONE @@ -397,7 +404,7 @@ Exp shows clean second-order slope at small Δt and stays accurate at Δt ≥ τ - **Variable-Δt around BC flips** (correctly schedule, with fine-zone clamp): improvement of 11–19% in max error for both VE and VEP, both Exp and BDF-1. The exp's plateau-period exactness shows clearly as the per-step error drops to near machine precision once the BC discontinuity is well-resolved. -Figures: `exp_integrator_phase_b_yield.png`, `exp_integrator_phase_b_largedt.png`, `exp_integrator_phase_b_square.png`, `exp_integrator_phase_b_vardt.png`. +Figures (in `experiments/exp-integrator/`): `exp_integrator_phase_b_yield.png`, `exp_integrator_phase_b_largedt.png`, `exp_integrator_phase_b_square.png`, `exp_integrator_phase_b_vardt.png`. ### Phase B UW3 jury-rig — partial (propagation snag identified) diff --git a/docs/developer/design/experiments/dminterp-multifield/_repro_dminterp_multifield_bug.py b/docs/developer/design/experiments/dminterp-multifield/_repro_dminterp_multifield_bug.py index 317dfa011..6600da964 100644 --- a/docs/developer/design/experiments/dminterp-multifield/_repro_dminterp_multifield_bug.py +++ b/docs/developer/design/experiments/dminterp-multifield/_repro_dminterp_multifield_bug.py @@ -20,7 +20,7 @@ Usage: pixi run -e amr-dev python -u \ - docs/developer/design/_repro_dminterp_multifield_bug.py + docs/developer/design/experiments/dminterp-multifield/_repro_dminterp_multifield_bug.py """ import numpy as np diff --git a/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_benches.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_benches.py index 49d488e34..1e95798e7 100644 --- a/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_benches.py +++ b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_benches.py @@ -13,7 +13,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_exp_integrator_phase_b_benches.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_benches.py """ from __future__ import annotations diff --git a/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_killer.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_killer.py index eebf48227..617f407f7 100644 --- a/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_killer.py +++ b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_killer.py @@ -16,7 +16,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_exp_integrator_phase_b_killer.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_killer.py """ from __future__ import annotations diff --git a/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_ti_iso.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_ti_iso.py index af0f42ff9..c5cbc4c0b 100644 --- a/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_ti_iso.py +++ b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_ti_iso.py @@ -15,7 +15,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_exp_integrator_phase_b_ti_iso.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_ti_iso.py """ import time diff --git a/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_validate.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_validate.py index b77c54500..4eec76f66 100644 --- a/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_validate.py +++ b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_validate.py @@ -10,7 +10,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_exp_integrator_phase_b_validate.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_b_validate.py """ import time diff --git a/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_d_split.py b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_d_split.py index 7d7eadf10..8e795240c 100644 --- a/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_d_split.py +++ b/docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_d_split.py @@ -26,7 +26,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_exp_integrator_phase_d_split.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_exp_integrator_phase_d_split.py """ import os diff --git a/docs/developer/design/experiments/exp-integrator/_phase_b_bdf_vs_etd_at_tight_yield.py b/docs/developer/design/experiments/exp-integrator/_phase_b_bdf_vs_etd_at_tight_yield.py index f0d2fef7d..5ef8af0e6 100644 --- a/docs/developer/design/experiments/exp-integrator/_phase_b_bdf_vs_etd_at_tight_yield.py +++ b/docs/developer/design/experiments/exp-integrator/_phase_b_bdf_vs_etd_at_tight_yield.py @@ -12,7 +12,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_phase_b_bdf_vs_etd_at_tight_yield.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_phase_b_bdf_vs_etd_at_tight_yield.py """ import os diff --git a/docs/developer/design/experiments/exp-integrator/_phase_b_etd1_at_tight_yield.py b/docs/developer/design/experiments/exp-integrator/_phase_b_etd1_at_tight_yield.py index 9efa414b1..65f881520 100644 --- a/docs/developer/design/experiments/exp-integrator/_phase_b_etd1_at_tight_yield.py +++ b/docs/developer/design/experiments/exp-integrator/_phase_b_etd1_at_tight_yield.py @@ -18,7 +18,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_phase_b_etd1_at_tight_yield.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_phase_b_etd1_at_tight_yield.py """ import os diff --git a/docs/developer/design/experiments/exp-integrator/_phase_d_killer_split.py b/docs/developer/design/experiments/exp-integrator/_phase_d_killer_split.py index f78d636c4..94fb8cbf9 100644 --- a/docs/developer/design/experiments/exp-integrator/_phase_d_killer_split.py +++ b/docs/developer/design/experiments/exp-integrator/_phase_d_killer_split.py @@ -10,7 +10,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_phase_d_killer_split.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_phase_d_killer_split.py """ import os diff --git a/docs/developer/design/experiments/exp-integrator/_phase_e_killer_hybrid.py b/docs/developer/design/experiments/exp-integrator/_phase_e_killer_hybrid.py index 6cc9a766a..a68611952 100644 --- a/docs/developer/design/experiments/exp-integrator/_phase_e_killer_hybrid.py +++ b/docs/developer/design/experiments/exp-integrator/_phase_e_killer_hybrid.py @@ -15,7 +15,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_phase_e_killer_hybrid.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_phase_e_killer_hybrid.py """ import os diff --git a/docs/developer/design/experiments/exp-integrator/_phase_f_predictor_corrector.py b/docs/developer/design/experiments/exp-integrator/_phase_f_predictor_corrector.py index 03225da89..4fe68f1e6 100644 --- a/docs/developer/design/experiments/exp-integrator/_phase_f_predictor_corrector.py +++ b/docs/developer/design/experiments/exp-integrator/_phase_f_predictor_corrector.py @@ -27,7 +27,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_phase_f_predictor_corrector.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_phase_f_predictor_corrector.py """ import os diff --git a/docs/developer/design/experiments/exp-integrator/_plot_phase_b_bdf_vs_etd.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_bdf_vs_etd.py index e74ce3a95..0ff287f76 100644 --- a/docs/developer/design/experiments/exp-integrator/_plot_phase_b_bdf_vs_etd.py +++ b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_bdf_vs_etd.py @@ -15,7 +15,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_plot_phase_b_bdf_vs_etd.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_plot_phase_b_bdf_vs_etd.py """ import os diff --git a/docs/developer/design/experiments/exp-integrator/_plot_phase_b_fields.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_fields.py index 0f7d7a95a..b77758e5c 100644 --- a/docs/developer/design/experiments/exp-integrator/_plot_phase_b_fields.py +++ b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_fields.py @@ -7,7 +7,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_plot_phase_b_fields.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_plot_phase_b_fields.py """ import os diff --git a/docs/developer/design/experiments/exp-integrator/_plot_phase_b_pyvista.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_pyvista.py index 8de371f2e..6fc271059 100644 --- a/docs/developer/design/experiments/exp-integrator/_plot_phase_b_pyvista.py +++ b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_pyvista.py @@ -11,12 +11,12 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_plot_phase_b_pyvista.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_plot_phase_b_pyvista.py Force re-capture:: rm output/phase_b_*.h5 output/phase_b_*.xdmf - pixi run -e amr-dev python -u docs/developer/design/_plot_phase_b_pyvista.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_plot_phase_b_pyvista.py """ import os diff --git a/docs/developer/design/experiments/exp-integrator/_plot_phase_b_results.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_results.py index fc1f7ab3a..05933d158 100644 --- a/docs/developer/design/experiments/exp-integrator/_plot_phase_b_results.py +++ b/docs/developer/design/experiments/exp-integrator/_plot_phase_b_results.py @@ -8,7 +8,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_plot_phase_b_results.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_plot_phase_b_results.py """ import os diff --git a/docs/developer/design/experiments/exp-integrator/_plot_phase_d_pyvista_split.py b/docs/developer/design/experiments/exp-integrator/_plot_phase_d_pyvista_split.py index d9d135b94..3e84b801b 100644 --- a/docs/developer/design/experiments/exp-integrator/_plot_phase_d_pyvista_split.py +++ b/docs/developer/design/experiments/exp-integrator/_plot_phase_d_pyvista_split.py @@ -11,7 +11,7 @@ Run:: - pixi run -e amr-dev python -u docs/developer/design/_plot_phase_d_pyvista_split.py + pixi run -e amr-dev python -u docs/developer/design/experiments/exp-integrator/_plot_phase_d_pyvista_split.py """ import os From c3cf228b9af560d467cb342bcdab916815f7f9c6 Mon Sep 17 00:00:00 2001 From: lmoresi Date: Sun, 5 Jul 2026 17:47:16 +0100 Subject: [PATCH 4/7] chore(deps): remove the unused pykdtree dependency (WA-26 / LE-22, ruling D13) pykdtree has not been the KDTree backend since the ckdtree (nanoflann) swap (commit 16cddf5): underworld3.kdtree re-exports ckdtree.KDTree and nothing imports pykdtree. Its OpenMP runtime is a fatal double-init crash hazard on macOS when loaded beside PETSc/numpy. Removed from pixi.toml; pixi.lock re-solved minimally (only the pykdtree entries drop, all environments). The kdtree.py module stays as the import point and its TODO(CLEANUP) is resolved; the stale binder-era comment in __init__.py is replaced with a pointer to the backend note. Underworld development team with AI support from Claude Code --- pixi.lock | 63 --------------------------------------- pixi.toml | 1 - src/underworld3/kdtree.py | 15 ++++------ 3 files changed, 5 insertions(+), 74 deletions(-) diff --git a/pixi.lock b/pixi.lock index 471215baa..3604d595d 100644 --- a/pixi.lock +++ b/pixi.lock @@ -247,7 +247,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.1-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -559,7 +558,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -1021,7 +1019,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.1-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -1518,7 +1515,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -2035,7 +2031,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.1-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -2532,7 +2527,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -2920,7 +2914,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -3229,7 +3222,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -3693,7 +3685,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -4190,7 +4181,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -4579,7 +4569,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -4891,7 +4880,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -5357,7 +5345,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -5857,7 +5844,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -6331,7 +6317,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.1-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -6765,7 +6750,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -7152,7 +7136,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -7483,7 +7466,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -7969,7 +7951,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -8484,7 +8465,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -8860,7 +8840,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -9227,7 +9206,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -9556,7 +9534,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -10041,7 +10018,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -10559,7 +10535,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -10967,7 +10942,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -11298,7 +11272,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -11784,7 +11757,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -12304,7 +12276,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -12801,7 +12772,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -13252,7 +13222,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -27966,38 +27935,6 @@ packages: - meshio>=4.3.2,<6 - numpy>=1.20.0 requires_python: '>=3.7' -- conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - sha256: 975ecf15f799242b59d4df4d38e02537865d4bd719df16589bb827b3df23bb07 - md5: 1af24b0eb99b1158c0d8c64a4d6c5d79 - depends: - - __glibc >=2.17,<3.0.a0 - - _openmp_mutex >=4.5 - - libgcc >=14 - - numpy >=1.23,<3 - - python >=3.12,<3.13.0a0 - - python_abi 3.12.* *_cp312 - license: LGPL-3.0-only - license_family: LGPL - purls: - - pkg:pypi/pykdtree?source=hash-mapping - size: 92151 - timestamp: 1762594909033 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - sha256: d9b54c705b37f5d94145d452a4398c21b24af6dffe16e4c9844a85c841c9c59f - md5: 47eb338f82a230ee1eb87991278ec9c0 - depends: - - __osx >=11.0 - - llvm-openmp >=19.1.7 - - numpy >=1.23,<3 - - python >=3.12,<3.13.0a0 - - python >=3.12,<3.13.0a0 *_cpython - - python_abi 3.12.* *_cp312 - license: LGPL-3.0-only - license_family: LGPL - purls: - - pkg:pypi/pykdtree?source=hash-mapping - size: 77602 - timestamp: 1762595314857 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda sha256: b015f430fe9ea2c53e14be13639f1b781f68deaa5ae74cd8c1d07720890cd02a md5: c65d7abdc9e60fd3af0ed852591adf1b diff --git a/pixi.toml b/pixi.toml index 8b98e4213..c0eafa97e 100644 --- a/pixi.toml +++ b/pixi.toml @@ -97,7 +97,6 @@ pytest-xdist = ">=3.8,<4" psutil = ">=5.9,<8" # leak-loop regression test in tests/test_0111_swarm_lifecycle.py # Mesh generation -pykdtree = ">=1.4,<2" meshio = ">=5.3,<6" # Utilities diff --git a/src/underworld3/kdtree.py b/src/underworld3/kdtree.py index 8ca3bd772..88193d42f 100644 --- a/src/underworld3/kdtree.py +++ b/src/underworld3/kdtree.py @@ -1,15 +1,10 @@ # KDTree module — re-exports the active backend's KDTree. # -# The active backend is ckdtree (set in __init__.py). pykdtree was the -# original backend but causes OpenMP double-init crashes on macOS when -# loaded alongside other OpenMP-using libraries (PETSc, numpy, etc.). -# See commit 16cddf5 "kdtree swap out (temporary)". -# -# TODO(CLEANUP): Remove pykdtree from dependencies entirely. It is not -# used and its OpenMP library causes fatal crashes on macOS when loaded -# alongside PETSc/numpy/scipy. The ckdtree (nanoflann) backend works -# reliably without OpenMP threading conflicts. -# See planning file: underworld.md (Active, 2026-02-13) +# The backend is ckdtree (nanoflann). The original pykdtree backend was +# removed from the dependency set entirely (2026-07, WA-26/LE-22): its +# OpenMP runtime caused fatal double-init crashes on macOS when loaded +# alongside other OpenMP-using libraries (PETSc, numpy, etc.). See +# commit 16cddf5 "kdtree swap out (temporary)" for the original swap. # # This module exists so that `import underworld3.kdtree` doesn't break # and any code referencing `underworld3.kdtree.KDTree` gets the working From 72ce9c22bd3fa03fa5026aa78be1af992ac68d2d Mon Sep 17 00:00:00 2001 From: lmoresi Date: Sun, 5 Jul 2026 17:47:34 +0100 Subject: [PATCH 5/7] chore(cleanup): loose-ends stale/delete verdicts for non-swarm, non-pyx files (WA-04/20/21/22/25, LE-09/18/19/20/23) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Executes the LOOSE-ENDS-AUDIT verdicts classified stale/delete: - ddt.py (LE-09 / WA-04): delete the dead 'if 0 and preserve_moments' blocks and the self.I integral they alone used; the documented preserve_moments parameter was a silent no-op and now raises NotImplementedError (regression test added in test_1053). - test_quantities_simplified.py (LE-18 / WA-20): delete — it imported a module that never existed. The uncovered multiplication-order cases are ported to test_0754 against the real uw.quantity API. - UnitAwareExpression-era placeholder skips (LE-19 / WA-21): delete the three empty pass-body skipped tests (test_0754:166,288; test_0756 coordinate_symbol_evaluation:164); the neighbouring genuine xfails stay. - test_0750_meshing_follow_metric (LE-20 / WA-22): delete the two xfail tests asserting elliptic-ma MA-mover capabilities the development merge deliberately dropped (surviving coverage: test_0760, test_0855; pointer note left). The third xfail (skip-threshold, #202) tracks a live reconciliation item and is kept. - ptest_0762:75 (refuted-appendix / WA-25): remove the stale skip — the hang it cited was issue #151, fixed 2026-04 (453e5063). The unskipped swarm round-trip passes at np2 and np4. - disk_snapshot.py (LE-23): correct the module docstring that still claimed only phase 1 existed; phases 2/3a/3b are implemented. - smoothing.py: no change — LE-24's verdict is that all its large comment blocks are physics/design prose, not commented-out code. Underworld development team with AI support from Claude Code --- src/underworld3/checkpoint/disk_snapshot.py | 13 +- src/underworld3/systems/ddt.py | 51 +-- .../ptest_0762_read_timestep_swarm_routed.py | 8 +- tests/test_0750_meshing_follow_metric.py | 44 +-- .../test_0754_arithmetic_closure_complete.py | 49 ++- .../test_0756_coordinate_symbol_evaluation.py | 13 - tests/test_1053_ddt_theta.py | 21 ++ tests/test_quantities_simplified.py | 332 ------------------ 8 files changed, 79 insertions(+), 452 deletions(-) delete mode 100644 tests/test_quantities_simplified.py diff --git a/src/underworld3/checkpoint/disk_snapshot.py b/src/underworld3/checkpoint/disk_snapshot.py index c9ed243cd..7d30d2000 100644 --- a/src/underworld3/checkpoint/disk_snapshot.py +++ b/src/underworld3/checkpoint/disk_snapshot.py @@ -13,8 +13,9 @@ the *layout* and the *metadata*, not the binary serialisation of fields. -File structure (target — phases 2+ fill in the bulk under these -groups; phase 1 writes the metadata and empty stub groups): +File structure (the phased writers below fill the bulk under these +groups; ``write_snapshot_skeleton`` stubs each group with a +``filled_by`` attribute naming its writer): my_run.snap.h5/ ├── /metadata (attrs: uw3_version, schema_version, @@ -26,10 +27,10 @@ ├── /swarms (phase 3 — possibly @external_file refs) └── /python_state (phase 3 — Snapshottable dataclasses as attrs) -Phase 1 (this commit): the metadata layer and the skeleton group -structure, with an inspectability acceptance test that asserts an -external reader (h5py here) sees meaningful information without any -UW3 imports. +Phases 1 (metadata + skeleton), 2 (mesh + variables) and 3 (swarms + +python_state) are all implemented in this module; an inspectability +acceptance test asserts an external reader (h5py) sees meaningful +information without any UW3 imports. """ from __future__ import annotations diff --git a/src/underworld3/systems/ddt.py b/src/underworld3/systems/ddt.py index 624d488aa..1cd56ad54 100644 --- a/src/underworld3/systems/ddt.py +++ b/src/underworld3/systems/ddt.py @@ -1388,7 +1388,9 @@ class SemiLagrangian(uw_object): smoothing : float, default=0.0 Smoothing parameter for projections. preserve_moments : bool, default=False - Use moment-preserving projection (experimental). + Not implemented. Passing ``True`` raises ``NotImplementedError``. + (The moment-preserving projection this promised was never wired in; + the parameter is retained so existing call signatures keep working.) with_forcing_history : bool, default=False When True, allocate an additional ``forcing_star`` MeshVariable (matching ``psi_star[0]``'s shape, vtype, degree, continuity) to @@ -1477,6 +1479,10 @@ def __init__( self._psi_fn = psi_fn self.V_fn = V_fn self.order = order + if preserve_moments: + raise NotImplementedError( + "preserve_moments is not currently implemented" + ) self.preserve_moments = preserve_moments self.with_forcing_history = with_forcing_history # Monotonicity limiter for the SL trace-back result. Bound @@ -1771,8 +1777,6 @@ def __init__( self._smoothing = smoothing - self.I = uw.maths.Integral(mesh, None) - try: import underworld3 as _uw @@ -2746,43 +2750,10 @@ def update_pre_solve( self.psi_star[i].array[...] = value_at_end_points - # disable this for now - Compute moments before update - if 0 and self.preserve_moments and self._workVar.num_components == 1: - - self.I.fn = self.psi_star[i].sym[0] - Imean0 = self.I.evaluate() - - self.I.fn = (self.psi_star[i].sym[0] - Imean0) ** 2 - IL20 = np.sqrt(self.I.evaluate()) - - - # disable this for now - Restore moments after update - if 0 and self.preserve_moments and self._workVar.num_components == 1: - - self.I.fn = self.psi_star[i].sym[0] - Imean = self.I.evaluate() - - self.I.fn = (self.psi_star[i].sym[0] - Imean) ** 2 - IL2 = np.sqrt(self.I.evaluate()) - - # TODO: DELETE remove swarm.access / data, replace with direct array assignment - # with self.mesh.access(self.psi_star[i]): - # self.psi_star[i].data[...] += Imean0 - Imean - - self.psi_star[i].array[...] += Imean0 - Imean - - self.I.fn = (self.psi_star[i].sym[0] - Imean0) ** 2 - IL2 = np.sqrt(self.I.evaluate()) - - # TODO: DELETE remove swarm.access / data, replace with direct array assignment - # with self.mesh.access(self.psi_star[i]): - # self.psi_star[i].data[...] = ( - # self.psi_star[i].data[...] - Imean0 - # ) * IL20 / IL2 + Imean0 - - self.psi_star[i].array[...] = ( - self.psi_star[i].array[...] - Imean0 - ) * IL20 / IL2 + Imean0 + # TODO(DESIGN): a moment-preserving correction (restore mean and L2 + # moment of psi_star after the semi-Lagrangian update) was removed + # here as dead code — see git history for the sketch if the + # `preserve_moments` option is ever implemented. # Phase-2 ALE: consume the one-step v_mesh pulse. Subsequent # non-adapt steps will see no pending displacement and run a diff --git a/tests/parallel/ptest_0762_read_timestep_swarm_routed.py b/tests/parallel/ptest_0762_read_timestep_swarm_routed.py index fc5c1ae7f..ef63aef2f 100644 --- a/tests/parallel/ptest_0762_read_timestep_swarm_routed.py +++ b/tests/parallel/ptest_0762_read_timestep_swarm_routed.py @@ -72,11 +72,9 @@ def test_meshvariable_read_timestep_parallel_round_trip(): _cleanup_shared_tmpdir(tmpdir) -@pytest.mark.skip( - reason="Pre-existing: Swarm.write_timestep hangs on N>1 with parallel h5py " - "(unrelated to read_timestep refactor). Serial round-trip is covered by " - "tests/test_0003_save_load.py::test_swarmvariable_save_and_load." -) +# The former skip here cited a parallel Swarm.write_timestep hang; that was +# issue #151, fixed 2026-04 (commit 453e5063) — the skip outlived the bug +# (LOOSE-ENDS-AUDIT refuted-claims appendix, 2026-07). @pytest.mark.mpi(min_size=2) @pytest.mark.level_1 @pytest.mark.tier_a diff --git a/tests/test_0750_meshing_follow_metric.py b/tests/test_0750_meshing_follow_metric.py index 0b33e73f7..f4008a267 100644 --- a/tests/test_0750_meshing_follow_metric.py +++ b/tests/test_0750_meshing_follow_metric.py @@ -319,44 +319,12 @@ def test_metric_choice_arc_length_builds_envelope(): assert v.max() <= 3.0 ** 2 + 1.0e-6 -@pytest.mark.tier_a -@pytest.mark.level_1 -@pytest.mark.xfail( - reason="Strong metric capture (alignment>0.6) was an elliptic-ma MA-mover " - "property; the development merge's follow_metric uses the gentler " - "anisotropic mover (~0 alignment with the mild arc-length monitor). " - "Arc-length capture is validated via the OT mover (test_0760).", - strict=False) -def test_follow_metric_arclength_clean_and_captures(): - m, T = _build_annulus_with_field() - moved = uw.meshing.follow_metric( - m, T, refinement=3.0, metric="arc-length") - assert moved is True - assert _inverted_count(m) == 0 # untangled map (polish removes slivers) - al = _sm.mesh_metric_mismatch( - m, _sm.metric_density_from_gradient( - m, T, refinement=3.0, metric_choice="arc-length", name="al2")) - assert al["alignment"] > 0.6 # mesh tracks the metric - - -@pytest.mark.tier_a -@pytest.mark.level_1 -@pytest.mark.xfail( - reason="follow_metric boundary-slip was an elliptic-ma MA-mover capability; " - "the development merge's follow_metric pins boundaries. Tangential boundary " - "slip is now via smooth_mesh_interior(method='mmpde', slip_surfaces=...) — " - "see test_0855.", - strict=False) -def test_follow_metric_boundary_slides_on_circle(): - m, T = _build_annulus_with_field() - isb = _sm._pinned_mask(m.dm, tuple(_sm._auto_pinned_labels(m))) - X0 = np.asarray(m.X.coords).copy() - uw.meshing.follow_metric(m, T, refinement=3.0, metric="arc-length") - X = np.asarray(m.X.coords) - r0 = np.linalg.norm(X0[isb], axis=1) - r = np.linalg.norm(X[isb], axis=1) - assert float(np.linalg.norm(X[isb] - X0[isb], axis=1).max()) > 1.0e-3 - assert float(np.abs(r - r0).max()) < 1.0e-6 # stayed on the ring +# NOTE (LE-20 / WA-22): two xfail tests were deleted here. They asserted +# elliptic-ma MA-mover capabilities (strong metric capture; boundary slip in +# follow_metric) that the development merge deliberately dropped. Surviving +# coverage: arc-length capture via the OT mover (test_0760); tangential +# boundary slip via smooth_mesh_interior(method='mmpde', slip_surfaces=...) +# (test_0855). See git history if the MA mover returns. @pytest.mark.tier_a diff --git a/tests/test_0754_arithmetic_closure_complete.py b/tests/test_0754_arithmetic_closure_complete.py index e14b48f57..003e822b5 100644 --- a/tests/test_0754_arithmetic_closure_complete.py +++ b/tests/test_0754_arithmetic_closure_complete.py @@ -163,15 +163,38 @@ def test_uwquantity_plus_unitawareexpression(self): assert isinstance(result.units, Unit), \ f"Result.units should be Pint Unit, got {type(result.units)}" - @pytest.mark.skip(reason="UnitAwareExpression class not implemented - feature replaced by simplified units architecture") - def test_unitawareexpression_minus_uwquantity(self): - """Test: UnitAwareExpression - UWQuantity works (reverse of Bug #3) +@pytest.mark.tier_a +@pytest.mark.level_2 # Units integration - intermediate complexity +class TestMultiplicationOrderIndependence: + """T_left + f*(T_right - T_left) must not depend on operand order. - NOTE: UnitAwareExpression was planned but not implemented. - The units architecture was simplified (see UNITS_SIMPLIFIED_DESIGN_2025-11.md). - This test is kept for documentation of planned feature. - """ - pass + Ported from the deleted ``test_quantities_simplified.py`` (which imported + a module that was never implemented): the original multiplication-order + bug gave different results for ``f * dT`` vs ``dT * f``. Expected value: + 0.1 * 273 + 1000 = 1027.3 kelvin for every ordering. + """ + + def _terms(self): + T_left = uw.quantity(1000, "kelvin") + T_right = uw.quantity(1273, "kelvin") + factor = uw.quantity(0.1, "dimensionless") + return T_left, T_right, factor + + def test_all_orderings_equal(self): + T_left, T_right, factor = self._terms() + + case1 = factor * (T_right - T_left) + T_left + case2 = (T_right - T_left) * factor + T_left + case3 = T_left + factor * (T_right - T_left) + case4 = T_left + (T_right - T_left) * factor + + for case in (case1, case2, case3, case4): + assert abs(case.value - 1027.3) < 0.01, \ + f"Expected 1027.3, got {case.value}" + + def test_scalar_multiplication_commutes(self): + T = uw.quantity(1000, "kelvin") + assert (T * 2).value == (2 * T).value == 2000 @pytest.mark.tier_a @@ -285,16 +308,6 @@ def test_multiplication_result_units_is_pint_unit(self): assert isinstance(result.units, Unit), \ f"Multiplication result.units should be Pint Unit, got {type(result.units)} (Bug #1!)" - @pytest.mark.skip(reason="UnitAwareExpression class not implemented - feature replaced by simplified units architecture") - def test_unitawareexpression_units_is_pint_unit(self): - """Test: UnitAwareExpression.units returns Pint Unit - - NOTE: UnitAwareExpression was planned but not implemented. - The units architecture was simplified (see UNITS_SIMPLIFIED_DESIGN_2025-11.md). - This test is kept for documentation of planned feature. - """ - pass - @pytest.mark.tier_a @pytest.mark.level_2 # Units integration - intermediate complexity diff --git a/tests/test_0756_coordinate_symbol_evaluation.py b/tests/test_0756_coordinate_symbol_evaluation.py index bb12ad47b..2d4016985 100644 --- a/tests/test_0756_coordinate_symbol_evaluation.py +++ b/tests/test_0756_coordinate_symbol_evaluation.py @@ -161,19 +161,6 @@ def test_coordinate_no_double_scaling(self): assert value > 1e5, \ f"Coordinate value {value:.2e} m is too small, expected ~1e6 m" - @pytest.mark.skip(reason="UnitAwareExpression class not implemented - feature replaced by simplified units architecture") - def test_unitawareexpression_coordinate_to_meters(self): - """ - Test: UnitAwareExpression(x, units.m).to('m') gives correct value. - - NOTE: UnitAwareExpression was planned but not implemented. - The units architecture was simplified (see UNITS_SIMPLIFIED_DESIGN_2025-11.md). - This test is kept for documentation of the double-scaling bug that was fixed. - - CRITICAL BUG (fixed): This was double-scaling to 8.41×10¹² meters. - """ - pass - @pytest.mark.tier_a # Production-ready - critical regression test def test_non_dimensionalise_unit_aware_array(self): """ diff --git a/tests/test_1053_ddt_theta.py b/tests/test_1053_ddt_theta.py index 7c5deb708..9f2f2f3a9 100644 --- a/tests/test_1053_ddt_theta.py +++ b/tests/test_1053_ddt_theta.py @@ -91,3 +91,24 @@ def test_theta_default_unchanged_when_omitted(self): assert d.theta == 0.5 assert float(d._am_coeffs[0].sym) == pytest.approx(0.5) assert float(d._am_coeffs[1].sym) == pytest.approx(0.5) + + +class TestPreserveMoments: + + def test_preserve_moments_true_raises(self): + """`preserve_moments` was a documented no-op (its implementation was + dead behind `if 0 and ...` and has been deleted); requesting it must + fail loudly rather than silently doing nothing (LE-09 / WA-04).""" + mesh = uw.meshing.StructuredQuadBox( + elementRes=(4, 4), + minCoords=(0.0, 0.0), + maxCoords=(1.0, 1.0), + ) + v = uw.discretisation.MeshVariable( + "U_pm", mesh, mesh.dim, degree=1) + psi = sympy.zeros(1, 1) + with pytest.raises(NotImplementedError): + ddt_module.SemiLagrangian( + mesh, psi_fn=psi, V_fn=v.sym, + vtype=uw.VarType.SCALAR, degree=2, continuous=False, + preserve_moments=True) diff --git a/tests/test_quantities_simplified.py b/tests/test_quantities_simplified.py deleted file mode 100644 index 71d4c5ffa..000000000 --- a/tests/test_quantities_simplified.py +++ /dev/null @@ -1,332 +0,0 @@ -""" -Test the simplified UWQuantity implementation. - -Tests: -1. Basic creation and properties -2. Arithmetic via Pint (the multiplication order bug) -3. Unit conversions -4. .data property (non-dimensional values) -5. SymPy compatibility - -NOTE: These tests import from `underworld3.function.quantities_simplified` -which was planned but never implemented. The existing quantities module is -`underworld3.function.quantities`. This entire file is skipped until the -simplified API is implemented or these tests are rewritten against the -existing quantities module. -""" - -import pytest -import numpy as np - -pytestmark = pytest.mark.skip( - reason="Tests import quantities_simplified module which does not exist. " - "Rewrite against underworld3.function.quantities or implement the module." -) - - -class TestSimplifiedQuantityBasics: - """Test basic UWQuantity creation and properties.""" - - def test_create_with_units(self): - """Create quantity with units.""" - from underworld3.function.quantities_simplified import quantity - - viscosity = quantity(1e21, "Pa*s") - - assert viscosity.value == 1e21 - assert viscosity.has_units - assert "pascal" in str(viscosity.units) or "Pa" in str(viscosity.units) - - def test_create_dimensionless(self): - """Create dimensionless quantity.""" - from underworld3.function.quantities_simplified import quantity - - factor = quantity(0.5) - - assert factor.value == 0.5 - assert not factor.has_units - assert factor.units is None - - def test_magnitude_alias(self): - """Test .magnitude is alias for .value.""" - from underworld3.function.quantities_simplified import quantity - - T = quantity(1000, "kelvin") - - assert T.magnitude == T.value == 1000 - - def test_dimensionality(self): - """Test dimensionality extraction.""" - from underworld3.function.quantities_simplified import quantity - - velocity = quantity(5, "m/s") - - dim = velocity.dimensionality - assert "[length]" in dim - assert "[time]" in dim - assert dim["[length]"] == 1 - assert dim["[time]"] == -1 - - -class TestSimplifiedQuantityArithmetic: - """Test arithmetic operations - the core of the fix.""" - - def test_addition_same_units(self): - """Add quantities with same units.""" - from underworld3.function.quantities_simplified import quantity - - T1 = quantity(1000, "kelvin") - T2 = quantity(273, "kelvin") - - result = T1 + T2 - assert result.value == 1273 - assert "kelvin" in str(result.units).lower() - - def test_subtraction_same_units(self): - """Subtract quantities with same units.""" - from underworld3.function.quantities_simplified import quantity - - T1 = quantity(1000, "kelvin") - T2 = quantity(273, "kelvin") - - result = T1 - T2 - assert result.value == 727 - assert "kelvin" in str(result.units).lower() - - def test_multiplication_with_units(self): - """Multiply quantities with units.""" - from underworld3.function.quantities_simplified import quantity - - length = quantity(100, "m") - width = quantity(50, "m") - - area = length * width - assert area.value == 5000 - # Should have m**2 - assert "meter ** 2" in str(area.units) or "m²" in str(area.units) or "meter**2" in str(area.units) - - def test_division_with_units(self): - """Divide quantities with units.""" - from underworld3.function.quantities_simplified import quantity - - distance = quantity(100, "km") - time = quantity(2, "hour") - - speed = distance / time - assert speed.value == 50 - # Should have km/hour or equivalent - - def test_multiplication_order_bug_case1(self): - """ - Case 1: factor * (T_right - T_left) + T_left - - This is the original multiplication order bug test. - """ - from underworld3.function.quantities_simplified import quantity - - T_left = quantity(1000, "kelvin") - T_right = quantity(1273, "kelvin") - factor = quantity(0.1, "dimensionless") - - result = factor * (T_right - T_left) + T_left - - # Expected: 0.1 * 273 + 1000 = 27.3 + 1000 = 1027.3 - assert abs(result.value - 1027.3) < 0.01 - - def test_multiplication_order_bug_case2(self): - """ - Case 2: (T_right - T_left) * factor + T_left - - Multiplication in different order. - """ - from underworld3.function.quantities_simplified import quantity - - T_left = quantity(1000, "kelvin") - T_right = quantity(1273, "kelvin") - factor = quantity(0.1, "dimensionless") - - result = (T_right - T_left) * factor + T_left - - # Expected: 273 * 0.1 + 1000 = 27.3 + 1000 = 1027.3 - assert abs(result.value - 1027.3) < 0.01 - - def test_multiplication_order_bug_case3(self): - """ - Case 3: T_left + factor * (T_right - T_left) - - Addition order swapped. - """ - from underworld3.function.quantities_simplified import quantity - - T_left = quantity(1000, "kelvin") - T_right = quantity(1273, "kelvin") - factor = quantity(0.1, "dimensionless") - - result = T_left + factor * (T_right - T_left) - - # Expected: 1000 + 0.1 * 273 = 1000 + 27.3 = 1027.3 - assert abs(result.value - 1027.3) < 0.01 - - def test_multiplication_order_bug_case4(self): - """ - Case 4: T_left + (T_right - T_left) * factor - - All orderings should give same result. - """ - from underworld3.function.quantities_simplified import quantity - - T_left = quantity(1000, "kelvin") - T_right = quantity(1273, "kelvin") - factor = quantity(0.1, "dimensionless") - - result = T_left + (T_right - T_left) * factor - - # Expected: 1000 + 273 * 0.1 = 1000 + 27.3 = 1027.3 - assert abs(result.value - 1027.3) < 0.01 - - def test_all_orderings_equal(self): - """All four orderings should give identical results.""" - from underworld3.function.quantities_simplified import quantity - - T_left = quantity(1000, "kelvin") - T_right = quantity(1273, "kelvin") - factor = quantity(0.1, "dimensionless") - - case1 = factor * (T_right - T_left) + T_left - case2 = (T_right - T_left) * factor + T_left - case3 = T_left + factor * (T_right - T_left) - case4 = T_left + (T_right - T_left) * factor - - # All should be equal - assert abs(case1.value - case2.value) < 1e-10 - assert abs(case2.value - case3.value) < 1e-10 - assert abs(case3.value - case4.value) < 1e-10 - - # And all should be 1027.3 - assert abs(case1.value - 1027.3) < 0.01 - - def test_scalar_multiplication(self): - """Multiply quantity by scalar.""" - from underworld3.function.quantities_simplified import quantity - - T = quantity(1000, "kelvin") - - result = T * 2 - assert result.value == 2000 - assert "kelvin" in str(result.units).lower() - - result2 = 2 * T - assert result2.value == 2000 - - def test_power(self): - """Test exponentiation.""" - from underworld3.function.quantities_simplified import quantity - - length = quantity(10, "m") - - area = length ** 2 - assert area.value == 100 - - volume = length ** 3 - assert volume.value == 1000 - - -class TestSimplifiedQuantityConversion: - """Test unit conversion methods.""" - - def test_to_conversion(self): - """Convert between compatible units.""" - from underworld3.function.quantities_simplified import quantity - - velocity = quantity(36, "km/hour") - velocity_ms = velocity.to("m/s") - - assert abs(velocity_ms.value - 10) < 0.01 - - def test_to_base_units(self): - """Convert to SI base units.""" - from underworld3.function.quantities_simplified import quantity - - pressure = quantity(1, "GPa") - base = pressure.to_base_units() - - assert base.value == 1e9 - - def test_to_reduced_units(self): - """Simplify complex unit expressions.""" - from underworld3.function.quantities_simplified import quantity - - # Create a dimensionless ratio - ratio = quantity(1000, "m") / quantity(1, "km") - reduced = ratio.to_reduced_units() - - assert abs(reduced.value - 1.0) < 0.01 - - -class TestSimplifiedQuantitySympyCompat: - """Test SymPy compatibility.""" - - def test_sympy_protocol(self): - """Test _sympy_() protocol.""" - from underworld3.function.quantities_simplified import quantity - import sympy - - T = quantity(1000, "kelvin") - sympy_val = T._sympy_() - - assert isinstance(sympy_val, sympy.Basic) - assert float(sympy_val) == 1000 - - def test_float_conversion(self): - """Test float() conversion.""" - from underworld3.function.quantities_simplified import quantity - - T = quantity(1000, "kelvin") - assert float(T) == 1000 - - def test_diff_returns_zero(self): - """Derivative of constant is zero.""" - from underworld3.function.quantities_simplified import quantity - import sympy - - x = sympy.Symbol('x') - T = quantity(1000, "kelvin") - - assert T.diff(x) == 0 - - -class TestSimplifiedQuantityDisplay: - """Test string representations.""" - - def test_str_with_units(self): - """String representation includes units.""" - from underworld3.function.quantities_simplified import quantity - - T = quantity(1000, "kelvin") - s = str(T) - - assert "1000" in s - assert "kelvin" in s.lower() - - def test_repr(self): - """Repr shows constructor form.""" - from underworld3.function.quantities_simplified import quantity - - T = quantity(1000, "kelvin") - r = repr(T) - - assert "UWQuantity" in r - assert "1000" in r - - def test_format(self): - """Test format specification.""" - from underworld3.function.quantities_simplified import quantity - - T = quantity(1000.123456, "kelvin") - formatted = f"{T:.2f}" - - assert "1000.12" in formatted - - -if __name__ == "__main__": - pytest.main([__file__, "-v"]) From 6868d959b8081ae69c1d7ce9f182fdd4cf559978 Mon Sep 17 00:00:00 2001 From: lmoresi Date: Sun, 5 Jul 2026 19:12:43 +0100 Subject: [PATCH 6/7] =?UTF-8?q?fix(deps):=20restore=20development's=20pixi?= =?UTF-8?q?.lock=20verbatim=20=E2=80=94=20defer=20lock=20cleanup=20to=20a?= =?UTF-8?q?=20dedicated=20env-refresh=20PR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pykdtree removal re-solve also downgraded numpy 2.5.0->2.4.6 across all environments, breaking the CI env at import (the known numpy/petsc4py ABI 'dtype size changed' failure class): every pytest batch died instantly with no output. pixi.toml keeps pykdtree removed; CI's --frozen install follows the lock, so the package remains installed-but-unused until the lock is refreshed deliberately, without collateral version churn. Underworld development team with AI support from Claude Code --- pixi.lock | 297 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 156 insertions(+), 141 deletions(-) diff --git a/pixi.lock b/pixi.lock index 3604d595d..02207d9ae 100644 --- a/pixi.lock +++ b/pixi.lock @@ -219,7 +219,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.3-nompi_py312hf6400b3_100.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-he970967_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.0-h26f9b46_0.conda @@ -247,6 +247,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.1-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -532,7 +533,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/netcdf4-1.7.3-nompi_py312h947358d_100.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hbfb3c88_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openmpi-5.0.10-h899237b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.0-h5503f6c_0.conda @@ -558,6 +559,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -976,7 +978,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-25.2.1-he2c55a7_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.30-pthreads_h6ec200e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/opencl-headers-2025.06.13-h5888daf_0.conda @@ -1019,6 +1021,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.1-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -1474,7 +1477,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h248ca61_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-25.2.1-h5230ea7_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openblas-0.3.30-openmp_hea878ba_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openh264-2.6.0-hb5b2745_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hbfb3c88_0.conda @@ -1515,6 +1518,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -1988,7 +1992,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-25.2.1-he2c55a7_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.30-pthreads_h6ec200e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/opencl-headers-2025.06.13-h5888daf_0.conda @@ -2031,6 +2035,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.1-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -2486,7 +2491,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h248ca61_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-25.2.1-h5230ea7_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openblas-0.3.30-openmp_hea878ba_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openh264-2.6.0-hb5b2745_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hbfb3c88_0.conda @@ -2527,6 +2532,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -2886,7 +2892,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.4-nompi_py312h25f8dc5_102.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda @@ -2914,6 +2920,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -3197,7 +3204,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/netcdf4-1.7.4-nompi_py312h5d59a02_102.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hd9e9057_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.1-hd24854e_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/overrides-7.7.0-pyhd8ed1ab_1.conda @@ -3222,6 +3229,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -3642,7 +3650,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-25.7.0-he4ff34a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.30-pthreads_h6ec200e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/opencl-headers-2025.06.13-h5888daf_0.conda @@ -3685,6 +3693,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -4141,7 +4150,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h784d473_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-25.7.0-hbfc8e16_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openblas-0.3.30-openmp_hea878ba_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openh264-2.6.0-hb5b2745_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hd9e9057_0.conda @@ -4181,6 +4190,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -4540,7 +4550,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.4-nompi_py312h25f8dc5_102.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openmpi-5.0.10-h611b0e2_0.conda @@ -4569,6 +4579,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -4854,7 +4865,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/netcdf4-1.7.4-nompi_py312h5d59a02_102.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hd9e9057_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openmpi-5.0.10-h899237b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.1-hd24854e_1.conda @@ -4880,6 +4891,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -5301,7 +5313,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-25.7.0-he4ff34a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.30-pthreads_h6ec200e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/opencl-headers-2025.06.13-h5888daf_0.conda @@ -5345,6 +5357,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -5803,7 +5816,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h784d473_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-25.7.0-hbfc8e16_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openblas-0.3.30-openmp_hea878ba_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openh264-2.6.0-hb5b2745_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hd9e9057_0.conda @@ -5844,6 +5857,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -6280,7 +6294,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.3-nompi_py312hf6400b3_100.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/opencl-headers-2025.06.13-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openh264-2.6.0-hc22cd8d_0.conda @@ -6317,6 +6331,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.1-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -6715,7 +6730,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/netcdf4-1.7.3-nompi_py312h947358d_100.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h248ca61_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openh264-2.6.0-hb5b2745_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hbfb3c88_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openldap-2.6.10-hbe55e7a_0.conda @@ -6750,6 +6765,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -7012,7 +7028,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.21.0-hae6b9f4_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.127-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda @@ -7048,7 +7064,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-openmp_hd680484_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.19-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.4-hd5a49e9_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpsl-0.22.0-hd9031aa_0.conda @@ -7105,7 +7121,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.3-nompi_py312hf6400b3_100.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.13-hbde042b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.0-h26f9b46_0.conda @@ -7136,6 +7152,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -7207,7 +7224,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.0-py312h4c3975b_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/uri-template-1.3.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.24.0-hd6090a7_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.14-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/webcolors-25.10.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-pyhd8ed1ab_3.conda @@ -7437,7 +7454,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/netcdf4-1.7.3-nompi_py312h947358d_100.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hbfb3c88_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openmpi-5.0.10-h07cac57_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.0-h5503f6c_0.conda @@ -7466,6 +7483,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -7634,7 +7652,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.8.1-hecca717_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/faiss-1.10.0-cpu_mkl_py312_hd7bdcb3_100.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/faiss-cpu-1.10.0-h718b53a_100.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-8.1.2-gpl_h6237aff_902.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-8.1.2-gpl_h1bf8424_901.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.11-mpi_mpich_h084ba78_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexcache-0.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexparser-0.4-pyhd8ed1ab_1.conda @@ -7739,7 +7757,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h7b12aa8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libamd-3.3.3-h456b2da_7100101.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.5-h434b012_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.4-h96ad9f0_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.88.0-hd24cca6_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-devel-1.88.0-hfcd1e18_7.conda @@ -7760,7 +7778,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.21.0-hae6b9f4_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdovi-3.3.2-ha23c83e_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.127-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda @@ -7820,7 +7838,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2026.2.1-h21c0c73_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2026.2.1-hecca717_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopus-1.6.1-h280c20c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.19-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libplacebo-7.360.1-h9eeb4b2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.4-hd5a49e9_1.conda @@ -7849,7 +7867,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libusb-1.0.29-h73b1eb8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.2-h5347b49_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libva-2.24.0-he1eb515_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libva-2.23.0-he1eb515_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvpl-2.16.0-h54a6638_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvpx-1.15.2-hecca717_0.conda @@ -7905,7 +7923,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-26.4.0-hc039f44_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.4-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.30-openmp_hd77311e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/opencl-headers-2025.06.13-h5888daf_0.conda @@ -7951,6 +7969,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -8057,7 +8076,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-9.5.2-py312h244374b_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.5.2-py312hd2ae51d_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.5.2-py312hfb62880_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.24.0-hd6090a7_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wayland-protocols-1.47-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.14-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/webcolors-25.10.0-pyhd8ed1ab_0.conda @@ -8421,7 +8440,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h248ca61_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-25.2.1-h5230ea7_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openblas-0.3.30-openmp_hea878ba_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openh264-2.6.0-hb5b2745_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hbfb3c88_0.conda @@ -8465,6 +8484,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -8811,7 +8831,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.4-nompi_py311ha0596eb_105.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda @@ -8840,6 +8860,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -9036,7 +9057,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hypre-3.1.0-hfcc2723_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.2-h33c6efd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda @@ -9082,7 +9103,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.0-default_h746c552_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcolamd-3.3.4-hf02c80a_7100101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.21.0-hae6b9f4_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.21.0-hcf29cc6_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda @@ -9121,7 +9142,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.55-h421ea60_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.3-h9abb657_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpsl-0.22.0-hd9031aa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libptscotch-7.0.11-int32_hf9c0034_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-14.3.0-h8f1669f_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libscotch-7.0.11-int32_hbb129e3_3.conda @@ -9175,7 +9195,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.4-nompi_py312h25f8dc5_102.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda @@ -9206,6 +9226,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -9506,7 +9527,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/netcdf4-1.7.4-nompi_py312h5d59a02_102.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hd9e9057_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.1-hd24854e_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/overrides-7.7.0-pyhd8ed1ab_1.conda @@ -9534,6 +9555,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -9751,7 +9773,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/httpx-sse-0.4.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hypre-3.1.0-hfcc2723_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.2-h33c6efd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda @@ -9826,7 +9848,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.0-default_h746c552_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcolamd-3.3.4-hf02c80a_7100101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.21.0-hae6b9f4_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.21.0-hcf29cc6_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda @@ -9891,7 +9913,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.55-h421ea60_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.3-h9abb657_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-6.33.5-h2b00c02_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpsl-0.22.0-hd9031aa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libptscotch-7.0.11-int32_hf9c0034_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.60.2-h61e6d4b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-14.3.0-h8f1669f_18.conda @@ -9972,7 +9993,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-25.7.0-he4ff34a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.33-openmp_hd77311e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/opencl-headers-2025.06.13-h5888daf_0.conda @@ -10018,6 +10039,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -10492,7 +10514,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h784d473_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-25.7.0-hbfc8e16_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openblas-0.3.30-openmp_hea878ba_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openh264-2.6.0-hb5b2745_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hd9e9057_0.conda @@ -10535,6 +10557,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -10910,7 +10933,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.4-nompi_py312h25f8dc5_102.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openmpi-5.0.10-h611b0e2_0.conda @@ -10942,6 +10965,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -11243,7 +11267,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/netcdf4-1.7.4-nompi_py312h5d59a02_102.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hd9e9057_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openmpi-5.0.10-h899237b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.1-hd24854e_1.conda @@ -11272,6 +11296,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -11710,7 +11735,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-25.7.0-he4ff34a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.33-openmp_hd77311e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/opencl-headers-2025.06.13-h5888daf_0.conda @@ -11757,6 +11782,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h9da60e5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -12232,7 +12258,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h784d473_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-25.7.0-hbfc8e16_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openblas-0.3.30-openmp_hea878ba_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openh264-2.6.0-hb5b2745_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hd9e9057_0.conda @@ -12276,6 +12302,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda @@ -12487,7 +12514,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.8.1-hecca717_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-8.1.2-gpl_h6237aff_902.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-8.1.2-gpl_h1bf8424_901.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.11-mpi_mpich_h084ba78_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexcache-0.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexparser-0.4-pyhd8ed1ab_1.conda @@ -12576,7 +12603,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h7b12aa8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libamd-3.3.3-h456b2da_7100101.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.5-h434b012_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.4-h96ad9f0_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.88.0-hd24cca6_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-devel-1.88.0-hfcd1e18_7.conda @@ -12597,7 +12624,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.21.0-hae6b9f4_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdovi-3.3.2-ha23c83e_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.127-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda @@ -12656,7 +12683,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2026.2.1-h21c0c73_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2026.2.1-hecca717_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopus-1.6.1-h280c20c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.19-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libplacebo-7.360.1-h9eeb4b2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.4-hd5a49e9_1.conda @@ -12684,7 +12711,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/liburing-2.12-hb700be7_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libusb-1.0.29-h73b1eb8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.2-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libva-2.24.0-he1eb515_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libva-2.23.0-he1eb515_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvpl-2.16.0-h54a6638_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvpx-1.15.2-hecca717_0.conda @@ -12732,7 +12759,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.3-nompi_py312hf6400b3_100.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.4-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/opencl-headers-2025.06.13-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openh264-2.6.0-hc22cd8d_0.conda @@ -12772,6 +12799,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -12865,7 +12893,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-9.5.2-py312h244374b_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.5.2-py312hd2ae51d_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.5.2-py312hfb62880_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.24.0-hd6090a7_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wayland-protocols-1.47-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.14-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/webcolors-25.10.0-pyhd8ed1ab_0.conda @@ -13184,7 +13212,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/netcdf4-1.7.3-nompi_py312h947358d_100.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h248ca61_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openh264-2.6.0-hb5b2745_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hbfb3c88_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openldap-2.6.10-hbe55e7a_0.conda @@ -13222,6 +13250,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.41.5-py312h6ef9ec0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-12.1-py312h1de3e18_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -15994,9 +16023,9 @@ packages: purls: [] size: 12485347 timestamp: 1773008832077 -- conda: https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-8.1.2-gpl_h6237aff_902.conda - sha256: be08b871acad2035f02eff5561d2f0c0bbfc4e12da44ed9074699a8e81e82281 - md5: ff2c7afbb2ea85fde7a662d2124baa44 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-8.1.2-gpl_h1bf8424_901.conda + sha256: 2d56b0d90a1e581e296a41aa0a0443c85f918a94780e779a23005be9128627be + md5: 0c457f1b2384bb0aa984831a79021a66 depends: - __glibc >=2.17,<3.0.a0 - alsa-lib >=1.2.16.1,<1.3.0a0 @@ -16006,15 +16035,15 @@ packages: - fontconfig >=2.18.1,<3.0a0 - fonts-conda-ecosystem - gmp >=6.3.0,<7.0a0 + - harfbuzz >=14.2.1 - lame >=3.100,<3.101.0a0 - - libass >=0.17.5,<0.17.6.0a0 + - libass >=0.17.4,<0.17.5.0a0 - libexpat >=2.8.1,<3.0a0 - libfreetype >=2.14.3 - libfreetype6 >=2.14.3 - libgcc >=14 - - libharfbuzz >=14.2.1 - libiconv >=1.18,<2.0a0 - - libjxl >=0.12,<1.0a0 + - libjxl >=0.11,<1.0a0 - liblzma >=5.8.3,<6.0a0 - libopenvino >=2026.2.1,<2026.2.2.0a0 - libopenvino-auto-batch-plugin >=2026.2.1,<2026.2.2.0a0 @@ -16033,7 +16062,7 @@ packages: - libplacebo >=7.360.1,<7.361.0a0 - librsvg >=2.62.3,<3.0a0 - libstdcxx >=14 - - libva >=2.24.0,<3.0a0 + - libva >=2.23.0,<3.0a0 - libvorbis >=1.3.7,<1.4.0a0 - libvpl >=2.16.0,<2.17.0a0 - libvpx >=1.15.2,<1.16.0a0 @@ -16057,8 +16086,8 @@ packages: license: GPL-2.0-or-later license_family: GPL purls: [] - size: 13043132 - timestamp: 1783096951485 + size: 13078770 + timestamp: 1782260267617 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ffmpeg-8.0.1-gpl_ha5d8480_114.conda sha256: 5ad931d8ae03ad6a76104dc79189ba0838eed15b814cb12ae94aed0f139e7e66 md5: c61afe756ee72cdb873b4a500a674975 @@ -19615,24 +19644,6 @@ packages: purls: [] size: 152179 timestamp: 1749328931930 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.5-h434b012_0.conda - sha256: 24d4b59a0267e1c159c3af82df106b42faeefccceba3c489044c93abf113c503 - md5: c1cb4d6e8a6e3f724740dee5346fc8b4 - depends: - - libgcc >=14 - - __glibc >=2.17,<3.0.a0 - - libfreetype >=2.14.3 - - libfreetype6 >=2.14.3 - - libzlib >=1.3.2,<2.0a0 - - fribidi >=1.0.16,<2.0a0 - - fontconfig >=2.18.1,<3.0a0 - - fonts-conda-ecosystem - - libiconv >=1.18,<2.0a0 - - harfbuzz >=14.2.1 - license: ISC - purls: [] - size: 154964 - timestamp: 1782298715788 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libass-0.17.4-hcbd7ca7_0.conda sha256: 079f5fdf7aace970a0db91cd2cc493c754dfdc4520d422ecec43d2561021167a md5: 0977f4a79496437ff3a2c97d13c4c223 @@ -20345,6 +20356,23 @@ packages: purls: [] size: 480327 timestamp: 1782911787190 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.21.0-hcf29cc6_1.conda + sha256: 7d243f45a48f62cb8e3b871dd336137fe0fb90094a191756fb553508837f6338 + md5: 2c1e55d695b11525c760b486ac0be517 + depends: + - __glibc >=2.17,<3.0.a0 + - krb5 >=1.22.2,<1.23.0a0 + - libgcc >=14 + - libnghttp2 >=1.68.1,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.7,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + purls: [] + size: 478914 + timestamp: 1782802520033 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.18.0-hd5a2499_1.conda sha256: dbc34552fc6f040bbcd52b4246ec068ce8d82be0e76bfe45c6984097758d37c2 md5: 2742a933ef07e91f38e3d33ad6fe937c @@ -20483,18 +20511,6 @@ packages: purls: [] size: 310785 timestamp: 1757212153962 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.127-hb03c661_0.conda - sha256: 7d3187c11b7ae66c5595a8afd5a7ce352a490527fdf6614cab129bc7f2c16ba3 - md5: d8d16b9b32a3c5df7e5b3350e2cbe058 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - libpciaccess >=0.19,<0.20.0a0 - license: MIT - license_family: MIT - purls: [] - size: 311505 - timestamp: 1778975798004 - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724 md5: c277e0a4d549b03ac1e9d6cbbe3d017b @@ -21522,7 +21538,6 @@ packages: - libbrotlienc >=1.2.0,<1.3.0a0 - libbrotlidec >=1.2.0,<1.3.0a0 license: BSD-3-Clause - license_family: BSD purls: [] size: 1849871 timestamp: 1783056664598 @@ -23133,17 +23148,6 @@ packages: purls: [] size: 28424 timestamp: 1749901812541 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.19-hb03c661_0.conda - sha256: f41721636a7c2e51bc2c642e1127955ab9c81145470714fdaac44d4d09e4af41 - md5: 33082e13b4769b48cfeb648e15bfe3fc - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - license: MIT - license_family: MIT - purls: [] - size: 29147 - timestamp: 1773533027610 - conda: https://conda.anaconda.org/conda-forge/linux-64/libplacebo-7.360.1-h9eeb4b2_0.conda sha256: 26cbbd3d7b91801826c779c3f7e87d071856d5cbe3d55b22777ca0d984fb02ed md5: e6324dfe6c02e0736bb9235f8ef3c8a6 @@ -24203,27 +24207,6 @@ packages: purls: [] size: 221308 timestamp: 1765652453244 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libva-2.24.0-he1eb515_0.conda - sha256: 96b938e39493331d796e0b0b805038b9ee11b0c192b571bbc6c7adc3701724ef - md5: 14f10db75eec75c02e56c858016f787e - depends: - - __glibc >=2.17,<3.0.a0 - - libdrm >=2.4.127,<2.5.0a0 - - libegl >=1.7.0,<2.0a0 - - libgcc >=14 - - libgl >=1.7.0,<2.0a0 - - libglx >=1.7.0,<2.0a0 - - libxcb >=1.17.0,<2.0a0 - - wayland >=1.25.0,<2.0a0 - - wayland-protocols - - xorg-libx11 >=1.8.13,<2.0a0 - - xorg-libxext >=1.3.7,<2.0a0 - - xorg-libxfixes >=6.0.2,<7.0a0 - license: MIT - license_family: MIT - purls: [] - size: 223532 - timestamp: 1782992630083 - conda: https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h54a6638_2.conda sha256: ca494c99c7e5ecc1b4cd2f72b5584cef3d4ce631d23511184411abcbb90a21a5 md5: b4ecbefe517ed0157c37f8182768271c @@ -26284,45 +26267,45 @@ packages: - pkg:pypi/notebook-shim?source=hash-mapping size: 16817 timestamp: 1733408419340 -- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda - sha256: dfcbeadb3e7ad0da7a55a0525884ca34c19584154e13cc4159396b305d1bd445 - md5: 6e31d55ee1110fda83b4f4045f4d73ff +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.5.0-py312h33ff503_0.conda + sha256: c8d5f70715fc6cd3dcd16fdd11b51879ed4484963f066b33fbaf20c4ffb153af + md5: 24f70d3db040fc69ee72cc38e55bc8e3 depends: - python - - libstdcxx >=14 - libgcc >=14 + - libstdcxx >=14 - __glibc >=2.17,<3.0.a0 - - liblapack >=3.9.0,<4.0a0 - - libblas >=3.9.0,<4.0a0 - python_abi 3.12.* *_cp312 - libcblas >=3.9.0,<4.0a0 + - liblapack >=3.9.0,<4.0a0 + - libblas >=3.9.0,<4.0a0 constrains: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/numpy?source=hash-mapping - size: 8759520 - timestamp: 1779169200325 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda - sha256: b09e03dace335a6f303352fc4e167243e04d7026d55008546fa643d224fb0bad - md5: 9f554fdfa902971390975b489e678c03 + - pkg:pypi/numpy?source=compressed-mapping + size: 8911732 + timestamp: 1782112536981 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.5.0-py312ha003a3f_0.conda + sha256: 36f7062ce484ce45b8fdb2ee48cbbc7c0023004ba01e692efd5cd70034d93609 + md5: f223ea9a1ca019ddbcfe28ce02ec366c depends: - python - - __osx >=11.0 - libcxx >=19 - - python_abi 3.12.* *_cp312 + - __osx >=11.0 + - libcblas >=3.9.0,<4.0a0 - liblapack >=3.9.0,<4.0a0 + - python_abi 3.12.* *_cp312 - libblas >=3.9.0,<4.0a0 - - libcblas >=3.9.0,<4.0a0 constrains: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/numpy?source=hash-mapping - size: 6843172 - timestamp: 1779169213435 + size: 6964084 + timestamp: 1782112554625 - conda: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.3-hb9d3cd8_0.conda sha256: 2254dae821b286fb57c61895f2b40e3571a070910fdab79a948ff703e1ea807b md5: 56f8947aa9d5cf37b0b3d43b83f34192 @@ -27935,6 +27918,38 @@ packages: - meshio>=4.3.2,<6 - numpy>=1.20.0 requires_python: '>=3.7' +- conda: https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.4.3-py312h4f23490_2.conda + sha256: 975ecf15f799242b59d4df4d38e02537865d4bd719df16589bb827b3df23bb07 + md5: 1af24b0eb99b1158c0d8c64a4d6c5d79 + depends: + - __glibc >=2.17,<3.0.a0 + - _openmp_mutex >=4.5 + - libgcc >=14 + - numpy >=1.23,<3 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/pykdtree?source=hash-mapping + size: 92151 + timestamp: 1762594909033 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pykdtree-1.4.3-py312hd01e8a4_2.conda + sha256: d9b54c705b37f5d94145d452a4398c21b24af6dffe16e4c9844a85c841c9c59f + md5: 47eb338f82a230ee1eb87991278ec9c0 + depends: + - __osx >=11.0 + - llvm-openmp >=19.1.7 + - numpy >=1.23,<3 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/pykdtree?source=hash-mapping + size: 77602 + timestamp: 1762595314857 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-12.1-py312h19bbe71_0.conda sha256: b015f430fe9ea2c53e14be13639f1b781f68deaa5ae74cd8c1d07720890cd02a md5: c65d7abdc9e60fd3af0ed852591adf1b From 8451d495f753fb4ef7a56bf467d87a00b0c658b0 Mon Sep 17 00:00:00 2001 From: lmoresi Date: Sun, 5 Jul 2026 21:22:47 +0100 Subject: [PATCH 7/7] ci: retrigger (no workflow run was created for 6868d959)