Modules¶
Box Mesh Generation¶
The volume FMM operates over a box-shaped mesh generated by volumential.meshgen
. It consists of two backends: a Python one that only generates uniform mesh, and a C++ one that is capable of performing adaptive mesh refinement.
Singular Integrals¶
Transform Method¶
(2D only) use Duffy-type transforms to desingularize the integrands.
Good at special kernel types (specifically 1/r
). The main downside of this method is its
complicated control flow (inefficient to parallelize). Thus it only supports CPU multi-threading, and extra dependency dill
is needed for it.
The 2D singular integrals are computed using the transform described in http://link.springer.com/10.1007/BF00370482.
- volumential.singular_integral_2d.box_quad(func, a, b, c, d, singular_point, args=(), tol=1.49e-08, rtol=1.49e-08, maxiter=50, vec_func=True, miniter=1)[source]¶
- Computes a (tensor product) double integral, with the integrand being
singular at some point inside the region.
Integrate func on [a, b]X[c, d] using transformed Gaussian quadrature with absolute tolerance tol.
- Parameters
func (function.) – A double variable Python function or method to integrate.
a (float.) – Lower-left corner of integration region.
b (float.) – Lower-right corner of integration region.
c (float.) – Upper-left corner of integration region.
d (float.) – Upper-right corner of integration region.
singular_point (tuple(float, float)) – The singular point of the integrand func.
args (tuple, optional.) – Extra arguments to pass to function.
tol (float, optional.) – rtol Iteration stops when error between last two iterates is less than tol OR the relative change is less than rtol.
rtol (float, optional.) – Iteration stops when error between last two iterates is less than tol OR the relative change is less than rtol.
maxiter (int, optional.) – Maximum order of Gaussian quadrature.
vec_func (bool, optional.) – True if func handles arrays as arguments (is a “vector” function). Default is True.
miniter (int, optional.) – Minimum order of Gaussian quadrature.
- Returns
val: Gaussian quadrature approximation (within tolerance) to integral.
err: Difference between last two estimates of the integral.
- Return type
tuple(float,float)
Droste Method¶
Use recursive brick-shaped subdivision, combined with simple bilinear transforms. The implementation is for 2/3D, written in loopy
and is optimized to take advantage of symmetries.
- class volumential.droste.DrosteBase(integral_knl, quad_order, case_vecs, n_brick_quad_points, special_radial_quadrature, nradial_quad_points)[source]¶
Base class for Droste methods. It uses sumpy tools to cache the loopy kernel.
- integral_knl¶
The integral kernel of sumpy.kernel type.
- interaction_case_vecs¶
The relative positions of the target box for each case.
- interaction_case_scls¶
The relative sizes of the target box for each case.
- special_radial_quadrature¶
If True, the radial direction uses a different quadrature rule. The radial direction is identified with the condition
ibrick_axis == iaxis
and always uses inameq0
.
- codegen_basis_eval(iaxis)[source]¶
Generate instructions to evaluate Chebyshev polynomial basis. (Chebyshev polynomials of the first kind T_n).
- class volumential.droste.DrosteFull(integral_knl, quad_order, case_vecs, n_brick_quad_points=50, special_radial_quadrature=False, nradial_quad_points=None)[source]¶
Build the full table directly.
- class volumential.droste.DrosteReduced(integral_knl=None, quad_order=None, case_vecs=None, n_brick_quad_points=50, knl_symmetry_tags=None, special_radial_quadrature=False, nradial_quad_points=None)[source]¶
Reduce the workload by only building part of the table and infer the rest of the table by symmetry.
- call_loopy_kernel_case(queue, base_case_id, **kwargs)[source]¶
Call the table builder on one base case, as given in :self.current_base_case: :arg source_box_extent :arg alpha :arg nlevels :arg extra_kernel_kwargs
- get_kernel(**kwargs)[source]¶
Reduced Droste is a 2-staged algorithm. The first stage uses the kernel from DrosteBase to build part of the table. In the second stage, an expansion kernel is called to fill the empty entries.
- class volumential.droste.InverseDrosteReduced(integral_knl, quad_order, case_vecs, n_brick_quad_points=50, knl_symmetry_tags=None, special_radial_quadrature=False, nradial_quad_points=None, auto_windowing=True)[source]¶
A variant of the Droste method. Instead of computing a volume potential, it computes the “inverse” to a Riesz potential, aka a “fractional Laplacian”.
Specifically, given an integral kernel G(r), this class supports the precomputation for integrals of the form
\[\int_B G(r) (u(x) - u(y)) dy\]For k-dimensional fractional Laplacian, \(G(r) = \frac{1}{r^{k+2s}}\).
The core part of concern (that is to be modified based on DrosteReduces):
... for BASIS_VARS, TGT_VARS, icase for ilevel for ibrick_axis, ibrick_side, QUAD_VARS PREPARE_BASIS_VALS <> density_val = DENSITY_VAL_ASSIGNMENT \ {id=density,dep=basis_evals} end end end ...
- call_loopy_kernel_case(queue, base_case_id, **kwargs)[source]¶
Call the table builder on one base case, as given in :self.current_base_case: :arg source_box_extent :arg alpha :arg delta :arg nlevels :arg extra_kernel_kwargs
- codegen_basis_tgt_eval(iaxis)[source]¶
Generate instructions to evaluate Chebyshev polynomial basis at the target point, given that the target point lies in the source box. (Chebyshev polynomials of the first kind T_n).
If the target point is not in the source box, the concerned instructions will return 0.
- codegen_der2_basis_tgt_eval(iaxis)[source]¶
Generate instructions to evaluate the second order derivatives of Chebyshev polynomial basis at the target point, given that the target lies in the source box. (Chebyshev polynomials of the first kind T_n).
If the target point is not in the source box, the concerned instructions will return 0.
The evaluation is based on Chebyshev polynomials of the second kind \(U_n\).
\[\frac{d^2 T_n}{dx^2} = n \frac{(n+1)T_n - U_n}{x^2 - 1}\]
Near-Field Tabulation¶
Symmetry Discovery¶
The set of symmetry operations that can be used to speed up precomputation depends on the dimension and symmetry properties of the kernel (e.g., is it a fundamental solution kernel or one of its derivatives?).
Interaction Enumeration¶
This module enumerates the set of interaction cases that could possibly happen in list1.
Table Lookup (Deprecated)¶
This module produces table lookup schemes given information about the kernel and the table data format. The module is deprecated in favor of volumential.nearfield_potential_table
and volumential.table_manager
.
- class volumential.list1.NearFieldEvalBase(integral_kernel, table_data_shapes, potential_kind=1, options=[], name=None, device=None, **kwargs)[source]¶
Base class of near-field evalulator.
- class volumential.list1.NearFieldFromCSR(integral_kernel, table_data_shapes, potential_kind=1, options=[], name=None, device=None, **kwargs)[source]¶
Evaluate the near-field potentials from CSR representation of the tree. The class supports auto-scaling of simple kernels.
- class volumential.list1.NearFieldEvalBase(integral_kernel, table_data_shapes, potential_kind=1, options=[], name=None, device=None, **kwargs)[source]¶
Base class of near-field evalulator.
- class volumential.list1.NearFieldFromCSR(integral_kernel, table_data_shapes, potential_kind=1, options=[], name=None, device=None, **kwargs)[source]¶
Evaluate the near-field potentials from CSR representation of the tree. The class supports auto-scaling of simple kernels.
Warning
Use volumential.nearfield_potential_table
and volumential.table_manager
instead! volumential.list1
is deprecated and will be removed in the future.
Table and Table Manager¶
The tables are stored in hdf5
format and managed through NearFieldInteractionTableManager
.
- class volumential.nearfield_potential_table.NearFieldInteractionTable(quad_order, method='gauss-legendre', dim=2, kernel_func=None, kernel_type=None, sumpy_kernel=None, build_method=None, source_box_extent=1, dtype=<class 'numpy.float64'>, inverse_droste=False, progress_bar=True, **kwargs)[source]¶
Class for a near-field interaction table.
A near-field interaction table stores precomputed singular integrals on template boxes and supports transforms to actual boxes on lookup. The query process is done through scaling the entries based on actual box sized.
Orientations are ordered counter-clockwise.
A template box is one of [0,1]^dim
- build_kernel_exterior_normalizer_table(cl_ctx, queue, pool=None, ncpus=None, mesh_order=5, quad_order=10, mesh_size=0.03, remove_tmp_files=True, **kwargs)[source]¶
Build the kernel exterior normalizer table for fractional Laplacians.
An exterior normalizer for kernel \(G(r)\) and target \(x\) is defined as
\[\int_{B^c} G(\lVert x - y \rVert) dy\]where \(B\) is the source box \([0, source_box_extent]^dim\).
- build_normalizer_table(pool=None, pb=None)[source]¶
Build normalizers, used for log-scaled kernels, currently only supported in 2D.
- build_table_via_transform()[source]¶
Build the full data table using transforms to remove the singularity.
- compute_table_entry(entry_id)[source]¶
Compute one entry in the table indexed by self.data[entry_id]
Input kernel function should be centered at origin.
- find_target_point(target_point_index, case_index)[source]¶
Apply proper transforms to find the target point’s coordinate.
Only translations and scalings are allowed in this step, avoiding the indices of quad points to be messed up.
- get_mode_cheb_coeffs(mode_index, cheb_order)[source]¶
Cheb coeffs of a mode. The projection process is performed on [0,1]^dim.
- get_potential_scaler(entry_id, source_box_size=1, kernel_type=None, kernel_power=None)[source]¶
Returns a helper function to rescale the table entry based on source_box’s actual size (edge length).
- class volumential.table_manager.NearFieldInteractionTableManager(dataset_filename='nft.hdf5', root_extent=1, dtype=<class 'numpy.float64'>, read_only='auto', **kwargs)[source]¶
A class that manages near field interaction table computation and storage.
Tables are stored under ‘Dimension/KernelName/QuadOrder/BoxLevel/dataset_name’ e.g., ‘2D/Laplace/Order_1/Level_0/data’
Only one table manager can exist for a dataset file with write access. The access can be controlled with the read_only argument. By default, the constructor tries to open the dataset with write access, and falls back to read-only if that fails.
- compute_and_update_table(dim, kernel_type, q_order, source_box_level=0, compute_method=None, cl_ctx=None, queue=None, **kwargs)[source]¶
Performs the precomputation and stores the results.
- get_kernel_function(dim, kernel_type, **kwargs)[source]¶
Kernel function is needed for building the table. This function provides support for some kernels such that the user can build and use the table without explicitly providing such information.
- get_kernel_function_type(dim, kernel_type)[source]¶
Determines how and to what extend the table data can be rescaled and reused.
- get_table(dim, kernel_type, q_order, source_box_level=0, force_recompute=False, compute_method=None, queue=None, **kwargs)[source]¶
Primary user interface. Get the specified table regardless of how. In the case of a cache miss or a forced re-computation, the method specified in the compute_method will be used.
Multipole/Local Expansions¶
- class volumential.expansion_wrangler_fpnd.FPNDExpansionWrangler(code_container, queue, tree, near_field_table, dtype, fmm_level_to_order, quad_order, potential_kind=1, source_extra_kwargs=None, kernel_extra_kwargs=None, self_extra_kwargs=None, list1_extra_kwargs=None)[source]¶
The default wrangler class.
- class volumential.expansion_wrangler_fpnd.FPNDExpansionWranglerCodeContainer(cl_context, multipole_expansion_factory, local_expansion_factory, target_kernels, exclude_self=False, use_rscale=None, strength_usage=None, source_kernels=None)[source]¶
The default code container.
- class volumential.expansion_wrangler_fpnd.FPNDFMMLibExpansionWrangler(code_container, queue, tree, near_field_table, dtype, fmm_level_to_order, quad_order, potential_kind=1, source_extra_kwargs=None, kernel_extra_kwargs=None, self_extra_kwargs=None, list1_extra_kwargs=None, *args, **kwargs)[source]¶
This expansion wrangler uses “fpnd” strategy. That is, Far field is computed via Particle approximation and Near field is computed Directly. The FMM is performed using FMMLib backend.
- source_extra_kwargs¶
Keyword arguments to be passed to interactions that involve the source field.
- kernel_extra_kwargs¶
Keyword arguments to be passed to interactions that involve expansions, but not the source field.
Much of this class is borrowed from pytential.qbx.fmmlib.
- coarsen_multipoles(level_start_source_parent_box_nrs, source_parent_boxes, mpoles)[source]¶
For each box in source_parent_boxes, gather (and translate) the box’s children’s multipole expansions in mpoles and add the resulting expansion into the box’s multipole expansion in mpoles.
- Returns
mpoles
- eval_direct(target_boxes, neighbor_source_boxes_starts, neighbor_source_boxes_lists, mode_coefs)[source]¶
For each box in target_boxes, evaluate the influence of the neighbor sources due to src_weights
This step amounts to looking up the corresponding entries in a pre-built table.
- Returns
a new potential array, see
output_zeros()
.
- eval_locals(level_start_target_box_nrs, target_boxes, local_exps)[source]¶
For each box in target_boxes, evaluate the local expansion in local_exps and return a new potential array.
- Returns
a new potential array, see
output_zeros()
.
- eval_multipoles(target_boxes_by_source_level, source_boxes_by_level, mpole_exps)[source]¶
For each box in target_boxes, evaluate the multipole expansion in mpole_exps in the nearby boxes given in starts and lists, and return a new potential array.
- Returns
a new potential array, see
output_zeros()
.
- finalize_potentials(potentials)[source]¶
Postprocess the reordered potentials. This is where global scaling factors could be applied.
- form_locals(level_start_target_or_target_parent_box_nrs, target_or_target_parent_boxes, starts, lists, src_weights)[source]¶
For each box in target_or_target_parent_boxes, form local expansions due to the sources in the nearby boxes given in starts and lists, and return a new local expansion array.
- Returns
a new local expansion array
- form_multipoles(level_start_source_box_nrs, source_boxes, src_weights)[source]¶
Return an expansions array containing multipole expansions in source_boxes due to sources with src_weights.
- multipole_to_local(level_start_target_box_nrs, target_boxes, src_box_starts, src_box_lists, mpole_exps)[source]¶
For each box in target_or_target_parent_boxes, translate and add the influence of the multipole expansion in mpole_exps into a new array of local expansions.
- Returns
a new (local) expansion array.
- refine_locals(level_start_target_or_target_parent_box_nrs, target_or_target_parent_boxes, local_exps)[source]¶
For each box in child_boxes, translate the box’s parent’s local expansion in local_exps and add the resulting expansion into the box’s local expansion in local_exps.
- Returns
local_exps
- reorder_potentials(potentials)[source]¶
Return a copy of potentials in user target order. source_weights is in tree target order.
- class volumential.expansion_wrangler_fpnd.FPNDFMMLibExpansionWranglerCodeContainer(cl_context, multipole_expansion_factory, local_expansion_factory, target_kernels, exclude_self=True, *args, **kwargs)[source]¶
Objects of this type serve as a place to keep the code needed for ExpansionWrangler if it is using fmmlib to perform multipole expansion and manipulations.
The interface is augmented with unecessary arguments acting as placeholders, such that it can be a drop-in replacement of sumpy backend.
- class volumential.expansion_wrangler_fpnd.FPNDSumpyExpansionWrangler(code_container, queue, tree, near_field_table, dtype, fmm_level_to_order, quad_order, potential_kind=1, source_extra_kwargs=None, kernel_extra_kwargs=None, self_extra_kwargs=None, list1_extra_kwargs=None)[source]¶
This expansion wrangler uses “fpnd” strategy. That is, Far field is computed via Particle approximation and Near field is computed Directly. The FMM is performed using sumpy backend.
- source_extra_kwargs¶
Keyword arguments to be passed to interactions that involve the source field.
- kernel_extra_kwargs¶
Keyword arguments to be passed to interactions that involve expansions, but not the source field.
- self_extra_kwargs¶
Keyword arguments to be passed for handling self interactions (singular integrals)
- coarsen_multipoles(level_start_source_parent_box_nrs, source_parent_boxes, mpoles)[source]¶
For each box in source_parent_boxes, gather (and translate) the box’s children’s multipole expansions in mpoles and add the resulting expansion into the box’s multipole expansion in mpoles.
- Returns
mpoles
- eval_direct(target_boxes, neighbor_source_boxes_starts, neighbor_source_boxes_lists, mode_coefs)[source]¶
For each box in target_boxes, evaluate the influence of the neighbor sources due to src_weights
This step amounts to looking up the corresponding entries in a pre-built table.
- Returns
a new potential array, see
output_zeros()
.
- eval_locals(level_start_target_box_nrs, target_boxes, local_exps)[source]¶
For each box in target_boxes, evaluate the local expansion in local_exps and return a new potential array.
- Returns
a new potential array, see
output_zeros()
.
- eval_multipoles(target_boxes_by_source_level, source_boxes_by_level, mpole_exps)[source]¶
For each box in target_boxes, evaluate the multipole expansion in mpole_exps in the nearby boxes given in starts and lists, and return a new potential array.
- Returns
a new potential array, see
output_zeros()
.
- finalize_potentials(potentials)[source]¶
Postprocess the reordered potentials. This is where global scaling factors could be applied.
- form_locals(level_start_target_or_target_parent_box_nrs, target_or_target_parent_boxes, starts, lists, src_weights)[source]¶
For each box in target_or_target_parent_boxes, form local expansions due to the sources in the nearby boxes given in starts and lists, and return a new local expansion array.
- Returns
a new local expansion array
- form_multipoles(level_start_source_box_nrs, source_boxes, src_weights)[source]¶
Return an expansions array containing multipole expansions in source_boxes due to sources with src_weights.
- multipole_to_local(level_start_target_box_nrs, target_boxes, src_box_starts, src_box_lists, mpole_exps)[source]¶
For each box in target_or_target_parent_boxes, translate and add the influence of the multipole expansion in mpole_exps into a new array of local expansions.
- Returns
a new (local) expansion array.
- refine_locals(level_start_target_or_target_parent_box_nrs, target_or_target_parent_boxes, local_exps)[source]¶
For each box in child_boxes, translate the box’s parent’s local expansion in local_exps and add the resulting expansion into the box’s local expansion in local_exps.
- Returns
local_exps
- reorder_potentials(potentials)[source]¶
Return a copy of potentials in user target order. source_weights is in tree target order.
- class volumential.expansion_wrangler_fpnd.FPNDSumpyExpansionWranglerCodeContainer(cl_context, multipole_expansion_factory, local_expansion_factory, target_kernels, exclude_self=False, use_rscale=None, strength_usage=None, source_kernels=None)[source]¶
Objects of this type serve as a place to keep the code needed for ExpansionWrangler if it is using sumpy to perform multipole expansion and manipulations.
Since
SumpyExpansionWrangler
necessarily must have apyopencl.CommandQueue
, but this queue is allowed to be more ephemeral than the code, the code’s lifetime is decoupled by storing it in this object.
Volume FMM¶
The volume potential obtained from the volume FMM is over the internal box mesh. To obtain the values on your own mesh points, an interpolation method is provided. Although the interpolation is \(O(N log N)\), it is almost always indistinguishable from \(O(N)\) in practice as the geometry lookup usually takes up a very small fraction of the total runtime.
- volumential.volume_fmm.drive_volume_fmm(traversal, expansion_wrangler, src_weights, src_func, direct_evaluation=False, timing_data=None, reorder_sources=True, reorder_potentials=True, **kwargs)[source]¶
Top-level driver routine for volume potential calculation via fast multiple method.
This function, and the interface it utilizes, is adapted from boxtree/fmm.py
The fast multipole method is a two-pass algorithm:
1. During the fist (upward) pass, the multipole expansions for all boxes at all levels are formed from bottom up.
2. In the second (downward) pass, the local expansions for all boxes at all levels at formed from top down.
- Parameters
traversal – A
boxtree.traversal.FMMTraversalInfo
instance.expansion_wrangler – An object implementing the expansion wrangler interface.
src_weights – Source ‘density/weights/charges’ time quad weights.. Passed unmodified to expansion_wrangler.
src_func – Source ‘density/weights/charges’ function. Passed unmodified to expansion_wrangler.
reorder_sources – Whether sources are in user order (if True, sources are reordered into tree order before conducting FMM).
reorder_potentials – Whether potentials should be in user order (if True, potentials are reordered into user order before return).
Returns the potentials computed by expansion_wrangler.
- volumential.volume_fmm.interpolate_volume_potential(target_points, traversal, wrangler, potential, potential_in_tree_order=False, target_radii=None, lbl_lookup=None, **kwargs)[source]¶
Interpolate the volume potential, only works for tensor-product quadrature formulae. target_points and potential should be an cl array.
- Parameters
wrangler – Used only for general info (nothing sumpy kernel specific). May also be None if the needed information is passed by kwargs.
potential_in_tree_order – Whether the potential is in tree order (as opposed to in user order).
- Lbl_lookup
a
boxtree.LeavesToBallsLookup
that has the lookup information for target points. Can be None if the lookup lists are provided separately in kwargs. If it is None and no other information is provided, the lookup will be built from scratch.
- class volumential.list1.NearFieldEvalBase(integral_kernel, table_data_shapes, potential_kind=1, options=[], name=None, device=None, **kwargs)[source]¶
Base class of near-field evalulator.
- class volumential.list1.NearFieldFromCSR(integral_kernel, table_data_shapes, potential_kind=1, options=[], name=None, device=None, **kwargs)[source]¶
Evaluate the near-field potentials from CSR representation of the tree. The class supports auto-scaling of simple kernels.
Function Extension¶
The volumential.function_extension
module provides helper functions to perform source density extensions using layer potentials.
Miscellaneous Tools¶
- class volumential.tools.BoxSpecificMap[source]¶
Box-specific transform that maps between datum defined on quadrature nodes. Being box-specific means that the transform for each box is independent from the rest of the boxes.
- class volumential.tools.BoxSpecificReduction[source]¶
Box-specific reduction that maps for each box a data vector defined on the quadrature nodes to a scalar. Being box-specific means that the reductions for each box is independent from the rest of the boxes.
- class volumential.tools.DiscreteLegendreTransform(dim, degree)[source]¶
Transform from nodal values to Legendre polynomial coefficients for all cells (leaf boxes of a boxtree Tree object). It is assumed that the traversal is built over a tree where the sources and targets coincide.
- class volumential.tools.InverseDiscreteLegendreTransform[source]¶
Box-specific transform that maps box-local modal coefficients to nodal values. Inverse of
DiscreteLegendreTransform
.
- class volumential.tools.ScalarFieldExpressionEvaluation(dim, expression, variables=None, dtype=<class 'numpy.float64'>, function_manglers=None, preamble_generators=None)[source]¶
Evaluate a field funciton on a set of D-d points. Useful for imposing analytic conditions efficiently.
- volumential.tools.clean_file(filename, new_name=None)[source]¶
Remove/rename file if exists. Fails silently when the file does not exist. Useful for, for example, writing output files that are meant to overwrite existing ones.
- volumential.tools.generate_leading_order_filtering(dim, n_dofs)[source]¶
Returns a filtering vector that is an indicator function of the node that corresponds to the leading order modal values in the Fourier space.
- volumential.tools.import_code(code, name, add_to_sys_modules=True)[source]¶
Dynamically generates a module.
- Parameters
code – can be any object containing code – string, file object, or
compiled code object. Returns a new module object initialized by dynamically importing the given code and optionally adds it to sys.modules under the given name.