示例#1
0
def test_actionConservation():

    #_____initialize some KKSPot_____
    Delta = 1.0
    pot = KuzminKutuzovStaeckelPotential(ac=20., Delta=Delta, normalize=True)

    #_____initialize an orbit (twice)_____
    vxvv = [1., 0.1, 1.1, 0.01, 0.1]
    o = Orbit(vxvv=vxvv)

    #_____integrate the orbit with C_____
    ts = numpy.linspace(0, 101, 100)
    o.integrate(ts, pot, method='leapfrog_c')

    #_____Setup ActionAngle object and calculate actions (Staeckel approximation)_____
    aAS = actionAngleStaeckel(pot=pot, delta=Delta, c=True)
    jrs, lzs, jzs = aAS(o.R(ts), o.vR(ts), o.vT(ts), o.z(ts), o.vz(ts))

    assert numpy.all(numpy.fabs(jrs - jrs[0]) < 10.**-8.), \
        'Radial action is not conserved along orbit.'

    assert numpy.all(numpy.fabs(lzs - lzs[0]) < 10.**-8.), \
        'Angular momentum is not conserved along orbit.'

    assert numpy.all(numpy.fabs(jzs - jzs[0]) < 10.**-8.), \
        'Vertical action is not conserved along orbit.'

    return None
示例#2
0
def test_estimateDelta():

    #_____initialize some KKSPot_____
    Delta = 1.0
    pot = KuzminKutuzovStaeckelPotential(ac=20., Delta=Delta, normalize=True)

    #_____initialize an orbit (twice)_____
    vxvv = [1., 0.1, 1.1, 0.01, 0.1]
    o = Orbit(vxvv=vxvv)

    #_____integrate the orbit with C_____
    ts = numpy.linspace(0, 101, 100)
    o.integrate(ts, pot, method='leapfrog_c')

    #____estimate Focal length Delta_____
    #for each time step individually:
    deltas_estimate = numpy.zeros(len(ts))
    for ii in range(len(ts)):
        deltas_estimate[ii] = estimateDeltaStaeckel(pot, o.R(ts[ii]),
                                                    o.z(ts[ii]))

    assert numpy.all(numpy.fabs(deltas_estimate - Delta) < 10.**-8), \
            'Focal length Delta estimated along the orbit is not constant.'

    #for all time steps together:
    delta_estimate = estimateDeltaStaeckel(pot, o.R(ts), o.z(ts))

    assert numpy.fabs(delta_estimate - Delta) < 10.**-8, \
            'Focal length Delta estimated from the orbit is not the same as the input focal length.'

    return None
示例#3
0
def test_actionAngleTorus_Staeckel_actions():
    from galpy.potential import KuzminKutuzovStaeckelPotential
    from galpy.actionAngle import actionAngleTorus, \
        actionAngleStaeckel
    delta = 1.2
    kp = KuzminKutuzovStaeckelPotential(normalize=1., Delta=delta)
    aAS = actionAngleStaeckel(pot=kp, delta=delta, c=True)
    tol = -3.
    aAT = actionAngleTorus(pot=kp, tol=tol)
    jr, jphi, jz = 0.075, 1.1, 0.05
    angler = numpy.array([0.])
    anglephi = numpy.array([numpy.pi])
    anglez = numpy.array([numpy.pi / 2.])
    # Calculate position from aAT
    RvR = aAT(jr, jphi, jz, angler, anglephi, anglez).T
    # Calculate actions from aAI
    ji = aAS(*RvR)
    djr = numpy.fabs((ji[0] - jr) / jr)
    dlz = numpy.fabs((ji[1] - jphi) / jphi)
    djz = numpy.fabs((ji[2] - jz) / jz)
    assert djr < 10.**tol, 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Jr at %f%%' % (
        djr * 100.)
    assert dlz < 10.**tol, 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Jr at %f%%' % (
        dlz * 100.)
    assert djz < 10.**tol, 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Jr at %f%%' % (
        djz * 100.)
    return None
