Crates.io | kifmm |
lib.rs | kifmm |
version | 2.0.0 |
source | src |
created_at | 2024-05-13 13:57:58.346371 |
updated_at | 2024-10-30 09:47:55.783232 |
description | Kernel-independent fast multipole method |
homepage | https://github.com/bempp/kifmm |
repository | https://github.com/bempp/kifmm |
max_upload_size | |
id | 1238481 |
size | 28,748,535 |
Our Rust APIs are simple, with the requirement for no temporary metadata files, or setup of ancillary data structures such as hierarchical trees, required by the user. FMMs are simply parameterised using the builder pattern, with operator chaining to modulate the type of the runtime object. At its simplest, a user only specifies buffers associated with source and target point coordinates, and associated source densities. Trait interfaces implemented for FMM objects allows users to access the associated objects such as kernels and data such as multipole expansions.
Indeed, the full API is more extensive, including features that enable for variable expansion orders by tree level useful for oscillatory problems, accelerated pre-computations for the BLAS based field translations based on randomised SVDs and alternative field translation implementations. Both Python and Rust examples can be found in the repository.
use rand::{thread_rng, Rng};
use green_kernels::{laplace_3d::Laplace3dKernel, types::GreenKernelEvalType};
use kifmm::{BlasFieldTranslationSaRcmp, SingleNodeBuilder, FmmSvdMode};
use kifmm::traits::tree::{FmmTree, Tree};
use kifmm::traits::fmm::Fmm;
fn main() {
// Generate some random source/target/charge data
let dim = 3;
let n_sources = 1000000;
let n_targets = 2000000;
// The number of vectors of source densities, FMM is configured from data
let n = 1;
let mut rng = thread_rng();
let mut sources = vec![0f32; n_sources * dim * n];
let mut targets = vec![0f32; n_targets * dim * n];
let mut charges = vec![0f32; n_sources * n];
sources.iter_mut().for_each(|s| *s = rng.gen());
targets.iter_mut().for_each(|t| *t = rng.gen());
charges.iter_mut().for_each(|c| *c = rng.gen());
// Set tree parameters
// Library refines tree till fewer than 'n_crit' points per leaf box
let n_crit = Some(150);
// Alternatively, users can specify the tree depth they require
let depth = None;
// Choose to branches associated with empty leaves from constructed tree
let prune_empty = true;
let timed = true; // Optionally time the operators
// Set FMM Parameters
// Can either set globally for whole tree, or level-by-level
let expansion_order = &[6];
// Parameters which control speed and accuracy of BLAS based field translation
let singular_value_threshold = Some(1e-5);
let check_surface_diff = Some(2);
// Create an FMM
let svd_mode = FmmSvdMode::Deterministic; // Choose SVD compression mode, random or deterministic
let mut fmm = SingleNodeBuilder::new(timed)
.tree(&sources, &targets, n_crit, depth, prune_empty) // Create tree
.unwrap()
.parameters(
&charges,
expansion_order, // Set expansion order, by tree level or globally
Laplace3dKernel::new(), // Choose kernel,
GreenKernelEvalType::Value, // Choose potential or potential + deriv evaluation
BlasFieldTranslationSaRcmp::new(
singular_value_threshold,
check_surface_diff,
svd_mode), // Choose field translation
)
.unwrap()
.build()
.unwrap();
// Run FMM
fmm.evaluate();
// Lookup potentials by leaf from target leaf boxes
let leaf_idx = 0;
let leaf = fmm.tree().target_tree().all_leaves().unwrap()[leaf_idx];
let leaf_potential = fmm.potential(&leaf);
}
We use Maturin for Python bindings, and provide an example of installation using the uv
package manager for Python below.
In order to enable plotting with MayaVi only Python 3.10.* is currently supported,
uv venv --python=3.10 && source .venv/bin/activate && uv pip install maturin pip
Note that Maturin must be run from the kifmm
crate root, not the workspace root.
maturin develop --release
We provide example usage of the Python API, as well as visualisation, in the python/examples
directory.
We provide a minimal C example using CMake in the c
folder to use the C bindings directly.