Skip to content

Commit

Permalink
Merge 5f72faa into b5dc705
Browse files Browse the repository at this point in the history
  • Loading branch information
simone-silvestri authored Sep 17, 2024
2 parents b5dc705 + 5f72faa commit 7227ef9
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 32 deletions.
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c"
MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195"
Oceananigans = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[compat]
Adapt = "4"
JLD2 = "0.4"
KernelAbstractions = "0.9"
MPI = "0.20"
Oceananigans = "0.91.3"
Oceananigans = "0.91.13"
OffsetArrays = "1"
julia = "1"

Expand Down
4 changes: 2 additions & 2 deletions src/OrthogonalSphericalShellGrids.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ using OffsetArrays

@inline convert_to_0_360(x) = ((x % 360) + 360) % 360

include("grid_utils.jl")
include("tripolar_grid_utils.jl")
include("zipper_boundary_condition.jl")
include("generate_tripolar_coordinates.jl")
include("tripolar_grid.jl")
include("grid_extensions.jl")
include("tripolar_grid_extensions.jl")
include("distributed_tripolar_grid.jl")
include("with_halo.jl")
include("split_explicit_free_surface.jl")
Expand Down
File renamed without changes.
24 changes: 9 additions & 15 deletions src/grid_utils.jl → src/tripolar_grid_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,15 @@ end
d = lat_lon_to_cartesian(φᶠᶠᵃ[ i , j+1], λᶠᶠᵃ[ i , j+1], 1)

Azᶜᶜᵃ[i, j] = spherical_area_quadrilateral(a, b, c, d) * radius^2

a = lat_lon_to_cartesian(φᶜᶠᵃ[i-1, j ], λᶜᶠᵃ[i-1, j ], 1)
b = lat_lon_to_cartesian(φᶜᶠᵃ[ i , j ], λᶜᶠᵃ[ i , j ], 1)
c = lat_lon_to_cartesian(φᶜᶠᵃ[ i , j+1], λᶜᶠᵃ[ i , j+1], 1)
d = lat_lon_to_cartesian(φᶜᶠᵃ[i-1, j+1], λᶜᶠᵃ[i-1, j+1], 1)

Azᶠᶜᵃ[i, j] = spherical_area_quadrilateral(a, b, c, d) * radius^2

a = lat_lon_to_cartesian(φᶠᶜᵃ[ i , j-1], λᶠᶜᵃ[ i , j-1], 1)
b = lat_lon_to_cartesian(φᶠᶜᵃ[i+1, j-1], λᶠᶜᵃ[i+1, j-1], 1)
c = lat_lon_to_cartesian(φᶠᶜᵃ[i+1, j ], λᶠᶜᵃ[i+1, j ], 1)
d = lat_lon_to_cartesian(φᶠᶜᵃ[ i , j ], λᶠᶜᵃ[ i , j ], 1)

Azᶜᶠᵃ[i, j] = spherical_area_quadrilateral(a, b, c, d) * radius^2


# To be able to conserve kinetic energy specifically the momentum equation,
# it is better to define the face areas as products of
# the edge lengths rather than using the spherical area of the face (cit JMC).
# TODO: find a reference to support this statement
Azᶠᶜᵃ[i, j] = Δyᶠᶜᵃ[i, j] * Δxᶠᶜᵃ[i, j]
Azᶜᶠᵃ[i, j] = Δyᶜᶠᵃ[i, j] * Δxᶜᶠᵃ[i, j]

# Face - Face areas are calculated as the Center - Center ones
a = lat_lon_to_cartesian(φᶜᶜᵃ[i-1, j-1], λᶜᶜᵃ[i-1, j-1], 1)
b = lat_lon_to_cartesian(φᶜᶜᵃ[ i , j-1], λᶜᶜᵃ[ i , j-1], 1)
c = lat_lon_to_cartesian(φᶜᶜᵃ[ i , j ], λᶜᶜᵃ[ i , j ], 1)
Expand Down
12 changes: 12 additions & 0 deletions test/dependencies_for_runtests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using OrthogonalSphericalShellGrids
using Oceananigans
using Oceananigans.Grids: halo_size
using Oceananigans.Utils
using Oceananigans.BoundaryConditions
using OrthogonalSphericalShellGrids: get_cartesian_nodes_and_vertices
using Oceananigans.CUDA
using Test

using KernelAbstractions: @kernel, @index

arch = CUDA.has_cuda_gpu() ? GPU() : CPU()
17 changes: 3 additions & 14 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
using OrthogonalSphericalShellGrids
using OrthogonalSphericalShellGrids.Oceananigans
using Oceananigans: GPU, CPU
using Oceananigans.CUDA
using Test
include("dependencies_for_runtests.jl")

arch = CUDA.has_cuda_gpu() ? GPU() : CPU()
include("test_tripolar_grid.jl")
include("test_zipper_boundary_conditions.jl")

@testset "OrthogonalSphericalShellGrids.jl" begin
# We probably do not need any unit tests.

# Test the grid?
grid = TripolarGrid(arch; size = (10, 10, 1))

# Test boundary conditions?
end
75 changes: 75 additions & 0 deletions test/test_tripolar_grid.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
include("dependencies_for_runtests.jl")

using Statistics: dot, norm
using Oceananigans.Utils: getregion
using Oceananigans.ImmersedBoundaries: immersed_cell

