Example #1
0
def test_freq_in_kmskpc():
    #Test the scaling, as 1/time, should scale as velocity/position
    vofid, rofid = 200., 8.
    assert numpy.fabs(2. * bovy_conversion.freq_in_kmskpc(vofid, rofid) /
                      bovy_conversion.freq_in_kmskpc(2. * vofid, rofid) - 1.
                      ) < 10.**-10., 'freq_in_kmskpc did not work as expected'
    assert numpy.fabs(.5 * bovy_conversion.freq_in_kmskpc(vofid, rofid) /
                      bovy_conversion.freq_in_kmskpc(vofid, 2 * rofid) - 1.
                      ) < 10.**-10., 'freq_in_kmskpc did not work as expected'
    return None
def custom_sample_aAt(sdf,n):
    """Custom time and frequency sampling based on Jason's investigations of Denis' simulations"""
    # Sample pericenter vs. continuous
    w= 0.28
    atperi= numpy.random.binomial(1,1.-w,size=n)
    # Setup output
    dO1s= numpy.zeros(n)
    dt= numpy.zeros(n)
    # First go through the pericenter ones: 
    # find all of the pericenter passages up to tdisrupt
    nperi= sdf._tdisrupt/sdf._progenitor_Omega[0]+2
    tps= sdf._progenitor_angle[0]/sdf._progenitor_Omega[0]\
        +numpy.arange(nperi)*2.*numpy.pi/sdf._progenitor_Omega[0]
    tps= tps[tps < sdf._tdisrupt]
    # Sample these with a linearly-increasing probability
    dt[atperi==1]= tps[numpy.random.choice(len(tps),
                                           size=numpy.sum(atperi),
                                           p=tps/numpy.sum(tps))]
    # Generate frequencies from the broad Gaussian
    dO1s[atperi==1]= numpy.random.normal(size=numpy.sum(atperi))\
        *0.049+0.306
    # Next do the continuous part
    dt[atperi==0]= (numpy.random.uniform(size=n-numpy.sum(atperi)))**(1./2.)\
        *sdf._tdisrupt
    dO1s[atperi==0]= numpy.random.normal(size=n-numpy.sum(atperi))\
        *0.023+0.243
    # Put everything together and rotate etc.
    dO1s/= bovy_conversion.freq_in_kmskpc(sdf._vo,sdf._ro)
    dO1s= numpy.array(dO1s)*sdf._sigMeanSign
    dO2s= numpy.random.normal(size=n)*numpy.sqrt(sdf._sortedSigOEig[1])
    dO3s= numpy.random.normal(size=n)*numpy.sqrt(sdf._sortedSigOEig[0])
    #Rotate into dOs in R,phi,z coordinates
    dO= numpy.vstack((dO3s,dO2s,dO1s))
    dO= numpy.dot(sdf._sigomatrixEig[1][:,sdf._sigomatrixEigsortIndx],
                  dO)
    Om= dO+numpy.tile(sdf._progenitor_Omega.T,(n,1)).T
    #Also generate angles
    da= numpy.random.normal(size=(3,n))*sdf._sigangle
    #Integrate the orbits relative to the progenitor
    da+= dO*numpy.tile(dt,(3,1))
    angle= da+numpy.tile(sdf._progenitor_angle.T,(n,1)).T
    return (Om,angle,dt)
