Replies: 5 comments 5 replies
-
Hi @lgloege, The easiest way would probably be to manually define the tracers like you have done already, and just omit the biogeochemistry since the carbon chemistry lives in the gas exchange boundary condition anyway. This seems to work for me: using OceanBioME
using Oceananigans
grid = RectilinearGrid(size=(3, 3, 30), extent=(10, 10, 200));
CO₂_flux = CarbonDioxideGasExchangeBoundaryCondition()
boundary_conditions = (; DIC = FieldBoundaryConditions(top = CO₂_flux))
tracers = (:T, :S, :DIC, :Alk) # note Alk not ALK
model = NonhydrostaticModel(; grid, boundary_conditions, tracers)
set!(model, DIC = 2200, Alk = 2000)
time_step!(model, 1000.0)
model.tracers.DIC
3×3×30 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 3×3×30 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo
├── boundary conditions: FieldBoundaryConditions
│ └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: ZeroFlux, top: Flux, immersed: ZeroFlux
└── data: 9×9×36 OffsetArray(::Array{Float64, 3}, -2:6, -2:6, -2:33) with eltype Float64 with indices -2:6×-2:6×-2:33
└── max=2200.0, min=2199.44, mean=2199.98 A next step if you wanted to specify something about what the DIC and alkalinity do could be to define a new bgc model with just DIC and Alkalinity then you won't have to specify the tracers too. |
Beta Was this translation helpful? Give feedback.
-
Thank! @jagoosw ! I see that I'm getting closer to what I am trying to do. Now my issue is returning pH. My naive solution was to pass Nx, Nz = 256, 128
H, L = 2kilometers, 1000kilometers
grid = RectilinearGrid(size = (Nx, Nz),
halo = (4, 4),
x = (-L, L),
z = (-H, 0),
topology = (Bounded, Flat, Bounded))
coriolis = FPlane(latitude = -45)
buoyancy = SeawaterBuoyancy(equation_of_state=LinearEquationOfState(thermal_expansion = 2e-4,
haline_contraction = 8e-4))
# =====================================
# wind stress
# =====================================
u₁₀ = 2 # m s⁻¹, average wind velocity 10 meters above the ocean
cᴰ = 2.5e-3 # dimensionless drag coefficient
ρₐ = 1.225 # kg m⁻³, average density of air at sea-level
ρₒ = 1026.0 # kg m⁻³, average density at the surface of the world ocean
τx = - ρₐ / ρₒ * cᴰ * u₁₀ * abs(u₁₀) # m² s⁻²
u_bcs = FieldBoundaryConditions(top = FluxBoundaryCondition(τx))
# =====================================
# CO2 gas transfer
# =====================================
carbon_chemistry = CarbonChemistry(return_pH = true)
CO₂_flux = CarbonDioxideGasExchangeBoundaryCondition(carbon_chemistry, air_concentration = 425, wind_speed=u₁₀)
DIC_bcs = FieldBoundaryConditions(top = CO₂_flux)
# =====================================
# Alk forcing
# add an Alk Forcing() here
# to be implemented
# =====================================
tracers = (:T, :S, :DIC, :Alk, :pH)
model = NonhydrostaticModel(; grid, buoyancy,
advection = UpwindBiased(order=5),
tracers,
coriolis,
closure = AnisotropicMinimumDissipation(),
boundary_conditions = (u=u_bcs, DIC=DIC_bcs))
set!(model, T = 20, S = 35, DIC = 2200, Alk = 2000)
simulation = Simulation(model, Δt=10.0, stop_time=40minutes)
# Print a progress message
progress_message(sim) = @printf("Iteration: %04d, time: %s, Δt: %s, max(|w|) = %.1e ms⁻¹, wall time: %s\n",
iteration(sim), prettytime(sim), prettytime(sim.Δt),
maximum(abs, sim.model.velocities.w), prettytime(sim.run_wall_time))
add_callback!(simulation, progress_message, IterationInterval(20))
filename = "test_sim"
simulation.output_writers[:slices] =
JLD2Writer(model, merge(model.velocities, model.tracers),
filename = filename * ".jld2",
indices = (:, :),
schedule = TimeInterval(1minute),
overwrite_existing = true)
run!(simulation) |
Beta Was this translation helpful? Give feedback.
-
This is maybe a separate discussion, but where i'm going with this is calculating uptake from an OAE release, very idealized right now. To do this I would need to difference two simulations. One with and one without additional alkalinity. I'm curious how challenging it would be calculate two carbonate systems in the same simulation. One that is a baseline "counterfactual" simulation and another that includes the additional alkalinity. Benefit is you only have to run the simulation once. I believe this is implemented in MARBL, but I don't see why it can't be generalized to the entire OceanBioME framework so it would work with all ecosystem models. I can open this up as a separate discussion if this is useful. I don't think my knowledge of Julia of or the codebase is there yet for me to make this contribution. Having that said, i'm happy to assist somebody is there is interest in this! I really want Oceanigans+OceanBioME to be the framework for ocean-based CDR modeling. |
Beta Was this translation helpful? Give feedback.
-
Thanks @jagoosw , so now the model is calculating the sqrt of a negative somewhere. This only happens after I turn on gas exchange. Here is the main part of the error message:
and here is my code using CairoMakie
using Dates
using NCDatasets
using Oceananigans
using OceanBioME
using Oceananigans.Units: meters, minute
# =======================================
# define architecture CPU or GPU
# =======================================
architecture = CPU()
# =======================================
# define model grid
# =======================================
x = (0, 15meters)
z = (-0.5meters, 0)
Δx, Δz = 0.01meters, 0.01meters
size = (Int(x[2]/Δx), Int(-z[1]/Δz))
topology = (Bounded, Flat, Bounded)
grid = RectilinearGrid(architecture; size, x, z, topology)
# =====================================
# wind stress
# =====================================
u₁₀ = 5 # m s⁻¹, average wind velocity 10 meters above the ocean
cᴰ = 2.5e-3 # dimensionless drag coefficient
ρₐ = 1.225 # kg m⁻³, average density of air at sea-level
ρₒ = 1026.0 # kg m⁻³, average density at the surface of the world ocean
τx = - ρₐ / ρₒ * cᴰ * u₁₀ * abs(u₁₀) # m² s⁻²
u_bcs = FieldBoundaryConditions(top = FluxBoundaryCondition(τx))
# =====================================
# CO2 gas transfer
# =====================================
CO₂_flux = CarbonDioxideGasExchangeBoundaryCondition(;air_concentration = 425, wind_speed=u₁₀)
DIC_bcs = FieldBoundaryConditions(top = CO₂_flux)
# =======================================
# Model paramters
# =======================================
# closure = ScalarDiffusivity(ν=1e-6, κ=1e-6)
closure = AnisotropicMinimumDissipation()
tracers = (:T, :S, :c, :DIC, :Alk)
coriolis = FPlane(f=0.2)
advection= UpwindBiased(order=5) #WENO()
boundary_conditions = (u=u_bcs, DIC=DIC_bcs)
# ---------------------------------------
# equation of state and buoyancy
# b = g (- β S - γ C) # ignore temperature influence
# ---------------------------------------
buoyancy = SeawaterBuoyancy(equation_of_state=LinearEquationOfState(thermal_expansion = 2e-4,
haline_contraction = 8e-4))
model = NonhydrostaticModel(; grid,
buoyancy,
tracers,
coriolis,
advection,
closure,
boundary_conditions)
# =======================================
# set intial salinity and tracers
# =======================================
# function to get index closest to value
closest_index(target, collection) = argmin(abs.(collection .- target))
# create x and z collections
xᶜ = collect(grid.xᶜᵃᵃ)
zᶜ = collect(grid.z.cᵃᵃᶜ)
# find index range for x ∈ [0, 0.15]
i₁ = closest_index(0.0, xᶜ)
i₂ = closest_index(0.15, xᶜ)
# find index range for z ∈ [-0.15, 0]
k₁ = closest_index(-0.15, zᶜ)
k₂ = closest_index(0.0, zᶜ)
# create zero array on center grid
S_initial = CenterField(grid)
c_initial = CenterField(grid)
# set values within the index range
S_initial[i₁:i₂, :, k₁:k₂] .= 25.0;
c_initial[i₁:i₂, :, k₁:k₂] .= 0.0078;
# now set the values in the model
set!(model, T=25, S=S_initial, c = c_initial, DIC = 2200, Alk = 2000)
simulation = Simulation(model; Δt = 0.005, stop_iteration=10)
# --------------------------------------------------
# output writer
# --------------------------------------------------
#filename = "test-release_$(string(today()))"
filename = "./test_sim"
fields = Dict("T" => model.tracers.T, "S" => model.tracers.S, "c" => model.tracers.c, "DIC" => model.tracers.DIC, "Alk" => model.tracers.Alk)
simulation.output_writers[:tracers] = JLD2Writer(model, fields;
filename = filename * ".jld2",
schedule = IterationInterval(20),
overwrite_existing = true)
run!(simulation)
simulation.stop_iteration = 100
simulation.Δt = 0.05
run!(simulation) i'm at a loss what the issue could be, any ideas on how to diagnose the issue? |
Beta Was this translation helpful? Give feedback.
-
Errors like this tend to arise when the model gets a value for T/S/DIC/Alk significantly out of the normal range. Looking at the specific equilibrium constant, it looks like it is only S that gets rooted: OceanBioME.jl/src/Models/CarbonChemistry/equilibrium_constants.jl Lines 243 to 250 in 5dafe8f I suspect that the timestep might not be small enough for the physics (to keep the CFL below 0.5 with this timestep the speed has to be less than 0.1m/s which seems unlikely with a 5m/s wind), so perhaps just trying a smaller timestep would work? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I would like to run some idealized simulations with just carbon chemistry and air-sea gas exchange. Ideally, I would like to be able to do something like this:
This obviously doesn't work. A somewhat hacky solution would be to to use the NPZD model and set
P
andZ
to zero. Curious if there is something more elegant than this so I don't have to carry aroundP
,Z
andD
tracers unnecessarily.Please let me know if there is a way to achieve this. Thanks
Beta Was this translation helpful? Give feedback.
All reactions