Ejemplo n.º 1
0
    def _read_first_frame(self):
        self.ts = ts = self._Timestep(self.n_atoms, **self._ts_kwargs)

        with openany(self.filename) as inf:
            # title
            inf.readline()
            # levcfg
            inf.readline()
            # box
            inf.readline()
            inf.readline()
            inf.readline()
            # nummol
            inf.readline()
            line = inf.readline()

            atom_iter = 0

            while line:
                if line.strip().startswith('MOL'):
                    line = inf.readline().strip()
                else:
                    ts._pos[atom_iter] = inf.readline().split()[:3]
                    atom_iter += 1
                    line = inf.readline()

            return ts
Ejemplo n.º 2
0
    def _read_first_frame(self):
        with util.openany(self.filename, 'rt') as espfile:
            n_atoms = 1
            for pos, line in enumerate(espfile, start=-3):
                if pos == -3:
                    time = float(line[1:-1])
                elif pos == -2:
                    n_atoms = int(line)
                    self.n_atoms = n_atoms
                    positions = np.zeros(
                        self.n_atoms * 3, dtype=np.float32).reshape(self.n_atoms, 3)
                    velocities = np.zeros(
                        self.n_atoms * 3, dtype=np.float32).reshape(self.n_atoms, 3)
                    forces = np.zeros(
                        self.n_atoms * 3, dtype=np.float32).reshape(self.n_atoms, 3)
                    self.ts = ts = self._Timestep(
                        self.n_atoms, **self._ts_kwargs)
                    self.ts.time = time
                elif pos == -1:
                    self.ts._unitcell[:3] = np.array(
                        list(map(float, line[1:-2].split())))
                elif pos < n_atoms:
                    positions[pos] = np.array(
                        list(map(float, line[1:-2].split())))
                elif pos < 2 * n_atoms:
                    velocities[pos - n_atoms] = np.array(
                        list(map(float, line[1:-2].split())))
                else:
                    forces[pos - 2 * n_atoms] = np.array(
                        list(map(float, line[1:-2].split())))

            ts.positions = np.copy(positions)
            ts.velocities = np.copy(velocities)
            ts.forces = np.copy(forces)
Ejemplo n.º 3
0
def split_charmm(info, data_dir=path.join(os.getcwd(), "data"), **kwargs):
    """Create a subtrajectory from a CHARMM trajectory.

    Parameters
    ----------
    info : :class:`collections.namedTuple`
        Contains information about the data subdirectory and start and
        stop frames
    data_dir : str, optional
        Location of the main data directory
    toppar : str, optional
        Directory containing CHARMM topology/parameter files
    trajectory : str, optional
        A CHARMM trajectory file (e.g., dcd)
    outfile : str, optional
        A CHARMM trajectory file (e.g., dcd)
    logfile : str, optional
        Log file for output of command
    charmm_version : int
        Version of CHARMM
    """
    # Trajectory splitting information
    subdir, start, stop = info
    subdir = path.join(data_dir, "{}".format(subdir))
    charmm_exec = mdutil.which("charmm")

    # Attempt to create the necessary subdirectory
    try:
        os.makedirs(subdir)
    except OSError:
        pass

    # Various filenames
    version = kwargs.get("charmm_version", 41)
    toppar = kwargs.get("toppar",
                        "/opt/local/charmm/c{:d}b1/toppar".format(version))
    trajectory = kwargs.get("trajectory", path.join(os.curdir, "md.dcd"))
    outfile = path.join(subdir, kwargs.get("outfile", "aa.dcd"))
    logfile = path.join(subdir, kwargs.get("logfile", "split.log"))
    inpfile = path.join(subdir, "split.inp")

    with mdutil.openany(inpfile, "w") as charmm_input:
        charmm_inp = charmm_split.split_inp.format(
            toppar=toppar,
            trajectory=trajectory,
            outfile=outfile,
            version=version,
            start=start,
            stop=stop,
        )
        charmm_inp = textwrap.dedent(charmm_inp[1:])
        print(charmm_inp, file=charmm_input)
    command = [
        charmm_exec,
        "-i",
        inpfile,
        "-o",
        path.join(subdir, logfile),
    ]
    subprocess.check_call(command)
Ejemplo n.º 4
0
 def load(self, filename):
     """Load the data file."""
     records = []
     with openany(filename) as data:
         for line in data:
             if line.startswith("#"):
                 continue
             records.append(map(float, line.split()))
     self.timeseries = np.array(records).T
