Skip to content

Commit e78f8a4

Browse files
committed
Add space with multiple columns
1 parent 337f0d1 commit e78f8a4

23 files changed

Lines changed: 754 additions & 14 deletions

File tree

docs/src/APIs/common_grids_api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ CommonGrids.ColumnGrid
1212
CommonGrids.Box3DGrid
1313
CommonGrids.SliceXZGrid
1414
CommonGrids.RectangleXYGrid
15+
CommonGrids.PointColumnEnsembleGrid
1516
```

docs/src/APIs/common_spaces_api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ CommonSpaces.ColumnSpace
1212
CommonSpaces.Box3DSpace
1313
CommonSpaces.SliceXZSpace
1414
CommonSpaces.RectangleXYSpace
15+
CommonSpaces.PointColumnEnsembleSpace
1516
```

ext/cuda/adapt.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ Adapt.adapt_structure(
1313
Adapt.adapt(to, grid.face_local_geometry),
1414
)
1515

16+
# PointCloudGrid has no quadrature_style field; pass nothing so that FD
17+
# operators on PointColumnEnsembleSpace work on CUDA.
18+
Adapt.adapt_structure(
19+
to::CUDA.KernelAdaptor,
20+
grid::Grids.ExtrudedFiniteDifferenceGrid{<:Grids.PointCloudGrid},
21+
) = Grids.DeviceExtrudedFiniteDifferenceGrid(
22+
Adapt.adapt(to, Grids.vertical_topology(grid)),
23+
nothing,
24+
Adapt.adapt(to, grid.global_geometry),
25+
Adapt.adapt(to, grid.center_local_geometry),
26+
Adapt.adapt(to, grid.face_local_geometry),
27+
)
28+
1629
Adapt.adapt_structure(
1730
to::CUDA.KernelAdaptor,
1831
grid::Grids.FiniteDifferenceGrid,
@@ -39,6 +52,12 @@ Adapt.adapt_structure(to::CUDA.KernelAdaptor, space::Spaces.PointSpace) =
3952
Adapt.adapt(to, Spaces.local_geometry_data(space)),
4053
)
4154

55+
Adapt.adapt_structure(to::CUDA.KernelAdaptor, space::Spaces.PointCloudLevelSpace) =
56+
Spaces.PointCloudLevelSpace(
57+
ClimaCore.DeviceSideContext(),
58+
Adapt.adapt(to, Spaces.local_geometry_data(space)),
59+
)
60+
4261
Adapt.adapt_structure(
4362
to::CUDA.KernelAdaptor,
4463
topology::Topologies.IntervalTopology,

src/CommonGrids/CommonGrids.jl

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,12 @@ grid = ExtrudedCubedSphereGrid(;
6767
module CommonGrids
6868

6969
export ExtrudedCubedSphereGrid,
70-
CubedSphereGrid, ColumnGrid, Box3DGrid, SliceXZGrid, RectangleXYGrid
70+
CubedSphereGrid,
71+
ColumnGrid,
72+
Box3DGrid,
73+
SliceXZGrid,
74+
RectangleXYGrid,
75+
PointColumnEnsembleGrid
7176

7277
import ClimaComms
7378
import ..DataLayouts,
@@ -706,4 +711,77 @@ function RectangleXYGrid(
706711
)
707712
end
708713

714+
"""
715+
PointColumnEnsembleGrid(
716+
::Type{<:AbstractFloat}; # defaults to Float64
717+
points::AbstractVector{Geometry.LatLongPoint{FT}},
718+
z_elem::Integer,
719+
z_min::Real,
720+
z_max::Real,
721+
radius::Real,
722+
device::ClimaComms.AbstractDevice = ClimaComms.device(),
723+
context::ClimaComms.AbstractCommsContext = ClimaComms.SingletonCommsContext(device),
724+
stretch::Meshes.StretchingRule = Meshes.Uniform(),
725+
z_mesh::Meshes.IntervalMesh = DefaultZMesh(FT; z_min, z_max, z_elem, stretch),
726+
)
727+
728+
A convenience constructor that builds an
729+
[`Grids.ExtrudedFiniteDifferenceGrid`](@ref) for N independent columns at
730+
arbitrary (lat, lon) locations on a sphere, given:
731+
732+
- `FT` the floating-point type (defaults to `Float64`) [`Float32`, `Float64`],
733+
- `points` a vector of `Geometry.LatLongPoint` specifying each column
734+
location,
735+
- `z_elem` the number of z-points,
736+
- `z_min` the domain minimum along the z-direction,
737+
- `z_max` the domain maximum along the z-direction,
738+
- `radius` the radius of the sphere,
739+
- `device` the `ClimaComms.device`,
740+
- `context` the `ClimaComms.context` (must be a `SingletonCommsContext`),
741+
- `stretch` the mesh `Meshes.StretchingRule` (defaults to
742+
[`Meshes.Uniform`](@ref)),
743+
- `z_mesh` the vertical mesh, defaults to an `Meshes.IntervalMesh` along `z`
744+
with given `stretch`.
745+
746+
There is no horizontal connectivity between columns. Horizontal operators are
747+
not supported. Use [`ClimaCore.Fields.bycolumn`](@ref) to iterate over columns.
748+
749+
# Example usage
750+
751+
```julia
752+
using ClimaCore.CommonGrids, ClimaCore.Geometry
753+
points = [LatLongPoint(0.0, 0.0), LatLongPoint(10.0, 20.0), LatLongPoint(-5.0, 90.0)]
754+
grid = PointColumnEnsembleGrid(;
755+
points = points,
756+
z_elem = 10,
757+
z_min = 0,
758+
z_max = 10_000,
759+
radius = 6.371229e6,
760+
)
761+
```
762+
"""
763+
PointColumnEnsembleGrid(; kwargs...) = PointColumnEnsembleGrid(Float64; kwargs...)
764+
function PointColumnEnsembleGrid(
765+
::Type{FT};
766+
points::AbstractVector{Geometry.LatLongPoint{FT}},
767+
z_elem::Integer,
768+
z_min::Real,
769+
z_max::Real,
770+
radius::Real = 6.371229e6,
771+
device::ClimaComms.AbstractDevice = ClimaComms.device(),
772+
context::ClimaComms.AbstractCommsContext = ClimaComms.SingletonCommsContext(device),
773+
stretch::Meshes.StretchingRule = Meshes.Uniform(),
774+
z_mesh::Meshes.IntervalMesh = DefaultZMesh(FT; z_min, z_max, z_elem, stretch),
775+
) where {FT}
776+
@assert context isa ClimaComms.SingletonCommsContext "PointColumnEnsembleGrid only supports SingletonCommsContext."
777+
@assert ClimaComms.device(context) == device "The given device and context device do not match."
778+
h_grid = Grids.PointCloudGrid(points; radius, device, context)
779+
z_topology = Topologies.IntervalTopology(
780+
ClimaComms.SingletonCommsContext(device),
781+
z_mesh,
782+
)
783+
z_grid = Grids.FiniteDifferenceGrid(z_topology)
784+
return Grids.ExtrudedFiniteDifferenceGrid(h_grid, z_grid)
785+
end
786+
709787
end # module

src/CommonSpaces/CommonSpaces.jl

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export ExtrudedCubedSphereSpace,
1313
Box3DSpace,
1414
SliceXZSpace,
1515
RectangleXYSpace,
16+
PointColumnEnsembleSpace,
1617
CellCenter,
1718
CellFace,
1819
face_space,
@@ -32,7 +33,8 @@ import ..CommonGrids:
3233
ColumnGrid,
3334
Box3DGrid,
3435
SliceXZGrid,
35-
RectangleXYGrid
36+
RectangleXYGrid,
37+
PointColumnEnsembleGrid
3638
import ..Spaces: face_space, center_space
3739

3840

@@ -426,4 +428,58 @@ RectangleXYSpace(; kwargs...) = RectangleXYSpace(Float64; kwargs...)
426428
RectangleXYSpace(::Type{FT}; kwargs...) where {FT} =
427429
Spaces.SpectralElementSpace2D(RectangleXYGrid(FT; kwargs...))
428430

431+
"""
432+
PointColumnEnsembleSpace(
433+
::Type{<:AbstractFloat}; # defaults to Float64
434+
points::AbstractVector{Geometry.LatLongPoint{FT}},
435+
z_elem::Integer,
436+
z_min::Real,
437+
z_max::Real,
438+
device::ClimaComms.AbstractDevice = ClimaComms.device(),
439+
context::ClimaComms.AbstractCommsContext = ClimaComms.SingletonCommsContext(device),
440+
stretch::Meshes.StretchingRule = Meshes.Uniform(),
441+
z_mesh::Meshes.IntervalMesh = DefaultZMesh(FT; z_min, z_max, z_elem, stretch),
442+
staggering::Staggering,
443+
)
444+
445+
Construct a [`Spaces.ExtrudedFiniteDifferenceSpace`](@ref) (aliased as
446+
`Spaces.PointCloudSpace`) for N independent columns at arbitrary (lat, lon)
447+
locations on a sphere, given:
448+
449+
- `FT` the floating-point type (defaults to `Float64`) [`Float32`, `Float64`]
450+
- `points` a vector of `Geometry.LatLongPoint` specifying each column location
451+
- `z_elem` the number of z-points
452+
- `z_min` the domain minimum along the z-direction
453+
- `z_max` the domain maximum along the z-direction
454+
- `device` the `ClimaComms.device`
455+
- `context` the `ClimaComms.context` (must be a `SingletonCommsContext`)
456+
- `stretch` the mesh `Meshes.StretchingRule` (defaults to [`Meshes.Uniform`](@ref))
457+
- `z_mesh` the vertical mesh, defaults to an `Meshes.IntervalMesh` along `z` with given `stretch`
458+
- `staggering` vertical staggering, can be one of [[`Grids.CellFace`](@ref), [`Grids.CellCenter`](@ref)]
459+
460+
Note that these arguments are all the same as [`CommonGrids.PointColumnEnsembleGrid`](@ref),
461+
except for `staggering`.
462+
463+
# Example usage
464+
465+
```julia
466+
using ClimaCore.CommonSpaces, ClimaCore.Geometry
467+
points = [LatLongPoint(0.0, 0.0), LatLongPoint(10.0, 20.0), LatLongPoint(-5.0, 90.0)]
468+
space = PointColumnEnsembleSpace(;
469+
points = points,
470+
z_elem = 10,
471+
z_min = 0,
472+
z_max = 10_000,
473+
staggering = CellCenter()
474+
)
475+
```
476+
"""
477+
function PointColumnEnsembleSpace end
478+
PointColumnEnsembleSpace(; kwargs...) = PointColumnEnsembleSpace(Float64; kwargs...)
479+
PointColumnEnsembleSpace(::Type{FT}; staggering::Staggering, kwargs...) where {FT} =
480+
Spaces.MultiColumnFiniteDifferenceSpace(
481+
PointColumnEnsembleGrid(FT; kwargs...),
482+
staggering,
483+
)
484+
429485
end # module

src/Fields/Fields.jl

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,22 @@ const CenterExtrudedFiniteDifferenceField{V, S} = Field{
116116
S,
117117
} where {V <: AbstractData, S <: Spaces.CenterExtrudedFiniteDifferenceSpace}
118118

119+
const MultiColumnFiniteDifferenceField{V, S} = Field{
120+
V,
121+
S,
122+
} where {V <: AbstractData, S <: Spaces.MultiColumnFiniteDifferenceSpace}
123+
const FaceMultiColumnFiniteDifferenceField{V, S} = Field{
124+
V,
125+
S,
126+
} where {V <: AbstractData, S <: Spaces.FaceMultiColumnFiniteDifferenceSpace}
127+
const CenterMultiColumnFiniteDifferenceField{V, S} = Field{
128+
V,
129+
S,
130+
} where {
131+
V <: AbstractData,
132+
S <: Spaces.CenterMultiColumnFiniteDifferenceSpace,
133+
}
134+
119135
#
120136
const SpectralElementField1D{V, S} =
121137
Field{V, S} where {V <: AbstractData, S <: Spaces.SpectralElementSpace1D}
@@ -497,6 +513,7 @@ Base.@propagate_inbounds function level(
497513
field::Union{
498514
CenterFiniteDifferenceField,
499515
CenterExtrudedFiniteDifferenceField,
516+
CenterMultiColumnFiniteDifferenceField,
500517
},
501518
v::Int,
502519
)
@@ -505,7 +522,11 @@ Base.@propagate_inbounds function level(
505522
Field(data, hspace)
506523
end
507524
Base.@propagate_inbounds function level(
508-
field::Union{FaceFiniteDifferenceField, FaceExtrudedFiniteDifferenceField},
525+
field::Union{
526+
FaceFiniteDifferenceField,
527+
FaceExtrudedFiniteDifferenceField,
528+
FaceMultiColumnFiniteDifferenceField,
529+
},
509530
v::PlusHalf,
510531
)
511532
hspace = level(axes(field), v)

src/Fields/indices.jl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,51 @@ bycolumn(
103103
device::ClimaComms.AbstractCPUDevice,
104104
) = bycolumn(fn, Spaces.horizontal_space(space), device)
105105

106+
function bycolumn(
107+
fn,
108+
space::Spaces.PointCloudSpace,
109+
::ClimaComms.CPUSingleThreaded,
110+
)
111+
N = Spaces.ncolumns(space)
112+
@inbounds for h in 1:N
113+
fn(ColumnIndex((1,), h))
114+
end
115+
return nothing
116+
end
117+
function bycolumn(
118+
fn,
119+
space::Spaces.PointCloudSpace,
120+
::ClimaComms.CPUMultiThreaded,
121+
)
122+
N = Spaces.ncolumns(space)
123+
@inbounds Threads.@threads for h in 1:N
124+
fn(ColumnIndex((1,), h))
125+
end
126+
return nothing
127+
end
128+
129+
function bycolumn(
130+
fn,
131+
space::Spaces.MultiColumnFiniteDifferenceSpace,
132+
::ClimaComms.CPUSingleThreaded,
133+
)
134+
N = Spaces.ncolumns(space)
135+
@inbounds for h in 1:N
136+
fn(ColumnIndex((1,), h))
137+
end
138+
return nothing
139+
end
140+
function bycolumn(
141+
fn,
142+
space::Spaces.MultiColumnFiniteDifferenceSpace,
143+
::ClimaComms.CPUMultiThreaded,
144+
)
145+
N = Spaces.ncolumns(space)
146+
@inbounds Threads.@threads for h in 1:N
147+
fn(ColumnIndex((1,), h))
148+
end
149+
return nothing
150+
end
106151

107152

108153
"""

src/Grids/Grids.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Meshes.domain(grid::AbstractGrid) = Meshes.domain(topology(grid))
7171

7272
include("finitedifference.jl")
7373
include("spectralelement.jl")
74+
include("pointcloud.jl")
7475
include("extruded.jl")
7576
include("column.jl")
7677
include("level.jl")
@@ -106,6 +107,7 @@ has_horizontal(::ExtrudedFiniteDifferenceGrid) = true
106107
has_horizontal(::DeviceSpectralElementGrid2D) = true
107108
has_horizontal(::SpectralElementGrid2D) = true
108109
has_horizontal(::SpectralElementGrid1D) = true
110+
has_horizontal(::PointCloudGrid) = true
109111

110112
"""
111113
has_vertical(::AbstractGrid)

src/Grids/extruded.jl

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ local_geometry_type(
4545
) where {H, V, A, GG, CLG, FLG} = eltype(CLG) # calls eltype from DataLayouts
4646

4747
function ExtrudedFiniteDifferenceGrid(
48-
horizontal_grid::Union{SpectralElementGrid1D, SpectralElementGrid2D},
48+
horizontal_grid::Union{SpectralElementGrid1D, SpectralElementGrid2D, PointCloudGrid},
4949
vertical_grid::FiniteDifferenceGrid,
5050
hypsography::HypsographyAdaption = Flat();
5151
deep = false,
@@ -70,7 +70,7 @@ end
7070

7171
# memoized constructor
7272
function ExtrudedFiniteDifferenceGrid(
73-
horizontal_grid::Union{SpectralElementGrid1D, SpectralElementGrid2D},
73+
horizontal_grid::Union{SpectralElementGrid1D, SpectralElementGrid2D, PointCloudGrid},
7474
vertical_grid::FiniteDifferenceGrid,
7575
hypsography::HypsographyAdaption,
7676
global_geometry::Geometry.AbstractGlobalGeometry,
@@ -96,7 +96,7 @@ end
9696

9797
# Non-memoized constructor. Should not generally be called, but can be defined for other Hypsography types
9898
function _ExtrudedFiniteDifferenceGrid(
99-
horizontal_grid::Union{SpectralElementGrid1D, SpectralElementGrid2D},
99+
horizontal_grid::Union{SpectralElementGrid1D, SpectralElementGrid2D, PointCloudGrid},
100100
vertical_grid::FiniteDifferenceGrid,
101101
hypsography::Flat,
102102
global_geometry::Geometry.AbstractGlobalGeometry,
@@ -126,6 +126,13 @@ end
126126

127127
topology(grid::ExtrudedFiniteDifferenceGrid) = topology(grid.horizontal_grid)
128128

129+
# For PointCloudGrid there is no horizontal topology; route context/device
130+
# through the horizontal grid directly (which stores its own context).
131+
ClimaComms.context(grid::ExtrudedFiniteDifferenceGrid{<:PointCloudGrid}) =
132+
ClimaComms.context(grid.horizontal_grid)
133+
ClimaComms.device(grid::ExtrudedFiniteDifferenceGrid{<:PointCloudGrid}) =
134+
ClimaComms.device(grid.horizontal_grid)
135+
129136
vertical_topology(grid::ExtrudedFiniteDifferenceGrid) =
130137
topology(grid.vertical_grid)
131138

src/Grids/level.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ level(
1515

1616
topology(levelgrid::LevelGrid) = topology(levelgrid.full_grid)
1717

18+
ClimaComms.context(levelgrid::LevelGrid) = ClimaComms.context(levelgrid.full_grid)
19+
ClimaComms.device(levelgrid::LevelGrid) = ClimaComms.device(levelgrid.full_grid)
20+
1821
# The DSS weights for extruded spaces are currently the same as the weights for
1922
# horizontal spaces. If we ever need to use extruded weights, this method will
2023
# need to extract the weights at a particular level.

0 commit comments

Comments
 (0)