Mercurial > repos > public > sbplib_julia
changeset 1496:ae2dbfb984a9 feature/grids/curvilinear
Merge feature/grids/componentview
author | Jonatan Werpers <jonatan@werpers.com> |
---|---|
date | Fri, 01 Dec 2023 15:01:44 +0100 |
parents | 64b58740e029 (diff) 62f9d0387a2a (current diff) |
children | 553111a15506 |
files | src/Grids/Grids.jl |
diffstat | 4 files changed, 200 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/Grids/Grids.jl Fri Dec 01 14:58:05 2023 +0100 +++ b/src/Grids/Grids.jl Fri Dec 01 15:01:44 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 @@ -32,11 +33,17 @@ export equidistant_grid +# 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 Fri Dec 01 15:01:44 2023 +0100 @@ -0,0 +1,46 @@ +# 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) + +# Iteration interface + +Base.iterate(g::CurvilinearGrid) = iterate(g.physicalcoordinates) +Base.iterate(g::CurvilinearGrid, state) = iterate(g.physicalcoordinates, state) + +Base.IteratorSize(::Type{<:CurvilinearGrid{<:Any, D}}) where D = Base.HasShape{D}() +Base.length(g::CurvilinearGrid) = length(g.logicalgrid) +Base.size(g::CurvilinearGrid) = size(g.logicalgrid) +Base.size(g::CurvilinearGrid, d) = size(g.logicalgrid, d) + +boundary_identifiers(g::CurvilinearGrid) = boundary_identifiers(g.logicalgrid) +boundary_indices(g::CurvilinearGrid, id::TensorGridBoundary) = boundary_indices(g.logicalgrid, id) + +function boundary_grid(g::CurvilinearGrid, id::TensorGridBoundary) + b_indices = boundary_indices(g.logicalgrid, id) + return CurvilinearGrid( + boundary_grid(g.logicalgrid, id), + g.physicalcoordinates[b_indices...], + g.jacobian[b_indices...], + ) +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 Fri Dec 01 14:58:05 2023 +0100 +++ b/src/Grids/tensor_grid.jl Fri Dec 01 15:01:44 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 Fri Dec 01 15:01:44 2023 +0100 @@ -0,0 +1,145 @@ +using Sbplib.Grids +using Sbplib.RegionIndices +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 + sg = CurvilinearGrid( + equidistant_grid((15,11), (0,0), (1,1)), + map(ξ̄ -> @SArray[ξ̄[1], ξ̄[2], -ξ̄[1]], lg), rand(SMatrix{2,3,Float64},15,11) + ) + + @test eltype(cg) == SVector{2,Float64} + @test eltype(sg) == SVector{3,Float64} + + @test eltype(typeof(cg)) == SVector{2,Float64} + @test eltype(typeof(sg)) == SVector{3,Float64} + + @test size(cg) == (11,11) + @test size(sg) == (15,11) + + @test size(cg,2) == 11 + @test size(sg,2) == 11 + + @test length(cg) == 121 + @test length(sg) == 165 + + @test Base.IteratorSize(cg) == Base.HasShape{2}() + @test Base.IteratorSize(typeof(cg)) == Base.HasShape{2}() + + @test Base.IteratorSize(sg) == Base.HasShape{2}() + @test Base.IteratorSize(typeof(sg)) == Base.HasShape{2}() + + element, state = iterate(cg) + @test element == lg[1,1].*2 + element, _ = iterate(cg, state) + @test element == lg[2,1].*2 + + element, state = iterate(sg) + @test element == sg.physicalcoordinates[1,1] + element, _ = iterate(sg, state) + @test element == sg.physicalcoordinates[2,1] + + @test collect(cg) == 2 .* lg + end + + @testset "Base" begin + @test ndims(cg) == 2 + end + + @testset "boundary_identifiers" begin + @test boundary_identifiers(cg) == boundary_identifiers(lg) + end + + @testset "boundary_indices" begin + @test boundary_indices(cg, CartesianBoundary{1,Lower}()) == boundary_indices(lg,CartesianBoundary{1,Lower}()) + @test boundary_indices(cg, CartesianBoundary{2,Lower}()) == boundary_indices(lg,CartesianBoundary{2,Lower}()) + @test boundary_indices(cg, CartesianBoundary{1,Upper}()) == boundary_indices(lg,CartesianBoundary{1,Upper}()) + end + + @testset "boundary_grid" begin + @test boundary_grid(cg, TensorGridBoundary{1, Lower}()) == 2. * boundary_grid(lg,TensorGridBoundary{1, Lower}()) + @test_broken boundary_grid(cg, TensorGridBoundary{1, Upper}()) == 2. * boundary_grid(lg,TensorGridBoundary{1, Upper}()) + @test_broken boundary_grid(cg, TensorGridBoundary{2, Lower}()) == 2. * boundary_grid(lg,TensorGridBoundary{2, Lower}()) + @test_broken boundary_grid(cg, TensorGridBoundary{2, Upper}()) == 2. * boundary_grid(lg,TensorGridBoundary{2, Upper}()) + end + + # TBD: Should curvilinear grid support refining and coarsening? + # This would require keeping the coordinate mapping around which seems burdensome, and might increase compilation time? + @testset "refine" begin + @test_broken refine(cg, 1) == cg + @test_broken refine(cg, 2) == CurvilinearGrid(refine(lg,2), x̄, J) + @test_broken refine(cg, 3) == CurvilinearGrid(refine(lg,3), x̄, J) + end + + @testset "coarsen" 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) + + @test_broken coarsen(cg, 1) == cg + @test_broken coarsen(cg, 2) == CurvilinearGrid(coarsen(lg,2), x̄, J) + + @test_broken false # @test_throws DomainError(3, "Size minus 1 must be divisible by the ratio.") coarsen(cg, 3) + end +end