Author: bugman Date: Wed Oct 1 19:44:24 2014 New Revision: 26112 URL: http://svn.gna.org/viewcvs/relax?rev=26112&view=rev Log: Implemented the structure.align user function backend. This is similar to the structure.superimpose user function, however the coordinate data structure only contains atoms which are in common to all structures. Modified: trunk/pipe_control/structure/main.py Modified: trunk/pipe_control/structure/main.py URL: http://svn.gna.org/viewcvs/relax/trunk/pipe_control/structure/main.py?rev=26112&r1=26111&r2=26112&view=diff ============================================================================== --- trunk/pipe_control/structure/main.py (original) +++ trunk/pipe_control/structure/main.py Wed Oct 1 19:44:24 2014 @@ -42,7 +42,7 @@ from pipe_control import molmol, pipes from pipe_control.interatomic import interatomic_loop from pipe_control.mol_res_spin import check_mol_res_spin_data, create_spin, generate_spin_id_unique, linear_ave, return_spin, spin_loop -from pipe_control.pipes import check_pipe +from pipe_control.pipes import check_pipe, get_pipe from pipe_control.structure.mass import pipe_centre_of_mass from status import Status; status = Status() from target_functions.ens_pivot_finder import Pivot_finder @@ -101,6 +101,133 @@ # Add a model. cdp.structure.structural_data.add_item(model_num=model_num) print("Created the empty model number %s." % model_num) + + +def align(pipes=None, models=None, method='fit to mean', atom_id=None, centre_type="centroid", centroid=None): + """Superimpose a set of related, but not identical structures. + + @keyword pipes: The data pipes to include in the alignment and superimposition. + @type pipes: list of str + @keyword models: The list of models to for each data pipe superimpose. The number of elements must match the pipes argument. If set to None, then all models will be used. + @type models: list of lists 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 + @keyword centre_type: The type of centre to superimpose over. This can either be the standard centroid superimposition or the CoM could be used instead. + @type centre_type: str + @keyword centroid: An alternative position of the centroid to allow for different superpositions, for example of pivot point motions. + @type centroid: list of float or numpy rank-1, 3D array + """ + + # 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)) + + # Check the type. + allowed = ['centroid', 'CoM'] + if centre_type not in allowed: + raise RelaxError("The superimposition centre type '%s' is unknown. It must be one of %s." % (centre_type, allowed)) + + # The data pipes to use. + if pipes == None: + pipes = [pipes.cdp_name()] + + # Checks. + for pipe in pipes: + check_pipe(pipe) + + # Initialise the models data structure. + if models == None: + models = [] + for i in range(len(pipes)): + models.append(None) + + # Assemble the atomic coordinates of all structures. + atom_ids = [] + atom_pos = [] + atom_elem = [] + for pipe_index in range(len(pipes)): + # The data pipe object. + dp = get_pipe(pipes[pipe_index]) + + # Validate the models. + dp.structure.validate_models(verbosity=0) + + # The selection object. + selection = dp.structure.selection(atom_id=atom_id) + + # Create a list of all models for this pipe. + if models[pipe_index] == None: + models[pipe_index] = [] + for model in dp.structure.model_loop(): + models[pipe_index].append(model.num) + + # Loop over the models. + for model in models[pipe_index]: + # Extend the lists. + atom_ids.append([]) + atom_pos.append({}) + atom_elem.append({}) + + # Add all coordinates and elements. + for mol_name, res_num, res_name, atom_name, elem, pos in dp.structure.atom_loop(selection=selection, model_num=model, mol_name_flag=True, res_num_flag=True, res_name_flag=True, atom_name_flag=True, pos_flag=True, element_flag=True): + # A unique identifier. + id = "#%s:%s&%s@%s" % (mol_name, res_num, res_name, atom_name) + if id == "#uniform_mol1:1&NH@N": + print id, pos[0] + + atom_ids[-1].append(id) + atom_pos[-1][id] = pos[0] + atom_elem[-1][id] = elem + + # Set up the structures for the superimposition algorithm. + num = len(atom_ids) + coord = [] + elements = [] + for i in range(num): + coord.append([]) + elements.append([]) + + # Find the common atoms and create the coordinate data structure. + for id in atom_ids[0]: + # Is the atom ID present in all other structures? + present = True + for i in range(num): + if id not in atom_ids[i]: + present = False + break + + # Not present, so skip the atom. + if not present: + continue + + # Add the atomic position to the coordinate list and the element to the element list. + for i in range(num): + coord[i].append(atom_pos[i][id]) + elements[i].append(atom_elem[i][id]) + + # Convert to a numpy array. + coord = array(coord, float64) + for i in range(num): + print coord[i][0] + + + # The different algorithms. + if method == 'fit to mean': + T, R, pivot = fit_to_mean(models=range(num), coord=coord, centre_type=centre_type, elements=elements, centroid=centroid) + elif method == 'fit to first': + T, R, pivot = fit_to_first(models=range(num), coord=coord, centre_type=centre_type, elements=elements, centroid=centroid) + + # Update to the new coordinates. + for pipe_index in range(len(pipes)): + for model in models[pipe_index]: + # Translate the molecule first (the rotational pivot is defined in the first model). + translate(T=T[i], model=model, pipe_name=pipes[pipe_index]) + + # Rotate the molecule. + rotate(R=R[i], origin=pivot[i], model=model, pipe_name=pipes[pipe_index]) def check_structure_func():