Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Immersed-boundary diffusion around two touching particles

This example demonstrates the general boundary/interface conditions of the pymrm immersed boundary method (IBM): construct_ibm_normal_derivative, construct_ibm_boundary_values and apply_ibm_interface. Two solid particles of radius RR touch on the centreline of a unit square filled with fluid. Steady diffusion is driven by domain boundary conditions c=1c=1 (left) and c=0c=0 (right), with no-flux top and bottom walls.

We solve the same geometry twice:

  1. Impermeable particles -- in the fluid a homogeneous Neumann condition ∂c/∂n=0\partial c/\partial n = 0 is imposed at the particle surface, while the inside of the particles is held at a Dirichlet value. The two sides are completely decoupled: the immersed wall is a no-flux obstacle for the fluid.

  2. Conjugate interface -- the particles have their own diffusion coefficient Din≠DoutD_\mathrm{in} \ne D_\mathrm{out} and the two regions are coupled through flux and value continuity at the surface.

The machinery has three layers:

  • construct_ibm_particles -- from the analytic Circle particles it finds the wall crossings and builds the directional ghost-cell data, with exact wall positions and outward normals (info.normals); the standard IBM object it returns feeds every step below;

  • construct_ibm_normal_derivative -- builds, on each side of every crossing, a one-sided formula for the outward normal derivative at the wall, qside≈αside cΓside+∑jγjcjq_\mathrm{side} \approx \alpha_\mathrm{side}\, c_\Gamma^\mathrm{side} + \sum_j \gamma_j c_j, from generalized finite differences on same-side cells;

  • construct_ibm_boundary_values / apply_ibm_interface -- eliminate the unknown wall values cΓc_\Gamma from the given boundary/interface equations and fold the result into the operator matrix.

Sign convention: the derivatives are outward per side, i.e. qoutq_\mathrm{out} points out of the fluid (into the solid) and qinq_\mathrm{in} points out of the solid, exactly as in construct_interface_matrices for grid-aligned multi-region models.

Analytic particles, IBM data and normal-derivative operators

The two disks are Circle particles; construct_ibm_particles locates the wall crossings, computing each cut-face wall position and outward normal exactly from the owning circle. With contact='merge' the touching disks act as one connected solid (as a union level set would), so no artificial crossing is created between them. construct_ibm_normal_derivative then builds the one-sided normal-derivative operators used by both parts of this notebook; we pass length_scale=R so stencils never reach farther than a fraction of the particle radius, and normals=info.normals so they use the exact surface normals.

The contact point is a geometric stress test: the fluid gap between the particles pinches to zero width and the solid is connected through the contact. Because the normals come from the analytic circles they stay exact right at the contact; the GFD stencil still lowers its polynomial degree there where too few well-placed same-side cells are available (the degree_* diagnostics below), and its flood-fill connectivity filter keeps stencils from leaking through the pinch to the other side.

wall crossings         : 304
out-side degrees used  : p=2: 296, p=1: 8   (unresolved: 0)
 in-side degrees used  : p=2: 304   (unresolved: 0)
<Figure size 550x550 with 1 Axes>

Bare Laplacian with the domain boundary conditions

We assemble the plain Laplacian Lap=div(grad)\mathsf{Lap} = \mathrm{div}(\mathrm{grad}) once, without any diffusion coefficient, including the domain boundary conditions (Dirichlet c=1c=1 left, c=0c=0 right, no-flux top/bottom). The diffusion coefficient is applied afterwards as a cell-centred diagonal factor (next section), which is exactly the −D div(grad)-D\,\mathrm{div}(\mathrm{grad}) form we want. The usual pymrm sign convention applies: the boundary contribution gg is added, so the bare-Laplacian equation reads Lap c+glap=…\mathsf{Lap}\, c + g_\mathrm{lap} = \dots.

Boundary molar flows (for the overall mole balance)

