Esempio n. 1
0
class BulkInfo(object):
    '''The bulk information like:
       ed(x), ed(y), ed(eta), T(x), T(y), T(eta)
       vx, vy, veta, ecc_x, ecc_p'''
    def __init__(self, cfg, ctx, queue, eos_table, compile_options):
        self.cfg = cfg
        self.ctx = ctx
        self.queue = queue
        self.eos_table = eos_table
        self.compile_options = list(compile_options)

        NX, NY, NZ = cfg.NX, cfg.NY, cfg.NZ
        self.h_ev = np.zeros((NX * NY * NZ, 4), cfg.real)
        self.h_pi = np.zeros(10 * NX * NY * NZ, self.cfg.real)

        # one dimensional
        self.ex, self.ey, self.ez = [], [], []
        self.vx, self.vy, self.vz = [], [], []

        # in transverse plane (z==0)
        self.exy, self.vx_xy, self.vy_xy, self.vz_xy = [], [], [], []

        self.pixx_xy, self.piyy_xy, self.pitx_xy = [], [], []

        # in reaction plane
        self.exz, self.vx_xz, self.vy_xz, self.vz_xz = [], [], [], []

        self.ecc2_vs_rapidity = []
        self.ecc1_vs_rapidity = []
        self.time = []
        self.edmax = []
        self.__loadAndBuildCLPrg()
        self.eos = Eos(cfg.eos_type)

        self.x = np.linspace(-floor(NX / 2) * cfg.DX,
                             floor(NX / 2) * cfg.DX,
                             NX,
                             endpoint=True)
        self.y = np.linspace(-floor(NY / 2) * cfg.DY,
                             floor(NY / 2) * cfg.DY,
                             NY,
                             endpoint=True)
        self.z = np.linspace(-floor(NZ / 2) * cfg.DZ,
                             floor(NZ / 2) * cfg.DZ,
                             NZ,
                             endpoint=True)

    def __loadAndBuildCLPrg(self):
        #load and build *.cl programs with compile self.compile_options
        edslice_src = '''#include"real_type.h"
            __kernel void get_ed(__global real4 * d_ev,
                                 __global real4 * d_ev_x0,
                                 __global real4 * d_ev_y0,
                                 __global real4 * d_ev_z0,
                                 __global real4 * d_ev_xy,
                                 __global real4 * d_ev_xz,
                                 __global real4 * d_ev_yz) {
                int gid = get_global_id(0);
                if ( gid < NX ) {
                    int j = NY/2; 
                    int k = NZ/2;
                    d_ev_x0[gid] = d_ev[gid*NY*NZ + j*NZ + k];

                    int i = gid;
                    for ( j = 0; j< NY; j ++ ) {
                        d_ev_xy[i*NY+j] = d_ev[i*NY*NZ + j*NZ + k];
                    }

                    j = NY/2;
                    for ( k = 0; k < NZ; k ++ ) {
                        d_ev_xz[i*NZ+k] = d_ev[i*NY*NZ + j*NZ + k];
                    }
                }

                if ( gid < NY ) {
                    int i = NX/2; 
                    int k = NZ/2;
                    d_ev_y0[gid] = d_ev[i*NY*NZ + gid*NZ + k];
                    int j = gid;
                    for ( k = 0; k < NZ; k ++ ) {
                        d_ev_yz[j*NZ+k] = d_ev[i*NY*NZ + j*NZ + k];
                    }
                }

                if ( gid < NZ ) {
                    int i = NX/2; 
                    int j = NY/2;
                    d_ev_z0[gid] = d_ev[i*NY*NZ + j*NZ + gid];
                }
            }

            __kernel void get_pimn(__global real * d_pi,
                                 __global real * d_pixx_xy,
                                 __global real * d_piyy_xy,
                                 __global real * d_pitx_xy)
            {
                int gid_x = get_global_id(0);
                int gid_y = get_global_id(1);

                int oid = gid_x*NY*(NZ/2) + gid_y*(NZ/2) + NZ/2;

                int nid = gid_x*NY + gid_y;

                d_pixx_xy[nid] = d_pi[10*oid + 4];
                d_piyy_xy[nid] = d_pi[10*oid + 7];
                d_pitx_xy[nid] = d_pi[10*oid + 1];
            }
            '''
        self.kernel_edslice = cl.Program(
            self.ctx,
            edslice_src).build(options=' '.join(self.compile_options))

    def get(self, tau, d_ev1, edmax, d_pi=None):
        self.time.append(tau)
        self.edmax.append(edmax)
        mf = cl.mem_flags
        NX, NY, NZ = self.cfg.NX, self.cfg.NY, self.cfg.NZ

        self.ecc_vs_rapidity(d_ev1)

        h_ev1d = np.zeros((2000, 4), self.cfg.real)
        h_evxy = np.zeros((NX * NY, 4), self.cfg.real)
        h_evxz = np.zeros((NX * NZ, 4), self.cfg.real)
        h_evyz = np.zeros((NY * NZ, 4), self.cfg.real)

        d_evx0 = cl.Buffer(self.ctx, mf.READ_WRITE, size=h_ev1d.nbytes)
        d_evy0 = cl.Buffer(self.ctx, mf.READ_WRITE, size=h_ev1d.nbytes)
        d_evz0 = cl.Buffer(self.ctx, mf.READ_WRITE, size=h_ev1d.nbytes)

        d_evxy = cl.Buffer(self.ctx, mf.READ_WRITE, size=h_evxy.nbytes)
        d_evxz = cl.Buffer(self.ctx, mf.READ_WRITE, size=h_evxz.nbytes)
        d_evyz = cl.Buffer(self.ctx, mf.READ_WRITE, size=h_evyz.nbytes)

        self.kernel_edslice.get_ed(self.queue, (2000, ), None, d_ev1, d_evx0,
                                   d_evy0, d_evz0, d_evxy, d_evxz,
                                   d_evyz).wait()

        h_evx0 = np.zeros((NX, 4), self.cfg.real)
        h_evy0 = np.zeros((NY, 4), self.cfg.real)
        h_evz0 = np.zeros((NZ, 4), self.cfg.real)
        cl.enqueue_copy(self.queue, h_evx0, d_evx0).wait()
        cl.enqueue_copy(self.queue, h_evy0, d_evy0).wait()
        cl.enqueue_copy(self.queue, h_evz0, d_evz0).wait()

        self.ex.append(h_evx0[:, 0])
        self.ey.append(h_evy0[:, 0])
        self.ez.append(h_evz0[:, 0])

        self.vx.append(h_evx0[:, 1])
        self.vy.append(h_evy0[:, 2])
        self.vz.append(h_evz0[:, 3])

        cl.enqueue_copy(self.queue, h_evxy, d_evxy).wait()
        cl.enqueue_copy(self.queue, h_evxz, d_evxz).wait()
        cl.enqueue_copy(self.queue, h_evyz, d_evyz).wait()

        self.exy.append(h_evxy[:, 0].reshape(NX, NY))
        self.vx_xy.append(h_evxy[:, 1].reshape(NX, NY))
        self.vy_xy.append(h_evxy[:, 2].reshape(NX, NY))

        self.exz.append(h_evxz[:, 0].reshape(NX, NZ))
        self.vx_xz.append(h_evxz[:, 1].reshape(NX, NZ))
        self.vy_xz.append(h_evxz[:, 2].reshape(NX, NZ))
        self.vz_xz.append(h_evxz[:, 3].reshape(NX, NZ))

        #logging.debug('d_pi is not None: %s'%(d_pi is not None))
        if d_pi is not None:
            h_pixx = np.zeros(NX * NY, self.cfg.real)
            h_piyy = np.zeros(NX * NY, self.cfg.real)
            h_pitx = np.zeros(NX * NY, self.cfg.real)
            d_pixx = cl.Buffer(self.ctx, mf.READ_WRITE, size=h_pixx.nbytes)
            d_piyy = cl.Buffer(self.ctx, mf.READ_WRITE, size=h_pixx.nbytes)
            d_pitx = cl.Buffer(self.ctx, mf.READ_WRITE, size=h_pixx.nbytes)
            self.kernel_edslice.get_pimn(self.queue, (NX, NY), None, d_pi,
                                         d_pixx, d_piyy, d_pitx).wait()

            cl.enqueue_copy(self.queue, h_pixx, d_pixx).wait()
            self.pixx_xy.append(h_pixx.reshape(NX, NY))

            cl.enqueue_copy(self.queue, h_piyy, d_piyy).wait()
            self.piyy_xy.append(h_piyy.reshape(NX, NY))

            cl.enqueue_copy(self.queue, h_pitx, d_pitx).wait()
            self.pitx_xy.append(h_pitx.reshape(NX, NY))

    def eccp(self, ed, vx, vy, vz=0.0, pixx=None, piyy=None, pitx=None):
        ''' eccx = <y*y-x*x>/<y*y+x*x> where <> are averaged 
            eccp = <Txx-Tyy>/<Txx+Tyy> '''
        ed[ed < 1.0E-10] = 1.0E-10
        pre = self.eos.f_P(ed)

        vr2 = vx * vx + vy * vy + vz * vz
        vr2[vr2 > 1.0] = 0.999999

        u0 = 1.0 / np.sqrt(1.0 - vr2)
        Tyy = (ed + pre) * u0 * u0 * vy * vy + pre
        Txx = (ed + pre) * u0 * u0 * vx * vx + pre
        T0x = (ed + pre) * u0 * u0 * vx

        v2 = 0.0

        if pixx is not None:
            pi_sum = (pixx + piyy).sum()
            pi_dif = (pixx - piyy).sum()
            v2 = ((Txx - Tyy).sum() + pi_dif) / ((Txx + Tyy).sum() + pi_sum)
        else:
            v2 = (Txx - Tyy).sum() / (Txx + Tyy).sum()

        v1 = T0x.sum() / (Txx + Tyy).sum()
        return v1, v2

    def mean_vr(self, ed, vx, vy, vz=0.0):
        ''' <vr> = <gamma * ed * sqrt(vx*vx + vy*vy)>/<gamma*ed>
        where <> are averaged over whole transverse plane'''
        ed[ed < 1.0E-10] = 1.0E-10
        vr2 = vx * vx + vy * vy + vz * vz
        vr2[vr2 > 1.0] = 0.999999
        u0 = 1.0 / np.sqrt(1.0 - vr2)
        vr = (u0 * ed * np.sqrt(vx * vx + vy * vy)).sum() / (u0 * ed).sum()
        return vr

    def total_entropy(self, tau, ed, vx, vy, vz=0.0):
        '''get the total entropy as a function of time'''
        ed[ed < 1.0E-10] = 1.0E-10
        vr2 = vx * vx + vy * vy + vz * vz
        vr2[vr2 > 1.0] = 0.999999
        u0 = 1.0 / np.sqrt(1.0 - vr2)
        return (u0 * self.eos.f_S(ed)).sum() * tau * self.cfg.DX * self.cfg.DY

    def ecc_vs_rapidity(self, d_ev):
        NX, NY, NZ = self.cfg.NX, self.cfg.NY, self.cfg.NZ
        cl.enqueue_copy(self.queue, self.h_ev, d_ev).wait()
        bulk = self.h_ev.reshape(NX, NY, NZ, 4)
        ecc1 = np.empty(NZ)
        ecc2 = np.empty(NZ)
        for k in range(NZ):
            ed = bulk[:, :, k, 0]
            vx = bulk[:, :, k, 1]
            vy = bulk[:, :, k, 2]
            vz = bulk[:, :, k, 3]
            ecc1[k], ecc2[k] = self.eccp(ed, vx, vy, vz)
        self.ecc1_vs_rapidity.append(ecc1)
        self.ecc2_vs_rapidity.append(ecc2)

    def save(self, viscous_on=False):
        # use absolute path incase call bulkinfo.save() from other directory
        path_out = os.path.abspath(self.cfg.fPathOut)

        np.savetxt(path_out + '/ex.dat', np.array(self.ex).T)
        np.savetxt(path_out + '/ey.dat', np.array(self.ey).T)
        np.savetxt(path_out + '/ez.dat', np.array(self.ez).T)

        np.savetxt(path_out + '/Tx.dat', self.eos.f_T(self.ex).T)
        np.savetxt(path_out + '/Ty.dat', self.eos.f_T(self.ey).T)
        np.savetxt(path_out + '/Tz.dat', self.eos.f_T(self.ez).T)

        np.savetxt(path_out + '/vx.dat', np.array(self.vx).T)
        np.savetxt(path_out + '/vy.dat', np.array(self.vy).T)
        np.savetxt(path_out + '/vz.dat', np.array(self.vz).T)

        if len(self.ecc2_vs_rapidity) != 0:
            np.savetxt(path_out + '/ecc2.dat',
                       np.array(self.ecc2_vs_rapidity).T)
            np.savetxt(path_out + '/ecc1.dat',
                       np.array(self.ecc1_vs_rapidity).T)

        entropy = []
        vr = []
        ecc2 = []
        ecc1 = []
        ecc2_visc = []
        for idx, exy in enumerate(self.exy):
            vx = self.vx_xy[idx]
            vy = self.vy_xy[idx]
            np.savetxt(path_out + '/edxy%d.dat' % idx, exy)
            np.savetxt(path_out + '/Txy%d.dat' % idx, self.eos.f_T(exy))
            np.savetxt(path_out + '/vx_xy%d.dat' % idx, vx)
            np.savetxt(path_out + '/vy_xy%d.dat' % idx, vy)
            tmp0, tmp1 = self.eccp(exy, vx, vy)
            ecc1.append(tmp0)
            ecc2.append(tmp1)
            vr.append(self.mean_vr(exy, vx, vy))
            tau = self.time[idx]
            entropy.append(self.total_entropy(tau, exy, vx, vy))

            if viscous_on:
                pixx = self.pixx_xy[idx]
                piyy = self.piyy_xy[idx]
                pitx = self.pitx_xy[idx]
                ecc_visc1, ecc_visc2 = self.eccp(exy,
                                                 vx,
                                                 vy,
                                                 pixx=pixx,
                                                 piyy=piyy,
                                                 pitx=pitx)

                ecc2_visc.append(ecc_visc2)

        for idx, exz in enumerate(self.exz):
            np.savetxt(path_out + '/ed_xz%d.dat' % idx, exz)
            np.savetxt(path_out + '/vx_xz%d.dat' % idx, self.vx_xz[idx])
            np.savetxt(path_out + '/vy_xz%d.dat' % idx, self.vy_xz[idx])
            np.savetxt(path_out + '/vz_xz%d.dat' % idx, self.vz_xz[idx])
            np.savetxt(path_out + '/T_xz%d.dat' % idx, self.eos.f_T(exz))

        np.savetxt(path_out + '/eccp.dat',
                   np.array(list(zip(self.time, ecc2))),
                   header='tau  eccp')

        if viscous_on:
            np.savetxt(path_out + '/eccp_visc.dat',
                       np.array(list(zip(self.time, ecc2_visc))),
                       header='tau  eccp_visc')

        np.savetxt(path_out + '/Tmax.dat',
                   np.array(list(zip(self.time, self.eos.f_T(self.edmax)))),
                   header='tau, Tmax')

        np.savetxt(path_out + '/edmax.dat',
                   np.array(list(zip(self.time, self.edmax))),
                   header='tau, edmax')

        np.savetxt(path_out + '/vr.dat',
                   np.array(list(zip(self.time, vr))),
                   header='tau <vr>')

        np.savetxt(path_out + '/entropy.dat',
                   np.array(list(zip(self.time, entropy))),
                   header='tau  entropy')
Esempio n. 2
0
class BulkInfo(object):
    '''The bulk information like:
       ed(x), ed(y), ed(eta), T(x), T(y), T(eta)
       vx, vy, veta, ecc_x, ecc_p'''
    def __init__(self, cfg, ctx, queue, eos_table, compile_options):
        self.cfg = cfg
        self.ctx = ctx
        self.queue = queue
        self.eos_table = eos_table
        self.compile_options = list(compile_options)

        NX, NY, NZ = cfg.NX, cfg.NY, cfg.NZ

        if NX % 2 == 1:
            self.x = np.linspace(-floor(NX / 2) * cfg.DX,
                                 floor(NX / 2) * cfg.DX,
                                 NX,
                                 endpoint=True)
            self.y = np.linspace(-floor(NY / 2) * cfg.DY,
                                 floor(NY / 2) * cfg.DY,
                                 NY,
                                 endpoint=True)
            self.z = np.linspace(-floor(NZ / 2) * cfg.DZ,
                                 floor(NZ / 2) * cfg.DZ,
                                 NZ,
                                 endpoint=True)
            #including grid point 0
        elif NX % 2 == 0:
            self.x = np.linspace(-((NX - 1) / 2.0) * cfg.DX,
                                 ((NX - 1) / 2.0) * cfg.DX,
                                 NX,
                                 endpoint=True)
            self.y = np.linspace(-((NY - 1) / 2.0) * cfg.DY,
                                 ((NY - 1) / 2.0) * cfg.DY,
                                 NY,
                                 endpoint=True)
            self.z = np.linspace(-floor(NZ / 2) * cfg.DZ,
                                 floor(NZ / 2) * cfg.DZ,
                                 NZ,
                                 endpoint=True)
            #NOT including grid point 0  for trento2D
        self.h_ev = np.zeros((NX * NY * NZ, 4), cfg.real)

        self.a_ed = cl_array.empty(self.queue, NX * NY * NZ, cfg.real)
        self.a_entropy = cl_array.empty(self.queue, NX * NY * NZ, cfg.real)

        # the momentum eccentricity as a function of rapidity
        self.a_eccp1 = cl_array.empty(self.queue, NZ, cfg.real)
        self.a_eccp2 = cl_array.empty(self.queue, NZ, cfg.real)

        # store the data in hdf5 file
        #h5_path = os.path.join(cfg.fPathOut, 'bulkinfo.h5')
        #self.f_hdf5 = h5py.File(h5_path, 'w')

        self.eos = Eos(cfg.eos_type)

        self.__load_and_build_cl_prg()

        # time evolution for , edmax and ed, T at (x=0,y=0,etas=0)
        self.time = []
        self.edmax = []
        self.edcent = []
        self.Tcent = []

        # time evolution for total_entropy, eccp, eccx and <vr>
        self.energy = []
        self.entropy = []
        self.eccp_vs_tau = []
        self.eccx = []
        self.vr = []

        # time evolution for bulk3D
        self.Tau_tijk = []
        self.X_tijk = []
        self.Y_tijk = []
        self.Z_tijk = []
        self.ED_tijk = []
        self.Tp_tijk = []
        #       self.Frc_tijk = []
        self.Vx_tijk = []
        self.Vy_tijk = []
        self.Vz_tijk = []

        # time evolution for bulk2D
        self.Tau_2d = []
        self.X_2d = []
        self.Y_2d = []
        self.ED_2d = []
        self.Tp_2d = []
        self.Vx_2d = []
        self.Vy_2d = []
        self.Vz_2d = []
        self.Frc_2d = []

    def __load_and_build_cl_prg(self):
        with open(os.path.join(cwd, 'kernel', 'kernel_bulkinfo.cl')) as f:
            prg_src = f.read()
            self.kernel_bulk = cl.Program(
                self.ctx,
                prg_src).build(options=' '.join(self.compile_options))

    #@profile
    def get(self, tau, d_ev, edmax, d_pi=None):
        ''' store the bulkinfo to hdf5 file '''
        NX, NY, NZ = self.cfg.NX, self.cfg.NY, self.cfg.NZ
        self.time.append(tau)
        self.edmax.append(edmax)

        cl.enqueue_copy(self.queue, self.h_ev, d_ev).wait()
        bulk = self.h_ev.reshape(NX, NY, NZ, 4)

        # tau=0.6 changes to tau='0p6'
        time_stamp = ('%s' % tau).replace('.', 'p')

        i0, j0, k0 = NX // 2, NY // 2, NZ // 2

        exy = bulk[:, :, k0, 0]
        vx = bulk[:, :, k0, 1]
        vy = bulk[:, :, k0, 2]
        vz2d = bulk[:, :, k0, 3].flatten()
        exy2d = bulk[:, :, k0, 0].flatten()
        vx2d = bulk[:, :, k0, 1].flatten()
        vy2d = bulk[:, :, k0, 2].flatten()
        Tp2d = self.eos.f_T(exy2d)

        ed_ijk = bulk[:, :, :, 0].flatten()
        vx_ijk = bulk[:, :, :, 1].flatten()
        vy_ijk = bulk[:, :, :, 2].flatten()
        vz_ijk = bulk[:, :, :, 3].flatten()
        Tp_ijk = self.eos.f_T(ed_ijk)

        xline = self.x
        xline2d = np.repeat(xline, NY)
        self.X_2d.extend(xline2d)
        x_ijk = np.repeat(xline, NY * NZ)
        self.X_tijk.extend(x_ijk)

        yline = self.y
        y_ij = np.tile(yline, NX)
        yline2d = np.tile(yline, NX)
        self.Y_2d.extend(yline2d)
        y_ijk = np.repeat(y_ij, NZ)
        self.Y_tijk.extend(y_ijk)

        zline = self.z
        z_ijk = np.tile(zline, NX * NY)
        self.Z_tijk.extend(z_ijk)

        tau_ijk = np.repeat(tau, NX * NY * NZ)
        tau2d = np.repeat(tau, NX * NY)
        frac2d = np.repeat(0, NX * NY)

        self.Tau_tijk.extend(tau_ijk)
        self.ED_tijk.extend(ed_ijk)
        self.Tp_tijk.extend(Tp_ijk)
        self.Vx_tijk.extend(vx_ijk)
        self.Vy_tijk.extend(vy_ijk)
        self.Vz_tijk.extend(vz_ijk)

        self.Tau_2d.extend(tau2d)
        self.ED_2d.extend(exy2d)
        self.Tp_2d.extend(Tp2d)
        self.Vx_2d.extend(vx2d)
        self.Vy_2d.extend(vy2d)
        self.Vz_2d.extend(vz2d)
        self.Frc_2d.extend(frac2d)

        self.eccp_vs_tau.append(self.eccp(exy, vx, vy)[1])
        self.vr.append(self.mean_vr(exy, vx, vy))

        #self.get_total_energy_and_entropy_on_gpu(tau, d_ev)

        ed_cent = exy[i0, j0]

        self.edcent.append(ed_cent)
        self.Tcent.append(self.eos.f_T(ed_cent))

        #ecc1, ecc2 = self.ecc_vs_rapidity(bulk)
        #ecc1, ecc2 = self.ecc_vs_rapidity_on_gpu(tau, d_ev)
        #self.f_hdf5.create_dataset('bulk1d/eccp1_tau%s'%time_stamp, data = ecc1)
        #self.f_hdf5.create_dataset('bulk1d/eccp2_tau%s'%time_stamp, data = ecc2)

        ## ed_x(y=0, z=0), ed_y(x=0, z=0), ed_z(x=0, y=0)
        #self.f_hdf5.create_dataset('bulk1d/ex_tau%s'%time_stamp, data = bulk[:, j0, k0, 0])
        #self.f_hdf5.create_dataset('bulk1d/ey_tau%s'%time_stamp, data = bulk[i0, :, k0, 0])
        #self.f_hdf5.create_dataset('bulk1d/ez_tau%s'%time_stamp, data = bulk[i0, j0, :, 0])

        ## vx_x(y=0, z=0), vy_y(x=0, z=0), vz_z(x=0, y=0)
        #self.f_hdf5.create_dataset('bulk1d/vx_tau%s'%time_stamp, data = bulk[:, j0, k0, 1])
        #self.f_hdf5.create_dataset('bulk1d/vy_tau%s'%time_stamp, data = bulk[i0, :, k0, 2])
        #self.f_hdf5.create_dataset('bulk1d/vz_tau%s'%time_stamp, data = bulk[i0, j0, :, 3])

        ## ed_xy(z=0), ed_xz(y=0), ed_yz(x=0)
        #self.f_hdf5.create_dataset('bulk2d/exy_tau%s'%time_stamp, data = bulk[:, :, k0, 0])
        #self.f_hdf5.create_dataset('bulk2d/exz_tau%s'%time_stamp, data = bulk[:, j0, :, 0])
        #self.f_hdf5.create_dataset('bulk2d/eyz_tau%s'%time_stamp, data = bulk[i0, :, :, 0])

        ## vx_xy(z=0), vx_xz(y=0), vx_yz(x=0)
        #self.f_hdf5.create_dataset('bulk2d/vx_xy_tau%s'%time_stamp, data = bulk[:, :, k0, 1])
        #self.f_hdf5.create_dataset('bulk2d/vx_xz_tau%s'%time_stamp, data = bulk[:, j0, :, 1])
        ##self.f_hdf5.create_dataset('bulk2d/vx_yz_tau%s'%time_stamp, data = bulk[i0, :, :, 1])

        ## vy_xy(z=0), vy_xz(y=0), vy_yz(x=0)
        #self.f_hdf5.create_dataset('bulk2d/vy_xy_tau%s'%time_stamp, data = bulk[:, :, k0, 2])
        ##self.f_hdf5.create_dataset('bulk2d/vy_xz_tau%s'%time_stamp, data = bulk[:, j0, :, 2])
        #self.f_hdf5.create_dataset('bulk2d/vy_yz_tau%s'%time_stamp, data = bulk[i0, :, :, 2])

        ## vz_xy(z=0), vz_xz(y=0), vz_yz(x=0)
        #self.f_hdf5.create_dataset('bulk2d/vz_xy_tau%s'%time_stamp, data = bulk[:, :, k0, 3])
        #self.f_hdf5.create_dataset('bulk2d/vz_xz_tau%s'%time_stamp, data = bulk[:, j0, :, 3])
        ##self.f_hdf5.create_dataset('bulk2d/vz_yz_tau%s'%time_stamp, data = bulk[i0, :, :, 3])

    def eccp(self, ed, vx, vy, vz=0.0):
        ''' eccx = <y*y-x*x>/<y*y+x*x> where <> are averaged 
            eccp = <Txx-Tyy>/<Txx+Tyy> '''
        ed[ed < 1.0E-10] = 1.0E-10
        pre = self.eos.f_P(ed)

        vr2 = vx * vx + vy * vy + vz * vz
        vr2[vr2 > 1.0] = 0.999999
        u0 = 1.0 / np.sqrt(1.0 - vr2)

        Tyy = (ed + pre) * u0 * u0 * vy * vy + pre
        Txx = (ed + pre) * u0 * u0 * vx * vx + pre
        T0x = (ed + pre) * u0 * u0 * vx
        v2 = (Txx - Tyy).sum() / (Txx + Tyy).sum()
        v1 = T0x.sum() / (Txx + Tyy).sum()
        return v1, v2

    def mean_vr(self, ed, vx, vy, vz=0.0):
        ''' <vr> = <gamma * ed * sqrt(vx*vx + vy*vy)>/<gamma*ed>
        where <> are averaged over whole transverse plane'''
        ed[ed < 1.0E-10] = 1.0E-10
        vr2 = vx * vx + vy * vy + vz * vz
        vr2[vr2 > 1.0] = 0.999999
        u0 = 1.0 / np.sqrt(1.0 - vr2)
        vr = (u0 * ed * np.sqrt(vx * vx + vy * vy)).sum() / (u0 * ed).sum()
        return vr

    def total_entropy(self, tau, ed, vx, vy, vz=0.0):
        '''get the total entropy (at mid rapidity ) as a function of time'''
        ed[ed < 1.0E-10] = 1.0E-10
        vr2 = vx * vx + vy * vy + vz * vz
        vr2[vr2 > 1.0] = 0.999999
        u0 = 1.0 / np.sqrt(1.0 - vr2)
        return (u0 * self.eos.f_S(ed)).sum() * tau * self.cfg.DX * self.cfg.DY

    def get_total_energy_and_entropy_on_gpu(self, tau, d_ev):
        NX, NY, NZ = self.cfg.NX, self.cfg.NY, self.cfg.NZ
        self.kernel_bulk.total_energy_and_entropy(self.queue, (NX, NY, NZ),
                                                  None, self.a_ed.data,
                                                  self.a_entropy.data, d_ev,
                                                  self.eos_table,
                                                  np.float32(tau)).wait()

        volum = tau * self.cfg.DX * self.cfg.DY * self.cfg.DZ

        e_total = cl_array.sum(self.a_ed).get() * volum
        s_total = cl_array.sum(self.a_entropy).get() * volum

        self.energy.append(e_total)
        self.entropy.append(s_total)

    def ecc_vs_rapidity(self, bulk):
        ''' bulk = self.h_ev.reshape(NX, NY, NZ, 4)'''
        NX, NY, NZ = self.cfg.NX, self.cfg.NY, self.cfg.NZ
        ecc1 = np.empty(NZ)
        ecc2 = np.empty(NZ)
        for k in range(NZ):
            ed = bulk[:, :, k, 0]
            vx = bulk[:, :, k, 1]
            vy = bulk[:, :, k, 2]
            vz = bulk[:, :, k, 3]
            ecc1[k], ecc2[k] = self.eccp(ed, vx, vy, vz)
        return ecc1, ecc2

    def ecc_vs_rapidity_on_gpu(self, tau, d_ev):
        NX, NY, NZ = self.cfg.NX, self.cfg.NY, self.cfg.NZ
        self.kernel_bulk.eccp_vs_rapidity(self.queue, (NZ * 256, ), (256, ),
                                          self.a_eccp1.data, self.a_eccp2.data,
                                          d_ev, self.eos_table,
                                          np.float32(tau)).wait()

        return self.a_eccp1.get(), self.a_eccp2.get()

    def save(self, viscous_on=False):
        # use absolute path incase call bulkinfo.save() from other directory
        path_out = os.path.abspath(self.cfg.fPathOut)

        np.savetxt(path_out + '/avg.dat',
                   np.array(
                       list(
                           zip(self.time, self.eccp_vs_tau, self.edcent,
                               self.entropy, self.energy, self.vr))),
                   header='tau, eccp, ed(0,0,0), stotal, Etotal, <vr>')

        #self.f_hdf5.create_dataset('coord/tau', data = self.time)
        #self.f_hdf5.create_dataset('coord/x', data = self.x)
        #self.f_hdf5.create_dataset('coord/y', data = self.y)
        #self.f_hdf5.create_dataset('coord/etas', data = self.z)

        #self.f_hdf5.create_dataset('avg/eccp', data = np.array(self.eccp_vs_tau))
        #self.f_hdf5.create_dataset('avg/edcent', data = np.array(self.edcent))
        #self.f_hdf5.create_dataset('avg/Tcent', data = self.eos.f_T(np.array(self.edcent)))
        #self.f_hdf5.create_dataset('avg/entropy', data = np.array(self.entropy))
        #self.f_hdf5.create_dataset('avg/energy', data = np.array(self.energy))
        #self.f_hdf5.create_dataset('avg/vr', data = np.array(self.vr))

        #self.f_hdf5.close()

        #np.savetxt(path_out + '/bulk3D.dat', \
        #np.array(zip(self.Tau_tijk, self.X_tijk, self.Y_tijk, self.Z_tijk, \
        #self.ED_tijk, self.Tp_tijk, self.Vx_tijk, self.Vy_tijk, self.Vz_tijk)), \
        #fmt='%.2f %.2f %.2f %.2f %.8e %.8e %.8e %.8e %.8e',header = 'tau x y z Ed T vx vy veta')

        np.savetxt(path_out + '/bulk2D.dat', \
        np.array(zip(self.Tau_2d, self.X_2d, self.Y_2d, \
        self.ED_2d, self.Tp_2d, self.Vx_2d, self.Vy_2d, self.Vz_2d , self.Frc_2d)), \
        fmt='%.2f %.2f %.2f %.8e %.8e %.8e %.8e %.8e %.1f',header = 'tau x y Ed T vx vy veta frc')