Ejemplo n.º 5
0
 def load(self, filename):
     """Load the data file."""
     records = []
     with openany(filename) as data:
         for line in data:
             if line.startswith('#'):
                 continue
             records.append(map(float, line.split()))
     self.timeseries = np.array(records).T
Ejemplo n.º 6
0
    def _read_out_natoms(self):
        with util.openany(self.filename, 'rt') as out:
            for line in out:
                m = re.match(r'\s*TOTAL NUMBER OF ATOMS\s*=\s*([0-9]+)\s*',line)
                if m is not None:
                    res = int(m.group(1))
                    break

        return res
    def _determine_runtyp(self):
        with util.openany(self.filename) as out:
            for line in out:
                m = re.match(r'^.*RUNTYP=([A-Z]+)\s+.*', line)
                if m is not None:
                    res = m.group(1).lower()
                    break

        return res
Ejemplo n.º 8
0
    def _read_out_natoms(self):
        with util.openany(self.filename) as out:
            for line in out:
                m = re.match(r'\s*TOTAL NUMBER OF ATOMS\s*=\s*([0-9]+)\s*',line)
                if m is not None:
                    res = int(m.group(1))
                    break

        return res
Ejemplo n.º 9
0
    def _determine_runtyp(self):
        with util.openany(self.filename) as out:
            for line in out:
                m = re.match(r'^.*RUNTYP=([A-Z]+)\s+.*', line)
                if m is not None:
                    res = m.group(1).lower()
                    break

        return res
Ejemplo n.º 10
0
    def run(self, store=True, force=False, start_frame=1, end_frame=None, step_value=1):
        """Analyze trajectory and produce timeseries.

        Stores results in :attr:`ContactAnalysis1.timeseries` (if store=True)
        and writes them to a data file. The average q is written to a second
        data file.
        *start_frame*
            The value of the first frame number in the trajectory to be used (default: frame 1)
        *end_frame*
            The value of the last frame number in the trajectory to be used (default: None -- use all frames)
        *step_value*
            The number of frames to skip during trajectory iteration (default: use every frame)
        """
        if self.output_exists(force=force):
            import warnings

            warnings.warn(
                "File %r already exists, loading it INSTEAD of trajectory %r. "
                "Use force=True to overwrite the output file. " % (self.output, self.universe.trajectory.filename)
            )
            self.load(self.output)
            return None

        with openany(self.output, "w") as out:
            out.write("# q1 analysis\n# nref = %d\n" % (self.nref))
            out.write("# frame  q1  n1\n")
            records = []
            self.qavg *= 0  # average contact existence
            A, B = self.selections
            # determine the end_frame value to use:
            total_frames = self.universe.trajectory.n_frames
            if not end_frame:
                # use the total number of frames in trajectory if no final value specified
                end_frame = total_frames
            for ts in self.universe.trajectory[start_frame:end_frame:step_value]:
                frame = ts.frame
                # use pre-allocated distance array to save a little bit of time
                MDAnalysis.lib.distances.distance_array(A.coordinates(), B.coordinates(), result=self.d)
                self.qarray(self.d, out=self.q)
                n1, q1 = self.qN(self.q, out=self._qtmp)
                self.qavg += self.q
                if store:
                    records.append((frame, q1, n1))
                out.write("%(frame)4d  %(q1)8.6f %(n1)5d\n" % vars())
        if store:
            self.timeseries = np.array(records).T
        n_frames = len(range(total_frames)[start_frame:end_frame:step_value])
        self.qavg /= n_frames
        np.savetxt(self.outarray, self.qavg, fmt="%8.6f")
        return self.output
Ejemplo n.º 11
0
 def load(self, filename):
     """Load the data file."""
     records = []
     with openany(filename) as data:
         for line in data:
             if line.startswith("#"):
                 continue
             records.append(map(float, line.split()))
     self.timeseries = np.array(records).T
     try:
         self.qavg = np.loadtxt(self.outarray)
     except IOError as err:
         if err.errno != errno.ENOENT:
             raise
Ejemplo n.º 12
0
 def load(self, filename):
     """Load the data file."""
     records = []
     with openany(filename) as data:
         for line in data:
             if line.startswith('#'):
                 continue
             records.append(map(float, line.split()))
     self.timeseries = np.array(records).T
     try:
         self.qavg = np.loadtxt(self.outarray)
     except IOError as err:
         if err.errno != errno.ENOENT:
             raise
