def analysis(self, frames='<STR_LIT:all>', ncpus=<NUM_LIT:1>, override=False, **kwargs):
if override is True:<EOL><INDENT>self.analysis_output = {}<EOL><DEDENT>if isinstance(frames, int):<EOL><INDENT>analysed_frame = self._analysis_serial(frames, ncpus, **kwargs)<EOL>if frames not in self.analysis_output.keys():<EOL><INDENT>self.analysis_output[frames] = analysed_frame<EOL><DEDENT>return analysed_frame<EOL><DEDENT>else:<EOL><INDENT>frames_for_analysis = []<EOL>if isinstance(frames, list):<EOL><INDENT>for frame in frames:<EOL><INDENT>if frame not in self.analysis_output.keys():<EOL><INDENT>frames_for_analysis.append(frame)<EOL><DEDENT><DEDENT><DEDENT>if isinstance(frames, tuple):<EOL><INDENT>for frame in range(frames[<NUM_LIT:0>], frames[<NUM_LIT:1>]):<EOL><INDENT>if frame not in self.analysis_output.keys():<EOL><INDENT>frames_for_analysis.append(frame)<EOL><DEDENT><DEDENT><DEDENT>if isinstance(frames, str):<EOL><INDENT>if frames in ['<STR_LIT:all>', '<STR_LIT>']:<EOL><INDENT>for frame in range(<NUM_LIT:0>, self.no_of_frames):<EOL><INDENT>if frame not in self.analysis_output.keys():<EOL><INDENT>frames_for_analysis.append(frame)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>self._analysis_parallel(frames_for_analysis, ncpus, **kwargs)<EOL><DEDENT>
Perform structural analysis on a frame/ set of frames.

Depending on the passed parameters a frame, a list of particular
frames, a range of frames (from, to), or all frames can be analysed
with this function.

The analysis is performed on each frame and each discrete molecule in
that frame separately. The steps are as follows:

1. A frame is extracted and returned as a :class:`MolecularSystem`.
2. If `swap_atoms` is set the atom ids are swapped.
3. If `forcefield` is set the atom ids are deciphered.
4. If `rebuild` is set the molecules in the system are rebuild.
5. Each discrete molecule is extracted as :class:`Molecule`
6. Each molecule is analysed with :func:`Molecule.full_analysis()`
7. Analysis output populates the :attr:`analysis_output` dictionary.

As the analysis of trajectories often have to be unique, many options
are conditional.

A side effect of this function is that the analysed frames are also
returned to the :attr:`frames` mimicking the behaviour of the
:func:`get_frames()`.

Parameters
----------
frames : :class:`int` or :class:`list` or :class:`touple` or :class:`str`
    Specified frame (:class:`int`), or frames (:class:`list`), or
    range (:class:`touple`), or `all`/`everything` (:class:`str`).
    (default='all')

override : :class:`bool`
    If True, an output already storred in :attr:`analysis_output` can
    be override. (default=False)

swap_atoms : :class:`dict`, optional
    If this kwarg is passed with an appropriate dictionary a
    :func:`pywindow.molecular.MolecularSystem.swap_atom_keys()` will
    be applied to the extracted frame.

forcefield : :class:`str`, optional
    If this kwarg is passed with appropriate forcefield keyword a
    :func:`pywindow.molecular.MolecularSystem.decipher_atom_keys()`
    will be applied to the extracted frame.

modular : :class:`bool`, optional
    If this kwarg is passed a
    :func:`pywindow.molecular.MolecularSystem.make_modular()`
    will be applied to the extracted frame. (default=False)

rebuild : :class:`bool`, optional
    If this kwarg is passed a `rebuild=True` is passed to
    :func:`pywindow.molecular.MolecularSystem.make_modular()` that
    will be applied to the extracted frame. (default=False)

ncpus : :class:`int`, optional
    If ncpus > 1, then the analysis is performed in parallel for the
    specified number of parallel jobs. Otherwise, it runs in serial.
    (default=1)

Returns
-------
None : :class:`NoneType`
    The function returns `None`, the analysis output is
    returned to :attr:`analysis_output` dictionary.