Source code for galpy.potential.MovingObjectPotential

###############################################################################
#   MovingObjectPotential.py: class that implements the potential coming from
#                             a moving object
###############################################################################
import copy
import numpy
from .Potential import Potential, _isNonAxi, flatten, \
    evaluatePotentials, evaluateRforces, evaluatezforces, evaluateDensities, _check_c
from .PlummerPotential import PlummerPotential
[docs]class MovingObjectPotential(Potential): """ Class that implements the potential coming from a moving object by combining any galpy potential with an integrated galpy orbit. """
[docs] def __init__(self,orbit,pot=None,amp=1.0, ro=None,vo=None): """ NAME: __init__ PURPOSE: initialize a MovingObjectPotential INPUT: orbit - the Orbit of the object (Orbit object) pot - A potential object or list of potential objects representing the potential of the moving object; should be spherical, but this is not checked [default= PlummerPotential(amp=0.06,b=0.01)] amp (=1.) another amplitude to apply to the potential ro=, vo= distance and velocity scales for translation into internal units (default from configuration file) OUTPUT: (none) HISTORY: 2011-04-10 - Started - Bovy (NYU) 2018-10-18 - Re-implemented to represent general object potentials using galpy potential models - James Lane (UofT) """ Potential.__init__(self,amp=amp,ro=ro,vo=vo) # If no potential supplied use a default Plummer sphere if pot is None: pot=PlummerPotential(amp=0.06,b=0.01) self._pot = pot else: pot=flatten(pot) if _isNonAxi(pot): raise NotImplementedError('MovingObjectPotential for non-axisymmetric potentials is not currently supported') self._pot=pot self._orb= copy.deepcopy(orbit) self._orb.turn_physical_off() self.isNonAxi= True self.hasC= _check_c(self._pot) return None
def _evaluate(self,R,z,phi=0.,t=0.): """ NAME: _evaluate PURPOSE: evaluate the potential at R,z, phi INPUT: R - Galactocentric cylindrical radius z - vertical height phi - azimuth t - time OUTPUT: Phi(R,z,phi) HISTORY: 2011-04-10 - Started - Bovy (NYU) 2018-10-18 - Updated for general object potential - James Lane (UofT) """ #Cylindrical distance Rdist = _cylR(R,phi,self._orb.R(t),self._orb.phi(t)) orbz = self._orb.z(t) if self._orb.dim() == 3 else 0 #Evaluate potential return evaluatePotentials(self._pot,Rdist,orbz-z,t=t, use_physical=False) def _Rforce(self,R,z,phi=0.,t=0.): """ NAME: _Rforce PURPOSE: evaluate the radial force for this potential INPUT: R - Galactocentric cylindrical radius z - vertical height phi - azimuth t - time OUTPUT: the radial force HISTORY: 2011-04-10 - Written - Bovy (NYU) 2018-10-18 - Updated for general object potential - James Lane (UofT) """ #Cylindrical distance Rdist = _cylR(R,phi,self._orb.R(t),self._orb.phi(t)) # Difference vector orbz = self._orb.z(t) if self._orb.dim() == 3 else 0 (xd,yd,zd) = _cyldiff(self._orb.R(t), self._orb.phi(t), orbz, R, phi, z) #Evaluate cylindrical radial force RF = evaluateRforces(self._pot,Rdist,zd,t=t,use_physical=False) # Return R force, negative of radial vector to evaluation location. return -RF*(numpy.cos(phi)*xd+numpy.sin(phi)*yd)/Rdist def _zforce(self,R,z,phi=0.,t=0.): """ NAME: _zforce PURPOSE: evaluate the vertical force for this potential INPUT: R - Galactocentric cylindrical radius z - vertical height phi - azimuth t - time OUTPUT: the vertical force HISTORY: 2011-04-10 - Written - Bovy (NYU) 2018-10-18 - Updated for general object potential - James Lane (UofT) """ #Cylindrical distance Rdist = _cylR(R,phi,self._orb.R(t),self._orb.phi(t)) # Difference vector orbz = self._orb.z(t) if self._orb.dim() == 3 else 0 (xd,yd,zd) = _cyldiff(self._orb.R(t), self._orb.phi(t), orbz, R, phi, z) #Evaluate and return z force return -evaluatezforces(self._pot,Rdist,zd,t=t,use_physical=False) def _phiforce(self,R,z,phi=0.,t=0.): """ NAME: _phiforce PURPOSE: evaluate the azimuthal force for this potential INPUT: R - Galactocentric cylindrical radius z - vertical height phi - azimuth t - time OUTPUT: the azimuthal force HISTORY: 2011-04-10 - Written - Bovy (NYU) 2018-10-18 - Updated for general object potential - James Lane (UofT) """ #Cylindrical distance Rdist = _cylR(R,phi,self._orb.R(t),self._orb.phi(t)) # Difference vector orbz = self._orb.z(t) if self._orb.dim() == 3 else 0 (xd,yd,zd) = _cyldiff(self._orb.R(t), self._orb.phi(t), orbz, R, phi, z) #Evaluate cylindrical radial force. RF = evaluateRforces(self._pot,Rdist,zd,t=t,use_physical=False) # Return phi force, negative of phi vector to evaluate location return -RF*R*(numpy.cos(phi)*yd-numpy.sin(phi)*xd)/Rdist def _dens(self,R,z,phi=0.,t=0.): """ NAME: _dens PURPOSE: evaluate the density for this potential INPUT: R - Galactocentric cylindrical radius z - vertical height phi - azimuth t - time OUTPUT: the density HISTORY: 2010-08-08 - Written - Bovy (NYU) """ #Cylindrical distance Rdist = _cylR(R,phi,self._orb.R(t),self._orb.phi(t)) # Difference vector orbz = self._orb.z(t) if self._orb.dim() == 3 else 0 (xd,yd,zd) = _cyldiff(self._orb.R(t), self._orb.phi(t), orbz, R, phi, z) # Return the density return evaluateDensities(self._pot,Rdist,zd,t=t,use_physical=False)
def _cylR(R1,phi1,R2,phi2): return numpy.sqrt(R1**2.+R2**2.-2.*R1*R2*numpy.cos(phi1-phi2)) # Cosine law def _cyldiff(R1,phi1,z1,R2,phi2,z2): dx = R1*numpy.cos(phi1)-R2*numpy.cos(phi2) dy = R1*numpy.sin(phi1)-R2*numpy.sin(phi2) dz = z1-z2 return (dx,dy,dz)