Uniquely Identifying Particles

In many cases, one can just identify particles by their position in the particle array, e.g. using sim.particles[5]. However, in cases where particles might get reordered in the particle array finding a particle might be difficult. This is why we added a hash attribute to particles.

In REBOUND particles might get rearranged when a tree code is used for the gravity or collision routine, when particles merge, when a particle leave the simulation box, or when you manually remove or add particles. For these cases, it is useful to keep track of which particle is which.

In this example, we show the basic usage of the hash attribute. We start by creating a simulation with 3 particles:


In [1]:
import rebound
sim = rebound.Simulation()
sim.add(m=1.)
sim.add(a=0.32)
sim.add(a=1.)
sim.add(a=2.)

We can set a hash directly:


In [2]:
sim.particles[0].hash = 42

We can also refer to a particle using a custom string as follows:


In [3]:
sim.particles[1].hash = "mercury"
sim.particles[2].hash = "earth"

REBOUND uses a hash function to convert "earth" to an effectively random integer, and we store that identifier in the particle's hash field. We can now access the particle with:


In [4]:
print(sim.get_particle_by_hash("earth"))


<rebound.Particle object, m=0.0 x=1.0 y=0.0 z=0.0 vx=0.0 vy=1.0 vz=0.0>

Of course, we can still access the particle in the standard way:


In [5]:
print(sim.particles[2])


<rebound.Particle object, m=0.0 x=1.0 y=0.0 z=0.0 vx=0.0 vy=1.0 vz=0.0>

We can remove the mercury particle with


In [6]:
sim.remove(hash="mercury")

If we try to access the earth particle in the same way as above, we get a different result because the particle moved from index 2 to index 1:


In [7]:
print(sim.get_particle_by_hash("earth"))
print(sim.particles[2])


<rebound.Particle object, m=0.0 x=1.0 y=0.0 z=0.0 vx=0.0 vy=1.0 vz=0.0>
<rebound.Particle object, m=0.0 x=2.0 y=0.0 z=0.0 vx=0.0 vy=0.7071067811865476 vz=0.0>

For convenience you can also add the hash when you add the particle to the simulation:


In [8]:
sim.add(a=1000., hash="Planet 9")
print(sim.get_particle_by_hash("Planet 9").a)


999.9999999999998

In [9]:
sim.add(a=2000., hash=3)
print(sim.get_particle_by_hash(3).a)


2000.0

If you need to assign many hashes and don't want to assign them individually, you can also let the simulation assign them unique hashes:


In [10]:
for i in range(3,13):
    sim.add(a=i)
    sim.particles[-1].hash = sim.generate_unique_hash()

If we print all the particles' hashes, ones that were not assigned one are 0, ones assigned strings will have random integers, and ones assigned by the simulation will be consecutive (plus a random offset):


In [11]:
for p in sim.particles:
    print(p.hash)


42
1424801690
0
545758163
3
10926
10927
10928
10929
10930
10931
10932
10933
10934
10935

We can also access particles through their hash directly:


In [12]:
print(sim.get_particle_by_hash(1424801690))


<rebound.Particle object, m=0.0 x=1.0 y=0.0 z=0.0 vx=0.0 vy=1.0 vz=0.0>

Only particles that have been assigned a non-zero hash can be accessed with sim.get_particle_by_hash. If you assign hashes manually and two particles share the same hash, sim.get_particle_by_hash will return the first hit in the particles array.


In [ ]: