Skip to content

Commit

Permalink
Merge pull request #128 from gaelforget/v0p3p6e
Browse files Browse the repository at this point in the history
add FaIR module, increase coverage
  • Loading branch information
gaelforget authored Sep 11, 2024
2 parents eaf7096 + 47d9cd4 commit 9603054
Show file tree
Hide file tree
Showing 10 changed files with 631 additions and 9 deletions.
9 changes: 8 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
Git = "d7ba0133-e1db-5d97-8f8c-041e4b3a1eb2"
Glob = "c27321d9-0574-5035-807b-f59d2c89b15c"
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
Expand All @@ -26,6 +29,7 @@ Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d"
IniFile = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
NetCDF = "30363a11-5582-574a-97bb-aa9a979735b9"
Oceananigans = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09"
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
Zarr = "0a941bbe-ad1d-11e8-39d9-ab76183a1d99"

Expand All @@ -34,21 +38,24 @@ ClimateModelsCondaExt = ["Conda"]
ClimateModelsIniFileExt = ["IniFile"]
ClimateModelsMakieExt = ["Makie"]
ClimateModelsNetCDFExt = ["NetCDF"]
ClimateModelsOceananigansExt = ["Oceananigans"]
ClimateModelsPyCallExt = ["PyCall"]
ClimateModelsZarrExt = ["Zarr"]

[compat]
CFTime = "0.1"
CSV = "0.6, 0.7, 0.8, 0.9, 0.10"
Conda = "1"
CFTime = "0.1"
DataDeps = "0.7"
DataFrames = "1"
Dataverse = "0.2"
Git = "1"
Glob = "1"
IniFile = "0.5"
JLD2 = "0.4, 0.5"
Makie = "0.21"
NetCDF = "0.11, 0.12"
Oceananigans = "0.90"
OrderedCollections = "1"
PyCall = "1"
Suppressor = "0.2"
Expand Down
2 changes: 2 additions & 0 deletions ext/ClimateModelsMakieExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ function plot_examples(ID=Symbol,stuff...)
Speedy_plot_input(stuff...)
elseif ID==:Speedy_zm
Speedy_plot_output_zm(stuff...)
elseif ID==:Speedy_xy
Speedy_plot_output_xy(stuff...)
elseif ID==:Hector
plot_Hector(stuff...)
elseif ID==:Hector_scenarios
Expand Down
9 changes: 7 additions & 2 deletions ext/ClimateModelsNetCDFExt.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module ClimateModelsNetCDFExt

using NetCDF
import ClimateModels: write_CMIP6_mean, read_CMIP6_mean, ModelConfig
import ClimateModels: write_CMIP6_mean, read_CMIP6_mean, AbstractModelConfig, read_NetCDF

function write_CMIP6_mean(x::ModelConfig,mm,meta)
function write_CMIP6_mean(x::AbstractModelConfig,mm,meta)
pth=joinpath(pathof(x),"output")
filename = joinpath(pth,"MeanMaps.nc")
varname = x.inputs["variable_id"]
Expand All @@ -21,4 +21,9 @@ module ClimateModelsNetCDFExt
return lon,lat,var
end

function read_NetCDF(file)
ncfile = NetCDF.open(file)
ncfile.vars
end

end
109 changes: 109 additions & 0 deletions ext/ClimateModelsOceananigansExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@

module ClimateModelsOceananigansExt

using Oceananigans, ClimateModels
import ClimateModels: JLD2, @printf, Oceananigans_launch
import ClimateModels: Oceananigans_setup_grid, Oceananigans_setup_BC
import ClimateModels: Oceananigans_build_model, Oceananigans_build_simulation

import Oceananigans.Units: minute, minutes, hour

function Oceananigans_setup_grid(Nz=50,Lz=50)
#Nz = 50 # number of points in the vertical direction
#Lz = 50 # (m) domain depth
fz(k)=-Lz*(Nz+1-k)/Nz #fz.(1:Nz+1) gives the vertical grid for w points
return RectilinearGrid(size = (32, 32, Nz), x = (0, 64), y = (0, 64), z = fz)
end

