Example Dysmalpy 2D fitting, using fitting wrapper

In this example, we use dysmalpy to measure the kinematics of galaxy GS4_43501 at \(z=1.613\) in 2D, using a fitting wrapper which simplifies the implementation of the fitting algorithm to the user. In this specific case, the fittign method is \(\texttt{MPFIT}\), as specified at the bottom of the fitting_2D_mpfit.params file. The notebook shows how to find the best fit models for the two-dimensional velocity and velocity dispersion profiles (\(v(x,y)\) and \(\sigma(x,y)\)). These fits allow us to measure quantities such as the total mass (disk+bulge), the effective radius \(r_\mathrm{eff}\), dark matter fraction \(f_\mathrm{DM}\) and velocity dispersion \(\sigma_0\).

The fitting includes the following components:

  • Disk + Bulge

  • NFW halo

  • Constant velocity dispersion

The structure of the notebook is the following:

  1. Setup steps (and load the params file)

  2. Run Dysmalpy fitting: 2D wrapper, with fit method= MPFIT

  3. Examine results

1) Setup steps

Import modules

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

from dysmalpy.fitting_wrappers import dysmalpy_fit_single
from dysmalpy.fitting_wrappers import utils_io
from dysmalpy import fitting

import os

import numpy as np
INFO:numexpr.utils:Note: NumExpr detected 10 cores but "NUMEXPR_MAX_THREADS" not set, so enforcing safe limit of 8.
INFO:numexpr.utils:NumExpr defaulting to 8 threads.

Setup notebook

# Setup plotting
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline

mpl.rcParams['figure.dpi']= 300
mpl.rc("savefig", dpi=300)

from IPython.core.display import Image

Set data, output paths

  • Note this will override the datadir and outdir specified in the param file.

    • (This is useful for the example here. When running from command line, it’s recommended to properly set the directories in the param file.)

# Data directory (datadir = /YOUR/DATA/PATH/)
filepath = os.path.abspath(fitting.__file__)
datadir = os.sep.join(os.path.dirname(filepath).split(os.sep)[:-1]+["tests", "test_data", ""])

# Load the parameters file from the examples directory
param_path = os.sep.join(os.path.dirname(filepath).split(os.sep)[:-1]+["examples", "examples_param_files", ""])
param_filename = param_path+'fitting_2D_mpfit.params'
print(param_filename)

# Where to save output files (output = /YOUR/OUTPUTS/PATH)
outdir = '/Users/sedona/data/dysmalpy_test_examples/JUPYTER_OUTPUT_2D_FITTING_WRAPPER/'
outdir = '/Users/jespejo/Dropbox/Postdoc/Data/dysmalpy_test_examples/JUPYTER_OUTPUT_2D_FITTING_WRAPPER/'
outdir_mpfit = outdir + 'MPFIT/'
/Users/jespejo/anaconda3/envs/test_dysmalpy/lib/python3.11/site-packages/dysmalpy/examples/examples_param_files/fitting_2D_mpfit.params

Settings in parameter file:

Note there are many commented out options / parameters. These given an more complete overview of the settings & parameters that can be specified with the fitting wrapper parameter files.

with open(param_filename, 'r') as f:
    print(f.read())
# Example parameters file for fitting a single object with 1D data
# Note: DO NOT CHANGE THE NAMES IN THE 1ST COLUMN AND KEEP THE COMMAS!!
# See README for a description of each parameter and its available options.

# ******************************* OBJECT INFO **********************************
galID,    GS4_43501    # Name of your object
z,        1.613        # Redshift



# ****************************** DATA INFO *************************************

datadir,          None                                   # Optional: Full path to data directory.

fdata_vel,            GS4_43501_Ha_vm.fits        # Full path to vel map. Alternatively, just the filename if 'datadir' is set.
fdata_verr,           GS4_43501_Ha_vm_err.fits    # Full path to vel. err map. Alternatively, just the filename if 'datadir' is set.
fdata_disp,           GS4_43501_Ha_dm.fits        # Full path to disp map. Alternatively, just the filename if 'datadir' is set.
fdata_derr,           GS4_43501_Ha_dm_err.fits    # Full path to disp. err map. Alternatively, just the filename if 'datadir' is set.
fdata_mask,           GS4_43501_Ha_m.fits         # Full path to mask
                                                         #   -- strongly recommended to have a mask
                                                         # Alternatively, just the filename if 'datadir' is set.
data_inst_corr,   True
symmetrize_data,  False                                  # Symmetrize data before fitting?

smoothing_type,       median                             # Is the data median smoothed
                                                         #   before extracting maps?
smoothing_npix,       3                                  # Number of pixels for smoothing aperture

## GALAXY CENTER:
# IMPORTANT: 0 indexed, so coordinates go from [0, nX-1] and [0, nY-1].
# So if using QFitsView, will need to subtract 1 from both coords (as QFitsView goes from [1,nX] and [1,nY])
xcenter,              None                       # Center position in maps, x coord. Default: (nX-1)/2.
ycenter,              None                       # Center position in maps, y coord. Default: (nY-1)/2.


# ***************************** OUTPUT *****************************************
outdir,           GS4_43501_2D_out/         # Full path for output directory


# ***************************** OBSERVATION SETUP ******************************

# Instrument Setup
# ------------------
pixscale,         0.125        # Pixel scale in arcsec/pixel
fov_npix,         37           # Number of pixels on a side of model cube
spec_type,   velocity          # DON'T CHANGE!
spec_start,     -1000.         # Starting value for spectral axis       // generally don't change
spec_step,         10.         # Step size for spectral axis in km/s    // generally don't change
nspec,            201          # Number of spectral steps               // generally don't change

# LSF Setup
# ---------
use_lsf,          True         # True/False if using an LSF
sig_inst_res,     51.0         # Instrumental dispersion in km/s


# PSF Setup
# ---------
psf_type,         Gaussian     # Gaussian, Moffat, or DoubleGaussian
psf_fwhm,         0.55         # PSF FWHM in arcsecs
psf_beta,         -99.         # Beta parameter for a Moffat PSF

