Skip to content

Commit 1cada5b

Browse files
committed
Refactor + add density GM prototype
1 parent cbd2945 commit 1cada5b

11 files changed

+390
-314
lines changed

Project.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "OceanTransportMatrixBuilder"
22
uuid = "c2b4a04e-6049-4fc4-aa6a-5508a29a1e1c"
33
authors = ["Benoit Pasquier <briochemc@gmail.com> and contributors"]
4-
version = "0.2.8"
4+
version = "0.3.0"
55

66
[deps]
77
Distances = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7"
@@ -18,6 +18,7 @@ julia = "1.10"
1818
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
1919
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
2020
DimensionalData = "0703355e-b756-11e9-17c0-8b28908087d0"
21+
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
2122
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
2223
GibbsSeaWater = "9a22fb26-0b63-4589-b28e-8f9d0b5c3d05"
2324
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
@@ -32,4 +33,4 @@ YAXArrays = "c21b50f5-aa40-41ea-b809-c0f5e47bfa5c"
3233
Zarr = "0a941bbe-ad1d-11e8-39d9-ab76183a1d99"
3334

3435
[targets]
35-
test = ["DimensionalData", "GibbsSeaWater", "GLMakie", "LinearAlgebra", "Makie", "NaNStatistics", "NetCDF", "Test", "TestItemRunner", "TestItems", "Unitful", "YAXArrays", "CSV", "DataFrames", "Zarr"]
36+
test = ["Downloads", "DimensionalData", "GibbsSeaWater", "GLMakie", "LinearAlgebra", "Makie", "NaNStatistics", "NetCDF", "Test", "TestItemRunner", "TestItems", "Unitful", "YAXArrays", "CSV", "DataFrames", "Zarr"]

src/OceanTransportMatrixBuilder.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ using Distances: haversine
99

1010
include("preprocessing.jl")
1111
include("matrixbuilding.jl")
12-
include("grids.jl")
13-
include("topology.jl")
12+
include("gridcellgeometry.jl")
13+
include("gridtopology.jl")
1414
include("derivatives.jl")
1515
include("extratools.jl") # <- I think this should be in a separate "base" repo
1616