function Oceananigans_setup_BC(Qʰ,u₁₀,Ev)
dTdz = 0.1 # K m⁻¹, bottom boundary condition
ρₒ = 1026 # kg m⁻³, average density at the surface of the world ocean
cᴾ = 3991 # J K⁻¹ kg⁻¹, typical heat capacity for seawater
Qᵀ(x, y, t) = (t) / (ρₒ * cᴾ) # K m s⁻¹, surface _temperature_ flux
T_bcs = FieldBoundaryConditions(top = FluxBoundaryCondition(Qᵀ),
bottom = GradientBoundaryCondition(dTdz))

cᴰ = 2.5e-3 # dimensionless drag coefficient
ρₐ = 1.225 # kg m⁻³, average density of air at sea-level
Qᵘ(x, y, t) = - ρₐ / ρₒ * cᴰ * u₁₀(t) * abs(u₁₀(t)) # m² s⁻²
u_bcs = FieldBoundaryConditions(top = FluxBoundaryCondition(Qᵘ))

(x, y, t, S) = - Ev(t) * S # [salinity unit] m s⁻¹
evaporation_bc = FluxBoundaryCondition(Qˢ, field_dependencies=:S)
S_bcs = FieldBoundaryConditions(top=evaporation_bc)

return (u=u_bcs,T=T_bcs,S=S_bcs)
end

##

function Oceananigans_build_model(grid,BC,IC)

buoyancy = SeawaterBuoyancy(equation_of_state=LinearEquationOfState(thermal_expansion=2e-4, haline_contraction=8e-4))

model = NonhydrostaticModel(
advection = UpwindBiasedFifthOrder(),
timestepper = :RungeKutta3,
grid = grid,
tracers = (:T, :S),
coriolis = FPlane(f=1e-4),
buoyancy = buoyancy,
closure = AnisotropicMinimumDissipation(),
boundary_conditions = (u=BC.u, T=BC.T, S=BC.S))

# initial conditions (as functions of x,y,z)
set!(model, u=IC.u, w=IC.u, T=IC.T, S=IC.S)

return model
end

function Oceananigans_build_simulation(model,Nh,rundir)
simulation = Simulation(model, Δt=10.0, stop_time=Nh*60minutes)

wizard = TimeStepWizard(cfl=1.0, max_change=1.1, max_Δt=20.0)
simulation.callbacks[:wizard] = Callback(wizard, IterationInterval(10))

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))
simulation.callbacks[:progress] = Callback(progress_message, IterationInterval(1minute))

eddy_viscosity = (; νₑ = model.diffusivity_fields.νₑ)
simulation.output_writers[:slices] =
JLD2OutputWriter(model, merge(model.velocities, model.tracers, eddy_viscosity),
dir = rundir,
filename = "daily_cycle.jld2",
indices = (:,Int(model.grid.Ny/2),:),
schedule = TimeInterval(1minute),
overwrite_existing = true)

simulation.output_writers[:checkpointer] =
Checkpointer(model, schedule=TimeInterval(24hour), dir = rundir, prefix="model_checkpoint")

##

fil=simulation.output_writers[:slices].filepath

xw, yw, zw = nodes(model.velocities.w)
xT, yT, zT = nodes(model.tracers.T)
coords=(xw, yw, zw, xT, yT, zT)

fil_coords=joinpath(rundir,"coords.jld2")
JLD2.jldopen(fil_coords, "w") do file
mygroup = JLD2.Group(file, "coords")
mygroup["xw"] = xw
mygroup["yw"] = yw
mygroup["zw"] = zw
mygroup["xT"] = xT
mygroup["yT"] = yT
mygroup["zT"] = zT
end

return simulation
end

Oceananigans_launch(x::OceananigansConfig) = run!(x.outputs["simulation"], pickup=true)

end

27 changes: 22 additions & 5 deletions src/ClimateModels.jl
Original file line number Diff line number Diff line change
@@ -1,34 +1,51 @@
module ClimateModels

using UUIDs, Suppressor, OrderedCollections
using Pkg, Git, TOML
using Pkg, Git, TOML, Printf, JLD2

function plot_examples end
function read_Zarr end
function write_CMIP6_mean end
function read_CMIP6_mean end
function read_IniFile end
function read_NetCDF end
function Oceananigans_setup_grid end
function Oceananigans_setup_BC end
function Oceananigans_build_model end
function Oceananigans_build_simulation end
function Oceananigans_launch end

