Flexure Correction


PypeIt can account for Spectral Flexure and Spatial Flexure in the instrument. The former is applied by default while the latter requires extra care and expertise.

We discuss each in turn.

Spatial Flexure

The code has a simple yet relatively robust method to cross-correlate the slits against any input image to determine a rigid, spatial offset. This algorithm is performed for any frame type by setting spat_flexure_correct = True in the process block of ProcessImagesPar Keywords.

We have made our own determinations for which instruments to enable this as the default. Inspect the Instrument-Specific Default Configuration list to see if your instrument is included (search for the value of spat_flexure_correct).

Depending on what frame types you choose to correct, the code will behave somewhat differently. Here we describe the options in increasing complexity.

Science/Standard Only

Most users may wish to only correct for flexure when processing standard and science frames. If you wish to turn on this correction add this to your PypeIt file:

        spat_flexure_correct = True
            spat_flexure_correct = True

This will:

  • Calculate a spatial offset for each science/standard frame from the slits

  • Apply this correction for the illumination flat

  • Apply this correction prior to sky subtraction and extraction

Tilts only

To apply the correction only to your “tilts” image, you would instead add the following to your PypeIt Reduction File:

            spat_flexure_correct = True

This will:

  • Calculate a spatial offset between the trace flats and the tilt image

  • Construct the tilt solution in that frame

  • Apply an offset to generate tilts and wavelengths for the associated science/standard images

Spectral Flexure

PypeIt calculates the spectral flexure correction, as a single pixel shift, by performing a cross-correlation between an extracted sky spectrum and an archived sky spectrum. This is then imposed on the wavelength solution with simple linear interpolation.

To enable this correction the parameter spec_method in FlexurePar Keywords should be set to boxcar or slitcen. The default for most spectrographs is spec_method = skip, i.e., no spectral flexure correction is performed. Inspect the Instrument-Specific Default Configuration list to see if spectral flexure is preformed by default for your instrument (i.e., search for the value of spec_method in the [flexure] parameter block).

If spec_method = boxcar (recommended) the observed sky spectrum flux is boxcar extracted, while the spectrum wavelength is taken from the extracted 1D object. If no objects have been extracted, set spec_method = slitcen, which uses a spectrum extracted from the center of each slit.

For the archived sky spectrum, generally, the Paranal sky spectrum (paranal_sky.fits) is used by default. However, this is different for Kast blue and LRIS blue where sky_kastb_600.fits and sky_LRISb_600.fits are respectively used (see Alternate sky models for all sky models).

Narrow sky emission lines dominate the analysis, but other features can affect the cross-correlation.

The maximum allowable spectral shift (in pixels) is set using the spec_maxshift FlexurePar Keywords, where the default is 20 pixels. If a spectrum is measured to have a shift greater than this value, the parameter excessive_shift determines how the code responds. The default value use_median allows the code to use the median flexure shift among all the objects in the same slit (if more than one object is detected) or among all the other slits. If a median value is not available, the flexure correction will not be applied to this spectrum. Optionally, the user may specify excessive_shift = crash to cause the code to stop execution with an error or excessive_shift = set_to_zero to allow the code to continue executing while skipping flexure correction (for this object) by setting the shift to zero or excessive_shift = continue to utilize the large shift value. This feature is included caveat emptor, and the user should carefully examine the flexure QA PNG images (QA/PNGs/<objname>_global_<DET>_<SLIT>_spec_flex_corr.png and similar) to be sure excessive flexure shift is not a spurious result of low signal-to-noise in the sky background before using the continue option.


The basic algorithm may be summarized as follows:

  1. Identify the overlapping wavelength range between data and archived sky.

  2. Rebin the archived sky spectrum onto the overlapping wavelength range.

  3. Smooth the sky spectrum to the resolution of the data, if the archive has higher spectral resolution (preferred).

  4. Normalize each spectrum to unit average sky counts

  5. Subtract a bspline continuum from each

  6. Perform a cross-correlation

  7. Fit the cross-correlation with a parabola to find center

  8. Apply shift

Alternate sky models

You may find that the default sky models are not the best suited for your data. If so, there is a script that allows the user to plot the extracted sky spectrum for their data against any of the sky models in the PypeIt archive.

The script usage can be displayed by calling the script with the -h option:

$ pypeit_compare_sky -h
usage: pypeit_compare_sky [-h] [--exten EXTEN] [--optimal]
                          [--scale_user SCALE_USER]
                          file skyfile

Compare the extracted sky spectrum against an archived sky model maintained by

positional arguments:
  file                  spec1d Spectral file
  skyfile               Archived PypeIt sky file (e.g. paranal_sky.fits)

  -h, --help            show this help message and exit
  --exten EXTEN         FITS extension (default: None)
  --optimal             Show Optimal? Default is boxcar (default: False)
  --scale_user SCALE_USER
                        Scale user spectrum by a factor (default: 1.0)

As noted above, the Paranal sky model is the default reference. Presently, we are finding that the sky spectrum at Mauna Kea (measured with LRIS) is sufficiently variable and dark that a robust solution is challenging. Fair results are achieved by using the instrument-specific sky spectra in the LowRedux package. The best practice currently is to use the one that best matches as an optional parameter

The models supplied with PypeIt are (see here),




Description to come


Mauna Kea sky observed with LRISb and the 400/3400 grism


Mauna Kea sky observed with LRISb and the 600/4000 grism [Default for lris_blue]


Mt. Hamilton sky observed with Kastb and the 600 grism [Default for kast_blue]


Description to come


We have also implemented a method to calculate a flexure correction across multiple detectors, i.e. with an expanded wavelength coverage. In contrast to the standard approach that estimates and applies a single pixel shift for the entire spectrum, this technique fits for a linear correction with wavelength.

Thus far, it has only been developed and fine-tuned for the 1200 line grating of Keck/DEIMOS. It is unlikely to work very well for wavelengths much blueward of 6000 angstrom (where sky emission lines are sparse).

Briefly, this algorithm:

  1. Match slits across pairs of red/blue detectors

  2. Measure the centroids of select sky lines

  3. Fit the flexure solutions, slit by slit

  4. Fit a 2D solution to all of the slits

  5. Write output, including QA

  6. The user then needs to read in the output and apply it to their spectra with their own custom code.

Future work may combine this approach with the standard (e.g. implement cross-correlation with a stretch).

If you wish to adopt this approach (not recommended for most users), there are several key steps:

First, modify your PypeIt Reduction File to turn off the standard flexure and to avoid the vacuum frame:

   spec_method = skip
      refframe = observed

Second, generate a Flexure File as described below.

Last, run the pypeit_multislit_flexure script. The script usage can be displayed by calling the script with the -h option:

$ pypeit_multislit_flexure -h
usage: pypeit_multislit_flexure [-h] [--clobber] [--debug] flex_file outroot

Calculate and apply flexure corrections for 1D spectra produced by PypeIt.

positional arguments:
  flex_file   File to guide flexure corrections for this multi-slit mode.  This
              file must have the following format:

              flexure read
              flexure end

  outroot     Output fileroot for the flexure fits saved as FITS.

  -h, --help  show this help message and exit
  --clobber   Clobber output files
  --debug     show debug plots?

and a typical call looks like:

pypeit_multislit_flexure file.flex out_root

where out_root is the prefix for the FITS file generated that contains the flexure solution for all of the slits.

Flexure File

After running PypeIt with the standard call, construct a simple Flexure File ,which is a type of Input File Format. It has a (required) Parameter Block that must specify the spectrograph name and a (required) Data Block that provides the table of files to process.

Here is an example file:

# User-defined execution parameters
spectrograph = keck_deimos

flexure read
flexure end

As desired, you can modify the FlexurePar Keywords in the top block.

Output File

The output file produced by pypeit_multislit_flexure is named ${outroot}${target}_${filename}.fits, where

  • outroot is the 2nd command-line argument (see above)

  • target is pulled from the header of the first spec1d file in the Flexure File (the TARGET header keyword must exist)

  • filename is parsed from the FILENAME header keyword:

    filename = header['FILENAME'].split('.')[2]

The file has the following two extensions:

HDU Name

HDU Type

Data Type




Empty data HDU. Contains basic header information.



All data from the MultiSlitFlexure datamodel