示例#1
0
def test_nemo_LogarithmicHaloPotential():
    lp = potential.LogarithmicHaloPotential(normalize=1.)
    tmax = 2.
    vo, ro = 210., 8.5
    o = Orbit([1., 0.1, 1.1, 0.3, 0.1, 0.4], ro=ro, vo=vo)
    run_orbitIntegration_comparison(o, lp, tmax, vo, ro, tol=0.03)
    return None
示例#2
0
def test_ChandrasekharDynamicalFrictionForce_constLambda():
    # Test that the ChandrasekharDynamicalFrictionForce with constant Lambda
    # agrees with analytical solutions for circular orbits:
    # assuming that a mass remains on a circular orbit in an isothermal halo
    # with velocity dispersion sigma and for constant Lambda:
    # r_final^2 - r_initial^2 = -0.604 ln(Lambda) GM/sigma t
    # (e.g., B&T08, p. 648)
    from galpy.util import conversion
    from galpy.orbit import Orbit
    ro, vo = 8., 220.
    # Parameters
    GMs = 10.**9. / conversion.mass_in_msol(vo, ro)
    const_lnLambda = 7.
    r_init = 2.
    dt = 2. / conversion.time_in_Gyr(vo, ro)
    # Compute
    lp = potential.LogarithmicHaloPotential(normalize=1., q=1.)
    cdfc= potential.ChandrasekharDynamicalFrictionForce(\
        GMs=GMs,const_lnLambda=const_lnLambda,
        dens=lp) # don't provide sigmar, so it gets computed using galpy.df.jeans
    o = Orbit([r_init, 0., 1., 0., 0., 0.])
    ts = numpy.linspace(0., dt, 1001)
    o.integrate(ts, [lp, cdfc], method='odeint')
    r_pred = numpy.sqrt(o.r()**2. -
                        0.604 * const_lnLambda * GMs * numpy.sqrt(2.) * dt)
    assert numpy.fabs(
        r_pred - o.r(ts[-1])
    ) < 0.01, 'ChandrasekharDynamicalFrictionForce with constant lnLambda for circular orbits does not agree with analytical prediction'
    return None
示例#3
0
def test_dynamfric_c_minr_warning():
    from galpy.orbit import Orbit
    times = numpy.linspace(0., 100., 1001)  #~3 Gyr at the Solar circle
    integrator = 'dop853_c'
    pot = potential.LogarithmicHaloPotential(normalize=1)
    # Setup orbit
    o = Orbit()
    # Setup dynamical friction object, with minr = 1, should thus reach it
    cdf= potential.ChandrasekharDynamicalFrictionForce(\
        GMs=0.5553870441722593,rhm=5./8.,dens=pot,minr=1.)
    # Integrate, should raise warning
    with pytest.warns(None) as record:
        o.integrate(times, pot + cdf, method=integrator)
    raisedWarning = False
    for rec in record:
        # check that the message matches
        raisedWarning += (
            str(rec.message.args[0]) ==
            "Orbit integration with ChandrasekharDynamicalFrictionForce entered domain where r < minr and ChandrasekharDynamicalFrictionForce is turned off; initialize ChandrasekharDynamicalFrictionForce with a smaller minr to avoid this if you wish (but note that you want to turn it off close to the center for an object that sinks all the way to r=0, to avoid numerical instabilities)"
        )
    assert raisedWarning, "Integrating an orbit that goes to r < minr with dynamical friction should have raised a warning, but didn't"
    return None
示例#4
0
def test_dynamfric_c_minr():
    from galpy.orbit import Orbit
    times = numpy.linspace(0., -100., 1001)  #~3 Gyr at the Solar circle
    integrator = 'dop853_c'
    pot = potential.LogarithmicHaloPotential(normalize=1)
    # Setup orbit, ~ LMC
    o = Orbit([
        5.13200034, 1.08033051, 0.23323391, -3.48068653, 0.94950884,
        -1.54626091
    ])
    # Setup dynamical friction object, with minr = 130 st always 0 for this orbit
    cdf= potential.ChandrasekharDynamicalFrictionForce(\
        GMs=0.5553870441722593,rhm=5./8.,dens=pot,minr=130./8.,maxr=500./8)
    # Integrate in C with dynamical friction
    o.integrate(times, pot + cdf, method=integrator)
    # Integrate in C without dynamical friction
    op = o()
    op.integrate(times, pot, method=integrator)
    # Compare r (most important)
    assert numpy.amax(numpy.fabs(o.r(times)-op.r(times))) < 10**-8., \
            'Dynamical friction in C does not properly use minr'
    return None
def predict_gd1obs(pot_params,c,b=1.,pa=0.,
                   sigv=0.4,td=10.,
                   phi1=0.,phi2=-1.,dist=10.2,
                   pmphi1=-8.5,pmphi2=-2.05,vlos=-285.,
                   ro=_REFR0,vo=_REFV0,
                   isob=None,nTrackChunks=8,multi=None,
                   useTM=False,
                   logpot=False,
                   verbose=True):
    """
    NAME:
       predict_gd1obs
    PURPOSE:
       Function that generates the location and velocity of the GD-1 stream (similar to predict_pal5obs), its width, and its length for a given potential and progenitor phase-space position
    INPUT:
       pot_params- array with the parameters of a potential model (see MWPotential2014Likelihood.setup_potential; only the basic parameters of the disk and halo are used, flattening is specified separately)
       c- halo flattening
       b= (1.) halo-squashed
       pa= (0.) halo PA
       sigv= (0.365) velocity dispersion in km/s
       td= (10.) stream age in Gyr
       phi1= (0.) Progenitor's phi1 position
       phi2= (-1.) Progenitor's phi2 position
       dist= (10.2) progenitor distance in kpc
       pmphi1= (-8.5) progenitor proper motion in phi1 in mas/yr
       pmphi2= (-2.) progenitor proper motion in phi2 in mas/yr
       vlos= (-250.) progenitor line-of-sight velocity in km/s
       ro= (project default) distance to the GC in kpc
       vo= (project default) circular velocity at R0 in km/s
       nTrackChunks= (8) nTrackChunks input to streamdf
       multi= (None) multi input to streamdf
       logpot= (False) if True, use a logarithmic potential instead
       isob= (None) if given, b parameter of actionAngleIsochroneApprox
       useTM= (True) use the TorusMapper to compute the track
       verbose= (True) print messages
    OUTPUT:
    HISTORY:
       2016-08-12 - Written - Bovy (UofT)
    """
    # Convert progenitor's phase-space position to l,b,...
    prog= Orbit(phi12_to_lb_6d(phi1,phi2,dist,pmphi1,pmphi2,vlos),
                lb=True,ro=ro,vo=vo,solarmotion=[-11.1,24.,7.25])
    if logpot:
        pot= potential.LogarithmicHaloPotential(normalize=1.,q=c)
    else:
        pot= MWPotential2014Likelihood.setup_potential(pot_params,c,
                                                       False,False,ro,vo,
                                                       b=b,pa=pa)
    success= True
    this_useTM= useTM
    try:
        sdf= setup_sdf(pot,prog,sigv,td,ro,vo,multi=multi,
                       isob=isob,nTrackChunks=nTrackChunks,
                       verbose=verbose,useTM=useTM,logpot=logpot)
    except:
        # Catches errors and time-outs
        success= False
    # Check for calc. issues
    if not success:
        return (numpy.zeros((1001,6))-1000000.,False)
        # Try again with TM
        this_useTM= True
        this_nTrackChunks= 21 # might as well
        sdf= setup_sdf(pot,prog,sigv,td,ro,vo,multi=multi,
                       isob=isob,nTrackChunks=this_nTrackChunks,
                       verbose=verbose,useTM=this_useTM,logpot=logpot)
    else:
        success= not this_useTM
    # Compute the track and convert it to phi12
    track_phi= convert_track_lb_to_phi12(sdf._interpolatedObsTrackLB)
    return (track_phi,success)
示例#6
0
tsteady = 3 * u.Gyr
N = 2  # number of arms
alpha = 10 * u.deg  # pitch angle, p in the paper
H = 0.18 * u.kpc  # arbitrary, not specified in the paper
Rs = 0.38

sp = potential.SpiralArmsPotential(amp=1,
                                   N=N,
                                   alpha=alpha,
                                   H=H,
                                   Rs=Rs,
                                   phi_ref=0)
phi_ref = -minimize(lambda phi: sp.dens(1, 0, phi[0]), x0=[0]).x[0]

dfc = dehnendf(beta=0, profileParams=(1 / 3, 1, 0.01), correct=True, niter=20)
lp = potential.LogarithmicHaloPotential(amp=1, normalize=1)

# 30% density perturbation
sp = potential.SpiralArmsPotential(amp=1,
                                   N=N,
                                   alpha=alpha,
                                   H=H,
                                   Rs=Rs,
                                   phi_ref=phi_ref)
amp30 = abs(lp.dens(R=1, z=0, phi=0) / sp.dens(R=1, z=0, phi=0) * 0.3)

n = 51

omegas = np.linspace(0, 2, 101)
oortA_array = np.empty(len(omegas))
oortB_array = np.empty(len(omegas))
示例#7
0
def predict_gd1obs(
    pot_params: Sequence[float],
    c: float,
    b: float = 1.0,
    pa: float = 0.0,
    sigv: float = 0.4,
    td: float = 10.0,
    dist: float = 10.2,
    pmphi1: float = -8.5,
    pmphi2: float = -2.05,
    phi1: float = 0.0,
    phi2: float = -1.0,
    vlos: float = -285.0,
    ro: float = REFR0,
    vo: float = REFV0,
    isob: Optional[bool] = None,
    nTrackChunks: int = 8,
    multi: Optional[Any] = None,
    useTM: bool = False,
    logpot: bool = False,
    verbose: bool = True,
):
    """Predict GD1-observed.

    Function that generates the location and velocity of the GD-1 stream,
    its width, and its length for a given potential
    and progenitor phase-space position.

    Parameters
    ----------
    pot_params
        array with the parameters of a potential model
        (see mw_pot.setup_potential;
         only the basic parameters of the disk and halo are used,
         flattening is specified separately)
    c
        halo flattening
    b
        (1.) halo-squashed
    pa
        (0.) halo PA
    sigv
        (0.365) velocity dispersion in km/s
    td
        (10.) stream age in Gyr
    phi1
        (0.) Progenitor's phi1 position
    phi2
        (-1.) Progenitor's phi2 position
    dist
        (10.2) progenitor distance in kpc
    pmphi1
        (-8.5) progenitor proper motion in phi1 in mas/yr
    pmphi2
        (-2.) progenitor proper motion in phi2 in mas/yr
    vlos
        (-250.) progenitor line-of-sight velocity in km/s
    ro
        (project default) distance to the GC in kpc
    vo
        (project default) circular velocity at R0 in km/s
    nTrackChunks
        (8) nTrackChunks input to streamdf
    multi
        (None) multi input to streamdf
    logpot
        (False) if True, use a logarithmic potential instead
    isob
        (None) if given, b parameter of actionAngleIsochroneApprox
    useTM
        (True) use the TorusMapper to compute the track
    verbose
        (True) print messages

    Notes
    -----
    2016-08-12 - Written - Bovy (UofT)

    """
    # Convert progenitor's phase-space position to l,b,...
    prog = Orbit(
        phi12_to_lb_6d(phi1, phi2, dist, pmphi1, pmphi2, vlos),
        lb=True,
        ro=ro,
        vo=vo,
        solarmotion=[-11.1, 24.0, 7.25],
    )
    if logpot:
        pot = potential.LogarithmicHaloPotential(normalize=1.0, q=c)
    else:
        pot = mw_pot.setup_potential(pot_params, c, False, False, ro, vo, b=b, pa=pa)
    success: bool = True
    this_useTM = useTM

    try:
        sdf = setup_sdf(
            pot,
            prog,
            sigv,
            td,
            ro,
            vo,
            multi=multi,
            isob=isob,
            nTrackChunks=nTrackChunks,
            verbose=verbose,
            useTM=useTM,
            logpot=logpot,
        )
    except:
        # Catches errors and time-outs
        success: bool = False

    # Check for calc. issues
    if not success:
        return (np.zeros((1001, 6)) - 1000000.0, False)
        # Try again with TM
        this_useTM = True
        this_nTrackChunks = 21  # might as well
        sdf = setup_sdf(
            pot,
            prog,
            sigv,
            td,
            ro,
            vo,
            multi=multi,
            isob=isob,
            nTrackChunks=this_nTrackChunks,
            verbose=verbose,
            useTM=this_useTM,
            logpot=logpot,
        )
    else:
        success: bool = not this_useTM

    # Compute the track and convert it to phi12
    track_phi = convert_track_lb_to_phi12(sdf._interpolatedObsTrackLB)

    return track_phi, success
示例#8
0
def test_dynamfric_c():
    import copy
    from galpy.orbit import Orbit
    from galpy.potential.Potential import _check_c
    from galpy.potential.mwpotentials import McMillan17
    #Basic parameters for the test
    times = numpy.linspace(0., -100., 1001)  #~3 Gyr at the Solar circle
    integrator = 'dop853_c'
    py_integrator = 'dop853'
    #Define all of the potentials (by hand, because need reasonable setup)
    MWPotential3021 = copy.deepcopy(potential.MWPotential2014)
    MWPotential3021[2] *= 1.5  # Increase mass by 50%
    pots= [potential.LogarithmicHaloPotential(normalize=1),
           potential.LogarithmicHaloPotential(normalize=1.3,
                                              q=0.9,b=0.7), #nonaxi
           potential.NFWPotential(normalize=1.,a=1.5),
           potential.MiyamotoNagaiPotential(normalize=.02,a=10.,b=10.),
           potential.MiyamotoNagaiPotential(normalize=.6,a=0.,b=3.), # special case
           potential.PowerSphericalPotential(alpha=2.3,normalize=2.),
           potential.DehnenSphericalPotential(normalize=4.,alpha=1.2),
           potential.DehnenCoreSphericalPotential(normalize=4.),
           potential.HernquistPotential(normalize=1.,a=3.5),
           potential.JaffePotential(normalize=1.,a=20.5),
           potential.DoubleExponentialDiskPotential(normalize=0.2,
                                                    hr=3.,hz=0.6),
           potential.FlattenedPowerPotential(normalize=3.),
           potential.FlattenedPowerPotential(normalize=3.,alpha=0), #special case
           potential.IsochronePotential(normalize=2.),
           potential.PowerSphericalPotentialwCutoff(normalize=0.3,rc=10.),
           potential.PlummerPotential(normalize=.6,b=3.),
           potential.PseudoIsothermalPotential(normalize=.1,a=3.),
           potential.BurkertPotential(normalize=.2,a=2.5),
           potential.TriaxialHernquistPotential(normalize=1.,a=3.5,
                                                b=0.8,c=0.9),
           potential.TriaxialNFWPotential(normalize=1.,a=1.5,b=0.8,c=0.9),
           potential.TriaxialJaffePotential(normalize=1.,a=20.5,b=0.8,c=1.4),
           potential.PerfectEllipsoidPotential(normalize=.3,a=3.,b=0.7,c=1.5),
           potential.PerfectEllipsoidPotential(normalize=.3,a=3.,b=0.7,c=1.5,
                                               pa=3.,zvec=[0.,1.,0.]), #rotated
           potential.HomogeneousSpherePotential(normalize=0.02,R=82./8), # make sure to go to dens = 0 part,
           potential.interpSphericalPotential(\
                    rforce=potential.HomogeneousSpherePotential(normalize=0.02,
                                                                R=82./8.),
                    rgrid=numpy.linspace(0.,82./8.,201)),
           potential.TriaxialGaussianPotential(normalize=.03,sigma=4.,b=0.8,c=1.5,pa=3.,zvec=[1.,0.,0.]),
           potential.SCFPotential(Acos=numpy.array([[[1.]]]), # same as Hernquist
                                  normalize=1.,a=3.5),
           potential.SCFPotential(Acos=numpy.array([[[1.,0.],[.3,0.]]]), # nonaxi
                                  Asin=numpy.array([[[0.,0.],[1e-1,0.]]]),
                                  normalize=1.,a=3.5),
           MWPotential3021,
           McMillan17 # SCF + DiskSCF
           ]
    #tolerances in log10
    tol = {}
    tol['default'] = -7.
    # Following are a little more difficult
    tol['DoubleExponentialDiskPotential'] = -4.5
    tol['TriaxialHernquistPotential'] = -6.
    tol['TriaxialNFWPotential'] = -6.
    tol['TriaxialJaffePotential'] = -6.
    tol['MWPotential3021'] = -6.
    tol['HomogeneousSpherePotential'] = -6.
    tol['interpSphericalPotential'] = -6.  # == HomogeneousSpherePotential
    tol['McMillan17'] = -6.
    for p in pots:
        if not _check_c(p, dens=True): continue  # dynamfric not in C!
        pname = type(p).__name__
        if pname == 'list':
            if isinstance(p[0],potential.PowerSphericalPotentialwCutoff) \
                    and len(p) > 1 \
                    and isinstance(p[1],potential.MiyamotoNagaiPotential) \
                    and len(p) > 2 \
                    and isinstance(p[2],potential.NFWPotential):
                pname = 'MWPotential3021'  # Must be!
            else:
                pname = 'McMillan17'
        #print(pname)
        if pname in list(tol.keys()): ttol = tol[pname]
        else: ttol = tol['default']
        # Setup orbit, ~ LMC
        o = Orbit([
            5.13200034, 1.08033051, 0.23323391, -3.48068653, 0.94950884,
            -1.54626091
        ])
        # Setup dynamical friction object
        if pname == 'McMillan17':
            cdf= potential.ChandrasekharDynamicalFrictionForce(\
                GMs=0.5553870441722593,rhm=5./8.,dens=p,maxr=500./8,nr=101)
            ttimes = numpy.linspace(0., -30.,
                                    1001)  #~1 Gyr at the Solar circle
        else:
            cdf= potential.ChandrasekharDynamicalFrictionForce(\
                GMs=0.5553870441722593,rhm=5./8.,dens=p,maxr=500./8,nr=201)
            ttimes = times
        # Integrate in C
        o.integrate(ttimes, p + cdf, method=integrator)
        # Integrate in Python
        op = o()
        op.integrate(ttimes, p + cdf, method=py_integrator)
        # Compare r (most important)
        assert numpy.amax(numpy.fabs(o.r(ttimes)-op.r(ttimes))) < 10**ttol, \
            'Dynamical friction in C does not agree with dynamical friction in Python for potential {}'.format(pname)
    return None