changeset 1480:4550beef9694 feature/boundary_conditions

Merge with default
author Vidar Stiernström <vidar.stiernstrom@it.uu.se>
date Sat, 23 Dec 2023 23:03:13 +0100
parents b96858a50e35 (current diff) 869a40cda18c (diff)
children ee242c3fe4af
files Notes.md
diffstat 9 files changed, 114 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/Notes.md	Sat Dec 23 23:01:28 2023 +0100
+++ b/Notes.md	Sat Dec 23 23:03:13 2023 +0100
@@ -331,3 +331,15 @@
 Could the implementation of LazyOuterProduct be simplified by making it a
 struct containing two or more LazyTensors? (using split_tuple in a similar way
 as TensorGrid)
+
+## Implementation of boundary_indices for more complex grids
+To represent boundaries of for example tet-elements we can use a type `IndexCollection` to index a grid function directly.
+
+```julia
+I = IndexCollection(...)
+v[I]
+```
+
+* This would impact how tensor grid works.
+* To make things homogenous maybe these index collections should be used for the more simple grids too.
+* The function `to_indices` from Base could be useful to implement for `IndexCollection`
--- a/src/Grids/Grids.jl	Sat Dec 23 23:01:28 2023 +0100
+++ b/src/Grids/Grids.jl	Sat Dec 23 23:03:13 2023 +0100
@@ -8,33 +8,29 @@
 export Grid
 export coordinate_size
 export component_type
+export grid_id
+export boundary_id
+export boundary_indices
+export boundary_identifiers
+export boundary_grid
+export eval_on
+export coarsen
+export getcomponent
+export refine
+
+export BoundaryIdentifier
+export TensorGridBoundary
+export CartesianBoundary
 
 export TensorGrid
 export ZeroDimGrid
 
-export TensorGridBoundary
-
-export grid_id
-export boundary_id
-
-export eval_on
-export getcomponent
-
-# BoundaryIdentifier
-export BoundaryIdentifier
+export EquidistantGrid
+export inverse_spacing
+export spacing
+export equidistant_grid
 
 
-# EquidistantGrid
-export EquidistantGrid
-export spacing
-export inverse_spacing
-export boundary_identifiers
-export boundary_grid
-export refine
-export coarsen
-export equidistant_grid
-export CartesianBoundary
-
 abstract type BoundaryIdentifier end
 
 include("grid.jl")
--- a/src/Grids/equidistant_grid.jl	Sat Dec 23 23:01:28 2023 +0100
+++ b/src/Grids/equidistant_grid.jl	Sat Dec 23 23:03:13 2023 +0100
@@ -29,6 +29,7 @@
 Base.IteratorSize(::Type{<:EquidistantGrid}) = Base.HasShape{1}()
 Base.length(g::EquidistantGrid) = length(g.points)
 Base.size(g::EquidistantGrid) = size(g.points)
+Base.size(g::EquidistantGrid, d) = size(g.points)[d]
 
 
 """
@@ -50,7 +51,8 @@
 boundary_identifiers(::EquidistantGrid) = (Lower(), Upper())
 boundary_grid(g::EquidistantGrid, id::Lower) = ZeroDimGrid(g[begin])
 boundary_grid(g::EquidistantGrid, id::Upper) = ZeroDimGrid(g[end])
-
+boundary_indices(g::EquidistantGrid, id::Lower) = (1,)
+boundary_indices(g::EquidistantGrid, id::Upper) = (length(g),)
 
 """
     refine(g::EquidistantGrid, r::Int)
--- a/src/Grids/grid.jl	Sat Dec 23 23:01:28 2023 +0100
+++ b/src/Grids/grid.jl	Sat Dec 23 23:03:13 2023 +0100
@@ -74,6 +74,18 @@
 # TBD: Can we implement a version here that accepts multiple ids and grouped boundaries? Maybe we need multiblock stuff?
 
 """
+    boundary_indices(g::Grid, id::BoundaryIdentifier)
+
+A collection of indices corresponding to the boundary with given id. For grids
+with Cartesian indexing these collections will be tuples with elements of type
+``Union{Int,Colon}``.
+
+When implementing this method it is expected that the returned collection can
+be used to index grid functions to obtain grid functions on the boundary grid.
+"""
+function boundary_indices end
+
+"""
     eval_on(g::Grid, f)
 
 Lazy evaluation of `f` on the grid. `f` can either be on the form `f(x,y,...)`
@@ -100,3 +112,5 @@
 
 _ncomponents(::Type{<:Number}) = 1
 _ncomponents(T::Type{<:SVector}) = length(T)
+
+
--- a/src/Grids/tensor_grid.jl	Sat Dec 23 23:01:28 2023 +0100
+++ b/src/Grids/tensor_grid.jl	Sat Dec 23 23:03:13 2023 +0100
@@ -43,9 +43,9 @@
 _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.length(g::TensorGrid) = prod(length, g.grids)
 Base.size(g::TensorGrid) = LazyTensors.concatenate_tuples(size.(g.grids)...)
+Base.size(g::TensorGrid, d) = size(g)[d]
 
 
 refine(g::TensorGrid, r::Int) = mapreduce(g->refine(g,r), TensorGrid, g.grids)
@@ -73,7 +73,6 @@
     return LazyTensors.concatenate_tuples(per_grid...)
 end
 
-
 """
     boundary_grid(g::TensorGrid, id::TensorGridBoundary)
 
