예제 #1
0
class MosaicRecipe(EmirRecipe):
    """
    The effect of recording a series of stare images, with the same
    acquisition parameters, and taken by pointing to a number of
    sky positions, with separations of the order of the EMIR FOV.
    This command is designed to fully cover a given area on the
    sky, but can also be used to point to a number of sky positions
    on which acquisition is only made at the beginning. Supersky
    frame(s) can be built from the image series.

    **Observing modes:**

        * Mosaic images

    """

    obresult = ObservationResultRequirement()
    # FIXME: this parameter is optional
    sources = Parameter([], 'List of x, y coordinates to measure FWHM')

    frame = Product(DataFrameType)
    catalog = Product(SourcesCatalog)

    def run(self, ri):
        return self.create_result(frame=DataFrame(None),
                                  catalog=SourcesCatalog())
예제 #2
0
파일: mos.py 프로젝트: gitter-badger/pyemir
class OffsetSpectraRecipe(EmirRecipe):
    """
    Observing mode:
        Offset spectra beyond the slit
    """

    obresult = ObservationResultRequirement()
    master_bpm = MasterBadPixelMaskRequirement()
    master_bias = MasterBiasRequirement()
    master_dark = MasterDarkRequirement()
    master_flat = MasterIntensityFlatFieldRequirement()
    master_spectral_ff = Requirement(prods.MasterSpectralFlat,
                                     'Master spectral flatfield')
    st_calibration = Requirement(prods.SlitTransmissionCalibration,
                                 'Slit tranmision calibration')
    w_calibration = Requirement(prods.WavelengthCalibration,
                                'Wavelength calibration')
    lines = Parameter('lines', None,
                      'List of x-lambda pairs of line coordinates')

    spectra = Product(prods.Spectra)
    catalog = Product(prods.LinesCatalog)

    def run(self, rinput):
        return self.create_result(spectra=prods.Spectra(),
                                  catalog=prods.LinesCatalog())
예제 #3
0
class CSUSpectraExtractionRecipe(EmirRecipe):
    """Extract spectra in image taken with the CSU configured"""

    # Recipe Requirements
    obresult = ObservationResultRequirement()
    master_bias = MasterBiasRequirement()
    master_dark = MasterDarkRequirement()
    master_flat = MasterIntensityFlatFieldRequirement()
    master_sky = MasterSkyRequirement()
    nrows_side = Parameter(5, 'Number of rows to extract around the center')
    slits_positions = Requirement(ArrayType,
                                  'Positions and widths of the slits')

    # Recipe products
    frame = Product(DataFrameType)
    rss = Product(DataFrameType)

    def run(self, rinput):
        _logger.info('starting extraction')

        flow = self.init_filters(rinput)

        hdulist = basic_processing_with_combination(rinput, flow=flow)

        hdr = hdulist[0].header
        self.set_base_headers(hdr)

        data1 = hdulist[0].data

        _logger.info('Create output images')
        rssdata = numpy.zeros(
            (rinput.slits_positions.shape[0], data1.shape[1]), dtype='float32')

        nrows = rinput.nrows_side
        # Loop over slits
        for idx, slit_coords in enumerate(rinput.slits_positions):

            x, y, ax, ay = slit_coords  # Coords in FITS coordinates

            ref_col = wc_to_pix(x - 1)
            ref_row = wc_to_pix(y - 1)

            _logger.info('Processing slit in column %i, row=%i', ref_col,
                         ref_row)

            # Simple extraction

            _logger.info('Extract %i rows around center', nrows)
            region = data1[ref_row - nrows:ref_row + nrows + 1, :]

            rssdata[idx, :] = region.mean(axis=0)

        hdurss = fits.PrimaryHDU(rssdata)

        result = self.create_result(frame=hdulist, rss=hdurss)

        return result
예제 #4
0
class ImageSkyRecipe(BaseRecipe):

    obresult = Requirement(ObservationResultType, "Observation Result")

    master_bias = Requirement(MasterBias, "Master Bias")
    master_flat = Requirement(MasterFlat, "Master Flat")

    # This field can be disabled via
    # query_options: sky_image: False
    # in drp.yaml
    sky_image = Requirement(
        SkyImage,
        description="Previous Sky Image",
        query_opts=ResultOf('sky.sky_image', node='prev'),
        default=None  # This value is used only if the query is disabled
    )
    final = Product(DataFrameType)

    def run(self, rinput):

        query_sky_image = self.query_options.get('sky_image', True)

        if query_sky_image:
            self.logger.debug('using sky, value=%s', rinput.sky_image)
        else:
            self.logger.debug('not using sky, value=%s', rinput.sky_image)

        # Here the raw images are processed
        # and a final image myframe is created
        myframe = produce_image(rinput.obresult)

        result = self.create_result(final=myframe)
        return result
예제 #5
0
class ArcCalibrationRecipe(EmirRecipe):

    obresult = ObservationResultRequirement()
    master_bpm = MasterBadPixelMaskRequirement()
    master_bias = MasterBiasRequirement()
    master_dark = MasterDarkRequirement()
    lines_catalog = Requirement(LinesCatalog, "Catalog of lines")
    polynomial_degree = Parameter(2,
                                  'Polynomial degree of the arc calibration')

    polynomial_coeffs = Product(ArrayType)

    def run(self, rinput):
        _logger.info('starting arc calibration')

        flow = self.init_filters(rinput)

        hdulist = basic_processing_with_combination(rinput, flow=flow)

        nslits = len(rinput.slits_catalog)
        coeff_table = numpy.zeros((nslits, rinput.polynomial_degree + 1))

        result = self.create_result(polynomial_coeffs=coeff_table)

        return result
예제 #6
0
class StareSpectraRecipe(EmirRecipe):
    """Process images in Stare spectra mode"""

    obresult = ObservationResultRequirement()
    master_bpm = reqs.MasterBadPixelMaskRequirement()
    master_bias = reqs.MasterBiasRequirement()
    master_dark = reqs.MasterDarkRequirement()
    master_flat = reqs.MasterSpectralFlatFieldRequirement()
    master_sky = reqs.SpectralSkyRequirement(optional=True)

    stare = Product(prods.DataFrameType)

    @emirdrp.decorators.loginfo
    def run(self, rinput):
        self.logger.info('starting stare spectra reduction')

        flow = self.init_filters(rinput)

        hdulist = basic_processing_with_combination(rinput,
                                                    flow,
                                                    method=median)
        hdr = hdulist[0].header
        self.set_base_headers(hdr)
        # Update SEC to 0
        hdr['SEC'] = 0

        self.logger.info('end stare spectra reduction')
        result = self.create_result(stare=hdulist)
        return result
예제 #7
0
class TargetAcquisitionRecipe(EmirRecipe):
    """
    Acquire a target.

    Recipe for the processing of target acquisition images.

    **Observing modes:**

        * Target acquisition


    """

    # Requirements
    obresult = ObservationResultRequirement()
    master_bpm = MasterBadPixelMaskRequirement()
    master_bias = MasterBiasRequirement()
    master_dark = MasterDarkRequirement()
    master_flat = MasterIntensityFlatFieldRequirement()

    # Products
    telescope_offset = Product(TelescopeOffset)

    def run(self, rinput):
        return self.create_result(telescope_offset=TelescopeOffset())
예제 #8
0
class WavelengthCalibrationRecipe(EmirRecipe):
    """Recipe to calibrate the spectral response.

    **Observing modes:**

        * Wavelength calibration (4.5)

    **Inputs:**

     * List of line positions
     * Calibrations up to spectral flatfielding

    **Outputs:**

     * Wavelength calibration structure

    **Procedure:**

     * TBD
    """

    master_bpm = MasterBadPixelMaskRequirement()
    master_bias = MasterBiasRequirement()
    master_dark = MasterDarkRequirement()
    master_flat = MasterIntensityFlatFieldRequirement()
    master_spectral_ff = MasterSpectralFlatFieldRequirement()

    cal = Product(WavelengthCalibration)

    def run(self, rinput):
        return self.create_result(cal=WavelengthCalibration())
예제 #9
0
파일: sky.py 프로젝트: gitter-badger/pyemir
class TestSkyCorrectRecipe(EmirRecipe):

    obresult = ObservationResultRequirement()
    master_bpm = MasterBadPixelMaskRequirement()
    master_bias = MasterBiasRequirement()
    master_dark = MasterDarkRequirement()
    master_flat = MasterIntensityFlatFieldRequirement()
    master_sky = Requirement(MasterIntensityFlat, 'Master Sky calibration')

    frame = Product(DataFrameType)

    def run(self, rinput):
        _logger.info('starting simple sky reduction')

        flow = self.init_filters(rinput)

        hdulist = basic_processing_with_combination(rinput,
                                                    flow,
                                                    method=median)
        hdr = hdulist[0].header
        self.set_base_headers(hdr)
        # Update SEC to 0
        hdr['SEC'] = 0

        result = self.create_result(frame=hdulist)

        return result
