Skip to content

Commit 1205972

Browse files
committed
use consistent spaces in regridding
1 parent ad0b387 commit 1205972

File tree

4 files changed

+79
-27
lines changed

4 files changed

+79
-27
lines changed

docs/src/regridders.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ computational domains. `TempestRegridder` performs all the interpolation ahead
3434
of time and saves the regridded fields to HDF5 files that can be read during the
3535
simulation.
3636

37+
Currently, `TempestRegridder` does not support regridding on 3D domains.
38+
The `InterpolationsRegridder` described below can be used for these cases.
39+
3740
### Example
3841

3942
Assuming `target_space` is a `ClimaCore` 2D spherical field, the input data is

ext/DataHandlingExt.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ function DataHandling.DataHandler(
146146
regridder_args = ()
147147

148148
if regridder_type == :TempestRegridder
149+
# TempestRegridder does not currently have the capability to regrid 3D
150+
# fields, so we check that the input space is not 3D
151+
@assert !(
152+
target_space isa ClimaCore.Spaces.ExtrudedFiniteDifferenceSpace
153+
)
149154
if !(:regrid_dir in regridder_kwargs)
150155
# If we do not have a regrid_dir, create one and broadcast it to all the MPI
151156
# processes

ext/TempestRegridderExt.jl

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Currently, this work with ClimaCoreTempestRemap. `ClimaCoreTempestRemap` uses Te
2121
a command-line utility. Hence, This function has to process files, so, for this regridder,
2222
we cannot really split file processing and remapping.
2323
24-
TempestRegridder only works on CPU and on a single process.
24+
TempestRegridder only works on CPU and on a single process, and for a non-3D target space.
2525
2626
Implicit assumptions in the code:
2727
- input_file contains "lat" and "lon"
@@ -225,12 +225,18 @@ function read_from_hdf5(REGRID_DIR, hd_outfile_root, time, varname, space)
225225
field = ClimaCore.InputOutput.read_field(hdfreader, varname)
226226
Base.close(hdfreader)
227227

228-
# Ensure the field is on the correct space when reusing regridded files
229-
# between simulations
228+
# Ensure the field is on the correct space
229+
@assert ClimaCore.Spaces.topology(axes(field)) ==
230+
ClimaCore.Spaces.topology(space)
231+
@assert ClimaCore.Spaces.quadrature_style(axes(field)) ==
232+
ClimaCore.Spaces.quadrature_style(space)
233+
@assert ClimaCore.Spaces.global_geometry(axes(field)) ==
234+
ClimaCore.Spaces.global_geometry(space)
235+
236+
# Since the spaces aren't the same, we need to copy the field values onto the space
230237
return swap_space(field, space)
231238
end
232239

233-
234240
"""
235241
write_to_hdf5(REGRID_DIR, hd_outfile_root, time, field, varname,
236242
comms_ctx = ClimaComms.SingletonCommsContext())
@@ -283,6 +289,44 @@ function write_to_hdf5(
283289
Base.close(hdfwriter)
284290
end
285291

292+
"""
293+
construct_singleton_space(space)
294+
295+
Constructs a singleton space from a given space. This is not ideal, but
296+
necessary to use TempestRemap regridding, which is not MPI or GPU compatible.
297+
"""
298+
function construct_singleton_space(space)
299+
# If doesn't make sense to regrid with GPUs/MPI processes
300+
cpu_context =
301+
ClimaComms.SingletonCommsContext(ClimaComms.CPUSingleThreaded())
302+
303+
# Check if input space was constructed using `spacefillingcurve`
304+
use_spacefillingcurve =
305+
ClimaCore.Spaces.topology(space).elemorder isa CartesianIndices ?
306+
false : true
307+
308+
mesh = ClimaCore.Spaces.topology(space).mesh
309+
topology = nothing
310+
if use_spacefillingcurve
311+
topology = ClimaCore.Topologies.Topology2D(
312+
cpu_context,
313+
mesh,
314+
ClimaCore.Topologies.spacefillingcurve(mesh),
315+
)
316+
else
317+
topology = ClimaCore.Topologies.Topology2D(cpu_context, mesh)
318+
end
319+
Nq =
320+
ClimaCore.Spaces.Quadratures.polynomial_degree(
321+
ClimaCore.Spaces.quadrature_style(space),
322+
) + 1
323+
space_singleton = ClimaCore.Spaces.SpectralElementSpace2D(
324+
topology,
325+
ClimaCore.Spaces.Quadratures.GLL{Nq}(),
326+
)
327+
328+
return space_singleton
329+
end
286330

287331
"""
288332
function hdwrite_regridfile_rll_to_cgll(
@@ -334,23 +378,9 @@ function hdwrite_regridfile_rll_to_cgll(
334378
weightfile = joinpath(REGRID_DIR, outfile_root * "_remap_weights.nc")
335379

336380
# If doesn't make sense to regrid with GPUs/MPI processes
337-
cpu_context =
338-
ClimaComms.SingletonCommsContext(ClimaComms.CPUSingleThreaded())
339-
340-
# Note: this topology gives us `space == space_undistributed` in the undistributed
341-
# case (as desired), which wouldn't hold if we used `spacefillingcurve` here.
342-
topology = ClimaCore.Topologies.Topology2D(
343-
cpu_context,
344-
ClimaCore.Spaces.topology(space).mesh,
345-
)
346-
Nq =
347-
ClimaCore.Spaces.Quadratures.polynomial_degree(
348-
ClimaCore.Spaces.quadrature_style(space),
349-
) + 1
350-
space_undistributed = ClimaCore.Spaces.SpectralElementSpace2D(
351-
topology,
352-
ClimaCore.Spaces.Quadratures.GLL{Nq}(),
353-
)
381+
space_singleton = construct_singleton_space(space)
382+
topology_singleton = ClimaCore.Spaces.topology(space_singleton)
383+
cpu_context = ClimaCore.Spaces.topology(space_singleton).context
354384

355385
if isfile(datafile_cgll) == false
356386
isdir(REGRID_DIR) ? nothing : mkpath(REGRID_DIR)
@@ -362,7 +392,7 @@ function hdwrite_regridfile_rll_to_cgll(
362392
ClimaCoreTempestRemap.rll_mesh(meshfile_rll; nlat = nlat, nlon = nlon)
363393

364394
# write cgll mesh, overlap mesh and weight file
365-
ClimaCoreTempestRemap.write_exodus(meshfile_cgll, topology)
395+
ClimaCoreTempestRemap.write_exodus(meshfile_cgll, topology_singleton)
366396
ClimaCoreTempestRemap.overlap_mesh(
367397
meshfile_overlap,
368398
meshfile_rll,
@@ -372,6 +402,10 @@ function hdwrite_regridfile_rll_to_cgll(
372402
# 'in_np = 1' and 'mono = true' arguments ensure mapping is conservative and monotone
373403
# Note: for a kwarg not followed by a value, set it to true here (i.e. pass 'mono = true' to produce '--mono')
374404
# Note: out_np = degrees of freedom = polynomial degree + 1
405+
Nq =
406+
ClimaCore.Spaces.Quadratures.polynomial_degree(
407+
ClimaCore.Spaces.quadrature_style(space),
408+
) + 1
375409
kwargs = (; out_type = out_type, out_np = Nq)
376410
kwargs = mono ? (; (kwargs)..., in_np = 1, mono = mono) : kwargs
377411
ClimaCoreTempestRemap.remap_weights(
@@ -400,8 +434,8 @@ function hdwrite_regridfile_rll_to_cgll(
400434

401435
target_unique_idxs =
402436
out_type == "cgll" ?
403-
collect(ClimaCore.Spaces.unique_nodes(space_undistributed)) :
404-
collect(ClimaCore.Spaces.all_nodes(space_undistributed))
437+
collect(ClimaCore.Spaces.unique_nodes(space_singleton)) :
438+
collect(ClimaCore.Spaces.all_nodes(space_singleton))
405439
target_unique_idxs_i =
406440
map(row -> target_unique_idxs[row][1][1], row_indices)
407441
target_unique_idxs_j =
@@ -412,7 +446,7 @@ function hdwrite_regridfile_rll_to_cgll(
412446

413447
R = (; target_idxs = target_unique_idxs, row_indices = row_indices)
414448

415-
offline_field = ClimaCore.Fields.zeros(FT, space_undistributed)
449+
offline_field = ClimaCore.Fields.zeros(FT, space_singleton)
416450

417451
times = [DateTime(0)]
418452
# Save regridded HDF5 file for each variable in `varnames`
@@ -452,6 +486,7 @@ function hdwrite_regridfile_rll_to_cgll(
452486
length(times),
453487
)
454488

489+
# Save regridded HDF5 file for each time slice
455490
map(
456491
x -> write_to_hdf5(
457492
REGRID_DIR,

test/data_handling.jl

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,24 @@ ClimaComms.init(context)
2626
if regridder_type == :TempestRegridder && Sys.iswindows()
2727
continue
2828
end
29-
for FT in (Float32, Float64)
29+
for FT in (Float32, Float64), use_spacefillingcurve in (true, false)
3030
radius = FT(6731e3)
3131
helem = 40
3232
Nq = 4
3333

3434
horzdomain = ClimaCore.Domains.SphereDomain(radius)
3535
horzmesh =
3636
ClimaCore.Meshes.EquiangularCubedSphere(horzdomain, helem)
37-
horztopology = ClimaCore.Topologies.Topology2D(context, horzmesh)
37+
if use_spacefillingcurve
38+
horztopology = ClimaCore.Topologies.Topology2D(
39+
context,
40+
horzmesh,
41+
ClimaCore.Topologies.spacefillingcurve(horzmesh),
42+
)
43+
else
44+
horztopology =
45+
ClimaCore.Topologies.Topology2D(context, horzmesh)
46+
end
3847
quad = ClimaCore.Spaces.Quadratures.GLL{Nq}()
3948
target_space =
4049
ClimaCore.Spaces.SpectralElementSpace2D(horztopology, quad)

0 commit comments

Comments
 (0)