Ejemplo n.º 13
0
    def run(self, store=True, force=False, start_frame=1, end_frame=None, step_value=1):
        """Analyze trajectory and produce timeseries.

        Stores results in :attr:`ContactAnalysis1.timeseries` (if store=True)
        and writes them to a data file. The average q is written to a second
        data file.
        *start_frame*
            The value of the first frame number in the trajectory to be used (default: frame 1)
        *end_frame*
            The value of the last frame number in the trajectory to be used (default: None -- use all frames)
        *step_value*
            The number of frames to skip during trajectory iteration (default: use every frame)
        """
        if self.output_exists(force=force):
            import warnings

            warnings.warn("File %r already exists, loading it INSTEAD of trajectory %r. "
                          "Use force=True to overwrite the output file. " %
                          (self.output, self.universe.trajectory.filename))
            self.load(self.output)
            return None

        with openany(self.output, 'w') as out:
            out.write("# q1 analysis\n# nref = {0:d}\n".format((self.nref)))
            out.write("# frame  q1  n1\n")
            records = []
            self.qavg *= 0  # average contact existence
            A, B = self.selections
            # determine the end_frame value to use:
            total_frames = self.universe.trajectory.n_frames
            if not end_frame:
                # use the total number of frames in trajectory if no final value specified
                end_frame = total_frames
            for ts in self.universe.trajectory[start_frame:end_frame:step_value]:
                frame = ts.frame
                # use pre-allocated distance array to save a little bit of time
                MDAnalysis.lib.distances.distance_array(A.coordinates(), B.coordinates(), result=self.d)
                self.qarray(self.d, out=self.q)
                n1, q1 = self.qN(self.q, out=self._qtmp)
                self.qavg += self.q
                if store:
                    records.append((frame, q1, n1))
                out.write("{frame:4d}  {q1:8.6f} {n1:5d}\n".format(**vars()))
        if store:
            self.timeseries = np.array(records).T
        n_frames = len(range(total_frames)[start_frame:end_frame:step_value])
        self.qavg /= n_frames
        np.savetxt(self.outarray, self.qavg, fmt="%8.6f")
        return self.output
Ejemplo n.º 14
0
    def _read_out_n_frames(self):
        if self.runtyp == 'optimize':
            trigger = re.compile(b'^.NSERCH=.*')
        elif self.runtyp == 'surface':
            trigger = re.compile(b'^.COORD 1=.*')

        self._offsets = offsets = []
        with util.openany(self.filename, 'rb') as out:
            line = True
            while not line == b'':  # while not EOF
                line = out.readline()
                if re.match(trigger, line):
                    offsets.append(out.tell() - len(line))

        return len(offsets)
Ejemplo n.º 15
0
    def _read_out_n_frames(self):
        if self.runtyp == 'optimize':
            trigger = re.compile(b'^.NSERCH=.*')
        elif self.runtyp == 'surface':
            trigger = re.compile(b'^.COORD 1=.*')

        self._offsets = offsets = []
        with util.openany(self.filename, 'rb') as out:
            line = True
            while not line == b'':  # while not EOF
                line = out.readline()
                if re.match(trigger, line):
                    offsets.append(out.tell() - len(line))

        return len(offsets)
Ejemplo n.º 16
0
    def load(self, filename):
        """Load the data file.

        Arguments
        ---------
        filename : string
            name of the data file to be read (can be compressed
            or a stream, see :func:`~MDAnalysis.lib.util.openany`
            for what is possible)
        """
        records = []
        with openany(filename) as data:
            for line in data:
                if line.startswith('#'): continue
                records.append(map(float, line.split()))
        return np.array(records)
Ejemplo n.º 17
0
    def load(self, filename):
        """Load the data file.

        Arguments
        ---------
        filename : string
            name of the data file to be read (can be compressed
            or a stream, see :func:`~MDAnalysis.lib.util.openany`
            for what is possible)
        """
        records = []
        with openany(filename) as data:
            for line in data:
                if line.startswith('#'): continue
                records.append(map(float, line.split()))
        return np.array(records)
Ejemplo n.º 18
0
    def write(self, filename):
        """Write the parameter table to file.

        Parameters
        ----------
        filename : str or stream
            Location to write the parameter table.
        """
        with openany(filename, mode="w") as table:
            self.table.to_csv(
                table,
                sep=native_str(" "),
                header=True,
                index=True,
                float_format="%.6f",
                encoding="utf-8",
            )