Example #3
0
def custom_sample_aAt(sdf, n):
    """Custom time and frequency sampling based on Jason's investigations of Denis' simulations"""
    # Sample pericenter vs. continuous
    w = 0.28
    atperi = numpy.random.binomial(1, 1. - w, size=n)
    # Setup output
    dO1s = numpy.zeros(n)
    dt = numpy.zeros(n)
    # First go through the pericenter ones:
    # find all of the pericenter passages up to tdisrupt
    nperi = sdf._tdisrupt / sdf._progenitor_Omega[0] + 2
    tps= sdf._progenitor_angle[0]/sdf._progenitor_Omega[0]\
        +numpy.arange(nperi)*2.*numpy.pi/sdf._progenitor_Omega[0]
    tps = tps[tps < sdf._tdisrupt]
    # Sample these with a linearly-increasing probability
    dt[atperi == 1] = tps[numpy.random.choice(len(tps),
                                              size=numpy.sum(atperi),
                                              p=tps / numpy.sum(tps))]
    # Generate frequencies from the broad Gaussian
    dO1s[atperi==1]= numpy.random.normal(size=numpy.sum(atperi))\
        *0.049+0.306
    # Next do the continuous part
    dt[atperi==0]= (numpy.random.uniform(size=n-numpy.sum(atperi)))**(1./2.)\
        *sdf._tdisrupt
    dO1s[atperi==0]= numpy.random.normal(size=n-numpy.sum(atperi))\
        *0.023+0.243
    # Put everything together and rotate etc.
    dO1s /= bovy_conversion.freq_in_kmskpc(sdf._vo, sdf._ro)
    dO1s = numpy.array(dO1s) * sdf._sigMeanSign
    dO2s = numpy.random.normal(size=n) * numpy.sqrt(sdf._sortedSigOEig[1])
    dO3s = numpy.random.normal(size=n) * numpy.sqrt(sdf._sortedSigOEig[0])
    #Rotate into dOs in R,phi,z coordinates
    dO = numpy.vstack((dO3s, dO2s, dO1s))
    dO = numpy.dot(sdf._sigomatrixEig[1][:, sdf._sigomatrixEigsortIndx], dO)
    Om = dO + numpy.tile(sdf._progenitor_Omega.T, (n, 1)).T
    #Also generate angles
    da = numpy.random.normal(size=(3, n)) * sdf._sigangle
    #Integrate the orbits relative to the progenitor
    da += dO * numpy.tile(dt, (3, 1))
    angle = da + numpy.tile(sdf._progenitor_angle.T, (n, 1)).T
    return (Om, angle, dt)
    def __init__(self,amp=1.,pot=None,omega=1.,pa=0.,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a SolidBodyRotationWrapper 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

           omega= (1.) the pattern speed (can be a Quantity)

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

        OUTPUT:

           (none)

        HISTORY:

           2017-08-22 - Started - Bovy (UofT)

        """
        WrapperPotential.__init__(self,amp=amp,pot=pot,ro=ro,vo=vo)
        if _APY_LOADED and isinstance(omega,units.Quantity):
            omega= omega.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        if _APY_LOADED and isinstance(pa,units.Quantity):
            pa= pa.to(units.rad).value
        self._omega= omega
        self._pa= pa
        self.hasC= True
        self.hasC_dxdv= True
    def __init__(self,amp=1.,pot=None,omega=1.,pa=0.,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a SolidBodyRotationWrapper 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

           omega= (1.) the pattern speed (can be a Quantity)

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

        OUTPUT:

           (none)

        HISTORY:

           2017-08-22 - Started - Bovy (UofT)

        """
        if _APY_LOADED and isinstance(omega,units.Quantity):
            omega= omega.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        if _APY_LOADED and isinstance(pa,units.Quantity):
            pa= pa.to(units.rad).value
        self._omega= omega
        self._pa= pa
        self.hasC= True
        self.hasC_dxdv= True
Example #6
0
    def __init__(self, *args, **kwargs):
        """
        NAME:

           __init__

        PURPOSE:

           initialize an actionAngleHarmonic object

        INPUT:

           omega= frequencies (can be Quantity)

           ro= distance from vantage point to GC (kpc; can be Quantity)

           vo= circular velocity at ro (km/s; can be Quantity)

        OUTPUT:
        
           instance

        HISTORY:

           2018-04-08 - Written - Bovy (Uoft)

        """
        actionAngle.__init__(self,
                             ro=kwargs.get('ro', None),
                             vo=kwargs.get('vo', None))
        if not 'omega' in kwargs:  #pragma: no cover
            raise IOError("Must specify omega= for actionAngleHarmonic")
        omega = kwargs.get('omega')
        if _APY_LOADED and isinstance(omega, units.Quantity):
            omega= omega.to(units.km/units.s/units.kpc).value \
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        self._omega = omega
        return None
    def __init__(self,amp=1.,omegas=0.65,A=-0.035,
                 alpha=-7.,m=2,gamma=math.pi/4.,p=None,
                 sigma=1.,to=0.,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a transient logarithmic spiral potential localized 
           around to

        INPUT:

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

           gamma - angle between sun-GC line and the line connecting the peak of the spiral pattern at the Solar radius (in rad; default=45 degree; can be Quantity)
        
           A - amplitude (alpha*potential-amplitude; default=0.035; can be Quantity)

           omegas= - pattern speed (default=0.65; can be Quantity)

           m= number of arms
           
           to= time at which the spiral peaks (can be Quantity)

           sigma= "spiral duration" (sigma in Gaussian amplitude; can be Quantity)
           
           Either provide:

              a) alpha=
               
              b) p= pitch angle (rad; can be Quantity)
              
        OUTPUT:

           (none)

        HISTORY:

           2011-03-27 - Started - Bovy (NYU)

        """
        planarPotential.__init__(self,amp=amp,ro=ro,vo=vo)
        if _APY_LOADED and isinstance(gamma,units.Quantity):
            gamma= gamma.to(units.rad).value
        if _APY_LOADED and isinstance(p,units.Quantity):
            p= p.to(units.rad).value
        if _APY_LOADED and isinstance(A,units.Quantity):
            A= A.to(units.km**2/units.s**2).value/self._vo**2.
        if _APY_LOADED and isinstance(omegas,units.Quantity):
            omegas= omegas.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        if _APY_LOADED and isinstance(to,units.Quantity):
            to= to.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        if _APY_LOADED and isinstance(sigma,units.Quantity):
            sigma= sigma.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        self._omegas= omegas
        self._A= A
        self._m= m
        self._gamma= gamma
        self._to= to
        self._sigma2= sigma**2.
        if not p is None:
            self._alpha= self._m/math.tan(p)
        else:
            self._alpha= alpha
        self.hasC= True
    def __init__(self,amp=1.,a=4.,b=0.,c=1.,normalize=False,
                 pa=0.4,omegab=1.8,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a softened-needle bar potential

        INPUT:

           amp - amplitude to be applied to the potential (default: 1); can be a Quantity with units of mass

           a= (4.) Bar half-length (can be Quantity)

           b= (1.) Triaxial softening length (can be Quantity)

           c= (1.) Prolate softening length (can be Quantity)

           pa= (0.4) The position angle of the x axis (rad or Quantity)

           omegab= (1.8) Pattern speed (can be Quantity)

           normalize - if True, normalize such that vc(1.,0.)=1., or, if given as a number, such that the force is this fraction of the force necessary to make vc(1.,0.)=1.

           ro=, vo= distance and velocity scales for translation into internal units (default from configuration file)

        OUTPUT:

           (none)

        HISTORY:

           2016-11-02 - Started - Bovy (UofT)

        """
        Potential.__init__(self,amp=amp,ro=ro,vo=vo,amp_units='mass')
        if _APY_LOADED and isinstance(a,units.Quantity):
            a= a.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(b,units.Quantity):
            b= b.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(c,units.Quantity):
            c= c.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(pa,units.Quantity):
            pa= pa.to(units.rad).value
        if _APY_LOADED and isinstance(omegab,units.Quantity):
            omegab= omegab.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        self._a= a
        self._b= b
        self._c2= c**2.
        self._pa= pa
        self._omegab= omegab
        self._force_hash= None
        self.hasC= True
        self.hasC_dxdv= False
        if normalize or \
                (isinstance(normalize,(int,float)) \
                     and not isinstance(normalize,bool)): #pragma: no cover 
            self.normalize(normalize)
        self.isNonAxi= True
        return None
