Datamodel

Introduction

The AMUSE datamodel is based on sets of particles.

Different astrophysical objects are all refered to as Particles in the AMUSE code. These objects can be:

  • Star
  • Black hole
  • Gas Particle
  • Dark Matter Particle

The astrophysical objects are all modelled using the Particle class . Objects of this class can have a varying set of attributes. These attributes can be defined by a script or a code.

Identity

All particles have a unique 64-bit key. This key is generator using a random number generator. The chances of duplicate keys using 64-bit integers are finite but very low.This chance of a duplicate key can be determined by a generalization of the birthday problem.

Duplicate keys::
>>> # given n random integers drawn from a discrete uniform distribution
>>> # with range [1,highest_integer], what is the probability
>>> # p(n;highest_integer) that at least two numbers are the same?
>>> import math
>>> number_of_bits = 64
>>> highest_integer = 2**number_of_bits
>>> number_of_particles = 1000000.0 # one million
>>> probability = 1.0 - math.exp( (-number_of_particles * (number_of_particles - 1.0))/ (2.0* highest_integer) )
>>> print probability
2.71050268896e-08
>>> # can also set the probablity and determine the set size
>>> probability = 0.00001 # 0.001 percent
>>> number_of_particles = math.sqrt(2 * highest_integer * math.log(1 / (1.0 - probability)))
>>> print number_of_particles
19207725.6894

If you use large sets or want to load a lot of simulations with different particles into a script the probablity of encountering a duplicate may be too high. An extension to more larger key sizes is planned but not yet implemented. You can check for duplicates in a set of particles by calling has_duplicates on a set.

Sets of particles

The AMUSE datamodel assumes all particles come in sets. The data of a particle is stored in the set.

This module provides access to all set handling in AMUSE. The actual implementation is in the base, storage and particle modules.

class amuse.datamodel.AbstractParticleSet(original=None)

Abstract superclass of all sets of particles. This class defines common code for all particle sets.

Particle sets define dynamic attributes. Attributes can be set and retrieved on the particles using common python syntax. These attributes can only have values with units.

>>> particles = Particles(2)
>>> particles.mass = [10.0, 20.0] | units.kg
>>> particles.mass
quantity<[10.0, 20.0] kg>
>>> particles.mass = 1.0 | units.kg
>>> particles.mass
quantity<[1.0, 1.0] kg>

Particle sets can be iterated over.

>>> particles = Particles(2)
>>> particles.mass = [10.0, 20.0] | units.kg
>>> for particle in particles:
...     print particle.mass
...
10.0 kg
20.0 kg

Particle sets can be indexed.

>>> particles = Particles(3)
>>> particles.x = [10.0, 20.0, 30.0] | units.m
>>> particles[1].x
quantity<20.0 m>

Particle sets can be sliced.

>>> particles = Particles(3)
>>> particles.x = [10.0, 20.0, 30.0] | units.m
>>> particles[1:].x
quantity<[20.0, 30.0] m>

Particle sets can be copied.

>>> particles = Particles(3)
>>> particles.x = [10.0, 20.0, 30.0] | units.m
>>> copy = particles.copy()
>>> particles.x = 2.0 | units.m
>>> particles.x
quantity<[2.0, 2.0, 2.0] m>
>>> copy.x
quantity<[10.0, 20.0, 30.0] m>

Particle sets can be added together. Attribute values are not stored by the resulting subset. The subset provides a view on two or more sets of particles. Changing attributes of the sum of sets will also change the attributes of each original set, contrary to copy().

>>> particles = Particles(4)
>>> particles1 = particles[:2]
>>> particles1.x = [1.0, 2.0] | units.m
>>> particles2 = particles[2:]
>>> particles2.x = [3.0, 4.0] | units.m
>>> new_set = particles1 + particles2
>>> print len(new_set)
4
>>> print new_set.x
[1.0, 2.0, 3.0, 4.0] m

Particle sets can be subtracted from each other. Like with addition, attribute values are not stored by the resulting subset.

>>> particles = Particles(4)
>>> particles.x = [1.0, 2.0, 3.0, 4.0] | units.m
>>> junk = particles[2:]
>>> new_set = particles - junk
>>> print len(new_set)
2
>>> print new_set.x
[1.0, 2.0] m
>>> print particles.x
[1.0, 2.0, 3.0, 4.0] m

Particle sets can have instance based or global vector attributes. A particle set stores a list of scalar values for each attribute. Some attributes are more naturally accessed as lists of vector values. Once defined, a particle set can convert the scalar values of 2 or more attributes into one vector attribute.