src/derivatives.jl

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ Returns the discrete difference
1212
# forward derivative in the i direction for centered data (A-grid)
1313
function ∂ᵢ₊(χ, modelgrid)
1414
χ = χ |> Array
15-
(; lon, lat, gridtype) = modelgrid
15+
(; lon, lat, arakawagrid) = modelgrid
1616
∂ᵢ₊χ = zeros(size(χ))
1717
for I in CartesianIndices(lon)
1818
P = (lon[I], lat[I])
19-
Iᵢ₊₁ = i₊₁(I, gridtype)
19+
Iᵢ₊₁ = i₊₁(I, arakawagrid)
2020
Pᵢ₊₁ = (lon[Iᵢ₊₁], lat[Iᵢ₊₁])
2121
d = haversine(P, Pᵢ₊₁)
2222
∂ᵢ₊χ[I, :] = (χ[Iᵢ₊₁, :] - χ[I, :]) / d
@@ -26,11 +26,11 @@ end
2626
# backward derivative in the i direction for centered data (A-grid)
2727
function ∂ᵢ₋(χ, modelgrid)
2828
χ = χ |> Array
29-
(; lon, lat, gridtype) = modelgrid
29+
(; lon, lat, arakawagrid) = modelgrid
3030
∂ᵢ₋χ = zeros(size(χ))
3131
for I in CartesianIndices(lon)
3232
P = (lon[I], lat[I])
33-
Iᵢ₋₁ = i₋₁(I, gridtype)
33+
Iᵢ₋₁ = i₋₁(I, arakawagrid)
3434
Pᵢ₋₁ = (lon[Iᵢ₋₁], lat[Iᵢ₋₁])
3535
d = haversine(P, Pᵢ₋₁)
3636
∂ᵢ₋χ[I, :] = (χ[I, :] - χ[Iᵢ₋₁, :]) / d
@@ -40,11 +40,11 @@ end
4040
# forward derivative in the j direction
4141
function ∂ⱼ₊(χ, modelgrid)
4242
χ = χ |> Array
43-
(; lon, lat, gridtype) = modelgrid
43+
(; lon, lat, arakawagrid) = modelgrid
4444
∂ⱼ₊χ = zeros(size(χ))
4545
for I in CartesianIndices(lon)
4646
P = (lon[I], lat[I])
47-
Iᵢ₊₁ = j₊₁(I, gridtype)
47+
Iᵢ₊₁ = j₊₁(I, arakawagrid)
4848
Pᵢ₊₁ = (lon[Iᵢ₊₁], lat[Iᵢ₊₁])
4949
d = haversine(P, Pᵢ₊₁)
5050
∂ⱼ₊χ[I, :] = (χ[Iᵢ₊₁, :] - χ[I, :]) / d
@@ -54,11 +54,11 @@ end
5454
# backward derivative in the j direction
5555
function ∂ⱼ₋(χ, modelgrid)
5656
χ = χ |> Array
57-
(; lon, lat, gridtype) = modelgrid
57+
(; lon, lat, arakawagrid) = modelgrid
5858
∂ⱼ₋χ = zeros(size(χ))
5959
for I in CartesianIndices(lon)
6060
P = (lon[I], lat[I])
61-
Iᵢ₋₁ = j₋₁(I, gridtype)
61+
Iᵢ₋₁ = j₋₁(I, arakawagrid)
6262
Pᵢ₋₁ = (lon[Iᵢ₋₁], lat[Iᵢ₋₁])
6363
d = haversine(P, Pᵢ₋₁)
6464
∂ⱼ₋χ[I, :] = (χ[I, :] - χ[Iᵢ₋₁, :]) / d
@@ -68,75 +68,82 @@ end
6868
# derivative in the k direction
6969
function ∂ₖ₊(χ, modelgrid)
7070
χ = χ |> Array
71-
(; zt, DZT3d, gridtype) = modelgrid
71+
(; zt, thkcello, arakawagrid) = modelgrid
7272
∂ₖ₊χ = zeros(size(χ))
7373
for I in CartesianIndices(χ)
74-
Iᵢ₊₁ = k₊₁(I, gridtype)
74+
Iᵢ₊₁ = k₊₁(I, arakawagrid)
7575
isnothing(Iᵢ₊₁) && continue
76-
h = (DZT3d[I] + DZT3d[Iᵢ₊₁]) / 2
76+
h = (thkcello[I] + thkcello[Iᵢ₊₁]) / 2
7777
∂ₖ₊χ[I] = (χ[Iᵢ₊₁] - χ[I]) / h
7878
end
7979
return ∂ₖ₊χ
8080
end
8181
# backward derivative in the k direction
8282
function ∂ₖ₋(χ, modelgrid)
8383
χ = χ |> Array
84-
(; zt, DZT3d, gridtype) = modelgrid
84+
(; zt, thkcello, arakawagrid) = modelgrid
8585
∂ₖ₋χ = zeros(size(χ))
8686
for I in CartesianIndices(χ)
87-
Iᵢ₋₁ = k₋₁(I, gridtype)
87+
Iᵢ₋₁ = k₋₁(I, arakawagrid)
8888
isnothing(Iᵢ₋₁) && continue
89-
h = (DZT3d[I] + DZT3d[Iᵢ₋₁]) / 2
89+
h = (thkcello[I] + thkcello[Iᵢ₋₁]) / 2
9090
∂ₖ₋χ[I] = (χ[I] - χ[Iᵢ₋₁]) / h
9191
end
9292
return ∂ₖ₋χ
9393
end
9494

