Source code for rpxdock.search.dockspec

import numpy as np
import rpxdock.homog as hm
from rpxdock.geom import sym

allowed_twocomp_architectures = """
D22 D32 D42 D52 D62 D72 D82
T32 T33 O32 O42 O43 I32 I52 I53
T32D T23D T33D
O32D O23D O42D O24D O43D O34D
I32D I23D I52D I54D I53D I35D
""".split()

[docs]class DockSpec1CompCage: def __init__(self, arch): assert len(arch) == 2 or (arch[0] == 'D' and arch[2] == '_') assert arch[:2] in "T2 T3 O2 O3 O4 I2 I3 I5 D2 D3 D4 D5 D6 D8".split() if arch[0] == 'D': assert arch[2] == '_' self.sym = arch[:2] self.nfold = int(arch[3]) else: self.sym = arch[0] self.nfold = int(arch[1]) self.arch = arch self.type = 'cage' self.num_components = 1 self.comp_is_dihedral = [False] self.axis = sym.axes[self.sym][self.nfold] self.axis_second = sym.axes_second[self.sym][self.nfold] # print(self.nfold) # print(self.axis) # print(self.axis_second) # assert 0 self.orig = hm.align_vector([0, 0, 1], self.axis) self.to_neighbor_olig = sym.to_neighbor_olig[self.sym][self.nfold] # print(self.to_neighbor_olig) # print(self.to_neighbor_olig @ self.axis) # print(self.axis_second) # assert 0 self.orig_second = self.to_neighbor_olig @ self.orig cang = hm.angle(self.axis, self.axis_second) aang = (np.pi - cang) / 2.0 self.slide_to_axis_displacement = np.sin(aang) / np.sin(cang) self.symframes_ = sym.symframes(self.sym) self.flip_axis = hm.hcross(self.axis, self.axis_second) self.nfold = np.array([self.nfold]) # print(self.sym, self.nfold)
[docs] def slide_dir(self): dirn = self.axis_second - self.axis return dirn[:3] / np.linalg.norm(dirn)
[docs] def placements(self, angles): place1 = hm.hrot(self.axis, angles, degrees=1) @ self.orig place2 = place1 @ hm.hrot([1, 0, 0], 180) # perp to z return np.concatenate([place1, place2])
[docs] def placements_second(self, placements): return self.to_neighbor_olig @ placements
[docs] def symframes(self, cellspacing=None, radius=None): return self.symframes_
[docs] def place_along_axis(self, pos, slide_dist): origshape = pos.shape pos = pos.reshape(-1, 4, 4) # pos2 = pos2.reshape(-1, 4, 4) adis = -slide_dist * self.slide_to_axis_displacement newt = self.axis * adis[:, None] newpos = pos.copy() newpos[:, :3, 3] = newt[:, :3] # newt2 = self.to_neighbor_olig @ newt[:, :, None] # newdelta = newt2.squeeze() - newt # olddelta = pos2[:, :, 3] - pos[:, :, 3] # assert np.allclose(newdelta, olddelta) return newpos.reshape(origshape)
[docs]class DockSpec2CompCage: def __init__(self, arch): self.arch = arch.upper() assert self.arch in allowed_twocomp_architectures assert len(self.arch) == 3 or self.arch.endswith('D') self.sym = arch if arch[0] == 'D' else arch[0] self.type = 'cage' self.num_components = 2 self.comp_is_dihedral = [False, self.arch.endswith('D')] self.nfold1 = int(arch[1]) self.nfold2 = int(arch[2]) self.nfold = np.array([self.nfold1, self.nfold2]) self.axis1 = sym.axes[self.sym[0]][self.nfold1] self.axis2 = sym.axes[self.sym[0]][self.nfold2] self.axis2 = sym.axes[self.sym[0]][33] if arch.startswith('T33') else self.axis2 self.axis1 = sym.axes['D'][22] if arch.startswith('D22') else self.axis1 self.axis = np.array([self.axis1, self.axis2]) self.axisperp = hm.hcross(self.axis1, self.axis2) self.orig1 = hm.align_vector([0, 0, 1], self.axis1) self.orig2 = hm.align_vector([0, 0, 1], self.axis2) self.orig = np.array([self.orig1, self.orig2]) self.symframes_ = sym.symframes(self.sym) self.axis1_second = sym.axes_second[self.sym][self.nfold1] self.axis2_second = sym.axes_second[self.sym][self.nfold2] self.to_neighbor_olig1 = sym.to_neighbor_olig[self.sym][self.nfold1] self.to_neighbor_olig2 = sym.to_neighbor_olig[self.sym][self.nfold2] if arch == 'T33': self.axis2_second = sym.axes_second[self.sym][33] self.to_neighbor_olig2 = sym.to_neighbor_olig[self.sym][33] if arch == 'D22': self.axis1_second = sym.axes_second[self.sym][22] self.to_neighbor_olig1 = sym.to_neighbor_olig[self.sym][22] self.axis_second = [self.axis1_second, self.axis2_second] self.to_neighbor_olig = np.array([self.to_neighbor_olig1, self.to_neighbor_olig2]) self.compframes = np.array([sym.symframes(self.nfold[i], self.axis[i]) for i in [0, 1]]) fax1 = hm.hcross(self.axis1, hm.hcross(self.axis1, self.axis2)) fax2 = hm.hcross(self.axis2, hm.hcross(self.axis2, self.axis1)) self.xflip = hm.hrot([fax1, fax2], np.pi) def __str__(self): return f'{self.arch} axis1 {self.axis1[:3]} axis2 {self.axis2[:3]}'
[docs] def slide_dir(self, angles): axisdelta = self.axis2 - self.axis1 axisdelta /= np.linalg.norm(axisdelta) dirs = hm.hrot(self.axisperp, angles) @ axisdelta return dirs[..., :3]
[docs] def placements1(self, angles, flip=True): place1 = hm.hrot(self.axis1, angles, degrees=1) @ self.orig1 if not flip: return place1 place2 = place1 @ hm.hrot([1, 0, 0], 180) return np.concatenate([place1, place2])
[docs] def placements2(self, angles): return hm.hrot(self.axis2, angles, degrees=1) @ self.orig2
[docs] def symframes(self, cellspacing=None, radius=None): return self.symframes_
[docs] def move_to_canonical_unit(self, pos1, pos2): origshape = pos1.shape pos1 = pos1.reshape(-1, 4, 4).copy() pos2 = pos2.reshape(-1, 4, 4).copy() xcen = self.symframes_[:, None] @ pos1[:, :, 3, None] xcen += self.symframes_[:, None] @ pos2[:, :, 3, None] tgt = self.axis1 + self.axis2 xdot = np.sum(xcen.squeeze(-1) * tgt, axis=2) x = self.symframes_[np.argmax(xdot, axis=0)] return (x @ pos1).reshape(origshape), (x @ pos2).reshape(origshape)
[docs] def place_along_axes(self, pos1, pos2): origshape = pos1.shape pos1 = pos1.reshape(-1, 4, 4).copy() pos2 = pos2.reshape(-1, 4, 4).copy() offset = pos2[:, :3, 3] - pos1[:, :3, 3] cang = hm.angle(self.axis1, self.axis2) cdis = np.linalg.norm(offset, axis=1) offset_norm = offset / cdis[:, None] dot1 = hm.hdot(offset_norm, self.axis1) dot2 = hm.hdot(offset_norm, self.axis2) axisdelta = hm.hnormalized(self.axis2 - self.axis1) aofst = np.sign(dot1 + dot2) * hm.angle(offset_norm, axisdelta) aang = (np.pi - cang) / 2.0 - aofst bang = (np.pi - cang) / 2.0 + aofst adis = cdis * np.sin(aang) / np.sin(cang) bdis = cdis * np.sin(bang) / np.sin(cang) newt1 = self.axis1[:3] * adis[:, None] newt2 = self.axis2[:3] * bdis[:, None] newoffset = newt2 - newt1 swap = hm.hdot(offset, newoffset) < 0 newt1[swap] *= -1 newt2[swap] *= -1 assert np.allclose(newt2 - newt1, offset[:, :3]) pos1[:, :3, 3] = newt1 pos2[:, :3, 3] = newt2 return (pos1.reshape(origshape), pos2.reshape(origshape))
[docs]class DockSpec3CompCage: def __init__(self, arch): assert len(arch) == 4 assert arch in "O432 I532".split() self.arch = arch self.type = 'cage' self.sym = arch[0] self.num_components = 3 self.symframes_ = sym.frames[self.sym] assert self.sym in "TOI" self.comp_is_dihedral = [False] * 3 self.nfold = np.array([int(arch[1]), int(arch[2]), int(arch[3])], dtype='i') self.axis = np.array([sym.axes[self.sym][n] for n in self.nfold]) self.axisperp = [ hm.hcross(self.axis[1], self.axis[2]), hm.hcross(self.axis[2], self.axis[0]), hm.hcross(self.axis[0], self.axis[1]) ] self.orig = [hm.align_vector([0, 0, 1], a) for a in self.axis] self.axis_second = [sym.axes_second[self.sym][n] for n in self.nfold] self.to_neighbor_olig = [sym.to_neighbor_olig[self.sym][n] for n in self.nfold] self.compframes = np.array([sym.symframes(self.nfold[i], self.axis[i]) for i in [0, 1, 2]]) self.xflip = hm.hrot([ hm.hcross(self.axis[0], hm.hcross(self.axis[0], self.axis[1])), hm.hcross(self.axis[1], hm.hcross(self.axis[1], self.axis[2])), hm.hcross(self.axis[2], hm.hcross(self.axis[2], self.axis[0])) ], np.pi)
[docs]class DockSpecMonomerToCyclic: def __init__(self, arch): assert len(arch) == 2 assert arch[0] == "C" self.type = 'cyclic' self.arch = arch self.num_components = 1 self.nfold = int(arch[1]) assert self.nfold > 1 self.angle = 2 * np.pi / self.nfold self.orig = np.eye(4) self.to_neighbor_monomer = hm.hrot([0, 0, 1], self.angle) self.orig_second = self.to_neighbor_monomer @ self.orig self.symframes_ = [hm.hrot([0, 0, 1], self.angle * i) for i in range(self.nfold)] self.tan_half_vertex = np.tan((np.pi - self.angle) / 2)
[docs] def slide_dir(self): return [1, 0, 0]
[docs] def placements_second(self, placements): return self.to_neighbor_monomer @ placements
[docs] def symframes(self, cellspacing=None, radius=None): return self.symframes_
[docs] def place_along_axis(self, pos, slide_dist): origshape = pos.shape pos = pos.reshape(-1, 4, 4) print(self.nfold, self.angle, self.tan_half_vertex) if self.nfold == 2: dx = slide_dist / 2 dy = 0 else: dx = slide_dist / 2 dy = dx * self.tan_half_vertex print("delta", slide_dist[0], dx[0], dy[0]) print(np.mean(dx), np.mean(dy)) newpos = pos.copy() newpos[:, 0, 3] = dx newpos[:, 1, 3] = dy return newpos.reshape(origshape)
_layer_comp_center_directions = dict( P6_632=(np.array([0.86602540378, 0.5, 0, 0]), np.array([0.86602540378, 0.0, 0, 0])), P4M_4=(np.array([1, 0, 0]), ), )
[docs]class DockSpec1CompMirrorLayer: def __init__(self, arch): arch = arch.upper() assert arch.startswith('P') self.arch = arch self.type = 'mirrorlayer' self.sym = arch self.nfold = np.array(list(arch.split('_')[1]), dtype='i') self.directions = _layer_comp_center_directions[arch] self.axis = np.array([np.array([0, 0, 1])] * 1) self.xflip = [hm.hrot([1, 0, 0], 180)] * 1 self.comp_is_dihedral = [False] self.num_components = 1 ang = 360 / self.nfold[0] self.to_neighbor_olig = [hm.hrot([0, 0, 1], ang)]
[docs]class DockSpec3CompLayer: def __init__(self, arch): arch = arch.upper() assert arch.startswith('P') assert 3 == len(arch.split('_')[1]) self.arch = arch self.type = 'layer' self.sym = arch self.nfold = np.array(list(arch.split('_')[1]), dtype='i') self.directions = _layer_comp_center_directions[arch] self.axis = np.array([np.array([0, 0, 1])] * 3) self.xflip = [hm.hrot([1, 0, 0], 180)] * 3 self.comp_is_dihedral = [False, False, False] self.num_components = 3 ang = 360 / self.nfold[0] self.to_neighbor_olig = [None, hm.hrot([0, 0, 1], ang), hm.hrot([0, 0, 1], ang)]