Example #1
0
    # note: use a 10x larger particle mass for halo than for bulge/disk
    agama.writeSnapshot("model_halo_final", \
        agama.GalaxyModel(potential=model.potential, df=dfHalo,  af=model.af).sample(3000000), format)

    # the remaining part computes and plots various diagnostics
    print("\033[1;33mComputing disk density and velocity profiles\033[0m")
    ax=plt.subplots(2, 3, figsize=(16,10))[1].reshape(-1)
    # take only the disk component
    modelDisk = agama.GalaxyModel(potential=model.potential, df=dfDisk, af=model.af)
    # radial grid for computing various quantities in the disk plane
    Sigma0 = float(iniPotenDisk["surfacedensity"])
    Rdisk  = float(iniPotenDisk["scaleradius"])
    Hdisk  =-float(iniPotenDisk["scaleheight"])
    sigmar0= float(iniDFDisk["sigmar0"])
    rsigmar= float(iniDFDisk["rsigmar"])
    R   = agama.nonuniformGrid(60, 0.01*Rdisk, 10.0*Rdisk)
    xyz = numpy.column_stack((R, R*0, R*0))
    print("Computing surface density")
    Sigma,rmsh,rmsv   = modelDisk.projectedMoments(R)
    print("Computing 3d density and velocity dispersion")
    rho,vel,sigma = modelDisk.moments(xyz, dens=True, vel=True, vel2=True)
    force, deriv = model.potential.forceDeriv(xyz)
    kappa = numpy.sqrt(-deriv[:,0] - 3*force[:,0]/R)
    ToomreQ = sigma[:,0]**0.5 * kappa / 3.36 / Sigma
    numpy.savetxt("disk_plane",
        numpy.column_stack((R, Sigma, rho, rmsh, sigma[:,0]**0.5, (sigma[:,2]-vel**2)**0.5, \
        sigma[:,1]**0.5, vel, ToomreQ)),
        header="R Sigma rho(R,z=0) height sigma_R sigma_phi sigma_z v_phi ToomreQ", fmt="%.6g")
    ax[0].plot(R, Sigma / (Sigma0 * numpy.exp(-R/Rdisk)), 'r-', label=r'$\Sigma$')
    ax[0].plot(R, rho   / (Sigma0 * numpy.exp(-R/Rdisk) * 0.25/Hdisk), 'g-', label=r'$\rho_{z=0}$')
    ax[0].plot(R, sigma[:,0]**0.5 / (sigmar0 * numpy.exp(-R/rsigmar)), 'b-', label=r'$\sigma_r$')
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)
command   = args.get('DO', 'run').upper()       # [REQ] operation mode: 'RUN' - run a model, 'PLOT' - show the model grid and maps
usehist   = args.get('HIST', 'n')[0] in 'yYtT1' # [OPT] whether to use LOSVD histograms as input (default 'no' is to use GH moments)
variant   = 'Hist' if usehist else 'GH'         # suffix for disinguishing runs using histogramed LOSVDs or GH moments
fileResult= 'results%s.txt' % variant           # [OPT] filename for collecting summary results for the entire model grid
numpy.random.seed(42)  # make things repeatable
numpy.set_printoptions(precision=4, linewidth=200, suppress=True)

### parameters for the density dataset
densityParams = dict(
    type  = 'DensityCylindricalLinear',   # [REQ]: variant of density discretization grid; remaining parameters depend on this choice
    gridr = agama.nonuniformGrid(nnodes=20, xmin=0.2, xmax=100.),  # [REQ] grid in cylindrical radius (TODO: determine automatically?)
    gridz = agama.nonuniformGrid(nnodes=15, xmin=0.2, xmax=15.0),  # [REQ] grid in vertical coordinate
    mmax  = 0  # [OPT] number of azimuthal-harmonic coefficients (0 for axisymmetric systems)
)
filenameMGE = 'mge.txt'       # [REQ] file with parameters of the MGE model for the surface density profile (if MGE is used)

### common parameters for kinematic datasets (though in principle they may also differ between them)
gridv  = numpy.linspace(-500, 500, 26)  # [REQ] the grid in model velocity space (will be multiplied by sqrt(Upsilon) when comparing to data)
velpsf = 0.0                  # [OPT] velocity-space PSF (usually not needed, as the spectroscopic fits produce deconvolved LOSVDs)
# [OPT] define the degree and velocity grid for the observed LOSVD provided as histograms or (less likely) higher-degree B-splines;
# the following two lines are needed [REQ] only if the input is provided in the form of binned LOSVDs (usehist=True),
# but we also use these parameters to generate mock LOSVD histograms if command=='MOCK'
hist_degree = 0               # [OPT] B-spline degree for the observed LOSVDs (0 means histogram)
hist_gridv  = numpy.linspace(-400, 400, 17)  # [OPT] velocity grid for the observed LOSVDs (boundaries of velocity bins, not centers!)