Ejemplo n.º 19
0
    def parse(self):
        with openany(self.filename) as inf:
            inf.readline()
            levcfg, imcon = map(int, inf.readline().split()[:2])
            # Box info
            if not imcon == 0:
                inf.readline()
                inf.readline()
                inf.readline()

            # Nummol
            inf.readline()

            # Loop over molecules
            resid = 1
            atomid = 0
            atoms = []
            segid = 'SYSTEM'

            line = inf.readline().strip()
            while line:
                if line.startswith('MOLECULE'):
                    resid += 1
                    resname = line.split()[1]
                else:
                    name = line.split()[0]
                    inf.readline()

                    atoms.append(
                        Atom(atomid,
                             name,
                             name,
                             resname,
                             resid,
                             segid,
                             1.0,
                             1.0,
                             universe=self._u))
                    atomid += 1

                line = inf.readline()

        return {'atoms': atoms}
Ejemplo n.º 20
0
def split_gmx(info, data_dir=path.join(os.getcwd(), "data"), **kwargs):
    """Create a subtrajectory from a Gromacs trajectory.

    Parameters
    ----------
    info : :class:`collections.namedTuple`
        Contains information about the data subdirectory and start and
        stop frames
    data_dir : str, optional
        Location of the main data directory
    topology : str, optional
        Topology filename (e.g., tpr gro g96 pdb brk ent)
    trajectory : str, optional
        A Gromacs trajectory file (e.g., xtc trr)
    index : str, optional
        A Gromacs index file (e.g., ndx)
    outfile : str, optional
        A Gromacs trajectory file (e.g., xtc trr)
    logfile : str, optional
        Log file for output of command
    system : int
        Atom selection from Gromacs index file (0 = System, 1 = Protein)
    """
    # Trajectory splitting information
    subdir, start, stop = info
    subdir = path.join(data_dir, "{}".format(subdir))
    gromacs_exec = mdutil.which("gmx")

    # Attempt to create the necessary subdirectory
    try:
        os.makedirs(subdir)
    except OSError:
        pass

    # Various filenames
    topology = kwargs.get("topology", "md.tpr")
    trajectory = kwargs.get("trajectory", path.join(os.curdir, "md.xtc"))
    index = kwargs.get("index")
    outfile = path.join(subdir, kwargs.get("outfile", "aa.xtc"))
    logfile = path.join(subdir, kwargs.get("logfile", "split.log"))

    if index is not None:
        command = [
            "gmx",
            "trjconv",
            "-s",
            topology,
            "-f",
            trajectory,
            "-n",
            index,
            "-o",
            outfile,
            "-b",
            "{:d}".format(start),
            "-e",
            "{:d}".format(stop),
        ]
    else:
        command = [
            gromacs_exec,
            "trjconv",
            "-s",
            topology,
            "-f",
            trajectory,
            "-o",
            outfile,
            "-b",
            "{:d}".format(start),
            "-e",
            "{:d}".format(stop),
        ]
    fd, fpath = tempfile.mkstemp(text=True)
    with mdutil.openany(fpath, "w") as temp:
        print(kwargs.get("system", 0), file=temp)
    with mdutil.openany(fpath, "r") as temp, \
        mdutil.openany(logfile, mode="w") as log:
        logger.info("Writing trajectory to {}".format(outfile))
        logger.info("Writing Gromacs output to {}".format(logfile))
        subprocess.check_call(command,
                              stdin=temp,
                              stdout=log,
                              stderr=subprocess.STDOUT)
    os.remove(fpath)
