def oneVsFollowing(self, conformation_number): """ Calculates the RMSD between a reference conformation and all other conformations with an id greater than it. If fitting symmetry groups are used, input coordinates won't be modified (as it works with coordinate copies). @param conformation_number: The id of the reference structure. @return: A numpy array of RMSD values. @author: vgil @date: 26/11/2012 """ np_coords_fit, np_coords_calc = self.__coords_reshaping() if self.fit_symmetry_groups == []: rmsds = pyRMSD.calculators.oneVsFollowing( availableCalculators()[self.calculator_type], np_coords_fit, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, conformation_number, self.number_of_conformations, self.calc_symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid) else: # If we have fitting symmetry groups, we have to try with all possible combinations. # Calculation symmetry groups are applied at C level, changing the way RMSD is calculated. symm_rmsds = [] for permutation in symm_permutations(self.fit_symmetry_groups): # Copy the coordinates and convert to matrix form for ease of indexing coords_copy = numpy.array(np_coords_fit, copy=True, dtype=numpy.float64) coords_copy.shape = (self.number_of_conformations, self.number_of_fitting_atoms, 3) # Apply the changes to reference for symm_group in permutation: # Do it only if the symm. group is not permuted. Otherwise we would always permute! if not symm_group in self.fit_symmetry_groups: for symm_pair in symm_group: swap_atoms(coords_copy[conformation_number], symm_pair[0], symm_pair[1]) # Flatten again to feed the C calculator coords_copy.shape = (self.number_of_conformations * self.number_of_fitting_atoms * 3) # And calculate the RMSD of this permutation symm_rmsds.append( pyRMSD.calculators.oneVsFollowing( availableCalculators()[self.calculator_type], coords_copy, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, conformation_number, self.number_of_conformations, self.calc_symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid)) # Pick the minimum rmsd of all possibilities. rmsds = min_rmsd_of_rmsds_list(numpy.array(symm_rmsds)) return rmsds
def oneVsFollowing(self, conformation_number): """ Calculates the RMSD between a reference conformation and all other conformations with an id greater than it. @param conformation_number: The id of the reference structure. @return: A numpy array of RMSD values. @author: vgil @date: 26/11/2012 """ np_coords_fit, np_coords_calc = self.__coords_reshaping() rmsds = pyRMSD.calculators.oneVsFollowing(availableCalculators()[self.calculator_type], np_coords_fit, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, conformation_number, self.number_of_conformations, self.symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid) return rmsds
def iterativeSuperposition(self): """ Calculates an iterative superposition of a set of conformations. When using this function, the input coordinates are changed (it wouldn't have too much sense otherwise). In this case calculation coordinates are not used as such, but as a secondary coordinates set that is rotate along with the primary fitting set (which allows to use different selections to do the iterative fit and any other calculation). Fit symmetry groups have no effect in iterative superposition. @author: vgil @date: 27/03/2013 """ np_coords_fit, np_coords_calc = self.__coords_reshaping() pyRMSD.calculators.iterativeSuperposition( availableCalculators()[self.calculator_type], np_coords_fit, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, self.number_of_conformations, self.calc_symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid, ) return numpy.reshape(np_coords_fit, (self.number_of_conformations, self.number_of_fitting_atoms, 3))
def pairwiseRMSDMatrix(self): """ Calculates the pairwise RMSD matrix for all conformations in the coordinates set. @return: A numpy array with the upper triangle of the matrix, in row major format. @author: vgil @date: 26/11/2012 """ np_coords_fit, np_coords_calc = self.__coords_reshaping() rmsd_values = pyRMSD.calculators.calculateRMSDCondensedMatrix( availableCalculators()[self.calculator_type], np_coords_fit, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, self.number_of_conformations, self.calc_symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid, ) # It has been necessary to add this hack to the function. When using symmetries, in one Test case, # the only way to make it work was to add this list() hack and changing return PyArray_Return(rmsds_list_obj); # by Py_INCREF(rmsds_list_obj); + return (PyObject*) rmsds_list_obj; in calculateRMSDCondensedMatrix # This problem only happens in some cases and I've been unable to guess why. # The error says: SystemError: ../Objects/listobject.c:169: bad argument to internal function return list(rmsd_values)
def do_math(datadir, reference, outputdir): # Use CUDA for GPU calculations, if avialable if 'QCP_CUDA_MEM_CALCULATOR' in availableCalculators(): pyrmsd_calc = 'QCP_CUDA_MEM_CALCULATOR' else: pyrmsd_calc = 'QCP_SERIAL_CALCULATOR' input_temp = [] for i in os.listdir(outputdir): if i.endswith('.pdb'): input_temp.append(os.path.join(outputdir, i )) input_pdbs = sorted(input_temp) #neighbors = find_neighbors(datadir, reference, 8) #point_mutants = mutant_rms(datadir, input_pdbs) neighborhood = neighborhood_rms(neighbors, reference, input_pdbs) global_ca = global_ca_rms(input_pdbs) return_output_dict = {} #return_output_dict['Point Mutant RMSDs'] = rmsd(input_pdbs, pyrmsd_calc, point_mutants) #return_output_dict['Neighborhood RMSD'] = rmsd(input_pdbs, pyrmsd_calc, neighborhood) return_output_dict['Global RMSD'] = rmsd(input_pdbs, pyrmsd_calc, global_ca) #chi_angles_output = chi_angles(datadir, input_pdbs) #if chi_angles_output != {}: # return_output_dict['X angles'] = chi_angles_output #else: # print 'No X angles!' return return_output_dict
def pairwiseRMSDMatrix(self): """ Calculates the pairwise RMSD matrix for all conformations in the coordinates set. @return: A numpy array with the upper triangle of the matrix, in row major format. @author: vgil @date: 26/11/2012 """ np_coords_fit, np_coords_calc = self.__coords_reshaping() rmsd_values = pyRMSD.calculators.calculateRMSDCondensedMatrix( availableCalculators()[self.calculator_type], np_coords_fit, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, self.number_of_conformations, self.symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid) return rmsd_values
def iterativeSuperposition(self): """ Calculates an iterative superposition of a set of conformations. When using this function, the input coordinates are changed (it wouldn't have too much sense otherwise). In this case calculation coordinates are not used as such, but as a secondary coordinates set that is rotate along with the primary fitting set (which allows to use different selections to do the iterative fit and any other calculation). @author: vgil @date: 27/03/2013 """ np_coords_fit, np_coords_calc = self.__coords_reshaping() pyRMSD.calculators.iterativeSuperposition( availableCalculators()[self.calculator_type], np_coords_fit, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, self.number_of_conformations, self.symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid)
def oneVsFollowing(self, conformation_number): """ Calculates the RMSD between a reference conformation and all other conformations with an id greater than it. @param conformation_number: The id of the reference structure. @return: A numpy array of RMSD values. @author: vgil @date: 26/11/2012 """ np_coords_fit, np_coords_calc = self.__coords_reshaping() rmsds = pyRMSD.calculators.oneVsFollowing( availableCalculators()[self.calculator_type], np_coords_fit, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, conformation_number, self.number_of_conformations, self.symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid) return rmsds
def pairwiseRMSDMatrix(self): """ Calculates the pairwise RMSD matrix for all conformations in the coordinates set. @return: A numpy array with the upper triangle of the matrix, in row major format. @author: vgil @date: 26/11/2012 """ np_coords_fit, np_coords_calc = self.__coords_reshaping() rmsd_values = pyRMSD.calculators.calculateRMSDCondensedMatrix(availableCalculators()[self.calculator_type], np_coords_fit, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, self.number_of_conformations, self.symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid) return rmsd_values
def do_math( reference, outputdir, predID): # Use CUDA for GPU calculations, if avialable if 'QCP_CUDA_MEM_CALCULATOR' in availableCalculators(): pyrmsd_calc = 'QCP_CUDA_MEM_CALCULATOR' else: pyrmsd_calc = 'QCP_SERIAL_CALCULATOR' input_temp = [] for app_output_dir in os.listdir(outputdir): for app_outfile in os.listdir(os.path.join(outputdir, app_output_dir)): #Mutant Structures if app_outfile == 'min_cst.mutate_bkrb_min_cst_0001_0001.pdb.gz': input_temp.append(os.path.join(outputdir, app_output_dir, app_outfile)) input_pdbs = sorted(input_temp) # WT Structures #if app_outfile == 'min_cst.repack-wt_bkrb_min_cst_0001_0001.pdb.gz': # input_temp.append(os.path.join(outputdir, app_output_dir, app_outfile )) # input_pdbs = sorted(input_temp) mutations, fresh_pdb = Fetch_PredID_Info(predID) point_mutants = mutant_coordinates(input_pdbs, predID, mutations, fresh_pdb) neighbors = find_neighbors( reference, predID, mutations, fresh_pdb, 8) neighborhood = neighborhood_coordinates(neighbors, reference, input_pdbs) global_ca = global_ca_coordinates(input_pdbs) return_output_dict = {} return_output_dict['Point Mutant RMSDs'] = rmsd( pyrmsd_calc, point_mutants) return_output_dict['Neighborhood RMSD'] = rmsd(pyrmsd_calc, neighborhood) return_output_dict['Global RMSD'] = rmsd(pyrmsd_calc, global_ca) chi_angles_output = chi_angles(input_pdbs, predID, mutations, fresh_pdb) if chi_angles_output != {}: return_output_dict['X angles'] = chi_angles_output else: print 'No X angles!' return return_output_dict
def pairwiseRMSDMatrix(self): """ Calculates the pairwise RMSD matrix for all conformations in the coordinates set. @return: A numpy array with the upper triangle of the matrix, in row major format. @author: vgil @date: 26/11/2012 """ np_coords_fit, np_coords_calc = self.__coords_reshaping() rmsd_values = pyRMSD.calculators.calculateRMSDCondensedMatrix( availableCalculators()[self.calculator_type], np_coords_fit, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, self.number_of_conformations, self.calc_symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid) # It has been necessary to add this hack to the function. When using symmetries, in one Test case, # the only way to make it work was to add this list() hack and changing return PyArray_Return(rmsds_list_obj); # by Py_INCREF(rmsds_list_obj); + return (PyObject*) rmsds_list_obj; in calculateRMSDCondensedMatrix # This problem only happens in some cases and I've been unable to guess why. # The error says: SystemError: ../Objects/listobject.c:169: bad argument to internal function return list(rmsd_values)
def __init__(self, calculatorType, fittingCoordsets, calculationCoordsets=None, fitSymmetryGroups=[], calcSymmetryGroups=[]): """ Class constructor. @param calculatorType: One of the calculators returned by 'availableCalculators()'. i.e. KABSCH_OMP_CALCULATOR @param fittingCoordsets: An array containing the used coordinates of each conformation. It has the following form: coordsets: [Conformation 1, Conformation 2, ..., Conformation N] Conformation: [Atom 1, Atom 2,..., Atom M] Atom: [x,y,z] This coordinates will be used for both structural superposition and RMSD calculation if the 'calculation coordinates' parameter is not defined. The array type is constrained to be a numpy.array object with dtype = numpy.float64 (dtype will not be always double by default). Input coordinates are modified after each operation (usually centered and superposed into reference conformation). @param calculationCoordsets: An array containing the coordinates used to calculate the RMSD. Must have the same structure than 'fittingCoordinates'. @param fitSymmetryGroups: List of symmetry groups. Symm. groups are a low-level structure-agnostic of the type of symmetries that can be found in some ligands, i.e. in rotating benzene groups. It can also be used in symmetries of bigger selections though. See :py:func:`pyRMSD.symmTools.symm_permutations` @param calcSymmetryGroups: As in 'fitSymmetryGroups', a list of symmetry groups. @author: vgil @date: 26/11/2012 """ if not calculatorType in availableCalculators(): print("Calculator ", calculatorType, " is not an available calculator.") raise ValueError else: self.fitting_coordinates = fittingCoordsets self.calculator_type = calculatorType self.number_of_conformations = self.fitting_coordinates.shape[0] self.number_of_fitting_atoms = self.fitting_coordinates.shape[1] self.calculation_coordinates = calculationCoordsets if self.calculation_coordinates is not None: self.calculation_coordinates = calculationCoordsets if self.number_of_conformations != self.calculation_coordinates.shape[ 0]: print( "Calculation coordinates must hold the same number of conformations than fitting coordinates." ) raise ValueError self.number_of_calculation_atoms = self.calculation_coordinates.shape[ 1] else: self.number_of_calculation_atoms = 0 # Default values for openMP and CUDA flags self.__threads_per_block = 32 self.__blocks_per_grid = 8 self.__number_of_threads = 8 # Symmetry group handling symm_groups_validation(fitSymmetryGroups) symm_groups_validation(calcSymmetryGroups) self.fit_symmetry_groups = fitSymmetryGroups self.calc_symmetry_groups = calcSymmetryGroups
def __init__(self, calculatorType, fittingCoordsets, calculationCoordsets = None, symmetryGroups = []): """ Class constructor. @param calculatorType: One of the calculators returned by 'availableCalculators()'. i.e. KABSCH_OMP_CALCULATOR @param fittingCoordsets: An array containing the used coordinates of each conformation. It has the following form: coordsets: [Conformation 1, Conformation 2, ..., Conformation N] Conformation: [Atom 1, Atom 2,..., Atom M] Atom: [x,y,z] This coordinates will be used for both structural superposition and RMSD calculation if the 'calculation coordinates' parameter is not defined. The array type is constrained to be a numpy.array object with dtype = numpy.float64 (dtype will not be always double by default). Input coordinates are modified after each operation (usually centered and superposed into reference conformation). @param calculationCoordsets: An array containing the coordinates used to calculate the RMSD. Must have the same structure than 'fittingCoordinates'. @param symmetryGroups: List of symmetry groups. Each symmetry group is a 2-Tuple of n-tuples defining interchangeable positions of current calculation coordinates (which will be the fitting coordinates, or the calculation coordinates if defined). For instance, given a calculator with this fitting coordinates (without calculation coordinates): a, b, c, d, e , f ; for conf1 a1, b1, c3, d4, e5, f6 ; for conf2 a2, b2, c3, d4, e5, f6 ; for conf3 and a symmetry group definition [((1,3),(2,4)),]. The final RMSDs would be the minimum RMSDs of: a, b, c, d, e , f ; for conf1 (original) a, c, b, e, d , f ; for conf1 (applying symmetry group) with: a1, b1, c3, d4, e5, f6 ; for conf2 a2, b2, c3, d4, e5, f6 ; for conf3 Symm. groups are a low-level structure-agnostic of the type of symmetries that can be found in some ligands, i.e. in rotating benzene groups. It can also be used in symmetries of bigger selections though. @author: vgil @date: 26/11/2012 """ if not calculatorType in availableCalculators(): print "Calculator ", calculatorType, " is not an available calculator." raise ValueError else: self.fitting_coordinates = fittingCoordsets self.calculator_type = calculatorType self.number_of_conformations = self.fitting_coordinates.shape[0] self.number_of_fitting_atoms = self.fitting_coordinates.shape[1] self.calculation_coordinates = calculationCoordsets if self.calculation_coordinates is not None: self.calculation_coordinates = calculationCoordsets if self.number_of_conformations != self.calculation_coordinates.shape[0]: print "Calculation coordinates must hold the same number of conformations than fitting coordinates." raise ValueError self.number_of_calculation_atoms = self.calculation_coordinates.shape[1] else: self.number_of_calculation_atoms = 0 # Default values for openMP and CUDA flags self.__threads_per_block = 32 self.__blocks_per_grid = 8 self.__number_of_threads = 8 # Symmetry group handling self.__check_symm_groups(symmetryGroups) self.symmetry_groups = symmetryGroups
import gc import traceback import json import ctypes import multiprocessing from multiprocessing.sharedctypes import Value, Array, RawArray # Use pyRMSD for RMSD calculations if available as it's much faster than BioPython try: import pyRMSD from pyRMSD.matrixHandler import MatrixHandler import pyRMSD.RMSDCalculator from pyRMSD.availableCalculators import availableCalculators # Use CUDA for GPU calculations, if avialable if 'QCP_CUDA_MEM_CALCULATOR' in availableCalculators(): pyrmsd_calc = 'QCP_CUDA_MEM_CALCULATOR' else: pyrmsd_calc = 'QCP_SERIAL_CALCULATOR' except ImportError: print 'Warning: could not import faster RMSD module. Falling back to slower biopython...' pyRMSD = None import Bio.PDB import Bio.PDB.Atom as Atom # Use MDAnalysis for distance calculations if available try: import MDAnalysis import MDAnalysis.analysis # from MDAnalysis.analysis import distances except ImportError:
def oneVsFollowing(self, conformation_number): """ Calculates the RMSD between a reference conformation and all other conformations with an id greater than it. If fitting symmetry groups are used, input coordinates won't be modified (as it works with coordinate copies). @param conformation_number: The id of the reference structure. @return: A numpy array of RMSD values. @author: vgil @date: 26/11/2012 """ np_coords_fit, np_coords_calc = self.__coords_reshaping() if self.fit_symmetry_groups == []: rmsds = pyRMSD.calculators.oneVsFollowing( availableCalculators()[self.calculator_type], np_coords_fit, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, conformation_number, self.number_of_conformations, self.calc_symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid, ) else: # If we have fitting symmetry groups, we have to try with all possible combinations. # Calculation symmetry groups are applied at C level, changing the way RMSD is calculated. symm_rmsds = [] for permutation in symm_permutations(self.fit_symmetry_groups): # Copy the coordinates and convert to matrix form for ease of indexing coords_copy = numpy.array(np_coords_fit, copy=True, dtype=numpy.float64) coords_copy.shape = (self.number_of_conformations, self.number_of_fitting_atoms, 3) # Apply the changes to reference for symm_group in permutation: # Do it only if the symm. group is not permuted. Otherwise we would always permute! if not symm_group in self.fit_symmetry_groups: for symm_pair in symm_group: swap_atoms(coords_copy[conformation_number], symm_pair[0], symm_pair[1]) # Flatten again to feed the C calculator coords_copy.shape = self.number_of_conformations * self.number_of_fitting_atoms * 3 # And calculate the RMSD of this permutation symm_rmsds.append( pyRMSD.calculators.oneVsFollowing( availableCalculators()[self.calculator_type], coords_copy, self.number_of_fitting_atoms, np_coords_calc, self.number_of_calculation_atoms, conformation_number, self.number_of_conformations, self.calc_symmetry_groups, self.__number_of_threads, self.__threads_per_block, self.__blocks_per_grid, ) ) # Pick the minimum rmsd of all possibilities. rmsds = min_rmsd_of_rmsds_list(numpy.array(symm_rmsds)) return rmsds
def __init__( self, calculatorType, fittingCoordsets, calculationCoordsets=None, fitSymmetryGroups=[], calcSymmetryGroups=[] ): """ Class constructor. @param calculatorType: One of the calculators returned by 'availableCalculators()'. i.e. KABSCH_OMP_CALCULATOR @param fittingCoordsets: An array containing the used coordinates of each conformation. It has the following form: coordsets: [Conformation 1, Conformation 2, ..., Conformation N] Conformation: [Atom 1, Atom 2,..., Atom M] Atom: [x,y,z] This coordinates will be used for both structural superposition and RMSD calculation if the 'calculation coordinates' parameter is not defined. The array type is constrained to be a numpy.array object with dtype = numpy.float64 (dtype will not be always double by default). Input coordinates are modified after each operation (usually centered and superposed into reference conformation). @param calculationCoordsets: An array containing the coordinates used to calculate the RMSD. Must have the same structure than 'fittingCoordinates'. @param fitSymmetryGroups: List of symmetry groups. Symm. groups are a low-level structure-agnostic of the type of symmetries that can be found in some ligands, i.e. in rotating benzene groups. It can also be used in symmetries of bigger selections though. See :py:func:`pyRMSD.symmTools.symm_permutations` @param calcSymmetryGroups: As in 'fitSymmetryGroups', a list of symmetry groups. @author: vgil @date: 26/11/2012 """ if not calculatorType in availableCalculators(): print "Calculator ", calculatorType, " is not an available calculator." raise ValueError else: self.fitting_coordinates = fittingCoordsets self.calculator_type = calculatorType self.number_of_conformations = self.fitting_coordinates.shape[0] self.number_of_fitting_atoms = self.fitting_coordinates.shape[1] self.calculation_coordinates = calculationCoordsets if self.calculation_coordinates is not None: self.calculation_coordinates = calculationCoordsets if self.number_of_conformations != self.calculation_coordinates.shape[0]: print "Calculation coordinates must hold the same number of conformations than fitting coordinates." raise ValueError self.number_of_calculation_atoms = self.calculation_coordinates.shape[1] else: self.number_of_calculation_atoms = 0 # Default values for openMP and CUDA flags self.__threads_per_block = 32 self.__blocks_per_grid = 8 self.__number_of_threads = 8 # Symmetry group handling symm_groups_validation(fitSymmetryGroups) symm_groups_validation(calcSymmetryGroups) self.fit_symmetry_groups = fitSymmetryGroups self.calc_symmetry_groups = calcSymmetryGroups
import pyRMSD from pyRMSD.matrixHandler import MatrixHandler import pyRMSD.RMSDCalculator from pyRMSD.availableCalculators import availableCalculators # Use CUDA for GPU calculations, if avialable if 'QCP_CUDA_MEM_CALCULATOR' in availableCalculators(): pyrmsd_calc = 'QCP_CUDA_MEM_CALCULATOR' else: pyrmsd_calc = 'QCP_SERIAL_CALCULATOR' import pyRMSD import prody import os import numpy as np import scipy.spatial.distance def pairwise_rmsd(input_pdbs): coordinates = np.array( [prody.parsePDB(input_pdb).select('calpha').getCoords() for input_pdb in input_pdbs] ) rmsd_matrix = pyRMSD.matrixHandler.MatrixHandler().createMatrix(coordinates, pyrmsd_calc) print scipy.spatial.distance.squareform( rmsd_matrix.get_data() ) if __name__ == '__main__': pdb_dir = os.path.join('..', '..', '.testdata','pdbs') input_pdbs = sorted( [os.path.join(pdb_dir, f ) for f in os.listdir(pdb_dir)] ) pairwise_rmsd( input_pdbs[:2] )
def __init__(self, calculatorType, fittingCoordsets, calculationCoordsets=None, symmetryGroups=[]): """ Class constructor. @param calculatorType: One of the calculators returned by 'availableCalculators()'. i.e. KABSCH_OMP_CALCULATOR @param fittingCoordsets: An array containing the used coordinates of each conformation. It has the following form: coordsets: [Conformation 1, Conformation 2, ..., Conformation N] Conformation: [Atom 1, Atom 2,..., Atom M] Atom: [x,y,z] This coordinates will be used for both structural superposition and RMSD calculation if the 'calculation coordinates' parameter is not defined. The array type is constrained to be a numpy.array object with dtype = numpy.float64 (dtype will not be always double by default). Input coordinates are modified after each operation (usually centered and superposed into reference conformation). @param calculationCoordsets: An array containing the coordinates used to calculate the RMSD. Must have the same structure than 'fittingCoordinates'. @param symmetryGroups: List of symmetry groups. Each symmetry group is a 2-Tuple of n-tuples defining interchangeable positions of current calculation coordinates (which will be the fitting coordinates, or the calculation coordinates if defined). For instance, given a calculator with this fitting coordinates (without calculation coordinates): a, b, c, d, e , f ; for conf1 a1, b1, c3, d4, e5, f6 ; for conf2 a2, b2, c3, d4, e5, f6 ; for conf3 and a symmetry group definition [((1,3),(2,4)),]. The final RMSDs would be the minimum RMSDs of: a, b, c, d, e , f ; for conf1 (original) a, c, b, e, d , f ; for conf1 (applying symmetry group) with: a1, b1, c3, d4, e5, f6 ; for conf2 a2, b2, c3, d4, e5, f6 ; for conf3 Symm. groups are a low-level structure-agnostic of the type of symmetries that can be found in some ligands, i.e. in rotating benzene groups. It can also be used in symmetries of bigger selections though. @author: vgil @date: 26/11/2012 """ if not calculatorType in availableCalculators(): print "Calculator ", calculatorType, " is not an available calculator." raise ValueError else: self.fitting_coordinates = fittingCoordsets self.calculator_type = calculatorType self.number_of_conformations = self.fitting_coordinates.shape[0] self.number_of_fitting_atoms = self.fitting_coordinates.shape[1] self.calculation_coordinates = calculationCoordsets if self.calculation_coordinates is not None: self.calculation_coordinates = calculationCoordsets if self.number_of_conformations != self.calculation_coordinates.shape[ 0]: print "Calculation coordinates must hold the same number of conformations than fitting coordinates." raise ValueError self.number_of_calculation_atoms = self.calculation_coordinates.shape[ 1] else: self.number_of_calculation_atoms = 0 # Default values for openMP and CUDA flags self.__threads_per_block = 32 self.__blocks_per_grid = 8 self.__number_of_threads = 8 # Symmetry group handling self.__check_symm_groups(symmetryGroups) self.symmetry_groups = symmetryGroups