from itertools import count
import numpy as np


class Particle(object):
    """Object containing all the properties for a single particle"""

    _ids = count(0)

    def __init__(self, main_data=None, x=np.zeros(2)):
        self.id = next(self._ids)
        self.main_data = main_data
        self.x = np.array(x)
        self.v = np.zeros(2)
        self.a = np.zeros(2)
        self.D = 0
        self.rho = main_data.rho0
        self.P = 0
        self.m = main_data.dx ** 2 * main_data.rho0  # initial mass depends on the initial particle spacing
        self.boundary = False  # Particle by default is not on the boundary
        # For predictor corrector
        self.prev_x = np.array(x)
        self.prev_v = np.zeros(2)
        self.prev_rho = main_data.rho0

    def calc_index(self):
        """Calculates the 2D integer index for the particle's location in the search grid"""
        # Calculates the bucket coordinates
        self.list_num = np.array((self.x - self.main_data.min_x) /
                                 (2.0 * self.main_data.h), int)

    def B(self):
        return (self.main_data.rho0 * self.main_data.c0 ** 2) / self.main_data.gamma

    def update_P(self):
        """
        Equation of state
        System is assumed slightly compressible
        """
        rho0 = self.main_data.rho0
        gamma = self.main_data.gamma
        self.P = self.B() * ((self.rho / rho0)**gamma - 1)

    def set_main_data(self, main_data):
        self.main_data = main_data

    def set_x(self, x):
        self.x = x
        self.calc_index()

    def set_v(self, v):
        self.v = v

    def set_a(self, a):
        self.a = a

    def set_D(self, D):
        self.D = D

    def set_rho(self, rho):
        self.rho = rho
        self.update_P()

    def m(self, m):
        self.m = m

    def list_attributes(self):
        x_s = "position: " + str(self.x) + ", "
        v_s = "velocity: " + str(self.v) + ", "
        a_s = "acceleration: " + str(self.a) + ", "
        D_s = "derivative of density: " + str(self.D) + ", "
        rho_s = "density: " + str(self.rho) + ", "
        m_s = "mass: " + str(self.m) + ", "
        P_s = "pressure: " + str(self.P) + ", "
        boundary_s = "is boundary: " + str(self.boundary)
        return [x_s + v_s + a_s + D_s + rho_s + m_s + P_s + boundary_s]

[((8, 11, 8, 19), 'itertools.count', 'count', ({(8, 17, 8, 18): '0'}, {}), '(0)', False, 'from itertools import count\n'), ((10, 41, 10, 52), 'numpy.zeros', 'np.zeros', ({(10, 50, 10, 51): '(2)'}, {}), '(2)', True, 'import numpy as np\n'), ((13, 17, 13, 28), 'numpy.array', 'np.array', ({(13, 26, 13, 27): 'x'}, {}), '(x)', True, 'import numpy as np\n'), ((14, 17, 14, 28), 'numpy.zeros', 'np.zeros', ({(14, 26, 14, 27): '2'}, {}), '(2)', True, 'import numpy as np\n'), ((15, 17, 15, 28), 'numpy.zeros', 'np.zeros', ({(15, 26, 15, 27): '2'}, {}), '(2)', True, 'import numpy as np\n'), ((22, 22, 22, 33), 'numpy.array', 'np.array', ({(22, 31, 22, 32): 'x'}, {}), '(x)', True, 'import numpy as np\n'), ((23, 22, 23, 33), 'numpy.zeros', 'np.zeros', ({(23, 31, 23, 32): '2'}, {}), '(2)', True, 'import numpy as np\n'), ((29, 24, 30, 63), 'numpy.array', 'np.array', ({(29, 33, 30, 57): '(self.x - self.main_data.min_x) / (2.0 * self.main_data.h)', (30, 59, 30, 62): 'int'}, {}), '((self.x - self.main_data.min_x) / (2.0 * self.main_data.h), int)', True, 'import numpy as np\n')]