Skip to content

Commit

Permalink
Merge pull request #878 from CliMA/js/driver-docs
Browse files Browse the repository at this point in the history
update driver docs
  • Loading branch information
juliasloan25 authored Jun 28, 2024
2 parents a4046f9 + ab93cd1 commit 9eaa136
Showing 1 changed file with 70 additions and 31 deletions.
101 changes: 70 additions & 31 deletions experiments/ClimaEarth/run_amip.jl
Original file line number Diff line number Diff line change
Expand Up @@ -191,22 +191,27 @@ Utilities.show_memory_usage(comms_ctx)
atmos_sim = atmos_init(atmos_config_object);
Utilities.show_memory_usage(comms_ctx)

thermo_params = get_thermo_params(atmos_sim) # TODO: this should be shared by all models #610
thermo_params = get_thermo_params(atmos_sim) # TODO: this should be shared by all models #342

#=
### Boundary Space
We use a common `Space` for all global surfaces. This enables the MPI processes to operate on the same columns in both
the atmospheric and surface components, so exchanges are parallelized. Note this is only possible when the
atmosphere and surface are of the same horizontal resolution.
Currently, we use the 2D surface space from the atmosphere model as our shared space,
but ultimately we want this to specified within the coupler and passed to all component models. (see issue #665)
=#

## init a 2D boundary space at the surface
boundary_space = CC.Spaces.horizontal_space(atmos_sim.domain.face_space) # TODO: specify this in the coupler and pass it to all component models #665

#=
### Land-sea Fraction
This is a static field that contains the area fraction of land and sea, ranging from 0 to 1. If applicable, sea ice is included in the sea fraction. at this stage.
Note that land-sea area fraction is different to the land-sea mask, which is a binary field (masks are used internally by the coupler to indicate passive cells that are not populated by a given component model).
This is a static field that contains the area fraction of land and sea, ranging from 0 to 1.
If applicable, sea ice is included in the sea fraction at this stage.
Note that land-sea area fraction is different to the land-sea mask, which is a binary field
(masks are used internally by the coupler to indicate passive cells that are not populated by a given component model).
=#

land_area_fraction =
Expand Down Expand Up @@ -235,6 +240,9 @@ In the `SlabPlanet` mode, all ocean and sea ice are dynamical models, namely the
- `slabplanet_aqua` = slab ocean everywhere
- `slabplanet_terra` = land everywhere
- `slabplanet_eisenman` = land + slab ocean + slab sea ice with an evolving thickness
In this section of the code, we initialize all component models and read in the prescribed data we'll be using.
The specific models and data that are set up depend on which mode we're running.
=#

ClimaComms.iamroot(comms_ctx) && @info(mode_name)
Expand Down Expand Up @@ -435,8 +443,10 @@ end

#=
## Coupler Initialization
The coupler needs to contain exchange information, manage the calendar and be able to access all component models. It can also optionally
save online diagnostics. These are all initialized here and saved in a global `CoupledSimulation` struct, `cs`.
The coupler needs to contain exchange information, access all component models, and manage the calendar,
among other responsibilities.
Objects containing information to enable these are initialized here and saved in the
global `CoupledSimulation` struct, `cs`, below.
=#

## coupler exchange fields
Expand Down Expand Up @@ -473,7 +483,7 @@ dates = (; date = [date], date0 = [date0], date1 = [Dates.firstdayofmonth(date0)

#=
### Online Diagnostics
User can write custom diagnostics in the `user_diagnostics.jl`.
The user can write custom diagnostics in the `user_diagnostics.jl` file.
Note, this will be replaced by the diagnostics framework currently in ClimaAtmos, once it is abstracted
into a more general package, so we can use it to save fields from surface models.
=#
Expand Down Expand Up @@ -516,7 +526,7 @@ end
The conservation checks are used to monitor the global energy and water conservation of the coupled system. The checks are only
applicable to the `slabplanet` mode, as the `amip` mode is not a closed system. The conservation checks are initialized here and
saved in a global `ConservationChecks` struct, `conservation_checks`.
saved in a global `ConservationChecks` struct, `conservation_checks`, which is then stored as part of the larger `cs` struct.
=#

## init conservation info collector
Expand All @@ -538,7 +548,7 @@ Callbacks are used to update at a specified interval. The callbacks are initiali
saved in a global `Callbacks` struct, `callbacks`. The `trigger_callback!` function is used to call the callback during the simulation below.
The frequency of the callbacks is specified in the `HourlyCallback` and `MonthlyCallback` structs. The `func` field specifies the function to be called,
the `ref_date` field specifies the reference (first) date for the callback, and the `active` field specifies whether the callback is active or not.
the `ref_date` field specifies the first date for the callback, and the `active` field specifies whether the callback is active or not.
The currently implemented callbacks are:
- `checkpoint_cb`: generates a checkpoint of all model states at a specified interval. This is mainly used for restarting simulations.
Expand Down Expand Up @@ -573,7 +583,7 @@ callbacks =
#=
## Initialize turbulent fluxes
Decide on the type of turbulent flux partition (see `FluxCalculator` documentation for more details).
Decide on the type of turbulent flux partition, partitioned or combined (see `FluxCalculator` documentation for more details).
=#
turbulent_fluxes = nothing
if config_dict["turb_flux_partition"] == "PartitionedStateFluxes"
Expand Down Expand Up @@ -651,8 +661,8 @@ Interfacer.step!(land_sim, Δt_cpl)
Interfacer.step!(ocean_sim, Δt_cpl)
Interfacer.step!(ice_sim, Δt_cpl)

# 4.turbulent fluxes: now we have all information needed for calculating the initial turbulent surface fluxes using the combined state
# or the partitioned state method
# 4.turbulent fluxes: now we have all information needed for calculating the initial turbulent
# surface fluxes using either the combined state or the partitioned state method
if cs.turbulent_fluxes isa FluxCalculator.CombinedStateFluxesMOST
## import the new surface properties into the coupler (note the atmos state was also imported in step 3.)
FieldExchanger.import_combined_surface_fields!(cs.fields, cs.model_sims, cs.turbulent_fluxes) # i.e. T_sfc, albedo, z0, beta, q_sfc
Expand Down Expand Up @@ -688,8 +698,9 @@ FieldExchanger.update_model_sims!(cs.model_sims, cs.fields, cs.turbulent_fluxes)
#=
## Coupling Loop
The coupling loop is the main part of the simulation. It runs the component models sequentially for one coupling timestep (`Δt_cpl`), and exchanges combined fields and calculates fluxes using combined states.
Note that we want to implement this in a dispatchable function to allow for other forms of timestepping (e.g. leapfrog). (TODO: #610)
The coupling loop is the main part of the simulation. It runs the component models sequentially for one coupling timestep (`Δt_cpl`) at a time,
and exchanges combined fields and calculates fluxes using the selected turbulent fluxes option.
Note that we want to implement this in a dispatchable function to allow for other forms of timestepping (e.g. leapfrog).
=#

function solve_coupler!(cs)
Expand All @@ -709,7 +720,7 @@ function solve_coupler!(cs)

if cs.mode.name == "amip"

## monthly read of boundary condition data for SST and SIC and CO2
## update values of SST, SIC, and CO2 for this timestep
if cs.dates.date[1] >= BCReader.next_date_in_file(cs.mode.SST_info)
BCReader.update_midmonth_data!(cs.dates.date[1], cs.mode.SST_info)
end
Expand Down Expand Up @@ -742,21 +753,25 @@ function solve_coupler!(cs)
end
end

## compute global energy
## compute global energy and water conservation checks
## (only for slabplanet if tracking conservation is enabled)
!isnothing(cs.conservation_checks) && ConservationChecker.check_conservation!(cs)
ClimaComms.barrier(comms_ctx)

## update water albedo from wind at dt_water_albedo (this will be extended to a radiation callback from the coupler)
## update water albedo from wind at dt_water_albedo
## (this will be extended to a radiation callback from the coupler)
TimeManager.trigger_callback!(cs, cs.callbacks.water_albedo)

## run component models sequentially for one coupling timestep (Δt_cpl)

## update the surface fractions for surface models,
## and update all component model simulations with the current fluxes stored in the coupler
Regridder.update_surface_fractions!(cs)
FieldExchanger.update_model_sims!(cs.model_sims, cs.fields, cs.turbulent_fluxes)

## step sims
## step component model simulations sequentially for one coupling timestep (Δt_cpl)
FieldExchanger.step_model_sims!(cs.model_sims, t)

## exchange combined fields and (if specified) calculate fluxes using combined states
## update the coupler with the new surface properties and calculate the turbulent fluxes
FieldExchanger.import_combined_surface_fields!(cs.fields, cs.model_sims, cs.turbulent_fluxes) # i.e. T_sfc, surface_albedo, z0, beta
if cs.turbulent_fluxes isa FluxCalculator.CombinedStateFluxesMOST
FluxCalculator.combined_turbulent_fluxes!(cs.model_sims, cs.fields, cs.turbulent_fluxes) # this updates the surface thermo state, sfc_ts, in ClimaAtmos (but also unnecessarily calculates fluxes)
Expand All @@ -776,16 +791,15 @@ function solve_coupler!(cs)
atmos_sim.integrator.p.precomputed.sfc_conditions .= new_p.precomputed.sfc_conditions
end

## update the coupler with the new atmospheric properties
FieldExchanger.import_atmos_fields!(cs.fields, cs.model_sims, cs.boundary_space, cs.turbulent_fluxes) # radiative and/or turbulent

## callback to update the fist day of month if needed (for BCReader)
TimeManager.trigger_callback!(cs, cs.callbacks.update_firstdayofmonth!)

## callback to checkpoint model state
TimeManager.trigger_callback!(cs, cs.callbacks.checkpoint)

end

return nothing
end

Expand All @@ -794,18 +808,32 @@ if haskey(ENV, "CI_PERF_SKIP_COUPLED_RUN") #hide
throw(:exit_profile_init) #hide
end #hide

## run the coupled simulation for one timestep to precompile everything before timing
#=
## Precompilation of Coupling Loop
Here we run the entire coupled simulation for two timesteps to precompile everything
for accurate timing of the overall simulation. After these two steps, we update the
beginning and end of the simulation timespan to the correct values.
=#

## run the coupled simulation for two timesteps to precompile
cs.tspan[2] = Δt_cpl * 2
solve_coupler!(cs)

## run the coupled simulation for the full timespan and time it
## update the timespan to the correct values
cs.tspan[1] = Δt_cpl * 2
cs.tspan[2] = tspan[2]

## Run garbage collection before solving for more accurate memory comparison to ClimaAtmos
GC.gc()

## Use ClimaComms.@elapsed to time the simulation on both CPU and GPU
#=
## Solving and Timing the Full Simulation
This is where the full coupling loop, `solve_coupler!` is called for the full timespan of the simulation.
We use the `ClimaComms.@elapsed` macro to time the simulation on both CPU and GPU, and use this
value to calculare the simulated years per day (SYPD) of the simulation.
=#
walltime = ClimaComms.@elapsed comms_ctx.device begin
s = CA.@timed_str begin
solve_coupler!(cs)
Expand All @@ -830,7 +858,18 @@ end

#=
## Postprocessing
Currently all postprocessing is performed using the root process only.
All postprocessing is performed using the root process only, if applicable.
Our postprocessing consists of outputting a number of plots and animations to visualize the model output.
The postprocessing includes:
- Energy and water conservation checks (if running SlabPlanet with checks enabled)
- Animations (if not running in MPI)
- AMIP plots of the final state of the model
- NCEP plots of reanalysis data
- Combined AMIP and NCEP plots
- Error against observations
- Optional additional atmosphere diagnostics plots
- Plots of useful coupler and component model fields for debugging
=#

if ClimaComms.iamroot(comms_ctx)
Expand Down Expand Up @@ -993,19 +1032,19 @@ if ClimaComms.iamroot(comms_ctx)
end
end

## ci plots
## plot extra atmosphere diagnostics if specified
if config_dict["ci_plots"]
@info "Generating CI plots"
include("user_io/ci_plots.jl")
make_plots(Val(:general_ci_plots), [atmos_sim.integrator.p.output_dir], dir_paths.artifacts)
end

## plot all model states and coupler fields (useful for debugging)
!(comms_ctx isa ClimaComms.MPICommsContext) && debug(cs, dir_paths.artifacts)
!CA.is_distributed(comms_ctx) && debug(cs, dir_paths.artifacts)

if isinteractive()
## clean up for interactive runs, retain all output otherwise
rm(dir_paths.output; recursive = true, force = true)
end
if isinteractive() #hide
## clean up for interactive runs, retain all output otherwise #hide
rm(dir_paths.output; recursive = true, force = true) #hide
end #hide

end

0 comments on commit 9eaa136

Please sign in to comment.