예제 #10
0
class DitherSkyRecipe(EmirRecipe):
    """Recipe to process data taken in dither sky mode.

    """

    obresult = ObservationResultRequirement()
    master_bpm = MasterBadPixelMaskRequirement()
    master_bias = MasterBiasRequirement()
    master_dark = MasterDarkRequirement()
    master_flat = MasterIntensityFlatFieldRequirement()

    skyframe = Product(MasterIntensityFlat)

    def run(self, rinput):
        _logger.debug('instrument %s, mode %s', rinput.obresult.instrument,
                      rinput.obresult.mode)
        _logger.info('starting sky reduction with dither')

        flow = self.init_filters(rinput)

        hdulist = basic_processing_with_segmentation(rinput,
                                                     flow,
                                                     method=median,
                                                     errors=True)

        hdr = hdulist[0].header
        self.set_base_headers(hdr)
        _logger.info('end sky reduction with dither')

        result = self.create_result(skyframe=hdulist)

        return result
예제 #11
0
class SimpleSkyRecipe(EmirRecipe):
    """Recipe to process data taken in intensity flat-field mode.

    """

    master_bpm = MasterBadPixelMaskRequirement()
    obresult = ObservationResultRequirement()
    master_bias = MasterBiasRequirement()
    master_dark = MasterDarkRequirement()
    master_flat = MasterIntensityFlatFieldRequirement()

    skyframe = Product(MasterIntensityFlat)

    def run(self, rinput):
        _logger.info('starting sky reduction')

        flow = self.init_filters(rinput)

        hdulist = basic_processing_with_combination(rinput,
                                                    flow,
                                                    method=median,
                                                    errors=True)

        hdr = hdulist[0].header
        self.set_base_headers(hdr)

        result = self.create_result(skyframe=hdulist)

        return result
예제 #12
0
class SkySpecRecipe(EmirRecipe):
    """Recipe to process data taken in spectral sky mode.

    """

    obresult = ObservationResultRequirement()
    master_bpm = reqs.MasterBadPixelMaskRequirement()
    master_bias = reqs.MasterBiasRequirement()
    master_dark = reqs.MasterDarkRequirement()
    master_flat = reqs.MasterSpectralFlatFieldRequirement()

    skyspec = Product(prods.SkySpectrum)

    def run(self, rinput):
        self.logger.info('starting spectral sky reduction')

        flow = self.init_filters(rinput)

        hdulist = basic_processing_with_combination(rinput,
                                                    flow,
                                                    method=median,
                                                    errors=True)

        hdr = hdulist[0].header
        self.set_base_headers(hdr)
        self.logger.info('end sky spectral reduction')

        result = self.create_result(skyspec=hdulist)

        return result
예제 #13
0
class TelescopeFineFocusRecipe(EmirRecipe):
    """
    Recipe to compute the telescope focus.

    **Observing modes:**

        * Telescope fine focus

    **Inputs:**

     * A list of images
     * A list of sky images
     * Bias, dark, flat
     * A model of the detector
     * List of focii

    **Outputs:**
     * Best focus

    """

    master_bpm = reqs.MasterBadPixelMaskRequirement()
    master_bias = reqs.MasterBiasRequirement()
    master_dark = reqs.MasterDarkRequirement()
    master_flat = reqs.MasterIntensityFlatFieldRequirement()
    objects = Parameter([], 'List of x-y pair of object coordinates'),

    focus = Product(TelescopeFocus)

    def run(self, rinput):
        return self.create_result(focus=TelescopeFocus())
예제 #14
0
class DTUFocusRecipe(EmirRecipe):
    """
    Recipe to compute the DTU focus.

    **Observing modes:**

        * EMIR focus control

    **Inputs:**

     * A list of images
     * A list of sky images
     * Bias, dark, flat
     * A model of the detector
     * List of focii

    **Outputs:**
     * Best focus

    """

    master_bpm = reqs.MasterBadPixelMaskRequirement()
    master_bias = reqs.MasterBiasRequirement()
    master_dark = reqs.MasterDarkRequirement()
    master_flat = reqs.MasterIntensityFlatFieldRequirement()
    objects = Parameter([], 'List of x-y pair of object coordinates'),
    msm_pattern = Parameter([], 'List of x-y pair of slit coordinates'),
    dtu_focus_range = Parameter(
        'dtu_focus_range', [], 'Focus range of the DTU: begin, end and step')

    focus = Product(DTUFocus)


    def run(self, rinput):
        return self.create_result(focus=DTUFocus())
