Source code for pNeuma_simulator.gang.particle

from matplotlib.patches import Ellipse
from numpy import array, atan2, cos, degrees, sin

from pNeuma_simulator import params


[docs] class Particle: """A class representing a two-dimensional particle. This class models a particle with position, velocity, and other attributes relevant to its motion and interactions. Attributes: ID (int): The unique identifier of the particle. mode (str): The mode of the particle, e.g., "Car" or "Moto". a_des (float): The desired acceleration. a0 (float): The initial acceleration. ttc (float): Time to collision. f_a (float): Distance to collision. image (object): The visual representation of the particle. leader (Particle): The leading particle. rad (float): The radius of the particle. gap (float): The gap between particles. tau (float): Adaptation time. lam (float): Lambda parameter. v0 (float): Initial velocity. d (float): Distance parameter. pos (numpy.ndarray): The position of the particle. vel (numpy.ndarray): The velocity of the particle. theta (float): The angle of the particle's velocity. interactions (list): List of interactions with other particles. """ def __init__(self, x, y, vx, vy, mode="Car", ID=None, styles=None): """Initialize the particle's position, velocity, mode and ID. Any key-value pairs passed in the styles dictionary will be passed as arguments to Matplotlib's Ellipse patch constructor. Args: x (float): The x-coordinate of the particle's position. y (float): The y-coordinate of the particle's position. vx (float): The x-component of the particle's velocity. vy (float): The y-component of the particle's velocity. mode (str, optional): The mode of the particle. Defaults to "Car". ID (int, optional): The unique identifier of the particle. Defaults to None. styles (dict, optional): A dictionary of styles for Matplotlib's Ellipse patch. Defaults to None. """ self.ID = ID self.mode = mode self.a_des = 0 self.a0 = 0 self.ttc = None self.f_a = None self.image = None self.leader = None self.rad = None self.gap = None self.tau = None self.lam = None self.v0 = None self.d = None self.pos = array((x, y)) self.vel = array((vx, vy)) self.theta = atan2(vy, vx) self.interactions = [] if self.mode == "Car": self.l = params.car_l # half length self.w = params.car_w # half width self.a = params.car_a # noise amplitude self.b = params.car_b # relaxation time else: self.l = params.moto_l # half length self.w = params.moto_w # half width self.a = params.moto_a # noise amplitude self.b = params.moto_b # relaxation time self.styles = styles if not self.styles: # Default ellipse styles self.styles = {"ec": "k", "fill": False} # For convenience, map the components of the particle's position and # velocity vector onto the attributes x, y, vx and vy. @property def x(self): return self.pos[0] @x.setter def x(self, value): self.pos[0] = value @property def y(self): return self.pos[1] @y.setter def y(self, value): self.pos[1] = value @property def vx(self): return self.vel[0] @vx.setter def vx(self, value): self.vel[0] = value self.theta = atan2(self.vy, value) @property def vy(self): return self.vel[1] @vy.setter def vy(self, value): self.vel[1] = value self.theta = atan2(value, self.vx)
[docs] def draw(self, ax): """Add this Particle's Ellipse patch to the Matplotlib Axes ax.""" ellipse = Ellipse(xy=self.pos, width=2 * self.l, height=2 * self.w, angle=degrees(self.theta), **self.styles) ax.add_patch(ellipse) return ellipse
[docs] def advance(self, dt, new_V, new_theta): """Advance the particle's position according to its velocity.""" self.vx = new_V * cos(new_theta) self.vy = new_V * sin(new_theta) # apply periodic boundary conditions self.pos = self.pos + self.vel * dt if self.pos[0] > params.L / 2: self.pos[0] -= params.L
[docs] def encode(self): my_dict = self.__dict__ my_dict.pop("image", None) my_dict.pop("rad", None) my_dict.pop("l", None) my_dict.pop("w", None) my_dict.pop("a", None) my_dict.pop("b", None) my_dict.pop("styles", None) return my_dict
def __deepcopy__(self, memodict={}): # https://stackoverflow.com/questions/24756712 copy_object = Particle(self.x, self.y, self.vx, self.vy, self.mode, self.ID, self.styles) copy_object.interactions = self.interactions copy_object.leader = self.leader copy_object.a_des = self.a_des copy_object.ttc = self.ttc copy_object.f_a = self.f_a copy_object.gap = self.gap copy_object.tau = self.tau copy_object.lam = self.lam copy_object.v0 = self.v0 copy_object.a0 = self.a0 copy_object.d = self.d return copy_object def __getitem__(self, key): """Get the value of a specific attribute of the particle.""" return getattr(self, key)