Skip to main content

Module threading

Module threading 

Source
Expand description

自穿检测 —— 链有没有从环里穿过去、两根键有没有交叉。

§为什么非有这一条不可

精修阶段有个决定:力场里放全部 对原子,而不是像 RDKit 那样只放 u − l ≤ 5.0 的对。理由是被滤掉的那些(实测占 16.8%,柔性大分子上最高 51%) 正是拓扑上远、几何上可能撞在一起的对 —— 也就是自穿会发生的地方。

但那个改动的目的一直没有对应的判据。 收益证明不了,也防不住后续改动把它 弄丢。判据一(越界)看不见自穿:链穿过环时,每一对原子的距离都可以完全合法 —— 穿过去的那根键与环上的键不共享原子,它们的距离约束只有一条很松的 vdW 下限, 而“穿过“与“贴着“在两两距离上几乎没有区别。

所以要直接量几何:线段与线段、线段与环面。

§两个量

  • 键-键穿插:两根互相够远的键(不共享原子,且拓扑距离 > RIGID_TOPO), 算两条线段的最短距离。贴得太近就是穿了 —— 阈值不是拍的,见 CROSS_TOL
  • 环穿刺:每个环按质心扇形三角化,数有多少条键的线段穿过任一三角形。

§环穿刺数的是交点的奇偶,不是“有没有交点“

扇形面片合起来是一张以环为边界的曲面,线段与它交奇数次才是从一侧走到 了另一侧。头一版用 .any(),数的是“有没有交点“ —— 环非凸时会假阳性: 质心可能落在环外,扇形面片于是把凹口也铺上了,链从凹口穿过 z 平面会与内外 两片各交一次,相交 2 次、mod-2 环绕数为 0(拓扑上没穿过去),.any() 照样报真。

判据 月牙环的凹口不算穿刺 钉的就是这个:18 元月牙环(外弧 r=4、内弧 r=2.6,θ∈[−150°,150°],18 个顶点的质心落在 r≈0.22 的空洞里、也就是环外), 链在半径 0.9 处竖直穿过。改回 .any() 它当场红。

这个改动在当前语料上一条都没改:feasibility(large.smihard.smi)、threading_oracle(smoke.bounds.jsonl)三份输出逐字节相同, conformer_oracle 除耗时那一行外也相同。语料里的环都小到基本是凸的, 真正会踩的是柔性大环和精修之前的嵌入坐标 —— 所以覆盖全靠那条手写判据, 差分语料在这件事上是空的。

两个都是确定的,复杂度 O(键²),56 原子的分子上几千次运算,可忽略。

Structs§

Threading
一个构型的自穿账。

Constants§

CROSS_TOL
两根不共享原子的键靠到多近就算穿插(Å)。
RIGID_TOPO
两根键的原子集之间,拓扑距离小到多少就不再算作可能互穿

Functions§

detect
数一个构型里的自穿。
segment_distance
两条线段之间的最短距离。
segment_hits_triangle
线段有没有穿过三角形(Möller–Trumbore,带线段参数的夹紧)。