Skip to content
Closed
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ed26eb8
use ConservativeRegridding
juliasloan25 Jan 22, 2026
26815d5
use TripolarGrid [skip ci]
juliasloan25 Jan 22, 2026
c4d1688
use TripolarGrid [skip ci]
juliasloan25 Jan 22, 2026
70c7164
Merge branch 'js/tripolar-conservative-jan2026' of github.com:CliMA/C…
simone-silvestri Jan 22, 2026
6dd5577
new ocean setup
simone-silvestri Jan 22, 2026
a4c9fbf
use ConservativeRegridding
juliasloan25 Jan 22, 2026
a9f117d
use TripolarGrid [skip ci]
juliasloan25 Jan 22, 2026
306f0e2
new ocean setup
simone-silvestri Jan 22, 2026
c228a8c
use CR#main
juliasloan25 Jan 23, 2026
f05866d
use higher elem order in CMIP
juliasloan25 Jan 27, 2026
31bf61c
fix julia 1.10 manifest; oceananigans typo
juliasloan25 Jan 27, 2026
accc24a
use Float64 for CMIPs
juliasloan25 Jan 28, 2026
ef773b9
fix rebase; use Adapt for regridder [skip ci]
juliasloan25 Jan 29, 2026
8516b9d
Merge branch 'js/tripolar-conservative-jan2026' of github.com:CliMA/C…
simone-silvestri Jan 29, 2026
410567b
Apply suggestion from @simone-silvestri
simone-silvestri Jan 29, 2026
2561ffb
Apply suggestion from @simone-silvestri
simone-silvestri Jan 29, 2026
759a890
Fix indentation for remapper_oc_to_cc assignment
simone-silvestri Jan 29, 2026
07cc1e5
remove ocean restoring
juliasloan25 Jan 29, 2026
d8c7cd6
add simpler Oceananigans model option
juliasloan25 Jan 29, 2026
67723ff
use Int8 for OffsetArray indexing
juliasloan25 Jan 29, 2026
ebfc122
fixes
juliasloan25 Jan 29, 2026
9f0a285
get ocean_simulation from CO
juliasloan25 Jan 29, 2026
7094cd2
fix input test
juliasloan25 Jan 29, 2026
5a5fa15
Revert "use Int8 for OffsetArray indexing"
juliasloan25 Jan 29, 2026
769dfda
try simple ocean for regular CI CMIPs
juliasloan25 Jan 29, 2026
e495d4f
use ocean setup from main for simple ocean
juliasloan25 Jan 30, 2026
1767141
use latest 8 bit integer fix
juliasloan25 Feb 4, 2026
494df64
use Int8 OffsetArrays fork
juliasloan25 Feb 4, 2026
eb96ab8
Revert "use latest 8 bit integer fix"
juliasloan25 Feb 5, 2026
c510950
Revert "use Int8 OffsetArrays fork"
juliasloan25 Feb 5, 2026
9ecd8ee
try running CMIP on non-P100 GPUs (without Int8 fix)
juliasloan25 Feb 5, 2026
25f0948
run CMIP on v100s
juliasloan25 Feb 5, 2026
c8ea286
make ocean setup even simpler; run on P100
juliasloan25 Feb 5, 2026
882893b
put value_per_element array on GPU
juliasloan25 Feb 4, 2026
14480d0
dispatch on SeaIceSim for get_field
juliasloan25 Feb 5, 2026
8f7a42e
use working ConservativeRegridding branch
juliasloan25 Feb 5, 2026
91a4c96
swap ocean/sea ice include order
juliasloan25 Feb 6, 2026
76469eb
Add ConservativeRegridding dependency to Project.toml
simone-silvestri Feb 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions config/ci_configs/cmip_oceananigans_climaseaice.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FLOAT_TYPE: "Float32"
FLOAT_TYPE: "Float64"
albedo_model: "CouplerAlbedo"
atmos_config_file: "config/atmos_configs/climaatmos_edonly.yml"
coupler_toml: ["toml/amip_edonly.toml"]
Expand All @@ -9,12 +9,13 @@ dt_ocean: "1800secs" # 30 minutes
dt_seaice: "1800secs" # 30 minutes
dz_bottom: 100.0
energy_check: false
h_elem: 8
h_elem: 32
ice_model: "clima_seaice"
land_model: "integrated"
land_spun_up_ic: false
mode_name: "cmip"
netcdf_output_at_levels: true
nh_poly: 1
ocean_model: "oceananigans"
output_default_diagnostics: true
radiation_reset_rng_seed: true
Expand Down
5 changes: 3 additions & 2 deletions config/ci_configs/cmip_oceananigans_climaseaice_bucket.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FLOAT_TYPE: "Float32"
FLOAT_TYPE: "Float64"
albedo_model: "CouplerAlbedo"
atmos_config_file: "config/atmos_configs/climaatmos_edonly.yml"
bucket_albedo_type: "map_temporal"
Expand All @@ -10,10 +10,11 @@ dt_ocean: "1800secs" # 30 minutes
dt_seaice: "1800secs" # 30 minutes
dz_bottom: 100.0
energy_check: false
h_elem: 8
h_elem: 32
ice_model: "clima_seaice"
mode_name: "cmip"
netcdf_output_at_levels: true
nh_poly: 1
ocean_model: "oceananigans"
output_default_diagnostics: true
radiation_reset_rng_seed: true
Expand Down
4 changes: 3 additions & 1 deletion config/longrun_configs/cmip_edonly_bucket.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FLOAT_TYPE: "Float32"
FLOAT_TYPE: "Float64"
aerosol_radiation: true
atmos_config_file: "config/atmos_configs/climaatmos_edonly.yml"
bucket_albedo_type: "map_temporal"
Expand All @@ -11,9 +11,11 @@ dt_ocean: "120secs" # 2 minutes
dt_rad: "1hours"
dt_seaice: "120secs" # 2 minutes
energy_check: false
h_elem: 64
ice_model: "clima_seaice"
insolation: "timevarying"
mode_name: "cmip"
nh_poly: 1
ocean_model: "oceananigans"
prescribed_aerosols: ["CB1", "CB2", "DST01", "OC1", "OC2", "SO4", "SSLT01"]
rmse_check: true
Expand Down
4 changes: 3 additions & 1 deletion config/longrun_configs/cmip_edonly_land.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FLOAT_TYPE: "Float32"
FLOAT_TYPE: "Float64"
aerosol_radiation: true
atmos_config_file: "config/atmos_configs/climaatmos_edonly.yml"
checkpoint_dt: "720hours"
Expand All @@ -10,11 +10,13 @@ dt_ocean: "120secs" # 2 minutes
dt_rad: "1hours"
dt_seaice: "120secs" # 2 minutes
energy_check: false
h_elem: 64
ice_model: "clima_seaice"
insolation: "timevarying"
land_model: "integrated"
land_spun_up_ic: false
mode_name: "cmip"
nh_poly: 1
ocean_model: "oceananigans"
prescribed_aerosols: ["CB1", "CB2", "DST01", "OC1", "OC2", "SO4", "SSLT01"]
rmse_check: true
Expand Down
31 changes: 30 additions & 1 deletion experiments/ClimaEarth/Manifest-v1.11.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