예제 #15
0
class SlitTransmissionRecipe(EmirRecipe):
    """Recipe to calibrate the slit transmission.

    **Observing modes:**

        * Slit transmission calibration (4.4)

    **Inputs:**

        * A list of uniformly illuminated images of MSM

    **Outputs:**

     * A list of slit transmission functions

    **Procedure:**

     * TBD

    """

    master_bpm = MasterBadPixelMaskRequirement()
    master_bias = MasterBiasRequirement()
    master_dark = MasterDarkRequirement()

    slit = Product(SlitTransmissionCalibration)

    def run(self, rinput):
        return self.create_result(slit=SlitTransmissionCalibration())
예제 #16
0
class BiasRecipe(EmirRecipe):
    """
    Recipe to process data taken in Bias image Mode.

    Bias images only appear in Simple Readout mode.

    **Observing modes:**

     * Bias Image (3.1)

    **Inputs:**

    **Outputs:**

     * A combined bias frame, with variance extension.
     * Statistics of the final image per channel (mean, median, variance)

    **Procedure:**

    The list of images can be readly processed by
    combining them with a median algorithm.

    """

    master_bpm = MasterBadPixelMaskRequirement()
    obresult = ObservationResultRequirement()

    biasframe = Product(MasterBias)

    def run(self, rinput):
        _logger.info('starting bias reduction')

        iinfo = gather_info_frames(rinput.obresult.frames)

        if iinfo:
            mode = iinfo[0]['readmode']
            if mode.lower() not in EMIR_BIAS_MODES:
                msg = 'readmode %s, is not a bias mode' % mode
                _logger.error(msg)
                raise RecipeError(msg)

        flow = lambda x: x
        hdulist = basic_processing_with_combination(rinput,
                                                    flow,
                                                    method=median,
                                                    errors=False)

        pdata = hdulist[0].data

        # update hdu header with
        # reduction keywords
        hdr = hdulist[0].header
        self.set_base_headers(hdr)
        hdr['CCDMEAN'] = pdata.mean()

        _logger.info('bias reduction ended')

        result = self.create_result(biasframe=DataFrame(hdulist))
        return result
예제 #17
0
class IntensityFlatRecipe(EmirRecipe):
    """Recipe to process data taken in intensity flat-field mode.

    Recipe to process intensity flat-fields. The flat-on and
    flat-off images are combined (method?) separately and the subtracted
    to obtain a thermal subtracted flat-field.

    **Observing modes:**

     * Intensity Flat-Field

    **Inputs:**

      * A master dark frame
      * Non linearity
      * A model of the detector.

    **Outputs:**

     * TBD

    **Procedure:**

     * A combined thermal subtracted flat field, normalized to median 1,
       with with variance extension and quality flag.

    """

    master_bpm = MasterBadPixelMaskRequirement()
    obresult = ObservationResultRequirement()
    master_bias = MasterBiasRequirement()
    master_dark = MasterDarkRequirement()

    flatframe = Product(MasterIntensityFlat)

    def run(self, rinput):
        _logger.info('starting flat reduction')

        errors = True

        flow = self.init_filters(rinput)
        hdulist = basic_processing_with_combination(rinput,
                                                    flow,
                                                    method=median,
                                                    errors=errors)

        hdr = hdulist[0].header
        self.set_base_headers(hdr)
        mm = hdulist[0].data.mean()
        hdr['CCDMEAN'] = mm

        hdulist[0].data /= mm
        if errors:
            hdulist['variance'].data /= (mm * mm)

        result = self.create_result(flatframe=hdulist)

        return result
예제 #18
0
class CoaddRecipe(EmirRecipe):
    """Generic Coadd Recipe"""

    obresult = ObservationResultRequirement()

    result_coadd = Product(prods.DataFrameType)

    @classmethod
    def build_recipe_input(cls, obsres, dal, pipeline='default'):
        return cls.build_recipe_input_gtc(obsres, dal, pipeline=pipeline)

    @classmethod
    def build_recipe_input_gtc(cls, obsres, dal, pipeline='default'):
        cls.logger.debug('start recipe input builder')

        # This depends on the RecipeResult
        result_field = 'spec_abba'

        stareImagesIds = obsres.stareSpectraIds
        cls.logger.debug('Coadd images IDS %s: ', stareImagesIds)
        stareImages = []
        for subresId in stareImagesIds:
            subres = dal.getRecipeResult(subresId)
            stareImages.append(subres['elements'][result_field])

        newOR = numina.core.ObservationResult()
        newOR.frames = stareImages
        newRI = cls.create_input(obresult=newOR)
        cls.logger.debug('end recipe input builder')
        return newRI

    def run(self, rinput):
        self.logger.info('starting coadd reduction')

        flow = self.init_filters(rinput)

        nimages = len(rinput.obresult.frames)
        self.logger.info('we receive %d images', nimages)
        if nimages == 0:
            msg = 'Received %d images' % nimages
            raise numina.exceptions.RecipeError(msg)

        hdulist = basic_processing_with_combination(
            rinput,
            flow,
            method=combine.mean,
            prolog="Process Generic Coadd"
        )

        hdr = hdulist[0].header
        self.set_base_headers(hdr)
        # Update SEC to 0
        # hdr['SEC'] = 0

        result = self.create_result(spec_coadd_abba=hdulist)
        self.logger.info('end coadd reduction')
        return result
예제 #19
0
class DarkRecipe(EmirRecipe):
    """Recipe to process data taken in Dark current image Mode.

    Recipe to process dark images. The dark images will be combined
    using the median.
    They do have to be of the same exposure time t.

    **Observing mode:**

     * Dark current Image (3.2)

    **Inputs:**

    **Outputs:**

     * A combined dark frame, with variance extension.
    """

    master_bpm = MasterBadPixelMaskRequirement()
    obresult = ObservationResultRequirement()
    master_bias = MasterBiasRequirement()

    darkframe = Product(MasterDark)

    def run(self, rinput):

        _logger.info('starting dark reduction')

        flow = self.init_filters(rinput)

        iinfo = gather_info_frames(rinput.obresult.frames)
        ref_exptime = 0.0
        for el in iinfo[1:]:
            if abs(el['texp'] - ref_exptime) > 1e-4:
                _logger.error('image with wrong exposure time')
                raise RecipeError('image with wrong exposure time')

        hdulist = basic_processing_with_combination(rinput,
                                                    flow,
                                                    method=median,
                                                    errors=True)

        pdata = hdulist[0].data

        # update hdu header with
        # reduction keywords

        hdr = hdulist[0].header
        self.set_base_headers(hdr)
        hdr['CCDMEAN'] = pdata.mean()

        _logger.info('dark reduction ended')
        result = self.create_result(darkframe=hdulist)
        return result
예제 #20
0
class SpectralFlatRecipe(EmirRecipe):

    master_bpm = MasterBadPixelMaskRequirement()
    obresult = ObservationResultRequirement()
    master_bias = MasterBiasRequirement()
    master_dark = MasterDarkRequirement()
    master_flat = MasterIntensityFlatFieldRequirement()

    flatframe = Product(MasterSpectralFlat)

    def run(self, rinput):
        return self.create_result(flatframe=MasterSpectralFlat())
예제 #21
0
class StareImageBaseRecipe(EmirRecipe):
    """Process images in Stare Image Mode"""

    obresult = ObservationResultRequirement()
    master_bpm = reqs.MasterBadPixelMaskRequirement()
    master_bias = reqs.MasterBiasRequirement()
    master_dark = reqs.MasterDarkRequirement()
    master_flat = reqs.MasterIntensityFlatFieldRequirement()
    master_sky = reqs.MasterSkyRequirement(optional=True)

    frame = Product(DataFrameType)

    def __init__(self, *args, **kwargs):
        super(StareImageBaseRecipe, self).__init__(*args, **kwargs)
        if False:
            self.query_options['master_sky'] = Ignore()

    @emirdrp.decorators.loginfo
    @emirdrp.decorators.timeit
    def run(self, rinput):
        self.logger.info('starting stare image reduction')

        flow = self.init_filters(rinput)

        hdulist = basic_processing_with_combination(
            rinput,
            flow,
            method=combine.median
        )
        hdr = hdulist[0].header
        self.set_base_headers(hdr)

        if rinput.master_bpm:
            hdul_bpm = rinput.master_bpm.open()
            hdu_bpm = generate_bpm_hdu(hdul_bpm[0])
        else:
            hdu_bpm = generate_empty_bpm_hdu(hdulist[0])

        # Append the BPM to the result
        hdulist.append(hdu_bpm)
        self.logger.info('end stare image reduction')
        result = self.create_result(frame=hdulist)

        return result

    def set_base_headers(self, hdr):
        """Set metadata in FITS headers."""
        hdr = super(StareImageBaseRecipe, self).set_base_headers(hdr)
        # Update SEC to 0
        hdr['SEC'] = 0
        return hdr
