Skip to content

Commit 16b2191

Browse files
committed
Plot error from AIDA calibs
1 parent 62af04e commit 16b2191

File tree

3 files changed

+192
-48
lines changed

3 files changed

+192
-48
lines changed

papers/ice_nucleation_2024/AIDA_calibrations.jl

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,32 @@ include(joinpath(pkgdir(CM), "papers", "ice_nucleation_2024", "calibration.jl"))
1616
include(joinpath(pkgdir(CM), "papers", "ice_nucleation_2024", "unpack_AIDA.jl"))
1717
include(joinpath(pkgdir(CM), "papers", "ice_nucleation_2024", "plots.jl"))
1818

19+
function MSE(
20+
n_iterations, n_ensembles,
21+
all_params, data_file_name_list,
22+
params_list, nuc_mode, FT, IC_list, end_sim,
23+
y_truth, Nₜ,
24+
)
25+
26+
loss_vector = [] # should have length of n_iterations with each element being the MSE from the whole batch of ensembles
27+
for iter in 1:n_iterations
28+
loss_iteration = []
29+
for ens in 1:n_ensembles
30+
loss_ensemble = []
31+
for exp in 1:length(data_file_name_list)
32+
parcel_ensemble =
33+
run_model([params_list[exp]], nuc_mode, all_params[iter][:, ens], FT, [IC_list[exp]], end_sim)
34+
loss_ensemble_exp = y_truth[exp][end] - (parcel_ensemble[9, end] / Nₜ[exp])
35+
append!(loss_ensemble, loss_ensemble_exp)
36+
end
37+
append!(loss_iteration, loss_ensemble)
38+
end
39+
append!(loss_vector, (sum(loss_iteration)^2)/(length(loss_iteration))) # MSE
40+
end
41+
42+
return loss_vector
43+
end
44+
1945
# Defining data names, start/end times, etc.
2046
global edf_data_names = [
2147
"in05_17_aida.edf", "in05_18_aida.edf",
@@ -129,12 +155,24 @@ for (batch_index, batch_name) in enumerate(batch_names)
129155
EKI_output = calibrate_J_parameters_EKI(FT, nuc_mode, params_list, IC_list, y_truth, end_sim, Γ)
130156
UKI_output = calibrate_J_parameters_UKI(FT, nuc_mode, params_list, IC_list, y_truth, end_sim, Γ)
131157

158+
EKI_calibrated_parameters = EKI_output[1] # MEAN of parameters from ensembles in FINAL iteration
159+
UKI_calibrated_parameters = UKI_output[1] # MEAN of parameters from ensembles in FINAL iteration
160+
EKI_all_params = EKI_output[2] # parameters from EACH ensemble in EACH iteration
161+
UKI_all_params = UKI_output[2] # parameters from EACH ensemble in EACH iteration
162+
EKI_mean_each_iter = EKI_output[3] # MEAN of parameters from ensembles in EACH iteration
163+
UKI_mean_each_iter = UKI_output[3] # MEAN of parameters from ensembles in EACH iteration
164+
UKI_final_iter_spread = UKI_output[4] # parameters for EACH ensemble in FINAL iteration
165+
EKI_error = EKI_output[4]
166+
UKI_error = UKI_output[5]
167+
132168
EKI_n_iterations = size(EKI_output[2])[1]
133169
EKI_n_ensembles = size(EKI_output[2][1])[2]
170+
UKI_n_iterations = size(UKI_output[2])[1]
171+
UKI_n_ensembles = size(UKI_output[2][1])[2]
172+
173+
EKI_calibrated_ensemble_means = ensemble_means(EKI_all_params, EKI_n_iterations, EKI_n_ensembles)
174+
UKI_calibrated_ensemble_means = ensemble_means(UKI_all_params, UKI_n_iterations, UKI_n_ensembles)
134175

135-
EKI_calibrated_parameters = EKI_output[1]
136-
UKI_calibrated_parameters = UKI_output[1]
137-
calibrated_ensemble_means = ensemble_means(EKI_output[2], EKI_n_iterations, EKI_n_ensembles)
138176
merge!(EKI_calibrated_coeff_dict, Dict(batch_name => EKI_calibrated_parameters))
139177
merge!(UKI_calibrated_coeff_dict, Dict(batch_name => UKI_calibrated_parameters))
140178

@@ -166,14 +204,18 @@ for (batch_index, batch_name) in enumerate(batch_names)
166204
(; AIDA_t_profile, AIDA_T_profile, AIDA_P_profile, AIDA_ICNC_profile, AIDA_e_profile) = AIDA_data
167205

168206
AIDA_ICNC_data_fig = plot_AIDA_ICNC_data(
169-
exp_names[exp_index],
207+
exp_names[exp_index], start_time[exp_index],
170208
AIDA_t_profile, AIDA_ICNC_profile,
171209
t_profile[exp_index], ICNC_moving_avg[exp_index], frozen_frac_moving_mean[exp_index],
172210
)
173211

174212
## Calibrated coefficients.
175213
# Did they converge?
176-
calibrated_coeffs_fig = plot_calibrated_coeffs(batch_name, EKI_n_iterations, calibrated_ensemble_means)
214+
calibrated_coeffs_fig = plot_calibrated_coeffs(
215+
batch_name,
216+
EKI_n_iterations, EKI_n_ensembles, EKI_all_params,
217+
UKI_n_iterations, UKI_n_ensembles, UKI_all_params,
218+
)
177219

178220
## Calibrated parcel simulations.
179221
# Does the calibrated parcel give reasonable outputs?
@@ -192,21 +234,32 @@ for (batch_index, batch_name) in enumerate(batch_names)
192234
)
193235

