comparison src/SbpOperators/volumeops/derivatives/second_derivative_variable.jl @ 1395:bdcdbd4ea9cd feature/boundary_conditions

Merge with default. Comment out broken tests for boundary_conditions at sat
author Vidar Stiernström <vidar.stiernstrom@it.uu.se>
date Wed, 26 Jul 2023 21:35:50 +0200
parents e9dfc1998d31
children 3684db043add
comparison
equal deleted inserted replaced
1217:ea2e8254820a 1395:bdcdbd4ea9cd
1 """
2 second_derivative_variable(g, coeff ..., [direction])
3
4 The variable second derivative operator as a `LazyTensor` on the given grid.
5 `coeff` is a grid function of the variable coefficient.
6
7 Approximates the d/dξ c d/dξ on `g` along the coordinate dimension specified
8 by `direction`.
9 """
10 function second_derivative_variable end
11
12 function second_derivative_variable(g::TensorGrid, coeff, stencil_set, dir::Int)
13 inner_stencil = parse_nested_stencil(eltype(coeff), stencil_set["D2variable"]["inner_stencil"])
14 closure_stencils = parse_nested_stencil.(eltype(coeff), stencil_set["D2variable"]["closure_stencils"])
15
16 return second_derivative_variable(g, coeff, inner_stencil, closure_stencils, dir)
17 end
18
19 function second_derivative_variable(g::EquidistantGrid, coeff, stencil_set)
20 return second_derivative_variable(TensorGrid(g), coeff, stencil_set, 1)
21 end
22
23 function second_derivative_variable(g::TensorGrid, coeff, inner_stencil::NestedStencil, closure_stencils, dir)
24 check_coefficient(g, coeff)
25
26 Δxᵢ = spacing(g.grids[dir])
27 scaled_inner_stencil = scale(inner_stencil, 1/Δxᵢ^2)
28 scaled_closure_stencils = scale.(Tuple(closure_stencils), 1/Δxᵢ^2)
29 return SecondDerivativeVariable(coeff, scaled_inner_stencil, scaled_closure_stencils, dir)
30 end
31
32 function check_coefficient(g, coeff)
33 if ndims(g) != ndims(coeff)
34 throw(ArgumentError("The coefficient has dimension $(ndims(coeff)) while the grid is dimension $(ndims(g))"))
35 end
36
37 if size(g) != size(coeff)
38 throw(DimensionMismatch("the size $(size(coeff)) of the coefficient does not match the size $(size(g)) of the grid"))
39 end
40 end
41
42
43 """
44 SecondDerivativeVariable{Dir,T,D,...} <: LazyTensor{T,D,D}
45
46 A second derivative operator in direction `Dir` with a variable coefficient.
47 """
48 struct SecondDerivativeVariable{Dir,T,D,M,IStencil<:NestedStencil{T},CStencil<:NestedStencil{T},TArray<:AbstractArray} <: LazyTensor{T,D,D}
49 inner_stencil::IStencil
50 closure_stencils::NTuple{M,CStencil}
51 coefficient::TArray
52
53 function SecondDerivativeVariable(coefficient::AbstractArray, inner_stencil::NestedStencil{T}, closure_stencils::NTuple{M,NestedStencil{T}}, dir) where {T,M}
54 D = ndims(coefficient)
55 IStencil = typeof(inner_stencil)
56 CStencil = eltype(closure_stencils)
57 TArray = typeof(coefficient)
58 return new{dir,T,D,M,IStencil,CStencil,TArray}(inner_stencil, closure_stencils, coefficient)
59 end
60 end
61
62 derivative_direction(::SecondDerivativeVariable{Dir}) where {Dir} = Dir
63
64 closure_size(op::SecondDerivativeVariable) = length(op.closure_stencils)
65
66 LazyTensors.range_size(op::SecondDerivativeVariable) = size(op.coefficient)
67 LazyTensors.domain_size(op::SecondDerivativeVariable) = size(op.coefficient)
68
69
70 function derivative_view(op, a, I)
71 d = derivative_direction(op)
72
73 Iview = Base.setindex(I,:,d)
74 return @view a[Iview...]
75 end
76
77 function apply_lower(op::SecondDerivativeVariable, v, I...)
78 ṽ = derivative_view(op, v, I)
79 c̃ = derivative_view(op, op.coefficient, I)
80
81 i = I[derivative_direction(op)]
82 return @inbounds apply_stencil(op.closure_stencils[i], c̃, ṽ, i)
83 end
84
85 function apply_interior(op::SecondDerivativeVariable, v, I...)
86 ṽ = derivative_view(op, v, I)
87 c̃ = derivative_view(op, op.coefficient, I)
88
89 i = I[derivative_direction(op)]
90 return apply_stencil(op.inner_stencil, c̃, ṽ, i)
91 end
92
93 function apply_upper(op::SecondDerivativeVariable, v, I...)
94 ṽ = derivative_view(op, v, I)
95 c̃ = derivative_view(op, op.coefficient, I)
96
97 i = I[derivative_direction(op)]
98 sz = domain_size(op)[derivative_direction(op)]
99 stencil = op.closure_stencils[sz-i+1]
100 return @inbounds apply_stencil_backwards(stencil, c̃, ṽ, i)
101 end
102
103 function LazyTensors.apply(op::SecondDerivativeVariable, v::AbstractArray, I::Vararg{Index})
104 if I[derivative_direction(op)] isa Index{Lower}
105 return apply_lower(op, v, Int.(I)...)
106 elseif I[derivative_direction(op)] isa Index{Upper}
107 return apply_upper(op, v, Int.(I)...)
108 elseif I[derivative_direction(op)] isa Index{Interior}
109 return apply_interior(op, v, Int.(I)...)
110 else
111 error("Invalid region")
112 end
113 end
114
115 function LazyTensors.apply(op::SecondDerivativeVariable, v::AbstractArray, I...)
116 dir = derivative_direction(op)
117 sz = domain_size(op)[dir]
118
119 i = I[dir]
120
121 I = map(i->Index(i, Interior), I)
122 if 0 < i <= closure_size(op)
123 I = Base.setindex(I, Index(i, Lower), dir)
124 return LazyTensors.apply(op, v, I...)
125 elseif closure_size(op) < i <= sz-closure_size(op)
126 I = Base.setindex(I, Index(i, Interior), dir)
127 return LazyTensors.apply(op, v, I...)
128 elseif sz-closure_size(op) < i <= sz
129 I = Base.setindex(I, Index(i, Upper), dir)
130 return LazyTensors.apply(op, v, I...)
131 else
132 error("Bounds error") # This should be `throw(BoundsError())` but the type inference is so fragile that it doesn't work. Needs investigation. / Jonatan 2023-06-08
133 end
134 end
135
136
137 # 2D Specific implementations to avoid type instability
138 # TBD: Can this be solved by fixing the general methods instead?
139
140
141 ## x-direction
142 function apply_lower(op::SecondDerivativeVariable{1}, v, i, j)
143 ṽ = @view v[:,j]
144 c̃ = @view op.coefficient[:,j]
145
146 return @inbounds apply_stencil(op.closure_stencils[i], c̃, ṽ, i)
147 end
148
149 function apply_interior(op::SecondDerivativeVariable{1}, v, i, j)
150 ṽ = @view v[:,j]
151 c̃ = @view op.coefficient[:,j]
152
153 return @inbounds apply_stencil(op.inner_stencil, c̃, ṽ, i)
154 end
155
156 function apply_upper(op::SecondDerivativeVariable{1}, v, i, j)
157 ṽ = @view v[:,j]
158 c̃ = @view op.coefficient[:,j]
159
160 sz = domain_size(op)[derivative_direction(op)]
161 stencil = op.closure_stencils[sz-i+1]
162 return @inbounds apply_stencil_backwards(stencil, c̃, ṽ, i)
163 end
164
165
166 ## y-direction
167 function apply_lower(op::SecondDerivativeVariable{2}, v, i, j)
168 ṽ = @view v[i,:]
169 c̃ = @view op.coefficient[i,:]
170
171 return @inbounds apply_stencil(op.closure_stencils[j], c̃, ṽ, j)
172 end
173
174 function apply_interior(op::SecondDerivativeVariable{2}, v, i, j)
175 ṽ = @view v[i,:]
176 c̃ = @view op.coefficient[i,:]
177
178 return @inbounds apply_stencil(op.inner_stencil, c̃, ṽ, j)
179 end
180
181 function apply_upper(op::SecondDerivativeVariable{2}, v, i, j)
182 ṽ = @view v[i,:]
183 c̃ = @view op.coefficient[i,:]
184
185 sz = domain_size(op)[derivative_direction(op)]
186 stencil = op.closure_stencils[sz-j+1]
187 return @inbounds apply_stencil_backwards(stencil, c̃, ṽ, j)
188 end