Пример #1
0
    def setup_class(cls):
        """Setup fixtures for testing."""
        agama.setUnits(mass=1, length=1, velocity=1)  # FIXME! bad
        cls.potential = agama.Potential(type="Plummer")

        # set up the rest
        super().setup_class()
Пример #2
0
    def setup_class(cls):
        """Setup fixtures for testing."""
        super().setup_class()

        # now agama stuff
        # override super
        agama.setUnits(mass=1, length=1, velocity=1)  # FIXME! bad
        cls.potential = agama.Potential(type="Plummer")
Пример #3
0
 def __init__(self, opt, ai_bar=None, ai_dark=None):
     opt.set_options(self)
     agama.setUnits(mass=1, length=1, velocity=1)
     if ai_bar is not None:
         self._tevolv_ = True
         self.ai_bar = ai_bar
         self.ai_dark = ai_dark
     else:
         self._tevolv_ = False
Пример #4
0
    def _gen_axisymmetric_(self, all_snaps=False):
        agama.setUnits(mass=1, length=1, velocity=1)
        if all_snaps:
            pot_file_list = []
            for index in self.snapshot_indices:
                pot_file_list.append(self._pot_cache_file_(index))
        else:
            pot_file_list = (self._pot_cache_file_(self.startnum), )

        for i, file in enumerate(pot_file_list):
            try:
                self.pdark = agama.Potential(file=file + '_dark')
                self.pbar = agama.Potential(file=file + '_bar')
                self.potential = agama.Potential(self.pdark, self.pbar)
            except:
                star_position = self.snapshots[i]['star'].prop(
                    'host.distance.principal')
                gas_position = self.snapshots[i]['gas'].prop(
                    'host.distance.principal')
                dark_position = self.snapshots[i]['dark'].prop(
                    'host.distance.principal')

                star_mass = self.snapshots[i]['star']['mass']
                gas_mass = self.snapshots[i]['gas']['mass']
                dark_mass = self.snapshots[i]['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),
                                            symmetry='a',
                                            gridsizer=20,
                                            gridsizez=20,
                                            mmax=0,
                                            Rmin=0.2,
                                            Rmax=50,
                                            Zmin=0.02,
                                            Zmax=10)
                self.pdark.export(file + '_dark')
                self.pbar.export(file + '_bar')
                self.potential = agama.Potential(self.pdark, self.pbar)
                self.potential.export(file)

        if self.axisymmetric_tevolve:
            self._gen_agama_interpolator_()

        return None
Пример #5
0
    def density(
        self,
        potential: PotentialType,
        points: TH.PositionType,
        *,
        frame: TH.OptFrameLikeType = None,
        representation_type: TH.OptRepresentationLikeType = None,
        **kwargs
    ) -> T.Tuple[TH.SkyCoordType, TH.QuantityType]:
        """Evaluate the density.

        Parameters
        ----------
        potential : `~agama.Potential`
            The potential.
        points : coord-array or |Representation| or None (optional)
            The points at which to evaluate the density.
        frame : |CoordinateFrame| or None (optional, keyword-only)
            The frame of the density. Potentials do not have an intrinsic
            reference frame, but if one is assigned, then anything needs to be
            converted to that frame.
        representation_type : |Representation| or None (optional, keyword-only)
            The representation type in which to return data.
        **kwargs
            Arguments into the density.

        Returns
        -------
        points: :class:`~astropy.coordinates.CoordinateFrame`
            The points.
        values : :class:`~astropy.unit.Quantity`
            Array of the specific-potential value at the points.

        """
        shape = points.shape[:]  # copy the shape

        p, _ = self._convert_to_frame(points, frame, representation_type)
        r = p.represent_as(coord.CartesianRepresentation)
        r = r.reshape(-1)  # unfortunately can't flatten in-place

        agama.setUnits(mass=1, length=1, velocity=1)  # TODO! bad
        values = potential.density(r.xyz.T) * (u.solMass / u.pc ** 3)

        # reshape
        r.shape = shape
        values.shape = shape

        # TODO! ScalarField to package together
        p, _ = self._convert_to_frame(p, frame, representation_type)
        return p, values