194236
## Looking at spread in UKI calibrated parameters
195-
ϕ_UKI = UKI_output[2]
196-
UKI_parcel_1 = run_model([params_list[exp_index]], nuc_mode, [ϕ_UKI[1,1], ϕ_UKI[2,1]], FT, [IC_list[exp_index]], end_sim)
197-
UKI_parcel_2 = run_model([params_list[exp_index]], nuc_mode, [ϕ_UKI[1,1], ϕ_UKI[2,1]], FT, [IC_list[exp_index]], end_sim)
198-
UKI_parcel_3 = run_model([params_list[exp_index]], nuc_mode, [ϕ_UKI[1,1], ϕ_UKI[2,1]], FT, [IC_list[exp_index]], end_sim)
199-
UKI_parcel_4 = run_model([params_list[exp_index]], nuc_mode, [ϕ_UKI[1,1], ϕ_UKI[2,1]], FT, [IC_list[exp_index]], end_sim)
200-
UKI_parcel_5 = run_model([params_list[exp_index]], nuc_mode, [ϕ_UKI[1,1], ϕ_UKI[2,1]], FT, [IC_list[exp_index]], end_sim)
237+
UKI_parcel_1 = run_model([params_list[exp_index]], nuc_mode, [UKI_final_iter_spread[1,1], UKI_final_iter_spread[2,1]], FT, [IC_list[exp_index]], end_sim)
238+
UKI_parcel_2 = run_model([params_list[exp_index]], nuc_mode, [UKI_final_iter_spread[1,2], UKI_final_iter_spread[2,2]], FT, [IC_list[exp_index]], end_sim)
239+
UKI_parcel_3 = run_model([params_list[exp_index]], nuc_mode, [UKI_final_iter_spread[1,3], UKI_final_iter_spread[2,3]], FT, [IC_list[exp_index]], end_sim)
240+
UKI_parcel_4 = run_model([params_list[exp_index]], nuc_mode, [UKI_final_iter_spread[1,4], UKI_final_iter_spread[2,4]], FT, [IC_list[exp_index]], end_sim)
241+
UKI_parcel_5 = run_model([params_list[exp_index]], nuc_mode, [UKI_final_iter_spread[1,5], UKI_final_iter_spread[2,5]], FT, [IC_list[exp_index]], end_sim)
201242

202243
UKI_spread_fig = plot_UKI_spread(
203244
exp_names[exp_index],
204245
t_profile[exp_index], frozen_frac_moving_mean[exp_index], Nₜ[exp_index],
205246
UKI_parcel_1, UKI_parcel_2, UKI_parcel_3, UKI_parcel_4, UKI_parcel_5, UKI_parcel,
206247
)
207248

