Example #1
0
def _fits2sl(fits_sect):
    pyth_slice = {}
    for k, sects in fits_sect.items():
        pyth_slice[k] = []
        for sect in sects:
            pyth_slice[k].append(fitsxy2py(sect))
    return pyth_slice
Example #2
0
def vertical_correct(ccd,
                     fitting_sections=None,
                     method='median',
                     sigclip_kw=dict(sigma=2, maxiters=5),
                     dtype='float32',
                     return_pattern=False,
                     update_header=True,
                     verbose=False):
    ''' Correct vertical strip patterns.

    Paramters
    ---------

    ccd : CCDData, HDU object, HDUList, or ndarray.
        The CCD to subtract the vertical pattern.

    fitting_sections : list of two str, optional.
        The sections to be used for the vertical pattern estimation. This must be identical to the
        usual FITS section (i.e., that used in SAO ds9 or IRAF, 1-indexing and last-index-inclusive),
        not in python. **Give it in the order of ``[<upper>, <lower>]`` in FITS y-coordinate.**

    method : str, optional.
        One of ``['med', 'avg', 'median', 'average', 'mean']``.

    sigma, maxiters : float and int, optional
        A sigma-clipping will be done to remove hot pixels and cosmic rays for estimating the vertical
        pattern. To turn sigma-clipping off, set ``maxiters=0``.

    sigclip_kw : dict, optional
        The keyword arguments for the sigma clipping.

    dtype : str, dtype, optional
        The data type to be returned.

    return_pattern : bool, optional.
        If `True`, the subtracted pattern will also be returned.
        Default is `False`.

    update_header : bool, optional.
        Whether to update the header if there is any.

    Return
    ------

    '''
    _t = Time.now()
    data, hdr = _parse_data_header(ccd)

    if fitting_sections is None:
        fitting_sections = VERTICALSECTS
    elif len(fitting_sections) != 2:
        raise ValueError("fitting_sections must have two elements.")

    if method in ['median', 'med']:
        methodstr = 'taking median'
        fun = np.median
        idx = 1
    elif method in ['average', 'avg', 'mean']:
        methodstr = 'taking average'
        fun = np.mean
        idx = 0
    else:
        raise ValueError(
            "method not understood; it must be one of [med, avg, median, average, mean]."
        )

    parts = []  # The two horizontal box areas from raw data
    strips = []  # The estimated patterns (1-D)
    for sect in fitting_sections:
        parts.append(data[fitsxy2py(sect)])

    try:
        if sigclip_kw["maxiters"] == 0:
            clipstr = "no clipping"
            for part in parts:
                strips.append(fun(part, axis=0))
    except KeyError:
        pass  # The user wants to use default value of maxiters in astropy.

    clipstr = f"sigma-clipping in astropy (v {astropy.__version__})"
    if sigclip_kw:
        clipstr += f", given {sigclip_kw}."
    else:
        clipstr += "."

    for part in parts:
        clip = sigma_clipped_stats(part, axis=0, **sigclip_kw)
        strips.append(clip[idx])

    ny, nx = data.shape
    vpattern = np.repeat(strips, ny / 2, axis=0)
    vsub = data - vpattern.astype(dtype)

    if update_header and hdr is not None:
        # add as history
        add_to_header(
            hdr,
            'h',
            verbose=verbose,
            t_ref=_t,
            s=f"Vertical pattern subtracted using {fitting_sections} by {methodstr} with {clipstr}"
        )

    try:
        nccd = CCDData(data=vsub, header=hdr)
    except ValueError:
        nccd = CCDData(data=vsub, header=hdr, unit='adu')

    nccd.data = nccd.data.astype(dtype)
    if return_pattern:
        return nccd, vpattern
    return nccd