Example #9
0
import numpy            as    np
import matplotlib.pylab as    plt
import galpy
from   galpy.util      import bovy_conversion
from   nemo_funcs      import tail_cut

R0 = 8.
V0 = 220.

fact  = bovy_conversion.freq_in_Gyr(220., 8.)
fact2 = bovy_conversion.freq_in_kmskpc(220., 8.)

#prog = np.loadtxt("/Users/anita/dyn-modeling-streams-2014/sim/test.dat", delimiter=',')
#tail = np.loadtxt("/Users/anita/Desktop/Meeting_2/tail_concatenated_final.txt")

tail = np.loadtxt("/home/bahmanyar/Github/AST1501/Codes/concatenated_2.0.txt")

tail = tail.T
#JR_p, Lz_p, Jz_p, omegaR_p, omega_phi_p, omegaz_p, thetaR_p, theta_phi_p, thetaz_p = prog[:,0], prog[:,1], prog[:,2], prog[:,3], prog[:,4], prog[:,5], prog[:,6], prog[:,7], prog[:,8]
JR_t, Lz_t, Jz_t, omegaR_t, omega_phi_t, omegaz_t, thetaR_t, theta_phi_t, thetaz_t = tail[:,0], tail[:,1], tail[:,2], tail[:,3], tail[:,4], tail[:,5], tail[:,6], tail[:,7], tail[:,8]

indx_t = tail_cut(tail)
#indx_p = tail_cut(prog)

# Tail
omegaR_t, omega_phi_t, omegaz_t,  = tail[indx_t,3], tail[indx_t,4], tail[indx_t,5]
JR_t, Lz_t, Jz_t                  = tail[indx_t,0], tail[indx_t,1], tail[indx_t,2]
thetaR_t, theta_phi_t, thetaz_t   = tail[indx_t,6], tail[indx_t,7], tail[indx_t,8]

