Automatically Derived Arrays

Pynbody includes a system which automatically derives one array from others. The idea is that this system

(1) permits analysis code to assume that certain arrays exist – whether or not they exist in the file;

(2) allows arrays to be kept up-to-date when they depend on other arrays

Built-in derived arrays

The quantities listed under derived are calculated for all simulation types. If you want, for example, to calculate the specific kinetic energy, you can just access the ke array and pynbody will calculate it:

In [1]: import pynbody

In [2]: s = pynbody.load('testdata/g15784.lr.01024.gz')

In [3]: s['ke']
Out[3]: 
SimArray([0.01443704, 0.01435218, 0.01545113, ..., 0.02690037, 0.02084463,
          0.02266956], '2.98e+06 km**2 a**2 s**-2')

Note that you cannot directly alter a derived array:

In [4]: s['ke'][0] = 0
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-115c2ca7f0b6> in <module>
----> 1 s['ke'][0] = 0

~/Science/pynbody/pynbody/array.py in q(a, *y, **kw)
    702             return w(a, *y, **kw)
    703         else:
--> 704             return w(a, *y)
    705 
    706     q.__name__ = w.__name__

~/Science/pynbody/pynbody/array.py in __setitem__(self, item, to)
    490             np.ndarray.__setitem__(self, item, to.in_units(self.units))
    491         else:
--> 492             np.ndarray.__setitem__(self, item, to)
    493 
    494     def __setslice__(self, a, b, to):

ValueError: assignment destination is read-only

But the array updates itself when one of its dependencies changes:

In [5]: s['vel']*=2

In [6]: s['ke']
Out[6]: 
SimArray([0.05774817, 0.05740871, 0.0618045 , ..., 0.10760149, 0.08337851,
          0.09067823], '2.98e+06 km**2 a**2 s**-2')

The recalculation only takes place when required – in the example above the ke array is stored (just like a normal array) until the velocity array is updated, at which point it is deleted. When you ask for the ke array again, it is recalculated.

This is why you’re not allowed to change values in a derived array – your changes could be overwritten, leading to confusing bugs. However, if you want to make a derived array back into a normal array you can do so.

In [7]: s['ke'].derived = False

In [8]: s['ke'][0] = 0

In [9]: s['ke']
Out[9]: 
SimArray([0.        , 0.05740871, 0.0618045 , ..., 0.10760149, 0.08337851,
          0.09067823], '2.98e+06 km**2 a**2 s**-2')

At this point you’ve taken full responsibility for the array, so if you update its dependencies the framework won’t help you out any longer:

In [10]: s['vel']*=2

In [11]: s['ke']
Out[11]: 
SimArray([0.        , 0.05740871, 0.0618045 , ..., 0.10760149, 0.08337851,
          0.09067823], '2.98e+06 km**2 a**2 s**-2')

To get the framework back on your side, you can delete the modified array:

In [12]: del s['ke']

In [13]: s['ke']
Out[13]: 
SimArray([0.23099267, 0.22963485, 0.247218  , ..., 0.43040596, 0.33351406,
          0.36271291], '2.98e+06 km**2 a**2 s**-2')

Defining your own deriving functions

You can easily define your own derived arrays. The easiest way to do this is using the decorator pynbody.derived_array. An example is given in the data access tutorial.

When your function is called, the framework monitors any arrays it retrieves from the simulation. It automatically marks the accessed arrays as dependencies for your function.

Built-in derived arrays for all snapshot classes

derived

Holds procedures for creating new arrays from existing ones, e.g. for getting the radial position. For more information see Automatically Derived Arrays.

pynbody.derived.r(self)[source]

Radial position

pynbody.derived.rxy(self)[source]

Cylindrical radius in the x-y plane

pynbody.derived.vr(self)[source]

Radial velocity

pynbody.derived.v2(self)[source]

Squared velocity

pynbody.derived.vt(self)[source]

Tangential velocity

pynbody.derived.ke(self)[source]

Specific kinetic energy

pynbody.derived.te(self)[source]

Specific total energy

pynbody.derived.j(self)[source]

Specific angular momentum

pynbody.derived.j2(self)[source]

Square of the specific angular momentum

pynbody.derived.jz(self)[source]

z-component of the angular momentum

pynbody.derived.vrxy(self)[source]

Cylindrical radial velocity in the x-y plane

pynbody.derived.vcxy(self)[source]

