Skip to content

Commit 85ed4cc

Browse files
authored
Merge pull request #815 from CliMA/ln/hierarchy-plots
Hierarchy visualizations
2 parents f2f6a6e + 19bf5da commit 85ed4cc

File tree

6 files changed

+255
-4
lines changed

6 files changed

+255
-4
lines changed

.buildkite/hierarchies/pipeline.yml

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
agents:
22
queue: new-central
33
slurm_time: 24:00:00
4-
modules: climacommon/2024_03_18
4+
modules: climacommon/2024_05_27
55

66
env:
77
JULIA_LOAD_PATH: "${JULIA_LOAD_PATH}:${BUILDKITE_BUILD_CHECKOUT_PATH}/.buildkite"
@@ -68,6 +68,16 @@ steps:
6868
slurm_gpus: 1
6969
modules: common
7070

71+
- label: "Clima: GPU ClimaCoupler Cloudless Aquaplanet"
72+
command:
73+
- "julia --color=yes --project=experiments/ClimaEarth/ experiments/ClimaEarth/run_cloudless_aquaplanet.jl"
74+
artifact_paths: "cloudless_aquaplanet/cloudless_aquaplanet/clima_atmos/*"
75+
agents:
76+
queue: clima
77+
slurm_mem: 20GB
78+
slurm_gpus: 1
79+
modules: common
80+
7181
- label: "Clima: GPU ClimaCoupler Cloudy Aquaplanet"
7282
command:
7383
- "julia --color=yes --project=experiments/ClimaEarth/ experiments/ClimaEarth/run_cloudy_aquaplanet.jl"

.buildkite/longruns/pipeline.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
agents:
22
queue: new-central
33
slurm_time: 24:00:00
4-
modules: climacommon/2024_04_30
4+
modules: climacommon/2024_05_27
55

66
env:
77
JULIA_LOAD_PATH: "${JULIA_LOAD_PATH}:${BUILDKITE_BUILD_CHECKOUT_PATH}/.buildkite"

.buildkite/pipeline.yml

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
agents:
22
queue: new-central
33
slurm_time: 4:00:00
4-
modules: climacommon/2024_04_30
4+
modules: climacommon/2024_05_27
55

66
env:
77
JULIA_LOAD_PATH: "${JULIA_LOAD_PATH}:${BUILDKITE_BUILD_CHECKOUT_PATH}/.buildkite"
@@ -397,6 +397,16 @@ steps:
397397
agents:
398398
slurm_mem: 20GB
399399

400+
- label: ":construction: Cloudless Aquaplanet"
401+
key: "cloudless_aquaplanet"
402+
command:
403+
- sed 's/t_end = "1000days"/t_end = "1days"/' experiments/ClimaEarth/run_cloudless_aquaplanet.jl > experiments/ClimaEarth/run_cloudless_aquaplanet_short.jl
404+
- "julia --color=yes --project=experiments/ClimaEarth/ experiments/ClimaEarth/run_cloudless_aquaplanet_short.jl"
405+
artifact_paths: "cloudless_aquaplanet/cloudless_aquaplanet/clima_atmos/*"
406+
407+
agents:
408+
slurm_mem: 20GB
409+
400410
- label: ":construction: Cloudy Aquaplanet"
401411
key: "cloudy_aquaplanet"
402412
command:
@@ -417,7 +427,14 @@ steps:
417427
agents:
418428
slurm_mem: 20GB
419429

420-
430+
- wait
431+
- label: ":construction: Hierarchy plots"
432+
key: "hierarchy_plots"
433+
command:
434+
- "julia --color=yes --project=experiments/ClimaEarth/ experiments/ClimaEarth/hierarchy/climate_plots.jl"
435+
artifact_paths: "paper_figs/*"
436+
agents:
437+
slurm_mem: 20GB
421438

422439
- group: "GPU integration tests"
423440
steps:
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Hierarchy Experiments for Global Climate Models
2+
3+
This directory contains a series of experiments that demonstrate the use of hierarchical modeling using ClimaEarth, with a focus on the atmospheric component. The hierarchy spans from a simple dry atmosphere to a more complex moist atmosphere with clouds and an Earth-like surface. The experiments are designed to be run in sequence, with each experiment building on the previous one. Each experiment is a self-contained run script that contains all necessary configurations.
4+
5+
## Experiments
6+
- Dry Held-Suarez
7+
- Moist Held-Suarez
8+
- Cloudless Aquaplanet
9+
- Cloudy Aquaplanet
10+
- Cloudy Slabplanet
11+
12+
## Postprocessing
13+
We provide a simple postprocessing script `climate_plots.jl` that can be used to visualize the results of each experiment, with some helper functions in `plot_helper.jl`.
14+
15+
## Associated publication
16+
- (in preparation)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# paper_figs
2+
using NCDatasets
3+
using Statistics
4+
using Plots
5+
6+
import Interpolations: LinearInterpolation
7+
import DelimitedFiles: writedlm, readdlm
8+
9+
include("plot_helper.jl")
10+
11+
for job_id in ["dry_held_suarez", "moist_held_suarez"]
12+
if isinteractive()
13+
DATA_DIR = "experiments/ClimaEarth/$job_id/$job_id/clima_atmos/output_active/"
14+
else
15+
build = ENV["BUILDKITE_BUILD_NUMBER"]
16+
DATA_DIR = "/central/scratch/esm/slurm-buildkite/climacoupler-ci/$build/climacoupler-ci/$job_id/$job_id/clima_atmos/output_active/"
17+
end
18+
19+
reduction = "6h_inst"
20+
PLOT_DIR = "paper_figs"
21+
22+
mkpath(PLOT_DIR)
23+
24+
# SUPPLEMENTAL: animation of surface temperature
25+
ta_sfc, lat, lon, z, time = get_nc_data_all("ta", reduction, DATA_DIR)
26+
anim = Plots.@animate for i in 1:size(ta_sfc, 1)
27+
Plots.contourf(
28+
lon,
29+
lat,
30+
ta_sfc[i, :, :, 1]',
31+
xlabel = "Longitude",
32+
ylabel = "Latitude",
33+
title = "$var",
34+
color = :viridis,
35+
clims = (260, 315),
36+
)
37+
end
38+
Plots.mp4(anim, joinpath(PLOT_DIR, "anim_ta_sfc.mp4"), fps = 10)
39+
40+
# Figure 2: climatology
41+
# this plots the time-mean (upper-level and surface) slices and zonal means of
42+
# the mass streamfunction, zonal wind, meridional wind, temperature, max. Eady growth rate, and vertical velocity
43+
vars = ["mass_strf", "va", "ua", "ta", "egr", "wa"]
44+
for var in vars
45+
plot_climate(var, DATA_DIR, PLOT_DIR, job_id, reduction = reduction, interpolate_to_pressure = true)
46+
end
47+
48+
# Figure 4: storm track diagnostics
49+
# this extracts the eddy heat flux and plots its climatology
50+
lev_st = 6
51+
ta_zm, ta_sfc, lat, lon, z = mean_climate_data("ta", reduction, DATA_DIR, lev_i = lev_st)
52+
va_zm, va_sfc, lat, lon, z = mean_climate_data("va", reduction, DATA_DIR, lev_i = lev_st)
53+
vT_zm, vT_sfc, lat, lon, z = mean_climate_data("vt", reduction, DATA_DIR, lev_i = lev_st)
54+
heat_flux_zm = vT_zm .- va_zm .* ta_zm
55+
56+
pa_zm, ~, ~, ~, ~ = mean_climate_data("pfull", reduction, DATA_DIR)
57+
pa_zm = pa_zm ./ 100 # convert to hPa
58+
pa_grid = [950, 800, 700, 600, 500, 400, 300, 200, 50]
59+
60+
heat_flux_int_zm = interpolate_to_pressure_coord_2d(heat_flux_zm, pa_zm, pa_grid)
61+
Plots.contourf(
62+
lat,
63+
-pa_grid,
64+
heat_flux_int_zm',
65+
xlabel = "Latitude (deg N)",
66+
ylabel = "Pressure (hPa)",
67+
title = "Heat flux",
68+
color = :viridis,
69+
ylims = (-pa_grid[1], -pa_grid[end]),
70+
yticks = (-pa_grid, pa_grid),
71+
)
72+
png(joinpath(PLOT_DIR, "$(job_id)_heat_flux.png"))
73+
74+
# Figure 5: storm track diagnostics reduced to timeseries
75+
# this plots the eddy heat flux and max. Eady growth rate in a sectorial selection
76+
lev_i, lat_s_i, lat_n_i, lon_w_i, lon_e_i = lev_st, 60, 75, 1, 30
77+
println(
78+
"Sectorial selevtion for timeseries: \n level: $(z[lev_i]), lat: $(lat[lat_s_i]) to $(lat[lat_n_i]), lon: $(lon[lon_w_i]) to $(lon[lon_e_i])",
79+
)
80+
81+
egr_all, lat, lon, z, time = get_nc_data_all("egr", reduction, DATA_DIR)
82+
egr_t = point_timeseries_data(egr_all, [lon_w_i, lon_e_i], [lat_s_i, lat_n_i], lev_i)
83+
84+
vT_all, lat, lon, z, time = get_nc_data_all("vt", reduction, DATA_DIR)
85+
va_all, lat, lon, z, time = get_nc_data_all("va", reduction, DATA_DIR)
86+
ta_all, lat, lon, z, time = get_nc_data_all("ta", reduction, DATA_DIR)
87+
heat_flux_all = vT_all .- va_all .* ta_all
88+
heat_flux_t = point_timeseries_data(heat_flux_all, [lon_w_i, lon_e_i], [lat_s_i, lat_n_i], lev_i)
89+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# plot_helper
2+
3+
"""
4+
get_nc_data_all(var, red, DATA_DIR)
5+
6+
Reads the netcdf file for the variable `var` and reduction `red` from the directory `DATA_DIR` and returns the variable, lat, lon, z, and time.
7+
"""
8+
get_nc_data_all = (var, red, DATA_DIR) -> begin
9+
ds = NCDataset("$DATA_DIR/$(var)_$red.nc")
10+
var = ds["$var"][:, :, :, :]
11+
lat = ds["lat"][:]
12+
lon = ds["lon"][:]
13+
z = ds["z"][:]
14+
time = ds["time"][:]
15+
close(ds)
16+
return var, lat, lon, z, time
17+
end
18+
19+
"""
20+
mean_climate_data(varname, reduction, DATA_DIR; lev_i = 1, spinup=1)
21+
22+
Postprocesses the climate data for the variable `varname` and `reduction` from the directory `DATA_DIR`. Returns the zonal mean and horizontal surface slice mean of the variable.
23+
"""
24+
mean_climate_data =
25+
(varname, reduction, DATA_DIR; lev_i = 1, spinup = 1) -> begin
26+
27+
var, lat, lon, z, time = get_nc_data_all(varname, reduction, DATA_DIR)
28+
@assert spinup < size(var, 1)
29+
30+
var_time_zonal_mean = mean(var[spinup:end, :, :, :], dims = (1, 2))[1, 1, :, :]
31+
var_time_mean_sfc = mean(var[spinup:end, :, :, :], dims = (1))[1, :, :, lev_i]
32+
33+
return var_time_zonal_mean, var_time_mean_sfc, lat, lon, z
34+
end
35+
36+
"""
37+
point_timeseries_data(variable, lon_i, lat_i, lev_i)
38+
39+
Returns the time series data for the variable `variable` at the indices `lon_i`, `lat_i`, and `lev_i`.
40+
"""
41+
point_timeseries_data =
42+
(variable, lon_i, lat_i, lev_i) -> begin
43+
44+
variable_time_mean = mean(variable[:, lon_i[1]:lon_i[2], lat_i[1]:lat_i[2], lev_i], dims = (2, 3))[:, 1, 1]
45+
46+
return variable_time_mean
47+
end
48+
49+
"""
50+
plot_climate(var, DATA_DIR, PLOT_DIR, job_id; reduction = "inst", interpolate_to_pressure = false)
51+
52+
Plots the zonal mean and horizontal surface slice mean of the variable `var` from the directory `DATA_DIR` and saves the plots in the directory `PLOT_DIR`.
53+
"""
54+
function plot_climate(var, DATA_DIR, PLOT_DIR, job_id; reduction = "inst", interpolate_to_pressure = false)
55+
strf_zm, strf_sfc, lat, lon, z = mean_climate_data(var, reduction, DATA_DIR)
56+
strf_zm, strf_upper, lat, lon, z = mean_climate_data(var, reduction, DATA_DIR, lev_i = 10)
57+
58+
# vertical-lat plot of zonal and time mean
59+
if interpolate_to_pressure
60+
pa_zm, ~, ~, ~, ~ = mean_climate_data("pfull", reduction, DATA_DIR)
61+
pa_zm = pa_zm ./ 100 # convert to hPa
62+
pa_grid = [950, 800, 700, 600, 500, 400, 300, 200, 50]
63+
strf_zm = interpolate_to_pressure_coord_2d(strf_zm, pa_zm, pa_grid)
64+
Plots.contourf(
65+
lat,
66+
-pa_grid,
67+
strf_zm',
68+
xlabel = "Latitude (deg N)",
69+
ylabel = "Pressure (hPa)",
70+
title = "$var",
71+
color = :viridis,
72+
ylims = (-pa_grid[1], -pa_grid[end]),
73+
yticks = (-pa_grid, pa_grid),
74+
)# , clims=(-1e10, 1e10))
75+
png(joinpath(PLOT_DIR, "$(job_id)_$(var)_pa.png"))
76+
else
77+
Plots.contourf(
78+
lat,
79+
z,
80+
strf_zm',
81+
xlabel = "Latitude",
82+
ylabel = "Height (km)",
83+
title = "$var",
84+
color = :viridis,
85+
ylims = (0, 3e4),
86+
yscale = :log10,
87+
yticks = ([1e3, 5e3, 10e3, 20e3, 30e3], ["1", "5", "10", "20", "30"]),
88+
)# , clims=(-1e10, 1e10)
89+
png(joinpath(PLOT_DIR, "$(job_id)_$var.png"))
90+
end
91+
92+
# horizontal slices
93+
Plots.contourf(lon, lat, strf_sfc', xlabel = "Longitude", ylabel = "Latitude", title = "$var", color = :viridis)#, clims=(-1e10, 1e10))
94+
png(joinpath(PLOT_DIR, "$(job_id)_$(var)_sfc.png"))
95+
96+
Plots.contourf(lon, lat, strf_upper', xlabel = "Longitude", ylabel = "Latitude", title = "$var", color = :viridis)#, clims=(-1e10, 1e10))
97+
png(joinpath(PLOT_DIR, "$(job_id)_$(var)_10km.png"))
98+
end
99+
100+
"""
101+
interpolate_to_pressure_coord_2d(var_zm, pa, pa_grid)
102+
103+
Interpolates the 2D variable `var_zm` to the pressure grid `pa_grid` using the pressure values `pa`.
104+
"""
105+
function interpolate_to_pressure_coord_2d(var_zm, pa, pa_grid)
106+
var_on_pa = zeros(size(var_zm, 1), length(pa_grid))
107+
for lat_i in collect(1:size(var_zm, 1))
108+
# Extract ua and corresponding ta values
109+
var_values = var_zm[lat_i, :]
110+
pa_values = pa[lat_i, :]
111+
112+
# Interpolate ua onto ta_grid
113+
for (pa_j, pa_val) in enumerate(pa_grid)
114+
itp_var = LinearInterpolation(-pa_values, var_values)
115+
var_on_pa[lat_i, pa_j] = itp_var(-pa_val)
116+
end
117+
end
118+
return var_on_pa
119+
end

0 commit comments

Comments
 (0)