Under the hood

Instruments

Overview

A chart view of the interactions of different models with the Instrument

GalPaK uses a virtual Instrument to convolve the simulation cubes and check against observed data. As each instrument has its own tweaks and quirks (both hardware and atmospheric), you can provide an instrument to GalPaK3D, the default one being MUSE in Wide Field Mode :

from galpak import run, SINFOK250
gk = run('my_sinfok250_cube.fits', instrument=SINFOK250())

Here are the available instruments :

Note

These instruments are objects, not string literals! Notice the parentheses : SINFOK250().

The spectral characteristics (pixel cdelt, etc.) are re-calibrated using the Cube’s header when you instantiate GalPaK. Pay attention in defining most appropriate values for the seeing or psf_fwhm(“) – psf_ba if not round – and lsf_fwhm (in units of cube) parameters. All of them by default use the gaussian PSF GaussianPointSpreadFunction.

Base Instrument Class

class galpak.Instrument(psf=None, lsf=None)[source]

This is a generic instrument class to use or extend.

psf: None|PointSpreadFunction
The 2D Point Spread Function instance to use in the convolution, or None (the default). When this parameter is None, the instrument’s PSF will not be applied to the cube.
lsf: None|LineSpreadFunction
The 1D Line Spread Function instance to use in the convolution, or None (the default). Will be used in the convolution to spread the PSF 2D image through a third axis, z. When this parameter is None, the instrument’s PSF will not be applied to the cube.
convolve(cube)[source]

Convolve the provided data cube using the 3D Spread Function made from the 2D PSF and 1D LSF. Should transform the input cube and return it. If the PSF or LSF is None, it will do nothing.

Warning

The 3D spread function and its fast fourier transform are memoized for optimization, so if you change the instrument’s parameters after a first run, the SF might not reflect your changes. Delete psf3d and psf3d_fft to clear the memory.

cube: HyperspectralCube

Hyperspectral Cube

This class is a very simple (understand : not fully-featured nor exhaustive) model of a hyperspectral cube.

class galpak.HyperspectralCube(data=None, header=None, verbose=False, filename=None, variance=None)[source]

A hyperspectral cube has 3 dimensions : 2 spatial, and 1 spectral. It is basically a rectangular region of the sky seen on a discrete subset of the light spectrum. It is heavily used in spectral imaging, and is provided by spectroscopic explorers such as MUSE.

This class is essentially a convenience wrapper for data values and header specs of a single hyperspectral cube.

It understands the basic arithmetic operations + - * / **, which should behave much like with numpy’s ndarrays, and update the header accordingly. An operation between a cube and a number will behave as expected, by applying the operation voxel-by-voxel to the cube. (it broadcasts the number to the shape of the cube) An operation between a cube and an image (a slice along the spectral axis, z) will behave as expected, by applying the operation image-by-image to the cube. (it broadcasts the image to the shape of the cube)

It also understands indexation of the form cube[zmin:zmax, ymin:ymax, xmin:xmax].

See also http://en.wikipedia.org/wiki/Hyperspectral_imaging .

Note : no FSCALE management is implemented yet.

You can load from a single HDU of a FITS (Flexible Image Transport System) file :

HyperspectralCube.from_file(filename, hdu_index=None, verbose=False)
data: numpy.ndarray|None
3D numpy ndarray holding the raw data. The indices are the pixel coordinates in the cube. Note that in order to be consistent with astropy.io.fits, data is indexed in that order : λ, y, x.
header: fits.Header|None
http://docs.astropy.org/en/latest/io/fits/api/headers.html Note: this might become its own wrapper class in the future.
verbose: boolean
Set to True to log everything and anything.
defaults_from_instrument(instrument=None)[source]
First reads the header for
xy_step (CDELT1 or CD1_1) z_step (CDELT3 or CD3_3) z_cunit (CUNIT3) crpix (CRPIX3) crval (CRVAL3).

If some of these are None, get the default values from the instrument and then reset the header :

xy_step: Instrument.xy_step –> self.xy_step z_step: Instrument.z_step –> self.z_step –> CDELT3 z_cunit: Instrument.z_cunit –> self.z_cunit –> CUNIT3 crpix: shape[0]/2 –> CRPIX3 crval: Instrument.z_central –> self.z_central –> CRVAL3

for CUNIT3 CRVAL3 CRPIX3 CDELT3

static from_file(filename, hdu_index=None, verbose=False)[source]

Factory to create a HyperspectralCube from one HDU in a FITS file. http://fits.gsfc.nasa.gov/fits_standard.html

No other file formats are supported at the moment. You may specify the index of the HDU you want. If you don’t, it will try to guess by searching for a HDU with EXTNAME=DATA, or it will pick the first HDU in the list that has 3 dimensions.

filename: string
An absolute or relative path to the FITS file we want to load. The astropy.io.fits module is used to open the file.
hdu_index: integer|None
Index of the HDU to load. If you set this, guessing is not attempted.
verbose: boolean
Should we fill up the log with endless chatter ?
Return type:HyperspectralCube
get_steps()[source]

Returns a list of the 3 steps [λ,y,x]. The units are the ones specified in the header.

has_header()[source]

Does this cube have a header ?

return boolean

initialize_self_cube()[source]

Initialize steps xy_steps z_steps z_cunnit and z_central z_central requires CRPIX3 CRVAL3 CDELT3

initialize_self_cube()[source]

Initialize steps xy_steps z_steps z_cunnit and z_central z_central requires CRPIX3 CRVAL3 CDELT3

is_empty()[source]

Is this cube void of any data ?

return boolean

sanitize(header=None, data=None)[source]

Procedurally apply various sanitization tasks : - http://docs.astropy.org/en/latest/io/fits/usage/verification.html (todo) - Fix spectral step keyword :

  • CDEL_3 –> CDELT3
  • CD3_3 –> CDELT3
  • Fix blatantly illegal units :
    • DEG –> deg
    • MICRONS –> um

Sanitizes this cube’s header and data, or provided header and data.

Warning

header and data are mutated, not copied, so this method returns nothing.

wavelength_of(pixel_index)[source]

Get the wavelength (in the unit specified in the header) of the specified pixel index along z. The pixel index should start at 0.

Return type:float
write_to(filename, overwrite=False)[source]

Write this cube to a FITS file.

filename: string
The filename (absolute or relative) of the file we want to write to. The astropy.io.fits module is used to write to the file.
overwrite: bool
When set to True, will overwrite the output file if it exists.

Note

This class is not fully formed yet and its API may evolve as it moves to its own module.

Galaxy Parameters

Important

A description of the parameter meaning can be found here


class galpak.GalaxyParameters(x=None, y=None, z=None, flux=None, radius=None, inclination=None, pa=None, turnover_radius=None, maximum_velocity=None, velocity_dispersion=None)[source]

A simple wrapper for an array of galaxy parameters. It is basically a flat numpy.ndarray of a bunch of floats with convenience attributes for explicit (and autocompleted!) access and mutation of parameters, and nice casting to string.

Warning

Undefined parameters will be NaN, not None.

Example :

from galpak import GalaxyParameters
gp = GalaxyParameters(x=1.618)

// Classic numpy.ndarray numeric access
assert(gp[0] == 1.618)
// Autocompleted and documented property access
assert(gp.x == 1.618)
// Convenience dictionary access,
assert(gp['x'] == 1.618)
// ... useful when you're iterating :
for (name in GalaxyParameters.names):
    print gp[name]
Parameters :
  • x (pix)
  • y (pix)
  • z (pix)
  • flux
  • radius aka. r½ (pix)
    half-light radius in pixel
  • inclination (deg)
  • pa (deg)
    position angle from y-axis, anti-clockwise.
  • turnover_radius aka. rv (pix)
    turnover radius for arctan, exp, velocity profile [is ignored for mass profile]
  • maximum_velocity aka. Vmax (km/s)
    de-projected V_max [forced to be positive, with 180deg added to PA]
  • velocity_dispersion aka. s0 (km/s)

Note that all the parameters are lowercase, even if they’re sometimes displayed mixed-case.

Additional attributes :
  • stdev : Optional stdev margin (GalaxyParametersError).
    GalPaK3D fills up this attribute.
static from_ndarray(a)[source]

Factory to easily create a GalaxyParameters object from an ordered ndarray whose elements are in the order of GalaxyParameters.names.

Use like this :

from galpak import GalaxyParameters
gp = GalaxyParameters.from_ndarray(my_ndarray_of_data)
Return type:GalaxyParameters
long_info(error_as_percentage=False)[source]

Casts to multi-line string. This is called by repr().

error_as_percentage: bool
When true, will print the stdev margin as a percentage of the value.
Return type:string
short_info()[source]

Casts to single-line string. This is called by print().

Looks like this : x=0.00 y=1.00 z=2.000000 flux=3.00e+00 r½=4.00 incl=5.00 PA=6.00 rv=7.00 Vmax=8.00 s0=9.00

Return type:string

A GalaxyParameters object gp is merely a glorified numpy.ndarray with convenience accessors and mutators :

Component Description
gp.x X coordinates of the center of the galaxy. (in pixels)
gp.y Y coordinates of the center of the galaxy. (in pixels)
gp.z Z coordinates of the center of the peak. (in pixels)
gp.flux Sum of the values of all pixels. (in the unit of the cube)
gp.radius Radius of the galaxy. (in pixels)
gp.inclination
gp.pitch
Inclination of the galaxy (in degrees), aka. pitch along observation axis.
gp.pa
gp.roll
Position Angle, clockwise from Y (in degrees), aka. roll along observation axis.
gp.rv
gp.turnover_radius
Inverse factor rv in expression arctan(r/rv).
gp.maximum_velocity Maximum Velocity. (in km/s)
gp.velocity_dispersion
gp.sigma0
Disk Dispersion spatially constant (in km/s) added in addition to kinematics dispersion.

Warning

the velocity_dispersion parameter is NOT the total dispersion. This parameter is akin to a turbulent term. It is added in quadrature to the dispersions due to the disk model and to the thickness. See Cresci et al. 2009, Genzel et al. 2011, and Bouche et al. 2015

You still can access the parameters like an indexed array

assert gp.x == gp[0]  # true
assert gp.y == gp[1]  # true
# ...
assert gp.sigma0 == gp[9]  # true

You may instantiate a GalaxyParameters object like so

from galpak import GalaxyParameters

gp = GalaxyParameters(z=0.65)
gp.x = 5.
assert gp.z == 0.65       # true
assert gp.x == 5.         # true

Warning

An undefined value in GalaxyParameters will be nan, not None

assert math.isnan(gp.pa)  # true
assert gp.pa is None      # false

The z attribute in a GalaxyParameter is in pixels, you may want the value in the physical unit specified in your Cube’s header.

To that effect, you may use the wavelength_of method of the HyperspectralCube:

from galpak import GalPaK3D
gk = GalPaK3D('my_muse_cube.fits')
gk.run_mcmc()

wavelength = gk.cube.wavelength_of(gk.galaxy.z)

Disk Model

class galpak.DiskModel(flux_profile='exponential', thickness_profile='gaussian', dispersion_profile='thick', rotation_curve='arctan', flux_image=None, line=None, redshift=None, cosmology='planck15')[source]

The first and default galpak Model (when unspecified). It simulates a simple disk galaxy using DiskParameters.

flux_profile: ‘exponential’ | ‘gaussian’ | ‘de_vaucouleurs’ | ‘sersicN2’ | ‘user’
The flux profile of the observed galaxy. The default is ‘exponential’. See http://en.wikipedia.org/wiki/Sersic%27s_law If ‘user’ provided flux map, specify flux_image. Currently unsupported
thickness_profile: ‘gaussian’ [default] | ‘exponential’ | ‘sech2’ | ‘none’
The perpendicular flux profile of the disk galaxy. The default is ‘gaussian’. If none, the galaxy will be a cylinder
rotation_curve: ‘arctan’ | ‘mass’ | ‘exp’ | ‘tanh’ | ‘isothermal’
The profile of the velocity v(r) can be in
  • ‘arctan’ (default) : ~ Vmax arctan(r/rV), rV=turnover radius
  • ‘tanh’ : Vmax tanh(r/rV), rV=turnover radius
  • ‘exp’ : inverted exponential, 1-exp(-r/rV)
  • ‘mass’ : a constant light-to-mass ratio v(r)=sqrt(G m(<r) / r)
  • ‘isothermal’ : an isothermal rotation curve v(r)=Vmax * sqrt(1-rV/r * arctan(r/rV)
dispersion_profile: ‘thick’ [default] | ‘thin’

The local disk dispersion from the rotation curve and disk thickness from Binney & Tremaine 2008, see Genzel et al. 2008. GalPak has 3 components for the dispersion:

  • a component from the rotation curve arising from mixing velocities of a disk with non-zero thickness.
  • a component from the local disk dispersion specified by disk_dispersion
  • a spatially constant dispersion, which is the output parameter velocity_dispersion.
line: None[default] | dict to fit doublets, use a dictionary with
line[‘wave’]=[l, lref] eg. [3726.2, 3728.9] # Observed or Rest line[‘ratio’]=[0.8, 1.0] eg. [0.8, 1.0] # The primary line for redshifts is the reddest
redshift: float
The redshift of the observed galaxy, used in mass calculus. Will override the redshift provided at init ; this is a convenience parameter. If this is not set anywhere, GalPak will not try to compute the mass.

Point Spread Functions

GalPaK provides the two most common PSF : Gaussian and Moffat.

You may use them as the psf argument of the Instrument, as described here.

Gaussian

All instruments use this PSF model by default, with their own configuration :

class galpak.GaussianPointSpreadFunction(fwhm=None, pa=0, ba=1.0)[source]

The default Gaussian Point Spread Function.

fwhm: float
Full Width Half Maximum in arcsec, aka. “seeing”.
pa: float [default is 0.]
Position Angle, clockwise rotation from Y of ellipse, in angular degrees.
ba: float [default is 1.0]
Axis ratio of the ellipsis, b/a ratio (y/x).
as_image(for_cube, xo=None, yo=None)[source]

Should return this PSF as a 2D image shaped [for_cube].

for_cube: HyperspectralCube
Has additional properties computed and attributed by GalPaK :
  • xy_step (in “)
  • z_step (in µm)
  • z_central (in µm)
Return type:ndarray

Moffat

class galpak.MoffatPointSpreadFunction(fwhm=None, alpha=None, beta=None, pa=None, ba=None)[source]

The Moffat Point Spread Function

fwhm if alpha is None: float [in arcsec]
Moffat’s distribution fwhm variable : http://en.wikipedia.org/wiki/Moffat_distribution
alpha if fwhm is None: float [in arcsec]
Moffat’s distribution alpha variable : http://en.wikipedia.org/wiki/Moffat_distribution
beta: float
Moffat’s distribution beta variable : http://en.wikipedia.org/wiki/Moffat_distribution
pa: float [default is 0.]
Position Angle, the clockwise rotation from Y of ellipse, in angular degrees.
ba: float [default is 1.0]
Axis ratio of the ellipsis, b/a ratio (y/x).
as_image(for_cube, xo=None, yo=None)[source]

Should return this PSF as a 2D image shaped [for_cube].

for_cube: HyperspectralCube
Has additional properties computed and attributed by GalPaK :
  • xy_step (in “)
  • z_step (in µm)
  • z_central (in µm)
Return type:ndarray

Interface

In order to furthermore customize the PSF you want to use, you can create your own PSF class and use it in the instrument, it simply needs to implement the following interface :

class galpak.PointSpreadFunction[source]

This is the interface all Point Spread Functions (PSF) should implement.

as_image(for_cube)[source]

Should return this PSF as a 2D image shaped [for_cube].

for_cube: HyperspectralCube
Has additional properties computed and attributed by GalPaK :
  • xy_step (in “)
  • z_step (in µm)
  • z_central (in µm)
Return type:ndarray

Line Spread Functions

GalPaK provides two LSFs : Gaussian and MUSE. These are used to extrude the 2D PSF image into 3D, right before its application in Fourier space.

You may use them as the lsf argument of the Instrument, as described here.

Gaussian

All instruments use this LSF model by default, with their own configuration :

class galpak.GaussianLineSpreadFunction(fwhm)[source]

A line spread function that spreads as a gaussian. We assume the centroid is in the middle.

fwhm: float
Full Width Half Maximum, in µm.
as_vector(for_cube)[source]

Should return this LSF as a 1D vector shaped [for_cube].

for_cube: HyperspectralCube

Return type:ndarray

MUSE

This LSF requires the mpdaf module, specifically mpdaf.MUSE.LSF.

As this LSF is optional, you must explicitly tell your instrument to use it when you want to.

class galpak.MUSELineSpreadFunction(model='qsim_v1')[source]

A line spread function that uses MPDAF’s LSF. See http://urania1.univ-lyon1.fr/mpdaf/chrome/site/DocCoreLib/user_manual_PSF.html

Warning

This requires the mpdaf module. Currently, the MPDAF module only works for odd arrays.

model: string
See mpdaf.MUSE.LSF’s typ parameter.
as_vector(cube)[source]

Should return this LSF as a 1D vector shaped [for_cube].

for_cube: HyperspectralCube

Return type:ndarray

Interface

In order to further customize the LSF you want to use, you can create your own LSF class and use it in the instrument, it simply needs to implement the following interface :

class galpak.LineSpreadFunction[source]

This is the interface all Line Spread Functions (LSF) should implement.

as_vector(for_cube)[source]

Should return this LSF as a 1D vector shaped [for_cube].

for_cube: HyperspectralCube

Return type:ndarray