-
Notifications
You must be signed in to change notification settings - Fork 186
/
grid_metrics.jl
143 lines (105 loc) · 4.16 KB
/
grid_metrics.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using Adapt
using Oceananigans.Operators
using Oceananigans.Fields: default_indices
abstract type AbstractGridMetric end
struct XSpacingMetric <: AbstractGridMetric end
struct YSpacingMetric <: AbstractGridMetric end
struct ZSpacingMetric <: AbstractGridMetric end
metric_function_prefix(::XSpacingMetric) = :Δx
metric_function_prefix(::YSpacingMetric) = :Δy
metric_function_prefix(::ZSpacingMetric) = :Δz
struct XAreaMetric <: AbstractGridMetric end
struct YAreaMetric <: AbstractGridMetric end
struct ZAreaMetric <: AbstractGridMetric end
metric_function_prefix(::XAreaMetric) = :Ax
metric_function_prefix(::YAreaMetric) = :Ay
metric_function_prefix(::ZAreaMetric) = :Az
struct VolumeMetric <: AbstractGridMetric end
metric_function_prefix(::VolumeMetric) = :V
# Convenient instances for users
const Δx = XSpacingMetric()
const Δy = YSpacingMetric()
"""
Δz = ZSpacingMetric()
Instance of `ZSpacingMetric` that generates `BinaryOperation`s
between `AbstractField`s and the vertical grid spacing evaluated
at the same location as the `AbstractField`.
`Δx` and `Δy` play a similar role for horizontal grid spacings.
Example
=======
```jldoctest
julia> using Oceananigans
julia> using Oceananigans.AbstractOperations: Δz
julia> c = CenterField(RectilinearGrid(size=(1, 1, 1), extent=(1, 2, 3)));
julia> c_dz = c * Δz # returns BinaryOperation between Field and GridMetricOperation
BinaryOperation at (Center, Center, Center)
├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×1 halo
└── tree:
* at (Center, Center, Center)
├── 1×1×1 Field{Center, Center, Center} on RectilinearGrid on CPU
└── Δzᶜᶜᶜ at (Center, Center, Center)
julia> c .= 1;
julia> c_dz[1, 1, 1]
3.0
```
"""
const Δz = ZSpacingMetric()
const Ax = XAreaMetric()
const Ay = YAreaMetric()
const Az = ZAreaMetric()
"""
volume = VolumeMetric()
Instance of `VolumeMetric` that generates `BinaryOperation`s
between `AbstractField`s and their cell volumes. Summing
this `BinaryOperation` yields an integral of `AbstractField`
over the domain.
Example
=======
```jldoctest
julia> using Oceananigans
julia> using Oceananigans.AbstractOperations: volume
julia> c = CenterField(RectilinearGrid(size=(2, 2, 2), extent=(1, 2, 3)));
julia> c .= 1;
julia> c_dV = c * volume
BinaryOperation at (Center, Center, Center)
├── grid: 2×2×2 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×2×2 halo
└── tree:
* at (Center, Center, Center)
├── 2×2×2 Field{Center, Center, Center} on RectilinearGrid on CPU
└── Vᶜᶜᶜ at (Center, Center, Center)
julia> c_dV[1, 1, 1]
0.75
julia> sum(c_dV)
6.0
```
"""
const volume = VolumeMetric()
"""
metric_function(loc, metric::AbstractGridMetric)
Return the function associated with `metric::AbstractGridMetric`
at `loc`ation.
"""
function metric_function(loc, metric::AbstractGridMetric)
code = Tuple(interpolation_code(ℓ) for ℓ in loc)
prefix = metric_function_prefix(metric)
metric_function_symbol = Symbol(prefix, code...)
return eval(metric_function_symbol)
end
struct GridMetricOperation{LX, LY, LZ, G, T, M} <: AbstractOperation{LX, LY, LZ, G, T}
metric :: M
grid :: G
function GridMetricOperation{LX, LY, LZ}(metric::M, grid::G) where {LX, LY, LZ, M, G}
T = eltype(grid)
return new{LX, LY, LZ, G, T, M}(metric, grid)
end
end
Adapt.adapt_structure(to, gm::GridMetricOperation{LX, LY, LZ}) where {LX, LY, LZ} =
GridMetricOperation{LX, LY, LZ}(Adapt.adapt(to, gm.metric),
Adapt.adapt(to, gm.grid))
on_architecture(to, gm::GridMetricOperation{LX, LY, LZ}) where {LX, LY, LZ} =
GridMetricOperation{LX, LY, LZ}(on_architecture(to, gm.metric),
on_architecture(to, gm.grid))
@inline Base.getindex(gm::GridMetricOperation, i, j, k) = gm.metric(i, j, k, gm.grid)
indices(::GridMetricOperation) = default_indices(3)
# Special constructor for BinaryOperation
GridMetricOperation(L, metric, grid) = GridMetricOperation{L[1], L[2], L[3]}(metric_function(L, metric), grid)