From 865c43cd5959a02dbe579597d71fe41db71dcb53 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Thu, 19 Sep 2024 12:04:49 +0100 Subject: [PATCH] start adding potential assemblers --- python/bempp/assembly/potential.py | 89 +++ python/test/test_potential_assembler.py | 32 + src/assembly/potential.rs | 2 +- src/assembly/potential/assemblers.rs | 14 +- .../potential/integrands/double_layer.rs | 2 + .../potential/integrands/single_layer.rs | 2 + src/bindings.rs | 697 +++++++++++++++++- 7 files changed, 834 insertions(+), 4 deletions(-) create mode 100644 python/bempp/assembly/potential.py create mode 100644 python/test/test_potential_assembler.py diff --git a/python/bempp/assembly/potential.py b/python/bempp/assembly/potential.py new file mode 100644 index 00000000..b14c8c88 --- /dev/null +++ b/python/bempp/assembly/potential.py @@ -0,0 +1,89 @@ +"""Potential assembly.""" + +import typing +import numpy as np +import numpy.typing as npt +from bempp._bempprs import lib as _lib, ffi as _ffi +from bempp.function_space import FunctionSpace +from ndelement.reference_cell import ReferenceCellType +from enum import Enum +from _cffi_backend import _CDataBase +from scipy.sparse import coo_matrix + +_dtypes = { + 0: np.float32, + 1: np.float64, +} +_ctypes = { + np.float32: "float", + np.float64: "double", +} + + +def _dtype_value(dtype): + """Get the u8 identifier for a data type.""" + for i, j in _dtypes.items(): + if j == dtype: + return i + raise TypeError("Invalid data type") + + +class OperatorType(Enum): + """Operator type.""" + + SingleLayer = 0 + DoubleLayer = 1 + + +class PotentialAssembler(object): + """Potential assembler.""" + + def __init__(self, rs_assembler: _CDataBase, owned: bool = True): + """Initialise.""" + self._rs_assembler = rs_assembler + self._owned = owned + + def __del__(self): + """Delete.""" + if self._owned: + _lib.free_potential_assembler(self._rs_assembler) + + def set_quadrature_degree(self, cell: ReferenceCellType, degree: int): + """Set the (non-singular) quadrature degree for a cell type.""" + if not _lib.potential_assembler_has_quadrature_degree(self._rs_assembler, cell.value): + raise ValueError(f"Invalid cell type: {cell}") + _lib.potential_assembler_set_quadrature_degree(self._rs_assembler, cell.value, degree) + + def quadrature_degree(self, cell: ReferenceCellType) -> int: + """Get the (non-singular) quadrature degree for a cell type.""" + if not _lib.potential_assembler_has_quadrature_degree(self._rs_assembler, cell.value): + raise ValueError(f"Invalid cell type: {cell}") + return _lib.potential_assembler_quadrature_degree(self._rs_assembler, cell.value) + + def set_batch_size(self, batch_size: int): + """Set the batch size.""" + _lib.potential_assembler_set_batch_size(self._rs_assembler, batch_size) + + @property + def batch_size(self) -> int: + """Get the batch size.""" + return _lib.potential_assembler_batch_size(self._rs_assembler) + + @property + def dtype(self): + """Data type.""" + return _dtypes[_lib.potential_assembler_dtype(self._rs_assembler)] + + @property + def _ctype(self): + """C data type.""" + return _ctypes[self.dtype] + + +def create_laplace_assembler( + operator_type: OperatorType, dtype: typing.Type[np.floating] = np.float64 +): + """Create a Laplace assembler.""" + return PotentialAssembler( + _lib.laplace_potential_assembler_new(operator_type.value, _dtype_value(dtype)) + ) diff --git a/python/test/test_potential_assembler.py b/python/test/test_potential_assembler.py new file mode 100644 index 00000000..b924b411 --- /dev/null +++ b/python/test/test_potential_assembler.py @@ -0,0 +1,32 @@ +import pytest +import numpy as np +from ndelement.reference_cell import ReferenceCellType +from bempp.assembly.potential import OperatorType, create_laplace_assembler +from bempp.function_space import function_space +from ndgrid.shapes import regular_sphere +from ndelement.ciarlet import create_family, Family, Continuity + + +@pytest.mark.parametrize( + "otype", + [ + OperatorType.SingleLayer, + OperatorType.DoubleLayer, + ], +) +def test_create_assembler(otype): + a = create_laplace_assembler(otype) + + assert a.quadrature_degree(ReferenceCellType.Triangle) != 3 + a.set_quadrature_degree(ReferenceCellType.Triangle, 3) + assert a.quadrature_degree(ReferenceCellType.Triangle) == 3 + with pytest.raises(ValueError): + a.set_quadrature_degree(ReferenceCellType.Interval, 3) + with pytest.raises(ValueError): + a.quadrature_degree(ReferenceCellType.Interval) + + assert a.batch_size != 4 + a.set_batch_size(4) + assert a.batch_size == 4 + + assert a.dtype == np.float64 diff --git a/src/assembly/potential.rs b/src/assembly/potential.rs index ab2ff885..db096252 100644 --- a/src/assembly/potential.rs +++ b/src/assembly/potential.rs @@ -1,6 +1,6 @@ //! Assembly of potential operators mod assemblers; pub(crate) mod cell_assemblers; -mod integrands; +pub mod integrands; pub use assemblers::PotentialAssembler; diff --git a/src/assembly/potential/assemblers.rs b/src/assembly/potential/assemblers.rs index db0f4281..1c18752b 100644 --- a/src/assembly/potential/assemblers.rs +++ b/src/assembly/potential/assemblers.rs @@ -135,15 +135,25 @@ impl< } /// Set (non-singular) quadrature degree for a cell type - pub fn quadrature_degree(&mut self, cell: ReferenceCellType, degree: usize) { + pub fn set_quadrature_degree(&mut self, cell: ReferenceCellType, degree: usize) { *self.options.quadrature_degrees.get_mut(&cell).unwrap() = degree; } + /// Get (non-singular) quadrature degree for a cell type + pub fn quadrature_degree(&self, cell: ReferenceCellType) -> Option { + self.options.quadrature_degrees.get(&cell).copied() + } + /// Set the maximum size of a batch of cells to send to an assembly function - pub fn batch_size(&mut self, size: usize) { + pub fn set_batch_size(&mut self, size: usize) { self.options.batch_size = size; } + /// Get the maximum size of a batch of cells to send to an assembly function + pub fn batch_size(&self) -> usize { + self.options.batch_size + } + fn assemble + Sync>( &self, output: &RawData2D, diff --git a/src/assembly/potential/integrands/double_layer.rs b/src/assembly/potential/integrands/double_layer.rs index 4d4adeac..4cd6a048 100644 --- a/src/assembly/potential/integrands/double_layer.rs +++ b/src/assembly/potential/integrands/double_layer.rs @@ -3,11 +3,13 @@ use crate::assembly::common::RlstArray; use crate::traits::{CellGeometry, PotentialIntegrand}; use rlst::{RlstScalar, UnsafeRandomAccessByRef}; +/// Integrand for a double layer potential operator pub struct DoubleLayerPotentialIntegrand { _t: std::marker::PhantomData, } impl DoubleLayerPotentialIntegrand { + /// Create new pub fn new() -> Self { Self { _t: std::marker::PhantomData, diff --git a/src/assembly/potential/integrands/single_layer.rs b/src/assembly/potential/integrands/single_layer.rs index 7a1291f0..df6b2084 100644 --- a/src/assembly/potential/integrands/single_layer.rs +++ b/src/assembly/potential/integrands/single_layer.rs @@ -3,11 +3,13 @@ use crate::assembly::common::RlstArray; use crate::traits::{CellGeometry, PotentialIntegrand}; use rlst::{RlstScalar, UnsafeRandomAccessByRef}; +/// Integrand for a single layer potential operator pub struct SingleLayerPotentialIntegrand { _t: std::marker::PhantomData, } impl SingleLayerPotentialIntegrand { + /// Create new pub fn new() -> Self { Self { _t: std::marker::PhantomData, diff --git a/src/bindings.rs b/src/bindings.rs index ab48e835..15e8e671 100644 --- a/src/bindings.rs +++ b/src/bindings.rs @@ -669,7 +669,7 @@ pub mod function { } } -pub mod assembly { +pub mod boundary_assembly { use super::function::{extract_space, FunctionSpaceWrapper, GridType, SpaceType}; use super::DType; use crate::assembly::common::SparseMatrixData; @@ -4435,3 +4435,698 @@ pub mod assembly { } } } + +pub mod potential_assembly { + use super::boundary_assembly::KernelType; + use super::function::{extract_space, FunctionSpaceWrapper, GridType, SpaceType}; + use super::DType; + use crate::assembly::common::SparseMatrixData; + use crate::{ + assembly::kernels::KernelEvaluator, + assembly::potential::integrands::{ + DoubleLayerPotentialIntegrand, SingleLayerPotentialIntegrand, + }, + assembly::potential::PotentialAssembler, + function::SerialFunctionSpace, + traits::{ + FunctionSpace, KernelEvaluator as KernelEvaluatorTrait, PotentialAssembly, + PotentialIntegrand, + }, + }; + use green_kernels::{helmholtz_3d::Helmholtz3dKernel, laplace_3d::Laplace3dKernel}; + use ndelement::{ciarlet::CiarletElement, types::ReferenceCellType}; + use ndgrid::SingleElementGrid; + use rlst::{c32, c64, rlst_array_from_slice_mut2, MatrixInverse, RlstScalar}; + use std::ffi::c_void; + use std::slice::from_raw_parts_mut; + + #[derive(Debug, PartialEq, Clone, Copy)] + #[repr(u8)] + pub enum PotentialOperator { + SingleLayer = 0, + DoubleLayer = 1, + } + + impl PotentialOperator { + fn from(value: u8) -> Option { + match value { + 0 => Some(PotentialOperator::SingleLayer), + 1 => Some(PotentialOperator::DoubleLayer), + _ => None, + } + } + } + + #[repr(C)] + pub struct PotentialAssemblerWrapper { + pub assembler: *const c_void, + pub itype: PotentialOperator, + pub ktype: KernelType, + pub dtype: DType, + } + impl Drop for PotentialAssemblerWrapper { + fn drop(&mut self) { + let Self { + assembler, + itype, + ktype, + dtype, + } = self; + match ktype { + KernelType::Laplace => match itype { + PotentialOperator::SingleLayer => match dtype { + DType::F32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut PotentialAssembler< + f32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::F64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut PotentialAssembler< + f64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match dtype { + DType::F32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut PotentialAssembler< + f32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::F64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut PotentialAssembler< + f64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + }, + KernelType::Helmholtz => match itype { + PotentialOperator::SingleLayer => match dtype { + DType::C32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut PotentialAssembler< + c32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::C64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut PotentialAssembler< + c64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match dtype { + DType::C32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut PotentialAssembler< + c32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::C64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut PotentialAssembler< + c64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + }, + } + } + } + + #[no_mangle] + pub unsafe extern "C" fn free_potential_assembler(a: *mut PotentialAssemblerWrapper) { + assert!(!a.is_null()); + unsafe { drop(Box::from_raw(a)) } + } + + pub(crate) unsafe fn extract_potential_assembler< + T: RlstScalar + MatrixInverse, + Integrand: PotentialIntegrand, + Kernel: KernelEvaluatorTrait, + >( + assembler: *const PotentialAssemblerWrapper, + ) -> *const PotentialAssembler { + (*assembler).assembler as *const PotentialAssembler + } + + pub(crate) unsafe fn extract_potential_assembler_mut< + T: RlstScalar + MatrixInverse, + Integrand: PotentialIntegrand, + Kernel: KernelEvaluatorTrait, + >( + assembler: *const PotentialAssemblerWrapper, + ) -> *mut PotentialAssembler { + (*assembler).assembler as *mut PotentialAssembler + } + + #[no_mangle] + pub unsafe extern "C" fn potential_assembler_has_quadrature_degree( + assembler: *mut PotentialAssemblerWrapper, + cell: u8, + ) -> bool { + let cell = ReferenceCellType::from(cell).unwrap(); + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + PotentialOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_potential_assembler::< + f32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_potential_assembler::< + f64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_potential_assembler::< + f32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_potential_assembler::< + f64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + }, + KernelType::Helmholtz => match (*assembler).itype { + PotentialOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_potential_assembler::< + c32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_potential_assembler::< + c64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_potential_assembler::< + c32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_potential_assembler::< + c64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + }, + } + .is_some() + } + + #[no_mangle] + pub unsafe extern "C" fn potential_assembler_set_quadrature_degree( + assembler: *mut PotentialAssemblerWrapper, + cell: u8, + degree: usize, + ) { + let cell = ReferenceCellType::from(cell).unwrap(); + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + PotentialOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_potential_assembler_mut::< + f32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::F64 => (*extract_potential_assembler_mut::< + f64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_potential_assembler_mut::< + f32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::F64 => (*extract_potential_assembler_mut::< + f64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + }, + KernelType::Helmholtz => match (*assembler).itype { + PotentialOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_potential_assembler_mut::< + c32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::C64 => (*extract_potential_assembler_mut::< + c64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_potential_assembler_mut::< + c32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::C64 => (*extract_potential_assembler_mut::< + c64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + }, + } + } + + #[no_mangle] + pub unsafe extern "C" fn potential_assembler_quadrature_degree( + assembler: *mut PotentialAssemblerWrapper, + cell: u8, + ) -> usize { + let cell = ReferenceCellType::from(cell).unwrap(); + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + PotentialOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_potential_assembler::< + f32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_potential_assembler::< + f64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_potential_assembler::< + f32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_potential_assembler::< + f64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + }, + KernelType::Helmholtz => match (*assembler).itype { + PotentialOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_potential_assembler::< + c32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_potential_assembler::< + c64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_potential_assembler::< + c32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_potential_assembler::< + c64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + }, + } + .unwrap() + } + + #[no_mangle] + pub unsafe extern "C" fn potential_assembler_set_batch_size( + assembler: *mut PotentialAssemblerWrapper, + batch_size: usize, + ) { + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + PotentialOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_potential_assembler_mut::< + f32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::F64 => (*extract_potential_assembler_mut::< + f64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_potential_assembler_mut::< + f32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::F64 => (*extract_potential_assembler_mut::< + f64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + }, + KernelType::Helmholtz => match (*assembler).itype { + PotentialOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_potential_assembler_mut::< + c32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::C64 => (*extract_potential_assembler_mut::< + c64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_potential_assembler_mut::< + c32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::C64 => (*extract_potential_assembler_mut::< + c64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + }, + } + } + + #[no_mangle] + pub unsafe extern "C" fn potential_assembler_batch_size( + assembler: *mut PotentialAssemblerWrapper, + ) -> usize { + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + PotentialOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_potential_assembler::< + f32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::F64 => (*extract_potential_assembler::< + f64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_potential_assembler::< + f32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::F64 => (*extract_potential_assembler::< + f64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + }, + KernelType::Helmholtz => match (*assembler).itype { + PotentialOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_potential_assembler::< + c32, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::C64 => (*extract_potential_assembler::< + c64, + SingleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + PotentialOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_potential_assembler::< + c32, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::C64 => (*extract_potential_assembler::< + c64, + DoubleLayerPotentialIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + }, + } + } + + #[no_mangle] + pub unsafe extern "C" fn potential_assembler_dtype( + assembler: *mut PotentialAssemblerWrapper, + ) -> u8 { + (*assembler).dtype as u8 + } + + unsafe fn laplace_potential_assembler_new_internal( + operator: PotentialOperator, + dtype: DType, + ) -> *const PotentialAssemblerWrapper { + Box::into_raw(Box::new(PotentialAssemblerWrapper { + assembler: match operator { + PotentialOperator::SingleLayer => { + Box::into_raw(Box::new( + PotentialAssembler::::new_laplace_single_layer(), + )) as *const c_void + } + PotentialOperator::DoubleLayer => { + Box::into_raw(Box::new( + PotentialAssembler::::new_laplace_double_layer(), + )) as *const c_void + } + }, + itype: operator, + ktype: KernelType::Laplace, + dtype, + })) + } + + #[no_mangle] + pub unsafe extern "C" fn laplace_potential_assembler_new( + operator: u8, + dtype: u8, + ) -> *const PotentialAssemblerWrapper { + let operator = PotentialOperator::from(operator).unwrap(); + let dtype = DType::from(dtype).unwrap(); + match dtype { + DType::F32 => laplace_potential_assembler_new_internal::(operator, dtype), + DType::F64 => laplace_potential_assembler_new_internal::(operator, dtype), + _ => { + panic!("Invalid data type"); + } + } + } + + unsafe fn helmholtz_potential_assembler_new_internal< + T: RlstScalar + MatrixInverse, + >( + wavenumber: T::Real, + operator: PotentialOperator, + dtype: DType, + ) -> *const PotentialAssemblerWrapper { + Box::into_raw(Box::new(PotentialAssemblerWrapper { + assembler: match operator { + PotentialOperator::SingleLayer => Box::into_raw(Box::new( + PotentialAssembler::::new_helmholtz_single_layer(wavenumber), + )) as *const c_void, + PotentialOperator::DoubleLayer => Box::into_raw(Box::new( + PotentialAssembler::::new_helmholtz_double_layer(wavenumber), + )) as *const c_void, + }, + itype: operator, + ktype: KernelType::Helmholtz, + dtype, + })) + } + + #[no_mangle] + pub unsafe extern "C" fn helmholtz_potential_assembler_new( + wavenumber: *const c_void, + operator: u8, + dtype: u8, + ) -> *const PotentialAssemblerWrapper { + let operator = PotentialOperator::from(operator).unwrap(); + let dtype = DType::from(dtype).unwrap(); + match dtype { + DType::C32 => helmholtz_potential_assembler_new_internal::( + *(wavenumber as *const f32), + operator, + dtype, + ), + DType::C64 => helmholtz_potential_assembler_new_internal::( + *(wavenumber as *const f64), + operator, + dtype, + ), + _ => { + panic!("Invalid data type"); + } + } + } +}