@@ -85,6 +84,16 @@
     return TensorGrid(new_grids...)
 end
 
+function boundary_indices(g::TensorGrid, id::TensorGridBoundary)
+    per_grid_ind = map(g.grids) do g
+        ntuple(i->:, ndims(g))
+    end
+
+    local_b_ind = boundary_indices(g.grids[grid_id(id)], boundary_id(id))
+    b_ind = Base.setindex(per_grid_ind, local_b_ind, grid_id(id))
+
+    return LazyTensors.concatenate_tuples(b_ind...)
+end
 
 function combined_coordinate_vector_type(coordinate_types...)
     combined_coord_length = mapreduce(_ncomponents, +, coordinate_types)
--- a/src/Grids/zero_dim_grid.jl	Sat Dec 23 23:01:28 2023 +0100
+++ b/src/Grids/zero_dim_grid.jl	Sat Dec 23 23:03:13 2023 +0100
@@ -25,3 +25,4 @@
 
 boundary_identifiers(g::ZeroDimGrid) = ()
 boundary_grid(g::ZeroDimGrid, ::Any) = throw(ArgumentError("ZeroDimGrid has no boundaries"))
+boundary_indices(g::ZeroDimGrid, ::Any) = throw(ArgumentError("ZeroDimGrid has no boundaries"))
--- a/test/Grids/equidistant_grid_test.jl	Sat Dec 23 23:01:28 2023 +0100
+++ b/test/Grids/equidistant_grid_test.jl	Sat Dec 23 23:03:13 2023 +0100
@@ -31,6 +31,8 @@
         @test size(EquidistantGrid(0:10)) == (11,)
         @test size(EquidistantGrid(0:0.1:10)) == (101,)
 
+        @test size(EquidistantGrid(0:0.1:10),1) == 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}()
@@ -66,6 +68,17 @@
         @test boundary_grid(g, Upper()) == ZeroDimGrid(1.0)
     end
 
+    @testset "boundary_indices" begin
+        g = EquidistantGrid(0:0.1:1)
+        @test boundary_indices(g, Lower()) == (1,)
+        @test boundary_indices(g, Upper()) == (11,)
+
+        g = EquidistantGrid(2:0.1:10)
+        @test boundary_indices(g, Lower()) == (1,)
+        @test boundary_indices(g, Upper()) == (81,)
+
+    end
+
     @testset "refine" begin
         g = EquidistantGrid(0:0.1:1)
         @test refine(g, 1) == g
@@ -107,8 +120,13 @@
     @testset "Base" begin
         @test eltype(equidistant_grid(4,0.0,1.0)) == Float64
         @test eltype(equidistant_grid((4,3),(0,0),(1,3))) <: AbstractVector{Float64}
+
         @test size(equidistant_grid(4,0.0,1.0)) == (4,)
         @test size(equidistant_grid((5,3), (0.0,0.0), (2.0,1.0))) == (5,3)
+
+        @test size(equidistant_grid((5,3), (0.0,0.0), (2.0,1.0)),1) == 5
+        @test size(equidistant_grid((5,3), (0.0,0.0), (2.0,1.0)),2) == 3
+
         @test ndims(equidistant_grid(4,0.0,1.0)) == 1
         @test ndims(equidistant_grid((5,3), (0.0,0.0), (2.0,1.0))) == 2
     end
--- a/test/Grids/tensor_grid_test.jl	Sat Dec 23 23:01:28 2023 +0100
+++ b/test/Grids/tensor_grid_test.jl	Sat Dec 23 23:03:13 2023 +0100
@@ -85,12 +85,30 @@
         @test eltype(TensorGrid(g₁, g₄)) == SVector{3,Float64}
         @test eltype(TensorGrid(g₁, g₄, g₂)) == SVector{4,Float64}
 
