pyfracval.gap_scaling ===================== .. py:module:: pyfracval.gap_scaling .. autoapi-nested-parse:: Convert a target inter-particle gap into a position-only scale factor. Ported from YASF-new's ``Config.cluster_gap_factor``/``cluster_gap_mode`` (``yasfpy/config.py``) -- the target gap is expressed as a multiple of the mean particle radius (``target_gap = gap_factor * r_mean``), not an absolute length, so it's meaningful across differently-scaled clusters. This module only *computes* the scale -- it never mutates or returns scaled coordinates. Applying the scale is a downstream concern (e.g. pyfastmm's ``ParticlesConfig.gap_factor``, which already does exactly ``positions *= gap_factor`` and needs nothing else changed): keeping that split means there is exactly one place a cluster's geometry is actually transformed, however many places compute *what* to transform it by. Module Contents --------------- .. py:function:: compute_gap_scale(coords, radii, gap_factor, mode = 'average') Return the position-only scale factor that achieves *gap_factor*. :param coords: Particle center positions. :type coords: (N, 3) array :param radii: Particle radii, same units as *coords*. :type radii: (N,) array :param gap_factor: Target minimum surface-to-surface gap between neighboring particles, as a multiple of the mean particle radius. ``None`` or ``0`` means no gap requirement -- returns ``1.0`` (the touching, as-generated case; a no-op for a caller that then does ``positions *= scale``). Must be ``>= 0``. :type gap_factor: float or None :param mode: How *gap_factor* becomes a scale factor: - ``"average"`` (default, matching YASF's own default): a cheap closed-form estimate from the mean radius, ``s = max(1, 1 + gap_factor / 2)``. Does not guarantee every pair individually clears the target gap for irregular (non-uniform-density) aggregates. - ``"strict"``: exact, via a KD-tree nearest-neighbor query -- finds the scale that gives the *closest* pair exactly the target gap, which (since scaling every position by one global factor scales every pairwise distance by that same factor) guarantees every other pair, starting further apart, clears it too. :type mode: {"average", "strict"} :returns: The scale factor ``s`` such that ``coords * s`` achieves the requested gap. Always ``>= 1.0``. :rtype: float :raises ValueError: If *gap_factor* is negative, *mode* is not one of the values above, or the resulting scale fails to eliminate all overlaps (checked directly, not assumed from the formula/computation).