include("interface.jl")
include("notebooks.jl")
include("toy_models.jl")
include("files.jl")
include("CMIP6.jl")
include("Hector.jl")
include("FaIR.jl")
include("Speedy.jl")
include("Oceananigans.jl")

import .notebooks: update
import .downloads: add_datadep
import .Hector: HectorConfig

export AbstractModelConfig, ModelConfig, PlutoConfig, HectorConfig
export ModelRun, @ModelRun, PkgDevConfig, add_datadep, read_Zarr, read_IniFile
import .FaIR: FaIRConfig
import .Speedy: SpeedyConfig
import .Oceananigans: OceananigansConfig

export AbstractModelConfig, ModelConfig, PlutoConfig
export HectorConfig, FaIRConfig, SpeedyConfig, OceananigansConfig
export ModelRun, @ModelRun, PkgDevConfig, add_datadep
export read_Zarr, read_IniFile, read_NetCDF
export clean, build, compile, setup, launch, update, notebooks
export put!, take!, pathof, readdir, log
#export git_log_init, git_log_msg, git_log_fil
#export git_log_prm, git_log_show
#export monitor, help, pause
#export train, compare, analyze
export RandomWalker, IPCC, CMIP6, Hector

export RandomWalker, IPCC, CMIP6, Hector, FaIR, Speedy
#don't export Oceananigans module, which would conflict with Oceananigans.jl
#export Oceananigans

#export OrderedDict, UUID, uuid4, @suppress

Expand Down
76 changes: 76 additions & 0 deletions src/FaIR.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@

module FaIR

import ClimateModels
import ClimateModels: setup, AbstractModelConfig

uuid4=ClimateModels.uuid4
UUID=ClimateModels.UUID
OrderedDict=ClimateModels.OrderedDict

function loop_over_scenarios()
scenarios=[:rcp26,:rcp45,:rcp60,:rcp85]
temperatures=[]

(fair,forward,RCPs)=ClimateModels.pyimport(:fair)

for i in scenarios
emissions=RCPs[i].Emissions.emissions
C,F,T = forward.fair_scm(emissions=emissions)
push!(temperatures,T)
end

scenarios,temperatures
end

"""
struct FaIRConfig <: AbstractModelConfig
Concrete type of `AbstractModelConfig` for `FaIR` model.
"""
Base.@kwdef struct FaIRConfig <: AbstractModelConfig
model :: String = "FaIR"
configuration :: String = "rcp45"
inputs :: OrderedDict{Any,Any} = OrderedDict{Any,Any}()
outputs :: OrderedDict{Any,Any} = OrderedDict(:C=>Float64[],:F=>Float64[],:T=>Float64[])
status :: OrderedDict{Any,Any} = OrderedDict{Any,Any}()
channel :: Channel{Any} = Channel{Any}(10)
folder :: String = tempdir()
ID :: UUID = uuid4()
end

function setup(x :: FaIRConfig)
!isdir(x.folder) ? mkdir(x.folder) : nothing
!isdir(pathof(x)) ? mkdir(pathof(x)) : nothing
try
ClimateModels.pyimport(:fair)
catch
ClimateModels.conda(:fair)
end
!isdir(joinpath(pathof(x),"log")) ? log(x,"initial setup",init=true) : nothing
put!(x.channel,FaIR_launch)
end

function FaIR_launch(x::FaIRConfig)
pth0=pwd()
cd(pathof(x))

(fair,forward,RCPs)=ClimateModels.pyimport(:fair)

emissions=RCPs.rcp85.Emissions.emissions
C,F,T = forward.fair_scm(emissions=emissions)

if isempty(x.outputs[:C])
push!.(Ref(x.outputs[:C]),C[:])
push!.(Ref(x.outputs[:F]),F[:])
push!.(Ref(x.outputs[:T]),T[:])
else
x.outputs[:C]=C[:]
x.outputs[:F]=F[:]
x.outputs[:T]=T[:]
end

cd(pth0)
end

end
Loading

0 comments on commit 9603054

Please sign in to comment.