Skip to content

Commit cc0d33a

Browse files
Avoiding distributed fill_halo_regions! in dynamics by extending the halos (#88)
* this should work? * launch this * remove this * go like this * make it work * try it out * let's go! * Update sea_ice_time_stepping.jl * Update sea_ice_model.jl * Optimize halo region filling for momentum equations Refactor halo region filling to only process local halos. * go ahead * add this * go back * Update sea_ice_model.jl * assume * Update runtests.jl * Adjust halo size calculation in sea ice model * add a test * separate tests * remove ext * ensure the correct group * fix distributed tests * add the dynamics * fix tests * sea ice model * another bugfix * add stuff * add Oceananigans * fix keyword * fix these tests * fix stuff * add with _halo * fix
1 parent 7314849 commit cc0d33a

File tree

8 files changed

+352
-110
lines changed

8 files changed

+352
-110
lines changed

.github/workflows/ci.yml

Lines changed: 127 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,150 @@
11
name: CI
2+
23
on:
3-
push:
4-
branches: [main]
5-
tags: ["*"]
64
pull_request:
5+
paths:
6+
- '.github/workflows/ci.yml'
7+
- 'src/**'
8+
- 'test/**'
9+
- 'Project.toml'
10+
push:
11+
branches:
12+
- main
13+
tags: '*'
14+
paths:
15+
- '.github/workflows/ci.yml'
16+
- 'src/**'
17+
- 'test/**'
18+
- 'Project.toml'
19+
20+
concurrency:
21+
# Skip intermediate builds: always.
22+
# Cancel intermediate builds: only if it is a pull request build.
23+
group: ${{ github.workflow }}-${{ github.ref }}
24+
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
25+
726
jobs:
8-
test:
9-
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
27+
checkpointing_tests:
28+
name: Checkpointing Tests - Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
29+
runs-on: ${{ matrix.os }}
30+
timeout-minutes: 120
31+
strategy:
32+
fail-fast: false
33+
matrix:
34+
version:
35+
- '1.10'
36+
os:
37+
- ubuntu-latest
38+
arch:
39+
- x64
40+
steps:
41+
- uses: actions/checkout@v5
42+
- uses: julia-actions/setup-julia@v2
43+
with:
44+
version: ${{ matrix.version }}
45+
arch: ${{ matrix.arch }}
46+
- uses: julia-actions/cache@v2
47+
- uses: julia-actions/julia-buildpkg@v1
48+
- uses: julia-actions/julia-runtest@v1
49+
env:
50+
TEST_GROUP: "checkpointing"
51+
52+
distributed:
53+
name: Distributed Tests - Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
54+
runs-on: ${{ matrix.os }}
55+
timeout-minutes: 120
56+
strategy:
57+
fail-fast: false
58+
matrix:
59+
version:
60+
- '1.10'
61+
os:
62+
- ubuntu-latest
63+
arch:
64+
- x64
65+
steps:
66+
- uses: actions/checkout@v5
67+
- uses: julia-actions/setup-julia@v2
68+
with:
69+
version: ${{ matrix.version }}
70+
arch: ${{ matrix.arch }}
71+
- uses: julia-actions/cache@v2
72+
- uses: julia-actions/julia-buildpkg@v1
73+
- uses: julia-actions/julia-runtest@v1
74+
env:
75+
TEST_GROUP: "distributed"
76+
77+
advection:
78+
name: Sea Ice Advection - Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
1079
runs-on: ${{ matrix.os }}
80+
timeout-minutes: 120
1181
strategy:
1282
fail-fast: false
1383
matrix:
1484
version:
1585
- '1.10'
16-
- '1.12'
1786
os:
1887
- ubuntu-latest
1988
arch:
2089
- x64
21-
- x86
22-
include:
23-
# test macOS and Windows with latest Julia only
24-
- os: macOS-latest
25-
arch: x64
26-
version: '1.10'
27-
- os: windows-latest
28-
arch: x64
29-
version: '1.10'
30-
- os: windows-latest
31-
arch: x86
32-
version: '1.10'
3390
steps:
34-
- uses: actions/checkout@v4
35-
- uses: julia-actions/setup-julia@latest
91+
- uses: actions/checkout@v5
92+
- uses: julia-actions/setup-julia@v2
3693
with:
3794
version: ${{ matrix.version }}
3895
arch: ${{ matrix.arch }}
39-
- uses: actions/cache@v3
96+
- uses: julia-actions/cache@v2
97+
- uses: julia-actions/julia-buildpkg@v1
98+
- uses: julia-actions/julia-runtest@v1
4099
env:
41-
cache-name: cache-artifacts
100+
TEST_GROUP: "advection"
101+
102+
timestepping:
103+
name: Time Stepping - Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
104+
runs-on: ${{ matrix.os }}
105+
timeout-minutes: 120
106+
strategy:
107+
fail-fast: false
108+
matrix:
109+
version:
110+
- '1.10'
111+
os:
112+
- ubuntu-latest
113+
arch:
114+
- x64
115+
steps:
116+
- uses: actions/checkout@v5
117+
- uses: julia-actions/setup-julia@v2
42118
with:
43-
path: ~/.julia/artifacts
44-
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
45-
restore-keys: |
46-
${{ runner.os }}-test-${{ env.cache-name }}-
47-
${{ runner.os }}-test-
48-
${{ runner.os }}-
119+
version: ${{ matrix.version }}
120+
arch: ${{ matrix.arch }}
121+
- uses: julia-actions/cache@v2
49122
- uses: julia-actions/julia-buildpkg@v1
50123
- uses: julia-actions/julia-runtest@v1
51-
- uses: julia-actions/julia-processcoverage@v1
52-
- uses: codecov/codecov-action@v2
124+
env:
125+
TEST_GROUP: "timestepping"
126+
127+
enthalpy:
128+
name: Enthalpy Model - Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
129+
runs-on: ${{ matrix.os }}
130+
timeout-minutes: 120
131+
strategy:
132+
fail-fast: false
133+
matrix:
134+
version:
135+
- '1.10'
136+
os:
137+
- ubuntu-latest
138+
arch:
139+
- x64
140+
steps:
141+
- uses: actions/checkout@v5
142+
- uses: julia-actions/setup-julia@v2
53143
with:
54-
file: lcov.info
144+
version: ${{ matrix.version }}
145+
arch: ${{ matrix.arch }}
146+
- uses: julia-actions/cache@v2
147+
- uses: julia-actions/julia-buildpkg@v1
148+
- uses: julia-actions/julia-runtest@v1
149+
env:
150+
TEST_GROUP: "enthalpy"

src/SeaIceDynamics/sea_ice_momentum_equations.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ function SeaIceMomentumEquation(grid;
5959
top_momentum_stress = nothing,
6060
bottom_momentum_stress = nothing,
6161
free_drift = nothing,
62-
solver = SplitExplicitSolver(150),
62+
solver = SplitExplicitSolver(grid; substeps=150),
6363
minimum_concentration = 1e-3,
6464
minimum_mass = 1.0)
6565

src/SeaIceDynamics/split_explicit_momentum_equations.jl

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,41 @@
11
using Oceananigans.Grids: AbstractGrid, architecture, halo_size
2-
using Oceananigans.BoundaryConditions: fill_halo_regions!, fill_halo_size, fill_halo_offset
32
using Oceananigans.Utils: configure_kernel
43
using Oceananigans.Architectures: convert_to_device
54
using Oceananigans.Fields: instantiated_location, boundary_conditions
5+
using Oceananigans.DistributedComputations: DistributedGrid
66
using Oceananigans.ImmersedBoundaries: peripheral_node
7+
using Oceananigans.BoundaryConditions: fill_halo_regions!, fill_halo_size, fill_halo_offset
8+
9+
using Oceananigans.Models.HydrostaticFreeSurfaceModels.SplitExplicitFreeSurfaces: split_explicit_kernel_size
710

8-
struct SplitExplicitSolver
9-
substeps :: Int
11+
struct SplitExplicitSolver{I, K}
12+
substeps :: I
13+
kernel_parameters :: K
1014
end
1115

1216
"""
13-
SplitExplicitSolver(; substeps=120)
17+
SplitExplicitSolver(grid; substeps=120)
1418
1519
Creates a `SplitExplicitSolver` that controls the dynamical evolution of sea-ice momentum
1620
by subcycling `substeps` times in between each ice_thermodynamics / tracer advection time step.
1721
1822
The default number of substeps is 120.
1923
"""
20-
SplitExplicitSolver(; substeps=120) = SplitExplicitSolver(substeps)
24+
SplitExplicitSolver(grid; substeps=120) = SplitExplicitSolver(substeps, :xy)
25+
26+
function SplitExplicitSolver(grid::DistributedGrid; substeps=120)
27+
Nx, Ny, _ = size(grid)
28+
Hx, Hy, _ = halo_size(grid)
29+
TX, TY, _ = topology(grid)
30+
kernel_sizes = map(split_explicit_kernel_size, (TX, TY), (Nx, Ny), (Hx, Hy))
31+
return SplitExplicitSolver(substeps, KernelParameters(kernel_sizes...))
32+
end
33+
34+
# When no grid is provided, we assume a serial grid with default kernel parameters
35+
SplitExplicitSolver(; substeps=120) = SplitExplicitSolver(substeps, :xy)
2136

2237
const SplitExplicitMomentumEquation = SeaIceMomentumEquation{<:SplitExplicitSolver}
38+
const ExtendedSplitExplicitMomentumEquation = SeaIceMomentumEquation{<:SplitExplicitSolver{<:Any, <:KernelParameters}}
2339

2440
"""
2541
time_step_momentum!(model, rheology::AbstractExplicitRheology, Δt)
@@ -58,10 +74,10 @@ function time_step_momentum!(model, dynamics::SplitExplicitMomentumEquation, Δt
5874
= model.ice_concentration,
5975
ρ = model.ice_density))
6076

61-
active_cells_map = Oceananigans.Grids.get_active_column_map(grid)
77+
params = dynamics.solver.kernel_parameters
6278

63-
u_velocity_kernel!, _ = configure_kernel(arch, grid, :xy, _u_velocity_step!; active_cells_map)
64-
v_velocity_kernel!, _ = configure_kernel(arch, grid, :xy, _v_velocity_step!; active_cells_map)
79+
u_velocity_kernel!, _ = configure_kernel(arch, grid, params, _u_velocity_step!)
80+
v_velocity_kernel!, _ = configure_kernel(arch, grid, params, _v_velocity_step!)
6581

6682
substeps = dynamics.solver.substeps
6783
initialize_rheology!(model, dynamics.rheology)
@@ -101,6 +117,9 @@ function time_step_momentum!(model, dynamics::SplitExplicitMomentumEquation, Δt
101117
converted_stresses_args = convert_to_device(arch, stresses_args)
102118

103119
for substep in 1 : substeps
120+
fill_halo_regions!(converted_u_halo...; only_local_halos = true)
121+
fill_halo_regions!(converted_v_halo...; only_local_halos = true)
122+
104123
# Compute stresses! depending on the particular rheology implementation
105124
compute_stresses!(dynamics, converted_stresses_args...)
106125

@@ -115,9 +134,6 @@ function time_step_momentum!(model, dynamics::SplitExplicitMomentumEquation, Δt
115134
v_velocity_kernel!(converted_v_args...)
116135
u_velocity_kernel!(converted_u_args...)
117136
end
118-
119-
fill_halo_regions!(converted_u_halo...)
120-
fill_halo_regions!(converted_v_halo...)
121137
end
122138
end
123139

src/sea_ice_model.jl

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@ using Oceananigans.TimeSteppers: TimeStepper
44
using Oceananigans.BoundaryConditions: regularize_field_boundary_conditions
55
using Oceananigans: tupleit, tracernames
66
using Oceananigans.Forcings: model_forcing
7+
using Oceananigans.Grids: halo_size, topology, with_halo
8+
using Oceananigans.Grids: LeftConnected, RightConnected, FullyConnected
79

10+
using ClimaSeaIce.SeaIceDynamics: ExtendedSplitExplicitMomentumEquation
811
using ClimaSeaIce.SeaIceThermodynamics: PrescribedTemperature
912
using ClimaSeaIce.SeaIceThermodynamics.HeatBoundaryConditions: flux_summary
1013

1114
@inline instantiate(T::DataType) = T()
1215
@inline instantiate(T) = T
1316

17+
const ConnectedTopology = Union{LeftConnected, RightConnected, FullyConnected}
18+
1419
struct SeaIceModel{GR, TD, D, TS, CL, U, T, IT, IC, ID, CT, STF, A, F, Arch} <: AbstractModel{TS, Arch}
1520
architecture :: Arch
1621
grid :: GR
@@ -72,8 +77,24 @@ function SeaIceModel(grid;
7277
boundary_conditions = regularize_field_boundary_conditions(boundary_conditions, grid, field_names)
7378

7479
if isnothing(velocities)
75-
u = Field{Face, Center, Nothing}(grid, boundary_conditions=boundary_conditions.u)
76-
v = Field{Center, Face, Nothing}(grid, boundary_conditions=boundary_conditions.v)
80+
81+
# Extend the halos for the velocity fields if the dynamics is
82+
# an extended split explicit momentum equation
83+
if dynamics isa ExtendedSplitExplicitMomentumEquation
84+
old_halos = halo_size(grid)
85+
Nsubsteps = length(dynamics.solver.substeps)
86+
TX, TY = topology(grid)
87+
Hx = TX() isa ConnectedTopology ? Nsubsteps + old_halos[1] : old_halos[1]
88+
Hy = TY() isa ConnectedTopology ? Nsubsteps + old_halos[2] : old_halos[2]
89+
90+
new_halos = (Hx, Hy, old_halos[3])
91+
velocity_grid = with_halo(new_halos, grid)
92+
else
93+
velocity_grid = grid
94+
end
95+
96+
u = Field{Face, Center, Nothing}(velocity_grid, boundary_conditions=boundary_conditions.u)
97+
v = Field{Center, Face, Nothing}(velocity_grid, boundary_conditions=boundary_conditions.v)
7798
velocities = (; u, v)
7899
end
79100

src/sea_ice_time_stepping.jl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,9 @@ function update_state!(model::SIM)
8383

8484
foreach(prognostic_fields(model)) do field
8585
mask_immersed_field_xy!(field, k=size(model.grid, 3))
86+
fill_halo_regions!(field, model.clock, fields(model))
8687
end
8788

88-
fill_halo_regions!(prognostic_fields(model), model.clock, fields(model))
89-
9089
update_model_field_time_series!(model, model.clock)
9190

9291
return nothing
@@ -104,4 +103,4 @@ function update_model_field_time_series!(model::SeaIceModel, clock::Clock)
104103
end
105104

106105
return nothing
107-
end
106+
end

test/distributed_tests_utils.jl

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using JLD2
2+
using MPI
3+
using Oceananigans
4+
using Oceananigans.DistributedComputations: reconstruct_global_field, reconstruct_global_grid
5+
using Oceananigans.Units
6+
using ClimaSeaIce
7+
using ClimaSeaIce.SeaIceDynamics: SeaIceMomentumEquation, ElastoViscoPlasticRheology, SemiImplicitStress
8+
9+
# Run the distributed grid simulation and save down reconstructed results
10+
function run_distributed_sea_ice(arch, filename)
11+
distributed_grid = RectilinearGrid(arch;
12+
size = (100, 100, 1),
13+
x = (-10kilometers, 10kilometers),
14+
y = (-10kilometers, 10kilometers),
15+
z = (-1, 0),
16+
halo = (5, 5, 5))
17+
18+
model = run_distributed_simulation(distributed_grid)
19+
20+
u = reconstruct_global_field(model.velocities.u)
21+
v = reconstruct_global_field(model.velocities.v)
22+
23+
if arch.local_rank == 0
24+
jldsave(filename; u = Array(interior(u, :, :, 1)),
25+
v = Array(interior(v, :, :, 1)))
26+
end
27+
28+
MPI.Barrier(MPI.COMM_WORLD)
29+
MPI.Finalize()
30+
31+
return nothing
32+
end
33+
34+
# Just a random simulation on a rectilinear grid
35+
function run_distributed_simulation(grid)
36+
37+
τᵤ = 0.01
38+
τᵥ = 0.01
39+
τₒ = SemiImplicitStress()
40+
41+
# We use an elasto-visco-plastic rheology and WENO seventh order
42+
# for advection of h and ℵ
43+
dynamics = SeaIceMomentumEquation(grid;
44+
top_momentum_stress = (u=τᵤ, v=τᵥ),
45+
bottom_momentum_stress = τₒ,
46+
rheology = ElastoViscoPlasticRheology(),
47+
solver = SplitExplicitSolver(grid, substeps=50))
48+
49+
model = SeaIceModel(grid; ice_thermodynamics = nothing, dynamics, advection = WENO(order=7))
50+
51+
for N in 1:100
52+
time_step!(model, 1minutes)
53+
end
54+
55+
return model
56+
end
57+

0 commit comments

Comments
 (0)