Hi,

I wrote a simple script which shows how FEniCS can be used to solve integral 
equations. 
At the moment FEniCS is combined with numpy to solve the problem, so I’d be 
grateful for 
pointers on how to solve the entire problem in FEniCS. Also, are there any 
objections to
this becoming a demo at some point? Thanks.

Best regards, Miro




from scipy.sparse import csr_matrix
from dolfin import *
import numpy as np

# We show how integral equations can be solved with FEniCS
#
# We consider an integral equation of the second type and want to find 
# u: [0, 1] -> R, such that
#
# u(x) - 0.5\int_{0}^{1}(x+1)\exp{-xy}u(y)dy = f(x)   in [0, 1],
#
# where f(x) = \exp{-x} - 0.5 + 0.5\exp{-(x+1)}. The problem has an exact
# solution u(x) = exp(-x). The problem is taken from Linear Integral Equations
# by Kress (p. 158)

# FEniCS is used in combination with numpy. For easy conversion of matrices
# we used uBLAS as backend
parameters['linear_algebra_backend'] = 'uBLAS'


def to_sparse(mat):
    'Convert DOLFIN uBLAS matrix to scipy.sparse matrix.'
    rows, cols, values = mat.data()
    return csr_matrix((values, cols, rows))


f = Expression('exp(-x[0])-0.5+0.5*exp(-(x[0]+1))')


def fredholm(N=32, with_plot=True):
    'Solve the problem on mesh with N elements.'
    # Discretize the domain
    mesh = UnitIntervalMesh(N)

    # Setup Vh
    V = FunctionSpace(mesh, 'CG', 1)
    u = TrialFunction(V)
    v = TestFunction(V)

    # The discretized problem becomes M*U - 0.5*M*C*U = b
    # where M is the mass matrix, C is the matrix of the kernel, b is the load 
    # vector and U has unknown expansion coefficients of the approximate solution
    # uh

    # Mass matrix
    m_form = inner(u, v)*dx
    M = assemble(m_form)
    M = to_sparse(M)

    # On Vh we approximate the kernel \int_{0}^{1}(x+1)*\exp{-xy}u(y)*dy by
    # \int_{0}^{1}(x+1) \exp{-xy} U_j v_j(y)*dy. Consider the function F_j(x),
    # 
    # F_j(x) = \int_{0}^{1}(x+1) \exp{-xy} v_j(y)*dy.
    #
    # We shall use its interpolant in Vh, that is F_j(x) = c^j_k v_k(x) where
    # c^j_k = L_k(F_j), L_k being the degrees of freedom of the finite element
    # space. Here we consider Lagrange elements, thus c^j_k = F_j(x_k).

    # We have x[0] <- y as the integration variable, and t <- x will be used to set
    # x_k
    kernel = Expression('(t+1)*exp(-t*x[0])', t=0, degree=8)
    # Coordinates of dofs as a array of shape (V.dim, )
    x_ks = V.dofmap().tabulate_all_coordinates(mesh).reshape((-1, 1))[:, 0]

    # Kernel matrix
    C = np.zeros(M.shape)
    # The row of C for x_k fixed can be made from the linear form
    row_form = inner(kernel, v)*dx
    for row, x_k in enumerate(x_ks):
        kernel.t = x_k
        row_values = assemble(row_form).array()
        C[row, :] = row_values

    # Load vector
    L = inner(f, v)*dx
    b = assemble(L).array()

    # The system is AU=b with A = M - 0.5 M.C.U
    A = M - 0.5*M.dot(C)

    # Solve
    U = np.linalg.solve(A, b)

    # Create uh
    uh = Function(V)
    uh.vector()[:] = U

    # Compare with exact solution
    u_exact = Expression('exp(-x[0])')

    if with_plot:
        plot(u_exact, mesh=mesh, title='exact')
        plot(uh, title='numeric')
        interactive()

    return errornorm(u_exact, uh, 'L2'), mesh.hmin()

# -----------------------------------------------------------------------------

if __name__ == '__main__':
    from math import log as ln
    
    # Run the convergence test
    for N in [16, 32, 64, 128, 256, 512, 1024]:
        e, h = fredholm(N=N, with_plot=False)
        if N != 16:
            rate = ln(e/e_)/ln(h/h_)
            print 'N=%d error=%4g rate=%.2f' % (N, e, rate)
        e_, h_ = e, h
_______________________________________________
fenics-support mailing list
fenics-support@fenicsproject.org
http://fenicsproject.org/mailman/listinfo/fenics-support

Reply via email to