thetaR_t    = (np.pi+(thetaR_t-np.median(tail[:,6]))) % (2.*np.pi)
theta_phi_t = (np.pi+(theta_phi_t-np.median(tail[:,7]))) % (2.*np.pi)
def test_freq_in_kmskpc():
    #Test the scaling, as 1/time, should scale as velocity/position
    vofid, rofid= 200., 8.
    assert numpy.fabs(2.*bovy_conversion.freq_in_kmskpc(vofid,rofid)/bovy_conversion.freq_in_kmskpc(2.*vofid,rofid)-1.) < 10.**-10., 'freq_in_kmskpc did not work as expected'
    assert numpy.fabs(.5*bovy_conversion.freq_in_kmskpc(vofid,rofid)/bovy_conversion.freq_in_kmskpc(vofid,2*rofid)-1.) < 10.**-10., 'freq_in_kmskpc did not work as expected'
    return None
Example #11
0
    def __init__(self, amp=1, ro=None, vo=None, amp_units='density',
                 N=2, alpha=0.2, r_ref=1, phi_ref=0, Rs=0.3, H=0.125, omega=0, Cs=[1]):

        """
        NAME:       
            __init__
        PURPOSE:
            initialize a spiral arms potential
        INPUT:
            :amp: amplitude to be applied to the potential (default: 1); 
                        can be a Quantity with units of density. (:math:`amp = 4 \\pi G \\rho_0`)
            :ro: distance scales for translation into internal units (default from configuration file)
            :vo: velocity scales for translation into internal units (default from configuration file)
            :N: number of spiral arms
            :alpha: pitch angle of the logarithmic spiral arms in radians (can be Quantity)
            :r_ref: fiducial radius where :math:`\\rho = \\rho_0` (:math:`r_0` in the paper by Cox and Gomez) (can be Quantity)
            :phi_ref: reference angle (:math:`\\phi_p(r_0)` in the paper by Cox and Gomez) (can be Quantity)
            :Rs: radial scale length of the drop-off in density amplitude of the arms (can be Quantity)
            :H: scale height of the stellar arm perturbation (can be Quantity)
            :Cs: list of constants multiplying the :math:`\cos(n \\gamma)` terms
            :omega: rotational pattern speed of the spiral arms (can be Quantity)
        OUTPUT:
            (none)
        HISTORY:
            Started - 2017-05-12  Jack Hong (UBC)

            Completed - 2017-07-04 Jack Hong (UBC)
        """

        Potential.__init__(self, amp=amp, ro=ro, vo=vo, amp_units=amp_units)
        if _APY_LOADED:
            if isinstance(alpha, units.Quantity):
                alpha = alpha.to(units.rad).value
            if isinstance(r_ref, units.Quantity):
                r_ref = r_ref.to(units.kpc).value / self._ro
            if isinstance(phi_ref, units.Quantity):
                phi_ref = phi_ref.to(units.rad).value
            if isinstance(Rs, units.Quantity):
                Rs = Rs.to(units.kpc).value / self._ro
            if isinstance(H, units.Quantity):
                H = H.to(units.kpc).value / self._ro
            if isinstance(omega, units.Quantity):
                omega = omega.to(units.km / units.s / units.kpc).value \
                        / bovy_conversion.freq_in_kmskpc(self._vo, self._ro)

        self._N = -N  # trick to flip to left handed coordinate system; flips sign for phi and phi_ref, but also alpha.
        self._alpha = -alpha  # we don't want sign for alpha to change, so flip alpha. (see eqn. 3 in the paper)
        self._sin_alpha = np.sin(-alpha)
        self._tan_alpha = np.tan(-alpha)
        self._r_ref = r_ref
        self._phi_ref = phi_ref
        self._Rs = Rs
        self._H = H
        self._Cs = np.array(Cs)
        self._ns = np.arange(1, len(Cs) + 1)
        self._omega = omega
        self._rho0 = 1 / (4 * np.pi)
        self._HNn = self._H * self._N * self._ns

        self.isNonAxi = True   # Potential is not axisymmetric
        self.hasC = True       # Potential has C implementation to speed up orbit integrations
        self.hasC_dxdv = True  # Potential has C implementation of second derivatives
