topo_metrics.knots#

Attributes#

Functions#

writhe_method_1a(→ tuple[float, float])

Method 1a: pairwise solid angles (Eqs 13, 15-16).

writhe_method_1b(→ tuple[float, float])

Method 1b: analytic Gauss integral (Eqs 13, 24-25).

writhe_method_2a(→ float)

Method 2a: Wr = Twz + Wrz - Tw (Eqs 30-34), z-axis projection.

writhe_method_2b(→ float)

Method 2b (le Bret-style):

linking_number_method_1a(→ float)

Gauss linking number for two CLOSED polygonal rings (method 1a).

linking_number_method_1b(→ float)

Gauss linking number for two CLOSED polygonal rings (method 1b analytic).

lk_round(→ tuple[int, bool])

Return (rounded_int, ok) where ok means |lk-round(lk)| <= tol.

linking_number_int(→ int)

Convert near-integer lk to integer.

is_linked_from_lk(→ bool)

Determine if two rings are linked from linking number value.

linking_number_pbc(, n_images, method, eps, ...)

Compute Gauss linking number between ringA and ringB under PBC by scanning

Module Contents#

topo_metrics.knots.nb = None[source]#
topo_metrics.knots.Array[source]#
topo_metrics.knots.writhe_method_1a(points: numpy.typing.ArrayLike, *, closed: bool = True, eps: float = 1e-12) tuple[float, float][source]#

Method 1a: pairwise solid angles (Eqs 13, 15-16).

topo_metrics.knots.writhe_method_1b(points: numpy.typing.ArrayLike, *, closed: bool = True, eps: float = 1e-12) tuple[float, float][source]#

Method 1b: analytic Gauss integral (Eqs 13, 24-25).

topo_metrics.knots.writhe_method_2a(points: numpy.typing.ArrayLike, *, eps: float = 1e-12) float[source]#

Method 2a: Wr = Twz + Wrz - Tw (Eqs 30-34), z-axis projection. Requires a closed chain.

topo_metrics.knots.writhe_method_2b(points: numpy.typing.ArrayLike, *, eps: float = 1e-12) float[source]#
Method 2b (le Bret-style):

Wr = Wrz - Tw with a_i = k×s_i/|k×s_i| (Eqs 35-38), k = z-axis.

Requires closed chain.

topo_metrics.knots.linking_number_method_1a(ring1: numpy.typing.ArrayLike, ring2: numpy.typing.ArrayLike, *, eps: float = 1e-12, disjoint_tol: float | None = None, disjoint_rel: float = 0.001, return_nan_if_not_disjoint: bool = True) float[source]#

Gauss linking number for two CLOSED polygonal rings (method 1a).

Disjointness:
  • if disjoint_tol is None: uses auto disjoint_tol from disjoint_rel

  • if disjoint_tol <= 0: skips the disjointness check

  • if not disjoint: returns nan or raises return_nan_if_not_disjoint=False

topo_metrics.knots.linking_number_method_1b(ring1: numpy.typing.ArrayLike, ring2: numpy.typing.ArrayLike, *, eps: float = 1e-12, disjoint_tol: float | None = None, disjoint_rel: float = 0.001, return_nan_if_not_disjoint: bool = True) float[source]#

Gauss linking number for two CLOSED polygonal rings (method 1b analytic).

Same disjointness behavior as method_1a.

topo_metrics.knots.lk_round(lk: float, tol: float = 1e-06) tuple[int, bool][source]#

Return (rounded_int, ok) where ok means |lk-round(lk)| <= tol.

topo_metrics.knots.linking_number_int(lk: float, tol: float = 1e-06) int[source]#

Convert near-integer lk to integer.

topo_metrics.knots.is_linked_from_lk(lk: float, *, tol: float = 1e-06) bool[source]#

Determine if two rings are linked from linking number value.

topo_metrics.knots.linking_number_pbc(ringA: Array, ringB: Array, *, cell: Array, pbc: tuple[bool, bool, bool] = (True, True, True), n_images: int = 1, method: str = '1a', eps: float = 1e-12, check_top_k: int | None = None, disjoint_tol: float | None = None, disjoint_rel: float = 0.001) tuple[float, tuple[int, int, int]][source]#

Compute Gauss linking number between ringA and ringB under PBC by scanning periodic images of ringB.

Returns (best_lk, best_image_shift) where best_image_shift is integer n such that:

ringB_shifted = ringB - (n @ cell)

Candidate scoring / selection:
  • compute min segment-segment dist^2 for each shift

  • discard candidates with dist < disjoint_tol

  • among remaining, choose the shift that maximizes |round(lk)|, tie-break by smaller dist^2, then smaller residual |lk-round(lk)|