Skip to content

Commit 85467c4

Browse files
authored
Merge pull request #2567 from CliMA/ln/precip-energy
Track precipitation energy in conservation check
2 parents 233d642 + e417da0 commit 85467c4

18 files changed

+190
-67
lines changed

.buildkite/pipeline.yml

+10-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ steps:
123123
- label: ":computer: orographic gravity wave parameterization unit test for 3d calculation"
124124
command: "julia --color=yes --project=examples test/orographic_gravity_wave/ogwd_3d.jl"
125125
artifact_paths: "orographic_gravity_wave_test_3d/*"
126-
126+
127127
- label: ":computer: single column non-orographic gravity wave parameterization"
128128
command: >
129129
julia --color=yes --project=examples examples/hybrid/driver.jl
@@ -294,6 +294,15 @@ steps:
294294
slurm_mem: 20GB
295295
slurm_constraint: icelake|cascadelake|skylake|epyc
296296

297+
- label: ":computer: aquaplanet (ρe_tot) slabocean equilmoist allsky radiation monin_obukhov varying insolation"
298+
command: >
299+
julia --color=yes --project=examples examples/hybrid/driver.jl
300+
--config_file $CONFIG_PATH/aquaplanet_rhoe_equil_clearsky_tvinsol_0M_slabocean.yml
301+
artifact_paths: "aquaplanet_rhoe_equil_clearsky_tvinsol_0M_slabocean/*"
302+
agents:
303+
slurm_mem: 20GB
304+
slurm_constraint: icelake|cascadelake|skylake|epyc
305+
297306
- group: "Sphere Examples (Topography)"
298307
steps:
299308

config/default_configs/default_config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ reference_job_id:
122122
Identifier of job to use as the "reference" solution in the quicklook plot; the current job's results get compared to the results of the quicklook job on the main branch
123123
value: ~
124124
vert_diff:
125-
help: "Vertical diffusion [`false` (default), `VerticalDiffusion`, `true` (defaults to `VerticalDiffusion`)]"
125+
help: "Vertical diffusion [`false` (default), `VerticalDiffusion`, `true` (defaults to `VerticalDiffusion`), `FriersonDiffusion`]"
126126
value: "false"
127127
hyperdiff:
128128
help: "Hyperdiffusion [`ClimaHyperdiffusion` (or `true`; default), `none` (or `false`)]"

config/longrun_configs/longrun_aquaplanet_amip.yml

+11-11
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,28 @@ z_max: 55000.0
33
z_elem: 63
44
dz_bottom: 30.0
55
dz_top: 3000.0
6-
moist: "equil"
7-
precip_model: "0M"
6+
moist: "equil"
7+
precip_model: "0M"
88
override_τ_precip: false
9-
rad: "allskywithclear"
9+
rad: "allskywithclear"
1010
idealized_insolation: false
1111
dt_rad: "1hours"
12-
surface_setup: "DefaultMoninObukhov"
13-
turbconv: "diagnostic_edmfx"
12+
surface_setup: "DefaultMoninObukhov"
13+
turbconv: "diagnostic_edmfx"
1414
implicit_diffusion: true
1515
approximate_linear_solve_iters: 2
1616
prognostic_tke: true
17-
edmfx_upwinding: "first_order"
18-
edmfx_entr_model: "Generalized"
19-
edmfx_detr_model: "Generalized"
20-
edmfx_nh_pressure: true
17+
edmfx_upwinding: "first_order"
18+
edmfx_entr_model: "Generalized"
19+
edmfx_detr_model: "Generalized"
20+
edmfx_nh_pressure: true
2121
edmfx_sgs_mass_flux: true
2222
edmfx_sgs_diffusive_flux: true
2323
rayleigh_sponge: true
2424
dt_save_state_to_disk: "1days"
25-
dt: "100secs"
25+
dt: "100secs"
2626
t_end: "30days"
27-
job_id: "longrun_aquaplanet_amip"
27+
job_id: "longrun_aquaplanet_amip"
2828
toml: [toml/longrun_aquaplanet_amip.toml]
2929
output_default_diagnostics: false
3030
diagnostics:

config/longrun_configs/longrun_aquaplanet_rhoe_equil_55km_nz63_clearsky_tvinsol_0M_slabocean.yml

+5
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,8 @@ check_conservation: true
2121
bubble: false
2222
job_id: "longrun_aquaplanet_rhoe_equil_55km_nz63_clearsky_tvinsol_0M_slabocean"
2323
toml: [toml/longrun_aquaplanet_rhoe_equil_55km_nz63_gray_0M.toml]
24+
output_default_diagnostics: false
25+
diagnostics:
26+
- short_name: ["ts", "ta", "thetaa", "ha", "pfull", "rhoa", "ua", "va", "wa", "hfes", "hur", "hus", "clw", "cli", "evspsbl", "rsd", "rsu", "rld", "rlu"]
27+
reduction_time: average
28+
period: 10days