示例#4
0
def test_actionAngleTorus_Staeckel_freqsAngles():
    from galpy.potential import KuzminKutuzovStaeckelPotential
    from galpy.actionAngle import actionAngleTorus, \
        actionAngleStaeckel
    delta = 1.2
    kp = KuzminKutuzovStaeckelPotential(normalize=1., Delta=delta)
    aAS = actionAngleStaeckel(pot=kp, delta=delta, c=True)
    tol = -3.
    aAT = actionAngleTorus(pot=kp, tol=tol)
    jr, jphi, jz = 0.075, 1.1, 0.05
    angler = numpy.array([0.1]) + numpy.linspace(0., numpy.pi, 101)
    angler = angler % (2. * numpy.pi)
    anglephi = numpy.array([numpy.pi]) + numpy.linspace(0., numpy.pi, 101)
    anglephi = anglephi % (2. * numpy.pi)
    anglez = numpy.array([numpy.pi / 2.]) + numpy.linspace(0., numpy.pi, 101)
    anglez = anglez % (2. * numpy.pi)
    # Calculate position from aAT
    RvRom = aAT.xvFreqs(jr, jphi, jz, angler, anglephi, anglez)
    # Calculate actions, frequencies, and angles from aAI
    ws = aAS.actionsFreqsAngles(*RvRom[0].T)
    dOr = numpy.fabs((ws[3] - RvRom[1]))
    dOp = numpy.fabs((ws[4] - RvRom[2]))
    dOz = numpy.fabs((ws[5] - RvRom[3]))
    dar = numpy.fabs((ws[6] - angler))
    dap = numpy.fabs((ws[7] - anglephi))
    daz = numpy.fabs((ws[8] - anglez))
    dar[dar > numpy.pi] -= 2. * numpy.pi
    dar[dar < -numpy.pi] += 2. * numpy.pi
    dap[dap > numpy.pi] -= 2. * numpy.pi
    dap[dap < -numpy.pi] += 2. * numpy.pi
    daz[daz > numpy.pi] -= 2. * numpy.pi
    daz[daz < -numpy.pi] += 2. * numpy.pi
    assert numpy.all(
        dOr < 10.**tol
    ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Or at %f%%' % (
        numpy.nanmax(dOr) * 100.)
    assert numpy.all(
        dOp < 10.**tol
    ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Ophi at %f%%' % (
        numpy.nanmax(dOp) * 100.)
    assert numpy.all(
        dOz < 10.**tol
    ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Oz at %f%%' % (
        numpy.nanmax(dOz) * 100.)
    assert numpy.all(
        dar < 10.**tol
    ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for ar at %f' % (
        numpy.nanmax(dar))
    assert numpy.all(
        dap < 10.**tol
    ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for aphi at %f' % (
        numpy.nanmax(dap))
    assert numpy.all(
        daz < 10.**tol
    ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for az at %f' % (
        numpy.nanmax(daz))
    return None
示例#5
0
def test_orbitIntegrationC():

    #_____initialize some KKSPot_____
    Delta = 1.0
    pot = KuzminKutuzovStaeckelPotential(ac=20., Delta=Delta, normalize=True)

    #_____initialize an orbit (twice)_____
    vxvv = [1., 0.1, 1.1, 0., 0.1]
    o_P = Orbit(vxvv=vxvv)
    o_C = Orbit(vxvv=vxvv)

    #_____integrate the orbit with python and C_____
    ts = numpy.linspace(0, 100, 101)
    o_P.integrate(ts, pot, method='leapfrog')  #python
    o_C.integrate(ts, pot, method='leapfrog_c')  #C

    for ii in range(5):
        exp3 = -1.7
        if ii == 0:
            Python, CC, string, exp1, exp2 = o_P.R(ts), o_C.R(
                ts), 'R', -5., -10.
        elif ii == 1:
            Python, CC, string, exp1, exp2 = o_P.z(ts), o_C.z(
                ts), 'z', -3.25, -4.
        elif ii == 2:
            Python, CC, string, exp1, exp2 = o_P.vR(ts), o_C.vR(
                ts), 'vR', -3., -10.
        elif ii == 3:
            Python, CC, string, exp1, exp2, exp3 = o_P.vz(ts), o_C.vz(
                ts), 'vz', -3., -4., -1.3
        elif ii == 4:
            Python, CC, string, exp1, exp2 = o_P.vT(ts), o_C.vT(
                ts), 'vT', -5., -10.

        rel_diff = numpy.fabs((Python - CC) / CC) < 10.**exp1
        abs_diff = (numpy.fabs(Python - CC) < 10.**exp2) * (numpy.fabs(Python)
                                                            < 10.**exp3)
        assert numpy.all(rel_diff+abs_diff), \
            'Orbit integration for '+string+' coordinate different in ' + \
            'C and Python implementation.'

    return None
