changeset 1370:4ef8fb75d144 feature/variable_derivatives

Start splitting out a second_derivative_variable function
author Jonatan Werpers <jonatan@werpers.com>
date Fri, 26 May 2023 21:39:08 +0200
parents ff64acfc1ec9
children d0e48c2e6aad
files src/SbpOperators/SbpOperators.jl src/SbpOperators/volumeops/derivatives/second_derivative_variable.jl test/SbpOperators/volumeops/derivatives/second_derivative_variable_test.jl
diffstat 3 files changed, 164 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/src/SbpOperators/SbpOperators.jl	Fri May 26 14:59:37 2023 +0200
+++ b/src/SbpOperators/SbpOperators.jl	Fri May 26 21:39:08 2023 +0200
@@ -20,6 +20,7 @@
 export normal_derivative
 export first_derivative
 export second_derivative
+export second_derivative_variable
 export undivided_skewed04
 
 using Sbplib.RegionIndices
--- a/src/SbpOperators/volumeops/derivatives/second_derivative_variable.jl	Fri May 26 14:59:37 2023 +0200
+++ b/src/SbpOperators/volumeops/derivatives/second_derivative_variable.jl	Fri May 26 21:39:08 2023 +0200
@@ -1,3 +1,51 @@
+"""
+    second_derivative_variable(g, coeff ..., [direction])
+
+The variable second derivative operator as a `LazyTensor` on the given grid.
+`coeff` is a grid function of the variable coefficient.
+
+Approximates the d/dξ c d/dξ on `g` along the coordinate dimension specified
+by `direction`.
+"""
+function second_derivative_variable end
+
+
+function second_derivative_variable(g::TensorGrid, coeff::AbstractArray, inner_stencil::NestedStencil, closure_stencils, dir)
+    check_coefficient(g, coeff)
+
+    Δxᵢ = spacing(g.grids[dir])
+    scaled_inner_stencil = scale(inner_stencil, 1/Δxᵢ^2)
+    scaled_closure_stencils = scale.(Tuple(closure_stencils), 1/Δxᵢ^2)
+    return SecondDerivativeVariable{dir, ndims(g)}(scaled_inner_stencil, scaled_closure_stencils, coeff)
+end
+
+function second_derivative_variable(g::EquidistantGrid, coeff::AbstractVector, inner_stencil::NestedStencil, closure_stencils)
+    return second_derivative_variable(TensorGrid(g), coeff, inner_stencil, closure_stencils, 1)
+end
+
+function second_derivative_variable(g::TensorGrid, coeff::AbstractArray, stencil_set, dir::Int)
+    inner_stencil    = parse_nested_stencil(eltype(coeff), stencil_set["D2variable"]["inner_stencil"])
+    closure_stencils = parse_nested_stencil.(eltype(coeff), stencil_set["D2variable"]["closure_stencils"])
+
+    return second_derivative_variable(g, coeff, inner_stencil, closure_stencils, dir)
+end
+
+function second_derivative_variable(g::EquidistantGrid, coeff::AbstractArray, stencil_set)
+    return second_derivative_variable(TensorGrid(g), coeff, stencil_set, 1)
+end
+
+
+function check_coefficient(g, coeff)
+    if ndims(g) != ndims(coeff)
+        throw(ArgumentError("The coefficient has dimension $(ndims(coeff)) while the grid is dimension $(ndims(g))"))
+    end
+
+    if size(g) != size(coeff)
+        throw(DimensionMismatch("the size $(size(coeff)) of the coefficient does not match the size $(size(g)) of the grid"))
+    end
+end
+
+
 # REVIEW: Fixa docs
 """
     SecondDerivativeVariable{Dir,T,D,...} <: LazyTensor{T,D,D}
@@ -17,60 +65,6 @@
     end
 end
 
-function SecondDerivativeVariable(g::TensorGrid, coeff::AbstractArray, inner_stencil::NestedStencil, closure_stencils, dir)
-    check_coefficient(g, coeff)
-
-    Δxᵢ = spacing(g.grids[dir])
-    scaled_inner_stencil = scale(inner_stencil, 1/Δxᵢ^2)
-    scaled_closure_stencils = scale.(Tuple(closure_stencils), 1/Δxᵢ^2)
-    return SecondDerivativeVariable{dir, ndims(g)}(scaled_inner_stencil, scaled_closure_stencils, coeff)
-end
-
-function SecondDerivativeVariable(g::EquidistantGrid, coeff::AbstractVector, inner_stencil::NestedStencil, closure_stencils)
-    return SecondDerivativeVariable(TensorGrid(g), coeff, inner_stencil, closure_stencils, 1)
-end
-
-@doc raw"""
-    SecondDerivativeVariable(g::EquidistantGrid, coeff::AbstractArray, stencil_set, dir)
-
-Create a `LazyTensor` for the second derivative with a variable coefficient
-`coeff` on `grid` from the stencils in `stencil_set`. The direction is
-determined by `dir`.
-
-`coeff` is a grid function on `grid`.
-
-# Example
-With
-```
-D = SecondDerivativeVariable(g, c, stencil_set, 2)
-```
-then `D*u` approximates
-```math
-\frac{\partial}{\partial y} c(x,y) \frac{\partial u}{\partial y},
-```
-on ``(0,1)⨯(0,1)`` represented by `g`.
-"""
-function SecondDerivativeVariable(g::TensorGrid, coeff::AbstractArray, stencil_set, dir::Int)
-    inner_stencil    = parse_nested_stencil(eltype(coeff), stencil_set["D2variable"]["inner_stencil"])
-    closure_stencils = parse_nested_stencil.(eltype(coeff), stencil_set["D2variable"]["closure_stencils"])
-
-    return SecondDerivativeVariable(g, coeff, inner_stencil, closure_stencils, dir)
-end
-
-function SecondDerivativeVariable(g::EquidistantGrid, coeff::AbstractArray, stencil_set) 
-    return SecondDerivativeVariable(TensorGrid(g), coeff, stencil_set, 1)
-end
-
-function check_coefficient(g, coeff)
-    if ndims(g) != ndims(coeff)
-        throw(ArgumentError("The coefficient has dimension $(ndims(coeff)) while the grid is dimension $(ndims(g))"))
-    end
-
-    if size(g) != size(coeff)
-        throw(DimensionMismatch("the size $(size(coeff)) of the coefficient does not match the size $(size(g)) of the grid"))
-    end
-end
-
 derivative_direction(::SecondDerivativeVariable{Dir}) where {Dir} = Dir
 
 closure_size(op::SecondDerivativeVariable) = length(op.closure_stencils)
--- a/test/SbpOperators/volumeops/derivatives/second_derivative_variable_test.jl	Fri May 26 14:59:37 2023 +0200
+++ b/test/SbpOperators/volumeops/derivatives/second_derivative_variable_test.jl	Fri May 26 21:39:08 2023 +0200
@@ -8,6 +8,121 @@
 
 using LinearAlgebra
 
+@testset "second_derivative_variable" begin
+    interior_stencil = CenteredNestedStencil((1/2, 1/2, 0.),(-1/2, -1., -1/2),( 0., 1/2, 1/2))
+    closure_stencils = [
+        NestedStencil(( 2.,  -1., 0.),(-3., 1.,  0.), (1., 0., 0.), center = 1),
+    ]
+
+    @testset "1D" begin
+        g = equidistant_grid(11, 0., 1.)
+        c = [  1.,  3.,  6., 10., 15., 21., 28., 36., 45., 55., 66.]
+
+
+        @testset "application" begin
+
+            function apply_to_functions(; v, c)
+                g = equidistant_grid(11, 0., 10.) # h = 1
+                c̄ = eval_on(g,c)
+                v̄ = eval_on(g,v)
+
+                D₂ᶜ = second_derivative_variable(g, c̄, interior_stencil, closure_stencils)
+                return D₂ᶜ*v̄
+            end
+
+            @test apply_to_functions(v=x->1.,  c=x-> -1.) == zeros(11)
+            @test apply_to_functions(v=x->1.,  c=x-> -x ) == zeros(11)
+            @test apply_to_functions(v=x->x,   c=x->  1.) == zeros(11)
+            @test apply_to_functions(v=x->x,   c=x-> -x ) == -ones(11)
+            @test apply_to_functions(v=x->x^2, c=x->  1.) == 2ones(11)
+        end
+    end
+
+    @testset "2D" begin
+        g = equidistant_grid((11,9), (0.,0.), (10.,8.)) # h = 1
+        c = eval_on(g, (x,y)->x+y)
+
+        @testset "application" begin
+            function apply_to_functions(dir; v, c)
+                g = equidistant_grid((11,9), (0.,0.), (10.,8.)) # h = 1
+                c̄ = eval_on(g,c)
+                v̄ = eval_on(g,v)
+
+                D₂ᶜ = second_derivative_variable(g, c̄, interior_stencil, closure_stencils,dir)
+                return D₂ᶜ*v̄
+            end
+
+            # x-direction
+            @test apply_to_functions(1,v=(x,y)->1.,  c=(x,y)-> -1.) == zeros(11,9)
+            @test apply_to_functions(1,v=(x,y)->1.,  c=(x,y)->- x ) == zeros(11,9)
+            @test apply_to_functions(1,v=(x,y)->x,   c=(x,y)->  1.) == zeros(11,9)
+            @test apply_to_functions(1,v=(x,y)->x,   c=(x,y)-> -x ) == -ones(11,9)
+            @test apply_to_functions(1,v=(x,y)->x^2, c=(x,y)->  1.) == 2ones(11,9)
+
+            @test apply_to_functions(1,v=(x,y)->1.,  c=(x,y)->- y ) == zeros(11,9)
+            @test apply_to_functions(1,v=(x,y)->y,   c=(x,y)->  1.) == zeros(11,9)
+            @test apply_to_functions(1,v=(x,y)->y,   c=(x,y)-> -y ) == zeros(11,9)
+            @test apply_to_functions(1,v=(x,y)->y^2, c=(x,y)->  1.) == zeros(11,9)
+
+            # y-direction
+            @test apply_to_functions(2,v=(x,y)->1.,  c=(x,y)-> -1.) == zeros(11,9)
+            @test apply_to_functions(2,v=(x,y)->1.,  c=(x,y)->- y ) == zeros(11,9)
+            @test apply_to_functions(2,v=(x,y)->y,   c=(x,y)->  1.) == zeros(11,9)
+            @test apply_to_functions(2,v=(x,y)->y,   c=(x,y)-> -y ) == -ones(11,9)
+            @test apply_to_functions(2,v=(x,y)->y^2, c=(x,y)->  1.) == 2ones(11,9)
+
+            @test apply_to_functions(2,v=(x,y)->1.,  c=(x,y)->- x ) == zeros(11,9)
+            @test apply_to_functions(2,v=(x,y)->x,   c=(x,y)->  1.) == zeros(11,9)
+            @test apply_to_functions(2,v=(x,y)->x,   c=(x,y)-> -x ) == zeros(11,9)
+            @test apply_to_functions(2,v=(x,y)->x^2, c=(x,y)->  1.) == zeros(11,9)
+
+
+            @testset "standard diagonal operators" begin
+                c(x,y) = exp(x) + exp(1.5(1-y))
+                v(x,y) = sin(x) + cos(1.5(1-y))
+
+                Dxv(x,y) = cos(x)*exp(x) - (exp(x) + exp(1.5 - 1.5y))*sin(x)
+                Dyv(x,y) = -1.5(1.5exp(x) + 1.5exp(1.5 - 1.5y))*cos(1.5 - 1.5y) - 2.25exp(1.5 - 1.5y)*sin(1.5 - 1.5y)
+
+                g₁ = equidistant_grid((60,67), (0.,0.), (1.,2.))
+                g₂ = refine(g₁,2)
+
+                c̄₁ = eval_on(g₁, c)
+                c̄₂ = eval_on(g₂, c)
+
+                v̄₁ = eval_on(g₁, v)
+                v̄₂ = eval_on(g₂, v)
+
+
+                function convergence_rate_estimate(stencil_set, dir, Dv_true)
+                    D₁ = second_derivative_variable(g₁, c̄₁, stencil_set, dir)
+                    D₂ = second_derivative_variable(g₂, c̄₂, stencil_set, dir)
+
+                    Dv̄₁ = D₁*v̄₁
+                    Dv̄₂ = D₂*v̄₂
+
+                    Dv₁ = eval_on(g₁,Dv_true)
+                    Dv₂ = eval_on(g₂,Dv_true)
+
+                    e₁ = norm(Dv̄₁ - Dv₁)/norm(Dv₁)
+                    e₂ = norm(Dv̄₂ - Dv₂)/norm(Dv₂)
+
+                    return log2(e₁/e₂)
+                end
+
+                stencil_set = read_stencil_set(sbp_operators_path()*"standard_diagonal.toml"; order = 2)
+                @test convergence_rate_estimate(stencil_set, 1, Dxv) ≈ 1.5 rtol = 1e-1
+                @test convergence_rate_estimate(stencil_set, 2, Dyv) ≈ 1.5 rtol = 1e-1
+
+                stencil_set = read_stencil_set(sbp_operators_path()*"standard_diagonal.toml"; order = 4)
+                @test convergence_rate_estimate(stencil_set, 1, Dxv) ≈ 2.5 rtol = 1e-1
+                @test convergence_rate_estimate(stencil_set, 2, Dyv) ≈ 2.5 rtol = 2e-1
+            end
+        end
+    end
+end
+
+
 @testset "SecondDerivativeVariable" begin
     interior_stencil = CenteredNestedStencil((1/2, 1/2, 0.),(-1/2, -1., -1/2),( 0., 1/2, 1/2))
     closure_stencils = [
@@ -139,49 +254,6 @@
             @test apply_to_functions(2,v=(x,y)->x,   c=(x,y)->  1.) == zeros(11,9)
             @test apply_to_functions(2,v=(x,y)->x,   c=(x,y)-> -x ) == zeros(11,9)
             @test apply_to_functions(2,v=(x,y)->x^2, c=(x,y)->  1.) == zeros(11,9)
-
-
-            @testset "standard diagonal operators" begin
-                c(x,y) = exp(x) + exp(1.5(1-y))
-                v(x,y) = sin(x) + cos(1.5(1-y))
-
-                Dxv(x,y) = cos(x)*exp(x) - (exp(x) + exp(1.5 - 1.5y))*sin(x)
-                Dyv(x,y) = -1.5(1.5exp(x) + 1.5exp(1.5 - 1.5y))*cos(1.5 - 1.5y) - 2.25exp(1.5 - 1.5y)*sin(1.5 - 1.5y)
-
-                g₁ = equidistant_grid((60,67), (0.,0.), (1.,2.))
-                g₂ = refine(g₁,2)
-
-                c̄₁ = eval_on(g₁, c)
-                c̄₂ = eval_on(g₂, c)
-
-                v̄₁ = eval_on(g₁, v)
-                v̄₂ = eval_on(g₂, v)
-
-
-                function convergence_rate_estimate(stencil_set, dir, Dv_true)
-                    D₁ = SecondDerivativeVariable(g₁, c̄₁, stencil_set, dir)
-                    D₂ = SecondDerivativeVariable(g₂, c̄₂, stencil_set, dir)
-
-                    Dv̄₁ = D₁*v̄₁
-                    Dv̄₂ = D₂*v̄₂
-
-                    Dv₁ = eval_on(g₁,Dv_true)
-                    Dv₂ = eval_on(g₂,Dv_true)
-
-                    e₁ = norm(Dv̄₁ - Dv₁)/norm(Dv₁)
-                    e₂ = norm(Dv̄₂ - Dv₂)/norm(Dv₂)
-
-                    return log2(e₁/e₂)
-                end
-
-                stencil_set = read_stencil_set(sbp_operators_path()*"standard_diagonal.toml"; order = 2)
-                @test convergence_rate_estimate(stencil_set, 1, Dxv) ≈ 1.5 rtol = 1e-1
-                @test convergence_rate_estimate(stencil_set, 2, Dyv) ≈ 1.5 rtol = 1e-1
-
-                stencil_set = read_stencil_set(sbp_operators_path()*"standard_diagonal.toml"; order = 4)
-                @test convergence_rate_estimate(stencil_set, 1, Dxv) ≈ 2.5 rtol = 1e-1
-                @test convergence_rate_estimate(stencil_set, 2, Dyv) ≈ 2.5 rtol = 2e-1
-            end
         end
     end
 end