diff --git a/Project.toml b/Project.toml index c6abe0d563..4f6b76c4d8 100644 --- a/Project.toml +++ b/Project.toml @@ -42,7 +42,7 @@ CSV = "0.10" CUDA = "5.3" ClimaComms = "0.5.6, 0.6" ClimaCore = "0.13.2, 0.14" -ClimaDiagnostics = "0.2" +ClimaDiagnostics = "0.2.4" ClimaParams = "0.10.2" ClimaUtilities = "0.1.2" DataFrames = "1" diff --git a/docs/src/diagnostics/users_diagnostics.md b/docs/src/diagnostics/users_diagnostics.md index b474f4994a..3af6c1388f 100644 --- a/docs/src/diagnostics/users_diagnostics.md +++ b/docs/src/diagnostics/users_diagnostics.md @@ -46,7 +46,7 @@ providing the space and output_dir defined in steps 1. and 2. Now that you defined your model and your writter, you can create a callback function to be called when solving your model. For example: ``` -diags = ClimaLand.default_diagnostics(model, 1.0; output_writer = nc_writer) +diags = ClimaLand.default_diagnostics(model, 1.0, reference_date; output_writer = nc_writer) diagnostic_handler = ClimaDiagnostics.DiagnosticsHandler(diags, Y, p, t0; dt = Δt) diff --git a/experiments/integrated/global/global_soil_canopy.jl b/experiments/integrated/global/global_soil_canopy.jl index 7d57c34470..d56e48d9d7 100644 --- a/experiments/integrated/global/global_soil_canopy.jl +++ b/experiments/integrated/global/global_soil_canopy.jl @@ -374,7 +374,8 @@ nc_writer = ClimaDiagnostics.Writers.NetCDFWriter(subsurface_space, output_dir) diags = ClimaLand.default_diagnostics( land, - t0; + t0, + ref_time; output_writer = nc_writer, average_period = :hourly, ) diff --git a/experiments/long_runs/land.jl b/experiments/long_runs/land.jl index f9a79ce126..3fd0a5dabe 100644 --- a/experiments/long_runs/land.jl +++ b/experiments/long_runs/land.jl @@ -601,7 +601,8 @@ function setup_prob(t0, tf, Δt; outdir = outdir, nelements = (101, 15)) diags = ClimaLand.default_diagnostics( land, - t0; + t0, + ref_time; output_writer = nc_writer, output_vars = :long, ) diff --git a/experiments/long_runs/soil.jl b/experiments/long_runs/soil.jl index 36e162739d..e636e22d38 100644 --- a/experiments/long_runs/soil.jl +++ b/experiments/long_runs/soil.jl @@ -420,7 +420,12 @@ function setup_prob(t0, tf, Δt; outdir = outdir, nelements = (101, 15)) nc_writer = ClimaDiagnostics.Writers.NetCDFWriter(subsurface_space, outdir) - diags = ClimaLand.default_diagnostics(soil, t0; output_writer = nc_writer) + diags = ClimaLand.default_diagnostics( + soil, + t0, + ref_time; + output_writer = nc_writer, + ) diagnostic_handler = ClimaDiagnostics.DiagnosticsHandler(diags, Y, p, t0; dt = Δt) diff --git a/experiments/standalone/Bucket/global_bucket_function.jl b/experiments/standalone/Bucket/global_bucket_function.jl index 2572ba23c8..b13656107e 100644 --- a/experiments/standalone/Bucket/global_bucket_function.jl +++ b/experiments/standalone/Bucket/global_bucket_function.jl @@ -168,7 +168,12 @@ space = bucket_domain.space.subsurface nc_writer = ClimaDiagnostics.Writers.NetCDFWriter(space, output_dir) -diags = ClimaLand.default_diagnostics(model, t0; output_writer = nc_writer) +diags = ClimaLand.default_diagnostics( + model, + t0, + ref_time; + output_writer = nc_writer, +) diagnostic_handler = ClimaDiagnostics.DiagnosticsHandler(diags, Y, p, t0; dt = Δt) diff --git a/src/diagnostics/Diagnostics.jl b/src/diagnostics/Diagnostics.jl index 81678eaee3..e41abb01a1 100644 --- a/src/diagnostics/Diagnostics.jl +++ b/src/diagnostics/Diagnostics.jl @@ -1,5 +1,7 @@ module Diagnostics +import Dates: Month, Period + import ClimaComms using ..Bucket: BucketModel @@ -13,7 +15,8 @@ import ..Domains: top_center_to_surface import ClimaDiagnostics: DiagnosticVariable, ScheduledDiagnostic, average_pre_output_hook! -import ClimaDiagnostics.Schedules: EveryStepSchedule, EveryDtSchedule +import ClimaDiagnostics.Schedules: + EveryStepSchedule, EveryDtSchedule, EveryCalendarDtSchedule import ClimaDiagnostics.Writers: HDF5Writer, NetCDFWriter diff --git a/src/diagnostics/default_diagnostics.jl b/src/diagnostics/default_diagnostics.jl index f87471b284..e6e4065eb3 100644 --- a/src/diagnostics/default_diagnostics.jl +++ b/src/diagnostics/default_diagnostics.jl @@ -15,6 +15,7 @@ export default_diagnostics reduction, output_writer, t_start, + reference_date, short_names...; pre_output_hook! = nothing, ) @@ -26,25 +27,37 @@ function common_diagnostics( reduction, output_writer, t_start, + reference_date, short_names...; pre_output_hook! = nothing, ) - return [ - ScheduledDiagnostic( - variable = get_diagnostic_variable(short_name), - compute_schedule_func = EveryStepSchedule(), - output_schedule_func = EveryDtSchedule(period; t_start), - reduction_time_func = reduction, - output_writer = output_writer, - pre_output_hook! = pre_output_hook!, - ) for short_name in short_names - ] + return vcat( + map(short_names) do short_name + output_schedule_func = + period isa Period ? + EveryCalendarDtSchedule(period; t_start, reference_date) : + EveryDtSchedule(period; t_start) + return ScheduledDiagnostic( + variable = get_diagnostic_variable(short_name), + compute_schedule_func = EveryStepSchedule(), + output_schedule_func = output_schedule_func, + reduction_time_func = reduction, + output_writer = output_writer, + pre_output_hook! = pre_output_hook!, + ) + end..., + ) end include("standard_diagnostic_frequencies.jl") # Bucket -function default_diagnostics(land_model::BucketModel, t_start; output_writer) +function default_diagnostics( + land_model::BucketModel, + t_start, + reference_date; + output_writer, +) define_diagnostics!(land_model) @@ -64,15 +77,21 @@ function default_diagnostics(land_model::BucketModel, t_start; output_writer) "ssfc", ] - default_outputs = - hourly_averages(bucket_diagnostics...; output_writer, t_start) + default_outputs = hourly_averages( + bucket_diagnostics...; + output_writer, + t_start, + reference_date, + ) + return [default_outputs...] end # SoilCanopyModel function default_diagnostics( land_model::SoilCanopyModel, - t_start; + t_start, + reference_date; output_writer, output_vars = :long, average_period = :daily, @@ -143,14 +162,26 @@ function default_diagnostics( end if average_period == :hourly - default_outputs = - hourly_averages(soilcanopy_diagnostics...; output_writer, t_start) + default_outputs = hourly_averages( + soilcanopy_diagnostics...; + output_writer, + t_start, + reference_date, + ) elseif average_period == :daily - default_outputs = - daily_averages(soilcanopy_diagnostics...; output_writer, t_start) - elseif average_period == :monthly # !! this is currently 30 days, not exact month - default_outputs = - monthly_averages(soilcanopy_diagnostics...; output_writer, t_start) + default_outputs = daily_averages( + soilcanopy_diagnostics...; + output_writer, + t_start, + reference_date, + ) + elseif average_period == :monthly + default_outputs = monthly_averages( + soilcanopy_diagnostics...; + output_writer, + t_start, + reference_date, + ) end return [default_outputs...] @@ -160,7 +191,8 @@ end # SoilModel function default_diagnostics( land_model::EnergyHydrology, - t_start; + t_start, + reference_date; output_writer, ) @@ -168,7 +200,11 @@ function default_diagnostics( soil_diagnostics = ["swc", "si", "sie"] - default_outputs = - daily_averages(soil_diagnostics...; output_writer, t_start) + default_outputs = daily_averages( + soil_diagnostics...; + output_writer, + t_start, + reference_date, + ) return [default_outputs...] end diff --git a/src/diagnostics/standard_diagnostic_frequencies.jl b/src/diagnostics/standard_diagnostic_frequencies.jl index abf80f4d47..b68b1ca02a 100644 --- a/src/diagnostics/standard_diagnostic_frequencies.jl +++ b/src/diagnostics/standard_diagnostic_frequencies.jl @@ -1,262 +1,272 @@ -""" - monthly_maxs(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the monthly max for the given variables. - -A month is defined as 30 days. -""" -monthly_maxs(short_names...; output_writer, t_start) = common_diagnostics( - 30 * 24 * 60 * 60 * one(t_start), - max, - output_writer, - t_start, - short_names..., -) -""" - monthly_max(short_names; output_writer, t_start) - -Return a `ScheduledDiagnostics` that computes the monthly max for the given variable. - -A month is defined as 30 days. -""" -monthly_max(short_names; output_writer, t_start) = - monthly_maxs(short_names; output_writer, t_start)[1] - -""" - monthly_mins(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the monthly min for the given variables. -""" -monthly_mins(short_names...; output_writer, t_start) = common_diagnostics( - 30 * 24 * 60 * 60 * one(t_start), - min, - output_writer, - t_start, - short_names..., -) -""" - monthly_min(short_names; output_writer, t_start) - -Return a `ScheduledDiagnostics` that computes the monthly min for the given variable. - -A month is defined as 30 days. -""" -monthly_min(short_names; output_writer, t_start) = - monthly_mins(short_names; output_writer, t_start)[1] - -""" - monthly_averages(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the monthly average for the given variables. - -A month is defined as 30 days. -""" -# An average is just a sum with a normalization before output -monthly_averages(short_names...; output_writer, t_start) = common_diagnostics( - 30 * 24 * 60 * 60 * one(t_start), - (+), - output_writer, - t_start, - short_names...; - pre_output_hook! = average_pre_output_hook!, -) -""" - monthly_average(short_names; output_writer, t_start) - -Return a `ScheduledDiagnostics` that compute the monthly average for the given variable. - -A month is defined as 30 days. -""" -# An average is just a sum with a normalization before output -monthly_average(short_names; output_writer, t_start) = - monthly_averages(short_names; output_writer, t_start)[1] - -""" - tendaily_maxs(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the max over ten days for the given variables. -""" -tendaily_maxs(short_names...; output_writer, t_start) = common_diagnostics( - 10 * 24 * 60 * 60 * one(t_start), - max, - output_writer, - t_start, - short_names..., -) -""" - tendaily_max(short_names; output_writer, t_start) - -Return a `ScheduledDiagnostics` that computes the max over ten days for the given variable. -""" -tendaily_max(short_names; output_writer, t_start) = - tendaily_maxs(short_names; output_writer, t_start)[1] - -""" - tendaily_mins(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the min over ten days for the given variables. -""" -tendaily_mins(short_names...; output_writer, t_start) = common_diagnostics( - 10 * 24 * 60 * 60 * one(t_start), - min, - output_writer, - t_start, - short_names..., -) -""" - tendaily_min(short_names; output_writer, t_start) - -Return a `ScheduledDiagnostics` that computes the min over ten days for the given variable. -""" -tendaily_min(short_names; output_writer, t_start) = - tendaily_mins(short_names; output_writer, t_start)[1] - -""" - tendaily_averages(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the average over ten days for the given variables. -""" -# An average is just a sum with a normalization before output -tendaily_averages(short_names...; output_writer, t_start) = common_diagnostics( - 10 * 24 * 60 * 60 * one(t_start), - (+), - output_writer, - t_start, - short_names...; - pre_output_hook! = average_pre_output_hook!, -) -""" - tendaily_average(short_names; output_writer, t_start) - -Return a `ScheduledDiagnostics` that compute the average over ten days for the given variable. -""" -# An average is just a sum with a normalization before output -tendaily_average(short_names; output_writer, t_start) = - tendaily_averages(short_names; output_writer, t_start)[1] - -""" - daily_maxs(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the daily max for the given variables. -""" -daily_maxs(short_names...; output_writer, t_start) = common_diagnostics( - 24 * 60 * 60 * one(t_start), - max, - output_writer, - t_start, - short_names..., -) -""" - daily_max(short_names; output_writer, t_start) - -Return a `ScheduledDiagnostics` that computes the daily max for the given variable. -""" -daily_max(short_names; output_writer, t_start) = - daily_maxs(short_names; output_writer, t_start)[1] - -""" - daily_mins(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the daily min for the given variables. -""" -daily_mins(short_names...; output_writer, t_start) = common_diagnostics( - 24 * 60 * 60 * one(t_start), - min, - output_writer, - t_start, - short_names..., -) -""" - daily_min(short_names; output_writer, t_start) - -Return a `ScheduledDiagnostics` that computes the daily min for the given variable. -""" -daily_min(short_names; output_writer, t_start) = - daily_mins(short_names; output_writer, t_start)[1] - -""" - daily_averages(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the daily average for the given variables. -""" -# An average is just a sum with a normalization before output -daily_averages(short_names...; output_writer, t_start) = common_diagnostics( - 24 * 60 * 60 * one(t_start), - (+), - output_writer, - t_start, - short_names...; - pre_output_hook! = average_pre_output_hook!, -) -""" - daily_average(short_names; output_writer, t_start) - -Return a `ScheduledDiagnostics` that compute the daily average for the given variable. -""" -# An average is just a sum with a normalization before output -daily_average(short_names; output_writer, t_start) = - daily_averages(short_names; output_writer, t_start)[1] - -""" - hourly_maxs(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the hourly max for the given variables. -""" -hourly_maxs(short_names...; output_writer, t_start) = common_diagnostics( - 60 * 60 * one(t_start), - max, - output_writer, - t_start, - short_names..., -) - -""" - hourly_max(short_names; output_writer, t_start) - -Return a `ScheduledDiagnostics` that computes the hourly max for the given variable. -""" -hourly_max(short_names; output_writer, t_start) = - hourly_maxs(short_names; output_writer, t_start)[1] - -""" - hourly_mins(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the hourly min for the given variables. -""" -hourly_mins(short_names...; output_writer, t_start) = common_diagnostics( - 60 * 60 * one(t_start), - min, - output_writer, - t_start, - short_names..., -) -""" - hourly_mins(short_names...; output_writer, t_start) - -Return a `ScheduledDiagnostics` that computes the hourly min for the given variable. -""" -hourly_min(short_names; output_writer, t_start) = - hourly_mins(short_names; output_writer, t_start)[1] - -# An average is just a sum with a normalization before output -""" - hourly_averages(short_names...; output_writer, t_start) - -Return a list of `ScheduledDiagnostics` that compute the hourly average for the given variables. -""" -hourly_averages(short_names...; output_writer, t_start) = common_diagnostics( - 60 * 60 * one(t_start), - (+), - output_writer, - t_start, - short_names...; - pre_output_hook! = average_pre_output_hook!, -) - -""" - hourly_average(short_names...; output_writer, t_start) - -Return a `ScheduledDiagnostics` that computes the hourly average for the given variable. -""" -hourly_average(short_names; output_writer, t_start) = - hourly_averages(short_names; output_writer, t_start)[1] +""" + monthly_maxs(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the monthly max for the given variables. +""" +monthly_maxs(short_names...; output_writer, t_start, reference_date) = + common_diagnostics(Month(1), max, output_writer, t_start, short_names...) + +""" + monthly_max(short_names; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that computes the monthly max for the given variable. +""" +monthly_max(short_names; output_writer, t_start, reference_date) = + monthly_maxs(short_names; output_writer, t_start, reference_date)[1] + +""" + monthly_mins(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the monthly min for the given variables. +""" +monthly_mins(short_names...; output_writer, t_start, reference_date) = + common_diagnostics(Month(1), min, output_writer, t_start, short_names...) + +""" + monthly_min(short_names; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that computes the monthly min for the given variable. +""" +monthly_min(short_names; output_writer, t_start, reference_date) = + monthly_mins(short_names; output_writer, t_start, reference_date)[1] + +""" + monthly_averages(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the monthly average for the given variables. +""" +# An average is just a sum with a normalization before output +monthly_averages(short_names...; output_writer, t_start, reference_date) = + common_diagnostics( + Month(1), + (+), + output_writer, + t_start, + reference_date, + short_names...; + pre_output_hook! = average_pre_output_hook!, + ) + +""" + monthly_average(short_names; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that compute the monthly average for the given variable. +""" +# An average is just a sum with a normalization before output +monthly_average(short_names; output_writer, t_start, reference_date) = + monthly_averages(short_names; output_writer, t_start, reference_date)[1] + +""" + tendaily_maxs(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the max over ten days for the given variables. +""" +tendaily_maxs(short_names...; output_writer, t_start, reference_date) = + common_diagnostics( + 10 * 24 * 60 * 60 * one(t_start), + max, + output_writer, + t_start, + reference_date, + short_names..., + ) + +""" + tendaily_max(short_names; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that computes the max over ten days for the given variable. +""" +tendaily_max(short_names; output_writer, t_start, reference_date) = + tendaily_maxs(short_names; output_writer, t_start, reference_date)[1] + +""" + tendaily_mins(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the min over ten days for the given variables. +""" +tendaily_mins(short_names...; output_writer, t_start, reference_date) = + common_diagnostics( + 10 * 24 * 60 * 60 * one(t_start), + min, + output_writer, + t_start, + reference_date, + short_names..., + ) + +""" + tendaily_min(short_names; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that computes the min over ten days for the given variable. +""" +tendaily_min(short_names; output_writer, t_start, reference_date) = + tendaily_mins(short_names; output_writer, t_start, reference_date)[1] + +""" + tendaily_averages(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the average over ten days for the given variables. +""" +# An average is just a sum with a normalization before output +tendaily_averages(short_names...; output_writer, t_start, reference_date) = + common_diagnostics( + 10 * 24 * 60 * 60 * one(t_start), + (+), + output_writer, + t_start, + reference_date, + short_names...; + pre_output_hook! = average_pre_output_hook!, + ) + +""" + tendaily_average(short_names; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that compute the average over ten days for the given variable. +""" +# An average is just a sum with a normalization before output +tendaily_average(short_names; output_writer, t_start, reference_date) = + tendaily_averages(short_names; output_writer, t_start, reference_date)[1] + +""" + daily_maxs(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the daily max for the given variables. +""" +daily_maxs(short_names...; output_writer, t_start, reference_date) = + common_diagnostics( + 24 * 60 * 60 * one(t_start), + max, + output_writer, + t_start, + reference_date, + short_names..., + ) + +""" + daily_max(short_names; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that computes the daily max for the given variable. +""" +daily_max(short_names; output_writer, t_start, reference_date) = + daily_maxs(short_names; output_writer, t_start, reference_date)[1] + +""" + daily_mins(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the daily min for the given variables. +""" +daily_mins(short_names...; output_writer, t_start, reference_date) = + common_diagnostics( + 24 * 60 * 60 * one(t_start), + min, + output_writer, + t_start, + reference_date, + short_names..., + ) + +""" + daily_min(short_names; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that computes the daily min for the given variable. +""" +daily_min(short_names; output_writer, t_start, reference_date) = + daily_mins(short_names; output_writer, t_start, reference_date)[1] + +""" + daily_averages(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the daily average for the given variables. +""" +# An average is just a sum with a normalization before output +daily_averages(short_names...; output_writer, t_start, reference_date) = + common_diagnostics( + 24 * 60 * 60 * one(t_start), + (+), + output_writer, + t_start, + reference_date, + short_names...; + pre_output_hook! = average_pre_output_hook!, + ) + +""" + daily_average(short_names; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that compute the daily average for the given variable. +""" +# An average is just a sum with a normalization before output +daily_average(short_names; output_writer, t_start, reference_date) = + daily_averages(short_names; output_writer, t_start, reference_date)[1] + +""" + hourly_maxs(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the hourly max for the given variables. +""" +hourly_maxs(short_names...; output_writer, t_start, reference_date) = + common_diagnostics( + 60 * 60 * one(t_start), + max, + output_writer, + t_start, + reference_date, + short_names..., + ) + +""" + hourly_max(short_names; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that computes the hourly max for the given variable. +""" +hourly_max(short_names; output_writer, t_start, reference_date) = + hourly_maxs(short_names; output_writer, t_start, reference_date)[1] + +""" + hourly_mins(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the hourly min for the given variables. +""" +hourly_mins(short_names...; output_writer, t_start, reference_date) = + common_diagnostics( + 60 * 60 * one(t_start), + min, + output_writer, + t_start, + reference_date, + short_names..., + ) + +""" + hourly_mins(short_names...; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that computes the hourly min for the given variable. +""" +hourly_min(short_names; output_writer, t_start, reference_date) = + hourly_mins(short_names; output_writer, t_start, reference_date)[1] + +# An average is just a sum with a normalization before output +""" + hourly_averages(short_names...; output_writer, t_start, reference_date) + +Return a list of `ScheduledDiagnostics` that compute the hourly average for the given variables. +""" +hourly_averages(short_names...; output_writer, t_start, reference_date) = + common_diagnostics( + 60 * 60 * one(t_start), + (+), + output_writer, + t_start, + reference_date, + short_names...; + pre_output_hook! = average_pre_output_hook!, + ) + +""" + hourly_average(short_names...; output_writer, t_start, reference_date) + +Return a `ScheduledDiagnostics` that computes the hourly average for the given variable. +""" +hourly_average(short_names; output_writer, t_start, reference_date) = + hourly_averages(short_names; output_writer, t_start, reference_date)[1]