示例#6
0
def test_density():
    #test the density calculation of the KuzminKutuzovStaeckelPotential
    #using parameters from Batsleer & Dejonghe 1994, tab. 2

    #_____parameters_____
    #table 2 in Batsleer & Dejonghe
    ac_D = [
        25., 25., 25., 25., 25., 25., 40., 40., 40., 40., 40., 50., 50., 50.,
        50., 50., 50., 75., 75., 75., 75., 75., 75., 100., 100., 100., 100.,
        100., 100., 150., 150., 150., 150., 150., 150.
    ]
    ac_H = [
        1.005, 1.005, 1.01, 1.01, 1.02, 1.02, 1.005, 1.005, 1.01, 1.01, 1.02,
        1.005, 1.005, 1.01, 1.01, 1.02, 1.02, 1.005, 1.005, 1.01, 1.01, 1.02,
        1.02, 1.005, 1.005, 1.01, 1.01, 1.02, 1.02, 1.005, 1.005, 1.01, 1.01,
        1.02, 1.02
    ]
    k = [
        0.05, 0.08, 0.075, 0.11, 0.105, 0.11, 0.05, 0.08, 0.075, 0.11, 0.11,
        0.05, 0.07, 0.07, 0.125, 0.1, 0.125, 0.05, 0.065, 0.07, 0.125, 0.10,
        0.125, 0.05, 0.065, 0.07, 0.125, 0.10, 0.125, 0.05, 0.065, 0.075,
        0.125, 0.11, 0.125
    ]
    Delta = [
        0.99, 1.01, 0.96, 0.99, 0.86, 0.88, 1.00, 1.01, 0.96, 0.99, 0.89, 1.05,
        1.06, 1.00, 1.05, 0.91, 0.97, 0.98, 0.99, 0.94, 0.98, 0.85, 0.91, 1.06,
        1.07, 1.01, 1.06, 0.94, 0.97, 1.06, 1.07, 0.98, 1.06, 0.94, 0.97
    ]
    Mmin = [
        7.49, 6.17, 4.08, 3.70, 2.34, 2.36, 7.57, 6.16, 4.08, 2.64, 2.38, 8.05,
        6.94, 4.37, 3.70, 2.48, 2.50, 7.37, 6.66, 4.05, 3.46, 2.33, 2.36, 8.14,
        7.27, 4.42, 3.72, 2.56, 2.50, 8.14, 7.26, 4.17, 3.72, 2.51, 2.50
    ]
    Mmax = [
        7.18, 6.12, 3.99, 3.69, 2.37, 2.40, 7.27, 6.11, 3.99, 2.66, 2.42, 7.76,
        6.85, 4.26, 3.72, 2.51, 2.54, 7.07, 6.51, 3.95, 3.48, 2.36, 2.40, 7.85,
        7.15, 4.30, 3.75, 2.58, 2.54, 7.85, 7.07, 4.08, 3.75, 2.53, 2.53
    ]
    rhomin = [
        0.04, 0.05, 0.04, 0.04, 0.03, 0.03, 0.06, 0.06, 0.05, 0.04, 0.04, 0.07,
        0.08, 0.06, 0.07, 0.04, 0.05, 0.08, 0.09, 0.07, 0.09, 0.05, 0.06, 0.12,
        0.13, 0.09, 0.13, 0.07, 0.09, 0.16, 0.19, 0.12, 0.18, 0.10, 0.12
    ]
    rhomax = [
        0.03, 0.03, 0.02, 0.03, 0.02, 0.02, 0.04, 0.04, 0.03, 0.03, 0.02, 0.05,
        0.05, 0.04, 0.05, 0.03, 0.03, 0.05, 0.06, 0.04, 0.06, 0.03, 0.04, 0.07,
        0.08, 0.06, 0.08, 0.04, 0.05, 0.09, 0.10, 0.07, 0.10, 0.06, 0.07
    ]
    Sigmin = [
        58, 52, 52, 49, 39, 40, 58, 55, 51, 44, 40, 59, 54, 53, 49, 41, 42, 58,
        55, 51, 48, 39, 40, 59, 55, 53, 49, 42, 42, 59, 55, 52, 49, 42, 42
    ]
    Sigmax = [
        45, 41, 38, 37, 28, 28, 45, 32, 37, 32, 30, 46, 43, 40, 37, 30, 31, 45,
        43, 38, 36, 28, 29, 46, 43, 40, 38, 31, 31, 46, 44, 39, 38, 30, 31
    ]

    for ii in range(len(ac_D)):

        if ac_D[ii] == 40.:
            continue
            #because I believe that there are typos in tab. 2 by Batsleer & Dejonghe...

        for jj in range(2):

            #_____parameters depending on solar position____
            if jj == 0:
                Rsun = 7.5
                zsun = 0.004
                GM = Mmin[ii]  #units: G = 1, M in 10^11 solar masses
                rho = rhomin[ii]
                Sig = Sigmin[ii]
            elif jj == 1:
                Rsun = 8.5
                zsun = 0.02
                GM = Mmax[ii]  #units: G = 1, M in 10^11 solar masses
                rho = rhomax[ii]
                Sig = Sigmax[ii]
            outstr = 'ac_D='+str(ac_D[ii])+', ac_H='+str(ac_H[ii])+', k='+str(k[ii])+', Delta='+str(Delta[ii])+\
                     ', Mtot='+str(GM)+'*10^11Msun, Rsun='+str(Rsun)+'kpc, rho(Rsun,zsun)='+str(rho)+'Msun/pc^3, Sig(Rsun,z<1.1kpc)='+str(Sig)+'Msun/pc^2'

            #_____setup potential_____
            amp_D = GM * k[ii]
            V_D = KuzminKutuzovStaeckelPotential(amp=amp_D,
                                                 ac=ac_D[ii],
                                                 Delta=Delta[ii],
                                                 normalize=False)
            amp_H = GM * (1. - k[ii])
            V_H = KuzminKutuzovStaeckelPotential(amp=amp_H,
                                                 ac=ac_H[ii],
                                                 Delta=Delta[ii],
                                                 normalize=False)
            pot = [V_D, V_H]

            #_____local density_____
            rho_calc = evaluateDensities(
                pot, Rsun, zsun) * 100.  #units: [solar mass / pc^3]
            rho_calc = round(rho_calc, 2)

            #an error of 0.01 corresponds to the significant digit
            #given in the table, to which the density was rounded,
            #to be wrong by one.
            assert numpy.fabs(rho_calc - rho) <= 0.01+10.**-8, \
                'Calculated density %f for KuzminKutuzovStaeckelPotential ' % rho_calc + \
                'with model parameters:\n'+outstr+'\n'+ \
                'does not agree with value from tab. 2 '+ \
                'by Batsleer & Dejonghe (1994)'

            #_____surface density_____
            Sig_calc, err = scipy.integrate.quad(
                lambda z: (evaluateDensities(pot, Rsun, z / 1000.) * 100.
                           ),  #units: [solar mass / pc^3]
                0.,
                1100.)  #units: pc
            Sig_calc = round(2. * Sig_calc)

            #an error of 1 corresponds to the significant digit
            #given in the table, to which the surface density was rounded,
            #to be wrong by one.
            assert numpy.fabs(Sig_calc - Sig) <= 1., \
                'Calculated surface density %f for KuzminKutuzovStaeckelPotential ' % Sig_calc + \
                'with model parameters:\n'+outstr+'\n'+ \
                'does not agree with value from tab. 2 '+ \
                'by Batsleer & Dejonghe (1994)'

    return None