@kernel function compute_nonorthogonality_angle!(angle, grid, xF, yF, zF)
i, j = @index(Global, NTuple)

@inbounds begin
x⁻ = xF[i, j]
y⁻ = yF[i, j]
z⁻ = zF[i, j]

x⁺¹ = xF[i + 1, j]
y⁺¹ = yF[i + 1, j]
z⁺¹ = zF[i + 1, j]
x⁺² = xF[i, j + 1]
y⁺² = yF[i, j + 1]
z⁺² = zF[i, j + 1]

v1 = (x⁺¹ - x⁻, y⁺¹ - y⁻, z⁺¹ - z⁻)
v2 = (x⁺² - x⁻, y⁺² - y⁻, z⁺² - z⁻)

# Check orthogonality by computing the angle between the vectors
cosθ = dot(v1, v2) / (norm(v1) * norm(v2))
immersed = immersed_cell(i, j, 1, grid)
angle[i, j] = ifelse(immersed, π / 2, acos(cosθ)) - π / 2

# convert to degrees
angle[i, j] = rad2deg(angle[i, j])
end
end

@testset "Orthogonality of family of ellipses and hyperbolae..." begin

# Test the orthogonality of a tripolar grid based on the orthogonality of a
# cubed sphere of the same size (1ᵒ in latitude and longitude)
cubed_sphere_grid = ConformalCubedSphereGrid(panel_size = (90, 90, 1), z = (0, 1))
cubed_sphere_panel = getregion(cubed_sphere_grid, 1)

angle_cubed_sphere = zeros(size(cubed_sphere_panel)...)
cartesian_nodes, _ = get_cartesian_nodes_and_vertices(cubed_sphere_panel, Face(), Face(), Center())
xF, yF, zF = cartesian_nodes
Nx, Ny, _ = size(cubed_sphere_panel)

# Exclude the corners from the computation! (They are definitely not orthogonal)
params = KernelParameters(5:Nx-5, 5:Ny-5)

launch!(CPU(), cubed_sphere_panel, params, compute_nonorthogonality_angle!, angle_cubed_sphere, cubed_sphere_panel, xF, yF, zF)

first_pole_longitude = λ¹ₚ = 75
north_poles_latitude = φₚ = 35

λ²ₚ = λ¹ₚ + 180

# Build a tripolar grid at 1ᵒ
underlying_grid = TripolarGrid(; size = (360, 180, 1), first_pole_longitude, north_poles_latitude)

# We need a bottom height field that ``masks'' the singularities
bottom_height(λ, φ) = ((abs- λ¹ₚ) < 5) & (abs(φₚ - φ) < 5)) |
((abs- λ²ₚ) < 5) & (abs(φₚ - φ) < 5)) |< -78) ? 1 : 0

# Exclude the singularities from the computation! (They are definitely not orthogonal)
tripolar_grid = ImmersedBoundaryGrid(underlying_grid, GridFittedBottom(bottom_height))
angle_tripolar = zeros(size(tripolar_grid)...)
cartesian_nodes, _ = get_cartesian_nodes_and_vertices(tripolar_grid.underlying_grid, Face(), Face(), Center())
xF, yF, zF = cartesian_nodes
Nx, Ny, _ = size(tripolar_grid)

launch!(CPU(), tripolar_grid, (Nx-1, Ny-1), compute_nonorthogonality_angle!, angle_tripolar, tripolar_grid, xF, yF, zF)

@test maximum(angle_tripolar) < maximum(angle_cubed_sphere)
@test minimum(angle_tripolar) > minimum(angle_cubed_sphere)
end
43 changes: 43 additions & 0 deletions test/test_zipper_boundary_conditions.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
include("dependencies_for_runtests.jl")

using OrthogonalSphericalShellGrids: Zipper

@testset "Zipper boundary conditions..." begin
grid = TripolarGrid(size = (10, 10, 1))
Nx, Ny, _ = size(grid)
Hx, Hy, _ = halo_size(grid)

c = CenterField(grid)
u = XFaceField(grid)
v = YFaceField(grid)

@test c.boundary_conditions.north.classification isa Zipper
@test u.boundary_conditions.north.classification isa Zipper
@test v.boundary_conditions.north.classification isa Zipper

@test c.boundary_conditions.north.condition == 1
@test u.boundary_conditions.north.condition == -1
@test v.boundary_conditions.north.condition == -1

set!(c, 1)
set!(u, 1)
set!(v, 1)

fill_halo_regions!(c)
fill_halo_regions!(u)
fill_halo_regions!(v)

north_boundary_c = view(c.data, :, Ny+1:Ny+Hy, 1)
north_boundary_v = view(v.data, :, Ny+1:Ny+Hy, 1)
@test all(north_boundary_c .== 1)
@test all(north_boundary_v .== -1)

# U is special, because periodicity is hardcoded in the x-direction
north_interior_boundary_u = view(u.data, 2:Nx-1, Ny+1:Ny+Hy, 1)
@test all(north_interior_boundary_u .== -1)

north_boundary_u_left = view(u.data, 1, Ny+1:Ny+Hy, 1)
north_boundary_u_right = view(u.data, Nx+1, Ny+1:Ny+Hy, 1)
@test all(north_boundary_u_left .== 1)
@test all(north_boundary_u_right .== 1)
end

0 comments on commit 7227ef9

Please sign in to comment.