Skip to content

Commit cad4b19

Browse files
committed
conservation computation, diagnostics, plotting [skip ci]
1 parent 45fe601 commit cad4b19

File tree

10 files changed

+389
-28
lines changed

10 files changed

+389
-28
lines changed

src/diagnostics/default_diagnostics.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,8 @@ function default_diagnostics(
270270
output_writer,
271271
output_vars = :short,
272272
average_period = :monthly,
273+
conservation = false,
274+
conservation_period = Day(10),
273275
) where {FT}
274276

275277
define_diagnostics!(land_model)
@@ -388,4 +390,25 @@ function default_diagnostics(
388390
start_date,
389391
)
390392
end
393+
394+
if conservation
395+
additional_diags = ["epa", "epac", "wvpa", "wvpac"]
396+
additional_outputs = vcat(
397+
map(additional_diags) do short_name
398+
output_schedule_func =
399+
conservation_period isa Period ?
400+
EveryCalendarDtSchedule(conservation_period; start_date) : EveryDtSchedule(conservation_period)
401+
return ScheduledDiagnostic(
402+
variable = get_diagnostic_variable(short_name),
403+
compute_schedule_func = EveryStepSchedule(),
404+
output_schedule_func = output_schedule_func,
405+
output_writer = output_writer,
406+
)
407+
end...,
408+
)
409+
else
410+
additional_outputs = []
411+
end
412+
413+
return [default_outputs..., additional_outputs...]
391414
end

src/diagnostics/land_compute_methods.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ end
5555
@diagnostic_compute "water_volume_per_area_change" EnergyHydrology Y.soil.∫F_vol_liq_water_dt
5656
@diagnostic_compute "energy_per_area_change" EnergyHydrology Y.soil.∫F_e_dt
5757

58+
@diagnostic_compute "water_volume_per_area" LandModel p.total_water
59+
@diagnostic_compute "energy_per_area" LandModel p.total_energy
60+
@diagnostic_compute "water_volume_per_area_change" LandModel Y.∫F_vol_liq_water_dt
61+
@diagnostic_compute "energy_per_area_change" LandModel Y.∫F_e_dt
62+
5863

5964
### BucketModel ###
6065

src/integrated/land.jl

Lines changed: 154 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ lsm_aux_vars(m::LandModel) = (
222222
:ϵ_sfc,
223223
:α_sfc,
224224
:α_ground,
225+
:total_energy,
226+
:total_water,
225227
)
226228

227229
"""
@@ -249,6 +251,8 @@ lsm_aux_types(m::LandModel{FT}) where {FT} = (
249251
FT,
250252
FT,
251253
NamedTuple{(:PAR, :NIR), Tuple{FT, FT}},
254+
FT,
255+
FT,
252256
)
253257

254258
"""
@@ -276,8 +280,157 @@ lsm_aux_domain_names(m::LandModel) = (
276280
:surface,
277281
:surface,
278282
:surface,
283+
:surface,
284+
:surface,
279285
)
280286

