# FMM2D.jl

FMM2D.jl is a Julia interface for computing N-body interactions using the Flatiron Institute's FMM2D library.

Currently, the wrapper only wraps the Helmholtz and Laplace functionalities.

## Helmholtz FMM

Let $c_j \in \mathbb{C},\ j = 1,\dots,N$ denote a collection of charge strengths, $v_j \in \mathbb{C},\ j = 1,\dots,N$ denote a collection of dipole strengths, and $\mathbf{d}_j\in\mathbb{R}^2,\ j = 1,\dots,N$ denote the corresponding dipole orientation vectors. Furthermore, $k \in \mathbb{C}$ denote the wave number.

The Fast Multipole Method is $O(n)$ algorithm that can be used to approximate the Helmholtz potential $u$ (and its gradient and Hessian) caused by the presence of a collection of sources $\mathbf{x}_j$ at target position $\mathbf{x}$. The direct computation of the potential is

$$ u(\mathbf{x}) = \sum_{j=1}^{N} c_jH_0^{(1)}(k|\mathbf{x} - \mathbf{x}_j|) - v_j\mathbf{d}_j\cdot\nabla H_0^{(1)}(k|\mathbf{x} - \mathbf{x}_j|), $$

where $H_0^{(1)}$ is the Hankel function of the first kind of order 0. When $\mathbf{x} = \mathbf{x}_j$ the $j$ th term is dropped from the sum.

### Example

using FMM2D
# Simple example for the FMM2D Library
thresh = 10.0^(-5) # Tolerance
zk = rand(ComplexF64) # Wavenumber
# Source-to-source
n = 200
sources = rand(2,n)
charges = rand(ComplexF64,n)
pg = 3 # Evaluate potential, gradient, and Hessian at the sources
vals = hfmm2d(eps=thresh,zk=zk,sources=sources,charges=charges,pg=pg)
vals.pot
vals.grad
vals.hess
# Source-to-target
m = 200
targets = rand(2,m)
pgt = 3 # Evaluate potential, gradient, and Hessian at the targets
vals = hfmm2d(targets=targets,eps=thresh,zk=zk,sources=sources,charges=charges,pgt=pgt)
vals.pottarg
vals.gradtarg
vals.hesstarg

## Laplace

The Laplace problem in 2D have the following form

$$ u(x) = \sum_{j=1}^{N} \left[c_{j} \text{log}\left(|x-x_{j}|\right) - d_{j}v_{j} \cdot \nabla( \text{log}(|x-x_{j}|) )\right], $$

In the case of complex charges and dipole strengths ($c_j, v_j \in \mathbb{C}^n$) the function call `lfmm2d`

has to be used. In the case of real charges and dipole strengths ($c_j, v_j \in \mathbb{R}^n$) the function call `rfmm2d`

has to be used.

### Example

using FMM2D
# Simple example for the FMM2D Library
thresh = 10.0^(-5) # Tolerance
# Source-to-source
n = 200
sources = rand(2,n)
charges = rand(ComplexF64,n)
dipvecs = randn(2,n)
dipstr = rand(ComplexF64,n)
pg = 3 # Evaluate potential, gradient, and Hessian at the sources
vals = lfmm2d(eps=thresh,sources=sources,charges=charges,dipvecs=dipvecs,dipstr=dipstr,pg=pg)
vals.pot
vals.grad
vals.hess
# Source-to-target
m = 100
targets = rand(2,m)
pgt = 3 # Evaluate potential, gradient, and Hessian at the targets
vals = lfmm2d(targets=targets,eps=thresh,sources=sources,charges=charges,dipvecs=dipvecs,dipstr=dipstr,pgt=pgt)
vals.pottarg
vals.gradtarg
vals.hesstarg

## Stokes

$$ u(x) = \sum_{j=1}^NG^\text{stok}(x,x_j)c_j + d_j\cdot T^\text{stok}(x,x_j)\cdot v_j $$

$$ p(x) = \sum_{j=1}^NP^\text{stok}(x,x_j)c_j + d_j\cdot \Pi^\text{stok}(x,x_j)\cdot v_j^\top $$

## Related Package

FMMLIB2D.jl interfaces the FMMLIB2D library which the FMM2D library improves on.