Skip to content

Hybrid 0th-order creation: clipped boundary cells, and cells that straddle a membrane - #32

Merged
jcschaff merged 1 commit into
mainfrom
fix/hybrid-zeroth-order-creation
Oct 8, 2026
Merged

jcschaff merged 1 commit into
mainfrom
fix/hybrid-zeroth-order-creation

Conversation

@jcschaff

@jcschaff jcschaff commented Oct 7, 2026

Copy link
Copy Markdown
Member

Fixes #24 and #26. Both are in the same loop: the OPTION_VCELL branch of zeroreact in smoldyn-2.38/source/Smoldyn/smolreact.c, which handles field-dependent 0th-order creation in a compartment (reaction_cmpt c r 0 -> A k*B;). The loop moved into a helper, zeroreactcmptmesh.

What changed

  • Hybrid 0th-order particle creation uses full cell volume at boundary nodes (overproduces by Σfull/Σactual) #24, boundary cells. Nodes on the domain walls own half, quarter or eighth cells. The Poisson count now uses each node's cell clipped to the domain, the same region randomPosInMesh fills, instead of the full dx·dy·dz.
  • Hybrid 0th-order creation in a compartment skips cells whose centre is outside (under-creates at curved membranes) #26, cells that straddle a membrane. A cell now draws if its node or any neighbouring node (face, edge or corner) is inside the compartment. The existing posincompart thinning then keeps exactly the molecules in cell ∩ compartment. Previously a cell drew only if its centre was inside, so straddling cells with the centre outside never created.
  • Where the rate is evaluated. For a straddling cell whose own node is outside, the rate comes from the nearest neighbouring node inside. The field at the outside node belongs to another region, so evaluating it there would read the wrong value.
  • Wall nodes. Membership is tested with each node nudged just inside the domain, because posincompart is ambiguous for points exactly on a wall.

Measured. Native runs through libvcell → pyvcell-fvsolver, 8 seeds each, B a static catalyst, comparing created A with the exact expectation. Before: the stock 0.10.7 wheel, numbers from the issues. After: this branch, built locally.

case before after
11×11×3 slab, box walls only (#24) 1.813 0.995 ± 0.004
ball R = 4 µm on a 37³ mesh, relative to the volume of Smoldyn's compartment (#26) ≈0.978 0.996 ± 0.002

The remaining ~0.5% is a separate start-up artifact: Smoldyn skips 0th-order creation for about the first 2 of 200 steps.

Not covered

  • I haven't run the C++ test suite locally; CI covers it.
  • The cases were run from viva-pde-particle: Studies A3 two-way-exchange and B2b sphere-cosim-vs-native.

Related: #25 (particle binning at the same membranes) and #23 (a second solve in one process); separate PRs.

🤖 Generated with Claude Code

…addle a membrane

Field-dependent 0th-order creation in a compartment (zeroreact, OPTION_VCELL)
drew Poisson(rate*dt*dx*dy*dz) molecules at each node whose centre was inside
the compartment. Two errors:

- Boundary nodes of the node-centred mesh own half, quarter or eighth cells,
  but the count used the full cell, so creation was overproduced by
  sum(full)/sum(clipped): 1.815x on an 11x11x3 slab (#24). The count now
  uses the cell clipped to the domain, the region randomPosInMesh fills.
- Cells that straddle a curved membrane with their centre outside never
  drew, so creation fell short next to membranes (#26). Every cell whose
  node or a neighbouring node is inside now draws, and the existing
  posincompart thinning keeps exactly the molecules in cell & compartment.
  The rate of a straddling cell whose node is outside is evaluated at the
  nearest neighbouring node inside the compartment, because the field at
  the node itself belongs to another region.

Node membership is tested with the node nudged just inside the domain,
since nodes on the domain walls are ambiguous to posincompart.

Fixes #24. Fixes #26.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jcschaff
jcschaff merged commit 14cde4b into main Oct 8, 2026
12 checks passed
@jcschaff jcschaff mentioned this pull request Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hybrid 0th-order particle creation uses full cell volume at boundary nodes (overproduces by Σfull/Σactual)

1 participant