-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev_moritz' into 'master'
Add preliminary implementation of Lake scheme from CryoGridLite See merge request cryogrid/cryogridjulia!116
- Loading branch information
Showing
11 changed files
with
274 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
using CryoGrid | ||
using CryoGrid.LiteImplicit | ||
using Plots | ||
|
||
Plots.plotly() | ||
|
||
CryoGrid.debug(true) | ||
|
||
forcings = loadforcings(CryoGrid.Presets.Forcings.Samoylov_ERA_MkL3_CCSM4_long_term); | ||
soilprofile = SoilProfile( | ||
0.0u"m" => MineralOrganic(por=0.80,sat=0.9,org=0.75), | ||
0.1u"m" => MineralOrganic(por=0.80,sat=1.0,org=0.25), | ||
0.4u"m" => MineralOrganic(por=0.55,sat=1.0,org=0.25), | ||
3.0u"m" => MineralOrganic(por=0.50,sat=1.0,org=0.0), | ||
10.0u"m" => MineralOrganic(por=0.30,sat=1.0,org=0.0), | ||
) | ||
tempprofile_linear = TemperatureProfile( | ||
-2.0u"m" => 0.0u"°C", | ||
0.0u"m" => 0.0u"°C", | ||
10.0u"m" => -10.0u"°C", | ||
1000.0u"m" => 10.2u"°C" | ||
) | ||
modelgrid = Grid(vcat(-1.0u"m":0.02u"m":-0.02u"m", CryoGrid.Presets.DefaultGrid_2cm)) | ||
z_top = -1.0u"m" | ||
z_sub = map(knot -> knot.depth, soilprofile) | ||
z_bot = modelgrid[end] | ||
upperbc = TemperatureGradient(forcings.Tair, NFactor(nf=0.5)) | ||
initT = initializer(:T, tempprofile_linear) | ||
@info "Building stratigraphy" | ||
heatop = Heat.EnthalpyImplicit() | ||
strat = @Stratigraphy( | ||
z_top => Top(upperbc), | ||
-1.0u"m" => Lake(heat=HeatBalance(heatop)), | ||
0.0u"m" => Ground(soilprofile[1].value, heat=HeatBalance(heatop)), | ||
z_bot => Bottom(GeothermalHeatFlux(0.053u"W/m^2")) | ||
); | ||
@info "Building tile" | ||
tile = @time Tile(strat, modelgrid, initT) | ||
# define time span, 5 years | ||
tspan = (DateTime(2010,12,30), DateTime(2012,12,30)) | ||
tspan_sol = convert_tspan(tspan) | ||
u0, du0 = @time initialcondition!(tile, tspan); | ||
prob = CryoGridProblem(tile, u0, tspan, saveat=24*3600.0, savevars=(:θw,:T,)) | ||
# set up integrator | ||
integrator = init(prob, LiteImplicitEuler(), dt=24*3600) | ||
# debug one step | ||
step!(integrator) | ||
|
||
for i in integrator | ||
state = getstate(integrator) | ||
if state.top.T_ub[1] > 0.0 | ||
break | ||
end | ||
end | ||
|
||
step!(integrator) | ||
state = getstate(integrator) | ||
state.top.T_ub | ||
state.lake.T | ||
|
||
@info "Running model" | ||
sol = @time solve(prob, LiteImplicitEuler(), dt=24*3600.0) | ||
out = CryoGridOutput(sol) | ||
|
||
# Plot the results | ||
zs = [-100,-50.0,-10.0,11.0]u"cm" | ||
cg = Plots.cgrad(:copper,rev=true); | ||
plot(convert_t.(dims(out.T, Ti)), Array(out.T[Z(Near(zs))])' |> ustrip, color=cg[LinRange(0.0,1.0,length(zs))]', ylabel="Temperature", title="", dpi=150) | ||
plot!(convert_t.(dims(out.T, Ti)), t -> forcings.Tair.(t), c=:blue, linestyle=:dash) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module Lakes | ||
|
||
using CryoGrid | ||
using CryoGrid.Utils | ||
using CryoGrid.Numerics | ||
|
||
export Lake | ||
include("lake_simple.jl") | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
abstract type LakeParameterization <: CryoGrid.Parameterization end | ||
|
||
Base.@kwdef struct SimpleLakeScheme{Thp} <: LakeParameterization | ||
heat::Thp = ThermalProperties() | ||
end | ||
|
||
Base.@kwdef struct Lake{Tpara<:LakeParameterization,Theat<:HeatBalance,Taux} <: CryoGrid.SubSurface | ||
para::Tpara = SimpleLakeScheme() | ||
heat::Theat = HeatBalance() | ||
aux::Taux = nothing | ||
end | ||
|
||
function get_upper_boundary_index(T_ub, θw) | ||
ubc_idx = 1 | ||
if T_ub >= zero(T_ub) | ||
@inbounds for i in eachindex(θw) | ||
ubc_idx = i | ||
if θw[i] < one(eltype(θw)) | ||
return ubc_idx | ||
end | ||
end | ||
end | ||
return ubc_idx+1 | ||
end | ||
|
||
# Material properties | ||
Heat.thermalproperties(lake::Lake) = lake.para.heat | ||
|
||
Hydrology.watercontent(::Lake, state) = 1.0 | ||
|
||
CryoGrid.processes(lake::Lake) = lake.heat | ||
|
||
CryoGrid.volumetricfractions(::Lake, state, i) = (state.θw[i], 1 - state.θw[i], 0.0) | ||
|
||
CryoGrid.variables(lake::Lake, heat::HeatBalance) = ( | ||
CryoGrid.variables(heat)..., | ||
# Diagnostic(:I_t, OnGrid(Cells), desc="Indicator variable for is thawed (1 or 0)."), | ||
Diagnostic(:ρ_w, Scalar, u"kg*m^-3", domain=0..Inf, desc = "density of water with temperature"), | ||
Diagnostic(:T_ub, Scalar, u"°C"), | ||
Diagnostic(:ubc_idx, Scalar, NoUnits, Int), | ||
) | ||
|
||
function CryoGrid.diagnosticstep!(::Lake, state) | ||
T_ub = getscalar(state.T_ub) | ||
@setscalar state.ubc_idx = get_upper_boundary_index(T_ub, state.θw) | ||
return false | ||
end | ||
|
||
function CryoGrid.initialcondition!(lake::Lake, state) | ||
initialcondition!(lake, lake.heat, state) | ||
diagnosticstep!(lake, state) | ||
end | ||
|
||
function CryoGrid.interact!(top::Top, bc::HeatBC, lake::Lake, heat::HeatBalanceImplicit, stop, slake) | ||
T_ub = slake.T_ub[1] = getscalar(stop.T_ub) | ||
ubc_idx = Int(getscalar(slake.ubc_idx)) | ||
# get variables | ||
an = slake.DT_an | ||
as = slake.DT_as | ||
ap = slake.DT_ap | ||
bp = slake.DT_bp | ||
k = slake.k | ||
dx = Δ(cells(slake.grid)) | ||
dxp = Δ(slake.grid) | ||
# outer lake cell | ||
bp[1] = T_ub*k[1] / (dxp[1]/2) / dxp[1] | ||
ap[1] = k[1] / (dxp[1]/2) / dxp[1] | ||
if ubc_idx > 1 | ||
as[1] = an[1] = zero(eltype(as)) | ||
end | ||
# inner lake cells | ||
@inbounds for i in 2:ubc_idx-1 | ||
bp[i] = T_ub*k[i] / dx[i-1] / dxp[i] | ||
ap[i] = an[i] | ||
as[i] = zero(eltype(as)) | ||
an[i] = zero(eltype(an)) | ||
end | ||
return nothing | ||
end | ||
function CryoGrid.interact!(lake::Lake, ::HeatBalanceImplicit, sub::SubSurface, ::HeatBalanceImplicit, slake, ssub) | ||
Δk₁ = CryoGrid.thickness(lake, slake, last) | ||
Δk₂ = CryoGrid.thickness(sub, ssub, first) | ||
Δz = CryoGrid.midpoint(sub, ssub, first) - CryoGrid.midpoint(lake, slake, last) | ||
ubc_idx = Int(getscalar(slake.ubc_idx)) | ||
# thermal conductivity between cells | ||
k = slake.k[end] = ssub.k[1] = | ||
@inbounds let k₁ = slake.kc[end], | ||
k₂ = ssub.kc[1], | ||
Δ₁ = Δk₁[end], | ||
Δ₂ = Δk₂[1]; | ||
harmonicmean(k₁, k₂, Δ₁, Δ₂) | ||
end | ||
slake.DT_ap[end] += slake.DT_as[end] = (ubc_idx <= length(slake.θw))*k / Δz / Δk₁ | ||
ssub.DT_ap[1] += ssub.DT_an[1] = k / Δz / Δk₂ | ||
return nothing | ||
end | ||
|
||
function CryoGrid.updatestate!(sub::Lake, heat::HeatBalance{FreeWater,<:Heat.MOLEnthalpy}, state) | ||
Heat.resetfluxes!(sub, heat, state) | ||
# Evaluate freeze/thaw processes | ||
Heat.freezethaw!(sub, heat, state) | ||
|
||
# force unfrozen water to Tair | ||
if all(state.θw .>= 1.) | ||
state.T .= state.T_ub | ||
state.H .= Heat.enthalpy.(state.T, state.C, heat.prop.L, state.θw) | ||
end | ||
|
||
# Update thermal conductivity | ||
Heat.thermalconductivity!(sub, heat, state) | ||
return nothing | ||
end | ||
|
||
function CryoGrid.computefluxes!(::Lake, ::HeatBalance{FreeWater,<:Heat.MOLEnthalpy}, state) | ||
Δk = Δ(state.grids.k) # cell sizes | ||
ΔT = Δ(state.grids.T) # midpoint distances | ||
# compute internal fluxes and non-linear diffusion assuming boundary fluxes have been set | ||
Numerics.nonlineardiffusion!(state.∂H∂t, state.jH, state.T, ΔT, state.k, Δk) | ||
return nothing | ||
end | ||
|
||
|
||
function CryoGrid.interact!( | ||
top::Top, | ||
bc::HeatBC, | ||
lake::Lake, | ||
heat::HeatBalance{FreeWater,<:Heat.MOLEnthalpy}, | ||
stop, | ||
slake | ||
) | ||
@setscalar slake.T_ub = stop.T_ub | ||
# boundary flux | ||
slake.jH[1] += CryoGrid.boundaryflux(bc, top, heat, lake, stop, slake) | ||
return nothing | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.