Skip to content

Conversation

@lmoresi
Copy link
Member

@lmoresi lmoresi commented Nov 18, 2025

The full release of UW3 should be at 3.0 ... when we do this, I would like to introduce some new coding patterns that are more conducive to the having and AI-bot (AI-Bat ?) give advice.

So that means there is a lot to review in here.

lmoresi and others added 30 commits August 8, 2025 20:45
Wrapper function for the access manager to improve usability
Minor deetails.
Attempting to fix up the evaluation to be internally consistent, adding the wrappers for the access manager (and calling it `array` for now).

Fix up tests to account for changes to evaluation array sizes on return (mostly squeezes)

Fix a couple of other evaluation bugs (like the need to add a zero vector to some nearly-constant matrices).

Repairing the quickstart guide here and there.
Fix for the first comment by @jcgraciosa.

Also needed to update the JIT code to understand the MATRIX variable type and removing the other types that are (currently) not used. These cause compilation errors if they are lit up by mistake (even if that variable is not in any expression).

Solvers: Navier Stokes / Advection-Diffusion - fix the projection terms and how they pack up their data.
Adding global evaluation routines to compute values anywhere in the distributed domain (also with extrapolation using rbf)
Fixing broken test (array shape)
Not setting initial rank - this has problems when the particle is located on the correct rank because it automatically, always gets migrated to rank 0 and we start hunting for it again (but always in the wrong place).
Missed one !
Nodal Point Swarm also had the issue of uninitialised rank. This causes particles on rank > 1 to be migrated to rank 0 on the first call to migrate. They then get lost ...

Potential fix @jcgraciosa but maybe not the only issue here.
Fixing lack of rank initialisation in swarm.populate.

Also: some changes to the derivative expressions code:
  - .where relevant sym returns the inner expression derived by the diff_variable inner expression in symbolic form (which is closer to the intent of .sym) and does not return the evaluated form.
  - .doit function returns the evaluated form (so this is like the sympy deferred derivative).
This code is *probably* no longer needed
And leaving NodalPointPICSwarm alone
Shortening some monster-sized files.
Imports etc should not change
…t in a more user friendly form attached to the swarm
lmoresi and others added 30 commits December 21, 2025 20:24
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Convert all Markdown math ($...$) to RST format (:math: and .. math::)
- Add module docstrings to 13 files (systems, discretisation, maths, etc.)
- Add/improve class docstrings for core API (Mesh, VarType, SwarmType, etc.)
- Mark internal functions (evaluate_nd, global_evaluate_nd) with See Also refs
- Mark constitutive_models_new.py as deprecated (scheduled for removal)
- Mark units_mixin as deprecated and scheduled for removal
- Remove unused meshing_legacy.py and _utils.py files

Files with new module docstrings:
- __init__.py, _var_types.py, swarm.py, coordinates.py, adaptivity.py
- constitutive_models.py, systems/__init__.py, discretisation/__init__.py
- maths/__init__.py, function/__init__.py, utilities/__init__.py
- cython/__init__.py

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…nsionalise

Fixes regression where equivalent unit specifications produced different
mesh densities (e.g., 500m vs 0.5km gave 5 nodes vs 996 nodes).

Root cause: model.to_model_magnitude() extracted raw .magnitude without
converting to base SI units first, causing 1000x scale differences.

Changes:
- Replace model.to_model_magnitude() calls with uw.scaling.non_dimensionalise()
  in meshing/cartesian.py, meshing/annulus.py, swarm.py, discretisation_mesh.py
- Fix non_dimensionalise() to handle UWQuantity objects (extract ._pint_qty)
- Fix sparse dimensionality dict access using .get("[dim]", 0) instead of ["[dim]"]

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add mesh.adapt() method and Surface.refinement_metric() for metric-based
mesh adaptation using PETSc/MMG. Key features:

- Surface.refinement_metric() creates H-field based on distance from surface
- mesh.adapt() refines/coarsens mesh while preserving variable references
- Surface distance variables treated as regular MeshVariables (not special-cased)
- Variables marked stale and recomputed lazily after adaptation

Metric tensor math: M = h⁻² × I (dimension-independent for 2D and 3D)
This defines edge lengths, not areas/volumes, so same formula applies.

Includes adaptive shear box example demonstrating ~10x refinement near
fault while maintaining approximately the same total element count.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add uw.Param() wrapper for typed parameters with units:
- ParamType enum (QUANTITY, RATIO, INTEGER, FLOAT, STRING, BOOLEAN)
- Pint-based CLI parsing with dimension validation
- Units required for quantity params (bare numbers rejected)
- Bounds checking after unit conversion
- Rich display with units/type info in notebooks
- Angle units work correctly (degree <-> radian interchangeable)

Backward compatible - plain types still work as before.

Example:
    params = uw.Params(
        uw_cell_size=uw.Param(0.5, units="km"),
        uw_viscosity=uw.Param(1e21, units="Pa*s"),
    )
    # CLI: python script.py -uw_cell_size "500 m"

Also adds user guide documentation in docs/beginner/parameters.qmd.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add public API functions for creating adaptation metrics from
MeshVariable data:

- create_metric(): Convert h-field directly to metric (M = 1/h²)
- metric_from_gradient(): Refine where gradients are steep
- metric_from_field(): Refine based on indicator field values

The metric tensor mathematics (M = h⁻² × I) is now documented
throughout, explaining the dimension-independent formula.

Gradient computation uses efficient local least-squares fitting
via scipy's cKDTree, avoiding the complexity of FEM projection.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Enable uw.function.evaluate(T.diff(x), coords) to work without explicit
projection, using Clement gradient interpolation for O(h) accurate results.

Changes:
- Add gradient_evaluation.py with evaluate_gradient() and helpers
- Modify mesh_vars_in_expression() to collect derivatives (check subclass first)
- Update evaluate_nd() to compute Clement gradients for derivative expressions
- Fix UWCoordinate.__hash__() to match BaseScalar hash (required for sympy.diff)

The implementation groups derivatives by source variable to avoid redundant
gradient computations (e.g., T.diff(x) + T.diff(y) computes T's gradient once).

Includes comparison notebook demonstrating projection vs Clement methods
with convergence analysis on simplex meshes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Relocate Ex_Gradient_Methods_Comparison.py from Notebooks/ to
docs/examples/utilities/intermediate/ for consistency with existing
documentation structure.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Replace ad-hoc local least-squares gradient estimation with PETSc's
DMPlexComputeGradientClementInterpolant via uw.function.compute_clement_gradient_at_nodes().

This is the proper FEM approach:
- O(h) accurate (same as least-squares approximation)
- No scipy dependency for gradient computation
- Consistent with new gradient evaluation infrastructure

The Clement method averages cell-wise gradients at vertices, providing
a robust gradient estimate without requiring a linear solve.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…ation

Update gradient_evaluation.py to properly handle:
- P2 (degree=2) fields by sampling at P1 vertex locations first
- Vector/tensor fields by extracting individual components
- Add `component` parameter to specify which component's gradient to compute

Key changes:
- evaluate_gradient() now accepts `component` parameter for vector fields
- compute_clement_gradient_at_nodes() similarly accepts `component`
- _evaluate_field_at_vertices() extracts component data correctly
- Use barycentric interpolation for arbitrary point evaluation

This fixes ValueError when evaluating expressions containing derivatives
of P2 vector fields like `stokes.Unknowns.Einv2`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add optional projection-based evaluation for expressions containing
derivatives, providing O(h²) accuracy vs O(h) for Clement interpolation.

New API parameters for uw.function.evaluate():
- gradient_method: "interpolant" (default, Clement) or "projection" (L2)
- force_l2: Force projection path for any expression
- smoothing: Projection smoothing parameter (dimensionless, default 1e-6)

Implementation:
- Add _evaluate_via_projection() that projects expression to work variable
  then interpolates to coordinates
- Work variable and projector cached on mesh for reuse
- Fix gradient_values key lookup bug (keyed by (var, component) tuples)

Performance (after warm-up):
- Simple derivatives: Projection ~1.2x faster than Clement
- Complex expressions: Clement faster (symbolic combination)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Create shared helper functions to eliminate code duplication between
petsc_interpolate and rbf_evaluate:

- _collect_mesh_varfns(): Collect variable symbols from mesh.vars
- _lambdify_and_evaluate(): Symbol substitution, lambdify, and evaluate

Both evaluation paths now use identical post-interpolation processing,
ensuring consistency and simplifying maintenance.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Introduces a high-level `mode` parameter to uw.function.evaluate() and
global_evaluate() with three options:

- "default": Accurate evaluation with L2 projection for derivatives (O(h²)),
  direct calculation otherwise. DMInterpolation inside mesh, RBF outside.
- "fast": Quick visualization with Clement gradient recovery (O(h), no solve),
  RBF interpolation everywhere.
- "projection": Always use L2 projection for smooth results.

Key changes:
- Derivatives now work with exterior points (resolved before interior/exterior split)
- Expert overrides (rbf, force_l2) available for fine-grained control
- Consistent behavior between evaluate() and global_evaluate()
- Updated GRADIENT_METHODS.md documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Remove units_mixin.py (688 lines) - functionality consolidated elsewhere
- Enhance units.py with improved dimensionalise/non_dimensionalise
- Clean up unit_aware_array.py and mathematical_mixin.py
- Simplify unit conversion logic
- Remove obsolete unit tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add new geometry utilities in geometry_tools.py
- Improve geographic mesh generation in geographic.py
- Update meshing module exports in __init__.py

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Remove units_backend dependency from MeshVariable (use Pint directly)
- Improve discretisation_mesh_variables.py with cleaner unit logic
- Update enhanced_variables.py for consistency
- Clean up model.py after units refactoring
- Enhance constitutive_models.py

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Enhance _jitextension.py with better error handling
- Add backend abstraction documentation to nd_array_callback.py
- Clean up utilities/__init__.py exports after units_mixin removal

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Update tutorials 6, 7, 8, 11, 14 for revised units API
- Improve code examples and explanations
- Sync .py versions with notebooks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Fix test_0101_kdtree.py for updated API
- Add test levels to scripts/test_levels.sh
- Update CLAUDE.md project configuration
- Minor fix to shear_box_2d_fault_adaptive.py example

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
New fault/surface meshing capability:
- Add faults.py with FaultSurface class for embedded fault geometry
- Support for fault slip, strain localization, and mesh refinement

Examples:
- shear_box_2d_fault.py: 2D fault slip example
- shear_box_3d_fault_adaptive.py: 3D adaptive mesh with fault

Tests:
- test_0850_faults.py: Fault surface unit tests
- test_0850_surfaces.py: Surface variable and interpolation tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Geographic tutorials:
- Ex_Geographic_Meshes.py: Geographic/cartographic mesh examples
- Ex_Spherical_Meshes.py: Spherical mesh generation examples

Tests:
- test_0800_optional_modules.py: Tests for optional module imports
- benchmark_projection_evaluate.py: Projection evaluation benchmarks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Track the output directory in git while ignoring generated files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Lightweight binder configuration that bootstraps pixi in postBuild:
- requirements.txt: Minimal bootstrap (empty)
- postBuild: Installs pixi, runtime environment, builds uw3, registers kernel
- start: Activates pixi environment before Jupyter sessions

This avoids slow conda petsc builds by using pixi's fast resolver.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
The symlink pointed to non-existent LICENCE.md, causing Docker
build failures on mybinder.org.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
MyBinder launches will use the separate uw-demo-launcher repository
which has pre-built conda environments for faster startup.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit updates ~45 example files to use the modern coordinate
access patterns:

- mesh.data → mesh.X.coords (deprecated coordinate access)
- var.data with mesh.data indexing → var.data with var.coords
- Removed unnecessary mesh.access() wrappers where safe

Key changes:
- Use var.coords for DOF coordinates (works for all element degrees)
- Use mesh.X.coords for mesh vertex coordinates
- Direct .data/.array access without access context manager

Note: Some mesh.access() patterns with multiple variables remain
for future review with uw.synchronised_array_update().

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Part of the migration to simplified data access patterns:
- Removed mesh.access() wrappers for single-variable assignments
- Removed empty mesh.access() wrappers (read-only patterns)
- Added TODO comments for multi-variable patterns to consider
  uw.synchronised_array_update()
- Added TODO comments for complex patterns requiring review

The access manager is no longer required for basic data operations.
Multi-variable synchronisation may still benefit from the new
uw.synchronised_array_update() context manager.

Files updated: 20 examples across heat_transfer, fluid_mechanics,
porous_flow, solid_mechanics, utilities, and free_surface categories.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Continue removing deprecated access manager patterns from examples:
- Single variable swarm.access(var): remove wrapper
- Empty swarm.access() for read: remove wrapper
- Multi-variable patterns: add TODO comment for uw.synchronised_array_update()

Affected patterns across 15 files:
- Material initialization with swarm data
- Visualization code reading material.data.copy()
- Particle coordinate updates (manual advection)
- Swarm-based function evaluation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit completes the migration away from deprecated access patterns:

Examples fixed (25 files):
- Removed with mesh.access() and swarm.access() wrappers
- Added TODO comments for multi-variable patterns
- Fixed mesh.data → mesh.X.coords for coordinate access
- Fixed meshbox.data → meshbox.X.coords deprecation

CLAUDE.md updates:
- Added "Access Context Managers NOT Required" section
- Documented deprecated vs current patterns
- Added coordinate access examples (mesh.X.coords, var.coords)
- Clarified swarm.data access patterns

Files modified:
- 14 main example files (fluid_mechanics, free_surface, porous_flow, utilities)
- 11 WIP/developer_tools files
- CLAUDE.md documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add 7 portable slash commands with relative paths for version control
- Simplify Data Access Patterns in CLAUDE.md to reference style guide
- Update .gitignore to track .claude/commands/*.md files
- Commands: check-patterns, test-units, test-solvers, test-regression,
  test-tier-a, test-tier-ab, test-units-classify

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants