ramp_fitting step

This step determines the mean count rate for each pixel by performing a linear fit to the pixel ramps. The count rate is determined by a linear fit to the cosmic-ray-free and saturation-free ramp segments for each pixel. Segments are derived using the 4-D GROUPDQ array of the input data set, under the assumption that the jump step will have already flagged CR’s. Segments are also terminated where saturation flags are found.

Official documentation for ramp_fitting can be found here:

https://jwst-pipeline.readthedocs.io/en/latest/jwst/ramp_fitting/index.html

Note that there are special use cases for this step (e.g. single group integrations) so the official documentation should be consulted for these cases.

Input data

An example of running the ramp_fitting step is now shown using a simple simulated observation of a galaxy with the MIRI Imager (F1130W filter) produced with MIRISim v2.3, with precending pipeline steps applied, i.e. jump output.

Python

Start by importing what will be used and set the CRDS_CONTEXT

# imports
import os, glob, shutil
import numpy as np
from matplotlib.colors import LogNorm
import matplotlib.pyplot as plt
from jwst import datamodels

# set the CRDS_CONTEXT
os.environ["CRDS_CONTEXT"] = "jwst_0641.pmap"

Import jump and print the docstring and spec to show some information

# import the step
from jwst.ramp_fitting import ramp_fit_step

# print the description and options
print(ramp_fit_step.RampFitStep.__doc__)
print(ramp_fit_step.RampFitStep.spec)
    This step fits a straight line to the value of counts vs. time to
    determine the mean count rate for each pixel.
    

        int_name = string(default='')
        save_opt = boolean(default=False) # Save optional output
        opt_name = string(default='')
        maximum_cores = option('none', 'quarter', 'half', 'all', default='none') # max number of processes to create
    

Set the name of the input file and run the step. This will produce an output file ending with _rampfitstep.fits

Parameters used:

output_use_model : boolean, optional, default=False
     propagate the input filename to the output

save_results: boolean, optional, default=False
     save the results to file

Note that the ramp_fitting will return the output datamodel(s) depending on the input. If the input file has only one integration, ramp_fitting will return the rate image datamodel. If the number of integrations is greater than 1, it will also return the rate-per-intgration datamodel, which can be used for TSO analysis.

Parameters unused:

save_opt : boolean, optional, default=False
     save the fit parameters. If the user is interested in the ramp segment fit parameters (slopes, intercepts, etc.) then this file should be saved. An example of      using this file is given below.

# user specified
my_input_file = 'det_image_seq1_MIRIMAGE_F1130Wexp1_jumpstep.fits'

# run the step
dm, dm_tso = ramp_fit_step.RampFitStep.call(my_input_file, output_use_model=True, save_results=True)
2020-10-29 14:29:19,047 - CRDS - ERROR -  Error determining best reference for 'pars-rampfitstep'  =   Unknown reference type 'pars-rampfitstep'
2020-10-29 14:29:19,050 - stpipe.RampFitStep - INFO - RampFitStep instance created.
2020-10-29 14:29:19,144 - stpipe.RampFitStep - INFO - Step RampFitStep running with args ('det_image_seq1_MIRIMAGE_F1130Wexp1_jumpstep.fits',).
2020-10-29 14:29:19,146 - stpipe.RampFitStep - INFO - Step RampFitStep parameters are: {'pre_hooks': [], 'post_hooks': [], 'output_file': None, 'output_dir': None, 'output_ext': '.fits', 'output_use_model': True, 'output_use_index': True, 'save_results': True, 'skip': False, 'suffix': None, 'search_output_file': True, 'input_dir': '', 'int_name': '', 'save_opt': False, 'opt_name': '', 'maximum_cores': 'none'}
2020-10-29 14:29:19,431 - stpipe.RampFitStep - INFO - Using READNOISE reference file: /Users/patrickkavanagh/crds_mirror/references/jwst/miri/jwst_miri_readnoise_0059.fits
2020-10-29 14:29:19,495 - stpipe.RampFitStep - INFO - Using GAIN reference file: /Users/patrickkavanagh/crds_mirror/references/jwst/miri/jwst_miri_gain_0008.fits
2020-10-29 14:29:19,521 - stpipe.RampFitStep - INFO - Using algorithm = ols
2020-10-29 14:29:19,522 - stpipe.RampFitStep - INFO - Using weighting = optimal
2020-10-29 14:29:19,698 - stpipe.RampFitStep - INFO - Number of leading groups that are flagged as DO_NOT_USE: 1
2020-10-29 14:30:10,040 - stpipe.RampFitStep - INFO - Number of groups per integration: 20
2020-10-29 14:30:10,041 - stpipe.RampFitStep - INFO - Number of integrations: 2
2020-10-29 14:30:10,299 - stpipe.RampFitStep - INFO - Saved model in det_image_seq1_MIRIMAGE_F1130Wexp1_rampfitstep.fits
2020-10-29 14:30:10,549 - stpipe.RampFitStep - INFO - Saved model in det_image_seq1_MIRIMAGE_F1130Wexp1_rampfitstep.fits
2020-10-29 14:30:10,550 - stpipe.RampFitStep - INFO - Step RampFitStep done