208-
end # plotting individual experiments
209-
end
249+
end # iterating over experiments in batch
250+
251+
# Parcel runs using ensemble means of parameters at each iteration for each exp in batch
252+
# EKI_loss_batch = MSE(EKI_n_iterations, EKI_n_ensembles, EKI_all_params, data_file_name_list, params_list, nuc_mode, FT, IC_list, end_sim, y_truth, Nₜ)
253+
# UKI_loss_batch = MSE(UKI_n_iterations, UKI_n_ensembles, UKI_all_params, data_file_name_list, params_list, nuc_mode, FT, IC_list, end_sim, y_truth, Nₜ)
254+
255+
## Plotting loss function over calibration iterations
256+
loss_fig = plot_loss_func(
257+
batch_name,
258+
EKI_n_iterations, UKI_n_iterations,
259+
EKI_error, UKI_error,
260+
)
261+
262+
end # iterating over batches
210263

211264
# Plotting overview
212265
plot_ICNC_overview(overview_data)

papers/ice_nucleation_2024/calibration.jl

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ function create_prior(FT, IN_mode, ; perfect_model = false, aerosol_type = nothi
249249
m_stats = [FT(100), FT(50), FT(0), Inf]
250250
c_stats = [FT(0.7), FT(20), -Inf, Inf]
251251
elseif aerosol_type == CMP.Dust(FT)
252-
m_stats = [FT(50), FT(50), FT(0), Inf]
253-
c_stats = [FT(0.7), FT(20), -Inf, Inf]
252+
m_stats = [FT(50), FT(70), FT(0), Inf]
253+
c_stats = [FT(0.7), FT(40), -Inf, Inf]
254254
else
255255
error("Aerosol type not supported for ABDINM. Check create_prior function.")
256256
end
@@ -350,9 +350,15 @@ function calibrate_J_parameters_EKI(FT, IN_mode, params, IC, y_truth, end_sim,
350350
digits = 6,
351351
)
352352

353+
mean_each_iter = []
354+
for i in 1:final_iter[1]
355+
push!(mean_each_iter, EKP.get_u_mean(EKI_obj, i))
356+
end
357+
353358
calibrated_coeffs = [m_coeff_ekp, c_coeff_ekp]
359+
error = EKP.get_error(EKI_obj)
354360

355-
return [calibrated_coeffs, ϕ_n_values]
361+
return [calibrated_coeffs, ϕ_n_values, mean_each_iter, error]
356362
end
357363

358364
function calibrate_J_parameters_UKI(FT, IN_mode, params, IC, y_truth, end_sim, Γ,; perfect_model = false)
@@ -394,14 +400,7 @@ function calibrate_J_parameters_UKI(FT, IN_mode, params, IC, y_truth, end_sim,
394400
# Update ensemble
395401
terminate = EKP.EnsembleKalmanProcesses.update_ensemble!(UKI_obj, G_ens)
396402
push!(err, EKP.get_error(UKI_obj)[end])
397-
# println(
398-
# "Iteration: " *
399-
# string(n) *
400-
# ", Error: " *
401-
# string(err[n]) *
402-
# " norm(Cov):" *
403-
# string(Distributions.norm(EKP.get_process(UKI_obj).uu_cov[n]))
404-
# )
403+
405404
if !isnothing(terminate)
406405
final_iter[1] = n - 1
407406
break
@@ -411,9 +410,19 @@ function calibrate_J_parameters_UKI(FT, IN_mode, params, IC, y_truth, end_sim,
411410
UKI_mean_u_space = EKP.get_u_mean_final(UKI_obj)
412411
UKI_mean = EKP.transform_unconstrained_to_constrained(prior, UKI_mean_u_space)
413412

414-
ϕ_n = EKP.get_ϕ_final(prior, UKI_obj)
413+
ϕ_n = EKP.get_ϕ_final(prior, UKI_obj) # final iteraiton for each ensemble
414+
all_ϕ_n = EKP.get_ϕ(prior, UKI_obj; return_array=true) # set of params for each ensembles AND each iteration
415+
416+
mean_each_iter = []
417+
for i in 1:(final_iter[1] + 1)
418+
mean_u_space = EKP.get_u_mean(UKI_obj, i)
419+
mean_u_space_transformed = EKP.transform_unconstrained_to_constrained(prior, mean_u_space)
420+
push!(mean_each_iter, mean_u_space_transformed)
421+
end
422+
423+
error = EKP.get_error(UKI_obj)
415424

416-
return [UKI_mean, ϕ_n, final_iter]
425+
return [UKI_mean, all_ϕ_n, mean_each_iter, ϕ_n, error]
417426
end
418427

419428
function ensemble_means(ϕ_n_values, N_iterations, N_ensemble)

papers/ice_nucleation_2024/plots.jl

Lines changed: 104 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import CairoMakie as MK
22

33
include(joinpath(pkgdir(CM), "parcel", "ParcelCommon.jl"))
44

5+
#! format: off
6+
57
"""
68
plot_AIDA_ICNC_data(
79
exp_name,
@@ -12,7 +14,7 @@ include(joinpath(pkgdir(CM), "parcel", "ParcelCommon.jl"))
1214
Plots raw AIDA ICNC data. Plot is saved and returned.
1315
"""
1416
function plot_AIDA_ICNC_data(
15-
exp_name,
17+
exp_name, start_time,
1618
AIDA_t_profile, AIDA_ICNC_profile,
1719
t_profile, ICNC_moving_avg, frozen_frac_moving_mean,
1820
)
@@ -34,8 +36,8 @@ function plot_AIDA_ICNC_data(
3436
linestyle = :dash,
3537
linewidth = 2,
3638
)
37-
MK.lines!(data_ax1, t_profile, ICNC_moving_avg, label = "AIDA ICNC moving mean", linewidth = 2.5, color = :blue)
38-
MK.lines!(data_ax2, t_profile, frozen_frac_moving_mean, linewidth = 2.5, color = :blue)
39+
MK.lines!(data_ax1, t_profile .+ start_time, ICNC_moving_avg, label = "AIDA ICNC moving mean", linewidth = 2.5, color = :blue)
40+
MK.lines!(data_ax2, t_profile .+ start_time, frozen_frac_moving_mean, linewidth = 2.5, color = :blue)
3941
MK.axislegend(data_ax1, framevisible = true, labelsize = 12, position = :rc)
4042
MK.save("$exp_name" * "_ICNC.svg", AIDA_data_fig)
4143

@@ -48,30 +50,70 @@ end
4850
4951
Plots evolution of calibrated coefficients over the EKI iterations. Plot is saved and returned.
5052
"""
51-
function plot_calibrated_coeffs(batch_name, EKI_n_iterations, calibrated_ensemble_means)
53+
function plot_calibrated_coeffs(
54+
batch_name,
55+
EKI_n_iterations, EKI_n_ensembles, EKI_all_params,
56+
UKI_n_iterations, UKI_n_ensembles, UKI_all_params,
57+
)
58+
EKI_x_axis = []
59+
UKI_x_axis = []
60+
EKI_m = []
61+
UKI_m = []
62+
EKI_c = []
63+
UKI_c = []
64+
65+
for iter in 1:EKI_n_iterations
66+
for ensemble_n in 1:EKI_n_ensembles
67+
append!(EKI_x_axis, iter)
68+
append!(EKI_m, EKI_all_params[iter][1, ensemble_n])
69+
append!(EKI_c, EKI_all_params[iter][2, ensemble_n])
70+
end
71+
end
72+
for iter in 1:UKI_n_iterations
73+
for ensemble_n in 1:UKI_n_ensembles
74+
append!(UKI_x_axis, iter)
75+
append!(UKI_m, UKI_all_params[iter][1, ensemble_n])
76+
append!(UKI_c, UKI_all_params[iter][2, ensemble_n])
77+
end
78+
end
5279

53-
calibrated_coeffs_fig = MK.Figure(size = (1100, 900), fontsize = 24)
80+
calibrated_coeffs_fig = MK.Figure(size = (900, 600), fontsize = 24)
5481
m_coeff_ax = MK.Axis(calibrated_coeffs_fig[1, 1], ylabel = "m coefficient [-]", title = "$batch_name")
5582
c_coeff_ax =
56-
MK.Axis(calibrated_coeffs_fig[1, 2], ylabel = "c coefficient [-]", xlabel = "iteration #", title = "EKI")
83+
MK.Axis(calibrated_coeffs_fig[1, 2], ylabel = "c coefficient [-]", xlabel = "iteration #", title = "Ensemble Mean")
5784

58-
MK.lines!(
85+
MK.scatter!(
5986
m_coeff_ax,
60-
collect(1:EKI_n_iterations),
61-
calibrated_ensemble_means[1],
62-
label = "ensemble mean",
63-
color = :orange,
64-
linewidth = 2.5,
87+
EKI_x_axis,
88+
EKI_m,
89+
label = "EKI",
90+
color = (:orange, 0.5),
91+
# marker = :xcross,
6592
)
66-
MK.lines!(
93+
MK.scatter!(
6794
c_coeff_ax,
68-
collect(1:EKI_n_iterations),
69-
calibrated_ensemble_means[2],
70-
label = "ensemble mean",
71-
color = :orange,
72-
linewidth = 2.5,
95+
EKI_x_axis,
96+
EKI_c,
97+
label = "EKI",
98+
color = (:orange, 0.5),
99+
# marker = :xcross
100+
)
101+
MK.scatter!(
102+
m_coeff_ax,
103+
UKI_x_axis,
104+
UKI_m,
105+
label = "UKI",
106+
color = (:fuchsia, 0.5),
107+
)
108+
MK.scatter!(
109+
c_coeff_ax,
110+
UKI_x_axis,
111+
UKI_c,
112+
label = "UKI",
113+
color = (:fuchsia, 0.5),
73114
)
74115

116+
MK.axislegend(m_coeff_ax, framevisible = false, labelsize = 18, position = :rt)
75117
MK.save("$batch_name" * "_calibrated_coeffs_fig.svg", calibrated_coeffs_fig)
76118

77119
return calibrated_coeffs_fig
@@ -293,14 +335,12 @@ function plot_UKI_spread(
293335
MK.errorbars!(ax_spread, t_profile, frozen_frac_moving_mean, error, color = (:blue, 0.3))
294336
MK.save("$exp_name" * "_UKI_spread_fig.svg", UKI_spread_fig)
295337

296-
return plot_UKI_spread
338+
return UKI_spread_fig
297339

298340
end
299341

300342
"""
301-
plot_ICNC_overview(
302-
EKI_calibrated_parcel, UKI_parcel,
303-
)
343+
plot_ICNC_overview(overview_data)
304344
305345
Plots frozen fraction evolution for EKI and UKI calibrated parcel simulations
306346
and AIDA data for all batch experiments. Plot is saved and returned.
@@ -390,3 +430,45 @@ function plot_ICNC_overview(overview_data)
390430

391431
return overview_fig
392432
end
433+
434+
"""
435+
plot_loss_func(
436+
batch_name,
437+
EKI_n_iterations, UKI_n_iterations,
438+
EKI_error, UKI_error,
439+
)
440+
441+
Plots the difference in loss functions over each iteration of
442+
calibration for a batch. Plot is saved and returned.
443+
"""
444+
function plot_loss_func(
445+
batch_name,
446+
EKI_n_iterations, UKI_n_iterations,
447+
EKI_error, UKI_error,
448+
)
449+
450+
loss_fig = MK.Figure(size = (700, 600), fontsize = 24)
451+
ax_loss = MK.Axis(loss_fig[1, 1], ylabel = "Error [-]", xlabel = "Iteration [-]", title = "$batch_name: Error")
452+
MK.lines!(
453+
ax_loss,
454+
collect(1:EKI_n_iterations),
455+
EKI_error,
456+
label = "EKI",
457+
linewidth = 2.5,
458+
color = :orange,
459+
)
460+
MK.lines!(
461+
ax_loss,
462+
collect(1:(UKI_n_iterations - 1)),
463+
UKI_error,
464+
label = "UKI",
465+
linewidth = 2.5,
466+
color = :fuchsia,
467+
)
468+
MK.axislegend(ax_loss, framevisible = false, labelsize = 18, position = :rc)
469+
MK.save("$batch_name" * "_loss_fig.svg", loss_fig)
470+
471+
return loss_fig
472+
473+
end
474+
#! format: on

0 commit comments

Comments
 (0)