julia_version = "1.11.8"
manifest_format = "2.0"
project_hash = "88cc89bf1807e712c8314e95f2147d5f7248896f"
project_hash = "63a52083e7157c640c34a856b0951a8330688e84"

[[deps.ADTypes]]
git-tree-sha1 = "f7304359109c768cf32dc5fa2d371565bb63b68a"
Expand Down Expand Up @@ -434,6 +434,11 @@ git-tree-sha1 = "34d9873079e4cb3d0c62926a225136824677073f"
uuid = "55437552-ac27-4d47-9aa3-63184e8fd398"
version = "1.0.0"

[[deps.ChunkSplitters]]
git-tree-sha1 = "63a3903063d035260f0f6eab00f517471c5dc784"
uuid = "ae650224-84b6-46f8-82ea-d812ca08434e"
version = "3.1.2"

[[deps.ClimaAnalysis]]
deps = ["Artifacts", "Dates", "Interpolations", "NCDatasets", "NaNStatistics", "OrderedCollections", "Reexport", "Statistics", "Unitful"]
git-tree-sha1 = "6becd117214e883e0069455303c43060a4d5eed1"
Expand Down Expand Up @@ -739,6 +744,30 @@ git-tree-sha1 = "d9d26935a0bcffc87d2613ce14c527c99fc543fd"
uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb"
version = "2.5.0"