We can now plot the input ramp image and the output slope (rate) image

# open input file
in_dm = datamodels.open('det_image_seq1_MIRIMAGE_F1130Wexp1_jumpstep.fits')

# plot
fig, axs = plt.subplots(1, 2, figsize=(14, 7), sharey=True)

axs[0].imshow(in_dm.data[0,-1,:,:], cmap='jet', interpolation='nearest', origin='lower', norm=LogNorm(vmin=1.1e4,vmax=6.5e4))
axs[0].annotate('jump step output (ramp)', xy=(0.0, 1.02), xycoords='axes fraction', fontsize=12, fontweight='bold', color='k')
axs[0].set_facecolor('black')
axs[1].imshow(dm.data, cmap='jet', interpolation='nearest', origin='lower', norm=LogNorm(vmin=10, vmax=150))
axs[1].annotate('DMS Level 2A (slope)', xy=(0.0, 1.02), xycoords='axes fraction', fontsize=12, fontweight='bold', color='k')
axs[1].set_facecolor('black')
plt.tight_layout()
plt.show()
2020-10-29 14:30:47,390 - stpipe - WARNING - /Users/patrickkavanagh/anaconda3/anaconda3/envs/jwst7.6/lib/python3.8/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
../_images/ramp_fitting_9_1.png

Command line

To achieve the same result from the command line there are a couple of options.

Option 1: Run the RampFitStep class using the strun command:

strun jwst.ramp_fitting.RampFitStep det_image_seq1_MIRIMAGE_F1130Wexp1_jumpstep.fits

Option 2: If they don’t already exist, collect the pipeline configuration files in your working directory using collect_pipeline_configs and then run the RampFitStep using the strun command with the associated ramp_fit.cfg file.

collect_pipeline_cfgs cfgs/

strun cfgs/ramp_fit.cfg det_image_seq1_MIRIMAGE_F1130Wexp1_jumpstep.fits

This will produce the same output file ending with _rampfitstep.fits

A full list of the command line options are given by running the following:

strun jwst.ramp_fitting.RampFitStep -h

or

strun cfgs/ramp_fit.cfg -h

Override reference file

The ramp_fitting step uses the readnoise and gain reference files. During ramp fitting, the GAIN values are used to temporarily convert the pixel values from units of DN to electrons, and convert the results of ramp fitting back to DN. The READNOISE values are used as part of the noise estimate for each pixel. Both are necessary for proper computation of noise estimates. To override these in Python:

# set the readnoise and gain reference file names
my_ref_rn = 'my_readnoise.fits'
my_ref_gn = 'my_gain.fits'

dm, dm_tso = ramp_fit_step.RampFitStep.call(my_input_file, output_use_model=True, save_results=True,
                                            override_readnoise=my_ref_rn, override_gain=my_ref_gn)

and using the command line:

strun jwst.ramp_fitting.RampFitStep det_image_seq1_MIRIMAGE_F1130Wexp1_jumpstep.fits  --override_readnoise my_readnoise.fits --override_gain my_gain.fits

or

strun cfgs/ramp_fit.cfg det_image_seq1_MIRIMAGE_F1130Wexp1_jumpstep.fits  --override_readnoise my_readnoise.fits --override_gain my_gain.fits

Save the segment fit results using save_opt