287+
function initialize_prognostic(
288+
model::LandModel{FT},
289+
coords::NamedTuple,
290+
) where {FT}
291+
components = land_components(model)
292+
Y_state_list = map(components) do (component)
293+
submodel = getproperty(model, component)
294+
getproperty(initialize_prognostic(submodel, coords), component)
295+
end
296+
conservation_vars = (:∫Fwdt, :∫Fedt)
297+
conservation_types = (FT, FT)
298+
conservation_domain_names = (:surface, :surface)
299+
conservation_state_list = initialize_vars(
300+
conservation_vars,
301+
conservation_types,
302+
conservation_domain_names,
303+
coords,
304+
:conservation_check,
305+
)
306+
Y = ClimaCore.Fields.FieldVector(;
307+
NamedTuple{(components..., conservation_vars...)}((
308+
Y_state_list...,
309+
conservation_state_list.conservation_check...,
310+
))...,
311+
)
312+
return Y
313+
end
314+
315+
function make_update_aux(land::LandModel)
316+
components = land_components(land)
317+
update_aux_function_list =
318+
map(x -> make_update_aux(getproperty(land, x)), components)
319+
function update_aux!(p, Y, t)
320+
for f! in update_aux_function_list
321+
f!(p, Y, t)
322+
end
323+
sfc_cache = p.scratch1 .* 0
324+
ClimaLand.total_liq_water_vol_per_area!(
325+
p.total_water,
326+
land,
327+
Y,
328+
p,
329+
t,
330+
sfc_cache,
331+
)
332+
ClimaLand.total_energy_per_area!(
333+
p.total_energy,
334+
land,
335+
Y,
336+
p,
337+
t,
338+
sfc_cache,
339+
)
340+
end
341+
return update_aux!
342+
end
343+
344+
function make_imp_tendency(land::LandModel)
345+
components = land_components(land)
346+
compute_imp_tendency_list =
347+
map(x -> make_compute_imp_tendency(getproperty(land, x)), components)
348+
update_aux! = make_update_aux(land)
349+
update_boundary_fluxes! = make_update_boundary_fluxes(land)
350+
function imp_tendency!(dY, Y, p, t)
351+
update_aux!(p, Y, t)
352+
update_boundary_fluxes!(p, Y, t)
353+
for f! in compute_imp_tendency_list
354+
f!(dY, Y, p, t)
355+
end
356+
# Soil and canopy implicit terms
357+
# soil contributions were computed by soil and account for snow cover fraction
358+
@. dY.∫Fedt = -(
359+
(1 - p.snow.snow_cover_fraction) * (
360+
p.soil.R_n +
361+
p.soil.turbulent_fluxes.lhf +
362+
p.soil.turbulent_fluxes.shf
363+
) +
364+
p.canopy.turbulent_fluxes.shf +
365+
p.canopy.turbulent_fluxes.lhf -
366+
p.canopy.radiative_transfer.SW_n -
367+
p.canopy.radiative_transfer.LW_n
368+
)
369+
@. dY.∫Fwdt = -(
370+
(1 - p.snow.snow_cover_fraction) *
371+
(p.drivers.P_liq + p.soil.turbulent_fluxes.vapor_flux_liq) +
372+
p.soil.R_s - p.soil.bottom_bc.water
373+
)
374+
375+
end
376+
return imp_tendency!
377+
end
378+
379+
function make_exp_tendency(land::LandModel{FT}) where {FT}
380+
components = land_components(land)
381+
compute_exp_tendency_list =
382+
map(x -> make_compute_exp_tendency(getproperty(land, x)), components)
383+
update_aux! = make_update_aux(land)
384+
update_boundary_fluxes! = make_update_boundary_fluxes(land)
385+
function exp_tendency!(dY, Y, p, t)
386+
update_aux!(p, Y, t)
387+
# Treat the following terms explicitly!
388+
389+
# update root extraction
390+
update_root_extraction!(p, Y, t, land) # defined in src/integrated/soil_canopy_root_interactions.jl
391+
392+
# Compute the ground heat flux in place:
393+
update_soil_snow_ground_heat_flux!(
394+
p,
395+
Y,
396+
land.soil.parameters,
397+
land.snow.parameters,
398+
land.soil.domain,
399+
FT,
400+
)
401+
# Treat the following terms explicitly!
402+
update_boundary_fluxes!(p, Y, t)
403+
for f! in compute_exp_tendency_list
404+
f!(dY, Y, p, t)
405+
end
406+
_LH_f0 = LP.LH_f0(land.soil.parameters.earth_param_set)
407+
_ρ_liq = LP.ρ_cloud_liq(land.soil.parameters.earth_param_set)
408+
ρe_falling_snow = -_LH_f0 * _ρ_liq # per unit vol of liquid water
409+
# Explicit source terms for soil, and snow fluxes
410+
# soil contributions were computed by soil and account for snow cover fraction
411+
@. dY.∫Fedt = -(
412+
p.drivers.P_snow * ρe_falling_snow +
413+
(
414+
p.snow.turbulent_fluxes.lhf +
415+
p.snow.turbulent_fluxes.shf +
416+
p.snow.R_n - p.snow.energy_runoff
417+
) * p.snow.snow_cover_fraction
418+
)
419+
# Explicit snow, canopy, source terms for soil (including sublimation, subsurface runoff)
420+
@. dY.∫Fwdt =
421+
-p.soil.R_ss -
422+
p.soil.turbulent_fluxes.vapor_flux_ice *
423+
(1 - p.snow.snow_cover_fraction) - (
424+
p.drivers.P_snow +
425+
(p.drivers.P_liq + p.snow.turbulent_fluxes.vapor_flux) *
426+
p.snow.snow_cover_fraction +
427+
p.canopy.turbulent_fluxes.transpiration
428+
)
429+
end
430+
return exp_tendency!
431+
end
432+
433+
281434
"""
282435
make_update_boundary_fluxes(
283436
land::LandModel{FT, MM, SM, RM, SnM},
@@ -313,9 +466,6 @@ function make_update_boundary_fluxes(
313466

314467
function update_boundary_fluxes!(p, Y, t)
315468
earth_param_set = land.soil.parameters.earth_param_set
316-
# update root extraction
317-
update_root_extraction!(p, Y, t, land) # defined in src/integrated/soil_canopy_root_interactions.jl
318-
319469
# Radiation - updates Rn for soil and snow also
320470
lsm_radiant_energy_fluxes!(
321471
p,
@@ -330,16 +480,6 @@ function make_update_boundary_fluxes(
330480
p,
331481
land.soil.parameters.earth_param_set,
332482
)
333-
334-
# Compute the ground heat flux in place:
335-
update_soil_snow_ground_heat_flux!(
336-
p,
337-
Y,
338-
land.soil.parameters,
339-
land.snow.parameters,
340-
land.soil.domain,
341-
FT,
342-
)
343483
#Now update snow boundary conditions, which rely on the ground heat flux
344484
update_snow_bf!(p, Y, t)
345485

@@ -527,7 +667,6 @@ function soil_boundary_fluxes!(
527667
p.excess_heat_flux +
528668
p.snow.snow_cover_fraction * p.ground_heat_flux +
529669
infiltration_energy_flux
530-
531670
return nothing
532671
end
533672

@@ -615,7 +754,7 @@ function snow_boundary_fluxes!(
615754
e_flux_falling_rain =
616755
Snow.energy_flux_falling_rain(bc.atmos, p, model.parameters)
617756

618-
# positive fluxes are TOWARDS atmos, but R_n positive if snow absorbs energy
757+
# positive fluxes are TOWARDS atmos
619758
@. p.snow.total_energy_flux =
620759
e_flux_falling_snow +
621760
(

src/integrated/soil_canopy_root_interactions.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ function update_root_extraction!(p, Y, t, land)
4242
z,
4343
land.canopy.hydraulics.parameters.rooting_depth,
4444
)
45+
4546
@. p.root_energy_extraction =
4647
p.root_extraction * ClimaLand.Soil.volumetric_internal_energy_liq(
4748
p.soil.T,
@@ -163,4 +164,5 @@ function ClimaLand.source!(
163164

164165
ClimaCore.Operators.column_integral_definite!(p.scratch1, p.root_extraction)
165166
@. dY.soil.∫F_vol_liq_water_dt += p.scratch1
167+
# We don't update ∫Sdz here because it cancels out by design with the bottom flux into the canopy (within the land model)
166168
end

src/integrated/soil_snow_model.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,6 @@ function soil_boundary_fluxes!(
359359
p.excess_heat_flux +
360360
p.snow.snow_cover_fraction * p.ground_heat_flux +
361361
infiltration_energy_flux
362-
363362
return nothing
364363
end
365364

src/shared_utilities/drivers.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,7 @@ function make_update_drivers(a::PrescribedAtmosphere{FT}) where {FT}
12271227
function update_drivers!(p, t)
12281228
evaluate!(p.drivers.P_liq, a.liquid_precip, t)
12291229
evaluate!(p.drivers.P_snow, a.snow_precip, t)
1230+
p.drivers.P_snow .*= 0
12301231
evaluate!(p.drivers.T, a.T, t)
12311232
evaluate!(p.drivers.P, a.P, t)
12321233
evaluate!(p.drivers.u, a.u, t)

src/shared_utilities/implicit_timestepping.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ function FieldMatrixWithSolver(Y::ClimaCore.Fields.FieldVector)
102102
explicit_vars = (
103103
@name(soil.∫F_vol_liq_water_dt),
104104
@name(soil.∫F_e_dt),
105+
@name(∫F_vol_liq_water_dt),
106+
@name(∫F_e_dt),
105107
@name(soilco2.C),
106108
@name(soil.θ_i),
107109
@name(canopy.hydraulics.ϑ_l),

src/simulations/initial_conditions.jl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,14 @@ function set_snow_initial_conditions!(
166166
regridder_type = regridder_type,
167167
extrapolation_bc = extrapolation_bc,
168168
)
169-
Y.snow.S .= SpaceVaryingInput(
170-
snow_ic_path,
171-
"swe",
172-
surface_space;
173-
regridder_type,
174-
regridder_kwargs = (; extrapolation_bc,),
175-
)
169+
Y.snow.S .=
170+
SpaceVaryingInput(
171+
snow_ic_path,
172+
"swe",
173+
surface_space;
174+
regridder_type,
175+
regridder_kwargs = (; extrapolation_bc,),
176+
) .* 0
176177
Y.snow.S_l .= 0
177178
p.snow.T .= enforce_snow_temperature_constraint.(Y.snow.S, p.snow.T)
178179
Y.snow.U .=

src/standalone/Vegetation/PlantHydraulics.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -342,11 +342,11 @@ function ClimaLand.Canopy.set_canopy_prescribed_field!(
342342
t,
343343
) where {FT}
344344
(; LAIfunction, SAI, RAI) = component.parameters.ai_parameterization
345-
evaluate!(p.canopy.hydraulics.area_index.leaf, LAIfunction, t)
346-
p.canopy.hydraulics.area_index.leaf .=
347-
clip.(p.canopy.hydraulics.area_index.leaf, FT(0.05))
348-
@. p.canopy.hydraulics.area_index.stem = SAI
349-
@. p.canopy.hydraulics.area_index.root = RAI
345+
#evaluate!(p.canopy.hydraulics.area_index.leaf, LAIfunction, t)
346+
p.canopy.hydraulics.area_index.leaf .= 0#
347+
#clip.(p.canopy.hydraulics.area_index.leaf, FT(0.05))
348+
@. p.canopy.hydraulics.area_index.stem = 0#SAI
349+
@. p.canopy.hydraulics.area_index.root = 0#RAI
350350
end
351351

352352
"""

0 commit comments

Comments
 (0)