Not unlike , we represent exponential-polynomial functions in an abstract way.
For instance, the function PolyExp
, and it is instanced with
p1 = PolyExp(4,[1.0; 0.0; 2.0; 0.0; 3.0],1/2)
The argument of PolyExp
are 1) the order of the polynomial, 2) a vector of coefficient in decreasing degree order, and 3) the exponential coefficient.
Two PolyExp
object can be multiplied *(::PolyExp,::PolyExp)
and compared ==(::PolyExp,::PolyExp)
.
The exponential-polynomial can be evaluated with evalPolyExp
. The following code plots p1
in the interval
using PyPlot
rc("text", usetex=true)
using FEBULIA
p1 = PolyExp(4,[1.0; 0.0; 2.0; 0.0; 3.0],0.5)
Xplot = collect(-40.0:0.01:2.5)
figure();
axP = subplot(111)
plot(Xplot,evalPolyExp(Xplot,p1))
xlabel("\$X\$",fontsize=12)
ylabel("\$P(X)\$",fontsize=12)
xlim(-41,3)
ylim(-1,192)
xticks(fontsize=12)
yticks(fontsize=12)
tight_layout(pad=0.5, w_pad=0.5, h_pad=0.5)
axP.annotate("\$P_1(X) = e^{\\frac{X}{2}}\\left(X^4+2X^2+3\\right)\$", xy=(3, 1), xycoords="axes fraction", xytext=(0.2, 0.7), textcoords="axes fraction", color="black",fontsize=14)
Basis function can be created from PolyExp
objects. For instance, a piecewise linear basis can be generated with basis_PE_BC
from the code
# discretization nodes
x0 = 0.0
xend = 1.0π
Ndisc = 200
X_nodes = collect(LinRange(x0,xend,Ndisc))
# polynomials
p1_lin = PolyExp(1,[1.0; 0.0],0.0)
p2_lin = PolyExp(1,[1.0; 0.0],0.0)
# boundary conditions
ul = 1.0
uu = 1.0
BC = BoundCond1D("Dirichlet","Dirichlet",X_nodes[1],X_nodes[end];lowBC=ul,upBC=uu)
# basis function
B_decomp = basis_PE_BC(X_nodes,p1_lin,p2_lin,BC)
The generation of the basis function requires two PolyExp
object, one for the first part of the inteval PolyExp
objects are shifted and the local PolyExp
is given by shift_PolyExp
.
The derivative of the functions may be symbolically computed with deriv
B_decomp_d = deriv(B_decomp)
and produce the exact derivatives using the corresponding PolyExp
objects.
The following figure show an example of basis functions and their derivatives in the linear and quadratic cases. The generative polynomial for the quadratic basis functions are
Suppose that you want to solve a diffusion equation for the quantity
with bondary conditions
and initial state
The diffusion coefficient
The weak form of the PDE with the test function
Let
Using this decomposition with the weak form leads to a system of ordinary differential equations (ODEs) that we write in the matrix form:
where
From this formulation it is possible to deal with the boundary conditions. The problem is set with homogeneous Neumann boundary conditions, i.e.
For the sake of simplicity, in the following, we choose a test function basis
Note that for this scheme to not diverge, the time step
For the numerical resolution of the diffusion equation, the following FEBULIA
tools will be used:
-
BoundCond1D
: boundary condition object with Neumann boundary conditions at each end of the interval -
basis_PE
: basis with linear and quadratic functions -
PolyExp
: exponential-polynomial representation of the generator of the basis functions (generator exponential-polynomials for the decomposition basis$p_1(X) = p_2(X) = X$ , and test function$p_1(X) = -X^2 +2X$ and$p_2(X) = X^2$ ) -
integrate
: for computing the matrix elements (it is an exact integration that relies on the exponential-polynomial representation, not a numerical integration)
The matrix elements are computed with the functions mj_PE
and qk_PE
using integrate
function mj_PE(j::Int64,i::Int64,E::basis_PE,B::basis_PE)
val = 0.0
# E[j] # test
# B[i] # decomposition
if (i==j)
val = integrate(B.p1[i]*E.p1[j],B.xl[i],B.xm[i]) + integrate(B.p2[i]*E.p2[j],B.xm[i],B.xu[i]);
elseif ((i+1)==j) # e.g. j=5 and i=4
val = integrate(B.p2[i]*E.p1[j],B.xm[i],B.xu[i])
elseif ((i-1)==j)
val = integrate(B.p1[i]*E.p2[j],B.xl[i],B.xm[i])
else
val = 0.0
end
val
end
function qk_PE(j::Int64,l::Int64,k::Int64,E::basis_PE,B1::basis_PE,B2::basis_PE) # projection line, line, column, projection basis, decomposition basis 1, decomposition basis 2
val = 0.0
if ((l==j) & (k==j))
val = integrate(B1.p1[l]*B2.p1[k]*E.p1[j],E.xl[j],E.xm[j]) + integrate(B1.p2[l]*B2.p2[k]*E.p2[j],E.xm[j],E.xu[j])
elseif ((l==j) & (k==(j+1)))
val = integrate(B1.p2[l]*B2.p1[k]*E.p2[j],E.xm[j],E.xu[j])
elseif ((l==j) & (k==(j-1)))
val = integrate(B1.p1[l]*B2.p2[k]*E.p1[j],E.xl[j],E.xm[j])
elseif ((l==(j+1)) & (k==j))
val = integrate(B1.p1[l]*B2.p2[k]*E.p2[j],E.xm[j],E.xu[j])
elseif ((l==(j-1)) & (k==j))
val = integrate(B1.p2[l]*B2.p1[k]*E.p1[j],E.xl[j],E.xm[j])
elseif ((l==(j+1)) & (k==(j+1)))
val = integrate(B1.p1[l]*B2.p1[k]*E.p2[j],E.xm[j],E.xu[j])
elseif ((l==(j+1)) & (k==(j-1)))
val = 0.0
elseif ((l==(j-1)) & (k==(j+1)))
val = 0.0
elseif ((l==(j-1)) & (k==(j-1)))
val = integrate(B1.p2[l]*B2.p2[k]*E.p1[j],E.xl[j],E.xm[j])
else
val = 0.0
end
val
end
Finally, the following figure is generated with diffusion_1D.jl.
The diffusing quantity
] add https://github.com/matthewozon/FEBULIA