# Wavelength recalibration with the sky lines (Mendel OH bands)¶

## Introduction¶

Data can be recalibrated in wavelength easily when one OH sky lines are visible in most parts of the field of view. Cubes observed in the red part of the spectrum (e.g. SN3 filter) are especially interesting in this respect.

The general idea is to extract integrated spectra at different positions in the field of view and measure the velocity of the sky lines (which should be 0 if the calibration was perfect) (see Martin et al. 2017a).

Then the correction map can be infered at each pixel by fitting a model.

The calibration model is based on a simple modeling of the interferometer.

## First step: checking the calibration¶

[1]:

# inline plotting for jupyter notebook. Do not put this line in a real python script.
%matplotlib inline

[2]:

# import base class for the manipulation of a SITELLE spectral cube: HDFCube
from orcs.process import SpectralCube
import pylab as pl

[3]:

# load spectral cube
cube = SpectralCube('/home/thomas/M31_SN3.merged.cm1.1.0.hdf5')

INFO| Data shape : (2048, 2064, 840)
INFO| Cube is in WAVENUMBER (cm-1)
INFO| Cube is CALIBRATED in wavenumber

[4]:

# extract and plot a spectrum of a large integrated region. The sky lines should appear.
axis, spectrum = cube.extract_spectrum(50, 50, 20)
pl.figure(figsize=(10,6))
pl.plot(axis, spectrum)
pl.xlim(14500, 15500)

INFO| Number of integrated pixels: 1257

 [==========] [100%] [completed in 1.77 s]

INFO| Init of the parallel processing server with 4 threads


[==========] [100%] [completed in 0.550 s]

[4]:

(14500, 15500)


### fitting the sky spectrum¶

we can also fit the integrated spectrum because there si a large number of sky lines and because we are not interested in a perfect fit (only the velocity is required), we can use a simple ‘sinc’ model with a fixed fwhm. All the lines are set to share the same velocity parameter and we set an inital guess of the velocity around 80 km/s. This general bias of 80 km/s is known (Martin et al. 2017b) and comes from the error made on the real wavelength of the calibration laser (which is falsely considered to be at 453.5 nm).

[5]:

sky_lines_cm1 = cube.get_sky_lines()
axis, spectrum, fit_res = cube.fit_lines_in_spectrum(50, 50, 20, sky_lines_cm1,
fmodel='sinc',
pos_def='1',
fwhm_def='fixed',
nofilter=False,
pos_cov=80)
print '\n===== Results ======'
print 'Velocity: ', fit_res['velocity_gvar']
pl.figure(figsize=(10,6))
pl.plot(axis, spectrum, ls=':', c='black')
pl.plot(axis, fit_res['fitted_vector'], ls='-', c='orange')
pl.xlim(14500, 15500)

INFO| Number of integrated pixels: 1257

 [==========] [100%] [completed in 0.028 s]

INFO| Init of the parallel processing server with 4 threads


[==========] [100%] [completed in 0.655 s]

WARNING| /home/thomas/Astro/Python/ORB/Orcs/orcs/core.py:1673: RuntimeWarning: invalid value encountered in sqrt
noise_counts = np.sqrt(total_counts)




===== Results ======
Velocity:  [72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5) 72.5(1.5)
72.5(1.5) 72.5(1.5)]

[5]:

(14500, 15500)


## Second step: Mapping the sky velocity¶

Warning: this process can take a long time because a spectrum is extracted and fitted for each point of a 40x40 grid by default. For a basic example it is recommended to limit the number of grid division to 10x10.

[6]:

cube.map_sky_velocity(80, div_nb=10) # the mean velocity bias is set around 80 km/s

INFO| fitting process already done. Do you really want to redo it again ?

type [yes]: yes

INFO| X range: 0 2048, Y range: 0 2064
INFO| 100 regions to fit
INFO| 93 sky lines to fit

 loading region: Shape : circle ( Number(1861.81818),Number(1876.36364),Number(85.33333) )


INFO| Init of the parallel processing server with 4 threads

 [==========] [100%] [completed in 30m1s]

INFO| Velocity of the first line (km/s): 75.5(1.2)