9595
# interpolation in the i direction
9696
function itpₖ₊(χ, modelgrid)
97-
(; gridtype) = modelgrid
97+
(; arakawagrid) = modelgrid
9898
χ = χ |> Array
9999
itpₖ₊χ = zeros(size(χ))
100100
for I in CartesianIndices(χ)
101-
Iᵢ₊₁ = k₊₁(I, gridtype)
101+
Iᵢ₊₁ = k₊₁(I, arakawagrid)
102102
isnothing(Iᵢ₊₁) && continue
103103
itpₖ₊χ[I] = (χ[Iᵢ₊₁] + χ[I]) / 2
104104
end
105105
return itpₖ₊χ
106106
end
107107
function itpₖ₋(χ, modelgrid)
108-
(; gridtype) = modelgrid
108+
(; arakawagrid) = modelgrid
109109
χ = χ |> Array
110110
itpₖ₋χ = zeros(size(χ))
111111
for I in CartesianIndices(χ)
112-
Iᵢ₋₁ = k₋₁(I, gridtype)
112+
Iᵢ₋₁ = k₋₁(I, arakawagrid)
113113
isnothing(Iᵢ₋₁) && continue
114114
itpₖ₋χ[I] = (χ[Iᵢ₋₁] + χ[I]) / 2
115115
end
116116
return itpₖ₋χ
117117
end
118118
function itpᵢ₊(χ, modelgrid)
119-
(; gridtype) = modelgrid
119+
(; arakawagrid) = modelgrid
120120
χ = χ |> Array
121121
itpᵢ₊χ = zeros(size(χ))
122122
for I in CartesianIndices(χ)
123-
Iᵢ₊₁ = i₊₁(I, gridtype)
123+
Iᵢ₊₁ = i₊₁(I, arakawagrid)
124124
itpᵢ₊χ[I] = (χ[Iᵢ₊₁] + χ[I]) / 2
125125
end
126126
return itpᵢ₊χ
127127
end
128128
function itpⱼ₊(χ, modelgrid)
129-
(; gridtype) = modelgrid
129+
(; arakawagrid) = modelgrid
130130
χ = χ |> Array
131131
itpⱼ₊χ = zeros(size(χ))
132132
for I in CartesianIndices(χ)
133-
Iᵢ₊₁ = j₊₁(I, gridtype)
133+
Iᵢ₊₁ = j₊₁(I, arakawagrid)
134134
itpⱼ₊χ[I] = (χ[Iᵢ₊₁] + χ[I]) / 2
135135
end
136136
return itpⱼ₊χ
137137
end
138138

139+
"""
140+
bolus_GM_velocity(σ, modelgrid; κGM = 600, maxslope = 0.01)
141+
142+
Returns the bolus velocity field due to the Gent-McWilliams parameterization,
143+
computed from the neutral density field `σ` (or potential density, ρθ in kg/m³).
139144
145+
Note: This is experimental at this stage.
146+
"""
140147
function bolus_GM_velocity(σ, modelgrid; κGM = 600, maxslope = 0.01)
141148
# σ is neutral density (or potential density, ρθ in kg/m³)
142149
σ = replace(σ, missing => 0, NaN => 0)
@@ -193,13 +200,13 @@ end
193200

194201

195202
# function ∂ᵢ(χ, modelgrid, shift=0, d=:f)
196-
# (;lon, lat, gridtype) = modelgrid
203+
# (;lon, lat, arakawagrid) = modelgrid
197204
# m = 1
198205
# ∂ᵢχ = zeros(size(χ))
199206
# # Draw a line along coordinate i and compute the distances
200207
# d = dᵢ₊(lon, lat)
201208
# for I in CartesianIndices(lon)
202-
# movingI = SVector(ishift(I, gridtype, xxx))
209+
# movingI = SVector(ishift(I, arakawagrid, xxx))
203210
# i, j = I.I
204211
# x = SVector(0, d[i])
205212
# w = stencil(x, 0, χ)

src/grids.jl renamed to src/gridcellgeometry.jl

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11

22

3-
abstract type ArakawaGrid end
3+
abstract type ArakawaGridCell end
44

5-
struct AGrid <: ArakawaGrid
5+
struct AGridCell <: ArakawaGridCell
6+
u_pos::Symbol
7+
v_pos::Symbol
68
end
79

8-
struct BGrid <: ArakawaGrid
10+
struct BGridCell <: ArakawaGridCell
11+
u_pos::Symbol
12+
v_pos::Symbol
913
end
1014

11-
struct CGrid <: ArakawaGrid
15+
struct CGridCell <: ArakawaGridCell
16+
u_pos::Symbol
17+
v_pos::Symbol
1218
end
1319

1420

1521
"""
16-
arakawa, uo_pos, vo_pos, uo_relerr, vo_relerr = gridtype(uo_lon, uo_lat, vo_lon, vo_lat, modelgrid)
22+
arakawa = getarakawagrid(u_lon, u_lat, v_lon, v_lat, modelgrid)
1723
1824
Returns the type of the grid (A, B, or C), the grid position of the velocity points,
1925
and the error of that position relative to the perimeter of the cell.
@@ -43,14 +49,14 @@ The different Arakawa grids recongnized here are:
4349
where each grid is centered in C.
4450
Also returns the distances from the velocity points to the grid points.
4551
"""
46-
function gridtype(uo_lon, uo_lat, vo_lon, vo_lat, modelgrid)
52+
function getarakawagrid(u_lon, u_lat, v_lon, v_lat, modelgrid)
4753

4854
# Unpack modelgrid
4955
(; lon, lat, lon_vertices, lat_vertices) = modelgrid
5056

5157
i = j = 1
52-
uo_point = (uo_lon[i, j], uo_lat[i, j])
53-
vo_point = (vo_lon[i, j], vo_lat[i, j])
58+
u_point = (u_lon[i, j], u_lat[i, j])
59+
v_point = (v_lon[i, j], v_lat[i, j])
5460

5561
C = (lon[i, j], lat[i, j])
5662
SW = (lon_vertices[1, i, j], lat_vertices[1, i, j])
@@ -64,75 +70,74 @@ function gridtype(uo_lon, uo_lat, vo_lon, vo_lat, modelgrid)
6470

6571
cell = (; C, SW, SE, NE, NW, S, N, W, E)
6672

67-
uo_distances = (; (k => haversine(P, uo_point) for (k,P) in pairs(cell))...)
68-
vo_distances = (; (k => haversine(P, vo_point) for (k,P) in pairs(cell))...)
73+
u_distances = (; (k => haversine(P, u_point) for (k,P) in pairs(cell))...)
74+
v_distances = (; (k => haversine(P, v_point) for (k,P) in pairs(cell))...)
6975

70-
uo_distance, uo_pos = findmin(uo_distances)
71-
vo_distance, vo_pos = findmin(vo_distances)
76+
u_distance, u_pos = findmin(u_distances)
77+
v_distance, v_pos = findmin(v_distances)
7278

7379
# Arakawa grid type
74-
if uo_pos == vo_pos == :C
75-
arakawa = AGrid()
76-
elseif uo_pos == vo_pos && uo_pos (:NE, :NW, :SE, :SW)
77-
arakawa = BGrid()
78-
elseif uo_pos (:E, :W) && vo_pos (:N, :S)
79-
arakawa = CGrid()
80+
if u_pos == v_pos == :C
81+
arakawa = AGridCell(u_pos, v_pos)
82+
elseif u_pos == v_pos && u_pos (:NE, :NW, :SE, :SW)
83+
arakawa = BGridCell(u_pos, v_pos)
84+
elseif u_pos (:E, :W) && v_pos (:N, :S)
85+
arakawa = CGridCell(u_pos, v_pos)
8086
else
8187
error("Unknown Arakawa grid type")
8288
end
8389

8490
cellperimeter = haversine(SW, SE) + haversine(SE, NE) + haversine(NE, NW) + haversine(NW, SW)
85-
uo_relerr = uo_distance / cellperimeter
86-
vo_relerr = vo_distance / cellperimeter
91+
relerr = (u_distance + v_distance) / cellperimeter
8792

88-
return arakawa, uo_pos, vo_pos, uo_relerr, vo_relerr
93+
relerr > 0.01 && warn("Relative error in grid positions in $arakawa is $relerr")
94+
95+
return arakawa
8996

9097
end
9198

9299
"""
93-
uo, uo_lon, uo_lat, vo, vo_lon, vo_lat = interpolateontodefaultCgrid(uo, uo_lon, uo_lat, vo, vo_lon, vo_lat, modelgrid)
100+
u, u_lon, u_lat, v, v_lon, v_lat = interpolateontodefaultCgrid(u, u_lon, u_lat, v, v_lon, v_lat, modelgrid)
94101
95-
Interpolates the velocity fields `uo` and `vo` from B- or C-grid
102+
Interpolates the velocity fields `u` and `v` from B- or C-grid
96103
onto the default C-grid (centered on the cell faces).
97104
"""
98-
interpolateontodefaultCgrid(uo, uo_lon, uo_lat, vo, vo_lon, vo_lat, modelgrid) = interpolateontodefaultCgrid(uo, uo_lon, uo_lat, vo, vo_lon, vo_lat, modelgrid, gridtype(uo_lon, uo_lat, vo_lon, vo_lat, modelgrid))
99-
interpolateontodefaultCgrid(uo, uo_lon, uo_lat, vo, vo_lon, vo_lat, modelgrid, ::CGrid) = uo, uo_lon, uo_lat, vo, vo_lon, vo_lat
100-
interpolateontodefaultCgrid(uo, uo_lon, uo_lat, vo, vo_lon, vo_lat, modelgrid, ::AGrid) = error("Interpolation not implemented for this grid type")
101-
# TODO this is clumsy to have to pass the gridtype but then recompute it
102-
function interpolateontodefaultCgrid(uo, uo_lon, uo_lat, vo, vo_lon, vo_lat, modelgrid, arakawa::BGrid)
103-
104-
arakawa, uo_pos, vo_pos, uo_relerr, vo_relerr = gridtype(uo_lon, uo_lat, vo_lon, vo_lat, modelgrid)
105+
interpolateontodefaultCgrid(u, u_lon, u_lat, v, v_lon, v_lat, modelgrid) = interpolateontodefaultCgrid(u, u_lon, u_lat, v, v_lon, v_lat, modelgrid, getarakawagrid(u_lon, u_lat, v_lon, v_lat, modelgrid))
106+
interpolateontodefaultCgrid(u, u_lon, u_lat, v, v_lon, v_lat, modelgrid, ::CGridCell) = u, u_lon, u_lat, v, v_lon, v_lat
107+
interpolateontodefaultCgrid(u, u_lon, u_lat, v, v_lon, v_lat, modelgrid, ::AGridCell) = error("Interpolation not implemented for A-grid type")
108+
function interpolateontodefaultCgrid(u, u_lon, u_lat, v, v_lon, v_lat, modelgrid, arakawa::BGridCell)
105109

