IFGF.jl

Author IntegralEquations
Popularity
5 Stars
Updated Last
8 Months Ago
Started In
August 2021

IFGF.jl

A Julia implementation of the Interpolated Factored Green Function Method

Stable Dev Build Status codecov

Installation

Install from the Pkg REPL:

pkg> add https://github.com/IntegralEquations/IFGF.jl

Overview

This package provides an implementation of the Interpolated Factored Green Function Method (IFGF) for accelerating the evaluation of certain dense linear operators arising in boundary integral equation methods. In particular, it provides an efficient approximation of the matrix-vector product for both non-oscillatory kernels (e.g. Laplace, Stokes) and oscillatory kernels (e.g. Helmholtz, Maxwell).

To illustrate how the IFGFOp can be used to approximate dense linear maps, consider the problem of computing Ax where A is an M×N matrix with entries given by A[i,j] = K(X[i],Y[j]), with K(x,y)=exp(ik|x-y|)/|x-y| being the kernel function, and X,Y being a vector of M and N points in three dimensions. The following code show how one may set up the aforementioned matrix:

using IFGF, LinearAlgebra, StaticArrays
import IFGF: wavenumber

# random points on a cube
const Point3D = SVector{3,Float64}
m,n = 100_000, 100_000
X,Y = rand(Point3D,m), rand(Point3D,n)

# define a the kernel matrix
struct HelmholtzMatrix <: AbstractMatrix{ComplexF64}
    X::Vector{Point3D}
    Y::Vector{Point3D}
    k::Float64
end

# indicate that this is an ocillatory kernel with wavenumber `k`
wavenumber(A::HelmholtzMatrix) = A.k

# functor interface
function (K::HelmholtzMatrix)(x,y)
    k = wavenumber(K)
    d = norm(x-y)
    exp(im*k*d)*inv(4*pi*d)
end

# abstract matrix interface
Base.size(::HelmholtzMatrix) = length(X), length(Y)
Base.getindex(A::HelmholtzMatrix,i::Int,j::Int) = A(A.X[i],A.Y[j])

# create the abstract matrix
k = 2π   
A = HelmholtzMatrix(X,Y,k)

Although the memory footprint of the object A is very small (it lazily computes its entries), multiplying it by a vector has complexity proportional to m*n, which can be prohibitively costly for large problem sizes. The IFGFOp computes an approximation as follows:

L = assemble_ifgf(A,X,Y; tol = 1e-4)

We can now use L in lieu of A to approximate the matrix vector product, as illustrated below:

x     = randn(ComplexF64,n)
y     = L*x

In order to assess the quality of the approximation, we may take a few random rows and compare the approximate result against the exact one:

I  = rand(1:m,100)
exact = [sum(A[i,j]*x[j] for j in 1:n) for i in I]
er    = norm(y[I]-exact) / norm(exact) 

The error should be smaller than the prescribed tolerance.

See the documentation for more details and examples.