Skip to content

Instantly share code, notes, and snippets.

@rokroskar
Last active December 28, 2015 08:49
Show Gist options
  • Save rokroskar/7474840 to your computer and use it in GitHub Desktop.
Save rokroskar/7474840 to your computer and use it in GitHub Desktop.

Simple class for generating actions for particles in a simulation that can be read using pynbody. The action calculation is done with galpy.

See the notebook for an example.

Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
import pynbody
from pynbody import grav_omp
import numpy as np
from galpy.potential import Potential
import hashlib
class SnapshotPotential(Potential):
"""
Create a snapshot potential object. The potential and forces are
calculated as needed through the _evaluate and _Rforce methods.
**Input**:
*s* : a simulation snapshot loaded with pynbody
**Optional Keywords**:
*num_threads* (4): number of threads to use for calculation
"""
def __init__(self, s, num_threads=4) :
self.s = s
self.point_hash = None
self.pots = None
self.rz_acc = None
self._amp = 1.0
def _evaluate(self, R,z,phi=None,t=None,dR=None,dphi=None) :
if isinstance(R,float) :
R = np.array([R])
if isinstance(z, float) :
z = np.array([z])
new_point_hash = hashlib.md5(np.array([R,z])).hexdigest()
if self.pots is None or new_point_hash != self.point_hash:
self.setup_potential(R,z)
self.point_hash = hashlib.md5(np.array([R,z])).hexdigest()
return self.pots
def _Rforce(self, R,z,phi=None,t=None,dR=None,dphi=None) :
if isinstance(R,float) :
R = np.array([R])
if isinstance(z, float) :
z = np.array([z])
new_point_hash = hashlib.md5(np.array([R,z])).hexdigest()
if self.rz_acc is None or new_point_hash != self.point_hash:
self.setup_potential(R,z)
self.point_hash = hashlib.md5(np.array([R,z])).hexdigest()
return self.rz_acc[:,0]
def setup_potential(self, R, z) :
#
# set up the four points per R,z pair to mimic axisymmetry
#
points = np.zeros((len(R),len(z),4,3))
for i in xrange(len(R)) :
for j in xrange(len(z)) :
points[i,j] = [(R[i],0,z[j]),
(0,R[i],z[j]),
(-R[i],0,z[j]),
(0,-R[i],z[j])]
points_new = points.reshape(points.size/3,3)
pot, acc = grav_omp.direct(self.s,points_new,num_threads=4)
pot = pot.reshape(len(R)*len(z),4)
acc = acc.reshape(len(R)*len(z),4,3)
#
# need to average the potentials
#
if len(pot) > 1:
pot = pot.mean(axis=1)
else :
pot = pot.mean()
#
# get the radial accelerations
#
rz_acc = np.zeros((len(R)*len(z),2))
rvecs = [(1.0,0.0,0.0),
(0.0,1.0,0.0),
(-1.0,0.0,0.0),
(0.0,-1.0,0.0)]
# reshape the acc to make sure we have a leading index even
# if we are only evaluating a single point, i.e. we have
# shape = (1,4,3) not (4,3)
acc = acc.reshape((len(rz_acc),4,3))
for i in xrange(len(R)) :
for j,rvec in enumerate(rvecs) :
rz_acc[i,0] += acc[i,j].dot(rvec)
rz_acc[i,1] += acc[i,j,2]
rz_acc /= 4.0
self.pots = pot
self.rz_acc = rz_acc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment