Skip to content

Commit b638fcd

Browse files
authored
use nearest neighbor interpolation (#1290)
1 parent 49987e2 commit b638fcd

File tree

11 files changed

+472
-68
lines changed

11 files changed

+472
-68
lines changed

.buildkite/longruns_gpu/pipeline.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ steps:
5353
env:
5454
CLIMACOMMS_DEVICE: "CUDA"
5555

56+
- label: ":snow_capped_mountain: Low-Res Snowy Land"
57+
command:
58+
- julia --color=yes --project=.buildkite experiments/long_runs/low_res_snowy_land.jl
59+
artifact_paths:
60+
- "lowres_snowy_land_longrun_gpu/*png"
61+
- "lowres_snowy_land_longrun_gpu/*pdf"
62+
agents:
63+
slurm_gpus: 1
64+
slurm_time: 3:00:00
65+
env:
66+
CLIMACOMMS_DEVICE: "CUDA"
67+
5668
- label: ":sunglasses: California regional simulation"
5769
command:
5870
- julia --color=yes --project=.buildkite experiments/long_runs/land_region.jl

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ ClimaLand.jl Release Notes
33

44
main
55
-------
6+
- Use nearest neighbor spatial interpolation PR[#1290](https://github.com/CliMA/ClimaLand.jl/pull/1290)
67
- Use global MODIS LAI for all simulations; remove `modis_lai_fluxnet_sites` artifact PR[#1282](https://github.com/CliMA/ClimaLand.jl/pull/1282)
78
- Use ClimaUtilities v0.1.25 to read in spatial data to a point using lat/lon PR[#1279](https://github.com/CliMA/ClimaLand.jl/pull/1279)
89
- Add data handling tools to FluxnetSimulationsExt and use throughout docs and experiments PR[#1238](https://github.com/CliMA/ClimaLand.jl/pull/1238)

experiments/long_runs/land_region.jl

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ outdir =
5151
ClimaUtilities.OutputPathGenerator.generate_output_path(diagnostics_outdir)
5252

5353
function setup_model(FT, context, start_date, Δt, domain, earth_param_set)
54-
55-
time_interpolation_method = LinearInterpolation(PeriodicCalendar())
5654
surface_space = domain.space.surface
5755
subsurface_space = domain.space.subsurface
5856

@@ -66,7 +64,7 @@ function setup_model(FT, context, start_date, Δt, domain, earth_param_set)
6664
earth_param_set,
6765
FT;
6866
max_wind_speed = 25.0,
69-
time_interpolation_method,
67+
time_interpolation_method = LinearInterpolation(PeriodicCalendar()),
7068
)
7169

7270
(; ν_ss_om, ν_ss_quartz, ν_ss_gravel) =
@@ -179,14 +177,14 @@ function setup_model(FT, context, start_date, Δt, domain, earth_param_set)
179177
# Set up plant hydraulics
180178
modis_lai_ncdata_path = ClimaLand.Artifacts.modis_lai_multiyear_paths(;
181179
context = context,
182-
start_date = start_date + Second(t0),
183-
end_date = start_date + Second(t0) + Second(tf),
180+
start_date,
181+
end_date = stop_date,
184182
)
185183
LAIfunction = ClimaLand.prescribed_lai_modis(
186184
modis_lai_ncdata_path,
187185
surface_space,
188186
start_date;
189-
time_interpolation_method,
187+
time_interpolation_method = LinearInterpolation(),
190188
)
191189
ai_parameterization =
192190
Canopy.PrescribedSiteAreaIndex{FT}(LAIfunction, SAI, RAI)
Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
# # Global run of land model at low resolution
2+
3+
# The code sets up and runs ClimaLand v1, which
4+
# includes soil, canopy, and snow, on a spherical domain,
5+
# using low resolution ERA5 data as forcing.
6+
7+
# Simulation Setup
8+
# Number of spatial elements: 30 in horizontal, 15 in vertical
9+
# Soil depth: 50 m
10+
# Simulation duration: 730 d
11+
# Timestep: 450 s
12+
# Timestepper: ARS111
13+
# Fixed number of iterations: 3
14+
# Jacobian update: every new Newton iteration
15+
# Atmos forcing update: every 3 hours
16+
17+
import ClimaComms
18+
ClimaComms.@import_required_backends
19+
using ClimaUtilities.ClimaArtifacts
20+
import ClimaUtilities.TimeManager: ITime, date
21+
22+
import ClimaDiagnostics
23+
import ClimaUtilities
24+
25+
import ClimaUtilities.TimeVaryingInputs:
26+
TimeVaryingInput, LinearInterpolation, PeriodicCalendar
27+
import ClimaUtilities.ClimaArtifacts: @clima_artifact
28+
import ClimaParams as CP
29+
using ClimaCore
30+
using ClimaLand
31+
using ClimaLand.Snow
32+
using ClimaLand.Soil
33+
using ClimaLand.Canopy
34+
import ClimaLand
35+
import ClimaLand.Parameters as LP
36+
import ClimaLand.Simulations: LandSimulation, solve!
37+
38+
using Dates
39+
40+
using CairoMakie, GeoMakie, Poppler_jll, ClimaAnalysis
41+
LandSimVis =
42+
Base.get_extension(
43+
ClimaLand,
44+
:LandSimulationVisualizationExt,
45+
).LandSimulationVisualizationExt;
46+
47+
const FT = Float64;
48+
context = ClimaComms.context()
49+
ClimaComms.init(context)
50+
device = ClimaComms.device()
51+
device_suffix = device isa ClimaComms.CPUSingleThreaded ? "cpu" : "gpu"
52+
root_path = "lowres_snowy_land_longrun_$(device_suffix)"
53+
diagnostics_outdir = joinpath(root_path, "global_diagnostics")
54+
outdir =
55+
ClimaUtilities.OutputPathGenerator.generate_output_path(diagnostics_outdir)
56+
57+
function setup_model(FT, start_date, stop_date, Δt, domain, earth_param_set)
58+
surface_space = domain.space.surface
59+
subsurface_space = domain.space.subsurface
60+
# Forcing data
61+
era5_ncdata_path = ClimaLand.Artifacts.era5_land_forcing_data2008_path(;
62+
context,
63+
lowres = true,
64+
)
65+
atmos, radiation = ClimaLand.prescribed_forcing_era5(
66+
era5_ncdata_path,
67+
surface_space,
68+
start_date,
69+
earth_param_set,
70+
FT;
71+
max_wind_speed = 25.0,
72+
time_interpolation_method = LinearInterpolation(PeriodicCalendar()),
73+
)
74+
75+
(; ν_ss_om, ν_ss_quartz, ν_ss_gravel) =
76+
ClimaLand.Soil.soil_composition_parameters(subsurface_space, FT)
77+
(; ν, hydrology_cm, K_sat, θ_r) =
78+
ClimaLand.Soil.soil_vangenuchten_parameters(subsurface_space, FT)
79+
soil_albedo = Soil.CLMTwoBandSoilAlbedo{FT}(;
80+
ClimaLand.Soil.clm_soil_albedo_parameters(surface_space)...,
81+
)
82+
S_s = ClimaCore.Fields.zeros(subsurface_space) .+ FT(1e-3)
83+
soil_params = Soil.EnergyHydrologyParameters(
84+
FT;
85+
ν,
86+
ν_ss_om,
87+
ν_ss_quartz,
88+
ν_ss_gravel,
89+
hydrology_cm,
90+
K_sat,
91+
S_s,
92+
θ_r,
93+
albedo = soil_albedo,
94+
)
95+
f_over = FT(3.28) # 1/m
96+
R_sb = FT(1.484e-4 / 1000) # m/s
97+
runoff_model = ClimaLand.Soil.Runoff.TOPMODELRunoff{FT}(;
98+
f_over = f_over,
99+
f_max = ClimaLand.Soil.topmodel_fmax(surface_space, FT),
100+
R_sb = R_sb,
101+
)
102+
103+
# Spatially varying canopy parameters from CLM
104+
g1 = ClimaLand.Canopy.clm_medlyn_g1(surface_space)
105+
rooting_depth = ClimaLand.Canopy.clm_rooting_depth(surface_space)
106+
(; is_c3, Vcmax25) =
107+
ClimaLand.Canopy.clm_photosynthesis_parameters(surface_space)
108+
(; Ω, G_Function, α_PAR_leaf, τ_PAR_leaf, α_NIR_leaf, τ_NIR_leaf) =
109+
ClimaLand.Canopy.clm_canopy_radiation_parameters(surface_space)
110+
111+
# Energy Balance model
112+
ac_canopy = FT(2.5e3)
113+
# Plant Hydraulics and general plant parameters
114+
SAI = FT(0.0) # m2/m2
115+
f_root_to_shoot = FT(3.5)
116+
RAI = FT(1.0)
117+
K_sat_plant = FT(7e-8) # m/s
118+
ψ63 = FT(-4 / 0.0098) # / MPa to m
119+
Weibull_param = FT(4) # unitless
120+
a = FT(0.2 * 0.0098) # 1/m
121+
conductivity_model =
122+
Canopy.PlantHydraulics.Weibull{FT}(K_sat_plant, ψ63, Weibull_param)
123+
retention_model = Canopy.PlantHydraulics.LinearRetentionCurve{FT}(a)
124+
plant_ν = FT(1.44e-4)
125+
plant_S_s = FT(1e-2 * 0.0098) # m3/m3/MPa to m3/m3/m
126+
n_stem = 0
127+
n_leaf = 1
128+
h_stem = FT(0.0)
129+
h_leaf = FT(1.0)
130+
zmax = FT(0.0)
131+
h_canopy = h_stem + h_leaf
132+
compartment_midpoints =
133+
n_stem > 0 ? [h_stem / 2, h_stem + h_leaf / 2] : [h_leaf / 2]
134+
compartment_surfaces =
135+
n_stem > 0 ? [zmax, h_stem, h_canopy] : [zmax, h_leaf]
136+
137+
z0_m = FT(0.13) * h_canopy
138+
z0_b = FT(0.1) * z0_m
139+
140+
soil_args = (domain = domain, parameters = soil_params)
141+
soil_model_type = Soil.EnergyHydrology{FT}
142+
143+
# Soil microbes model
144+
soilco2_type = Soil.Biogeochemistry.SoilCO2Model{FT}
145+
soilco2_ps = Soil.Biogeochemistry.SoilCO2ModelParameters(FT)
146+
Csom = ClimaLand.PrescribedSoilOrganicCarbon{FT}(TimeVaryingInput((t) -> 5))
147+
148+
soilco2_args = (; domain = domain, parameters = soilco2_ps)
149+
150+
# Now we set up the canopy model, which we set up by component:
151+
# Component Types
152+
canopy_component_types = (;
153+
autotrophic_respiration = Canopy.AutotrophicRespirationModel{FT},
154+
radiative_transfer = Canopy.TwoStreamModel{FT},
155+
photosynthesis = Canopy.FarquharModel{FT},
156+
conductance = Canopy.MedlynConductanceModel{FT},
157+
hydraulics = Canopy.PlantHydraulicsModel{FT},
158+
energy = Canopy.BigLeafEnergyModel{FT},
159+
)
160+
# Individual Component arguments
161+
# Set up autotrophic respiration
162+
autotrophic_respiration_args =
163+
(; parameters = Canopy.AutotrophicRespirationParameters(FT))
164+
# Set up radiative transfer
165+
radiative_transfer_args = (;
166+
parameters = Canopy.TwoStreamParameters(
167+
FT;
168+
Ω,
169+
α_PAR_leaf,
170+
τ_PAR_leaf,
171+
α_NIR_leaf,
172+
τ_NIR_leaf,
173+
G_Function,
174+
)
175+
)
176+
# Set up conductance
177+
conductance_args =
178+
(; parameters = Canopy.MedlynConductanceParameters(FT; g1))
179+
# Set up photosynthesis
180+
photosynthesis_args =
181+
(; parameters = Canopy.FarquharParameters(FT, is_c3; Vcmax25 = Vcmax25))
182+
# Set up plant hydraulics
183+
modis_lai_ncdata_path = ClimaLand.Artifacts.modis_lai_multiyear_paths(;
184+
context = nothing,
185+
start_date,
186+
end_date = stop_date,
187+
)
188+
LAIfunction = ClimaLand.prescribed_lai_modis(
189+
modis_lai_ncdata_path,
190+
surface_space,
191+
start_date;
192+
time_interpolation_method = LinearInterpolation(),
193+
)
194+
ai_parameterization =
195+
Canopy.PrescribedSiteAreaIndex{FT}(LAIfunction, SAI, RAI)
196+
197+
plant_hydraulics_ps = Canopy.PlantHydraulics.PlantHydraulicsParameters(;
198+
ai_parameterization = ai_parameterization,
199+
ν = plant_ν,
200+
S_s = plant_S_s,
201+
rooting_depth = rooting_depth,
202+
conductivity_model = conductivity_model,
203+
retention_model = retention_model,
204+
)
205+
plant_hydraulics_args = (
206+
parameters = plant_hydraulics_ps,
207+
n_stem = n_stem,
208+
n_leaf = n_leaf,
209+
compartment_midpoints = compartment_midpoints,
210+
compartment_surfaces = compartment_surfaces,
211+
)
212+
213+
energy_args = (parameters = Canopy.BigLeafEnergyParameters{FT}(ac_canopy),)
214+
215+
# Canopy component args
216+
canopy_component_args = (;
217+
autotrophic_respiration = autotrophic_respiration_args,
218+
radiative_transfer = radiative_transfer_args,
219+
photosynthesis = photosynthesis_args,
220+
conductance = conductance_args,
221+
hydraulics = plant_hydraulics_args,
222+
energy = energy_args,
223+
)
224+
225+
# Other info needed
226+
shared_params = Canopy.SharedCanopyParameters{FT, typeof(earth_param_set)}(
227+
z0_m,
228+
z0_b,
229+
earth_param_set,
230+
)
231+
232+
canopy_model_args = (;
233+
parameters = shared_params,
234+
domain = ClimaLand.obtain_surface_domain(domain),
235+
)
236+
237+
# Snow model
238+
# α_snow = Snow.ConstantAlbedoModel(FT(0.7))
239+
# Set β = 0 in order to regain model without density dependence
240+
α_snow = Snow.ZenithAngleAlbedoModel(
241+
FT(0.64),
242+
FT(0.06),
243+
FT(2);
244+
β = FT(0.4),
245+
x0 = FT(0.2),
246+
)
247+
horz_degree_res =
248+
sum(ClimaLand.Domains.average_horizontal_resolution_degrees(domain)) / 2 # mean of resolution in latitude and longitude, in degrees
249+
scf = Snow.WuWuSnowCoverFractionModel(
250+
FT(0.08),
251+
FT(1.77),
252+
FT(1.0),
253+
horz_degree_res,
254+
)
255+
snow_parameters = SnowParameters{FT}(
256+
Δt;
257+
earth_param_set = earth_param_set,
258+
α_snow = α_snow,
259+
scf = scf,
260+
)
261+
snow_args = (;
262+
parameters = snow_parameters,
263+
domain = ClimaLand.obtain_surface_domain(domain),
264+
)
265+
snow_model_type = Snow.SnowModel
266+
267+
land_input = (
268+
atmos = atmos,
269+
radiation = radiation,
270+
runoff = runoff_model,
271+
soil_organic_carbon = Csom,
272+
)
273+
land = LandModel{FT}(;
274+
soilco2_type = soilco2_type,
275+
soilco2_args = soilco2_args,
276+
land_args = land_input,
277+
soil_model_type = soil_model_type,
278+
soil_args = soil_args,
279+
canopy_component_types = canopy_component_types,
280+
canopy_component_args = canopy_component_args,
281+
canopy_model_args = canopy_model_args,
282+
snow_args = snow_args,
283+
snow_model_type = snow_model_type,
284+
)
285+
return land
286+
end
287+
# Note that since the Northern hemisphere's winter season is defined as DJF,
288+
# we simulate from and until the beginning of
289+
# March so that a full season is included in seasonal metrics.
290+
start_date = DateTime("2008-03-01")
291+
stop_date = DateTime("2010-03-02")
292+
Δt = 450.0
293+
nelements = (30, 15)
294+
domain = ClimaLand.Domains.global_domain(
295+
FT;
296+
context,
297+
nelements,
298+
mask_threshold = FT(0.99),
299+
)
300+
params = LP.LandParameters(FT)
301+
model = setup_model(FT, start_date, stop_date, Δt, domain, params)
302+
user_callbacks = (
303+
ClimaLand.NaNCheckCallback(
304+
Dates.Month(6),
305+
start_date,
306+
ITime(Δt, epoch = start_date),
307+
mask = ClimaLand.Domains.landsea_mask(ClimaLand.get_domain(model)),
308+
),
309+
ClimaLand.ReportCallback(10000),
310+
)
311+
simulation =
312+
LandSimulation(FT, start_date, stop_date, Δt, model; user_callbacks, outdir)
313+
@info "Run: Global Soil-Canopy-Snow Model"
314+
@info "Resolution: $nelements"
315+
@info "Timestep: $Δt s"
316+
@info "Start Date: $start_date"
317+
@info "Stop Date: $stop_date"
318+
ClimaLand.Simulations.solve!(simulation)
319+
320+
LandSimVis.make_annual_timeseries(simulation; savedir = root_path)
321+
LandSimVis.make_heatmaps(simulation; savedir = root_path, date = stop_date)
322+
LandSimVis.make_leaderboard_plots(simulation; savedir = root_path)

0 commit comments

Comments
 (0)