def cone_edge(mol=None, cone_obj=None, res_name='CON', res_num=None, chain_id='', apex=None, axis=None, R=None, scale=None, inc=None, distribution='uniform'): """Add a residue to the atomic data representing a cone of the given angle. A series of vectors totalling the number of increments and starting at the origin are equally spaced around the cone axis. The atoms representing neighbouring vectors will be directly bonded together. This will generate an object representing the outer edge of a cone. @keyword mol: The molecule container. @type mol: MolContainer instance @keyword cone_obj: The cone object. This should provide the limit_check() method with determines the limits of the distribution accepting two arguments, the polar angle phi and the azimuthal angle theta, and return True if the point is in the limits or False if outside. It should also provide the phi_max() method for returning the phi value for the given theta. @type cone_obj: class instance @keyword res_name: The residue name. @type res_name: str @keyword res_num: The residue number. @type res_num: int @keyword chain_id: The chain identifier. @type chain_id: str @keyword apex: The apex of the cone. @type apex: numpy array, len 3 @keyword axis: The central axis of the cone. If supplied, then this arg will be used to construct the rotation matrix. @type axis: numpy array, len 3 @keyword R: A 3x3 rotation matrix. If the axis arg supplied, then this matrix will be ignored. @type R: 3x3 numpy array @keyword scale: The scaling factor to stretch all points by. @type scale: float @keyword inc: The number of increments or number of vectors used to generate the outer edge of the cone. @type inc: int @keyword distribution: The type of point distribution to use. This can be 'uniform' or 'regular'. @type distribution: str """ # The atom numbers (and indices). atom_num = 1 if len(mol.atom_num): atom_num = mol.atom_num[-1]+1 # Add an atom for the cone apex. mol.atom_add(pdb_record='HETATM', atom_num=atom_num, atom_name='APX', res_name=res_name, res_num=res_num, pos=apex, segment_id=None, element='H') origin_atom = atom_num # Get the polar and azimuthal angles for the distribution. if distribution == 'uniform': phi, theta = angles_uniform(inc) else: phi, theta = angles_regular(inc) # Initialise the rotation matrix. if R is None: R = eye(3) # Get the rotation matrix. if axis != None: two_vect_to_R(array([0, 0, 1], float64), axis, R) # Determine the maximum phi values of the point just above the edge. phi_max = zeros(len(theta), float64) for i in range(len(theta)): phi_max[i] = cone_obj.phi_max(theta[i]) # Move around the azimuth. atom_num = atom_num + 1 for i in range(len(theta)): # The vector in the unrotated frame. x = cos(theta[i]) * sin(phi_max[i]) y = sin(theta[i])* sin(phi_max[i]) z = cos(phi_max[i]) vector = array([x, y, z], float64) # Rotate the vector. vector = dot(R, vector) # The atom id. atom_id = 'T' + repr(i) # The atom position. pos = apex+vector*scale # Add the vector as a H atom of the cone residue. mol.atom_add(pdb_record='HETATM', atom_num=atom_num, atom_name=get_proton_name(atom_num), res_name=res_name, res_num=res_num, pos=pos, segment_id=None, element='H') # Join the longitude atom to the cone apex. mol.atom_connect(index1=origin_atom-1, index2=atom_num-1) # Increment the atom number. atom_num = atom_num + 1 # Build the cone edge. for i in range(origin_atom, atom_num-2): mol.atom_connect(index1=i, index2=i+1) # Connect the last radial array to the first (to zip up the circle). mol.atom_connect(index1=atom_num-2, index2=origin_atom)
def generate_vector_dist(mol=None, res_name=None, res_num=None, chain_id='', centre=zeros(3, float64), R=eye(3), warp=eye(3), phi_max_fn=None, scale=1.0, inc=20, distribution='uniform'): """Generate a uniformly distributed distribution of atoms on a warped sphere. The vectors from the function vect_dist_spherical_angles() are used to generate the distribution. These vectors are rotated to the desired frame using the rotation matrix 'R', then each compressed or stretched by the dot product with the 'warp' matrix. Each vector is centred and at the head of the vector, a proton is placed. @keyword mol: The molecule container. @type mol: MolContainer instance @keyword res_name: The residue name. @type res_name: str @keyword res_num: The residue number. @type res_num: int @keyword chain_id: The chain identifier. @type chain_id: str @keyword centre: The centre of the distribution. @type centre: numpy array, len 3 @keyword R: The optional 3x3 rotation matrix. @type R: 3x3 numpy array @keyword warp: The optional 3x3 warping matrix. @type warp: numpy array @keyword phi_max_fn: A function with determines the limits of the distribution. It should accept the azimuthal angle theta as an argument and return the corresponding maximum allowed polar angle phi. @type phi_max_fn: function @keyword scale: The scaling factor to stretch all rotated and warped vectors by. @type scale: float @keyword inc: The number of increments or number of vectors. @type inc: int @keyword distribution: The type of point distribution to use. This can be 'uniform' or 'regular'. @type distribution: str """ # Initial atom number. if len(mol.atom_num) == 0: origin_num = 1 else: origin_num = mol.atom_num[-1] + 1 atom_num = origin_num # Get the uniform vector distribution. print(" Creating the uniform vector distribution.") vectors = vect_dist_spherical_angles(inc=inc, distribution=distribution) # Get the polar and azimuthal angles for the distribution. if distribution == 'uniform': phi, theta = angles_uniform(inc) else: phi, theta = angles_regular(inc) # Init the arrays for stitching together. edge = zeros(len(theta)) edge_index = zeros(len(theta), int) edge_atom = zeros(len(theta)) # Determine the maximum phi values of the point just above the edge, and create a set of vectors to use for all points outside of the limits. if phi_max_fn: phi_max = zeros(len(theta), float64) edge_vectors = zeros((len(theta), 3), float64) for i in range(len(theta)): # The maximum angle. phi_max[i] = phi_max_fn(theta[i]) # The vector in the unrotated frame. edge_vectors[i, 0] = cos(theta[i]) * sin(phi_max[i]) edge_vectors[i, 1] = sin(theta[i]) * sin(phi_max[i]) edge_vectors[i, 2] = cos(phi_max[i]) # Loop over the radial array of vectors (change in longitude). for i in range(len(theta)): # Loop over the vectors of the radial array (change in latitude). for j in range(len(phi)): # The vector to use. if phi_max_fn and phi[j] > phi_max_fn(theta[i]): vector = edge_vectors[i] else: vector = vectors[i + j * len(theta)] # Update the edge for this longitude. if not edge[i]: edge[i] = 1 edge_index[i] = j edge_atom[i] = atom_num # Rotate the vector into the frame. vector = dot(R, vector) # Warp the vector. vector = dot(warp, vector) # Scale the vector. vector = vector * scale # Position relative to the centre of mass. pos = centre + vector # Add the vector as a H atom of the TNS residue. mol.atom_add(pdb_record='HETATM', atom_num=atom_num, atom_name=get_proton_name(atom_num), res_name=res_name, chain_id=chain_id, res_num=res_num, pos=pos, segment_id=None, element='H') # Connect to the previous atom to generate the longitudinal lines (except for the first point). if j > edge_index[i]: mol.atom_connect(index1=atom_num - 1, index2=atom_num - 2) # Connect across the radial arrays (to generate the latitudinal lines). if i != 0 and j >= edge_index[i - 1]: # The number of atoms back to the previous longitude. num = len(phi) - edge_index[i] # Latitude line. mol.atom_connect(index1=atom_num - 1, index2=atom_num - 1 - num) # Connect the last radial array to the first (to zip up the geometric object and close the latitudinal lines). if i == len(theta) - 1 and j >= edge_index[0]: # The number of atom in the first longitude line. num = origin_num + j - edge_index[0] # Zipping up. mol.atom_connect(index1=atom_num - 1, index2=num - 1) # Increment the atom number. atom_num = atom_num + 1
def generate_vector_dist(mol=None, res_name=None, res_num=None, chain_id='', centre=zeros(3, float64), R=eye(3), warp=eye(3), phi_max_fn=None, scale=1.0, inc=20, distribution='uniform'): """Generate a uniformly distributed distribution of atoms on a warped sphere. The vectors from the function vect_dist_spherical_angles() are used to generate the distribution. These vectors are rotated to the desired frame using the rotation matrix 'R', then each compressed or stretched by the dot product with the 'warp' matrix. Each vector is centred and at the head of the vector, a proton is placed. @keyword mol: The molecule container. @type mol: MolContainer instance @keyword res_name: The residue name. @type res_name: str @keyword res_num: The residue number. @type res_num: int @keyword chain_id: The chain identifier. @type chain_id: str @keyword centre: The centre of the distribution. @type centre: numpy array, len 3 @keyword R: The optional 3x3 rotation matrix. @type R: 3x3 numpy array @keyword warp: The optional 3x3 warping matrix. @type warp: numpy array @keyword phi_max_fn: A function with determines the limits of the distribution. It should accept the azimuthal angle theta as an argument and return the corresponding maximum allowed polar angle phi. @type phi_max_fn: function @keyword scale: The scaling factor to stretch all rotated and warped vectors by. @type scale: float @keyword inc: The number of increments or number of vectors. @type inc: int @keyword distribution: The type of point distribution to use. This can be 'uniform' or 'regular'. @type distribution: str """ # Initial atom number. if len(mol.atom_num) == 0: origin_num = 1 else: origin_num = mol.atom_num[-1]+1 atom_num = origin_num # Get the uniform vector distribution. print(" Creating the uniform vector distribution.") vectors = vect_dist_spherical_angles(inc=inc, distribution=distribution) # Get the polar and azimuthal angles for the distribution. if distribution == 'uniform': phi, theta = angles_uniform(inc) else: phi, theta = angles_regular(inc) # Init the arrays for stitching together. edge = zeros(len(theta)) edge_index = zeros(len(theta), int) edge_atom = zeros(len(theta)) # Determine the maximum phi values of the point just above the edge, and create a set of vectors to use for all points outside of the limits. if phi_max_fn: phi_max = zeros(len(theta), float64) edge_vectors = zeros((len(theta), 3), float64) for i in range(len(theta)): # The maximum angle. phi_max[i] = phi_max_fn(theta[i]) # The vector in the unrotated frame. edge_vectors[i, 0] = cos(theta[i]) * sin(phi_max[i]) edge_vectors[i, 1] = sin(theta[i])* sin(phi_max[i]) edge_vectors[i, 2] = cos(phi_max[i]) # Loop over the radial array of vectors (change in longitude). for i in range(len(theta)): # Loop over the vectors of the radial array (change in latitude). for j in range(len(phi)): # The vector to use. if phi_max_fn and phi[j] > phi_max_fn(theta[i]): vector = edge_vectors[i] else: vector = vectors[i + j*len(theta)] # Update the edge for this longitude. if not edge[i]: edge[i] = 1 edge_index[i] = j edge_atom[i] = atom_num # Rotate the vector into the frame. vector = dot(R, vector) # Warp the vector. vector = dot(warp, vector) # Scale the vector. vector = vector * scale # Position relative to the centre of mass. pos = centre + vector # Add the vector as a H atom of the TNS residue. mol.atom_add(pdb_record='HETATM', atom_num=atom_num, atom_name=get_proton_name(atom_num), res_name=res_name, chain_id=chain_id, res_num=res_num, pos=pos, segment_id=None, element='H') # Connect to the previous atom to generate the longitudinal lines (except for the first point). if j > edge_index[i]: mol.atom_connect(index1=atom_num-1, index2=atom_num-2) # Connect across the radial arrays (to generate the latitudinal lines). if i != 0 and j >= edge_index[i-1]: # The number of atoms back to the previous longitude. num = len(phi) - edge_index[i] # Latitude line. mol.atom_connect(index1=atom_num-1, index2=atom_num-1-num) # Connect the last radial array to the first (to zip up the geometric object and close the latitudinal lines). if i == len(theta)-1 and j >= edge_index[0]: # The number of atom in the first longitude line. num = origin_num + j - edge_index[0] # Zipping up. mol.atom_connect(index1=atom_num-1, index2=num-1) # Increment the atom number. atom_num = atom_num + 1