106-
uo_pos == vo_pos == :NE || error("Interpolation not implemented for this B-grid type")
110+
(; u_pos, v_pos) = arakawa
111+
u_pos == v_pos == :NE || error("Interpolation not implemented for this B-grid($u_pos,$v_pos) type")
107112

108-
_FillValue = uo.properties["_FillValue"]
113+
_FillValue = u.properties["_FillValue"]
109114

110-
# Make sure uo and vo are in memory
111-
uo = uo |> Array
112-
vo = vo |> Array
115+
# Make sure u and v are in memory
116+
u = u |> Array
117+
v = v |> Array
113118

114-
nx, ny, nz = size(uo)
119+
nx, ny, nz = size(u)
115120

116121
# unpack modelgrid
117122
(; lon_vertices, lat_vertices) = modelgrid
118123

119-
# It seems that uo/vo is NaN on boundaries (for ACCESS-ESM1-5)
120-
# and that umo/vmo were computed as if uo/vo were 0 on boundaries
124+
# It seems that u/v is NaN on boundaries (for ACCESS-ESM1-5)
125+
# and that umo/vmo were computed as if u/v were 0 on boundaries
121126
# so that's what we do here
122-
uo2 = replace(uo, _FillValue => 0.0)
123-
vo2 = replace(vo, _FillValue => 0.0)
124-
uo2 = 0.5(uo2 + [fill(0.0, nx, 1, nz);; uo2[:, 1:end-1, :]])
125-
vo2 = 0.5(vo2 + [fill(0.0, 1, ny, nz); vo2[1:end-1, :, :]])
127+
u2 = replace(u, _FillValue => 0.0)
128+
v2 = replace(v, _FillValue => 0.0)
129+
u2 = 0.5(u2 + [fill(0.0, nx, 1, nz);; u2[:, 1:end-1, :]])
130+
v2 = 0.5(v2 + [fill(0.0, 1, ny, nz); v2[1:end-1, :, :]])
126131
SE_points = [(lon, lat) for (lon, lat) in zip(lon_vertices[2, :, :], lat_vertices[2, :, :])]
127132
NE_points = [(lon, lat) for (lon, lat) in zip(lon_vertices[3, :, :], lat_vertices[3, :, :])]
128133
NW_points = [(lon, lat) for (lon, lat) in zip(lon_vertices[4, :, :], lat_vertices[4, :, :])]
129-
uo2_points = [midpointonsphere(SE, NE) for (SE, NE) in zip(NE_points, SE_points)]
130-
vo2_points = [midpointonsphere(NE, NW) for (NE, NW) in zip(NW_points, NE_points)]
131-
uo2_lon = [P[1] for P in uo2_points]
132-
uo2_lat = [P[2] for P in uo2_points]
133-
vo2_lon = [P[1] for P in vo2_points]
134-
vo2_lat = [P[2] for P in vo2_points]
135-
return uo2, uo2_lon, uo2_lat, vo2, vo2_lon, vo2_lat
134+
u2_points = [midpointonsphere(SE, NE) for (SE, NE) in zip(NE_points, SE_points)]
135+
v2_points = [midpointonsphere(NE, NW) for (NE, NW) in zip(NW_points, NE_points)]
136+
u2_lon = [P[1] for P in u2_points]
137+
u2_lat = [P[2] for P in u2_points]
138+
v2_lon = [P[1] for P in v2_points]
139+
v2_lat = [P[2] for P in v2_points]
140+
return u2, u2_lon, u2_lat, v2, v2_lon, v2_lat
136141

137142
end
138143

0 commit comments

Comments
 (0)