Comparison of CCA Sticking Methods#
Warning
The densification result on this page was withdrawn on 2026-07-30. The reported “100% success, 20x faster” figure counted aggregates that were geometrically invalid — every densified aggregate examined carried 43–69% residual particle overlap — and was scored on radius of gyration, a quantity densification optimizes directly and which therefore cannot distinguish an aggregate at Df=2.1 from a compressed one at Df=1.8. Evaluated against the density–density correlation function, densified aggregates fall roughly 0.5 below their target Df. See correlation_validation.md.
The rigid-search comparisons on this page are unaffected, and their central finding stands: search strategy does not determine hard-regime success. backtracking_pairing.md identifies the variable that does.
This page compares the CCA (cluster-cluster aggregation) sticking
strategies evaluated between early and mid-2026. The production default
is Fibonacci-spiral sticking with an incremental active-set overlap
check. None of the alternatives evaluated below outperformed it.
Non-default implementations are archived under pyfracval/experimental/
(see Implementation notes).
Background: geometric frustration#
In hard parameter regimes — high Df, low kf, wide polydispersity
(e.g. Df=2.25, kf=0.95, rp_gstd=1.9) — CCA sticking success rates fall
to roughly 17–20%, independent of how the rotation search is conducted.
The cause is geometric frustration: the fractal scaling law fixes the
contact distance (gamma_pc) at which two clusters must be placed, and
at these parameter combinations no overlap-free relative orientation
exists at that distance. Refining the search cannot recover a solution
that does not exist.
Method comparison#
Hard regime: N=128, Df=2.25, kf=0.95, rp_gstd=1.9. Source:
benchmark_results/profiles/method_comparison_hard_regime/,
benchmark_results/profiles/soft_quick_test/ (30 trials per method
unless noted; commit d241350).
Method |
Success rate |
Median wall time |
Verdict |
|---|---|---|---|
Baseline (vanilla Fibonacci, single rotation mode) |
16.7% |
42.2 s |
reference |
Bounding-volume pair pre-filter |
16.7% |
41.0 s |
no improvement |
SSA (surface-accessibility) pair filter |
16.7% |
41.9 s |
no improvement |
Γ-expansion (gamma relaxation, max 3 attempts) |
16.7% |
41.4 s |
no improvement |
BV filter + Γ-expansion combined |
16.7% |
41.9 s |
no improvement |
FFT rigid-body docking (64³ grid) |
16.7% |
42.1 s |
no improvement |
FFT rigid-body docking (128³ grid) |
16.7% |
42.2 s |
no improvement |
Soft potential relaxation (paired baseline: 20.0%) |
20.0% |
35.6 s |
no improvement over its own baseline (34.6 s) |
Densification (generate at Df=1.8/kf=1.0, densify to target) |
100.0% |
2.1 s |
withdrawn — see warning above |
Densification (generate at Df=2.0/kf=1.0, densify to target) |
100.0% |
2.6 s |
withdrawn — see warning above |
All rigid-body modifications to the sticking search — pair pre-filters, Γ relaxation, their combination, and FFT-based rigid docking at two grid resolutions — fall within noise of the baseline. Soft potential relaxation is likewise statistically indistinguishable from its own paired baseline. This pattern is consistent with the frustration diagnosis: when no overlap-free orientation exists at the enforced contact distance, the manner in which orientations are searched is immaterial.
Fractal accuracy of densified aggregates (withdrawn)#
Source: benchmark_results/fractal_structure_validation.json. Retained
for the record; the accuracy metric used here (Rg agreement) is
insufficient for the reasons given in the warning above.
Method |
Success rate |
Mean |Rg error| |
Max |Rg error| |
|---|---|---|---|
Baseline (rigid sticking, successes only) |
40.0% (12/30) |
1.67% |
3.52% |
Densify (source Df=2.0) |
100.0% (30/30) |
0.42% |
0.93% |
Densify (source Df=1.8) |
100.0% (30/30) |
1.04% |
1.84% |
Retry rotation modes#
Source: benchmark_results/profiles/retry_mode_matrix_hard_v1/ (12
trials per mode, hard regime, N=256 and N=512).
Mode |
N=256 success |
N=256 median |
N=512 success |
N=512 median |
|---|---|---|---|---|
|
8.3% (1/12) |
57.6 s |
16.7% (2/12) |
115.8 s |
|
8.3% (1/12) |
56.4 s |
16.7% (2/12) |
115.8 s |
|
8.3% (1/12) |
56.8 s |
16.7% (2/12) |
115.8 s |
|
8.3% (1/12) |
58.3 s |
16.7% (2/12) |
114.2 s |
The four rotation-retry strategies produce identical success counts and statistically indistinguishable timing at both sizes tested. Broadening the rotation search does not help when no orientation is overlap-free at the required contact distance.
Candidate ordering policies#
Source: benchmark_results/profiles/candidate_policy_probe_v1/ (8
trials per policy, N=512).
Policy |
Success rate |
Median wall time |
|---|---|---|
|
12.5% (1/8) |
73.8 s |
|
12.5% (1/8) |
75.2 s |
Both policies produce the same outcome. The sample is small (n=8 per
arm), but taken together with the retry-mode result above it supports
the conclusion that the manner in which a contact pair is searched
matters far less than whether a valid contact pair exists at the
enforced gamma_pc.
Discussion#
The production path remains vanilla Fibonacci sticking with a single
rotation mode, incremental active-set overlap checking, and baseline
candidate ordering; pyfracval/cca/ (pairing.py, candidates.py,
sticking.py, fallbacks.py, aggregator.py) is organized around this
path. Each alternative evaluated here was a plausible hypothesis that
did not change the outcome when measured. The results are consistent
across all variants and support a single interpretation: hard-regime
failure is a property of the pairing and contact-distance constraints,
not of the search over orientations. Subsequent work on cluster pairing
(pairing_frustration.md,
backtracking_pairing.md) confirmed this
interpretation and moved the boundary.
Limitations#
The retry-mode and candidate-policy comparisons use small trial counts
(8–12 per arm) at a single hard-regime point. Distinguishing “no
effect” from insufficient statistical power would require a larger
sweep across multiple (Df, kf, rp_gstd) points;
configs/plausibility_step2_feature_matrix.toml and
benchmarks/build_feature_matrix_config.py provide the harness this
was originally built with.
Implementation notes#
Non-winning implementations are archived under
pyfracval/experimental/ rather than removed, since a different
parameterization of the same idea (e.g. Γ-expansion with a larger
expansion budget, or FFT docking at higher rotation sampling density)
may warrant revisiting. Each remains reachable through the same config
flags as before; cca/ retains a thin opt-in dispatch:
Retry rotation modes (
alternate,dual_jitter,coarse_grid,coarse_to_fine) —experimental/retry_modes.pyPair feasibility pre-filters (bounding-volume, SSA) —
experimental/pair_prefilters.pyΓ-expansion —
experimental/gamma_expansion.pyFFT rigid-body docking —
experimental/fft_docking.pySoft potential relaxation —
experimental/soft_relaxation.pyNon-baseline candidate scoring policies (
leaf_soft/leaf_score/leaf_hybrid) —experimental/candidate_policies.py
The soft-accept and rigid-repair config flags (cca_soft_accept_*,
cca_repair_*) were confirmed to have no remaining implementation
(no reader anywhere in the codebase) and were removed outright rather
than archived.