Field Solvers and Boundary Conditions
Choosing a Solver First
Section titled “Choosing a Solver First”| Goal | Recommended setting | Notes |
|---|---|---|
| Small mesh smoke test | field_solver = "auto" or "direct" | direct is exact but costs O(nelem) |
| Larger production run | field_solver = "fmm" | See Coulomb FMM Core Details |
| Two-periodic-axis boundary | field_bc_mode = "periodic2" and field_solver = "fmm" | Exactly two axes must be periodic |
| Accuracy checks and debugging | Compare direct and fmm on a small case | Keep mesh and particle settings identical |
In the current implementation, periodic2 is FMM-only. Treat auto as the convenient choice for small and medium field_bc_mode="free" cases.
4. Coulomb field from boundary-element charge
Section titled “4. Coulomb field from boundary-element charge”Source:
bem_field_solver,
bem_field_solver_config,
bem_field_solver_eval
4.1 Direct evaluation
Section titled “4.1 Direct evaluation”In direct mode, every element contributes directly to the field at evaluation point r.
The cost is O(nelem) per evaluation point.
As the particle step count and particle count grow, this dominates, so large-element cases use treecode or FMM.
4.2 Length normalization
Section titled “4.2 Length normalization”sim.field_normalization selects the internal length scale L0.
| Value | L0 |
|---|---|
si | 1 m |
length | sim.field_length_scale |
box | max(box_max - box_min) |
mesh | maximum width of the mesh bounding box |
Internally the solver evaluates with:
The field is converted back to SI by multiplying by k_c / L0^2; the potential is converted by k_c / L0.
Input settings and output CSV files remain in SI units.
5. Switching between direct / treecode / FMM
Section titled “5. Switching between direct / treecode / FMM”Source:
init_field_solver,
refresh_field_solver,
eval_e_field_solver,
Coulomb FMM core details
5.1 Mode selection
Section titled “5.1 Mode selection”sim.field_solver accepts:
| Value | Behavior |
|---|---|
direct | Always use direct sum |
treecode | Use octree plus monopole approximation |
fmm | Use the Coulomb FMM core |
auto | Use treecode if nelem >= tree_min_nelem, otherwise direct |
In the current implementation, periodic2 requires field_solver="fmm".
5.2 Treecode
Section titled “5.2 Treecode”The treecode partitions element centroids into an octree.
- Put all element indices in
elem_order. - Compute the AABB of element centroids in the node.
- Stop at a leaf if the element count is
leaf_maxor smaller, or if the node cannot be split. - Otherwise classify by the node center into eight octants and build child nodes recursively.
refresh_field_solver recomputes node monopoles bottom-up.
During evaluation, a node is accepted as far field from its radius R and distance d to the target point.
Accepted nodes are evaluated as monopoles. Rejected nodes are descended, and leaves use direct sum.
For nodes with strong charge cancellation, monopole error can be large; if abs(Q) < charge_cancellation_tol * sum(abs(q_i)), far-field acceptance is suppressed.
5.3 FMM
Section titled “5.3 FMM”FMM mode calls a simulator-independent Coulomb FMM core. The field-solver adapter handles:
- Convert mesh centroids to source coordinates
src_pos(3, nelem). - Build the geometry-dependent plan with
build_plan(plan, src_pos, options). - Update the charge-dependent state with
update_state(plan, state, q_elem). - Call
eval_point(plan, state, r, e)for each particle position.
For P2M / M2M / M2L / L2L / L2P details, see Coulomb FMM core details.
6. periodic2 field boundary
Section titled “6. periodic2 field boundary”Source:
bem_field_solver_config,
bem_coulomb_fmm_periodic,
bem_collision
sim.field_bc_mode="periodic2" treats exactly two of the three axes as periodic.
An axis is periodic when bc_low(axis) == bc_high(axis) == periodic.
The third axis is the open direction.
6.1 Validation
Section titled “6.1 Validation”periodic2 requires:
sim.use_box = true- exactly two periodic axes
box_max - box_min > 0for each periodic axissim.field_solver = "fmm"
field_periodic_far_correction accepts auto, none, and m2l_root_oracle.
The current implementation normalizes auto to none for compatibility.
m2l_root_oracle is a diagnostic far correction enabled only by explicit request.
6.2 Near images and far correction
Section titled “6.2 Near images and far correction”field_periodic_image_layers = N enumerates near images along the two periodic axes as:
The FMM core combines primary-cell sources and image sources for near contributions.
With m2l_root_oracle, the build stage fits a root-local correction from the Ewald residual and injects it into the root local expansion at runtime.
6.3 Collision side
Section titled “6.3 Collision side”The collision-side periodic2 logic is separate from the field-calculation FMM.
find_first_hit_periodic2 computes the needed image-shift range from the particle segment and the canonical mesh AABB, then tests the shifted segment against the base mesh.
If multiple candidates have the same t, ties are broken deterministically by element index and image shift.