Source code for pynbody.analysis.gravity

"""

gravity
=======

Functions for calculating the gravitational potential and accelerations. 

"""


from .. import units
from .. import array

import math
import numpy as np


[docs]def potential(f, pos_vec, eps=None, unit=None): """ Calculates the gravitational potential at the specified position using all particles in the specified snapshot. The gravitational softening length is determined by (in order of preference): 1. The parameter eps (scalar, unit or array) 2. The array f['eps'] 3. f.properties['eps'] (scalar or unit) """ if eps is None: try: eps = f['eps'] except KeyError: eps = f.properties['eps'] if isinstance(eps, str): eps = units.Unit(eps) if isinstance(eps, units.UnitBase): eps = eps.in_units(f['pos'].units, **f.conversion_context()) d_pos = f['pos'] - pos_vec GM_by_r = units.G * f['mass'] / \ ((d_pos ** 2).sum(axis=1) + eps ** 2) ** (1, 2) if unit is not None: GM_by_r.convert_units(unit) return -(GM_by_r.sum())
[docs]def accel(f, pos_vec, eps=None): """ Calculates the gravitational acceleration vector at the specified position using all particles in the specified snapshot. The gravitational softening length is determined by (in order of preference): 1. The parameter eps (scalar, unit or array) 2. The array f['eps'] 3. f.properties['eps'] (scalar or unit) """ if eps is None: try: eps = f['eps'] except KeyError: eps = f.properties['eps'] if isinstance(eps, str): eps = units.Unit(eps) if isinstance(eps, units.UnitBase): eps = eps.in_units(f['pos'].units, **f.conversion_context()) d_pos = f['pos'] - pos_vec GM_by_r3 = units.G * f['mass'] / \ ((d_pos ** 2).sum(axis=1) + eps ** 2) ** (3, 2) return -(d_pos.T * GM_by_r3).sum(axis=1)
[docs]def midplane_rot_curve(f, rxy_points, eps=None): """ Calculates the midplane rotation curve at a specified set of points. Used primarily by :func:`pynbody.analysis.profile.v_circ` """ u_out = (units.G * f['mass'].units / f['pos'].units) ** (1, 2) vels = [] for r in rxy_points: # Do four samples like Tipsy does r_acc_r = [] for pos in [(r, 0, 0), (0, r, 0), (-r, 0, 0), (0, -r, 0)]: acc = accel(f, pos, eps) r_acc_r.append(np.dot(acc, pos)) vel2 = np.mean(r_acc_r) if vel2 > 0: vel = math.sqrt(vel2) else: vel = 0 vels.append(vel) x = array.SimArray(vels, units=u_out) x.sim = f.ancestor return x
[docs]def midplane_potential(f, rxy_points, eps=None): """ Calculates the midplane potential at a specified set of points. Used primarily by :func:`pynbody.analysis.profile.pot` """ u_out = units.G * f['mass'].units / f['pos'].units pots = [] for r in rxy_points: # Do four samples like Tipsy does pot = [] for pos in [(r, 0, 0), (0, r, 0), (-r, 0, 0), (0, -r, 0)]: pot.append(potential(f, pos, eps)) pots.append(np.mean(pot)) x = array.SimArray(pots, units=u_out) x.sim = f.ancestor return x