def draw(self, graphics): """ Draw something on the canvas @param graphics: the graphics object (L{PolyLine3D}, or L{VisualizationGraphics}) to be drawn """ self.last_draw = (graphics, ) self.configure(cursor='watch') self.update_idletasks() graphics.project(self.axis, self.plane) p1, p2 = graphics.boundingBoxPlane() center = 0.5*(p1+p2) scale = self.plotbox_size / (p2-p1) sign = scale/Numeric.fabs(scale) if self.scale is None: minscale = Numeric.minimum.reduce(Numeric.fabs(scale)) self.scale = 0.9*minscale scale = sign*self.scale box_center = self.plotbox_origin + 0.5*self.plotbox_size shift = -center*scale + box_center + self.translate graphics.scaleAndShift(scale, shift) items, depths = graphics.lines() sort = Numeric.argsort(depths) for index in sort: x1, y1, x2, y2, color, width = items[index] Line(self.canvas, x1, y1, x2, y2, fill=color, width=width) self.configure(cursor='top_left_arrow') self.update_idletasks()
def draw(self, graphics): """ Draw something on the canvas @param graphics: the graphics object (L{PolyLine3D}, or L{VisualizationGraphics}) to be drawn """ self.last_draw = (graphics, ) self.configure(cursor='watch') self.update_idletasks() graphics.project(self.axis, self.plane) p1, p2 = graphics.boundingBoxPlane() center = 0.5 * (p1 + p2) scale = self.plotbox_size / (p2 - p1) sign = scale / N.fabs(scale) if self.scale is None: minscale = N.minimum.reduce(N.fabs(scale)) self.scale = 0.9 * minscale scale = sign * self.scale box_center = self.plotbox_origin + 0.5 * self.plotbox_size shift = -center * scale + box_center + self.translate graphics.scaleAndShift(scale, shift) items, depths = graphics.lines() sort = N.argsort(depths) for index in sort: x1, y1, x2, y2, color, width = items[index] Line(self.canvas, x1, y1, x2, y2, fill=color, width=width) self.configure(cursor='top_left_arrow') self.update_idletasks()
def __init__(self, universe=None, temperature=300. * Units.K, subspace=None, delta=None, sparse=False): if universe == None: return Features.checkFeatures(self, universe) Core.NormalModes.__init__( self, universe, subspace, delta, sparse, ['array', 'imaginary', 'frequencies', 'omega_sq']) self.temperature = temperature self.weights = N.sqrt(self.universe.masses().array) self.weights = self.weights[:, N.NewAxis] self._forceConstantMatrix() ev = self._diagonalize() self.imaginary = N.less(ev, 0.) self.omega_sq = ev self.frequencies = N.sqrt(N.fabs(ev)) / (2. * N.pi) self.sort_index = N.argsort(self.frequencies) self.array.shape = (self.nmodes, self.natoms, 3) self.cleanup()
def paintEvent(self, event): graphics = self.last_draw[0] if graphics is None: return graphics.project(self.axis, self.plane) p1, p2 = graphics.boundingBoxPlane() center = 0.5*(p1+p2) scale = self.plotbox_size / (p2-p1) sign = scale/N.fabs(scale) if self.scale is None: minscale = N.minimum.reduce(N.fabs(scale)) self.scale = 0.9*minscale scale = sign*self.scale box_center = self.plotbox_origin + 0.5*self.plotbox_size shift = -center*scale + box_center + self.translate graphics.scaleAndShift(scale, shift) items, depths = graphics.lines() sort = N.argsort(depths) painter = QPainter() painter.begin(self) painter.fillRect(self.rect(), QBrush(self.background_color)) if colors_by_name: for index in sort: x1, y1, x2, y2, color, width = items[index] painter.setPen(QPen(QColor(color), width, Qt.SolidLine)) painter.drawLine(x1, y1, x2, y2) else: for index in sort: x1, y1, x2, y2, color, width = items[index] painter.setPen(QPen(getattr(Qt, color), width, Qt.SolidLine)) painter.drawLine(x1, y1, x2, y2) painter.end()
def normalizingTransformation(self, repr=None): """Returns a linear transformation that shifts the center of mass of the object to the coordinate origin and makes its principal axes of inertia parallel to the three coordinate axes. A specific representation can be chosen by setting |repr| to Ir : x y z <--> b c a IIr : x y z <--> c a b IIIr : x y z <--> a b c Il : x y z <--> c b a IIl : x y z <--> a c b IIIl : x y z <--> b a c """ from Scientific.LA import determinant cm, inertia = self.centerAndMomentOfInertia() ev, diag = inertia.diagonalization() if determinant(diag.array) < 0: diag.array[0] = -diag.array[0] if repr != None: seq = Numeric.argsort(ev) if repr == 'Ir': seq = Numeric.array([seq[1], seq[2], seq[0]]) elif repr == 'IIr': seq = Numeric.array([seq[2], seq[0], seq[1]]) elif repr == 'Il': seq = Numeric.seq[2::-1] elif repr == 'IIl': seq[1:3] = Numeric.array([seq[2], seq[1]]) elif repr == 'IIIl': seq[0:2] = Numeric.array([seq[1], seq[0]]) elif repr != 'IIIr': print 'unknown representation' diag.array = Numeric.take(diag.array, seq) return Transformation.Rotation(diag)*Transformation.Translation(-cm)
def normalizingTransformation(self, repr=None): """Returns a linear transformation that shifts the center of mass of the object to the coordinate origin and makes its principal axes of inertia parallel to the three coordinate axes. A specific representation can be chosen by setting |repr| to Ir : x y z <--> b c a IIr : x y z <--> c a b IIIr : x y z <--> a b c Il : x y z <--> c b a IIl : x y z <--> a c b IIIl : x y z <--> b a c """ from Scientific.LA import determinant cm, inertia = self.centerAndMomentOfInertia() ev, diag = inertia.diagonalization() if determinant(diag.array) < 0: diag.array[0] = -diag.array[0] if repr != None: seq = Numeric.argsort(ev) if repr == 'Ir': seq = Numeric.array([seq[1], seq[2], seq[0]]) elif repr == 'IIr': seq = Numeric.array([seq[2], seq[0], seq[1]]) elif repr == 'Il': seq = Numeric.seq[2::-1] elif repr == 'IIl': seq[1:3] = Numeric.array([seq[2], seq[1]]) elif repr == 'IIIl': seq[0:2] = Numeric.array([seq[1], seq[0]]) elif repr != 'IIIr': print 'unknown representation' diag.array = Numeric.take(diag.array, seq) return Transformation.Rotation(diag) * Transformation.Translation(-cm)
def __init__(self, universe=None, friction=None, temperature=300. * Units.K, subspace=None, delta=None, sparse=False): if universe == None: return Features.checkFeatures(self, universe) Core.NormalModes.__init__(self, universe, subspace, delta, sparse, ['array', 'inv_relaxation_times']) self.friction = friction self.temperature = temperature self.weights = N.sqrt(friction.array) self.weights = self.weights[:, N.NewAxis] self._forceConstantMatrix() ev = self._diagonalize() self.inv_relaxation_times = ev self.sort_index = N.argsort(self.inv_relaxation_times) self.array.shape = (self.nmodes, self.natoms, 3) self.cleanup()
def _setupSimilarities(self, items, similarities, symmetric, minimal_similarity): self.similarities = [] self.index = {} self.smallest_similarity = None self.largest_similarity = None self.median_similarity = None # Check for array of similarities if isinstance(similarities, N.ArrayType): if similarities.shape != 2 * (self.nitems, ): raise ValueError("Similarity array has wrong shape") for i in range(self.nitems): for k in range(self.nitems): if i != k: self._storeSimilarity(i, k, similarities[i, k], minimal_similarity) # Check for callable similarity function elif callable(similarities): for i in range(self.nitems): for k in range(i + 1, self.nitems): s = similarities(self.items[i], self.items[k]) self._storeSimilarity(i, k, s, minimal_similarity) if not symmetric: s = similarities(self.items[k], self.items[i]) self._storeSimilarity(k, i, s, minimal_similarity) # Assume list of (i, k, s) triples else: for i, k, s in similarities: if i < 0 or i > self.nitems or k < 0 or k > self.nitems: raise ValueError("Index out of range in " + str((i, k, s))) if i == k: raise ValueError("Equal indices in " + str((i, k, s))) self._storeSimilarity(i, k, s, minimal_similarity) if symmetric: self._storeSimilarity(k, i, s, minimal_similarity) # Add indices for self terms for i in range(self.nitems): self._storeSimilarity(i, i, None, None) # Convert similarities to array self.nsimilarities = len(self.similarities) self.similarities = N.array(self.similarities[:-self.nitems]) # Find smallest, largest, and median self.smallest_similarity = N.minimum.reduce(self.similarities) self.largest_similarity = N.maximum.reduce(self.similarities) sort_indices = N.argsort(self.similarities) ns = int(len(self.similarities) / 2) if ns % 2 == 1: self.median_similarity = self.similarities[sort_indices[ns]] else: self.median_similarity = \ (self.similarities[sort_indices[ns]] + self.similarities[sort_indices[ns-1]])/2.
def _setupSimilarities(self, items, similarities, symmetric, minimal_similarity): self.similarities = [] self.index = {} self.smallest_similarity = None self.largest_similarity = None self.median_similarity = None # Check for array of similarities if isinstance(similarities, N.ArrayType): if similarities.shape != 2*(self.nitems,): raise ValueError("Similarity array has wrong shape") for i in range(self.nitems): for k in range(self.nitems): if i != k: self._storeSimilarity(i, k, similarities[i, k], minimal_similarity) # Check for callable similarity function elif callable(similarities): for i in range(self.nitems): for k in range(i+1, self.nitems): s = similarities(self.items[i], self.items[k]) self._storeSimilarity(i, k, s, minimal_similarity) if not symmetric: s = similarities(self.items[k], self.items[i]) self._storeSimilarity(k, i, s, minimal_similarity) # Assume list of (i, k, s) triples else: for i, k, s in similarities: if i < 0 or i > self.nitems or k < 0 or k > self.nitems: raise ValueError("Index out of range in " + str((i, k, s))) if i == k: raise ValueError("Equal indices in " + str((i, k, s))) self._storeSimilarity(i, k, s, minimal_similarity) if symmetric: self._storeSimilarity(k, i, s, minimal_similarity) # Add indices for self terms for i in range(self.nitems): self._storeSimilarity(i, i, None, None) # Convert similarities to array self.nsimilarities = len(self.similarities) self.similarities = N.array(self.similarities[:-self.nitems]) # Find smallest, largest, and median self.smallest_similarity = N.minimum.reduce(self.similarities) self.largest_similarity = N.maximum.reduce(self.similarities) sort_indices = N.argsort(self.similarities) ns = len(self.similarities) if ns % 2 == 1: self.median_similarity = self.similarities[sort_indices[ns/2]] else: self.median_similarity = \ (self.similarities[sort_indices[ns/2]] + self.similarities[sort_indices[ns/2-1]])/2.
def defineResolutionShells(self, nrefl_per_shell): assert nrefl_per_shell <= self.nreflections indices = N.argsort(self.ssq) self.res_shells = [] for first in range(0, len(indices), nrefl_per_shell/2): self.res_shells.append(indices[first:first+nrefl_per_shell]) if len(self.res_shells[-1]) < nrefl_per_shell: self.res_shells[-1] = indices[-nrefl_per_shell:] break self.ssq_av_shell = N.array([0.99*N.minimum.reduce(self.ssq)] + [N.sum(N.take(self.ssq, rs))/len(rs) for rs in self.res_shells] + \ [1.001*N.maximum.reduce(self.ssq)]) # Separate each list into centric and acentric reflections self.res_shells = [(N.array([ri for ri in rs if self.centric[ri]], N.Int32), N.array([ri for ri in rs if not self.centric[ri]], N.Int32)) for rs in self.res_shells]
def __init__(self, universe=None, temperature = 300, subspace = None, delta = None, sparse = False): if universe == None: return Features.checkFeatures(self, universe) Core.NormalModes.__init__(self, universe, subspace, delta, sparse, ['array', 'force_constants']) self.temperature = temperature self.weights = N.ones((1, 1), N.Float) self._forceConstantMatrix() ev = self._diagonalize() self.force_constants = ev self.sort_index = N.argsort(self.force_constants) self.array.shape = (self.nmodes, self.natoms, 3) self.cleanup()
def __init__(self, universe = None, friction = None, temperature = 300.*Units.K, subspace = None, delta = None, sparse = False): if universe == None: return Features.checkFeatures(self, universe) Core.NormalModes.__init__(self, universe, subspace, delta, sparse, ['array', 'inv_relaxation_times']) self.friction = friction self.temperature = temperature self.weights = N.sqrt(friction.array) self.weights = self.weights[:, N.NewAxis] self._forceConstantMatrix() ev = self._diagonalize() self.inv_relaxation_times = ev self.sort_index = N.argsort(self.inv_relaxation_times) self.array.shape = (self.nmodes, self.natoms, 3) self.cleanup()
def normalizingTransformation(self, repr=None): """ Calculate a linear transformation that shifts the center of mass of the object to the coordinate origin and makes its principal axes of inertia parallel to the three coordinate axes. :param repr: the specific representation for axis alignment: Ir : x y z <--> b c a IIr : x y z <--> c a b IIIr : x y z <--> a b c Il : x y z <--> c b a IIl : x y z <--> a c b IIIl : x y z <--> b a c :returns: the normalizing transformation :rtype: Scientific.Geometry.Transformation.RigidBodyTransformation """ from Scientific.LA import determinant cm, inertia = self.centerAndMomentOfInertia() ev, diag = inertia.diagonalization() if determinant(diag.array) < 0: diag.array[0] = -diag.array[0] if repr != None: seq = N.argsort(ev) if repr == 'Ir': seq = N.array([seq[1], seq[2], seq[0]]) elif repr == 'IIr': seq = N.array([seq[2], seq[0], seq[1]]) elif repr == 'Il': seq = N.seq[2::-1] elif repr == 'IIl': seq[1:3] = N.array([seq[2], seq[1]]) elif repr == 'IIIl': seq[0:2] = N.array([seq[1], seq[0]]) elif repr != 'IIIr': print 'unknown representation' diag.array = N.take(diag.array, seq) return Transformation.Rotation(diag) * Transformation.Translation(-cm)
def normalizingTransformation(self, repr=None): """ Calculate a linear transformation that shifts the center of mass of the object to the coordinate origin and makes its principal axes of inertia parallel to the three coordinate axes. :param repr: the specific representation for axis alignment: Ir : x y z <--> b c a IIr : x y z <--> c a b IIIr : x y z <--> a b c Il : x y z <--> c b a IIl : x y z <--> a c b IIIl : x y z <--> b a c :returns: the normalizing transformation :rtype: Scientific.Geometry.Transformation.RigidBodyTransformation """ from Scientific.LA import determinant cm, inertia = self.centerAndMomentOfInertia() ev, diag = inertia.diagonalization() if determinant(diag.array) < 0: diag.array[0] = -diag.array[0] if repr != None: seq = N.argsort(ev) if repr == 'Ir': seq = N.array([seq[1], seq[2], seq[0]]) elif repr == 'IIr': seq = N.array([seq[2], seq[0], seq[1]]) elif repr == 'Il': seq = N.seq[2::-1] elif repr == 'IIl': seq[1:3] = N.array([seq[2], seq[1]]) elif repr == 'IIIl': seq[0:2] = N.array([seq[1], seq[0]]) elif repr != 'IIIr': print 'unknown representation' diag.array = N.take(diag.array, seq) return Transformation.Rotation(diag)*Transformation.Translation(-cm)
def __init__(self, universe=None, temperature = 300.*Units.K, subspace = None, delta = None, sparse = False): if universe == None: return Features.checkFeatures(self, universe) Core.NormalModes.__init__(self, universe, subspace, delta, sparse, ['array', 'imaginary', 'frequencies', 'omega_sq']) self.temperature = temperature self.weights = N.sqrt(self.universe.masses().array) self.weights = self.weights[:, N.NewAxis] self._forceConstantMatrix() ev = self._diagonalize() self.imaginary = N.less(ev, 0.) self.omega_sq = ev self.frequencies = N.sqrt(N.fabs(ev)) / (2.*N.pi) self.sort_index = N.argsort(self.frequencies) self.array.shape = (self.nmodes, self.natoms, 3) self.cleanup()
def __init__(self, universe=None, temperature=300, subspace=None, delta=None, sparse=False): if universe == None: return Features.checkFeatures(self, universe) Core.NormalModes.__init__(self, universe, subspace, delta, sparse, ['array', 'force_constants']) self.temperature = temperature self.weights = N.ones((1, 1), N.Float) self._forceConstantMatrix() ev = self._diagonalize() self.force_constants = ev self.sort_index = N.argsort(self.force_constants) self.array.shape = (self.nmodes, self.natoms, 3) self.cleanup()
universe.protein = Protein('bala1') # Minimize minimizer = ConjugateGradientMinimizer(universe, actions=[StandardLogOutput(50)]) minimizer(convergence = 1.e-3, steps = 10000) # Set up the subspace: rigid-body translation and rotation for each residue subspace = RigidMotionSubspace(universe, universe.protein.residues()) # Calculate normal modes modes = VibrationalModes(universe, subspace=subspace) # Calculate full modes for comparison full_modes = VibrationalModes(universe, subspace=None) # Compare the modes. For each reduced mode, find the full mode with # the most similar displacement vector. Print both frequencies and # the overlap of the displacement vectors. masses = universe.masses() for i in range(6, len(modes)): m1 = modes[i] overlap = [] for m2 in full_modes: o = m1.massWeightedDotProduct(m2) / \ N.sqrt(m1.massWeightedDotProduct(m1)) / \ N.sqrt(m2.massWeightedDotProduct(m2)) overlap.append(abs(o)) best = N.argsort(overlap)[-1] print m1.frequency, full_modes[best].frequency, overlap[best]
def __init__(self, universe=None, temperature=300. * Units.K, subspace=None, delta=None, sparse=False): """ :param universe: the system for which the normal modes are calculated; it must have a force field which provides the second derivatives of the potential energy :type universe: :class:~MMTK.Universe.Universe :param temperature: the temperature for which the amplitudes of the atomic displacement vectors are calculated. A value of None can be specified to have no scaling at all. In that case the mass-weighted norm of each normal mode is one. :type temperature: float :param subspace: the basis for the subspace in which the normal modes are calculated (or, more precisely, a set of vectors spanning the subspace; it does not have to be orthogonal). This can either be a sequence of :class:~MMTK.ParticleProperties.ParticleVector objects or a tuple of two such sequences. In the second case, the subspace is defined by the space spanned by the second set of vectors projected on the complement of the space spanned by the first set of vectors. The first set thus defines directions that are excluded from the subspace. The default value of None indicates a standard normal mode calculation in the 3N-dimensional configuration space. :param delta: the rms step length for numerical differentiation. The default value of None indicates analytical differentiation. Numerical differentiation is available only when a subspace basis is used as well. Instead of calculating the full force constant matrix and then multiplying with the subspace basis, the subspace force constant matrix is obtained by numerical differentiation of the energy gradients along the basis vectors of the subspace. If the basis is much smaller than the full configuration space, this approach needs much less memory. :type delta: float :param sparse: a flag that indicates if a sparse representation of the force constant matrix is to be used. This is of interest when there are no long-range interactions and a subspace of smaller size then 3N is specified. In that case, the calculation will use much less memory with a sparse representation. :type sparse: bool """ if universe == None: return Features.checkFeatures(self, universe) Core.NormalModes.__init__( self, universe, subspace, delta, sparse, ['array', 'imaginary', 'frequencies', 'omega_sq']) self.temperature = temperature self.weights = N.sqrt(self.universe.masses().array) self.weights = self.weights[:, N.NewAxis] self._forceConstantMatrix() ev = self._diagonalize() self.imaginary = N.less(ev, 0.) self.omega_sq = ev self.frequencies = N.sqrt(N.fabs(ev)) / (2. * N.pi) self.sort_index = N.argsort(self.frequencies) self.array.shape = (self.nmodes, self.natoms, 3) self.cleanup()
def internalRun(self): """Runs the analysis.""" self.chrono = default_timer() orderedAtoms = sorted(self.universe.atomList(), key = operator.attrgetter('index')) selectedAtoms = Collection([orderedAtoms[ind] for ind in self.subset]) M1_2 = N.zeros((3*self.nSelectedAtoms,), N.Float) weightList = [N.sqrt(el[1]) for el in sorted([(at.index, at.mass()) for at in selectedAtoms])] for i in range(len(weightList)): M1_2[3*i:3*(i+1)] = weightList[i] invM1_2 = (1.0/M1_2)*N.identity(3*self.nSelectedAtoms, typecode = N.Float) # The initial structure configuration. initialStructure = self.trajectory.configuration[self.first] averageStructure = ParticleVector(self.universe) for conf in self.trajectory.configuration[self.first:self.last:self.skip]: averageStructure += self.universe.configurationDifference(initialStructure, conf) averageStructure = averageStructure/self.nFrames averageStructure = initialStructure + averageStructure mdr = N.zeros((self.nFrames, 3*self.nSelectedAtoms), N.Float) # Calculate the fluctuation matrix. sigmaPrim = N.zeros((3*self.nSelectedAtoms, 3*self.nSelectedAtoms), N.Float) comp = 0 for conf in self.trajectory.configuration[self.first:self.last:self.skip]: mdr[comp,:] = M1_2*N.ravel(N.compress(self.mask,(conf-averageStructure).array,0)) sigmaPrim += mdr[comp,:, N.NewAxis] * mdr[N.NewAxis, comp, :] comp += 1 sigmaPrim = sigmaPrim/float(self.nFrames) try: # Calculate the quasiharmonic modes omega, dx = Heigenvectors(sigmaPrim) except MemoryError: raise Error('Not enough memory to diagonalize the %sx%s fluctuation matrix.' % sigmaPrim.shape) # Due to numerical imprecisions, the result can have imaginary parts. # In that case, throw the imaginary parts away. # Conversion from uma*nm2 to kg*m2 (SI) omega = omega.real/(Units.kg*Units.m**2) omega = (Units.Hz/Units.invcm)*N.sqrt((Units.k_B*Units.K*self.temperature/Units.J)*(1.0/omega)) dx = dx.real dx = N.dot(invM1_2, dx) # Sort eigen vectors by decreasing fluctuation amplitude. indices = N.argsort(omega)[::-1] omega = N.take(omega, indices) dx = N.take(dx, indices) # Eq 66 of the reference paper. mdr = N.take(mdr, indices, axis = 1) at = N.dot(mdr,N.transpose(dx)) # The NetCDF output file is opened. outputFile = NetCDFFile(self.output, 'w') outputFile.title = self.__class__.__name__ outputFile.jobinfo = self.information + '\nOutput file written on: %s\n\n' % asctime() # The universe is emptied from its objects keeping just its topology. self.universe.removeObject(self.universe.objectList()[:]) # The atoms of the subset are copied atoms = copy.deepcopy(selectedAtoms.atomList()) # And their parent attribute removed to allow their transfer in the empty universe. for a in atoms: a.parent = None ac = AtomCluster(atoms,name='QHACluster') self.universe.addObject(ac) # Some dimensions are created. # NEIVALS = the number eigen values outputFile.createDimension('NEIGENVALS', len(omega)) # UDESCR = the universe description length outputFile.createDimension('UDESCR', len(self.universe.description())) # NATOMS = the number of atoms of the universe outputFile.createDimension('NATOMS', self.nSelectedAtoms) # NFRAMES = the number of frames. outputFile.createDimension('NFRAMES', self.nFrames) # NCOORDS = the number of coordinates (always = 3). outputFile.createDimension('NCOORDS', 3) # 3N. outputFile.createDimension('3N', 3*self.nSelectedAtoms) if self.universe.cellParameters() is not None: outputFile.createDimension('BOXDIM', len(self.universe.cellParameters())) # Creation of the NetCDF output variables. # EIVALS = the eigen values. OMEGA = outputFile.createVariable('omega', N.Float, ('NEIGENVALS',)) OMEGA[:] = omega # EIVECS = array of eigen vectors. DX = outputFile.createVariable('dx', N.Float, ('NEIGENVALS','NEIGENVALS')) DX[:,:] = dx # The time. TIMES = outputFile.createVariable('time', N.Float, ('NFRAMES',)) TIMES[:] = self.times[:] TIMES.units = 'ps' # MODE = the mode number. MODE = outputFile.createVariable('mode', N.Float, ('3N',)) MODE[:] = 1 + N.arange(3*self.nSelectedAtoms) # LCI = local character indicator. See eq 56. LCI = outputFile.createVariable('local_character_indicator', N.Float, ('3N',)) LCI[:] = (dx**4).sum(0) # GCI = global character indicator. See eq 57. GCI = outputFile.createVariable('global_character_indicator', N.Float, ('3N',)) GCI[:] = (N.sqrt(3.0*self.nSelectedAtoms)/(N.absolute(dx)).sum(0))**4 # Projection of MD traj onto normal modes. See eq 66.. AT = outputFile.createVariable('at', N.Float, ('NFRAMES','3N')) AT[:,:] = at[:,:] # DESCRIPTION = the universe description. DESCRIPTION = outputFile.createVariable('description', N.Character, ('UDESCR',)) DESCRIPTION[:] = self.universe.description() # AVGSTRUCT = the average structure. AVGSTRUCT = outputFile.createVariable('avgstruct', N.Float, ('NATOMS','NCOORDS')) AVGSTRUCT[:,:] = N.compress(self.mask,averageStructure.array,0) # If the universe is periodic, create an extra variable storing the box size. if self.universe.cellParameters() is not None: BOXSIZE = outputFile.createVariable('box_size', N.Float, ('BOXDIM',)) BOXSIZE[:] = self.universe.cellParameters() outputFile.close() self.toPlot = None self.chrono = default_timer() - self.chrono return None
universe.protein = Protein('bala1') # Minimize minimizer = ConjugateGradientMinimizer(universe, actions=[StandardLogOutput(50)]) minimizer(convergence=1.e-3, steps=10000) # Set up the subspace: rigid-body translation and rotation for each residue subspace = RigidMotionSubspace(universe, universe.protein.residues()) # Calculate normal modes modes = VibrationalModes(universe, subspace=subspace) # Calculate full modes for comparison full_modes = VibrationalModes(universe, subspace=None) # Compare the modes. For each reduced mode, find the full mode with # the most similar displacement vector. Print both frequencies and # the overlap of the displacement vectors. masses = universe.masses() for i in range(6, len(modes)): m1 = modes[i] overlap = [] for m2 in full_modes: o = m1.massWeightedDotProduct(m2) / \ N.sqrt(m1.massWeightedDotProduct(m1)) / \ N.sqrt(m2.massWeightedDotProduct(m2)) overlap.append(abs(o)) best = N.argsort(overlap)[-1] print(f"{m1.frequency} {full_modes[best].frequency} {overlap[best]}")
def __init__(self, universe = None, friction = None, temperature = 300.*Units.K, subspace = None, delta = None, sparse = False): """ :param universe: the system for which the normal modes are calculated; it must have a force field which provides the second derivatives of the potential energy :type universe: :class:`~MMTK.Universe.Universe` :param friction: the friction coefficient for each particle. Note: The friction coefficients are not mass-weighted, i.e. they have the dimension of an inverse time. :type friction: :class:`~MMTK.ParticleProperties.ParticleScalar` :param temperature: the temperature for which the amplitudes of the atomic displacement vectors are calculated. A value of None can be specified to have no scaling at all. In that case the mass-weighted norm of each normal mode is one. :type temperature: float :param subspace: the basis for the subspace in which the normal modes are calculated (or, more precisely, a set of vectors spanning the subspace; it does not have to be orthogonal). This can either be a sequence of :class:`~MMTK.ParticleProperties.ParticleVector` objects or a tuple of two such sequences. In the second case, the subspace is defined by the space spanned by the second set of vectors projected on the complement of the space spanned by the first set of vectors. The first set thus defines directions that are excluded from the subspace. The default value of None indicates a standard normal mode calculation in the 3N-dimensional configuration space. :param delta: the rms step length for numerical differentiation. The default value of None indicates analytical differentiation. Numerical differentiation is available only when a subspace basis is used as well. Instead of calculating the full force constant matrix and then multiplying with the subspace basis, the subspace force constant matrix is obtained by numerical differentiation of the energy gradients along the basis vectors of the subspace. If the basis is much smaller than the full configuration space, this approach needs much less memory. :type delta: float :param sparse: a flag that indicates if a sparse representation of the force constant matrix is to be used. This is of interest when there are no long-range interactions and a subspace of smaller size then 3N is specified. In that case, the calculation will use much less memory with a sparse representation. :type sparse: bool """ if universe == None: return Features.checkFeatures(self, universe) Core.NormalModes.__init__(self, universe, subspace, delta, sparse, ['array', 'inv_relaxation_times']) self.friction = friction self.temperature = temperature self.weights = N.sqrt(friction.array) self.weights = self.weights[:, N.NewAxis] self._forceConstantMatrix() ev = self._diagonalize() self.inv_relaxation_times = ev self.sort_index = N.argsort(self.inv_relaxation_times) self.array.shape = (self.nmodes, self.natoms, 3) self.cleanup()