示例#1
0
def my_moments(potential, df, point):
    # create an action finder to transform from position+velocity to actions
    af = agama.ActionFinder(potential)

    # function to be integrated over [scaled] velocity
    def integrand(scaledv):
        # input is a Nx3 array of velocity values in polar coordinates (|v|, theta, phi)
        sintheta = numpy.sin(scaledv[:, 1])
        posvel   = numpy.column_stack(( \
            numpy.tile(point, len(scaledv)).reshape(-1,3), \
            scaledv[:,0] * sintheta * numpy.cos(scaledv[:,2]), \
            scaledv[:,0] * sintheta * numpy.sin(scaledv[:,2]), \
            scaledv[:,0] * numpy.cos(scaledv[:,1]) ))
        jacobian = scaledv[:,
                           0]**2 * sintheta  # jacobian of the above transformation
        actions = af(posvel)  # compute actions at the given points
        return df(
            actions
        ) * jacobian  # and return the values of DF times the jacobian

    # integration region: |v| from 0 to escape velocity, theta and phi are angles of spherical coords
    v_esc = (-2 * potential.potential(point))**0.5
    result, error, neval = agama.integrateNdim(integrand, [0, 0, 0],
                                               [v_esc, numpy.pi, 2 * numpy.pi],
                                               toler=1e-5)
    return result
示例#2
0
def main():
    pot = agama.Potential(type="Dehnen", mass=1, scaleRadius=1.)
    actf = agama.ActionFinder(pot)
    particles, masses = createHernquistModel(100000)
    actions = actf(particles)

    # do a parameter search to find best-fit distribution function describing these particles
    initparams = numpy.array([2.0, 4.0, 1.0, 1.0, 0.0])
    result = minimize(model_search_fnc,
                      initparams,
                      args=(actions, ),
                      method='Nelder-Mead',
                      options=dict(maxiter=1000, maxfev=1000, disp=True))

    # explore the parameter space around the best-fit values using the MCMC chain
    try:
        import matplotlib.pyplot as plt, emcee, corner
    except ImportError as ex:
        print ex, "\nYou need to install 'emcee' and 'corner' packages"
    print 'Starting MCMC'
    ndim = len(initparams)
    nwalkers = 16  # number of parallel walkers in the chain
    nsteps = 300  # number of steps in MCMC chain
    nburnin = 100  # number of initial steps to discard
    # initial coverage of parameter space - around the best-fit solution with a small dispersion
    initwalkers = [
        result.x + 0.01 * numpy.random.randn(ndim) for i in range(nwalkers)
    ]
    sampler = emcee.EnsembleSampler(nwalkers,
                                    ndim,
                                    model_search_emcee,
                                    args=(actions, ))
    sampler.run_mcmc(initwalkers, nsteps)

    # show the time evolution of parameters carried by the ensemble of walkers (time=number of MC steps)
    fig, axes = plt.subplots(ndim + 1, 1, sharex=True)
    for i in range(ndim):
        axes[i].plot(sampler.chain[:, :, i].T, color='k', alpha=0.5)
        axes[i].set_ylabel(labels[i])
    # last panel shows the evolution of log-likelihood for the ensemble of walkers
    axes[-1].plot(sampler.lnprobability.T, color='k', alpha=0.5)
    axes[-1].set_ylabel('log(L)')
    maxloglike = numpy.max(sampler.lnprobability)
    axes[-1].set_ylim(maxloglike - 3 * ndim, maxloglike)
    fig.tight_layout(h_pad=0.)
    plt.show()

    # show the posterior distribution of parameters
    samples = sampler.chain[:, nburnin:, :].reshape((-1, ndim))
    trueval = (1.56, 1.55, 5.29, 1.22, 1.56)  # believed to be best-fit values
    corner.corner(samples, \
        labels=labels, quantiles=[0.16, 0.5, 0.84], truths=trueval)
    plt.show()
    print "Acceptance fraction: ", numpy.mean(
        sampler.acceptance_fraction)  # should be in the range 0.2-0.5
    print "Autocorrelation time: ", sampler.acor  # should be considerably shorter than the total number of steps
示例#3
0
    def modelLikelihood(self, params):
        '''
        Compute the likelihood of model (df+potential specified by scaled params)
        against the data (array of Nx6 position/velocity coordinates of tracer particles).
        This is the function to be maximized; if parameters are outside the allowed range, it returns -infinity
        '''
        prior = self.model.prior(params)
        if prior == -numpy.inf:
            print "Out of range"
            return prior
        try:
            # Compute log-likelihood of DF with given params against an array of actions
            pot = self.model.createPotential(params)
            df = self.model.createDF(params)
            if phase_space_info_mode == 6:  # actions of tracer particles
                if self.particles.shape[
                        0] > 2000:  # create an action finder object for a faster evaluation
                    actions = agama.ActionFinder(pot)(self.particles)
                else:
                    actions = agama.actions(self.particles, pot)
                df_val = df(actions)  # values of DF for these actions
            else:  # have full phase space info for resampled input particles (missing components are filled in)
                af = agama.ActionFinder(pot)
                actions = af(
                    self.samples)  # actions of resampled tracer particles
                # compute values of DF for these actions, multiplied by sample weights
                df_val = df(actions) * self.weights
                # compute the weighted sum of likelihoods of all samples for a single particle,
                # replacing the improbable samples (with NaN as likelihood) with zeroes
                df_val = numpy.sum(numpy.nan_to_num(
                    df_val.reshape(-1, num_subsamples)),
                                   axis=1)

            loglike = numpy.sum(numpy.log(df_val))
            if numpy.isnan(loglike): loglike = -numpy.inf
            loglike += prior
            print "LogL=%.8g" % loglike
            return loglike
        except ValueError as err:
            print "Exception ", err
            return -numpy.inf
 def iterate(self):
     if len(self.components) == 0:
         raise TypeError("'components' is an empty list")
     # prepare ground: make sure the potential and the corresponding action finder are defined
     if self.potential is None:
         self.updatePotential()
     elif self.af is None:
         self.af = agama.ActionFinder(self.potential)
     # compute the density of all components
     for ic, component in enumerate(self.components):
         print("Computing density for component %i..." % ic)
         component.update(self.potential, self.af)
     # update the total potential and the corresponding action finder
     self.updatePotential()
 def updatePotential(self):
     print("Updating potential...")
     # sort out density and potential components into several groups
     densitySph = []
     densityCyl = []
     potentials = []
     for component in self.components:
         dens = component.getDensity()
         if dens is not None:
             if component.disklike: densityCyl.append(dens)
             else: densitySph.append(dens)
         else:
             potentials.append(component.getPotential())
     # create a single Multipole potential for all non-disk-like density components
     if len(densitySph) > 0:
         potentials.append(
             agama.Potential(type='Multipole',
                             density=agama.Density(*densitySph),
                             gridsizer=self.sizeradialsph,
                             rmin=self.rminsph,
                             rmax=self.rmaxsph,
                             lmax=self.lmaxangularsph,
                             mmax=0,
                             symmetry='a'))
     # create a single CylSpline potential representing all disk-like density components
     if len(densityCyl) > 0:
         potentials.append(
             agama.Potential(type='CylSpline',
                             density=agama.Density(*densityCyl),
                             gridsizer=self.sizeradialcyl,
                             rmin=self.rmincyl,
                             rmax=self.rmaxcyl,
                             gridsizez=self.sizeverticalcyl,
                             zmin=self.zmincyl,
                             zmax=self.zmaxcyl,
                             mmax=0,
                             symmetry='a'))
     # combine all potential components and reinitialize the action finder
     self.potential = agama.Potential(*potentials)
     print("Updating action finder...")
     self.af = agama.ActionFinder(self.potential)
示例#6
0
    diskPot = agama.Potential( \
        type="CylSpline", particles=(diskParticles[:,0:3], diskParticles[:,6]), \
        gridsizer=20, gridsizez=20, mmax=0, Rmin=0.2, Rmax=100, Zmin=0.05, Zmax=50)
    print("%f s to init %s potential for the disk; value at origin=%f (km/s)^2" % \
        ((time.clock()-tbegin), diskPot.name(), diskPot.potential(0,0,0)))

    # save the potentials into text files; on the next call may load them instead of re-computing
    diskPot.export("model_stars_final.pot")
    haloPot.export("model_dm_final.pot")