+        @test eltype(typeof(TensorGrid(g₁, g₂))) == SVector{2,Float64}
+        @test eltype(typeof(TensorGrid(g₁, g₃))) == SVector{2,Float64}
+        @test eltype(typeof(TensorGrid(g₁, g₂, g₃))) == SVector{3,Float64}
+        @test eltype(typeof(TensorGrid(g₁, g₄))) == SVector{3,Float64}
+        @test eltype(typeof(TensorGrid(g₁, g₄, g₂))) == SVector{4,Float64}
+
         @test size(TensorGrid(g₁, g₂)) == (11,6)
         @test size(TensorGrid(g₁, g₃)) == (11,10)
         @test size(TensorGrid(g₁, g₂, g₃)) == (11,6,10)
         @test size(TensorGrid(g₁, g₄)) == (11,)
         @test size(TensorGrid(g₁, g₄, g₂)) == (11,6)
 
+        @test size(TensorGrid(g₁, g₂, g₃),1) == 11
+        @test size(TensorGrid(g₁, g₂, g₃),2) == 6
+        @test size(TensorGrid(g₁, g₂, g₃),3) == 10
+        @test size(TensorGrid(g₁, g₄, g₂),1) == 11
+        @test size(TensorGrid(g₁, g₄, g₂),2) == 6
+
+        @test length(TensorGrid(g₁, g₂)) == 66
+        @test length(TensorGrid(g₁, g₃)) == 110
+        @test length(TensorGrid(g₁, g₂, g₃)) == 660
+        @test length(TensorGrid(g₁, g₄)) == 11
+        @test length(TensorGrid(g₁, g₄, g₂)) == 66
+
         @test Base.IteratorSize(TensorGrid(g₁, g₂)) == Base.HasShape{2}()
         @test Base.IteratorSize(TensorGrid(g₁, g₃)) == Base.HasShape{2}()
         @test Base.IteratorSize(TensorGrid(g₁, g₂, g₃)) == Base.HasShape{3}()
@@ -151,6 +169,21 @@
         @test boundary_grid(TensorGrid(g₁, g₂), TensorGridBoundary{1, Upper}()) == TensorGrid(ZeroDimGrid(g₁[end]), g₂)
         @test boundary_grid(TensorGrid(g₁, g₄), TensorGridBoundary{1, Upper}()) == TensorGrid(ZeroDimGrid(g₁[end]), g₄)
     end
+
+    @testset "boundary_indices" begin
+        g₁ = EquidistantGrid(range(0,1,length=11))
+        g₂ = EquidistantGrid(range(2,3,length=6))
+        g₄ = ZeroDimGrid(@SVector[1,2])
+
+        @test boundary_indices(TensorGrid(g₁, g₂), TensorGridBoundary{1, Lower}()) == (1,:)
+        @test boundary_indices(TensorGrid(g₁, g₂), TensorGridBoundary{1, Upper}()) == (11,:)
+        @test boundary_indices(TensorGrid(g₁, g₂), TensorGridBoundary{2, Lower}()) == (:,1)
+        @test boundary_indices(TensorGrid(g₁, g₂), TensorGridBoundary{2, Upper}()) == (:,6)
+        @test boundary_indices(TensorGrid(g₁, g₄), TensorGridBoundary{1, Lower}()) == (1,)
+        @test boundary_indices(TensorGrid(g₁, g₄), TensorGridBoundary{1, Upper}()) == (11,)
+        @test boundary_indices(TensorGrid(g₄,g₁), TensorGridBoundary{2, Lower}()) == (1,)
+        @test boundary_indices(TensorGrid(g₄,g₁), TensorGridBoundary{2, Upper}()) == (11,)
+    end
 end
 
 @testset "combined_coordinate_vector_type" begin
--- a/test/Grids/zero_dim_grid_test.jl	Sat Dec 23 23:01:28 2023 +0100
+++ b/test/Grids/zero_dim_grid_test.jl	Sat Dec 23 23:03:13 2023 +0100
@@ -41,4 +41,8 @@
     @testset "boundary_grid" begin
         @test_throws ArgumentError("ZeroDimGrid has no boundaries") boundary_grid(ZeroDimGrid(@SVector[1.0,2.0]), :bid)
     end
+
+    @testset "boundary_indices" begin
+        @test_throws ArgumentError("ZeroDimGrid has no boundaries") boundary_indices(ZeroDimGrid(@SVector[1.0,2.0]), :bid)
+    end
 end