INFO| Velocity of the first line (km/s): 75.8(1.2)
INFO| Velocity of the first line (km/s): 73.8(1.5)
INFO| Velocity of the first line (km/s): 71.6(1.4)
INFO| Velocity of the first line (km/s): 72.5(1.7)
INFO| Velocity of the first line (km/s): 69.9(1.6)
INFO| Velocity of the first line (km/s): 67.5(1.6)
INFO| Velocity of the first line (km/s): 66.6(1.5)
INFO| Velocity of the first line (km/s): 72.7(1.5)
INFO| Velocity of the first line (km/s): 70.7(2.0)
INFO| Velocity of the first line (km/s): 77.0(1.3)
INFO| Velocity of the first line (km/s): 76.6(1.3)
INFO| Velocity of the first line (km/s): 77.0(1.3)
INFO| Velocity of the first line (km/s): 72.7(1.5)
INFO| Velocity of the first line (km/s): 70.2(1.6)
INFO| Velocity of the first line (km/s): 65.8(1.5)
INFO| Velocity of the first line (km/s): 67.8(1.5)
INFO| Velocity of the first line (km/s): 68.4(1.6)
INFO| Velocity of the first line (km/s): 67.5(1.5)
INFO| Velocity of the first line (km/s): 71.9(1.7)
INFO| Velocity of the first line (km/s): 77.5(1.4)
INFO| Velocity of the first line (km/s): 78.0(1.3)
INFO| Velocity of the first line (km/s): 76.9(1.3)
INFO| Velocity of the first line (km/s): 74.6(1.5)
INFO| Velocity of the first line (km/s): 76.3(1.6)
INFO| Velocity of the first line (km/s): 78.7(1.7)
INFO| Velocity of the first line (km/s): 95.6(1.8)
INFO| Velocity of the first line (km/s): 61.9(1.6)
INFO| Velocity of the first line (km/s): 59.6(1.4)
INFO| Velocity of the first line (km/s): 73.7(1.5)
INFO| Velocity of the first line (km/s): 78.5(1.2)
INFO| Velocity of the first line (km/s): 77.0(1.3)
INFO| Velocity of the first line (km/s): 77.4(1.7)
INFO| Velocity of the first line (km/s): 62.9(1.8)
INFO| Velocity of the first line (km/s): 71.5(2.0)
INFO| Velocity of the first line (km/s): 83.8(2.1)
INFO| Velocity of the first line (km/s): 54.1(1.6)
INFO| Velocity of the first line (km/s): 50.8(1.5)
INFO| Velocity of the first line (km/s): 75.2(1.3)
INFO| Velocity of the first line (km/s): 78.6(1.3)
INFO| Velocity of the first line (km/s): 73.2(1.9)
INFO| Velocity of the first line (km/s): 80.2(1.9)
INFO| Velocity of the first line (km/s): 96.9(2.4)
INFO| Velocity of the first line (km/s): 68.6(2.7)
INFO| Velocity of the first line (km/s): 77.2(2.0)
INFO| Velocity of the first line (km/s): 70.0(1.7)
INFO| Velocity of the first line (km/s): 109.7(2.0)
INFO| Velocity of the first line (km/s): 79.8(1.6)
INFO| Velocity of the first line (km/s): 74.7(1.2)
INFO| Velocity of the first line (km/s): 79.2(1.3)
INFO| Velocity of the first line (km/s): 76.9(1.5)
INFO| Velocity of the first line (km/s): 80.0(2.2)
INFO| Velocity of the first line (km/s): 91.5(2.6)
INFO| Velocity of the first line (km/s): 91.9(2.9)
INFO| Velocity of the first line (km/s): 85.7(2.9)
INFO| Velocity of the first line (km/s): 106.5(2.1)
INFO| Velocity of the first line (km/s): 78.5(1.9)
INFO| Velocity of the first line (km/s): 75.3(1.5)
INFO| Velocity of the first line (km/s): 77.5(1.1)
INFO| Velocity of the first line (km/s): 79.5(1.4)
INFO| Velocity of the first line (km/s): 78.3(1.7)
INFO| Velocity of the first line (km/s): 80.7(2.6)
INFO| Velocity of the first line (km/s): 78.4(2.6)
INFO| Velocity of the first line (km/s): 83.0(2.6)
INFO| Velocity of the first line (km/s): 61.3(2.4)
INFO| Velocity of the first line (km/s): 76.4(2.2)
INFO| Velocity of the first line (km/s): 77.7(1.7)
INFO| Velocity of the first line (km/s): 73.6(1.4)
INFO| Velocity of the first line (km/s): 80.7(1.7)
INFO| Velocity of the first line (km/s): 80.2(1.4)
INFO| Velocity of the first line (km/s): 80.5(1.5)
INFO| Velocity of the first line (km/s): 82.6(2.5)
INFO| Velocity of the first line (km/s): 79.7(2.5)
INFO| Velocity of the first line (km/s): 80.8(2.7)
INFO| Velocity of the first line (km/s): 83.9(2.3)
INFO| Velocity of the first line (km/s): 78.4(1.9)
INFO| Velocity of the first line (km/s): 72.5(1.3)
INFO| Velocity of the first line (km/s): 77.2(1.2)
INFO| Velocity of the first line (km/s): 80.00(98)
INFO| Velocity of the first line (km/s): 84.2(1.5)
INFO| Velocity of the first line (km/s): 81.0(1.4)
INFO| Velocity of the first line (km/s): 86.3(1.7)
INFO| Velocity of the first line (km/s): 82.1(2.0)
INFO| Velocity of the first line (km/s): 87.0(2.0)
INFO| Velocity of the first line (km/s): 81.8(1.9)
INFO| Velocity of the first line (km/s): 80.5(1.6)
INFO| Velocity of the first line (km/s): 82.4(1.1)
INFO| Velocity of the first line (km/s): 80.33(93)
INFO| Velocity of the first line (km/s): 86.09(89)
INFO| Velocity of the first line (km/s): 84.4(1.7)
INFO| Velocity of the first line (km/s): 82.8(1.4)
INFO| Velocity of the first line (km/s): 82.3(1.6)
INFO| Velocity of the first line (km/s): 83.9(1.7)
INFO| Velocity of the first line (km/s): 83.9(1.5)
INFO| Velocity of the first line (km/s): 85.7(1.4)
INFO| Velocity of the first line (km/s): 83.8(1.1)
INFO| Velocity of the first line (km/s): 83.41(78)
INFO| Velocity of the first line (km/s): 83.27(81)
INFO| Velocity of the first line (km/s): 83.79(69)
WARNING| /home/thomas/Astro/Python/ORB/Orcs/orcs/process.py:293: RuntimeWarning: invalid value encountered in greater
sky_vel_map_err[sky_vel_map_err > threshold] = np.nan

WARNING| /home/thomas/Astro/Python/ORB/Orcs/orcs/utils.py:234: RuntimeWarning: invalid value encountered in greater
vel[vel > np.nanpercentile(vel, 95)] = np.nan

INFO| First laser wavelentgh calibration estimation: 543.360393931 nm
INFO| Angle at the center of the frame: 15.4961225377
WARNING| /home/thomas/Astro/Python/ORB/Orb/orb/utils/image.py:1054: RuntimeWarning: invalid value encountered in less
calib_laser_map[np.nonzero(calib_laser_map < value_min)] = np.nan

INFO| > Binning calibration map
WARNING| /home/thomas/Astro/Python/ORB/Orb/orb/utils/image.py:938: RuntimeWarning: Mean of empty slice
return np.squeeze(np.nanmean(np.nanmean(im_view, axis=3), axis=1))

INFO| > Calibration laser map fit
INFO|   > First fit on the central portion of the calibration laser map (30.0% of the total size)
INFO|     > Calibration laser map fit parameters:
distance to mirror: 23.6929241755 cm
X angle from the optical axis to the center: 0.0 degrees (Fixed)
Y angle from the optical axis to the center: 15.5034808559 degrees
Tip-tilt angle of the detector along X: 0.0 degrees (Fixed)
Tip-tilt angle of the detector along Y: 0.0 degrees (Fixed)
Rotation angle of the detector: 0.0 degrees (Fixed)
Calibration laser wavelength: 543.360393931 nm (Fixed)
Error on fit: mean -1.14673527496e-06, std 0.0515053224534 (in nm)
Error on fit: mean -0.000633135183075, std 28.4371052962 (in km/s)
INFO|   > Second fit on the central portion of the calibration laser map (30.0% of the total size)
INFO|     > Calibration laser map fit parameters:
distance to mirror: 23.6769365598 cm
X angle from the optical axis to the center: -0.467348352077 degrees
Y angle from the optical axis to the center: 15.4964238437 degrees
Tip-tilt angle of the detector along X: 0.42697977166 degrees
Tip-tilt angle of the detector along Y: -1.21990584691 degrees
Rotation angle of the detector: 0.0 degrees (Fixed)
Calibration laser wavelength: 543.360393931 nm (Fixed)
Error on fit: mean -3.7990067481e-07, std 0.000789283567367 (in nm)
Error on fit: mean -0.000209750662205, std 0.435779038838 (in km/s)
INFO|   > Third fit on a larger portion of the map (50.0% of the total size)
INFO|     > Calibration laser map fit parameters:
distance to mirror: 23.7139453434 cm
X angle from the optical axis to the center: -0.467712143263 degrees
Y angle from the optical axis to the center: 15.4967978522 degrees
Tip-tilt angle of the detector along X: 0.302814070934 degrees
Tip-tilt angle of the detector along Y: -0.700373883437 degrees
Rotation angle of the detector: 0.0 degrees (Fixed)
Calibration laser wavelength: 543.360393931 nm (Fixed)
Error on fit: mean -2.79665822043e-06, std 0.00312193857261 (in nm)
Error on fit: mean -0.0015440902125, std 1.72368391632 (in km/s)
INFO|   > Zernike polynomials fit of the residual wavefront
WARNING| /home/thomas/Astro/Python/ORB/Orb/orb/ext/zern.py:54: DeprecationWarning: object of type <type 'float'> cannot be safely interpreted as an integer.
r0v = np.linspace(-1-center[0], 1-center[0], r0).astype(dtype).reshape(-1,1)

WARNING| /home/thomas/Astro/Python/ORB/Orb/orb/ext/zern.py:55: DeprecationWarning: object of type <type 'float'> cannot be safely interpreted as an integer.
r1v = np.linspace(-1-center[1], 1-center[1], r1).astype(dtype).reshape(1,-1)

WARNING| /home/thomas/Astro/Python/ORB/Orb/orb/ext/zern.py:78: DeprecationWarning: factorial is deprecated!
Importing factorial from scipy.misc is deprecated in scipy 1.0.0. Use scipy.special.factorial instead.
wf += rho**(n-2.0*k) * (-1.0)**k * fac(n-k) / ( fac(k) * fac( (n+m)/2.0 - k ) * fac( (n-m)/2.0 - k ) )

INFO| Standard deviation of the residual: 1.84988533513e-05
INFO| Median relative error (err/val)): 0.05%
INFO| > final error (std on 50.0% of the total size): 1.764e-05 nm, 9.739e-03 km/s
INFO|     > New calibration laser map fit parameters:
distance to mirror: 23.6645056026 cm
X angle from the optical axis to the center: -0.0876246192104 degrees
Y angle from the optical axis to the center: 15.4806867301 degrees
Tip-tilt angle of the detector along X: 4.61907978407 degrees
Tip-tilt angle of the detector along Y: 0.330879299387 degrees
Rotation angle of the detector: 1.41678376849 degrees
Calibration laser wavelength: 543.423849077 nm

INFO| fit residual std (in km/s):
INFO| median error on the data (in km/s)
INFO| Data written as M31_SN3.1.0.ORCS/M31_SN3.1.0.calibration_laser_map.fits in 0.24 s
INFO| Data written as M31_SN3.1.0.ORCS/M31_SN3.1.0.wavefront_map.fits in 0.46 s
INFO| Data written as M31_SN3.1.0.ORCS/M31_SN3.1.0.skymap.fits in 0.27 s


## Resulting data¶

The most important result is the skymap which gives the modelized velocity of the sky in the field of view and permit to correct the measured velocities in the cube.This map is named *skymap.fits.

In this particular case this is M31_SN3.1.0.ORCS/M31_SN3.1.0.skymap.fits

The histogram displays the difference between the measured velocity and the fitted velocity at each valid data point.

You can see by looking at the other maps that in the cas of M31 there are some data points at the center of the field which could not give a valid velocity of the sky. This comes from the fact that M31 is very bright at the center and the sky lines are lost in the noise produced by the high continuum background. Modelling the interferometer makes possible to estimate the velocity of the lines at the center of the field where no real data has been obtained. And the result is stricking, it works particularly well even if the case of M31 (Martin et al. 2017a)

## Calibrating your data with the sky velocity map¶

Once the velocity map is passed to the SpectralCube class, the class will internaly make the appropriate corrections so that the measured velocity of any spectrum will be corrected. But it will also correct the spectral misalignment of the spectra before extracting the data which should have an effect on the broadening of the lines when a spectrum is integrated over a large field of view with a non-negligible gradient on the velocity calibration.

[7]:

# the computed sky velocity map is passed to cube
cube.correct_wavelength('M31_SN3.1.0.ORCS/M31_SN3.1.0.skymap.fits')

[8]:

# The same sky spectrum is now extracted and fitted and the measured velocity is now similar to 0 km/s.
# Note that the calibration map used here has not been calculated with a 40x40 grid. The calibration
# quality would have been better in this case.

sky_lines_cm1 = cube.get_sky_lines()
axis, spectrum, fit_res = cube.fit_lines_in_spectrum(50, 50, 20, sky_lines_cm1,
fmodel='sinc',
pos_def='1',
fwhm_def='fixed',
nofilter=False,
pos_cov=80)
print '\n===== Results ======'
print 'Velocity: ', fit_res['velocity_gvar']
pl.figure(figsize=(10,6))
pl.plot(axis, spectrum, ls=':', c='black')
pl.plot(axis, fit_res['fitted_vector'], ls='-', c='orange')
pl.xlim(14500, 15500)

INFO| Number of integrated pixels: 1257

 [==========] [100%] [completed in 0.046 s]

INFO| Init of the parallel processing server with 4 threads

 [==========] [100%] [completed in 1.21 s]

===== Results ======
Velocity:  [-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5) -1.3(1.5)
-1.3(1.5) -1.3(1.5)]

[8]:

(14500, 15500)

[ ]: