Skip to content

Commit bc09a95

Browse files
committed
make allocating remap call non-allocating remap
1 parent a388e58 commit bc09a95

File tree

1 file changed

+59
-25
lines changed

1 file changed

+59
-25
lines changed

src/Interfacer.jl

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -458,15 +458,14 @@ abstract type SlabplanetTerraMode <: AbstractSlabplanetSimulationMode end
458458
Remap the given `field` onto the `target_space`. If the field is already
459459
on the target space or a compatible one, it is returned unchanged.
460460
461-
Note that this method has a lot of allocations and is not efficient.
461+
This is a convenience wrapper around `remap!` that allocates the output field.
462462
463463
Non-ClimaCore fields should provide a method to this function.
464464
"""
465465
function remap end
466466

467-
function remap(field::CC.Fields.Field, target_space::CC.Spaces.AbstractSpace)
468-
source_space = axes(field)
469-
comms_ctx = ClimaComms.context(source_space)
467+
function remap(source_field::CC.Fields.Field, target_space::CC.Spaces.AbstractSpace)
468+
source_space = axes(source_field)
470469

471470
# Check if the source and target spaces are compatible
472471
spaces_are_compatible =
@@ -481,7 +480,53 @@ function remap(field::CC.Fields.Field, target_space::CC.Spaces.AbstractSpace)
481480
end
482481

483482
# If the spaces are the same or one is a subspace of the other, we can just return the input field
484-
spaces_are_compatible && return field
483+
spaces_are_compatible && return source_field
484+
485+
# Allocate target field and call remap!
486+
target_field = CC.Fields.zeros(target_space)
487+
remap!(target_field, source_field)
488+
return target_field
489+
end
490+
491+
function remap(source_field::Number, target_space::CC.Spaces.AbstractSpace)
492+
# Allocate target field and call remap!
493+
target_field = CC.Fields.zeros(target_space)
494+
remap!(target_field, source_field)
495+
return target_field
496+
end
497+
498+
"""
499+
remap!(target_field, source_field)
500+
501+
Remap the given `source_field` onto the `target_field`. This is the core non-allocating
502+
implementation.
503+
504+
Non-ClimaCore fields should provide a method to this function.
505+
"""
506+
function remap! end
507+
508+
function remap!(target_field::CC.Fields.Field, source_field::CC.Fields.Field)
509+
source_space = axes(source_field)
510+
target_space = axes(target_field)
511+
comms_ctx = ClimaComms.context(source_space)
512+
513+
# Check if the source and target spaces are compatible
514+
spaces_are_compatible =
515+
source_space == target_space ||
516+
CC.Spaces.issubspace(source_space, target_space) ||
517+
CC.Spaces.issubspace(target_space, source_space)
518+
519+
# TODO: Handle remapping of Vectors correctly
520+
if hasproperty(source_field, :components)
521+
@assert length(source_field.components) == 1 "Can only work with simple vectors"
522+
source_field = source_field.components.data.:1
523+
end
524+
525+
# If the spaces are the same or one is a subspace of the other, we can just copy
526+
if spaces_are_compatible
527+
target_field .= source_field
528+
return nothing
529+
end
485530

486531
# Get vector of LatLongPoints for the target space to get the hcoords
487532
# Copy target coordinates to CPU if they are on GPU
@@ -493,10 +538,10 @@ function remap(field::CC.Fields.Field, target_space::CC.Spaces.AbstractSpace)
493538
# Remap the field, using MPI if applicable
494539
if comms_ctx isa ClimaComms.SingletonCommsContext
495540
# Remap source field to target space as an array
496-
remapped_array = CC.Remapping.interpolate(field, hcoords, [])
541+
remapped_array = CC.Remapping.interpolate(source_field, hcoords, [])
497542

498-
# Convert remapped array to a field in the target space
499-
return CC.Fields.array2field(remapped_array, target_space)
543+
# Copy remapped array into target field
544+
target_field .= CC.Fields.array2field(remapped_array, target_space)
500545
else
501546
# Gather then broadcast the global hcoords and offsets
502547
offset = [length(hcoords)]
@@ -506,33 +551,22 @@ function remap(field::CC.Fields.Field, target_space::CC.Spaces.AbstractSpace)
506551
# Interpolate on root and broadcast to all processes
507552
remapper = CC.Remapping.Remapper(source_space; target_hcoords = all_hcoords)
508553
remapped_array =
509-
ClimaComms.bcast(comms_ctx, CC.Remapping.interpolate(remapper, field))
554+
ClimaComms.bcast(comms_ctx, CC.Remapping.interpolate(remapper, source_field))
510555

511556
my_ending_offset = sum(all_offsets[1:ClimaComms.mypid(comms_ctx)])
512557
my_starting_offset = my_ending_offset - offset[]
513558

514-
# Convert remapped array to a field in the target space on each process
515-
return CC.Fields.array2field(
559+
# Copy remapped array into target field on each process
560+
target_field .= CC.Fields.array2field(
516561
remapped_array[(1 + my_starting_offset):my_ending_offset],
517562
target_space,
518563
)
519564
end
565+
return nothing
520566
end
521567

522-
function remap(num::Number, target_space::CC.Spaces.AbstractSpace)
523-
return num
524-
end
525-
526-
"""
527-
remap!(target_field, source)
528-
529-
Remap the given `source` onto the `target_field`.
530-
531-
Non-ClimaCore fields should provide a method to [`Interfacer.remap`](@ref), or directly to this
532-
function.
533-
"""
534-
function remap!(target_field, source)
535-
target_field .= remap(source, axes(target_field))
568+
function remap!(target_field::CC.Fields.Field, source::Number)
569+
fill!(target_field, source)
536570
return nothing
537571
end
538572

0 commit comments

Comments
 (0)