diff --git a/Project.toml b/Project.toml index 42b07660a9..e4d162965f 100644 --- a/Project.toml +++ b/Project.toml @@ -10,6 +10,7 @@ ClimaComms = "3a4d1b5c-c61d-41fd-a00a-5873ba7a1b0d" ClimaCore = "d414da3d-4745-48bb-8d80-42e94e092884" ClimaCoreTempestRemap = "d934ef94-cdd4-4710-83d6-720549644b70" ClimaLSM = "7884a58f-fab6-4fd0-82bb-ecfedb2d8430" +ClimaUtilities = "b3f4f4ca-9299-4f7f-bd9b-81e1242a7513" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" Insolation = "e98cc03f-d57e-4e3c-b70c-8d51efe9e0d8" @@ -34,6 +35,7 @@ ClimaComms = "0.5" ClimaCore = "0.10" ClimaCoreTempestRemap = "0.3" ClimaLSM = "0.3.2" +ClimaUtilities = "0.1.1" DocStringExtensions = "0.8, 0.9" Insolation = "0.6" JLD2 = "0.4" diff --git a/docs/Project.toml b/docs/Project.toml index 66005a86ff..757d5c53ae 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,5 +1,6 @@ [deps] ClimaCoupler = "4ade58fe-a8da-486c-bd89-46df092ec0c7" +ClimaUtilities = "b3f4f4ca-9299-4f7f-bd9b-81e1242a7513" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" diff --git a/docs/make.jl b/docs/make.jl index d6de55f844..443f171057 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -64,7 +64,6 @@ interface_pages = [ "utilities.md", "bcreader.md", "testhelper.md", - "timemanager.md", ] performance_pages = ["performance.md"] diff --git a/docs/src/timemanager.md b/docs/src/timemanager.md deleted file mode 100644 index 9fd9c162a7..0000000000 --- a/docs/src/timemanager.md +++ /dev/null @@ -1,16 +0,0 @@ -# TimeManager - -This module contains functions that handle dates and times -in simulations. The functions in this module often call -functions from Julia's [Dates](https://docs.julialang.org/en/v1/stdlib/Dates/) module. - -## TimeManager API - -```@docs -ClimaCoupler.TimeManager.current_date -ClimaCoupler.TimeManager.strdate_to_datetime -ClimaCoupler.TimeManager.datetime_to_strdate -ClimaCoupler.TimeManager.trigger_callback -ClimaCoupler.TimeManager.Monthly -ClimaCoupler.TimeManager.EveryTimestep -``` diff --git a/experiments/AMIP/modular/Manifest.toml b/experiments/AMIP/modular/Manifest.toml index 0970cc4942..984851fbed 100644 --- a/experiments/AMIP/modular/Manifest.toml +++ b/experiments/AMIP/modular/Manifest.toml @@ -2,7 +2,7 @@ julia_version = "1.8.5" manifest_format = "2.0" -project_hash = "43b11af04e9e53b2a11737cbd1cdc443f9bb9f21" +project_hash = "62d8abc16253da5976b5e35ddf6ad7883a59e86e" [[deps.ADTypes]] git-tree-sha1 = "5d2e21d7b0d8c22f67483ef95ebdc39c0e6b6003" @@ -144,9 +144,9 @@ version = "0.1.2" [[deps.CLIMAParameters]] deps = ["DocStringExtensions", "TOML", "Test"] -git-tree-sha1 = "d35d039179f27abc063f7ae5c564573fe5316bb2" +git-tree-sha1 = "9872c4383d3c212096b2750bf1c2237a4670a3af" uuid = "6eacf6c3-8458-43b9-ae03-caf5306d3d53" -version = "0.7.19" +version = "0.7.20" [[deps.CPUSummary]] deps = ["CpuId", "IfElse", "PrecompileTools", "Static"] @@ -239,7 +239,7 @@ uuid = "d934ef94-cdd4-4710-83d6-720549644b70" version = "0.3.5" [[deps.ClimaCoupler]] -deps = ["CLIMAParameters", "ClimaAtmos", "ClimaComms", "ClimaCore", "ClimaCoreTempestRemap", "ClimaLSM", "Dates", "DocStringExtensions", "HDF5", "Insolation", "JLD2", "NCDatasets", "OrdinaryDiffEq", "Plots", "PrettyTables", "SciMLBase", "StaticArrays", "Statistics", "SurfaceFluxes", "TempestRemap_jll", "TerminalLoggers", "Thermodynamics", "UnPack"] +deps = ["CLIMAParameters", "ClimaAtmos", "ClimaComms", "ClimaCore", "ClimaCoreTempestRemap", "ClimaLSM", "ClimaUtilities", "Dates", "DocStringExtensions", "Insolation", "JLD2", "NCDatasets", "OrdinaryDiffEq", "Plots", "PrettyTables", "SciMLBase", "StaticArrays", "Statistics", "SurfaceFluxes", "TempestRemap_jll", "TerminalLoggers", "Thermodynamics", "UnPack"] path = "../../.." uuid = "4ade58fe-a8da-486c-bd89-46df092ec0c7" version = "0.1.0" @@ -256,6 +256,14 @@ git-tree-sha1 = "54b602435b0107b6c2dfe7664e0f7ff5fc78fb91" uuid = "595c0a79-7f3d-439a-bc5a-b232dc3bde79" version = "0.7.7" +[[deps.ClimaUtilities]] +deps = ["CFTime", "Dates"] +git-tree-sha1 = "8108441c603a0921e81d5aa5ff07655a7c44c0a1" +repo-rev = "js/timemanager" +repo-url = "https://github.com/CliMA/ClimaUtilities.jl.git" +uuid = "b3f4f4ca-9299-4f7f-bd9b-81e1242a7513" +version = "0.1.1" + [[deps.CloseOpenIntervals]] deps = ["Static", "StaticArrayInterface"] git-tree-sha1 = "70232f82ffaab9dc52585e0dd043b5e0c6b714f1" @@ -276,9 +284,9 @@ version = "0.7.2" [[deps.ColorSchemes]] deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"] -git-tree-sha1 = "d9a8f86737b665e15a9641ecbac64deef9ce6724" +git-tree-sha1 = "67c1f244b991cad9b0aa4b7540fb758c2488b129" uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" -version = "3.23.0" +version = "3.24.0" [[deps.ColorTypes]] deps = ["FixedPointNumbers", "Random"] @@ -408,9 +416,9 @@ version = "0.1.0+0" [[deps.DiffEqBase]] deps = ["ArrayInterface", "ChainRulesCore", "DataStructures", "Distributions", "DocStringExtensions", "EnumX", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "FunctionWrappersWrappers", "LinearAlgebra", "Logging", "Markdown", "MuladdMacro", "Parameters", "PreallocationTools", "PrecompileTools", "Printf", "RecursiveArrayTools", "Reexport", "Requires", "SciMLBase", "SciMLOperators", "Setfield", "SparseArrays", "Static", "StaticArraysCore", "Statistics", "Tricks", "TruncatedStacktraces", "ZygoteRules"] -git-tree-sha1 = "6ece6f2956dea6380d8e5e6eadaab1bb9af20cce" +git-tree-sha1 = "0d9982e8dee851d519145857e79a17ee33ede154" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.129.0" +version = "6.130.0" [[deps.DiffEqCallbacks]] deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "Functors", "LinearAlgebra", "Markdown", "NLsolve", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArraysCore"] @@ -473,6 +481,12 @@ git-tree-sha1 = "bdb1942cd4c45e3c678fd11569d5cccd80976237" uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56" version = "1.0.4" +[[deps.EpollShim_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "8e9441ee83492030ace98f9789a654a6d0b1f643" +uuid = "2702e6a9-849d-5ed8-8c21-79e8b8f9ee43" +version = "0.0.20230411+0" + [[deps.ExceptionUnwrapping]] deps = ["Test"] git-tree-sha1 = "e90caa41f5a86296e014e148ee061bd6c3edec96" @@ -824,9 +838,9 @@ version = "1.0.0" [[deps.JLD2]] deps = ["FileIO", "MacroTools", "Mmap", "OrderedCollections", "Pkg", "Printf", "Reexport", "Requires", "TranscodingStreams", "UUIDs"] -git-tree-sha1 = "aa6ffef1fd85657f4999030c52eaeec22a279738" +git-tree-sha1 = "773125c999b4ebfe31e679593c8af7f43f401f1c" uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -version = "0.4.33" +version = "0.4.34" [[deps.JLFzf]] deps = ["Pipe", "REPL", "Random", "fzf_jll"] @@ -1387,9 +1401,9 @@ version = "1.2.0" [[deps.Preferences]] deps = ["TOML"] -git-tree-sha1 = "7eb1686b4f04b82f96ed7a4ea5890a4f0c7a09f1" +git-tree-sha1 = "00805cd429dcb4870060ff49ef443486c262e38e" uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.4.0" +version = "1.4.1" [[deps.PrettyTables]] deps = ["Crayons", "LaTeXStrings", "Markdown", "Printf", "Reexport", "StringManipulation", "Tables"] @@ -1421,9 +1435,9 @@ version = "5.15.3+2" [[deps.QuadGK]] deps = ["DataStructures", "LinearAlgebra"] -git-tree-sha1 = "6ec7ac8412e83d57e313393220879ede1740f9ee" +git-tree-sha1 = "eeab25344bf9901146c0200a7ca64ea479f8bf5c" uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" -version = "2.8.2" +version = "2.9.0" [[deps.REPL]] deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] @@ -1539,9 +1553,9 @@ version = "0.6.39" [[deps.SciMLBase]] deps = ["ADTypes", "ArrayInterface", "ChainRulesCore", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "EnumX", "FillArrays", "FunctionWrappersWrappers", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "PrecompileTools", "Preferences", "RecipesBase", "RecursiveArrayTools", "Reexport", "RuntimeGeneratedFunctions", "SciMLOperators", "StaticArraysCore", "Statistics", "SymbolicIndexingInterface", "Tables", "TruncatedStacktraces", "ZygoteRules"] -git-tree-sha1 = "6de099dba3c80e23bde1d19011161ea91a23ed6b" +git-tree-sha1 = "916b8a94c0d61fa5f7c5295649d3746afb866aff" uuid = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -version = "1.98.0" +version = "1.98.1" [[deps.SciMLNLSolve]] deps = ["DiffEqBase", "LineSearches", "NLsolve", "Reexport", "SciMLBase"] @@ -1741,10 +1755,10 @@ uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" version = "1.0.1" [[deps.Tables]] -deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits", "Test"] -git-tree-sha1 = "1544b926975372da01227b382066ab70e574a3ec" +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits"] +git-tree-sha1 = "a1f34829d5ac0ef499f6d84428bd6b4c71f02ead" uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" -version = "1.10.1" +version = "1.11.0" [[deps.Tar]] deps = ["ArgTools", "SHA"] @@ -1900,10 +1914,10 @@ uuid = "19fa3120-7c27-5ec5-8db8-b0b0aa330d6f" version = "0.2.0" [[deps.Wayland_jll]] -deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] -git-tree-sha1 = "ed8d92d9774b077c53e1da50fd81a36af3744c1c" +deps = ["Artifacts", "EpollShim_jll", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "7558e29847e99bc3f04d6569e82d0f5c54460703" uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" -version = "1.21.0+0" +version = "1.21.0+1" [[deps.Wayland_protocols_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] @@ -2143,6 +2157,6 @@ version = "3.5.0+0" [[deps.xkbcommon_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] -git-tree-sha1 = "9ebfc140cc56e8c2156a15ceac2f0302e327ac0a" +git-tree-sha1 = "9c304562909ab2bab0262639bd4f444d7bc2be37" uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" -version = "1.4.1+0" +version = "1.4.1+1" diff --git a/experiments/AMIP/modular/Project.toml b/experiments/AMIP/modular/Project.toml index 1e3102b32f..d7882bdd0a 100644 --- a/experiments/AMIP/modular/Project.toml +++ b/experiments/AMIP/modular/Project.toml @@ -11,6 +11,7 @@ ClimaCoreTempestRemap = "d934ef94-cdd4-4710-83d6-720549644b70" ClimaCoupler = "4ade58fe-a8da-486c-bd89-46df092ec0c7" ClimaLSM = "7884a58f-fab6-4fd0-82bb-ecfedb2d8430" ClimaTimeSteppers = "595c0a79-7f3d-439a-bc5a-b232dc3bde79" +ClimaUtilities = "b3f4f4ca-9299-4f7f-bd9b-81e1242a7513" CloudMicrophysics = "6a9e3e04-43cd-43ba-94b9-e8782df3c71b" Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" Dierckx = "39dd38d3-220a-591b-8e3c-4c3a8c710a94" diff --git a/experiments/AMIP/modular/coupler_driver_modular.jl b/experiments/AMIP/modular/coupler_driver_modular.jl index 994318dd04..e724446cb5 100644 --- a/experiments/AMIP/modular/coupler_driver_modular.jl +++ b/experiments/AMIP/modular/coupler_driver_modular.jl @@ -65,6 +65,7 @@ import YAML using ClimaCore.Utilities: half, PlusHalf using ClimaCore: InputOutput, Fields import ClimaCore.Spaces as Spaces +import ClimaUtilities: TimeManager if !(@isdefined parsed_args) # coupler defaults include("cli_options.jl") @@ -138,10 +139,9 @@ import ClimaCoupler.Regridder: update_surface_fractions!, combine_surfaces!, combine_surfaces_from_sol!, dummmy_remap!, binary_mask import ClimaCoupler.ConservationChecker: EnergyConservationCheck, WaterConservationCheck, check_conservation!, plot_global_conservation -import ClimaCoupler.Utilities: CoupledSimulation, float_type, swap_space! +import ClimaCoupler.Utilities: CoupledSimulation, float_type, swap_space!, current_date 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.Diagnostics: get_var, init_diagnostics, accumulate_diagnostics!, save_diagnostics, TimeMean import ClimaCoupler.PostProcessor: postprocess @@ -384,7 +384,7 @@ User can write custom diagnostics in the `user_diagnostics.jl`. monthly_3d_diags = init_diagnostics( (:T, :u, :q_tot, :q_liq_ice), atmos_sim.domain.center_space; - save = Monthly(), + save = TimeManager.Monthly(), operations = (; accumulate = TimeMean([Int(0)])), output_dir = COUPLER_OUTPUT_DIR, name_tag = "monthly_mean_3d_", @@ -393,7 +393,7 @@ monthly_3d_diags = init_diagnostics( monthly_2d_diags = init_diagnostics( (:precipitation_rate, :toa_fluxes, :T_sfc, :tubulent_energy_fluxes), boundary_space; - save = Monthly(), + save = TimeManager.Monthly(), operations = (; accumulate = TimeMean([Int(0)])), output_dir = COUPLER_OUTPUT_DIR, name_tag = "monthly_mean_2d_", @@ -567,18 +567,24 @@ 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 + ## function to checkpoint model state + checkpoint_func = + (monthly_checkpoint, cs, comms_ctx, t, COUPLER_ARTIFACTS_DIR) -> 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 + func_args = (monthly_checkpoint, cs, comms_ctx, t, COUPLER_ARTIFACTS_DIR) + ## perform monthly callback and increment `cs.dates.date1` if `cs.dates.date` passes to next month + TimeManager.trigger_callback( + cs.dates.date1[1], + cs.dates.date[1], + TimeManager.Monthly(), + checkpoint_func, + func_args, + ) end @show walltime diff --git a/src/BCReader.jl b/src/BCReader.jl index 92a81fbed9..d7723d2ab8 100644 --- a/src/BCReader.jl +++ b/src/BCReader.jl @@ -7,9 +7,10 @@ monthly to daily intervals. """ module BCReader -using ..Utilities, ..Regridder, ..TimeManager +using ..Utilities, ..Regridder using ClimaCore: Fields using ClimaComms +import ClimaUtilities: TimeManager using Dates using JLD2 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/ClimaCoupler.jl b/src/ClimaCoupler.jl index bcd40ca48e..7175534b6c 100644 --- a/src/ClimaCoupler.jl +++ b/src/ClimaCoupler.jl @@ -11,7 +11,6 @@ include("CoupledSimulations/coupled_simulation.jl") include("CouplerState/coupler_state.jl") include("../test/TestHelper.jl") include("Utilities.jl") -include("TimeManager.jl") include("Regridder.jl") include("ConservationChecker.jl") include("BCReader.jl") diff --git a/src/Diagnostics.jl b/src/Diagnostics.jl index 109ddbc079..931d66e1c7 100644 --- a/src/Diagnostics.jl +++ b/src/Diagnostics.jl @@ -8,7 +8,7 @@ module Diagnostics using ClimaCore: Spaces, Fields, InputOutput using ClimaCoupler.Utilities: CoupledSimulation using Dates -using ClimaCoupler.TimeManager: AbstractFrequency, Monthly, EveryTimestep, trigger_callback +using ClimaUtilities.TimeManager: Monthly, EveryTimestep, trigger_callback using ClimaComms export get_var, init_diagnostics, accumulate_diagnostics!, save_diagnostics, TimeMean @@ -131,13 +131,20 @@ end Saves all entries in `dg` in separate HDF5 files per variable in `output_dir`. """ function save_diagnostics(cs::CoupledSimulation) - for dg in cs.diagnostics + # extract dates for callback condition check + date_cutoff = cs.dates.date1[1] + date_current = cs.dates.date[1] + # define function to perform diagnostic saving if callback is triggered + save_func = (cs) -> for dg in cs.diagnostics if trigger_callback(cs, dg.save) pre_save(dg.operations.accumulate, cs, dg) save_diagnostics(cs, dg) post_save(dg.operations.accumulate, cs, dg) end end + func_args = (cs,) + # perform monthly callback and increment `cs.dates.date1` if `date_current` passes to next month + trigger_callback(date_cutoff, date_current, Monthly(), save_func, func_args) end function save_diagnostics(cs::CoupledSimulation, dg::DiagnosticsGroup) diff --git a/src/Regridder.jl b/src/Regridder.jl index 678b3e549b..3d9b261740 100644 --- a/src/Regridder.jl +++ b/src/Regridder.jl @@ -8,10 +8,10 @@ via ClimaCoreTempestRemap wrappers. module Regridder using ..Utilities -using ..TimeManager using ..Interfacer using ClimaCore: Meshes, Domains, Topologies, Spaces, Fields, InputOutput using ClimaComms +using ClimaUtilities.TimeManager using NCDatasets using ClimaCoreTempestRemap using Dates @@ -144,7 +144,7 @@ function hdwrite_regridfile_rll_to_cgll( if "time" in ds data_dates = Dates.DateTime.(ds["time"][:]) elseif "date" in ds - data_dates = TimeManager.strdate_to_datetime.(string.(ds["date"][:])) + data_dates = strdate_to_datetime.(string.(ds["date"][:])) else @warn "No dates available in file $datafile_rll" data_dates = [Dates.DateTime(0)] diff --git a/src/TimeManager.jl b/src/TimeManager.jl deleted file mode 100644 index 51ffd098a8..0000000000 --- a/src/TimeManager.jl +++ /dev/null @@ -1,66 +0,0 @@ -""" - TimeManager - -This module facilitates calendar functions and temporal interpolations -of data. -""" -module TimeManager - -using ..Utilities -using Dates - -export current_date, - strdate_to_datetime, datetime_to_strdate, AbstractFrequency, Monthly, EveryTimestep, trigger_callback - - -""" - current_date(cs::CoupledSimulation, t::Int) - -Return the model date at the current timestep. - -# Arguments -- `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) - -""" - strdate_to_datetime(strdate::String) - -Convert from String ("YYYYMMDD") to Date format, -required by the official AMIP input files. - -# Arguments -- `strdate`: [String] to be converted to Date type -""" -strdate_to_datetime(strdate::String) = - Dates.DateTime(parse(Int, strdate[1:4]), parse(Int, strdate[5:6]), parse(Int, strdate[7:8])) - -""" - datetime_to_strdate(datetime::DateTime) - -Convert from Date to String ("YYYYMMDD") format. - -# Arguments -- `datetime`: [DateTime] object to be converted to string -""" -datetime_to_strdate(datetime::DateTime) = - string(lpad(Dates.year(datetime), 4, "0")) * - string(string(lpad(Dates.month(datetime), 2, "0"))) * - string(lpad(Dates.day(datetime), 2, "0")) - -abstract type AbstractFrequency end -struct Monthly <: AbstractFrequency end -struct EveryTimestep <: AbstractFrequency end - -""" - trigger_callback(cs, ::Monthly) - -Returns `true` if the current date is equal to or exceeds the saved first of the month at time of 00:00:00. - -# Arguments -- `cs`: [CoupledSimulation] containing info about the simulation -""" -trigger_callback(cs::CoupledSimulation, ::Monthly) = cs.dates.date[1] >= cs.dates.date1[1] ? true : false - -end diff --git a/src/Utilities.jl b/src/Utilities.jl index 5d24753067..f085e458b1 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -7,8 +7,9 @@ modules in the coupler. module Utilities using ClimaCore: Fields, Spaces +using Dates -export CoupledSimulation, float_type, swap_space! +export CoupledSimulation, float_type, swap_space!, current_date """ AbstractSimulation @@ -74,4 +75,15 @@ function swap_space!(field_out, field_in::Fields.Field) return field_out end +""" + current_date(cs::CoupledSimulation, t::Int) + +Return the model date at the current timestep. + +# Arguments +- `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) + end # module diff --git a/test/Project.toml b/test/Project.toml index 9b8e729038..fe58fd220f 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -7,6 +7,7 @@ ClimaCore = "d414da3d-4745-48bb-8d80-42e94e092884" ClimaCoupler = "4ade58fe-a8da-486c-bd89-46df092ec0c7" ClimaLSM = "7884a58f-fab6-4fd0-82bb-ecfedb2d8430" ClimaTimeSteppers = "595c0a79-7f3d-439a-bc5a-b232dc3bde79" +ClimaUtilities = "b3f4f4ca-9299-4f7f-bd9b-81e1242a7513" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" diff --git a/test/bcreader_tests.jl b/test/bcreader_tests.jl index bfaf495fc1..bf5a9fb124 100644 --- a/test/bcreader_tests.jl +++ b/test/bcreader_tests.jl @@ -2,9 +2,10 @@ Unit tests for ClimaCoupler BCReader module =# -using ClimaCoupler: Regridder, BCReader, TimeManager, Utilities +using ClimaCoupler: Regridder, BCReader, Utilities using ClimaCore: Fields, Meshes, Domains, Topologies, Spaces using ClimaComms +using ClimaUtilities: TimeManager using Test using Dates using NCDatasets @@ -198,7 +199,7 @@ for FT in (Float32, Float64) # step in time walltime = @elapsed for t in ((tspan[1] + Δt):Δt:tspan[end]) - cs_t.dates.date[1] = TimeManager.current_date(cs_t, t) # if not global, `date`` is not updated. Check that this still runs when distributed. + cs_t.dates.date[1] = Utilities.current_date(cs_t, t) # if not global, `date`` is not updated. Check that this still runs when distributed. model_date = cs_t.dates.date[1] callback_date = BCReader.next_date_in_file(bcf_info) diff --git a/test/diagnostics_tests.jl b/test/diagnostics_tests.jl index 741b8592d5..2659e4c4a0 100644 --- a/test/diagnostics_tests.jl +++ b/test/diagnostics_tests.jl @@ -5,8 +5,8 @@ using Test using Dates using ClimaCore: InputOutput using ClimaComms +using ClimaUtilities.TimeManager: Monthly, EveryTimestep using ClimaCoupler: Utilities -using ClimaCoupler.TimeManager: EveryTimestep, Monthly using ClimaCoupler.TestHelper: create_space import ClimaCoupler.Diagnostics: get_var, diff --git a/test/mpi_tests/bcreader_mpi_tests.jl b/test/mpi_tests/bcreader_mpi_tests.jl index 119de1c941..5945b552a9 100644 --- a/test/mpi_tests/bcreader_mpi_tests.jl +++ b/test/mpi_tests/bcreader_mpi_tests.jl @@ -8,6 +8,7 @@ that MPI can be enabled for testing of these functions. using ClimaCoupler: Regridder, BCReader, TimeManager, Utilities using ClimaCore: Fields, Meshes, Domains, Topologies, Spaces using ClimaComms +import ClimaUtilities: TimeManager using Test using Dates using NCDatasets @@ -146,7 +147,7 @@ end # step in time walltime = @elapsed for t in ((tspan[1] + Δt):Δt:tspan[end]) - cs_t.dates.date[1] = TimeManager.current_date(cs_t, t) # if not global, `date`` is not updated. Check that this still runs when distributed. + cs_t.dates.date[1] = Utilities.current_date(cs_t, t) # if not global, `date`` is not updated. Check that this still runs when distributed. model_date = cs_t.dates.date[1] callback_date = BCReader.next_date_in_file(bcf_info) diff --git a/test/runtests.jl b/test/runtests.jl index 3999d83a97..d4a2634e8d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -21,9 +21,6 @@ end @safetestset "Utilities tests" begin include("utilities_tests.jl") end -@safetestset "TimeManager tests" begin - include("time_manager_tests.jl") -end @safetestset "FieldExchanger tests" begin include("field_exchanger_tests.jl") end diff --git a/test/time_manager_tests.jl b/test/time_manager_tests.jl deleted file mode 100644 index bb711e2e41..0000000000 --- a/test/time_manager_tests.jl +++ /dev/null @@ -1,70 +0,0 @@ -#= - Unit tests for ClimaCoupler TimeManager module -=# - -using Test -using Dates -using ClimaCoupler: Utilities, TimeManager -using ClimaComms - -for FT in (Float32, Float64) - @testset "test current_date" begin - date0 = date = DateTime("19790321", dateformat"yyyymmdd") - dates = (; date = [date], date0 = [date0], date1 = [Dates.firstdayofmonth(date0)]) - tspan = (Int(1), Int(90 * 86400)) # Jan-Mar - Δt_cpl = 1 * 24 * 3600 - - # Fill in only the necessary parts of the simulation - cs = Utilities.CoupledSimulation{FT}( - ClimaComms.SingletonCommsContext(), # comms_ctx - dates, # dates - nothing, # boundary_space - nothing, # fields - nothing, # parsed_args - nothing, # conservation_checks - tspan, # tspan - Int(0), # t - Int(Δt_cpl), # Δt_cpl - (;), # surface_masks - (;), # model_sims - (;), # mode - (), # diagnostics - ) - - for t in ((tspan[1] + Δt_cpl):Δt_cpl:tspan[end]) - @test TimeManager.current_date(cs, t) == date0 + Dates.Second(t) - end - end -end - -@testset "test strdate_to_datetime" begin - @test TimeManager.strdate_to_datetime("19000101") == Dates.DateTime(1900, 1, 1) - @test TimeManager.strdate_to_datetime("00000101") == Dates.DateTime(0, 1, 1) -end - -@testset "test datetime_to_strdate" begin - @test TimeManager.datetime_to_strdate(Dates.DateTime(1900, 1, 1)) == "19000101" - @test TimeManager.datetime_to_strdate(Dates.DateTime(0, 1, 1)) == "00000101" -end - -@testset "trigger_callback" begin - date0 = date = DateTime("19790321", dateformat"yyyymmdd") - dates = (; date = [date], date0 = [date0], date1 = [Dates.firstdayofmonth(date0)]) - - cs = Utilities.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 - ) - @test TimeManager.trigger_callback(cs, TimeManager.Monthly()) == true -end diff --git a/test/utilities_tests.jl b/test/utilities_tests.jl index e26a9f8959..e87c30cd7b 100644 --- a/test/utilities_tests.jl +++ b/test/utilities_tests.jl @@ -2,7 +2,9 @@ Unit tests for ClimaCoupler Utilities module =# +import Dates using Test +import ClimaComms using ClimaCoupler: Utilities, TestHelper using ClimaCore: Fields @@ -39,4 +41,32 @@ for FT in (Float32, Float64) @test parent(field1) == parent(field2) @test axes(field2) == space2 end + + @testset "test current_date" begin + date0 = date = Dates.DateTime("19790321", Dates.dateformat"yyyymmdd") + dates = (; date = [date], date0 = [date0], date1 = [Dates.firstdayofmonth(date0)]) + tspan = (Int(1), Int(90 * 86400)) # Jan-Mar + Δt_cpl = 1 * 24 * 3600 + + # Fill in only the necessary parts of the simulation + cs = Utilities.CoupledSimulation{FT}( + ClimaComms.SingletonCommsContext(), # comms_ctx + dates, # dates + nothing, # boundary_space + nothing, # fields + nothing, # parsed_args + nothing, # conservation_checks + tspan, # tspan + Int(0), # t + Int(Δt_cpl), # Δt_cpl + (;), # surface_masks + (;), # model_sims + (;), # mode + (), # diagnostics + ) + + for t in ((tspan[1] + Δt_cpl):Δt_cpl:tspan[end]) + @test Utilities.current_date(cs, t) == date0 + Dates.Second(t) + end + end end