As stated above, the fit results to ramp segments can be saved using the save_opt parameter. The file will be saved with name ending _fitopt.fits. To do this in Python:

dm, dm_tso = ramp_fit_step.RampFitStep.call(my_input_file, output_use_model=True, save_results=True,
                                            save_opt=True)
2020-10-29 14:31:08,315 - stpipe - WARNING - /Users/patrickkavanagh/anaconda3/anaconda3/envs/jwst7.6/lib/python3.8/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)

2020-10-29 14:31:08,778 - CRDS - ERROR -  Error determining best reference for 'pars-rampfitstep'  =   Unknown reference type 'pars-rampfitstep'
2020-10-29 14:31:08,780 - stpipe.RampFitStep - INFO - RampFitStep instance created.
2020-10-29 14:31:08,858 - stpipe.RampFitStep - INFO - Step RampFitStep running with args ('det_image_seq1_MIRIMAGE_F1130Wexp1_jumpstep.fits',).
2020-10-29 14:31:08,859 - stpipe.RampFitStep - INFO - Step RampFitStep parameters are: {'pre_hooks': [], 'post_hooks': [], 'output_file': None, 'output_dir': None, 'output_ext': '.fits', 'output_use_model': True, 'output_use_index': True, 'save_results': True, 'skip': False, 'suffix': None, 'search_output_file': True, 'input_dir': '', 'int_name': '', 'save_opt': True, 'opt_name': '', 'maximum_cores': 'none'}
2020-10-29 14:31:09,126 - stpipe.RampFitStep - INFO - Using READNOISE reference file: /Users/patrickkavanagh/crds_mirror/references/jwst/miri/jwst_miri_readnoise_0059.fits
2020-10-29 14:31:09,145 - stpipe.RampFitStep - INFO - Using GAIN reference file: /Users/patrickkavanagh/crds_mirror/references/jwst/miri/jwst_miri_gain_0008.fits
2020-10-29 14:31:09,167 - stpipe.RampFitStep - INFO - Using algorithm = ols
2020-10-29 14:31:09,168 - stpipe.RampFitStep - INFO - Using weighting = optimal
2020-10-29 14:31:09,320 - stpipe.RampFitStep - INFO - Number of leading groups that are flagged as DO_NOT_USE: 1
2020-10-29 14:32:05,841 - stpipe.RampFitStep - INFO - Number of groups per integration: 20
2020-10-29 14:32:05,842 - stpipe.RampFitStep - INFO - Number of integrations: 2
2020-10-29 14:32:08,656 - stpipe.RampFitStep - INFO - Saved model in det_image_seq1_MIRIMAGE_F1130Wexp1_fitopt.fits
2020-10-29 14:32:08,881 - stpipe.RampFitStep - INFO - Saved model in det_image_seq1_MIRIMAGE_F1130Wexp1_rampfitstep.fits
2020-10-29 14:32:09,167 - stpipe.RampFitStep - INFO - Saved model in det_image_seq1_MIRIMAGE_F1130Wexp1_rampfitstep.fits
2020-10-29 14:32:09,168 - stpipe.RampFitStep - INFO - Step RampFitStep done

and using the command line:

strun jwst.ramp_fitting.RampFitStep det_image_seq1_MIRIMAGE_F1130Wexp1_jumpstep.fits --save_opt

or

strun cfgs/ramp_fit.cfg det_image_seq1_MIRIMAGE_F1130Wexp1_jumpstep.fits --save_opt

We can plot the fits to individual segments in the integrations. In the sample file there are two integrations. The segment fits are shown with the segment slopes, weights and final slope value.

# load the fit results file and input file to a datamodel
fitopt_dm = datamodels.RampFitOutputModel('det_image_seq1_MIRIMAGE_F1130Wexp1_fitopt.fits')
in_dm = datamodels.open(my_input_file)

# set the sample pixel (selected knowing there is a jump on the ramp)
pixel = [550, 393]

# get the output slope value
final_slope = dm.data[pixel[1], pixel[0]]

# plot
fig, axs = plt.subplots(1, 2, figsize=(12, 5))

