From c69e907801c4dcd5968e963d658c4b26a8a3805b Mon Sep 17 00:00:00 2001 From: Lenka Novakova Date: Tue, 31 Oct 2023 16:12:04 -0700 Subject: [PATCH] init in TimeManager + uni tests implement in driver add docs fix tests add CA LD path add hourly checkpoints to pipeline revs --- .buildkite/longruns/pipeline.yml | 3 + .buildkite/pipeline.yml | 16 +-- Project.toml | 2 +- config/longrun_configs/dyamond_target.yml | 2 +- ...ingle_modular_ft64_hourly_checkpoints.yml} | 6 +- ...e_modular_ft64_hourly_checkpoints_co2.yml} | 6 +- config/model_configs/interactive_debug.yml | 2 +- docs/src/timemanager.md | 4 + experiments/AMIP/modular/cli_options.jl | 4 +- .../components/atmosphere/climaatmos_init.jl | 4 +- .../AMIP/modular/coupler_driver_modular.jl | 45 ++++--- .../AMIP/modular/user_io/user_logging.jl | 18 +++ src/Checkpointer.jl | 1 - src/Interfacer.jl | 9 +- src/TimeManager.jl | 91 +++++++++++++- test/bcreader_tests.jl | 2 + test/conservation_checker_tests.jl | 4 + test/debug/debug_amip_plots.jl | 2 + test/diagnostics_tests.jl | 6 + test/interfacer_tests.jl | 2 + test/mpi_tests/bcreader_mpi_tests.jl | 2 + test/mpi_tests/local_checks.sh | 4 +- test/regridder_tests.jl | 2 + test/time_manager_tests.jl | 111 ++++++++++++++++++ 24 files changed, 302 insertions(+), 46 deletions(-) rename config/model_configs/{coarse_single_modular_ft64_monthly_checkpoints.yml => coarse_single_modular_ft64_hourly_checkpoints.yml} (64%) rename config/model_configs/{coarse_single_modular_ft64_monthly_checkpoints_co2.yml => coarse_single_modular_ft64_hourly_checkpoints_co2.yml} (64%) diff --git a/.buildkite/longruns/pipeline.yml b/.buildkite/longruns/pipeline.yml index ee25252f10..8d765fe5d0 100644 --- a/.buildkite/longruns/pipeline.yml +++ b/.buildkite/longruns/pipeline.yml @@ -14,6 +14,9 @@ env: CONFIG_PATH: "config/longrun_configs" PERF_CONFIG_PATH: "config/perf_configs" + LD_LIBRARY_PATH: "/central/scratch/esm/slurm-buildkite/climaatmos-ci/depot/cpu/artifacts/e9feeabfa989549ac1dac61e4df5f2849149ad6d/lib/:${LD_LIBRARY_PATH}" + + timeout_in_minutes: 1440 steps: diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 90e5ae88c0..f650e7d07d 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -16,6 +16,8 @@ env: PERF_CONFIG_PATH: "config/perf_configs" MPI_CONFIG_PATH: "config/mpi_configs" + LD_LIBRARY_PATH: "/central/scratch/esm/slurm-buildkite/climaatmos-ci/depot/cpu/artifacts/e9feeabfa989549ac1dac61e4df5f2849149ad6d/lib/:${LD_LIBRARY_PATH}" + timeout_in_minutes: 1440 steps: @@ -240,10 +242,10 @@ steps: # command: "julia --color=yes --project=experiments/AMIP/modular/ experiments/AMIP/modular/coupler_driver_modular.jl --coupled true --surface_setup PrescribedSurface --moist equil --vert_diff true --rad allskywithclear --rayleigh_sponge false --energy_check true --mode_name slabplanet --t_end 10days --dt_save_to_sol 3600secs --dt_cpl 21600 --dt 200secs --dt_rad 6hours --idealized_insolation true --mono_surface true --h_elem 4 --precip_model 0M --run_name target_params_in_slab1" # artifact_paths: "experiments/AMIP/modular/output/slabplanet/target_params_in_slab1_artifacts/total_energy*.png" - - label: "AMIP - modular Float64 + monthly checkpoint" + - label: "AMIP - modular Float64 + hourly checkpoint" key: "modular_amip" - command: "julia --color=yes --project=experiments/AMIP/modular/ experiments/AMIP/modular/coupler_driver_modular.jl --config_file $CONFIG_PATH/coarse_single_modular_ft64_monthly_checkpoints.yml" - artifact_paths: "experiments/AMIP/modular/output/amip/coarse_single_modular_ft64_monthly_checkpoints_artifacts/*" + command: "julia --color=yes --project=experiments/AMIP/modular/ experiments/AMIP/modular/coupler_driver_modular.jl --config_file $CONFIG_PATH/coarse_single_modular_ft64_hourly_checkpoints.yml" + artifact_paths: "experiments/AMIP/modular/output/amip/coarse_single_modular_ft64_hourly_checkpoints_artifacts/*" env: FLAME_PLOT: "" BUILD_HISTORY_HANDLE: "" @@ -251,10 +253,10 @@ steps: slurm_ntasks: 1 slurm_mem: 20GB - - label: "AMIP - modular Float64 + monthly checkpoint + co2" - key: "coarse_single_modular_ft64_monthly_checkpoints_co2" - command: "julia --color=yes --project=experiments/AMIP/modular/ experiments/AMIP/modular/coupler_driver_modular.jl --config_file $CONFIG_PATH/coarse_single_modular_ft64_monthly_checkpoints_co2.yml" - artifact_paths: "experiments/AMIP/modular/output/amip/coarse_single_modular_ft64_monthly_checkpoints_co2_artifacts/*" + - label: "AMIP - modular Float64 + hourly checkpoint + co2" + key: "coarse_single_modular_ft64_hourly_checkpoints_co2" + command: "julia --color=yes --project=experiments/AMIP/modular/ experiments/AMIP/modular/coupler_driver_modular.jl --config_file $CONFIG_PATH/coarse_single_modular_ft64_hourly_checkpoints_co2.yml" + artifact_paths: "experiments/AMIP/modular/output/amip/coarse_single_modular_ft64_hourly_checkpoints_co2_artifacts/*" env: FLAME_PLOT: "" BUILD_HISTORY_HANDLE: "" diff --git a/Project.toml b/Project.toml index 51ae77e025..761dcec110 100644 --- a/Project.toml +++ b/Project.toml @@ -38,7 +38,7 @@ Insolation = "0.6" JLD2 = "0.4" NCDatasets = "0.11, 0.12" OrdinaryDiffEq = "5, 6" -Plots = "1" +Plots = "1.39.0" SciMLBase = "1" StaticArrays = "1" SurfaceFluxes = "0.7" diff --git a/config/longrun_configs/dyamond_target.yml b/config/longrun_configs/dyamond_target.yml index bd574b1cc0..fbae6b5f37 100644 --- a/config/longrun_configs/dyamond_target.yml +++ b/config/longrun_configs/dyamond_target.yml @@ -11,4 +11,4 @@ dt_save_to_disk: "0.5days" turb_flux_partition: "CombinedStateFluxes" atmos_config_file: "config/longrun_configs/longrun_aquaplanet_dyamond.yml" atmos_toml_file: "toml/longrun_aquaplanet_dyamond.toml" -monthly_checkpoint: false +hourly_checkpoint: false diff --git a/config/model_configs/coarse_single_modular_ft64_monthly_checkpoints.yml b/config/model_configs/coarse_single_modular_ft64_hourly_checkpoints.yml similarity index 64% rename from config/model_configs/coarse_single_modular_ft64_monthly_checkpoints.yml rename to config/model_configs/coarse_single_modular_ft64_hourly_checkpoints.yml index ec9df3362c..05d902c8dc 100644 --- a/config/model_configs/coarse_single_modular_ft64_monthly_checkpoints.yml +++ b/config/model_configs/coarse_single_modular_ft64_hourly_checkpoints.yml @@ -1,5 +1,5 @@ -run_name: "coarse_single_modular_ft64_monthly_checkpoints" -monthly_checkpoint: true +run_name: "coarse_single_modular_ft64_hourly_checkpoints" +hourly_checkpoint: true moist: "equil" vert_diff: "true" rad: "gray" @@ -15,4 +15,4 @@ h_elem: 6 dt_save_restart: "10days" precip_model: "0M" apply_limiter: false -job_id: "coarse_single_modular_ft64_monthly_checkpoints" +job_id: "coarse_single_modular_ft64_hourly_checkpoints" diff --git a/config/model_configs/coarse_single_modular_ft64_monthly_checkpoints_co2.yml b/config/model_configs/coarse_single_modular_ft64_hourly_checkpoints_co2.yml similarity index 64% rename from config/model_configs/coarse_single_modular_ft64_monthly_checkpoints_co2.yml rename to config/model_configs/coarse_single_modular_ft64_hourly_checkpoints_co2.yml index dd5270a4d5..cb4e7f7b5c 100644 --- a/config/model_configs/coarse_single_modular_ft64_monthly_checkpoints_co2.yml +++ b/config/model_configs/coarse_single_modular_ft64_hourly_checkpoints_co2.yml @@ -1,5 +1,5 @@ -run_name: "coarse_single_modular_ft64_monthly_checkpoints_co2" -monthly_checkpoint: true +run_name: "coarse_single_modular_ft64_hourly_checkpoints_co2" +hourly_checkpoint: true moist: "equil" vert_diff: "true" rad: "allskywithclear" @@ -15,4 +15,4 @@ h_elem: 6 dt_save_restart: "10days" precip_model: "0M" apply_limiter: false -job_id: "coarse_single_modular_ft64_monthly_checkpoints_co2" +job_id: "coarse_single_modular_ft64_hourly_checkpoints_co2" diff --git a/config/model_configs/interactive_debug.yml b/config/model_configs/interactive_debug.yml index db0ba1bfbc..a5ec7c15dc 100644 --- a/config/model_configs/interactive_debug.yml +++ b/config/model_configs/interactive_debug.yml @@ -14,4 +14,4 @@ dt_save_restart: "5days" precip_model: "0M" run_name: "interactive_debug_run" job_id: "interactive_debug_run" -monthly_checkpoint: true \ No newline at end of file +hourly_checkpoint: true \ No newline at end of file diff --git a/docs/src/timemanager.md b/docs/src/timemanager.md index 9fd9c162a7..5a8bd6e2ea 100644 --- a/docs/src/timemanager.md +++ b/docs/src/timemanager.md @@ -13,4 +13,8 @@ ClimaCoupler.TimeManager.datetime_to_strdate ClimaCoupler.TimeManager.trigger_callback ClimaCoupler.TimeManager.Monthly ClimaCoupler.TimeManager.EveryTimestep +ClimaCoupler.TimeManager.trigger_callback! +ClimaCoupler.TimeManager.HourlyCallback +ClimaCoupler.TimeManager.MonthlyCallback +ClimaCoupler.TimeManager.update_firstdayofmonth! ``` diff --git a/experiments/AMIP/modular/cli_options.jl b/experiments/AMIP/modular/cli_options.jl index bdc66d342c..335b5f1c2d 100644 --- a/experiments/AMIP/modular/cli_options.jl +++ b/experiments/AMIP/modular/cli_options.jl @@ -30,8 +30,8 @@ function argparse_settings() help = "Method to partition turbulent fluxes. [`PartitionedStateFluxes`, `CombinedStateFluxes`]" arg_type = String default = "CombinedStateFluxes" - "--monthly_checkpoint" # TODO generalize to any frequency - help = "Boolean flag indicating whether to checkpoint monthly" + "--hourly_checkpoint" + help = "Boolean flag indicating whether to checkpoint at intervals of 1 hour or multiple hours" arg_type = Bool default = false "--restart_dir" diff --git a/experiments/AMIP/modular/components/atmosphere/climaatmos_init.jl b/experiments/AMIP/modular/components/atmosphere/climaatmos_init.jl index 6bc52835fe..fa507fe712 100644 --- a/experiments/AMIP/modular/components/atmosphere/climaatmos_init.jl +++ b/experiments/AMIP/modular/components/atmosphere/climaatmos_init.jl @@ -8,8 +8,8 @@ import ClimaCoupler.FluxCalculator: extrapolate_ρ_to_sfc, get_surface_params using ClimaCore: Fields.level, Geometry -import ClimaCoupler.FieldExchanger: get_thermo_params -import ClimaCoupler.Interfacer: get_field, update_field!, name, get_model_state_vector +import ClimaCoupler.Interfacer: get_field, update_field!, name +import ClimaCoupler.Checkpointer: get_model_state_vector using StaticArrays # the clima atmos `integrator` is now defined diff --git a/experiments/AMIP/modular/coupler_driver_modular.jl b/experiments/AMIP/modular/coupler_driver_modular.jl index 3a0e20998d..43cb8d1de6 100644 --- a/experiments/AMIP/modular/coupler_driver_modular.jl +++ b/experiments/AMIP/modular/coupler_driver_modular.jl @@ -76,7 +76,16 @@ import ClimaCoupler.ConservationChecker: import ClimaCoupler.Utilities: swap_space! import ClimaCoupler.BCReader: bcfile_info_init, float_type_bcf, update_midmonth_data!, next_date_in_file, interpolate_midmonth_to_daily -import ClimaCoupler.TimeManager: current_date, datetime_to_strdate, trigger_callback, Monthly, EveryTimestep +import ClimaCoupler.TimeManager: + current_date, + datetime_to_strdate, + trigger_callback, + Monthly, + EveryTimestep, + HourlyCallback, + MonthlyCallback, + update_firstdayofmonth!, + trigger_callback! import ClimaCoupler.Diagnostics: get_var, init_diagnostics, accumulate_diagnostics!, save_diagnostics, TimeMean import ClimaCoupler.PostProcessor: postprocess @@ -90,8 +99,7 @@ import ClimaCoupler.Interfacer: LandModelSimulation, OceanModelSimulation, get_field, - update_field!, - update_sim! + update_field! import ClimaCoupler.FluxCalculator: PartitionedStateFluxes, CombinedStateFluxes, @@ -156,7 +164,7 @@ tspan = (Int(0), t_end) saveat = time_to_seconds(config_dict["dt_save_to_sol"]) date0 = date = DateTime(config_dict["start_date"], dateformat"yyyymmdd") mono_surface = config_dict["mono_surface"] -monthly_checkpoint = config_dict["monthly_checkpoint"] +hourly_checkpoint = config_dict["hourly_checkpoint"] restart_dir = config_dict["restart_dir"] restart_t = Int(config_dict["restart_t"]) @@ -439,6 +447,13 @@ if energy_check conservation_checks = (; energy = EnergyConservationCheck(model_sims), water = WaterConservationCheck(model_sims)) end +dir_paths = (; output = COUPLER_OUTPUT_DIR, artifacts = COUPLER_ARTIFACTS_DIR) +checkpoint_cb = + HourlyCallback(dt = FT(48), func = checkpoint_sims, ref_date = [dates.date[1]], active = hourly_checkpoint) # bi-daily +update_firstdayofmonth!_cb = + MonthlyCallback(dt = FT(1), func = update_firstdayofmonth!, ref_date = [dates.date1[1]], active = true) # for BCReader +callbacks = (; checkpoint = checkpoint_cb, update_firstdayofmonth! = update_firstdayofmonth!_cb) + ## coupler simulation cs = CoupledSimulation{FT}( comms_ctx, @@ -454,6 +469,8 @@ cs = CoupledSimulation{FT}( model_sims, mode_specifics, diagnostics, + callbacks, + dir_paths, ); #= @@ -572,13 +589,13 @@ function solve_coupler!(cs) ## run component models sequentially for one coupling timestep (Δt_cpl) ClimaComms.barrier(comms_ctx) + update_surface_fractions!(cs) update_model_sims!(cs.model_sims, cs.fields, turbulent_fluxes) ## step sims step_model_sims!(cs.model_sims, t) ## exchange combined fields and (if specified) calculate fluxes using combined states - update_surface_fractions!(cs) import_combined_surface_fields!(cs.fields, cs.model_sims, cs.boundary_space, turbulent_fluxes) # i.e. T_sfc, albedo, z0, beta if turbulent_fluxes isa CombinedStateFluxes combined_turbulent_fluxes!(cs.model_sims, cs.fields, turbulent_fluxes) # this updates the surface thermo state, sfc_ts, in ClimaAtmos (but also unnecessarily calculates fluxes) @@ -594,19 +611,11 @@ function solve_coupler!(cs) import_atmos_fields!(cs.fields, cs.model_sims, cs.boundary_space, turbulent_fluxes) # radiative and/or turbulent - ## monthly callbacks - if trigger_callback(cs, Monthly()) - ## step to the next calendar month - cs.dates.date1[1] += Dates.Month(1) - ## checkpoint model state - if monthly_checkpoint - for sim in cs.model_sims - if get_model_state_vector(sim) !== nothing - checkpoint_model_state(sim, comms_ctx, Int(t), output_dir = COUPLER_ARTIFACTS_DIR) - end - end - end - end + ## callback to update the fist day of month if needed (for BCReader) + trigger_callback!(cs, cs.callbacks.update_firstdayofmonth!) + + ## callback to checkpoint model state + trigger_callback!(cs, cs.callbacks.checkpoint) end @show walltime diff --git a/experiments/AMIP/modular/user_io/user_logging.jl b/experiments/AMIP/modular/user_io/user_logging.jl index 10c4a284dc..cfc89c2550 100644 --- a/experiments/AMIP/modular/user_io/user_logging.jl +++ b/experiments/AMIP/modular/user_io/user_logging.jl @@ -1,3 +1,5 @@ +using ClimaCoupler: Checkpointer + """ Base.show(io::IO, dict::Dict) @@ -8,3 +10,19 @@ function Base.show(io::IO, dict::Dict) println(io, " $k => $(dict[k])") end end + +# user callbacks +""" + checkpoint_sims(cs::CoupledSimulation, _) + +This is a callback function that checkpoints all simulations defined in the current coupled simulation. +""" +function checkpoint_sims(cs::CoupledSimulation, _) + for sim in cs.model_sims + if get_model_state_vector(sim) !== nothing + t = Dates.datetime2epochms(cs.dates.date[1]) + t0 = Dates.datetime2epochms(cs.dates.date0[1]) + Checkpointer.checkpoint_model_state(sim, cs.comms_ctx, Int((t - t0) / 1e3), output_dir = cs.dirs.artifacts) + end + end +end diff --git a/src/Checkpointer.jl b/src/Checkpointer.jl index bfb0a86e65..a9d8e8c221 100644 --- a/src/Checkpointer.jl +++ b/src/Checkpointer.jl @@ -8,7 +8,6 @@ module Checkpointer using ClimaCore: Fields, InputOutput using ClimaCoupler: Interfacer using Dates -using ClimaCoupler.TimeManager: AbstractFrequency, Monthly, EveryTimestep, trigger_callback using ClimaComms export get_model_state_vector, checkpoint_model_state, restart_model_state! diff --git a/src/Interfacer.jl b/src/Interfacer.jl index 16b626b965..343113dbd1 100644 --- a/src/Interfacer.jl +++ b/src/Interfacer.jl @@ -46,6 +46,9 @@ struct CoupledSimulation{ NTSM <: NamedTuple, NTMS <: NamedTuple, NTM <: NamedTuple, + TD <: Tuple, + NTC <: NamedTuple, + NTP <: NamedTuple, } comms_ctx::X dates::D @@ -59,10 +62,12 @@ struct CoupledSimulation{ surface_fractions::NTSM model_sims::NTMS mode::NTM - diagnostics::Tuple + diagnostics::TD + callbacks::NTC + dirs::NTP end -CoupledSimulation{FT}(args...) where {FT} = CoupledSimulation{FT, typeof.(args[1:12])...}(args...) +CoupledSimulation{FT}(args...) where {FT} = CoupledSimulation{FT, typeof.(args[1:end])...}(args...) """ float_type(::CoupledSimulation) diff --git a/src/TimeManager.jl b/src/TimeManager.jl index 4d6fcf1c0d..876b115bda 100644 --- a/src/TimeManager.jl +++ b/src/TimeManager.jl @@ -6,11 +6,23 @@ of data. """ module TimeManager -using ..Interfacer: CoupledSimulation +using ..Interfacer using Dates +using DocStringExtensions +const DSE = DocStringExtensions + export current_date, - strdate_to_datetime, datetime_to_strdate, AbstractFrequency, Monthly, EveryTimestep, trigger_callback + strdate_to_datetime, + datetime_to_strdate, + trigger_callback, + AbstractFrequency, + Monthly, + EveryTimestep, + trigger_callback!, + HourlyCallback, + MonthlyCallback, + update_firstdayofmonth! """ @@ -22,7 +34,7 @@ Return the model date at the current timestep. - `cs`: [CoupledSimulation] containing info about the simulation - `t`: [Real] number of seconds since simulation began """ -current_date(cs::CoupledSimulation, t::Real) = cs.dates.date0[1] + Dates.Second(t) +current_date(cs::Interfacer.CoupledSimulation, t::Real) = cs.dates.date0[1] + Dates.Second(t) """ strdate_to_datetime(strdate::String) @@ -63,4 +75,77 @@ Returns `true` if the current date is equal to or exceeds the saved first of the """ trigger_callback(cs::CoupledSimulation, ::Monthly) = cs.dates.date[1] >= cs.dates.date1[1] ? true : false + +abstract type CouplerCallback end + +""" + do_nothing(::Interfacer.CoupledSimulation, _) + +This is a helper callback function that does nothing. +""" +do_nothing(::Interfacer.CoupledSimulation, _) = nothing + +""" + HourlyCallback{FT} + +This is a callback type that triggers at intervals of 1h or multiple hours. + +# Fields + +$(DSE.FIELDS) +""" +@kwdef struct HourlyCallback{FT} <: CouplerCallback + dt::FT = FT(1) # hours + func::Function = do_nothing + ref_date::Array = [Dates.DateTime(0)] + active::Bool = false + data::Array = [] +end + +""" + MonthlyCallback{FT} + +This is a callback type that triggers at intervals of 1 month or multiple months. + +# Fields + +$(DSE.FIELDS) +""" +@kwdef struct MonthlyCallback{FT} <: CouplerCallback + dt::FT = FT(1) # months + func::Function = do_nothing + ref_date::Array = [Dates.DateTime(0)] + active::Bool = false + data::Array = [] +end + +dt_cb(cb::HourlyCallback) = Dates.Hour(cb.dt) +dt_cb(cb::MonthlyCallback) = Dates.Month(cb.dt) + +""" + trigger_callback!(cs::Interfacer.CoupledSimulation, cb::CouplerCallback) + +This function triggers a callback function if the current date is equal to or exceeds the saved callback reference date. +As well as executing the functions `func`, it automatically updates the reference date, `ref_date`, for the next callback interval. +""" +function trigger_callback!(cs::Interfacer.CoupledSimulation, cb::CouplerCallback) + if cb.active + current_date = cs.dates.date[1] + if current_date >= cb.ref_date[1] + cb.func(cs, cb) + cb.ref_date[1] = cb.ref_date[1] + dt_cb(cb) + end + end +end + +""" + update_firstdayofmonth!(cs::Interfacer.CoupledSimulation, _) + +This function updates the first of the month reference date. +""" +function update_firstdayofmonth!(cs, _) + cs.dates.date1[1] = cs.dates.date1[1] + Dates.Month(1) + @info("update_firstdayofmonth! at $(cs.dates.date)") +end + end diff --git a/test/bcreader_tests.jl b/test/bcreader_tests.jl index 9541305bcc..f5ac7dee73 100644 --- a/test/bcreader_tests.jl +++ b/test/bcreader_tests.jl @@ -194,6 +194,8 @@ for FT in (Float32, Float64) (;), # model_sims (;), # mode (), # diagnostics + (;), # callbacks + (;), # dirs ) # step in time diff --git a/test/conservation_checker_tests.jl b/test/conservation_checker_tests.jl index 29def0d1b1..4ca7742ef7 100644 --- a/test/conservation_checker_tests.jl +++ b/test/conservation_checker_tests.jl @@ -86,6 +86,8 @@ get_field(s::TestLand, ::Val{:area_fraction}) = ones(s.i.space) .* 0.25 model_sims, # model_sims (;), # mode (), # diagnostics + (;), # callbacks + (;), # dirs ) # set non-zero radiation and precipitation @@ -163,6 +165,8 @@ end model_sims, # model_sims (;), # mode (), # diagnostics + (;), # callbacks + (;), # dirs ) tot_energy, tot_water = check_conservation!(cs) diff --git a/test/debug/debug_amip_plots.jl b/test/debug/debug_amip_plots.jl index 17454fc9a3..fd8b4540df 100644 --- a/test/debug/debug_amip_plots.jl +++ b/test/debug/debug_amip_plots.jl @@ -69,6 +69,8 @@ plot_field_names(sim::SurfaceStub) = (:stub_field,) model_sims, # model_sims (;), # mode (), # diagnostics + (;), # callbacks + (;), # dirs ) output_plots = "test_debug" diff --git a/test/diagnostics_tests.jl b/test/diagnostics_tests.jl index f20027ecf8..da2f13669e 100644 --- a/test/diagnostics_tests.jl +++ b/test/diagnostics_tests.jl @@ -52,6 +52,8 @@ end (;), # model_sims (;), # mode (dg_2d,), + (;), # callbacks + (;), # dirs ) accumulate_diagnostics!(cs) @test cs.diagnostics[1].field_vector[1] == expected_results[c_i] @@ -86,6 +88,8 @@ if !Sys.iswindows() # Windows has NetCDF / HDF5 support limitations (;), # model_sims (;), # mode (dg_2d,), # diagnostics + (;), # callbacks + (;), # dirs ) save_diagnostics(cs, cs.diagnostics[1]) file = filter(x -> endswith(x, ".hdf5"), readdir(test_dir)) @@ -124,6 +128,8 @@ end (;), # model_sims (;), # mode (dg_2d,), + (;), # callbacks + (;), # dirs ) accumulate_diagnostics!(cs) @test cs.diagnostics[1].field_vector[1] == expected_results[c_i][1] diff --git a/test/interfacer_tests.jl b/test/interfacer_tests.jl index e103f2412d..9c51f7ffca 100644 --- a/test/interfacer_tests.jl +++ b/test/interfacer_tests.jl @@ -43,6 +43,8 @@ for FT in (Float32, Float64) (;), # model_sims (;), # mode (), # diagnostics + (;), # callbacks + (;), # dirs ) @test float_type(cs) == FT diff --git a/test/mpi_tests/bcreader_mpi_tests.jl b/test/mpi_tests/bcreader_mpi_tests.jl index 00cdea126e..5adb7e16de 100644 --- a/test/mpi_tests/bcreader_mpi_tests.jl +++ b/test/mpi_tests/bcreader_mpi_tests.jl @@ -140,6 +140,8 @@ end (;), # model_sims (;), # mode (), # diagnostics + (;), # callbacks + (;), # dirs ) ClimaComms.barrier(comms_ctx) diff --git a/test/mpi_tests/local_checks.sh b/test/mpi_tests/local_checks.sh index 634dc1b757..d2ca6c8bc8 100644 --- a/test/mpi_tests/local_checks.sh +++ b/test/mpi_tests/local_checks.sh @@ -33,8 +33,8 @@ julia --project=artifacts -e 'using Pkg; Pkg.status()' julia --project=artifacts artifacts/download_artifacts.jl # run spin up -# - specify `--monthly_checkpoint true` to save monthly checkpoints of all model prognostic states -mpiexec julia --color=yes --project=experiments/AMIP/modular/ experiments/AMIP/modular/coupler_driver_modular.jl --run_name $RUN_NAME --coupled true --start_date 19790101 --monthly_checkpoint true --anim true --surface_setup PrescribedSurface --dt_cpl 200 --energy_check false --mode_name amip --mono_surface false --vert_diff true --moist equil --rad clearsky --precip_model 0M --z_elem 35 --dz_bottom 50 --h_elem 12 --kappa_4 3e16 --rayleigh_sponge true --alpha_rayleigh_uh 0 --dt 200secs --t_end 0.1days --job_id $RUN_NAME --dt_save_to_sol 1000days --dt_save_to_disk 10days --apply_limiter false --FLOAT_TYPE Float64 +# - specify `--hourly_checkpoint true` to save monthly checkpoints of all model prognostic states +mpiexec julia --color=yes --project=experiments/AMIP/modular/ experiments/AMIP/modular/coupler_driver_modular.jl --run_name $RUN_NAME --coupled true --start_date 19790101 --hourly_checkpoint true --anim true --surface_setup PrescribedSurface --dt_cpl 200 --energy_check false --mode_name amip --mono_surface false --vert_diff true --moist equil --rad clearsky --precip_model 0M --z_elem 35 --dz_bottom 50 --h_elem 12 --kappa_4 3e16 --rayleigh_sponge true --alpha_rayleigh_uh 0 --dt 200secs --t_end 0.1days --job_id $RUN_NAME --dt_save_to_sol 1000days --dt_save_to_disk 10days --apply_limiter false --FLOAT_TYPE Float64 # init using a restart # - specify the directory of the `checkpoint/` folder (i.e., `--restart_dir`) and time (in secs; `--restart_t`) of the restart file diff --git a/test/regridder_tests.jl b/test/regridder_tests.jl index 44d57d9b8e..bdb653896f 100644 --- a/test/regridder_tests.jl +++ b/test/regridder_tests.jl @@ -81,6 +81,8 @@ for FT in (Float32, Float64) (; ice_sim = DummyStub((; area_fraction = ice_d)), ocean_sim = SurfaceStub((; area_fraction = ocean_d))), # model_sims (;), # mode (), # diagnostics + (;), # callbacks + (;), # dirs ) Regridder.update_surface_fractions!(cs) diff --git a/test/time_manager_tests.jl b/test/time_manager_tests.jl index b972aa9427..61c77d871d 100644 --- a/test/time_manager_tests.jl +++ b/test/time_manager_tests.jl @@ -29,6 +29,8 @@ for FT in (Float32, Float64) (;), # model_sims (;), # mode (), # diagnostics + (;), # callbacks + (;), # dirs ) for t in ((tspan[1] + Δt_cpl):Δt_cpl:tspan[end]) @@ -65,6 +67,115 @@ end (;), # model_sims (;), # mode (), # diagnostics + (;), # callbacks + (;), # dirs ) @test TimeManager.trigger_callback(cs, TimeManager.Monthly()) == true end + +@testset "trigger_callback!" begin + + FT = Float64 + date0 = date = DateTime("19790321", dateformat"yyyymmdd") + dates = (; date = [date], date0 = [date0], date1 = [Dates.firstdayofmonth(date0)]) + + function counter_func(cs, cb) + cb.data .+= 1 + end + twhohourly_inactive = TimeManager.HourlyCallback{FT}(dt = 2, ref_date = [date0]) + twhohourly_nothing = TimeManager.HourlyCallback{FT}(dt = 2, ref_date = [date0], active = true) + twhohourly_counter = + TimeManager.HourlyCallback{FT}(dt = 2, ref_date = [date0], func = counter_func, data = [0], active = true) + monthly_counter = + TimeManager.MonthlyCallback{FT}(func = counter_func, ref_date = [date0], data = [0], active = true) + + cs = Interfacer.CoupledSimulation{Float64}( + nothing, # comms_ctx + dates, # dates + nothing, # boundary_space + nothing, # fields + nothing, # parsed_args + nothing, # conservation_checks + (Int(0), Int(1000)), # tspan + Int(200), # t + Int(200), # Δt_cpl + (;), # surface_masks + (;), # model_sims + (;), # mode + (), # diagnostics + (; + twhohourly_inactive = twhohourly_inactive, + twhohourly_nothing = twhohourly_nothing, + twhohourly_counter = twhohourly_counter, + monthly_counter = monthly_counter, + ), # callbacks + (;), # dirs + ) + + TimeManager.trigger_callback!(cs, cs.callbacks.twhohourly_inactive) + TimeManager.trigger_callback!(cs, cs.callbacks.twhohourly_nothing) + TimeManager.trigger_callback!(cs, cs.callbacks.twhohourly_counter) + TimeManager.trigger_callback!(cs, cs.callbacks.monthly_counter) + @test cs.callbacks.twhohourly_inactive.ref_date[1] == date0 + @test cs.callbacks.twhohourly_nothing.ref_date[1] == cs.dates.date0[1] + Dates.Hour(2) + @test cs.callbacks.twhohourly_counter.ref_date[1] == cs.dates.date0[1] + Dates.Hour(2) + @test cs.callbacks.monthly_counter.ref_date[1] == cs.dates.date0[1] + Dates.Month(1) + @test cs.callbacks.twhohourly_counter.data[1] == 1 + @test cs.callbacks.monthly_counter.data[1] == 1 + + cs.dates.date .+= Dates.Hour(2) + TimeManager.trigger_callback!(cs, cs.callbacks.twhohourly_inactive) + TimeManager.trigger_callback!(cs, cs.callbacks.twhohourly_nothing) + TimeManager.trigger_callback!(cs, cs.callbacks.twhohourly_counter) + TimeManager.trigger_callback!(cs, cs.callbacks.monthly_counter) + @test cs.callbacks.twhohourly_inactive.ref_date[1] == date0 + @test cs.callbacks.twhohourly_nothing.ref_date[1] == cs.dates.date0[1] + Dates.Hour(4) + @test cs.callbacks.twhohourly_counter.ref_date[1] == cs.dates.date0[1] + Dates.Hour(4) + @test cs.callbacks.monthly_counter.ref_date[1] == cs.dates.date0[1] + Dates.Month(1) + @test cs.callbacks.twhohourly_counter.data[1] == 2 + @test cs.callbacks.monthly_counter.data[1] == 1 + + cs.dates.date .+= Dates.Month(1) + TimeManager.trigger_callback!(cs, cs.callbacks.twhohourly_inactive) + TimeManager.trigger_callback!(cs, cs.callbacks.twhohourly_nothing) + TimeManager.trigger_callback!(cs, cs.callbacks.twhohourly_counter) + TimeManager.trigger_callback!(cs, cs.callbacks.monthly_counter) + @test cs.callbacks.twhohourly_inactive.ref_date[1] == date0 + @test cs.callbacks.twhohourly_inactive.ref_date[1] == date0 + @test cs.callbacks.twhohourly_nothing.ref_date[1] == cs.dates.date0[1] + Dates.Hour(6) + @test cs.callbacks.twhohourly_counter.ref_date[1] == cs.dates.date0[1] + Dates.Hour(6) + @test cs.callbacks.monthly_counter.ref_date[1] == cs.dates.date0[1] + Dates.Month(2) + @test cs.callbacks.twhohourly_counter.data[1] == 3 + @test cs.callbacks.monthly_counter.data[1] == 2 + +end + +# TimeManager +@testset "update_firstdayofmonth!" begin + + FT = Float64 + date0 = date = DateTime("19790321", dateformat"yyyymmdd") + dates = (; date = [date], date0 = [date0], date1 = [Dates.firstdayofmonth(date0)]) + + cs = Interfacer.CoupledSimulation{Float64}( + nothing, # comms_ctx + dates, # dates + nothing, # boundary_space + nothing, # fields + nothing, # parsed_args + nothing, # conservation_checks + (Int(0), Int(1000)), # tspan + Int(200), # t + Int(200), # Δt_cpl + (;), # surface_masks + (;), # model_sims + (;), # mode + (), # diagnostics + (;), # callbacks + (;), # dirs + ) + + TimeManager.update_firstdayofmonth!(cs, nothing) + @test cs.dates.date1[1] == Dates.firstdayofmonth(date0) + Dates.Month(1) + +end