Skip to content

[codex] Add uniform grid vector calculus functionals#1724

Open
loliverhennigh wants to merge 2 commits into
NVIDIA:mainfrom
loliverhennigh:grid-vector-calculus-functionals
Open

[codex] Add uniform grid vector calculus functionals#1724
loliverhennigh wants to merge 2 commits into
NVIDIA:mainfrom
loliverhennigh:grid-vector-calculus-functionals

Conversation

@loliverhennigh

Copy link
Copy Markdown
Collaborator

Summary

Adds uniform-grid vector calculus functionals for periodic Cartesian grids:

  • uniform_grid_divergence
  • uniform_grid_curl
  • uniform_grid_laplacian

Each functional follows the existing FunctionSpec pattern with a Torch reference backend and a fused Warp backend. The Warp paths launch dedicated custom kernels instead of composing through uniform_grid_gradient, so the accelerated backend avoids intermediate derivative tensors.

This also exposes MeshPoissonDiskSample and MeshToVoxelFraction in the functional benchmark registry and adds derivative docs entries with figures for the three new uniform-grid vector calculus functionals.

Notes

The Laplacian compare hook uses a small absolute tolerance for fourth-order CUDA parity. Fourth-order second-derivative stencils subtract nearly equal float32 values, and the fused Warp kernel and composed Torch reference take different rounding paths on CUDA. Analytic tests still cover physical finite-difference accuracy separately.

Validation

Local CPU/MPS-host validation:

  • uv run --frozen pytest -q test/nn/functional/derivatives/test_uniform_grid_divergence.py test/nn/functional/derivatives/test_uniform_grid_curl.py test/nn/functional/derivatives/test_uniform_grid_laplacian.py
    • 40 passed
  • uv run --frozen pytest -q test/nn/functional
    • 359 passed, 49 skipped
  • uv run --frozen ruff check physicsnemo/nn/functional/derivatives/uniform_grid_divergence physicsnemo/nn/functional/derivatives/uniform_grid_curl physicsnemo/nn/functional/derivatives/uniform_grid_laplacian test/nn/functional/derivatives/test_uniform_grid_divergence.py test/nn/functional/derivatives/test_uniform_grid_curl.py test/nn/functional/derivatives/test_uniform_grid_laplacian.py benchmarks/physicsnemo/nn/functional/registry.py physicsnemo/nn/functional/__init__.py physicsnemo/nn/functional/derivatives/__init__.py
    • passed
  • git diff --check
    • passed

RTX 4090 validation:

  • Environment: NVIDIA GeForce RTX 4090, Torch 2.11.0+cu130, Warp 1.13.0
  • Focused derivative suite on RTX 4090:
    • 80 passed

RTX 4090 fused Warp timing sanity check, compile time excluded:

Case Torch Warp Speedup Max abs diff
divergence 2D order 4, (2, 1024, 1024) 0.230 ms 0.051 ms 4.49x 1.137e-13
curl 2D order 4, (2, 1024, 1024) 0.223 ms 0.051 ms 4.38x 5.960e-08
laplacian 2D order 4, (1024, 1024) 0.128 ms 0.045 ms 2.83x 3.974e-03
divergence 3D order 2, (3, 128, 128, 128) 0.495 ms 0.053 ms 9.27x 0.000e+00
curl 3D order 2, (3, 128, 128, 128) 0.535 ms 0.055 ms 9.64x 0.000e+00
laplacian 3D order 2, (128, 128, 128) 0.188 ms 0.049 ms 3.82x 9.537e-07

@copy-pr-bot

copy-pr-bot Bot commented Jun 11, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@loliverhennigh

Copy link
Copy Markdown
Collaborator Author

Hey @ktangsali, I had a little bit of time this week and started flushing out some of the gradient/functionals work in PhysicsNemo.

I’m working my way toward the mesh gradient functionals and trying to get some real acceleration there. This PR adds uniform-grid divergence, curl, and Laplacian functionals with fused Warp kernels plus Torch references and tests:

#1724

No rush, but when you get a chance, can you take a quick look at this?

