def write(self,filename,start=None,step=None,delta=None,load=True): """Write hopping trajectory as standard dcd file. write('TAP') :Arguments: load = True Immediately loads the trajectory so that further calls to next() will use the computed trajectory and don't use expensive mapping. Ignore the other options and leave them at the defaults. Currently, only the whole trajectory is written. All atoms in the original trajectory are written to the output so you should be able to use your original psf file. NOTE: Fixed atoms are possibly not accounted for properly. Note that it is your responsibility to load the TAP trajectory and the appropriate psf together as there is very limited information stored in the dcd itself. """ set_verbosity(self.verbosity) # this is stupid psfname = self.filename(filename,'psf') dcdname = self.filename(filename,'dcd') # see MDAnalysis/src/dcd/dcd.c for explanations if start is None: start = self.traj.start_timestep # starting time step for DCD file if step is None: step = self.traj.skip_timestep # NSAVC (# ts between written DCD frames) if delta is None: delta = self.traj.delta # length of ts (AKMA units) dcdwriter = MDAnalysis.DCD.DCDWriter(dcdname,self.ts.numatoms, start,step,delta, remarks='TAP trajectory') pm = ProgressMeter(self.numframes, interval=10, format="Mapping TAP frame %(step)5d/%(numsteps)6d [%(percentage)5.1f%%]\r") for ts in self.map_dcd(): dcdwriter.write_next_timestep(ts) pm.echo(ts.frame) dcdwriter.close() logger.info("TAPTrajectory.write(): wrote TAP traj %r.", dcdname) if load is True: self.TAPtraj = MDAnalysis.DCD.DCDReader(dcdname) self.trajectory = self.TAPtraj
def convert(self, gentop=True): natoms = self.frames.numatoms nframes = self.frames.numframes if gentop: self.universe.atoms.write(self.top_new) # write first frame as topology self.frames.rewind() writer = MDAnalysis.Writer(self.trj_new, natoms) percentage = ProgressMeter(nframes, interval=10, format="Fitted frame %(step)5d/%(numsteps)d [%(percentage)5.1f%%]\r") for ts in self.frames: writer.write(self.universe.atoms) percentage.echo(ts.frame) writer.close_trajectory()
def run(self, force=False): """ Run all the required passes :Keywords: *force* Will overwrite previous results if they exist """ # if results exist, don't waste any time if not self.solution['results'] is None and not force: return master_results = numpy.zeros_like(numpy.arange(self._starts[0], self._stops[0], self._skip), dtype=numpy.float32) # for normalising later counter = numpy.zeros_like(master_results, dtype=numpy.float32) pm = ProgressMeter(self.nruns, interval=1, format="Performing run %(step)5d/%(numsteps)d" "[%(percentage)5.1f%%]\r") for i, (start, stop) in enumerate(izip(self._starts, self._stops)): pm.echo(i + 1) # needed else trj seek thinks a numpy.int64 isn't an int? results = self._single_run(int(start), int(stop)) nresults = len(results) if nresults == len(master_results): master_results += results counter += 1.0 else: master_results[:nresults] += results counter[:nresults] += 1.0 master_results /= counter self.solution['time'] = numpy.arange( len(master_results), dtype=numpy.float32) * self.u.trajectory.dt * self._skip self.solution['results'] = master_results
def run(self, force=False): """ Run all the required passes :Keywords: *force* Will overwrite previous results if they exist """ # if results exist, don't waste any time if not self.solution["results"] is None and not force: return master_results = numpy.zeros_like( numpy.arange(self._starts[0], self._stops[0], self._skip), dtype=numpy.float32 ) # for normalising later counter = numpy.zeros_like(master_results, dtype=numpy.float32) pm = ProgressMeter( self.nruns, interval=1, format="Performing run %(step)5d/%(numsteps)d" "[%(percentage)5.1f%%]\r" ) for i, (start, stop) in enumerate(izip(self._starts, self._stops)): pm.echo(i + 1) # needed else trj seek thinks a numpy.int64 isn't an int? results = self._single_run(int(start), int(stop)) nresults = len(results) if nresults == len(master_results): master_results += results counter += 1.0 else: master_results[:nresults] += results counter[:nresults] += 1.0 master_results /= counter self.solution["time"] = ( numpy.arange(len(master_results), dtype=numpy.float32) * self.u.trajectory.dt * self._skip ) self.solution["results"] = master_results
def rms_fit_trj(traj, reference, select='all', filename=None, rmsdfile=None, prefix='rmsfit_', mass_weighted=False, tol_mass=0.1, force=True, quiet=False, **kwargs): """RMS-fit trajectory to a reference structure using a selection. Both reference *ref* and trajectory *traj* must be :class:`MDAnalysis.Universe` instances. If they contain a trajectory then it is used. The output file format is determined by the file extension of *filename*. One can also use the same universe if one wants to fit to the current frame. :Arguments: *traj* trajectory, :class:`MDAnalysis.Universe` object *reference* reference coordinates; :class:`MDAnalysis.Universe` object (uses the current time step of the object) *select* 1. any valid selection string for :meth:`~MDAnalysis.core.AtomGroup.AtomGroup.selectAtoms` that produces identical selections in *mobile* and *reference*; or 2. a dictionary ``{'mobile':sel1, 'reference':sel2}`` (the :func:`fasta2select` function returns such a dictionary based on a ClustalW_ or STAMP_ sequence alignment); or 3. a tuple ``(sel1, sel2)`` When using 2. or 3. with *sel1* and *sel2* then these selections can also each be a list of selection strings (to generate a AtomGroup with defined atom order as described under :ref:`ordered-selections-label`). *filename* file name for the RMS-fitted trajectory or pdb; defaults to the original trajectory filename (from *traj*) with *prefix* prepended *rmsdfile* file name for writing the RMSD timeseries [``None``] *prefix* prefix for autogenerating the new output filename *mass_weighted* do a mass-weighted RMSD fit *tol_mass* Reject match if the atomic masses for matched atoms differ by more than *tol_mass* [0.1] *force* - ``True``: Overwrite an existing output trajectory (default) - ``False``: simply return if the file already exists *quiet* - ``True``: suppress progress and logging for levels INFO and below. - ``False``: show all status messages and do not change the the logging level (default) .. Note:: If *kwargs* All other keyword arguments are passed on the trajectory :class:`~MDAnalysis.coordinates.base.Writer`; this allows manipulating/fixing trajectories on the fly (e.g. change the output format by changing the extension of *filename* and setting different parameters as described for the corresponding writer). :Returns: *filename* (either provided or auto-generated) .. _ClustalW: http://www.clustal.org/ .. _STAMP: http://www.compbio.dundee.ac.uk/manuals/stamp.4.2/ .. versionchanged:: 0.8 Added *kwargs* to be passed to the trajectory :class:`~MDAnalysis.coordinates.base.Writer` and *filename* is returned. """ frames = traj.trajectory if quiet: # should be part of a try ... finally to guarantee restoring the log level logging.disable(logging.WARN) kwargs.setdefault('remarks', 'RMS fitted trajectory to reference') if filename is None: path, fn = os.path.split(frames.filename) filename = os.path.join(path, prefix + fn) _Writer = frames.Writer else: _Writer = frames.OtherWriter if os.path.exists(filename) and not force: logger.warn( "{0} already exists and will NOT be overwritten; use force=True if you want this" .format(filename)) return filename writer = _Writer(filename, **kwargs) del _Writer select = _process_selection(select) ref_atoms = reference.selectAtoms(*select['reference']) traj_atoms = traj.selectAtoms(*select['mobile']) natoms = traj_atoms.numberOfAtoms() check_same_atoms(ref_atoms, traj_atoms, tol_mass=tol_mass) logger.info("RMS-fitting on %d atoms." % len(ref_atoms)) if mass_weighted: # if performing a mass-weighted alignment/rmsd calculation weight = ref_atoms.masses() / ref_atoms.masses().mean() else: weight = None # reference centre of mass system # (compatibility with pre 1.0 numpy: explicitly cast coords to float32) ref_com = ref_atoms.centerOfMass().astype(numpy.float32) ref_coordinates = ref_atoms.coordinates() - ref_com # allocate the array for selection atom coords traj_coordinates = traj_atoms.coordinates().copy() # RMSD timeseries nframes = len(frames) rmsd = numpy.zeros((nframes, )) # R: rotation matrix that aligns r-r_com, x~-x~com # (x~: selected coordinates, x: all coordinates) # Final transformed traj coordinates: x' = (x-x~_com)*R + ref_com rot = numpy.zeros(9, dtype=numpy.float64) # allocate space for calculation R = numpy.matrix(rot.reshape(3, 3)) percentage = ProgressMeter( nframes, interval=10, quiet=quiet, format="Fitted frame %(step)5d/%(numsteps)d [%(percentage)5.1f%%]\r") for k, ts in enumerate(frames): # shift coordinates for rotation fitting # selection is updated with the time frame x_com = traj_atoms.centerOfMass().astype(numpy.float32) traj_coordinates[:] = traj_atoms.coordinates() - x_com # Need to transpose coordinates such that the coordinate array is # 3xN instead of Nx3. Also qcp requires that the dtype be float64 # (I think we swapped the position of ref and traj in CalcRMSDRotationalMatrix # so that R acts **to the left** and can be broadcasted; we're saving # one transpose. [orbeckst]) rmsd[k] = qcp.CalcRMSDRotationalMatrix( ref_coordinates.T.astype(numpy.float64), traj_coordinates.T.astype(numpy.float64), natoms, rot, weight) R[:, :] = rot.reshape(3, 3) # Transform each atom in the trajectory (use inplace ops to avoid copying arrays) # (Marginally (~3%) faster than "ts._pos[:] = (ts._pos - x_com) * R + ref_com".) ts._pos -= x_com ts._pos[:] = ts._pos * R # R acts to the left & is broadcasted N times. ts._pos += ref_com writer.write(traj.atoms) # write whole input trajectory system percentage.echo(ts.frame) logger.info("Wrote %d RMS-fitted coordinate frames to file %r", frames.numframes, filename) if not rmsdfile is None: numpy.savetxt(rmsdfile, rmsd) logger.info("Wrote RMSD timeseries to file %r", rmsdfile) if quiet: # should be part of a try ... finally to guarantee restoring the log level logging.disable(logging.NOTSET) return filename
def run(self, **kwargs): """Analyze trajectory and produce timeseries. Stores the hydrogen bond data per frame as :attr:`HydrogenBondAnalysis.timeseries` (see there for output format). .. SeeAlso:: :meth:`HydrogenBondAnalysis.generate_table` for processing the data into a different format. .. versionchanged:: 0.7.6 Results are not returned, only stored in :attr:`~HydrogenBondAnalysis.timeseries` and duplicate hydrogen bonds are removed from output (can be suppressed with *remove_duplicates* = ``False``) """ logger.info("HBond analysis: starting") logger.debug("HBond analysis: donors %r", self.donors) logger.debug("HBond analysis: acceptors %r", self.acceptors) remove_duplicates = kwargs.pop('remove_duplicates', True) # False: old behaviour if not remove_duplicates: logger.warn("Hidden feature remove_duplicates = True activated: you will probably get duplicate H-bonds.") verbose = kwargs.pop('verbose', False) if verbose != self.verbose: self.verbose = verbose logger.debug("Toggling verbose to %r", self.verbose) if not self.verbose: logger.debug("HBond analysis: For full step-by-step debugging output use verbose=True") self.timeseries = [] self.timesteps = [] logger.info("checking trajectory...") # numframes can take a while! try: frames = numpy.arange(self.u.trajectory.numframes)[self.traj_slice] except: logger.error("Problem reading trajectory or trajectory slice incompatible.") logger.exception() raise pm = ProgressMeter(len(frames), format="HBonds frame %(step)5d/%(numsteps)d [%(percentage)5.1f%%]\r") try: self.u.trajectory.time def _get_timestep(): return self.u.trajectory.time logger.debug("HBond analysis is recording time step") except NotImplementedError: # chained reader or xyz(?) cannot do time yet def _get_timestep(): return self.u.trajectory.frame logger.warn("HBond analysis is recording frame number instead of time step") logger.info("Starting analysis (frame index start=%d stop=%d, step=%d)", (self.traj_slice.start or 0), (self.traj_slice.stop or self.u.trajectory.numframes), self.traj_slice.step or 1) for ts in self.u.trajectory[self.traj_slice]: # all bonds for this timestep frame_results = [] # dict of tuples (atomid, atomid) for quick check if # we already have the bond (to avoid duplicates) already_found = {} frame = ts.frame timestep = _get_timestep() self.timesteps.append(timestep) pm.echo(ts.frame) self.logger_debug("Analyzing frame %(frame)d, timestep %(timestep)f ps", vars()) if self.update_selection1: self._update_selection_1() if self.update_selection2: self._update_selection_2() if self.selection1_type in ('donor', 'both'): self.logger_debug("Selection 1 Donors <-> Acceptors") ns_acceptors = NS.AtomNeighborSearch(self._s2_acceptors) for i,donor_h_set in self._s1_donors_h.items(): d = self._s1_donors[i] for h in donor_h_set: res = ns_acceptors.search_list(AtomGroup([h]), self.distance) for a in res: angle = self.calc_angle(d,h,a) dist = self.calc_eucl_distance(h,a) if angle >= self.angle and dist <= self.distance: self.logger_debug("S1-D: %s <-> S2-A: %s %f A, %f DEG" % (h.number+1, a.number+1, dist, angle)) #self.logger_debug("S1-D: %r <-> S2-A: %r %f A, %f DEG" % (h, a, dist, angle)) frame_results.append([h.number+1, a.number+1, '%s%s:%s' % (h.resname, repr(h.resid), h.name), '%s%s:%s' % (a.resname, repr(a.resid), a.name), dist, angle]) already_found[(h.number+1, a.number+1)] = True if self.selection1_type in ('acceptor', 'both'): self.logger_debug("Selection 1 Acceptors <-> Donors") ns_acceptors = NS.AtomNeighborSearch(self._s1_acceptors) for i,donor_h_set in self._s2_donors_h.items(): d = self._s2_donors[i] for h in donor_h_set: res = ns_acceptors.search_list(AtomGroup([h]), self.distance) for a in res: if remove_duplicates and \ ((h.number+1, a.number+1) in already_found or \ (a.number+1, h.number+1) in already_found): continue angle = self.calc_angle(d,h,a) dist = self.calc_eucl_distance(h,a) if angle >= self.angle and dist <= self.distance: self.logger_debug("S1-A: %s <-> S2-D: %s %f A, %f DEG" % (a.number+1, h.number+1, dist, angle)) #self.logger_debug("S1-A: %r <-> S2-D: %r %f A, %f DEG" % (a, h, dist, angle)) frame_results.append([h.number+1, a.number+1, '%s%s:%s' % (h.resname, repr(h.resid), h.name), '%s%s:%s' % (a.resname, repr(a.resid), a.name), dist, angle]) self.timeseries.append(frame_results) logger.info("HBond analysis: complete; timeseries with %d hbonds in %s.timeseries", self.count_by_time().count.sum(), self.__class__.__name__)
def run(self, **kwargs): """Analyze trajectory and produce timeseries. Stores the hydrogen bond data per frame as :attr:`HydrogenBondAnalysis.timeseries` (see there for output format). .. SeeAlso:: :meth:`HydrogenBondAnalysis.generate_table` for processing the data into a different format. .. versionchanged:: 0.7.6 Results are not returned, only stored in :attr:`~HydrogenBondAnalysis.timeseries` and duplicate hydrogen bonds are removed from output (can be suppressed with *remove_duplicates* = ``False``) """ logger.info("HBond analysis: starting") logger.debug("HBond analysis: donors %r", self.donors) logger.debug("HBond analysis: acceptors %r", self.acceptors) remove_duplicates = kwargs.pop('remove_duplicates', True) # False: old behaviour if not remove_duplicates: logger.warn( "Hidden feature remove_duplicates = True activated: you will probably get duplicate H-bonds." ) verbose = kwargs.pop('verbose', False) if verbose != self.verbose: self.verbose = verbose logger.debug("Toggling verbose to %r", self.verbose) if not self.verbose: logger.debug( "HBond analysis: For full step-by-step debugging output use verbose=True" ) self.timeseries = [] self.timesteps = [] logger.info("checking trajectory...") # numframes can take a while! try: frames = numpy.arange(self.u.trajectory.numframes)[self.traj_slice] except: logger.error( "Problem reading trajectory or trajectory slice incompatible.") logger.exception() raise pm = ProgressMeter( len(frames), format="HBonds frame %(step)5d/%(numsteps)d [%(percentage)5.1f%%]\r" ) try: self.u.trajectory.time def _get_timestep(): return self.u.trajectory.time logger.debug("HBond analysis is recording time step") except NotImplementedError: # chained reader or xyz(?) cannot do time yet def _get_timestep(): return self.u.trajectory.frame logger.warn( "HBond analysis is recording frame number instead of time step" ) logger.info( "Starting analysis (frame index start=%d stop=%d, step=%d)", (self.traj_slice.start or 0), (self.traj_slice.stop or self.u.trajectory.numframes), self.traj_slice.step or 1) for ts in self.u.trajectory[self.traj_slice]: # all bonds for this timestep frame_results = [] # dict of tuples (atomid, atomid) for quick check if # we already have the bond (to avoid duplicates) already_found = {} frame = ts.frame timestep = _get_timestep() self.timesteps.append(timestep) pm.echo(ts.frame) self.logger_debug( "Analyzing frame %(frame)d, timestep %(timestep)f ps", vars()) if self.update_selection1: self._update_selection_1() if self.update_selection2: self._update_selection_2() if self.selection1_type in ('donor', 'both'): self.logger_debug("Selection 1 Donors <-> Acceptors") ns_acceptors = NS.AtomNeighborSearch(self._s2_acceptors) for i, donor_h_set in self._s1_donors_h.items(): d = self._s1_donors[i] for h in donor_h_set: res = ns_acceptors.search_list(AtomGroup([h]), self.distance) for a in res: angle = self.calc_angle(d, h, a) if self.distance_type in ('hydrogen'): dist = self.calc_eucl_distance(h, a) if self.distance_type in ('heavy'): dist = self.calc_eucl_distance(d, a) #print "{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n".format(d,h,a,dist,dist2,angle) if angle >= self.angle and dist <= self.distance: self.logger_debug( "S1-D: %s <-> S2-A: %s %f A, %f DEG" % (h.number + 1, a.number + 1, dist, angle)) #self.logger_debug("S1-D: %r <-> S2-A: %r %f A, %f DEG" % (h, a, dist, angle)) frame_results.append([ h.number + 1, a.number + 1, '%s%s:%s' % (h.resname, repr(h.resid), h.name), '%s%s:%s' % (a.resname, repr(a.resid), a.name), dist, angle ]) already_found[(h.number + 1, a.number + 1)] = True if self.selection1_type in ('acceptor', 'both'): self.logger_debug("Selection 1 Acceptors <-> Donors") ns_acceptors = NS.AtomNeighborSearch(self._s1_acceptors) for i, donor_h_set in self._s2_donors_h.items(): d = self._s2_donors[i] for h in donor_h_set: res = ns_acceptors.search_list(AtomGroup([h]), self.distance) for a in res: if remove_duplicates and \ ((h.number+1, a.number+1) in already_found or \ (a.number+1, h.number+1) in already_found): continue angle = self.calc_angle(d, h, a) if self.distance_type in ('hydrogen'): dist = self.calc_eucl_distance(h, a) if self.distance_type in ('heavy'): dist = self.calc_eucl_distance(d, a) if angle >= self.angle and dist <= self.distance: self.logger_debug( "S1-A: %s <-> S2-D: %s %f A, %f DEG" % (a.number + 1, h.number + 1, dist, angle)) #self.logger_debug("S1-A: %r <-> S2-D: %r %f A, %f DEG" % (a, h, dist, angle)) frame_results.append([ h.number + 1, a.number + 1, '%s%s:%s' % (h.resname, repr(h.resid), h.name), '%s%s:%s' % (a.resname, repr(a.resid), a.name), dist, angle ]) self.timeseries.append(frame_results) logger.info( "HBond analysis: complete; timeseries with %d hbonds in %s.timeseries", self.count_by_time().count.sum(), self.__class__.__name__)
def run(self, **kwargs): """Perform RMSD analysis on the trajectory. A number of parameters can be changed from the defaults. The result is stored as the array :attr:`RMSD.rmsd`. :Keywords: *start*, *stop*, *step* start and stop frame index with step size: analyse ``trajectory[start:stop:step]`` [``None``] *mass_weighted* do a mass-weighted RMSD fit *tol_mass* Reject match if the atomic masses for matched atoms differ by more than *tol_mass* *ref_frame* frame index to select frame from *reference* """ from itertools import izip start = kwargs.pop('start', None) stop = kwargs.pop('stop', None) step = kwargs.pop('step', None) mass_weighted = kwargs.pop('mass_weighted', self.mass_weighted) ref_frame = kwargs.pop('ref_frame', self.ref_frame) natoms = self.traj_atoms.numberOfAtoms() trajectory = self.universe.trajectory traj_atoms = self.traj_atoms if mass_weighted: # if performing a mass-weighted alignment/rmsd calculation weight = self.ref_atoms.masses() / self.ref_atoms.masses().mean() else: weight = None # reference centre of mass system current_frame = self.reference.trajectory.ts.frame - 1 try: # Move to the ref_frame # (coordinates MUST be stored in case the ref traj is advanced elsewhere or if ref == mobile universe) self.reference.trajectory[ref_frame] ref_com = self.ref_atoms.centerOfMass() ref_coordinates = self.ref_atoms.positions - ref_com # makes a copy if self.groupselections_atoms: groupselections_ref_coords_T_64 = [ self.reference.selectAtoms(*s['reference']).positions.T.astype(numpy.float64) for s in self.groupselections] finally: # Move back to the original frame self.reference.trajectory[current_frame] ref_coordinates_T_64 = ref_coordinates.T.astype(numpy.float64) # allocate the array for selection atom coords traj_coordinates = traj_atoms.coordinates().copy() if self.groupselections_atoms: # Only carry out a rotation if we want to calculate secondary RMSDs. # R: rotation matrix that aligns r-r_com, x~-x~com # (x~: selected coordinates, x: all coordinates) # Final transformed traj coordinates: x' = (x-x~_com)*R + ref_com rot = numpy.zeros(9, dtype=numpy.float64) # allocate space for calculation R = numpy.matrix(rot.reshape(3, 3)) else: rot = None # RMSD timeseries nframes = len(numpy.arange(0, len(trajectory))[start:stop:step]) rmsd = numpy.zeros((nframes, 3 + len(self.groupselections_atoms))) percentage = ProgressMeter(nframes, interval=10, format="RMSD %(rmsd)5.2f A at frame %(step)5d/%(numsteps)d [%(percentage)5.1f%%]\r") for k, ts in enumerate(trajectory[start:stop:step]): # shift coordinates for rotation fitting # selection is updated with the time frame x_com = traj_atoms.centerOfMass().astype(numpy.float32) traj_coordinates[:] = traj_atoms.coordinates() - x_com rmsd[k, :2] = ts.frame, trajectory.time if self.groupselections_atoms: # 1) superposition structures # Need to transpose coordinates such that the coordinate array is # 3xN instead of Nx3. Also qcp requires that the dtype be float64 # (I think we swapped the position of ref and traj in CalcRMSDRotationalMatrix # so that R acts **to the left** and can be broadcasted; we're saving # one transpose. [orbeckst]) rmsd[k, 2] = qcp.CalcRMSDRotationalMatrix(ref_coordinates_T_64, traj_coordinates.T.astype(numpy.float64), natoms, rot, weight) R[:, :] = rot.reshape(3, 3) # Transform each atom in the trajectory (use inplace ops to avoid copying arrays) # (Marginally (~3%) faster than "ts._pos[:] = (ts._pos - x_com) * R + ref_com".) ts._pos -= x_com ts._pos[:] = ts._pos * R # R acts to the left & is broadcasted N times. ts._pos += ref_com # 2) calculate secondary RMSDs for igroup, (refpos, atoms) in enumerate( izip(groupselections_ref_coords_T_64, self.groupselections_atoms), 3): rmsd[k, igroup] = qcp.CalcRMSDRotationalMatrix(refpos, atoms['mobile'].positions.T.astype(numpy.float64), atoms['mobile'].numberOfAtoms(), None, weight) else: # only calculate RMSD by setting the Rmatrix to None # (no need to carry out the rotation as we already get the optimum RMSD) rmsd[k, 2] = qcp.CalcRMSDRotationalMatrix(ref_coordinates_T_64, traj_coordinates.T.astype(numpy.float64), natoms, None, weight) percentage.echo(ts.frame, rmsd=rmsd[k, 2]) self.rmsd = rmsd
# create universe with trajectory elements; make reference universe u = md.Universe(args.top, args.traj) uref = md.Universe(args.ref) # establish resnums A = u.selectAtoms('segid PROA') B = u.selectAtoms('segid PROB') A.residues.set_resnum(A.residues.resids() + 2) B.residues.set_resnum(A.residues.resids() + 2) Aref = uref.selectAtoms('segid PROA') Bref = uref.selectAtoms('segid PROB') Aref.residues.set_resnum(Aref.residues.resids() + 2) Bref.residues.set_resnum(Aref.residues.resids() + 2) # get selections of dimerization domain dimersel = [NapA_ss[x] for x in NapA_dimer] dimer = u.selectAtoms(*dimersel) dimerref = uref.selectAtoms(*dimersel) # loop through trajectory fitting to ref, write out w = md.Writer(args.outtraj, u.trajectory.numatoms) pm = ProgressMeter(u.trajectory.numframes, interval=100) for ts in u.trajectory: pm.echo(ts.frame) aln.alignto(dimer, dimerref) w.write(ts) w.close_trajectory()
def write(self,filename,start=None,step=None,delta=None,load=True): """Write hopping trajectory as standard dcd file, together with a minimal psf. write('hop') Arguments: load = True Immediately loads the trajectory so that further calls to next() will use the computed trajectory and don't use expensive mapping. Ignore the other options and leave them at the defaults. Currently, only the whole trajectory is written. For visualization one also needs the dummy psf of the group. Results: filename.trajectory and filename.psf Note that it is your responsibility to load the hopping trajectory and the appropriate psf together as there is very limited information stored in the dcd itself. """ set_verbosity(self.verbosity) # this is stupid psfname = self.filename(filename,'psf') dcdname = self.filename(filename,'dcd') # see MDAnalysis/src/dcd/dcd.c for explanations; # other trajectories do not have certain values so we just fake them... if start is None: try: start = self.traj.start_timestep # starting time step for DCD file except AttributeError: start = 1 if step is None: try: step = self.traj.skip_timestep # NSAVC (# ts between written DCD frames) except AttributeError: step = 1 if delta is None: from MDAnalysis.core.units import get_conversion_factor delta_ps = self.traj.convert_time_from_native(self.traj.delta) # length of ts in ps delta = get_conversion_factor('time', 'ps', 'AKMA') * delta_ps dcdwriter = MDAnalysis.coordinates.DCD.DCDWriter(dcdname,self.ts.numatoms, start,step,delta, remarks='Hopping trajectory: x=site y=orbit_site z=0') pm = ProgressMeter(self.numframes, interval=10, format="Mapping frame %(step)5d/%(numsteps)6d [%(percentage)5.1f%%]\r") for ts in self.map_dcd(): dcdwriter.write_next_timestep(ts) pm.echo(ts.frame) dcdwriter.close() logger.info("HoppingTrajectory.write(): wrote hoptraj %r.", dcdname) self.write_psf(psfname) logger.info("HoppingTrajectory.write(): wrote hoppsf %r.", psfname) if load is True: self.__init__(filename=filename,verbosity=self.verbosity)
def rms_fit_trj(traj, reference, select='all', filename=None, rmsdfile=None, prefix='rmsfit_', mass_weighted=False, tol_mass=0.1, force=True, quiet=False, **kwargs): """RMS-fit trajectory to a reference structure using a selection. Both reference *ref* and trajectory *traj* must be :class:`MDAnalysis.Universe` instances. If they contain a trajectory then it is used. The output file format is determined by the file extension of *filename*. One can also use the same universe if one wants to fit to the current frame. :Arguments: *traj* trajectory, :class:`MDAnalysis.Universe` object *reference* reference coordinates; :class:`MDAnalysis.Universe` object (uses the current time step of the object) *select* 1. any valid selection string for :meth:`~MDAnalysis.core.AtomGroup.AtomGroup.selectAtoms` that produces identical selections in *mobile* and *reference*; or 2. a dictionary ``{'mobile':sel1, 'reference':sel2}`` (the :func:`fasta2select` function returns such a dictionary based on a ClustalW_ or STAMP_ sequence alignment); or 3. a tuple ``(sel1, sel2)`` When using 2. or 3. with *sel1* and *sel2* then these selections can also each be a list of selection strings (to generate a AtomGroup with defined atom order as described under :ref:`ordered-selections-label`). *filename* file name for the RMS-fitted trajectory or pdb; defaults to the original trajectory filename (from *traj*) with *prefix* prepended *rmsdfile* file name for writing the RMSD timeseries [``None``] *prefix* prefix for autogenerating the new output filename *mass_weighted* do a mass-weighted RMSD fit *tol_mass* Reject match if the atomic masses for matched atoms differ by more than *tol_mass* [0.1] *force* - ``True``: Overwrite an existing output trajectory (default) - ``False``: simply return if the file already exists *quiet* - ``True``: suppress progress and logging for levels INFO and below. - ``False``: show all status messages and do not change the the logging level (default) .. Note:: If *kwargs* All other keyword arguments are passed on the trajectory :class:`~MDAnalysis.coordinates.base.Writer`; this allows manipulating/fixing trajectories on the fly (e.g. change the output format by changing the extension of *filename* and setting different parameters as described for the corresponding writer). :Returns: *filename* (either provided or auto-generated) .. _ClustalW: http://www.clustal.org/ .. _STAMP: http://www.compbio.dundee.ac.uk/manuals/stamp.4.2/ .. versionchanged:: 0.8 Added *kwargs* to be passed to the trajectory :class:`~MDAnalysis.coordinates.base.Writer` and *filename* is returned. """ frames = traj.trajectory if quiet: # should be part of a try ... finally to guarantee restoring the log level logging.disable(logging.WARN) kwargs.setdefault('remarks', 'RMS fitted trajectory to reference') if filename is None: path, fn = os.path.split(frames.filename) filename = os.path.join(path, prefix + fn) _Writer = frames.Writer else: _Writer = frames.OtherWriter if os.path.exists(filename) and not force: logger.warn("{0} already exists and will NOT be overwritten; use force=True if you want this".format(filename)) return filename writer = _Writer(filename, **kwargs) del _Writer select = _process_selection(select) ref_atoms = reference.selectAtoms(*select['reference']) traj_atoms = traj.selectAtoms(*select['mobile']) natoms = traj_atoms.numberOfAtoms() check_same_atoms(ref_atoms, traj_atoms, tol_mass=tol_mass) logger.info("RMS-fitting on %d atoms." % len(ref_atoms)) if mass_weighted: # if performing a mass-weighted alignment/rmsd calculation weight = ref_atoms.masses() / ref_atoms.masses().mean() else: weight = None # reference centre of mass system # (compatibility with pre 1.0 numpy: explicitly cast coords to float32) ref_com = ref_atoms.centerOfMass().astype(numpy.float32) ref_coordinates = ref_atoms.coordinates() - ref_com # allocate the array for selection atom coords traj_coordinates = traj_atoms.coordinates().copy() # RMSD timeseries nframes = len(frames) rmsd = numpy.zeros((nframes,)) # R: rotation matrix that aligns r-r_com, x~-x~com # (x~: selected coordinates, x: all coordinates) # Final transformed traj coordinates: x' = (x-x~_com)*R + ref_com rot = numpy.zeros(9, dtype=numpy.float64) # allocate space for calculation R = numpy.matrix(rot.reshape(3, 3)) percentage = ProgressMeter(nframes, interval=10, quiet=quiet, format="Fitted frame %(step)5d/%(numsteps)d [%(percentage)5.1f%%]\r") for k, ts in enumerate(frames): # shift coordinates for rotation fitting # selection is updated with the time frame x_com = traj_atoms.centerOfMass().astype(numpy.float32) traj_coordinates[:] = traj_atoms.coordinates() - x_com # Need to transpose coordinates such that the coordinate array is # 3xN instead of Nx3. Also qcp requires that the dtype be float64 # (I think we swapped the position of ref and traj in CalcRMSDRotationalMatrix # so that R acts **to the left** and can be broadcasted; we're saving # one transpose. [orbeckst]) rmsd[k] = qcp.CalcRMSDRotationalMatrix(ref_coordinates.T.astype(numpy.float64), traj_coordinates.T.astype(numpy.float64), natoms, rot, weight) R[:, :] = rot.reshape(3, 3) # Transform each atom in the trajectory (use inplace ops to avoid copying arrays) # (Marginally (~3%) faster than "ts._pos[:] = (ts._pos - x_com) * R + ref_com".) ts._pos -= x_com ts._pos[:] = ts._pos * R # R acts to the left & is broadcasted N times. ts._pos += ref_com writer.write(traj.atoms) # write whole input trajectory system percentage.echo(ts.frame) logger.info("Wrote %d RMS-fitted coordinate frames to file %r", frames.numframes, filename) if not rmsdfile is None: numpy.savetxt(rmsdfile, rmsd) logger.info("Wrote RMSD timeseries to file %r", rmsdfile) if quiet: # should be part of a try ... finally to guarantee restoring the log level logging.disable(logging.NOTSET) return filename