Ejemplo n.º 21
0
    def write(self, selection, bonds=None, angles=None, frame=None):
        """Write selection at current trajectory frame to file.

        The sections for Atoms, Masses, Velocities, Bonds, Angles,
        Dihedrals, and Impropers (if these are defined) are
        written. The Atoms section is written in the "full" sub-style
        if charges are available or "molecular" sub-style if they are
        not. Molecule id in atoms section is set to to 0.

        No other sections are written to the DATA file.
        As of this writing, other sections are not parsed into the topology
        by the :class:`DATAReader`.

        Note
        ----
        If the selection includes a partial fragment, then only the bonds,
        angles, etc. whose atoms are contained within the selection will be
        included.

        Parameters
        ----------
        selection : AtomGroup or Universe
            MDAnalysis AtomGroup (selection or Universe.atoms) or also Universe
        
        bonds : np.array (nbonds * 3)
            [[atom index1 (0-indexed), atom index2 (0-indexed), bond type (1-indexed)]]

        angles: np.array (nangles * 4)
            [[atom1, atom2 (apex/center atom), atom3, angle type (1-indexed)]]
            atom indices 0-indexed

        frame : int (optional)
            optionally move to frame number `frame`

        """
        u = selection.universe
        if frame is not None:
            u.trajectory[frame]
        else:
            frame = u.trajectory.ts.frame

        # make sure to use atoms (Issue 46)
        atoms = selection.atoms

        # check that types can be converted to ints if they aren't ints already
        try:
            atoms.types.astype(np.int32)
        except ValueError:
            t = 1; types = {}
            for atom in atoms:
                if atom.name in types.keys():
                    atom.type = types[atom.name]
                else:
                    atom.type = t
                    types[atom.name] = t
                    t += 1
            print('LAMMPS.DATAWriter: atom types must be '+
                  'convertible to integers '+
                  'so I changed atom types!')
            print('Please note this assignment is '+
                  'NOT temporary!!')
            print(types)

        try:
            velocities = atoms.velocities
        except (NoDataError, AttributeError):
            has_velocities = False
        else:
            has_velocities = True

        features = {}
        with util.openany(self.filename, 'w') as self.f:
            self.f.write('LAMMPS data file via SMDAnalysis\n')
            self.f.write('\n')
            self.f.write('{:>12d}  atoms\n'.format(len(atoms)))
            
            if bonds is not None:
                self.f.write('{:>12d}  {}\n'.format(len(bonds), 'bonds'))
            if angles is not None:
                self.f.write('{:>12d}  {}\n'.format(len(angles), 'angles'))

            attrs = [('dihedral', 'dihedrals'), ('improper', 'impropers')]

            for btype, attr_name in attrs:
                try:
                    features[btype] = atoms.__getattribute__(attr_name)
                    self.f.write('{:>12d}  {}\n'.format(len(features[btype]),
                                 attr_name))
                    features[btype] = features[btype].atomgroup_intersection(
                                      atoms, strict=True)
                except AttributeError:
                    features[btype] = None
                    self.f.write('{:>12d}  {}\n'.format(0, attr_name))

            self.f.write('\n')
            self.f.write('{:>12d}  atom types\n'.format(max(atoms.types.astype(np.int32))))
            
            if bonds is not None:
                self.f.write('{:>12d}  {} types\n'.format(
                    len(np.unique(bonds[:,2])), 'bond'))

            if angles is not None:
                self.f.write('{:>12d}  {} types\n'.format(
                    len(np.unique(angles[:,3])), 'angle'))

            for btype, attr in features.items():
                if attr is None:
                    self.f.write('{:>12d}  {} types\n'.format(0, btype))
                else:
                    self.f.write('{:>12d}  {} types\n'.format(len(attr.types()),
                                                              btype))

            self._write_dimensions(atoms.dimensions)

            self._write_masses(atoms)
            self._write_atoms(atoms)

            if bonds is not None:
                self._write_bonds(bonds)

            if angles is not None:
                self._write_angles(angles)

            for attr in features.values():
                if attr is None or len(attr) == 0:
                    continue
                self._write_bonds(attr)

            if has_velocities:
                self._write_velocities(atoms)
