Concepts
This page provides the mathematical and algorithmic background for Potts.jl. Understanding these ideas is not required to run simulations, but it will help you design experiments, tune parameters, and interpret results.
The Cellular Potts Model
Lattice Representation
A Potts simulation lives on a discrete lattice $\Lambda \subset \mathbb{Z}^d$ (typically $d = 2$ or $d = 3$). Each lattice site $\mathbf{x} \in \Lambda$ carries an integer cell ID $\sigma(\mathbf{x}) \in \{0, 1, 2, \ldots, N_\text{cells}\}$. The value $\sigma = 0$ denotes the background medium. All sites with the same non-zero ID belong to the same cell — cells are therefore contiguous domains of equal labels embedded in the lattice.
Each cell $i$ also has an associated cell type $\tau(i)$ drawn from a small discrete set (e.g. A, B, Medium). Cell types determine which biological rules apply to a cell.
Cell IDs and Type IDs
Two distinct integer spaces are used throughout the API:
Cell IDs (
σ): assigned to lattice sites.σ = 0is the background medium. Active cells have IDs1, 2, …, N_cells, assigned sequentially as cells are placed during initialization.cell_dataarrays are indexed directly by cell ID.Cell type IDs (
τ): integers1, 2, …, N_typesassigned to each non-backgroundCellTypein the order they appear incell_typesofPottsSystem. The background type (is_background=true) is excluded from this numbering.cell_data.cell_types[i]returns the type IDτof celli.
[!IMPORTANT] Both spaces are strictly 1-based. There is no "0th cell" and no "0th type." When writing callbacks or metrics that filter by cell type, use the type ID, and prefer symbolic lookup over hardcoded integers to avoid silent bugs if the
cell_typesordering changes.
Dynamic Property Allocation
The cell_data array is dynamically allocated based on the specific physics components in your PottsSystem. Instead of a massive struct containing every possible property, PottsState allocates exactly and only the memory required by your instantiated Penalties, Trackers, and Events.
For instance, if your simulation does not include a SurfaceAreaComponent or a SurfaceAreaTracker, the target_surface_areas array will simply not exist. Accessing it will throw a FieldError.
[!NOTE] If you are building custom
PenaltiesorEvents, you must define theCorePotts.required_variablestrait for your type (e.g.,CorePotts.required_variables(::MyPenalty) = (my_custom_field = Float32,)) so the system correctly allocates your required arrays on the GPU!
Monte Carlo Dynamics
At each Monte Carlo step (MCS) the following procedure is repeated $|\Lambda|$ times (one sweep):
- Pick a source site $\mathbf{x}$ uniformly at random.
- Pick a target (neighbour) site $\mathbf{x}'$ from the neighbourhood of $\mathbf{x}$.
- Propose the copy $\sigma(\mathbf{x}) \leftarrow \sigma(\mathbf{x}')$.
- Compute the energy change $\Delta H$ that this copy would cause.
- Accept or reject according to the Metropolis-Hastings criterion (see below).
The Hamiltonian
The total energy of a configuration is a sum of penalty terms:
\[H = H_\text{volume} + H_\text{surface} + H_\text{adhesion} + H_\text{length} + \cdots\]
Each penalty term encodes one biological constraint. The exact form of each term is described in detail on the Penalties page. The key property exploited by the engine is locality: because a copy attempt at site $\mathbf{x}$ only changes cell IDs in a small neighbourhood, $\Delta H$ can be evaluated in $O(1)$ time using pre-computed incremental statistics maintained by trackers.
Metropolis-Hastings Acceptance
A copy proposal is accepted with probability
\[P_\text{accept}(\Delta H) = \begin{cases} 1 & \text{if } \Delta H \leq 0 \\[4pt] \exp\!\left(-\dfrac{\Delta H}{T}\right) & \text{if } \Delta H > 0 \end{cases}\]
where $T$ is an effective temperature (the T parameter of the algorithm). Low $T$ makes the simulation "stiffer" — it accepts few energy-increasing moves and the system closely tracks local energy minima. High $T$ allows large fluctuations.
The Hastings Correction for Parallel Updates
When multiple sites are updated simultaneously (as in CheckerboardMetropolis or ParallelMetropolis), a naive application of the Metropolis criterion is biased because the proposal distribution is no longer symmetric. CorePotts applies the Hastings correction: the acceptance probability is multiplied by the ratio of the reverse-proposal probability to the forward-proposal probability,
\[P_\text{accept} = \min\!\left(1,\; \frac{q(\mathbf{x}' \to \mathbf{x})}{q(\mathbf{x} \to \mathbf{x}')}\, e^{-\Delta H / T}\right)\]
where $q(\mathbf{x} \to \mathbf{x}')$ is the probability that site $\mathbf{x}'$ was chosen as the copy source given that $\mathbf{x}$ was the target. For uniform neighbour sampling this ratio equals the ratio of neighbourhood sizes, which equals 1 for regular (isotropic) topologies.
HST Penalties (Hubbard-Stratonovich Transformation)
Motivation
The classical volume penalty is
\[H_\text{vol}(i) = \lambda_V \bigl(v_i - V_i^{\rm target}\bigr)^2\]
This quadratic form is convenient but breaks detailed balance when the target volume $V_i^{\rm target}$ is itself a stochastic variable (e.g. during growth or when it is learned from data), because the energy landscape changes between the proposal and its reverse.
The HST Reformulation
The Hubbard-Stratonovich transformation introduces an auxiliary continuous variable $\phi_i$ for each cell and rewrites the Boltzmann weight as a Gaussian integral:
\[e^{-\lambda_V (v_i - V_i)^2 / T} \propto \int d\phi_i \; e^{-\phi_i^2 / 2} \, e^{-\lambda_V (v_i - \phi_i)^2 / T}\]
The auxiliary field $\phi_i$ evolves between MCS steps via a discrete Ornstein-Uhlenbeck SDE:
\[\phi_i(t + \Delta t) = (1 - \eta \, \Delta t)\,\phi_i(t) + \eta \, v_i(t)\, \Delta t + \sqrt{2 \eta T}\; \xi(t)\]
where $\xi(t)$ is white noise and $\eta$ (the eta keyword argument) sets the relaxation rate.
Why HST Restores Detailed Balance
Because $\phi_i$ is now a genuine (auxiliary) degree of freedom that evolves independently, the joint system $(\sigma, \phi)$ satisfies detailed balance with respect to the augmented Hamiltonian. This is particularly important for penalties coupled to dynamic targets (growth, division) and for NeuralPotts, where the energy function is learned.
Use HSTVolumeComponent, HSTLengthComponent, or HSTSurfaceAreaComponent wherever you need this guarantee.
[!NOTE] HST components carry a small computational overhead per MCS compared to their classical counterparts because the auxiliary fields must be updated. For most simulations with static targets the classical quadratic penalties are sufficient.
Trackers
Naively computing $H$ for the full lattice after every copy attempt would cost $O(|\Lambda|)$ per step. Trackers maintain running statistics — cell volume, surface area, centroid, principal-axis length, etc. — and update them incrementally in $O(1)$ per copy attempt.
The internal update loop is:
1. Propose copy σ(x) ← σ(x′)
2. For each active tracker: compute the Δ-contribution to ΔH
3. Accept/reject
4. If accepted: apply tracker updates (increment/decrement counters)No $O(N)$ scan of the lattice ever occurs during the hot loop; the lattice is only scanned once at initialisation.
[!TIP] Trackers are registered automatically when you add components to a
PottsSystem. You do not need to manage them manually. At problem construction,build_initial_stateseeds the lattice from anAbstractLayout, theninitialize_metrics!performs a single O(|\Lambda|) scan to populate all tracker arrays. Every subsequent update is O(1).
GPU Parallelism: Checkerboard Graph Colouring
The key obstacle to parallelising the Metropolis update is write conflicts: if two adjacent sites are updated simultaneously, they may interfere with each other's $\Delta H$ evaluation.
The CheckerboardMetropolis algorithm resolves this by partitioning the lattice into colour classes such that no two sites of the same colour are neighbours. For VonNeumannTopology{2} (4-connected) this is the standard 2-colouring (black/white squares). For MooreTopology{2} (8-connected) a 4-colouring is used. For 3D topologies the colouring is extended analogously.
Within each colour class all sites are completely independent, so copy attempts can be evaluated and committed in parallel on a GPU (via CUDA.jl or Metal.jl) or in parallel CPU threads. The algorithm cycles through all colour classes in one MCS, so one full sweep still visits every site exactly once.
[!IMPORTANT] For extended topologies (
ExtendedVonNeumannTopology,ExtendedMooreTopology) the neighbourhood radius is larger than 1, which requires more colour classes.ParallelMetropoliswith the lottery mechanism is often a better choice for those cases.