예제 #22
0
class DTUFlexureRecipe(EmirRecipe):

    """

    **Observing modes:**

        * DTU Flexure compensation
    """

    obresult = ObservationResultRequirement()
    calibration = Product(DTUFlexureCalibration)

    def run(self, rinput):
        return self.create_result(calibration=DTUFlexureCalibration())
예제 #23
0
class AstrometricCalibrationRecipe(EmirRecipe):

    """

    **Observing modes:**

        * Astrometric calibration
    """

    obresult = ObservationResultRequirement()
    calibration = Product(DataFrameType)

    def run(self, rinput):
        return self.create_result(calibration=None)
예제 #24
0
class RotationCenterRecipe(EmirRecipe):

    """

    **Observing modes:**

        * Centre of rotation
    """

    obresult = ObservationResultRequirement()
    calibration = Product(PointingOriginCalibration)

    def run(self, rinput):
        return self.create_result(calibration=PointingOriginCalibration())
예제 #25
0
class SpectralCharacterizationRecipe(EmirRecipe):

    """

    **Observing modes:**

        * Spectral characterization
    """

    obresult = ObservationResultRequirement()
    calibration = Product(WavelengthCalibration)

    def run(self, rinput):
        return self.create_result(calibration=WavelengthCalibration())
예제 #26
0
class DTU_Z_CalibrationRecipe(EmirRecipe):

    """

    **Observing modes:**

        * DTU Z calibration
    """
    obresult = ObservationResultRequirement()
    dtu_range = Parameter([], 'DTU range: begin, end and step')

    calibration = Product(DTU_Z_Calibration)

    def run(self, rinput):
        return self.create_result(calibration=DTU_Z_Calibration())
예제 #27
0
class ImageRecipe(BaseRecipe):

    obresult = Requirement(ObservationResultType, "Observation Result")
    master_bias = Requirement(MasterBias, "Master Bias")
    master_flat = Requirement(MasterFlat, "Master Flat")
    final = Product(DataFrameType)

    def run(self, rinput):

        # Here the raw images are processed
        # and a final image myframe is created
        myframe = produce_image(rinput.obresult)

        result = self.create_result(final=myframe)
        return result
예제 #28
0
class SpectroPhotometricCalibrationRecipe(EmirRecipe):

    """

    **Observing modes:**

        * Spectrophotometric calibration
    """

    obresult = ObservationResultRequirement()
    sphot = Parameter([], 'Information about standard stars')

    calibration = Product(SpectroPhotometricCalibration)

    def run(self, rinput):
        return self.create_result(calibration=SpectroPhotometricCalibration())
예제 #29
0
class FocalPlaneCalibrationRecipe(EmirRecipe):

    """

    **Observing modes:**

        * Lateral color
    """

    obresult = ObservationResultRequirement()

    calibration = Product(PointingOriginCalibration)


    def run(self, rinput):
        return self.create_result(calibration=PointingOriginCalibration())
예제 #30
0
class TestBiasCorrectRecipe(EmirRecipe):

    obresult = ObservationResultRequirement()
    master_bpm = MasterBadPixelMaskRequirement()
    master_bias = MasterBiasRequirement()
    frame = Product(DataFrameType)

    def run(self, rinput):
        _logger.info('starting simple bias reduction')

        flow = self.init_filters(rinput)
        hdu = basic_processing_with_combination(rinput, flow, method=median)
        hdr = hdu.header
        hdr['NUMRNAM'] = (self.__class__.__name__, 'Numina recipe name')
        hdr['NUMRVER'] = (self.__version__, 'Numina recipe version')
        hdulist = fits.HDUList([hdu])

        result = self.create_result(frame=hdulist)
        return result