config/longrun_configs/longrun_aquaplanet_rhoe_equil_clearsky_tvinsol_0M_slabocean.yml

+5
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,8 @@ prognostic_surface: "PrognosticSurfaceTemperature"
1313
check_conservation: true
1414
bubble: false
1515
job_id: "longrun_aquaplanet_rhoe_equil_clearsky_tvinsol_0M_slabocean"
16+
output_default_diagnostics: false
17+
diagnostics:
18+
- short_name: ["ts", "ta", "thetaa", "ha", "pfull", "rhoa", "ua", "va", "wa", "hfes", "hur", "hus", "clw", "cli", "evspsbl", "rsd", "rsu", "rld", "rlu"]
19+
reduction_time: average
20+
period: 10days

config/longrun_configs/longrun_sphere_hydrostatic_balance_rhoe.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ h_elem: 16
22
z_elem: 45
33
dz_bottom: 30.0
44
dt: "400secs"
5-
perturb_initstate: false
6-
discrete_hydrostatic_balance: true
7-
t_end: "800days"
8-
dt_save_state_to_disk: "10days"
5+
perturb_initstate: false
6+
discrete_hydrostatic_balance: true
7+
t_end: "800days"
8+
dt_save_state_to_disk: "10days"
99
job_id: "longrun_sphere_hydrostatic_balance_rhoe"

config/longrun_configs/longrun_ssp_bw_rhoe_equil_highres.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
dt_save_state_to_disk: "10days"
22
initial_condition: "MoistBaroclinicWave"
3-
max_newton_iters_ode: 3
3+
approximate_linear_solve_iters: 2
44
z_elem: 45
55
dt: "150secs"
66
t_end: "100days"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
FLOAT_TYPE: "Float32"
2+
dt_save_state_to_disk: "10days"
3+
t_end: "10days"
4+
moist: "equil"
5+
precip_model: "0M"
6+
surface_setup: "DefaultMoninObukhov"
7+
vert_diff: "FriersonDiffusion"
8+
implicit_diffusion: true
9+
approximate_linear_solve_iters: 2
10+
rad: "clearsky"
11+
idealized_insolation: false
12+
dt_rad: "1hours"
13+
prognostic_surface: "PrognosticSurfaceTemperature"
14+
check_conservation: true
15+
bubble: false
16+
job_id: "aquaplanet_rhoe_equil_clearsky_tvinsol_0M_slabocean"
17+
output_default_diagnostics: false
18+
diagnostics:
19+
- short_name: ["ts", "ta", "thetaa", "ha", "pfull", "rhoa", "ua", "va", "wa", "hfes", "hur", "hus", "clw", "cli", "evspsbl", "rsd", "rsu", "rld", "rlu"]
20+
reduction_time: average
21+
period: 10days

config/model_configs/diagnostic_edmfx_trmm_stretched_box.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@ surface_setup: TRMM_LBA
66
turbconv: diagnostic_edmfx
77
implicit_diffusion: true
88
approximate_linear_solve_iters: 2
9-
max_newton_iters_ode: 1
109
prognostic_tke: true
1110
edmfx_upwinding: first_order
12-
edmfx_entr_model: "Generalized"
13-
edmfx_detr_model: "Generalized"
11+
edmfx_entr_model: "Generalized"
12+
edmfx_detr_model: "Generalized"
1413
edmfx_nh_pressure: true
1514
edmfx_sgs_mass_flux: true
1615
edmfx_sgs_diffusive_flux: true

config/perf_configs/flame_perf_target_frierson.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
vert_diff: "FriersonDiffusion"
2-
max_newton_iters_ode: 2
2+
pproximate_linear_solve_iters: 2
33
use_krylov_method: true
44
use_dynamic_krylov_rtol: false
55
krylov_rtol: 0.99

config/perf_configs/flame_sphere_baroclinic_wave_rhoe_equilmoist_expvdiff.yml

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
max_newton_iters_ode: 1
21
use_krylov_method: true
32
use_dynamic_krylov_rtol: false
43
krylov_rtol: 0.99

examples/hybrid/driver.jl

+43-28
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# When Julia 1.10+ is used interactively, stacktraces contain reduced type information to make them shorter.
2-
# On the other hand, the full type information is printed when julia is not run interactively.
2+
# On the other hand, the full type information is printed when julia is not run interactively.
33
# Given that ClimaCore objects are heavily parametrized, non-abbreviated stacktraces are hard to read,
44
# so we force abbreviated stacktraces even in non-interactive runs.
55
# (See also Base.type_limited_string_from_context())
@@ -58,29 +58,7 @@ if !isempty(integrator.tstops)
5858
end
5959
CA.verify_callbacks(sol.t)
6060