Cylindrical tangential velocity in the x-y plane

pynbody.derived.vphi(self)[source]

Azimuthal velocity (synonym for vcxy)

pynbody.derived.vtheta(self)[source]

Velocity projected to polar direction

pynbody.derived.v_mean(self)[source]

SPH-smoothed mean velocity

pynbody.derived.v_disp(self)[source]

SPH-smoothed local velocity dispersion

pynbody.derived.age(self)[source]

Stellar age determined from formation time and current snapshot time

pynbody.derived.X(s, b='K')

K magnitude from analysis.luminosity.calc_mags

pynbody.derived.lum_den(s)

Luminosity density in astronomy-friendly units: 10^(-0.4 K_mag) per unit volume. The magnitude is taken from analysis.luminosity.calc_mags.

pynbody.derived.theta(self)[source]

Angle from the z axis, from [0:2pi]

pynbody.derived.alt(self)[source]

Angle from the horizon, from [-pi/2:pi/2]

pynbody.derived.az(self)[source]

Angle in the xy plane from the x axis, from [-pi:pi]

pynbody.derived.cs(self)[source]

Sound speed

pynbody.derived.mu(sim, t0=None)[source]

mean molecular mass, i.e. the mean atomic mass per particle

pynbody.derived.p(sim)[source]

Pressure

pynbody.derived.u(self)[source]

Gas internal energy derived from temperature

pynbody.derived.temp(self)[source]

Gas temperature derived from internal energy

pynbody.derived.zeldovich_offset(self)[source]

The position offset in the current snapshot according to the Zel’dovich approximation applied to the current velocities. (Only useful in the generation or analysis of initial conditions.)

pynbody.derived.aform(self)[source]

The expansion factor at the time specified by the tform array.

pynbody.derived.tform(self)[source]

The time of the specified expansion factor in the aform

tipsy

Note

These take advantage of arrays present in Gasoline snapshots

pynbody.snapshot.tipsy.HII(sim)[source]

Number of HII ions per proton mass

pynbody.snapshot.tipsy.HeIII(sim)[source]

Number of HeIII ions per proton mass

pynbody.snapshot.tipsy.ne(sim)[source]

Number of electrons per proton mass

pynbody.snapshot.tipsy.hetot(self)[source]

Helium mass fraction including correction based on metallicity

pynbody.snapshot.tipsy.hydrogen(self)[source]

Hydrogen mass fraction including correction based on metallicity

pynbody.snapshot.tipsy.feh(self)[source]

Iron abundance [Fe/H] derived from tipsy array FeMassFrac, with solar values from Asplund et al 09

pynbody.snapshot.tipsy.oxh(self)[source]

Oxygen abundance [O/H] derived from tipsy array FeMassFrac, with solar values from Asplund et al 09

pynbody.snapshot.tipsy.ofe(self)[source]

Oxygen-to-iron ratio [O/Fe] derived from tipsy arrays OxMassFrac and FeMassFrac with solar values from Asplund et al 09

pynbody.snapshot.tipsy.mgfe(sim)[source]

Magnesium-to-iron ratio [Mg/Fe] derived from tipsy arrays MgMassFrac and FeMassFrac with solar values from Asplund et al 09

pynbody.snapshot.tipsy.nefe(sim)[source]

Neon-to-iron ratio [Ne/Fe] derived from tipsy arrays MgMassFrac and FeMassFrac with solar values from Asplund et al 09

pynbody.snapshot.tipsy.sife(sim)[source]

Silicon-to-iron ratio [Si/Fe] derived from tipsy arrays MgMassFrac and FeMassFrac with solar values from Asplund et al 09

pynbody.snapshot.tipsy.c_s(self)[source]

Ideal gas sound speed based on pressure and density

pynbody.snapshot.tipsy.c_s_turb(self)[source]

Turbulent sound speed (from Mac Low & Klessen 2004)

pynbody.snapshot.tipsy.mjeans(self)[source]

Classical Jeans mass

pynbody.snapshot.tipsy.mjeans_turb(self)[source]

Turbulent Jeans mass

pynbody.snapshot.tipsy.ljeans(self)[source]

Jeans length

pynbody.snapshot.tipsy.ljeans_turb(self)[source]

Turbulent Jeans length

gadget

No special derived quantities at the moment.

Ramses

pynbody.snapshot.ramses.mass(sim)[source]