-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Operator exponential #763
Comments
Operator exponentials are hard, particularly with boundary conditions. You can define them with Cauchy integral formula or with rational approximations, but to my knowledge this requires knowledge of the spectrum. |
I tried using your method in your heat equation example with both BCs Neumann, but I get a Also what exactly is going on in these lines? B = [ldirichlet(S); rneumann(S)]
B = B[1:2,1:n]
B = B[1:2,1:2]\B
M = C[1:n-2,1:n]
M = M - M[:,1:2]*B # remove degrees of freedom
A = M[:,3:end]\L[1:n-2,3:n] For nonlinear problems and interfacing with DifferentialEquations, would @ChrisRackauckas be more familiar with the progress on that front? |
It’s because Neumann conditions have a zero first column. To make it work you’d have to permute the first 3 columns first |
I am having some trouble getting that workaround to work. I've done perm = [2;3;1;4:n]
B = B[1:2,1:n][:,perm] but what other columns/vectors should I permute and permute back? And is |
The method works as follows. First we make sure
Differentiating we get (M - M[:,1:2]*B)*u_t = (A - A[:,1:2]*B)*u The new mass matrix and RHS have zeros in the first two columns so we can drop those rows. But if B[1:2,1:2] \ B*P*v = 0
M*P*v_t = A*P*v Relabelling, this is the same as before hence one can proceed. I'll try to get an example working in ContinuumArrays.jl which will be cleaner |
Thank you, this is fantastic! I updated my little heat equation tutorial with this implementation, along with some basic checks. I'm new to this having only recently seen your JuliaCon 2018 talk, so not everything is clear, but I'm slowly working through your 2013 SIAM paper and learning a lot from it. I tried the same PDE with the extended state space (X x T) formulation here, but I noticed that on my (fairly old) laptop, the backslash solve gets stuck even at |
I think in this setting time stepping is preferable: solutions to PDEs in rectangles usually have corner singularities which a tensor based method will try to resolve. time-stepping avoids this because these singularities aren’t present on slices. Note the reason your simple example does not hit this issue is not because of the number of coefficients, but because (I believe) every even derivative vanishes, which is precisely the condition needed to avoid corner singularities. |
Hey @mjyshin, you can also do this with a symmetric-definite and banded eigendecomposition when propagating with self-adjoint linear differential operators. A reference on the code below is here, and this was followed up with more detail by my former M Sc student in his thesis. Sample code for your problem: using ApproxFun, LinearAlgebra
import ApproxFun: bandwidth
d = Segment(0..1)
S = Ultraspherical(0.5, d)
NS = NormalizedPolynomialSpace(S)
D = Derivative(S)
θ = (D=0.05, )
Δ = D^2
L = -θ.D*Δ # We'll negate this later
ϵ = 10^-1.5
u0 = Fun(x->(tanh((x-0.3)/ϵ)-tanh((x-0.7)/ϵ))/2, S)
C = Conversion(domainspace(L), rangespace(L))
B = [ldirichlet(S); rneumann(S)]
QS = QuotientSpace(B)
Q = Conversion(QS, S)
D1 = Conversion(S, NS)
D2 = Conversion(NS, S)
R = D1*Q
P = cache(PartialInverseOperator(C, (0, bandwidth(L, 1) + bandwidth(R, 1) + bandwidth(C, 2))))
AA = R'D1*P*L*D2*R
BB = R'R
n = ncoefficients(u0)
SB = Symmetric(BB[1:n,1:n], :L)
SA = Symmetric(AA[1:n,1:n], :L) + 0*SB # + 0*SB is a bug workaround for bandwidths in A smaller than bandwidths in B.
F = eigen(SA, SB);
F.values .= - F.values # negation complete!
w = Fun(x-> Number((B*u0)[1]) + Number((B*u0)[2])*x, S, 2) # A degree-1 polynomial that exactly captures nonzero boundary data
v0 = Q\(u0-w) # We'll represent u(x,t) = v(x,t) + w(x), where v satisfies 0 boundary data for all time
pad!(v0, n)
# u' = L u with B u = c
# Let u = v + w, where v evoles and w contains the nonzero boundary data.
# Then v' = L (v + w) = Lv since Lw = 0.
# L = B^{-1} A = VΛV^{-1}, VᵀBV = I => V^{-1} = VᵀB
# L = VΛVᵀB
# exp(tL) = Vexp(tΛ)VᵀB
vt = t -> Fun(QS, F.vectors*(Diagonal(exp.(t.*F.values))*(F.vectors'*(SB*v0.coefficients))))
t = 0:0.5:5
v = vt.(t)
u0(0) - v[end](0) - w(0) # left boundary condition
u0'(1) - (Q*v[end])'(1) - w'(1) # right boundary condition |
Wow, thank you both for your inputs. @MikaelSlevinsky I appreciate all the resources. I certainly have a long reading list for the next several weekends to parse through your code. A few thoughts:
Thanks again! I think it'll be nice to someday have this type of propagator operation baked into ApproxFun for everyone. |
w = Fun(S, B[1:2,1:2]\[Number((B*u0)[1]); Number((B*u0)[2])]) # A degree-1 polynomial that exactly captures nonzero boundary data The general boundary condition check is w = Fun(S, B[1:2,1:3]\[Number((B*u0)[1]); Number((B*u0)[2])]) # A degree-2 polynomial that exactly captures nonzero boundary data Secondly, since u = exp(tL) v0 + exp(tL) w = exp(tL) v0 + w + tLw, because (tL)^k w = 0 for k ≥ 2, since L is diffusion and w is at most quadratic. Now to check the boundary conditions in the Neumann case |
@MikaelSlevinsky, your method works as advertised for Dirichlet and Neumann (and mixed) BCs. If we define Also, do you know of a way to propagate |
This can be done with connection coefficients, but since these are generally upper-triangular and dense, the bandwidths of banded operators are hard to preserve (they would require some sophisticated numerical test for small coefficients worth truncating). In that sense, it's best to work with the original differential operator. The operator's polynomial variable coefficients don't need to be expanded in Legendre series; they can be in Chebyshev expansions in case that helps.
I think this is just general autonomous time-stepping, so I don't know anything specific to orthogonal polynomials in this regard. |
This is a somewhat unrelated question, but is there any meaning to the adjoint of an ApproxFun operator in Julia |
This is a motivation for using ContinuumArrays.jl as it makes adjoints well-defined |
Wow, very interesting (ContinuumArrays I mean). Looks kind of Chebfun-y, given that a function I've been using ApproxFun on the Kolmogorov equations (here), and it would be cool to be able to just define the generator |
First of all, thank you for developing this package, it's a very instructive way to learn about function decomposition methods!
And I do like the way time dependent PDEs can be solved by extending the state-space to include the time domain (see this example) and defining the IC as a Dirichlet BC.
But I was wondering if there was any discussion/plan of solving linear PDEs (
u' = A*u
) with the exponential of operators (u = exp(A*t)*u0
) by overloadingexp
? Matlab's chebfun has theexpm
function (see examples here and here), but it seems like the operators there have BCs baked in. There is an ApproxFun example too, but it's not very intuitive as one is not applying the propagator to aFun
type directly, and you need to explicitly specify how many coefficients to use.Also for more general PDEs, what is the status on using
Fun
inODEProblem
? I noticed that naively defining something likeand plugging it into
ODEProblem(model!,u0,tspan,p)
won't work. I noticed this question has been asked before, but since it's been a few years, I was wondering if there was any progress on this front?Thank you again!
The text was updated successfully, but these errors were encountered: