Skip to content

Commit

Permalink
Merge pull request #3123 from CliMA/gb/check_conservation
Browse files Browse the repository at this point in the history
Move conservation check to src
  • Loading branch information
Sbozzolo authored Jun 21, 2024
2 parents 35a0822 + 02358f7 commit 23387fc
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 42 deletions.
53 changes: 11 additions & 42 deletions examples/hybrid/driver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -116,55 +116,24 @@ end

# Conservation checks
if config.parsed_args["check_conservation"]
@info "Checking conservation"
FT = Spaces.undertype(axes(sol.u[end].c.ρ))
@info "Checking conservation"
(; energy_conservation, mass_conservation, water_conservation) =
CA.check_conservation(sol)

@info " Net energy change / total energy: $energy_conservation"
@info " Net mass change / total mass: $mass_conservation"

# energy
energy_total = sum(sol.u[end].c.ρe_tot)
energy_atmos_change = sum(sol.u[end].c.ρe_tot) - sum(sol.u[1].c.ρe_tot)
sfc = p.atmos.surface_model
if sfc isa CA.PrognosticSurfaceTemperature
sfc_cρh = sfc.ρ_ocean * sfc.cp_ocean * sfc.depth_ocean
energy_total +=
CA.horizontal_integral_at_boundary(sol.u[end].sfc.T .* sfc_cρh)
energy_surface_change =
CA.horizontal_integral_at_boundary(
sol.u[end].sfc.T .- sol.u[1].sfc.T,
) * sfc_cρh
else
energy_surface_change = -p.net_energy_flux_sfc[][]
end
energy_radiation_input = -p.net_energy_flux_toa[][]

energy_net =
abs(
energy_atmos_change + energy_surface_change -
energy_radiation_input,
) / energy_total
@info " Net energy change: $energy_net"
if CA.has_no_source_or_sink(config.parsed_args)
@test (energy_net / energy_total) 0 atol = 50 * eps(FT)
else
@test (energy_net / energy_total) 0 atol = sqrt(eps(FT))
end

if CA.has_no_source_or_sink(config.parsed_args)
# mass
@test sum(sol.u[1].c.ρ) sum(sol.u[end].c.ρ) rtol = 50 * eps(FT)
@test energy_conservation 0 atol = 50 * eps(FT)
@test mass_conservation 0 atol = 50 * eps(FT)
else
@test energy_conservation 0 atol = sqrt(eps(FT))
if sfc isa CA.PrognosticSurfaceTemperature
# water
water_total = sum(sol.u[end].c.ρq_tot)
water_atmos_change =
sum(sol.u[end].c.ρq_tot) - sum(sol.u[1].c.ρq_tot)
water_surface_change = CA.horizontal_integral_at_boundary(
sol.u[end].sfc.water .- sol.u[1].sfc.water,
)

water_net =
abs(water_atmos_change + water_surface_change) / water_total
@info " Net water change: $water_net"
@test water_net 0 atol = 100 * sqrt(eps(FT))
@info " Net water change: $water_conservation"
@test water_conservation 0 atol = 100 * sqrt(eps(FT))
end
end
end
Expand Down
64 changes: 64 additions & 0 deletions src/solver/solve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,67 @@ function precompile_callbacks(integrator)
@assert B
return nothing
end


check_conservation(simulation::AtmosSimulation) =
check_conservation(simulation.integrator.sol)
check_conservation(integrator::CTS.DistributedODEIntegrator) =
check_conservation(integrator.sol)
check_conservation(atmos_sol::AtmosSolveResults) =
check_conservation(atmos_sol.sol)

"""
check_conservation(sol)
check_conservation(simulation)
check_conservation(integrator)
Return:
- `energy_conservation = energy_net / energy_total`
- `mass_conservation = (mass(t_end) - mass(t_0)) / mass(t_0)`
- `water_conservation = (water_atmos + water_surface) / water_total`
"""
function check_conservation(sol)
# energy
energy_total = sum(sol.u[end].c.ρe_tot)
energy_atmos_change = sum(sol.u[end].c.ρe_tot) - sum(sol.u[1].c.ρe_tot)
p = sol.prob.p
sfc = p.atmos.surface_model
if sfc isa PrognosticSurfaceTemperature
sfc_cρh = sfc.ρ_ocean * sfc.cp_ocean * sfc.depth_ocean
energy_total +=
horizontal_integral_at_boundary(sol.u[end].sfc.T .* sfc_cρh)
energy_surface_change =
horizontal_integral_at_boundary(
sol.u[end].sfc.T .- sol.u[1].sfc.T,
) * sfc_cρh
else
energy_surface_change = -p.net_energy_flux_sfc[][]
end
energy_radiation_input = -p.net_energy_flux_toa[][]

energy_conservation =
abs(
energy_atmos_change + energy_surface_change -
energy_radiation_input,
) / energy_total

mass_conservation =
(sum(sol.u[end].c.ρ) - sum(sol.u[1].c.ρ)) / sum(sol.u[1].c.ρ)

water_conservation = zero(Spaces.undertype(axes(sol.u[end].c.ρ)))

if sfc isa PrognosticSurfaceTemperature
# water
water_total = sum(sol.u[end].c.ρq_tot)
water_atmos_change = sum(sol.u[end].c.ρq_tot) - sum(sol.u[1].c.ρq_tot)
water_surface_change = horizontal_integral_at_boundary(
sol.u[end].sfc.water .- sol.u[1].sfc.water,
)

water_conservation =
abs(water_atmos_change + water_surface_change) / water_total
end

return (; energy_conservation, mass_conservation, water_conservation)
end

0 comments on commit 23387fc

Please sign in to comment.