>>> from amuse.support.data import particle_attributes
>>> particles = Particles(2)
>>> particles.x = [1.0 , 2.0] | units.m
>>> particles.y = [3.0 , 4.0] | units.m
>>> particles.z = [5.0 , 6.0] | units.m
>>> particles.add_vector_attribute("p", ["x","y","z"])
>>> particles.p
quantity<[[ 1.  3.  5.], [ 2.  4.  6.]] m>
>>> particles.p[0]
quantity<[1.0, 3.0, 5.0] m>
>>> particles.position # "position" is a global vector attribute, coupled to x,y,z
quantity<[[ 1.  3.  5.], [ 2.  4.  6.]] m>
__add__(particles)

Returns a particle subset, composed of the given particle(s) and this particle set. Attribute values are not stored by the subset. The subset provides a view on two or more sets of particles.

Parameters:particles – (set of) particle(s) to be added to self.
>>> particles = Particles(4)
>>> particles1 = particles[:2]
>>> particles1.x = [1.0, 2.0] | units.m
>>> particles2 = particles[2:]
>>> particles2.x = [3.0, 4.0] | units.m
>>> new_set = particles1 + particles2
>>> new_set  
<amuse.datamodel.particles.ParticlesSubset object at 0x...>
>>> print len(new_set)
4
>>> print new_set.x
[1.0, 2.0, 3.0, 4.0] m
__sub__(particles)

Returns a subset of the set without the given particle(s) Attribute values are not stored by the subset. The subset provides a view on two or more sets of particles.

Parameters:particles – (set of) particle(s) to be subtracted from self.
>>> particles = Particles(4)
>>> particles.x = [1.0, 2.0, 3.0, 4.0] | units.m
>>> junk = particles[2:]
>>> new_set = particles - junk
>>> new_set  
<amuse.datamodel.particles.ParticlesSubset object at 0x...>
>>> print len(new_set)
2
>>> print new_set.x
[1.0, 2.0] m
>>> print particles.x
[1.0, 2.0, 3.0, 4.0] m
add_particle(particle)

Add one particle to the set.

Parameters:particle – particle to add
>>> particles = Particles()
>>> print len(particles)
0
>>> particle = Particle()
>>> particle.x = 1.0 | units.m
>>> particles.add_particle(particle)  
<amuse.datamodel.particles.Particle object at ...>
>>> print len(particles)
1
>>> print particles.x
[1.0] m
add_particles(particles)

Adds particles from the supplied set to this set. Attributes and values are copied over.

Note

For performance reasons the particles are not checked for duplicates. When the same particle is part of both sets errors may occur.

Parameters:particles – set of particles to copy values from
>>> particles1 = Particles(2)
>>> particles1.x = [1.0, 2.0] | units.m
>>> particles2 = Particles(2)
>>> particles2.x = [3.0, 4.0] | units.m
>>> particles1.add_particles(particles2)  
<amuse.datamodel.particles.ParticlesSubset object at 0x...>
>>> print len(particles1)
4
>>> print particles1.x
[1.0, 2.0, 3.0, 4.0] m
as_set()

Returns a subset view on this set. The subset will contain all particles of this set.

>>> particles = Particles(3)
>>> particles.x = [1.0, 2.0, 3.0] | units.m
>>> subset = particles.as_set()
>>> print subset.x
[1.0, 2.0, 3.0] m
>>> print particles.x
[1.0, 2.0, 3.0] m
copy_values_of_attribute_to(attribute_name, particles)

Copy values of one attribute from this set to the other set. Will only copy values for the particles in both sets. See also synchronize_to().

If you need to do this a lot, setup a dedicated channel.

>>> particles1 = Particles(2)
>>> particles1.x = [1.0, 2.0] | units.m
>>> particles2 = particles1.copy()
>>> print particles2.x
[1.0, 2.0] m
>>> p3 = particles1.add_particle(Particle())
>>> particles1.x = [3.0, 4.0, 5.0] | units.m
>>> particles1.copy_values_of_attribute_to("x", particles2)
>>> print particles2.x
[3.0, 4.0] m
difference(other)

Returns a new subset containing the difference between this set and the provided set.

>>> particles = Particles(3)
>>> particles.mass = [10.0, 20.0, 30.0] | units.kg
>>> particles.x = [1.0, 2.0, 3.0] | units.m
>>> subset = particles.select(lambda x : x > 15.0 | units.kg, ["mass"])
>>> less_than_15kg = particles.difference(subset)
>>> len(subset)
2
>>> len(less_than_15kg)
1
has_duplicates()

Returns True when a set contains a particle with the same key more than once. Particles with the same key are interpreted as the same particles.

>>> particles = Particles()
>>> p1 = particles.add_particle(Particle(1))
>>> p2 = particles.add_particle(Particle(2))
>>> particles.has_duplicates()
False
>>> p3 = particles.add_particle(Particle(1))
>>> particles.has_duplicates()
True
>>> p3 == p1
True
remove_particle(particle)

Removes a particle from this set.

Result is undefined if particle is not part of the set

Parameters:particle – particle to remove from this set
>>> particles1 = Particles(2)
>>> particles1.x = [1.0, 2.0] | units.m
>>> particles1.remove_particle(particles1[0])
>>> print len(particles1)
1
>>> print particles1.x
[2.0] m
remove_particles(particles)

Removes particles from the supplied set from this set.

Parameters:particles – set of particles to remove from this set
>>> particles1 = Particles(2)
>>> particles1.x = [1.0, 2.0] | units.m
>>> particles2 = Particles()
>>> particles2.add_particle(particles1[0]) 
<amuse.datamodel.particles.Particle object at ...>
>>> particles1.remove_particles(particles2)
>>> print len(particles1)
1
>>> print particles1.x
[2.0] m
reversed()

Returns a subset with the same particles, but with reversed sequenctial order (the first particle will become last)

>>> particles = Particles(3)
>>> particles.radius = [1.0, 2.0, 3.0] | units.m
>>> r = particles.reversed()
>>> print r.radius
[3.0, 2.0, 1.0] m
select(selection_function, attributes)

Returns a subset view on this set. The subset will contain all particles for which the selection function returned True. The selection function is called with scalar quantities defined by the attributes parameter

>>> particles = Particles(3)
>>> particles.mass = [10.0, 20.0, 30.0] | units.kg
>>> particles.x = [1.0, 2.0, 3.0] | units.m
>>> subset = particles.select(lambda x : x > 15.0 | units.kg, ["mass"])
>>> print subset.mass
[20.0, 30.0] kg
>>> print subset.x
[2.0, 3.0] m
select_array(selection_function, attributes=())

Returns a subset view on this set. The subset will contain all particles for which the selection function returned True. The selection function is called with a vector quantities containing all the values for the attributes parameter.

This function can be faster than the select function as it works on entire arrays. The selection_function is called once.

>>> particles = Particles(3)
>>> particles.mass = [10.0, 20.0, 30.0] | units.kg
>>> particles.x = [1.0, 2.0, 3.0] | units.m
>>> subset = particles.select_array(lambda x : x > 15.0 | units.kg, ["mass"])
>>> print subset.mass
[20.0, 30.0] kg
>>> print subset.x
[2.0, 3.0] m
>>> particles = Particles(1000)
>>> particles.x = units.m.new_quantity(numpy.arange(1,1000))
>>> subset = particles.select_array(lambda x : x > (500 | units.m), ("x",) )
>>> print len(subset)
499
sorted_by_attribute(attribute, kind='mergesort')

Returns a subset with the same particles, but sorted using the given attribute name

Argument :kind, the sort method for supported kinds see the numpy.sort documentation
>>> particles = Particles(3)
>>> particles.mass = [2.0, 3.0, 1.0] | units.kg
>>> particles.radius = [1.0, 2.0, 3.0] | units.m
>>> sorted = particles.sorted_by_attribute('mass')
>>> print sorted.mass
[1.0, 2.0, 3.0] kg
>>> print sorted.radius
[3.0, 1.0, 2.0] m
sorted_by_attributes(*attributes)

Returns a subset with the same particles, but sorted using the given attribute names. The last attribute name in the call is used for the primary sort order, the second-to-last attribute name for the secondary sort order, and so on. See also numpy.lexsort

>>> particles = Particles(4)
>>> particles.mass = [2.0, 3.0, 1.0, 4.0] | units.kg
>>> particles.radius = [3.0, 2.0, 1.0, 2.0] | units.m
>>> sorted = particles.sorted_by_attributes('mass', 'radius')
>>> print sorted.radius
[1.0, 2.0, 2.0, 3.0] m
>>> print sorted.mass
[1.0, 3.0, 4.0, 2.0] kg
synchronize_to(other_particles)

Synchronize the particles of this set with the contents of the provided set.

After this call the other_particles set will have the same particles as this set.

This call will check if particles have been removed or added it will not copy values of existing particles over.

