@@ -67,7 +67,12 @@ grid = ExtrudedCubedSphereGrid(;
6767module CommonGrids
6868
6969export ExtrudedCubedSphereGrid,
70- CubedSphereGrid, ColumnGrid, Box3DGrid, SliceXZGrid, RectangleXYGrid
70+ CubedSphereGrid,
71+ ColumnGrid,
72+ Box3DGrid,
73+ SliceXZGrid,
74+ RectangleXYGrid,
75+ PointColumnEnsembleGrid
7176
7277import ClimaComms
7378import .. DataLayouts,
@@ -706,4 +711,77 @@ function RectangleXYGrid(
706711 )
707712end
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+
709787end # module
0 commit comments