Ejemplo n.º 22
0
    def run(self, store=True, force=False, start=0, stop=None, step=1,
            **kwargs):
        """Analyze trajectory and produce timeseries.

        Stores results in :attr:`ContactAnalysis1.timeseries` (if store=True)
        and writes them to a data file. The average q is written to a second
        data file.
        *start*
            The value of the first frame index in the trajectory to be used
            (default: index 0)
        *stop*
            The value of the last frame index in the trajectory to be used
            (default: None -- use all frames)
        *step*
            The number of frames to skip during trajectory iteration (default:
            use every frame)

        """

        if 'start_frame' in kwargs:
            warnings.warn("start_frame argument has been deprecated, use "
                          "start instead -- removal targeted for version "
                          "0.15.0", DeprecationWarning)
            start = kwargs.pop('start_frame')

        if 'end_frame' in kwargs:
            warnings.warn("end_frame argument has been deprecated, use "
                          "stop instead -- removal targeted for version "
                          "0.15.0", DeprecationWarning)
            stop = kwargs.pop('end_frame')

        if 'step_value' in kwargs:
            warnings.warn("step_value argument has been deprecated, use "
                          "step instead -- removal targeted for version "
                          "0.15.0", DeprecationWarning)
            step = kwargs.pop('step_value')

        if self.output_exists(force=force):
            warnings.warn("File %r already exists, loading it INSTEAD of "
                          "trajectory %r. Use force=True to overwrite "
                          "the output file. " %
                          (self.output, self.universe.trajectory.filename))
            self.load(self.output)
            return None

        with openany(self.output, 'w') as out:
            out.write("# q1 analysis\n# nref = {0:d}\n".format((self.nref)))
            out.write("# frame  q1  n1\n")
            records = []
            self.qavg *= 0  # average contact existence
            A, B = self.selections
            for ts in self.universe.trajectory[start:stop:step]:
                frame = ts.frame
                # use pre-allocated distance array to save a little bit of time
                MDAnalysis.lib.distances.distance_array(A.coordinates(),
                                                        B.coordinates(),
                                                        result=self.d)
                self.qarray(self.d, out=self.q)
                n1, q1 = self.qN(self.q, out=self._qtmp)
                self.qavg += self.q
                if store:
                    records.append((frame, q1, n1))
                out.write("{frame:4d}  {q1:8.6f} {n1:5d}\n".format(**vars()))
        if store:
            self.timeseries = np.array(records).T
        n_frames = len(np.arange(
            self.universe.trajectory.n_frames)[start:stop:step])
        if n_frames > 0:
            self.qavg /= n_frames
        else:
            logger.warn("No frames were analyzed. "
                        "Check values of start, stop, step.")
            logger.debug("start={start} stop={stop} step={step}".format(**vars()))
        np.savetxt(self.outarray, self.qavg, fmt="%8.6f")
        return self.output
Ejemplo n.º 23
0
    def run(self,
            store=True,
            force=False,
            start=0,
            stop=None,
            step=1,
            **kwargs):
        """Analyze trajectory and produce timeseries.

        Stores results in :attr:`ContactAnalysis1.timeseries` (if store=True)
        and writes them to a data file. The average q is written to a second
        data file.
        *start*
            The value of the first frame index in the trajectory to be used
            (default: index 0)
        *stop*
            The value of the last frame index in the trajectory to be used
            (default: None -- use all frames)
        *step*
            The number of frames to skip during trajectory iteration (default:
            use every frame)

        """

        if 'start_frame' in kwargs:
            warnings.warn(
                "start_frame argument has been deprecated, use "
                "start instead -- removal targeted for version "
                "0.15.0", DeprecationWarning)
            start = kwargs.pop('start_frame')

        if 'end_frame' in kwargs:
            warnings.warn(
                "end_frame argument has been deprecated, use "
                "stop instead -- removal targeted for version "
                "0.15.0", DeprecationWarning)
            stop = kwargs.pop('end_frame')

        if 'step_value' in kwargs:
            warnings.warn(
                "step_value argument has been deprecated, use "
                "step instead -- removal targeted for version "
                "0.15.0", DeprecationWarning)
            step = kwargs.pop('step_value')

        if self.output_exists(force=force):
            warnings.warn("File %r already exists, loading it INSTEAD of "
                          "trajectory %r. Use force=True to overwrite "
                          "the output file. " %
                          (self.output, self.universe.trajectory.filename))
            self.load(self.output)
            return None

        with openany(self.output, 'w') as out:
            out.write("# q1 analysis\n# nref = {0:d}\n".format((self.nref)))
            out.write("# frame  q1  n1\n")
            records = []
            self.qavg *= 0  # average contact existence
            A, B = self.selections
            for ts in self.universe.trajectory[start:stop:step]:
                frame = ts.frame
                # use pre-allocated distance array to save a little bit of time
                MDAnalysis.lib.distances.distance_array(A.coordinates(),
                                                        B.coordinates(),
                                                        result=self.d)
                self.qarray(self.d, out=self.q)
                n1, q1 = self.qN(self.q, out=self._qtmp)
                self.qavg += self.q
                if store:
                    records.append((frame, q1, n1))
                out.write("{frame:4d}  {q1:8.6f} {n1:5d}\n".format(**vars()))
        if store:
            self.timeseries = np.array(records).T
        n_frames = len(
            np.arange(self.universe.trajectory.n_frames)[start:stop:step])
        if n_frames > 0:
            self.qavg /= n_frames
        else:
            logger.warn("No frames were analyzed. "
                        "Check values of start, stop, step.")
            logger.debug(
                "start={start} stop={stop} step={step}".format(**vars()))
        np.savetxt(self.outarray, self.qavg, fmt="%8.6f")
        return self.output