### parameters of the 1st kinematic dataset
    model.iterate()
    printoutInfo(model, 1)

    # now that we have a reasonable guess for the total potential,
    # we may initialize the DF of the stellar disk
    dfDisk = agama.DistributionFunction(pot=model.pot, **iniDFDisk)

    # we can compute the masses even though we don't know the density profile yet
    print "**** STARTING TWO-COMPONENT MODELLING ****\nMasses are: ", \
        "Mhalo=%g,"  % dfHalo.totalMass(), \
        "Mbulge=%g," % dfBulge.totalMass(), \
        "Mdisk=%g"   % dfDisk.totalMass()

    # and replace the static disk component them with a DF-based disk one
    model.components[2] = agama.Component(df=dfDisk, disklike=True, \
        gridR=agama.nonuniformGrid(int(iniSCMDisk['sizeRadialCyl']), \
            float(iniSCMDisk['RminCyl']), float(iniSCMDisk['RmaxCyl'])), \
        gridz=agama.nonuniformGrid(int(iniSCMDisk['sizeVerticalCyl']), \
            float(iniSCMDisk['zminCyl']), float(iniSCMDisk['zmaxCyl'])) )

    # do a few more iterations to obtain the self-consistent density profile for both disks
    for iteration in range(6,9):
        print "Starting iteration #%d" % iteration
        model.iterate()
        printoutInfo(model, iteration)

    print "Computing disk density and velocity profiles"
    R=numpy.linspace(0.2,10,50)
    xyz=numpy.vstack((R,R*0,R*0)).T
    Sigma,_   = agama.GalaxyModel(pot=model.pot, df=dfDisk, af=model.af).projectedMoments(R)
    rho,sigma = agama.GalaxyModel(pot=model.pot, df=dfDisk, af=model.af).moments(xyz)
    force, deriv = model.pot.forceDeriv(xyz)
Example #4
0
"""
import agama, numpy

# density profile
den = agama.Density(type='Dehnen',
                    axisRatioY=0.8,
                    axisRatioZ=0.6,
                    scaleRadius=1,
                    mass=1,
                    gamma=1)

# potential corresponding to this density
pot = agama.Potential(type='Multipole', lmax=8, mmax=6, density=den)

# target1 is discretized density profile
target1 = agama.Target(type='DensityClassicLinear', gridr=agama.nonuniformGrid(25, 0.1, 20.0), \
    axisratioy=0.8, axisratioz=0.6, stripsPerPane=2)

# target2 is discretized kinematic constraint (we will enforce velocity isotropy)
target2 = agama.Target(type='KinemShell',
                       gridR=agama.nonuniformGrid(15, 0.2, 10.0),
                       degree=1)

# construct initial conditions for the orbit library
initcond, weightprior = den.sample(5000, potential=pot)

# integration time is 50 orbital periods
inttimes = 50 * pot.Tcirc(initcond)
# integrate all orbits, storing the recorded data corresponding to each target
# in the data1 and data2 arrays, and the trajectories - in trajs
data1, data2, trajs = agama.orbit(potential=pot, ic=initcond, time=inttimes, \
Example #5
0
    model.iterate()
    printoutInfo(model, 1)

    # now that we have a reasonable guess for the total potential,
    # we may initialize the DF of the stellar disk
    dfDisk = agama.DistributionFunction(pot=model.pot, **iniDFDisk)

    # we can compute the masses even though we don't know the density profile yet
    print "**** STARTING TWO-COMPONENT MODELLING ****\nMasses are: ", \
        "Mhalo=%g,"  % dfHalo.totalMass(), \
        "Mbulge=%g," % dfBulge.totalMass(), \
        "Mdisk=%g"   % dfDisk.totalMass()

    # and replace the static disk component them with a DF-based disk one
    model.components[2] = agama.Component(df=dfDisk, disklike=True, \
        gridR=agama.nonuniformGrid(int(iniSCMDisk['sizeRadialCyl']), \
            float(iniSCMDisk['RminCyl']), float(iniSCMDisk['RmaxCyl'])), \
        gridz=agama.nonuniformGrid(int(iniSCMDisk['sizeVerticalCyl']), \
            float(iniSCMDisk['zminCyl']), float(iniSCMDisk['zmaxCyl'])) )

    # do a few more iterations to obtain the self-consistent density profile for both disks
    for iteration in range(6, 9):
        print "Starting iteration #%d" % iteration
        model.iterate()
        printoutInfo(model, iteration)

    print "Computing disk density and velocity profiles"
    R = numpy.linspace(0.2, 10, 50)
    xyz = numpy.vstack((R, R * 0, R * 0)).T
    Sigma, _ = agama.GalaxyModel(pot=model.pot, df=dfDisk,
                                 af=model.af).projectedMoments(R)
    rho, sigma = agama.GalaxyModel(pot=model.pot, df=dfDisk,
# stellar potential
potstars = agama.Potential(type='Sersic',
                           sersicIndex=4,
                           axisRatioZ=0.6,
                           scaleRadius=1,
                           mass=1)

# central black hole (slightly softened)
potbh = agama.Potential(type='Plummer', scaleRadius=1e-4, mass=0.1)

# total potential
pot = agama.Potential(potstars, potbh)

# discretized density profile is recorded on a grid of radial points and spherical harmonics up to lmax
gridr = agama.nonuniformGrid(
    50, 0.02,
    20.0)  # !! make sure that the grid covers the range of interest !!
target = agama.Target(type='DensitySphHarm', gridr=gridr, lmax=8, mmax=0)

# discretized density profile to be used as the density constraint
rhs = target(potstars)
print("Density constraint values")
for i in range(len(gridr)):
    print("%s: mass= %g" % (target[i], rhs[i]))

# construct initial conditions for the orbit library:
# use the anisotropic Jeans eqs to set the (approximate) shape of the velocity ellipsoid and the mean v_phi;
beta = 0.0  # velocity anisotropy in R/z plane: >0 - sigma_R>sigma_z, <0 - reverse.
kappa = 0.8  # sets the amount of rotation v_phi vs. dispersion sigma_phi; 1 is rather fast rotation, 0 - no rot.
initcond, _ = potstars.sample(10000, potential=pot, beta=beta, kappa=kappa)
Example #7
0
def plotModel(model, df):
    print('Creating density and kinematic plots...')
    gridx = numpy.linspace(0, 0.70, 141)
    gridz = numpy.linspace(0, 0.25, 51)
    gridxz = numpy.column_stack(
        (numpy.tile(gridx, len(gridz)), numpy.repeat(gridz, len(gridx))))
    gridxyz = numpy.column_stack(
        (numpy.tile(gridx, len(gridz)), numpy.zeros(len(gridx) * len(gridz)),
         numpy.repeat(gridz, len(gridx))))
    nsc = model.components[0].getDensity()
    nsd = model.components[1].getDensity()
    rho_nsd = nsd.density(gridxyz).reshape(len(gridz), len(gridx))
    Sig_nsd = nsd.projectedDensity(gridxz, beta=numpy.pi / 2).reshape(
        len(gridz), len(gridx))
    plt.figure(figsize=(20, 15))
    ax = numpy.array(
        [plt.axes([0.035, 0.81 - 0.195 * i, 0.38, 0.18]) for i in range(5)] +
        [plt.axes([0.425, 0.81 - 0.195 * i, 0.38, 0.18])
         for i in range(5)]).reshape(2, 5).T
    ax[0, 0].contour(gridx,
                     gridz,
                     numpy.log10(rho_nsd),
                     levels=numpy.log10(numpy.max(rho_nsd)) +
                     numpy.linspace(-6, -0, 16),
                     cmap='Blues')
    ax[0, 1].contour(gridx,
                     gridz,
                     numpy.log10(Sig_nsd),
                     levels=numpy.log10(numpy.max(Sig_nsd)) +
                     numpy.linspace(-6, -0, 16),
                     cmap='Blues')
    # compute moments on a coarser grid
    gridx = agama.nonuniformGrid(20, 0.02, 0.70)
    gridz = agama.nonuniformGrid(10, 0.02, 0.25)
    gridxz = numpy.column_stack(
        (numpy.tile(gridx, len(gridz)), numpy.repeat(gridz, len(gridx))))
    gridxyz = numpy.column_stack(
        (numpy.tile(gridx, len(gridz)), numpy.zeros(len(gridx) * len(gridz)),
         numpy.repeat(gridz, len(gridx))))
    gm = agama.GalaxyModel(model.potential, df)
    gridv = numpy.linspace(0, 100, 11)
    # intrinsic moments
    vel, vel2 = gm.moments(gridxyz,
                           dens=False,
                           vel=True,
                           vel2=True,
                           beta=numpy.pi / 2)
    plt.clabel(ax[1, 0].contour(gridx,
                                gridz,
                                -vel[:, 2].reshape(len(gridz), len(gridx)),
                                levels=gridv,
                                cmap='Blues'),
               fmt='%.0f')
    plt.clabel(ax[2, 0].contour(gridx,
                                gridz,
                                numpy.sqrt(vel2[:, 2] - vel[:, 2]**2).reshape(
                                    len(gridz), len(gridx)),
                                levels=gridv,
                                cmap='Blues'),
               fmt='%.0f')
    plt.clabel(ax[3, 0].contour(gridx,
                                gridz,
                                numpy.sqrt(vel2[:, 0] - vel[:, 0]**2).reshape(
                                    len(gridz), len(gridx)),
                                levels=gridv,
                                cmap='Blues'),
               fmt='%.0f')
    plt.clabel(ax[4, 0].contour(gridx,
                                gridz,
                                numpy.sqrt(vel2[:, 1] - vel[:, 1]**2).reshape(
                                    len(gridz), len(gridx)),
                                levels=gridv,
                                cmap='Blues'),
               fmt='%.0f')
    # projected moments
    vel, vel2 = gm.moments(gridxz,
                           dens=False,
                           vel=True,
                           vel2=True,
                           beta=numpy.pi / 2)
    plt.clabel(ax[1, 1].contour(gridx,
                                gridz,
                                -vel[:, 2].reshape(len(gridz), len(gridx)),
                                levels=gridv,
                                cmap='Blues'),
               fmt='%.0f')
    plt.clabel(ax[2, 1].contour(gridx,
                                gridz,
                                numpy.sqrt(vel2[:, 2] - vel[:, 2]**2).reshape(
                                    len(gridz), len(gridx)),
                                levels=gridv,
                                cmap='Blues'),
               fmt='%.0f')
    plt.clabel(ax[3, 1].contour(gridx,
                                gridz,
                                numpy.sqrt(vel2[:, 0] - vel[:, 0]**2).reshape(
                                    len(gridz), len(gridx)),
                                levels=gridv,
                                cmap='Blues'),
               fmt='%.0f')
    plt.clabel(ax[4, 1].contour(gridx,
                                gridz,
                                numpy.sqrt(vel2[:, 1] - vel[:, 1]**2).reshape(
                                    len(gridz), len(gridx)),
                                levels=gridv,
                                cmap='Blues'),
               fmt='%.0f')
    labels = ['density', 'v_los', 'sigma_los', 'sigma_R', 'sigma_z']
    colors = ['c', 'm', 'b', 'r', 'g']
    # fiducial fields for computing projected velocity distributions
    points = [[0.05, 0.01], [0.15, 0.01], [0.15, 0.10], [0.30, 0.01]]
    for i in range(5):
        ax[i, 0].set_ylabel('z [kpc]', labelpad=4)
        ax[i, 1].set_yticklabels([])
        ax[i, 0].text(0.5,
                      0.98,
                      'intrinsic ' + labels[i],
                      ha='center',
                      va='top',
                      transform=ax[i, 0].transAxes,
                      color=colors[i])
        ax[i, 1].text(0.5,
                      0.98,
                      'projected ' + labels[i],
                      ha='center',
                      va='top',
                      transform=ax[i, 1].transAxes,
                      color=colors[i])
        if i < 4:
            ax[i, 0].set_xticklabels([])
            ax[i, 1].set_xticklabels([])
        else:
            ax[i, 0].set_xlabel('R [kpc]', labelpad=2)
            ax[i, 1].set_xlabel('R [kpc]', labelpad=2)
        ax[i, 0].set_xlim(min(gridx), max(gridx))
        ax[i, 1].set_xlim(min(gridx), max(gridx))
        ax[i, 0].set_ylim(min(gridz), max(gridz))
        ax[i, 1].set_ylim(min(gridz), max(gridz))
        for k, point in enumerate(points):
            ax[i, 1].text(point[0],
                          point[1],
                          chr(k + 65),
                          ha='center',
                          va='center',
                          color='olive')
    gridv = numpy.linspace(
        -250, 250, 26)  # coarse grid for computing the velocity distribution
    gridV = numpy.linspace(
        -250, 250,
        101)  # fine grid for plotting a smoother spline-interpolated VDF
    vdfx, vdfz, vdfd = gm.vdf(points, gridv, beta=numpy.pi / 2)
    for i in range(4):
        ax = plt.axes([0.845, 0.75 - 0.24 * i, 0.15, 0.225])
        ax.plot(gridV, vdfd[i](-gridV), 'b', label='f(v_los)')
        ax.plot(gridV, vdfx[i](-gridV), 'r', label='f(v_R)')
        ax.plot(gridV, vdfz[i](-gridV), 'g', label='f(v_z)')
        ax.set_yscale('log')
        ax.text(0.02,
                0.98,
                'field %s' % chr(i + 65),
                ha='left',
                va='top',
                transform=ax.transAxes,
                color='olive')
        ax.set_xlim(min(gridv), max(gridv))
        ax.set_ylim(1e-5, 3e-2)
        if i < 3:
            ax.set_xticklabels([])
        else:
            ax.set_xlabel('V [km/s]')
        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()
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
ca = numpy.cos(ang)
ca[18] = ca[54] = 0
circ = [numpy.column_stack((rr * ca, rr * sa)) for rr in gridr[1:]]
poly = [circ[0]] + [
    numpy.vstack((p1, p2[::-1])) for p1, p2 in zip(circ[1:], circ[:-1])
]
numaper = len(