Skip to content

Commit e02bee7

Browse files
committed
fixed and simplified half offset
1 parent 8c8226e commit e02bee7

14 files changed

+279
-179
lines changed

src/MOL_utils.jl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,23 @@ function unitindices(N::Int) #create unit CartesianIndex for each dimension
7474
end
7575

7676
function split_additive_terms(eq)
77+
# Calling the methods from symbolicutils matches the expressions
7778
rhs_arg = istree(eq.rhs) && (SymbolicUtils.operation(eq.rhs) == +) ? SymbolicUtils.arguments(eq.rhs) : [eq.rhs]
78-
lhs_arg = istree(eq.lhs) && (SymbolicUtils.operation(eq.lhs) == +) ? SymbolicUtils.arguments(eq.lhs) : [eq.lhs]
79+
lhs_arg = istree(eq.lhs) && (SymbolicUtils.operation(eq.lhs) == +) ? SymbolicUtils.arguments(eq.lhs) : [eq.lhs]
7980

8081
return vcat(lhs_arg,rhs_arg)
8182
end
8283

84+
function clip(I::CartesianIndex, s::DiscreteSpace{N}, j::Int) where N
85+
# Clip the index by 1 at each end of the dimension
86+
I1 = unitindices(N)[j]
87+
return I[j] > length(s, j) ? I-I1 : I+I1
88+
end
89+
90+
subsmatch(expr, rule) = isequal(substitute(expr, rule), expr) ? false : true
91+
92+
93+
8394
half_range(x) = -div(x,2):div(x,2)
8495

8596

src/bcs/generate_bc_eqs.jl

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
1-
function _boundary_rules(s, orders, val)
2-
args = copy(s.params)
1+
function _boundary_rules(s, orders, x, val)
2+
#TODO: Change this around to detect boundary variables anywhere in the eq
3+
args = copy(s.params)
34

4-
if isequal(val, floor(val))
5-
args = [substitute.(args, (x=>val,)), substitute.(args, (x=>Int(val),))]
6-
else
7-
args = [substitute.(args, (x=>val,))]
8-
end
9-
substitute.(args, (x=>lowerboundary(x),))
10-
11-
rules = [@rule operation(u)(arg...) => (u, x) for u in s.vars, arg in args]
5+
args = substitute.(args, (x=>val,))
6+
7+
rules = [operation(u)(args...) => (operation(u)(args...), x) for u in ū]
128

13-
return vcat(rules, vec([@rule (Differential(x)^d)(operation(u)(arg...)) => (u, x) for d in orders[x], u in s.vars, arg in args]))
9+
return vcat(rules, vec([(Differential(x)^d)(operation(u)(args...)) => (operation(u)(args...), x) for d in orders[x], u in ]))
1410
end
1511

1612
function generate_boundary_matching_rules(s, orders)
@@ -19,9 +15,9 @@ function generate_boundary_matching_rules(s, orders)
1915
upperboundary(x) = last(s.axies[x])
2016

2117
# Rules to match boundary conditions on the lower boundaries
22-
lower = reduce(vcat, [_boundary_rules(s, orders, lowerboundary(x)) for x in s.vars])
18+
lower = reduce(vcat, [_boundary_rules(s, orders, x, lowerboundary(x)) for x in s.])
2319

24-
upper = reduce(vcat, [_boundary_rules(s, orders, upperboundary(x)) for x in s.vars])
20+
upper = reduce(vcat, [_boundary_rules(s, orders, x, upperboundary(x)) for x in s.])
2521

