From 0e32fa38a3cfc7694554c77ed577f3e7655734c5 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Wed, 18 Sep 2024 15:42:12 +0100 Subject: [PATCH] wrap boundary assembler options --- examples/assembly.rs | 4 +- pyproject.toml | 2 +- python/bempp/__init__.py | 2 +- python/bempp/assembly/__init__.py | 3 + python/bempp/assembly/boundary.py | 112 ++ python/bempp/function_space.py | 7 +- python/test/test_boundary_assembler.py | 37 + src/assembly/boundary.rs | 2 +- src/assembly/boundary/assemblers.rs | 27 +- src/assembly/boundary/integrands.rs | 2 + .../integrands/adjoint_double_layer.rs | 2 + .../boundary/integrands/double_layer.rs | 2 + .../boundary/integrands/hypersingular.rs | 4 + .../boundary/integrands/single_layer.rs | 2 + src/bindings.rs | 1701 ++++++++++++++++- 15 files changed, 1894 insertions(+), 15 deletions(-) create mode 100644 python/bempp/assembly/__init__.py create mode 100644 python/bempp/assembly/boundary.py create mode 100644 python/test/test_boundary_assembler.py diff --git a/examples/assembly.rs b/examples/assembly.rs index 586eaa09..0f94e8d4 100644 --- a/examples/assembly.rs +++ b/examples/assembly.rs @@ -21,11 +21,11 @@ fn main() { // Adjust the quadrature degree for non-singular integrals on a triangle. // This makes the integrals use a quadrature rule with 16 points - a.quadrature_degree(ReferenceCellType::Triangle, 16); + a.set_quadrature_degree(ReferenceCellType::Triangle, 16); // Adjust the quadrature degree for singular integrals on a pair ortriangles. // This makes the integrals use a quadrature rule based on a rule on an interval with 4 points - a.singular_quadrature_degree( + a.set_singular_quadrature_degree( (ReferenceCellType::Triangle, ReferenceCellType::Triangle), 4, ); diff --git a/pyproject.toml b/pyproject.toml index 318e317c..abe1dfa6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [ "ndelement", "ndgrid" ] -packages = ["bempp"] +packages = ["bempp", "bempp.assembly"] [project.urls] homepage = "https://github.com/bempp/bempp-rs" diff --git a/python/bempp/__init__.py b/python/bempp/__init__.py index 1cffbb27..6b92b118 100644 --- a/python/bempp/__init__.py +++ b/python/bempp/__init__.py @@ -1,3 +1,3 @@ """Bempp.""" -from bempp import function_space +from bempp import function_space, assembly diff --git a/python/bempp/assembly/__init__.py b/python/bempp/assembly/__init__.py new file mode 100644 index 00000000..205f2856 --- /dev/null +++ b/python/bempp/assembly/__init__.py @@ -0,0 +1,3 @@ +"""Assembly.""" + +from bempp.assembly import boundary diff --git a/python/bempp/assembly/boundary.py b/python/bempp/assembly/boundary.py new file mode 100644 index 00000000..afea702a --- /dev/null +++ b/python/bempp/assembly/boundary.py @@ -0,0 +1,112 @@ +"""Boundary assembly.""" + +import typing +import numpy as np +from bempp._bempprs import lib as _lib +from ndelement.reference_cell import ReferenceCellType +from enum import Enum +from _cffi_backend import _CDataBase + +_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 + AdjointDoubleLayer = 2 + Hypersingular = 3 + ElectricField = 4 + MagneticField = 5 + + +class BoundaryAssembler(object): + """Boundary 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_boundary_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.boundary_assembler_has_quadrature_degree(self._rs_assembler, cell.value): + raise ValueError(f"Invalid cell type: {cell}") + _lib.boundary_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.boundary_assembler_has_quadrature_degree(self._rs_assembler, cell.value): + raise ValueError(f"Invalid cell type: {cell}") + return _lib.boundary_assembler_quadrature_degree(self._rs_assembler, cell.value) + + def set_singular_quadrature_degree( + self, cell0: ReferenceCellType, cell1: ReferenceCellType, degree: int + ): + """Set the singular quadrature degree for a cell type.""" + if not _lib.boundary_assembler_has_singular_quadrature_degree( + self._rs_assembler, cell0.value, cell1.value + ): + raise ValueError(f"Invalid cell pair: {cell0} and {cell1}") + _lib.boundary_assembler_set_singular_quadrature_degree( + self._rs_assembler, cell0.value, cell1.value, degree + ) + + def singular_quadrature_degree(self, cell0: ReferenceCellType, cell1: ReferenceCellType) -> int: + """Get the singular_quadrature degree for a cell type.""" + if not _lib.boundary_assembler_has_singular_quadrature_degree( + self._rs_assembler, cell0.value, cell1.value + ): + raise ValueError(f"Invalid cell pair: {cell0} and {cell1}") + return _lib.boundary_assembler_singular_quadrature_degree( + self._rs_assembler, cell0.value, cell1.value + ) + + def set_batch_size(self, batch_size: int): + """Set the batch size.""" + _lib.boundary_assembler_set_batch_size(self._rs_assembler, batch_size) + + @property + def batch_size(self) -> int: + """Get the batch size.""" + return _lib.boundary_assembler_batch_size(self._rs_assembler) + + @property + def dtype(self): + """Data type.""" + return _dtypes[_lib.boundary_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 BoundaryAssembler( + _lib.laplace_boundary_assembler_new(operator_type.value, _dtype_value(dtype)) + ) diff --git a/python/bempp/function_space.py b/python/bempp/function_space.py index c6b8a9a3..ad15b76d 100644 --- a/python/bempp/function_space.py +++ b/python/bempp/function_space.py @@ -9,6 +9,7 @@ from ndgrid.ownership import Owned, Ghost from ndelement.ciarlet import ElementFamily, CiarletElement from ndelement.reference_cell import ReferenceCellType +from _cffi_backend import _CDataBase _dtypes = { 0: np.float32, @@ -23,13 +24,15 @@ class FunctionSpace(object): """Function space.""" - def __init__(self, rs_space): + def __init__(self, rs_space: _CDataBase, owned: bool = True): """Initialise.""" self._rs_space = rs_space + self._owned = True def __del__(self): """Delete.""" - _lib.free_space(self._rs_space) + if self._owned: + _lib.free_space(self._rs_space) def element(self, entity: ReferenceCellType) -> CiarletElement: """Get the grid that this space is defined on.""" diff --git a/python/test/test_boundary_assembler.py b/python/test/test_boundary_assembler.py new file mode 100644 index 00000000..3211af28 --- /dev/null +++ b/python/test/test_boundary_assembler.py @@ -0,0 +1,37 @@ +import pytest +import numpy as np +from ndelement.reference_cell import ReferenceCellType +from bempp.assembly.boundary import OperatorType, create_laplace_assembler + + +@pytest.mark.parametrize( + "otype", + [ + OperatorType.SingleLayer, + OperatorType.DoubleLayer, + OperatorType.AdjointDoubleLayer, + OperatorType.Hypersingular, + ], +) +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.singular_quadrature_degree(ReferenceCellType.Triangle, ReferenceCellType.Triangle) != 3 + a.set_singular_quadrature_degree(ReferenceCellType.Triangle, ReferenceCellType.Triangle, 3) + assert a.singular_quadrature_degree(ReferenceCellType.Triangle, ReferenceCellType.Triangle) == 3 + with pytest.raises(ValueError): + a.set_singular_quadrature_degree(ReferenceCellType.Interval, ReferenceCellType.Interval, 3) + + 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/boundary.rs b/src/assembly/boundary.rs index 6162d01b..e3ab7598 100644 --- a/src/assembly/boundary.rs +++ b/src/assembly/boundary.rs @@ -1,7 +1,7 @@ //! Assembly of boundary operators mod assemblers; pub(crate) mod cell_pair_assemblers; -mod integrands; +pub mod integrands; pub use assemblers::BoundaryAssembler; diff --git a/src/assembly/boundary/assemblers.rs b/src/assembly/boundary/assemblers.rs index 7453a0c7..20170a37 100644 --- a/src/assembly/boundary/assemblers.rs +++ b/src/assembly/boundary/assemblers.rs @@ -484,12 +484,17 @@ 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).map(|i| *i) + } + /// Set singular quadrature degree for a pair of cell types - pub fn singular_quadrature_degree( + pub fn set_singular_quadrature_degree( &mut self, cells: (ReferenceCellType, ReferenceCellType), degree: usize, @@ -501,11 +506,27 @@ impl< .unwrap() = degree; } + /// Get singular quadrature degree for a pair of cell types + pub fn singular_quadrature_degree( + &self, + cells: (ReferenceCellType, ReferenceCellType), + ) -> Option { + self.options + .singular_quadrature_degrees + .get(&cells) + .map(|i| *i) + } + /// 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 + } + /// Assemble the singular contributions fn assemble_singular + Sync>( &self, diff --git a/src/assembly/boundary/integrands.rs b/src/assembly/boundary/integrands.rs index 8b552761..18356253 100644 --- a/src/assembly/boundary/integrands.rs +++ b/src/assembly/boundary/integrands.rs @@ -27,6 +27,7 @@ pub struct BoundaryIntegrandSum< impl, I1: BoundaryIntegrand> BoundaryIntegrandSum { + /// Create new pub fn new(integrand0: I0, integrand1: I1) -> Self { Self { integrand0, @@ -63,6 +64,7 @@ pub struct BoundaryIntegrandScalarProduct> BoundaryIntegrandScalarProduct { + /// Create new pub fn new(scalar: T, integrand: I) -> Self { Self { scalar, integrand } } diff --git a/src/assembly/boundary/integrands/adjoint_double_layer.rs b/src/assembly/boundary/integrands/adjoint_double_layer.rs index 1cd6d0c9..ea2fcd97 100644 --- a/src/assembly/boundary/integrands/adjoint_double_layer.rs +++ b/src/assembly/boundary/integrands/adjoint_double_layer.rs @@ -2,11 +2,13 @@ use crate::traits::{Access1D, Access2D, BoundaryIntegrand, GeometryAccess}; use rlst::RlstScalar; +/// Integrand for an adjoint double layer boundary operator pub struct AdjointDoubleLayerBoundaryIntegrand { _t: std::marker::PhantomData, } impl AdjointDoubleLayerBoundaryIntegrand { + /// Create new pub fn new() -> Self { Self { _t: std::marker::PhantomData, diff --git a/src/assembly/boundary/integrands/double_layer.rs b/src/assembly/boundary/integrands/double_layer.rs index 01979a43..cc1b2fed 100644 --- a/src/assembly/boundary/integrands/double_layer.rs +++ b/src/assembly/boundary/integrands/double_layer.rs @@ -2,11 +2,13 @@ use crate::traits::{Access1D, Access2D, BoundaryIntegrand, GeometryAccess}; use rlst::RlstScalar; +/// Integrand for a double layer boundary operator pub struct DoubleLayerBoundaryIntegrand { _t: std::marker::PhantomData, } impl DoubleLayerBoundaryIntegrand { + /// Create new pub fn new() -> Self { Self { _t: std::marker::PhantomData, diff --git a/src/assembly/boundary/integrands/hypersingular.rs b/src/assembly/boundary/integrands/hypersingular.rs index ae77f61c..478bdf2f 100644 --- a/src/assembly/boundary/integrands/hypersingular.rs +++ b/src/assembly/boundary/integrands/hypersingular.rs @@ -2,11 +2,13 @@ use crate::traits::{Access1D, Access2D, BoundaryIntegrand, GeometryAccess}; use rlst::RlstScalar; +/// Integrand for the curl curl term of a hypersingular boundary operator pub struct HypersingularCurlCurlBoundaryIntegrand { _t: std::marker::PhantomData, } impl HypersingularCurlCurlBoundaryIntegrand { + /// Create new pub fn new() -> Self { Self { _t: std::marker::PhantomData, @@ -52,11 +54,13 @@ unsafe impl BoundaryIntegrand for HypersingularCurlCurlBoundaryIn } } +/// Integrand for the normal normal term of a hypersingular boundary operator pub struct HypersingularNormalNormalBoundaryIntegrand { _t: std::marker::PhantomData, } impl HypersingularNormalNormalBoundaryIntegrand { + /// Create new pub fn new() -> Self { Self { _t: std::marker::PhantomData, diff --git a/src/assembly/boundary/integrands/single_layer.rs b/src/assembly/boundary/integrands/single_layer.rs index 600c1b05..458477ac 100644 --- a/src/assembly/boundary/integrands/single_layer.rs +++ b/src/assembly/boundary/integrands/single_layer.rs @@ -2,11 +2,13 @@ use crate::traits::{Access1D, Access2D, BoundaryIntegrand, GeometryAccess}; use rlst::RlstScalar; +/// Integrand for a single layer boundary operator pub struct SingleLayerBoundaryIntegrand { _t: std::marker::PhantomData, } impl SingleLayerBoundaryIntegrand { + /// Create new pub fn new() -> Self { Self { _t: std::marker::PhantomData, diff --git a/src/bindings.rs b/src/bindings.rs index dbcabf12..ede6b87c 100644 --- a/src/bindings.rs +++ b/src/bindings.rs @@ -12,11 +12,16 @@ pub enum DType { C64 = 3, } -#[derive(Debug, PartialEq, Clone, Copy)] -#[repr(u8)] -pub enum RealDType { - F32 = 0, - F64 = 1, +impl DType { + fn from(value: u8) -> Option { + match value { + 0 => Some(DType::F32), + 1 => Some(DType::F64), + 2 => Some(DType::C32), + 3 => Some(DType::C64), + _ => None, + } + } } mod function { @@ -663,3 +668,1689 @@ mod function { } } } + +mod assembly { + use super::DType; + use crate::{ + assembly::boundary::integrands::{ + AdjointDoubleLayerBoundaryIntegrand, BoundaryIntegrandScalarProduct, + BoundaryIntegrandSum, DoubleLayerBoundaryIntegrand, + HypersingularCurlCurlBoundaryIntegrand, HypersingularNormalNormalBoundaryIntegrand, + SingleLayerBoundaryIntegrand, + }, + assembly::boundary::BoundaryAssembler, + assembly::kernels::KernelEvaluator, + traits::{BoundaryIntegrand, KernelEvaluator as KernelEvaluatorTrait}, + }; + use green_kernels::{helmholtz_3d::Helmholtz3dKernel, laplace_3d::Laplace3dKernel}; + use ndelement::types::ReferenceCellType; + use rlst::{c32, c64, MatrixInverse, RlstScalar}; + use std::ffi::c_void; + + type LaplaceHypersingularBoundaryIntegrand = HypersingularCurlCurlBoundaryIntegrand; + type HelmholtzHypersingularBoundaryIntegrand = BoundaryIntegrandSum< + T, + HypersingularCurlCurlBoundaryIntegrand, + BoundaryIntegrandScalarProduct>, + >; + + #[derive(Debug, PartialEq, Clone, Copy)] + #[repr(u8)] + pub enum BoundaryOperator { + SingleLayer = 0, + DoubleLayer = 1, + AdjointDoubleLayer = 2, + Hypersingular = 3, + ElectricField = 4, + MagneticField = 5, + } + + impl BoundaryOperator { + fn from(value: u8) -> Option { + match value { + 0 => Some(BoundaryOperator::SingleLayer), + 1 => Some(BoundaryOperator::DoubleLayer), + 2 => Some(BoundaryOperator::AdjointDoubleLayer), + 3 => Some(BoundaryOperator::Hypersingular), + 4 => Some(BoundaryOperator::ElectricField), + 5 => Some(BoundaryOperator::MagneticField), + _ => None, + } + } + } + + #[derive(Debug, PartialEq, Clone, Copy)] + #[repr(u8)] + pub enum KernelType { + Laplace = 0, + Helmholtz = 1, + } + + #[repr(C)] + pub struct BoundaryAssemblerWrapper { + pub assembler: *const c_void, + pub itype: BoundaryOperator, + pub ktype: KernelType, + pub dtype: DType, + } + impl Drop for BoundaryAssemblerWrapper { + fn drop(&mut self) { + let Self { + assembler, + itype, + ktype, + dtype, + } = self; + match ktype { + KernelType::Laplace => match itype { + BoundaryOperator::SingleLayer => match dtype { + DType::F32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + f32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::F64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + f64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match dtype { + DType::F32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + f32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::F64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + f64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match dtype { + DType::F32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + f32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::F64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + f64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match dtype { + DType::F32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + f32, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::F64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + f64, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + KernelType::Helmholtz => match itype { + BoundaryOperator::SingleLayer => match dtype { + DType::C32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + c32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::C64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + c64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match dtype { + DType::C32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + c32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::C64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + c64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match dtype { + DType::C32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + c32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::C64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + c64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match dtype { + DType::C32 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + c32, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + DType::C64 => drop(unsafe { + Box::from_raw( + *assembler + as *mut BoundaryAssembler< + c64, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >, + ) + }), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + } + } + } + + #[no_mangle] + pub unsafe extern "C" fn free_boundary_assembler(a: *mut BoundaryAssemblerWrapper) { + assert!(!a.is_null()); + unsafe { drop(Box::from_raw(a)) } + } + + pub(crate) unsafe fn extract_boundary_assembler< + T: RlstScalar + MatrixInverse, + Integrand: BoundaryIntegrand, + Kernel: KernelEvaluatorTrait, + >( + assembler: *const BoundaryAssemblerWrapper, + ) -> *const BoundaryAssembler { + (*assembler).assembler as *const BoundaryAssembler + } + + pub(crate) unsafe fn extract_boundary_assembler_mut< + T: RlstScalar + MatrixInverse, + Integrand: BoundaryIntegrand, + Kernel: KernelEvaluatorTrait, + >( + assembler: *const BoundaryAssemblerWrapper, + ) -> *mut BoundaryAssembler { + (*assembler).assembler as *mut BoundaryAssembler + } + + #[no_mangle] + pub unsafe extern "C" fn boundary_assembler_has_quadrature_degree( + assembler: *mut BoundaryAssemblerWrapper, + cell: u8, + ) -> bool { + let cell = ReferenceCellType::from(cell).unwrap(); + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_boundary_assembler::< + f64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_boundary_assembler::< + f64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_boundary_assembler::< + f64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_boundary_assembler::< + f64, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + KernelType::Helmholtz => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_boundary_assembler::< + c64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_boundary_assembler::< + c64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_boundary_assembler::< + c64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_boundary_assembler::< + c64, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + } + .is_some() + } + + #[no_mangle] + pub unsafe extern "C" fn boundary_assembler_set_quadrature_degree( + assembler: *mut BoundaryAssemblerWrapper, + cell: u8, + degree: usize, + ) { + let cell = ReferenceCellType::from(cell).unwrap(); + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + KernelType::Helmholtz => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_quadrature_degree(cell, degree), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + } + } + + #[no_mangle] + pub unsafe extern "C" fn boundary_assembler_quadrature_degree( + assembler: *mut BoundaryAssemblerWrapper, + cell: u8, + ) -> usize { + let cell = ReferenceCellType::from(cell).unwrap(); + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_boundary_assembler::< + f64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_boundary_assembler::< + f64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_boundary_assembler::< + f64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::F64 => (*extract_boundary_assembler::< + f64, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + KernelType::Helmholtz => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_boundary_assembler::< + c64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_boundary_assembler::< + c64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_boundary_assembler::< + c64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + DType::C64 => (*extract_boundary_assembler::< + c64, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .quadrature_degree(cell), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + } + .unwrap() + } + + #[no_mangle] + pub unsafe extern "C" fn boundary_assembler_has_singular_quadrature_degree( + assembler: *mut BoundaryAssemblerWrapper, + cell0: u8, + cell1: u8, + ) -> bool { + let cells = ( + ReferenceCellType::from(cell0).unwrap(), + ReferenceCellType::from(cell1).unwrap(), + ); + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::F64 => (*extract_boundary_assembler::< + f64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::F64 => (*extract_boundary_assembler::< + f64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::F64 => (*extract_boundary_assembler::< + f64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::F64 => (*extract_boundary_assembler::< + f64, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + KernelType::Helmholtz => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::C64 => (*extract_boundary_assembler::< + c64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::C64 => (*extract_boundary_assembler::< + c64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::C64 => (*extract_boundary_assembler::< + c64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::C64 => (*extract_boundary_assembler::< + c64, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + } + .is_some() + } + + #[no_mangle] + pub unsafe extern "C" fn boundary_assembler_set_singular_quadrature_degree( + assembler: *mut BoundaryAssemblerWrapper, + cell0: u8, + cell1: u8, + degree: usize, + ) { + let cells = ( + ReferenceCellType::from(cell0).unwrap(), + ReferenceCellType::from(cell1).unwrap(), + ); + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + KernelType::Helmholtz => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_singular_quadrature_degree(cells, degree), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + } + } + + #[no_mangle] + pub unsafe extern "C" fn boundary_assembler_singular_quadrature_degree( + assembler: *mut BoundaryAssemblerWrapper, + cell0: u8, + cell1: u8, + ) -> usize { + let cells = ( + ReferenceCellType::from(cell0).unwrap(), + ReferenceCellType::from(cell1).unwrap(), + ); + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::F64 => (*extract_boundary_assembler::< + f64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::F64 => (*extract_boundary_assembler::< + f64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::F64 => (*extract_boundary_assembler::< + f64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::F64 => (*extract_boundary_assembler::< + f64, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + KernelType::Helmholtz => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::C64 => (*extract_boundary_assembler::< + c64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::C64 => (*extract_boundary_assembler::< + c64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::C64 => (*extract_boundary_assembler::< + c64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + DType::C64 => (*extract_boundary_assembler::< + c64, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .singular_quadrature_degree(cells), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + } + .unwrap() + } + + #[no_mangle] + pub unsafe extern "C" fn boundary_assembler_set_batch_size( + assembler: *mut BoundaryAssemblerWrapper, + batch_size: usize, + ) { + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler_mut::< + f32, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::F64 => (*extract_boundary_assembler_mut::< + f64, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + KernelType::Helmholtz => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler_mut::< + c32, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + DType::C64 => (*extract_boundary_assembler_mut::< + c64, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .set_batch_size(batch_size), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + } + } + + #[no_mangle] + pub unsafe extern "C" fn boundary_assembler_batch_size( + assembler: *mut BoundaryAssemblerWrapper, + ) -> usize { + match (*assembler).ktype { + KernelType::Laplace => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::F64 => (*extract_boundary_assembler::< + f64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::F64 => (*extract_boundary_assembler::< + f64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::F64 => (*extract_boundary_assembler::< + f64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::F32 => (*extract_boundary_assembler::< + f32, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::F64 => (*extract_boundary_assembler::< + f64, + LaplaceHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + KernelType::Helmholtz => match (*assembler).itype { + BoundaryOperator::SingleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::C64 => (*extract_boundary_assembler::< + c64, + SingleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::DoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::C64 => (*extract_boundary_assembler::< + c64, + DoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::AdjointDoubleLayer => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::C64 => (*extract_boundary_assembler::< + c64, + AdjointDoubleLayerBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + BoundaryOperator::Hypersingular => match (*assembler).dtype { + DType::C32 => (*extract_boundary_assembler::< + c32, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + DType::C64 => (*extract_boundary_assembler::< + c64, + HelmholtzHypersingularBoundaryIntegrand, + KernelEvaluator>, + >(assembler)) + .batch_size(), + _ => { + panic!("Invalid data type"); + } + }, + _ => { + panic!("Invalid operator"); + } + }, + } + } + + #[no_mangle] + pub unsafe extern "C" fn boundary_assembler_dtype( + assembler: *mut BoundaryAssemblerWrapper, + ) -> u8 { + (*assembler).dtype as u8 + } + + unsafe fn laplace_boundary_assembler_new_internal( + operator: BoundaryOperator, + dtype: DType, + ) -> *const BoundaryAssemblerWrapper { + Box::into_raw(Box::new(BoundaryAssemblerWrapper { + assembler: match operator { + BoundaryOperator::SingleLayer => Box::into_raw(Box::new( + BoundaryAssembler::::new_laplace_single_layer(), + )) as *const c_void, + BoundaryOperator::DoubleLayer => Box::into_raw(Box::new( + BoundaryAssembler::::new_laplace_double_layer(), + )) as *const c_void, + BoundaryOperator::AdjointDoubleLayer => Box::into_raw(Box::new( + BoundaryAssembler::::new_laplace_adjoint_double_layer(), + )) as *const c_void, + BoundaryOperator::Hypersingular => Box::into_raw(Box::new( + BoundaryAssembler::::new_laplace_hypersingular(), + )) as *const c_void, + _ => { + panic!("Invalid operator"); + } + }, + itype: operator, + ktype: KernelType::Laplace, + dtype, + })) + } + + #[no_mangle] + pub unsafe extern "C" fn laplace_boundary_assembler_new( + operator: u8, + dtype: u8, + ) -> *const BoundaryAssemblerWrapper { + let operator = BoundaryOperator::from(operator).unwrap(); + let dtype = DType::from(dtype).unwrap(); + match dtype { + DType::F32 => laplace_boundary_assembler_new_internal::(operator, dtype), + DType::F64 => laplace_boundary_assembler_new_internal::(operator, dtype), + // DType::C32 => laplace_boundary_assembler_new_internal::(operator, dtype), + // DType::C64 => laplace_boundary_assembler_new_internal::(operator, dtype), + _ => { + panic!("Invalid data type"); + } + } + } + + unsafe fn helmholtz_boundary_assembler_new_internal< + T: RlstScalar + MatrixInverse, + >( + wavenumber: T::Real, + operator: BoundaryOperator, + dtype: DType, + ) -> *const BoundaryAssemblerWrapper { + Box::into_raw(Box::new(BoundaryAssemblerWrapper { + assembler: match operator { + BoundaryOperator::SingleLayer => Box::into_raw(Box::new( + BoundaryAssembler::::new_helmholtz_single_layer(wavenumber), + )) as *const c_void, + BoundaryOperator::DoubleLayer => Box::into_raw(Box::new( + BoundaryAssembler::::new_helmholtz_double_layer(wavenumber), + )) as *const c_void, + BoundaryOperator::AdjointDoubleLayer => Box::into_raw(Box::new( + BoundaryAssembler::::new_helmholtz_adjoint_double_layer(wavenumber), + )) as *const c_void, + BoundaryOperator::Hypersingular => Box::into_raw(Box::new( + BoundaryAssembler::::new_helmholtz_hypersingular(wavenumber), + )) as *const c_void, + _ => { + panic!("Invalid operator"); + } + }, + itype: operator, + ktype: KernelType::Helmholtz, + dtype, + })) + } + + #[no_mangle] + pub unsafe extern "C" fn helmholtz_boundary_assembler_new( + wavenumber: *const c_void, + operator: u8, + dtype: u8, + ) -> *const BoundaryAssemblerWrapper { + let operator = BoundaryOperator::from(operator).unwrap(); + let dtype = DType::from(dtype).unwrap(); + match dtype { + DType::C32 => helmholtz_boundary_assembler_new_internal::( + *(wavenumber as *const f32), + operator, + dtype, + ), + DType::C64 => helmholtz_boundary_assembler_new_internal::( + *(wavenumber as *const f64), + operator, + dtype, + ), + _ => { + panic!("Invalid data type"); + } + } + } +}