https://programmingattack.com/articles/optimizing-the-article-life-from-a-thousand-to-a-milion-particles * Home * Projects * Articles * * Optimizing the Particle Life: From 400 to 4 million particles (Part 1) [1] Why Particle Life? For one of my programming classes this semester, my task was writing a program in Python. It was only an introductory course, so it didn't have to be anything fancy. Whenever I get assignments like this one, my choice is simple: I enjoy tinkering around with cellular automata and particle simulations. I have had an eye on Particle Life for quite a while now. The idea belongs to Jeffrey Ventrella, who called it "Clusters." As the name suggests, its simple rules result in the emergence of lifelike, cell-like structures interacting with one another. During my experiments, I was also amazed by the fact that applying the same rules on much larger scales gives us a resemblance to many different phenomena in nature, somewhat like electron clouds or cosmic structures. I, personally, found it mesmerizing, and I got completely absorbed by writing this program for the better part of a week, completely neglecting other things I needed to take care of. But what do I even mean by emergence in the paragraph above? Have you ever wondered how a flock of birds operates? How is it able to travel, forage, and respond to predators? An individual bird does not have a blueprint of the flock's final behavior and its part in it. Instead, a singular bird operates based on simple rules guiding its behavior. For example, in boids, an algorithm simulating the flocking behavior of birds, an individual agent's interaction must adhere to (a simplified) set of rules: 1. Stay separated to avoid crowding local flockmates. 2. Align with the average direction of your local flockmates. 3. Navigate towards the average position of your local flockmates to retain cohesion. The complexity of the flock emerges from every agent in the system following these rules. Flock has distinct properties that arose from the behavior of its components, but there's no way for us to deduce these properties from the rules we applied to individual agents. This is why we can call a flock a complex system. Human societies, the universe, climate, cities--all these are examples of complex systems. And the simulation we'll write is an example of it as well. You'll see for yourself how the structures we'll see on the screen are described nowhere in the code but emerge as a result of uncomplicated rules generated for every particle randomly each time we start the program. There are multiple implementations of the algorithm available online. To contribute something new, I decided to focus on the optimization of the program. This is a deep-dive, several-piece series, but at the end, we'll render a million particles in real-time, which makes it completely worth the time spent on the project! The rules The first thing we need to specify is the number of classes of particles. We will denote these classes by their colors, and how particles interact with each other will depend on their respective colors. This force can be attractive or repulsive, depending on our color-attraction matrix. It doesn't have to be symmetric: red particles can be attracted to green particles, but green particles can be repulsed by red ones. To visualize this dependence, let's see an example matrix with two classes of particles and forces ranging from -1.0 to 1.0: Red Blue Red .86 -.15 Blue .33 .24 In this case, red particles are strongly attracted to one another. They're slightly repulsed by blue ones. Blue particles also attract each other, although in a weaker manner, and they're also attracted to red particles. This force works within a radius that we'll specify. But within a fraction of this radius, we have another force, the universal repulsive force. Otherwise, particles that are attracted to each other would end up collapsing into one. This is how we can visualize our force function, assuming the force value between two particles to be 1.0 and a repulsive radius of 1/4 of the max radius: [graph] Of course, these rules are not set in stone. In the following parts, you will see how slight changes in force function affect our system: [graph][graph][graph] So far, so good. You must admit that these rules are really beautifully simple. It's time to write a Python script to test if I can get it up and running. After some time, and some frustrating errors originating from Qt, my particles came to life. Below, you can find the whole script. I tried to add explicit comments to every line so that there aren't any confusing bits. A little note about system parameters: those are arbitrarily chosen values. You have to experiment for a bit to see what works and what doesn't. import numpy as np import colorsys as cs import random as rd import sys import math from PySide6.QtCore import * from PySide6.QtWidgets import * from PySide6.QtGui import * width = 800 height = 800 #function definitions def buildAttractionMatrix(m): return (m*2)-1 # Multiple random between [0.0,1.0] by 2 and substract one to get random between [-1.0,1.0] #With HSL, unlike RGB, to change color we have to update only one value [[H]SL -> Hue]. Hence, it will work perfectly #for generating predefined no of colors, sufficiently distinct from one another. Since our GUI library accepts only RGB colors, #we have to convert it RGB. def createColors(m): colors = list() for i in range(m): hueValue = (i *( 360/(m - 1))) #hsvtorgb() returns values between [0.0,1.0] hence i*255 color = tuple(round(i * 255) for i in cs.hsv_to_rgb(hueValue/100,1,1)) colors.append(QColor(color[0],color[1],color[2])) return colors def force(d, f): #d - ratio of particles distance and max distance , f - force according to attraction matrix repRadius = 0.25 #universal repulsive force that prevents our particles from collapsing into each other #25% is an arbitrary value I tested to behave the best - feel free to experiment, like with other system parameters. if (d