"""Concatenate, slice, and/or select DCD files."""
from ..apptools import *
__all__ = ['prody_catdcd']
[docs]def prody_catdcd(*dcd, **kwargs):
"""Concatenate *dcd* files.
:arg select: atom selection
:arg align: atom selection for aligning frames
:arg pdb: PDB file used in atom selections and as reference for alignment
:arg psf: PSF file used in atom selections
:arg output: output filename
:arg first: index of the first output frame
:arg last: index of the last output frame
:arg stride: number of steps between output frames"""
import prody
LOGGER = prody.LOGGER
if kwargs.get('numframes', False):
from sys import stdout
for fn in dcd:
stdout.write(str(prody.DCDFile(fn).numFrames()) + '\n')
return
from os.path import splitext
ag = None
psf = kwargs.get('psf', None)
if psf:
ag = prody.parsePSF(psf)
pdb = kwargs.get('pdb', None)
if pdb:
if ag:
ag = prody.parsePDB(pdb, ag=ag)
else:
ag = prody.parsePDB(pdb)
align = kwargs.get('align', None)
select = kwargs.get('select', None)
if select == 'all':
select = None
if ag is None and (align or select):
raise ValueError('one of PSF or PDB files must be provided for '
'align and select options to work')
dcd = list(dcd)
traj = prody.Trajectory(dcd.pop(0))
while dcd:
traj.addFile(dcd.pop(0))
if ag:
traj.link(ag)
if ag.numCoordsets():
traj.setCoords(ag.getCoords())
if select:
select = ag.select(select)
if select is None:
raise ValueError('{0} did not match any atoms'
.format(repr(kwargs.get('select'))))
else:
select = ag
LOGGER.info('{0} atoms are selected for writing output.'
.format(len(select)))
if align:
align = ag.select(align)
traj.setAtoms(align)
LOGGER.info('{0} atoms are selected for aligning frames.'
.format(len(align)))
output = kwargs.get('output', 'trajectory.dcd')
out = prody.DCDFile(output, 'w')
count = 0
stride = kwargs.get('stride', 1)
goto = stride != 1
slc = slice(kwargs.get('first', 0), kwargs.get('last', -1),
stride).indices(len(traj)+1)
for i in range(*slc):
if goto:
traj.goto(i)
frame = next(traj)
if align:
frame.superpose()
if select:
out.write(select._getCoords(), frame.getUnitcell())
else:
out.write(frame._getCoords(), frame.getUnitcell())
count += 1
traj.close()
out.close()
LOGGER.info("{0} frames are written into {1}."
.format(count, output))
def addCommand(commands):
subparser = commands.add_parser('catdcd',
help='concatenate dcd files')
subparser.add_argument('--quiet', help="suppress info messages to stderr",
action=Quiet, nargs=0)
subparser.add_argument('--examples', action=UsageExample, nargs=0,
help='show usage examples and exit')
subparser.set_defaults(usage_example=
"""Concatenate two DCD files and output all atmos:
$ prody catdcd mdm2.dcd mdm2sim2.dcd
Concatenate two DCD files and output backbone atoms:
$ prody catdcd mdm2.dcd mdm2sim2.dcd --pdb mdm2.pdb -s bb""")
subparser.add_argument('-s', '--select', default='all', type=str,
dest='select', metavar='SEL',
help='atom selection (default: %(default)s)')
subparser.add_argument('-o', '--output', type=str, metavar='FILE',
default='trajectory.dcd',
help='output filename (default: %(default)s)')
subparser.add_argument('-n', '--num', default=False, action='store_true',
dest='numframes',
help='print the number of frames in each file and exit')
subparser.add_argument('--psf',
help='PSF filename (must have same number of atoms as DCDs)')
subparser.add_argument('--pdb',
help='PDB filename (must have same number of atoms as DCDs)')
subparser.add_argument('--first', metavar='INT', type=int, default=0,
help='index of the first output frame, default: %(default)s')
subparser.add_argument('--last', metavar='INT', type=int, default=-1,
help='index of the last output frame, default: %(default)s')
subparser.add_argument('--stride', metavar='INT', type=int, default=1,
help='number of steps between output frames, default: %(default)s')
subparser.add_argument('--align', metavar='SEL', type=str,
help='atom selection for aligning frames, a PSF or PDB file must be '
'provided, if a PDB is provided frames will be superposed onto '
'PDB coordinates')
subparser.add_argument('dcd', nargs='+',
help='DCD filename(s) (all must have same number of atoms)')
subparser.set_defaults(subparser=subparser)
subparser.set_defaults(func=lambda ns: prody_catdcd(
*ns.__dict__.pop('dcd'), **ns.__dict__))