Example #3
0
def fit_fourier(data,
                freqs,
                mask=None,
                filt=None,
                apply_crrej_mask=False,
                apply_sigclip_mask=True,
                fitting_y_sections=None,
                subtract_x_sections=["[520:900]"],
                npool=5):
    """Fit Fourier series along column."""
    if mask is None:
        _mask = np.zeros(data.shape).astype(bool)
    else:
        _mask = mask.copy()

    if apply_crrej_mask:
        if filt is None:
            raise ValueError("filt must be given if apply_crrej_mask is True.")
        mask_cr = cr_reject_nic(data, filt=filt, verbose=False).mask
        _mask = _mask | mask_cr

    if fitting_y_sections is None:
        try:
            fitting_y_sections = FOURIERSECTS[filt]
        except KeyError:
            fitting_y_sections = ["[10:245]", "[850:1010]"]
    elif isinstance(fitting_y_sections, str):
        fitting_y_sections = [fitting_y_sections]

    if isinstance(subtract_x_sections, str):
        subtract_x_sections = [subtract_x_sections]

    noslice = slice(None, None, None)
    subsls = [(noslice, fitsxy2py(s)[0]) for s in subtract_x_sections]
    fitsls = [(fitsxy2py(s)[0], noslice) for s in fitting_y_sections]

    fitmask = np.ones(data.shape).astype(bool)  # initialize with masking True
    submask = np.ones(data.shape).astype(bool)  # initialize with masking True
    for fitsl in fitsls:
        fitmask[fitsl] = False

    for subsl in subsls:
        submask[subsl] = False

    _mask = _mask | fitmask | submask

    if apply_sigclip_mask:
        _data = np.ma.array(data, mask=mask)
        mask_sc = sigma_clip(_data, axis=0, sigma=3, maxiters=5).mask
        _mask = _mask | mask_sc

    ny, nx = data.shape
    yy, xx = np.mgrid[:ny, :nx]

    pool = Pool(npool)
    args = [
        list(yy.T),  # x to eval (= y_index of data, 0~1024)
        list(data.T),  # y for fit (pixel value)
        list(_mask.T),  # mask for fit
        [freqs] * nx,
        np.arange(nx)  # x_index of data
    ]
    res = np.array(pool.starmap(_fitter, np.array(args).T))
    pool.close()
    res = res[np.argsort(res[:, 0])]  # sort by index
    popts = np.array(res[:, 1])
    pattern = np.stack(res[:, 2], axis=1)

    return pattern, popts, _mask
Example #4
0
        pyth_slice[k] = []
        for sect in sects:
            pyth_slice[k].append(fitsxy2py(sect))
    return pyth_slice


def OBJSLICES(right_half=False):
    return _fits2sl(OBJSECTS(right_half))


FOURIERSLICES = _fits2sl(FOURIERSECTS)
NICSLICES = {}
VERTICALSLICES = []

for k, sect in NICSECTS.items():
    NICSLICES[k] = fitsxy2py(sect)

for sect in VERTICALSECTS:
    VERTICALSLICES.append(fitsxy2py(sect))

FOURIPEAKSLICE = fitsxy2py(FOURIPEAKSECT)


NHAO_LOCATION = dict(lon=134.3356, lat=35.0253, elevation=0.449)


def infer_filter(ccd, filt=None, verbose=True):
    if filt is None:
        try:
            filt = ccd.header["FILTER"]
            if verbose:
Example #5
0
    for k, sects in fits_sect.items():
        pyth_slice[k] = []
        for sect in sects:
            pyth_slice[k].append(fitsxy2py(sect))
    return pyth_slice


def OBJSLICES(right_half=False):
    return _fits2sl(OBJSECTS(right_half))


NICSLICES = {}
VERTICALSLICES = []

for k, sect in NICSECTS.items():
    NICSLICES[k] = fitsxy2py(sect)

for sect in VERTICALSECTS:
    VERTICALSLICES.append(fitsxy2py(sect))

NHAO_LOCATION = dict(lon=134.3356, lat=35.0253, elevation=0.449)


def infer_filter(ccd, filt=None, verbose=True):
    if filt is None:
        try:
            filt = ccd.header["FILTER"]
            if verbose:
                print(f"Assuming filter is '{filt}' from header.")
        except (KeyError, AttributeError):
            raise TypeError("Filter cannot be inferred from the given ccd.")