61-
if ClimaComms.iamroot(config.comms_ctx)
62-
@info "Plotting"
63-
make_plots(Val(Symbol(reference_job_id)), simulation.output_dir)
64-
@info "Plotting done"
65-
66-
@info "Creating tarballs"
67-
Tar.create(
68-
f -> endswith(f, ".nc"),
69-
simulation.output_dir,
70-
joinpath(simulation.output_dir, "nc_files.tar"),
71-
)
72-
Tar.create(
73-
f -> endswith(f, r"hdf5|h5"),
74-
simulation.output_dir,
75-
joinpath(simulation.output_dir, "hdf5_files.tar"),
76-
)
77-
78-
foreach(readdir(simulation.output_dir)) do f
79-
endswith(f, r"nc|hdf5|h5") && rm(joinpath(simulation.output_dir, f))
80-
end
81-
@info "Tarballs created"
82-
end
83-
61+
# Scaling check
8462
if CA.is_distributed(config.comms_ctx)
8563
nprocs = ClimaComms.nprocs(config.comms_ctx)
8664
comms_ctx = config.comms_ctx
@@ -105,6 +83,7 @@ if CA.is_distributed(config.comms_ctx)
10583
end
10684
end
10785

86+
# Check if selected output has changed from the previous recorded output (bit-wise comparison)
10887
include(joinpath(@__DIR__, "..", "..", "regression_tests", "mse_tables.jl"))
10988
if config.parsed_args["regression_test"]
11089
# Test results against main branch
@@ -135,7 +114,9 @@ end
135114
@info "Callback verification, n_expected_calls: $(CA.n_expected_calls(integrator))"
136115
@info "Callback verification, n_measured_calls: $(CA.n_measured_calls(integrator))"
137116

117+
# Conservation checks
138118
if config.parsed_args["check_conservation"]
119+
@info "Checking conservation"
139120
FT = Spaces.undertype(axes(sol.u[end].c.ρ))
140121

141122
# energy
@@ -154,8 +135,14 @@ if config.parsed_args["check_conservation"]
154135
energy_surface_change = -p.net_energy_flux_sfc[][]
155136
end
156137
energy_radiation_input = -p.net_energy_flux_toa[][]
157-
@test (energy_atmos_change + energy_surface_change) / energy_total
158-
energy_radiation_input / energy_total atol = 5 * sqrt(eps(FT))
138+
139+
energy_net =
140+
abs(
141+
energy_atmos_change + energy_surface_change -
142+
energy_radiation_input,
143+
) / energy_total
144+
@info " Net energy change: $energy_net"
145+
@test (energy_net / energy_total) 0 atol = sqrt(eps(FT))
159146

160147
if p.atmos.moisture_model isa CA.DryModel
161148
# density
@@ -169,12 +156,16 @@ if config.parsed_args["check_conservation"]
169156
water_surface_change = CA.horizontal_integral_at_boundary(
170157
sol.u[end].sfc.water .- sol.u[1].sfc.water,
171158
)
172-
@test (water_atmos_change + water_surface_change) / water_total 0 atol =
173-
100 * sqrt(eps(FT))
159+
160+
water_net =
161+
abs(water_atmos_change + water_surface_change) / water_total
162+
@info " Net water change: $water_net"
163+
@test water_net 0 atol = 100 * sqrt(eps(FT))
174164
end
175165
end
176166
end
177167

168+
# Precipitation characteristic checks
178169
if config.parsed_args["check_precipitation"]
179170
# run some simple tests based on the output
180171
FT = Spaces.undertype(axes(sol.u[end].c.ρ))
@@ -227,3 +218,27 @@ if config.parsed_args["check_precipitation"]
227218
@test maximum(sol.prob.p.precomputed.ᶜcloud_fraction[colidx]) <= FT(1)
228219
end
229220
end
221+
222+
# Visualize the solution
223+
if ClimaComms.iamroot(config.comms_ctx)
224+
@info "Plotting"
225+
make_plots(Val(Symbol(reference_job_id)), simulation.output_dir)
226+
@info "Plotting done"
227+
228+
@info "Creating tarballs"
229+
Tar.create(
230+
f -> endswith(f, ".nc"),
231+
simulation.output_dir,
232+
joinpath(simulation.output_dir, "nc_files.tar"),
233+
)
234+
Tar.create(
235+
f -> endswith(f, r"hdf5|h5"),
236+
simulation.output_dir,
237+
joinpath(simulation.output_dir, "hdf5_files.tar"),
238+
)
239+
240+
foreach(readdir(simulation.output_dir)) do f
241+
endswith(f, r"nc|hdf5|h5") && rm(joinpath(simulation.output_dir, f))
242+
end
243+
@info "Tarballs created"
244+
end

post_processing/ci_plots.jl

+53-2
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,59 @@ function make_plots(
475475
)
476476
end
477477

478+
function make_plots(
479+
::Union{
480+
Val{:aquaplanet_rhoe_equil_clearsky_tvinsol_0M_slabocean},
481+
Val{:longrun_aquaplanet_rhoe_equil_clearsky_tvinsol_0M_slabocean},
482+
Val{
483+
:longrun_aquaplanet_rhoe_equil_55km_nz63_clearsky_tvinsol_0M_slabocean,
484+
},
485+
},
486+
simulation_path,
487+
)
488+
simdir = SimDir(simulation_path)
489+
490+
491+
reduction = "average"
492+
period = "10d"
493+
short_names_3D = [
494+
"ta",
495+
"thetaa",
496+
"rhoa",
497+
"ua",
498+
"va",
499+
"wa",
500+
"hur",
501+
"hus",
502+
"clw",
503+
"cli",
504+
"rsd",
505+
"rsu",
506+
"rld",
507+
"rlu",
508+
]
509+
short_names_sfc = ["hfes", "evspsbl", "ts"]
510+
vars_3D = [
511+
get(simdir; short_name, reduction, period) |> ClimaAnalysis.average_lon for short_name in short_names_3D
512+
]
513+
vars_sfc = [
514+
get(simdir; short_name, reduction, period) for
515+
short_name in short_names_sfc
516+
]
517+
make_plots_generic(
518+
simulation_path,
519+
vars_3D,
520+
time = LAST_SNAP,
521+
more_kwargs = YLOGSCALE,
522+
)
523+
make_plots_generic(
524+
simulation_path,
525+
vars_sfc,
526+
time = LAST_SNAP,
527+
output_name = "summary_sfc",
528+
)
529+
end
530+
478531
AquaplanetPlots = Union{
479532
Val{:sphere_aquaplanet_rhoe_equilmoist_allsky_gw_res},
480533
Val{:mpi_sphere_aquaplanet_rhoe_equilmoist_clearsky},
@@ -483,10 +536,8 @@ AquaplanetPlots = Union{
483536
Val{:longrun_aquaplanet_rhoe_equil_55km_nz63_clearsky_diagedmf_diffonly_0M},
484537
Val{:longrun_aquaplanet_rhoe_equil_55km_nz63_clearsky_diagedmf_0M},
485538
Val{:longrun_aquaplanet_rhoe_equil_55km_nz63_allsky_diagedmf_0M},
486-
Val{:longrun_aquaplanet_rhoe_equil_55km_nz63_clearsky_tvinsol_0M_slabocean},
487539
Val{:longrun_aquaplanet_rhoe_equil_55km_nz63_clearsky_tvinsol_0M_earth},
488540
Val{:longrun_aquaplanet_rhoe_equil_highres_allsky_ft32},
489-
Val{:longrun_aquaplanet_rhoe_equil_clearsky_tvinsol_0M_slabocean},
490541
Val{:longrun_aquaplanet_dyamond},
491542
Val{:longrun_aquaplanet_amip},
492543
}

src/cache/cache.jl

+13
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct AtmosCache{
2626
RAD,
2727
NETFLUXTOA,
2828
NETFLUXSFC,
29+
CONSCHECK,
2930
OD,
3031
}
3132
"""Timestep of the simulation (in seconds). This is also used by callbacks and tendencies"""
@@ -89,6 +90,9 @@ struct AtmosCache{
8990
net_energy_flux_toa::NETFLUXTOA
9091
net_energy_flux_sfc::NETFLUXSFC
9192

93+
"""Conservation check for prognostic surface temperature"""
94+
conservation_check::CONSCHECK
95+
9296
"""Directory output."""
9397
output_dir::OD
9498
end
@@ -142,6 +146,14 @@ function build_cache(Y, atmos, params, surface_setup, sim_info)
142146
net_energy_flux_toa = [Geometry.WVector(FT(0))]
143147
net_energy_flux_sfc = [Geometry.WVector(FT(0))]
144148

149+
conservation_check =
150+
!(atmos.precip_model isa NoPrecipitation) ?
151+
(;
152+
col_integrated_precip_energy_tendency = zeros(
153+
axes(Fields.level(Geometry.WVector.(Y.f.u₃), half)),
154+
)
155+
) : (; col_integrated_precip_energy_tendency = (;))
156+
145157
limiter = if isnothing(atmos.numerics.limiter)
146158
nothing
147159
elseif atmos.numerics.limiter isa QuasiMonotoneLimiter
@@ -224,6 +236,7 @@ function build_cache(Y, atmos, params, surface_setup, sim_info)
224236
radiation,
225237
net_energy_flux_toa,
226238
net_energy_flux_sfc,
239+
conservation_check,
227240
output_dir,
228241
)
229242

0 commit comments

Comments
 (0)