简体   繁体   中英

Particle-particle collision in box with periodic boundaries

The Task

For a class in molecular dynamics, I have to simulate 100 particles in a box with periodic boundaries. I have to take particle-particle collisions into account, since the walls are 'transparent' those interactions can be happen across the boundaries. Since the simulation should cover 50000 steps, and I'm expecting more and more additional tasks in the future, I want my code as efficient as possible (I have to use python, despite the long run time).

The Setting

The system consists of

  • 100 Particles
  • Box with x = 10, y = 5
  • Mass = 2
  • Radius = 0.2
  • Velocity |v| = 0.5 per step
  • Simulation of 50000 steps

What I've done so fare

I have found this example for particles in a box with particle-particle collision. Since the author used a efficient implementation, I took his approach. My relevant code parts are (in strong resemblance to the linked site):

class particlesInPeriodicBox:
    # define the particle properties
    def __init__(self,
                 initialState = [[0,0,0,0]], # state with form [x, y, vx, vy] for each particle
                 boundaries = [0, 10, 0, 5], # box boundaries with form [xmin, xmax, ymin, ymax] in nm
                 radius = 0.2, # particle radius in nm
                 mass = 2): # mass in g/mol. Here a parameter instead of a global variable
        self.initialState = np.asarray(initialState, dtype=float)
        self.state = self.initialState.copy()
        self.radius = radius
        self.time = 0 # keep count of time, if time, i want to implement a 'clock'
        self.mass = mass # mass
        self.boundaries = boundaries
    def collision(self):
        """
        now, one has to check for collisions. I do this by distance check and will solve this problems below.
        To minimize the simulation time I then will only consider the particles that colided.
        """
        dist = squareform(pdist(self.state[:, :2])) # direct distance

        colPart1, colPart2 = np.where(dist < 2 * self.radius) # define collision partners 1 and 2 as those where the distance between the centeres are smaller than two times the radius

        # resolve self-self collissions
        unique = (colPart1 < colPart2)
        colPart1 = colPart1[unique]
        colPart2 = colPart2[unique]

        """
        The following loop resolves the collisions. I zip the lists of collisionpartners to one aray,
        where one entry contains both colisionpartners.
        """
        for cp1, cp2 in zip(colPart1, colPart2): # cp1/cp2 are the two particles colliding in one collision.
            # masses could be different in future...
            m1 = self.mass[cp1]
            m2 = self.mass[cp2]

            # take the position (x,y) tuples for the two particles
            r1 = self.state[cp1, :2]
            r2 = self.state[cp2, :2]

            # same with velocities
            v1 = self.state[cp1, 2:]
            v2 = self.state[cp2, 2:]

            # get relative parameters
            r = r1-r2
            v = r2-r1

            # center of mass velocity:
            vcm = (m1 * v1 + m2 * v2) / (m1 + m2)

            """
            This is the part with the elastic collision
            """
            dotrr = np.dot(r, r) # the dot product of the relative position with itself
            dotvr = np.dot(v, r) # the dot product of the relative velocity with the relative position 
            v = 2 * r * dotvr / dotrr - v # new relative velocity

            """
            In this center of mass frame, the velocities 'reflect' on the center of mass in oposite directions
            """
            self.state[cp1, 2:] = vcm + v * m2/(m1 + m2) # new velocity of particle 1 still considering possible different masses
            self.state[cp2, 2:] = vcm - v * m1/(m1 + m2) # new velocity of particle 2

As I understand it, this technique of handling the operations to the whole arrays is more efficient than manually looping through it every time. Moving the particles 'trough' the wall is easy, I just subtract or add the dimension of the box, respectively. But:

The Problem

For now the algorithm only sees collision inside the box, but not across the boundaries. I thought about this problem a while now, and come up with the following Ideas:

  • I could make a total of 9 copies of this system in a 3x3 grid, and only considering the middle one, can so look into the neighboring cells for the nearest neighbor search. BUT i can't think of a effective way to implement this despite the fact, that this approach seams to be the standard way
  • Every other idea has some hand waving use of modulo, and im almost sure, that this is not the way to go.

If I had to boil it down, I guess my key questions are:

How do I take periodic boundaries into account when calculating

  • the distance between particles?
  • the actual particle-particle collision (elastic) and resulting directions?

For the first problem it might be possible to use techniques like in Calculation of Contact/Coordination number with Periodic Boundary Conditions , but Im not sure if that is the most efficient way.

Thank you!

Modulus is likely as quick an operation as you're going to get. In any self-respecting run-time system, this will attach directly to the on-chip floating-divide operations, which may well be faster than a tedious set of "if-subtract" pairs.

I think your 9-cell solution is overkill. Use 4 cells in a 2x2 matrix and check two regions: the original cell, and the same dimensions centered on the "four corners" point (middle of the 2x2). For any pair of points, the proper distance is the lesser of these two. Note that this method also gives you a frame in which you can easily calculate the momentum changes.

A third possible approach is to double the dimensions (ala the 2x2 above), but give each particle four sets of coordinates, one in each box. Alter your algorithms to consider all four when computing distance. If you have good vectorization packages and parallelism, this might be the preferred solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM