def random_ellipsoid(box, size, min_axis): # return a random ellipsoid record of the form: # [ ELLIPSOID, x_pos, y_pos, z_pos, size, x0, y0, z0, x1, y1, z2, x2, y2, z2 ] # where the xyz vectors are orthogonal and of length 1.0 or less. box = box - size tmp0 = cpv.random_vector() tmp1 = cpv.random_vector() tmp2 = cpv.cross_product(tmp1, tmp0) tmp3 = cpv.cross_product(tmp1, tmp2) tmp4 = cpv.cross_product(tmp2, tmp3) tmp2 = cpv.normalize(tmp2) tmp3 = cpv.normalize(tmp3) tmp4 = cpv.normalize(tmp4) primary = cpv.scale(tmp2, random()) secondary = cpv.scale(tmp3,random()) tertiary = cpv.scale(tmp4,random()) factor = 1.0 / max( cpv.length(primary), cpv.length(secondary), cpv.length(tertiary)) primary = cpv.scale(primary, factor) secodary = cpv.scale(secondary, factor) tertiary = cpv.scale(tertiary, factor) return [ ELLIPSOID, size + random() * box, size + random() * box, size + random() * box, max(random() * size, min_axis), ] + primary + secondary + tertiary
def visualize_orientation(direction, center=[0.0] * 3, scale=1.0, symmetric=False, color='green', color2='red'): ''' DESCRIPTION Draw an arrow. Helper function for "helix_orientation" etc. ''' from pymol import cgo color_list = cmd.get_color_tuple(color) color2_list = cmd.get_color_tuple(color2) if symmetric: scale *= 0.5 end = cpv.add(center, cpv.scale(direction, scale)) radius = 0.3 obj = [cgo.SAUSAGE] obj.extend(center) obj.extend(end) obj.extend([ radius, 0.8, 0.8, 0.8, ]) obj.extend(color_list) if symmetric: start = cpv.sub(center, cpv.scale(direction, scale)) obj.append(cgo.SAUSAGE) obj.extend(center) obj.extend(start) obj.extend([ radius, 0.8, 0.8, 0.8, ]) obj.extend(color2_list) coneend = cpv.add( end, cpv.scale(direction, 4.0 * radius / cpv.length(direction))) obj.append(cgo.CONE) obj.extend(end) obj.extend(coneend) obj.extend([ radius * 1.75, 0.0, ]) obj.extend(color_list * 2) obj.extend([ 1.0, 1.0, # Caps ]) cmd.load_cgo(obj, get_unused_name('oriVec'), zoom=0)
def pdbBox(line): ''' Parses a gro box line and returns a pdb CRYST1 line ''' from math import degrees from chempy.cpv import length, get_angle v = [10*float(i) for i in line.split()] + 6*[0] # Padding for rectangular boxes v1, v2, v3 = (v[0], v[3], v[4]), (v[5], v[1], v[6]), (v[7], v[8], v[2]) a = length(v1) b = length(v2) c = length(v3) alpha = degrees(get_angle(v2, v3)) beta = degrees(get_angle(v1, v3)) gamma = degrees(get_angle(v1, v2)) return _pdbBoxLine % (a, b, c, alpha, beta, gamma)
def visualize_orientation(direction, center=[0.0]*3, scale=1.0, symmetric=False, color='green', color2='red'): ''' DESCRIPTION Draw an arrow. Helper function for "helix_orientation" etc. ''' from pymol import cgo color_list = cmd.get_color_tuple(color) color2_list = cmd.get_color_tuple(color2) if symmetric: scale *= 0.5 end = cpv.add(center, cpv.scale(direction, scale)) radius = 0.3 obj = [cgo.SAUSAGE] obj.extend(center) obj.extend(end) obj.extend([ radius, 0.8, 0.8, 0.8, ]) obj.extend(color_list) if symmetric: start = cpv.sub(center, cpv.scale(direction, scale)) obj.append(cgo.SAUSAGE) obj.extend(center) obj.extend(start) obj.extend([ radius, 0.8, 0.8, 0.8, ]) obj.extend(color2_list) coneend = cpv.add(end, cpv.scale(direction, 4.0*radius/cpv.length(direction))) obj.append(cgo.CONE) obj.extend(end) obj.extend(coneend) obj.extend([ radius * 1.75, 0.0, ]) obj.extend(color_list * 2) obj.extend([ 1.0, 1.0, # Caps ]) cmd.load_cgo(obj, get_unused_name('oriVec'), zoom=0)
def scramble(self,mode): if self.cmd.count_atoms(self.sculpt_object): sc_tmp = "_scramble_tmp" if mode == 0: self.cmd.select(sc_tmp,self.sculpt_object+ " and not (fixed or restrained)") if mode == 1: self.cmd.select(sc_tmp,self.sculpt_object+ " and not (fixed)") extent = self.cmd.get_extent(sc_tmp) center = self.cmd.get_position(sc_tmp) radius = 1.25*cpv.length(cpv.sub(extent[0],extent[1])) self.cmd.alter_state(self.cmd.get_state(), sc_tmp, "(x,y,z)=rsp(pos,rds)", space= { 'rsp' : cpv.random_displacement, 'pos' : center, 'rds' : radius }) self.cmd.delete(sc_tmp)
def helix_orientation_hbond(selection, visualize=1, cutoff=3.5, quiet=0): ''' DESCRIPTION Get the center and direction of a helix as vectors. Will only work for alpha helices and gives slightly different results than helix_orientation. Averages direction of O(i)->N(i+4) hydrogen bonds. USAGE helix_orientation selection [, visualize [, cutoff]] ARGUMENTS cutoff = float: maximal hydrogen bond distance {default: 3.5} SEE ALSO helix_orientation ''' visualize, quiet, cutoff = int(visualize), int(quiet), float(cutoff) stored.x = dict() cmd.iterate_state(STATE, '(%s) and name N+O' % (selection), 'stored.x.setdefault(resv, dict())[name] = x,y,z') vec_list = [] for resi in stored.x: resi_other = resi + 4 if 'O' in stored.x[resi] and resi_other in stored.x: if 'N' in stored.x[resi_other]: vec = cpv.sub(stored.x[resi_other]['N'], stored.x[resi]['O']) if cpv.length(vec) < cutoff: vec_list.append(vec) if len(vec_list) == 0: print 'warning: count == 0' raise CmdException vec = _vec_sum(vec_list) vec = cpv.normalize(vec) return _common_orientation(selection, vec, visualize, quiet)
def compute_surface_normals(): ''' Compute average normals from all adjacent triangles on each vertex ''' from functools import reduce # don't use cpv.normalize which has an RSMALL4 limit normalize = lambda v: cpv.scale(v, 1. / cpv.length(v)) for face in table['face']: if 'vertex_index' in face: indices = face['vertex_index'] elif 'vertex_indices' in face: indices = face['vertex_indices'] else: return f_vert = [vertices[i] for i in indices] f_xyz = [(v['x'], v['y'], v['z']) for v in f_vert] try: normal = normalize(cpv.cross_product( cpv.sub(f_xyz[1], f_xyz[0]), cpv.sub(f_xyz[2], f_xyz[1]))) except ZeroDivisionError: continue for v in f_vert: v.setdefault('normals', []).append(normal) for v in vertices: try: v['nx'], v['ny'], v['nz'] = normalize( reduce(cpv.add, v.pop('normals'))) except (KeyError, ZeroDivisionError): continue
def angle_between_domains(selection1, selection2, method='align', state1=STATE, state2=STATE, visualize=1, quiet=1): ''' DESCRIPTION Angle by which a molecular selection would be rotated when superposing on a selection2. Do not use for measuring angle between helices, since the alignment of the helices might involve a rotation around the helix axis, which will result in a larger angle compared to the angle between helix axes. USAGE angle_between_domains selection1, selection2 [, method ] ARGUMENTS selection1 = string: atom selection of first helix selection2 = string: atom selection of second helix method = string: alignment command like "align" or "super" {default: align} EXAMPLE fetch 3iplA 3iplB, async=0 select domain1, resi 1-391 select domain2, resi 392-475 align 3iplA and domain1, 3iplB and domain1 angle_between_domains 3iplA and domain2, 3iplB and domain2 SEE ALSO align, super, angle_between_helices ''' import math try: import numpy except ImportError: print ' Error: numpy not available' raise CmdException state1, state2 = int(state1), int(state2) visualize, quiet = int(visualize), int(quiet) if cmd.is_string(method): try: method = cmd.keyword[method][0] except KeyError: print 'no such method:', method raise CmdException mobile_tmp = get_unused_name('_') cmd.create(mobile_tmp, selection1, state1, 1, zoom=0) try: method(mobile=mobile_tmp, target=selection2, mobile_state=1, target_state=state2, quiet=quiet) mat = cmd.get_object_matrix(mobile_tmp) except: print ' Error: superposition with method "%s" failed' % (method.__name__) raise CmdException finally: cmd.delete(mobile_tmp) try: # Based on transformations.rotation_from_matrix # Copyright (c) 2006-2012, Christoph Gohlke R33 = [mat[i:i+3] for i in [0,4,8]] R33 = numpy.array(R33, float) # direction: unit eigenvector of R33 corresponding to eigenvalue of 1 w, W = numpy.linalg.eig(R33.T) i = w.real.argmax() direction = W[:, i].real # rotation angle depending on direction m = direction.argmax() i,j,k,l = [ [2,1,1,2], [0,2,0,2], [1,0,0,1]][m] cosa = (R33.trace() - 1.0) / 2.0 sina = (R33[i, j] + (cosa - 1.0) * direction[k] * direction[l]) / direction[m] angle = math.atan2(sina, cosa) angle = abs(math.degrees(angle)) except: print ' Error: rotation from matrix failed' raise CmdException if not quiet: try: # make this import optional to support running this script standalone from .querying import centerofmass, gyradius except (ValueError, ImportError): gyradius = None try: # PyMOL 1.7.1.6+ centerofmass = cmd.centerofmass except AttributeError: centerofmass = lambda s: cpv.scale(cpv.add(*cmd.get_extent(s)), 0.5) center1 = centerofmass(selection1) center2 = centerofmass(selection2) print ' Angle: %.2f deg, Displacement: %.2f angstrom' % (angle, cpv.distance(center1, center2)) if visualize: center1 = numpy.array(center1, float) center2 = numpy.array(center2, float) center = (center1 + center2) / 2.0 if gyradius is not None: rg = numpy.array(gyradius(selection1), float) else: rg = 10.0 h1 = numpy.cross(center2 - center1, direction) h2 = numpy.dot(R33, h1) h1 *= rg / cpv.length(h1) h2 *= rg / cpv.length(h2) for pos in [center1, center2, center1 + h1, center1 + h2]: cmd.pseudoatom(mobile_tmp, pos=list(pos), state=1) # measurement object for angle and displacement name = get_unused_name('measurement') cmd.distance(name, *['%s`%d' % (mobile_tmp, i) for i in [1,2]]) cmd.angle(name, *['%s`%d' % (mobile_tmp, i) for i in [3,1,4]]) # CGO arrow for axis of rotation visualize_orientation(direction, center1, rg, color='blue') cmd.delete(mobile_tmp) return angle
def angle_between_domains(selection1, selection2, method='align', state1=STATE, state2=STATE, visualize=1, quiet=1): ''' DESCRIPTION Angle by which a molecular selection would be rotated when superposing on a selection2. Do not use for measuring angle between helices, since the alignment of the helices might involve a rotation around the helix axis, which will result in a larger angle compared to the angle between helix axes. USAGE angle_between_domains selection1, selection2 [, method ] ARGUMENTS selection1 = string: atom selection of first helix selection2 = string: atom selection of second helix method = string: alignment command like "align" or "super" {default: align} EXAMPLE fetch 3iplA 3iplB, bsync=0 select domain1, resi 1-391 select domain2, resi 392-475 align 3iplA and domain1, 3iplB and domain1 angle_between_domains 3iplA and domain2, 3iplB and domain2 SEE ALSO align, super, angle_between_helices ''' import math try: import numpy except ImportError: print(' Error: numpy not available') raise CmdException state1, state2 = int(state1), int(state2) visualize, quiet = int(visualize), int(quiet) if cmd.is_string(method): try: method = cmd.keyword[method][0] except KeyError: print('no such method:', method) raise CmdException mobile_tmp = get_unused_name('_') cmd.create(mobile_tmp, selection1, state1, 1, zoom=0) try: method(mobile=mobile_tmp, target=selection2, mobile_state=1, target_state=state2, quiet=quiet) mat = cmd.get_object_matrix(mobile_tmp) except: print(' Error: superposition with method "%s" failed' % (method.__name__)) raise CmdException finally: cmd.delete(mobile_tmp) try: # Based on transformations.rotation_from_matrix # Copyright (c) 2006-2012, Christoph Gohlke R33 = [mat[i:i + 3] for i in [0, 4, 8]] R33 = numpy.array(R33, float) # direction: unit eigenvector of R33 corresponding to eigenvalue of 1 w, W = numpy.linalg.eig(R33.T) i = w.real.argmax() direction = W[:, i].real # rotation angle depending on direction m = direction.argmax() i, j, k, l = [[2, 1, 1, 2], [0, 2, 0, 2], [1, 0, 0, 1]][m] cosa = (R33.trace() - 1.0) / 2.0 sina = (R33[i, j] + (cosa - 1.0) * direction[k] * direction[l]) / direction[m] angle = math.atan2(sina, cosa) angle = abs(math.degrees(angle)) except: print(' Error: rotation from matrix failed') raise CmdException if not quiet: try: # make this import optional to support running this script standalone from .querying import centerofmass, gyradius except (ValueError, ImportError): gyradius = None try: # PyMOL 1.7.1.6+ centerofmass = cmd.centerofmass except AttributeError: centerofmass = lambda s: cpv.scale(cpv.add(*cmd.get_extent(s)), 0.5) center1 = centerofmass(selection1) center2 = centerofmass(selection2) print(' Angle: %.2f deg, Displacement: %.2f angstrom' % (angle, cpv.distance(center1, center2))) if visualize: center1 = numpy.array(center1, float) center2 = numpy.array(center2, float) center = (center1 + center2) / 2.0 if gyradius is not None: rg = numpy.array(gyradius(selection1), float) else: rg = 10.0 h1 = numpy.cross(center2 - center1, direction) h2 = numpy.dot(R33, h1) h1 *= rg / cpv.length(h1) h2 *= rg / cpv.length(h2) for pos in [center1, center2, center1 + h1, center1 + h2]: cmd.pseudoatom(mobile_tmp, pos=list(pos), state=1) # measurement object for angle and displacement name = get_unused_name('measurement') cmd.distance(name, *['%s`%d' % (mobile_tmp, i) for i in [1, 2]]) cmd.angle(name, *['%s`%d' % (mobile_tmp, i) for i in [3, 1, 4]]) # CGO arrow for axis of rotation visualize_orientation(direction, center1, rg, color='blue') cmd.delete(mobile_tmp) return angle