Skip to content
This repository was archived by the owner on Jul 19, 2023. It is now read-only.

Commit adb5e9f

Browse files
Merge pull request #517 from xtalax/nonuniform-complete
Nonuniform complete derivative operator constructors
2 parents f34cbaf + 3245b70 commit adb5e9f

File tree

2 files changed

+343
-165
lines changed

2 files changed

+343
-165
lines changed

src/derivative_operators/derivative_operator.jl

Lines changed: 148 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ function nonlinear_diffusion!{N}(du::AbstractVector{T}, second_differential_orde
3737
#p is given as some function of q , p being the diffusion coefficient
3838

3939
@assert approx_order>1 "approximation_order must be greater than 1."
40-
if first_differential_order > 0
40+
if first_differential_order > 0
4141
du .= (CenteredDifference{N}(first_differential_order,approx_order,dx,nknots)*q).*(CenteredDifference{N}(second_differential_order,approx_order,dx,nknots)*p)
42-
else
42+
else
4343
du .= q[2:(nknots + 1)].*(CenteredDifference{N}(second_differential_order,approx_order,dx,nknots)*p)
4444
end
4545

@@ -88,10 +88,10 @@ function CenteredDifference{N}(derivative_order::Int,
8888
offside = 0
8989

9090
coefficients = fill!(Vector{T}(undef,len),0)
91-
91+
9292
compute_coeffs!(coeff_func, coefficients)
93-
94-
93+
94+
9595

9696
DerivativeOperator{T,N,false,T,typeof(stencil_coefs),
9797
typeof(low_boundary_coefs),typeof(high_boundary_coefs),typeof(coefficients),
@@ -148,8 +148,8 @@ function CenteredDifference{N}(derivative_order::Int,
148148
coefficients = zeros(T,len)
149149

150150
compute_coeffs!(coeff_func, coefficients)
151-
152-
151+
152+
153153
DerivativeOperator{T,N,false,typeof(dx),typeof(stencil_coefs),
154154
typeof(low_boundary_coefs),typeof(high_boundary_coefs),typeof(coefficients),
155155
typeof(coeff_func)}(
@@ -206,6 +206,45 @@ function CompleteCenteredDifference(derivative_order::Int,
206206
)
207207
end
208208

209+
function CompleteCenteredDifference(derivative_order::Int,
210+
approximation_order::Int, x::AbstractVector{T}) where {T<:Real,N}
211+
stencil_length = derivative_order + approximation_order - 1 + (derivative_order + approximation_order) % 2
212+
boundary_stencil_length = derivative_order + approximation_order
213+
stencil_x = zeros(T, stencil_length)
214+
boundary_point_count = endpoint = div(stencil_length, 2)
215+
len = length(x)
216+
dx = [x[i+1] - x[i] for i in 1:length(x)-1]
217+
interior_x = boundary_point_count+1:len-boundary_point_count
218+
dummy_x = -div(stencil_length, 2):div(stencil_length, 2)-1
219+
low_boundary_x = [zero(T); cumsum(dx[1:boundary_stencil_length-1])]
220+
high_boundary_x = cumsum(dx[end-boundary_stencil_length+1:end])
221+
# Because it's a N x (N+2) operator, the last stencil on the sides are the [b,0,x,x,x,x] stencils, not the [0,x,x,x,x,x] stencils, since we're never solving for the derivative at the boundary point.
222+
deriv_spots = (-div(stencil_length, 2)+1):-1
223+
224+
stencil_coefs = [convert(SVector{stencil_length,T}, calculate_weights(derivative_order, x[i], x[i-endpoint:i+endpoint])) for i in interior_x]
225+
low_boundary_coefs = SVector{boundary_stencil_length,T}[convert(SVector{boundary_stencil_length,T},
226+
calculate_weights(derivative_order, low_boundary_x[i+1], low_boundary_x)) for i in 0:boundary_point_count-1]
227+
228+
229+
high_boundary_coefs = SVector{boundary_stencil_length,T}[convert(SVector{boundary_stencil_length,T},
230+
calculate_weights(derivative_order, high_boundary_x[end-i], high_boundary_x)) for i in 0:boundary_point_count-1]
231+
232+
offside = 0
233+
coefficients = nothing
234+
235+
DerivativeOperator{eltype(x),Nothing,false,typeof(dx),typeof(stencil_coefs),
236+
typeof(low_boundary_coefs),typeof(high_boundary_coefs),typeof(coefficients),
237+
Nothing}(
238+
derivative_order, approximation_order, dx,
239+
len, stencil_length,
240+
stencil_coefs,
241+
boundary_stencil_length,
242+
boundary_point_count,
243+
low_boundary_coefs,
244+
high_boundary_coefs, offside, coefficients, nothing
245+
)
246+
end
247+
209248

210249
"""
211250
A helper function to compute the coefficients of a derivative operator including the boundary coefficients in the half offset centered scheme. See table 2 in https://web.njit.edu/~jiang/math712/fornberg.pdf
@@ -240,7 +279,6 @@ function CompleteHalfCenteredDifference(derivative_order::Int,
240279
# _high_boundary_coefs = SVector{boundary_stencil_length, T}[convert(SVector{boundary_stencil_length, T}, (1/dx^derivative_order) * calculate_weights(derivative_order, oneunit(T)*x0, reverse(right_boundary_x))) for x0 in R_boundary_deriv_spots]
241280

242281
offside = 0
243-
244282
coefficients = nothing
245283

246284

@@ -255,6 +293,52 @@ function CompleteHalfCenteredDifference(derivative_order::Int,
255293
)
256294
end
257295

296+
function CompleteHalfCenteredDifference(derivative_order::Int,
297+
approximation_order::Int, x::T) where {T<:AbstractVector{<:Real},N}
298+
@assert approximation_order > 1 "approximation_order must be greater than 1."
299+
centered_stencil_length = approximation_order + 2 * Int(floor(derivative_order / 2)) + (approximation_order % 2)
300+
boundary_stencil_length = derivative_order + approximation_order
301+
endpoint = div(centered_stencil_length, 2)
302+
hx = [(x[i] + x[i+1]) / 2 for i in 1:length(x)-1]
303+
dx = [x[i+1] - x[i] for i in 1:length(x)-1]
304+
305+
306+
low_boundary_x = @view(x[1:boundary_stencil_length])
307+
high_boundary_x = @view(x[end-boundary_stencil_length+1:end])
308+
309+
boundary_point_count = div(centered_stencil_length, 2) # -1 due to the ghost point
310+
# ? Is fornberg valid when taking an x0 outside of the stencil i.e at the boundary?
311+
312+
L_boundary_deriv_spots = hx[1:div(centered_stencil_length, 2)]
313+
# Because it's a N x (N+2) operator, the last stencil on the sides are the [b,0,x,x,x,x] stencils, not the [0,x,x,x,x,x] stencils, since we're never solving for the derivative at the boundary point.
314+
#deriv_spots = (-div(stencil_length,2)+1) : -1 # unused
315+
316+
R_boundary_deriv_spots = hx[length(hx):-1:length(hx)-div(centered_stencil_length, 2)+1]
317+
318+
stencil_coefs = [convert(SVector{centered_stencil_length,eltype(x)}, calculate_weights(derivative_order, hx[i], x[i-endpoint+1:i+endpoint])) for i in endpoint+1:length(x)-endpoint]
319+
# For each boundary point, for each tappoint in the half offset central difference stencil, we need to calculate the coefficients for the stencil.
320+
321+
322+
low_boundary_coefs = [convert(SVector{boundary_stencil_length,eltype(x)}, calculate_weights(derivative_order, offset, low_boundary_x)) for offset in L_boundary_deriv_spots]
323+
324+
high_boundary_coefs = [convert(SVector{boundary_stencil_length,eltype(x)}, calculate_weights(derivative_order, offset, high_boundary_x)) for offset in R_boundary_deriv_spots]
325+
326+
# _high_boundary_coefs = SVector{boundary_stencil_length, T}[convert(SVector{boundary_stencil_length, T}, (1/dx^derivative_order) * calculate_weights(derivative_order, oneunit(T)*x0, reverse(right_boundary_x))) for x0 in R_boundary_deriv_spots]
327+
328+
offside = 0
329+
coefficients = nothing
330+
331+
DerivativeOperator{eltype(x),Nothing,false,typeof(dx),typeof(stencil_coefs),
332+
typeof(low_boundary_coefs),typeof(high_boundary_coefs),typeof(coefficients),Nothing}(
333+
derivative_order, approximation_order, dx, 1, centered_stencil_length,
334+
stencil_coefs,
335+
boundary_stencil_length,
336+
boundary_point_count,
337+
low_boundary_coefs,
338+
high_boundary_coefs, offside, coefficients, nothing
339+
)
340+
end
341+
258342
struct UpwindDifference{N} end
259343

260344
"""
@@ -290,7 +374,7 @@ function UpwindDifference{N}(derivative_order::Int,
290374

291375
@assert offside > -1 "Number of offside points should be non-negative"
292376
@assert offside <= div(derivative_order + approximation_order - 1,2) "Number of offside points should not exceed the primary wind points"
293-
377+
294378
stencil_length = derivative_order + approximation_order
295379
boundary_stencil_length = derivative_order + approximation_order
296380
boundary_point_count = boundary_stencil_length - 2 - offside
@@ -357,7 +441,7 @@ function UpwindDifference{N}(derivative_order::Int,
357441

358442
# compute high_boundary_coefs: low_boundary_coefs[upwind = 1 downwind = 2, index of point]
359443
_upwind_coefs = SMatrix{1,boundary_point_count + offside}([convert(SVector{boundary_stencil_length, T}, calculate_weights(derivative_order, x[i+1], x[len-boundary_stencil_length+3:len+2])) for i in len-boundary_point_count+1-offside:len])
360-
if offside == 0
444+
if offside == 0
361445
_downwind_coefs = SMatrix{1,boundary_point_count}([convert(SVector{boundary_stencil_length,T}, calculate_weights(derivative_order, x[i+1], x[i-stencil_length+2:i+1])) for i in len-boundary_point_count+1:len])
362446
elseif offside == 1
363447
_downwind_coefs = SMatrix{1,boundary_point_count + offside}([convert(SVector{boundary_stencil_length,T}, calculate_weights(derivative_order, x[i+1], x[i-stencil_length+2+offside:i+1+offside])) for i in len-boundary_point_count+1-offside:len-offside+1])
@@ -390,25 +474,24 @@ function CompleteUpwindDifference(derivative_order::Int,
390474
offside::Int=0) where {T<:Real,N}
391475

392476
@assert offside > -1 "Number of offside points should be non-negative"
393-
@assert offside <= div(derivative_order + approximation_order - 1,2) "Number of offside points should not exceed the primary wind points"
394477

395478
stencil_length = derivative_order + approximation_order
396479
boundary_stencil_length = derivative_order + approximation_order
397-
boundary_point_count = boundary_stencil_length - 1 - offside
480+
low_boundary_point_count = offside
481+
high_boundary_point_count = stencil_length - 1 - offside
398482

399483
# TODO: Clean up the implementation here so that it is more readable and easier to extend in the future
400484
dummy_x = (0.0 - offside) : stencil_length - 1.0 - offside
401485
stencil_coefs = convert(SVector{stencil_length, T}, (1/dx^derivative_order) * calculate_weights(derivative_order, 0.0, dummy_x))
402-
403486
low_boundary_x = 0.0:(boundary_stencil_length-1)
404-
L_boundary_deriv_spots = 0.0:boundary_stencil_length - 2.0 - offside
487+
L_boundary_deriv_spots = 0.0:low_boundary_point_count-1
405488
_low_boundary_coefs = SVector{boundary_stencil_length, T}[convert(SVector{boundary_stencil_length, T}, (1/dx^derivative_order) * calculate_weights(derivative_order, oneunit(T)*x0, low_boundary_x)) for x0 in L_boundary_deriv_spots]
406-
low_boundary_coefs = convert(SVector{boundary_point_count},_low_boundary_coefs)
489+
low_boundary_coefs = convert(SVector{low_boundary_point_count},_low_boundary_coefs)
407490

408491
high_boundary_x = 0.0:-1.0:-(boundary_stencil_length-1.0)
409-
R_boundary_deriv_spots = 0.0:-1.0:-(boundary_stencil_length-2.0)
492+
R_boundary_deriv_spots = 0.0:-1.0:-(high_boundary_point_count-1.0)
410493
_high_boundary_coefs = SVector{boundary_stencil_length, T}[convert(SVector{boundary_stencil_length, T}, ((-1/dx)^derivative_order) * calculate_weights(derivative_order, oneunit(T)*x0, high_boundary_x)) for x0 in R_boundary_deriv_spots]
411-
high_boundary_coefs = convert(SVector{boundary_point_count + offside},reverse(_high_boundary_coefs))
494+
high_boundary_coefs = convert(SVector{high_boundary_point_count},reverse(_high_boundary_coefs))
412495

413496
coefficients = nothing
414497

@@ -419,12 +502,59 @@ function CompleteUpwindDifference(derivative_order::Int,
419502
derivative_order, approximation_order, dx, 1, stencil_length,
420503
stencil_coefs,
421504
boundary_stencil_length,
422-
boundary_point_count,
505+
high_boundary_point_count,
423506
low_boundary_coefs,
424507
high_boundary_coefs,offside,coefficients,nothing
425508
)
426509
end
427510

511+
# TODO implement the non-uniform grid
512+
function CompleteUpwindDifference(derivative_order::Int,
513+
approximation_order::Int, x::AbstractVector{T}, offside::Int=0) where {T<:Real,N}
514+
515+
@assert offside > -1 "Number of offside points should be non-negative"
516+
517+
stencil_length = derivative_order + approximation_order
518+
@assert offside <= stencil_length - 1 "Number of offside points should be less than or equal to the stencil length"
519+
boundary_stencil_length = derivative_order + approximation_order
520+
low_boundary_point_count = offside
521+
high_boundary_point_count = stencil_length - 1 - offside
522+
523+
dx = [x[i+1] - x[i] for i in 1:length(x)-1]
524+
525+
low_boundary_x = @view(x[1:boundary_stencil_length])
526+
high_boundary_x = @view(x[end-boundary_stencil_length+1:end])
527+
528+
L_boundary_deriv_spots = x[1:low_boundary_point_count]
529+
# Because it's a N x (N+2) operator, the last stencil on the sides are the [b,0,x,x,x,x] stencils, not the [0,x,x,x,x,x] stencils, since we're never solving for the derivative at the boundary point.
530+
#deriv_spots = (-div(stencil_length,2)+1) : -1 # unused
531+
532+
R_boundary_deriv_spots = x[end-high_boundary_point_count+1:end]
533+
534+
stencil_coefs = [convert(SVector{stencil_length,eltype(x)}, calculate_weights(derivative_order, x[i], @view(x[i-offside:i+stencil_length-1-offside]))) for i in low_boundary_point_count+1:length(x)-high_boundary_point_count]
535+
# For each boundary point, for each tappoint in the half offset central difference stencil, we need to calculate the coefficients for the stencil.
536+
537+
538+
low_boundary_coefs = [convert(SVector{boundary_stencil_length,eltype(x)}, calculate_weights(derivative_order, offset, low_boundary_x)) for offset in L_boundary_deriv_spots]
539+
540+
541+
high_boundary_coefs = [convert(SVector{boundary_stencil_length,eltype(x)}, calculate_weights(derivative_order, offset, high_boundary_x)) for offset in R_boundary_deriv_spots]
542+
543+
# _high_boundary_coefs = SVector{boundary_stencil_length, T}[convert(SVector{boundary_stencil_length, T}, (1/dx^derivative_order) * calculate_weights(derivative_order, oneunit(T)*x0, reverse(right_boundary_x))) for x0 in R_boundary_deriv_spots]
544+
545+
offside = 0
546+
coefficients = nothing
547+
548+
DerivativeOperator{eltype(x),Nothing,false,typeof(dx),typeof(stencil_coefs),
549+
typeof(low_boundary_coefs),typeof(high_boundary_coefs),typeof(coefficients),Nothing}(
550+
derivative_order, approximation_order, dx, 1, stencil_length,
551+
stencil_coefs,
552+
boundary_stencil_length,
553+
high_boundary_point_count,
554+
low_boundary_coefs,
555+
high_boundary_coefs, offside, coefficients, nothing
556+
)
557+
end
428558

429559
CenteredDifference(args...) = CenteredDifference{1}(args...)
430560
UpwindDifference(args...;kwargs...) = UpwindDifference{1}(args...;kwargs...)

0 commit comments

Comments
 (0)