Skip to content

Commit

Permalink
src
Browse files Browse the repository at this point in the history
  • Loading branch information
juliasloan25 committed Apr 9, 2024
1 parent 9cb582b commit 0a236d5
Show file tree
Hide file tree
Showing 12 changed files with 235 additions and 240 deletions.
19 changes: 9 additions & 10 deletions src/BCReader.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ monthly to daily intervals.
"""
module BCReader

using ..Utilities, ..Regridder, ..TimeManager
using ClimaCore: Fields
using ClimaComms
using Dates
using JLD2
import JLD2
import ClimaComms
import ClimaCore as CC
import ..Utilities, ..Regridder, ..TimeManager

export BCFileInfo,
float_type_bcf, bcfile_info_init, update_midmonth_data!, next_date_in_file, interpolate_midmonth_to_daily
Expand Down Expand Up @@ -64,10 +63,10 @@ Remap the values of a `field` onto the space of the
`bcf_info`'s land_fraction without scaling.
# Arguments
- `field`: [Fields.Field] contains the values to be remapped.
- `field`: [CC.Fields.Field] contains the values to be remapped.
- `bcf_info`: [BCFileInfo] contains a land_fraction to remap onto the space of.
"""
no_scaling(field::Fields.Field, bcf_info::BCFileInfo{FT}) where {FT} =
no_scaling(field::CC.Fields.Field, bcf_info::BCFileInfo{FT}) where {FT} =
Utilities.swap_space!(zeros(axes(bcf_info.land_fraction)), field)

"""
Expand Down Expand Up @@ -99,7 +98,7 @@ and returns the info packaged in a single struct.
- `interpolate_daily`: [Bool] switch to trigger daily interpolation.
- `segment_idx0`: [Vector{Int}] reference date which, after initialization, refers to the the first file date index used minus 1 (segment_idx[1] - 1)
- `scaling function`: [Function] scales, offsets or transforms `varname`.
- `land_fraction`: [Fields.field] fraction with 1 = land, 0 = ocean / sea-ice.
- `land_fraction`: [CC.Fields.field] fraction with 1 = land, 0 = ocean / sea-ice.
- `date0`: [Dates.DateTime] start date of the file data.
- `mono`: [Bool] flag for monotone remapping of `datafile_rll`.
Expand Down Expand Up @@ -138,7 +137,7 @@ function bcfile_info_init(
data_dates = JLD2.load(joinpath(bcfile_dir, hd_outfile_root * "_times.jld2"), "times")

# init time tracking info
current_fields = Fields.zeros(FT, boundary_space), Fields.zeros(FT, boundary_space)
current_fields = CC.Fields.zeros(FT, boundary_space), CC.Fields.zeros(FT, boundary_space)
segment_length = [Int(0)]

# unless the start file date is specified, find the closest one to the start date
Expand Down Expand Up @@ -299,7 +298,7 @@ or returns the first Field if interpolation is switched off.
- `bcf_info`: [BCFileInfo] contains fields to be interpolated.
# Returns
- Fields.field
- CC.Fields.field
"""
function interpolate_midmonth_to_daily(date, bcf_info::BCFileInfo{FT}) where {FT}
(; segment_length, segment_idx, all_dates, monthly_fields, interpolate_daily) = bcf_info
Expand Down
18 changes: 9 additions & 9 deletions src/Checkpointer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ This module contains template functions for checkpointing the model states and r
"""
module Checkpointer

using ClimaCore: Fields, InputOutput
using ClimaCoupler: Interfacer
using Dates
using ClimaComms
import ClimaComms
import ClimaCore as CC
import ..Interfacer

export get_model_prog_state, checkpoint_model_state, restart_model_state!

"""
Expand Down Expand Up @@ -36,9 +36,9 @@ function checkpoint_model_state(
@info "Saving checkpoint " * Interfacer.name(sim) * " model state to HDF5 on day $day second $sec"
mkpath(joinpath(output_dir, "checkpoint"))
output_file = joinpath(output_dir, "checkpoint", "checkpoint_" * Interfacer.name(sim) * "_$t.hdf5")
checkpoint_writer = InputOutput.HDF5Writer(output_file, comms_ctx)
InputOutput.HDF5.write_attribute(checkpoint_writer.file, "time", t)
InputOutput.write!(checkpoint_writer, Y, "model_state")
checkpoint_writer = CC.InputOutput.HDF5Writer(output_file, comms_ctx)
CC.InputOutput.HDF5.write_attribute(checkpoint_writer.file, "time", t)
CC.InputOutput.write!(checkpoint_writer, Y, "model_state")
Base.close(checkpoint_writer)
return nothing

Expand All @@ -63,8 +63,8 @@ function restart_model_state!(
@info "Setting " Interfacer.name(sim) " state to checkpoint: $input_file, corresponding to day $day second $sec"

# open file and read
restart_reader = InputOutput.HDF5Reader(input_file, comms_ctx)
Y_new = InputOutput.read_field(restart_reader, "model_state")
restart_reader = CC.InputOutput.HDF5Reader(input_file, comms_ctx)
Y_new = CC.InputOutput.read_field(restart_reader, "model_state")
Base.close(restart_reader)

# set new state
Expand Down
17 changes: 5 additions & 12 deletions src/ConservationChecker.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,8 @@ This module contains functions that check global conservation of energy and wate
"""
module ConservationChecker

using ClimaCore: ClimaCore, Geometry, Meshes, Domains, Topologies, Spaces, Fields, InputOutput
using ClimaComms
using NCDatasets
using ClimaCoreTempestRemap
using Dates
using JLD2
using Plots
using ClimaAtmos: RRTMGPI
using ClimaLand
using ClimaCoupler.Utilities: swap_space!
import ClimaCoupler: Interfacer
import Plots
import ..Interfacer, ..Utilities

export AbstractConservationCheck,
EnergyConservationCheck, WaterConservationCheck, check_conservation!, plot_global_conservation
Expand Down Expand Up @@ -165,7 +156,9 @@ function check_conservation!(
total = 0

# net precipitation (for surfaces that don't collect water)
PE_net = coupler_sim.fields.P_net .+= swap_space!(zeros(boundary_space), surface_water_gain_from_rates(coupler_sim))
PE_net =
coupler_sim.fields.P_net .+=
Utilities.swap_space!(zeros(boundary_space), surface_water_gain_from_rates(coupler_sim))

# save surfaces
for sim in model_sims
Expand Down
88 changes: 43 additions & 45 deletions src/Diagnostics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
This module contains functions for defining, gathering and outputting online model diagnostics from the Coupler.
"""
module Diagnostics

using ClimaCore: Spaces, Fields, InputOutput
using ClimaCoupler.Interfacer: CoupledSimulation, float_type
using Dates
using ClimaCoupler.TimeManager: AbstractFrequency, Monthly, EveryTimestep, trigger_callback
using ClimaComms
import Dates
import ClimaCore as CC
import ..Interfacer, ..TimeManager

export get_var, init_diagnostics, accumulate_diagnostics!, save_diagnostics, TimeMean

Expand All @@ -29,7 +26,7 @@ Defines a concrete diagnostics group type with fields `field_vector`, `operation
`output_dir` and `name_tag`.
"""
struct DiagnosticsGroup{S, NTO <: NamedTuple} <: AbstractOutputGroup
field_vector::Fields.FieldVector
field_vector::CC.Fields.FieldVector
operations::NTO
save::S
output_dir::String
Expand Down Expand Up @@ -57,8 +54,8 @@ end
"""
function init_diagnostics(
names::Tuple,
space::Spaces.AbstractSpace;
save = EveryTimestep(),
space::CC.Spaces.AbstractSpace;
save = TimeManager.EveryTimestep(),
operations = (;),
output_dir = "",
name_tag = "",
Expand All @@ -68,18 +65,18 @@ Initializes diagnostics groups.
"""
function init_diagnostics(
names::Tuple,
space::Spaces.AbstractSpace;
save = EveryTimestep(),
space::CC.Spaces.AbstractSpace;
save = TimeManager.EveryTimestep(),
operations = (;),
output_dir = "",
name_tag = "",
)
data = NamedTuple{names}(ntuple(i -> Fields.zeros(space), length(names)))
return DiagnosticsGroup(Fields.FieldVector(; data...), operations, save, output_dir, name_tag)
data = NamedTuple{names}(ntuple(i -> CC.Fields.zeros(space), length(names)))
return DiagnosticsGroup(CC.Fields.FieldVector(; data...), operations, save, output_dir, name_tag)
end

"""
get_var(cs::CoupledSimulation, x)
get_var(cs::Interfacer.CoupledSimulation, x)
Defines variable extraction from the coupler simulation. User specific diagnostics
should extend this function in the experiments folder.
Expand All @@ -89,14 +86,14 @@ Example:
get_var(cs, ::Val{:T_sfc}) = cs.fields.T_S
"""
get_var(::CoupledSimulation, x) = @warn "Variable $x is not defined."
get_var(::Interfacer.CoupledSimulation, x) = @warn "Variable $x is not defined."

"""
accumulate_diagnostics!(cs::CoupledSimulation)
accumulate_diagnostics!(cs::Interfacer.CoupledSimulation)
Accumulates user-defined diagnostics listed in the in the `field_vector` of each `dg`.
"""
function accumulate_diagnostics!(cs::CoupledSimulation)
function accumulate_diagnostics!(cs::Interfacer.CoupledSimulation)
for dg in cs.diagnostics
if dg.operations.accumulate !== nothing
# TODO: avoid collecting at each timestep where not needed
Expand All @@ -106,74 +103,74 @@ function accumulate_diagnostics!(cs::CoupledSimulation)
end

"""
collect_diags(cs::CoupledSimulation, dg::DiagnosticsGroup)
collect_diags(cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup)
Collects diagnostics in diags names.
"""
function collect_diags(cs::CoupledSimulation, dg::DiagnosticsGroup)
FT = float_type(cs)
function collect_diags(cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup)
FT = Interfacer.float_type(cs)
diags = (;)

diag_names = propertynames(dg.field_vector)
for name in diag_names
diags = (; diags..., zip((name,), (FT.(get_var(cs, Val(name))),))...)
end

return Fields.FieldVector(; diags...)
return CC.Fields.FieldVector(; diags...)
end

"""
iterate_operations(cs::CoupledSimulation, dg::DiagnosticsGroup, diags::Fields.FieldVector)
iterate_operations(cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup, diags::CC.Fields.FieldVector)
Applies iteratively all specified diagnostics operations.
"""
function iterate_operations(cs::CoupledSimulation, dg::DiagnosticsGroup, new_diags::Fields.FieldVector)
function iterate_operations(cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup, new_diags::CC.Fields.FieldVector)
for op in dg.operations
operation(cs, dg, new_diags, op)
end
end

"""
operation(cs::CoupledSimulation, dg::DiagnosticsGroup, new_diags::Fields.FieldVector, ::TimeMean)
operation(cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup, new_diags::CC.Fields.FieldVector, ::TimeMean)
Accumulates in time all entries in `new_diags` and saves the result in `dg.field_vector`, while
increasing the `dg.ct` counter.
"""
function operation(::CoupledSimulation, dg::DiagnosticsGroup, new_diags::Fields.FieldVector, ::TimeMean)
function operation(::Interfacer.CoupledSimulation, dg::DiagnosticsGroup, new_diags::CC.Fields.FieldVector, ::TimeMean)
dg.field_vector .+= new_diags
dg.operations.accumulate.ct[1] += Int(1)

return nothing
end

"""
operation(cs::CoupledSimulation, dg::DiagnosticsGroup, new_diags::Fields.FieldVector, ::Nothing)
operation(cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup, new_diags::CC.Fields.FieldVector, ::Nothing)
Accumulates in time all entries in `new_diags` and saves the result in `dg.field_vector`, while
increasing the `dg.ct` counter.
"""
function operation(::CoupledSimulation, dg::DiagnosticsGroup, new_diags::Fields.FieldVector, ::Nothing)
function operation(::Interfacer.CoupledSimulation, dg::DiagnosticsGroup, new_diags::CC.Fields.FieldVector, ::Nothing)
dg.field_vector .= new_diags
return nothing
end

"""
save_diagnostics(cs::CoupledSimulation)
save_diagnostics(cs::Interfacer.CoupledSimulation)
save_diagnostics(cs::CoupledSimulation, dg::DiagnosticsGroup, output_dir::String)
save_diagnostics(cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup, output_dir::String)
Saves all entries in `dg` in separate HDF5 files per variable in `output_dir`.
"""
function save_diagnostics(cs::CoupledSimulation)
function save_diagnostics(cs::Interfacer.CoupledSimulation)
for dg in cs.diagnostics
if trigger_callback(cs, dg.save)
if TimeManager.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
end
function save_diagnostics(cs::CoupledSimulation, dg::DiagnosticsGroup)
function save_diagnostics(cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup)

date = cs.dates.date[1]
tag = dg.name_tag
Expand All @@ -190,55 +187,56 @@ function save_diagnostics(cs::CoupledSimulation, dg::DiagnosticsGroup)
for (name, values) in zip(diag_names, diag_values)
output_file = joinpath(output_dir, "$name.$tag." * string(date) * ".hdf5")
@info " $output_file"
hdfwriter = InputOutput.HDF5Writer(output_file, cs.comms_ctx)
InputOutput.HDF5.write_attribute(hdfwriter.file, "unix time", save_time_format(date, diag_save))
InputOutput.write!(hdfwriter, values, string(name))
hdfwriter = CC.InputOutput.HDF5Writer(output_file, cs.comms_ctx)
CC.InputOutput.HDF5.write_attribute(hdfwriter.file, "unix time", save_time_format(date, diag_save))
CC.InputOutput.write!(hdfwriter, values, string(name))
Base.close(hdfwriter)
end
return nothing

end

"""
save_time_format(date::Dates.DateTime, ::Monthly)
save_time_format(date::Dates.DateTime, ::TimeManager.Monthly)
Converts the DateTime `date` to the conventional Unix format (seconds elapsed since 00:00:00 UTC on 1 January 1970).
"""
function save_time_format(date::Dates.DateTime, ::Monthly)
function save_time_format(date::Dates.DateTime, ::TimeManager.Monthly)
date_m1 = date - Dates.Day(1) # obtain previous month
datetime = Dates.DateTime(Dates.yearmonth(date_m1)[1], Dates.yearmonth(date_m1)[2])
Dates.datetime2unix(datetime)
end

save_time_format(date::Dates.DateTime, ::EveryTimestep) = Dates.datetime2unix(date)
save_time_format(date::Dates.DateTime, ::TimeManager.EveryTimestep) = Dates.datetime2unix(date)

"""
pre_save(::TimeMean, cs::CoupledSimulation, dg::DiagnosticsGroup)
pre_save(::TimeMean, cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup)
Divides the accumulated sum by 'ct' to form the mean, before saving the diagnostics.
"""
function pre_save(::TimeMean, cs::CoupledSimulation, dg::DiagnosticsGroup)
function pre_save(::TimeMean, cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup)
dg.field_vector .= dg.field_vector / dg.operations.accumulate.ct[1]
end

"""
pre_save(::Nothing, cs::CoupledSimulation, dg::DiagnosticsGroup
pre_save(::Nothing, cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup
Collects variables and performs all specified operations before saving the snapshot diagnostics.
"""
pre_save(::Nothing, cs::CoupledSimulation, dg::DiagnosticsGroup) = iterate_operations(cs, dg, collect_diags(cs, dg))
pre_save(::Nothing, cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup) =
iterate_operations(cs, dg, collect_diags(cs, dg))

"""
post_save(::TimeMean, cs::CoupledSimulation, dg::DiagnosticsGroup)
post_save(::TimeMean, cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup)
Resets accumulating fields and counts after saving the diagnostics.
"""
function post_save(::TimeMean, cs::CoupledSimulation, dg::DiagnosticsGroup)
function post_save(::TimeMean, cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup)
FT = eltype(dg.field_vector)
dg.field_vector .= FT(0.0)
dg.operations.accumulate.ct .= FT(0)
end

post_save(::Nothing, cs::CoupledSimulation, dg::DiagnosticsGroup) = nothing
post_save(::Nothing, cs::Interfacer.CoupledSimulation, dg::DiagnosticsGroup) = nothing

end # module
10 changes: 4 additions & 6 deletions src/FieldExchanger.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ atmospheric and surface component models.
"""
module FieldExchanger

import ..Interfacer, ..FluxCalculator, ..Regridder

export import_atmos_fields!,
import_combined_surface_fields!, update_sim!, update_model_sims!, reinit_model_sims!, step_model_sims!

using ClimaCoupler: Interfacer, FluxCalculator, Regridder, Utilities
import ClimaCoupler.Interfacer: step!, reinit!

"""
import_atmos_fields!(csf, model_sims, boundary_space, turbulent_fluxes)
Expand Down Expand Up @@ -180,7 +178,7 @@ Iterates `reinit!` over all component model simulations saved in `cs.model_sims`
"""
function reinit_model_sims!(model_sims)
for sim in model_sims
reinit!(sim)
Interfacer.reinit!(sim)
end
end

Expand All @@ -195,7 +193,7 @@ Iterates `step!` over all component model simulations saved in `cs.model_sims`.
"""
function step_model_sims!(model_sims, t)
for sim in model_sims
step!(sim, t)
Interfacer.step!(sim, t)
end
end

Expand Down
Loading

0 comments on commit 0a236d5

Please sign in to comment.