# Source code for galpy.potential.CorotatingRotationWrapperPotential

###############################################################################
#   CorotatingRotationWrapperPotential.py: Wrapper to make a potential rotate
#                                          with a fixed R x pattern speed,
#                                          around the z axis
###############################################################################
from .WrapperPotential import parentWrapperPotential
from ..util import conversion
[docs]class CorotatingRotationWrapperPotential(parentWrapperPotential):
"""Potential wrapper class that implements rotation with fixed R x pattern-speed around the z-axis. Can be used to make spiral structure that is everywhere co-rotating. The potential is rotated by replacing

.. math::

\\phi \\rightarrow \\phi + \\frac{V_p(R)}{R} \\times \\left(t-t_0\\right) + \\mathrm{pa}

with :math:V_p(R) the circular velocity curve, :math:t_0 a reference time---time at which the potential is unchanged by the wrapper---and :math:\\mathrm{pa} the position angle at :math:t=0. The circular velocity is parameterized as

.. math::

V_p(R) = V_{p,0}\,\\left(\\frac{R}{R_0}\\right)^\\beta\,.

"""
[docs]    def __init__(self,amp=1.,pot=None,vpo=1.,beta=0.,to=0.,pa=0.,
ro=None,vo=None):
"""
NAME:

__init__

PURPOSE:

initialize a CorotatingRotationWrapper Potential

INPUT:

amp - amplitude to be applied to the potential (default: 1.)

pot - Potential instance or list thereof; this potential is made to rotate around the z axis by the wrapper

vpo= (1.) amplitude of the circular-velocity curve (can be a Quantity)

beta= (0.) power-law amplitude of the circular-velocity curve

to= (0.) reference time at which the potential == pot

pa= (0.) the position angle (can be a Quantity)

OUTPUT:

(none)

HISTORY:

2018-02-21 - Started - Bovy (UofT)

"""
vpo= conversion.parse_velocity(vpo,vo=self._vo)
to= conversion.parse_time(to,ro=self._ro,vo=self._vo)
pa= conversion.parse_angle(pa)
self._vpo= vpo
self._beta= beta
self._pa= pa
self._to= to
self.hasC= True
self.hasC_dxdv= True

def _wrap(self,attribute,*args,**kwargs):
kwargs['phi']= kwargs.get('phi',0.)\
-self._vpo*args[0]**(self._beta-1.)*(kwargs.get('t',0.)-self._to)\
-self._pa
return self._wrap_pot_func(attribute)(self._pot,*args,**kwargs)

# Derivatives that involve R need to be adjusted, bc they require also
# the R dependence of phi to be taken into account
def _Rforce(self,*args,**kwargs):
kwargs['phi']= kwargs.get('phi',0.)\
-self._vpo*args[0]**(self._beta-1.)*(kwargs.get('t',0.)-self._to)\
-self._pa
return self._wrap_pot_func('_Rforce')(self._pot,*args,**kwargs)\
-self._wrap_pot_func('_phiforce')(self._pot,*args,**kwargs)\
*(self._vpo*(self._beta-1.)*args[0]**(self._beta-2.)
*(kwargs.get('t',0.)-self._to))

def _R2deriv(self,*args,**kwargs):
kwargs['phi']= kwargs.get('phi',0.)\
-self._vpo*args[0]**(self._beta-1.)*(kwargs.get('t',0.)-self._to)\
-self._pa
phiRderiv= -self._vpo*(self._beta-1.)*args[0]**(self._beta-2.)\
*(kwargs.get('t',0.)-self._to)
return self._wrap_pot_func('_R2deriv')(self._pot,*args,**kwargs)\
+2.*self._wrap_pot_func('_Rphideriv')(self._pot,*args,**kwargs)\
*phiRderiv\
+self._wrap_pot_func('_phi2deriv')(self._pot,*args,**kwargs)\
*phiRderiv**2.\
+self._wrap_pot_func('_phiforce')(self._pot,*args,**kwargs)\
*(self._vpo*(self._beta-1.)*(self._beta-2.)
*args[0]**(self._beta-3.)*(kwargs.get('t',0.)-self._to))

def _Rphideriv(self,*args,**kwargs):
kwargs['phi']= kwargs.get('phi',0.)\
-self._vpo*args[0]**(self._beta-1.)*(kwargs.get('t',0.)-self._to)\
-self._pa
return self._wrap_pot_func('_Rphideriv')(self._pot,*args,**kwargs)\
-self._wrap_pot_func('_phi2deriv')(self._pot,*args,**kwargs)\
*self._vpo*(self._beta-1.)*args[0]**(self._beta-2.)\
*(kwargs.get('t',0.)-self._to)