@@ -15,6 +15,7 @@ function SciMLBase.symbolic_discretize(pdesys::ModelingToolkit.PDESystem,discret
1515 pdeeqs = pdesys. eqs isa Vector ? pdesys. eqs : [pdesys. eqs]
1616 t = discretization. time
1717 nottime = filter (x-> x. val != t. val,pdesys. indvars)
18+ nspace = length (nottime)
1819
1920 # Discretize space
2021 space = map (nottime) do x
@@ -33,13 +34,13 @@ function SciMLBase.symbolic_discretize(pdesys::ModelingToolkit.PDESystem,discret
3334 depvars = map (pdesys. depvars) do u
3435 [Num (Variable {Symbolics.FnType{Tuple{Any}, Real}} (Base. nameof (ModelingToolkit. operation (u. val)),II. I... ))(t) for II in indices]
3536 end
36- spacevals = map (y-> [Pair (nottime[i],space[i][y. I[i]]) for i in 1 : length (nottime) ],indices)
37+ spacevals = map (y-> [Pair (nottime[i],space[i][y. I[i]]) for i in 1 : nspace ],indices)
3738
3839
3940 # ## INITIAL AND BOUNDARY CONDITIONS ###
4041 # Build symbolic maps for boundaries
41- edges = reduce (vcat,[[vcat ([Colon () for j in 1 : i- 1 ],1 ,[Colon () for j in i+ 1 : length (nottime) ]),
42- vcat ([Colon () for j in 1 : i- 1 ],size (depvars[1 ],i),[Colon () for j in i+ 1 : length (nottime) ])] for i in 1 : length (nottime) ])
42+ edges = reduce (vcat,[[vcat ([Colon () for j in 1 : i- 1 ],1 ,[Colon () for j in i+ 1 : nspace ]),
43+ vcat ([Colon () for j in 1 : i- 1 ],size (depvars[1 ],i),[Colon () for j in i+ 1 : nspace ])] for i in 1 : nspace ])
4344
4445 # edgeindices = [indices[e...] for e in edges]
4546 edgevals = reduce (vcat,[[nottime[i]=> first (space[i]),nottime[i]=> last (space[i])] for i in 1 : length (space)])
@@ -51,11 +52,11 @@ function SciMLBase.symbolic_discretize(pdesys::ModelingToolkit.PDESystem,discret
5152 subvar (depvar) = substitute .((depvar,),edgevals)
5253 depvarmaps = reduce (vcat,[subvar (depvar) .=> edgevars[i] for (i, depvar) in enumerate (pdesys. depvars)])
5354 # depvarderivmaps will dictate what to replace the Differential terms with
54- if length (nottime) == 1
55+ if nspace == 1
5556 # 1D system
56- left_weights (j) = DiffEqOperators. calculate_weights (discretization. upwind_order, 0.0 , space[j][1 : 2 ])
57- right_weights (j) = DiffEqOperators. calculate_weights (discretization. upwind_order, 0.0 , space[j][end - 1 : end ])
58- central_neighbor_idxs (i,j) = [i+ CartesianIndex ([ifelse (l== j,- 1 ,0 ) for l in 1 : length (nottime) ]. .. ),i,i+ CartesianIndex ([ifelse (l== j,1 ,0 ) for l in 1 : length (nottime) ]. .. )]
57+ left_weights (j) = DiffEqOperators. calculate_weights (discretization. upwind_order, space[j][ 1 ] , space[j][1 : 2 ])
58+ right_weights (j) = DiffEqOperators. calculate_weights (discretization. upwind_order, space[j][ end ] , space[j][end - 1 : end ])
59+ central_neighbor_idxs (i,j) = [i+ CartesianIndex ([ifelse (l== j,- 1 ,0 ) for l in 1 : nspace ]. .. ),i,i+ CartesianIndex ([ifelse (l== j,1 ,0 ) for l in 1 : nspace ]. .. )]
5960 left_idxs = central_neighbor_idxs (CartesianIndex (2 ),1 )[1 : 2 ]
6061 right_idxs (j) = central_neighbor_idxs (CartesianIndex (length (space[j])- 1 ),1 )[end - 1 : end ]
6162 # Constructs symbolic spatially discretized terms of the form e.g. au₂ - bu₁
@@ -86,7 +87,7 @@ function SciMLBase.symbolic_discretize(pdesys::ModelingToolkit.PDESystem,discret
8687
8788 # Replace Differential terms in the bc lhs with the symbolic spatially discretized terms
8889 # TODO : Fix Neumann and Robin on higher dimension
89- lhs = length (nottime) == 1 ? substitute (bc. lhs,depvarderivmaps[i]) : bc. lhs
90+ lhs = nspace == 1 ? substitute (bc. lhs,depvarderivmaps[i]) : bc. lhs
9091
9192 # Replace symbol in the bc lhs with the spatial discretized term
9293 lhs = substitute (lhs,depvarmaps[i])
@@ -101,28 +102,42 @@ function SciMLBase.symbolic_discretize(pdesys::ModelingToolkit.PDESystem,discret
101102 # ## PDE EQUATIONS ###
102103 interior = indices[[2 : length (s)- 1 for s in space]. .. ]
103104 eqs = vec (map (Base. product (interior,pdeeqs)) do p
104- i,eq = p
105-
106- # TODO : Number of points in the central_neighbor_idxs should be dependent
107- # on discretization.centered_order
105+ II,eq = p
106+
107+ # Create a stencil in the required dimension centered around 0
108+ # e.g. (-1,0,1) for 2nd order, (-2,-1,0,1,2) for 4th order, etc
109+ order = discretization. centered_order
110+ stencil_indices (j) = [1 : ifelse (l== j,order+ 1 ,1 ) for l in 1 : nspace]
111+ stencil_shift (j) = [ifelse (l== j,order÷ 2 + 1 ,1 ) for l in 1 : nspace]
112+ stencil (j) = CartesianIndices (Tuple (stencil_indices (j))) .- CartesianIndex (stencil_shift (j)... )
113+
108114 # TODO : Generalize central difference handling to allow higher even order derivatives
109- central_neighbor_idxs (i,j) = [i+ CartesianIndex ([ifelse (l== j,- 1 ,0 ) for l in 1 : length (nottime)]. .. ),i,i+ CartesianIndex ([ifelse (l== j,1 ,0 ) for l in 1 : length (nottime)]. .. )]
110- central_weights (i,j) = DiffEqOperators. calculate_weights (2 , 0.0 , space[j][i[j]- 1 : i[j]+ 1 ])
111- central_deriv (i,j,k) = dot (central_weights (i,j),depvars[k][central_neighbor_idxs (i,j)])
112- central_deriv_rules = [(Differential (s)^ 2 )(pdesys. depvars[k]) => central_deriv (i,j,k) for (j,s) in enumerate (nottime), k in 1 : length (pdesys. depvars)]
113- valrules = vcat ([pdesys. depvars[k] => depvars[k][i] for k in 1 : length (pdesys. depvars)],
114- [nottime[j] => space[j][i[j]] for j in 1 : length (nottime)])
115-
115+ # The central neighbour indices should add the stencil to II, unless II is too close
116+ # to an edge in which case we need to shift away from the edge
117+ # Calculate buffers
118+ I1 = oneunit (first (indices))
119+ Imin = first (indices) + I1 * (order÷ 2 )
120+ Imax = last (indices) - I1 * (order÷ 2 )
121+ # Use max and min to apply buffers
122+ central_neighbor_idxs (II,j) = stencil (j) .+ max (Imin,min (II,Imax))
123+ central_neighbor_space (II,j) = vec (space[j][map (i-> i[j],central_neighbor_idxs (II,j))])
124+ central_weights (II,j) = DiffEqOperators. calculate_weights (2 , space[j][II[j]], central_neighbor_space (II,j))
125+ central_deriv (II,j,k) = dot (central_weights (II,j),depvars[k][central_neighbor_idxs (II,j)])
126+
127+ central_deriv_rules = [(Differential (s)^ 2 )(u) => central_deriv (II,j,k) for (j,s) in enumerate (nottime), (k,u) in enumerate (pdesys. depvars)]
128+ valrules = vcat ([pdesys. depvars[k] => depvars[k][II] for k in 1 : length (pdesys. depvars)],
129+ [nottime[j] => space[j][II[j]] for j in 1 : nspace])
130+
116131 # TODO : Use rule matching for nonlinear Laplacian
117-
132+
118133 # TODO : upwind rules needs interpolation into `@rule`
119134 # forward_weights(i,j) = DiffEqOperators.calculate_weights(discretization.upwind_order, 0.0, [space[j][i[j]],space[j][i[j]+1]])
120135 # reverse_weights(i,j) = DiffEqOperators.calculate_weights(discretization.upwind_order, 0.0, [space[j][i[j]-1],space[j][i[j]]])
121136 # upwinding_rules = [@rule(*(~~a,(Differential(nottime[j]))(u),~~b) => IfElse.ifelse(*(~~a..., ~~b...,)>0,
122137 # *(~~a..., ~~b..., dot(reverse_weights(i,j),depvars[k][central_neighbor_idxs(i,j)[1:2]])),
123138 # *(~~a..., ~~b..., dot(forward_weights(i,j),depvars[k][central_neighbor_idxs(i,j)[2:3]]))))
124- # for j in 1:length(nottime) , k in 1:length(pdesys.depvars)]
125-
139+ # for j in 1:nspace , k in 1:length(pdesys.depvars)]
140+
126141 rules = vcat (vec (central_deriv_rules),valrules)
127142 substitute (eq. lhs,rules) ~ substitute (eq. rhs,rules)
128143 end )
0 commit comments