diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 64534e23d2..ce2a9f9330 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -140,7 +140,6 @@ steps: agents: slurm_mem: 20GB - # Test: non-monotonous remapping for land mask - label: "Slabplanet: non-monotonous surface remap" key: "slabplanet_non-monotonous" command: "julia --color=yes --project=experiments/AMIP/modular/ experiments/AMIP/modular/coupler_driver_modular.jl --config_file $CONFIG_PATH/slabplanet_nonmono.yml" @@ -168,6 +167,13 @@ steps: agents: slurm_mem: 20GB + - label: "Slabplanet: eisenman sea ice" + key: "slabplanet_eisenman" + command: "julia --color=yes --project=experiments/AMIP/modular/ experiments/AMIP/modular/coupler_driver_modular.jl --config_file $CONFIG_PATH/slabplanet_eisenman.yml" + artifact_paths: "experiments/AMIP/modular/output/slabplanet_eisenman/slabplanet_eisenman_artifacts/*" + agents: + slurm_mem: 20GB + # AMIP # ... diff --git a/config/model_configs/interactive_debug.yml b/config/model_configs/interactive_debug.yml index 8a18dd668b..bd2d4df0e4 100644 --- a/config/model_configs/interactive_debug.yml +++ b/config/model_configs/interactive_debug.yml @@ -4,7 +4,7 @@ rad: "gray" energy_check: true mode_name: "slabplanet" t_end: "10days" -dt_save_to_sol: "2days" +dt_save_to_sol: "0.5days" dt_cpl: 400 dt: "400secs" mono_surface: true diff --git a/config/model_configs/slabplanet_eisenman.yml b/config/model_configs/slabplanet_eisenman.yml new file mode 100644 index 0000000000..a1322309b4 --- /dev/null +++ b/config/model_configs/slabplanet_eisenman.yml @@ -0,0 +1,17 @@ +run_name: "slabplanet_eisenman" +surface_setup: "PrescribedSurface" +moist: "equil" +vert_diff: "true" +rad: "gray" +energy_check: true +mode_name: "slabplanet_eisenman" +t_end: "10days" +dt_save_to_sol: "9days" +dt_cpl: 200 +dt: "200secs" +mono_surface: true +h_elem: 6 +precip_model: "0M" +anim: true +apply_limiter: false +job_id: "slabplanet_eisenman" diff --git a/experiments/AMIP/modular/components/ocean/eisenman_seaice.md b/experiments/AMIP/modular/components/ocean/eisenman_seaice.md new file mode 100644 index 0000000000..d5f9530963 --- /dev/null +++ b/experiments/AMIP/modular/components/ocean/eisenman_seaice.md @@ -0,0 +1,60 @@ +# Eisenman-Zhang Model +Thermodynamic 0-layer model, based on the Semtner 1979 model and later refined by +Eisenman & Wettlaufer (2009) and Zhang et al. (2021). + +There are three prognostic variables, the height of ice (`h_i`), the ocean mixed layer depth (`T_ml`) and the surface air temperature (`T_s`). + +## Formulation +In ice-covered conditions: +$$ +L_i \frac{dh_i}{dt} = F_{atm} - F_{base} - Q +$$ +with the density-weighted latent heat of fusion, $L_i=3 \times 10^8$ J m$^{-3}$, and where the (upward-pointing) flux into the atmosphere is +$$ +F_{atm} = F_{rad} + F_{SH} + F_{LH} +$$ +where $F\_{rad}$ is the net radiative flux, $F_{SH}$ is the sensible heat flux and $F_{LH}$ is the latent heat flux. + +The basal flux is +$$ +F_{base} = F_0(T_{ml} - T_{melt}) +$$ +where $T_{melt} = 273.16$ K is the freezing temperature, and the basal heat coefficient $F_0 = 120$ W m$^{-2}$ K$^{-1}$. + +The lateral oceanic heat flux is parameterized as a prescribed $Q$-flux. With $F_{base} = T_{ml}^{t+1} = T_{melt}$ when ice is present, and zero $Q$-flux in the default setup, the base flux is zero in that case. + +The surface temperature of the ice-covered surface is solved by balancing $F_{atm}(T_s)$ and the conductive heat flux through the ice slab, $F_{ice}$: +$$ +F_{atm} = F_{ice} = k_i \frac{T_{melt} - T_s}{h_i} +$$ +where $k_i = 2$ W m$^{-2}$ K$^{-1}$ is the thermal conductivity of ice. +Currently the solve is implemented as one Newton iteration (sufficient for the current spatial and temporal resolution - see Semtner, 1976): +$$ +T_s^{t+1} = T_s + \frac{F}{dF /d T_s} = T_s^{t} + \frac{- F_{atm}^t + F_{ice}^{t+1}}{k_i/h_i^{t+1} + d F_{atm}^t / d T_s^t} +$$ +where $h_i^{t+1}$ is the updated $h^i$ from the previous section, and $d F_{atm}^t / d T_s^t$ needs to be estimated using $T_s + \delta T$. + +### Warm surface +In ice-free conditions, the ocean temperature $T_{ml}$ assumes the standard slab model representation: +$$ +\rho_w c_w h_{ml}\frac{dT_{ml}}{dt} = - F_{atm} +$$ +In this case, $T_s^{t+1} = T_{ml}^{t+1}$ + +### Frazil ice formation +The frazil ice formation rate is parameterized as a function of the mixed layer temperature. It occurs when the newly calculated ocean temperature $T_{ml}^{t+1} < T_{melt}$. Since the mixed layer is not allowed to cool below $T_{melt}$, the energy deficit is used to grow ice: +$$ +\frac{dh_i}{dt} = \Delta h_i^{t+1} + \frac{\Delta T \rho_w c_w h_{ml}}{L_i \Delta t} +$$ +with $\Delta T = T_{melt} - T_{ml}^{t+1} $. + +### Transition to ice-free conditions +- If the updated $h_i^{t+1} < 0$ from a non-zero $h_i^t$, the ice height is set to zero and the surplus energy warms the mixed layer. + +## Potential extensions +- add area `ice_area_fraction` adjustment (e.g., assuming a minimal thickness of sea ice, below which the grid area becomes part ice and part ocean) + +# References +- [Semtner 1976](https://journals.ametsoc.org/view/journals/phoc/6/3/1520-0485_1976_006_0379_amfttg_2_0_co_2.xml) +- [Eisenman & Wettlaufer 2009](https://www.pnas.org/doi/full/10.1073/pnas.0806887106) +- [Zhang et al 2021](https://agupubs.onlinelibrary.wiley.com/doi/pdf/10.1029/2021MS002671), whose implementation can be found on [GitHub](https://github.com/sally-xiyue/fms-idealized/blob/sea_ice_v1.0/exp/sea_ice/srcmods/mixed_layer.f90) \ No newline at end of file diff --git a/experiments/AMIP/modular/components/ocean/eisenman_seaice_init.jl b/experiments/AMIP/modular/components/ocean/eisenman_seaice_init.jl new file mode 100644 index 0000000000..0d4b424bb7 --- /dev/null +++ b/experiments/AMIP/modular/components/ocean/eisenman_seaice_init.jl @@ -0,0 +1,330 @@ +import ClimaCoupler: FluxCalculator +import ClimaTimeSteppers as CTS +import DiffEqBase: ODEProblem, init, step! +import ClimaCoupler.FluxCalculator: update_turbulent_fluxes_point!, differentiate_turbulent_fluxes! +import ClimaCoupler.Interfacer: get_field, update_field! +using ClimaCore.Fields: getindex + +""" + EisenmanIceSimulation{P, Y, D, I} + +Thermodynamic 0-layer, based on the Semtner 1979 model and later refined by +Eisenmen 2009 and Zhang et al 2021. +""" +struct EisenmanIceSimulation{P, Y, D, I} <: SeaIceModelSimulation + params_ice::P + Y_init::Y + domain::D + integrator::I +end +name(::EisenmanIceSimulation) = "EisenmanIceSimulation" + +Base.@kwdef struct EisenmanIceParameters{FT <: AbstractFloat} + z0m::FT = 1e-3 # roughness length for momentum [m] + z0b::FT = 1e-5 # roughness length for buoyancy [m] + C0_base::FT = 120 # ice base transfer coefficient [W / m2 / K] + T_base::FT = 273.16 # ice base temperature [K] + L_ice::FT = 3e8 # latent heat coefficient for ice [J / m3] + T_freeze::FT = 273.16 # temperature at freezing point [K] + k_ice::FT = 2 # thermal conductivity of ice [W / m / K] + α::FT = 0.70 # albedo + σ::FT = 5.67e-8 # Stefan Boltzmann constant [W / m^2 / K^4] +end + +Base.@kwdef struct EisenmanOceanParameters{FT <: AbstractFloat} + h::FT = 1 # mixed layer depth [m] + ρ::FT = 1020 # density of the mixed layer [kg / m^3] + c::FT = 4000 # mixed layer heat capacity [J / kg / K ] + z0m::FT = 1e-3 # roughness length for momentum [m] + z0b::FT = 1e-5 # roughness length for buoyancy [m] + α::FT = 0.1 # albedo +end + +""" + state_init(p::EisenmanIceParameters, space) + +Initialize the state vectors for the Eisenman-Zhang sea ice model. +""" +function state_init(p::EisenmanIceParameters, space::Spaces.AbstractSpace) + Y = Fields.FieldVector( + T_sfc = ones(space) .* p.T_freeze, + h_ice = zeros(space), + T_ml = ones(space) .* 277, + q_sfc = ClimaCore.Fields.zeros(space), + ) + Ya = Fields.FieldVector( + F_turb = ClimaCore.Fields.zeros(space), + ∂F_turb_energy∂T_sfc = ClimaCore.Fields.zeros(space), + F_rad = ClimaCore.Fields.zeros(space), + e_base = ClimaCore.Fields.zeros(space), + ocean_qflux = ClimaCore.Fields.zeros(space), + ρ_sfc = ClimaCore.Fields.zeros(space), + ) + return Y, Ya +end + +""" + get_∂F_rad_energy∂T_sfc(T_sfc, p) + +Calculate the derivative of the radiative flux with respect to the surface temperature. +""" +function get_∂F_rad_energy∂T_sfc(T_sfc, p) + FT = eltype(T_sfc) + @. FT(4) * (FT(1) - p.α) * p.σ * T_sfc^3 +end + +""" + solve_eisenman_model!(Y, Ya, p, Δt::FT) + +Solve the Eisenman-Zhang sea ice model for one timestep. +""" +function solve_eisenman_model!(Y, Ya, p, thermo_params, Δt) + + # model parameter sets + (; p_i, p_o) = p + + C0_base = p_i.C0_base + T_base = p_i.T_base + L_ice = p_i.L_ice + T_freeze = p_i.T_freeze + k_ice = p_i.k_ice + + hρc_ml = p_o.h * p_o.ρ * p_o.c + + # prognostic + (; T_sfc, h_ice, T_ml, q_sfc) = Y + + # auxiliary + (; F_turb, ∂F_turb_energy∂T_sfc, F_rad, ocean_qflux, e_base) = Ya + + # local + F_atm = @. F_turb + F_rad + ∂F_atmo∂T_sfc = get_∂F_rad_energy∂T_sfc.(T_sfc, Ref(p_i)) .+ ∂F_turb_energy∂T_sfc + + # ice thickness and mixed layer temperature changes due to atmosphereic and ocean fluxes + ice_covered = parent(h_ice)[1] > 0 + if ice_covered # ice-covered + F_base = @. C0_base * (T_ml - T_base) + ΔT_ml = @. -(F_base - ocean_qflux) * Δt / (hρc_ml) + Δh_ice = @. (F_atm - F_base - ocean_qflux) * Δt / L_ice + @. e_base .+= F_base * Δt + else # ice-free + ΔT_ml = @. -(F_atm - ocean_qflux) * Δt / (hρc_ml) + Δh_ice = 0 + end + + # T_ml is not allowed to be below freezing + frazil_ice_formation = parent(T_ml .+ ΔT_ml)[1] < T_freeze + if frazil_ice_formation + # Note that ice formation, which requires T_m < T_freeze, implies that Δh_ice increases + Δh_ice = @. Δh_ice - (T_ml + ΔT_ml - T_freeze) * (hρc_ml) / L_ice + ΔT_ml = @. T_freeze - T_ml + end + + # adjust ocean temperature if transition to ice-free + transition_to_icefree = (parent(h_ice)[1] > 0) & (parent(h_ice .+ Δh_ice)[1] <= 0) + if transition_to_icefree + ΔT_ml = @. ΔT_ml - (h_ice + Δh_ice) * L_ice / (hρc_ml) + Δh_ice = @. -h_ice + end + + # solve for T_sfc + remains_ice_covered = (parent(h_ice .+ Δh_ice)[1] > 0) + if remains_ice_covered + # if ice covered, solve implicity (for now one Newton iteration: ΔT_s = - F(T_s) / dF(T_s)/dT_s ) + h = @. h_ice + Δh_ice + F_conductive = @. k_ice / h * (T_base - T_sfc) + numerator = @. -F_atm + F_conductive + denominator = @. k_ice / h + ∂F_atmo∂T_sfc + ΔT_sfc = @. numerator / denominator + surface_melting = (parent(T_sfc .+ ΔT_sfc)[1] > T_freeze) + if surface_melting + ΔT_sfc = @. T_freeze - T_sfc # NB: T_sfc not storing energy + end + # surface is ice-covered, so update T_sfc as ice surface temperature + T_sfc .+= ΔT_sfc + # update surface humidity + @. q_sfc = TD.q_vap_saturation_generic.(thermo_params, T_sfc, Ya.ρ_sfc, TD.Ice()) + else # ice-free, so update T_sfc as mixed layer temperature + T_sfc .= T_ml .+ ΔT_ml + # update surface humidity + @. q_sfc = TD.q_vap_saturation_generic.(thermo_params, T_sfc, Ya.ρ_sfc, TD.Liquid()) + end + + Y.T_ml .+= ΔT_ml + Y.h_ice .+= Δh_ice + Y.T_sfc .= T_sfc + Y.q_sfc .= q_sfc + + return Y, Ya +end + +""" + ∑tendencies(dY, Y, cache, _) + +Calculate the tendencies for the Eisenman-Zhang sea ice model. +""" +function ∑tendencies(dY, Y, cache, _) + FT = eltype(dY) + Δt = cache.Δt + Ya = cache.Ya + thermo_params = cache.thermo_params + p = cache.params + + @. dY.T_ml = -Y.T_ml / Δt + @. dY.h_ice = -Y.h_ice / Δt + @. dY.T_sfc = -Y.T_sfc / Δt + @. dY.q_sfc = -Y.q_sfc / Δt + + Fields.bycolumn(axes(Y.T_sfc)) do colidx + solve_eisenman_model!(Y[colidx], Ya[colidx], p, thermo_params, Δt) + end + + # Get dY/dt + @. dY.T_ml += Y.T_ml / Δt + @. dY.h_ice += Y.h_ice / Δt + @. dY.T_sfc += Y.T_sfc / Δt + @. dY.q_sfc = -Y.q_sfc / Δt + + # update ice area fraction (binary mask for now) + cache.ice_area_fraction .= Regridder.binary_mask.(Y.h_ice, threshold = eps()) + +end + +""" + eisenman_seaice_init(::Type{FT}, tspan; space = nothing, area_fraction = nothing, thermo_params = nothing, stepper = CTS.RK4(), dt = 0.02, saveat = 1.0e10) + +Initialize the Eisenman-Zhang sea ice model and simulation. +""" +function eisenman_seaice_init( + ::Type{FT}, + tspan; + space = nothing, + area_fraction = nothing, + thermo_params = nothing, + stepper = CTS.RK4(), + dt = 0.02, + saveat = 1.0e10, +) where {FT} + + params_ice = EisenmanIceParameters{FT}() + params_ocean = EisenmanOceanParameters{FT}() + params = (; p_i = params_ice, p_o = params_ocean) + + # initiate prognostic variables + Y, Ya = state_init(params_ice, space) + + ode_algo = CTS.ExplicitAlgorithm(stepper) + ode_function = CTS.ClimaODEFunction(T_exp! = ∑tendencies, dss! = weighted_dss_slab!) + + cache = (; + Ya = Ya, + Δt = dt, + params = params, + area_fraction = area_fraction, + ice_area_fraction = zeros(space), + thermo_params = thermo_params, + dss_buffer = ClimaCore.Spaces.create_dss_buffer(ClimaCore.Fields.zeros(space)), + ) + problem = ODEProblem(ode_function, Y, FT.(tspan), cache) + integrator = init(problem, ode_algo, dt = FT(dt), saveat = FT(saveat), adaptive = false) + + sim = EisenmanIceSimulation(params, Y, space, integrator) + @warn name(sim) * + " assumes gray radiation, no snow coverage, and PartitionedStateFluxes for the surface flux calculation." + return sim +end + +# extensions required by Interfacer +get_field(sim::EisenmanIceSimulation, ::Val{:surface_temperature}) = sim.integrator.u.T_sfc +get_field(sim::EisenmanIceSimulation, ::Val{:surface_humidity}) = sim.integrator.u.q_sfc +get_field(sim::EisenmanIceSimulation, ::Val{:roughness_momentum}) = + @. sim.integrator.p.params.p_i.z0m * (sim.integrator.p.ice_area_fraction) + + sim.integrator.p.params.p_o.z0m .* (1 - sim.integrator.p.ice_area_fraction) +get_field(sim::EisenmanIceSimulation, ::Val{:roughness_buoyancy}) = + @. sim.integrator.p.params.p_i.z0b * (sim.integrator.p.ice_area_fraction) + + sim.integrator.p.params.p_o.z0b .* (1 - sim.integrator.p.ice_area_fraction) +get_field(sim::EisenmanIceSimulation, ::Val{:beta}) = convert(eltype(sim.integrator.u), 1.0) +get_field(sim::EisenmanIceSimulation, ::Val{:albedo}) = + @. sim.integrator.p.params.p_i.α * (sim.integrator.p.ice_area_fraction) + + sim.integrator.p.params.p_o.α .* (1 - sim.integrator.p.ice_area_fraction) +get_field(sim::EisenmanIceSimulation, ::Val{:area_fraction}) = sim.integrator.p.area_fraction +get_field(sim::EisenmanIceSimulation, ::Val{:air_density}) = sim.integrator.p.Ya.ρ_sfc + +function update_field!(sim::EisenmanIceSimulation, ::Val{:area_fraction}, field::Fields.Field) + sim.integrator.p.area_fraction .= field +end +function update_field!(sim::EisenmanIceSimulation, ::Val{:turbulent_energy_flux}, field) + parent(sim.integrator.p.Ya.F_turb) .= parent(field) +end +function update_field!(sim::EisenmanIceSimulation, ::Val{:radiative_energy_flux}, field) + parent(sim.integrator.p.Ya.F_rad) .= parent(field) +end +function update_field!(sim::EisenmanIceSimulation, ::Val{:air_density}, field) + parent(sim.integrator.p.Ya.ρ_sfc) .= parent(field) +end + +# extensions required by FieldExchanger +step!(sim::EisenmanIceSimulation, t) = step!(sim.integrator, t - sim.integrator.t, true) +reinit!(sim::EisenmanIceSimulation) = reinit!(sim.integrator) + +# extensions required by FluxCalculator (partitioned fluxes) +function update_turbulent_fluxes_point!(sim::EisenmanIceSimulation, fields::NamedTuple, colidx::Fields.ColumnIndex) + (; F_turb_energy) = fields + @. sim.integrator.p.Ya.F_turb[colidx] = F_turb_energy +end + +""" + get_model_state_vector(sim::EisenmanIceSimulation) + +Extension of Checkpointer.get_model_state_vector to get the model state. +""" +function get_model_state_vector(sim::EisenmanIceSimulation) + return sim.integrator.u +end + +""" + differentiate_turbulent_fluxes!(sim::EisenmanIceSimulation, args) + +Extension of differentiate_turbulent_fluxes! from FluxCalculator to get the turbulent fluxes. +""" +differentiate_turbulent_fluxes!(sim::EisenmanIceSimulation, args) = + differentiate_turbulent_fluxes!(sim::EisenmanIceSimulation, args..., ΔT_sfc = 0.1) + +function update_field!(sim::EisenmanIceSimulation, ::Val{:∂F_turb_energy∂T_sfc}, field, colidx) + sim.integrator.p.Ya.∂F_turb_energy∂T_sfc[colidx] .= field +end + + +""" + get_field(sim::EisenmanIceSimulation, ::Val{:energy}) + +Extension of Interfacer.get_field to get the energy of the ocean. +It is the sum of the heat content of the mixed layer, the heat content of the ice, the heat flux from the ocean below ice. +""" +function get_field(sim::EisenmanIceSimulation, ::Val{:energy}) + p_i = sim.integrator.p.params.p_i + p_o = sim.integrator.p.params.p_o + C0_base = p_i.C0_base + T_base = p_i.T_base + L_ice = p_i.L_ice + T_freeze = p_i.T_freeze + k_ice = p_i.k_ice + ocean_qflux = sim.integrator.p.Ya.ocean_qflux + + cache = sim.integrator.p + Δt = cache.Δt + e_base = cache.Ya.e_base + ocean_qflux = cache.Ya.ocean_qflux + + hρc_ml = p_o.h * p_o.ρ * p_o.c + + e_ml = @. p_o.h * p_o.ρ * p_o.c * sim.integrator.u.T_ml # heat + e_ice = @. p_i.L_ice * sim.integrator.u.h_ice # phase + e_qflux = @. ocean_qflux * sim.integrator.t + + return @. e_ml + e_ice + e_qflux + e_base + +end + +get_field(sim::EisenmanIceSimulation, ::Val{:water}) = nothing diff --git a/experiments/AMIP/modular/components/slab_utils.jl b/experiments/AMIP/modular/components/slab_utils.jl index f59ca37915..3cdb9d61b9 100644 --- a/experiments/AMIP/modular/components/slab_utils.jl +++ b/experiments/AMIP/modular/components/slab_utils.jl @@ -1,11 +1,3 @@ -""" - get_slab_energy(slab_sim, T_sfc) - -Returns the internal energy per unit area of the slab. -""" -get_slab_energy(slab_sim, T_sfc) = - slab_sim.integrator.p.params.ρ .* slab_sim.integrator.p.params.c .* T_sfc .* slab_sim.integrator.p.params.h - """ weighted_dss_slab!(Y::ClimaCore.Fields.FieldVector, p::NamedTuple, _) diff --git a/experiments/AMIP/modular/coupler_driver_modular.jl b/experiments/AMIP/modular/coupler_driver_modular.jl index e83f47bf85..f4ad4d7275 100644 --- a/experiments/AMIP/modular/coupler_driver_modular.jl +++ b/experiments/AMIP/modular/coupler_driver_modular.jl @@ -111,6 +111,7 @@ include("components/land/bucket_init.jl") include("components/land/bucket_utils.jl") include("components/ocean/slab_ocean_init.jl") include("components/ocean/prescr_seaice_init.jl") +include("components/ocean/eisenman_seaice_init.jl") ## helpers for user-specified IO include("user_io/user_diagnostics.jl") @@ -316,6 +317,31 @@ elseif mode_name == "slabplanet" thermo_params = thermo_params, )) + mode_specifics = (; name = mode_name, SST_info = nothing, SIC_info = nothing) + +elseif mode_name == "slabplanet_eisenman" + ## ocean + ocean_sim = ocean_init( + FT; + tspan = tspan, + dt = Δt_cpl, + space = boundary_space, + saveat = saveat, + area_fraction = ClimaCore.Fields.zeros(boundary_space), # zero, since ML is calculated below + thermo_params = thermo_params, + ) + + ## sea ice (here set to zero area coverage) + ice_sim = eisenman_seaice_init( + FT, + tspan, + space = boundary_space, + area_fraction = (FT(1) .- land_fraction), + dt = Δt_cpl, + saveat = saveat, + thermo_params = thermo_params, + ) + mode_specifics = (; name = mode_name, SST_info = nothing, SIC_info = nothing) end @@ -384,7 +410,7 @@ diagnostics = (monthly_3d_diags, monthly_2d_diags) conservation_checks = nothing if energy_check @assert( - mode_name == "slabplanet" && !CA.is_distributed(ClimaComms.context(boundary_space)), + mode_name[1:10] == "slabplanet" && !CA.is_distributed(ClimaComms.context(boundary_space)), "Only non-distributed slabplanet allowable for energy_check" ) conservation_checks = (; energy = EnergyConservationCheck(model_sims), water = WaterConservationCheck(model_sims)) @@ -577,7 +603,7 @@ Currently all postprocessing is performed using the root process only. if ClimaComms.iamroot(comms_ctx) ## energy check plots - if !isnothing(cs.conservation_checks) && cs.mode.name == "slabplanet" + if !isnothing(cs.conservation_checks) && cs.mode.name[1:10] == "slabplanet" @info "Conservation Check Plots" plot_global_conservation( cs.conservation_checks.energy, diff --git a/experiments/AMIP/modular/user_io/viz_explorer.jl b/experiments/AMIP/modular/user_io/viz_explorer.jl index a366dad0c3..765d56e052 100644 --- a/experiments/AMIP/modular/user_io/viz_explorer.jl +++ b/experiments/AMIP/modular/user_io/viz_explorer.jl @@ -21,7 +21,6 @@ function plot_anim(cs, out_dir = ".") anim = Plots.@animate for u in sol_atm.u Plots.plot(Fields.level(u.c.ρe_tot, 1) .- Fields.level(sol_atm.u[1].c.ρe_tot, 1), clims = (-5000, 50000)) - println(parent(Fields.level(u.c.ρe_tot, 1) .- Fields.level(sol_atm.u[1].c.ρe_tot, 1))[1]) end Plots.mp4(anim, joinpath(out_dir, "anim_rhoe_anom.mp4"), fps = 10) @@ -45,6 +44,17 @@ function plot_anim(cs, out_dir = ".") ) Plots.plot(combined_field) end + elseif mode_name == "slabplanet_eisenman" + slab_ice_sim = slab_ice_sim.integrator.sol + anim = Plots.@animate for (bucketu, iceu) in zip(sol_slab.u, slab_ice_sim.u) + land_T_sfc = get_land_temp_from_state(cs.model_sims.land_sim, bucketu) + combine_surfaces_from_sol!( + combined_field, + cs.surface_fractions, + (; land = land_T_sfc, ocean = FT(0), ice = iceu.T_sfc), + ) + Plots.plot(combined_field) + end elseif mode_name == "amip" sol_slab_ice = slab_ice_sim.integrator.sol @@ -82,6 +92,19 @@ function plot_anim(cs, out_dir = ".") end Plots.mp4(anim, joinpath(out_dir, "bucket_snow.mp4"), fps = 10) + if mode_name == "slabplanet_eisenman" + sol_ice = cs.model_sims.ice_sim.integrator.sol + combined_field = zeros(boundary_space) + anim = Plots.@animate for sol_iceu in sol_ice.u + combine_surfaces_from_sol!( + combined_field, + cs.surface_fractions, + (; land = 0.0, ocean = 0.0, ice = sol_iceu.h_ice), + ) + Plots.plot(combined_field) + end + Plots.mp4(anim, joinpath(out_dir, "eisenman_seaice.mp4"), fps = 10) + end # plot surface fluxes # TODO as part of the flux accumulation PR end diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/Manifest.toml b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/Manifest.toml deleted file mode 100644 index 8b285e6ceb..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/Manifest.toml +++ /dev/null @@ -1,1678 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -julia_version = "1.7.1" -manifest_format = "2.0" - -[[deps.AbstractFFTs]] -deps = ["ChainRulesCore", "LinearAlgebra"] -git-tree-sha1 = "6f1d9bc1c08f9f4a8fa92e3ea3cb50153a1b40d4" -uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" -version = "1.1.0" - -[[deps.AbstractTrees]] -git-tree-sha1 = "03e0550477d86222521d254b741d470ba17ea0b5" -uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" -version = "0.3.4" - -[[deps.Adapt]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "af92965fb30777147966f58acb05da51c5616b5f" -uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "3.3.3" - -[[deps.ArgTools]] -uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" - -[[deps.ArnoldiMethod]] -deps = ["LinearAlgebra", "Random", "StaticArrays"] -git-tree-sha1 = "62e51b39331de8911e4a7ff6f5aaf38a5f4cc0ae" -uuid = "ec485272-7323-5ecc-a04f-4719b315124d" -version = "0.2.0" - -[[deps.ArrayInterface]] -deps = ["Compat", "IfElse", "LinearAlgebra", "Requires", "SparseArrays", "Static"] -git-tree-sha1 = "1ee88c4c76caa995a885dc2f22a5d548dfbbc0ba" -uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "3.2.2" - -[[deps.ArrayLayouts]] -deps = ["FillArrays", "LinearAlgebra", "SparseArrays"] -git-tree-sha1 = "c23473c60476e62579c077534b9643ec400f792b" -uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" -version = "0.8.6" - -[[deps.Artifacts]] -uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" - -[[deps.BFloat16s]] -deps = ["LinearAlgebra", "Printf", "Random", "Test"] -git-tree-sha1 = "a598ecb0d717092b5539dbbe890c98bac842b072" -uuid = "ab4f0b2a-ad5b-11e8-123f-65d77653426b" -version = "0.2.0" - -[[deps.Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[deps.BitTwiddlingConvenienceFunctions]] -deps = ["Static"] -git-tree-sha1 = "28bbdbf0354959db89358d1d79d421ff31ef0b5e" -uuid = "62783981-4cbd-42fc-bca8-16325de8dc4b" -version = "0.1.3" - -[[deps.BlockArrays]] -deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra"] -git-tree-sha1 = "18f1eda0090a516927c5bede54c1ea36b5bf13d5" -uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -version = "0.16.16" - -[[deps.Bzip2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2" -uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" -version = "1.0.8+0" - -[[deps.CEnum]] -git-tree-sha1 = "eb4cb44a499229b3b8426dcfb5dd85333951ff90" -uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" -version = "0.4.2" - -[[deps.CFTime]] -deps = ["Dates", "Printf"] -git-tree-sha1 = "ed2e76c1c3c43fd9d0cb9248674620b29d71f2d1" -uuid = "179af706-886a-5703-950a-314cd64e0468" -version = "0.1.2" - -[[deps.CLIMAParameters]] -deps = ["Test"] -git-tree-sha1 = "17ece0add9940728f8120a1561fc3361be6a6f26" -uuid = "6eacf6c3-8458-43b9-ae03-caf5306d3d53" -version = "0.4.3" - -[[deps.CPUSummary]] -deps = ["CpuId", "IfElse", "Static"] -git-tree-sha1 = "0eaf4aedad5ccc3e39481db55d72973f856dc564" -uuid = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" -version = "0.1.22" - -[[deps.CUDA]] -deps = ["AbstractFFTs", "Adapt", "BFloat16s", "CEnum", "CompilerSupportLibraries_jll", "ExprTools", "GPUArrays", "GPUCompiler", "LLVM", "LazyArtifacts", "Libdl", "LinearAlgebra", "Logging", "Printf", "Random", "Random123", "RandomNumbers", "Reexport", "Requires", "SparseArrays", "SpecialFunctions", "TimerOutputs"] -git-tree-sha1 = "19fb33957a5f85efb3cc10e70cf4dd4e30174ac9" -uuid = "052768ef-5323-5732-b1bb-66c8b64840ba" -version = "3.10.0" - -[[deps.Cairo_jll]] -deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2" -uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" -version = "1.16.1+1" - -[[deps.Calculus]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" -uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9" -version = "0.5.1" - -[[deps.Cassette]] -git-tree-sha1 = "063b2e77c5537a548c5bf2f44161f1d3e1ab3227" -uuid = "7057c7e9-c182-5462-911a-8362d720325c" -version = "0.3.10" - -[[deps.ChainRulesCore]] -deps = ["Compat", "LinearAlgebra", "SparseArrays"] -git-tree-sha1 = "9950387274246d08af38f6eef8cb5480862a435f" -uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.14.0" - -[[deps.ChangesOfVariables]] -deps = ["ChainRulesCore", "LinearAlgebra", "Test"] -git-tree-sha1 = "1e315e3f4b0b7ce40feded39c73049692126cf53" -uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" -version = "0.1.3" - -[[deps.ClimaAtmos]] -deps = ["CLIMAParameters", "ClimaCore", "ClimaCorePlots", "ClimaCoreVTK", "CloudMicrophysics", "DiffEqCallbacks", "IntervalSets", "JLD2", "LinearAlgebra", "OrdinaryDiffEq", "Pkg", "Printf", "StaticArrays", "Test", "Thermodynamics", "UnPack"] -path = "/Users/lenkanovak/ClimaCoupler.jl/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/../../../../ClimaAtmos.jl_cpl/" -uuid = "b2c96348-7fb7-4fe0-8da9-78d88439e717" -version = "0.1.0" - -[[deps.ClimaComms]] -deps = ["CUDA", "KernelAbstractions", "StaticArrays"] -git-tree-sha1 = "50fbb76557f11e28ec21ad2fbe5e7547f1b1f432" -uuid = "3a4d1b5c-c61d-41fd-a00a-5873ba7a1b0d" -version = "0.3.0" - -[[deps.ClimaCommsMPI]] -deps = ["ClimaComms", "KernelAbstractions", "MPI"] -git-tree-sha1 = "2a1857a51eab7e1b15dd709ccef3c3ccabd7a6f6" -uuid = "5f86816e-8b66-43b2-912e-75384f99de49" -version = "0.3.2" - -[[deps.ClimaCore]] -deps = ["Adapt", "BlockArrays", "CUDA", "ClimaComms", "CubedSphere", "DataStructures", "DiffEqBase", "DocStringExtensions", "ForwardDiff", "GaussQuadrature", "InteractiveUtils", "IntervalSets", "LinearAlgebra", "RecursiveArrayTools", "RootSolvers", "Rotations", "SparseArrays", "Static", "StaticArrays", "Statistics", "UnPack"] -git-tree-sha1 = "fc27777d9e4166ee5a195af715e0484d2dd85ed6" -uuid = "d414da3d-4745-48bb-8d80-42e94e092884" -version = "0.10.3" - -[[deps.ClimaCorePlots]] -deps = ["ClimaCore", "RecipesBase", "StaticArrays", "TriplotBase"] -git-tree-sha1 = "fb369432478d010ba9a2bd06b288d7a40467903b" -uuid = "cf7c7e5a-b407-4c48-9047-11a94a308626" -version = "0.2.3" - -[[deps.ClimaCoreTempestRemap]] -deps = ["ClimaCore", "Dates", "LinearAlgebra", "NCDatasets", "PkgVersion", "TempestRemap_jll", "Test"] -git-tree-sha1 = "f70e2666a48c38bc95cb40d5cc99bedc0dc8b0e3" -uuid = "d934ef94-cdd4-4710-83d6-720549644b70" -version = "0.3.3" - -[[deps.ClimaCoreVTK]] -deps = ["ClimaCore", "WriteVTK"] -git-tree-sha1 = "2a0f6f12ccdf50089e708b68e73b1fe08fb53cd8" -uuid = "c8b6d40d-e815-466f-95ae-c48aefa668fa" -version = "0.7.1" - -[[deps.CloseOpenIntervals]] -deps = ["ArrayInterface", "Static"] -git-tree-sha1 = "f576084239e6bdf801007c80e27e2cc2cd963fe0" -uuid = "fb6a15b2-703c-40df-9091-08a04967cfa9" -version = "0.1.6" - -[[deps.CloudMicrophysics]] -deps = ["CLIMAParameters", "DocStringExtensions", "SpecialFunctions", "Thermodynamics"] -git-tree-sha1 = "25d3f2d97cfae8b2326a7bb2f37fb274d2df0a73" -uuid = "6a9e3e04-43cd-43ba-94b9-e8782df3c71b" -version = "0.4.0" - -[[deps.CodecZlib]] -deps = ["TranscodingStreams", "Zlib_jll"] -git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da" -uuid = "944b1d66-785c-5afd-91f1-9de20f533193" -version = "0.7.0" - -[[deps.ColorSchemes]] -deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Random"] -git-tree-sha1 = "7297381ccb5df764549818d9a7d57e45f1057d30" -uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" -version = "3.18.0" - -[[deps.ColorTypes]] -deps = ["FixedPointNumbers", "Random"] -git-tree-sha1 = "a985dc37e357a3b22b260a5def99f3530fb415d3" -uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" -version = "0.11.2" - -[[deps.ColorVectorSpace]] -deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"] -git-tree-sha1 = "3f1f500312161f1ae067abe07d13b40f78f32e07" -uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" -version = "0.9.8" - -[[deps.Colors]] -deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] -git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" -uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" -version = "0.12.8" - -[[deps.CommonSolve]] -git-tree-sha1 = "68a0743f578349ada8bc911a5cbd5a2ef6ed6d1f" -uuid = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2" -version = "0.2.0" - -[[deps.CommonSubexpressions]] -deps = ["MacroTools", "Test"] -git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" -uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" -version = "0.3.0" - -[[deps.Compat]] -deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] -git-tree-sha1 = "b153278a25dd42c65abbf4e62344f9d22e59191b" -uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "3.43.0" - -[[deps.CompilerSupportLibraries_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" - -[[deps.ConstructionBase]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "f74e9d5388b8620b4cee35d4c5a618dd4dc547f4" -uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" -version = "1.3.0" - -[[deps.Contour]] -deps = ["StaticArrays"] -git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7" -uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" -version = "0.5.7" - -[[deps.CpuId]] -deps = ["Markdown"] -git-tree-sha1 = "fcbb72b032692610bfbdb15018ac16a36cf2e406" -uuid = "adafc99b-e345-5852-983c-f28acb93d879" -version = "0.3.1" - -[[deps.CubedSphere]] -deps = ["Elliptic", "Printf", "Rotations", "TaylorSeries", "Test"] -git-tree-sha1 = "f66fabd1ee5df59a7ba47c7873a6332c19e0c03f" -uuid = "7445602f-e544-4518-8976-18f8e8ae6cdb" -version = "0.2.0" - -[[deps.DEDataArrays]] -deps = ["ArrayInterface", "DocStringExtensions", "LinearAlgebra", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] -git-tree-sha1 = "5e5f8f363c8c9a2415ef9185c4e0ff6966c87d52" -uuid = "754358af-613d-5f8d-9788-280bf1605d4c" -version = "0.2.2" - -[[deps.DataAPI]] -git-tree-sha1 = "fb5f5316dd3fd4c5e7c30a24d50643b73e37cd40" -uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" -version = "1.10.0" - -[[deps.DataStructures]] -deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "cc1a8e22627f33c789ab60b36a9132ac050bbf75" -uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.12" - -[[deps.DataValueInterfaces]] -git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" -uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" -version = "1.0.0" - -[[deps.Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" - -[[deps.DelimitedFiles]] -deps = ["Mmap"] -uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" - -[[deps.DensityInterface]] -deps = ["InverseFunctions", "Test"] -git-tree-sha1 = "80c3e8639e3353e5d2912fb3a1916b8455e2494b" -uuid = "b429d917-457f-4dbc-8f4c-0cc954292b1d" -version = "0.4.0" - -[[deps.DiffEqBase]] -deps = ["ArrayInterface", "ChainRulesCore", "DEDataArrays", "DataStructures", "Distributions", "DocStringExtensions", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "IterativeSolvers", "LabelledArrays", "LinearAlgebra", "Logging", "MuladdMacro", "NonlinearSolve", "Parameters", "PreallocationTools", "Printf", "RecursiveArrayTools", "RecursiveFactorization", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "StaticArrays", "Statistics", "SuiteSparse", "ZygoteRules"] -git-tree-sha1 = "bd3812f2be255da87a2438c3b87a0a478cdbd050" -uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.84.0" - -[[deps.DiffEqCallbacks]] -deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "NLsolve", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] -git-tree-sha1 = "cfef2afe8d73ed2d036b0e4b14a3f9b53045c534" -uuid = "459566f4-90b8-5000-8ac3-15dfb0a30def" -version = "2.23.1" - -[[deps.DiffResults]] -deps = ["StaticArrays"] -git-tree-sha1 = "c18e98cba888c6c25d1c3b048e4b3380ca956805" -uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" -version = "1.0.3" - -[[deps.DiffRules]] -deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] -git-tree-sha1 = "28d605d9a0ac17118fe2c5e9ce0fbb76c3ceb120" -uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" -version = "1.11.0" - -[[deps.Distances]] -deps = ["LinearAlgebra", "SparseArrays", "Statistics", "StatsAPI"] -git-tree-sha1 = "3258d0659f812acde79e8a74b11f17ac06d0ca04" -uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" -version = "0.10.7" - -[[deps.Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" - -[[deps.Distributions]] -deps = ["ChainRulesCore", "DensityInterface", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "Test"] -git-tree-sha1 = "8a6b49396a4058771c5c072239b2e0a76e2e898c" -uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" -version = "0.25.58" - -[[deps.DocStringExtensions]] -deps = ["LibGit2"] -git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b" -uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.6" - -[[deps.Downloads]] -deps = ["ArgTools", "LibCURL", "NetworkOptions"] -uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" - -[[deps.DualNumbers]] -deps = ["Calculus", "NaNMath", "SpecialFunctions"] -git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566" -uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" -version = "0.6.8" - -[[deps.EarCut_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d" -uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" -version = "2.2.3+0" - -[[deps.Elliptic]] -git-tree-sha1 = "71c79e77221ab3a29918aaf6db4f217b89138608" -uuid = "b305315f-e792-5b7a-8f41-49f472929428" -version = "1.0.1" - -[[deps.Expat_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "bad72f730e9e91c08d9427d5e8db95478a3c323d" -uuid = "2e619515-83b5-522b-bb60-26c02a35a201" -version = "2.4.8+0" - -[[deps.ExponentialUtilities]] -deps = ["ArrayInterface", "GPUArrays", "GenericSchur", "LinearAlgebra", "Printf", "SparseArrays", "libblastrampoline_jll"] -git-tree-sha1 = "8173af6a65279017e564121ce940bb84ca9a35c9" -uuid = "d4d017d3-3776-5f7e-afef-a10c40355c18" -version = "1.16.0" - -[[deps.ExprTools]] -git-tree-sha1 = "56559bbef6ca5ea0c0818fa5c90320398a6fbf8d" -uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" -version = "0.1.8" - -[[deps.FFMPEG]] -deps = ["FFMPEG_jll"] -git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" -uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" -version = "0.4.1" - -[[deps.FFMPEG_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] -git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f" -uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" -version = "4.4.0+0" - -[[deps.FastBroadcast]] -deps = ["LinearAlgebra", "Polyester", "Static"] -git-tree-sha1 = "b6bf57ec7a3f294c97ae46124705a9e6b906a209" -uuid = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -version = "0.1.15" - -[[deps.FastClosures]] -git-tree-sha1 = "acebe244d53ee1b461970f8910c235b259e772ef" -uuid = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" -version = "0.3.2" - -[[deps.FileIO]] -deps = ["Pkg", "Requires", "UUIDs"] -git-tree-sha1 = "9267e5f50b0e12fdfd5a2455534345c4cf2c7f7a" -uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" -version = "1.14.0" - -[[deps.FillArrays]] -deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"] -git-tree-sha1 = "246621d23d1f43e3b9c368bf3b72b2331a27c286" -uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" -version = "0.13.2" - -[[deps.FiniteDiff]] -deps = ["ArrayInterface", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays"] -git-tree-sha1 = "51c8f36c81badaa0e9ec405dcbabaf345ed18c84" -uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" -version = "2.11.1" - -[[deps.FixedPointNumbers]] -deps = ["Statistics"] -git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" -uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" -version = "0.8.4" - -[[deps.Fontconfig_jll]] -deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03" -uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" -version = "2.13.93+0" - -[[deps.Formatting]] -deps = ["Printf"] -git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" -uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" -version = "0.4.2" - -[[deps.ForwardDiff]] -deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions", "StaticArrays"] -git-tree-sha1 = "2f18915445b248731ec5db4e4a17e451020bf21e" -uuid = "f6369f11-7733-5829-9624-2563aa707210" -version = "0.10.30" - -[[deps.FreeType2_jll]] -deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] -git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9" -uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" -version = "2.10.4+0" - -[[deps.FriBidi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" -uuid = "559328eb-81f9-559d-9380-de523a88c83c" -version = "1.0.10+0" - -[[deps.FunctionWrappers]] -git-tree-sha1 = "241552bc2209f0fa068b6415b1942cc0aa486bcc" -uuid = "069b7b12-0de2-55c6-9aab-29f3d0a68a2e" -version = "1.1.2" - -[[deps.Future]] -deps = ["Random"] -uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" - -[[deps.GLFW_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] -git-tree-sha1 = "51d2dfe8e590fbd74e7a842cf6d13d8a2f45dc01" -uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" -version = "3.3.6+0" - -[[deps.GPUArrays]] -deps = ["Adapt", "LLVM", "LinearAlgebra", "Printf", "Random", "Serialization", "Statistics"] -git-tree-sha1 = "c783e8883028bf26fb05ed4022c450ef44edd875" -uuid = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7" -version = "8.3.2" - -[[deps.GPUCompiler]] -deps = ["ExprTools", "InteractiveUtils", "LLVM", "Libdl", "Logging", "TimerOutputs", "UUIDs"] -git-tree-sha1 = "d8c5999631e1dc18d767883f621639c838f8e632" -uuid = "61eb1bfa-7361-4325-ad38-22787b887f55" -version = "0.15.2" - -[[deps.GR]] -deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "RelocatableFolders", "Serialization", "Sockets", "Test", "UUIDs"] -git-tree-sha1 = "b316fd18f5bc025fedcb708332aecb3e13b9b453" -uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" -version = "0.64.3" - -[[deps.GR_jll]] -deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "1e5490a51b4e9d07e8b04836f6008f46b48aaa87" -uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" -version = "0.64.3+0" - -[[deps.GaussQuadrature]] -deps = ["SpecialFunctions"] -git-tree-sha1 = "eb6f1f48aa994f3018cbd029a17863c6535a266d" -uuid = "d54b0c1a-921d-58e0-8e36-89d8069c0969" -version = "0.5.8" - -[[deps.GenericSchur]] -deps = ["LinearAlgebra", "Printf"] -git-tree-sha1 = "fb69b2a645fa69ba5f474af09221b9308b160ce6" -uuid = "c145ed77-6b09-5dd9-b285-bf645a82121e" -version = "0.5.3" - -[[deps.GeometryBasics]] -deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] -git-tree-sha1 = "83ea630384a13fc4f002b77690bc0afeb4255ac9" -uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" -version = "0.4.2" - -[[deps.Gettext_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] -git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" -uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" -version = "0.21.0+0" - -[[deps.Glib_jll]] -deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "a32d672ac2c967f3deb8a81d828afc739c838a06" -uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" -version = "2.68.3+2" - -[[deps.Graphite2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" -uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" -version = "1.3.14+0" - -[[deps.Graphs]] -deps = ["ArnoldiMethod", "Compat", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"] -git-tree-sha1 = "57c021de207e234108a6f1454003120a1bf350c4" -uuid = "86223c79-3864-5bf0-83f7-82e725a168b6" -version = "1.6.0" - -[[deps.Grisu]] -git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" -uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" -version = "1.0.2" - -[[deps.HDF5_jll]] -deps = ["Artifacts", "JLLWrappers", "LibCURL_jll", "Libdl", "OpenSSL_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "bab67c0d1c4662d2c4be8c6007751b0b6111de5c" -uuid = "0234f1f7-429e-5d53-9886-15a909be8d59" -version = "1.12.1+0" - -[[deps.HTTP]] -deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] -git-tree-sha1 = "0fa77022fe4b511826b39c894c90daf5fce3334a" -uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" -version = "0.9.17" - -[[deps.HarfBuzz_jll]] -deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] -git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" -uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" -version = "2.8.1+1" - -[[deps.HostCPUFeatures]] -deps = ["BitTwiddlingConvenienceFunctions", "IfElse", "Libdl", "Static"] -git-tree-sha1 = "18be5268cf415b5e27f34980ed25a7d34261aa83" -uuid = "3e5b6fbb-0976-4d2c-9146-d79de83f2fb0" -version = "0.1.7" - -[[deps.Hwloc]] -deps = ["Hwloc_jll"] -git-tree-sha1 = "92d99146066c5c6888d5a3abc871e6a214388b91" -uuid = "0e44f5e4-bd66-52a0-8798-143a42290a1d" -version = "2.0.0" - -[[deps.Hwloc_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "303d70c961317c4c20fafaf5dbe0e6d610c38542" -uuid = "e33a78d0-f292-5ffc-b300-72abe9b543c8" -version = "2.7.1+0" - -[[deps.HypergeometricFunctions]] -deps = ["DualNumbers", "LinearAlgebra", "SpecialFunctions", "Test"] -git-tree-sha1 = "cb7099a0109939f16a4d3b572ba8396b1f6c7c31" -uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" -version = "0.3.10" - -[[deps.IfElse]] -git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1" -uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" -version = "0.1.1" - -[[deps.Inflate]] -git-tree-sha1 = "f5fc07d4e706b84f72d54eedcc1c13d92fb0871c" -uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" -version = "0.1.2" - -[[deps.IniFile]] -git-tree-sha1 = "f550e6e32074c939295eb5ea6de31849ac2c9625" -uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f" -version = "0.5.1" - -[[deps.InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[deps.IntervalSets]] -deps = ["Dates", "Statistics"] -git-tree-sha1 = "ad841eddfb05f6d9be0bff1fa48dcae32f134a2d" -uuid = "8197267c-284f-5f27-9208-e0e47529a953" -version = "0.6.2" - -[[deps.InverseFunctions]] -deps = ["Test"] -git-tree-sha1 = "336cc738f03e069ef2cac55a104eb823455dca75" -uuid = "3587e190-3f89-42d0-90ee-14403ec27112" -version = "0.1.4" - -[[deps.IrrationalConstants]] -git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" -uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" -version = "0.1.1" - -[[deps.IterTools]] -git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5" -uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" -version = "1.4.0" - -[[deps.IterativeSolvers]] -deps = ["LinearAlgebra", "Printf", "Random", "RecipesBase", "SparseArrays"] -git-tree-sha1 = "1169632f425f79429f245113b775a0e3d121457c" -uuid = "42fd0dbc-a981-5370-80f2-aaf504508153" -version = "0.9.2" - -[[deps.IteratorInterfaceExtensions]] -git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" -uuid = "82899510-4779-5014-852e-03e436cf321d" -version = "1.0.0" - -[[deps.JLD2]] -deps = ["FileIO", "MacroTools", "Mmap", "OrderedCollections", "Pkg", "Printf", "Reexport", "TranscodingStreams", "UUIDs"] -git-tree-sha1 = "81b9477b49402b47fbe7f7ae0b252077f53e4a08" -uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -version = "0.4.22" - -[[deps.JLLWrappers]] -deps = ["Preferences"] -git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" -uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" -version = "1.4.1" - -[[deps.JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.3" - -[[deps.JpegTurbo_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "b53380851c6e6664204efb2e62cd24fa5c47e4ba" -uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" -version = "2.1.2+0" - -[[deps.KernelAbstractions]] -deps = ["Adapt", "Cassette", "InteractiveUtils", "MacroTools", "SpecialFunctions", "StaticArrays", "UUIDs"] -git-tree-sha1 = "cb7d8b805413025a5bc866fc036b426223ffc059" -uuid = "63c18a36-062a-441e-b654-da1e3ab1ce7c" -version = "0.7.2" - -[[deps.LAME_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" -uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" -version = "3.100.1+0" - -[[deps.LERC_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434" -uuid = "88015f11-f218-50d7-93a8-a6af411a945d" -version = "3.0.0+1" - -[[deps.LLVM]] -deps = ["CEnum", "LLVMExtra_jll", "Libdl", "Printf", "Unicode"] -git-tree-sha1 = "c8d47589611803a0f3b4813d9e267cd4e3dbcefb" -uuid = "929cbde3-209d-540e-8aea-75f648917ca0" -version = "4.11.1" - -[[deps.LLVMExtra_jll]] -deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg", "TOML"] -git-tree-sha1 = "771bfe376249626d3ca12bcd58ba243d3f961576" -uuid = "dad2f222-ce93-54a1-a47d-0025e8a3acab" -version = "0.0.16+0" - -[[deps.LZO_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" -uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" -version = "2.10.1+0" - -[[deps.LaTeXStrings]] -git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" -uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" -version = "1.3.0" - -[[deps.LabelledArrays]] -deps = ["ArrayInterface", "ChainRulesCore", "LinearAlgebra", "MacroTools", "StaticArrays"] -git-tree-sha1 = "1cccf6d366e51fbaf80303158d49bb2171acfeee" -uuid = "2ee39098-c373-598a-b85f-a56591580800" -version = "1.9.0" - -[[deps.Latexify]] -deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"] -git-tree-sha1 = "46a39b9c58749eefb5f2dc1178cb8fab5332b1ab" -uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" -version = "0.15.15" - -[[deps.LayoutPointers]] -deps = ["ArrayInterface", "LinearAlgebra", "ManualMemory", "SIMDTypes", "Static"] -git-tree-sha1 = "b651f573812d6c36c22c944dd66ef3ab2283dfa1" -uuid = "10f19ff3-798f-405d-979b-55457f8fc047" -version = "0.1.6" - -[[deps.LazyArtifacts]] -deps = ["Artifacts", "Pkg"] -uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" - -[[deps.LeftChildRightSiblingTrees]] -deps = ["AbstractTrees"] -git-tree-sha1 = "b864cb409e8e445688bc478ef87c0afe4f6d1f8d" -uuid = "1d6d02ad-be62-4b6b-8a6d-2f90e265016e" -version = "0.1.3" - -[[deps.LibCURL]] -deps = ["LibCURL_jll", "MozillaCACerts_jll"] -uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" - -[[deps.LibCURL_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] -uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" - -[[deps.LibGit2]] -deps = ["Base64", "NetworkOptions", "Printf", "SHA"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" - -[[deps.LibSSH2_jll]] -deps = ["Artifacts", "Libdl", "MbedTLS_jll"] -uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" - -[[deps.Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" - -[[deps.Libffi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" -uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" -version = "3.2.2+1" - -[[deps.Libgcrypt_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] -git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" -uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" -version = "1.8.7+0" - -[[deps.Libglvnd_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] -git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf" -uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" -version = "1.3.0+3" - -[[deps.Libgpg_error_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" -uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" -version = "1.42.0+0" - -[[deps.Libiconv_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778" -uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" -version = "1.16.1+1" - -[[deps.Libmount_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" -uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" -version = "2.35.0+0" - -[[deps.Libtiff_jll]] -deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] -git-tree-sha1 = "c9551dd26e31ab17b86cbd00c2ede019c08758eb" -uuid = "89763e89-9b03-5906-acba-b20f662cd828" -version = "4.3.0+1" - -[[deps.Libuuid_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" -uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" -version = "2.36.0+0" - -[[deps.LightXML]] -deps = ["Libdl", "XML2_jll"] -git-tree-sha1 = "e129d9391168c677cd4800f5c0abb1ed8cb3794f" -uuid = "9c8b4983-aa76-5018-a973-4c85ecc9e179" -version = "0.9.0" - -[[deps.LineSearches]] -deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] -git-tree-sha1 = "f27132e551e959b3667d8c93eae90973225032dd" -uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" -version = "7.1.1" - -[[deps.LinearAlgebra]] -deps = ["Libdl", "libblastrampoline_jll"] -uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" - -[[deps.LogExpFunctions]] -deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] -git-tree-sha1 = "09e4b894ce6a976c354a69041a04748180d43637" -uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" -version = "0.3.15" - -[[deps.Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[deps.LoopVectorization]] -deps = ["ArrayInterface", "CPUSummary", "ChainRulesCore", "CloseOpenIntervals", "DocStringExtensions", "ForwardDiff", "HostCPUFeatures", "IfElse", "LayoutPointers", "LinearAlgebra", "OffsetArrays", "PolyesterWeave", "SIMDDualNumbers", "SLEEFPirates", "SpecialFunctions", "Static", "ThreadingUtilities", "UnPack", "VectorizationBase"] -git-tree-sha1 = "4392c19f0203df81512b6790a0a67446650bdce0" -uuid = "bdcacae8-1622-11e9-2a5c-532679323890" -version = "0.12.110" - -[[deps.MPI]] -deps = ["Distributed", "DocStringExtensions", "Libdl", "MPICH_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "Pkg", "Random", "Requires", "Serialization", "Sockets"] -git-tree-sha1 = "d56a80d8cf8b9dc3050116346b3d83432b1912c0" -uuid = "da04e1cc-30fd-572f-bb4f-1f8673147195" -version = "0.19.2" - -[[deps.MPICH_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "Pkg", "TOML"] -git-tree-sha1 = "089ec72dbf7d7a853626f438d140d0a642ddbda4" -uuid = "7cb0a576-ebde-5e09-9194-50597f1243b4" -version = "4.0.2+4" - -[[deps.MPIPreferences]] -deps = ["Libdl", "Preferences"] -git-tree-sha1 = "49f10d34284610c125421c7a4e6f913e4bc00897" -uuid = "3da0fdf6-3ccc-4f1b-acd9-58baa6c99267" -version = "0.1.3" - -[[deps.MacroTools]] -deps = ["Markdown", "Random"] -git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf" -uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -version = "0.5.9" - -[[deps.ManualMemory]] -git-tree-sha1 = "bcaef4fc7a0cfe2cba636d84cda54b5e4e4ca3cd" -uuid = "d125e4d3-2237-4719-b19c-fa641b8a4667" -version = "0.1.8" - -[[deps.Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[deps.MbedTLS]] -deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] -git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe" -uuid = "739be429-bea8-5141-9913-cc70e7f3736d" -version = "1.0.3" - -[[deps.MbedTLS_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" - -[[deps.Measures]] -git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f" -uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" -version = "0.3.1" - -[[deps.MicrosoftMPI_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "a16aa086d335ed7e0170c5265247db29172af2f9" -uuid = "9237b28f-5490-5468-be7b-bb81f5f5e6cf" -version = "10.1.3+2" - -[[deps.Missings]] -deps = ["DataAPI"] -git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f" -uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" -version = "1.0.2" - -[[deps.Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" - -[[deps.MozillaCACerts_jll]] -uuid = "14a3606d-f60d-562e-9121-12d972cd8159" - -[[deps.MuladdMacro]] -git-tree-sha1 = "c6190f9a7fc5d9d5915ab29f2134421b12d24a68" -uuid = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -version = "0.2.2" - -[[deps.NCDatasets]] -deps = ["CFTime", "DataStructures", "Dates", "NetCDF_jll", "Printf"] -git-tree-sha1 = "17e39eb5bbe564f48bdbefbd103bd3f49fcfcb9b" -uuid = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" -version = "0.11.9" - -[[deps.NLSolversBase]] -deps = ["DiffResults", "Distributed", "FiniteDiff", "ForwardDiff"] -git-tree-sha1 = "50310f934e55e5ca3912fb941dec199b49ca9b68" -uuid = "d41bc354-129a-5804-8e4c-c37616107c6c" -version = "7.8.2" - -[[deps.NLsolve]] -deps = ["Distances", "LineSearches", "LinearAlgebra", "NLSolversBase", "Printf", "Reexport"] -git-tree-sha1 = "019f12e9a1a7880459d0173c182e6a99365d7ac1" -uuid = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" -version = "4.5.1" - -[[deps.NaNMath]] -git-tree-sha1 = "b086b7ea07f8e38cf122f5016af580881ac914fe" -uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -version = "0.3.7" - -[[deps.NetCDF_jll]] -deps = ["Artifacts", "HDF5_jll", "JLLWrappers", "LibCURL_jll", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Pkg", "Zlib_jll", "nghttp2_jll"] -git-tree-sha1 = "598f1a5e9829b3e57f233f98b34a22b376dff373" -uuid = "7243133f-43d8-5620-bbf4-c2c921802cf3" -version = "400.702.402+0" - -[[deps.NetworkOptions]] -uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" - -[[deps.NonlinearSolve]] -deps = ["ArrayInterface", "FiniteDiff", "ForwardDiff", "IterativeSolvers", "LinearAlgebra", "RecursiveArrayTools", "RecursiveFactorization", "Reexport", "SciMLBase", "Setfield", "StaticArrays", "UnPack"] -git-tree-sha1 = "aeebff6a2a23506e5029fd2248a26aca98e477b3" -uuid = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" -version = "0.3.16" - -[[deps.OffsetArrays]] -deps = ["Adapt"] -git-tree-sha1 = "e6c5f47ba51b734a4e264d7183b6750aec459fa0" -uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" -version = "1.11.1" - -[[deps.Ogg_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" -uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" -version = "1.3.5+1" - -[[deps.OpenBLAS32_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "9c6c2ed4b7acd2137b878eb96c68e63b76199d0f" -uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" -version = "0.3.17+0" - -[[deps.OpenBLAS_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] -uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" - -[[deps.OpenLibm_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "05823500-19ac-5b8b-9628-191a04bc5112" - -[[deps.OpenMPI_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "Pkg", "TOML"] -git-tree-sha1 = "6198c6dc3b5c3dc01854879197a5f382a60f947d" -uuid = "fe0851c0-eecd-5654-98d4-656369965a5c" -version = "4.1.3+1" - -[[deps.OpenSSL_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "ab05aa4cc89736e95915b01e7279e61b1bfe33b8" -uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "1.1.14+0" - -[[deps.OpenSpecFun_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" -uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" -version = "0.5.5+0" - -[[deps.Opus_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" -uuid = "91d4177d-7536-5919-b921-800302f37372" -version = "1.3.2+0" - -[[deps.OrderedCollections]] -git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" -uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.4.1" - -[[deps.OrdinaryDiffEq]] -deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DocStringExtensions", "ExponentialUtilities", "FastClosures", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "Logging", "LoopVectorization", "MacroTools", "MuladdMacro", "NLsolve", "Polyester", "PreallocationTools", "RecursiveArrayTools", "Reexport", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] -git-tree-sha1 = "e7c3b814328cce3d22dd635ca547e70a6990993a" -uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -version = "5.71.2" - -[[deps.PCRE_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488" -uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc" -version = "8.44.0+0" - -[[deps.PDMats]] -deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] -git-tree-sha1 = "027185efff6be268abbaf30cfd53ca9b59e3c857" -uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" -version = "0.11.10" - -[[deps.Parameters]] -deps = ["OrderedCollections", "UnPack"] -git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe" -uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a" -version = "0.12.3" - -[[deps.Parsers]] -deps = ["Dates"] -git-tree-sha1 = "1285416549ccfcdf0c50d4997a94331e88d68413" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.3.1" - -[[deps.Pixman_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29" -uuid = "30392449-352a-5448-841d-b1acce4e97dc" -version = "0.40.1+0" - -[[deps.Pkg]] -deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] -uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" - -[[deps.PkgVersion]] -deps = ["Pkg"] -git-tree-sha1 = "a7a7e1a88853564e551e4eba8650f8c38df79b37" -uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688" -version = "0.1.1" - -[[deps.PlotThemes]] -deps = ["PlotUtils", "Statistics"] -git-tree-sha1 = "8162b2f8547bc23876edd0c5181b27702ae58dce" -uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" -version = "3.0.0" - -[[deps.PlotUtils]] -deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"] -git-tree-sha1 = "bb16469fd5224100e422f0b027d26c5a25de1200" -uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" -version = "1.2.0" - -[[deps.Plots]] -deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "Unzip"] -git-tree-sha1 = "d457f881ea56bbfa18222642de51e0abf67b9027" -uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -version = "1.29.0" - -[[deps.Polyester]] -deps = ["ArrayInterface", "BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "ManualMemory", "PolyesterWeave", "Requires", "Static", "StrideArraysCore", "ThreadingUtilities"] -git-tree-sha1 = "0578fa5fde97f8cf19aa89f8373d92624314f547" -uuid = "f517fe37-dbe3-4b94-8317-1923a5111588" -version = "0.6.9" - -[[deps.PolyesterWeave]] -deps = ["BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "Static", "ThreadingUtilities"] -git-tree-sha1 = "7e597df97e46ffb1c8adbaddfa56908a7a20194b" -uuid = "1d0040c9-8b98-4ee7-8388-3f51789ca0ad" -version = "0.1.5" - -[[deps.PreallocationTools]] -deps = ["Adapt", "ArrayInterface", "ForwardDiff", "LabelledArrays"] -git-tree-sha1 = "6c138c8510111fa47b5d2ed8ada482d97e279bee" -uuid = "d236fae5-4411-538c-8e31-a6e3d9e00b46" -version = "0.2.4" - -[[deps.Preferences]] -deps = ["TOML"] -git-tree-sha1 = "47e5f437cc0e7ef2ce8406ce1e7e24d44915f88d" -uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.3.0" - -[[deps.Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" - -[[deps.ProgressLogging]] -deps = ["Logging", "SHA", "UUIDs"] -git-tree-sha1 = "80d919dee55b9c50e8d9e2da5eeafff3fe58b539" -uuid = "33c8b6b6-d38a-422a-b730-caa89a2f386c" -version = "0.1.4" - -[[deps.Qt5Base_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"] -git-tree-sha1 = "c6c0f690d0cc7caddb74cef7aa847b824a16b256" -uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1" -version = "5.15.3+1" - -[[deps.QuadGK]] -deps = ["DataStructures", "LinearAlgebra"] -git-tree-sha1 = "78aadffb3efd2155af139781b8a8df1ef279ea39" -uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" -version = "2.4.2" - -[[deps.Quaternions]] -deps = ["DualNumbers", "LinearAlgebra", "Random"] -git-tree-sha1 = "b327e4db3f2202a4efafe7569fcbe409106a1f75" -uuid = "94ee1d12-ae83-5a48-8b1c-48b8ff168ae0" -version = "0.5.6" - -[[deps.REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[deps.Random]] -deps = ["SHA", "Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[deps.Random123]] -deps = ["Random", "RandomNumbers"] -git-tree-sha1 = "afeacaecf4ed1649555a19cb2cad3c141bbc9474" -uuid = "74087812-796a-5b5d-8853-05524746bad3" -version = "1.5.0" - -[[deps.RandomNumbers]] -deps = ["Random", "Requires"] -git-tree-sha1 = "043da614cc7e95c703498a491e2c21f58a2b8111" -uuid = "e6cf234a-135c-5ec9-84dd-332b85af5143" -version = "1.5.3" - -[[deps.RecipesBase]] -git-tree-sha1 = "6bf3f380ff52ce0832ddd3a2a7b9538ed1bcca7d" -uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" -version = "1.2.1" - -[[deps.RecipesPipeline]] -deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"] -git-tree-sha1 = "dc1e451e15d90347a7decc4221842a022b011714" -uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" -version = "0.5.2" - -[[deps.RecursiveArrayTools]] -deps = ["Adapt", "ArrayInterface", "ChainRulesCore", "DocStringExtensions", "FillArrays", "GPUArrays", "LinearAlgebra", "RecipesBase", "StaticArrays", "Statistics", "ZygoteRules"] -git-tree-sha1 = "6b25d6ba6361ccba58be1cf9ab710e69f6bc96f8" -uuid = "731186ca-8d62-57ce-b412-fbd966d074cd" -version = "2.27.1" - -[[deps.RecursiveFactorization]] -deps = ["LinearAlgebra", "LoopVectorization", "Polyester", "StrideArraysCore", "TriangularSolve"] -git-tree-sha1 = "a9a852c7ebb08e2a40e8c0ab9830a744fa283690" -uuid = "f2c3362d-daeb-58d1-803e-2bc74f2840b4" -version = "0.2.10" - -[[deps.Reexport]] -git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" -uuid = "189a3867-3050-52da-a836-e630ba90ab69" -version = "1.2.2" - -[[deps.RelocatableFolders]] -deps = ["SHA", "Scratch"] -git-tree-sha1 = "cdbd3b1338c72ce29d9584fdbe9e9b70eeb5adca" -uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" -version = "0.1.3" - -[[deps.Requires]] -deps = ["UUIDs"] -git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" -uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.3.0" - -[[deps.Rmath]] -deps = ["Random", "Rmath_jll"] -git-tree-sha1 = "bf3188feca147ce108c76ad82c2792c57abe7b1f" -uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" -version = "0.7.0" - -[[deps.Rmath_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "68db32dff12bb6127bac73c209881191bf0efbb7" -uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" -version = "0.3.0+0" - -[[deps.RootSolvers]] -deps = ["DocStringExtensions", "ForwardDiff"] -git-tree-sha1 = "08c746c1b621e88953650133e46428bfecc11058" -uuid = "7181ea78-2dcb-4de3-ab41-2b8ab5a31e74" -version = "0.3.0" - -[[deps.Rotations]] -deps = ["LinearAlgebra", "Quaternions", "Random", "StaticArrays", "Statistics"] -git-tree-sha1 = "3177100077c68060d63dd71aec209373c3ec339b" -uuid = "6038ab10-8711-5258-84ad-4b1120ba62dc" -version = "1.3.1" - -[[deps.SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" - -[[deps.SIMDDualNumbers]] -deps = ["ForwardDiff", "IfElse", "SLEEFPirates", "VectorizationBase"] -git-tree-sha1 = "62c2da6eb66de8bb88081d20528647140d4daa0e" -uuid = "3cdde19b-5bb0-4aaf-8931-af3e248e098b" -version = "0.1.0" - -[[deps.SIMDTypes]] -git-tree-sha1 = "330289636fb8107c5f32088d2741e9fd7a061a5c" -uuid = "94e857df-77ce-4151-89e5-788b33177be4" -version = "0.1.0" - -[[deps.SLEEFPirates]] -deps = ["IfElse", "Static", "VectorizationBase"] -git-tree-sha1 = "ac399b5b163b9140f9c310dfe9e9aaa225617ff6" -uuid = "476501e8-09a2-5ece-8869-fb82de89a1fa" -version = "0.6.32" - -[[deps.SciMLBase]] -deps = ["ArrayInterface", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "RecipesBase", "RecursiveArrayTools", "StaticArrays", "Statistics", "Tables", "TreeViews"] -git-tree-sha1 = "8161f13168845aefff8dc193b22e3fcb4d8f91a9" -uuid = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -version = "1.31.5" - -[[deps.Scratch]] -deps = ["Dates"] -git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda" -uuid = "6c6a2e73-6563-6170-7368-637461726353" -version = "1.1.0" - -[[deps.Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[deps.Setfield]] -deps = ["ConstructionBase", "Future", "MacroTools", "Requires"] -git-tree-sha1 = "38d88503f695eb0301479bc9b0d4320b378bafe5" -uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46" -version = "0.8.2" - -[[deps.SharedArrays]] -deps = ["Distributed", "Mmap", "Random", "Serialization"] -uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" - -[[deps.Showoff]] -deps = ["Dates", "Grisu"] -git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" -uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" -version = "1.0.3" - -[[deps.SimpleTraits]] -deps = ["InteractiveUtils", "MacroTools"] -git-tree-sha1 = "5d7e3f4e11935503d3ecaf7186eac40602e7d231" -uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" -version = "0.9.4" - -[[deps.Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[deps.SortingAlgorithms]] -deps = ["DataStructures"] -git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508" -uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" -version = "1.0.1" - -[[deps.SparseArrays]] -deps = ["LinearAlgebra", "Random"] -uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - -[[deps.SparseDiffTools]] -deps = ["Adapt", "ArrayInterface", "Compat", "DataStructures", "FiniteDiff", "ForwardDiff", "Graphs", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays", "VertexSafeGraphs"] -git-tree-sha1 = "314a07e191ea4a5ea5a2f9d6b39f03833bde5e08" -uuid = "47a9eef4-7e08-11e9-0b38-333d64bd3804" -version = "1.21.0" - -[[deps.SpecialFunctions]] -deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] -git-tree-sha1 = "bc40f042cfcc56230f781d92db71f0e21496dffd" -uuid = "276daf66-3868-5448-9aa4-cd146d93841b" -version = "2.1.5" - -[[deps.Static]] -deps = ["IfElse"] -git-tree-sha1 = "7f5a513baec6f122401abfc8e9c074fdac54f6c1" -uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" -version = "0.4.1" - -[[deps.StaticArrays]] -deps = ["LinearAlgebra", "Random", "Statistics"] -git-tree-sha1 = "cd56bf18ed715e8b09f06ef8c6b781e6cdc49911" -uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.4.4" - -[[deps.Statistics]] -deps = ["LinearAlgebra", "SparseArrays"] -uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" - -[[deps.StatsAPI]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "c82aaa13b44ea00134f8c9c89819477bd3986ecd" -uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" -version = "1.3.0" - -[[deps.StatsBase]] -deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] -git-tree-sha1 = "8977b17906b0a1cc74ab2e3a05faa16cf08a8291" -uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -version = "0.33.16" - -[[deps.StatsFuns]] -deps = ["ChainRulesCore", "HypergeometricFunctions", "InverseFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] -git-tree-sha1 = "5783b877201a82fc0014cbf381e7e6eb130473a4" -uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" -version = "1.0.1" - -[[deps.StrideArraysCore]] -deps = ["ArrayInterface", "CloseOpenIntervals", "IfElse", "LayoutPointers", "ManualMemory", "Requires", "SIMDTypes", "Static", "ThreadingUtilities"] -git-tree-sha1 = "e03eacc0b8c1520e73aa84922ce44a14f024b210" -uuid = "7792a7ef-975c-4747-a70f-980b88e8d1da" -version = "0.3.6" - -[[deps.StructArrays]] -deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"] -git-tree-sha1 = "e75d82493681dfd884a357952bbd7ab0608e1dc3" -uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" -version = "0.6.7" - -[[deps.SuiteSparse]] -deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] -uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" - -[[deps.TOML]] -deps = ["Dates"] -uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" - -[[deps.TableTraits]] -deps = ["IteratorInterfaceExtensions"] -git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" -uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" -version = "1.0.1" - -[[deps.Tables]] -deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits", "Test"] -git-tree-sha1 = "5ce79ce186cc678bbb5c5681ca3379d1ddae11a1" -uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" -version = "1.7.0" - -[[deps.Tar]] -deps = ["ArgTools", "SHA"] -uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" - -[[deps.TaylorSeries]] -deps = ["InteractiveUtils", "LinearAlgebra", "Markdown", "Requires", "SparseArrays"] -git-tree-sha1 = "66f4d1993bae49eeba21a1634b5f65782585a42c" -uuid = "6aa5eb33-94cf-58f4-a9d0-e4b2c4fc25ea" -version = "0.10.13" - -[[deps.TempestRemap_jll]] -deps = ["Artifacts", "HDF5_jll", "JLLWrappers", "Libdl", "NetCDF_jll", "OpenBLAS32_jll", "Pkg"] -git-tree-sha1 = "36382ed08c138a6e2696976bf8abaae5ff4e5bd4" -uuid = "8573a8c5-1df0-515e-a024-abad257ee284" -version = "2.1.3+2" - -[[deps.TensorCore]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" -uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" -version = "0.1.1" - -[[deps.TerminalLoggers]] -deps = ["LeftChildRightSiblingTrees", "Logging", "Markdown", "Printf", "ProgressLogging", "UUIDs"] -git-tree-sha1 = "62846a48a6cd70e63aa29944b8c4ef704360d72f" -uuid = "5d786b92-1e48-4d6f-9151-6b4477ca9bed" -version = "0.1.5" - -[[deps.Test]] -deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[deps.Thermodynamics]] -deps = ["CLIMAParameters", "DocStringExtensions", "KernelAbstractions", "Random", "RootSolvers"] -git-tree-sha1 = "44f5a700a6b60b97663b2467f0c7b62dfe15e983" -uuid = "b60c26fb-14c3-4610-9d3e-2d17fe7ff00c" -version = "0.7.1" - -[[deps.ThreadingUtilities]] -deps = ["ManualMemory"] -git-tree-sha1 = "f8629df51cab659d70d2e5618a430b4d3f37f2c3" -uuid = "8290d209-cae3-49c0-8002-c8c24d57dab5" -version = "0.5.0" - -[[deps.TimerOutputs]] -deps = ["ExprTools", "Printf"] -git-tree-sha1 = "7638550aaea1c9a1e86817a231ef0faa9aca79bd" -uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" -version = "0.5.19" - -[[deps.TranscodingStreams]] -deps = ["Random", "Test"] -git-tree-sha1 = "216b95ea110b5972db65aa90f88d8d89dcb8851c" -uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" -version = "0.9.6" - -[[deps.TreeViews]] -deps = ["Test"] -git-tree-sha1 = "8d0d7a3fe2f30d6a7f833a5f19f7c7a5b396eae6" -uuid = "a2a6695c-b41b-5b7d-aed9-dbfdeacea5d7" -version = "0.3.0" - -[[deps.TriangularSolve]] -deps = ["CloseOpenIntervals", "IfElse", "LayoutPointers", "LinearAlgebra", "LoopVectorization", "Polyester", "Static", "VectorizationBase"] -git-tree-sha1 = "b8d08f55b02625770c09615d96927b3a8396925e" -uuid = "d5829a12-d9aa-46ab-831f-fb7c9ab06edf" -version = "0.1.11" - -[[deps.TriplotBase]] -git-tree-sha1 = "4d4ed7f294cda19382ff7de4c137d24d16adc89b" -uuid = "981d1d27-644d-49a2-9326-4793e63143c3" -version = "0.1.0" - -[[deps.URIs]] -git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355" -uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" -version = "1.3.0" - -[[deps.UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" - -[[deps.UnPack]] -git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" -uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" -version = "1.0.2" - -[[deps.Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" - -[[deps.UnicodeFun]] -deps = ["REPL"] -git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" -uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" -version = "0.4.1" - -[[deps.Unzip]] -git-tree-sha1 = "34db80951901073501137bdbc3d5a8e7bbd06670" -uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d" -version = "0.1.2" - -[[deps.VectorizationBase]] -deps = ["ArrayInterface", "CPUSummary", "HostCPUFeatures", "Hwloc", "IfElse", "LayoutPointers", "Libdl", "LinearAlgebra", "SIMDTypes", "Static"] -git-tree-sha1 = "b86092766ccbb59aefa7e8c6fa01b10e1934e78c" -uuid = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f" -version = "0.21.32" - -[[deps.VertexSafeGraphs]] -deps = ["Graphs"] -git-tree-sha1 = "8351f8d73d7e880bfc042a8b6922684ebeafb35c" -uuid = "19fa3120-7c27-5ec5-8db8-b0b0aa330d6f" -version = "0.2.0" - -[[deps.Wayland_jll]] -deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] -git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23" -uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" -version = "1.19.0+0" - -[[deps.Wayland_protocols_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "4528479aa01ee1b3b4cd0e6faef0e04cf16466da" -uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" -version = "1.25.0+0" - -[[deps.WriteVTK]] -deps = ["Base64", "CodecZlib", "FillArrays", "LightXML", "TranscodingStreams"] -git-tree-sha1 = "bff2f6b5ff1e60d89ae2deba51500ce80014f8f6" -uuid = "64499a7a-5c06-52f2-abe2-ccb03c286192" -version = "1.14.2" - -[[deps.XML2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a" -uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" -version = "2.9.12+0" - -[[deps.XSLT_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] -git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" -uuid = "aed1982a-8fda-507f-9586-7b0439959a61" -version = "1.1.34+0" - -[[deps.Xorg_libX11_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] -git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527" -uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" -version = "1.6.9+4" - -[[deps.Xorg_libXau_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" -uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" -version = "1.0.9+4" - -[[deps.Xorg_libXcursor_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] -git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd" -uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" -version = "1.2.0+4" - -[[deps.Xorg_libXdmcp_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" -uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" -version = "1.1.3+4" - -[[deps.Xorg_libXext_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] -git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" -uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" -version = "1.3.4+4" - -[[deps.Xorg_libXfixes_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] -git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4" -uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" -version = "5.0.3+4" - -[[deps.Xorg_libXi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] -git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246" -uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" -version = "1.7.10+4" - -[[deps.Xorg_libXinerama_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"] -git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123" -uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" -version = "1.1.4+4" - -[[deps.Xorg_libXrandr_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"] -git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631" -uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" -version = "1.5.2+4" - -[[deps.Xorg_libXrender_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] -git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" -uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" -version = "0.9.10+4" - -[[deps.Xorg_libpthread_stubs_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" -uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" -version = "0.1.0+3" - -[[deps.Xorg_libxcb_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] -git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6" -uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" -version = "1.13.0+3" - -[[deps.Xorg_libxkbfile_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] -git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2" -uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" -version = "1.1.0+4" - -[[deps.Xorg_xcb_util_image_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" -uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" -version = "0.4.0+1" - -[[deps.Xorg_xcb_util_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] -git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" -uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" -version = "0.4.0+1" - -[[deps.Xorg_xcb_util_keysyms_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" -uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" -version = "0.4.0+1" - -[[deps.Xorg_xcb_util_renderutil_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" -uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" -version = "0.3.9+1" - -[[deps.Xorg_xcb_util_wm_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" -uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" -version = "0.4.1+1" - -[[deps.Xorg_xkbcomp_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"] -git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b" -uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" -version = "1.4.2+4" - -[[deps.Xorg_xkeyboard_config_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"] -git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d" -uuid = "33bec58e-1273-512f-9401-5d533626f822" -version = "2.27.0+4" - -[[deps.Xorg_xtrans_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" -uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" -version = "1.4.0+3" - -[[deps.Zlib_jll]] -deps = ["Libdl"] -uuid = "83775a58-1f1d-513f-b197-d71354ab007a" - -[[deps.Zstd_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "e45044cd873ded54b6a5bac0eb5c971392cf1927" -uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" -version = "1.5.2+0" - -[[deps.ZygoteRules]] -deps = ["MacroTools"] -git-tree-sha1 = "8c1a8e4dfacb1fd631745552c8db35d0deb09ea0" -uuid = "700de1a5-db45-46bc-99cf-38207098b444" -version = "0.2.2" - -[[deps.libass_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] -git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" -uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" -version = "0.15.1+0" - -[[deps.libblastrampoline_jll]] -deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] -uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" - -[[deps.libfdk_aac_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" -uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" -version = "2.0.2+0" - -[[deps.libpng_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] -git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" -uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" -version = "1.6.38+0" - -[[deps.libvorbis_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] -git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" -uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" -version = "1.3.7+1" - -[[deps.nghttp2_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" - -[[deps.p7zip_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" - -[[deps.x264_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" -uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" -version = "2021.5.5+0" - -[[deps.x265_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" -uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" -version = "3.5.0+0" - -[[deps.xkbcommon_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] -git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6" -uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" -version = "0.9.1+5" diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/Project.toml b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/Project.toml deleted file mode 100644 index 2d0b65aacc..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/Project.toml +++ /dev/null @@ -1,25 +0,0 @@ -[deps] -ClimaAtmos = "b2c96348-7fb7-4fe0-8da9-78d88439e717" -ClimaComms = "3a4d1b5c-c61d-41fd-a00a-5873ba7a1b0d" -ClimaCommsMPI = "5f86816e-8b66-43b2-912e-75384f99de49" -ClimaCore = "d414da3d-4745-48bb-8d80-42e94e092884" -ClimaCorePlots = "cf7c7e5a-b407-4c48-9047-11a94a308626" -ClimaCoreTempestRemap = "d934ef94-cdd4-4710-83d6-720549644b70" -IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" -NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" -OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -ProgressLogging = "33c8b6b6-d38a-422a-b730-caa89a2f386c" -SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" -TempestRemap_jll = "8573a8c5-1df0-515e-a024-abad257ee284" -TerminalLoggers = "5d786b92-1e48-4d6f-9151-6b4477ca9bed" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" - -[compat] - -[extras] -CPUSummary = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/README.md b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/README.md deleted file mode 100644 index af3bf27287..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/README.md +++ /dev/null @@ -1,159 +0,0 @@ -# **Baroclinic Wave + Slab** - -# Atmosphere -The momentum equations are in the advective form, and tracers in the consevative form, namely: - -- Density: -$$ \frac{\partial \rho}{\partial t} + \nabla \cdot ({\rho \vec{u}})= 0 $$ - -- Momentum (flux form): -$$ \frac{\partial \vec{u_h}}{\partial t} + \vec{u} \cdot \nabla \vec{u_h} = - \frac{1}{\rho}\nabla_h p -+ \frac{\partial}{\partial z} K_v \frac{\partial}{\partial z} \vec{u_h} -$$ -$$ \frac{\partial w}{\partial t} + \vec{u} \cdot \nabla w= -- \frac{1}{\rho}\frac{\partial p}{\partial z} -- \nabla_z \Phi -+ \frac{\partial}{\partial z} K_v \frac{\partial}{\partial z} w -$$ - -- Total energy: -$$ \frac{\partial \rho e_{tot}}{\partial t} + \nabla \cdot (\rho h_{tot} \vec{u}) = \frac{\partial}{\partial z} K_v \frac{\partial}{\partial z} h_{tot} -$$ - -where the total specific enthalpy and total specific energy are -$$ h_{tot} = e_{tot} + \frac{p}{\rho} \,\,\,\,\,\,\,\, \,\,\,\,\,\,\,\, e_{tot} = c_v T + \Phi + \frac{1}{2}\vec{u}^2 -$$ -(note that $h_{tot} \neq h = c_vT + p/\rho = c_p T$, the specific enthalpy in the thermodynamic sense), $\Phi = gz$ is the geopotential, -$u_h$ is the horizontal velocity vector, $w$ the vertical velocity, $\rho$ the density, $p$ pressure, $K_v$ the vertical diffusivity (assumed constant here). - -## Boundary conditions (BCs) -- We implement BCs similarly to other climate models. - - First-order fluxes (i.e., advective fluxes) are always set to zero, corresponding to the *free-slip* and *impenetrable* BC, where: - $$ - w = 0 \,\,\,\,\,\,\, \partial_t w = 0 \,\,\,\,\,\,\, \nabla \times\vec{u_h}=0 \,\,\,\,\,\,\, \nabla \cdot \vec{\rho u_h}=0 \,\,\,\,\,\,\, \nabla \cdot \rho h_{tot} \vec{u_h}=0 - $$ - - Second-order fluxes (i.e., diffusive fluxes) - - `No Flux`: By default we have *impenetrable* or *insulating* BCs (no second-order fluxes) at all boundaries. - - `Bulk Formula`: Applied to tracers (e.g., temperature and moisture), this imposes a boundary fluxes (e.g., sensible and latent heat) calculated using the bulk aerodynamic formulae using prescribed surface values of ($T_{sfc}$ and $q_{sfc}^{sat}$). At the surface, the bulk sensible heat flux formula for total enthalpy essentially replaces the above: - $$ (K_v \rho \partial_z h_{tot})_{sfc}$$ - For **total energy**, we have two choices: - - 1. enthalpy flux: - $$ (K_v \rho \partial_z h_{tot})_{sfc} \rightarrow - \hat{n} \cdot \rho C_H ||u||^{1} (h^1- h_{sfc}) - = F_S - $$ - - 2. sensible (and latent) heat flux. The sensible heat flux is: - $$ (K_v \rho \partial_z h_{tot})_{sfc} \rightarrow - \hat{n} \cdot C_H c_{pd} ρ^{1} ||u||^{1} (T^{1} - T_{sfc}) - + \hat{n} \cdot C_H ρ^{1} ||u||^{1} (\Phi^{1} - \Phi_{sfc}) - = F_S - $$ - where $^{1}$ corresponds to the lowest model level, $C_H$ is the dimensionless thermal transfer coefficient, $c_{pd}$ is the specific heat capacity for dry air $||u||$ the wind speed. This is the *bulk turbulent sensible heat flux* parameterization, and $F_S$ is positive when atmosphere receives energy from the surface. - The contribution of the kinetic energy is usually O(1e4) smaller and is neglected, but it can be added to F_S as: - $$ - F_{S_{tot}} = F_S + \hat{n} \cdot C_D ρ^{1} ||u||^{1} (\vec{u_h}^{1})^2 - $$ - - `Drag Law`: essentially the bulk formula for momentum - $$ \frac{\partial}{\partial z} K_v \frac{\partial}{\partial z} \vec{u_h} \rightarrow - \hat{n} \cdot C_D ρ^{1} ||u||^{1} \vec{u_h}^{1} - = F_M - $$ - - `Coupled Bulk Formula`: same as `Bulk Formula`, but surface quantities (e.g. $T_{sfc}$) are passed from the state of the neighboring model. - - - The diffusive fluxes are applied via the `vertical_diffusion` ClimaAtmos model sub-component. To apply boundary fluxes without diffusion in the atmospheric interior, the viscosity coefficient needs to be set to zero: $ν = FT(0)$. - - We use `SurfaceFluxes.jl` to deal with the Monin Obukhov calculations - -## Current setup -- total energy and momentum - - at z=0: - - ρe: `Coupled Bulk Formula` latent heat flux + sensible heat flux (will be combined into enthalpy flux formulation in SurfaceFluxes.jl) - - uh: `Drag Law` - - the the top: - - $F_S = F_M = 0$ - - values - - simple setup: $C_D = C_H = 0.001$, interior diffusivity is set to $\nu = 5$ m^2/s - - ClimaAtmos setup ∀ p > p_pbl : $C_D = C_E = 0.0044 exp(-\frac{(p_{pbl} - p)}{p_{strato}}^2)$ - - where $p_{pbl} = 8e4$ Pa, $p_{strato} = 1e4$ Pa - -- All other boundary fluxes are set to 0. - -## Initial conditions -- we initialize with a perturbation in a balanced background state, as in: -https://climate.ucdavis.edu/pubs/UMJS2013QJRMS.pdf - -# Heat Slab -The slab solves for temperature in a single layer, whose tendency is the accumulated fluxes divided by the coupling timestep plus a parameterisation of the internal processes, $G$. -$$ -\rho c h_s \, \partial_t T_{sfc} = - F_{integ} / \Delta t_{coupler} -$$ - -# Distribution -## Julia multithreading -- we can run using multiple threads if the command line argument `enable_threading` is true (e.g., run with `julia --project --threads 8`). - -## MPI via ClimaComms.jl -- for AMIP we want the surface columns to be on the same processors as the atmos columns. Since all all surface domains will be on masked spheres, all of them can inherit the same distributed horizontal space from the atmos model. -- for this we need to run the `sbatch_job.sh` script, which sets up the `CLIMACORE_DISTRIBUTED` environment variable and job specifications, and runs the coupler_driver with `mpiexec` - -## Regridding -- not needed for AMIP. ClimaCoreTempestRemap can be easily re-introduced for a single processor, but will require more work for MPI runs. - -# Tests -## Conservation -- this uses the `sum` of `ClimaCore/Fields/mapreduce.jl`, which produces a sum weighted by the area Jacobian. - - one can easily check this by summing a field of ones using the domain's space: - ``` - field_of_ones = ones(center_space) - sum(field_of_ones) ≈ (4*pi*domain_radius^2) * domain_height - ``` -- Radiation - - By default radiation is a `PeriodicCallback` applied in `ClimaAtmos` every 6h. This updates the radiation fluxes field, `ᶠradiation_flux`, which itself is applied at every timestep via: - ``` - @. Yₜ.c.ρe -= ᶜdivᵥ(ᶠradiation_flux) - ``` - - The TOA fluxes can be accessed via `level(ᶠradiation_flux, end - half)`. Their net sum (or imbalance) represents sources and sinks to the earth system and these need to balance the net energy change. Ideally the TOA fluxes will balance to near zero. - -## Performance -- using `@elapsed` to measure the walltime of the coupling loop -- 1. strong scaling - - increasing the number of precessing elements (MPI processes or threads) - -- 2. weak scaling - - increasing the number of precessing elements (MPI processes or threads) with job size (vertical resolution) - -- 3. comparison to stand-alone atmos - - using the original ClimaAtmos driver (using `solve!`) - -## Physical correctness -- run the default for 20 days - -# Prescribed SST and Sea Ice -- We simply prescribe SSTs from a file as `T_sfc`. As for sea ice, we will follow GFDL's [AMIP setup](https://pcmdi.llnl.gov/mips/amip/home/Documentation/20gfdl.html#RTFToC31) and use prescribed sea ice concentrations and a constant ice thickness, $h_{i} = 2m$ ice thickness, while solving for $T_{sfc}$: -$$ -\frac{dT_{sfc}}{dt} = - frac{h_i(F_{atm} - F_{conductive}) / k_i} -$$ -where -$$ -F_{conductive} = \frac{k_i (T_{base} - {T_sfc})}{h_{i}} -$$ -with the thermal conductivity of ice, $k_i = 2$ W m$^{-2}$ K$^{-1}$, and $T_{base} = 273.16$ K. For now we use an Euler timestepper (and use $T_{sfc}$ of the previous timestep), though this may be solved implicitly in the future. - -## Data source -- https://gdex.ucar.edu/dataset/158_asphilli.html - - MODEL.SST.HAD187001-198110.OI198111-202203.nc - - MODEL.ICE.HAD187001-198110.OI198111-202203.nc -- N.B.: the [pcmdi link](https://pcmdi.llnl.gov/mips/amip/details/amipbc_dwnld.php), used in most AMIP papers, is broken - - -# NB: -- first coupled iteration does not call rhs! -- slab `T_sfc` gets huge numbers when using `SSPRK33`. ok with `Euler` -- do not init global fields with mpi context - -# References -- [Kang et al 2021](https://arxiv.org/abs/2101.09263) -- [kth.se blog for strong and weak scaling](https://www.kth.se/blogs/pdc/2018/11/scalability-strong-and-weak-scaling/) - - - - diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/atmos/atmos_init.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/atmos/atmos_init.jl deleted file mode 100644 index ed4721987b..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/atmos/atmos_init.jl +++ /dev/null @@ -1,88 +0,0 @@ -# atmos_init: for ClimaAtmos pre-AMIP interface - -# clone locally ClimaAtmos and checkout the checkpoint branch (this is necessary because the driver is currently not a module, and the checkpoint branch avoids the necessity for frequent updates) -CWD = pwd() -ATMOS_DIR = CWD * "/../../../../ClimaAtmos.jl_cpl/" - -run(`rm -rf $ATMOS_DIR`) -ClimaComms.barrier(comms_ctx) - -if !is_distributed || (is_distributed && ClimaComms.iamroot(comms_ctx)) - run(`git clone https://github.com/CliMA/ClimaAtmos.jl.git $ATMOS_DIR`) - run(`chmod 775 checkout_ClimaAtmos.sh`) - run(`."/"checkout_ClimaAtmos.sh $ATMOS_DIR`) -end - -ClimaComms.barrier(comms_ctx) - -Pkg.develop(path = ATMOS_DIR) -Pkg.activate(joinpath(ATMOS_DIR, "examples")) -Pkg.instantiate() -Pkg.add(PackageSpec(name = "ClimaCore", version = "0.10.3")) - -driver_orig = ATMOS_DIR * "examples/hybrid/driver.jl" -driver_new = ATMOS_DIR * "examples/hybrid/driver_new.jl" - -# get only the chunks of the driver.jl we need (i.e. before solve!) -if !is_distributed || (is_distributed && ClimaComms.iamroot(comms_ctx)) - - run( - pipeline( - `awk '$1=="sol" {f=0;next} f{print;next} NR==1 {f=1}'`; - stdin = driver_orig, - stdout = driver_new, - append = false, - ), - ) - - # remove the hard coded tendency specifications (so that we can define a diffusion tendency that allows for the correct coupled boundary conditions) - run(`sed -i.bak -e '94,123d' $driver_new`) # yep! - - # remove hard coded MPI init (optional but neater) - run(`sed -i.bak -e '98,119d' $driver_new`) # yep! -end - -# init model using the modified driver -include(joinpath(ATMOS_DIR, "examples/hybrid/cli_options.jl")) - -parsed_args = parse_commandline(argparse_settings()) - -# add coupler-taylored CA functions -TEST_NAME = "coupled_atmos" - -coupler_atmos_file = CWD * "/atmos/" * TEST_NAME * ".jl" - -ClimaComms.barrier(comms_ctx) -include(coupler_atmos_file) - -# specify sim parameters -const FT = parsed_args["FLOAT_TYPE"] == "Float64" ? Float64 : Float32 # parsed_args["FLOAT_TYPE"] = FT -parsed_args["dt"] = string(Δt_cpl) * "secs" -parsed_args["t_end"] = string(t_end) * "secs" -parsed_args["enable_threading"] = true -parsed_args["dt_save_to_sol"] = string(saveat) * "secs" - -atoms_setup_dir = joinpath(ATMOS_DIR, "examples/hybrid/sphere/") - -if !is_distributed || (is_distributed && ClimaComms.iamroot(comms_ctx)) - run(`cp $coupler_atmos_file $atoms_setup_dir`) -end - -# init model using the modified driver -ClimaComms.barrier(comms_ctx) -Pkg.add(PackageSpec(name = "ClimaCore", version = "0.10.3")) -Pkg.pin("ClimaCore") -include(driver_new) # this stops just before `solve!` - -spaces = (; center_space = center_space, face_space = face_space) - -struct AtmosSimulation{P, Y, D, I} - params::P - Y_init::Y - domain::D - integrator::I -end - -function atmos_init(::Type{FT}, Y, spaces, integrator; params = nothing) where {FT} - AtmosSimulation(params, Y, spaces, integrator) -end diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/atmos/coupled_atmos.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/atmos/coupled_atmos.jl deleted file mode 100644 index f337f24167..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/atmos/coupled_atmos.jl +++ /dev/null @@ -1,131 +0,0 @@ -using ClimaCore.Geometry: ⊗ - -# These functions are copied from the ClimaAtmos driver and modified for the coupler (TODO: update when interface is stable) -function vertical_diffusion_boundary_layer_coupled_tendency!(Yₜ, Y, p, t) - ᶜρ = Y.c.ρ - (; ᶜp, ᶠv_a, ᶠz_a, ᶠK_E) = p # assume ᶜts and ᶜp have been updated - (; ρ_dif_flux_h_tot, dif_flux_ρq_tot, ρ_dif_flux_uₕ) = p - ᶠgradᵥ = Operators.GradientC2F() # apply BCs to ᶜdivᵥ, which wraps ᶠgradᵥ - - Fields.field_values(ᶠv_a) .= Fields.field_values(Spaces.level(Y.c.uₕ, 1)) .* one.(Fields.field_values(ᶠz_a)) # TODO: fix VIJFH copyto! to remove this - @. ᶠK_E = eddy_diffusivity_coefficient(norm(ᶠv_a), ᶠz_a, ᶠinterp(ᶜp)) #* FT(0) - - # Total Energy - if :ρe in propertynames(Y.c) - ᶜdivᵥ = Operators.DivergenceF2C( - top = Operators.SetValue(Geometry.WVector(FT(0))), - bottom = Operators.SetValue(.-ρ_dif_flux_h_tot), - ) - @. Yₜ.c.ρe += ᶜdivᵥ(ᶠK_E * ᶠinterp(ᶜρ) * ᶠgradᵥ((Y.c.ρe + ᶜp) / ᶜρ)) - end - - # Liquid Mass and Total Mass - if :ρq_tot in propertynames(Y.c) - ᶜdivᵥ = Operators.DivergenceF2C( - top = Operators.SetValue(Geometry.WVector(FT(0))), - bottom = Operators.SetValue(.-dif_flux_ρq_tot), - ) - @. Yₜ.c.ρq_tot += ᶜdivᵥ(ᶠK_E * ᶠinterp(ᶜρ) * ᶠgradᵥ(Y.c.ρq_tot / ᶜρ)) - @. Yₜ.c.ρ += ᶜdivᵥ(ᶠK_E * ᶠinterp(ᶜρ) * ᶠgradᵥ(Y.c.ρq_tot / ᶜρ)) - end - - # Momentum - if :uₕ in propertynames(Y.c) - ᶜdivᵥ = Operators.DivergenceF2C( - top = Operators.SetValue(Geometry.Contravariant3Vector(FT(0)) ⊗ Geometry.Covariant12Vector(FT(0), FT(0))), - bottom = Operators.SetValue(.-ρ_dif_flux_uₕ), - ) - - @. Yₜ.c.uₕ += ᶜdivᵥ(ᶠK_E * ᶠgradᵥ(Y.c.uₕ)) - end - -end - -function vertical_diffusion_boundary_layer_coupled_cache(Y; Cd = FT(0.0014), Ch = FT(0.0014)) - ᶠz_a = similar(Y.f, FT) - z_bottom = Spaces.level(Fields.coordinate_field(Y.c).z, 1) - Fields.field_values(ᶠz_a) .= Fields.field_values(z_bottom) .* one.(Fields.field_values(ᶠz_a)) - # TODO: fix VIJFH copyto! to remove the one.(...) - - if :ρq_tot in propertynames(Y.c) - dif_flux_ρq_tot = similar(z_bottom, Geometry.WVector{FT}) #ones(axes(z_bottom)) - else - dif_flux_ρq_tot = Ref(Geometry.WVector(FT(0))) - end - - ρ_dif_flux_uₕ = - Geometry.Contravariant3Vector.(zeros(axes(z_bottom))) .⊗ - Geometry.Covariant12Vector.(zeros(axes(z_bottom)), zeros(axes(z_bottom))) - - if (:ρq_liq in propertynames(Y.c) && :ρq_ice in propertynames(Y.c) && :ρq_tot in propertynames(Y.c)) - ts_type = TD.PhaseNonEquil{FT} - elseif :ρq_tot in propertynames(Y.c) - ts_type = TD.PhaseEquil{FT} - else - ts_type = TD.PhaseDry{FT} - end - coef_type = SF.Coefficients{ - FT, - SF.InteriorValues{FT, Tuple{FT, FT}, ts_type}, - SF.SurfaceValues{FT, Tuple{FT, FT}, TD.PhaseEquil{FT}}, - } - - return (; - ᶠv_a = similar(Y.f, eltype(Y.c.uₕ)), - ᶠz_a, - ᶠK_E = similar(Y.f, FT), - flux_coefficients = similar(z_bottom, coef_type), - ρ_dif_flux_h_tot = similar(z_bottom, Geometry.WVector{FT}), - dif_flux_ρq_tot, - ρ_dif_flux_uₕ, - ∂F_aero∂T_sfc = zeros(axes(z_bottom)), - Cd, - Ch, - ) -end - -additional_cache(Y, params, dt; use_tempest_mode = false) = merge( - hyperdiffusion_cache(Y; κ₄ = FT(2e17), use_tempest_mode), - sponge ? rayleigh_sponge_cache(Y, dt) : NamedTuple(), - isnothing(microphy) ? NamedTuple() : zero_moment_microphysics_cache(Y), - isnothing(forcing) ? NamedTuple() : held_suarez_cache(Y), - isnothing(rad) ? NamedTuple() : rrtmgp_model_cache(Y, params; radiation_mode, idealized_h2o), - vert_diff ? vertical_diffusion_boundary_layer_coupled_cache(Y) : NamedTuple(), - (; - tendency_knobs = (; - hs_forcing = forcing == "held_suarez", - microphy_0M = microphy == "0M", - rad_flux = !isnothing(rad), - vert_diff, - hyperdiff, - ) - ), -) - -additional_tendency!(Yₜ, Y, p, t) = begin - (; rad_flux, vert_diff, hs_forcing) = p.tendency_knobs - (; microphy_0M, hyperdiff) = p.tendency_knobs - hyperdiff && hyperdiffusion_tendency!(Yₜ, Y, p, t) - sponge && rayleigh_sponge_tendency!(Yₜ, Y, p, t) - hs_forcing && held_suarez_tendency!(Yₜ, Y, p, t) - vert_diff && vertical_diffusion_boundary_layer_coupled_tendency!(Yₜ, Y, p, t) - microphy_0M && zero_moment_microphysics_tendency!(Yₜ, Y, p, t) - rad_flux && rrtmgp_model_tendency!(Yₜ, Y, p, t) -end - -# switch on required additional tendencies / parameterizations -parsed_args["microphy"] = "0M" -parsed_args["forcing"] = nothing -parsed_args["idealized_h2o"] = false -parsed_args["vert_diff"] = true -parsed_args["rad"] = "gray" -parsed_args["hyperdiff"] = true -parsed_args["config"] = "sphere" -parsed_args["moist"] = "equil" - -function array2field(array, space) # reversing the RRTMGP function field2array (TODO: this now exists in ClimaAtmos) - FT = eltype(array) - Nq = Spaces.Quadratures.polynomial_degree(space.horizontal_space.quadrature_style) + 1 - ne = space.horizontal_space.topology.mesh.ne - return Fields.Field(VIJFH{FT, Nq}(reshape(array, size(array, 1), Nq, Nq, 1, ne * ne * 6)), space) -end diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/checkout_ClimaAtmos.sh b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/checkout_ClimaAtmos.sh deleted file mode 100755 index 729d3633c8..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/checkout_ClimaAtmos.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -cd $1 -git checkout origin/ln/stable-interface-checkpoint diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_driver.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_driver.jl deleted file mode 100644 index d6241cc245..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_driver.jl +++ /dev/null @@ -1,263 +0,0 @@ -# coupler_driver -# don't forget to run with threading: julia --project --threads 8 (MPI not that useful for debugging coarse runs) - -# import packages -using Pkg -import SciMLBase: step! -using OrdinaryDiffEq -using OrdinaryDiffEq: ODEProblem, solve, SSPRK33, savevalues!, Euler -using LinearAlgebra -import Test: @test -using ClimaCore.Utilities: half, PlusHalf -import ClimaCore.Spaces as Spaces - -Pkg.add(PackageSpec(name = "ClimaCore", version = "0.10.3")) - -# import coupler utils -include("coupler_utils/flux_calculator.jl") -include("coupler_utils/conservation_checker.jl") -include("coupler_utils/regridder.jl") -include("coupler_utils/masker.jl") -include("coupler_utils/general_helper.jl") - -# # initiate spatial and temporal info -debug_mode = true -t_end = debug_mode ? 100e2 : 2592000 #* 3 -tspan = (0, t_end) -Δt_cpl = 2e2 -saveat = debug_mode ? Δt_cpl * 1 : Δt_cpl * 100 - -@show debug_mode - -# init MPI -include("mpi/mpi_init.jl") -# init atmos model component -include("atmos/atmos_init.jl") -atmos_sim = atmos_init(FT, Y, spaces, integrator, params = params); - -# init a 2D boundary space at the surface, assuming the same instance (and MPI distribution if applicable) as the atmos domain above -boundary_space = ClimaCore.Fields.level(atmos_sim.domain.face_space, half) # global surface grid - -# init land-sea mask -infile = "data/seamask.nc" -mask = land_sea_mask(FT, infile, "LSMASK", boundary_space) # TODO: split up the nc file to individual times for faster computation - -# init surface (slab) model components -include("slab/slab_init.jl") # stub for ClimaLSM's Bucket -slab_sim = slab_init(FT, tspan, dt = Δt_cpl, space = boundary_space, saveat = saveat, mask = mask); - -include("slab_ocean/slab_init.jl") -prescribed_sst = false -if prescribed_sst == true - SST = ncreader_rll_to_cgll_from_space(FT, "data/sst.nc", "SST", boundary_space) # a sample SST field from https://gdex.ucar.edu/dataset/158_asphilli.html - SST = swap_space!(zeros(axes(mask)), SST) .* (abs.(mask .- 1)) .+ FT(273.15) # TODO: avoids the "space not the same instance" error - ocean_params = OceanSlabParameters(FT(20), FT(1500.0), FT(800.0), FT(280.0), FT(1e-3), FT(1e-5)) -else - slab_ocean_sim = slab_ocean_init(FT, tspan, dt = Δt_cpl, space = boundary_space, saveat = saveat, mask = mask) -end - -include("slab_ice/slab_init.jl") -prescribed_sic = false -if prescribed_sic == true - # sample SST field - SIC = ncreader_rll_to_cgll_from_space(FT, "data/sic.nc", "SEAICE", boundary_space) - SIC = swap_space!(zeros(axes(mask)), SIC) .* (abs.(mask .- 1)) - slab_ice_sim = slab_ice_init( - FT, - tspan, - nothing, - dt = Δt_cpl, - space = boundary_space, - saveat = saveat, - prescribed_sic_data = SIC, - ) -else - ocean_params = slab_ocean_sim.integrator.p.params - slab_ice_sim = slab_ice_init(FT, tspan, ocean_params, dt = Δt_cpl, space = boundary_space, saveat = saveat) -end - -# init coupler -coupler_sim = CouplerSimulation{FT}(boundary_space, mask, integrator.t, FT(Δt_cpl)) - -# init coupler's boundary fields for regridding (TODO: technically this can be bypassed by directly rigridding on model grids) -T_S = ClimaCore.Fields.zeros(boundary_space) # temperature -z0m_S = ClimaCore.Fields.zeros(boundary_space) -z0b_S = ClimaCore.Fields.zeros(boundary_space) - -F_A = ClimaCore.Fields.zeros(boundary_space) # aerodynamic turbulent fluxes -F_R = ClimaCore.Fields.zeros(boundary_space) # radiative fluxes -dF_A = ClimaCore.Fields.zeros(boundary_space) # aerodynamic turbulent fluxes - -# init conservation info collector -CS = OnlineConservationCheck([], [], [], [], [], []) - -# coupling loop -@show "Starting coupling loop" -walltime = @elapsed for t in (tspan[1]:Δt_cpl:tspan[end]) - @show t - - ## Atmos - ## Turbulent surface fluxes - - # coupler_get: T_sfc, z0m, z0b - combined_field = zeros(boundary_space) - if prescribed_sst == true - parent(combined_field) .= - combine_surface.( - parent(mask) .- parent(slab_ice_sim.integrator.p.Ya.ice_mask .* FT(2)), - parent(slab_sim.integrator.u.T_sfc), - parent(SST), - parent(slab_ice_sim.integrator.u.T_sfc), - ) # prescribed SSTs - dummmy_remap!(T_S, combined_field) - parent(combined_field) .= - combine_surface.( - parent(mask), - parent(slab_sim.integrator.p.params.z0m .* mask), - parent(ocean_params.z0m .* (abs.(mask .- 1))), - ) - dummmy_remap!(z0m_S, combined_field) - parent(combined_field) .= - combine_surface.( - parent(mask), - parent(slab_sim.integrator.p.params.z0b .* mask), - parent(ocean_params.z0b .* (abs.(mask .- 1))), - ) - dummmy_remap!(z0b_S, combined_field) - else - if prescribed_sic == true - parent(combined_field) .= - combine_surface.( - parent(mask) .- parent(slab_ice_sim.integrator.p.Ya.ice_mask .* FT(2)), - parent(slab_sim.integrator.u.T_sfc), - parent(slab_ocean_sim.integrator.u.T_sfc), - parent(slab_ice_sim.integrator.u.T_sfc), - ) - dummmy_remap!(T_S, combined_field) - parent(combined_field) .= - combine_surface.( - parent(mask), - parent(slab_sim.integrator.p.params.z0m .* mask), - parent(slab_ocean_sim.integrator.p.params.z0m .* (abs.(mask .- 1))), - ) - dummmy_remap!(z0m_S, combined_field) - parent(combined_field) .= - combine_surface.( - parent(mask), - parent(slab_sim.integrator.p.params.z0b .* mask), - parent(slab_ocean_sim.integrator.p.params.z0b .* (abs.(mask .- 1))), - ) - dummmy_remap!(z0b_S, combined_field) - else - parent(combined_field) .= - combine_surface.( - parent(mask) .- parent(slab_ice_sim.integrator.p.Ya.ice_mask .* FT(2)), - parent(slab_sim.integrator.u.T_sfc), - parent(slab_ice_sim.integrator.u.T_sfc), - parent(slab_ice_sim.integrator.u.T_sfc), - ) - dummmy_remap!(T_S, combined_field) - parent(combined_field) .= - combine_surface.( - parent(mask), - parent(slab_sim.integrator.p.params.z0m .* mask), - parent(slab_ocean_sim.integrator.p.params.z0m .* (abs.(mask .- 1))), - ) - dummmy_remap!(z0m_S, combined_field) - parent(combined_field) .= - combine_surface.( - parent(mask), - parent(slab_sim.integrator.p.params.z0b .* mask), - parent(slab_ocean_sim.integrator.p.params.z0b .* (abs.(mask .- 1))), - ) - dummmy_remap!(z0b_S, combined_field) - end - end - - # calculate turbulent fluxes on atmos grid and save in atmos cache - info_sfc = (; T_sfc = T_S, z0m = z0m_S, z0b = z0b_S, ice_mask = slab_ice_sim.integrator.p.Ya.ice_mask) - calculate_surface_fluxes_atmos_grid!(atmos_sim.integrator, info_sfc) - - atmos_sim.integrator.p.rrtmgp_model.surface_temperature .= field2array(T_S) # supplied to atmos for radiation - - # run - step!(atmos_sim.integrator, t - atmos_sim.integrator.t, true) # NOTE: instead of Δt_cpl, to avoid accumulating roundoff error - - #clip TODO: this is bad!! > limiters - parent(atmos_sim.integrator.u.c.ρq_tot) .= heaviside.(parent(atmos_sim.integrator.u.c.ρq_tot)) # negligible for total energy cons - - # coupler_push!: get accumulated fluxes from atmos in the surface fields - F_A .= ClimaCore.Fields.zeros(boundary_space) - dummmy_remap!(F_A, atmos_sim.integrator.p.ρ_dif_flux_h_tot) - F_R .= ClimaCore.Fields.zeros(boundary_space) - parsed_args["rad"] == "gray" ? dummmy_remap!(F_R, level(atmos_sim.integrator.p.ᶠradiation_flux, half)) : nothing # TODO: albedo hard coded... - dF_A .= ClimaCore.Fields.zeros(boundary_space) - dummmy_remap!(dF_A, atmos_sim.integrator.p.∂F_aero∂T_sfc) - - ## Slab land - # coupler_get: F_aero, F_rad - slab_F_aero = slab_sim.integrator.p.F_aero - @. slab_F_aero = F_A - slab_F_rad = slab_sim.integrator.p.F_rad - @. slab_F_rad = F_R - - # run - step!(slab_sim.integrator, t - slab_sim.integrator.t, true) - - ## Slab ocean - # coupler_get: F_aero, F_rad - if (prescribed_sst !== true) && (prescribed_sic == true) - slab_ocean_F_aero = slab_ocean_sim.integrator.p.F_aero - @. slab_ocean_F_aero = F_A - slab_ocean_F_rad = slab_ocean_sim.integrator.p.F_rad - @. slab_ocean_F_rad = F_R - - # run - step!(slab_ocean_sim.integrator, t - slab_ocean_sim.integrator.t, true) - end - # conservation info "callback" logging at every Δt_cpl - - ## Slab ice - # coupler_get: F_aero, F_rad - slab_ice_F_aero = slab_ice_sim.integrator.p.Ya.F_aero - @. slab_ice_F_aero = F_A - slab_ice_F_rad = slab_ice_sim.integrator.p.Ya.F_rad - @. slab_ice_F_rad = F_R - slab_ice_∂F_aero∂T_sfc = slab_ice_sim.integrator.p.Ya.∂F_aero∂T_sfc - @. slab_ice_∂F_aero∂T_sfc = dF_A - - # run - step!(slab_ice_sim.integrator, t - slab_ice_sim.integrator.t, true) - - if !is_distributed && (@isdefined CS) - check_conservation(CS, coupler_sim, atmos_sim, slab_sim, slab_ocean_sim, slab_ice_sim) - end -end - -@show walltime - -@show "Postprocessing" -# collect solutions -sol_atm = atmos_sim.integrator.sol -sol_slab = slab_sim.integrator.sol -sol_slab_ice = slab_ice_sim.integrator.sol -sol_slab_ocean = prescribed_sst !== true ? slab_ocean_sim.integrator.sol : nothing - -# conservation check -if @isdefined CSoffline - check_conservation(CSoffline, coupler_sim, atmos_sim, slab_sim, slab_ocean_sim, slab_ice_sim, "conservation.png") -end - -plot_global_energy(CS, coupler_sim, "total_energy_Xdyn.png") - -# # animations -# include("coupler_utils/viz_explorer.jl") -# plot_anim(atmos_sim, slab_sim, slab_ice_sim, slab_ice_sim) # ice sim holds ocean info - -# # vtk output for viz -# include("coupler_utils/vtk_helper.jl") -# space_new = retype_space(h_space, Float64) -# times = 0:saveat:t_end -# Sol_Tsfc = map(i -> convert_field_to_type(space_new, sol_slab.u[i].T_sfc), 1:length(times)) -# Sol_Tsfc_ice = map(i -> convert_field_to_type(space_new, sol_slab_ice.u[i].T_sfc), 1:length(times)) -# ClimaCoreVTK.writepvd(joinpath("data", "tt_5"), times, (T_sfc = Sol_Tsfc, T_sfc_ice = Sol_Tsfc_ice) , basis = :lagrange) diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/conservation_checker.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/conservation_checker.jl deleted file mode 100644 index 09dafdcb87..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/conservation_checker.jl +++ /dev/null @@ -1,152 +0,0 @@ -# generalise this into coupler-specific function - -abstract type AbstractCheck end - -struct OnlineConservationCheck{A} <: AbstractCheck - ρe_tot_atmos::A - ρe_tot_land::A - ρe_tot_ocean::A - ρe_tot_seaice::A - toa_net_source::A - ice_base_source::A -end -function check_conservation( - cs::OnlineConservationCheck, - coupler_sim, - atmos_sim = nothing, - land_sim = nothing, - ocean_sim = nothing, - seaice_sim = nothing, - radiation = true, -) - mask = coupler_sim.land_mask - - z = parent(Fields.coordinate_field(face_space).z) - Δz_bot = FT(0.5) * (z[2, 1, 1, 1, 1] - z[1, 1, 1, 1, 1]) - - boundary_space_field = zeros(coupler_sim.boundary_space) - - u_atm = atmos_sim !== nothing ? atmos_sim.integrator.u.c.ρe : nothing - u_lnd = land_sim !== nothing ? swap_space!(zeros(coupler_sim.boundary_space), land_sim.integrator.u.T_sfc) : nothing - u_ocn = - ocean_sim !== nothing ? swap_space!(zeros(coupler_sim.boundary_space), ocean_sim.integrator.u.T_sfc) : nothing - u_ice = - seaice_sim !== nothing ? swap_space!(zeros(coupler_sim.boundary_space), seaice_sim.integrator.u.T_sfc) : nothing - - # global sums - land_e = land_sim !== nothing ? sum(get_slab_energy(land_sim, u_lnd)) ./ Δz_bot : FT(0) - - if atmos_sim !== nothing - atmos_e = sum(u_atm) - - if radiation - - Δz_top = FT(0.5) * (z[end, 1, 1, 1, 1] - z[end - 1, 1, 1, 1, 1]) - nz = length(z[:, 1, 1, 1, 1]) - - LWu_TOA = Fields.level( - array2field(FT.(atmos_sim.integrator.p.rrtmgp_model.face_lw_flux_up), face_space), - nz - half, - ) - SWd_TOA = Fields.level( - array2field(FT.(atmos_sim.integrator.p.rrtmgp_model.face_sw_flux_dn), face_space), - nz - half, - ) - SWu_TOA = Fields.level( - array2field(FT.(atmos_sim.integrator.p.rrtmgp_model.face_sw_flux_up), face_space), - nz - half, - ) - - radiation_sources = -sum(SWd_TOA .- LWu_TOA .- SWu_TOA) ./ Δz_top - radiation_sources_accum = - size(cs.toa_net_source)[1] > 0 ? cs.toa_net_source[end] + radiation_sources .* coupler_sim.Δt : - radiation_sources .* coupler_sim.Δt# accumulated radiation sources + sinks - - - push!(cs.toa_net_source, radiation_sources_accum) - end - end - - ocean_mask(univ_mask, value1 = FT(-0.5), value2 = FT(0.5)) = - ((univ_mask >= FT(value1) && (univ_mask <= FT(value2))) ? FT(1) : FT(0)) - ice_mask_f(univ_mask, value1 = FT(-0.5)) = ((univ_mask <= FT(value1)) ? FT(1) : FT(0)) - - if (prescribed_sst !== true) && (prescribed_sic == true) - # zero out the ocean where there's sea ice - univ_mask = parent(mask) .- parent(seaice_sim.integrator.p.Ya.ice_mask .* FT(2)) - value1, value2 = (FT(-0.5), FT(0.5)) - - u_ocn_ = similar(u_ocn) - parent(u_ocn_) .= ocean_mask.(parent(univ_mask)) .* parent(u_ocn) - u_ocn = u_ocn_ - - ocean_e = ocean_sim !== nothing ? sum(get_slab_energy(ocean_sim, u_ocn)) ./ Δz_bot : FT(0) - seaice_e = seaice_sim !== nothing ? sum(get_slab_energy(seaice_sim, u_ice)) ./ Δz_bot : FT(0) - - # save to coupler cache - atmos_sim !== nothing ? push!(cs.ρe_tot_atmos, atmos_e) : nothing - land_sim !== nothing ? push!(cs.ρe_tot_land, land_e) : nothing - ocean_sim !== nothing ? push!(cs.ρe_tot_ocean, ocean_e) : nothing - seaice_sim !== nothing ? push!(cs.ρe_tot_seaice, seaice_e) : nothing - end - - if (prescribed_sic == false) - - # ocean (from T_ml) - u_ocn = - seaice_sim !== nothing ? swap_space!(zeros(coupler_sim.boundary_space), seaice_sim.integrator.u.T_ml) : - nothing - parent(u_ocn) .= abs.(parent(mask) .- FT(1)) .* parent(u_ocn) - ocean_e = ocean_sim !== nothing ? sum(get_ml_energy(seaice_sim, u_ocn)) ./ Δz_bot : FT(0) - - # ice (from h_ice) - u_ice = - seaice_sim !== nothing ? swap_space!(zeros(coupler_sim.boundary_space), seaice_sim.integrator.u.h_ice) : - nothing - parent(u_ice) .= abs.(parent(mask) .- FT(1)) .* parent(u_ice) - seaice_e = ocean_sim !== nothing ? sum(get_dyn_ice_energy(seaice_sim, u_ice)) ./ Δz_bot : FT(0) - - # save to coupler cache - atmos_sim !== nothing ? push!(cs.ρe_tot_atmos, atmos_e) : nothing - land_sim !== nothing ? push!(cs.ρe_tot_land, land_e) : nothing - ocean_sim !== nothing ? push!(cs.ρe_tot_ocean, ocean_e) : nothing - seaice_sim !== nothing ? push!(cs.ρe_tot_seaice, seaice_e) : nothing - end - -end - -function plot_global_energy(CS, coupler_sim, figname = "total_energy.png") - times = (coupler_sim.Δt):(coupler_sim.Δt):(atmos_sim.integrator.t) - diff_ρe_tot_atmos = (CS.ρe_tot_atmos .- CS.ρe_tot_atmos[1]) - diff_ρe_tot_slab = (CS.ρe_tot_land .- CS.ρe_tot_land[1]) - diff_ρe_tot_slab_seaice = (CS.ρe_tot_seaice .- CS.ρe_tot_seaice[1]) - diff_ρe_tot_slab_ocean = (CS.ρe_tot_ocean .- CS.ρe_tot_ocean[1]) - diff_toa_net_source = (CS.toa_net_source .- CS.toa_net_source[1]) - - tot = CS.ρe_tot_atmos .+ CS.ρe_tot_ocean .+ CS.ρe_tot_land .+ CS.ρe_tot_seaice .+ CS.toa_net_source - - times_days = floor.(times ./ (24 * 60 * 60)) - Plots.plot(diff_ρe_tot_atmos, label = "atmos") - Plots.plot!(diff_ρe_tot_slab, label = "land") - Plots.plot!(diff_ρe_tot_slab_ocean, label = "ocean") - Plots.plot!(diff_ρe_tot_slab_seaice, label = "seaice") - Plots.plot!(diff_toa_net_source, label = "toa") - - Plots.plot!( - tot .- tot[3], - label = "tot", - xlabel = "time [days]", - ylabel = "energy(t) - energy(t=0) [J]", - xticks = (collect(1:length(times))[1:1000:end], times_days[1:1000:end]), - color = "black", - ) - Plots.savefig(figname) - Plots.plot( - log.(abs.(tot .- tot[1]) / tot[1]), - label = "tot", - xlabel = "time [days]", - ylabel = "log( | e(t) - e(t=0)| / e(t=0))", - xticks = (collect(1:length(times))[1:50:end], times_days[1:50:end]), - ) - Plots.savefig(figname[1:(end - 4)] * "_logerror.png") -end diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/flux_calculator.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/flux_calculator.jl deleted file mode 100644 index be91ed1e27..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/flux_calculator.jl +++ /dev/null @@ -1,131 +0,0 @@ -using ClimaCore.Geometry: ⊗ -using ClimaCore.Utilities: half, PlusHalf - -""" -calculate_surface_fluxes_atmos_grid!(integrator) - -- TODO: generalize interface for regridding and take land state out of atmos's integrator.p -""" -function calculate_surface_fluxes_atmos_grid!(integrator, info_sfc) - p = integrator.p - (; ᶜts, ρ_dif_flux_h_tot, ρ_dif_flux_q_tot, ρ_dif_flux_uₕ, ∂F_aero∂T_sfc, params, Cd, Ch) = p - - (; T_sfc, z0m, z0b, ice_mask) = info_sfc - Y = integrator.u - - # Turbulent surface flux calculation - tsf = - constant_T_saturated_surface_coefs_coupled.( - Spaces.level(ᶜts, 1), - Geometry.UVVector.(Spaces.level(Y.c.uₕ, 1)), - Spaces.level(Fields.coordinate_field(Y.c).z, 1), - FT(0), # TODO: get actual value of z_sfc - swap_space!(zeros(axes(Spaces.level(Y.c, 1))), T_sfc), # remove when same instance issue is resolved - params, - swap_space!(zeros(axes(Spaces.level(Y.c, 1))), z0m), # TODO: get these roughness lengths from land - swap_space!(zeros(axes(Spaces.level(Y.c, 1))), z0b), - Cd, - Ch, - ) - - # Total energy flux - if :ρe in propertynames(Y.c) - - flux_energy = ones(axes(ρ_dif_flux_h_tot)) - parent(flux_energy) .= parent(tsf.shf .+ tsf.lhf .* swap_space!(zeros(axes(tsf.shf)), abs.(ice_mask .- FT(1)))) # only SHF above sea ice - @. ρ_dif_flux_h_tot = Geometry.WVector(flux_energy) #Geometry.WVector.(swap_space!(zeros(axes(ρ_dif_flux_h_tot)), tsf.shf .+ tsf.lhf) ) - end - - # Moisture mass flux - if :ρq_tot in propertynames(Y.c) - flux_mass = ones(axes(ρ_dif_flux_q_tot)) - parent(flux_mass) .= parent(tsf.E .* swap_space!(zeros(axes(tsf.E)), abs.(ice_mask .- FT(1)))) - @. ρ_dif_flux_q_tot = Geometry.WVector(flux_mass) # no E above sea ice - end - - # Momentum flux - u_space = axes(tsf.ρτxz) # TODO: delete when "space not the same instance" error is dealt with - normal = Geometry.WVector.(ones(u_space)) # TODO: this will need to change for topography - ρ_1 = Fields.Field(Fields.field_values(Fields.level(Y.c.ρ, 1)), u_space) # TODO: delete when "space not the same instance" error is dealt with - if :uₕ in propertynames(Y.c) - parent(ρ_dif_flux_uₕ) .= # TODO: remove parent when "space not the same instance" error is dealt with - parent( - Geometry.Contravariant3Vector.(normal) .⊗ - Geometry.Covariant12Vector.(Geometry.UVVector.(tsf.ρτxz ./ ρ_1, tsf.ρτyz ./ ρ_1)), - ) - end - - # calculate gradient - TODO: make this just optional (only required by stub sea ice model) - ΔT_sfc = FT(0.1) # following FMS - tsf1 = - constant_T_saturated_surface_coefs_coupled.( - Spaces.level(ᶜts, 1), - Geometry.UVVector.(Spaces.level(Y.c.uₕ, 1)), - Spaces.level(Fields.coordinate_field(Y.c).z, 1), - FT(0), # TODO: get actual value of z_sfc - swap_space!(zeros(axes(Spaces.level(Y.c, 1))), T_sfc .+ ΔT_sfc), # remove when same instance issue is resolved - params, - swap_space!(zeros(axes(Spaces.level(Y.c, 1))), z0m), # TODO: get these roughness lengths from land - swap_space!(zeros(axes(Spaces.level(Y.c, 1))), z0b), - Cd, - Ch, - ) - - p.∂F_aero∂T_sfc .= ((tsf1.shf .+ tsf1.lhf) .- (tsf.shf .+ tsf.lhf)) ./ ΔT_sfc - - return nothing -end - -function variable_T_saturated_surface_coefs(ts_int, uₕ_int, z_int, z_sfc, T_sfc, params, z0m, z0b) - - # get the near-surface thermal state - T_int = TD.air_temperature(params, ts_int) - Rm_int = TD.gas_constant_air(params, ts_int) - ρ_sfc = TD.air_density(params, ts_int) * (T_sfc / T_int)^(TD.cv_m(params, ts_int) / Rm_int) # use ideal gas law and hydrostatic balance to extrapolate for surface density - - q_sfc = TD.q_vap_saturation_generic(params, T_sfc, ρ_sfc, TD.Liquid()) # TODO: assumes all surface is water covered. Generalize! - ts_sfc = TD.PhaseEquil_ρTq(params, ρ_sfc, T_sfc, q_sfc) - - # wrap state values - sc = SF.ValuesOnly{FT}(; - state_in = SF.InteriorValues(z_int, (uₕ_int.u, uₕ_int.v), ts_int), - state_sfc = SF.SurfaceValues(z_sfc, (FT(0), FT(0)), ts_sfc), - z0m = z0m, - z0b = z0b, - ) - - # calculate all fluxes - tsf = SF.surface_conditions(params, sc, SF.UniversalFunctions.Businger()) - - E = SF.evaporation(sc, params, tsf.Ch) - - return (; shf = tsf.shf, lhf = tsf.lhf, E = E, ρτxz = tsf.ρτxz, ρτyz = tsf.ρτyz) -end - -function constant_T_saturated_surface_coefs_coupled(ts_int, uₕ_int, z_int, z_sfc, T_sfc, params, z0m, z0b, Cd, Ch) - - # get the near-surface thermal state - T_int = TD.air_temperature(params, ts_int) - Rm_int = TD.gas_constant_air(params, ts_int) - ρ_sfc = TD.air_density(params, ts_int) * (T_sfc / T_int)^(TD.cv_m(params, ts_int) / Rm_int) # use ideal gas law and hydrostatic balance to extrapolate for surface density - - q_sfc = TD.q_vap_saturation_generic(params, T_sfc, ρ_sfc, TD.Liquid()) # TODO: assumes all surface is water covered. Generalize! - ts_sfc = TD.PhaseEquil_ρTq(params, ρ_sfc, T_sfc, q_sfc) - - # wrap state values - sc = SF.Coefficients{FT}(; - state_in = SF.InteriorValues(z_int, (uₕ_int.u, uₕ_int.v), ts_int), - state_sfc = SF.SurfaceValues(z_sfc, (FT(0), FT(0)), ts_sfc), - z0m = z0m, #FT(1e-3), - z0b = z0b, #FT(1e-5), - Cd = Cd, #FT(0.001), - Ch = Ch, #FT(0.0001), - ) - - # calculate all fluxes - tsf = SF.surface_conditions(params, sc, SF.UniversalFunctions.Businger()) # here can specify tol, maxiter - - E = SF.evaporation(sc, params, tsf.Ch) - - return (; shf = tsf.shf, lhf = tsf.lhf, E = E, ρτxz = tsf.ρτxz, ρτyz = tsf.ρτyz) -end diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/general_helper.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/general_helper.jl deleted file mode 100644 index 0f8a997d18..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/general_helper.jl +++ /dev/null @@ -1,21 +0,0 @@ -# most of these functions are temporary helpers until upstream issues are resolved - -# TODO: unify with coupler interface -struct CouplerSimulation{FT, B, M} - boundary_space::B - mask::M - t::FT - Δt::FT -end - -CouplerSimulation{FT}(args...) where {FT} = CouplerSimulation{FT, typeof.(args[1:2])...}(args...) -float_type(::CouplerSimulation{FT}) where {FT} = FT - -get_u(sim, t) = Geometry.UVVector.(sim.integrator.sol.u[t].c.uₕ).components.data.:1 - -function swap_space!(field_out, field_in) - parent(field_out) .= parent(field_in) - return field_out -end - -heaviside(var) = var < 0 ? 0 : var diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/masker.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/masker.jl deleted file mode 100644 index 47ce0c5509..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/masker.jl +++ /dev/null @@ -1,42 +0,0 @@ -# TODO: build abstraction -# abstract type AbstractMaskType end -# struct land_sea_mask{I, FT, D} <: AbstractMaskType -# infile:: String -# ne:: I -# Nq:: I -# R:: FT -# data:: D -# end - -function land_sea_mask(FT, infile, varname, h_space; outfile = "data_cc.nc") - R = h_space.topology.mesh.domain.radius - ne = h_space.topology.mesh.ne - Nq = Spaces.Quadratures.polynomial_degree(h_space.quadrature_style) + 1 - - mask = ncreader_rll_to_cgll(FT, infile, varname, ne = ne, R = R, Nq = Nq) - mask = clean_mask.(FT, mask) - # land_sea_mask(infile, ne, Nq, R, mask) -end - -""" -clean_mask(FT, mask) -- convert to integer values after interpolation (but keep type as floats foe easier calculation (TODO)) -""" -clean_mask(FT, mask) = mask > FT(0.7) ? FT(1) : FT(0) - -""" -combine_surface(mask, sfc_1, sfc_2) -- combine two masked surfaces on the same horizontal topology (TODO: generalize to more surfaces and different resolutions) -""" -combine_surface(mask, sfc_1, sfc_2, value = 0.5) = - (mask > FT(value) ? sfc_1 : FT(0)) + (mask <= FT(value) ? sfc_2 : FT(0)) -combine_surface(mask, sfc_1, sfc_2, sfc_3, value1 = -0.5, value2 = 0.5) = - (mask < FT(value1) ? sfc_3 : FT(0)) + - ((mask >= FT(value1) && (mask <= FT(value2))) ? sfc_2 : FT(0)) + - (mask > FT(value2) ? sfc_1 : FT(0)) - -""" -apply_mask(mask, condition, yes, no, value = 0.5) -- apply mask mased on a threshold value in the mask -""" -apply_mask(mask, condition, yes, no, value) = condition(mask, value) ? yes : no diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/regridder.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/regridder.jl deleted file mode 100644 index a0ec60db5d..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/regridder.jl +++ /dev/null @@ -1,123 +0,0 @@ -import ClimaCore -using ClimaCore: Geometry, Meshes, Domains, Topologies, Spaces, Fields -using NCDatasets -import Pkg; -Pkg.add("TempestRemap_jll"); -using TempestRemap_jll -using Test -using ClimaCoreTempestRemap - -REGRID_DIR = "regrid_tmp/" - -function reshape_sparse_to_field!(field::Fields.Field, in_array::Array, R) - field_array = parent(field) - - fill!(field_array, zero(eltype(field_array))) - Nf = size(field_array, 3) - - f = 1 - for (n, row) in enumerate(R.row_indices) - it, jt, et = (view(R.target_idxs[1], n), view(R.target_idxs[2], n), view(R.target_idxs[3], n)) - for f in 1:Nf - field_array[it, jt, f, et] .= in_array[row] - end - end - # broadcast to the redundant nodes using unweighted dss - space = axes(field) - topology = Spaces.topology(space) - hspace = Spaces.horizontal_space(space) - Spaces.dss!(Fields.field_values(field), topology, hspace.quadrature_style) - return field -end - -""" -ncreader_rll_to_cgll() -- nc file needs to be in the exodus format -""" -function ncreader_rll_to_cgll( - FT, - datafile_rll, - varname; - outfile = "data_cgll.nc", - ne = 4, - R = 5.0, - Nq = 5, - clean_exodus = true, -) - isdir(REGRID_DIR) ? nothing : mkpath(REGRID_DIR) - - nlat, nlon = NCDataset(datafile_rll) do ds - (ds.dim["lat"], ds.dim["lon"]) - end - - meshfile_rll = joinpath(REGRID_DIR, "mesh_rll.g") - rll_mesh(meshfile_rll; nlat = nlat, nlon = nlon) - - meshfile_cgll = joinpath(REGRID_DIR, "mesh_cgll.g") - - domain = Domains.SphereDomain(R) - mesh = Meshes.EquiangularCubedSphere(domain, ne) - topology = Topologies.Topology2D(mesh) - quad = Spaces.Quadratures.GLL{Nq}() - space = Spaces.SpectralElementSpace2D(topology, quad) - coords = Fields.coordinate_field(space) - - # write mesh - write_exodus(meshfile_cgll, topology) - - meshfile_overlap = joinpath(REGRID_DIR, "mesh_overlap.g") - overlap_mesh(meshfile_overlap, meshfile_rll, meshfile_cgll) - - weightfile = joinpath(REGRID_DIR, "remap_weights.nc") - remap_weights(weightfile, meshfile_rll, meshfile_cgll, meshfile_overlap; out_type = "cgll", out_np = Nq) - - datafile_cgll = joinpath(REGRID_DIR, outfile) - - apply_remap(datafile_cgll, datafile_rll, weightfile, [varname]) - - # read the remapped file - offline_outarray = NCDataset(datafile_cgll, "r") do ds_wt - ds_wt[varname][:][:, 1] - end - - offline_outarray = FT.(offline_outarray) - - field_o = Fields.zeros(FT, space) - - # need to populate all nodes - weights, col_indices, row_indices = NCDataset(weightfile, "r") do ds_wt - (Array(ds_wt["S"]), Array(ds_wt["col"]), Array(ds_wt["row"])) - end - - out_type = "cgll" - - target_unique_idxs = out_type == "cgll" ? collect(Spaces.unique_nodes(space)) : collect(Spaces.all_nodes(space)) - - target_unique_idxs_i = map(row -> target_unique_idxs[row][1][1], row_indices) - target_unique_idxs_j = map(row -> target_unique_idxs[row][1][2], row_indices) - target_unique_idxs_e = map(row -> target_unique_idxs[row][2], row_indices) - - target_unique_idxs = (target_unique_idxs_i, target_unique_idxs_j, target_unique_idxs_e) - - R = (; target_idxs = target_unique_idxs, row_indices = row_indices) - - offline_field = similar(field_o) - - clean_exodus ? run(`mkdir -p $REGRID_DIR`) : nothing - - reshape_sparse_to_field!(offline_field, offline_outarray, R) - -end - -function ncreader_rll_to_cgll_from_space(FT, infile, varname, h_space) - R = h_space.topology.mesh.domain.radius - ne = h_space.topology.mesh.ne - Nq = Spaces.Quadratures.polynomial_degree(h_space.quadrature_style) + 1 - - mask = ncreader_rll_to_cgll(FT, infile, varname, ne = ne, R = R, Nq = Nq) -end - -# for AMIP we don't need regridding. When we do we re-introduce the ClimaCoreTempestRemap -function dummmy_remap!(target, source) # TODO: bring back Tempest regrid - parent(target) .= parent(source) -end diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/viz_explorer.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/viz_explorer.jl deleted file mode 100644 index 97a1eec3b3..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/viz_explorer.jl +++ /dev/null @@ -1,93 +0,0 @@ -using ClimaCorePlots -using ClimaCore: Geomtry - -function plot_anim(atmos_sim, slab_sim, slab_ocean_sim, slab_ice_sim) # TODO: uses global defs - - sol_atm = atmos_sim.integrator.sol - sol_slab = slab_sim.integrator.sol - sol_slab_ocean = slab_ocean_sim.integrator.sol - sol_slab_ice = slab_ice_sim.integrator.sol - - anim = Plots.@animate for u in sol_atm.u - Plots.plot(Fields.level(Geometry.UVVector.(u.c.uₕ).components.data.:1, 1)) - end - Plots.mp4(anim, "anim_u.mp4", fps = 10) - - anim = Plots.@animate for u in sol_atm.u - Plots.plot(Fields.level(Geometry.UVVector.(u.c.uₕ).components.data.:1, 5)) - end - Plots.mp4(anim, "anim_u_7km.mp4", fps = 10) - - anim = Plots.@animate for u in sol_atm.u - Plots.plot(Fields.level(u.c.ρe, 1)) - end - Plots.mp4(anim, "anim_rhoe.mp4", fps = 10) - - anim = Plots.@animate for u in sol_slab.u - Plots.plot(u.T_sfc)#, clims = (240, 330)) - end - Plots.mp4(anim, "slab_T.mp4", fps = 10) - - anim = Plots.@animate for u in sol_atm.u - Plots.plot(Fields.level(u.c.ρe, 1) .- Fields.level(sol_atm.u[1].c.ρe, 1), clims = (-5000, 50000)) - end - Plots.mp4(anim, "anim_rhoe_anom.mp4", fps = 10) - - anim = Plots.@animate for u in sol_atm.u - Plots.plot(Fields.level(u.c.ρe, 5) .- Fields.level(sol_atm.u[1].c.ρe, 5), clims = (-1000, 3000)) - end - Plots.mp4(anim, "anim_rhoe_anom_7km.mp4", fps = 10) - - anim = Plots.@animate for u in sol_atm.u - Plots.plot(Fields.level(u.c.ρq_tot, 1))#.- Fields.level(sol_atm.u[1].c.ρt_tot,1), clims = (-5000, 50000) ) - end - Plots.mp4(anim, "anim_rhoqt.mp4", fps = 10) - - anim = Plots.@animate for u in sol_atm.u - Plots.plot(Fields.level(u.c.ρq_tot, 2), clims = (0, 0.005))#.- Fields.level(sol_atm.u[1].c.ρt_tot,1), clims = (-5000, 50000) ) - end - Plots.mp4(anim, "anim_rhoqt_1km_v2.mp4", fps = 10) - - anim = Plots.@animate for u in sol_atm.u - Plots.plot(Fields.level(u.c.ρq_tot, 5), clims = (0, 0.001))#.- Fields.level(sol_atm.u[1].c.ρt_tot,1), clims = (-5000, 50000) ) - end - Plots.mp4(anim, "anim_rhoqt_7km_v2.mp4", fps = 10) - - anim = Plots.@animate for u in sol_atm.u - Plots.plot(mask) - end - Plots.mp4(anim, "mask.mp4", fps = 10) - - times = 0:saveat:t_end - anim = Plots.@animate for t_i in 1:1:length(sol_slab.u) - t = t_i / 24 / 60 / 60 - u = sol_slab.u[t_i] - u_o = sol_slab_ocean.u[1] - u_i = sol_slab_ice.u[t_i] - combined_field = similar(u.T_sfc) - #parent(combined_field) .= combine_surface.(parent(mask), parent(u.T_sfc), parent(SST) ) - parent(combined_field) .= - combine_surface.( - parent(mask) .- parent(slab_ice_sim.integrator.p.Ya.ice_mask .* FT(2)), - parent(u.T_sfc), - parent(u_o.T_sfc), - parent(u_i.T_sfc), - ) - Plots.plot(combined_field, clims = (265, 310), title = ("day: $t")) - end - Plots.mp4(anim, "slab_T_combo.mp4", fps = 10) - - if :h_ice in propertynames(sol_slab_ice.u[1]) - anim = Plots.@animate for t_i in 1:1:length(sol_slab.u) - u = slab_ice_sim.integrator.sol.u[t_i] - t = t_i / 24 / 60 / 60 - Plots.plot( - u.h_ice .* swap_space!(zeros(axes(u.h_ice)), abs.(mask .- FT(1))), - clims = (0, 0.35), - title = ("day: $t"), - )#.- Fields.level(sol_atm.u[1].c.ρt_tot,1), clims = (-5000, 50000) ) - end - Plots.mp4(anim, "h_ice.mp4", fps = 10) - end - -end diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/vtk_helper.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/vtk_helper.jl deleted file mode 100644 index 6f57c639bc..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/coupler_utils/vtk_helper.jl +++ /dev/null @@ -1,45 +0,0 @@ -## Plot VTK output on the 2D cubed-sphere, building on from ClimaCoreWorkshops -using ClimaCoreVTK - -# Plot the time series - -""" - convert_field_to_type(space_old, space_new, field) -- used specifically to convert a Field from Float32 to Float64, which is acceptable for ClimaCoreVTK.writepvd -""" -function convert_field_to_type(space_new, field_old) - fieldT = ones(space_new) - fieldT_data = convert.(eltype(space_new), parent(field_old)) - parent(fieldT) .= fieldT_data - return fieldT -end - -""" - retype_space(space::ClimaCore.Spaces.ExtrudedFiniteDifferenceSpace{CellCenter}, T) -- used specifically to convert a space from Float32 to Float64, which feed into `convert_field_to_type` -""" -function retype_space(space::ClimaCore.Spaces.ExtrudedFiniteDifferenceSpace{ClimaCore.Spaces.CellCenter}, T) - R = space.horizontal_space.topology.mesh.domain.radius - ne = space.horizontal_space.topology.mesh.ne - Nq = Spaces.Quadratures.polynomial_degree(space.horizontal_space.quadrature_style) + 1 - - horizontal_meshT = cubed_sphere_mesh(; radius = T(R), h_elem = ne) - h_spaceT = make_horizontal_space(horizontal_meshT, quad, nothing) - - z_stretch = Meshes.GeneralizedExponentialStretching(T(500), T(5000)) # TODO - z_max = space.vertical_topology.mesh.domain.coord_max.z - z_elem = 10 # TODO - spaceT, _ = make_hybrid_spaces(h_spaceT, T(z_max), z_elem, z_stretch) - return spaceT -end - -function retype_space(space::ClimaCore.Spaces.SpectralElementSpace2D, T) - R = space.topology.mesh.domain.radius - ne = space.topology.mesh.ne - Nq = Spaces.Quadratures.polynomial_degree(space.quadrature_style) + 1 - - horizontal_meshT = cubed_sphere_mesh(; radius = T(R), h_elem = ne) - h_spaceT = make_horizontal_space(horizontal_meshT, quad, nothing) - - return h_spaceT -end diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/mpi/mpi_init.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/mpi/mpi_init.jl deleted file mode 100644 index 94ef7f6dc3..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/mpi/mpi_init.jl +++ /dev/null @@ -1,33 +0,0 @@ -import Pkg; -Pkg.add("ClimaComms"); -import Pkg; -Pkg.add("ClimaCommsMPI"); - -using ClimaComms -using ClimaCommsMPI - - -is_distributed = get(ENV, "CLIMACORE_DISTRIBUTED", "") == "MPI" - -using Logging -if is_distributed - using ClimaComms - if ENV["CLIMACORE_DISTRIBUTED"] == "MPI" - using ClimaCommsMPI - const comms_ctx = ClimaCommsMPI.MPICommsContext() - else - error("ENV[\"CLIMACORE_DISTRIBUTED\"] only supports the \"MPI\" option") - end - const pid, nprocs = ClimaComms.init(comms_ctx) - logger_stream = ClimaComms.iamroot(comms_ctx) ? stderr : devnull - prev_logger = global_logger(ConsoleLogger(logger_stream, Logging.Info)) - @info "Setting up distributed run on $nprocs \ - processor$(nprocs == 1 ? "" : "s")" -else - const comms_ctx = nothing - using TerminalLoggers: TerminalLogger - prev_logger = global_logger(TerminalLogger()) -end -atexit() do - global_logger(prev_logger) -end diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/sbatch_job.sh b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/sbatch_job.sh deleted file mode 100644 index 5ea211350b..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/sbatch_job.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - - -#SBATCH --ntasks=2 -#SBATCH --time=10:00:00 # walltime - -set -euo pipefail # kill the job if anything fails -set -x # echo script - -module purge -module load julia/1.9.3 openmpi/4.1.1 hdf5/1.12.1-ompi411 #netcdf-c/4.6.1 - -export JULIA_NUM_THREADS=${SLURM_CPUS_PER_TASK:=1} -export JULIA_MPI_BINARY=system -export JULIA_CUDA_USE_BINARYBUILDER=false - -# run instantiate/precompile serial -julia --project -e 'using Pkg; Pkg.instantiate(); Pkg.build()' - -export CLIMACORE_DISTRIBUTED="MPI" -mpiexec julia --project coupler_driver.jl diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/slab/slab_init.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/slab/slab_init.jl deleted file mode 100644 index aefcb86e0e..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/slab/slab_init.jl +++ /dev/null @@ -1,91 +0,0 @@ -# slab_rhs! -using ClimaCore - -struct ThermalSlabParameters# <: CLIMAParameters.AbstractEarthParameterSet{F} - h::FT - ρ::FT - c::FT - T_init::FT - z0m::FT - z0b::FT -end - -# domain -function ShellDomain(; radius = 6371e3, Nel = 8, Nq = 2) - domain = ClimaCore.Domains.SphereDomain(radius) - mesh = ClimaCore.Meshes.EquiangularCubedSphere(domain, Nel) - topology = ClimaCore.Topologies.Topology2D(mesh) - quad = ClimaCore.Spaces.Quadratures.GLL{Nq}() - space = ClimaCore.Spaces.SpectralElementSpace2D(topology, quad) -end - -struct SlabSimulation{P, Y, D, I} - params::P - Y_init::Y - domain::D - integrator::I -end - -# init simulation -function slab_space_init(::Type{FT}, space, p; anomaly = false, hs_sfc = false) where {FT} - - coords = ClimaCore.Fields.coordinate_field(space) - - # initial condition - T_sfc = map(coords) do coord - T_sfc_0 = FT(p.T_init) - radlat = coord.lat / FT(180) * pi - ΔT = FT(0) - if anomaly == true - anom_ampl = FT(0) - lat_0 = FT(60) / FT(180) * pi - lon_0 = FT(-90) / FT(180) * pi - radlon = coord.long / FT(180) * pi - stdev = FT(5) / FT(180) * pi - ΔT = anom_ampl * exp(-((radlat - lat_0)^2 / 2stdev^2 + (radlon - lon_0)^2 / 2stdev^2)) - elseif hs_sfc == true - ΔT = -FT(60) * sin(radlat)^2 - end - T_sfc_0 + ΔT - end - - # prognostic variable - Y = ClimaCore.Fields.FieldVector(T_sfc = T_sfc) - - return Y, space -end - -get_slab_energy(slab_sim, T_sfc) = slab_sim.params.ρ .* slab_sim.params.c .* T_sfc .* slab_sim.params.h - -function slab_rhs!(dY, Y, Ya, t) - """ - Slab: - ∂_t T_sfc = F_aero + G - """ - p, F_aero, F_rad, mask = Ya - - rhs = @. -(F_aero + F_rad) / (p.h * p.ρ * p.c) - parent(dY.T_sfc) .= apply_mask.(parent(mask), >, parent(rhs), FT(0), FT(0.5)) -end - -function slab_init( - ::Type{FT}, - tspan; - stepper = Euler(), - nelements = 6, - npolynomial = 4, - dt = 0.02, - saveat = 1.0e10, - space = nothing, - mask = nothing, -) where {FT} - - params = ThermalSlabParameters(FT(1), FT(1500.0), FT(800.0), FT(315.0), FT(1e-3), FT(1e-5)) # T_init close to the average of T_1 in atmos - - Y, space = slab_space_init(FT, space, params, hs_sfc = true) - Ya = (params = params, F_aero = ClimaCore.Fields.zeros(space), F_rad = ClimaCore.Fields.zeros(space), mask = mask) #auxiliary - problem = OrdinaryDiffEq.ODEProblem(slab_rhs!, Y, tspan, Ya) - integrator = OrdinaryDiffEq.init(problem, stepper, dt = dt, saveat = saveat) - - SlabSimulation(params, Y, space, integrator) -end diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/slab_ice/slab_init.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/slab_ice/slab_init.jl deleted file mode 100644 index f4a1de79cd..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/slab_ice/slab_init.jl +++ /dev/null @@ -1,213 +0,0 @@ -# slab_ice - -# sea-ice parameters -struct IceSlabParameters# <: CLIMAParameters.AbstractEarthParameterSet{F} - h::FT # sea ice height - ρ::FT - c::FT - T_init::FT - z0m::FT - z0b::FT - ρc_ml::FT # density times heat transfer coefficient for mixed layer [J / m2 / K ] - F0_base::FT # ice base transfer coefficient [W / m2 / K] - T_base::FT # ice base temperature [K] - L_ice::FT # latent heat coefficient for ice [J / m3] - h_ml::FT # mixed layer depth [m] - T_freeze::FT # temperature at freezing point [K] - k_ice::FT # thermal conductivity of ice [W / m / K] - α::FT # albedo - σ::FT # Stefan Boltzmann constant -end - -# init simulation -function slab_ice_space_init(::Type{FT}, space, p) where {FT} - - # prognostic variable - Y = Fields.FieldVector(T_sfc = ones(space) .* p.T_freeze, h_ice = zeros(space), T_ml = ones(space) .* p.T_freeze) - - return Y, space -end - -""" - solve_ice!(dT_sfc, T_sfc, (parameters, F_accumulated), t) - -slab RHS with an implicit solve ice and explicit (forward Euler) solve for ocean - -""" -function solve_ice!(integ, Δt) - - Y = integ.u - Ya = integ.p.Ya - p = integ.p.Ya.params - - # prognostic - T_ml = Y.T_ml - T_sfc = Y.T_sfc - h_ice = Y.h_ice - - # auxiliary - F_atm = @. Ya.F_aero + Ya.F_rad - ∂F_atm∂T_sfc = get_∂F_atm∂T_sfc(p, T_sfc, Ya) # this will be passed from atmos/SF.jl - F_base = similar(T_sfc) - - sm = semtner_zero_layer_model.(T_ml, T_sfc, h_ice, F_atm, ∂F_atm∂T_sfc, Ref(p), Ref(Δt)) - - T_ml .= sm.T_ml - h_ice .= sm.h_ice - T_sfc .= sm.T_sfc - F_base .= sm.F_base - - # update state - @. Y.T_ml = T_ml - @. Y.h_ice = h_ice - @. Y.T_sfc = T_sfc - - Ya.ice_mask .= get_ice_mask.(h_ice) - Ya.F_base .= F_base - - return nothing -end - - -function semtner_zero_layer_model(T_ml, T_sfc, h_ice, F_atm, ∂F_atm∂T_sfc, p, Δt) - - # local - ocean_qflux = FT(0) - F_base = FT(0) - - # ice thickness and mixed layer temperature changes due to atmosphereic and ocean fluxes - if h_ice > 0 # ice-covered - F_base = p.F0_base * (T_ml - p.T_base) - ΔT_ml = -(F_base + ocean_qflux) * Δt / (p.h_ml * p.ρc_ml) - Δh_ice = (F_atm - F_base) * Δt / p.L_ice - else # ice-free - ΔT_ml = -(F_atm + ocean_qflux) * Δt / (p.h_ml * p.ρc_ml) - Δh_ice = 0 - end - - # adjust if transition to ice-covered - if (T_ml[1] + ΔT_ml[1] < p.T_freeze) - Δh_ice = Δh_ice - (T_ml + ΔT_ml - p.T_freeze) * (p.h_ml * p.ρc_ml) / p.L_ice - ΔT_ml = p.T_freeze - T_ml - end - - # adjust if transition to ice-free - if ((h_ice[1] > 0) & (h_ice[1] + Δh_ice[1] <= 0)) - ΔT_ml = ΔT_ml - (h_ice + Δh_ice) * p.L_ice / (p.h_ml * p.ρc_ml) - Δh_ice = -h_ice - end - - # solve for T_sfc - if (h_ice[1] + Δh_ice[1] > 0) # surface is ice-covered - # if ice covered, solve implicity (for now one Newton iteration: ΔT_s = - F(T_s) / dF(T_s)/dT_s ) - F_conductive = p.k_ice / (h_ice + Δh_ice) * (p.T_base - T_sfc) - ΔT_sfc = (-F_atm + F_conductive) / (p.k_ice / (h_ice + Δh_ice) + ∂F_atm∂T_sfc) - if (T_sfc[1] + ΔT_sfc[1] > p.T_freeze) - ΔT_sfc = p.T_freeze - T_sfc - end - # surface is ice-covered, so update T_sfc as ice surface temperature - - T_sfc += FT(ΔT_sfc) - else # ice-free, so update T_sfc as mixed layer temperature - T_sfc = FT(T_ml + ΔT_ml) - end - - T_ml += FT(ΔT_ml) - h_ice += FT(Δh_ice) - - return (; T_ml = FT(T_ml), h_ice = FT(h_ice), F_base = FT(F_base), T_sfc = FT(T_sfc)) -end - -get_∂F_atm∂T_sfc(p, T_sfc, Ya) = @. FT(4) * (FT(1) - p.α) * p.σ * T_sfc^3 + Ya.∂F_aero∂T_sfc - -function ∑tendencies_ice_stub(du, u, p, t) - dY = du - Y = u - FT = eltype(dY) - - if p.Ya.prescribed_sic_data !== nothing # Prognostic eqn for T_sfc - - @show "pres SIC" - params = p.Ya.params - F_aero = p.Ya.F_aero - F_rad = p.Ya.F_rad - ice_mask = p.Ya.ice_mask - - F_conductive = @. params.k_ice / (params.h) * (params.T_base - Y.T_sfc) .* FT(0) - rhs = @. (-F_aero - F_rad + F_conductive) / (params.h * params.ρ * params.c) - - # ∂F_atm∂T_sfc = get_∂F_atm∂T_sfc(p, T_sfc, Ya) - # rhs = @. (-F_aero - F_rad + F_conductive) / (p.k_ice / params.h + ∂F_atm∂T_sfc) - parent(dY.T_sfc) .= apply_mask.(parent(ice_mask), >, parent(rhs), FT(0), FT(0)) - else - solve_ice!((; u = u, p = p), p.Ya.Δt) # timestepping outside of DeffEq (but DeffEq still used here for saving vars in `integ.sol`) - - @. dY.T_ml = FT(0) - @. dY.h_ice = FT(0) - @. dY.T_sfc = FT(0) - end -end - -function slab_ice_init( - ::Type{FT}, - tspan, - ocean_params; - stepper = Euler(), - nelements = 6, - npolynomial = 4, - dt = 0.02, - saveat = 1.0e10, - space = nothing, - mask = nothing, - prescribed_sic_data = nothing, -) where {FT} - - params = IceSlabParameters( - FT(2), - FT(1500.0), - FT(800.0), - FT(280.0), - FT(1e-3), - FT(1e-5), - FT(ocean_params.ρ * ocean_params.c), #rho c - FT(120), - FT(273.16), - FT(3e8), - FT(ocean_params.h), # h_ml - FT(273.16), - FT(2), - FT(0.38), - FT(5.67e-8), - ) # TODO: better interface, use CLIMAParameters - - ice_mask = - prescribed_sic_data !== nothing ? get_ice_mask.(prescribed_sic_data .- FT(25)) : ClimaCore.Fields.zeros(space) # here 25% and lower is considered ice free # TODO: generalize to a smooth function of ice fraction - - #ice_mask = ClimaCore.Fields.zeros(space) - Y, space = slab_ice_space_init(FT, space, params) - Ya = (; - params = params, - F_aero = ClimaCore.Fields.zeros(space), - ∂F_aero∂T_sfc = ClimaCore.Fields.zeros(space), - F_rad = ClimaCore.Fields.zeros(space), - mask = mask, - ice_mask = ice_mask, - Δt = dt, - prescribed_sic_data = prescribed_sic_data, - F_base = ClimaCore.Fields.zeros(space), - ) #auxiliary - - problem = OrdinaryDiffEq.ODEProblem(∑tendencies_ice_stub, Y, tspan, (; Ya = Ya)) - integrator = OrdinaryDiffEq.init(problem, stepper, dt = dt, saveat = saveat) - - - SlabSimulation(params, Y, space, integrator) -end - -get_ice_mask(h_ice) = h_ice > FT(0) ? FT(1) : FT(0) - -get_ml_energy(slab_sim, T_sfc) = T_sfc .* slab_sim.params.h_ml .* slab_sim.params.ρc_ml #slab_sim.params.ρ .* slab_sim.params.c .* T_sfc .* slab_sim.params.h - -get_ice_energy(slab_sim, T_sfc) = T_sfc ./ slab_sim.params.h .* slab_sim.params.k_ice - -get_dyn_ice_energy(seaice_sim, h_ice) = .-h_ice .* seaice_sim.integrator.p.Ya.params.L_ice diff --git a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/slab_ocean/slab_init.jl b/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/slab_ocean/slab_init.jl deleted file mode 100644 index 36423d0fe3..0000000000 --- a/experiments/AMIP/moist_mpi_earth_dynamical_sea_ice/slab_ocean/slab_init.jl +++ /dev/null @@ -1,70 +0,0 @@ -# slab_rhs! -using ClimaCore - -# ocean parameters -struct OceanSlabParameters# <: CLIMAParameters.AbstractEarthParameterSet{F} - h::FT - ρ::FT - c::FT - T_init::FT - z0m::FT - z0b::FT -end - -# init simulation -function slab_ocean_space_init(::Type{FT}, space, p) where {FT} - - coords = ClimaCore.Fields.coordinate_field(space) - - # initial condition - T_sfc = map(coords) do coord - T_sfc_0 = FT(p.T_init) #- FT(275) # close to the average of T_1 in atmos - anom_ampl = FT(0) - radlat = coord.lat / FT(180) * pi - lat_0 = FT(60) / FT(180) * pi - lon_0 = FT(-90) / FT(180) * pi - radlon = coord.long / FT(180) * pi - stdev = FT(5) / FT(180) * pi - anom = anom_ampl * exp(-((radlat - lat_0)^2 / 2stdev^2 + (radlon - lon_0)^2 / 2stdev^2)) - T_sfc = T_sfc_0 + anom - end - - # prognostic variable - Y = ClimaCore.Fields.FieldVector(T_sfc = T_sfc) - - return Y, space -end - -# ode -function slab_ocean_rhs!(dY, Y, Ya, t) - """ - Slab ocean: - ∂_t T_sfc = F_aero + G - """ - p, F_aero, F_rad, mask = Ya - - rhs = @. -(F_aero + F_rad) / (p.h * p.ρ * p.c) - parent(dY.T_sfc) .= apply_mask.(parent(mask), <, parent(rhs), FT(0), FT(0.5)) -end - -function slab_ocean_init( - ::Type{FT}, - tspan; - stepper = Euler(), - nelements = 6, - npolynomial = 4, - dt = 0.02, - saveat = 1.0e10, - space = nothing, - mask = nothing, -) where {FT} - - params = OceanSlabParameters(FT(20), FT(1500.0), FT(800.0), FT(280.0), FT(1e-3), FT(1e-5)) - - Y, space = slab_ocean_space_init(FT, space, params) - Ya = (params = params, F_aero = ClimaCore.Fields.zeros(space), F_rad = ClimaCore.Fields.zeros(space), mask = mask) #auxiliary - problem = OrdinaryDiffEq.ODEProblem(slab_ocean_rhs!, Y, tspan, Ya) - integrator = OrdinaryDiffEq.init(problem, stepper, dt = dt, saveat = saveat) - - SlabSimulation(params, Y, space, integrator) -end diff --git a/experiments/ClimaCore/bc-wave-slab/conservation.jl b/experiments/ClimaCore/bc-wave-slab/conservation.jl index 9c31abb7b1..28d3fa5f7b 100644 --- a/experiments/ClimaCore/bc-wave-slab/conservation.jl +++ b/experiments/ClimaCore/bc-wave-slab/conservation.jl @@ -7,7 +7,7 @@ end function check_conservation(cs, atmos_sim, slab_sim) atmos_field = atmos_sim.integrator.u.thermodynamics.ρe_tot - slab_field = get_slab_energy(slab_sim) + slab_field = get_total_energy(slab_sim) ρe_tot_atmos = sum(atmos_field) ρe_tot_slab = sum(slab_field) @@ -16,7 +16,7 @@ function check_conservation(cs, atmos_sim, slab_sim) push!(cs.ρe_tot_slab, ρe_tot_slab) end -function get_slab_energy(slab_sim) +function get_total_energy(slab_sim) ρe_tot = slab_sim.params.ρ .* slab_sim.params.c .* slab_sim.integrator.u.T_sfc .* slab_sim.params.h end diff --git a/src/FluxCalculator.jl b/src/FluxCalculator.jl index 88118899e8..2d2daa89bd 100644 --- a/src/FluxCalculator.jl +++ b/src/FluxCalculator.jl @@ -161,21 +161,29 @@ function partitioned_turbulent_fluxes!( thermo_state_sfc = surface_thermo_state(sim, thermo_params, thermo_state_int, colidx) # set inputs based on whether the surface_scheme is `MoninObukhovScheme` or `BulkScheme` - inputs = surface_inputs( - surface_scheme, + surface_params = get_surface_params(atmos_sim) + scheme_properties = get_scheme_properties(surface_scheme, sim, colidx) + input_args = (; thermo_state_sfc, thermo_state_int, uₕ_int, z_int, z_sfc, - get_scheme_properties(surface_scheme, sim, colidx), + scheme_properties, + surface_params, + surface_scheme, + colidx, ) + inputs = surface_inputs(surface_scheme, input_args) - # update fluxes in the coupler - surface_params = get_surface_params(atmos_sim) - F_turb_ρτxz, F_turb_ρτyz, F_shf, F_lhf, F_turb_moisture = - get_surface_fluxes_point!(inputs, surface_params) + # calculate the surface fluxes + fluxes = get_surface_fluxes_point!(inputs, surface_params) + (; F_turb_ρτxz, F_turb_ρτyz, F_shf, F_lhf, F_turb_moisture) = fluxes + + # perform additional diagnostics if required + differentiate_turbulent_fluxes!(sim, (thermo_params, input_args, fluxes)) + # update fluxes in the coupler fields = (; F_turb_ρτxz = F_turb_ρτxz, F_turb_ρτyz = F_turb_ρτyz, @@ -186,7 +194,7 @@ function partitioned_turbulent_fluxes!( # update the fluxes of this surface model update_turbulent_fluxes_point!(sim, fields, colidx) - # add the flux contributing from this surface + # add the flux contributing from this surface to the coupler field @. csf.F_turb_ρτxz[colidx] += F_turb_ρτxz * area_fraction * area_mask @. csf.F_turb_ρτyz[colidx] += F_turb_ρτyz * area_fraction * area_mask @. csf.F_turb_energy[colidx] += (F_shf .+ F_lhf) * area_fraction * area_mask @@ -231,10 +239,12 @@ end Returns the inputs for the surface model simulation `sim`. """ -function surface_inputs(::BulkScheme, thermo_state_sfc, thermo_state_int, uₕ_int, z_int, z_sfc, surface_properties) +function surface_inputs(::BulkScheme, input_args::NamedTuple) + + (; thermo_state_sfc, thermo_state_int, uₕ_int, z_int, z_sfc, scheme_properties) = input_args FT = Spaces.undertype(axes(z_sfc)) - (; z0b, z0m, Ch, Cd, beta, gustiness) = surface_properties + (; z0b, z0m, Ch, Cd, beta, gustiness) = scheme_properties # wrap state values return @. SF.Coefficients( SF.InteriorValues(z_int, uₕ_int, thermo_state_int), # state_in @@ -251,18 +261,10 @@ function surface_inputs(::BulkScheme, thermo_state_sfc, thermo_state_int, uₕ_i beta, # beta ) end -function surface_inputs( - ::MoninObukhovScheme, - thermo_state_sfc, - thermo_state_int, - uₕ_int, - z_int, - z_sfc, - surface_properties, -) +function surface_inputs(::MoninObukhovScheme, input_args::NamedTuple) + (; thermo_state_sfc, thermo_state_int, uₕ_int, z_int, z_sfc, scheme_properties) = input_args FT = Spaces.undertype(axes(z_sfc)) - - (; z0b, z0m, Ch, Cd, beta, gustiness) = surface_properties + (; z0b, z0m, Ch, Cd, beta, gustiness) = scheme_properties # wrap state values return @. SF.ValuesOnly( @@ -289,15 +291,19 @@ function surface_thermo_state( sim::Interfacer.SurfaceModelSimulation, thermo_params::TD.Parameters.ThermodynamicsParameters, thermo_state_int, - colidx::Fields.ColumnIndex, + colidx::Fields.ColumnIndex; + δT_sfc = 0, ) + FT = eltype(parent(thermo_state_int)) @warn("Simulation " * Interfacer.name(sim) * " uses the default thermo (saturated) surface state", maxlog = 10) - T_sfc = Interfacer.get_field(sim, Val(:surface_temperature), colidx) # + # get surface temperature (or perturbed surface temperature for differentiation) + T_sfc = Interfacer.get_field(sim, Val(:surface_temperature), colidx) .+ FT(δT_sfc) ρ_sfc = extrapolate_ρ_to_sfc.(thermo_params, thermo_state_int, T_sfc) # ideally the # calculate elsewhere, here just getter... q_sfc = TD.q_vap_saturation_generic.(thermo_params, T_sfc, ρ_sfc, TD.Liquid()) # default: saturated liquid surface @. TD.PhaseEquil_ρTq.(thermo_params, ρ_sfc, T_sfc, q_sfc) end + # TODO: (an equivalent of) this function also lives in Atmos and Land - should move to general utilities """ extrapolate_ρ_to_sfc(thermo_params, ts_int, T_sfc) @@ -332,7 +338,13 @@ function get_surface_fluxes_point!(inputs, surface_params::SF.Parameters.Surface # moisture F_turb_moisture = @. SF.evaporation(surface_params, inputs, outputs.Ch) - return F_turb_ρτxz, F_turb_ρτyz, F_shf, F_lhf, F_turb_moisture + return (; + F_turb_ρτxz = F_turb_ρτxz, + F_turb_ρτyz = F_turb_ρτyz, + F_shf = F_shf, + F_lhf = F_lhf, + F_turb_moisture = F_turb_moisture, + ) end """ @@ -369,4 +381,38 @@ end update_turbulent_fluxes_point!(sim::Interfacer.SurfaceStub, fields::NamedTuple, colidx::Fields.ColumnIndex) = nothing +differentiate_turbulent_fluxes!(::Interfacer.SurfaceModelSimulation, args) = nothing + +""" + differentiate_turbulent_fluxes(sim::Interfacer.SurfaceModelSimulation, thermo_params, input_args, fluxes, δT_sfc = 0.1) + +Differentiates the turbulent fluxes in the surface model simulation `sim` with respect to the surface temperature, +using δT_sfc as the perturbation. +""" +function differentiate_turbulent_fluxes!( + sim::Interfacer.SurfaceModelSimulation, + thermo_params, + input_args, + fluxes; + δT_sfc = 0.1, +) + (; thermo_state_int, surface_params, surface_scheme, colidx) = input_args + thermo_state_sfc_dT = surface_thermo_state(sim, thermo_params, thermo_state_int, colidx, δT_sfc = δT_sfc) + input_args = merge(input_args, (; thermo_state_sfc = thermo_state_sfc_dT)) + + # set inputs based on whether the surface_scheme is `MoninObukhovScheme` or `BulkScheme` + inputs = surface_inputs(surface_scheme, input_args) + + # calculate the surface fluxes + _, _, F_shf_δT_sfc, F_lhf_δT_sfc, _ = get_surface_fluxes_point!(inputs, surface_params) + + (; F_shf, F_lhf) = fluxes + + # calculate the derivative + ∂F_turb_energy∂T_sfc = @. (F_shf_δT_sfc + F_lhf_δT_sfc - F_shf - F_lhf) / δT_sfc + + Interfacer.update_field!(sim, Val(:∂F_turb_energy∂T_sfc), ∂F_turb_energy∂T_sfc, colidx) + +end + end # module diff --git a/test/Project.toml b/test/Project.toml index 16a35d98b6..a6933f950f 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -9,6 +9,7 @@ ClimaCoupler = "4ade58fe-a8da-486c-bd89-46df092ec0c7" ClimaLSM = "7884a58f-fab6-4fd0-82bb-ecfedb2d8430" ClimaTimeSteppers = "595c0a79-7f3d-439a-bc5a-b232dc3bde79" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" Insolation = "e98cc03f-d57e-4e3c-b70c-8d51efe9e0d8" IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" diff --git a/test/component_model_tests/eisenman_seaice_tests.jl b/test/component_model_tests/eisenman_seaice_tests.jl new file mode 100644 index 0000000000..05118b900b --- /dev/null +++ b/test/component_model_tests/eisenman_seaice_tests.jl @@ -0,0 +1,356 @@ +import Test: @test, @testset + +using ClimaCore +using ClimaCore: Fields, Spaces + +import ClimaCoupler +import ClimaCoupler.TestHelper +import ClimaCoupler.Interfacer: SeaIceModelSimulation +import ClimaCoupler: Regridder + +import CLIMAParameters as CP +import Thermodynamics as TD +import Thermodynamics.Parameters as TP + +include("../../experiments/AMIP/modular/components/ocean/eisenman_seaice_init.jl") + +FT = Float64 +params_ice = EisenmanIceParameters{FT}() +params_ocean = EisenmanOceanParameters{FT}() +params = (; p_i = params_ice, p_o = params_ocean) + +Δt = FT(1e6) + +# create a boundary space +boundary_space = TestHelper.create_space(FT) + +# thermodynammic parameter set +aliases = string.(fieldnames(TP.ThermodynamicsParameters)) +toml_dict = CP.create_toml_dict(FT; dict_type = "alias") +pairs = CP.get_parameter_values!(toml_dict, aliases, "Thermodynamics") +thermo_params = TP.ThermodynamicsParameters{FT}(; pairs...) + +@testset "No net fluxes" begin + Y, Ya = state_init(params_ice, boundary_space) + + # ice covered + Y.h_ice .= 1 + + # no conductive flux, or basal interface flux + Y.T_sfc .= params_ice.T_base + Y.T_ml .= params_ice.T_base + + # no atmos fluxes, F_a + Ya.∂F_turb_energy∂T_sfc .= .-get_∂F_rad_energy∂T_sfc.(Y.T_sfc, Ref(params_ice)) # ∂F_turb_energy∂T_sfc + ∂F_rad_energy∂T_sfc = 0 + Ya.F_rad .= 0 + Ya.F_turb .= 0 + + Fields.bycolumn(boundary_space) do colidx + solve_eisenman_model!(Y[colidx], Ya[colidx], params, thermo_params, Δt) + end + @test all(parent(Ya.e_base) .≈ 0) + @test all(parent(Y.T_ml) .≈ params_ice.T_base) + @test all(parent(Y.T_sfc) .≈ params_ice.T_base) + @test all(parent(Y.h_ice) .≈ 1) +end + +@testset "Radiative fluxes: outgoing longwave -> ice growth" begin + Y, Ya = state_init(params_ice, boundary_space) + + # ice covered + Y.h_ice .= 1 + h_ice_0 = deepcopy(Y.h_ice) + + # no conductive flux, or basal interface flux + Y.T_sfc .= params_ice.T_base + Y.T_ml .= params_ice.T_base + + # ice growth due to outgoing longwave + # only radiative (no aerodynamic) atmos fluxes considered here (F_atm = F_rad) + Ya.∂F_turb_energy∂T_sfc .= 0 + ∂F_atm∂T_sfc = get_∂F_rad_energy∂T_sfc(Y.T_sfc, params_ice) .+ Ya.∂F_turb_energy∂T_sfc + @. Ya.F_rad = (1 - params_ice.α) * params_ice.σ * Y.T_sfc .^ 4 # outgoing longwave + + Fields.bycolumn(boundary_space) do colidx + solve_eisenman_model!(Y[colidx], Ya[colidx], params, thermo_params, Δt) + end + + F_atm = @. Ya.F_rad + Ya.F_turb + + @test all(parent(Ya.e_base) .≈ 0) + @test all(parent(Y.T_ml) .≈ params_ice.T_base) # ocean temperature below ice remains unchanged + h_ice_new = @. h_ice_0 + F_atm * Δt / params_ice.L_ice + @test all(parent(Y.h_ice) .≈ parent(h_ice_new)) # ice growth + T_sfc_new = @. params_ice.T_base .+ (-F_atm) / (params_ice.k_ice / (h_ice_new) + ∂F_atm∂T_sfc) + @test all(parent(Y.T_sfc) .≈ parent(T_sfc_new)) # surface temperature decreases +end + +@testset "Radiative fluxes balance turbulent fluxes -> no ice growth" begin + # no ice growth due to outgoing longwave = incoming longwave + incoming shortwave + # (NB: incoming independent of T_sfc) + Y, Ya = state_init(params_ice, boundary_space) + + # ice covered + Y.h_ice .= 1 + h_ice_0 = deepcopy(Y.h_ice) + + # prescribe radiative and tubulent fluxes + Ya.F_rad .= 100 + Ya.F_turb .= -100 + + # no conductive flux, or basal interface flux + Y.T_sfc .= params_ice.T_base + Y.T_ml .= params_ice.T_base + + Fields.bycolumn(boundary_space) do colidx + solve_eisenman_model!(Y[colidx], Ya[colidx], params, thermo_params, Δt) + end + + F_atm = @. Ya.F_rad + Ya.F_turb + ∂F_atm∂T_sfc = 0 + + @test all(parent(Ya.e_base) .≈ 0) # no contribution from basal fluxes + @test all(parent(Y.T_ml) .≈ params_ice.T_base) # ocean temperature stays at freezing point + h_ice_new = @. h_ice_0 + F_atm * Δt / params_ice.L_ice + @test all(parent(Y.h_ice) .≈ parent(h_ice_new)) # no ice growth + T_sfc_new = @. params_ice.T_base .+ (-F_atm) / (params_ice.k_ice / (h_ice_new) + ∂F_atm∂T_sfc) + @test all(parent(Y.T_sfc) .≈ parent(T_sfc_new)) # surface temperature decreases +end + +@testset "Ice surface temperature never exceeds the freezing point (even when positive radiative and conductive fluxes)" begin + + Y, Ya = state_init(params_ice, boundary_space) + + # ice covered + Y.h_ice .= 10 + h_ice_0 = deepcopy(Y.h_ice) + + # no basal interface fluxes + Y.T_ml .= params_ice.T_base + + # net incoming energy + Ya.F_turb .= 0 + Ya.F_rad .= @. (1 - params_ice.α) * params_ice.σ * Y.T_sfc^4 - 300 # outgoing longwave < incoming longwave + incoming shortwave + + # non-zero conductive flux + Y.T_sfc .= params_ice.T_base .- 1 + T_sfc_0 = deepcopy(Y.T_sfc) + + Fields.bycolumn(boundary_space) do colidx + solve_eisenman_model!(Y[colidx], Ya[colidx], params, thermo_params, Δt) + end + + F_atm = @. Ya.F_rad + Ya.F_turb + ∂F_atm∂T_sfc = 0 + + F_conductive = @. params_ice.k_ice / (Y.h_ice) * (params_ice.T_base - T_sfc_0) + ΔT_sfc = @. (-F_atm + F_conductive) / (params_ice.k_ice / (Y.h_ice) + ∂F_atm∂T_sfc) + + @test all(parent(Ya.e_base) .≈ 0) # no contribution from basal fluxes + @test all(parent(Y.T_ml) .≈ params_ice.T_base) # ocean temperature stays at freezing point + h_ice_new = @. h_ice_0 + F_atm * Δt / params_ice.L_ice + @test all(parent(Y.h_ice) .≈ parent(h_ice_new)) # ice growth + @test all(parent(Y.T_sfc) .≈ params_ice.T_base) # ice surface temperature doesn't exceed freezing + @test all(parent(Y.T_sfc) .< parent(T_sfc_0 .+ ΔT_sfc)) +end + +@testset "Transition to ice free due to incoming > outgoing" begin + + Y, Ya = state_init(params_ice, boundary_space) + + # ice covered + Y.h_ice .= 0.1 + h_ice_0 = deepcopy(Y.h_ice) + + # prescribe radiative and tubulent fluxes + Ya.F_rad .= @. (1 - params_ice.α) * params_ice.σ * Y.T_sfc .^ 4 - 300 # outgoing longwave < incoming longwave + incoming shortwave + Ya.F_turb .= 0 + ∂F_atm∂T_sfc = 0 + + # no conductive flux, or basal interface flux + Y.T_sfc .= params_ice.T_base + Y.T_ml .= params_ice.T_base + T_ml_0 = deepcopy(Y.T_ml) + + Fields.bycolumn(boundary_space) do colidx + solve_eisenman_model!(Y[colidx], Ya[colidx], params, thermo_params, Δt) + end + + F_atm = @. Ya.F_rad + Ya.F_turb + + @test all(parent(Y.h_ice) .≈ 0) # ice melts + T_ml_new = @. T_ml_0 - (F_atm) * Δt / (params_ocean.h * params_ocean.ρ * params_ocean.c) - + h_ice_0 * params_ice.L_ice / (params_ocean.h * params_ocean.ρ * params_ocean.c) + @test all(parent(Y.T_ml) .≈ parent(T_ml_new)) # ocean temperature increases due to F_atm (reduced by the latent heat of melting) + +end + +@testset "Mixed layer warming due to net negative radiation fluxes" begin + Y, Ya = state_init(params_ice, boundary_space) + + # ice free + Y.h_ice .= 0 + h_ice_0 = deepcopy(Y.h_ice) + + # no conductive flux, or basal interface flux + Y.T_sfc .= params_ice.T_base + Y.T_ml .= params_ice.T_base + T_ml_0 = deepcopy(Y.T_ml) + + # net positive radiative fluxes + Y.T_sfc .= params_ice.T_base + Ya.F_turb .= 0 + Ya.F_rad .= @. (1 - params_ice.α) * params_ice.σ * Y.T_sfc^4 - 300 + + Fields.bycolumn(boundary_space) do colidx + solve_eisenman_model!(Y[colidx], Ya[colidx], params, thermo_params, Δt) + end + + F_atm = @. Ya.F_rad + Ya.F_turb + + @test all(parent(Ya.e_base) .≈ 0) # no contribution from basal fluxes + T_ml_new = @. T_ml_0 - (F_atm) * Δt / (params_ocean.h * params_ocean.ρ * params_ocean.c) + @test all(parent(Y.T_ml) .≈ parent(T_ml_new)) # ocean temperature increases + @test all(parent(Y.h_ice) .≈ 0) # no ice + @test all(parent(Y.T_sfc) .≈ parent(T_ml_new)) # surface temperature = ocean temperature + +end + +@testset "Mixed layer freezing due to net positive radiation fluxes" begin + + Y, Ya = state_init(params_ice, boundary_space) + + # ice free + Y.h_ice .= 0 + h_ice_0 = deepcopy(Y.h_ice) + + # no conductive flux, or basal interface flux + Y.T_sfc .= params_ice.T_base + Y.T_ml .= params_ice.T_base + T_sfc_0 = deepcopy(Y.T_sfc) + T_ml_0 = deepcopy(Y.T_ml) + + # net outgoing longwave + Ya.F_rad .= @. (1 - params_ice.α) * params_ice.σ * Y.T_sfc^4 + + Fields.bycolumn(boundary_space) do colidx + solve_eisenman_model!(Y[colidx], Ya[colidx], params, thermo_params, Δt) + end + + F_atm = @. Ya.F_rad + Ya.F_turb + ∂F_atm∂T_sfc = get_∂F_rad_energy∂T_sfc(T_sfc_0, params_ice) .+ Ya.∂F_turb_energy∂T_sfc + + @test all(parent(Ya.e_base) .≈ 0) # no contribution from basal fluxes + @test all(parent(Y.T_ml) .≈ params_ice.T_freeze) # ocean temperature remains at the freezing point + h_ice_new = @. (F_atm - (T_ml_0 - params_ice.T_freeze) * params_ocean.h * params_ocean.ρ * params_ocean.c) * Δt / + params_ice.L_ice + @test all(parent(Y.h_ice) .≈ parent(h_ice_new)) # ice growth + @test all(parent(Y.h_ice) .> 0) + T_sfc_new = @. T_sfc_0 - F_atm / (params_ice.k_ice / (h_ice_new) + ∂F_atm∂T_sfc) + @test all(parent(Y.T_sfc) .≈ parent(T_sfc_new)) # surface temperature decreases +end + +# conductive flux and q flux +@testset "Non-zero conductive flux" begin + Y, Ya = state_init(params_ice, boundary_space) + Δt = FT(100) + + # ice covered + Y.h_ice .= 10 + h_ice_0 = deepcopy(Y.h_ice) + + # non-zero interface basal + ΔT_ml = 10 + Y.T_ml .= params_ice.T_base .+ ΔT_ml + T_ml_0 = deepcopy(Y.T_ml) + + # zero conductive fluxes + Y.T_sfc .= params_ice.T_base + + # zero atmos fluxes and their derivatives + Ya.∂F_turb_energy∂T_sfc .= .-get_∂F_rad_energy∂T_sfc.(Y.T_sfc, Ref(params_ice)) # ∂F_turb_energy∂T_sfc + ∂F_rad_energy∂T_sfc = 0 + Ya.F_turb .= 0 + Ya.F_rad .= 0 + + Fields.bycolumn(boundary_space) do colidx + solve_eisenman_model!(Y[colidx], Ya[colidx], params, thermo_params, Δt) + end + + @test all(parent(Ya.e_base) .≈ params_ice.C0_base * ΔT_ml * Δt) # non-zero contribution from basal flux + T_ml_new = T_ml_0 .- params_ice.C0_base .* ΔT_ml * Δt / (params_ocean.h * params_ocean.ρ * params_ocean.c) + @test all(parent(Y.T_ml) .≈ parent(T_ml_new)) # ocean temperature decreases + @test all(parent(Y.T_ml) .< parent(T_ml_0)) + h_ice_new = @. h_ice_0 - params_ice.C0_base * 10 * Δt / params_ice.L_ice + @test all(parent(Y.h_ice) .≈ parent(h_ice_new)) + @test all(parent(Y.T_sfc) .≈ params_ice.T_base) # surface temperature unchanged (T_ml can affect in only if ice free) +end + +@testset "Nonzero Q-flux (~horizontal ocean transport)" begin + Y, Ya = state_init(params_ice, boundary_space) + Δt = FT(100) + + # ice covered + Y.h_ice .= 10 + h_ice_0 = deepcopy(Y.h_ice) + + # positive q_flux (positive toward current column) + Ya.ocean_qflux .= 100 + + # no conductive flux, or basal interface flux + Y.T_sfc .= params_ice.T_base + Y.T_ml .= params_ice.T_base + T_ml_0 = deepcopy(Y.T_ml) + + # no atmos fluxes or their derivatives + Ya.∂F_turb_energy∂T_sfc .= .-get_∂F_rad_energy∂T_sfc.(Y.T_sfc, Ref(params_ice)) # ∂F_turb_energy∂T_sfc + ∂F_rad_energy∂T_sfc = 0 + Ya.F_turb .= 0 + Ya.F_rad .= 0 + + Fields.bycolumn(boundary_space) do colidx + solve_eisenman_model!(Y[colidx], Ya[colidx], params, thermo_params, Δt) + end + + @test all(parent(Ya.e_base) .≈ 0) # no contribution from basal flux + T_ml_new = @. T_ml_0 + Ya.ocean_qflux * Δt / (params_ocean.h * params_ocean.ρ * params_ocean.c) + @test all(parent(Y.T_ml) .≈ parent(T_ml_new)) # qflux increases ocean temperature + @test all(parent(Y.T_ml) .> parent(T_ml_0)) + @test all(parent(Y.T_sfc) .≈ params_ice.T_base) # surface temperature unchanged (T_ml can affect in only if ice free) + h_ice_new = @. h_ice_0 - Ya.ocean_qflux * Δt / params_ice.L_ice + @test all(parent(Y.h_ice) .≈ parent(h_ice_new)) # # qflux decreases sea-ice thickness + @test all(parent(Y.h_ice) .< parent(h_ice_0)) +end + +include("../../experiments/AMIP/modular/components/slab_utils.jl") +@testset "step! update + total energy calculation" begin + + Δt = 1000 + + sim = eisenman_seaice_init( + FT, + (0, 2e6), + space = boundary_space, + area_fraction = ones(boundary_space), + thermo_params = thermo_params, + stepper = CTS.RK4(), + dt = Δt, + saveat = 1.0e10, + ) + sim.integrator.p.Ya.F_turb .= 0 + sim.integrator.p.Ya.F_rad .= 300 + sim.integrator.u.T_ml .= sim.integrator.p.params.p_i.T_freeze # init conditions for ocean temperature + + total_energy_0 = get_field(sim, Val(:energy)) + h_ice_0 = deepcopy(sim.integrator.u.h_ice) + + step!(sim, Δt) + h_ice = sim.integrator.u.h_ice + @test all(parent(h_ice) .≈ 0.001) + step!(sim, 2 * Δt) + h_ice = sim.integrator.u.h_ice + @test all(parent(h_ice) .≈ 0.002) + + total_energy_calc = (get_field(sim, Val(:energy)) .- total_energy_0) + total_energy_expeted = 300 .* ones(boundary_space) .* 2 .* Δt + @test all(parent(total_energy_calc) .≈ parent(total_energy_expeted)) + +end diff --git a/test/flux_calculator_tests.jl b/test/flux_calculator_tests.jl index 2f93f9f9b7..14c0626f4c 100644 --- a/test/flux_calculator_tests.jl +++ b/test/flux_calculator_tests.jl @@ -1,5 +1,5 @@ -using ClimaCore: Meshes, Domains, Topologies, Spaces, Fields, InputOutput +using ClimaCore: Meshes, Domains, Topologies, Spaces, Fields, InputOutput, Geometry using ClimaCoupler: Utilities, Regridder, TestHelper using Test import ClimaCoupler.FluxCalculator: @@ -13,7 +13,12 @@ import ClimaCoupler.FluxCalculator: partitioned_turbulent_fluxes!, get_surface_params, update_turbulent_fluxes_point!, - surface_thermo_state + surface_thermo_state, + surface_inputs, + get_surface_fluxes_point!, + get_scheme_properties, + surface_thermo_state, + differentiate_turbulent_fluxes! import ClimaCoupler: Interfacer FT = Float64 @@ -291,6 +296,26 @@ struct DummySurfaceSimulation3{M, Y, D, I} <: Interfacer.SurfaceModelSimulation integrator::I end Interfacer.get_field(sim::DummySurfaceSimulation3, ::Val{:surface_temperature}) = sim.integrator.T +Interfacer.get_field(sim::DummySurfaceSimulation3, ::Val{:area_fraction}) = sim.integrator.p.area_fraction +Interfacer.get_field(sim::DummySurfaceSimulation3, ::Val{:heat_transfer_coefficient}) = sim.integrator.p.Ch +Interfacer.get_field(sim::DummySurfaceSimulation3, ::Val{:drag_coefficient}) = sim.integrator.p.Cd +Interfacer.get_field(sim::DummySurfaceSimulation3, ::Val{:beta}) = sim.integrator.p.beta + +function Interfacer.update_field!(sim::DummySurfaceSimulation3, ::Val{:∂F_turb_energy∂T_sfc}, field, colidx) + sim.integrator.p.∂F_turb_energy∂T_sfc[colidx] .= field +end +function surface_thermo_state( + sim::DummySurfaceSimulation3, + thermo_params::TD.Parameters.ThermodynamicsParameters, + thermo_state_int, + colidx::Fields.ColumnIndex, +) + + T_sfc = Interfacer.get_field(sim, Val(:surface_temperature), colidx) + ρ_sfc = @. T_sfc * 0.0 .+ 1.2 # arbitrary + q_sfc = @. T_sfc * 0.0 # dry surface + @. TD.PhaseEquil_ρTq.(thermo_params, ρ_sfc, T_sfc, q_sfc) +end @testset "update_turbulent_fluxes_point!" begin sim = Interfacer.SurfaceStub([]) @@ -307,7 +332,7 @@ end @testset "surface_thermo_state" begin boundary_space = TestHelper.create_space(FT) _ones = Fields.ones(boundary_space) - sim = DummySurfaceSimulation3( + surface_sim = DummySurfaceSimulation3( [], [], [], @@ -317,5 +342,64 @@ end thermo_params = get_thermo_params(atmos_sim) thermo_state_int = Interfacer.get_field(atmos_sim, Val(:thermo_state_int)) colidx = Fields.ColumnIndex{2}((1, 1), 73) # arbitrary index - @test surface_thermo_state(sim, thermo_params, thermo_state_int[colidx], colidx).ρ == thermo_state_int[colidx].ρ + @test surface_thermo_state(surface_sim, thermo_params, thermo_state_int[colidx], colidx).ρ == + thermo_state_int[colidx].ρ +end + +@testset "differentiate_turbulent_fluxes!" begin + boundary_space = TestHelper.create_space(FT) + _ones = Fields.ones(boundary_space) + surface_sim = DummySurfaceSimulation3( + [], + [], + [], + (; + T = _ones .* FT(300), + ρ = _ones .* FT(1.2), + p = (; + q = _ones .* FT(0.00), + area_fraction = _ones, + Ch = FT(0.001), + Cd = FT(0.001), + beta = _ones, + ∂F_turb_energy∂T_sfc = _ones .* 0, + q_sfc = _ones .* 0, + ), + ), + ) + atmos_sim = TestAtmos((; FT = FT), [], [], (; T = _ones .* FT(300), ρ = _ones .* FT(1.2), q = _ones .* FT(0.00))) + thermo_params = get_thermo_params(atmos_sim) + colidx = Fields.ColumnIndex{2}((1, 1), 73) # arbitrary index + + thermo_state_int = Interfacer.get_field(atmos_sim, Val(:thermo_state_int))[colidx] + surface_scheme = BulkScheme() + surface_params = get_surface_params(atmos_sim) + uₕ_int = Geometry.UVVector.(Geometry.Covariant12Vector.(_ones .* 1.0, _ones .* 1.0))[colidx] + z_int = _ones[colidx] + z_sfc = (_ones .* 0.0)[colidx] + thermo_state_sfc = surface_thermo_state(surface_sim, thermo_params, thermo_state_int[colidx], colidx) + scheme_properties = get_scheme_properties(surface_scheme, surface_sim, colidx) + input_args = (; + thermo_state_sfc, + thermo_state_int, + uₕ_int, + z_int, + z_sfc, + surface_params, + surface_scheme, + scheme_properties, + colidx, + ) + + inputs = surface_inputs(surface_scheme, input_args) + fluxes = get_surface_fluxes_point!(inputs, surface_params) + + dFdTs = differentiate_turbulent_fluxes!(surface_sim, thermo_params, input_args, fluxes, δT_sfc = 1) + + sf_out = SF.surface_conditions.(surface_params, inputs) + + cp_m = TD.cp_m.(thermo_params, thermo_state_int) + dFdTs_analytical = @. thermo_state_sfc.ρ * sf_out.Ch * SF.windspeed.(inputs) * cp_m + + @test all(isapprox(parent(dFdTs), parent(dFdTs_analytical), atol = 0.1)) end diff --git a/test/runtests.jl b/test/runtests.jl index 45eb30cfe2..b3ba03d36f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -51,8 +51,12 @@ end @safetestset "component model test: prescr. sea ice" begin include("component_model_tests/prescr_seaice_tests.jl") end +@safetestset "component model test: eisenman sea ice" begin + include("component_model_tests/eisenman_seaice_tests.jl") +end @safetestset "component model test: slab ocean" begin include("component_model_tests/slab_ocean_tests.jl") end + # include("CoupledSimulations/cplsolver.jl")