Skip to content
Snippets Groups Projects
TraceWin.py 58.7 KiB
Newer Older
Yngve Levinsen's avatar
Yngve Levinsen committed
class dst:
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:
    - x [m]
    - xp [rad]
    - y [m]
    - yp [rad]
    - phi [rad]
    - E [MeV] (kinetic energy)
    """

    def __init__(self, filename=None, freq=352.21, mass=938.272, Ib=0.0):
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..
        self._columns = ["x", "xp", "y", "yp", "phi", "E"]
Yngve Levinsen's avatar
Yngve Levinsen committed
        self._indirect_columns = ["r", "rp"]
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 = Ib
            self.freq = freq
Yngve Levinsen's avatar
Yngve Levinsen committed
            self._data = numpy.zeros((self.Np, 6))
            self.mass = mass
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
Yngve Levinsen's avatar
Yngve Levinsen committed
        self._data = numpy.append(self._data, [[x, xp, y, yp, phi, E]], 0)
        self.Np += 1
    def append_many(self, array):
        Append a matrix of particle vectors.

        Matrix on form 6xN, where N is number of particles.
        Each row should hold [x,xp,y,yp,phi,E]
        Units m,rad, MeV
        import numpy

        self._data = numpy.append(self._data, array, 0)
        self.Np += len(array)

    def combine_dst(self, other):
        Appends the particles from another dst object to this one

        if abs(self.mass - other.mass) > 1e-5:
Yngve Levinsen's avatar
Yngve Levinsen committed
            raise ValueError("Adding two distributions with differing mass: {} and {}".format(self.mass, other.mass))
        if abs(self.freq - other.freq) > 1e-5:
Yngve Levinsen's avatar
Yngve Levinsen committed
            raise ValueError("You are trying to add two distributions with differing freq: {} and {}".format(self.freq, other.freq))

        self.append_many(other._data)
        self.Ib = (self.Ib * self.Np + other.Ib * other.Np) / (self.Np + other.Np)
        Removes all particles from the distribution, or the line specified by i
Yngve Levinsen's avatar
Yngve Levinsen committed
        if i is None:
            self._data = numpy.delete(self._data, numpy.s_[:], 0)
            self.Np = 0
            self._data = numpy.delete(self._data, i, 0)
            self.Np -= 1
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

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

Yngve Levinsen's avatar
Yngve Levinsen committed
        # shortnaming
Yngve Levinsen's avatar
Yngve Levinsen committed
        i8 = numpy.int8
Yngve Levinsen's avatar
Yngve Levinsen committed
        i16 = numpy.int16
        i32 = numpy.int32
        f64 = numpy.float64
Yngve Levinsen's avatar
Yngve Levinsen committed
        # dummy, Np, Ib, freq, dummy
Yngve Levinsen's avatar
Yngve Levinsen committed
        Header_type = numpy.dtype([("dummy12", i16), ("Np", i32), ("Ib", f64), ("freq", f64), ("dummy3", i8)])
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
        Table = numpy.fromfile(fin, dtype=numpy.float64, count=self.Np * 7 + 1)
        if len(Table) == self.Np * 7 + 1:
Yngve Levinsen's avatar
Yngve Levinsen committed
            self._data = Table[:-1].reshape(self.Np, 7)
        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:
        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):
Yngve Levinsen's avatar
Yngve Levinsen committed
        return self._columns[:] + self._indirect_columns[:]
Yngve Levinsen's avatar
Yngve Levinsen committed

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
        import numpy

Yngve Levinsen's avatar
Yngve Levinsen committed
        try:
Yngve Levinsen's avatar
Yngve Levinsen committed
            if key == "r":
                return numpy.sqrt(self["x"] ** 2 + self["y"] ** 2)
            elif key == "rp":
                return numpy.sqrt(self["xp"] ** 2 + self["yp"] ** 2)
            else:
                i = self._columns.index(key)
                return self._data[:, i]

        except ValueError:
            raise KeyError(f"Unknown key '{key}', available keys: {self.keys()}")
Yngve Levinsen's avatar
Yngve Levinsen committed

    def __setitem__(self, key, value):
        try:
            i = self._columns.index(key)
            self._data[:, i] = value
Yngve Levinsen's avatar
Yngve Levinsen committed
        except ValueError:
            raise KeyError(f"Unknown key '{key}', available keys: {self.keys()}")
    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)
Yngve Levinsen's avatar
Yngve Levinsen committed

        from struct import pack
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:
            data = numpy.append(data, numpy.zeros((len(data), 1)), 1)
        elif not toutatis and data.shape[1] == 7:
            data = data[:, :-1]
Yngve Levinsen's avatar
Yngve Levinsen committed
        # convert x,y from m to cm:
        data[:, 0] *= 1e2
        data[:, 2] *= 1e2
Yngve Levinsen's avatar
Yngve Levinsen committed

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

        fout.write(pack("{}d".format(len(data)), *data))
Yngve Levinsen's avatar
Yngve Levinsen committed

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

Yngve Levinsen's avatar
Yngve Levinsen committed
    def subplot(self, index, x, y=None, nb=100, mask=None, xlim=None, ylim=None):
        Create a subplot histogram similar to TraceWin.

        Example::
            import numpy as np
            from ess import TraceWin
            from matplotlib import pyplot as plt
Loading
Loading full blame...