Пример #6
0
    def __init__(self, options_reader, grid_snapshot=None):

        agama.setUnits(mass=1, length=1, velocity=1)

        self.G = G_astropy.to_value(u.kpc**2 * u.km / (u.s * u.Myr * u.Msun))
        self.theta = 0.5

        self.convert_kms_Myr_to_kpc = 20000.0 * np.pi / (61478577.0)
        self.kpc_in_km = 3.08567758E16
        # opt = options_reader(options_file)
        options_reader.set_options(self)
        self.options_reader = options_reader

        self.snapshot_indices = range(self.startnum - self.num_prior,
                                      self.endnum + 1)
        self.initial_key = self.num_prior

        if not os.path.isdir(self.cache_directory):
            os.makedirs(self.cache_directory)

        if self.axisymmetric:
            if self.axisymmetric_tevolve:
                self._read_snapshots_()
                self._gen_axisymmetric_(all_snaps=True)
                self.evolve_model(0 | units.Myr)
            else:
                self._read_snapshots_(first_only=True)
                self._gen_axisymmetric_()
            return None

        self._read_snapshots_()

        # find starting star
        self._init_starting_star_()

        # set up trackers
        self._init_starting_star_interpolators_()

        # set up grid
        if grid_snapshot is not None:
            self._init_grid_(grid_snapshot)
        else:
            self._init_grid_()

        self.evolve_model(0 | units.Myr)

        self.grid._grid_evolved_kdtree_ = cKDTree(self.grid.evolved_grid)
Пример #7
0
'''

import sys, numpy, agama

############### parse parameters from command-line arguments or assign default values #############
arglist = []
for arg in sys.argv[1:]:
    nameval = arg.split('=')
    if len(nameval)!=2:
        raise ValueError('Command-line arguments should be in the form  name=value')
    arglist.append([nameval[0].upper(), nameval[1]])
args = dict(arglist)

distance  = float(args.get('DISTANCE', 20626))  # [REQ] assumed distance [kpc]
arcsec2kpc= distance * numpy.pi / 648000        # conversion factor (number of kiloparsecs in one arcsecond)
agama.setUnits(mass=1, length=arcsec2kpc, velocity=1)  # [OPT] units: mass = 1 Msun, length = 1", velocity = 1 km/s
Mbh       = float(args.get('MBH', 0))           # [REQ] mass of the central black hole  [Msun]
Omega     = float(args.get('OMEGA', 0))         # [REQ] pattern speed (relevant only for non-axisymmetric models) [km/s/length_unit]
halotype  =       args.get('HALOTYPE', 'nfw')   # [OPT] halo type: 'LOG' or 'NFW'
vhalo     = float(args.get('VHALO', 190))       # [OPT] asymptotic (LOG) or peak (NFW) circular velocity of the halo [km/s]
rhalo     = float(args.get('RHALO', 150))       # [OPT] core (LOG) or scale (NFW) radius of the halo [lenth_unit]
Upsilon   = float(args.get('UPSILON', 1.0))     # [OPT] initial value of mass-to-light ratio in the search
multstep  = float(args.get('MULTSTEP', 1.02))   # [OPT] multiplicative step for increasing/decreasing Upsilon during grid search
numOrbits = int  (args.get('NUMORBITS', 20000)) # [OPT] number of orbit in the model (size of orbit library)
intTime   = float(args.get('INTTIME', 100.0))   # [OPT] integration time in units of orbital period
regul     = float(args.get('REGUL', 1. ))       # [OPT] regularization parameter (larger => more uniform orbit weight distribution in models)
incl      = float(args.get('INCL', 60.0))       # [REQ] inclination angle (0 is face-on, 90 is edge-on) [degrees]
beta      = incl * numpy.pi/180                 # same in radians
alpha     = float(args.get('ALPHA', 0.0))       # [REQ] azimuthal angle of viewing direction in the model coordinates (relevant only for non-axisym)
degree    = int  (args.get('DEGREE', 2))        # [OPT] degree of B-splines  (0 means histograms, 2 or 3 is preferred)
symmetry  = 'a'                                 # [OPT] symmetry of the model ('s'pherical, 'a'xisymmetric, 't'riaxial)
Пример #8
0
 def __init__(self, opt):
     opt.set_options(self)
     agama.setUnits(mass=1, length=1, velocity=1)
Пример #9
0
from pygaia.astrometry.coordinates import CoordinateTransformation, Transformations
from pygaia.astrometry.vectorastrometry import cartesianToSpherical, astrometryToPhaseSpace,\
    phaseSpaceToAstrometry
from pygaia.errors.astrometric import properMotionErrorSkyAvg, properMotionMinError, properMotionMaxError, parallaxErrorSkyAvg

#orbit
import agama

pyplot.rcParams['ps.useafm'] = True
pyplot.rcParams['pdf.use14corefonts'] = True
pyplot.rcParams['text.usetex'] = True

# unit (just for normalization)
_R0 = 8.0  # 8 kpc
_V0 = 220.  # 220 km/s
"""
#position and velocity of the Sun
_xGC_sun_kpc = -8.0  #you can set to (-_R0) if you want
_yGC_sun_kpc =  0.
_zGC_sun_kpc =  0.
_vxGC_sun    =  11.1
_vyGC_sun    =  232.24 #you can set to (_V0) if you want
_vzGC_sun    =  7.25

#MWPotential2014-----
agama.setUnits( mass=1., length=_R0, velocity=_V0)
p_bulge = dict(type='Spheroid', densityNorm=2.70033e9, gamma=1.8, beta=1.8, scaleRadius=8./_R0, outerCutoffRadius=1.9/_R0)
p_disk  = dict(type='MiyamotoNagai', mass=6.819386e10, scaleradius=3./_R0, scaleheight=0.28/_R0)
p_halo  = dict(type='Spheroid', densityNorm=4.34527e9, axisRatioZ=1.0, gamma=1.0, beta=3.0, scaleRadius=2.)
#--------------------
# Agama potential
Пример #10
0
# THIRD PARTY
import agama
import astropy.coordinates as coord
import astropy.units as u
import numpy as np

# PROJECT-SPECIFIC
import discO.type_hints as TH
from .type_hints import PotentialType
from discO.core.wrapper import PotentialWrapper, PotentialWrapperMeta
from discO.utils import resolve_representationlike, vectorfield

##############################################################################
# Parameters

agama.setUnits(mass=1, length=1, velocity=1)  # FIXME! bad

##############################################################################
# CODE
##############################################################################


class AGAMAPotentialMeta(PotentialWrapperMeta):
    """Metaclass for wrapping :mod:`~agama` potentials."""

    def total_mass(self, potential: TH.PositionType) -> TH.QuantityType:
        """Evaluate the total mass.

        Parameters
        ----------
        potential : object
Пример #11
0
from galpy.potential import *
from galpy.actionAngle import *
from galpy.orbit import *
import agama        # this allows access to potential, action finder, orbit integration, etc. as standalone classes and routines
import galpy_agama  # this enables galpy-compatible interface to potentials
import numpy, matplotlib, matplotlib.pyplot as plt, time
matplotlib.rcParams['legend.frameon']=False

###1. set up galpy potential
g_bulge = PowerSphericalPotentialwCutoff(alpha=1.8, rc=1.9/8, amp=0.03)
g_disk  = MiyamotoNagaiPotential(a=3./8, b=0.28/8, amp=0.755)
g_halo  = NFWPotential(a=2., amp=4.85)
g_pot   = [g_bulge,g_disk,g_halo]   # same as MWPotential2014

###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()
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,
    ini.read(iniFileName)
    iniPotenThinDisc = dict(ini.items("Potential thin disc"))
    iniPotenThickDisc= dict(ini.items("Potential thick disc"))
    iniPotenGasDisc  = dict(ini.items("Potential gas disc"))
    iniPotenBulge    = dict(ini.items("Potential bulge"))
    iniPotenDarkHalo = dict(ini.items("Potential dark halo"))
    iniDFThinDisc    = dict(ini.items("DF thin disc"))
    iniDFThickDisc   = dict(ini.items("DF thick disc"))
    iniDFStellarHalo = dict(ini.items("DF stellar halo"))
    iniDFDarkHalo    = dict(ini.items("DF dark halo"))
    iniSCMHalo       = dict(ini.items("SelfConsistentModel halo"))
    iniSCMDisc       = dict(ini.items("SelfConsistentModel disc"))
    iniSCM           = dict(ini.items("SelfConsistentModel"))

    # define external unit system describing the data (including the parameters in INI file)
    agama.setUnits(length=1, velocity=1, mass=1)   # in Kpc, km/s, Msun

    # initialize the SelfConsistentModel object (only the potential expansion parameters)
    model = agama.SelfConsistentModel(**iniSCM)

    # create initial ('guessed') density profiles of all components
    densityBulge       = agama.Density(**iniPotenBulge)
    densityDarkHalo    = agama.Density(**iniPotenDarkHalo)
    densityThinDisc    = agama.Density(**iniPotenThinDisc)
    densityThickDisc   = agama.Density(**iniPotenThickDisc)
    densityGasDisc     = agama.Density(**iniPotenGasDisc)
    densityStellarDisc = agama.Density(densityThinDisc, densityThickDisc)  # composite

    # add components to SCM - at first, all of them are static density profiles
    model.components.append(agama.Component(dens=densityDarkHalo,    disklike=False))
    model.components.append(agama.Component(dens=densityStellarDisc, disklike=True))
Пример #13
0
        if i == 0:
            ax.legend(loc='lower center', frameon=False)
            ax.text(1.0,
                    1.05,
                    'projected velocity distributions in fields',
                    ha='right',
                    va='center',
                    transform=ax.transAxes)
        ax.set_ylabel('f(V)', labelpad=3)
    plt.savefig('nsd_model.pdf')
    plt.show()


if __name__ == '__main__':

    agama.setUnits(length=1, velocity=1, mass=1e10)  # 1 kpc, 1 km/s, 1e10 Msun

    # initialize the SelfConsistentModel object (only the potential expansion parameters)
    model = agama.SelfConsistentModel(RminCyl=0.005,
                                      RmaxCyl=1.0,
                                      sizeRadialCyl=25,
                                      zminCyl=0.005,
                                      zmaxCyl=1.0,
                                      sizeVerticalCyl=25)

    # construct a two component model: NSD + NSC
    # NSD -> generated self-consistently
    # NSC -> kept fixed as an external potential

    # NSC best-fitting model from Chatzopoulos et al. 2015 (see Equation 28 here: https://arxiv.org/pdf/2007.06577.pdf)
    density_NSC_init = agama.Density(type='Dehnen',
Пример #14
0
#!/usr/bin/python
"""
This example illustrates various usage scenarios for Target objects, used in Schwarzschild models.
"""
import agama, numpy

numpy.set_printoptions(linewidth=100,
                       formatter={'all': lambda x: '%11.6f' % x})

# set up some random physical units, to test the correction of unit conversion
agama.setUnits(length=3.4567, mass=12345, velocity=6.7)

# physical constituents of a model: potential and a corresponding isotropic DF
pot = agama.Potential(type='Plummer', scaleRadius=0.1, mass=100)
dens = pot
df = agama.DistributionFunction(type='QuasiSpherical', potential=pot)
gm = agama.GalaxyModel(pot, df)
vesc = (-2 * pot.potential(0, 0, 0))**0.5  # escape velocity from r=0
#print("escape velocity: %g" % vesc)

# define a grid in radius and a series of concentric rings for recording LOSVD
gridr = agama.nonuniformGrid(10, 0.025,
                             1)  # grid in radius (denser at small radii)
gridx = agama.symmetricGrid(
    19, 0.025, 1)  # grids in x,y - symmetrically mirror about origin
gridv = numpy.linspace(-vesc, vesc, 25)  # grid in velocity space
ang = numpy.linspace(
    0, 2 * numpy.pi,
    73)  # approximate a circle with a polygon with this many vertices
sa = numpy.sin(ang)
sa[36] = sa[72] = 0
        zmin=0.25 * scaleHeight,
        zmax=10.0 * scaleHeight,
        mmax=3 *
        numberOfArms,  # each arm is represented by three harmonic terms: m, m*2, m*3
        symmetry='bisymmetric' if numberOfArms %
        2 == 0 else 4,  # 4 means the z-reflection symmetry
        gridSizeZ=20,
        # rule of thumb for the radial grid spacing is to resolve
        # the change in the pitch angle of the spiral with one grid cell
        gridSizeR=max(
            25,
            numpy.log(10.0 / 0.01) / numpy.tan(pitchAngle) * numberOfArms))


agama.setUnits(
    length=1, velocity=1,
    mass=1)  # some arbitrary units - everything is scale-invariant here
numberOfArms = 3
pitchAngle = numpy.pi / 8
scaleRadius = 1.0
scaleHeight = 0.1
surfaceDensityD = 1.0  # density of the underlying axisymmetric disk
surfaceDensityS = surfaceDensityD * 0.5  # amplitude of the density variation of the spiral pattern
phi0 = numpy.pi / 10  # [arbitrary] phase angle at R=scaleRadius
pot_spiral = createSpiralPotential(numberOfArms, surfaceDensityS, scaleRadius,
                                   scaleHeight, pitchAngle, phi0)
pot_disk = agama.Potential(
    type='disk',
    surfaceDensity=surfaceDensityD,
    scaleRadius=scaleRadius,
    scaleHeight=-scaleHeight
Пример #16
0
pos[:, 0] += numpy.random.normal(
    scale=0.1,
    size=nboot * nclust)  # uncertainty in solar distance from Galactic center
vel[:, 0] += numpy.random.normal(scale=1.0, size=nboot *
                                 nclust)  # uncertainty in solar velocity
vel[:, 1] += numpy.random.normal(scale=3.0, size=nboot * nclust)
vel[:, 2] += numpy.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 = numpy.column_stack((pos, vel))
numpy.savetxt('posvel.txt', posvel, fmt='%.6g')

# STEP 2: compute the orbits, min/max galactocentric radii, and actions, for all Monte Carlo samples
import agama
print(agama.setUnits(length=1, velocity=1,
                     mass=1))  # units: kpc, km/s, Msun; time unit ~ 1 Gyr
potential = agama.Potential(
    '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 = numpy.minimum(20., potential.Tcirc(posvel) * 100)
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):
Пример #17
0
   (of course, this is only possible if the orbit of the planet is circular);
2) let the two point masses move around on a pre-computed trajectory, and integrate the motion
   of the test particle in an inertial frame, but with a time-dependent potential;
3) same as above, but use a built-in potential of two moving point masses -- KeplerOrbit.
The third approach is more accurate than the second, because the orbit of the two massive
bodies is computed analytically, and is more general than the first one, because it can be
used even for an eccentric planet. However, the second approach is still more general
and can be used with an arbitrary number of moving potentials.
"""
import agama, numpy, os, matplotlib.pyplot as plt

ax = plt.subplots(1, 3, figsize=(15, 5))[1]

au = 4.84814e-9  # 1 astronomical unit in kpc
# work in solar system units: 1 AU, 1 Msun, 1 km/s, 4.74 yr
agama.setUnits(length=au, mass=1, velocity=1)

r0 = 1.  # AU
v0 = 29.784694  # km/s - orbital velocity of Earth
om = v0 / r0  # Omega - angular frequency of rotation
tu = 4.7405  # years in one time unit
ic = [
    r0, 0, 0, 0, v0, 0
]  # initial conditions for the orbit - at the other side of the Sun from Earth
tmax = 20


def convertToCorotatingFrame(t, o):
    return numpy.column_stack(
        (o[:, 0] * numpy.cos(om * t) + o[:, 1] * numpy.sin(om * t),
         o[:, 1] * numpy.cos(om * t) - o[:, 0] * numpy.sin(om * t), o[:, 2],
Пример #18
0
        print("Vectorized:\n", Gpot.hessian(points.T))
        print("Pointwise:\n",
              numpy.dstack([Gpot.hessian(point) for point in points]))
        print(
            "Checking vectorization of hessian for A: the two arrays should be equivalent"
        )
        print("Vectorized:\n", Apot.hessian(points.T))
        print("Pointwise:\n",
              numpy.dstack([Apot.hessian(point) for point in points]))


test(gpot1, Gpot1, Apot1)
test(gpot2, Gpot2, Apot2)
test(gpot3, Gpot3, Apot3)
test(gpot4, Gpot4, Apot4)
#test(gpot5, Gpot5, Apot5)  #### this one also fails because of hessian (and the absense of density method in gala)

# now test potentials defined with units
agama.setUnits(length=1, mass=1,
               velocity=977.792594852689)  # velocity unit = 1 kpc / 1 Myr
gpot6 = gala.potential.MilkyWayPotential()
Gpot6 = agama.GalaPotential(gpot6)
Apot6 = agama.GalaPotential(
    dict(type='miyamotonagai', mass=6.8e10, scaleradius=3.0,
         scaleheight=0.28),  # disk
    dict(type='dehnen', mass=5.00e9, scaleradius=1.0),  # bulge
    dict(type='dehnen', mass=1.71e9, scaleradius=0.07),  # nucleus
    dict(type='nfw', mass=5.4e11, scaleradius=15.62),  # halo
    units=Gpot6.units)
test(gpot6, Gpot6, Apot6, test_hessian=False)
Пример #19
0
        4.68875471e-01
    ] +
    # long bar 1
    [
        4.95381575e+08, 5.36363324e+00, 9.58522229e-01, 6.10542494e-01,
        9.69645220e-01, 3.05125124e+00, 3.19043585e+00, 5.58255674e-01,
        1.67310332e+01, 3.19575493e+00
    ] +
    # long bar 2
    [
        1.74304936e+13, 4.77961423e-01, 2.66853061e-01, 2.51516920e-01,
        1.87882599e+00, 9.80136710e-01, 2.20415408e+00, 7.60708626e+00,
        -2.72907665e+01, 1.62966434e+00
    ])

agama.setUnits(length=1, mass=1, velocity=1)  # 1 kpc, 1 Msun, 1 km/s
den = makeDensityModel(params)
pot = makePotentialModel(params)
pot.export('Portail17.ini')
print('Created MW potential: total mass in stars=%.3g Msun, halo=%.3g Msun' %
      (pot[0].totalMass(), pot[1].totalMass()))
# create an axisymmetrized version of the potential for plotting the true circular-velocity curve
pot_axi = agama.Potential(
    agama.Potential(type='CylSpline',
                    potential=pot[0],
                    mmax=0,
                    gridsizeR=25,
                    gridsizez=25,
                    Rmin=0.1,
                    Rmax=40,
                    zmin=0.05,
Пример #20
0
    def specific_force(
        self,
        potential: PotentialType,
        points: TH.PositionType,
        *,
        frame: TH.OptFrameLikeType = None,
        representation_type: TH.OptRepresentationLikeType = None,
        **kwargs
    ) -> vectorfield.BaseVectorField:
        """Evaluate the specific force.

        Parameters
        ----------
        potential : :class:`~agama.Potential`
            The potential.
        points : coord-array or |Representation| or None (optional)
            The points at which to evaluate the potential.
        frame : |CoordinateFrame| or None (optional, keyword-only)
            The frame of the potential. Potentials do not have an intrinsic
            reference frame, but if one is assigned, then anything needs to be
            converted to that frame.
        representation_type : |Representation| or None (optional, keyword-only)
            The representation type in which to return data.
        **kwargs
            Arguments into the potential.

        Returns
        -------
        `~discO.utils.vectorfield.BaseVectorField` subclass instance
            Type set by `representation_type`

        """
        shape = points.shape[:]  # copy the shape
        p, _ = self._convert_to_frame(points, frame, representation_type)
        # AGAMA uses a flattened Cartesian representation
        r = p.represent_as(coord.CartesianRepresentation).reshape(-1)

        agama.setUnits(mass=1, length=1, velocity=1)  # TODO! bad
        Fx, Fy, Fz = (
            potential.force(r.xyz.T).T
            / u.kpc.to(u.km)  # adjustment in AGAMA units
            * (u.km / u.s ** 2)
        )

        # reshape
        r.shape = shape
        Fx.shape = shape
        Fy.shape = shape
        Fz.shape = shape

        # return vectorfield
        # TODO? convert back to from_frame?
        vf = vectorfield.CartesianVectorField(
            points=r,
            vf_x=Fx,
            vf_y=Fy,
            vf_z=Fz,
            frame=frame,
        )

        if representation_type is not None:
            vf = vf.represent_as(
                resolve_representationlike(representation_type),
            )

        return vf
Пример #21
0
import agama

mass_unit = (1.0/4.3)*(10.0**(6.0))

agama.setUnits(mass=mass_unit, length=1, velocity=1)

pot = agama.Potential(type='Spheroid', gamma=1.0, beta=3.1, scaleRadius=2.5, outerCutoffRadius=15.0)
df = agama.DistributionFunction(type='QuasiSpherical',potential=pot)
model = agama.GalaxyModel(pot,df)
M = model.sample(10000)

print(M[0][9999,0])
agama.writeSnapshot('test_snapshot.snp',M,'n')


Пример #22
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()
Пример #23
0
using numpy vectorized math operations, which improves efficiency.
"""
import numpy
# if the module has been installed to the globally known directory, just import it
try:
    import agama
except ImportError:  # otherwise load the shared library from the parent folder
    import sys
    sys.path += ['../']
    try:
        import agama
    except ImportError as ex:
        sys.exit("\033[1;31mFAILED TO IMPORT AGAMA: %s\033[0m" % ex)

# set some non-trivial dimensional units to test the correctness of unit conversion within the library
agama.setUnits(length=1, mass=1e5, velocity=1)

# note that the value of the gravitational constant in these units is stored as agama.G


# user-defined density profile should be a function with a single argument --
# a 2d array Mx3, evaluating the density simultaneously at M points,
# i.e., it should operate with columns of the input array x[:,0], x[:,1], etc.
# To create a user function with arbitrary internal constants
# (such as mass, scale radius, etc.) which are not fixed a priori,
# we use a 'factory routine' that takes these internal parameters as arguments,
# and creates an anonymous (lambda) function with these parameters built-in.
def makeUserDensity(mass, radius):
    # we use column-wise sum (along axis 1) to obtain r^2 = x[0]^2+x[1]^2+x[2]^2
    return lambda x: \
        3 / (4*numpy.pi) * mass * radius**2 * \
Пример #24
0
    iniPotenGasDisk  = dict(ini.items("Potential gas disk"))
    iniPotenBulge    = dict(ini.items("Potential bulge"))
    iniPotenDarkHalo = dict(ini.items("Potential dark halo"))
    iniDFThinDisk    = dict(ini.items("DF thin disk"))
    iniDFThickDisk   = dict(ini.items("DF thick disk"))
    iniDFStellarHalo = dict(ini.items("DF stellar halo"))
    iniDFDarkHalo    = dict(ini.items("DF dark halo"))
    iniDFBulge       = dict(ini.items("DF bulge"))
    iniSCMHalo       = dict(ini.items("SelfConsistentModel halo"))
    iniSCMBulge      = dict(ini.items("SelfConsistentModel bulge"))
    iniSCMDisk       = dict(ini.items("SelfConsistentModel disk"))
    iniSCM           = dict(ini.items("SelfConsistentModel"))
    solarRadius      = ini.getfloat("Data", "SolarRadius")

    # define external unit system describing the data (including the parameters in INI file)
    agama.setUnits(length=1, velocity=1, mass=1)   # in Kpc, km/s, Msun

    # initialize the SelfConsistentModel object (only the potential expansion parameters)
    model = agama.SelfConsistentModel(**iniSCM)

    # create initial ('guessed') density profiles of all components
    densityBulge       = agama.Density(**iniPotenBulge)
    densityDarkHalo    = agama.Density(**iniPotenDarkHalo)
    densityThinDisk    = agama.Density(**iniPotenThinDisk)
    densityThickDisk   = agama.Density(**iniPotenThickDisk)
    densityGasDisk     = agama.Density(**iniPotenGasDisk)
    densityStellarDisk = agama.Density(densityThinDisk, densityThickDisk)  # composite

    # add components to SCM - at first, all of them are static density profiles
    model.components.append(agama.Component(density=densityStellarDisk, disklike=True))
    model.components.append(agama.Component(density=densityBulge,       disklike=False))
Пример #25
0
#!/usr/bin/python
"""
This script illustrates the use of the class agama.GalpyPotential, which is a subclass of
both galpy.potential.Potential and agama.Potential, and provides both interfaces
suitable for orbit integration and action finder routines.
"""

import agama
import galpy.potential, galpy.actionAngle, galpy.orbit
import numpy, time, matplotlib.pyplot as plt

### set up galpy potential
g_pot = galpy.potential.MWPotential2014

### set up equivalent potential from the Agama library, which also provides potential interface for galpy
agama.setUnits(mass=1., length=8., velocity=220)
a_pot = agama.GalpyPotential("../data/MWPotential2014galpy.ini")

### initialization of the action finder needs to be done once for the given potential
dt = time.time()
a_actfinder = agama.ActionFinder(a_pot, interp=False)
print('Time to set up 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, interp=True)
print('Time to set up 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,
Пример #26
0
    axes[1,indx].set_xscale('log')
    axes[1,indx].set_yscale('log')
    #axes[1,indx].legend(loc='lower left')
    axes[1,indx].set_xlim(rmin, rmax)
    axes[1,indx].set_ylim(densmin, densmax)
    axes[1,indx].set_xlabel('$r$')
    axes[1,indx].set_ylabel(r'$\rho$')
    axes[1,indx].text( (rmin*rmax)**0.5, densmin*2, label, ha='center')


################  MAIN PROGRAM  ##################
#base     = "gs010_bs050_rcrs100_rarcinf_core_0400mpc3_df"
if len(sys.argv)<=1:
    print "Provide the data file name as the command-line argument"
    exit()
agama.setUnits(mass=1, length=1, velocity=1)
base     = sys.argv[1]
model    = ModelParams(base)
rmin     = 0.01
rmax     = 100.
velmin   = 0.
velmax   = 40.
radii    = numpy.logspace(numpy.log10(rmin), numpy.log10(rmax), 25)
midradii = (radii[1:] * radii[:-1])**0.5
xyz      = numpy.vstack((radii, numpy.zeros_like(radii), numpy.zeros_like(radii))).T

# plot the inferred density of dark matter and its log-slope as functions of radius
fig,axes = pyplot.subplots(2, 3, figsize=(12,8))
plot_profiles("6"+base+"/"+base+"_1000_0.dat",     0,  '6d, no errors')
plot_profiles("5"+base+"/"+base+"_1000_0_err.dat", 1, r'5d, $\delta v$=2 km/s')
plot_profiles("3"+base+"/"+base+"_1000_0_err.dat", 2, r'3d, $\delta v$=2 km/s')
Пример #27
0
                                               reg=True)
    # convert the grid-based density profile into a full-fledged potential
    contracted_pot = agama.Potential(
        type="Multipole",
        symmetry="spherical",
        rmin=rmin,
        rmax=rmax,
        density=lambda xyz: numpy.exp(
            dens_contracted_interp(numpy.log(numpy.sum(xyz**2, axis=1)) * 0.5)
        ))
    return contracted_pot


if __name__ == '__main__':
    # example of usage of the above function for the Milky Way potential from Cautun+ 2020
    agama.setUnits(mass=1., length=1., velocity=1.)  # Msun, kpc, km/s
    # DM halo
    fb = 4.825 / 30.7  # Planck 1 baryon fraction
    m200 = 0.969e12  # the DM halo mass
    conc = 8.76
    NFW_rho0 = 3486926.735447284
    NFW_rs = 25.20684733101539
    # Note subtletly in Cautun20 NFW definition, scaled overdensity changes from paper value!

    # bulge
    params_bulge = dict(type='Spheroid',
                        densityNorm=1.03e11,
                        axisRatioZ=0.5,
                        gamma=0,
                        beta=1.8,
                        scaleRadius=0.075,
Пример #28
0
    They are not provided in the distribution, but could be created by running
    example_self_consistent_model.py
    The potential is computed from the snapshot itself, by creating a suitable
    potential expansion for each component: Multipole for the halo and CylSpline
    for the disk. This actually takes most of the time. We save the constructed
    potentials to text files, and on the subsequent launches of this program
    they are loaded from these files, speeding up the initialization.
    Then we compute actions for all particles from the disk component,
    and store them in a text file.

    An equivalent example in C++ is located in tests folder.
"""
import agama, numpy, time

#1. set units (in Msun, Kpc, km/s)
agama.setUnits(mass=1, length=1, velocity=1)

#2. get in N-body snapshots: columns 0 to 2 are position, 3 to 5 are velocity, 6 is mass
tbegin = time.clock()
try:
    diskParticles = numpy.loadtxt("model_stars_final")
    haloParticles = numpy.loadtxt("model_dm_final")
except:
    print("Input snapshot files are not available; " \
        "you may create them by running example_self_consistent_model.py")
    exit()

print("%g s to load %d disk particles (total mass=%g Msun) " \
    "and %d halo particles (total mass=%g Msun)" % \
    ( time.clock()-tbegin, \
    diskParticles.shape[0], numpy.sum(diskParticles[:,6]), \
Пример #29
0
from galpy.potential import *
from galpy.actionAngle import *
from galpy.orbit import *
import agama        # this allows access to potential, action finder, orbit integration, etc. as standalone classes and routines
import galpy_agama  # this enables galpy-compatible interface to potentials
import numpy, matplotlib, matplotlib.pyplot as plt, time
matplotlib.rcParams['legend.frameon']=False

###1. set up galpy potential
g_bulge = PowerSphericalPotentialwCutoff(alpha=1.8, rc=1.9/8, amp=0.03)
g_disk  = MiyamotoNagaiPotential(a=3./8, b=0.28/8, amp=0.755)
g_halo  = NFWPotential(a=2., amp=4.85)
g_pot   = [g_bulge,g_disk,g_halo]   # same as MWPotential2014

###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)
Пример #30
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)
Пример #31
0
# aux functions for determining the nature of objects
def isFloat(obj):
    return isinstance(obj, float)


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)