Default Canopy Model Tutorial
Now that we've run a simple default soil model simulation in Getting Started, let's try doing the same with the canopy model.
This tutorial sets up our CanopyModel on a column domain. The model prognoses canopy temperature and liquid water content, and diagnoses many more variables. Here you'll see that the setup for different models is very similar, and we'll highlight the changes between them.
Note: we use SI units unless otherwise specified. See our Physical Units documentation for more information.
First import the Julia packages we'll need.
import ClimaParams as CP
using ClimaUtilities.TimeVaryingInputs: TimeVaryingInput
using ClimaLand
using ClimaLand.Domains
using ClimaLand.Canopy
import ClimaLand.Simulations: LandSimulation, solve!
import ClimaLand.Parameters as LP
using Dates
import ClimaDiagnostics
using CairoMakie, ClimaAnalysis, GeoMakie, Printf, StatsBase
import ClimaLand.LandSimVis as LandSimVis
Choose a floating point precision, and get the parameter set, which holds constants used across CliMA models.
FT = Float32
toml_dict = LP.create_toml_dict(FT);
We will run this simulation on a point domain at a lat/lon location near Yellowstone National Park. This is different from the soil example, which ran on a column, because the soil model has depth and the canopy model does not.
longlat = FT.((-110.6, 44.6))
domain = Domains.Point(; z_sfc = FT(0.0), longlat);
surface_space = domain.space.surface;
We choose the initial and final simulation times as DatesTimes, and a timestep in seconds.
start_date = DateTime(2008);
stop_date = start_date + Second(60 * 60 * 72);
dt = 900.0;
Whereas the soil model takes in 2 forcing objects (atmosphere and radiation), the canopy takes in 3 (atmosphere, radiation, and ground). Here we read in the first two from ERA5 data, and specify that the following ground conditions will be prescribed: emissivity, albedo, temperature, and soil moisture. We also set up a constant leaf area index (LAI); for an example reading LAI from MODIS data, please see the canopy_tutorial.jl tutorial. This differs from the soil example because we have the extra inputs of the ground conditions and LAI.
atmos, radiation = ClimaLand.prescribed_forcing_era5(
start_date,
stop_date,
surface_space,
toml_dict,
FT;
use_lowres_forcing = true,
);
ground = PrescribedGroundConditions{FT}();
LAI = TimeVaryingInput((t) -> FT(1.0));
Now, we can create the canopy model. This constructor uses default parameters and parameterizations, but these can also be overwritten, which we'll demonstrate in later tutorials. Of course, this model construction differs from the soil example because we're using a different model type, but the approach remains the same.
model =
Canopy.CanopyModel{FT}(domain, (; atmos, radiation, ground), LAI, toml_dict);
Define a function to set initial conditions for the prognostic variables. Since these are specific to the model physics, the contents here differ from the soil example, but the function structure remains the same. The variables initialized here are described in the Model Equations section of the documentation.
function set_ic!(Y, p, t0, model)
ψ_leaf_0 = FT(-2e5 / 9800)
(; retention_model, ν, S_s) = model.hydraulics.parameters
S_l_ini = Canopy.PlantHydraulics.inverse_water_retention_curve(
retention_model,
ψ_leaf_0,
ν,
S_s,
)
Y.canopy.hydraulics.ϑ_l.:1 .=
Canopy.PlantHydraulics.augmented_liquid_fraction.(ν, S_l_ini)
evaluate!(Y.canopy.energy.T, atmos.T, t0)
end
set_ic! (generic function with 1 method)
Since we'll want to make some plots, let's set up an object to save the model output periodically, as we did for the soil tutorial.
diag_writer = ClimaDiagnostics.Writers.DictWriter();
diagnostics = ClimaLand.Diagnostics.default_diagnostics(
model,
start_date;
output_vars = ["ct", "trans"],
output_writer = diag_writer,
reduction_period = :hourly,
);
Now construct the LandSimulation
object, which contains the model and additional timestepping information. This is identical to the soil example.
simulation = LandSimulation(
start_date,
stop_date,
dt,
model;
set_ic!,
updateat = Second(dt),
user_callbacks = (),
diagnostics,
);
Now we can run the simulation!
solve!(simulation);
We can optionally save the simulation parameters to a file for later reference. Here we specify the filepath where we want to save the parameters, and then ClimaParams handles the saving. Note that any parameters overwritten via keyword arguments when constructing models will not be reflected in this file (in this example there are none).
parameter_log_file = "default_canopy_parameters.toml"
CP.log_parameter_information(toml_dict, parameter_log_file)
┌ Warning: Keys are present in parameter file but not used in the simulation.
│ Typically this is due to a mismatch in parameter name in toml and in source. Offending keys: Any["beta_min", "bucket_z_0m", "pmodel_Ha_Vcmax", "f_over", "pmodel_ϕ0_c3", "z0", "pmodel_ϕ0_c4", "pmodel_ϕa1_c4", "pmodel_bRd", "bucket_z_0b", "critical_snow_fraction", "alpha_0", "moisture_stress_c", "x0", "pmodel_oi", "delta_S", "bucket_beta_decay_exponent", "bucket_capacity_fraction", "pmodel_ΔHko", "k", "alpha_snow", "pmodel_α", "pmodel_ΔHkc", "pmodel_aRd", "pmodel_ϕa0_c3", "pmodel_Kc25", "pmodel_ϕa2_c4", "pmodel_Hd_Vcmax", "pmodel_Γstar25", "pmodel_ϕa1_c3", "pmodel_Ha_Jmax", "delta_alpha", "R_sb", "pmodel_Hd_Jmax", "pmodel_aS_Vcmax", "pmodel_bS_Vcmax", "bucket_soil_conductivity", "pmodel_aS_Jmax", "critical_snow_water_equivalent", "pmodel_fC3", "pmodel_cstar", "pmodel_ΔHΓstar", "beta_0", "pmodel_bS_Jmax", "pmodel_ϕa2_c3", "land_bucket_capacity", "bucket_soil_heat_capacity", "pmodel_Ko25", "beta", "pmodel_β", "pmodel_ϕa0_c4", "gamma"]
└ @ ClimaParams ~/.julia/packages/ClimaParams/c6eE0/src/ClimaParams.jl:358
Let's plot some results, for example diurnally averaged canopy temperature and transpiration over time:
LandSimVis.make_diurnal_timeseries(
simulation;
short_names = ["ct", "trans"],
plot_stem_name = "default_canopy",
);
Atmospheric forcing data: Hersbach et al. [18]
This page was generated using Literate.jl.