Parameters:other_particles – particle set wich has to be updated
>>> particles = Particles(2)
>>> particles.x = [1.0, 2.0] | units.m
>>> copy = particles.copy()
>>> new_particle = Particle()
>>> new_particle.x = 3.0 | units.m
>>> particles.add_particle(new_particle)
<amuse.datamodel.particles.Particle object at ...>
>>> print particles.x
[1.0, 2.0, 3.0] m
>>> print copy.x
[1.0, 2.0] m
>>> particles.synchronize_to(copy)
>>> print copy.x
[1.0, 2.0, 3.0] m
to_string(attributes_to_show=None)

Display string of a particle set.

>>> p0 = Particle(10)
>>> p1 = Particle(11)
>>> particles = Particles()
>>> particles.add_particle(p0) 
<amuse.datamodel.particles.Particle object at ...>
>>> particles.add_particle(p1) 
<amuse.datamodel.particles.Particle object at ...>
>>> particles.x = [4.0 , 3.0] | units.m
>>> particles.y = [5.0 , 2.0] | units.km
>>> print particles 
                 key            x            y
                   -            m           km
====================  ===========  ===========
                  10    4.000e+00    5.000e+00
                  11    3.000e+00    2.000e+00
====================  ===========  ===========
class amuse.datamodel.Particles(size=0, storage=None, keys=None, keys_generator=None, particles=None, **attributes)

A set of particles. Attributes and values are stored in a private storage model. This storage model can store the values in the python memory space, in the memory space of the code or in a HDF5 file. By default the storage model is in memory.

class amuse.datamodel.ParticlesSubset(particles, keys)

A subset of particles. Attribute values are not stored by the subset. The subset provides a limited view to the particles.

Particle subset objects are not supposed to be created directly. Instead use the to_set or select methods.

add_particles_to_store(keys, attributes=[], values=[])

Adds particles from to the subset, also adds the particles to the superset

remove_particles_from_store(keys)

Removes particles from the subset, and removes particles from the super set

union(other)

Returns a new subset containing the union between this set and the provided set.

>>> particles = Particles(3)
>>> particles.mass = [10.0, 20.0, 30.0] | units.kg
>>> subset1 = particles.select(lambda x : x > 25.0 | units.kg, ["mass"])
>>> subset2 = particles.select(lambda x : x < 15.0 | units.kg, ["mass"])
>>> union = subset1.union(subset2)
>>> len(union)
2
>>> sorted(union.mass.value_in(units.kg))
[10.0, 30.0]
class amuse.datamodel.ParticlesWithUnitsConverted(particles, converter)

A view on a particle sets. Used when to convert values between incompatible sets of units. For example to convert from si units to nbody units.

The converter must have implement the ConverterInterface.

>>> from amuse.units import nbody_system
>>> particles_nbody = Particles(2)
>>> particles_nbody.x = [10.0 , 20.0] | nbody_system.length
>>> convert_nbody = nbody_system.nbody_to_si(10 | units.kg , 5 | units.m )
>>> particles_si = ParticlesWithUnitsConverted(
...     particles_nbody,
...     convert_nbody.as_converter_from_si_to_nbody())
...
>>> print particles_nbody.x
[10.0, 20.0] length
>>> print particles_si.x
[50.0, 100.0] m
>>> particles_si.x = [200.0, 400.0] | units.m
>>> print particles_nbody.x
[40.0, 80.0] length
class ConverterInterface

Interface definition for the converter.

source
The source quantity is in the units of the user of a ParticlesWithUnitsConverted object
target
The target quantity must be in the units of the internal particles set.
from_source_to_target(quantity)

Converts the quantity from the source units to the target units.

Parameters:quantity – quantity to convert
from_target_to_source(quantity)

Converts the quantity from the target units to the source units.

Parameters:quantity – quantity to convert

object

class amuse.datamodel.Particle(key=None, particles_set=None, **keyword_arguments)

A physical object or a physical region simulated as a physical object (cloud particle).

All attributes defined on a particle are specific for that particle (for example mass or position). A particle contains a set of attributes, some attributes are generic and applicable for multiple modules. Other attributes are specific and are only applicable for a single module.

__add__(particles)

Returns a particle subset, composed of the given particle(s) and this particle. Attribute values are not stored by the subset. The subset provides a view on the particles.

Parameters:particles – particle(s) to be added to self.
>>> particles = Particles(2)
>>> particle1 = particles[0]
>>> particle1.x = 1.0 | units.m
>>> particle2 = particles[1]
>>> particle2.x = 2.0 | units.m
>>> new_set = particle1 + particle2
>>> new_set  
<amuse.datamodel.particles.ParticlesSubset object at 0x...>
>>> print len(new_set)
2
>>> print new_set.x
[1.0, 2.0] m
__sub__(particles)

Raises an exception: cannot subtract particle(s) from a particle.

as_set()

Returns a subset view on the set containing this particle. The subset view includes this particle and no other particles.

>>> particles = Particles(2)
>>> particles.x = [1.0, 2.0] | units.m
>>> particle2 = particles[1]
>>> print particle2.x
2.0 m
>>> particles_with_one_particle = particle2.as_set()
>>> len(particles_with_one_particle)
1
>>> print particles_with_one_particle.x
[2.0] m

Methods to retreive physical properties of the particles set

amuse.datamodel.particle_attributes.center_of_mass(particles)

Returns the center of mass of the particles set. The center of mass is defined as the average of the positions of the particles, weighted by their masses.

>>> from amuse.datamodel import Particles
>>> particles = Particles(2)
>>> particles.x = [-1.0, 1.0] | units.m
>>> particles.y = [0.0, 0.0] | units.m
>>> particles.z = [0.0, 0.0] | units.m
>>> particles.mass = [1.0, 1.0] | units.kg
>>> particles.center_of_mass()
quantity<[0.0, 0.0, 0.0] m>
amuse.datamodel.particle_attributes.center_of_mass_velocity(particles)

Returns the center of mass velocity of the particles set. The center of mass velocity is defined as the average of the velocities of the particles, weighted by their masses.

>>> from amuse.datamodel import Particles
>>> particles = Particles(2)
>>> particles.vx = [-1.0, 1.0] | units.ms
>>> particles.vy = [0.0, 0.0] | units.ms
>>> particles.vz = [0.0, 0.0] | units.ms
>>> particles.mass = [1.0, 1.0] | units.kg
>>> particles.center_of_mass_velocity()
quantity<[0.0, 0.0, 0.0] m * s**-1>
amuse.datamodel.particle_attributes.kinetic_energy(particles)

Returns the total kinetic energy of the particles in the particles set.

>>> from amuse.datamodel import Particles
>>> particles = Particles(2)
>>> particles.vx = [-1.0, 1.0] | units.ms
>>> particles.vy = [0.0, 0.0] | units.ms
>>> particles.vz = [0.0, 0.0] | units.ms
>>> particles.mass = [1.0, 1.0] | units.kg
>>> particles.kinetic_energy()
quantity<1.0 m**2 * kg * s**-2>
amuse.datamodel.particle_attributes.potential_energy(particles, smoothing_length_squared=quantity<zero>, G=quantity<6.67428e-11 m**3 * kg**-1 * s**-2>)

Returns the total potential energy of the particles in the particles set.

Parameters:
  • smooting_length_squared – the smoothing length is added to every distance.
  • G – gravitational constant, need to be changed for particles in different units systems
>>> from amuse.datamodel import Particles
>>> particles = Particles(2)
>>> particles.x = [0.0, 1.0] | units.m
>>> particles.y = [0.0, 0.0] | units.m
>>> particles.z = [0.0, 0.0] | units.m
>>> particles.mass = [1.0, 1.0] | units.kg
>>> particles.potential_energy()
quantity<-6.67428e-11 m**2 * kg * s**-2>
amuse.datamodel.particle_attributes.particle_specific_kinetic_energy(set, particle)

Returns the specific kinetic energy of a particle.

>>> from amuse.datamodel import Particles
>>> particles = Particles(2)
>>> particles.vx = [0.0, 1.0] | units.ms
>>> particles.vy = [0.0, 0.0] | units.ms
>>> particles.vz = [0.0, 0.0] | units.ms
>>> particles.mass = [1.0, 1.0] | units.kg
>>> particles[1].specific_kinetic_energy()
quantity<0.5 m**2 * s**-2>
amuse.datamodel.particle_attributes.particle_potential(set, particle, smoothing_length_squared=quantity<zero>, gravitationalConstant=quantity<6.67428e-11 m**3 * kg**-1 * s**-2>)

Returns the potential energy of a particle.

>>> from amuse.datamodel import Particles
>>> particles = Particles(2)
>>> particles.x = [0.0, 1.0] | units.m
>>> particles.y = [0.0, 0.0] | units.m
>>> particles.z = [0.0, 0.0] | units.m
>>> particles.mass = [1.0, 1.0] | units.kg
>>> particles[1].potential()
quantity<-6.67428e-11 m**2 * s**-2>

Table Of Contents

Previous topic

Quantities and Units

Next topic

Particle Attributes

This Page