Author: bugman Date: Wed Oct 26 12:24:24 2011 New Revision: 14925 URL: http://svn.gna.org/viewcvs/relax?rev=14925&view=rev Log: Implemented the back end of the structure.superimpose user function. This only implements the 'fit to first' algorithm. The 'fit to mean' is yet to be implemented. Modified: 1.3/generic_fns/structure/internal.py 1.3/generic_fns/structure/main.py 1.3/generic_fns/structure/superimpose.py Modified: 1.3/generic_fns/structure/internal.py URL: http://svn.gna.org/viewcvs/relax/1.3/generic_fns/structure/internal.py?rev=14925&r1=14924&r2=14925&view=diff ============================================================================== --- 1.3/generic_fns/structure/internal.py (original) +++ 1.3/generic_fns/structure/internal.py Wed Oct 26 12:24:24 2011 @@ -1044,6 +1044,27 @@ mol.z[i] = pos[2] + def translate(self, T=None, model=None): + """Displace the structural information by the given translation vector. + + @keyword T: The translation vector. + @type T: numpy 3D, rank-1 array + @keyword model: The model to rotate. If None, all models will be rotated. + @type model: int + """ + + # Loop over the models. + for model_cont in self.model_loop(model): + # Loop over the molecules. + for mol in model_cont.mol: + # Loop over the atoms. + for i in range(len(mol.atom_num)): + # Translate. + mol.x[i] = mol.x[i] + T[0] + mol.y[i] = mol.y[i] + T[1] + mol.z[i] = mol.z[i] + T[2] + + def write_pdb(self, file, model_num=None): """Method for the creation of a PDB file from the structural data. Modified: 1.3/generic_fns/structure/main.py URL: http://svn.gna.org/viewcvs/relax/1.3/generic_fns/structure/main.py?rev=14925&r1=14924&r2=14925&view=diff ============================================================================== --- 1.3/generic_fns/structure/main.py (original) +++ 1.3/generic_fns/structure/main.py Wed Oct 26 12:24:24 2011 @@ -37,6 +37,7 @@ from generic_fns.structure.api_base import Displacements from generic_fns.structure.internal import Internal from generic_fns.structure.scientific import Scientific_data +from generic_fns.structure.superimpose import kabsch from relax_errors import RelaxError, RelaxFileError, RelaxNoPdbError, RelaxNoSequenceError from relax_io import get_file_path, open_write_file, write_spin_data from relax_warnings import RelaxWarning, RelaxNoPDBFileWarning, RelaxZeroVectorWarning @@ -487,6 +488,94 @@ spin.xh_vect = xh_vect +def superimpose(models=None, method='fit to mean', atom_id=None): + """Superimpose a set of structural models. + + @keyword models: The list of models to superimpose. If set to None, then all models will be used. + @type models: list of int or None + @keyword method: The superimposition method. It must be one of 'fit to mean' or 'fit to first'. + @type method: str + @keyword atom_id: The molecule, residue, and atom identifier string. This matches the spin ID string format. + @type atom_id: str or None + """ + + # Check the method. + allowed = ['fit to mean', 'fit to first'] + if method not in allowed: + raise RelaxError("The superimposition method '%s' is unknown. It must be one of %s." % (method, allowed)) + + # Create a list of all models. + if models == None: + models = [] + for model in cdp.structure.model_loop(): + models.append(model.num) + + # The different algorithms. + if method == 'fit to mean': + superimpose_to_mean(models=models, atom_id=atom_id) + elif method == 'fit to first': + superimpose_to_first(models=models, atom_id=atom_id) + + +def superimpose_to_first(models=None, atom_id=None): + """Superimpose a set of structural models using the fit to first algorithm. + + @keyword models: The list of models to superimpose. + @type models: list of int + @keyword atom_id: The molecule, residue, and atom identifier string. This matches the spin ID string format. + @type atom_id: str or None + """ + + # Print out. + print("\nSuperimposition of structural models %s using the 'fit to first' algorithm." % models) + + # Assemble the atomic coordinates of the first model. + coord_to = [] + for pos in cdp.structure.atom_loop(atom_id=atom_id, model_num=models[0], pos_flag=True): + coord_to.append(pos[0]) + coord_to = array(coord_to) + + # Loop over the ending models. + for model in models[1:]: + # Assemble the atomic coordinates. + coord_from = [] + for pos in cdp.structure.atom_loop(atom_id=atom_id, model_num=model, pos_flag=True): + coord_from.append(pos[0]) + coord_from = array(coord_from) + + # Calculate the displacements (Kabsch algorithm). + trans_vect, trans_dist, R, axis, angle, pivot = kabsch(name_from='model %s'%models[0], name_to='model %s'%model, coord_from=coord_from, coord_to=coord_to) + + # Translate the molecule first (the rotational pivot is defined in the first model). + translate(T=trans_vect, model=model) + + # Rotate the molecule. + rotate(R=R, origin=pivot, model=model) + + +def translate(T=None, model=None): + """Shift the structural data by the specified translation vector. + + @keyword T: The translation vector. + @type T: numpy rank-1, 3D array or list of float + @keyword model: The model to translate. If None, all models will be rotated. + @type model: int + """ + + # Test if the current data pipe exists. + pipes.test() + + # Test if the structure exists. + if not hasattr(cdp, 'structure') or not cdp.structure.num_models() or not cdp.structure.num_molecules(): + raise RelaxNoPdbError + + # Convert the args to numpy float data structures. + T = array(T, float64) + + # Call the specific code. + cdp.structure.translate(T=T, model=model) + + def vectors(attached=None, spin_id=None, model=None, verbosity=1, ave=True, unit=True): """Extract the bond vectors from the loaded structures and store them in the spin container. Modified: 1.3/generic_fns/structure/superimpose.py URL: http://svn.gna.org/viewcvs/relax/1.3/generic_fns/structure/superimpose.py?rev=14925&r1=14924&r2=14925&view=diff ============================================================================== --- 1.3/generic_fns/structure/superimpose.py (original) +++ 1.3/generic_fns/structure/superimpose.py Wed Oct 26 12:24:24 2011 @@ -64,8 +64,8 @@ @type coord_to: numpy rank-2, Nx3 array @keyword centroid: An alternative position of the centroid, used for studying pivoted systems. @type centroid: list of float or numpy rank-1, 3D array - @return: The translation vector T, translation distance d, rotation matrix R, rotation axis r, and rotation angle theta. - @rtype: numpy rank-1 3D array, float, numpy rank-2 3D array, numpy rank-1 3D array, float + @return: The translation vector T, translation distance d, rotation matrix R, rotation axis r, rotation angle theta, and the rotational pivot defined as the centroid of the ending structure. + @rtype: numpy rank-1 3D array, float, numpy rank-2 3D array, numpy rank-1 3D array, float, numpy rank-1 3D array """ # Calculate the centroids. @@ -86,7 +86,7 @@ # Print out. if verbosity >= 1: - print("\n\nCalculating the rotational and translational displacements from model %s to model %s.\n" % (name_from, name_to)) + print("\n\nCalculating the rotational and translational displacements from %s to %s using the Kabsch algorithm.\n" % (name_from, name_to)) print("Start centroid: [%20.15f, %20.15f, %20.15f]" % (centroid_from[0], centroid_from[1], centroid_from[2])) print("End centroid: [%20.15f, %20.15f, %20.15f]" % (centroid_to[0], centroid_to[1], centroid_to[2])) print("Translation vector: [%20.15f, %20.15f, %20.15f]" % (trans_vect[0], trans_vect[1], trans_vect[2])) @@ -99,7 +99,7 @@ print("Rotation angle (deg): %.15f" % (angle / 2.0 / pi * 360.0)) # Return the data. - return trans_vect, trans_dist, R, axis, angle + return trans_vect, trans_dist, R, axis, angle, centroid_to def kabsch_rotation(coord_from=None, coord_to=None, centroid_from=None, centroid_to=None):