Skip to content

Commit 8e9155a

Browse files
luraessutkinis
andauthored
Add support for more grid operators (#81)
This PR adds support for second-order derivatives, including Laplacian and general `divg_grad` operators. --------- Co-authored-by: Ivan Utkin <iutkin@ethz.ch>
1 parent 856ebb5 commit 8e9155a

12 files changed

+398
-25
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "Chmy"
22
uuid = "33a72cf0-4690-46d7-b987-06506c2248b9"
33
authors = ["Ivan Utkin <iutkin@ethz.ch>, Ludovic Raess <ludovic.rass@gmail.com>, and contributors"]
4-
version = "0.1.23"
4+
version = "0.1.24"
55

66
[deps]
77
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"

docs/src/concepts/grid_operators.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,42 @@ Chmy.jl currently supports various finite difference operators for fields define
77
| $\frac{\partial}{\partial x} P$ | ` ∂x(P, g, I)` |
88
| $\frac{\partial}{\partial y} P$ | ` ∂y(P, g, I)` |
99
| $\frac{\partial}{\partial z} P$ | ` ∂z(P, g, I)` |
10-
| $\nabla P$ | ` divg(P, g, I)` |
10+
| $\frac{\partial^2}{\partial x^2} P$ | ` ∂²x(P, g, I)` |
11+
| $\frac{\partial^2}{\partial y^2} P$ | ` ∂²y(P, g, I)` |
12+
| $\frac{\partial^2}{\partial z^2} P$ | ` ∂²z(P, g, I)` |
13+
| $\nabla P$ | `divg(P, g, I)` |
14+
| $\Delta P$ | `lapl(P, g, I)` |
15+
| $\nabla \cdot χ \nabla P$ | `divg_grad(P, χ, g, I)` |
1116

1217
## Computing the Divergence of a Vector Field
1318

14-
To illustrate the usage of grid operators, we compute the divergence of an vector field $V$ using the `divg` function. We first allocate memory for required fields.
19+
To illustrate the usage of grid operators, we compute the divergence of a vector field $V$, the Laplacian of a scalar field $P$ and the divergence-gradient of a scalar field $C$ weighted by the coefficient $χ$ using the `divg`, `lapl` and `divg_grad` functions, respectively. We first allocate memory for required fields.
1520

1621
```julia
17-
V = VectorField(backend, grid)
22+
P = Field(backend, grid, Center())
23+
C = Field(backend, grid, Center())
24+
χ = Field(backend, grid, Center()) # works also for Vertex()
1825
∇V = Field(backend, grid, Center())
26+
V = VectorField(backend, grid)
1927
# use set! to set up the initial vector field...
2028
```
2129

2230
The kernel that computes the divergence needs to have the grid information passed as for other finite difference operators.
2331

2432
```julia
25-
@kernel inbounds = true function update_∇!(V, ∇V, g::StructuredGrid, O)
33+
@kernel inbounds = true function update!(∇V, V, P, C, χ, g::StructuredGrid, O)
2634
I = @index(Global, Cartesian)
2735
I = I + O
2836
∇V[I] = divg(V, g, I)
37+
P[I] = lapl(P, g, I)
38+
C[I] = divg_grad(C, χ, g, I)
2939
end
3040
```
3141

3242
The kernel can then be launched when required as we detailed in section [Kernels](./kernels.md).
3343

3444
```julia
35-
launch(arch, grid, update_∇! => (V, ∇V, grid))
45+
launch(arch, grid, update! => (V, V, P, C, χ, grid))
3646
```
3747

3848
## Masking
@@ -125,4 +135,3 @@ and can be launched with some launcher defined using `launch = Launcher(arch, gr
125135
```julia
126136
launch(arch, grid, interpolate_ρ! => (ρ, ρx, ρy, grid))
127137
```
128-

src/Chmy.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,19 @@ export
5151
xcenters, ycenters, zcenters,
5252

5353
# GridOperators
54-
left, right, δ, ∂,
54+
left, right, δ, ∂, ∂², ∂k∂,
5555
InterpolationRule, Linear, HarmonicLinear,
5656
itp, lerp, hlerp,
57-
divg, vmag,
57+
divg, divg_grad, lapl, vmag,
5858
AbstractMask, FieldMask, FieldMask1D, FieldMask2D, FieldMask3D, at,
5959

60-
leftx, rightx, δx, ∂x,
61-
lefty, righty, δy, ∂y,
62-
leftz, rightz, δz, ∂z,
60+
leftx, rightx, δx, ∂x, ∂²x, ∂k∂x,
61+
lefty, righty, δy, ∂y, ∂²y, ∂k∂y,
62+
leftz, rightz, δz, ∂z, ∂²z, ∂k∂z,
6363

64-
leftx_masked, rightx_masked, δx_masked, ∂x_masked,
65-
lefty_masked, righty_masked, δy_masked, ∂y_masked,
66-
leftz_masked, rightz_masked, δz_masked, ∂z_masked,
64+
leftx_masked, rightx_masked, δx_masked, ∂x_masked, ∂²x_masked, ∂k∂x_masked,
65+
lefty_masked, righty_masked, δy_masked, ∂y_masked, ∂²y_masked, ∂k∂y_masked,
66+
leftz_masked, rightz_masked, δz_masked, ∂z_masked, ∂²z_masked, ∂k∂z_masked,
6767

6868
# KernelLaunch
6969
Launcher,

src/GridOperators/GridOperators.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
module GridOperators
22

3-
export left, right, δ, ∂
3+
export left, right, δ, ∂, ∂², ∂k∂
44

55
export InterpolationRule, Linear, HarmonicLinear
66
export itp, lerp, hlerp
77

8-
export divg, vmag
8+
export divg, divg_grad, lapl, vmag
99

1010
export AbstractMask, FieldMask, FieldMask1D, FieldMask2D, FieldMask3D, at
1111

src/GridOperators/cartesian_field_operators.jl

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ for (dim, coord) in enumerate((:x, :y, :z))
33
_r = Symbol(:right, coord)
44
= Symbol(, coord)
55
_∂ = Symbol(:∂, coord)
6+
_∂² = Symbol(:∂², coord)
7+
_∂k∂ = Symbol(:∂k∂, coord)
68

79
@eval begin
8-
export $_δ, $_∂, $_l, $_r
10+
export $_δ, $_∂, $_∂², $_∂k∂, $_l, $_r
911

1012
"""
1113
$($_l)(f, I)
@@ -42,5 +44,23 @@ for (dim, coord) in enumerate((:x, :y, :z))
4244
@add_cartesian function $_∂(f::AbstractField, grid, I::Vararg{Integer,N}) where {N}
4345
(f, grid, Dim($dim), I...)
4446
end
47+
48+
"""
49+
$($_∂²)(f, grid, I)
50+
51+
Directional partial second derivative in $($(string(coord))) direction.
52+
"""
53+
@add_cartesian function $_∂²(f::AbstractField, grid, I::Vararg{Integer,N}) where {N}
54+
∂²(f, grid, Dim($dim), I...)
55+
end
56+
57+
"""
58+
$($_∂k∂)(f, k, grid, I)
59+
60+
Directional divergence of gradient times coefficient `k` in $($(string(coord))) direction.
61+
"""
62+
@add_cartesian function $_∂k∂(f::AbstractField, k::AbstractField, grid, I::Vararg{Integer,N}) where {N}
63+
∂k∂(f, k, grid, Dim($dim), I...)
64+
end
4565
end
4666
end

src/GridOperators/field_operators.jl

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
@add_cartesian function left(f::AbstractField, dim, I::Vararg{Integer,N}) where {N}
33
loc = location(f)
44
from = flipped(loc, dim)
5-
left(f, loc, from, dim, I...)
5+
return left(f, loc, from, dim, I...)
66
end
77

88
@add_cartesian function right(f::AbstractField, dim, I::Vararg{Integer,N}) where {N}
99
loc = location(f)
1010
from = flipped(loc, dim)
11-
right(f, loc, from, dim, I...)
11+
return right(f, loc, from, dim, I...)
1212
end
1313

1414
@add_cartesian function δ(f::AbstractField, dim, I::Vararg{Integer,N}) where {N}
@@ -20,10 +20,33 @@ end
2020
@add_cartesian function (f::AbstractField, grid, dim, I::Vararg{Integer,N}) where {N}
2121
loc = location(f)
2222
from = flipped(loc, dim)
23-
(f, loc, from, grid, dim, I...)
23+
return (f, loc, from, grid, dim, I...)
24+
end
25+
26+
@add_cartesian function ∂²(f::AbstractField, grid, dim, I::Vararg{Integer,N}) where {N}
27+
loc = location(f)
28+
from = location(f)
29+
return ∂²(f, loc, from, grid, dim, I...)
30+
end
31+
32+
@add_cartesian function ∂k∂(f::AbstractField, k::AbstractField, grid, dim, I::Vararg{Integer,N}) where {N}
33+
loc = location(f)
34+
from = location(f)
35+
return ∂k∂(f, k, loc, from, grid, dim, I...)
2436
end
2537

2638
# covariant derivatives
39+
"""
40+
divg(V, grid, I...)
41+
42+
Compute the divergence of a vector field `V` on a structured grid `grid`.
43+
This operation is performed along all dimensions of the grid.
44+
45+
## Arguments
46+
- `V`: The vector field represented as a named tuple of fields.
47+
- `grid`: The structured grid on which the operation is performed.
48+
- `I...`: The indices specifying the location on the grid
49+
"""
2750
@propagate_inbounds @generated function divg(V::NamedTuple{names,<:NTuple{N,AbstractField}}, grid::StructuredGrid{N}, I::Vararg{Integer,N}) where {names,N}
2851
quote
2952
@inline
@@ -35,6 +58,61 @@ end
3558
return divg(V, grid, Tuple(I)...)
3659
end
3760

61+
"""
62+
lapl(F, grid, I...)
63+
64+
Compute the Laplacian of a field `F` on a structured grid `grid`.
65+
This operation is performed along all dimensions of the grid.
66+
67+
## Arguments
68+
- `F`: The field whose Laplacian is to be computed.
69+
- `grid`: The structured grid on which the operation is performed.
70+
- `I...`: The indices specifying the location on the grid
71+
"""
72+
@propagate_inbounds @generated function lapl(F::AbstractField, grid::StructuredGrid{N}, I::Vararg{Integer,N}) where {N}
73+
quote
74+
@inline
75+
Base.Cartesian.@ncall $N (+) D -> ∂²(F, grid, Dim(D), I...)
76+
end
77+
end
78+
79+
@propagate_inbounds function lapl(F::AbstractField, grid::StructuredGrid{N}, I::CartesianIndex{N}) where {N}
80+
return lapl(F, grid, Tuple(I)...)
81+
end
82+
83+
"""
84+
divg_grad(F, K, grid, I...)
85+
86+
Compute the divergence of the gradient of a field `F` weighted by a coefficient `K` on a structured grid `grid`.
87+
This operation is performed along all dimensions of the grid.
88+
89+
## Arguments
90+
- `F`: The field whose gradient is to be computed.
91+
- `K`: The weighting field for the gradient.
92+
- `grid`: The structured grid on which the operation is performed.
93+
- `I`: The indices specifying the location on the grid.
94+
"""
95+
@propagate_inbounds @generated function divg_grad(F::AbstractField, K::AbstractField, grid::StructuredGrid{N}, I::Vararg{Integer,N}) where {N}
96+
quote
97+
@inline
98+
Base.Cartesian.@ncall $N (+) D -> ∂k∂(F, K, grid, Dim(D), I...)
99+
end
100+
end
101+
102+
@propagate_inbounds function divg_grad(F::AbstractField, K::AbstractField, grid::StructuredGrid{N}, I::CartesianIndex{N}) where {N}
103+
return divg_grad(F, K, grid, Tuple(I)...)
104+
end
105+
106+
"""
107+
vmag(V, grid, I...)
108+
109+
Compute the magnitude of a vector field `V` at a given grid location `I` in a structured grid `grid`.
110+
111+
## Arguments
112+
- `V`: A named tuple representing the vector field, where each component is an `AbstractField`.
113+
- `grid`: The structured grid on which the vector field is defined.
114+
- `I...`: The indices specifying the location on the grid.
115+
"""
38116
@propagate_inbounds @generated function vmag(V::NamedTuple{names,<:NTuple{N,AbstractField}}, grid::StructuredGrid{N}, I::Vararg{Integer,N}) where {names,N}
39117
quote
40118
@inline

src/GridOperators/masked_cartesian_field_operators.jl

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ for (dim, coord) in enumerate((:x, :y, :z))
33
_r = Symbol(:right, coord)
44
= Symbol(, coord)
55
_∂ = Symbol(:∂, coord)
6+
_∂² = Symbol(:∂², coord)
7+
_∂k∂ = Symbol(:∂k∂, coord)
68

79
@eval begin
8-
export $_δ, $_∂, $_l, $_r
10+
export $_δ, $_∂, $_∂², $_∂k∂, $_l, $_r
911

1012
"""
1113
$($_l)(f, ω, I)
@@ -42,5 +44,23 @@ for (dim, coord) in enumerate((:x, :y, :z))
4244
@add_cartesian function $_∂(f::AbstractField, ω::AbstractMask, grid, I::Vararg{Integer,N}) where {N}
4345
(f, ω, grid, Dim($dim), I...)
4446
end
47+
48+
"""
49+
$($_∂²)(f, ω, grid, I)
50+
51+
Directional partial second derivative in $($(string(coord))) direction, masked with `ω`.
52+
"""
53+
@add_cartesian function $_∂²(f::AbstractField, ω::AbstractMask, grid, I::Vararg{Integer,N}) where {N}
54+
∂²(f, ω, grid, Dim($dim), I...)
55+
end
56+
57+
"""
58+
$($_∂k∂)(f, k, ω, grid, I)
59+
60+
Directional divergence of gradient times coefficient `k` in $($(string(coord))) direction, masked with `ω`.
61+
"""
62+
@add_cartesian function $_∂k∂(f::AbstractField, k::AbstractField, ω::AbstractMask, grid, I::Vararg{Integer,N}) where {N}
63+
∂k∂(f, k, ω, grid, Dim($dim), I...)
64+
end
4565
end
4666
end

src/GridOperators/masked_field_operators.jl

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ end
1414
@add_cartesian function δ(f::AbstractField, ω::AbstractMask, dim, I::Vararg{Integer,N}) where {N}
1515
loc = location(f)
1616
from = flipped(loc, dim)
17-
δ(f, loc, from, ω, dim, I...)
17+
return δ(f, loc, from, ω, dim, I...)
1818
end
1919

2020
@add_cartesian function (f::AbstractField, ω::AbstractMask, grid, dim, I::Vararg{Integer,N}) where {N}
@@ -23,7 +23,31 @@ end
2323
return (f, loc, from, ω, grid, dim, I...)
2424
end
2525

26+
@add_cartesian function ∂²(f::AbstractField, ω::AbstractMask, grid, dim, I::Vararg{Integer,N}) where {N}
27+
loc = location(f)
28+
from = location(f)
29+
return ∂²(f, loc, from, ω, grid, dim, I...)
30+
end
31+
32+
@add_cartesian function ∂k∂(f::AbstractField, k::AbstractField, ω::AbstractMask, grid, dim, I::Vararg{Integer,N}) where {N}
33+
loc = location(f)
34+
from = location(f)
35+
return ∂k∂(f, k, loc, from, ω, grid, dim, I...)
36+
end
37+
2638
# covariant derivatives
39+
"""
40+
divg(V::NamedTuple{names,<:NTuple{N,AbstractField}}, ω::AbstractMask{T,N}, grid::StructuredGrid{N}, I::Vararg{Integer,N}) where {names,T,N}
41+
42+
Compute the divergence of a vector field `V` on a structured grid `grid`, using the mask `ω` to handle masked regions.
43+
This operation is performed along all dimensions of the grid.
44+
45+
## Arguments:
46+
- `V::NamedTuple{names,<:NTuple{N,AbstractField}}`: The vector field represented as a named tuple of fields.
47+
- `ω::AbstractMask`: The mask for the grid.
48+
- `grid::StructuredGrid{N}`: The structured grid on which the operation is performed.
49+
- `I`: The indices specifying the location on the grid (Tuple or Cartesian indices).
50+
"""
2751
@propagate_inbounds @generated function divg(V::NamedTuple{names,<:NTuple{N,AbstractField}},
2852
ω::AbstractMask{T,N},
2953
grid::StructuredGrid{N},
@@ -40,3 +64,64 @@ end
4064
I::CartesianIndex{N}) where {names,T,N}
4165
return divg(V, ω, grid, Tuple(I)...)
4266
end
67+
68+
"""
69+
lapl(F::AbstractField, ω::AbstractMask{T,N}, grid::StructuredGrid{N}, I::Vararg{Integer,N}) where {T,N}
70+
71+
Compute the Laplacian of a field `F` on a structured grid `grid`.
72+
This operation is performed along all dimensions of the grid.
73+
74+
## Arguments
75+
- `F::AbstractField`: The field whose Laplacian is to be computed.
76+
- `ω::AbstractMask`: The mask for the grid.
77+
- `grid::StructuredGrid{N}`: The structured grid on which the operation is performed.
78+
- `I`: The indices specifying the location on the grid (Tuple or Cartesian indices).
79+
"""
80+
@propagate_inbounds @generated function lapl(F::AbstractField,
81+
ω::AbstractMask{T,N},
82+
grid::StructuredGrid{N},
83+
I::Vararg{Integer,N}) where {T,N}
84+
quote
85+
@inline
86+
Base.Cartesian.@ncall $N (+) D -> ∂²(F, ω, grid, Dim(D), I...)
87+
end
88+
end
89+
90+
@propagate_inbounds function lapl(F::AbstractField,
91+
ω::AbstractMask{T,N},
92+
grid::StructuredGrid{N},
93+
I::CartesianIndex{N}) where {T,N}
94+
return lapl(F, ω, grid, Tuple(I)...)
95+
end
96+
97+
"""
98+
divg_grad(F::AbstractField, K::AbstractField, ω::AbstractMask{T,N}, grid::StructuredGrid{N}, I::Vararg{Integer,N}) where {T,N}
99+
100+
Compute the divergence of the diffusion flux of a field `F` weighted by a coefficient `K` on a structured grid `grid`.
101+
This operation is performed along all dimensions of the grid.
102+
103+
## Arguments
104+
- `F::AbstractField`: The field whose gradient is to be computed.
105+
- `K::AbstractField`: The weighting field for the gradient.
106+
- `ω::AbstractMask`: The mask for the grid.
107+
- `grid::StructuredGrid{N}`: The structured grid on which the operation is performed.
108+
- `I`: The indices specifying the location on the grid (Tuple or Cartesian indices).
109+
"""
110+
@propagate_inbounds @generated function divg_grad(F::AbstractField,
111+
K::AbstractField,
112+
ω::AbstractMask{T,N},
113+
grid::StructuredGrid{N},
114+
I::Vararg{Integer,N}) where {T,N}
115+
quote
116+
@inline
117+
Base.Cartesian.@ncall $N (+) D -> ∂k∂(F, K, ω, grid, Dim(D), I...)
118+
end
119+
end
120+
121+
@propagate_inbounds function divg_grad(F::AbstractField,
122+
K::AbstractField,
123+
ω::AbstractMask{T,N},
124+
grid::StructuredGrid{N},
125+
I::CartesianIndex{N}) where {T,N}
126+
return divg_grad(F, K, ω, grid, Tuple(I)...)
127+
end

0 commit comments

Comments
 (0)