[[deps.ConservativeRegridding]]
deps = ["ChunkSplitters", "DocStringExtensions", "Extents", "GeoInterface", "GeometryOps", "GeometryOpsCore", "LinearAlgebra", "ProgressMeter", "SciMLPublic", "SortTileRecursiveTree", "SparseArrays", "StableTasks", "StaticArrays"]
git-tree-sha1 = "14be129cf6c44210906eef3fd017fd9ba57acd43"
repo-rev = "main"
repo-url = "https://github.com/JuliaGeo/ConservativeRegridding.jl.git"
uuid = "8e50ac2c-eb48-49bc-a402-07c87b949343"
version = "0.2.0"

[deps.ConservativeRegridding.extensions]
ConservativeRegriddingClimaCoreExt = "ClimaCore"
ConservativeRegriddingHealpixExt = "Healpix"
ConservativeRegriddingInterfacesExt = "Interfaces"
ConservativeRegriddingOceananigansExt = "Oceananigans"
ConservativeRegriddingRingGridsExt = "RingGrids"
ConservativeRegriddingSpeedyWeatherExt = ["RingGrids", "SpeedyWeather"]

[deps.ConservativeRegridding.weakdeps]
ClimaCore = "d414da3d-4745-48bb-8d80-42e94e092884"
Healpix = "9f4e344d-96bc-545a-84a3-ae6b9e1b672b"
Interfaces = "85a1e053-f937-4924-92a5-1367d23b7b87"
Oceananigans = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09"
RingGrids = "d1845624-ad4f-453b-8ff4-a8db365bf3a7"
SpeedyWeather = "9e226e20-d153-4fed-8a5b-493def4f21a9"

[[deps.ConstructionBase]]
git-tree-sha1 = "b4b092499347b18a015186eae3042f72267106cb"
uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
Expand Down
31 changes: 30 additions & 1 deletion experiments/ClimaEarth/Manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

julia_version = "1.10.9"
manifest_format = "2.0"
project_hash = "b6758675118500db19bc41873b8c8741b74a3997"
project_hash = "6b7bac012d444043544ee6ea533d5321afdc5bde"

[[deps.ADTypes]]
git-tree-sha1 = "f7304359109c768cf32dc5fa2d371565bb63b68a"
Expand Down Expand Up @@ -431,6 +431,11 @@ git-tree-sha1 = "34d9873079e4cb3d0c62926a225136824677073f"
uuid = "55437552-ac27-4d47-9aa3-63184e8fd398"
version = "1.0.0"

[[deps.ChunkSplitters]]
git-tree-sha1 = "63a3903063d035260f0f6eab00f517471c5dc784"
uuid = "ae650224-84b6-46f8-82ea-d812ca08434e"
version = "3.1.2"

[[deps.ClimaAnalysis]]
deps = ["Artifacts", "Dates", "Interpolations", "NCDatasets", "NaNStatistics", "OrderedCollections", "Reexport", "Statistics", "Unitful"]
git-tree-sha1 = "6becd117214e883e0069455303c43060a4d5eed1"
Expand Down Expand Up @@ -738,6 +743,30 @@ git-tree-sha1 = "d9d26935a0bcffc87d2613ce14c527c99fc543fd"
uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb"
version = "2.5.0"

