Trajectory class
****************

This subsection describes the API of the "Trajectory" class. While the
"RKFTrajectoryFile" clearly represents a file, the "Trajectory" is set
up to represent the trajectory itself. It behaves like a list of
"Molecule" objects, while keeping the memory requirements to a
minimum. A "Trajectory" object can be associated with a single RKF
file, or with multiple RKF files. In the latter case, the frames will
be concatenated.

class Trajectory(filenames)

   Class representing an AMS trajectory

   It creates molecule objects along the trajectory in a list-like
   fashion. It can also perform analysis tasks.

   Basic use of the "Trajectory" class works as follows:

   >>> from scm.plams import Trajectory

   >>> trajec = Trajectory('ams.rkf')
   >>> nsteps = len(trajec)

   >>> mol100 = trajec[100]
   >>> for i,mol in enumerate(trajec):
   ...     if i == 100:
   ...         print (mol is mol100)
   ...
   True

   As with a regular list, accessing the same element twice yields the
   same instance of the molecule.

   A trajectory may consist of multiple RKF files, for instance after
   a restarted MD run.

   >>> trajec = Trajectory(['md1.results/ams.rkf','md2.results/ams.rkf'])
   >>> nsteps = len(trajec)
   >>> print ('NSteps in each file: ',trajec.lengths)
   NSteps in each file:  [181, 19]

   Otherwise the object behaves the same, and iteration occurs over
   the concatenated files.

   Note:

     It is possible to change the molecule objects once they are
     loaded, but this will not change the underlying files. When the
     altered molecule objects have been garbage collected, and the
     same frame is read anew, this frame will have the original
     molecule attributes.

     >>> import gc
     >>> from scm.plams import Trajectory

     >>> trajec = Trajectory('ams.rkf')
     >>> mol = trajec[100]
     >>> print (mol.properties.charge)
     0.0
     >>> mol.properties.charge = 10000.
     >>> print (trajec[100].properties.charge)
     1000.0

     >>> # remove the reference
     >>> mol = None
     >>> gc.collect()
     >>> print (trajec[100].properties.charge)
     0.

   The "Trajectory" object can also be used to perform analysis, using
   "AMSAnalysisJob" behind the scenes.

   >>> from scm.plams import Settings, Trajectory
   >>> from scm.plams import init, finish

   >>> trajec = Trajectory('ams.rkf')

   >>> # Define the type of analysis
   >>> settings = Settings()
   >>> settings.input.Task = 'RadialDistribution'
   >>> settings.input.RadialDistribution.AtomsFrom.Element = ['O']
   >>> settings.input.RadialDistribution.AtomsTo.Element = ['O']

   >>> # Run the analysis
   >>> plots = trajec.run_analysis(settings)

   >>> # Store the plot in human readable format
   >>> for plot in plots :
   ...     plot.write('%s'%(plot.name+'.txt'))

   This results in a text file named RadialDistribution_1.txt, which
   contains data organized in columns.

   run_analysis(settings, steprange=None)

      Calls the AMS analysis tool behind the scenes

      * "settings"  -- PLAMS Settings object Example :

        >>> settings = Settings()
        >>> settings.input.Task = 'AutoCorrelation'
        >>> settings.input.AutoCorrelation.Property = 'Velocities'
        >>> settings.input.AutoCorrelation.MaxFrame = 2000

      * "steprange" -- Start frame, end frame, and stepsize. The
        default (None) corresponds to all frames in the object

      Returns a list of AMSAnalysisPlot objects. Main attributes of
      the AMSAnalysisPlot objects are :

      * "name"    -- The name of the plot

      * "x"       -- A list of lists containing the values of the
        coordinate system If the coordinate system is 1D, then it is a
        list containing a single list of values x =
        [[x1,x2,x3,x4,...,xn]]

      * "y"       -- A list containing the function values

      * "write()" -- A method returning a string containing all plot
        info