# in this case there are two integrations, show each
for int_num in [0, 1]:
    
    # identify the jump indices using the jump flag in the groupdq extension
    groupdq_ramp = in_dm.groupdq[int_num, :, pixel[1], pixel[0]]
    idx = [i for i ,v in enumerate(groupdq_ramp >= 4) if v]

    # get the number of segments
    seg_num = len(idx) + 1

    # add extra element to the start of the idx array to make plotting easier
    idx = [0] + idx

    if len(idx) > 1:
        # cycle through segments
        for n in range(seg_num):
            
            try:
                ramp_seg = in_dm.data[int_num, idx[n]:idx[n+1], pixel[1], pixel[0]]
                group = np.arange(idx[n], idx[n+1])
            except IndexError:
                ramp_seg = in_dm.data[int_num, idx[n]:, pixel[1], pixel[0]]
                group = np.arange(idx[n], in_dm.data.shape[1])
                

            # convert group number to exposure time
            exp_time = (group+1) * in_dm.meta.exposure.group_time

            # plot the ramp segments
            axs[int_num].plot(exp_time, ramp_seg, marker='o', markersize=3, linestyle='-', linewidth=0, c='r')

            # get the slopes/intercepts for the segment from the datamodel
            slope = fitopt_dm.slope[int_num, n, pixel[1], pixel[0]]
            yint = fitopt_dm.yint[int_num, n, pixel[1], pixel[0]]
            weight = fitopt_dm.weights[int_num, n, pixel[1], pixel[0]]
            
            # plot fit to the segment
            fit = slope * exp_time + yint
            axs[int_num].plot(exp_time, fit, marker='o', markersize=0, linestyle='-', linewidth=1, c='k')
            axs[int_num].annotate('s=%0.2e' % slope, xy=(min(exp_time), min(fit)+300), fontsize=8, color='k')
            axs[int_num].annotate('w=%0.2e' % weight, xy=(min(exp_time), min(fit)-300), fontsize=8, color='k')

            axs[int_num].annotate('Final slope: %0.2e' % final_slope, xy=(0.5, 0.05), 
                                 xycoords='axes fraction', fontsize=8, color='k')
            axs[int_num].annotate('Pixel: %d,%d' % (pixel[0],pixel[1]), xy=(0.05, 0.95), 
                                 xycoords='axes fraction', fontsize=10, color='k')
            axs[int_num].set_xlabel('Time (s)')
            axs[int_num].set_ylabel('DN')
            
    else:
        ramp_seg = in_dm.data[int_num, :, pixel[1], pixel[0]]
        group = np.arange(in_dm.data.shape[1]) + 1

        # convert group number to exposure time
        exp_time = group * in_dm.meta.exposure.group_time

        # plot the ramp segments
        axs[int_num].plot(exp_time, ramp_seg, marker='o', markersize=3, linestyle='-', linewidth=0, c='r')

        # get the slopes/intercepts for the segment from the datamodel
        slope = fitopt_dm.slope[int_num, 0, pixel[1], pixel[0]]
        yint = fitopt_dm.yint[int_num, 0, pixel[1], pixel[0]]
        weight = fitopt_dm.weights[int_num, 0, pixel[1], pixel[0]]

        # plot fit to the segment
        fit = slope * exp_time + yint
        axs[int_num].plot(exp_time, fit, marker='o', markersize=0, linestyle='-', linewidth=1, c='k')
        axs[int_num].annotate('s=%0.2e' % slope, xy=(min(exp_time), min(fit)+300), fontsize=8, color='k')
        axs[int_num].annotate('w=%0.2e' % weight, xy=(min(exp_time), min(fit)-300), fontsize=8, color='k')

        axs[int_num].annotate('Final slope: %0.2e' % final_slope, xy=(0.5, 0.05), 
                             xycoords='axes fraction', fontsize=8, color='k')
        axs[int_num].annotate('Pixel: %d,%d' % (pixel[0],pixel[1]), xy=(0.05, 0.95), 
                             xycoords='axes fraction', fontsize=10, color='k')
        axs[int_num].set_xlabel('Time (s)')
        axs[int_num].set_ylabel('DN')

plt.tight_layout()
plt.show()
2020-10-29 14:33:15,053 - stpipe - WARNING - /Users/patrickkavanagh/anaconda3/anaconda3/envs/jwst7.6/lib/python3.8/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
  and should_run_async(code)
../_images/ramp_fitting_18_1.png