@loliverhennigh loliverhennigh force-pushed the grid-vector-calculus-functionals branch 2 times, most recently from 07d1557 to a1b62e6 Compare June 12, 2026 16:28
@loliverhennigh loliverhennigh marked this pull request as ready for review June 12, 2026 16:47
@greptile-apps

greptile-apps Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds three new uniform-grid vector calculus functionals — uniform_grid_divergence, uniform_grid_curl, and uniform_grid_laplacian — each following the existing FunctionSpec pattern with a PyTorch reference backend and a fused Warp backend. The mathematical correctness of all stencils and their adjoints was verified: the 3D curl backward correctly exploits curl's self-adjointness under periodic boundary conditions, the Laplacian backward re-applies the Laplacian (also self-adjoint), and all 2D backward kernels match the analytical adjoint of their respective anti-symmetric finite-difference operators.

  • All three Warp _impl files independently redefine four identical periodic-wrap helper functions (_wrap_plus1/minus1/plus2/minus2) instead of adding them to the shared ..uniform_grid_gradient._warp_impl.utils module already imported by each file.
  • Spacing positivity is validated inside the accumulation loop in the divergence and laplacian Torch impls, meaning a bad later entry triggers an error after partial computation has already occurred; the curl Torch impl validates all spacing up-front before computing anything.
  • Input validation runs twice on every Warp dispatch call: once in the public wrapper (uniform_grid_*_warp) and again inside the custom op (uniform_grid_*_impl).

Important Files Changed

Filename Overview
physicsnemo/nn/functional/derivatives/uniform_grid_divergence/_warp_impl.py Adds fused Warp custom op for divergence with correct forward/backward kernels; helper wrap functions are duplicated from the other two warp impls and validation runs twice per call
physicsnemo/nn/functional/derivatives/uniform_grid_curl/_warp_impl.py Adds fused Warp custom op for curl; 3D backward correctly reuses the forward curl kernel (self-adjoint property under periodic BCs); 2D backward uses dedicated adjoint kernels; same duplication of wrap helpers
physicsnemo/nn/functional/derivatives/uniform_grid_laplacian/_warp_impl.py Adds fused Warp Laplacian; backward correctly applies Laplacian again (self-adjoint operator); same helper-function duplication across warp impls
physicsnemo/nn/functional/derivatives/uniform_grid_divergence/_torch_impl.py Correct PyTorch divergence implementation; spacing validation happens inside the accumulation loop rather than up-front, inconsistent with the curl impl
physicsnemo/nn/functional/derivatives/uniform_grid_curl/_torch_impl.py Correct PyTorch curl implementation; spacing is validated before any computation; stencil formulas verified correct
physicsnemo/nn/functional/derivatives/uniform_grid_laplacian/_torch_impl.py Correct 4th-order Laplacian stencil; spacing validation inside loop, same inconsistency as divergence
physicsnemo/nn/functional/derivatives/uniform_grid_divergence/uniform_grid_divergence.py Clean FunctionSpec implementation; correct benchmark/backward cases; parity tolerances look reasonable
physicsnemo/nn/functional/derivatives/uniform_grid_curl/uniform_grid_curl.py Clean FunctionSpec; benchmark inputs are smooth and periodic; parity tolerances appropriate
physicsnemo/nn/functional/derivatives/uniform_grid_laplacian/uniform_grid_laplacian.py FunctionSpec is correct; _COMPARE_ATOL=5e-3 and _COMPARE_BACKWARD_ATOL=1e-2 are notably loose but justified by the PR description for fourth-order float32 rounding
test/nn/functional/derivatives/test_uniform_grid_divergence.py Good coverage: analytic accuracy (1D/2D/3D x order 2/4), public-function smoke test, Warp backend parity, forward/backward gradient parity, error handling, and make_inputs contract tests
test/nn/functional/derivatives/test_uniform_grid_curl.py Analytic curl expected values verified correct; test structure mirrors divergence with full forward/backward parity and error-handling coverage
test/nn/functional/derivatives/test_uniform_grid_laplacian.py Analytic Laplacian expected values are correct; analytic tolerance (atol=2e-1) is appropriately loose for discretisation error on small grids; Warp parity tests use the FunctionSpec tolerance