#3c. combine the two potentials into a single composite one
totalPot = agama.Potential(diskPot, haloPot)

#4. compute actions for disk particles
tbegin = time.clock()
actFinder = agama.ActionFinder(totalPot)
print("%f s to init action finder" % (time.clock() - tbegin))

tbegin = time.clock()
actions = actFinder(diskParticles[:, 0:6])
print("%f s to compute actions for %i particles" %
      (time.clock() - tbegin, diskParticles.shape[0]))

#5. write out data
Rz = numpy.vstack((numpy.sqrt(diskParticles[:, 0]**2 + diskParticles[:, 1]**2),
                   diskParticles[:, 2])).T
energy    = (totalPot.potential(diskParticles[:,0:3]) + \
    0.5 * numpy.sum(diskParticles[:,3:6]**2, axis=1) ).reshape(-1,1)
numpy.savetxt( "disk_actions.txt", numpy.hstack((Rz, actions, energy)), \
    header="R[Kpc]\tz[Kpc]\tJ_r[Kpc*km/s]\tJ_z[Kpc*km/s]\tJ_phi[Kpc*km/s]\tE[(km/s)^2]", \
    fmt="%.6g", delimiter="\t" )
示例#7
0
    R_z = np.array([[np.cos(theta[2]), -np.sin(theta[2]), 0],
                    [np.sin(theta[2]), np.cos(theta[2]), 0], [0, 0, 1]])
    R = np.dot(R_x, np.dot(R_y, R_z))

    # this is the real one
    # R = np.dot(R_z, np.dot( R_y, R_x ))
    return R


def euler_rotate(theta, vec):
    mat = euler_matrix(theta)
    return np.transpose(np.tensordot(mat, np.transpose(vec), axes=1))


potential = agama.Potential(file='fiducial_pot')
af = agama.ActionFinder(potential, interp=False)

# read in simulated positions and velocities
posfile = 'pos_' + sys.argv[1] + '.npy'
velfile = 'vel_' + sys.argv[1] + '.npy'
pos_full = np.load(posfile)
vel_full = np.load(velfile)

global nframes, npart, ndim, pos, vel


def init_minimizer(cadence):
    pos = pos_full[::cadence]
    vel = vel_full[::cadence]

    nframes, npart, ndim = np.shape(pos)
示例#8
0
def main(args: Optional[list] = None,
         opts: Optional[argparse.Namespace] = None):
    """Script Function.

    Parameters
    ----------
    args : list, optional
        an optional single argument that holds the sys.argv list,
        except for the script name (e.g., argv[1:])
    opts : Namespace, optional
        pre-constructed results of parsed args
        if not None, used ONLY if args is None

    """
    if opts is not None and args is None:
        pass
    else:
        if opts is not None:
            warnings.warn("Not using `opts` because `args` are given")
        parser = make_parser()
        opts = parser.parse_args(args)

    foutname = DATA + "result_orbits.txt"

    if not os.path.isfile(foutname):

        # STEP 1: create Monte Carlo realizations of position and velocity of each cluster,
        # sampling from their measured uncertainties.

        # this file should have been produced by run_fit.py
        tab = np.loadtxt(DATA + "summary.txt", dtype=str)
        names = tab[:, 0]  # 0th column is the cluster name (string)
        tab = tab[:, 1:].astype(float)  # remaining columns are numbers
        ra0 = tab[:, 0]  # coordinates of cluster centers [deg]
        dec0 = tab[:, 1]
        dist0 = tab[:, 2]  # distance [kpc]
        vlos0 = tab[:, 3]  # line-of-sight velocity [km/s]
        vlose = tab[:, 4]  # its error estimate
        pmra0 = tab[:, 7]  # mean proper motion [mas/yr]
        pmdec0 = tab[:, 8]
        pmrae = tab[:, 9]  # its uncertainty
        pmdece = tab[:, 10]
        pmcorr = tab[:,
                     11]  # correlation coefficient for errors in two PM components
        vlose = np.maximum(
            vlose,
            2.0)  # assumed error of at least 2 km/s on line-of-sight velocity
        diste = (dist0 * 0.46 * 0.1
                 )  # assumed error of 0.1 mag in distance modulus

        # create bootstrap samples
        np.random.seed(42)  # ensure repeatability of random samples
        nboot = 100  # number of bootstrap samples for each cluster
        nclust = len(tab)
        ra = np.repeat(ra0, nboot)
        dec = np.repeat(dec0, nboot)
        pmra = np.repeat(pmra0, nboot)
        pmdec = np.repeat(pmdec0, nboot)
        for i in range(nclust):
            # draw PM realizations from a correlated 2d gaussian for each cluster
            A = np.random.normal(size=nboot)
            B = (np.random.normal(size=nboot) * (1 - pmcorr[i]**2)**0.5 +
                 A * pmcorr[i])
            pmra[i * nboot:(i + 1) * nboot] += pmrae[i] * A
            pmdec[i * nboot:(i + 1) * nboot] += pmdece[i] * B
        vlos = np.repeat(vlos0, nboot) + np.hstack(
            [np.random.normal(scale=e, size=nboot) for e in vlose])
        dist = np.repeat(dist0, nboot) + np.hstack(
            [np.random.normal(scale=e, size=nboot) for e in diste])

        # convert coordinates from heliocentric (ra,dec,dist,PM,vlos) to Galactocentric (kpc and km/s)
        u.kms = u.km / u.s
        c_sky = coord.ICRS(
            ra=ra * u.degree,
            dec=dec * u.degree,
            pm_ra_cosdec=pmra * u.mas / u.yr,
            pm_dec=pmdec * u.mas / u.yr,
            distance=dist * u.kpc,
            radial_velocity=vlos * u.kms,
        )
        c_gal = c_sky.transform_to(
            coord.Galactocentric(
                galcen_distance=8.2 * u.kpc,
                galcen_v_sun=coord.CartesianDifferential([10.0, 248.0, 7.0] *
                                                         u.kms),
            ))
        pos = np.column_stack(
            (c_gal.x / u.kpc, c_gal.y / u.kpc, c_gal.z / u.kpc))
        vel = np.column_stack(
            (c_gal.v_x / u.kms, c_gal.v_y / u.kms, c_gal.v_z / u.kms))
        # add uncertainties from the solar position and velocity
        pos[:, 0] += np.random.normal(
            scale=0.1, size=nboot *
            nclust)  # uncertainty in solar distance from Galactic center
        vel[:, 0] += np.random.normal(scale=1.0, size=nboot *
                                      nclust)  # uncertainty in solar velocity
        vel[:, 1] += np.random.normal(scale=3.0, size=nboot * nclust)
        vel[:, 2] += np.random.normal(scale=1.0, size=nboot * nclust)
        pos[:, 0] *= (
            -1
        )  # revert back to normal orientation of coordinate system (solar position at x=+8.2)
        vel[:, 0] *= -1  # same for velocity
        posvel = np.column_stack((pos, vel)).value
        np.savetxt(DATA + "posvel.txt", posvel, fmt="%.6g")

        # STEP 2: compute the orbits, min/max galactocentric radii, and actions, for all Monte Carlo samples

        print(agama.setUnits(
            length=1, velocity=1,
            mass=1))  # units: kpc, km/s, Msun; time unit ~ 1 Gyr
        potential = agama.Potential(
            DATA + "McMillan17.ini")  # MW potential from McMillan(2017)

        # compute orbits for each realization of initial conditions,
        # integrated for 100 dynamical times or 20 Gyr (whichever is lower)
        print(
            "Computing orbits for %d realizations of cluster initial conditions"
            % len(posvel))
        inttime = np.minimum(20.0, potential.Tcirc(posvel) * 100)
        orbits = agama.orbit(ic=posvel,
                             potential=potential,
                             time=inttime,
                             trajsize=1000)[:, 1]
        rmin = np.zeros(len(orbits))
        rmax = np.zeros(len(orbits))
        for i, o in enumerate(orbits):
            r = np.sum(o[:, 0:3]**2, axis=1)**0.5
            rmin[i] = np.min(r) if len(r) > 0 else np.nan
            rmax[i] = np.max(r) if len(r) > 0 else np.nan
        # replace nboot samples rmin/rmax with their median and 68% confidence intervals for each cluster
        rmin = np.nanpercentile(rmin.reshape(nclust, nboot), [16, 50, 84],
                                axis=1)
        rmax = np.nanpercentile(rmax.reshape(nclust, nboot), [16, 50, 84],
                                axis=1)

        # compute actions for the same initial conditions
        actfinder = agama.ActionFinder(potential)
        actions = actfinder(posvel)
        # again compute the median and 68% confidence intervals for each cluster
        actions = np.nanpercentile(actions.reshape(nclust, nboot, 3),
                                   [16, 50, 84],
                                   axis=1)

        # compute the same confidence intervals for the total energy
        energy = potential.potential(
            posvel[:, 0:3]) + 0.5 * np.sum(posvel[:, 3:6]**2, axis=1)
        energy = np.percentile(energy.reshape(nclust, nboot), [16, 50, 84],
                               axis=1)

        # write the orbit parameters, actions and energy - one line per cluster, with the median and uncertainties
        fileout = open(foutname, "w")
        fileout.write(
            "# Name         \t     pericenter[kpc]   \t     apocenter[kpc]    \t"
            +
            "       Jr[kpc*km/s]    \t       Jz[kpc*km/s]    \t      Jphi[kpc*km/s]   \t    Energy[km^2/s^2]   \n"
        )
        for i in range(nclust):
            fileout.write(("%-15s" + "\t%7.2f" * 6 + "\t%7.0f" * 12 + "\n") % (
                names[i],
                rmin[0, i],
                rmin[1, i],
                rmin[2, i],
                rmax[0, i],
                rmax[1, i],
                rmax[2, i],
                actions[0, i, 0],
                actions[1, i, 0],
                actions[2, i, 0],
                actions[0, i, 1],
                actions[1, i, 1],
                actions[2, i, 1],
                actions[0, i, 2],
                actions[1, i, 2],
                actions[2, i, 2],
                energy[0, i],
                energy[1, i],
                energy[2, i],
            ))
        fileout.close()
示例#9
0
agama.setUnits(mass=1, length=1, velocity=1)

# import the MW potential from gala
bulge = agama.Potential(type='Dehnen', gamma=1, mass=5E9, scaleRadius=1.0)
nucleus = agama.Potential(type='Dehnen',
                          gamma=1,
                          mass=1.71E09,
                          scaleRadius=0.07)
disk = agama.Potential(type='MiyamotoNagai',
                       mass=6.80e+10,
                       scaleRadius=3.0,
                       scaleHeight=0.28)
halo = agama.Potential(type='NFW', mass=5.4E11, scaleRadius=15.62)
mwpot = agama.Potential(bulge, nucleus, disk, halo)

af = agama.ActionFinder(mwpot, interp=False)

pos_vel = np.array([8., 0., 0., 75., 150., 50.])
agama_act = af(pos_vel)

# now do it for gala

pot = gp.MilkyWayPotential()

w0 = gd.PhaseSpacePosition(pos=[8, 0, 0.] * u.kpc,
                           vel=[75, 150, 50.] * u.km / u.s)

w = gp.Hamiltonian(pot).integrate_orbit(w0, dt=0.5, n_steps=10000)
gala_act = gd.find_actions(w, N_max=8)
示例#10
0
def isTuple(obj, length):
    return isinstance(obj, tuple) and len(obj) == length


def isArray(obj, shape):
    return isinstance(obj, numpy.ndarray) and obj.shape == shape


# set up some non-trivial dimensional units
agama.setUnits(length=2, velocity=3, mass=4e6)

dens = agama.Density(type='plummer')
pots = agama.Potential(type='dehnen', gamma=0)  # spherical potential
potf = agama.Potential(type='plummer', q=0.75)  # flattened potential
pott = agama.Potential(type='plummer', p=0.75, q=0.5)  # triaxial potential
actf = agama.ActionFinder(potf)
actm = agama.ActionMapper(potf, [1, 1, 1])
df0 = agama.DistributionFunction(type='quasispherical',
                                 density=pots,
                                 potential=pots,
                                 r_a=2.0)
df1 = agama.DistributionFunction(type='quasispherical',
                                 density=dens,
                                 potential=pots,
                                 beta0=-0.2)
df2 = agama.DistributionFunction(df1, df0)  # composite DF with two components
gms1 = agama.GalaxyModel(pots, df1)  # simple DF, spherical potential
gms2 = agama.GalaxyModel(pots, df2)  # composite DF (2 components), spherical
gmf1 = agama.GalaxyModel(potf, df1)  # simple, flattened
Phi0 = pots.potential(0, 0, 0)  # value of the potential at origin
示例#11
0
###2. set up equivalent potential from the Agama library
agama.setUnits( mass=1., length=8., velocity=345.67)
p_bulge = {"type":"SpheroidDensity", "densityNorm":6.669e9,
    "gamma":1.8, "beta":1.8, "scaleRadius":1, "outerCutoffRadius":1.9/8};
p_disk  = {"type":"MiyamotoNagai", "mass":1.678e11, "scaleradius":3./8, "scaleheight":0.28/8};
p_halo  = {"type":"SpheroidDensity", "densityNorm":1.072e10,
    "gamma":1.0, "beta":3.0, "scaleRadius":2.};
### one can create the genuine instance of Agama potential as follows:
#c_pot   = agama.Potential("../data/MWPotential2014.ini")   # read parameters from ini file
#c_pot   = agama.Potential(p_bulge, p_disk, p_halo) # or create potential from a list of parameters
### or one can instead create a galpy-compatible potential as follows:
w_pot   = galpy_agama.CPotential(p_bulge, p_disk, p_halo)  # same as above, two variants
### ...and then use _pot member variable to access the instance of raw Agama potential
dt = time.time()
### initialization of the action finder needs to be done once for the given potential
c_actfinder = agama.ActionFinder(w_pot._pot, interp=False)
print 'Time to set up action finder: %s s' % (time.time()-dt)
### we have a faster but less accurate "interpolated action finder", which takes a bit longer to initialize
i_actfinder = agama.ActionFinder(w_pot._pot, interp=True)
print 'Time to set up interpolated action finder: %s s' % (time.time()-dt)

### conversion from prolate spheroidal to cylindrical coords
def ProlSphToCyl(la, nu, ifd):
    return ( ((la - ifd*ifd) * (1 - abs(nu)/ifd**2))**0.5, (la*abs(nu))**0.5 / ifd * numpy.sign(nu) )

### show coordinate grid in prolate spheroidal coords
def plotCoords(ifd, maxR):
    la = numpy.linspace(0, maxR, 32)**2 + ifd**2
    ls = numpy.linspace(0, 1, 21)
    nu = ls*ls*(3-2*ls)*ifd**2
    for i in range(len(la)):
### instead we use a Multipole expansion (which never needs the value of the original potential at 0);
### it is less accurate in this case, but still acceptable
#g_pot_approx = agama.Potential(type='CylSpline', potential=g_pot_hybrid, symmetry='axi', rmin=0.01, rmax=10, zmin=0.01, zmax=10)
g_pot_approx = agama.Potential(type='Multipole',
                               potential=g_pot_hybrid,
                               symmetry='axi',
                               rmin=0.01,
                               rmax=10,
                               lmax=20)
#g_pot_approx.export('example_galpy.ini')  # may save the potential coefs for later use
print('Time to set up a CylSpline approximation to galpy potential: %.4g s' %
      (time.time() - dt))

### initialization of the action finder needs to be done once for the given potential
dt = time.time()
a_actfinder = agama.ActionFinder(a_pot_hybrid, interp=False)
print('Time to set up agama action finder: %.4g s' % (time.time() - dt))
### we have a faster but less accurate "interpolated action finder", which takes a bit longer to initialize
dt = time.time()
i_actfinder = agama.ActionFinder(a_pot_hybrid, interp=True)
print('Time to set up agama interpolated action finder: %.4g s' %
      (time.time() - dt))


### conversion from prolate spheroidal to cylindrical coords
def ProlSphToCyl(la, nu, fd):
    return (((la - fd * fd) * (1 - abs(nu) / fd**2))**0.5,
            (la * abs(nu))**0.5 / fd * numpy.sign(nu))


### show coordinate grid in prolate spheroidal coords
示例#13
0
#!/usr/bin/python
# illustrate the use of Torus Machine for transformation from action/angle to position/velocity
import agama, numpy, matplotlib.pyplot as plt
ax = plt.subplots(2, 2, figsize=(15, 10))[1]
pot = agama.Potential(type='Plummer', mass=10, axisratioz=.6)
act = [1.0, 2.0, 3.0]  # Jr, Jz, Jphi - some fiducial values
am = agama.ActionMapper(pot,
                        act)  # J,theta -> x,v (Torus), with the given actions
af = agama.ActionFinder(pot)  # x,v -> J,theta (Staeckel fudge)
t = numpy.linspace(0, 100, 1001)
# construct the orbit using Torus
xv_torus = am(
    numpy.column_stack((am.Omegar * t, am.Omegaz * t, am.Omegaphi * t)))
ax[0, 0].plot((xv_torus[:, 0]**2 + xv_torus[:, 1]**2)**0.5,
              xv_torus[:, 2],
              label='torus')
# construct the orbit by numerically integrating the equations of motion
_, xv_orbit = agama.orbit(ic=xv_torus[0],
                          potential=pot,
                          time=t[-1],
                          trajsize=len(t))
ax[0, 0].plot((xv_orbit[:, 0]**2 + xv_orbit[:, 1]**2)**0.5,
              xv_orbit[:, 2],
              label='orbit')
# compute actions for the torus orbit using Staeckel approximation
J, theta, Omega = af(xv_torus, angles=True)
ax[0, 1].plot(t, J, label='J,torus')
ax[1, 1].plot(t, Omega, label='Omega,torus')
ax[1, 0].plot(t, theta, label='theta,torus')
# same for the actual orbit
J, theta, Omega = af(xv_orbit, angles=True)
示例#14
0
 def update_t(self, t):
     bar_pot = agama.Potential(file=self.ai_bar(t))
     dark_pot = agama.Potential(file=self.ai_dark(t))
     self.potential = agama.Potential(bar_pot, dark_pot)
     self.af = agama.ActionFinder(self.potential, interp=False)
示例#15
0
orbits = agama.orbit(ic=posvel,
                     potential=potential,
                     time=inttime,
                     trajsize=1000)[:, 1]
rmin = numpy.zeros(len(orbits))
rmax = numpy.zeros(len(orbits))
for i, o in enumerate(orbits):
    r = numpy.sum(o[:, 0:3]**2, axis=1)**0.5
    rmin[i] = numpy.min(r) if len(r) > 0 else numpy.nan
    rmax[i] = numpy.max(r) if len(r) > 0 else numpy.nan
# replace nboot samples rmin/rmax with their median and 68% confidence intervals for each cluster
rmin = numpy.nanpercentile(rmin.reshape(nclust, nboot), [16, 50, 84], axis=1)
rmax = numpy.nanpercentile(rmax.reshape(nclust, nboot), [16, 50, 84], axis=1)

# compute actions for the same initial conditions
actfinder = agama.ActionFinder(potential)
actions = actfinder(posvel)
# again compute the median and 68% confidence intervals for each cluster
actions = numpy.nanpercentile(actions.reshape(nclust, nboot, 3), [16, 50, 84],
                              axis=1)

# compute the same confidence intervals for the total energy
energy = potential.potential(
    posvel[:, 0:3]) + 0.5 * numpy.sum(posvel[:, 3:6]**2, axis=1)
energy = numpy.percentile(energy.reshape(nclust, nboot), [16, 50, 84], axis=1)

# write the orbit parameters, actions and energy - one line per cluster, with the median and uncertainties
fileout = open("result_orbits.txt", "w")
fileout.write(
    "# Name         \t     pericenter[kpc]   \t     apocenter[kpc]    \t" +
    "       Jr[kpc*km/s]    \t       Jz[kpc*km/s]    \t      Jphi[kpc*km/s]   \t    Energy[km^2/s^2]   \n"
示例#16
0
    def update_index(self, index, ss_id=None, snap=None):
        agama.setUnits(mass=1, length=1, velocity=1)
        self.current_index = index
        self.ss_id = ss_id

        if snap is not None:
            self.snap = snap
        else:
            self.snap = \
                gizmo.io.Read.read_snapshots(['star', 'gas', 'dark'],
                                             'index', index,
                                             properties=['id', 'position',
                                                         'velocity', 'mass',
                                                         'form.scalefactor'],
                                             simulation_directory=
                                             self.simulation_directory,
                                             assign_principal_axes=True)

        if self.sim_name is None:
            head = gizmo.io.Read.read_header(snapshot_value=self.startnum,
                                             simulation_directory=
                                             self.simulation_directory)
            self.sim_name = head['simulation.name'].replace(" ", "_")

        potential_cache_file = self.cache_directory + '/potential_id'+str(index)
        potential_cache_file += '_' + self.sim_name + '_pot'
        try:
            self.potential = agama.Potential(file=potential_cache_file)
        except:
            star_position = self.snap['star'].prop('host.distance.principal')
            gas_position = self.snap['gas'].prop('host.distance.principal')
            dark_position = self.snap['dark'].prop('host.distance.principal')

            star_mass = self.snap['star']['mass']
            gas_mass = self.snap['gas']['mass']
            dark_mass = self.snap['dark']['mass']



            position = np.concatenate((star_position, gas_position))
            mass = np.concatenate((star_mass, gas_mass))

            #TODO make these user-controllable
            self.pdark = agama.Potential(type="Multipole",
                                        particles=(dark_position, dark_mass),
                                        symmetry='a', gridsizeR=20, lmax=2)
            self.pbar = agama.Potential(type="CylSpline",
                                        particles=(position, mass),
                                        gridsizer=20, gridsizez=20,
                                        mmax=0, Rmin=0.2, symmetry='a',
                                        Rmax=50, Zmin=0.02, Zmax=10)
            self.potential = agama.Potential(self.pdark, self.pbar)
            self.potential.export(potential_cache_file)

        if ss_id is not None:
            self.ss_init = True
            ss_key = np.where(self.snap['star']['id'] == self.ss_id)[0]
            self.chosen_position = self.snap['star'].prop(
                'host.distance.principal')[ss_key]
            self.chosen_velocity = self.snap['star'].prop(
                'host.velocity.principal')[ss_key]
        else:
            self.ss_init = False

        self.af = agama.ActionFinder(self.potential, interp=False)
示例#17
0
p_halo = {
    "type": "SpheroidDensity",
    "densityNorm": 1.072e10,
    "gamma": 1.0,
    "beta": 3.0,
    "scaleRadius": 2.
}
### one can create the genuine instance of Agama potential as follows:
#c_pot   = agama.Potential("../data/MWPotential2014.ini")   # read parameters from ini file
#c_pot   = agama.Potential(p_bulge, p_disk, p_halo) # or create potential from a list of parameters
### or one can instead create a galpy-compatible potential as follows:
w_pot = galpy_agama.CPotential(p_bulge, p_disk,
                               p_halo)  # same as above, two variants
### ...and then use _pot member variable to access the instance of raw Agama potential
dt = time.time()
c_actfinder = agama.ActionFinder(w_pot._pot)
print 'Time to set up action finder: %s s' % (time.time() - dt)

### this needs to be done once for the given potential,
### and initializes the interfocal distance estimator for all values of E and L


### conversion from prolate spheroidal to cylindrical coords
def ProlSphToCyl(la, nu, ifd):
    return (((la - ifd * ifd) * (1 - abs(nu) / ifd**2))**0.5,
            (la * abs(nu))**0.5 / ifd * numpy.sign(nu))


### show coordinate grid in prolate spheroidal coords
def plotCoords(ifd, maxR):
    la = numpy.linspace(0, maxR, 32)**2 + ifd**2