Skip to content

Commit 5e579bb

Browse files
committed
Add plots for MOC variability
1 parent c00070a commit 5e579bb

2 files changed

Lines changed: 315 additions & 0 deletions

File tree

src/plot_MOCs_variability.jl

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
# # qsub -I -P xv83 -q express -l mem=47GB -l storage=scratch/gh0+scratch/xv83 -l walltime=01:00:00 -l ncpus=12
2+
# # This is Fig. S7? in Pasquier et al. (GRL, 2025) # TODO: check figure number
3+
4+
# using Pkg
5+
# Pkg.activate(".")
6+
# Pkg.instantiate()
7+
8+
# using OceanTransportMatrixBuilder
9+
# using NetCDF
10+
# using YAXArrays
11+
# using DataFrames
12+
# using DimensionalData
13+
# # using SparseArrays
14+
# # using LinearAlgebra
15+
# using Unitful
16+
# using Unitful: s, yr, m, kg
17+
# using CairoMakie
18+
# using GeoMakie
19+
# using Interpolations
20+
# using OceanBasins
21+
# using Statistics
22+
# using StatsBase
23+
# using NaNStatistics
24+
# using Format
25+
# using GeometryBasics
26+
# using LibGEOS
27+
# using GeometryOps
28+
29+
# include("plotting_functions.jl")
30+
31+
# model = "ACCESS-ESM1-5"
32+
33+
# time_windows = [
34+
# "Jan1850-Dec1859",
35+
# "Jan2030-Dec2039",
36+
# "Jan2090-Dec2099",
37+
# ]
38+
39+
# experiments = [
40+
# "historical",
41+
# "ssp370",
42+
# "ssp370",
43+
# ]
44+
# experiments2 = [
45+
# "historical",
46+
# "SSP-3.70",
47+
# "SSP-3.70",
48+
# ]
49+
50+
# members = ["r$(r)i1p1f1" for r in 1:40]
51+
52+
# lumpby = "month"
53+
# months = 1:12
54+
55+
56+
# # Gadi directory for input files
57+
# fixedvarsinputdir = "/scratch/xv83/TMIP/data/$model"
58+
# # Load areacello and volcello for grid geometry
59+
# volcello_ds = open_dataset(joinpath(fixedvarsinputdir, "volcello.nc"))
60+
# areacello_ds = open_dataset(joinpath(fixedvarsinputdir, "areacello.nc"))
61+
62+
63+
# # Load fixed variables in memory
64+
# areacello = readcubedata(areacello_ds.areacello)
65+
# volcello = readcubedata(volcello_ds.volcello)
66+
# lon = readcubedata(volcello_ds.lon)
67+
# lat = readcubedata(volcello_ds.lat)
68+
# lev = volcello_ds.lev
69+
# # Identify the vertices keys (vary across CMIPs / models)
70+
# volcello_keys = propertynames(volcello_ds)
71+
# lon_vertices_key = volcello_keys[findfirst(x -> occursin("lon", x) & occursin("vert", x), string.(volcello_keys))]
72+
# lat_vertices_key = volcello_keys[findfirst(x -> occursin("lat", x) & occursin("vert", x), string.(volcello_keys))]
73+
# lon_vertices = readcubedata(getproperty(volcello_ds, lon_vertices_key))
74+
# lat_vertices = readcubedata(getproperty(volcello_ds, lat_vertices_key))
75+
76+
# # Make makegridmetrics
77+
# gridmetrics = makegridmetrics(; areacello, volcello, lon, lat, lev, lon_vertices, lat_vertices)
78+
# (; lon_vertices, lat_vertices) = gridmetrics
79+
80+
# # Make indices
81+
# indices = makeindices(gridmetrics.v3D)
82+
83+
84+
# ϕsnorth = map(time_windows, experiments) do time_window, experiment
85+
86+
# ϕsnorth_ensemble = map(members) do member
87+
88+
# inputdir = "/scratch/xv83/TMIP/data/$model/$experiment/$member/$(time_window)"
89+
# cycloinputdir = joinpath(inputdir, "cyclomonth")
90+
# umo_ds = open_dataset(joinpath(cycloinputdir, "umo.nc"))
91+
# vmo_ds = open_dataset(joinpath(cycloinputdir, "vmo.nc"))
92+
# ψᵢGM_ds = open_dataset(joinpath(cycloinputdir, "tx_trans_gm.nc"))
93+
# ψⱼGM_ds = open_dataset(joinpath(cycloinputdir, "ty_trans_gm.nc"))
94+
# ψᵢsubmeso_ds = open_dataset(joinpath(cycloinputdir, "tx_trans_submeso.nc"))
95+
# ψⱼsubmeso_ds = open_dataset(joinpath(cycloinputdir, "ty_trans_submeso.nc"))
96+
# mlotst_ds = open_dataset(joinpath(cycloinputdir, "mlotst.nc"))
97+
98+
# mean_days_in_month = umo_ds.mean_days_in_month |> Array
99+
# w = Weights(mean_days_in_month)
100+
101+
# umo = dropdims(mean(readcubedata(umo_ds.umo), w; dims=:month), dims=:month)
102+
# vmo = dropdims(mean(readcubedata(vmo_ds.vmo), w; dims=:month), dims=:month)
103+
104+
# ψᵢGM = dropdims(mean(readcubedata(ψᵢGM_ds.tx_trans_gm), w; dims=:month), dims=:month)
105+
# ψⱼGM = dropdims(mean(readcubedata(ψⱼGM_ds.ty_trans_gm), w; dims=:month), dims=:month)
106+
# ψᵢsubmeso = dropdims(mean(readcubedata(ψᵢsubmeso_ds.tx_trans_submeso), w; dims=:month), dims=:month)
107+
# ψⱼsubmeso = dropdims(mean(readcubedata(ψⱼsubmeso_ds.ty_trans_submeso), w; dims=:month), dims=:month)
108+
109+
# # Replace missing values and convert to arrays
110+
# # I think latest YAXArrays converts _FillValues to missing
111+
# ψᵢGM = replace(ψᵢGM |> Array, missing => 0) .|> Float64
112+
# ψⱼGM = replace(ψⱼGM |> Array, missing => 0) .|> Float64
113+
# ψᵢsubmeso = replace(ψᵢsubmeso |> Array, missing => 0) .|> Float64
114+
# ψⱼsubmeso = replace(ψⱼsubmeso |> Array, missing => 0) .|> Float64
115+
116+
# # Also remove missings in umo and vmo
117+
# umo = replace(umo, missing => 0)
118+
# vmo = replace(vmo, missing => 0)
119+
120+
# # Take the vertical diff of zonal/meridional transport diagnostics to get their mass transport
121+
# (nx, ny, _) = size(ψᵢGM)
122+
# ϕᵢGM = diff([fill(0.0, nx, ny, 1);;; ψᵢGM |> Array], dims=3)
123+
# ϕⱼGM = diff([fill(0.0, nx, ny, 1);;; ψⱼGM |> Array], dims=3)
124+
# ϕᵢsubmeso = diff([fill(0.0, nx, ny, 1);;; ψᵢsubmeso |> Array], dims=3)
125+
# ϕⱼsubmeso = diff([fill(0.0, nx, ny, 1);;; ψⱼsubmeso |> Array], dims=3)
126+
127+
# # TODO fix incompatible dimensions betwewen umo and ϕᵢGM/ϕᵢsubmeso Dim{:i} and Dim{:xu_ocean}
128+
# ϕ = let umo = umo + ϕᵢGM + ϕᵢsubmeso, vmo = vmo + ϕⱼGM + ϕⱼsubmeso
129+
# facefluxesfrommasstransport(; umo, vmo, gridmetrics, indices)
130+
# end
131+
132+
# return ϕ.north
133+
# end
134+
135+
# end
136+
137+
138+
# # unpack model grid
139+
# (; lon, lat, zt, v3D,) = gridmetrics
140+
# lev = zt
141+
# # unpack indices
142+
# (; wet3D, N) = indices
143+
144+
# # basins
145+
# basin_keys = (:ATL, :INDOPAC, :GBL)
146+
# basin_strs = ("Atlantic", "Indo-Pacific", "Global")
147+
# OCEANS = OceanBasins.oceanpolygons()
148+
# isatlnoSO(lat, lon, o) = isatlantic(lat, lon, o) .& (lat .≥ -30)
149+
# isindopacific(lat, lon, o) = (isindian(lat, lon, o) .| ispacific(lat, lon, o)) .& (lat .≥ -30)
150+
# isglobal(lat, lon, o) = trues(size(lat))
151+
# basin_functions = (isatlnoSO, isindopacific, isglobal)
152+
# basin_values = (reshape(f(lat[:], lon[:], OCEANS), size(lat)) for f in basin_functions)
153+
# basins = (; (basin_keys .=> basin_values)...)
154+
# basin_latlims_values = [clamp.(0 .* (-5, +5) .+ extrema(lat[.!isnan.(v3D[:,:,1]) .& basin[:,:,1]]), -80, 80) for basin in basins]
155+
# basin_latlims = (; (basin_keys .=> basin_latlims_values)...)
156+
157+
158+
159+
# Plot meridional overturning circulation for each basin
160+
161+
ρ = 1035.0 # density (kg/m^3)
162+
163+
levels = -24:2:24
164+
colormap = cgrad(:curl, length(levels) + 1; categorical=true, rev=true)
165+
extendlow = colormap[1]
166+
extendhigh = colormap[end]
167+
colormap = cgrad(colormap[2:end-1]; categorical=true)
168+
169+
fig = Figure(size = (1000, 250length(ϕsnorth)), fontsize = 18)
170+
axs = Array{Any, 2}(undef, (length(ϕsnorth), length(basin_keys)))
171+
contours = Array{Any, 2}(undef, (length(ϕsnorth), length(basin_keys)))
172+
# for (icol, (basin_key, basin)) in enumerate(pairs(basins))
173+
174+
X = dropdims(maximum(lat, dims=1), dims=1)
175+
176+
foo = Dict()
177+
178+
for (irow, (x3Ds, time_window, experiment)) in enumerate(zip(ϕsnorth, time_windows, experiments2))
179+
foo[time_window] = fill(NaN, 40)
180+
for (member, x3D) in enumerate(x3Ds)
181+
for (icol, (basin_key, basin)) in enumerate(pairs(basins))
182+
183+
(basin_key == :ATL) || continue
184+
185+
x2D = dropdims(reverse(nancumsum(reverse(nansum(basin .* x3D, dims = 1), dims=3), dims = 3), dims=3), dims = 1) # kg/s
186+
x2Dmask = zonalaverage(1, gridmetrics; mask = basin) .> 0
187+
x2D[.!x2Dmask] .= +1e100
188+
x2D[:, 1:10] .= +1e100
189+
190+
# convert to Sv
191+
x2D = x2D / 1e6 / ρ # Sv
192+
193+
val, idx = findmin(x2D)
194+
195+
foo[time_window][member] = val
196+
197+
@show val, zt[idx[2]], X[idx[1]]
198+
199+
end
200+
end
201+
end
202+
203+
foo
204+
205+
foofoo
206+
207+
for _ in 1:10
208+
for _ in 1:10
209+
for _ in 1:10
210+
211+
212+
local ax = Axis(fig[irow, icol],
213+
backgroundcolor = :lightgray,
214+
xgridvisible = true, ygridvisible = true,
215+
xgridcolor = (:black, 0.05), ygridcolor = (:black, 0.05),
216+
ylabel = "depth (m)")
217+
218+
X = dropdims(maximum(lat, dims=1), dims=1)
219+
Y = zt
220+
Z = x2D
221+
co = contourf!(ax, X, Y, Z;
222+
levels,
223+
colormap,
224+
nan_color = :lightgray,
225+
extendlow,
226+
extendhigh,
227+
)
228+
translate!(co, 0, 0, -100)
229+
contours[irow, icol] = co
230+
231+
xlim = basin_latlims[basin_key]
232+
# basin2 = LONGTEXT[basin]
233+
234+
ax.yticks = (ztick, zticklabel)
235+
xticks = -90:30:90
236+
ax.xticks = (xticks, latticklabel.(xticks))
237+
ylims!(ax, zlim)
238+
# xlims!(ax, (-90, 90))
239+
xlims!(ax, xlim)
240+
241+
242+
hidexdecorations!(ax,
243+
label = irow < size(axs, 1), ticklabels = irow < size(axs, 1),
244+
ticks = irow < size(axs, 1), grid = false)
245+
hideydecorations!(ax,
246+
label = icol > 1, ticklabels = icol > 1,
247+
ticks = icol > 1, grid = false)
248+
249+
(icol == 1) && Label(fig[irow, 0]; text = "$experiment $(time_window[4:7])s", rotation = π/2, tellheight = false)
250+
251+
axs[irow, icol] = ax
252+
end
253+
254+
Label(fig[0, icol], "$(basin_strs[icol]) MOC", tellwidth = false)
255+
256+
257+
end
258+
259+
cb = Colorbar(fig[1:size(axs, 1), length(basin_keys) + 1], contours[1, 1];
260+
vertical = true, flipaxis = true,
261+
# ticks = (, cbarticklabelformat.(levels)),
262+
tickformat = x -> map(t -> replace(format("{:+d}", t), "-" => ""), x),
263+
label = "MOC (Sv)",
264+
)
265+
cb.height = Relative(0.666)
266+
267+
for (ibasin, xlims) in enumerate(basin_latlims)
268+
# Label(f[0, ibasin], LONGTEXT[basin], fontsize=20, tellwidth=false)
269+
colsize!(fig.layout, ibasin, Auto(xlims[2] - xlims[1]))
270+
end
271+
272+
rowgap!(fig.layout, 15)
273+
# rowgap!(fig.layout, 4, 15)
274+
# # # rowgap!(fig.layout, 5, 10)
275+
colgap!(fig.layout, 15)
276+
# title = "$model ensemble-mean MOC"
277+
# Label(fig[-1, 1:3]; text = title, fontsize = 20, tellwidth = false)
278+
279+
labels = [
280+
"a" "b" "c"
281+
"d" "e" "f"
282+
"g" "h" "i"
283+
]
284+
285+
labeloptions = (
286+
font = :bold,
287+
align = (:left, :bottom),
288+
offset = (5, 2),
289+
space = :relative,
290+
fontsize = 24
291+
)
292+
293+
for (ax, label) in zip(axs, labels)
294+
txt = text!(ax, 0, 0; text = label, labeloptions..., strokecolor = :white, strokewidth = 3)
295+
translate!(txt, 0, 0, 100)
296+
txt= text!(ax, 0, 0; text = label, labeloptions...)
297+
translate!(txt, 0, 0, 100)
298+
end
299+
300+
fig
301+
302+
outputdir = "output/plots"
303+
304+
# save plot
305+
outputfile = joinpath(outputdir, "$(model)_MOC_change_for_Reviewer2.png")
306+
@info "Saving MOC as image file:\n $(outputfile)"
307+
save(outputfile, fig)
308+
outputfile = joinpath(outputdir, "$(model)_MOC_change_for_Reviewer2.pdf")
309+
@info "Saving MOC as image file:\n $(outputfile)"
310+
save(outputfile, fig)
311+
312+
313+
314+
315+

0 commit comments

Comments
 (0)