To check the overall mole balance we need the molar flow crossing the left and right outer walls. The xx-derivative at the vertical grid faces is ∂c/∂x=gradx c+ggrad,x\partial c/\partial x = \mathsf{grad}_x\, c + g_{\mathrm{grad},x} (the same finite-volume gradient used in the operator), and the molar flux in the +x+x direction is −D ∂c/∂x-D\,\partial c/\partial x. Integrating that flux over a boundary column of faces gives the molar flow (per unit depth) through that wall; both outer walls lie in the fluid, so the fluid coefficient applies there. A positive flow_left enters the domain and a positive flow_right leaves it. In steady state with no volumetric sources the two must be equal to solver precision -- the discrete finite-volume fluxes telescope, so whatever enters at the left has to leave at the right.

Part 1: no-flux particles (Neumann outside, Dirichlet inside)

On the fluid side we impose the homogeneous Neumann condition

1⋅qout+0⋅cΓout=0⟺∂c∂n∣Γ=0,1 \cdot q_\mathrm{out} + 0 \cdot c_\Gamma^\mathrm{out} = 0 \qquad\Longleftrightarrow\qquad \left.\frac{\partial c}{\partial n}\right|_\Gamma = 0 ,

i.e. the wall equation dictionary {'a': 1, 'b': 0, 'd': 0} (any Robin condition a*q + b*c = d works the same way). construct_ibm_boundary_values eliminates the unknown fluid-side wall value, returning it as a sparse function of the field, cΓout=Hc+hc_\Gamma^\mathrm{out} = \mathsf H c + h. This enters the system through the wall source matrices G_out/G_in returned by apply_ibm(..., return_bc='matrix').

The solid side is completely decoupled from the fluid: there we simply prescribe a Dirichlet wall value cΓin=csolidc_\Gamma^\mathrm{in} = c_\mathrm{solid}, exactly as in the plain Dirichlet IBM (a known value contributes G_in @ values to the source). Since the solid interior keeps a diffusion equation with this wall value as its only boundary condition, it relaxes to the uniform value csolidc_\mathrm{solid} -- it is only there for display; the fluid solution does not depend on it.

As with the Dirichlet IBM, any independently assembled right-hand-side contribution (here the domain-boundary vector g_bc) must pass through apply_ibm_vector so it receives the same row conditioning as the matrix.

liquid min/max : 0.0011 / 0.9989
solid  min/max : 0.5000 / 0.5000   (should equal c_solid = 0.5)

With impermeable particles all flux has to bend around the solid: iso-concentration lines meet the surface at right angles (zero normal derivative). The profile through the particle centreline shows the decoupling -- the solid sits at csolidc_\mathrm{solid}, independent of the neighbouring fluid values.

<Figure size 1100x460 with 3 Axes>

Overall mole balance. The fluid is source-free and the particle surfaces carry no flux, so every mole entering at the left must leave at the right. The empty channel (no particles) would pass D Δc H/W=D=1D\,\Delta c\,H/W = D = 1; the impermeable particles obstruct the path and reduce the throughput below that reference.

left  boundary (inflow)  : 0.672428
right boundary (outflow) : 0.672428
relative imbalance       : 2.71e-13
empty-channel reference  : 1.000000  (throughput ratio 0.672)

Part 2: conjugate interface with different diffusion coefficients

Now the particles participate in the transport with their own diffusivity Din≠DoutD_\mathrm{in} \ne D_\mathrm{out}, coupled to the fluid by the conjugate interface conditions

Dout qout+Din qin=0(flux continuity),cΓout−cΓin=0(value continuity).D_\mathrm{out}\, q_\mathrm{out} + D_\mathrm{in}\, q_\mathrm{in} = 0 \qquad\text{(flux continuity)},\qquad c_\Gamma^\mathrm{out} - c_\Gamma^\mathrm{in} = 0 \qquad\text{(value continuity)} .

(Remember qoutq_\mathrm{out} and qinq_\mathrm{in} are both outward derivatives, so flux continuity is a sum, not a difference.) In dictionary form -- identical to the ic format of construct_interface_matrices -- this is

ic = ({'a': (D_out, D_in), 'b': (0.0, 0.0), 'd': 0.0},
      {'a': (0.0, 0.0), 'b': (1.0, -1.0), 'd': 0.0})

A partition coefficient (cout=K cinc_\mathrm{out} = K\, c_\mathrm{in}) or a contact resistance would only change these coefficients.

Keep the diffusion coefficient outside the Laplacian

Away from the interface each region has a uniform diffusion coefficient, so before the interface conditions are applied the balances are simply

fluid: −Dout∇2c=0,solid: −Din∇2c=0,\text{fluid: } -D_\mathrm{out}\nabla^2 c = 0, \qquad \text{solid: } -D_\mathrm{in}\nabla^2 c = 0 ,

i.e. the diffusion coefficient sits outside the Laplacian. We build this directly: one bare Laplacian Lap=div(grad)\mathsf{Lap} = \mathrm{div}(\mathrm{grad}) (already assembled above) and a cell-centred field of diffusion coefficients, DoutD_\mathrm{out} in the fluid and DinD_\mathrm{in} in the solid. construct_coefficient_matrix turns that field into a diagonal matrix D\mathsf D, and the operator is simply

L=− D Lap.\mathsf L = -\,\mathsf D\,\mathsf{Lap} .

Because D\mathsf D is diagonal it just scales each row (each cell equation) by the diffusion coefficient at that cell centre. We deliberately do not define DD on the cell faces through a mixture rule (harmonic or arithmetic averaging of DoutD_\mathrm{out} and DinD_\mathrm{in}): a face-averaged coefficient would impose its own smeared, first-order coupling across the cut cells and interfere with the sharp ghost-cell treatment. All communication between the two regions must come exclusively from the interface conditions, which apply_ibm_interface folds into the cut-cell rows.

Interface values and fluxes

With return_values=True we also get the elimination operators cΓside=Hside c+hsidec_\Gamma^\mathrm{side} = \mathsf H_\mathrm{side}\, c + h_\mathrm{side}, useful for post-processing wall concentrations and, combined with construct_ibm_normal_derivative_ops, wall fluxes. Since the elimination enforces the two interface equations exactly, the recovered values satisfy them to machine precision -- a consistency check of the assembly (the accuracy of the solution is governed by the reconstruction order, second order here).

max |c_out - c_in|            : 0.00e+00
max |D_out q_out + D_in q_in| : 5.12e-13

Because the particles conduct better than the fluid (Din=5DoutD_\mathrm{in} = 5 D_\mathrm{out}), iso-concentration lines are now attracted into the solid and refract at the surface. The centreline profile is continuous across the interfaces (value continuity) but shows a kink: flux continuity forces the slope inside the particles to be about Dout/DinD_\mathrm{out}/D_\mathrm{in} times the outside slope.

<Figure size 1100x460 with 3 Axes>

Overall mole balance. The interface conditions enforce flux continuity, so no moles accumulate at the particle surfaces; with a source-free interior the inflow again equals the outflow. Now the better-conducting particles (Din=5 DoutD_\mathrm{in} = 5\, D_\mathrm{out}) form high-conductance bridges across the channel, so the throughput exceeds the empty-channel reference Dout=1D_\mathrm{out} = 1.

left  boundary (inflow)  : 1.553690
right boundary (outflow) : 1.553690
relative imbalance       : 2.92e-13
empty-channel reference  : 1.000000  (throughput ratio 1.554)

Summary

  • construct_ibm_normal_derivative provides one-sided normal-derivative formulas at every wall crossing; everything else in this notebook consumed them.

  • A single-side wall condition (Neumann/Robin in the fluid, unmodelled or pinned solid) uses construct_ibm_boundary_values together with the G_out/G_in source matrices of apply_ibm(..., return_bc='matrix').

  • Two-side interface conditions (conjugate transfer, partition coefficients, contact resistance) use apply_ibm_interface with the same two-equation ic dictionaries as grid-aligned construct_interface_matrices.

  • For piecewise-constant diffusivities, build one bare Laplacian and a cell-centred diffusion-coefficient field, then form −D div(grad)-\mathsf D\,\mathrm{div}(\mathrm{grad}) with a diagonal D\mathsf D from construct_coefficient_matrix -- keeping DD outside the Laplacian, never a face-averaged DD -- so that the interface physics comes only from the imposed interface conditions.

  • The overall mole balance closes to solver precision in both cases (left inflow = right outflow): impermeable particles reduce the throughput below the empty-channel value, while better-conducting particles raise it above.