changeset 1448:0322c181a1cd feature/grids/curvilinear

Merge default
author Jonatan Werpers <jonatan@werpers.com>
date Wed, 22 Nov 2023 17:53:31 +0100
parents 433245fd33c0 (diff) f217c6167952 (current diff)
children a0b1449dba4e
files src/Grids/tensor_grid.jl test/Grids/tensor_grid_test.jl
diffstat 4 files changed, 217 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/Grids/Grids.jl	Wed Nov 22 17:52:03 2023 +0100
+++ b/src/Grids/Grids.jl	Wed Nov 22 17:53:31 2023 +0100
@@ -1,3 +1,4 @@
+# TODO: Double check that the interfaces for indexing and iterating are fully implemented and tested for all grids.
 module Grids
 
 using Sbplib.RegionIndices
@@ -35,11 +36,18 @@
 export equidistant_grid
 export CartesianBoundary
 
+
+# CurvilinearGrid
+export CurvilinearGrid
+export jacobian
+export logicalgrid
+
 abstract type BoundaryIdentifier end
 
 include("grid.jl")
 include("tensor_grid.jl")
 include("equidistant_grid.jl")
 include("zero_dim_grid.jl")
+include("curvilinear_grid.jl")
 
 end # module
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Grids/curvilinear_grid.jl	Wed Nov 22 17:53:31 2023 +0100
@@ -0,0 +1,92 @@
+# TBD: Rename to MappedGrid?
+struct CurvilinearGrid{T,D, GT<:Grid{<:Any,D}, CT<:AbstractArray{T,D}, JT<:AbstractArray{<:AbstractArray{<:Any, 2}, D}} <: Grid{T,D}
+    logicalgrid::GT
+    physicalcoordinates::CT
+    jacobian::JT
+end
+
+jacobian(g::CurvilinearGrid) = g.jacobian
+logicalgrid(g::CurvilinearGrid) = g.logicalgrid
+
+
+# Indexing interface
+Base.getindex(g::CurvilinearGrid, I::Vararg{Int}) = g.physicalcoordinates[I...]
+Base.eachindex(g::CurvilinearGrid) = eachindex(g.logicalgrid)
+
+Base.firstindex(g::CurvilinearGrid, d) = firstindex(g.logicalgrid, d)
+Base.lastindex(g::CurvilinearGrid, d) = lastindex(g.logicalgrid, d)
+
+# function Base.getindex(g::TensorGrid, I...)
+#     szs = ndims.(g.grids)
+
+#     Is = LazyTensors.split_tuple(I, szs)
+#     ps = map((g,I)->SVector(g[I...]), g.grids, Is)
+
+#     return vcat(ps...)
+# end
+
+# function Base.eachindex(g::TensorGrid)
+#     szs = LazyTensors.concatenate_tuples(size.(g.grids)...)
+#     return CartesianIndices(szs)
+# end
+
+# # Iteration interface
+# Base.iterate(g::TensorGrid) = iterate(Iterators.product(g.grids...)) |> _iterate_combine_coords
+# Base.iterate(g::TensorGrid, state) = iterate(Iterators.product(g.grids...), state) |> _iterate_combine_coords
+# _iterate_combine_coords(::Nothing) = nothing
+# _iterate_combine_coords((next,state)) = combine_coordinates(next...), state
+
+# Base.IteratorSize(::Type{<:TensorGrid{<:Any, D}}) where D = Base.HasShape{D}()
+# Base.eltype(::Type{<:TensorGrid{T}}) where T = T
+# Base.length(g::TensorGrid) = sum(length, g.grids)
+# Base.size(g::TensorGrid) = LazyTensors.concatenate_tuples(size.(g.grids)...)
+
+
+# refine(g::TensorGrid, r::Int) = mapreduce(g->refine(g,r), TensorGrid, g.grids)
+# coarsen(g::TensorGrid, r::Int) = mapreduce(g->coarsen(g,r), TensorGrid, g.grids)
+
+# """
+#     TensorGridBoundary{N, BID} <: BoundaryIdentifier
+
+# A boundary identifier for a tensor grid. `N` Specifies which grid in the
+# tensor product and `BID` which boundary on that grid.
+# """
+# struct TensorGridBoundary{N, BID} <: BoundaryIdentifier end
+# grid_id(::TensorGridBoundary{N, BID}) where {N, BID} = N
+# boundary_id(::TensorGridBoundary{N, BID}) where {N, BID} = BID()
+
+# """
+#     boundary_identifiers(g::TensorGrid)
+
+# Returns a tuple containing the boundary identifiers of `g`.
+# """
+# function boundary_identifiers(g::TensorGrid)
+#     per_grid = map(eachindex(g.grids)) do i
+#         return map(bid -> TensorGridBoundary{i, typeof(bid)}(), boundary_identifiers(g.grids[i]))
+#     end
+#     return LazyTensors.concatenate_tuples(per_grid...)
+# end
+
+
+# """
+#     boundary_grid(g::TensorGrid, id::TensorGridBoundary)
+
+# The grid for the boundary of `g` specified by `id`.
+# """
+# function boundary_grid(g::TensorGrid, id::TensorGridBoundary)
+#     local_boundary_grid = boundary_grid(g.grids[grid_id(id)], boundary_id(id))
+#     new_grids = Base.setindex(g.grids, local_boundary_grid, grid_id(id))
+#     return TensorGrid(new_grids...)
+# end
+
+
+
+
+
+
+
+
+# Do we add a convenience function `curvilinear_grid`? It could help with
+# creating the logical grid, evaluating functions and possibly calculating the
+# entries in the jacobian.
+
--- a/src/Grids/tensor_grid.jl	Wed Nov 22 17:52:03 2023 +0100
+++ b/src/Grids/tensor_grid.jl	Wed Nov 22 17:53:31 2023 +0100
@@ -1,3 +1,5 @@
+# TODO: Check this file and other grids for duplicate implementation of general methods implemented for Grid
+
 """
     TensorGrid{T,D} <: Grid{T,D}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/Grids/curvilinear_grid_test.jl	Wed Nov 22 17:53:31 2023 +0100
@@ -0,0 +1,115 @@
+using Sbplib.Grids
+using Test
+using StaticArrays
+
+@testset "CurvilinearGrid" begin
+    lg = equidistant_grid((11,11), (0,0), (1,1)) # TODO: Change dims of the grid to be different
+    x̄ = map(ξ̄ -> 2ξ̄, lg)
+    J = map(ξ̄ -> @SArray(fill(2., 2, 2)), lg)
+    cg = CurvilinearGrid(lg, x̄, J)
+
+    # TODO: Test constructor for different dims of range and domain for the coordinates
+    # TODO: Test constructor with different type than TensorGrid. a dummy type?
+
+    @test_broken false # @test_throws ArgumentError("Sizes must match") CurvilinearGrid(lg, map(ξ̄ -> @SArray[ξ̄[1], ξ̄[2], -ξ̄[1]], lg), rand(SMatrix{2,3,Float64},15,11))
+
+
+    @test cg isa Grid{SVector{2, Float64},2}
+
+    @test jacobian(cg) isa Array{<:AbstractMatrix}
+    @test logicalgrid(cg) isa Grid
+
+    @testset "Indexing Interface" begin
+        cg = CurvilinearGrid(lg, x̄, J)
+        @test cg[1,1] == [0.0, 0.0]
+        @test cg[4,2] == [0.6, 0.2]
+        @test cg[6,10] == [1., 1.8]
+
+        @test cg[begin, begin] == [0.0, 0.0]
+        @test cg[end,end] == [2.0, 2.0]
+        @test cg[begin,end] == [0., 2.]
+
+        @test eachindex(cg) == CartesianIndices((11,11))
+
+        @testset "cartesian indexing" begin
+            cases = [
+                 (1,1) ,
+                 (3,5) ,
+                 (10,6),
+                 (1,1) ,
+                 (3,2) ,
+            ]
+
+            @testset "i = $is" for (lg, is) ∈ cases
+                @test cg[CartesianIndex(is...)] == cg[is...]
+            end
+        end
+
+        @testset "eachindex" begin
+            @test eachindex(cg) == CartesianIndices((11,11))
+        end
+
+        @testset "firstindex" begin
+            @test firstindex(cg, 1) == 1
+            @test firstindex(cg, 2) == 1
+        end
+
+        @testset "lastindex" begin
+            @test lastindex(cg, 1) == 11
+            @test lastindex(cg, 2) == 11
+        end
+    end
+    # TODO: Test with different types of logical grids
+
+    @testset "Iterator interface" begin
+        # @test eltype(EquidistantGrid(0:10)) == Int
+        # @test eltype(EquidistantGrid(0:2:10)) == Int
+        # @test eltype(EquidistantGrid(0:0.1:10)) == Float64
+
+        # @test size(EquidistantGrid(0:10)) == (11,)
+        # @test size(EquidistantGrid(0:0.1:10)) == (101,)
+
+        # @test collect(EquidistantGrid(0:0.1:0.5)) == [0.0, 0.1, 0.2, 0.3, 0.4, 0.5]
+
+        # @test Base.IteratorSize(EquidistantGrid{Float64, StepRange{Float64}}) == Base.HasShape{1}()
+    end
+
+    @testset "Base" begin
+        # @test ndims(EquidistantGrid(0:10)) == 1
+    end
+
+    @testset "boundary_identifiers" begin
+        # g = EquidistantGrid(0:0.1:10)
+        # @test boundary_identifiers(g) == (Lower(), Upper())
+        # @inferred boundary_identifiers(g)
+    end
+
+    @testset "boundary_grid" begin
+        # g = EquidistantGrid(0:0.1:1)
+        # @test boundary_grid(g, Lower()) == ZeroDimGrid(0.0)
+        # @test boundary_grid(g, Upper()) == ZeroDimGrid(1.0)
+    end
+
+    @testset "refine" begin
+        # g = EquidistantGrid(0:0.1:1)
+        # @test refine(g, 1) == g
+        # @test refine(g, 2) == EquidistantGrid(0:0.05:1)
+        # @test refine(g, 3) == EquidistantGrid(0:(0.1/3):1)
+    end
+
+    @testset "coarsen" begin
+        # g = EquidistantGrid(0:1:10)
+        # @test coarsen(g, 1) == g
+        # @test coarsen(g, 2) == EquidistantGrid(0:2:10)
+
+        # g = EquidistantGrid(0:0.1:1)
+        # @test coarsen(g, 1) == g
+        # @test coarsen(g, 2) == EquidistantGrid(0:0.2:1)
+
+        # g = EquidistantGrid(0:10)
+        # @test coarsen(g, 1) == EquidistantGrid(0:1:10)
+        # @test coarsen(g, 2) == EquidistantGrid(0:2:10)
+
+        # @test_throws DomainError(3, "Size minus 1 must be divisible by the ratio.") coarsen(g, 3)
+    end
+end