Example #12
0
    def __init__(self,
                 amp=1.,
                 omegas=0.65,
                 A=-0.035,
                 alpha=-7.,
                 m=2,
                 gamma=math.pi / 4.,
                 p=None,
                 tform=None,
                 tsteady=None,
                 ro=None,
                 vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a logarithmic spiral potential

        INPUT:

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

           gamma - angle between sun-GC line and the line connecting the peak of the spiral pattern at the Solar radius (in rad; default=45 degree; or can be Quantity)
        
           A - amplitude (alpha*potential-amplitude; default=0.035; can be Quantity

           omegas= - pattern speed (default=0.65; can be Quantity)

           m= number of arms
           
           Either provide:

              a) alpha=
               
              b) p= pitch angle (rad; can be Quantity)
              
           tform - start of spiral growth / spiral period (default: -Infinity)

           tsteady - time from tform at which the spiral is fully grown / spiral period (default: 2 periods)

        OUTPUT:

           (none)

        HISTORY:

           2011-03-27 - Started - Bovy (NYU)

        """
        planarPotential.__init__(self, amp=amp, ro=ro, vo=vo)
        if _APY_LOADED and isinstance(gamma, units.Quantity):
            gamma = gamma.to(units.rad).value
        if _APY_LOADED and isinstance(p, units.Quantity):
            p = p.to(units.rad).value
        if _APY_LOADED and isinstance(A, units.Quantity):
            A = A.to(units.km**2 / units.s**2).value / self._vo**2.
        if _APY_LOADED and isinstance(omegas, units.Quantity):
            omegas= omegas.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        self._omegas = omegas
        self._A = A
        self._m = m
        self._gamma = gamma
        if not p is None:
            self._alpha = self._m / math.tan(p)
        else:
            self._alpha = alpha
        self._ts = 2. * math.pi / self._omegas
        if not tform is None:
            self._tform = tform * self._ts
        else:
            self._tform = None
        if not tsteady is None:
            self._tsteady = self._tform + tsteady * self._ts
        else:
            if self._tform is None: self._tsteady = None
            else: self._tsteady = self._tform + 2. * self._ts
        self.hasC = True
Example #13
0
    def __init__(self,amp=1.,omegas=0.65,A=-0.035,
                 alpha=-7.,m=2,gamma=math.pi/4.,p=None,
                 tform=None,tsteady=None,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a logarithmic spiral potential

        INPUT:

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

           gamma - angle between sun-GC line and the line connecting the peak of the spiral pattern at the Solar radius (in rad; default=45 degree; or can be Quantity)
        
           A - amplitude (alpha*potential-amplitude; default=0.035; can be Quantity

           omegas= - pattern speed (default=0.65; can be Quantity)

           m= number of arms
           
           Either provide:

              a) alpha=
               
              b) p= pitch angle (rad; can be Quantity)
              
           tform - start of spiral growth / spiral period (default: -Infinity)

           tsteady - time from tform at which the spiral is fully grown / spiral period (default: 2 periods)

        OUTPUT:

           (none)

        HISTORY:

           2011-03-27 - Started - Bovy (NYU)

        """
        planarPotential.__init__(self,amp=amp,ro=ro,vo=vo)
        if _APY_LOADED and isinstance(gamma,units.Quantity):
            gamma= gamma.to(units.rad).value
        if _APY_LOADED and isinstance(p,units.Quantity):
            p= p.to(units.rad).value
        if _APY_LOADED and isinstance(A,units.Quantity):
            A= A.to(units.km**2/units.s**2).value/self._vo**2.
        if _APY_LOADED and isinstance(omegas,units.Quantity):
            omegas= omegas.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        self._omegas= omegas
        self._A= A
        self._m= m
        self._gamma= gamma
        if not p is None:
            self._alpha= self._m/math.tan(p)
        else:
            self._alpha= alpha
        self._ts= 2.*math.pi/self._omegas
        if not tform is None:
            self._tform= tform*self._ts
        else:
            self._tform= None
        if not tsteady is None:
            self._tsteady= self._tform+tsteady*self._ts
        else:
            if self._tform is None: self._tsteady= None
            else: self._tsteady= self._tform+2.*self._ts
        self.hasC= True