Reviews (1): Last reviewed commit: "Address vector calculus functional revie..." | Re-trigger Greptile

Comment on lines +78 to +83
vector_field: torch.Tensor,
spacing: float | Sequence[float] = 1.0,
order: int = 2,
) -> torch.Tensor:
"""Compute periodic uniform-grid divergence with PyTorch tensor ops."""
grid_ndim = validate_vector_field(vector_field)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Spacing validation deferred inside accumulation loop

The positivity check for dx lives inside the main accumulation loop, so if a later spacing entry is invalid the partial derivative for earlier axes has already been computed before the error is raised. Both the curl and (separately) the warp implementations validate all spacing values up-front before any computation. Bringing divergence and laplacian in line with that pattern would make the three implementations consistent and avoids wasted computation on bad inputs.

Comment on lines +65 to +82
@wp.func
def _wrap_plus1(i: int, n: int) -> int:
return (i + 1) % n


@wp.func
def _wrap_minus1(i: int, n: int) -> int:
return (i + n - 1) % n


@wp.func
def _wrap_plus2(i: int, n: int) -> int:
return (i + 2) % n


@wp.func
def _wrap_minus2(i: int, n: int) -> int:
return (i + n - 2) % n

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Warp helper functions duplicated across all three _warp_impl.py files

_wrap_plus1, _wrap_minus1, _wrap_plus2, and _wrap_minus2 are defined identically in uniform_grid_divergence/_warp_impl.py, uniform_grid_curl/_warp_impl.py, and uniform_grid_laplacian/_warp_impl.py. The implementations already share the public-facing utilities (_launch_dim, _normalize_spacing, _warp_launch_context, etc.) from ..uniform_grid_gradient._warp_impl.utils. Consolidating the wrap helpers into that shared utils module would eliminate the duplication and make future changes (e.g., a different periodic-wrap strategy) a single-site edit.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +455 to +482
@torch.library.custom_op(
"physicsnemo::uniform_grid_divergence_warp_impl", mutates_args=()
)
def uniform_grid_divergence_impl(
vector_field: torch.Tensor,
spacing_meta: torch.Tensor,
order: int,
) -> torch.Tensor:
"""Evaluate uniform-grid divergence with fused Warp kernels."""
grid_ndim = validate_vector_field(vector_field)
spacing_tuple = tuple(float(v) for v in spacing_meta.tolist())
_validate_positive_spacing(spacing_tuple)
order = _validate_order(int(order))
orig_dtype = vector_field.dtype
vector_field_fp32 = _to_fp32_contiguous(vector_field)
output_fp32 = torch.empty(
vector_field_fp32.shape[1:],
device=vector_field_fp32.device,
dtype=torch.float32,
)
_launch_divergence_forward(
vector_field_fp32=vector_field_fp32,
spacing_tuple=spacing_tuple[:grid_ndim],
order=order,
output_fp32=output_fp32,
)
return _restore_dtype(output_fp32, orig_dtype)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Input validation runs twice on the Warp dispatch path

uniform_grid_divergence_warp (the public wrapper) calls validate_vector_field, _validate_positive_spacing, and _validate_order, then forwards to uniform_grid_divergence_impl, which repeats all three checks. This double-validation pattern is present in the curl and laplacian warp paths as well. While correct, it means every Warp call pays validation overhead twice. If the custom op is ever exercised directly (e.g., through torch.compile graph capture or export), the second validation acts as a safety net; but in the normal dispatch path it is redundant.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@loliverhennigh loliverhennigh force-pushed the grid-vector-calculus-functionals branch from a1b62e6 to f7bbfc6 Compare June 12, 2026 17:14
@loliverhennigh

Copy link
Copy Markdown
Collaborator Author

/blossom-ci

1 similar comment
@loliverhennigh

Copy link
Copy Markdown
Collaborator Author

/blossom-ci

@loliverhennigh loliverhennigh force-pushed the grid-vector-calculus-functionals branch from f7bbfc6 to bdee451 Compare June 25, 2026 18:23
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.

1 participant