# ## ELLIPTICAL PSF:
# psf_type,         Gaussian     # Gaussian, Moffat, or DoubleGaussian
# psf_fwhm_major,   0.55         # PSF major axis FWHM in arcsecs
# psf_fwhm_minor,   0.25         # PSF minor axis FWHM in arcsecs
# psf_PA,           0.           # PA of PSF major axis, in deg E of N. (0=N, 90=E)
# psf_beta,         -99.         # Beta parameter for a Moffat PSF

# # DoubleGaussian:  settings instead of psf_fwhm
# psf_type,         DoubleGaussian
# psf_fwhm1,        0.16         # FWHM of PSF component 1, in arcsecs. SINFONI AO: 0.16
# psf_fwhm2,        0.48         # FWHM of PSF component 1, in arcsecs. SINFONI AO: 0.48
# psf_scale1,       0.368        # Flux scaling (*not* peak height) of component 1. SINFONI AO: 0.368
# psf_scale2,       0.632        # Flux scaling (*not* peak height) of component 2. SINFONI AO: 0.632


# **************************** SETUP MODEL *************************************

# Model Settings
# -------------
# List of components to use:  SEPARATE WITH SPACES
## MUST always keep:            geometry   zheight_gaus
## RECOMMENDED:   always keep:   disk+bulge   const_disp_prof
components_list,         disk+bulge   const_disp_prof   geometry   zheight_gaus  halo

# possible options:
#       disk+bulge, sersic, blackhole
#       const_disp_prof,   geometry,   zheight_gaus,  halo,
#       radial_flow, uniform_planar_radial_flow, uniform_bar_flow, uniform_wedge_flow,
#       unresolved_outflow, biconical_outflow,
#       CAUTION: azimuthal_planar_radial_flow, variable_bar_flow, spiral_flow

# List of components that emit light. SEPARATE WITH SPACES
##   Current options: disk+bulge / bulge / disk [corresponding to the mass disk+bulge component],
##              also:    light_sersic, light_gaussian_ring
light_components_list,   disk
# NOTE: if a separate light profile (eg light_sersic) is used,
#       this MUST be changed to  e.g., 'light_components_list,   light_sersic'

adiabatic_contract,  False     # Apply adiabatic contraction?
pressure_support,    True      # Apply assymmetric drift correction?
noord_flat,          True      # Apply Noordermeer flattenning?
oversample,          1         # Spatial oversample factor
oversize,            1         # Oversize factor

moment_calc,         False     # If False, observed maps fit with GAUSSIANS

zcalc_truncate,      True      # Truncate in zgal direction when calculating or not
n_wholepix_z_min,    3         # Minimum number of whole pixels in zgal dir, if zcalc_truncate=True


# ********************************************************************************
# DISK + BULGE
# ------------

# Initial Values
total_mass,           11.0     # Total mass of disk and bulge log(Msun)
bt,                   0.3     # Bulge-to-Total Ratio
r_eff_disk,           5.0     # Effective radius of disk in kpc
n_disk,               1.0      # Sersic index for disk
invq_disk,            5.0      # disk scale length to zheight ratio for disk

n_bulge,              4.0      # Sersic index for bulge
invq_bulge,           1.0      # disk scale length to zheight ratio for bulge
r_eff_bulge,          1.0      # Effective radius of bulge in kpc

# Fixed? True if its a fixed parameter, False otherwise
total_mass_fixed,     False
r_eff_disk_fixed,     False

bt_fixed,             True
n_disk_fixed,         True
r_eff_bulge_fixed,    True
n_bulge_fixed,        True

# Parameter bounds. Lower and upper bounds
total_mass_bounds,   10.0  13.0
bt_bounds,           0.0  1.0
r_eff_disk_bounds,   0.1  30.0
n_disk_bounds,       1.0  8.0
r_eff_bulge_bounds,  1.0  5.0
n_bulge_bounds,      1.0  8.0



# # ********************************************************************************
# # BLACK HOLE
# # ------------
#
# # Initial Values
# BH_mass,             11.     # log(Msun)
#
# # Fixed? True if its a fixed parameter, False otherwise
# BH_mass_fixed,       False
#
# # Parameter bounds. Lower and upper bounds
# BH_mass_bounds,      6.  18.




# # ********************************************************************************
# # Separate light profile: (Truncated) Sersic profile
# # ------------
# # Initial values
# L_tot_sersic,        1.     # arbitrary units
# lr_eff,              4.     # kpc
# lsersic_n,           1.     # Sersic index of light profile
# lsersic_rinner,      0.     # [kpc] Inner truncation radius of sersic profile. 0   = no truncation
# lsersic_router,     inf     # [kpc] Outer truncation radius of sersic profile. inf = no truncation
#
# # Fixed? True if its a fixed parameter, False otherwise
# L_tot_sersic_fixed,   True
# lr_eff_fixed,         False
# lsersic_n_fixed,      True
# lsersic_rinner_fixed, True
# lsersic_router_fixed, True
#
# # Parameter bounds. Lower and upper bounds
# L_tot_sersic_bounds,    0.   2.       # arbitrary units
# lr_eff_bounds,          0.5  15.      # kpc
# lsersic_n_bounds,       0.5  8.
# lsersic_rinner_bounds,   0.  5.	    # kpc
# lsersic_router_bounds,   4.  20.      # kpc


# # ********************************************************************************
# # Separate light profile: Gaussian ring
# # ------------
# # Initial values
# L_tot_gaus_ring,     1.      # arbitrary units
# R_peak_gaus_ring,    6.      # kpc
# FWHM_gaus_ring,   1.      # kpc
#
# # Fixed? True if its a fixed parameter, False otherwise
# L_tot_gaus_ring_fixed,    True
# R_peak_gaus_ring_fixed,   True
# FWHM_gaus_ring_fixed,  True
#
# # Parameter bounds. Lower and upper bounds
# L_tot_gaus_ring_bounds,   0.  2.    # arbitrary units
# R_peak_gaus_ring_bounds,  0.  15.   # kpc
# FWHM_gaus_ring_bounds, 0.1 10.   # kpc




# ********************************************************************************
# ********************************************************************************
# ********************************************************************************
# DARK MATTER HALO
# ----------------

# Halo type: options: NFW / twopowerhalo / burkert / einasto / dekelzhao
halo_profile_type,   NFW

# ** NOTE **: Uncomment the section below corresponding to the selected halo type.

# ********************************************************************************
#    NFW halo

# Initial Values
mvirial,             11.0       # Halo virial mass in log(Msun)
halo_conc,           5.0        # Halo concentration parameter
fdm,                 0.5        # Dark matter fraction at r_eff_disk

# Fixed? True if its a fixed parameter, False otherwise. Also set False if it will be tied (below)
mvirial_fixed,       True
halo_conc_fixed,     True
fdm_fixed,           False

# Parameter bounds. Lower and upper bounds
mvirial_bounds,      10.0 13.0
halo_conc_bounds,    1.0 20.0
fdm_bounds,          0.0 1.0

# Tie the parameters?
fdm_tied,            True      # for NFW, fdm_tied=True determines fDM from Mvirial (+baryons)
mvirial_tied,        False     # for NFW, mvirial_tied=True determines Mvirial from fDM (+baryons)
# ********************************************************************************

# # ********************************************************************************
# #    Two-power halo
#
# # Initial Values
# mvirial,             11.5       # Halo virial mass in log(Msun)
# halo_conc,           5.0        # Halo concentration parameter
# fdm,                 0.5        # Dark matter fraction at r_eff_disk
# alpha,               1.         # TPH: inner slope. NFW has alpha=1
# beta,                3.         # TPH: outer slope. NFW has beta=3
#
# # Fixed? True if its a fixed parameter, False otherwise. Also set False if it will be tied (below)
# mvirial_fixed,       False
# halo_conc_fixed,     True
# fdm_fixed,           False
# alpha_fixed,         False
# beta_fixed,          True
#
# # Parameter bounds. Lower and upper bounds
# mvirial_bounds,      10.0 13.0
# halo_conc_bounds,    1.0 20.0
# fdm_bounds,          0.0 1.0
# alpha_bounds,        0.0  3.0
# beta_bounds,         1.0  4.0
#
# # Tie the parameters?
# fdm_tied,       True      # for non-NFW, fdm_tied=True determines fDM from other halo params (+baryons)
# mvirial_tied,   True      # for non-NFW, mvirial_tied=True determines Mvirial from SMHM+fgas + baryon total_mass
# alpha_tied,     False     # for TPH, alpha_tied=True determines alpha from free fDM + other parameters.
#
# ### OTHER SETTINGS:
# mhalo_relation,    Moster18     ## SMHM relation to use for tying Mvir to Mbar. options: Moster18 / Behroozi13
#
# fgas,                0.5        # Gas fraction for SMHM inference of Mvir if 'mvirial_tied=True'
# lmstar,              -99.       # Currently code uses fgas to infer lmstar
#                                 # from fitting baryon total_mass for SMHM relation
# # ********************************************************************************

# # ********************************************************************************
# #    Burkert halo
#
# # Initial Values
# mvirial,             11.5       # Halo virial mass in log(Msun)
# halo_conc,           5.0        # Halo concentration parameter
# fdm,                 0.5        # Dark matter fraction at r_eff_disk
# rB,                  10.        # Burkert: Halo core radius, in kpc
#
# # Fixed? True if its a fixed parameter, False otherwise. Also set False if it will be tied (below)
# mvirial_fixed,       False
# halo_conc_fixed,     True
# fdm_fixed,           False
# rB_fixed,            False
#
# # Parameter bounds. Lower and upper bounds
# mvirial_bounds,      10.0 13.0
# halo_conc_bounds,    1.0 20.0
# fdm_bounds,          0.0 1.0
# rB_bounds,           1.0  20.0
#
# # Tie the parameters?
# fdm_tied,       True      # for non-NFW, fdm_tied=True determines fDM from other halo params (+baryons)
# mvirial_tied,   True      # for non-NFW, mvirial_tied=True determines Mvirial from SMHM+fgas + baryon total_mass
# rB_tied,        False     # for Burkert, rB_tied=True determines rB from free fDM + other parameters.
#
# ### OTHER SETTINGS:
# mhalo_relation,    Moster18     ## SMHM relation to use for tying Mvir to Mbar. options: Moster18 / Behroozi13
#
# fgas,                0.5        # Gas fraction for SMHM inference of Mvir if 'mvirial_tied=True'
# lmstar,              -99.       # Currently code uses fgas to infer lmstar
#                                 # from fitting baryon total_mass for SMHM relation
# # ********************************************************************************

# # ********************************************************************************
# #    Einasto halo
# # Initial Values
# mvirial,             11.5       # Halo virial mass in log(Msun)
# halo_conc,           5.0        # Halo concentration parameter
# fdm,                 0.5        # Dark matter fraction at r_eff_disk
# alphaEinasto,        1.         # Einasto: Halo profile index
#
# # Fixed? True if its a fixed parameter, False otherwise. Also set False if it will be tied (below)
# mvirial_fixed,       False
# halo_conc_fixed,     True
# fdm_fixed,           False
# alphaEinasto_fixed,  False
#
# # Parameter bounds. Lower and upper bounds
# mvirial_bounds,      10.0 13.0
# halo_conc_bounds,    1.0 20.0
# fdm_bounds,          0.0 1.0
# alphaEinasto_bounds, 0.0  2.0
#
# # Tie the parameters?
# fdm_tied,           True      # for non-NFW, fdm_tied=True determines fDM from other halo params (+baryons)
# mvirial_tied,       True      # for non-NFW, mvirial_tied=True determines Mvirial from SMHM+fgas + baryon total_mass
# alphaEinasto_tied,  False     # for Einasto, alphaEinasto_tied=True determines alphaEinasto from free fDM + other params.
#
# ### OTHER SETTINGS:
# mhalo_relation,    Moster18     ## SMHM relation to use for tying Mvir to Mbar. options: Moster18 / Behroozi13
#
# fgas,                0.5        # Gas fraction for SMHM inference of Mvir if 'mvirial_tied=True'
# lmstar,              -99.       # Currently code uses fgas to infer lmstar
#                                 # from fitting baryon total_mass for SMHM relation
# # ********************************************************************************


