https://github.com/oameye/helmholtzdecomposition
Analytical Helmholtz decomposition of vector fields in n dimensions
https://github.com/oameye/helmholtzdecomposition
analytical helmholtz-decomposition vector-fields
Last synced: about 1 month ago
JSON representation
Analytical Helmholtz decomposition of vector fields in n dimensions
- Host: GitHub
- URL: https://github.com/oameye/helmholtzdecomposition
- Owner: oameye
- License: cc0-1.0
- Created: 2025-09-08T12:41:00.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2025-09-08T15:21:29.000Z (9 months ago)
- Last Synced: 2025-09-08T17:27:29.471Z (9 months ago)
- Topics: analytical, helmholtz-decomposition, vector-fields
- Language: Mathematica
- Homepage:
- Size: 25.4 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# HelmholtzDecomposition
Analytical Helmholtz decomposition of n-dimensional vector fields, following Richters & Glötzl, *Analytical Helmholtz Decomposition of n-Dimensional Vector Fields* ([10.1016/j.jmaa.2023.127138](https://doi.org/10.1016/j.jmaa.2023.127138)). Given a vector field `f`, the decomposition
```
f = g + r, Curl[g] == 0, Div[r] == 0
```
is constructed once and exposed through a single function `HelmholtzDecomposition` returning a queryable result object.
## Install
```mathematica
PacletInstall["https://github.com/oameye/HelmholtzDecomposition/releases/download/v2.0.0/HelmholtzDecomposition-2.0.0.paclet"]
```
Or, working from a checkout:
```mathematica
PacletDirectoryLoad["/path/to/HelmholtzDecomposition"];
Needs["HelmholtzDecomposition`"];
```
## Quick start
```mathematica
Needs["HelmholtzDecomposition`"];
hd = HelmholtzDecomposition[{x^2 + y, x y}, {x, y}];
hd["Gradient"] (* {x^2 + y^2/2, x y} *)
hd["Rotational"] (* {-(1/2)(-2 + y) y, 0} *)
hd["Potential"] (* scalar P with Grad[P] == g *)
hd["Verify"] (* <|GradientCurlFree -> True, ...|> *)
List @@ hd (* {g, r}, handy for destructuring *)
```
## API — one function, queryable result
```mathematica
hd = HelmholtzDecomposition[f, xvec, opts] (* explicit coords *)
hd = HelmholtzDecomposition[f, opts] (* auto-detect coords from f *)
```
The result has head `HelmholtzDecomposition` and renders as a collapsible summary box in notebooks. It is queried by string property:
| Property | Meaning |
|---|---|
| `"Gradient"` | curl-free component `g` |
| `"Rotational"` | divergence-free component `r` |
| `"Potential"` | scalar `P` with `Grad[P, xvec] == g` |
| `"AntisymmetricPotential"` | the n-dimensional 2-form `Rij` whose row-divergence is `r` |
| `"VectorPotentialA"` | (3D only) vector `A` with `Curl[A] == r` |
| `"PotentialMatrix"` | the underlying potential matrix `Fij` |
| `"Residual"` | `f - g - r`, simplified |
| `"Verify"` | `<|"GradientCurlFree", "RotationalDivergenceFree", "ResidualZero"|>` |
| `"Field"`, `"Coordinates"` | the inputs |
| `"Properties"` | the list of valid property names |
| `"Association"` | the raw underlying Association |
`List @@ hd` returns `{g, r}` (handy for destructuring), `Normal[hd]` returns the underlying Association, `Length[hd]` returns the field dimension. Querying an unknown property returns `$Failed` with a message.
### Options
```mathematica
HelmholtzDecomposition[f, xvec,
SimplificationFunction -> FullSimplify, (* or Simplify, Identity, ... *)
Assumptions :> $Assumptions, (* forwarded to the simplifier *)
Verbose -> False, (* trace the algorithm via Echo *)
Caching -> True, (* memoize on (f, xvec, simp, asm, tc) *)
TimeConstraint -> Infinity (* circuit breaker forwarded to the simplifier *)
]
```
`Identity` is special-cased so `SimplificationFunction -> Identity` skips simplification cleanly.
### Caching
Results are memoized by default on the tuple `(f, xvec, SimplificationFunction, Assumptions)`. Repeated calls cost effectively nothing. Drop the cache with `ClearHelmholtzCache[]` (returns the number of evicted entries), or pass `Caching -> False` for a single bypass.
### Failure modes
The function returns `$Failed` (with a typed message under `HelmholtzDecomposition::*`) on:
- length mismatch between `f` and `xvec` (`::nomatch`)
- ambiguous coordinate auto-detection (`::autocoord`)
- atomic terms outside the polynomial / exponential / sine / cosine grammar (`::nodec`)
- query for an unknown property (`::nokey`)
- query for `"VectorPotentialA"` outside 3D (`::baddim`)
- non-boolean `Verbose` (`::badverbose`)
## Notes
**Simplifier contract.** `SimplificationFunction` must accept the call shape `simp[expr, asm, TimeConstraint -> tc]`. `FullSimplify`, `Simplify`, and the special-cased `Identity` all satisfy this. A custom simplifier `myFn[expr_] := ...` would receive arguments it doesn't expect; wrap with `Function[{e, _, _}, myFn[e]]` if needed.
**Cache key is the symbolic expression.** The cache is keyed on `(f, xvec, simp, asm, tc)` as written, not on currently-bound values. If you call `HelmholtzDecomposition[{x^2}, {x}]`, then assign `x = 5`, then call again, the cached object is returned — even though `f` would now evaluate to `{25}`. This is the right semantic (the field is a symbolic expression, parameters bind at access) but worth knowing.
**Property access re-evaluates.** `hd["Field"]` returns the stored expression and re-evaluates against current bindings. So `hd["Field"]` after `x = 5` evaluates to a numeric vector. Same caveat.
## Citation and license
Please cite the original paper and Zenodo repository when using this code.
- [Zenodo repository](https://zenodo.org/records/7680297)
- Erhard Glötzl, Oliver Richters. *Helmholtz decomposition and potential functions for n-dimensional analytic vector fields*. [10.1016/j.jmaa.2023.127138](https://doi.org/10.1016/j.jmaa.2023.127138)