[[deps.ConservativeRegridding]]
deps = ["ChunkSplitters", "DocStringExtensions", "Extents", "GeoInterface", "GeometryOps", "GeometryOpsCore", "LinearAlgebra", "ProgressMeter", "SciMLPublic", "SortTileRecursiveTree", "SparseArrays", "StableTasks", "StaticArrays"]
git-tree-sha1 = "14be129cf6c44210906eef3fd017fd9ba57acd43"
repo-rev = "main"
repo-url = "https://github.com/JuliaGeo/ConservativeRegridding.jl.git"
uuid = "8e50ac2c-eb48-49bc-a402-07c87b949343"
version = "0.2.0"

[deps.ConservativeRegridding.extensions]
ConservativeRegriddingClimaCoreExt = "ClimaCore"
ConservativeRegriddingHealpixExt = "Healpix"
ConservativeRegriddingInterfacesExt = "Interfaces"
ConservativeRegriddingOceananigansExt = "Oceananigans"
ConservativeRegriddingRingGridsExt = "RingGrids"
ConservativeRegriddingSpeedyWeatherExt = ["RingGrids", "SpeedyWeather"]

[deps.ConservativeRegridding.weakdeps]
ClimaCore = "d414da3d-4745-48bb-8d80-42e94e092884"
Healpix = "9f4e344d-96bc-545a-84a3-ae6b9e1b672b"
Interfaces = "85a1e053-f937-4924-92a5-1367d23b7b87"
Oceananigans = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09"
RingGrids = "d1845624-ad4f-453b-8ff4-a8db365bf3a7"
SpeedyWeather = "9e226e20-d153-4fed-8a5b-493def4f21a9"

[[deps.ConstructionBase]]
git-tree-sha1 = "b4b092499347b18a015186eae3042f72267106cb"
uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
Expand Down
3 changes: 3 additions & 0 deletions experiments/ClimaEarth/Project.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[deps]
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63"
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
Cairo = "159f3aea-2a34-519c-b102-8c37f9878175"
Expand All @@ -17,6 +18,7 @@ ClimaParams = "5c42b081-d73a-476f-9059-fd94b934656c"
ClimaSeaIce = "6ba0ff68-24e6-4315-936c-2e99227c95a4"
ClimaTimeSteppers = "595c0a79-7f3d-439a-bc5a-b232dc3bde79"
ClimaUtilities = "b3f4f4ca-9299-4f7f-bd9b-81e1242a7513"
ConservativeRegridding = "8e50ac2c-eb48-49bc-a402-07c87b949343"
EnsembleKalmanProcesses = "aa8a2aa5-91d8-4396-bcef-d4f2ec43552d"
GPUCompiler = "61eb1bfa-7361-4325-ad38-22787b887f55"
GeoMakie = "db073c08-6b98-4ee5-b6a4-5efafb3259c6"
Expand Down Expand Up @@ -47,5 +49,6 @@ ClimaTimeSteppers = "0.7, 0.8"
ClimaUtilities = "0.1"
Insolation = "0.10.2"
Interpolations = "0.14, 0.15"
JLD2 = "0.4, 0.5, 0.6"
Poppler_jll = "24"
StaticArrays = "1"
46 changes: 14 additions & 32 deletions experiments/ClimaEarth/components/ocean/clima_seaice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ function ClimaSeaIceSimulation(

# Get the initial area fraction from the fractional ice concentration
boundary_space = axes(ocean.area_fraction)
area_fraction = Interfacer.remap(boundary_space, ice.model.ice_concentration)
area_fraction = Interfacer.remap(boundary_space, ice.model.ice_concentration, remapping)

sim = ClimaSeaIceSimulation(
ice,
Expand Down Expand Up @@ -332,23 +332,13 @@ function FluxCalculator.update_turbulent_fluxes!(sim::ClimaSeaIceSimulation, fie
F_turb_ρτxz_uv = sim.remapping.temp_uv_vec.components.data.:1
F_turb_ρτyz_uv = sim.remapping.temp_uv_vec.components.data.:2

# Remap momentum fluxes onto reduced 2D Center, Center fields using scratch arrays and fields
CC.Remapping.interpolate!(
sim.remapping.scratch_arr1,
sim.remapping.remapper_cc,
F_turb_ρτxz_uv,
)
OC.set!(sim.remapping.scratch_cc1, sim.remapping.scratch_arr1) # zonal momentum flux
CC.Remapping.interpolate!(
sim.remapping.scratch_arr2,
sim.remapping.remapper_cc,
F_turb_ρτyz_uv,
)
OC.set!(sim.remapping.scratch_cc2, sim.remapping.scratch_arr2) # meridional momentum flux
# Remap momentum fluxes onto reduced 2D Center, Center fields
Interfacer.remap!(sim.remapping.scratch_field_oc1, F_turb_ρτxz, sim.remapping) # zonal momentum flux
Interfacer.remap!(sim.remapping.scratch_field_oc2, F_turb_ρτyz, sim.remapping) # meridional momentum flux
Comment on lines +336 to +337
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug (fixed in new branch)

Suggested change
Interfacer.remap!(sim.remapping.scratch_field_oc1, F_turb_ρτxz, sim.remapping) # zonal momentum flux
Interfacer.remap!(sim.remapping.scratch_field_oc2, F_turb_ρτyz, sim.remapping) # meridional momentum flux
Interfacer.remap!(sim.remapping.scratch_field_oc1, F_turb_ρτxz_uv, sim.remapping) # zonal momentum flux
Interfacer.remap!(sim.remapping.scratch_field_oc2, F_turb_ρτyz_uv, sim.remapping) # meridional momentum flux


# Rename for clarity; these are now Center, Center Oceananigans fields
F_turb_ρτxz_cc = sim.remapping.scratch_cc1
F_turb_ρτyz_cc = sim.remapping.scratch_cc2
F_turb_ρτxz_cc = sim.remapping.scratch_field_oc1
F_turb_ρτyz_cc = sim.remapping.scratch_field_oc2

# Set the momentum flux BCs at the correct locations using the remapped scratch fields
# Note that this requires the sea ice model to always be run with dynamics turned on
Expand All @@ -362,12 +352,12 @@ function FluxCalculator.update_turbulent_fluxes!(sim::ClimaSeaIceSimulation, fie
)

# Remap the latent and sensible heat fluxes using scratch arrays
CC.Remapping.interpolate!(sim.remapping.scratch_arr1, sim.remapping.remapper_cc, F_lh) # latent heat flux
CC.Remapping.interpolate!(sim.remapping.scratch_arr2, sim.remapping.remapper_cc, F_sh) # sensible heat flux
Interfacer.remap!(sim.remapping.scratch_field_oc1, F_lh, sim.remapping) # latent heat flux
Interfacer.remap!(sim.remapping.scratch_field_oc2, F_sh, sim.remapping) # sensible heat flux

# Rename for clarity; recall F_turb_energy = F_lh + F_sh
remapped_F_lh = sim.remapping.scratch_arr1
remapped_F_sh = sim.remapping.scratch_arr2
remapped_F_lh = OC.interior(sim.remapping.scratch_field_oc1, :, :, 1)
remapped_F_sh = OC.interior(sim.remapping.scratch_field_oc2, :, :, 1)

# Update the sea ice only where the concentration is greater than zero.
si_flux_heat = sim.ice.model.external_heat_fluxes.top[1]
Expand Down Expand Up @@ -405,19 +395,11 @@ function FieldExchanger.update_sim!(sim::ClimaSeaIceSimulation, csf)
ice_concentration = sim.ice.model.ice_concentration

# Remap radiative flux onto scratch array; rename for clarity
CC.Remapping.interpolate!(
sim.remapping.scratch_arr1,
sim.remapping.remapper_cc,
csf.SW_d,
)
remapped_SW_d = sim.remapping.scratch_arr1
Interfacer.remap!(sim.remapping.scratch_field_oc1, csf.SW_d, sim.remapping) # shortwave radiation
remapped_SW_d = OC.interior(sim.remapping.scratch_field_oc1, :, :, 1)

CC.Remapping.interpolate!(
sim.remapping.scratch_arr2,
sim.remapping.remapper_cc,
csf.LW_d,
)
remapped_LW_d = sim.remapping.scratch_arr2
Interfacer.remap!(sim.remapping.scratch_field_oc2, csf.LW_d, sim.remapping) # longwave radiation
remapped_LW_d = OC.interior(sim.remapping.scratch_field_oc2, :, :, 1)

# Update only the part due to radiative fluxes. For the full update, the component due
# to latent and sensible heat is missing and will be updated in update_turbulent_fluxes.
Expand Down
72 changes: 0 additions & 72 deletions experiments/ClimaEarth/components/ocean/climaocean_helpers.jl
Original file line number Diff line number Diff line change
@@ -1,46 +1,3 @@
"""
to_node(pt::CC.Geometry.LatLongPoint)

Transform `LatLongPoint` into a tuple (long, lat, 0), where the 0 is needed because we only
care about the surface.
"""
@inline to_node(pt::CC.Geometry.LatLongPoint) = pt.long, pt.lat, zero(pt.lat)
# This next one is needed if we have "LevelGrid"
@inline to_node(pt::CC.Geometry.LatLongZPoint) = pt.long, pt.lat, zero(pt.lat)

"""
map_interpolate!(target_field::CC.Fields.Field, source_field::OC.Field)

Interpolate the given 3D field onto the target field, modifying the target field in place.

If the underlying grid does not contain a given point, writes 0 instead.

Note: `map_interpolate!` does not support interpolation from `Field`s defined on
`OrthogononalSphericalShellGrids` such as the `TripolarGrid`.
"""
function map_interpolate!(target_field::CC.Fields.Field, source_field::OC.Field)
points = CC.Fields.coordinate_field(axes(target_field))
loc = map(L -> L(), OC.Fields.location(source_field))
grid = source_field.grid
data = source_field.data

# TODO: There has to be a better way
min_lat, max_lat = extrema(OC.φnodes(grid, OC.Center(), OC.Center(), OC.Center()))

# Use map! on the field directly, which handles complex data layouts correctly
map!(target_field, points) do pt
FT = eltype(pt)

# The oceananigans grid does not cover the entire globe, so we should not
# interpolate outside of its latitude bounds. Instead we return 0
min_lat < pt.lat < max_lat || return FT(0)

fᵢ = OC.Fields.interpolate(to_node(pt), data, loc, grid)
return convert(FT, fᵢ)::FT
end
return nothing
end

"""
surface_flux(f::OC.AbstractField)

Expand All @@ -55,35 +12,6 @@ function surface_flux(f::OC.AbstractField)
end
end

function Interfacer.remap!(target_field::CC.Fields.Field, source_field::OC.Field)
map_interpolate!(target_field, source_field)
return nothing
end

function Interfacer.remap!(
target_field::CC.Fields.Field,
operation::OC.AbstractOperations.AbstractOperation,
)
evaluated_field = OC.Field(operation)
OC.compute!(evaluated_field)
Interfacer.remap!(target_field, evaluated_field)
return nothing
end

function Interfacer.remap(target_space, field::OC.Field)
# Allocate target field and call remap!
target_field = CC.Fields.zeros(target_space)
Interfacer.remap!(target_field, field)
return target_field
end

function Interfacer.remap(target_space, operation::OC.AbstractOperations.AbstractOperation)
# Allocate target field and call remap!
target_field = CC.Fields.zeros(target_space)
Interfacer.remap!(target_field, operation)
return target_field
end

"""
set_from_extrinsic_vector!(vector, grid, u_cc, v_cc)

Expand Down
Loading
Loading