Skip to content
Snippets Groups Projects
TraceWin.py 36.8 KiB
Newer Older
Yngve Levinsen's avatar
Yngve Levinsen committed
from __future__ import print_function
Yngve Levinsen's avatar
Yngve Levinsen committed

Yngve Levinsen's avatar
Yngve Levinsen committed
class dst:
Yngve Levinsen's avatar
Yngve Levinsen committed
    '''
Yngve Levinsen's avatar
Yngve Levinsen committed
    Simple class to read in a
Yngve Levinsen's avatar
Yngve Levinsen committed
    TraceWin distribution file

    Class afterwards hold the following
    dictionary items:
Yngve Levinsen's avatar
Yngve Levinsen committed
      - x [m]
Yngve Levinsen's avatar
Yngve Levinsen committed
      - xp [rad]
Yngve Levinsen's avatar
Yngve Levinsen committed
      - y [m]
Yngve Levinsen's avatar
Yngve Levinsen committed
      - yp [rad]
      - phi [rad]
Yngve Levinsen's avatar
Yngve Levinsen committed
    '''
Yngve Levinsen's avatar
Yngve Levinsen committed
    def __init__(self, filename=None):
Yngve Levinsen's avatar
Yngve Levinsen committed
        # easy storage..
Yngve Levinsen's avatar
Yngve Levinsen committed
        self.filename = filename
Yngve Levinsen's avatar
Yngve Levinsen committed
        # used to create dict behaviour..
Yngve Levinsen's avatar
Yngve Levinsen committed
        self._columns = ['x', 'xp', 'y', 'yp', 'phi', 'E']
Yngve Levinsen's avatar
Yngve Levinsen committed
        if filename:
            # read in the file..
            self._readBinaryFile()
        else:
            import numpy
Yngve Levinsen's avatar
Yngve Levinsen committed
            self.Np = 0
            self.Ib = 0.0
            self.freq = 352.21
            self._data = numpy.zeros((self.Np, 6))
            self.mass = 0.0
Yngve Levinsen's avatar
Yngve Levinsen committed

Yngve Levinsen's avatar
Yngve Levinsen committed
    def append(self, x=0.0, xp=0.0, y=0.0, yp=0.0, E=0.0, phi=0.0):
        '''
        Append one particle to the distribution

        - Kinetic Energy in MeV
        - x,y in m
        - xp,yp in rad
        - phi in rad
        '''
        import numpy

Yngve Levinsen's avatar
Yngve Levinsen committed
        self._data = numpy.append(self._data, [[x, xp, y, yp, phi, E]], 0)
        self.Np += 1

    def remove(self, i=None):
        '''
        Removes all particles from the distribution, or the line specified by i
        '''
        import numpy

Yngve Levinsen's avatar
Yngve Levinsen committed
        if i is None:
            self._data=numpy.delete(self._data,numpy.s_[:], 0)
Yngve Levinsen's avatar
Yngve Levinsen committed
            self._data=numpy.delete(self._data, i, 0)
Yngve Levinsen's avatar
Yngve Levinsen committed
    def _readBinaryFile(self):
Yngve Levinsen's avatar
Yngve Levinsen committed
        # Thanks Ema!
Yngve Levinsen's avatar
Yngve Levinsen committed

        import numpy

Yngve Levinsen's avatar
Yngve Levinsen committed
        fin=open(self.filename,'r')
Yngve Levinsen's avatar
Yngve Levinsen committed

        # dummy, Np, Ib, freq, dummy
        Header_type = numpy.dtype([
            ('dummy12', numpy.int16),
            ('Np',      numpy.int32),
            ('Ib',      numpy.float64),
            ('freq',    numpy.float64),
            ('dummy3',  numpy.int8)
            ])
Yngve Levinsen's avatar
Yngve Levinsen committed
        Header = numpy.fromfile(fin, dtype=Header_type, count=1)
        self.Np = Header['Np'][0]
        self.Ib = Header['Ib'][0]
        self.freq = Header['freq'][0]
Yngve Levinsen's avatar
Yngve Levinsen committed

Yngve Levinsen's avatar
Yngve Levinsen committed
        # Some toutatis distributions has an undocumented 7th line of 0's
Yngve Levinsen's avatar
Yngve Levinsen committed
        Table = numpy.fromfile(fin, dtype=numpy.float64, count=self.Np*7+1)
Yngve Levinsen's avatar
Yngve Levinsen committed
        if len(Table)==self.Np*7+1:
Yngve Levinsen's avatar
Yngve Levinsen committed
            self._data = Table[:-1].reshape(self.Np, 7)
Yngve Levinsen's avatar
Yngve Levinsen committed
        elif len(Table)==self.Np*6+1: # this is true in most cases
Yngve Levinsen's avatar
Yngve Levinsen committed
            self._data = Table[:-1].reshape(self.Np, 6)
Yngve Levinsen's avatar
Yngve Levinsen committed
        else:
Yngve Levinsen's avatar
Yngve Levinsen committed
            raise ValueError("Incorrect table dimensions found:", len(Table))
Yngve Levinsen's avatar
Yngve Levinsen committed

Yngve Levinsen's avatar
Yngve Levinsen committed
        # convert x,y from cm to m:
Yngve Levinsen's avatar
Yngve Levinsen committed
        self._data[:,0] *= 1e-2
        self._data[:,2] *= 1e-2
Yngve Levinsen's avatar
Yngve Levinsen committed

Yngve Levinsen's avatar
Yngve Levinsen committed
        self.mass = Table[-1]
Yngve Levinsen's avatar
Yngve Levinsen committed

Yngve Levinsen's avatar
Yngve Levinsen committed
    def keys(self):
        return self._columns[:]

Yngve Levinsen's avatar
Yngve Levinsen committed
    def __getitem__(self, key):
Yngve Levinsen's avatar
Yngve Levinsen committed
        # makes the class function as a dictionary
        # e.g. dst['x'] returns the x array..
Yngve Levinsen's avatar
Yngve Levinsen committed
        try:
Yngve Levinsen's avatar
Yngve Levinsen committed
            i=self._columns.index(key)
Yngve Levinsen's avatar
Yngve Levinsen committed
            return self._data[:, i]
Yngve Levinsen's avatar
Yngve Levinsen committed
        except:
            raise ValueError("Available keys: "+str(self._columns))

    def __setitem__(self, key, value):
        try:
            i=self._columns.index(key)
Yngve Levinsen's avatar
Yngve Levinsen committed
            self._data[:,i] = value
Yngve Levinsen's avatar
Yngve Levinsen committed
        except:
            raise ValueError("Available keys: "+str(self._columns))
    
    def save(self, filename, toutatis=False):
Yngve Levinsen's avatar
Yngve Levinsen committed
        '''
        Save the distribution file
        so it can be read by TraceWin again

        :param filename: Name of file
        :param toutatis: Include 7th column of zeros

Yngve Levinsen's avatar
Yngve Levinsen committed
        Stolen from Ryoichi's func.py (with permission)
        '''

        from struct import pack
Yngve Levinsen's avatar
Yngve Levinsen committed

Yngve Levinsen's avatar
Yngve Levinsen committed
        fout=open(filename, 'wb')
        fout.write(pack('b', 125))
        fout.write(pack('b', 100))
        fout.write(pack('i', self.Np))
        fout.write(pack('d', self.Ib))
        fout.write(pack('d', self.freq))
        fout.write(pack('b', 125))
Yngve Levinsen's avatar
Yngve Levinsen committed

Yngve Levinsen's avatar
Yngve Levinsen committed
        data = self._data.copy()
Yngve Levinsen's avatar
Yngve Levinsen committed

        if toutatis and data.shape[1]==6:
Yngve Levinsen's avatar
Yngve Levinsen committed
            data = numpy.append(data,numpy.zeros((len(data),1)),1)
        elif not toutatis and data.shape[1]==7:
Yngve Levinsen's avatar
Yngve Levinsen committed
            data = data[:,:-1]
Yngve Levinsen's avatar
Yngve Levinsen committed
        # convert x,y from m to cm:
Yngve Levinsen's avatar
Yngve Levinsen committed
        data[:,0] *= 1e2
        data[:,2] *= 1e2
Yngve Levinsen's avatar
Yngve Levinsen committed

Yngve Levinsen's avatar
Yngve Levinsen committed
            data = data.reshape(self.Np*7, 1)
Yngve Levinsen's avatar
Yngve Levinsen committed
            data = data.reshape(self.Np*6, 1)
Yngve Levinsen's avatar
Yngve Levinsen committed

Yngve Levinsen's avatar
Yngve Levinsen committed
        for x in data:
Yngve Levinsen's avatar
Yngve Levinsen committed
            fout.write(pack('d', x))
Yngve Levinsen's avatar
Yngve Levinsen committed

Yngve Levinsen's avatar
Yngve Levinsen committed
        fout.write(pack('d', self.mass))
Yngve Levinsen's avatar
Yngve Levinsen committed
        fout.close()

    def subplot(self, index, x, y=None, nb=100, mask=None):
        '''
        Create a subplot histogram similar to TraceWin.

        Example::
            import numpy as np
            from ess import TraceWin
            from matplotlib import pyplot as plt
            data=TraceWin.dst('part_dtl1.dst')
            m=np.where(data['E']>3.5)
            data.subplot(221,'x','xp',mask=m)
            data.subplot(222,'y','yp',mask=m)
            data.subplot(223,'phi','E',mask=m)
            data.subplot(224,'x','y',mask=m)
            plt.show()

        '''
        from matplotlib.colors import LogNorm
        import matplotlib.pyplot as plt
        import numpy as np

        units={ 'x': 'mm', 'y': 'mm',
                'xp': 'mrad', 'yp': 'mrad',
                'E': 'MeV', 'phi': 'deg'
              }
        # get X and Y data
        if mask!=None:
Yngve Levinsen's avatar
Yngve Levinsen committed
            dx = dx[mask]
Yngve Levinsen's avatar
Yngve Levinsen committed
            dy = np.array(self[y])

        if x in ['x','y','xp','yp']:
            dx*=1e3
        if y in ['x','y','xp','yp']:
            dy*=1e3
        if x in ['phi']:
            dx-=np.average(dx)
            dx*=180/np.pi
        if y in ['phi']:
Loading
Loading full blame...