# # ********************************************************************************
# #    Dekel-Zhao halo
# # Initial Values
# mvirial,             12.0       # Halo virial mass in log(Msun)
# s1,                  1.5        # Inner logarithmic slope (at resolution r1=0.01*Rvir)
# c2,                  25.0       # Concentration parameter (defined relative to c, a)
# fdm,                 0.5        # Dark matter fraction at r_eff_disk
#
# # Fixed? True if its a fixed parameter, False otherwise. Also set False if it will be tied (below)
# mvirial_fixed,       False
# s1_fixed,            False
# c2_fixed,            False
# fdm_fixed,           False
#
# # Parameter bounds. Lower and upper bounds
# mvirial_bounds,      10.0 13.0  # log(Msun)
# s1_bounds,           0.0  2.0
# c2_bounds,           0.0  40.0
# fdm_bounds,          0.0  1.0
#
# # Tie the parameters?
# mvirial_tied,       True      # mvirial_tied=True determines Mvirial from fDM, s1, c2.
# s1_tied,            True      # Tie the s1 to M*/Mvir using best-fit Freundlich+20 (Eqs 45, 47, 48, Table 1)
# c2_tied,            True      # Tie the c2 to M*/Mvir using best-fit Freundlich+20 (Eqs 47, 49, Table 1)
# fdm_tied,           False     # for non-NFW, fdm_tied=True determines fDM from other halo params (+baryons)
#
# ### OTHER SETTINGS:
# lmstar,             10.5      # Used to infer s1, c2 if s1_tied or c2_tied = True
#
# # ********************************************************************************


# ********************************************************************************
# INTRINSIC DISPERSION PROFILE
# ------------------

# Initial Values
sigma0,              39.0      # Constant intrinsic dispersion value

# Fixed? True if its a fixed parameter, False otherwise
sigma0_fixed,        False

# Parameter bounds. Lower and upper bounds
sigma0_bounds,       5.0 300.0



# ********************************************************************************
# ********************************************************************************
# ********************************************************************************
# HIGHER ORDER COMPONENTS: INFLOW, OUTFLOW
# ----------------------------------------

# # ********************************************************************************
# # UNIFORM SPHERICAL RADIAL FLOW -- in rhat direction in spherical coordinates
# # radial_flow
# # -------------------
#
# vr,     -90.             # Radial flow [km/s]. Positive: Outflow. Negative: Inflow.


# # ********************************************************************************
# # UNIFORM PLANAR RADIAL FLOW -- in Rhat direction in cylindrical coordinates
# #                               (eg, radial in galaxy midplane)
# # uniform_planar_radial_flow
# # -------------------
#
# vr,     -90.             # Radial flow [km/s]. Positive: Outflow. Negative: Inflow.


# # ********************************************************************************
# # UNIFORM BAR FLOW -- in xhat direction along bar in cartesian coordinates,
# #                     with bar at an angle relative to galaxy major axis (blue)
# # uniform_bar_flow
# # -------------------
#
# vbar,     -90.             # Bar flow [km/s]. Positive: Outflow. Negative: Inflow.
# phi,       90.             # Azimuthal angle of bar [degrees], counter-clockwise from blue major axis.
#                            # Default is 90 (eg, along galaxy minor axis)
# bar_width,  2              # Width of the bar perpendicular to bar direction.
#                            # Bar velocity only is nonzero between -bar_width/2 < ygal < bar_width/2.


# # ********************************************************************************
# # UNIFORM WEDGE FLOW -- in planar radial flow in cylindrical coordinates, restricted to pos, neg wedges
# # uniform_wedge_flow
# # -------------------
#
# vr,       -90.             # Radial flow [km/s]. Positive: Outflow. Negative: Inflow.
# theta,     60.             # Opening angle of wedge [deg]. (the full angular span)
# phi,       90.             # Angle offset relative to the galaxy angle, so the wedge center is at phi.
#                            # Default: 90 deg, so centered along minor axis


# # ********************************************************************************
# # UNRESOLVED OUTFLOW -- at galaxy center (ie, AGN unresolved outflow)
# # unresolved_outflow
# # -------------------
#
# vcenter,    0.             # Central velocity of the Gaussian in km/s
# fwhm,       1000.          # FWHM of the Gaussian in km/s
# amplitude,  1.e12          # Amplitude of the Gaussian, for flux in ~M/L=1 luminosity units
#                            # with the dimming applied ... roughly ....


# # ********************************************************************************
# # BICONICAL OUTFLOW
# # biconical_outflow
# # -------------------
#
# n,          0.5                 # Power law index
# vmax,       500.                # Maximum velocity of the outflow in km/s
# rturn,       5.                 # Turn-over radius in kpc of the velocty profile
# thetain,     30.                # Half inner opening angle in degrees. Measured from the bicone axis
# dtheta,      20.                # Difference between inner and outer opening angle in degrees
# rend,        10.                # Maximum radius of the outflow in kpc
# norm_flux,   8.                 # Log flux amplitude of the outflow at r = 0.
#                                 # Need to check dimming/flux conventions
# tau_flux,    1.                 # Exponential decay rate of the flux
# biconical_profile_type, both    # Type of velocity profile:
#                                 # 'both', 'increase', 'decrease', 'constant'
# biconical_outflow_dispersion, 80.  # Dispersion (stddev of gaussian) of biconical outflow, km/s


# # ********************************************************************************
# # VARIABLE BAR FLOW -- in xhat direction along bar in cartesian coordinates,
# #                      with bar at an angle relative to galaxy major axis (blue)
# #                      CAUTION!!!
# # variable_bar_flow
# # -------------------
#
# vbar_func_bar_flow,   -90.*np.exp(-R/5.)  # Bar flow FUNCTION [km/s]. Positive: Outflow. Negative: Inflow.
# phi,       90.             # Azimuthal angle of bar [degrees], counter-clockwise from blue major axis.
#                            # Default is 90 (eg, along galaxy minor axis)
# bar_width,  2              # Width of the bar perpendicular to bar direction.
#                            # Bar velocity only is nonzero between -bar_width/2 < ygal < bar_width/2.


# # ********************************************************************************
# # AZIMUTHAL PLANAR RADIAL FLOW -- in Rhat direction in cylindrical coordinates
# #                               (eg, radial in galaxy midplane), with an added azimuthal term
# #                               CAUTION!!!
# # azimuthal_planar_radial_flow
# # -------------------
#
# vr_func_azimuthal_planar_flow,    -90.*np.exp(-R/5.)  # Radial flow [km/s].
#                                                       # Positive: Outflow. Negative: Inflow.
# m,          2               #  Number of modes in the azimuthal pattern. m=0 gives a purely radial profile.
# phi0,       0.              # Angle offset relative to the galaxy angle [deg],
#                             # so the azimuthal variation goes as cos(m(phi_gal - phi0))



# # ********************************************************************************
# # SPIRAL DENSIY WAVE FLOW -- as in Davies et al. 2009, ApJ, 702, 114
# #                           Here assuming CONSTANT velocity -- try to match real Vrot...
# #                           CAUTION!!!  NO SPACES IN FUNCTION DEFINITONS!
# # spiral_flow
# # -------------------
#
# Vrot_func_spiral_flow,   150.+0.*R        # Unperturbed rotation velocity of the galaxy
# dVrot_dR_func_spiral_flow, 0.*R             # Derivative of Vrot(R) -- ideally evaluated analytically, otherwise very slow.
# rho0_func_spiral_flow, 1.e11*np.exp(-R/5.)  # Unperturbed midplane density profile of the galaxy
# f_func_spiral_flow, (np.sqrt(m**2-2.)*Vrot(R)/cs)*np.log(R)  # Function describing the spiral shape, m*phi = f(R)
#                                                                     # with k = df/dR
# k_func_spiral_flow, (np.sqrt(m**2-2.)*Vrot(R)/cs)/R            # Function for radial wavenumber
#
# m,       2              # Number of photometric/density spiral arms.
# cs,     10.             # Sound speed of medium, in km/s.
# epsilon, 1.             # Density contrast of perturbation (unitless).
# Om_p,   0.              # Angular speed of the driving force, Omega_p
# phi0,   0.              # Angle offset of the arm winding, in degrees. Default: 0.


# ********************************************************************************
# ********************************************************************************
# ********************************************************************************


# ********************************************************************************
# ZHEIGHT PROFILE
# ---------------

# Initial Values
sigmaz,              0.9      # Gaussian width of the galaxy in z, in kpc

# Fixed? True if its a fixed parameter, False otherwise
sigmaz_fixed,        False

# Parameter bounds. Lower and upper bounds
sigmaz_bounds,       0.1 1.0


# Tie the zheight to the effective radius of the disk?
# If set to True, make sure sigmaz_fixed is False
zheight_tied,        True


# GEOMETRY
# --------

# Initial Values
inc,                 72.   # Inclination of galaxy, 0=face-on, 90=edge-on
pa,                  145.
xshift,              0.        # pixels
yshift,              -0.13        # pixels
vel_shift,           0.      # km/s

# Fixed? True if its a fixed parameter, False otherwise
inc_fixed,           False
pa_fixed,            False
xshift_fixed,        False
yshift_fixed,        False
vel_shift_fixed,     False

# Parameter bounds. Lower and upper bounds
inc_bounds,          42.   82.
pa_bounds,           132.  152.
xshift_bounds,       -1.5  1.5        # pixels
yshift_bounds,       -1.5  1.5        # pixels
vel_shift_bounds,    -100.  100.        # km/s



# **************************** Fitting Settings ********************************

fit_method,      mpfit     # mcmc, nested, or mpfit

do_plotting,     True      # Produce all output plots?

fitdispersion,   True      # Simultaneously fit the velocity and dispersion?
fitflux,         False     # Also fit for the flux?


# MPFIT Settings
#----------------
maxiter,         200       # Maximum number of iterations before mpfit quits

Add some settings for this notebook example:

plot_type = 'png'

Run Dysmalpy fitting: 2D wrapper, with fit method= MPFIT

dysmalpy_fit_single.dysmalpy_fit_single(param_filename=param_filename, 
                                        datadir=datadir, outdir=outdir_mpfit, 
                                        plot_type='png', overwrite=True)
INFO:DysmalPy:dysmalpy.Galaxy:
********************************************************************
*** INFO ***
instrument.fov[0,1]=(37,37) is being reset to match 2D maps (27, 27)
********************************************************************

INFO:DysmalPy:*************************************
INFO:DysmalPy: Fitting: GS4_43501 using MPFIT
INFO:DysmalPy:    obs: OBS
INFO:DysmalPy:        velocity file: /Users/jespejo/anaconda3/envs/test_dysmalpy/lib/python3.11/site-packages/dysmalpy/tests/test_data/GS4_43501_Ha_vm.fits
INFO:DysmalPy:        dispers. file: /Users/jespejo/anaconda3/envs/test_dysmalpy/lib/python3.11/site-packages/dysmalpy/tests/test_data/GS4_43501_Ha_dm.fits
INFO:DysmalPy:        nSubpixels: 1
INFO:DysmalPy:    mvirial_tied: False
INFO:DysmalPy:
MPFIT Fitting:
Start: 2024-11-04 15:59:59.073699

INFO:DysmalPy:Iter 1  CHI-SQUARE = 4863.95731  DOF = 404
   disk+bulge:total_mass = 11  
   disk+bulge:r_eff_disk = 5  
   dispprof_LINE:sigma0 = 39  
   geom_1:inc = 72  
   geom_1:pa = 145  
   geom_1:xshift = 0  
   geom_1:yshift = -0.13  
   geom_1:vel_shift = 0  

INFO:DysmalPy:Iter 2  CHI-SQUARE = 3391.858655  DOF = 404
   disk+bulge:total_mass = 11.02256749  
   disk+bulge:r_eff_disk = 6.314016605  
   dispprof_LINE:sigma0 = 33.36135137  
   geom_1:inc = 80.1969795  
   geom_1:pa = 144.0786096  
   geom_1:xshift = -0.3915117315  
   geom_1:yshift = -0.2053268919  
   geom_1:vel_shift = 0.470343974  

INFO:DysmalPy:Iter 3  CHI-SQUARE = 3070.291053  DOF = 404
   disk+bulge:total_mass = 11.17493291  
   disk+bulge:r_eff_disk = 8.822236059  
   dispprof_LINE:sigma0 = 28.7835928  
   geom_1:inc = 79.525108  
   geom_1:pa = 143.0253885  
   geom_1:xshift = -0.4590096803  
   geom_1:yshift = -0.2284259521  
   geom_1:vel_shift = 0.3610861955  

INFO:DysmalPy:Iter 4  CHI-SQUARE = 2124.533719  DOF = 404
   disk+bulge:total_mass = 11.23876486  
   disk+bulge:r_eff_disk = 10.84611558  
   dispprof_LINE:sigma0 = 26.41974081  
   geom_1:inc = 78.24159899  
   geom_1:pa = 144.0666743  
   geom_1:xshift = -0.5126667736  
   geom_1:yshift = -0.5584810651  
   geom_1:vel_shift = 0.8034814807  

INFO:DysmalPy:Iter 5  CHI-SQUARE = 1858.95427  DOF = 404
   disk+bulge:total_mass = 11.22284368  
   disk+bulge:r_eff_disk = 10.55852661  
   dispprof_LINE:sigma0 = 26.95611728  
   geom_1:inc = 77.02489459  
   geom_1:pa = 145.2829668  
   geom_1:xshift = -0.5206432527  
   geom_1:yshift = -0.8504292774  
   geom_1:vel_shift = 1.037174844  

INFO:DysmalPy:Iter 6  CHI-SQUARE = 1799.964493  DOF = 404
   disk+bulge:total_mass = 11.24931363  
   disk+bulge:r_eff_disk = 11.37911566  
   dispprof_LINE:sigma0 = 26.63716887  
   geom_1:inc = 77.25523512  
   geom_1:pa = 146.549937  
   geom_1:xshift = -0.3864614764  
   geom_1:yshift = -0.9338220054  
   geom_1:vel_shift = 0.9299774842  

INFO:DysmalPy:Iter 7  CHI-SQUARE = 1755.790678  DOF = 404
   disk+bulge:total_mass = 11.23880745  
   disk+bulge:r_eff_disk = 11.10273218  
   dispprof_LINE:sigma0 = 24.51821952  
   geom_1:inc = 76.93602404  
   geom_1:pa = 146.1685048  
   geom_1:xshift = -0.1835254312  
   geom_1:yshift = -1.073486741  
   geom_1:vel_shift = 0.7280803198  

INFO:DysmalPy:Iter 8  CHI-SQUARE = 1755.033023  DOF = 404
   disk+bulge:total_mass = 11.24050004  
   disk+bulge:r_eff_disk = 11.11478921  
   dispprof_LINE:sigma0 = 24.69401168  
   geom_1:inc = 76.63700138  
   geom_1:pa = 146.7513809  
   geom_1:xshift = -0.1953901937  
   geom_1:yshift = -1.070126186  
   geom_1:vel_shift = 0.7261058258  

INFO:DysmalPy:Iter 9  CHI-SQUARE = 1750.217717  DOF = 404
   disk+bulge:total_mass = 11.24061494  
   disk+bulge:r_eff_disk = 11.11607529  
   dispprof_LINE:sigma0 = 25.01605169  
   geom_1:inc = 76.67592341  
   geom_1:pa = 146.7793715  
   geom_1:xshift = -0.185203532  
   geom_1:yshift = -1.070160913  
   geom_1:vel_shift = 0.7289132677  

INFO:DysmalPy:Iter 10  CHI-SQUARE = 1750.082449  DOF = 404
   disk+bulge:total_mass = 11.24063747  
   disk+bulge:r_eff_disk = 11.11622614  
   dispprof_LINE:sigma0 = 25.11113924  
   geom_1:inc = 76.67072013  
   geom_1:pa = 146.7774838  
   geom_1:xshift = -0.1858546538  
   geom_1:yshift = -1.070151373  
   geom_1:vel_shift = 0.7287818672  

INFO:DysmalPy:Iter 11  CHI-SQUARE = 1750.022426  DOF = 404
   disk+bulge:total_mass = 11.24064704  
   disk+bulge:r_eff_disk = 11.11627646  
   dispprof_LINE:sigma0 = 25.12610883  
   geom_1:inc = 76.66746622  
   geom_1:pa = 146.7783321  
   geom_1:xshift = -0.1858525364  
   geom_1:yshift = -1.070192788  
   geom_1:vel_shift = 0.7289287385  

INFO:DysmalPy:Iter 12  CHI-SQUARE = 1749.878728  DOF = 404
   disk+bulge:total_mass = 11.24065361  
   disk+bulge:r_eff_disk = 11.11629826  
   dispprof_LINE:sigma0 = 25.15805123  
   geom_1:inc = 76.6668677  
   geom_1:pa = 146.7786316  
   geom_1:xshift = -0.1856982592  
   geom_1:yshift = -1.070196524  
   geom_1:vel_shift = 0.7289823194  

INFO:DysmalPy:Iter 13  CHI-SQUARE = 1749.864321  DOF = 404
   disk+bulge:total_mass = 11.24065464  
   disk+bulge:r_eff_disk = 11.11629646  
   dispprof_LINE:sigma0 = 25.16055143  
   geom_1:inc = 76.66647618  
   geom_1:pa = 146.7787255  
   geom_1:xshift = -0.1856770347  
   geom_1:yshift = -1.070198525  
   geom_1:vel_shift = 0.7289948036  

INFO:DysmalPy:Iter 14  CHI-SQUARE = 1749.835605  DOF = 404
   disk+bulge:total_mass = 11.24065611  
   disk+bulge:r_eff_disk = 11.11628035  
   dispprof_LINE:sigma0 = 25.16788657  
   geom_1:inc = 76.66603205  
   geom_1:pa = 146.7790628  
   geom_1:xshift = -0.185658349  
   geom_1:yshift = -1.070197881  
   geom_1:vel_shift = 0.7290073537  

INFO:DysmalPy:Iter 15  CHI-SQUARE = 1749.806514  DOF = 404
   disk+bulge:total_mass = 11.24065803  
   disk+bulge:r_eff_disk = 11.11632404  
   dispprof_LINE:sigma0 = 25.17372288  
   geom_1:inc = 76.66555138  
   geom_1:pa = 146.7795419  
   geom_1:xshift = -0.1856254474  
   geom_1:yshift = -1.070213453  
   geom_1:vel_shift = 0.7290327874  

INFO:DysmalPy:Iter 16  CHI-SQUARE = 1749.801064  DOF = 404
   disk+bulge:total_mass = 11.2406584  
   disk+bulge:r_eff_disk = 11.1163272  
   dispprof_LINE:sigma0 = 25.17472982  
   geom_1:inc = 76.6652504  
   geom_1:pa = 146.7795455  
   geom_1:xshift = -0.185617335  
   geom_1:yshift = -1.070215226  
   geom_1:vel_shift = 0.7290310108  

INFO:DysmalPy:Iter 17  CHI-SQUARE = 1749.793622  DOF = 404
   disk+bulge:total_mass = 11.24065907  
   disk+bulge:r_eff_disk = 11.11632529  
   dispprof_LINE:sigma0 = 25.17763378  
   geom_1:inc = 76.66499883  
   geom_1:pa = 146.7796311  
   geom_1:xshift = -0.1856239212  
   geom_1:yshift = -1.070220109  
   geom_1:vel_shift = 0.7290276926  

INFO:DysmalPy:Iter 18  CHI-SQUARE = 1749.782348  DOF = 404
   disk+bulge:total_mass = 11.24066023  
   disk+bulge:r_eff_disk = 11.11631647  
   dispprof_LINE:sigma0 = 25.18002597  
   geom_1:inc = 76.66412292  
   geom_1:pa = 146.779641  
   geom_1:xshift = -0.1856137391  
   geom_1:yshift = -1.070225286  
   geom_1:vel_shift = 0.729034287  

INFO:DysmalPy:Iter 19  CHI-SQUARE = 1749.760549  DOF = 404
   disk+bulge:total_mass = 11.24066182  
   disk+bulge:r_eff_disk = 11.11635545  
   dispprof_LINE:sigma0 = 25.18380674  
   geom_1:inc = 76.6633357  
   geom_1:pa = 146.7797417  
   geom_1:xshift = -0.1855873429  
   geom_1:yshift = -1.070223568  
   geom_1:vel_shift = 0.7290825612  

INFO:DysmalPy:Iter 20  CHI-SQUARE = 1749.756106  DOF = 404
   disk+bulge:total_mass = 11.24066218  
   disk+bulge:r_eff_disk = 11.11635462  
   dispprof_LINE:sigma0 = 25.18491728  
   geom_1:inc = 76.66313876  
   geom_1:pa = 146.7798613  
   geom_1:xshift = -0.185584283  
   geom_1:yshift = -1.070222421  
   geom_1:vel_shift = 0.7290837185  

INFO:DysmalPy:
End: 2024-11-04 16:00:11.117629

******************
Time= 12.04 (sec),   0:12.04 (m:s)
MPFIT Status = 2
MPFIT Error/Warning Message = None
******************
------------------------------------------------------------------
 Dysmalpy MPFIT fitting complete for: GS4_43501
   output folder: /Users/jespejo/Dropbox/Postdoc/Data/dysmalpy_test_examples/JUPYTER_OUTPUT_2D_FITTING_WRAPPER/MPFIT/
------------------------------------------------------------------
 

Examine results

Result plots

Read in parameter file

params = utils_io.read_fitting_params(fname=param_filename)

# Override data + output paths:
params['datadir'] = datadir
params['outdir'] = outdir_mpfit

# Add the plot type:
params['plot_type'] = plot_type


f_galmodel = params['outdir'] + '{}_model.pickle'.format(params['galID'])
f_results =  params['outdir'] + '{}_{}_results.pickle'.format(params['galID'], 
                                                        params['fit_method'])

Best-fit plot

# Look at best-fit:
filepath = outdir_mpfit+"{}_{}_bestfit_{}.{}".format(params['galID'], 
                                                     params['fit_method'], 
                                                     params['obs_1_name'], 
                                                     params['plot_type'])
Image(filename=filepath, width=600)
../../_images/30dc09103c9ad82d7d5b6367917f1ec33123c2b52e975905cf74d3d045f0c5d2.png

Directly generating result plots

Reload the galaxy, results files:

gal, results = fitting.reload_all_fitting(filename_galmodel=f_galmodel, 
                                          filename_results=f_results, 
                                          fit_method=params['fit_method'])

Plot the best-fit results:

results.plot_results(gal)
../../_images/30dc09103c9ad82d7d5b6367917f1ec33123c2b52e975905cf74d3d045f0c5d2.png

Results reports

We now look at the results reports, which include the best-fit values and uncertainties (as well as other fitting settings and output).

# Print report
print(results.results_report(gal=gal))
###############################
 Fitting for GS4_43501

Date: 2024-11-04 16:00:12.513962

    obs: OBS
         Datafiles:
             vel :  /Users/jespejo/anaconda3/envs/test_dysmalpy/lib/python3.11/site-packages/dysmalpy/tests/test_data/GS4_43501_Ha_vm.fits
             disp: /Users/jespejo/anaconda3/envs/test_dysmalpy/lib/python3.11/site-packages/dysmalpy/tests/test_data/GS4_43501_Ha_dm.fits
         fit_velocity:           True
         fit_dispersion:         True
         fit_flux:               False
         moment:           False
         zcalc_truncate:        True
         n_wholepix_z_min:      3
         oversample:            1
         oversize:              1


Fitting method: MPFIT
    fit status: 2

pressure_support:      True
pressure_support_type: 1

###############################
 Fitting results
-----------
 disk+bulge
    total_mass         11.2407  +/-   0.0135
    r_eff_disk         11.1164  +/-   0.4071

    n_disk              1.0000  [FIXED]
    r_eff_bulge         1.0000  [FIXED]
    n_bulge             4.0000  [FIXED]
    bt                  0.3000  [FIXED]
    mass_to_light       1.0000  [FIXED]

    noord_flat          True
-----------
 halo
    mvirial            11.0000  [FIXED]
    fdm                 0.1583  [TIED]
    conc                5.0000  [FIXED]
-----------
 dispprof_LINE
    sigma0             25.1849  +/-   1.1831
-----------
 zheightgaus
    sigmaz              1.8883  [TIED]
-----------
 geom_1
    inc                76.6631  +/-   0.5704
    pa                146.7799  +/-   0.3628
    xshift             -0.1856  +/-   0.0104
    yshift             -1.0702  +/-   0.0212
    vel_shift           0.7291  +/-   0.0600

-----------
Adiabatic contraction: False

-----------
Red. chisq: 4.3311

-----------
obs OBS: Rout,max,2D: 11.1201

To directly save the results report to a file, we can use the following:

# Save report to file:
f_report = params['outdir'] + '{}_fit_report.txt'.format(params['galID'])
results.results_report(gal=gal, filename=f_report)

Also note the fitting wrappers automatically save two versions of the report files:

fbase = '{}_{}_bestfit_results'.format(params['galID'], params['fit_method'])
f_report_pretty =  params['outdir'] + fbase + '_report.info'
f_report_machine = params['outdir'] + fbase + '.dat'

The “pretty” version, automatically saved as *_best_fit_results_report.info, is formatted to be human-readable, and includes more information on the fit settings at the beginning (for reference).

with open(f_report_pretty, 'r') as f:
    lines = [line.rstrip() for line in f]
    for line in lines: print(line)
###############################
 Fitting for GS4_43501

Date: 2024-11-04 16:00:11.922759

    obs: OBS
         Datafiles:
             vel :  /Users/jespejo/anaconda3/envs/test_dysmalpy/lib/python3.11/site-packages/dysmalpy/tests/test_data/GS4_43501_Ha_vm.fits
             disp: /Users/jespejo/anaconda3/envs/test_dysmalpy/lib/python3.11/site-packages/dysmalpy/tests/test_data/GS4_43501_Ha_dm.fits
         fit_velocity:           True
         fit_dispersion:         True
         fit_flux:               False
         moment:           False
         zcalc_truncate:        True
         n_wholepix_z_min:      3
         oversample:            1
         oversize:              1


Fitting method: MPFIT
    fit status: 2

pressure_support:      True
pressure_support_type: 1

###############################
 Fitting results
-----------
 disk+bulge
    total_mass         11.2407  +/-   0.0135
    r_eff_disk         11.1164  +/-   0.4071

    n_disk              1.0000  [FIXED]
    r_eff_bulge         1.0000  [FIXED]
    n_bulge             4.0000  [FIXED]
    bt                  0.3000  [FIXED]
    mass_to_light       1.0000  [FIXED]

    noord_flat          True
-----------
 halo
    mvirial            11.0000  [FIXED]
    fdm                 0.1583  [TIED]
    conc                5.0000  [FIXED]
-----------
 dispprof_LINE
    sigma0             25.1849  +/-   1.1831
-----------
 zheightgaus
    sigmaz              1.8883  [TIED]
-----------
 geom_1
    inc                76.6631  +/-   0.5704
    pa                146.7799  +/-   0.3628
    xshift             -0.1856  +/-   0.0104
    yshift             -1.0702  +/-   0.0212
    vel_shift           0.7291  +/-   0.0600

-----------
Adiabatic contraction: False

-----------
Red. chisq: 4.3311

-----------
obs OBS: Rout,max,2D: 11.1201

The “machine” version, automatically saved as *_best_fit_results.dat, is formatted as a machine-readable space-separated ascii file. It includes key parameter fit information, as well as the best-fit reduced chisq.

with open(f_report_machine, 'r') as f:
    lines = [line.rstrip() for line in f]
    for line in lines: print(line)
# component             param_name      fixed       best_value   l68_err     u68_err
disk+bulge              total_mass      False        11.2407      0.0135      0.0135
disk+bulge              r_eff_disk      False        11.1164      0.4071      0.4071
disk+bulge              n_disk          True          1.0000    -99.0000    -99.0000
disk+bulge              r_eff_bulge     True          1.0000    -99.0000    -99.0000
disk+bulge              n_bulge         True          4.0000    -99.0000    -99.0000
disk+bulge              bt              True          0.3000    -99.0000    -99.0000
disk+bulge              mass_to_light   True          1.0000    -99.0000    -99.0000
halo                    mvirial         True         11.0000    -99.0000    -99.0000
halo                    fdm             TIED          0.1583    -99.0000    -99.0000
halo                    conc            True          5.0000    -99.0000    -99.0000
dispprof_LINE           sigma0          False        25.1849      1.1831      1.1831
zheightgaus             sigmaz          TIED          1.8883    -99.0000    -99.0000
geom_1                  inc             False        76.6631      0.5704      0.5704
geom_1                  pa              False       146.7799      0.3628      0.3628
geom_1                  xshift          False        -0.1856      0.0104      0.0104
geom_1                  yshift          False        -1.0702      0.0212      0.0212
geom_1                  vel_shift       False         0.7291      0.0600      0.0600
mvirial                 -----           -----        11.0000    -99.0000    -99.0000
fit_status              -----           -----              2    -99.0000    -99.0000
adiab_contr             -----           -----          False    -99.0000    -99.0000
redchisq                -----           -----         4.3311    -99.0000    -99.0000
noord_flat              -----           -----           True    -99.0000    -99.0000
pressure_support        -----           -----           True    -99.0000    -99.0000
pressure_support_type   -----           -----              1    -99.0000    -99.0000
obs:OBS:moment          -----           -----          False    -99.0000    -99.0000
obs:OBS:Routmax2D       -----           -----        11.1201    -99.0000    -99.0000