Example #14
0
    def __init__(self,amp=105/96*3.3*10**10*units.Msun,a=1.,n=2,b=0.35,c=0.2375,omegab=0.001,
                 pa=0.,normalize=False,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a triaxial two-power-density potential
        
        INPUT:
        
           amp - amplitude to be applied to the potential (default: 1); can be a Quantity with units of mass or Gxmass
        
           a - scale radius (can be Quantity)
        
           n - power of Ferrers density (n > 0)
        
           b - y-to-x axis ratio of the density
        
           c - z-to-x axis ratio of the density

           omegab - rotation speed of the bar (can be Quantity)
        
           pa= (None) If set, the position angle of the x axis (rad or Quantity)
        
           normalize - if True, normalize such that vc(1.,0.)=1., or, if given as a number, such that the force is this fraction of the force necessary to make vc(1.,0.)=1.
        
           ro=, vo= distance and velocity scales for translation into internal units (default from configuration file)
        
        OUTPUT:
        
           (none)
        
        HISTORY:
        
           2016-06-30 - Started - Semyeong Oh
        
        """
        Potential.__init__(self,amp=amp,ro=ro,vo=vo,amp_units='mass')
        if _APY_LOADED and isinstance(a,units.Quantity):
            a= a.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(omegab,units.Quantity):
            omegab= omegab.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        if _APY_LOADED and isinstance(pa,units.Quantity):
            pa= pa.to(units.rad).value
        self.a= a
        self._scale= self.a
        if n <= 0:
            raise IOError('FerrersPotential requires n > 0')
        self.n= n
        self._b= b
        self._c= c
        self._omegab= omegab
        self._a2= self.a*a
        self._b2= self._b*b
        self._c2= self._c*c
        self._force_hash= None
        self._pa = pa
        if normalize or \
                (isinstance(normalize,(int,float)) \
                     and not isinstance(normalize,bool)): #pragma: no cover
            self.normalize(normalize)
        if np.fabs(self._b-1.) > 10.**-10.:
            self.isNonAxi= True
        return None
Example #15
0
    def __init__(self,
                 amp=1.,
                 a=1.,
                 n=2,
                 b=0.35,
                 c=0.2375,
                 omegab=0.,
                 pa=0.,
                 normalize=False,
                 ro=None,
                 vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a Ferrers potential

        INPUT:

           amp - total mass of the ellipsoid determines the amplitude of the potential; can be a Quantity with units of mass or Gxmass

           a - scale radius (can be Quantity)

           n - power of Ferrers density (n > 0)

           b - y-to-x axis ratio of the density

           c - z-to-x axis ratio of the density

           omegab - rotation speed of the ellipsoid (can be Quantity)

           pa= (None) If set, the position angle of the x axis (rad or Quantity)

           normalize - if True, normalize such that vc(1.,0.)=1., or, if given as a number, such that the force is this fraction of the force necessary to make vc(1.,0.)=1.

           ro=, vo= distance and velocity scales for translation into internal units (default from configuration file)

        OUTPUT:

           (none)

        """
        Potential.__init__(self, amp=amp, ro=ro, vo=vo, amp_units='mass')
        if _APY_LOADED and isinstance(a, units.Quantity):
            a = a.to(units.kpc).value / self._ro
        if _APY_LOADED and isinstance(omegab, units.Quantity):
            omegab= omegab.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        if _APY_LOADED and isinstance(pa, units.Quantity):
            pa = pa.to(units.rad).value
        self.a = a
        self._scale = self.a
        if n <= 0:
            raise ValueError('FerrersPotential requires n > 0')
        self.n = n
        self._b = b
        self._c = c
        self._omegab = omegab
        self._a2 = self.a**2
        self._b2 = self._b**2.
        self._c2 = self._c**2.
        self._force_hash = None
        self._pa = pa
        self._rhoc_M = gamma(n + 2.5) / gamma(n +
                                              1) / np.pi**1.5 / a**3 / b / c
        if normalize or \
                (isinstance(normalize,(int,float)) \
                     and not isinstance(normalize,bool)): #pragma: no cover
            self.normalize(normalize)
        if np.fabs(self._b - 1.) > 10.**-10.:
            self.isNonAxi = True
        return None
Example #16
0
    def __init__(self,amp=1.,a=1.,n=2,b=0.35,c=0.2375,omegab=0.,
                 pa=0.,normalize=False,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a Ferrers potential

        INPUT:

           amp - total mass of the ellipsoid determines the amplitude of the potential; can be a Quantity with units of mass or Gxmass

           a - scale radius (can be Quantity)

           n - power of Ferrers density (n > 0)

           b - y-to-x axis ratio of the density

           c - z-to-x axis ratio of the density

           omegab - rotation speed of the ellipsoid (can be Quantity)

           pa= (None) If set, the position angle of the x axis (rad or Quantity)

           normalize - if True, normalize such that vc(1.,0.)=1., or, if given as a number, such that the force is this fraction of the force necessary to make vc(1.,0.)=1.

           ro=, vo= distance and velocity scales for translation into internal units (default from configuration file)

        OUTPUT:

           (none)

        """
        Potential.__init__(self,amp=amp,ro=ro,vo=vo,amp_units='mass')
        if _APY_LOADED and isinstance(a,units.Quantity):
            a= a.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(omegab,units.Quantity):
            omegab= omegab.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        if _APY_LOADED and isinstance(pa,units.Quantity):
            pa= pa.to(units.rad).value
        self.a= a
        self._scale= self.a
        if n <= 0:
            raise ValueError('FerrersPotential requires n > 0')
        self.n= n
        self._b= b
        self._c= c
        self._omegab= omegab
        self._a2= self.a**2
        self._b2= self._b**2.
        self._c2= self._c**2.
        self._force_hash= None
        self._pa = pa
        self._rhoc_M = gamma(n+2.5)/gamma(n+1) / np.pi**1.5/a**3/b/c
        if normalize or \
                (isinstance(normalize,(int,float)) \
                     and not isinstance(normalize,bool)): #pragma: no cover
            self.normalize(normalize)
        if np.fabs(self._b-1.) > 10.**-10.:
            self.isNonAxi= True
        return None
Example #17
0
    def __init__(self,amp=1.,omegab=None,rb=None,chi=0.8,
                 rolr=0.9,barphi=25.*_degtorad,
                 tform=-4.,tsteady=None,beta=0.,
                 alpha=0.01,Af=None,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a Dehnen bar potential

        INPUT:

           amp - amplitude to be applied to the potential (default:
           1., see alpha or Ab below)

           barphi - angle between sun-GC line and the bar's major axis
           (in rad; default=25 degree; or can be Quantity))

           tform - start of bar growth / bar period (default: -4)

           tsteady - time from tform at which the bar is fully grown / bar period (default: -tform/2, st the perturbation is fully grown at tform/2)

           Either provide:

              a) rolr - radius of the Outer Lindblad Resonance for a
                 circular orbit (can be Quantity)
              
                 chi - fraction R_bar / R_CR (corotation radius of bar)

                 alpha - relative bar strength (default: 0.01)

                 beta - power law index of rotation curve (to
                 calculate OLR, etc.)
               
              b) omegab - rotation speed of the bar (can be Quantity)
              
                 rb - bar radius (can be Quantity)
                 
                 Af - bar strength (can be Quantity)
              
        OUTPUT:

           (none)

        HISTORY:

           2010-11-24 - Started - Bovy (NYU)

           2017-06-23 - Converted to 3D following Monari et al. (2016) - Bovy (UofT/CCA)

        """
        Potential.__init__(self,amp=amp,ro=ro,vo=vo)
        if _APY_LOADED and isinstance(barphi,units.Quantity):
            barphi= barphi.to(units.rad).value
        if _APY_LOADED and isinstance(rolr,units.Quantity):
            rolr= rolr.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(rb,units.Quantity):
            rb= rb.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(omegab,units.Quantity):
            omegab= omegab.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        if _APY_LOADED and isinstance(Af,units.Quantity):
            Af= Af.to(units.km**2/units.s**2).value/self._vo**2.
        self.hasC= True
        self.hasC_dxdv= True
        self.isNonAxi= True
        self._barphi= barphi
        if omegab is None:
            self._rolr= rolr
            self._chi= chi
            self._beta= beta
            #Calculate omegab and rb
            self._omegab= 1./((self._rolr**(1.-self._beta))/(1.+numpy.sqrt((1.+self._beta)/2.)))
            self._rb= self._chi*self._omegab**(1./(self._beta-1.))
            self._alpha= alpha
            self._af= self._alpha/3./self._rb**3.
        else:
            self._omegab= omegab
            self._rb= rb
            self._af= Af
        self._tb= 2.*numpy.pi/self._omegab
        self._tform= tform*self._tb
        if tsteady is None:
            self._tsteady= self._tform/2.
        else:
            self._tsteady= self._tform+tsteady*self._tb
Example #18
0
    def __init__(self,
                 amp=1,
                 ro=None,
                 vo=None,
                 amp_units='density',
                 N=2,
                 alpha=0.2,
                 r_ref=1,
                 phi_ref=0,
                 Rs=0.3,
                 H=0.125,
                 omega=0,
                 Cs=[1]):
        """
        NAME:       
            __init__
        PURPOSE:
            initialize a spiral arms potential
        INPUT:
            :amp: amplitude to be applied to the potential (default: 1); 
                        can be a Quantity with units of density. (:math:`amp = 4 \\pi G \\rho_0`)
            :ro: distance scales for translation into internal units (default from configuration file)
            :vo: velocity scales for translation into internal units (default from configuration file)
            :N: number of spiral arms
            :alpha: pitch angle of the logarithmic spiral arms in radians (can be Quantity)
            :r_ref: fiducial radius where :math:`\\rho = \\rho_0` (:math:`r_0` in the paper by Cox and Gomez) (can be Quantity)
            :phi_ref: reference angle (:math:`\\phi_p(r_0)` in the paper by Cox and Gomez) (can be Quantity)
            :Rs: radial scale length of the drop-off in density amplitude of the arms (can be Quantity)
            :H: scale height of the stellar arm perturbation (can be Quantity)
            :Cs: list of constants multiplying the :math:`\cos(n \\gamma)` terms
            :omega: rotational pattern speed of the spiral arms (can be Quantity)
        OUTPUT:
            (none)
        HISTORY:
            Started - 2017-05-12  Jack Hong (UBC)

            Completed - 2017-07-04 Jack Hong (UBC)
        """

        Potential.__init__(self, amp=amp, ro=ro, vo=vo, amp_units=amp_units)
        if _APY_LOADED:
            if isinstance(alpha, units.Quantity):
                alpha = alpha.to(units.rad).value
            if isinstance(r_ref, units.Quantity):
                r_ref = r_ref.to(units.kpc).value / self._ro
            if isinstance(phi_ref, units.Quantity):
                phi_ref = phi_ref.to(units.rad).value
            if isinstance(Rs, units.Quantity):
                Rs = Rs.to(units.kpc).value / self._ro
            if isinstance(H, units.Quantity):
                H = H.to(units.kpc).value / self._ro
            if isinstance(omega, units.Quantity):
                omega = omega.to(units.km / units.s / units.kpc).value \
                        / bovy_conversion.freq_in_kmskpc(self._vo, self._ro)

        self._N = -N  # trick to flip to left handed coordinate system; flips sign for phi and phi_ref, but also alpha.
        self._alpha = -alpha  # we don't want sign for alpha to change, so flip alpha. (see eqn. 3 in the paper)
        self._sin_alpha = np.sin(-alpha)
        self._tan_alpha = np.tan(-alpha)
        self._r_ref = r_ref
        self._phi_ref = phi_ref
        self._Rs = Rs
        self._H = H
        self._Cs = np.array(Cs)
        self._ns = np.arange(1, len(Cs) + 1)
        self._omega = omega
        self._rho0 = 1 / (4 * np.pi)
        self._HNn = self._H * self._N * self._ns

        self.isNonAxi = True  # Potential is not axisymmetric
        self.hasC = True  # Potential has C implementation to speed up orbit integrations
        self.hasC_dxdv = True  # Potential has C implementation of second derivatives
Example #19
0
    def __init__(self,
                 amp=1.,
                 omegas=0.65,
                 A=-0.035,
                 alpha=-7.,
                 m=2,
                 gamma=math.pi / 4.,
                 p=None,
                 sigma=1.,
                 to=0.,
                 ro=None,
                 vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a transient logarithmic spiral potential localized 
           around to

        INPUT:

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

           gamma - angle between sun-GC line and the line connecting the peak of the spiral pattern at the Solar radius (in rad; default=45 degree; can be Quantity)
        
           A - amplitude (alpha*potential-amplitude; default=0.035; can be Quantity)

           omegas= - pattern speed (default=0.65; can be Quantity)

           m= number of arms
           
           to= time at which the spiral peaks (can be Quantity)

           sigma= "spiral duration" (sigma in Gaussian amplitude; can be Quantity)
           
           Either provide:

              a) alpha=
               
              b) p= pitch angle (rad; can be Quantity)
              
        OUTPUT:

           (none)

        HISTORY:

           2011-03-27 - Started - Bovy (NYU)

        """
        planarPotential.__init__(self, amp=amp, ro=ro, vo=vo)
        if _APY_LOADED and isinstance(gamma, units.Quantity):
            gamma = gamma.to(units.rad).value
        if _APY_LOADED and isinstance(p, units.Quantity):
            p = p.to(units.rad).value
        if _APY_LOADED and isinstance(A, units.Quantity):
            A = A.to(units.km**2 / units.s**2).value / self._vo**2.
        if _APY_LOADED and isinstance(omegas, units.Quantity):
            omegas= omegas.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        if _APY_LOADED and isinstance(to, units.Quantity):
            to= to.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        if _APY_LOADED and isinstance(sigma, units.Quantity):
            sigma= sigma.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        self._omegas = omegas
        self._A = A
        self._m = m
        self._gamma = gamma
        self._to = to
        self._sigma2 = sigma**2.
        if not p is None:
            self._alpha = self._m / math.tan(p)
        else:
            self._alpha = alpha
        self.hasC = True