示例#7
0
def test_vcirc():
    #test the circular velocity of the KuzminKutuzovStaeckelPotential
    #using parameters from Batsleer & Dejonghe 1994, fig. 1-3
    #and their formula eq. (10)

    #_____model parameters______
    #surface ratios of disk and halo:
    ac_Ds = [50., 50., 50., 50., 50., 50., 40., 40., 40.]
    ac_Hs = [1.005, 1.005, 1.005, 1.01, 1.01, 1.01, 1.02, 1.02, 1.02]
    #disk contribution to total mass:
    ks = [0.05, 0.06, 0.07, 0.07, 0.1, 0.125, 0.1, 0.12, 0.125]
    #focal distance:
    Delta = 1.

    for ii in range(9):
        ac_D = ac_Ds[ii]
        ac_H = ac_Hs[ii]
        k = ks[ii]

        #_____setup potential_____
        #first try, not normalized:
        V_D = KuzminKutuzovStaeckelPotential(amp=k,
                                             ac=ac_D,
                                             Delta=Delta,
                                             normalize=False)
        V_H = KuzminKutuzovStaeckelPotential(amp=(1. - k),
                                             ac=ac_H,
                                             Delta=Delta,
                                             normalize=False)
        pot = [V_D, V_H]
        #normalization according to Batsleer & Dejonghe 1994:
        V00 = evaluatePotentials(pot, 0., 0.)
        #second try, normalized:
        V_D = KuzminKutuzovStaeckelPotential(amp=k / (-V00),
                                             ac=ac_D,
                                             Delta=Delta,
                                             normalize=False)
        V_H = KuzminKutuzovStaeckelPotential(amp=(1. - k) / (-V00),
                                             ac=ac_H,
                                             Delta=Delta,
                                             normalize=False)
        pot = [V_D, V_H]

        #_____calculate rotation curve_____
        Rs = numpy.linspace(0., 20., 100)
        z = 0.
        vcirc_calc = numpy.sqrt(-Rs * evaluateRforces(pot, Rs, z))

        #_____vcirc by Batsleer & Dejonghe eq. (10) (with proper Jacobian)_____
        def vc2w(R):
            g_D = Delta**2 / (1. - ac_D**2)
            a_D = g_D - Delta**2
            g_H = Delta**2 / (1. - ac_H**2)
            a_H = g_H - Delta**2
            l = R**2 - a_D
            q = a_H - a_D
            termD = numpy.sqrt(l) * (numpy.sqrt(l) + numpy.sqrt(-g_D))**2
            termH = numpy.sqrt(l - q) * (numpy.sqrt(l - q) +
                                         numpy.sqrt(-g_D - q))**2
            return R**2 * (k / termD + (1. - k) / termH)

        vcirc_formula = numpy.sqrt(vc2w(Rs) / (-V00))

        assert numpy.all(numpy.fabs(vcirc_calc - vcirc_formula) < 10**-8.), \
                'Calculated circular velocity for KuzminKutuzovStaeckelPotential '+ \
                'does not agree with eq. (10) (corrected by proper Jacobian) '+ \
                'by Batsleer & Dejonghe (1994)'

    return None