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 a circle (two components)

This example demonstrates the directional ghost-cell immersed boundary method (IBM) in pymrm. The solid circle is described analytically as a Circle particle and turned into immersed-boundary data by construct_ibm_particles; the field is advanced with apply_ibm / apply_ibm_vector. A non-spatial axis (axes / shape) allows different Dirichlet wall values per component.

We solve unsteady diffusion for two independent components on a square domain

∂uk∂t+∇⋅(−D ∇uk)=0,k=0,1\frac{\partial u_k}{\partial t} + \nabla\cdot\left(-D\,\nabla u_k\right) = 0, \quad k=0,1

with the following conditions:

  • Left & right walls: Dirichlet, uk=0u_k = 0.

  • Top & bottom walls: no-flux Neumann.

  • Immersed circle (solid obstacle) -- two-sided IBM with per-component wall values:

    • u0=1u_0 = 1 / u1=0.5u_1 = 0.5 on the outside (fluid),

    • u0=u1=0u_0 = u_1 = 0 on the inside (solid).

  • Initial condition: uk=2u_k = 2 everywhere.

The field array has shape (N, N, Nc) with axes=(0, 1) marking the spatial axes and the component axis at position 2.

Analytic circle and cell classification

The circle is a Circle((cx, cy), R) particle; construct_ibm_particles classifies the cells it covers and computes the exact wall crossings. Passing axes=(0, 1) and shape=(N, N, Nc) marks axis 2 as non-spatial (component), so ibm.n_cells = N*N*Nc, ibm.ns_size = Nc, and each wall crossing spans Nc rows in the operator matrix. info.pseudo_sdf is a sign-correct field (< 0 inside the disk) used here only for the solid mask in the plots; both sides share the same ibm.coords.

IBM wall crossings : 164
ns_size (components): 2
n_cells (full)      : 13122  = 81x81x2
<Figure size 500x500 with 1 Axes>

Diffusion operator with the domain boundary conditions

construct_grad and construct_div accept the full shape (N, N, Nc). Assembling the operator along axis=0 and axis=1 automatically creates a block-diagonal structure in the component axis: each component diffuses independently with the same spatial stencil. The domain BCs (a * du/dn + b * u = d) are applied identically to both components via broadcasting.

Apply the immersed boundary method

values_outside and values_inside have shape (n_crossings, Nc), providing independent Dirichlet values per component at each wall crossing. apply_ibm handles both the outside and inside modifications, and both components, in a single call. The matrix is modified once and factorised once. apply_ibm_vector applies the same per-row conditioning to the time-varying RHS.

Time integration (implicit Euler)

Each step solves a_mod_mat @ u = scale_rhs(u_old/dt - g_bc) - g_wall. The field u is a flat vector of length N*N*Nc; component k occupies every Nc-th element starting at k (C-order, component axis last).

<Figure size 1000x440 with 4 Axes>

Result

Both components reach their respective steady states. Component 0 approaches 1 at the circle and 0 at the side walls; component 1 approaches 0.5 at the circle. The solid disk relaxes to 0 for both.

component 0  fluid min/max: 0.014 / 0.996  solid min/max: 0.000 / 0.000
component 1  fluid min/max: 0.007 / 0.498  solid min/max: 0.000 / 0.000
<Figure size 1000x800 with 6 Axes>