def normalize_pts(self, pts1, pts2): #print pts1 A = pts1[:, 0:2] B = pts2[:, 0:2] assert len(A) == len(B) N = A.shape[0] # total points # find centroids centroid_A = rmsd.centroid(A) centroid_B = rmsd.centroid(B) # centre the points AA = A - centroid_A BB = B - centroid_B #get optimal rotation matrix R = rmsd.kabsch(AA, BB) # Apply transformation AA1 = np.dot(AA, R) angle1 = math.atan2(R[1][0], R[1][1]) pts1[:, 0:2] = AA1 + centroid_B # rotate the rotations pts1[:, 2] -= angle1 return rmsd.rmsd(AA1, BB)
def test_pdb(example_path="examples", threshold=0.001): """ A simple test for the PDB functionality :return: True if all test passed """ p_atoms, P = rmsd.get_coordinates(example_path+'/ci2_1.pdb', 'pdb') q_atoms, Q = rmsd.get_coordinates(example_path+'/ci2_2.pdb', 'pdb') n_rmsd = rmsd.rmsd(P, Q) Pc = rmsd.centroid(P) Qc = rmsd.centroid(Q) P -= Pc Q -= Qc k_rmsd = rmsd.kabsch_rmsd(P, Q) q_rmsd = rmsd.quaternion_rmsd(P, Q) if abs(n_rmsd - 26.975) > threshold: print('Failed to calculate normal RMSD, result: {0}'.format(n_rmsd)) return False if abs(k_rmsd - 11.777) > threshold: print('Failed to calculate Kabsch RMSD, result: {0}'.format(k_rmsd)) return False if abs(q_rmsd - 11.777) > threshold: print('Failed to calculate quaternion RMSD, result: {0}'.format(q_rmsd)) return False if abs(q_rmsd - k_rmsd) > threshold ** 2: print('Failed to yield similar Kabsch and quaternion RMSD, result: {0} vs {1}'.format(k_rmsd, q_rmsd)) return False return True
def rmsd_distance(atoms_list, coordinates_list, translation=False, rotation=False): N = len(atoms_list) kernel = np.zeros((N, N)) # Lower triangular for i in range(N): for j in range(i): coord_i = coordinates_list[i] coord_j = coordinates_list[j] # unique pairs if translation: coord_i = coord_i - rmsd.centroid(coord_i) coord_j = coord_j - rmsd.centroid(coord_j) if rotation: kernel[i, j] = rmsd.kabsch_rmsd(coord_i, coord_j) else: kernel[i, j] = rmsd.rmsd(coord_i, coord_j) kernel[j, i] = kernel[i, j] # np.fill_diagonal(kernel, 0.0) # iu2 = np.triu_indices(N, 1) # il2 = np.tril_indices(N, -1) # kernel[iu2] = kernel[il2] return kernel
def alin(A,B): A -= rmsd.centroid(A) B -= rmsd.centroid(B) #print (B) U = rmsd.kabsch(A, B) A = np.dot(A, U) return A, B, rmsd.rmsd(A,B)
def calc_rmsd(mol1, mol2): mol_coord1 = mol_to_coord_mat(mol1) mol_coord2 = mol_to_coord_mat(mol2) #Localize on centroid mol_coord1 -= rmsd.centroid(mol_coord1) mol_coord2 -= rmsd.centroid(mol_coord2) return rmsd.quaternion_rmsd(mol_coord1, mol_coord2)
def CalRmsdFrame(coor_frame, ref_coor_frame): """ Calculate the rmsd between two frames. """ coor_tmp = coor_frame.reshape(-1, 3) ref_tmp = ref_coor_frame.reshape(-1, 3) coor_tmp -= rmsd.centroid(coor_tmp) ref_tmp -= rmsd.centroid(ref_tmp) return rmsd.kabsch_rmsd(coor_tmp, ref_tmp)
def KabschTransform(MAT_B, MAT_R): C_road = rmsd.centroid(MAT_R) # centreroid of the road points C_back = rmsd.centroid(MAT_B) # centreroid of the back points XYZroad_centered = MAT_R - C_road #XYZ of road after centering XYZback_centered = MAT_B - C_back #XYZ of back after centering R = rmsd.kabsch( XYZroad_centered, XYZback_centered ) # the optimal rotation matrix to rotate road points to back coordinates return C_road, C_back, R
def count_rmsd(t1, t2): P = np.array([[float(v.x), float(v.y), float(v.z)] for v in t1.points]) Q = np.array([[float(v.x), float(v.y), float(v.z)] for v in t2.points]) # print("RMSD before translation: ", round(rmsd.kabsch_rmsd(P, Q), 6)) P -= rmsd.centroid(P) Q -= rmsd.centroid(Q) # print("RMSD after translation: ", round(rmsd.kabsch_rmsd(P, Q), 6)) return round(rmsd.kabsch_rmsd(P, Q), 4) # round 6 in triangles_matrix
def get_transformation_matrix_kabsch(q, p): # compute centroids Pc = rmsd.centroid(p) Qc = rmsd.centroid(q) # Kabsch algorithm for estimating R and t T = np.identity(4) T[:3, :3] = rmsd.kabsch(p - Pc, q - Qc) T[:3, 3] = Pc - np.dot(T[:3, :3], Qc) return T
def RMSDmetric(structure1, structure2): numParticles = len(structure1) / 3 coords1 = structure1.reshape(int(numParticles), 3) coords2 = structure2.reshape(int(numParticles), 3) coords1 = coords1 - rmsd.centroid(coords1) coords2 = coords2 - rmsd.centroid(coords2) return rmsd.kabsch_rmsd(coords1, coords2)
def crmsd_kabsch(A, B): # Translate A -= rmsd.centroid(A) B -= rmsd.centroid(B) # Rotate U = rmsd.kabsch(A, B) A = np.dot(A, U) return rmsd.rmsd(A, B)
def compute_similarity(site_a, site_b): """ Compute the similarity between two given ActiveSite instances. Input: two ActiveSite instances Output: the similarity between them (a floating point number) """ # Get strings of single letter aa residues s_a = output_aa_string(site_a.residues) s_b = output_aa_string(site_b.residues) # Align strings using local alignment algorithm which relies # on dynamic programming to compute all possible alignments and # returns the highest scoring alignment. # Local alignment aims to find the max alignment for substrings # of two larger strings. # Matches = +1 # Mismatches, gaps = +0 alignments = pairwise2.align.localxx(s_a, s_b) # perform alignment if len(alignments) == 0: return float("inf") # return INF if no alignment found align_a, align_b, s = alignments[0][:3] # extract first alignment # Output indices where nucleotides in alignment match inds_a, inds_b = match(align_a, align_b) if len(inds_a) < 2: return float("inf") # Create matrix of coordinates for atom CA V = create_coord_matrix(site_a, inds_a) W = create_coord_matrix(site_b, inds_b) # Center and rotate Ca matrices then calculate Root-Mean-Square-Deviation (RMSD) # It measures the average distance between backbone atoms of two # superimposed proteins. # The greater the RMSD, the less similar the proteins are. # A RMSD equal to 0 represents identical proteins. # Each protein is a matrix containing x, y, and z coordinates for each CA atom # The rows of the two matrices are matching residues obtained from the alignment # To minimize RMSD you must first center the coordinates on the origin so the # two vectors can be near each other. V -= rmsd.centroid(V) W -= rmsd.centroid(W) # Then find the optimal rotation for matrix W that aligns it best with V # This is the Kabasch algorithm which works by calculating a covariance matrix # and then finding the singular value decomposition (SVD) of the cov. matrix # Last, find the optimal rotation matrix which is the dot product of V and W # optimized by lowest RMSD return rmsd.kabsch_rmsd(V,W)
def test_reorder_inertia_hungarian(): # coordinates of scrambled and rotated butane atoms = np.array( ["C", "C", "C", "C", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H"] ) p_coord = np.array( [ [2.142e00, 1.395e00, -8.932e00], [3.631e00, 1.416e00, -8.537e00], [4.203e00, -1.200e-02, -8.612e00], [5.691e00, 9.000e-03, -8.218e00], [1.604e00, 7.600e-01, -8.260e00], [1.745e00, 2.388e00, -8.880e00], [2.043e00, 1.024e00, -9.930e00], [4.169e00, 2.051e00, -9.210e00], [3.731e00, 1.788e00, -7.539e00], [3.665e00, -6.470e-01, -7.940e00], [4.104e00, -3.840e-01, -9.610e00], [6.088e00, -9.830e-01, -8.270e00], [5.791e00, 3.810e-01, -7.220e00], [6.230e00, 6.440e-01, -8.890e00], ] ) q_coord = np.array( [ [6.71454, -5.53848, -3.50851], [6.95865, -6.22697, -2.15264], [8.16747, -5.57632, -1.45606], [5.50518, -6.19016, -4.20589], [5.33617, -5.71137, -5.14853], [7.58263, -5.64795, -4.12498], [6.51851, -4.49883, -3.35011], [6.09092, -6.11832, -1.53660], [5.70232, -7.22908, -4.36475], [7.15558, -7.26640, -2.31068], [8.33668, -6.05459, -0.51425], [7.97144, -4.53667, -1.29765], [4.63745, -6.08152, -3.58986], [9.03610, -5.68475, -2.07173], ] ) p_coord -= rmsd.centroid(p_coord) q_coord -= rmsd.centroid(q_coord) review = rmsd.reorder_inertia_hungarian(atoms, atoms, p_coord, q_coord) result_rmsd = rmsd.kabsch_rmsd(p_coord, q_coord[review]) np.testing.assert_almost_equal(0, result_rmsd, decimal=2)
def kabsch(pointsCurrent, pointsRef): C_curr = rmsd.centroid(pointsCurrent) C_ref = rmsd.centroid(pointsRef) points_curr_norm = pointsCurrent - C_curr # XYZ current after centering points_ref_norm = pointsRef - C_ref # the optimal rotation matrix to rotate XYZcurrent to XYZref R = rmsd.kabsch(points_curr_norm, points_ref_norm) return (R, C_curr, C_ref)
def test_icp(A, shuffle = 1): # Generate a random dataset for i in range(num_tests): print('test', i) B = np.copy(A) # Translate t = np.random.rand(dim)*translation B += t # Rotate R = rotation_matrix(np.random.rand(dim), np.random.rand() * rotation) B = np.dot(R, B.T).T # Add noise B += np.random.randn(N, dim) * noise_sigma # Shuffle to disrupt correspondence if (shuffle == 1): np.random.shuffle(B) #B[0:100] = 0 #Bcenter = rmsd.centroid(B) #B[0:100] = Bcenter print("Normal squared_distance", squared_distance(A, B)) plot3d(A, B) # Run ICP A -= rmsd.centroid(A) B -= rmsd.centroid(B) T, distances, iterations = icp.icp(B, A, tolerance=0.000001) print(T.shape) # Make C a homogeneous representation of B C = np.ones((N, 4)) C[:,0:3] = np.copy(B) # Transform C C = np.dot(T, C.T).T C = C[:, 0:3] print("Rotated squared_distance", squared_distance(A, C)) plot3d(A, C) #assert np.mean(distances) < 6*noise_sigma # mean error should be small #assert np.allclose(T[0:3,0:3].T, R, atol=6*noise_sigma) # T and R should be inverses #assert np.allclose(-T[0:3,3], t, atol=6*noise_sigma) # T and t should be inverses return
def generate_set(A, B): Asize = A.shape[0] Bsize = B.shape[0] temp = np.zeros((max(Asize, Bsize), 3)) if (Asize < Bsize): temp += rmsd.centroid(A) temp[0:Asize] = A A = temp else: temp += rmsd.centroid(B) temp[0:Bsize] = B B = temp return A, B
def normalize_pts(pts1, pts2): #print pts1 A = pts1[:, 0:2] B = pts2[:, 0:2] assert len(A) == len(B) N = A.shape[0] # total points # find centroids centroid_A = rmsd.centroid(A) centroid_B = rmsd.centroid(B) # centre the points AA = A - centroid_A BB = B - centroid_B #get optimal rotation matrix R = rmsd.kabsch(AA, BB) # Apply transformation AA1 = np.dot(AA, R) angle1 = math.atan2(R[1][0], R[1][1]) #try flippin' it AA[:, 1] *= -1 #get optimal rotation matrix R = rmsd.kabsch(AA, BB) # Apply transformation AA2 = np.dot(AA, R)#get optimal rotation matrix angle2 = math.atan2(R[1][0], R[1][1]) #go with whichever one is better a2diff = np.abs(pts2[:,2]-(pts1[:,2]-angle2)) a1diff = np.abs(pts2[:,2]-(pts1[:,2]+angle1)) #angle differences are fun! for i in range(0, len(a1diff)): while (a2diff[i] > np.pi): a2diff[i] -= 2*np.pi while (a1diff[i] > np.pi): a1diff[i] -= 2*np.pi print np.degrees(a2diff), np.degrees(a1diff) if (np.sum(np.abs(a1diff)) > np.sum(np.abs(a2diff))): pts1[:, 0:2] = AA2 + centroid_B # rotate the rotations (backwards, since we mirrored the thing) pts1[:, 2] -= angle2 return rmsd.rmsd(AA2, BB) else: pts1[:, 0:2] = AA1 + centroid_B # rotate the rotations pts1[:, 2] += angle1 return rmsd.rmsd(AA1, BB)
def center_and_kabsch(P, Q): """ returns centroid of P, Q and a rotational matrix (in subsequent analyses, you may want to subtract centroidP/Q from your point sets) that minimizes RMSD between corresponding points in P and Q, *when applied to P* """ P = np.array(P) Q = np.array(Q) centroidP = rmsd.centroid(P) centroidQ = rmsd.centroid(Q) P = P - centroidP Q = Q - centroidQ return centroidP, centroidQ, rmsd.kabsch(P, Q)
def calculate_rmsd(mol_id, geometry_id1=None, geometry_id2=None, heavy_atoms_only=False): # These cause circular import errors if we put them at the top of the file from ._girder import GirderClient from ._calculation import GirderMolecule # Allow the user to pass in a GirderMolecule instead of an id if isinstance(mol_id, GirderMolecule): mol_id = mol_id._id if geometry_id1 is None: cjson1 = GirderClient().get('/molecules/%s/cjson' % mol_id) else: cjson1 = GirderClient().get('/molecules/%s/geometries/%s/cjson' % (mol_id, geometry_id1)) if geometry_id2 is None: cjson2 = GirderClient().get('/molecules/%s/cjson' % mol_id) else: cjson2 = GirderClient().get('/molecules/%s/geometries/%s/cjson' % (mol_id, geometry_id2)) coords1 = cjson1['atoms']['coords']['3d'] coords1_triplets = zip(coords1[0::3], coords1[1::3], coords1[2::3]) A = np.array([x for x in coords1_triplets]) coords2 = cjson2['atoms']['coords']['3d'] coords2_triplets = zip(coords2[0::3], coords2[1::3], coords2[2::3]) B = np.array([x for x in coords2_triplets]) if heavy_atoms_only: atomic_numbers = cjson1['atoms']['elements']['number'] heavy_indices = [i for i, n in enumerate(atomic_numbers) if n != 1] A = A.take(heavy_indices, 0) B = B.take(heavy_indices, 0) # Translate A -= rmsd.centroid(A) B -= rmsd.centroid(B) # Rotate U = rmsd.kabsch(A, B) A = np.dot(A, U) return rmsd.rmsd(A, B)
def xyz4a_position(i, lines): template1 = np.array([[-0.93454, 0.91954, 1.11786], [-0.01675, 0.03488, 0.58954], [1.10621, 0.72253, -0.004], [1.6148, 1.14817, -0.57075]]) template2 = np.array([[-0.93454, 0.91954, 1.11786], [-0.01675, 0.03488, 0.58954], [1.10621, 0.72253, -0.004], [1.6148, 1.14817, -0.57075], [-0.64719, -0.82998, -0.40926], [-1.12252, -1.99515, -0.72338]]) amino_acid_position = [] for k in range(i, i + 4, 1): try: x = lines[k][30:38] y = lines[k][38:46] z = lines[k][46:54] amino_acid_position.append(np.asarray([x, y, z], dtype=float)) except: sys.exit( "Error parsing input for the following line: \n{0:s}".format( lines[k])) amino_acid_position = np.asarray(amino_acid_position) #print amino_acid_position a_acid_p = amino_acid_position - rmsd.centroid(amino_acid_position) template1 -= rmsd.centroid(template1) #centroid P2 into f template2 = template2 - rmsd.centroid(template2) #for debug print '*************8888888888888888' #print template1.shape#(4,3) #print a_acid_p.shape#(5,3) #print template2.shape#(6.3) rot = rmsd.kabsch(template1, a_acid_p) #pp is the rotated martix,Rotate matrix P2 unto Q new_position = np.dot(template2, rot) #translation the P2 into initial position after rotation new_position += rmsd.centroid(amino_acid_position) C = new_position.tolist() #print new_position #print lenthg #for n in range(0,6,1): position5 = ('%8s' % str(float('%.3f' % C[4][0]))) + ('%8s' % str( float('%.3f' % C[4][1]))) + ('%8s' % str(float('%.3f' % C[4][2]))) position6 = ('%8s' % str(float('%.3f' % C[5][0]))) + ('%8s' % str( float('%.3f' % C[5][1]))) + ('%8s' % str(float('%.3f' % C[5][2]))) print 'print the position of position 5 and position 6' return position5, position6
def getkabschangle(Ac, Bc): # Ac = Ac[:,0:3:2] # Bc = Bc[:,0:3:2] # Manipulate A = Ac - rmsd.centroid(Ac) B = Bc - rmsd.centroid(Bc) U = rmsd.kabsch(A, B) # print(U) degvals = (rotationMatrixToEulerAngles(U)) return degvals[1] """
def get_rmsd(coords, reference): """ Calculate the rmsd of the given coordinates compared to a reference. Input: > coords list[np.array, np.array, ...]; coordinates to be compared vs. the reference coordinates > reference list[np.array, np.array, ...]; reference to compare coordinates to Sources: https://pypi.org/project/rmsd/ """ # translate center of geometry to the origin for reference and # current frame coords -= rmsd.centroid(coords) reference -= rmsd.centroid(reference) return rmsd.kabsch_rmsd(coords, reference)
def calc_rmsd(coords1, coords2): """Calculate root-mean square deviation. Parameters ---------- coords1 : list(list(str,int,int,int)) The coordinates for the first molecule (conformer). coords2 : list(list(str,int,int,int)) The coordinates for the second molecule (conformer). Notes ----- The coordinates are given as follows: atom name, x coord, y coord, z coord Example for carbon monoxide: [[C, 0.0, 0.0, 0.0],[O, 1.0, 0.0, 0.0]] The distances are in Angstroms. Returns ------- rmsd : float The rmsd between two molecular geometries. This rmsd is calculated after applying centering and a rotation matrix (calculated via the Kabsch algorithm). """ # trivial check assert len(coords1) == len(coords2) # first turn lists into numpy arrays (otherwise # cannot perform some rmsd operations) # and excise atom names (not needed for rmsd) mol1 = np.array([[coords1[i][1], coords1[i][2], coords1[i][3]] for i in range(len(coords1))]) mol2 = np.array([[coords2[i][1], coords2[i][2], coords2[i][3]] for i in range(len(coords2))]) # first center each molecule mol1 -= rmsd.centroid(mol1) mol2 -= rmsd.centroid(mol2) # calculate the rotation matrix rot_matrix = rmsd.kabsch(mol1, mol2) # apply the rotation matrix mol1 = np.dot(mol1, rot_matrix) # finally get the rmsd return rmsd.rmsd(mol1, mol2)
def test_best_fit(A, shuffle = 1): # Generate a random dataset for i in range(num_tests): print('test', i) B = np.copy(A) # Translate t = np.random.rand(dim)*translation B += t # Rotate R = rotation_matrix(np.random.rand(dim), np.random.rand()*rotation) B = np.dot(R, B.T).T # Add noise B += np.random.randn(N, dim) * noise_sigma # Shuffle to disrupt correspondence if (shuffle == 1): np.random.shuffle(B) print("Normal squared_distance", squared_distance(A, B)) plot3d(A, B) # Find best fit transform A -= rmsd.centroid(A) B -= rmsd.centroid(B) T, R1, t1 = icp.best_fit_transform(B, A) # Make C a homogeneous representation of B C = np.ones((N, 4)) C[:,0:3] = B # Transform C C = np.dot(T, C.T).T C = C[:, 0:3] print("Rotated squared_distance", squared_distance(A, C)) plot3d(A, C) #assert np.allclose(C[:,0:3], A, atol=6*noise_sigma) # T should transform B (or C) to A #assert np.allclose(-t1, t, atol=6*noise_sigma) # t and t1 should be inverses #assert np.allclose(R1.T, R, atol=6*noise_sigma) # R and R1 should be inverses return
def test_quaternion_rmsd_pdb(): filename_p = "ci2_1.pdb" filename_q = "ci2_2.pdb" filename_p = pathlib.PurePath(RESOURCE_PATH, filename_p) filename_q = pathlib.PurePath(RESOURCE_PATH, filename_q) p_atoms, p_coord = rmsd.get_coordinates_pdb(filename_p) q_atoms, q_coord = rmsd.get_coordinates_pdb(filename_q) p_center = rmsd.centroid(p_coord) q_center = rmsd.centroid(q_coord) p_coord -= p_center q_coord -= q_center result = rmsd.quaternion_rmsd(p_coord, q_coord) np.testing.assert_almost_equal(11.7768, result, decimal=3)
def align_coordinates(coordinates): # Align everything to first coordinate coordinates = copy.deepcopy(coordinates) coordinate_ref = coordinates[0] coordinate_ref -= rmsd.centroid(coordinate_ref) coordinates[0] = coordinate_ref for i, coordinate in enumerate(coordinates[1:]): coordinate -= rmsd.centroid(coordinate) U = rmsd.kabsch(coordinate, coordinate_ref) coordinate = np.dot(coordinate, U) coordinates[i] = coordinate return coordinates
def calculate_transformation_kabsch( src_points: np.ndarray, dst_points: np.ndarray) -> Tuple[np.array, float]: """ Calculates the optimal rigid transformation from src_points to dst_points (regarding the least squares error) Parameters: ----------- src_points: array (3,N) matrix dst_points: array (3,N) matrix Returns: ----------- rotation_matrix: array (3,3) matrix translation_vector: array (3,1) matrix rmsd_value: float """ assert src_points.shape == dst_points.shape if src_points.shape[0] != 3: raise Exception( "The input data matrix had to be transposed in order to compute transformation." ) src_points = src_points.transpose() dst_points = dst_points.transpose() src_points_centered = src_points - rmsd.centroid(src_points) dst_points_centered = dst_points - rmsd.centroid(dst_points) rotation_matrix = rmsd.kabsch(src_points_centered, dst_points_centered) rmsd_value = rmsd.kabsch_rmsd(src_points_centered, dst_points_centered) translation_vector = rmsd.centroid(dst_points) - np.matmul( rmsd.centroid(src_points), rotation_matrix) return create_homogenous(rotation_matrix.transpose(), translation_vector.transpose()), rmsd_value
def myRMSDmetric(arr1, arr2): """ This function is built under the assumption that the space dimension is 3!!! Requirement from sklearn radius_neighbors_graph: The callable should take two arrays as input and return one value indicating the distance between them. Input: One row from reshaped XYZ trajectory as number of steps times nDOF Inside: Reshape to XYZ format and apply rmsd as r=rmsd(X[i], X[j]) Output: rmsd distance """ nParticles = len(arr1) / 3 assert (nParticles == int(nParticles)) X1 = arr1.reshape(int(nParticles), 3) X2 = arr2.reshape(int(nParticles), 3) X1 = X1 - rmsd.centroid(X1) X2 = X2 - rmsd.centroid(X2) return rmsd.kabsch_rmsd(X1, X2)
def normalize_pts_old(pts1, pts2, win): #print pts1 A = pts1[:, 0:2] B = pts2[:, 0:2] assert len(A) == len(B) N = A.shape[0] # total points # find centroids centroid_A = rmsd.centroid(A) centroid_B = rmsd.centroid(B) # centre the points AA = A - centroid_A BB = B - centroid_B #get optimal rotation matrix R = rmsd.kabsch(AA, BB) # Apply transformation AA1 = np.dot(AA, R) angle1 = math.atan2(R[1][0], R[1][1]) i=0 for pt in pts1: pt_graphics = Point(int(pt[0]-centroid_A[0]+centroid_B[0]), int(pt[1]-centroid_A[1]+centroid_B[1])) cir = Circle(pt_graphics, 8) cir.setOutline('green') cir.draw(win) line = Line(pt_graphics, Point(pt_graphics.x+8*np.cos(-pt[2]), pt_graphics.y+8*np.sin(-pt[2]))) line.draw(win) text = Text(pt_graphics, str(i)) i += 1 text.draw(win) pts1[:, 0:2] = AA1 + centroid_B # rotate the rotations pts1[:, 2] -= angle1 return rmsd.rmsd(AA1, BB)
def test_centroid(): a1 = np.array([-19.658, 17.18, 25.163], dtype=float) a2 = np.array([-20.573, 18.059, 25.88], dtype=float) a3 = np.array([-22.018, 17.551, 26.0], dtype=float) atms = np.asarray([a1, a2, a3]) centroid = rmsd.centroid(atms) assert 3 == len(centroid) np.testing.assert_array_almost_equal([-20.7496, 17.5966, 25.6810], centroid, decimal=3)
def calc_rmsd(self): """ Calculate normal, translated, and rotated RMSD. """ tmp_1, tmp_2 = self.coord_1.copy(), self.coord_2.copy() self.rmsd_normal = rmsd.rmsd(self.coord_1, self.coord_2) # Manipulate recenter self.coord_1 -= rmsd.centroid(self.coord_1) self.coord_2 -= rmsd.centroid(self.coord_2) self.rmsd_translate = rmsd.rmsd(self.coord_1, self.coord_2) # Rotate rotation_matrix = rmsd.kabsch(self.coord_1, self.coord_2) self.coord_1 = np.dot(self.coord_1, rotation_matrix) self.rmsd_rotate = rmsd.rmsd(self.coord_1, self.coord_2) self.coord_1, self.coord_2 = tmp_1, tmp_2
def main(self): """ main object to run DSR as command line program """ dbatoms = [] # The database content: import atomhandling basefilename = filename_wo_ending(self.res_file) if not basefilename: print('*** Illegal option ***') sys.exit() if len(self.reslist) == 0: print("*** The input file is empty. Can not proceed! ***") sys.exit() find_atoms = atomhandling.FindAtoms(self.reslist) rle = ResListEdit(self.reslist, find_atoms) dsrp = DSRParser(self.reslist) self.fragment = dsrp.fragment restraints = self.gdb.get_restraints(self.fragment) # this is only executed once db_residue_string = self.gdb.get_resi(self.fragment) dbatoms = self.gdb.get_atoms(self.fragment, self.invert) # only the atoms of the dbentry as list # the atomtypes of the dbentry as list e.g. ['C', 'N', ...] db_atom_types = atomhandling.get_atomtypes(dbatoms) sf = atomhandling.SfacTable(self.reslist, db_atom_types) sfac_table = sf.set_sfac_table() # from now on this sfac table is set resi = Resi(dsrp, db_residue_string, find_atoms) # line where the dsr command is found in the resfile: if dsrp.cf3_active: from cf3fit import CF3 cf3 = CF3(rle, find_atoms, self.reslist, self.fragment, sfac_table, basefilename, dsrp, resi, self.res_file, self.options) if self.fragment == 'cf3': cf3.cf3(afix='130') if self.fragment == 'cf6': cf3.cf3(afix='120') if self.fragment == 'cf9': cf3.cf9() print('\nFinished...') sys.exit() # checks have to be after CF3, CF6 etc. self.gdb.check_consistency(self.fragment) self.gdb.check_db_atom_consistency(self.fragment) self.gdb.check_db_restraints_consistency(self.fragment) self.gdb.check_sadi_consistence(self.fragment) if dsrp.occupancy: rle.set_free_variables(dsrp.occupancy) restraints = remove_resi(restraints) # corrects the atom type according to the previous defined global sfac table: dbatoms = atomhandling.set_final_db_sfac_types(db_atom_types, dbatoms, sfac_table) if not dsrp.unit_line: print('*** No UNIT instruction in res file found! Can not proceed! ***') print('Inserting {} into res File.'.format(self.fragment)) if self.invert: print('Fragment inverted.') print('Source atoms: {}'.format(', '.join(dsrp.source))) print('Target atoms: {}'.format(', '.join(dsrp.target))) shx = ShelxlRefine(self.reslist, basefilename, find_atoms, self.options) shx.backup_shx_file() # several checks if the atoms in the dsr command line are consistent atomhandling.check_source_target(dsrp.source, dsrp.target, dbatoms) num = atomhandling.NumberScheme(self.reslist, dbatoms, dsrp) # returns also the atom names if residue is active fragment_numberscheme = num.get_fragment_number_scheme() print('Fragment atom names: {}'.format(', '.join(fragment_numberscheme))) dfix_head = '' if dsrp.dfix: restr = Restraints(self.fragment, self.gdb) dfix_12 = restr.get_formated_12_dfixes() dfix_13 = restr.get_formated_13_dfixes() flats = restr.get_formated_flats() restraints = dfix_12 + dfix_13 + flats # ##########Not using SHELXL for fragment fit: ########### print("--- Using fast fragment fit ---") if self.options.target_coords: target_coords = chunks(self.options.target_coords, 3) else: # {'C1': ['1.123', '0.7456', '3.245']} target_coordinates = find_atoms.get_atomcoordinates(dsrp.target) target_coords = [target_coordinates[key] for key in dsrp.target] # Uppercase is important here to avoid KeyErrors in source_atoms generation atnames = self.gdb.get_atomnames(self.fragment, uppercase=True) source_atoms = dict(zip(atnames, self.gdb.get_coordinates(self.fragment, cartesian=True, invert=self.invert))) # Coordinates only from the source, not the entire fragment: source_coords = [source_atoms[x] for x in dsrp.source] target_coords = [frac_to_cart(x, rle.get_cell()) for x in target_coords] from rmsd import fit_fragment # The source and target atom coordinates are fitted first. Then The complete fragment # is rotated and translated to the target position as calculated before. # parameter cartiesian has to be false here: fragment_coords = self.gdb.get_coordinates(self.fragment, cartesian=False, invert=self.invert) fitted_fragment, rmsd = fit_fragment(fragment_coords, source_atoms=source_coords, target_atoms=target_coords) # Moving back to the position of the first atom to have a reference: import numpy as np from rmsd import centroid # I have to make sure that I use the centroid of the correct atoms from target and source, # otherwise the fragment is shifted to a wrong position. # The third atom from the fragment e.g. has to be the third from the fragment to get # the correct centroid: center_difference = centroid(np.array(target_coords)) - \ centroid(np.array([list(fitted_fragment)[atnames.index(dsrp.source[x])] for x in range(len(source_coords))])) # finishing shift to correct centroid: fitted_fragment += center_difference # Or even lower than 0.1? if rmsd < 0.1: print('Fragment fit successful with RMSD of: {:8.3}'.format(rmsd)) else: print('*** Fragment fit might have failed with RMSD of: {:8.3} ***'.format(rmsd)) fitted_fragment = [cart_to_frac(x, rle.get_cell()) for x in fitted_fragment] afix_entry = [] e2s = Elem_2_Sfac(sfac_table) for at, coord, atype in zip(fragment_numberscheme, fitted_fragment, db_atom_types): sfac_num = str(e2s.elem_2_sfac(atype)) if dsrp.occupancy: occ = float(dsrp.occupancy) else: occ = 11.0 afix_entry.append(isoatomstr.format(at, sfac_num, coord[0], coord[1], coord[2], occ, 0.03)) afix_entry = "\n".join(afix_entry) new_atomnames = list(reversed(fragment_numberscheme)) same_resi = '' if not dsrp.resiflag: restraints = rename_restraints_atoms(new_atomnames, self.gdb.get_atomnames(self.fragment), restraints) else: restraints = resi.format_restraints(restraints) # SADI\n same_resi = ["SAME_{} {} > {}\n".format(resi.get_residue_class, new_atomnames[-1], new_atomnames[0])] # Adds a "SAME_resiclass firstatom > lastatom" to the afix: if not self.options.rigid_group: restraints += same_resi # if dsrp.resiflag: # <- Or should I do this? restraints += ["SIMU 0.04 0.08 1"] if not options.external_restr: restraints = remove_duplicate_restraints(self.reslist, restraints, resi.get_residue_class) restraints = wrap_headlines(restraints) dfx_file_name = '' if dsrp.part: afix_entry = "PART {} {}\n".format(dsrp.part, dsrp.occupancy) + afix_entry + "\nPART 0" if dsrp.resiflag: afix_entry = 'RESI {} {}\n{}\nRESI 0'.format(resi.get_residue_class, resi.get_resinumber, afix_entry) if self.options.rigid_group: afix_entry = 'AFIX 9\n' + afix_entry if options.external_restr and not self.rigid: pname, ext = os.path.splitext(basefilename + '.dfix') if dsrp.dfix: dfx_file_name = pname + "_dfx" + ext else: dfx_file_name = pname + ext dfx_file_name = write_dbhead_to_file(dsrp, dfx_file_name, restraints, resi.get_residue_class, resi.get_resinumber) if dsrp.resiflag: restraints = 'REM Restraints for residue {}:\n+{}\n' \ .format(resi.get_residue_class, dfx_file_name) else: restraints = 'REM Restraints for DSR fragment:\n+{}\n' \ .format(dfx_file_name) if self.options.rigid_group: afix_entry += '\nAFIX 0\n' # Adds the origin of restraints and fragment to res file: import textwrap source = textwrap.wrap("REM Restraints for Fragment {}, {} from: {}. " "Please cite https://doi.org/10.1107/S1600576718004508".format( self.fragment, self.gdb.get_fragment_name(self.fragment), self.gdb.get_src(self.fragment)), width=74, subsequent_indent='REM ') source = '\n'.join(source) + '\n' # check if restraints already inserted: for line in self.reslist: try: if line.split()[4] == self.fragment + ',': source = '' break except IndexError: continue # + 'AFIX 0\n' before hklf seems to be not needed after shelx-2013: self.reslist[dsrp.hklf_line - 1] = self.reslist[dsrp.hklf_line - 1] + afix_entry + '\n' if not self.rigid: self.reslist[dsrp.unit_line] = self.reslist[dsrp.unit_line] + source + ''.join(restraints) # write to file: self.rl.write_resfile(self.reslist, '.res') if dsrp.command == 'REPLACE': print("Replace mode active\n") self.rl = ResList(self.res_file) reslist = self.rl.get_res_list() self.reslist, find_atoms = atomhandling.replace_after_fit(self.rl, reslist, resi, fragment_numberscheme, rle.get_cell()) self.rl.write_resfile(self.reslist, '.res') os.remove(shx.backup_file)
[2.0, 1.5]]) # Same "molecule" B = np.array([[1.0, 1.0], [1.0, 2.0], [2.0, 1.5]]) B *= 1.4 # Translate B -= 3 # Rotate B = np.dot(B, rotation_matrix(90)) print("Normal RMSD", rmsd.rmsd(A, B)) save_plot(A, B, "plot_beginning.png") # Manipulate A -= rmsd.centroid(A) B -= rmsd.centroid(B) print("Centered RMSD", rmsd.rmsd(A, B)) save_plot(A, B, "plot_centered.png") U = rmsd.kabsch(A, B) A = np.dot(A, U) print("Translated RMSD", rmsd.rmsd(A, B)) save_plot(A, B, "plot_translated.png")