diff --git a/experiments/ClimaEarth/Manifest.toml b/experiments/ClimaEarth/Manifest.toml index f702e4c217..6a50fe0d11 100644 --- a/experiments/ClimaEarth/Manifest.toml +++ b/experiments/ClimaEarth/Manifest.toml @@ -1,6 +1,6 @@ # This file is machine-generated - editing it directly is not advised -julia_version = "1.10.6" +julia_version = "1.10.7" manifest_format = "2.0" project_hash = "9d4daca72a27dd26a4e46ba913787d7e63971347" @@ -326,7 +326,7 @@ uuid = "d934ef94-cdd4-4710-83d6-720549644b70" version = "0.3.18" [[deps.ClimaCoupler]] -deps = ["ClimaComms", "ClimaCore", "ClimaCoreTempestRemap", "Dates", "JLD2", "Logging", "NCDatasets", "SciMLBase", "StaticArrays", "SurfaceFluxes", "Thermodynamics"] +deps = ["ClimaComms", "ClimaCore", "ClimaCoreTempestRemap", "ClimaUtilities", "Dates", "JLD2", "Logging", "NCDatasets", "SciMLBase", "StaticArrays", "SurfaceFluxes", "Thermodynamics"] path = "../.." uuid = "4ade58fe-a8da-486c-bd89-46df092ec0c7" version = "0.1.1" diff --git a/experiments/ClimaEarth/run_amip.jl b/experiments/ClimaEarth/run_amip.jl index 9c22ad7fa3..3e38feb0ba 100644 --- a/experiments/ClimaEarth/run_amip.jl +++ b/experiments/ClimaEarth/run_amip.jl @@ -83,6 +83,7 @@ We can additionally pass the configuration dictionary to the component model ini include("cli_options.jl") include("user_io/arg_parsing.jl") +include("user_io/postprocessing.jl") config_dict = get_coupler_config() # Select the correct timestep for each component model based on which are available @@ -817,78 +818,16 @@ The postprocessing includes: =# if ClimaComms.iamroot(comms_ctx) - - ## energy check plots - if !isnothing(cs.conservation_checks) && cs.mode.type isa AbstractSlabPlanetModeType - @info "Conservation Check Plots" - plot_global_conservation( - cs.conservation_checks.energy, - cs, - conservation_softfail, - figname1 = joinpath(dir_paths.artifacts, "total_energy_bucket.png"), - figname2 = joinpath(dir_paths.artifacts, "total_energy_log_bucket.png"), - ) - plot_global_conservation( - cs.conservation_checks.water, - cs, - conservation_softfail, - figname1 = joinpath(dir_paths.artifacts, "total_water_bucket.png"), - figname2 = joinpath(dir_paths.artifacts, "total_water_log_bucket.png"), - ) - end - - ## plotting AMIP results - if cs.mode.type isa AMIP_mode - if use_coupler_diagnostics - ## plot data that correspond to the model's last save_hdf5 call (i.e., last month) - @info "AMIP plots" - - ## ClimaESM - include("user_io/diagnostics_plots.jl") - - # define variable names and output directories for each diagnostic - amip_short_names_atmos = ["ta", "ua", "hus", "clw", "pr", "ts", "toa_fluxes_net"] - amip_short_names_coupler = ["F_turb_energy"] - output_dir_coupler = dir_paths.output - - # Check if all output variables are available in the specified directories - make_diagnostics_plots( - atmos_output_dir, - dir_paths.artifacts, - short_names = amip_short_names_atmos, - output_prefix = "atmos_", - ) - make_diagnostics_plots( - output_dir_coupler, - dir_paths.artifacts, - short_names = amip_short_names_coupler, - output_prefix = "coupler_", - ) - end - - # Check this because we only want monthly data for making plots - if t_end > 84600 * 31 * 3 && output_default_diagnostics - include("leaderboard/leaderboard.jl") - leaderboard_base_path = dir_paths.artifacts - compute_leaderboard(leaderboard_base_path, atmos_output_dir) - compute_pfull_leaderboard(leaderboard_base_path, atmos_output_dir) - end - end - ## plot extra atmosphere diagnostics if specified - if plot_diagnostics - @info "Plotting diagnostics" - include("user_io/diagnostics_plots.jl") - make_diagnostics_plots(atmos_output_dir, dir_paths.artifacts) - end - - ## plot all model states and coupler fields (useful for debugging) - !CA.is_distributed(comms_ctx) && debug(cs, dir_paths.artifacts) - - # if isinteractive() #hide - # ## clean up for interactive runs, retain all output otherwise #hide - # rm(dir_paths.output; recursive = true, force = true) #hide - # end #hide - - ## close all AMIP diagnostics file writers - !isnothing(amip_diags_handler) && map(diag -> close(diag.output_writer), amip_diags_handler.scheduled_diagnostics) + postprocessing_vars = (; + dir_paths, + plot_diagnostics, + use_coupler_diagnostics, + output_default_diagnostics, + t_end, + conservation_softfail, + atmos_output_dir, + amip_diags_handler, + comms_ctx, + ) + postprocess_sim(cs.mode.type, cs, postprocessing_vars) end diff --git a/experiments/ClimaEarth/user_io/postprocessing.jl b/experiments/ClimaEarth/user_io/postprocessing.jl new file mode 100644 index 0000000000..7a8d6bfd8c --- /dev/null +++ b/experiments/ClimaEarth/user_io/postprocessing.jl @@ -0,0 +1,123 @@ +## helpers for user-specified IO +include("debug_plots.jl") +include("diagnostics_plots.jl") + +""" + postprocess_sim(mode_type::AbstractSlabPlanetModeType, cs, postprocessing_vars) + +If they exist, perform conservation checks, for any slabplanet simulation, and then call +`common_postprocessing` to perform common postprocessing tasks that are common to all simulation types. +""" +function postprocess_sim(mode_type::AbstractSlabPlanetModeType, cs, postprocessing_vars) + (; + dir_paths, + plot_diagnostics, + use_coupler_diagnostics, + output_default_diagnostics, + t_end, + conservation_softfail, + atmos_output_dir, + amip_diags_handler, + comms_ctx, + ) = postprocessing_vars + + if !isnothing(cs.conservation_checks) + @info "Conservation Check Plots" + plot_global_conservation( + cs.conservation_checks.energy, + cs, + conservation_softfail, + figname1 = joinpath(dir_paths.artifacts, "total_energy_bucket.png"), + figname2 = joinpath(dir_paths.artifacts, "total_energy_log_bucket.png"), + ) + plot_global_conservation( + cs.conservation_checks.water, + cs, + conservation_softfail, + figname1 = joinpath(dir_paths.artifacts, "total_water_bucket.png"), + figname2 = joinpath(dir_paths.artifacts, "total_water_log_bucket.png"), + ) + end + common_postprocessing(cs, postprocessing_vars) +end + +""" + postprocess_sim(mode_type::AMIP_mode, cs, postprocessing_vars) + +Conditionally plot AMIP diagnostics and call `common_postprocessing` to perform +postprocessing tasks that are common to all simulation types. +""" +function postprocess_sim(mode_type::AMIP_mode, cs, postprocessing_vars) + (; + dir_paths, + plot_diagnostics, + use_coupler_diagnostics, + output_default_diagnostics, + t_end, + conservation_softfail, + atmos_output_dir, + amip_diags_handler, + comms_ctx, + ) = postprocessing_vars + + if use_coupler_diagnostics + ## plot data that correspond to the model's last save_hdf5 call (i.e., last month) + @info "AMIP plots" + + ## ClimaESM + include("user_io/diagnostics_plots.jl") + + # define variable names and output directories for each diagnostic + amip_short_names_atmos = ["ta", "ua", "hus", "clw", "pr", "ts", "toa_fluxes_net"] + amip_short_names_coupler = ["F_turb_energy"] + output_dir_coupler = dir_paths.output + + # Check if all output variables are available in the specified directories + make_diagnostics_plots( + atmos_output_dir, + dir_paths.artifacts, + short_names = amip_short_names_atmos, + output_prefix = "atmos_", + ) + make_diagnostics_plots( + output_dir_coupler, + dir_paths.artifacts, + short_names = amip_short_names_coupler, + output_prefix = "coupler_", + ) + end + + # Check this because we only want monthly data for making plots + if t_end > 84600 * 31 * 3 && output_default_diagnostics + include("leaderboard/leaderboard.jl") + leaderboard_base_path = dir_paths.artifacts + compute_leaderboard(leaderboard_base_path, atmos_output_dir) + compute_pfull_leaderboard(leaderboard_base_path, atmos_output_dir) + end + common_postprocessing(cs, postprocessing_vars) +end + +""" + common_postprocessing(cs, postprocessing_vars) + +Perfrom postprocessing common to all simulation types. +""" +function common_postprocessing(cs, postprocessing_vars) + (; plot_diagnostics, comms_ctx, dir_paths, amip_diags_handler, atmos_output_dir) = postprocessing_vars + if plot_diagnostics + @info "Plotting diagnostics" + include("user_io/diagnostics_plots.jl") + make_diagnostics_plots(atmos_output_dir, dir_paths.artifacts) + end + + ## plot all model states and coupler fields (useful for debugging) + !CA.is_distributed(comms_ctx) && debug(cs, dir_paths.artifacts) + + # if isinteractive() #hide + # ## clean up for interactive runs, retain all output otherwise #hide + # rm(dir_paths.output; recursive = true, force = true) #hide + # end #hide + + ## close all AMIP diagnostics file writers + !isnothing(amip_diags_handler) && map(diag -> close(diag.output_writer), amip_diags_handler.scheduled_diagnostics) +end