2622
return (lower, upper)
2723
end
@@ -35,9 +31,9 @@ function BoundaryHandler!!(u0, bceqs, bcs, s::DiscreteSpace, depvar_ops, tspan,
3531
t=s.time
3632

3733
if t === nothing
38-
initmaps = s.vars
34+
initmaps =
3935
else
40-
initmaps = substitute.(s.vars,[t=>tspan[1]])
36+
initmaps = substitute.(,[t=>tspan[1]])
4137
end
4238

4339
# Create some rules to match which bundary/variable a bc concerns
@@ -56,13 +52,13 @@ function BoundaryHandler!!(u0, bceqs, bcs, s::DiscreteSpace, depvar_ops, tspan,
5652
# * Assume in the form `u(...) ~ ...` for now
5753
bcdepvar = first(get_depvars(bc.lhs, depvar_ops))
5854

59-
if any(u -> isequal(operation(u), operation(bcdepvar)), s.vars)
55+
if any(u -> isequal(operation(u), operation(bcdepvar)), )
6056
if t !== nothing && operation(bc.lhs) isa Sym && !any(x -> isequal(x, t.val), arguments(bc.lhs))
6157
# initial condition
6258
# * Assume that the initial condition is not in terms of the initial derivative
6359
initindex = findfirst(isequal(bc.lhs), initmaps)
6460
if initindex !== nothing
65-
push!(u0,vec(s.discvars[s.vars[initindex]] .=> substitute.((bc.rhs,),gridvals(s))))
61+
push!(u0,vec(s.discvars[[initindex]] .=> substitute.((bc.rhs,),gridvals(s))))
6662
end
6763
else
6864
# Split out additive terms
@@ -72,23 +68,26 @@ function BoundaryHandler!!(u0, bceqs, bcs, s::DiscreteSpace, depvar_ops, tspan,
7268
boundary = nothing
7369
# Check whether the bc is on the lower boundary, or periodic
7470
for term in terms, r in lower_boundary_rules
75-
if r(term) !== nothing
76-
u_, x_ = (term, r(term))
71+
#Check if the rule changes the expression
72+
if subsmatch(term, r)
73+
# Get the matched variables from the rule
74+
u_, x_ = r.second
75+
# Mark the boundary
7776
boundary = LowerBoundary()
78-
for term_ in setdiff(terms, term)
79-
for r in upper_boundary_rules
80-
if r(term_) !== nothing
81-
# boundary = PeriodicBoundary()
82-
#TODO: Add handling for perioodic boundary conditions here
83-
end
84-
end
85-
end
77+
# for term_ in setdiff(terms, term)
78+
# for r_ in upper_boundary_rules
79+
# if subsmatch(term_, r_) !== nothing
80+
# boundary = PeriodicBoundary()
81+
# #TODO: Add handling for perioodic boundary conditions here
82+
# end
83+
# end
84+
# end
8685
break
8786
end
8887
end
8988
for term in terms, r in upper_boundary_rules
90-
if r(term) !== nothing
91-
u_, x_ = (term, r(term))
89+
if subsmatch(term, r)
90+
u_, x_ = r.second
9291
boundary = UpperBoundary()
9392
break
9493
end
@@ -115,10 +114,10 @@ function generate_bc_rules(II, derivweights, s::DiscreteSpace{N,M,G}, bc, u_, x_
115114
depvarbcmaps = []
116115

117116
# * Assume that the BC is in terms of an explicit expression, not containing references to variables other than u_ at the boundary
118-
for u in s.vars
117+
for u in
119118
if isequal(operation(u), operation(u_))
120119
# What to replace derivatives at the boundary with
121-
depvarderivbcmaps = [(Differential(x)^d)(u_) => central_difference(derivweights.map[Differential(x_)^d], II, s, (s.x2i[x_], x_), u, ufunc) for d in derivweights.orders[x_]]
120+
depvarderivbcmaps = [(Differential(x_)^d)(u_) => central_difference(derivweights.map[Differential(x_)^d], II, s, (s.x2i[x_], x_), u, ufunc) for d in derivweights.orders[x_]]
122121
# ? Does this need to be done for all variables at the boundary?
123122
depvarbcmaps = [u_ => s.discvars[u][II]]
124123
break
@@ -136,8 +135,6 @@ end
136135

137136
function generate_bc_rules(II, derivweights, s::DiscreteSpace{N,M,G}, bc, u_, x_, boundary::AbstractTruncatingBoundary) where {N, M, G<:EdgeAlignedGrid}
138137

139-
offset(::LowerBoundary) = 1/2
140-
offset(::UpperBoundary) = -1/2
141138
ufunc(v, I, x) = s.discvars[v][I]
142139

143140
depvarderivbcmaps = []
@@ -146,11 +143,11 @@ function generate_bc_rules(II, derivweights, s::DiscreteSpace{N,M,G}, bc, u_, x_
146143
# depvarbcmaps will dictate what to replace the variable terms with in the bcs
147144
# replace u(t,0) with u₁, etc
148145
# * Assume that the BC is in terms of an explicit expression, not containing references to variables other than u_ at the boundary
149-
for u in s.vars
146+
for u in
150147
if isequal(operation(u), operation(u_))
151-
depvarderivbcmaps = [(Differential(x)^d)(u_) => half_offset_centered_difference(derivweights.halfoffsetmap[Differential(x_)^d], II, s, offset(boundary), (s.x2i[x_],x_), u, ufunc) for d in derivweights.orders[x_]]
148+
depvarderivbcmaps = [(Differential(x_)^d)(u_) => half_offset_centered_difference(derivweights.halfoffsetmap[Differential(x_)^d], II, s, (s.x2i[x_],x_), u, ufunc) for d in derivweights.orders[x_]]
152149

153-
depvarbcmaps = [u_ => half_offset_centered_difference(derivweights.interpmap[x_], II, s, offset(boundary), (s.x2i[x_],x_), u, ufunc)]
150+
depvarbcmaps = [u_ => half_offset_centered_difference(derivweights.interpmap[x_], II, s, (s.x2i[x_],x_), u, ufunc)]
154151
break
155152
end
156153
end

src/bcs/scratch.jl

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
2+
using DiffEqOperators
3+
4+
"""
5+
Inner function for `get_half_offset_weights_and_stencil` (see below).
6+
"""
7+
function _get_weights_and_stencil(D, I)
8+
# k => i of itap -
9+
# offset is important due to boundary proximity
10+
# The low boundary coeffs has a heirarchy of coefficients following: number of indices from boundary -> which half offset point does it correspond to -> weights
11+
if I <= (D.boundary_point_count)
12+
println("low boundary")
13+
weights = D.low_boundary_coefs[I]
14+
offset = 1 - I
15+
Itap = [I + (i+offset) for i in 0:(D.boundary_stencil_length-1)]
16+
elseif I > (20 - D.boundary_point_count)
17+
println("high boundary")
18+
19+
weights = D.high_boundary_coefs[20-I+1]
20+
offset = 20 - I
21+
Itap = [I + (i+offset) for i in (-D.boundary_stencil_length+1):1:0]
22+
else
23+
println("interior")
24+
25+
weights = D.stencil_coefs
26+
Itap = [I + i for i in (1-div(D.stencil_length,2)):(div(D.stencil_length,2))]
27+
end
28+
29+
return (weights, Itap)
30+
end
31+
32+
33+
function clip(I, n)
34+
return I>(n/2) ? I-1 : I+1
35+
36+
end
37+
38+
for I in [2,19, 3, 18, 10]
39+
40+
D = CompleteHalfCenteredDifference(1, 6, 1.0)
41+
42+
43+
44+
outerweights, outerstencil = _get_weights_and_stencil(D, clip(I,20))
45+
46+
# Get the correct weights and stencils for this II
47+
48+
@show I
49+
@show outerweights
50+
@show outerstencil
51+
52+
53+
for II in outerstencil
54+
println()
55+
println("II: ", II)
56+
println()
57+
weights, stencil = _get_weights_and_stencil(D, II)
58+
println(weights)
59+
println(stencil)
60+
end
61+
62+
end

src/discretization/MOL_discretization.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ function SciMLBase.symbolic_discretize(pdesys::PDESystem, discretization::Method
3434
# Read the independent variables,
3535
# ignore if the only argument is [t]
3636
allindvars = Set(filter(xs->!isequal(xs, [t]), map(arguments, depvars)))
37-
allnottime = Set(filter(!isempty, map(u->filter(x-> t === nothing || !isequal(x, t.val), arguments(u)), depvars)))
38-
if isempty(allnottime)
37+
allx̄ = Set(filter(!isempty, map(u->filter(x-> t === nothing || !isequal(x, t.val), arguments(u)), depvars)))
38+
if isempty(allx̄)
3939
push!(alleqs, pde)
4040
push!(alldepvarsdisc, depvars)
4141
for bc in bcs
@@ -45,13 +45,13 @@ function SciMLBase.symbolic_discretize(pdesys::PDESystem, discretization::Method
4545
end
4646
else
4747
# make sure there is only one set of independent variables per equation
48-
@assert length(allnottime) == 1
49-
nottime = first(allnottime)
48+
@assert length(allx̄) == 1
49+
= first(allx̄)
5050
@assert length(allindvars) == 1
5151
indvars = first(allindvars)
5252

5353
# Get the grid
54-
s = DiscreteSpace(domain, depvars, indvars, nottime, discretization)
54+
s = DiscreteSpace(domain, depvars, indvars, , discretization)
5555

5656
# Get the finite difference weights
5757
derivweights = DifferentialDiscretizer(pde, s, discretization)
@@ -64,12 +64,12 @@ function SciMLBase.symbolic_discretize(pdesys::PDESystem, discretization::Method
6464

6565
# Discretize the equation on the interior
6666
pdeeqs = vec(map(interior) do II
67-
rules = vcat(generate_finite_difference_rules(II, s, pde, derivweights), valrules(s, II))
67+
rules = vcat(generate_finite_difference_rules(II, s, pde, derivweights), valmaps(s, II))
6868
substitute(pde.lhs,rules) ~ substitute(pde.rhs,rules)
6969
end)
7070

7171
push!(alleqs,pdeeqs)
72-
push!(alldepvarsdisc, reduce(vcat, s.discvars))
72+
push!(alldepvarsdisc, reduce(vcat, values(s.discvars)))
7373
end
7474
end
7575

src/discretization/differential_discretizer.jl

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ function DifferentialDiscretizer(pde, s, discretization)
1212
# TODO: Include bcs in this calculation
1313
d_orders(x) = reverse(sort(collect(union(differential_order(pde.rhs, x), differential_order(pde.lhs, x)))))
1414

15-
# central_deriv_rules = [(Differential(s)^2)(u) => central_deriv(2,II,j,k) for (j,s) in enumerate(s.nottime), (k,u) in enumerate(s.vars)]
15+
# central_deriv_rules = [(Differential(s)^2)(u) => central_deriv(2,II,j,k) for (j,s) in enumerate(s.), (k,u) in enumerate()]
1616
differentialmap = Array{Pair{Num,DiffEqOperators.DerivativeOperator},1}()
1717
nonlinlap = []
1818
interp = []
1919
orders = []
2020
# Hardcoded to centered difference, generate weights for each differential
2121
# TODO: Add handling for upwinding
22-
for x in s.nottime
22+
for x in s.
2323
push!(orders, x => d_orders(x))
2424
# TODO: Only generate weights for derivatives that are actually used and avoid redundant calculations
2525
rs = [(Differential(x)^d) => CompleteCenteredDifference(d, approx_order, s.dxs[x] ) for d in last(orders).second]
@@ -60,51 +60,39 @@ function central_difference(D, II, s, jx, u, ufunc)
6060
return dot(weights, ufunc(u, Itap, x))
6161
end
6262

63+
6364
"""
64-
Inner function for `get_half_offset_weights_and_stencil` (see below).
65+
Get the weights and stencil for the inner half offset centered difference for the nonlinear laplacian for a given index and differentiating variable.
66+
67+
Does not discretize so that the weights can be used in a replacement rule
68+
TODO: consider refactoring this to harmonize with centered difference
6569
"""
66-
function _get_weights_and_stencil(D, II, I1, s, k, j, x)
67-
# k => i of itap -
70+
function get_half_offset_weights_and_stencil(D, II, s, jx)
71+
j, x = jx
72+
# unit index in direction of the derivative
73+
I1 = unitindices(nparams(s))[j]
6874
# offset is important due to boundary proximity
69-
# The low boundary coeffs has a heirarchy of coefficients following: number of indices from boundary -> which half offset point does it correspond to -> weights
70-
if II[j] <= (D.boundary_point_count-1)
71-
weights = D.low_boundary_coefs[II[j]][k]
75+
76+
if II[j] <= D.boundary_point_count
77+
weights = D.low_boundary_coefs[II[j]]
7278
offset = 1 - II[j]
7379
Itap = [II + (i+offset)*I1 for i in 0:(D.boundary_stencil_length-1)]
74-
elseif II[j] > (length(s, x) - D.boundary_point_count - 1)
75-
weights = D.high_boundary_coefs[length(s,x)-II[j]+1][k]
80+
elseif II[j] > (length(s, x) - D.boundary_point_count)
81+
weights = D.high_boundary_coefs[length(s, x)-II[j]+1]
7682
offset = length(s, x) - II[j]
7783
Itap = [II + (i+offset)*I1 for i in (-D.boundary_stencil_length+1):1:0]
7884
else
7985
weights = D.stencil_coefs
80-
Itap = [II + (i+1)*I1 for i in half_range(D.stencil_length)]
86+
Itap = [II + i*I1 for i in (1-div(D.stencil_length,2)):(div(D.stencil_length,2))]
8187
end
8288

8389
return (weights, Itap)
8490
end
8591

86-
"""
87-
Get the weights and stencil for the inner half offset centered difference for the nonlinear laplacian for a given index and differentiating variable.
88-
89-
Does not discretize so that the weights can be used in a replacement rule
90-
TODO: consider refactoring this to harmonize with centered difference
91-
"""
92-
function get_half_offset_weights_and_stencil(D, II, s, offset, jx)
93-
j, x = jx
94-
I1 = unitindices(nparams(s))[j]
95-
# Shift the current index to the correct offset
96-
II_prime = II + Int(offset-0.5)*I1
97-
@assert all(i-> 0<i<=length(s,x), II_prime) "Index out of bounds"
98-
return _get_weights_and_stencil(D, II_prime, I1, s, offset, j, x)
99-
end
10092

10193
# i is the index of the offset, assuming that there is one precalculated set of weights for each offset required for a first order finite difference
102-
function half_offset_centered_difference(D, II, s, offset, jx, u, ufunc)
103-
j, x = jx
104-
I1 = unitindices(nparams(s))[j]
105-
# Shift the current index to the correct offset
106-
II_prime = II + Int(offset-0.5)*I1
107-
# Get the weights and stencil
108-
(weights, Itap) = _get_weights_and_stencil(D, II_prime, I1, s, offset, j, x)
94+
function half_offset_centered_difference(D, II, s, jx, u, ufunc)
95+
96+
(weights, Itap) = get_half_offset_weights_and_stencil(D, II, s, jx)
10997
return dot(weights, ufunc(u, Itap, x))
11098
end

0 commit comments

Comments
 (0)