An open API service indexing awesome lists of open source software.

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

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)