pax_global_header 0000666 0000000 0000000 00000000064 15101150060 0014477 g ustar 00root root 0000000 0000000 52 comment=d06bc46b17811cf4172846214c7197a5aec914a2 astropy-astroscrappy-d06bc46/ 0000775 0000000 0000000 00000000000 15101150060 0016342 5 ustar 00root root 0000000 0000000 astropy-astroscrappy-d06bc46/.github/ 0000775 0000000 0000000 00000000000 15101150060 0017702 5 ustar 00root root 0000000 0000000 astropy-astroscrappy-d06bc46/.github/dependabot.yml 0000664 0000000 0000000 00000001120 15101150060 0022524 0 ustar 00root root 0000000 0000000 # To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "github-actions" # See documentation for possible values directory: ".github/workflows" # Location of package manifests schedule: interval: "monthly" groups: actions: patterns: - "*" astropy-astroscrappy-d06bc46/.github/workflows/ 0000775 0000000 0000000 00000000000 15101150060 0021737 5 ustar 00root root 0000000 0000000 astropy-astroscrappy-d06bc46/.github/workflows/python-tests.yml 0000664 0000000 0000000 00000005471 15101150060 0025152 0 ustar 00root root 0000000 0000000 name: Run unit tests on: push: pull_request: workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: tests: name: ${{ matrix.name }} (${{ matrix.os }}, ${{ matrix.toxenv }}) runs-on: ${{ matrix.os }} if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]'))" strategy: fail-fast: false matrix: include: - name: Python 3.10 with required dependencies os: ubuntu-22.04 # gcc 11.2 python-version: "3.10" toxenv: py310-test-numpy126 - name: Python 3.11 with required dependencies os: macos-latest python-version: "3.11" toxenv: py311-test-astropy60 - name: Python 3.12 with required dependencies os: ubuntu-24.04 # gcc 13.2 python-version: "3.12" toxenv: py312-test-astropy70 coverage: true - name: Python 3.13 with required dependencies os: windows-latest python-version: "3.13" toxenv: py313-test - name: Python 3.14 with required dependencies os: macos-latest python-version: "3.14" toxenv: py314-test - name: Code style checks os: ubuntu-latest python-version: "3.13" toxenv: codestyle steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: python -m pip install tox - name: Run tests if: "! matrix.coverage" run: tox -v -e ${{ matrix.toxenv }} - name: Run tests with coverage if: "matrix.coverage" run: | pip install Cython extension-helpers numpy COVERAGE=1 pip install -e .[test] pytest --pyargs astroscrappy docs --cov astroscrappy - name: Upload coverage to codecov if: "matrix.coverage" run: | pip install codecov codecov publish: needs: tests uses: OpenAstronomy/github-actions-workflows/.github/workflows/publish.yml@28e947497bed4d6ec3fa1d66d198e95a1d17bc63 # v2.2.1 with: test_extras: test test_command: pytest -p no:warnings --pyargs astroscrappy targets: | - cp*-manylinux_x86_64 - target: cp*-manylinux_aarch64 runs-on: ubuntu-24.04-arm - cp*-macosx_x86_64 - cp*-macosx_arm64 - cp*-win_amd64 secrets: pypi_token: ${{ secrets.pypi_token }} anaconda_token: ${{ secrets.anaconda_token }} astropy-astroscrappy-d06bc46/.gitignore 0000664 0000000 0000000 00000001341 15101150060 0020331 0 ustar 00root root 0000000 0000000 # Compiled files *.py[cod] *.a *.o *.so a.out __pycache__ .idea # Ignore .c files by default to avoid including generated code. If you want to # add a non-generated .c extension, use `git add -f filename.c`. *.c # Other generated files */version.py */cython_version.py htmlcov .coverage MANIFEST .ipynb_checkpoints # Sphinx docs/api docs/_build # Eclipse editor project files .project .pydevproject .settings # Pycharm editor project files .idea # Floobits project files .floo .flooignore # Packages/installer info *.egg *.egg-info dist build eggs .eggs parts bin var sdist develop-eggs .installed.cfg distribute-*.tar.gz # Other .cache .tox .*.sw[op] *~ .project .pydevproject .settings pip-wheel-metadata/ # Mac OSX .DS_Store astropy-astroscrappy-d06bc46/.readthedocs.yml 0000664 0000000 0000000 00000000252 15101150060 0021427 0 ustar 00root root 0000000 0000000 version: 2 build: image: latest python: version: 3.7 install: - method: pip path: . extra_requirements: - docs - all formats: [] astropy-astroscrappy-d06bc46/CHANGES.rst 0000664 0000000 0000000 00000003101 15101150060 0020137 0 ustar 00root root 0000000 0000000 1.3.0 (2025-10-31) ------------------ - The minimum supported version of Python is now 3.10. - Avoid conflicts with c23's new keywords. 1.2.0 (2024-05-02) ------------------ - Updated package infrastructure. - Fixed compatibility with Numpy 2.0 and recent versions of SciPy. - The minimum supported version of Python is now 3.9. - Change to normalization for convolution fine structure method to instead use a matched filter. 1.1.0 (2021-11-19) ------------------ - Added the option to add a variance array - Added the ability to subtract a background array rather than a single value. - To accommodate these changes, we now return the cleaned array in the same units as the user provides, ADU rather than electrons and with the background included. 1.0.5 (2016-08-16) ------------------ - Updated to newest version of astropy package template. - Fixed median cleaning. There was a subtle bug that the crmask was defined as a unit8 array. This was then used to clean the image, but this acted as indexes 0 and 1 rather than a boolean array that was intended 1.0.4 (2016-02-29) ------------------ - Fixed setup_requires so that it doesn't install astropy when using egg_info. - Pinned coverage version to 3.7.1. - Removed dependence on endianness in tests - Fixed build issues on windows 1.0.3 (2015-09-29) ------------------ - Updated URL in setup.cfg. 1.0.2 (2015-09-29) ------------------ - Added .h files to MANIFEST.in 1.0.1 (2015-09-29) ------------------ - Fixed bug in MANIFEST.in that was excluding *.pyx files. 1.0 (2015-09-29) ---------------- - Initial release. astropy-astroscrappy-d06bc46/MANIFEST.in 0000664 0000000 0000000 00000000665 15101150060 0020107 0 ustar 00root root 0000000 0000000 include README.rst include CHANGES.rst include setup.cfg include LICENSE.rst include pyproject.toml include astroscrappy/tests/coveragerc recursive-exclude . astroscrappy.c recursive-exclude astroscrappy/utils image_utils.c median_utils.c recursive-include astroscrappy *.pyx *.pxd recursive-include docs * recursive-include licenses * recursive-include scripts * prune build prune docs/_build prune docs/api global-exclude *.pyc *.o astropy-astroscrappy-d06bc46/README.rst 0000664 0000000 0000000 00000005633 15101150060 0020040 0 ustar 00root root 0000000 0000000 Astro-SCRAPPY: The Speedy Cosmic Ray Annihilation Package in Python =================================================================== .. image:: https://readthedocs.org/projects/astroscrappy/badge/?version=latest :alt: Documentation Status :target: https://astroscrappy.readthedocs.io/en/latest/?badge=latest .. image:: https://github.com/astropy/astroscrappy/workflows/Run%20unit%20tests/badge.svg :target: https://github.com/astropy/astroscrappy/actions :alt: CI Status .. image:: https://codecov.io/gh/astropy/astroscrappy/branch/main/graph/badge.svg :target: https://codecov.io/gh/astropy/astroscrappy :alt: AstroScrappy's Coverage Status .. image:: https://zenodo.org/badge/36837126.svg :target: https://zenodo.org/badge/latestdoi/36837126 An optimized cosmic ray detector. :Author: Curtis McCully Astro-SCRAPPY is designed to detect cosmic rays in images (numpy arrays), based on Pieter van Dokkum's L.A.Cosmic algorithm. Much of this was originally adapted from cosmics.py written by Malte Tewes. I have ported all of the slow functions to Cython/C, and optimized where I can. This is designed to be as fast as possible so some of the readability has been sacrificed, specifically in the C code. If you use this code, please cite the Zendo DOI: https://zenodo.org/record/1482019 Please cite the original paper which can be found at: http://www.astro.yale.edu/dokkum/lacosmic/ van Dokkum 2001, PASP, 113, 789, 1420 (article : http://adsabs.harvard.edu/abs/2001PASP..113.1420V) This code requires Cython, preferably version >= 0.21. Parallelization is achieved using OpenMP. This code should compile (although the Cython files may have issues) using a compiler that does not support OMP, e.g. clang. Notes ----- There are some differences from original LA Cosmic: - Automatic recognition of saturated stars. This avoids treating such stars as large cosmic rays. - I have tried to optimize all of the code as much as possible while maintaining the integrity of the algorithm. One of the key speedups is to use a separable median filter instead of the true median filter. While these are not identical, they produce comparable results and the separable version is much faster. - This implementation is much faster than the Python by as much as a factor of ~17 depending on the given parameters, even without running multiple threads. With multiple threads, this can be increased easily by another factor of 2. This implementation is much faster than the original IRAF version, improvment by a factor of ~90. The arrays always must be C-contiguous, thus all loops are y outer, x inner. This follows the astropy.io.fits (pyfits) convention. scipy is required for certain tests to pass, but the code itself does not depend on scipy. License ------- This project is Copyright (c) Astropy Developers and licensed under the terms of the BSD 3-Clause license. See the licenses folder for more information. astropy-astroscrappy-d06bc46/astroscrappy/ 0000775 0000000 0000000 00000000000 15101150060 0021074 5 ustar 00root root 0000000 0000000 astropy-astroscrappy-d06bc46/astroscrappy/__init__.py 0000664 0000000 0000000 00000004447 15101150060 0023216 0 ustar 00root root 0000000 0000000 # Licensed under a 3-clause BSD style license - see LICENSE.rst """ Astro-SCRAPPY: The Speedy Cosmic Ray Annihilation Package in Python =================================================================== An optimized cosmic ray detector :Author: Curtis McCully Astro-SCRAPPY is designed to detect cosmic rays in images (numpy arrays), originally based on Pieter van Dokkum's L.A.Cosmic algorithm. Much of this was originally adapted from cosmics.py written by Malte Tewes. I have ported all of the slow functions to Cython/C, and optimized where I can. This is designed to be as fast as possible so some of the readability has been sacrificed, specifically in the C code. L.A.Cosmic = LAplacian Cosmic ray detection If you use this code, please cite the Zendo DOI: https://zenodo.org/record/1482019 Please cite the original paper which can be found at: http://www.astro.yale.edu/dokkum/lacosmic/ van Dokkum 2001, PASP, 113, 789, 1420 (article : http://adsabs.harvard.edu/abs/2001PASP..113.1420V) This code requires Cython, preferably version >= 0.21. Parallelization is achieved using OpenMP. This code should compile (although the Cython files may have issues) using a compiler that does not support OMP, e.g. clang. Notes ----- There are some differences from original LACosmic: - Automatic recognition of saturated stars. This avoids treating such stars as large cosmic rays. - I have tried to optimize all of the code as much as possible while maintaining the integrity of the algorithm. One of the key speedups is to use a separable median filter instead of the true median filter. While these are not identical, they produce comparable results and the separable version is much faster. - This implementation is much faster than the Python by as much as a factor of 28 depending on the given parameters. This implementation is much faster than the original IRAF version, by a factor of ~90. Note that arrays always must be C-contiguous, thus all loops are y outer, x inner. This follows the Pyfits convention. scipy is required for certain tests to pass, but the code itself does not depend on scipy. """ from .astroscrappy import * # noqa from .utils import * # noqa from .version import version as __version__ # noqa __all__ = ['detect_cosmics'] # noqa astropy-astroscrappy-d06bc46/astroscrappy/astroscrappy.pyx 0000664 0000000 0000000 00000077141 15101150060 0024402 0 ustar 00root root 0000000 0000000 # Licensed under a 3-clause BSD style license - see LICENSE.rst # cython: boundscheck=False, nonecheck=False, wraparound=False, language_level=3, cdivision=True """ Name : astroscrappy: The Speedy Cosmic Ray Annihilation Package in Python Author : Curtis McCully Date : October 2014 """ import numpy as np cimport numpy as np np.import_array() cimport cython from cython.parallel cimport parallel, prange from .utils import * from .utils.median_utils cimport cymedian from libc.stdint cimport uint8_t ctypedef uint8_t bool from libc.stdlib cimport malloc, free def detect_cosmics(indat, inmask=None, inbkg=None, invar=None, float sigclip=4.5, float sigfrac=0.3, float objlim=5.0, float gain=1.0, float readnoise=6.5, float satlevel=65536.0, int niter=4, sepmed=True, cleantype='meanmask', fsmode='median', psfmodel='gauss', float psffwhm=2.5, int psfsize=7, psfk=None, float psfbeta=4.765, verbose=False): """detect_cosmics(indat, inmask=None, inbkg=None, invar=None, sigclip=4.5, sigfrac=0.3, objlim=5.0, gain=1.0, readnoise=6.5, satlevel=65536.0, niter=4, sepmed=True, cleantype='meanmask', fsmode='median', psfmodel='gauss', psffwhm=2.5, psfsize=7, psfk=None, psfbeta=4.765, verbose=False)\n Detect cosmic rays in a numpy array. If you use this code, please cite the Zendo DOI: https://zenodo.org/record/1482019 Please cite the original paper which can be found at: http://www.astro.yale.edu/dokkum/lacosmic/ van Dokkum 2001, PASP, 113, 789, 1420 (article : http://adsabs.harvard.edu/abs/2001PASP..113.1420V) Parameters ---------- indat : float numpy array Input data array that will be used for cosmic ray detection. This should include the sky background (or a mean background level, added back in after sky subtraction), so that noise can be estimated correctly from the data values. This should be in units of "counts". inmask : boolean numpy array, optional Input bad pixel mask. Values of True will be ignored in the cosmic ray detection/cleaning process. Default: None. inbkg : float numpy array, optional A pre-determined background image, to be subtracted from ``indat`` before running the main detection algorithm. This is used primarily with spectroscopic data, to remove sky lines and the cross-section of an object continuum during iteration, "protecting" them from spurious rejection (see the above paper). This background is not removed from the final, cleaned output (`cleanarr`). This should be in units of "counts", the same units of indat. This inbkg should be free from cosmic rays. When estimating the cosmic-ray free noise of the image, we will treat ``inbkg`` as a constant Poisson contribution to the variance. invar : float numpy array, optional A pre-determined estimate of the data variance (ie. noise squared) in each pixel, generated by previous processing of ``indat``. If provided, this is used in place of an internal noise model based on ``indat``, ``gain`` and ``readnoise``. This still gets median filtered and cleaned internally, to estimate what the noise in each pixel *would* be in the absence of cosmic rays. This should be in units of "counts" squared. sigclip : float, optional Laplacian-to-noise limit for cosmic ray detection. Lower values will flag more pixels as cosmic rays. Default: 4.5. sigfrac : float, optional Fractional detection limit for neighboring pixels. For cosmic ray neighbor pixels, a lapacian-to-noise detection limit of sigfrac * sigclip will be used. Default: 0.3. objlim : float, optional Minimum contrast between Laplacian image and the fine structure image. Increase this value if cores of bright stars are flagged as cosmic rays. Default: 5.0. gain : float, optional Gain of the image (electrons / ADU). We always need to work in electrons for cosmic ray detection. Default: 1.0 readnoise : float, optional Read noise of the image (electrons). Used to generate the noise model of the image. Default: 6.5. satlevel : float, optional Saturation of level of the image (electrons). This value is used to detect saturated stars and pixels at or above this level are added to the mask. Default: 65536.0. niter : int, optional Number of iterations of the LA Cosmic algorithm to perform. Default: 4. sepmed : boolean, optional Use the separable median filter instead of the full median filter. The separable median is not identical to the full median filter, but they are approximately the same and the separable median filter is significantly faster and still detects cosmic rays well. Default: True cleantype : {'median', 'medmask', 'meanmask', 'idw'}, optional Set which clean algorithm is used:\n 'median': An umasked 5x5 median filter\n 'medmask': A masked 5x5 median filter\n 'meanmask': A masked 5x5 mean filter\n 'idw': A masked 5x5 inverse distance weighted interpolation\n Default: "meanmask". fsmode : {'median', 'convolve'}, optional Method to build the fine structure image:\n 'median': Use the median filter in the standard LA Cosmic algorithm 'convolve': Convolve the image with the psf kernel to calculate the fine structure image using a matched filter technique. Default: 'median'. psfmodel : {'gauss', 'gaussx', 'gaussy', 'moffat'}, optional Model to use to generate the psf kernel if fsmode == 'convolve' and psfk is None. The current choices are Gaussian and Moffat profiles. 'gauss' and 'moffat' produce circular PSF kernels. The 'gaussx' and 'gaussy' produce Gaussian kernels in the x and y directions respectively. Default: "gauss". psffwhm : float, optional Full Width Half Maximum of the PSF to use to generate the kernel. Default: 2.5. psfsize : int, optional Size of the kernel to calculate. Returned kernel will have size psfsize x psfsize. psfsize should be odd. Default: 7. psfk : float numpy array, optional PSF kernel array to use for the fine structure image if fsmode == 'convolve'. If None and fsmode == 'convolve', we calculate the psf kernel using 'psfmodel'. Default: None. psfbeta : float, optional Moffat beta parameter. Only used if fsmode=='convolve' and psfmodel=='moffat'. Default: 4.765. verbose : boolean, optional Print to the screen or not. Default: False. Returns ------- crmask : boolean numpy array The cosmic ray mask (boolean) array with values of True where there are cosmic ray detections. cleanarr : float numpy array The cleaned data array. Notes ----- To reproduce the most similar behavior to the original LA Cosmic (written in IRAF), set inmask = None, satlevel = np.inf, sepmed=False, cleantype='medmask', and fsmode='median'. The original IRAF version distinguishes between spectroscopic and imaging data. This version does not. For best results on spectra, we recommend that you include an estimate of the background. One can generally obtain this by fitting columns with a smooth function. To efficiently identify cosmic rays, LA Cosmic and therefore astroscrappy estimates the cosmic ray free noise by smoothing the variance using a median filter. To minimize false positives on bright sky lines, if ``inbkg`` is provided, we do not smooth the variance contribution from the provided background. We only smooth the variance that is in addition to the Poisson contribution from the background so that we do not underestimate the noise (and therefore run the risk of flagging false positives) near narrow, bright sky lines. """ # Grab the sizes of the input array cdef int nx = indat.shape[1] cdef int ny = indat.shape[0] # Tell the compiler about the loop indices so it can optimize them. cdef int i, j = 0 # Make a copy of the data as the cleanarr that we work on # This guarantees that that the data will be contiguous and makes sure we # don't edit the input data. cleanarr = np.empty((ny, nx), dtype=np.float32, order='C') # Set the initial values to those of the data array # Multiply by the gain; the statistics only work properly with electrons. cleanarr[:, :] = indat[:, :] * gain if inbkg is not None: bkg = np.empty((ny, nx), dtype=np.float32, order='C') bkg[:, :] = inbkg[:, :] * gain # Setup the mask if inmask is None: # By default don't mask anything mask = np.zeros((ny, nx), dtype=np.uint8, order='C') else: # Make a copy of the input mask mask = np.empty((ny, nx), dtype=np.uint8, order='C') mask[:, :] = inmask[:, :] # Copy any noise estimates so we can clean them like the data, otherwise # use the main data array instead. if invar is not None and inbkg is not None: clean_var = invar * (gain * gain) - bkg elif invar is not None and inbkg is None: clean_var = invar * (gain * gain) elif invar is None and inbkg is not None: clean_var = cleanarr - bkg + readnoise * readnoise else: clean_var = cleanarr + readnoise * readnoise # Find the saturated stars and add them to the mask update_mask(np.asarray(cleanarr), np.asarray(mask), satlevel, sepmed) # Subtract the input sky model, if applicable. if inbkg is not None: cleanarr -= bkg # Find the unmasked pixels to calculate the sky. gooddata = np.zeros(int(nx * ny - np.asarray(mask).sum()), dtype=np.float32, order='c') igoodpix = 0 gooddata[:] = cleanarr[np.logical_not(mask)] # Get the default background level for large cosmic rays. background_level = median(gooddata, len(gooddata)) goodvar = np.empty_like(gooddata, order='c') goodvar[:] = clean_var[np.logical_not(mask)] background_var_level = median(goodvar, len(goodvar)) del goodvar del gooddata # Set up the psf kernel if necessary. if psfk is None and fsmode == 'convolve': # calculate the psf kernel psfk if psfmodel == 'gauss': psfk = gausskernel(psffwhm, psfsize) elif psfmodel == 'gaussx': psfk = gaussxkernel(psffwhm, psfsize) elif psfmodel == 'gaussy': psfk = gaussykernel(psffwhm, psfsize) elif psfmodel == 'moffat': psfk = moffatkernel(psffwhm, psfbeta, psfsize) else: raise ValueError('Please choose a supported PSF model.') # Reverse the psf kernel as that is what we use in the convolution throughout psfk[:, :] = psfk[::-1, ::-1] # Define a cosmic ray mask # This is what will be returned at the end crmask = np.zeros((ny, nx), dtype=np.uint8, order='C') # Calculate the detection limit for neighbor pixels cdef float sigcliplow = sigfrac * sigclip # Run lacosmic for up to maxiter iterations # We stop if no more cosmic ray pixels are found (quite rare) if verbose: print("Starting {} L.A.Cosmic iterations".format(niter)) for i in range(niter): if verbose: print("Iteration {}:".format(i + 1)) # Detect the cosmic rays # We subsample, convolve, clip negative values, # and rebin to original size subsam = subsample(cleanarr) conved = laplaceconvolve(subsam) del subsam conved[conved < 0] = 0.0 # This is called L+ in the original LA Cosmic/cosmics.py s = rebin(conved) del conved # Build a noise map, to compare the laplacian to, based on the input # data or (if supplied) input variance. If variance is used, it still # gets filtered, since we can best identify cosmic rays using what the # noise in a pixel *should* be, rather than what it actually is after # a cosmic ray hit. if sepmed: m5 = sepmedfilt7(clean_var) else: m5 = medfilt5(clean_var) # Here we add back in the background to get the full variance. m5 here is effectively the CR free variance if inbkg is not None: m5 += bkg # Clip noise so that we can take a square root m5[m5 < 0.00001] = 0.00001 noise = np.sqrt(m5) del m5 # Laplacian signal to noise ratio : s /= 2.0 * noise # the 2.0 is from the 2x2 subsampling and is denoted f_s in the original paper # This s is called sigmap in the original lacosmic.cl if sepmed: sp = sepmedfilt7(s) else: sp = medfilt5(s) # Remove the large structures (s prime) : sp = s - sp del s # Find the candidate cosmic rays goodpix = np.logical_not(mask) cosmics = np.logical_and(sp > sigclip, goodpix) # Build the fine structure image : # TODO: we can gain a reasonable performance boost if we only calculate the fine structure stuff for cosmic # pixels instead of the whole image if fsmode == 'convolve': # Use a match filter, the (reversed) psf convolved with the image / variance f = convolve(cleanarr / noise / noise, psfk) # Normalize by the sum of the weights to get the flux of the source assuming it was actually a psf. # This will pull the value of pixels that do not look like psfs (e.g. CRs) down. f = f / convolve(1.0 / noise / noise, psfk) elif fsmode == 'median': if sepmed: f = sepmedfilt5(cleanarr) else: f = medfilt3(cleanarr) else: raise ValueError('Please choose a valid fine structure mode.') if sepmed: m7 = sepmedfilt9(f) else: m7 = medfilt7(f) # Note that original paper compares L+ / Fine Structure Image < threshold. # The original code and therefore we compare S' / Fine Structure Image < threshold. # As such, we scale the fine structure image by the noise here so it is in the same units as S'. f = (f - m7) / noise # Clip f as we will divide by f. Similar to the IRAF version. f[f < 0.01] = 0.01 del m7 del noise # S' / F is still not exactly what is in the paper as we have subtracted the "sampling flux" from S # via the median filter. This should be an optimization because we have removed the smooth component # and are therefore comparing the candidate "CR flux" only. cosmics = np.logical_and(cosmics, (sp / f) > objlim) del f # What follows is a special treatment for neighbors, with more relaxed # constraints. # We grow these cosmics a first time to determine the immediate # neighborhood. cosmics = dilate3(cosmics) cosmics = np.logical_and(cosmics, goodpix) # From this grown set, we keep those that have sp > sigmaclip # Note that the only new pixels that should be added here are ones that were rejected by the # objlim test. As they are neighbors to true CRs, we take that as a prior that CR probability # of the neighboring pixel is enhanced. cosmics = np.logical_and(sp > sigclip, cosmics) # Now we repeat this procedure, but lower the detection limit to siglow cosmics = dilate3(cosmics) cosmics = np.logical_and(cosmics, goodpix) del goodpix cosmics = np.logical_and(sp > sigcliplow, cosmics) del sp # Our CR counter numcr = cosmics.sum() # Update the crmask with the cosmics we have found crmask[:, :] = np.logical_or(crmask, cosmics)[:, :] del cosmics if verbose: print("{} cosmic pixels this iteration".format(numcr)) # If we didn't find anything, we're done. if numcr == 0: break # otherwise clean the image and iterate if cleantype == 'median': # Unmasked median filter clean_median(cleanarr, crmask, nx, ny) clean_median(clean_var, crmask, nx, ny) # Masked mean filter elif cleantype == 'meanmask': clean_meanmask(cleanarr, crmask, mask, nx, ny, background_level) clean_meanmask(clean_var, crmask, mask, nx, ny, background_var_level) # Masked median filter elif cleantype == 'medmask': clean_medmask(cleanarr, crmask, mask, nx, ny, background_level) clean_medmask(clean_var, crmask, mask, nx, ny, background_var_level) # Inverse distance weighted interpolation elif cleantype == 'idw': clean_idwinterp(cleanarr, crmask, mask, nx, ny, background_level) clean_idwinterp(clean_var, crmask, mask, nx, ny, background_var_level) else: raise ValueError("""cleantype must be one of the following values: [median, meanmask, medmask, idw]""") # Restore the sky background if needed. if inbkg is not None: cleanarr += bkg cleanarr /= gain return crmask.astype(np.bool_), cleanarr def update_mask(np.ndarray[np.float32_t, ndim=2, mode='c', cast=True] data, np.ndarray[np.uint8_t, ndim=2, mode='c', cast=True] mask, float satlevel, bool sepmed): """update_mask(data, mask, satlevel, sepmed)\n Find staturated stars and puts them in the mask. This can then be used to avoid these regions in cosmic detection and cleaning procedures. The median filter is used to find large symmetric regions of saturated pixels (i.e. saturated stars). Parameters ---------- data : float numpy array The data array in which we look for saturated stars. mask : boolean numpy array Bad pixel mask. This mask will be dilated using dilate3 and then combined with the saturated star mask. satlevel : float Saturation level of the image. This value can be lowered if the cores of bright (saturated) stars are not being masked. sepmed : boolean Use the separable median or not. The separable median is not identical to the full median filter, but they are approximately the same and the separable median filter is significantly faster. """ # Find all of the saturated pixels satpixels = data >= satlevel # Use the median filter to estimate the large scale structure if sepmed: m5 = sepmedfilt7(data) else: m5 = medfilt5(data) # Use the median filtered image to find the cores of saturated stars # The 10 here is arbitray. Malte Tewes uses 2.0 in cosmics.py, but I # wanted to get more of the cores of saturated stars. satpixels = np.logical_and(satpixels, m5 > (satlevel / 10.0)) # Grow the input mask by one pixel to make sure we cover bad pixels grow_mask = dilate3(mask) # Dilate the saturated star mask to remove edge effects in the mask dilsatpixels = dilate5(satpixels, 2) del satpixels # Combine the saturated pixels with the given input mask # Note, we work on the mask pixels in place mask[:, :] = np.logical_or(dilsatpixels, grow_mask)[:, :] del grow_mask cdef void clean_meanmask(float[:, ::1] cleanarr, bool[:, ::1] crmask, bool[:, ::1] mask, int nx, int ny, float background_level): """clean_meanmask(cleanarr, crmask, mask, nx, ny, background_level)\n Clean the bad pixels in cleanarr using a 5x5 masked mean filter. Parameters ---------- cleanarr : float numpy array The array to be cleaned. crmask : boolean numpy array Cosmic ray mask. Pixels with a value of True in this mask will be cleaned. mask : boolean numpy array Bad pixel mask. Values of True indicate bad pixels. nx : int Size of cleanarr in the x-direction. Note cleanarr has dimensions ny x nx. ny : int Size of cleanarr in the y-direction. Note cleanarr has dimensions ny x nx. background_level : float Average value of the background. This value will be used if there are no good pixels in a 5x5 region. """ # Go through all of the pixels, ignore the borders cdef int i, j, k, l, numpix cdef float s cdef bool badpix with nogil, parallel(): # For each pixel for j in prange(2, ny - 2): for i in range(2, nx - 2): # if the pixel is in the crmask if crmask[j, i]: numpix = 0 s = 0.0 # sum the 25 pixels around the pixel # ignoring any pixels that are masked for l in range(-2, 3): for k in range(-2, 3): badpix = crmask[j + l, i + k] badpix = badpix or mask[j + l, i + k] if not badpix: s = s + cleanarr[j + l, i + k] numpix = numpix + 1 # if the pixels count is 0 # then put in the background of the image if numpix == 0: s = background_level else: # else take the mean s = s / float(numpix) cleanarr[j, i] = s cdef void clean_median(float[:, ::1] cleanarr, bool[:, ::1] crmask, int nx, int ny): """clean_medmask(cleanarr, crmask, mask, nx, ny, background_level)\n Clean the bad pixels in cleanarr using a 5x5 masked median filter. Parameters ---------- cleanarr : float numpy array The array to be cleaned. crmask : boolean numpy array Cosmic ray mask. Pixels with a value of True in this mask will be cleaned. nx : int size of cleanarr in the x-direction. Note cleanarr has dimensions ny x nx. ny : int size of cleanarr in the y-direction. Note cleanarr has dimensions ny x nx. """ # Go through all of the pixels, ignore the borders cdef int k, l, i, j, counter cdef float * medarr # For each pixel with nogil, parallel(): medarr = < float * > malloc(25 * sizeof(float)) for j in prange(2, ny - 2): for i in range(2, nx - 2): # if the pixel is in the crmask if crmask[j, i]: # median the 25 pixels around the pixel counter = 0 for l in range(-2, 3): for k in range(-2, 3): medarr[counter] = cleanarr[j + l, i + k] counter =+ 1 cleanarr[j, i] = cymedian(medarr, 25) free(medarr) cdef void clean_medmask(float[:, ::1] cleanarr, bool[:, ::1] crmask, bool[:, ::1] mask, int nx, int ny, float background_level): """clean_medmask(cleanarr, crmask, mask, nx, ny, background_level)\n Clean the bad pixels in cleanarr using a 5x5 masked median filter. Parameters ---------- cleanarr : float numpy array The array to be cleaned. crmask : boolean numpy array Cosmic ray mask. Pixels with a value of True in this mask will be cleaned. mask : boolean numpy array Bad pixel mask. Values of True indicate bad pixels. nx : int size of cleanarr in the x-direction. Note cleanarr has dimensions ny x nx. ny : int size of cleanarr in the y-direction. Note cleanarr has dimensions ny x nx. background_level : float Average value of the background. This value will be used if there are no good pixels in a 5x5 region. """ # Go through all of the pixels, ignore the borders cdef int k, l, i, j, numpix cdef float * medarr cdef bool badpixel # For each pixel with nogil, parallel(): medarr = < float * > malloc(25 * sizeof(float)) for j in prange(2, ny - 2): for i in range(2, nx - 2): # if the pixel is in the crmask if crmask[j, i]: numpix = 0 # median the 25 pixels around the pixel ignoring # any pixels that are masked for l in range(-2, 3): for k in range(-2, 3): badpixel = crmask[j + l, i + k] badpixel = badpixel or mask[j + l, i + k] if not badpixel: medarr[numpix] = cleanarr[j + l, i + k] numpix = numpix + 1 # if the pixels count is 0 then put in the background # of the image if numpix == 0: cleanarr[j, i] = background_level else: # else take the median cleanarr[j, i] = cymedian(medarr, numpix) free(medarr) cdef void clean_idwinterp(float[:, ::1] cleanarr, bool[:, ::1] crmask, bool[:, ::1] mask, int nx, int ny, float background_level): """clean_idwinterp(cleanarr, crmask, mask, nx, ny, background_level)\n Clean the bad pixels in cleanarr using a 5x5 using inverse distance weighted interpolation. Parameters ---------- cleanarr : float numpy array The array to be cleaned. crmask : boolean numpy array Cosmic ray mask. Pixels with a value of True in this mask will be cleaned. mask : boolean numpy array Bad pixel mask. Values of True indicate bad pixels. nx : int Size of cleanarr in the x-direction (int). Note cleanarr has dimensions ny x nx. ny : int Size of cleanarr in the y-direction (int). Note cleanarr has dimensions ny x nx. background_level : float Average value of the background. This value will be used if there are no good pixels in a 5x5 region. """ # Go through all the pixels, ignore the borders cdef int i, j, k, l cdef float f11, f12, f21, f22 = background_level cdef int x1, x2, y1, y2 weightsarr = np.array([[0.35355339, 0.4472136, 0.5, 0.4472136, 0.35355339], [0.4472136, 0.70710678, 1., 0.70710678, 0.4472136], [0.5, 1., 0., 1., 0.5], [0.4472136, 0.70710678, 1., 0.70710678, 0.4472136], [0.35355339, 0.4472136, 0.5, 0.4472136, 0.35355339]], dtype=np.float32) cdef float[:, ::1] weights = weightsarr cdef float wsum cdef float val cdef int x, y # For each pixel with nogil, parallel(): for j in prange(2, ny - 2): for i in range(2, nx - 2): # if the pixel is in the crmask if crmask[j, i]: wsum = 0.0 val = 0.0 for l in range(-2, 3): y = j + l for k in range(-2, 3): x = i + k if not (crmask[y, x] or mask[y, x]): val = val + weights[l+2, k+2] * cleanarr[y, x] wsum = wsum + weights[l+2, k+2] if wsum < 1e-6: cleanarr[j, i] = background_level else: cleanarr[j, i] = val / wsum def gausskernel(float psffwhm, int kernsize): """gausskernel(psffwhm, kernsize)\n Calculate a circular Gaussian psf kernel. Parameters ---------- psffwhm : float Full Width Half Maximum of the PSF to use to generate the kernel. kernsize : int Size of the kernel to calculate. kernsize should be odd. Returned kernel will have size kernsize x kernsize. Returns ------- kernel : float numpy array Gaussian PSF kernel with size kernsize x kernsize. """ kernel = np.zeros((kernsize, kernsize), dtype=np.float32) # Make a grid of x and y values x = np.tile(np.arange(kernsize) - kernsize / 2, (kernsize, 1)) y = x.transpose().copy() # Calculate the offset, r r2 = x * x + y * y # Calculate the kernel sigma2 = psffwhm * psffwhm / 2.35482 / 2.35482 kernel[:, :] = np.exp(-0.5 * r2 / sigma2)[:, :] # Normalize the kernel kernel /= kernel.sum() return kernel def gaussxkernel(float psffwhm, int kernsize): """gaussxkernel(psffwhm, kernsize)\n Calculate a Gaussian kernel in the x-direction. This can be used for spectroscopic data. Parameters ---------- psffwhm : float Full Width Half Maximum of the PSF to use to generate the kernel. kernsize : int Size of the kernel to calculate. kernsize should be odd. Returned kernel will have size kernsize x kernsize. Returns ------- kernel : float numpy array Gaussian(x) kernel with size kernsize x kernsize. """ kernel = np.zeros((kernsize, kernsize), dtype=np.float32) # Make a grid of x and y values x = np.tile(np.arange(kernsize) - kernsize / 2, (kernsize, 1)) # Calculate the kernel sigma2 = psffwhm * psffwhm / 2.35482 / 2.35482 kernel[:, :] = np.exp(-0.5 * x * x / sigma2)[:, :] # Normalize the kernel kernel /= kernel.sum() return kernel def gaussykernel(float psffwhm, int kernsize): """gaussykernel(psffwhm, kernsize)\n Calculate a Gaussian kernel in the y-direction. This can be used for spectroscopic data. Parameters ---------- psffwhm : float Full Width Half Maximum of the PSF to use to generate the kernel. kernsize : int Size of the kernel to calculate. kernsize should be odd. Returned kernel will have size kernsize x kernsize. Returns ------- kernel : float numpy array Gaussian(y) kernel with size kernsize x kernsize. """ kernel = np.zeros((kernsize, kernsize), dtype=np.float32) # Make a grid of x and y values x = np.tile(np.arange(kernsize) - kernsize / 2, (kernsize, 1)) y = x.transpose().copy() # Calculate the kernel sigma2 = psffwhm * psffwhm / 2.35482 / 2.35482 kernel[:, :] = np.exp(-0.5 * y * y / sigma2)[:, :] # Normalize the kernel kernel /= kernel.sum() return kernel cdef moffatkernel(float psffwhm, float beta, int kernsize): """moffatkernel(psffwhm, beta, kernsize)\n Calculate a Moffat psf kernel. Parameters ---------- psffwhm : float Full Width Half Maximum of the PSF to use to generate the kernel. beta : float Moffat beta parameter kernsize : int Size of the kernel to calculate. Returned kernel will have size kernsize x kernsize. kernsize should be odd. Returns ------- kernel : float numpy array Moffat kernel with size kernsize x kernsize. """ kernel = np.zeros((kernsize, kernsize), dtype=np.float32) # Make a grid of x and y values x = np.tile(np.arange(kernsize) - kernsize / 2, (kernsize, 1)) y = x.transpose().copy() # Calculate the offset r r = np.sqrt(x * x + y * y) # Calculate the kernel hwhm = psffwhm / 2.0 alpha = hwhm / np.sqrt(np.power(2.0, (1.0 / beta)) - 1.0) kernel[:, :] = (np.power(1.0 + (r * r / alpha / alpha), -1.0 * beta))[:, :] # Normalize the kernel. kernel /= kernel.sum() return kernel astropy-astroscrappy-d06bc46/astroscrappy/conftest.py 0000664 0000000 0000000 00000003645 15101150060 0023303 0 ustar 00root root 0000000 0000000 # This file is used to configure the behavior of pytest when using the Astropy # test infrastructure. It needs to live inside the package in order for it to # get picked up when running the tests inside an interpreter using # packagename.test import os from astropy.version import version as astropy_version # For Astropy 3.0 and later, we can use the standalone pytest plugin if astropy_version < '3.0': from astropy.tests.pytest_plugins import * # noqa del pytest_report_header ASTROPY_HEADER = True else: try: from pytest_astropy_header.display import PYTEST_HEADER_MODULES, TESTED_VERSIONS ASTROPY_HEADER = True except ImportError: ASTROPY_HEADER = False def pytest_configure(config): if ASTROPY_HEADER: config.option.astropy_header = True # Customize the following lines to add/remove entries from the list of # packages for which version numbers are displayed when running the tests. PYTEST_HEADER_MODULES.pop('Pandas', None) PYTEST_HEADER_MODULES['scikit-image'] = 'skimage' from . import __version__ packagename = os.path.basename(os.path.dirname(__file__)) TESTED_VERSIONS[packagename] = __version__ # Uncomment the last two lines in this block to treat all DeprecationWarnings as # exceptions. For Astropy v2.0 or later, there are 2 additional keywords, # as follow (although default should work for most cases). # To ignore some packages that produce deprecation warnings on import # (in addition to 'compiler', 'scipy', 'pygments', 'ipykernel', and # 'setuptools'), add: # modules_to_ignore_on_import=['module_1', 'module_2'] # To ignore some specific deprecation warning messages for Python version # MAJOR.MINOR or later, add: # warnings_to_ignore_by_pyver={(MAJOR, MINOR): ['Message to ignore']} # from astropy.tests.helper import enable_deprecations_as_exceptions # noqa # enable_deprecations_as_exceptions() astropy-astroscrappy-d06bc46/astroscrappy/setup_package.py 0000664 0000000 0000000 00000000653 15101150060 0024265 0 ustar 00root root 0000000 0000000 import os from numpy import get_include from setuptools import Extension ROOT = os.path.relpath(os.path.dirname(__file__)) def get_extensions(): sources = [os.path.join(ROOT, "astroscrappy.pyx")] ext = Extension( name="astroscrappy.astroscrappy", define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")], include_dirs=[get_include()], sources=sources, ) return [ext] astropy-astroscrappy-d06bc46/astroscrappy/tests/ 0000775 0000000 0000000 00000000000 15101150060 0022236 5 ustar 00root root 0000000 0000000 astropy-astroscrappy-d06bc46/astroscrappy/tests/__init__.py 0000664 0000000 0000000 00000000154 15101150060 0024347 0 ustar 00root root 0000000 0000000 # Licensed under a 3-clause BSD style license - see LICENSE.rst """ This module contains package tests. """ astropy-astroscrappy-d06bc46/astroscrappy/tests/data/ 0000775 0000000 0000000 00000000000 15101150060 0023147 5 ustar 00root root 0000000 0000000 astropy-astroscrappy-d06bc46/astroscrappy/tests/data/gmos.fits 0000664 0000000 0000000 00001367300 15101150060 0025015 0 ustar 00root root 0000000 0000000 SIMPLE = T / conforms to FITS standard BITPIX = 8 / array data type NAXIS = 0 / number of array dimensions EXTEND = T COMMENT FITS (Flexible Image Transport System) format is defined in 'AstronomyCOMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H INSTRUME= 'GMOS-S ' / Instrument used to acquire data OBJECT = 'LTT7379 ' / Object Name OBSTYPE = 'OBJECT ' / Observation type OBSCLASS= 'partnerCal' / Observe class GEMPRGID= 'GS-2019B-Q-305' / Gemini programme ID OBSID = 'GS-2019B-Q-305-7' / Observation ID / Data label DATALAB = 'GS-2019B-Q-305-7-004' / DHS data label OBSERVER= 'J. Chavez' / Observer OBSERVAT= 'Gemini-South' / Name of telescope (Gemini-North|Gemini-South) TELESCOP= 'Gemini-South' / Gemini-North PARALLAX= 0. / Parallax of Target RADVEL = 0. / Heliocentric Radial Velocity EPOCH = 2000. / Epoch for Target coordinates EQUINOX = 2000. / Equinox of coordinate system TRKEQUIN= 2000. / Tracking equinox SSA = 'P. Candia' / SSA RA = 279.108125 / Right Ascension DEC = -44.31025 / Declination of Target ELEVATIO= 66.91005 / Current Elevation AZIMUTH = 133.776055555556 / Current Azimuth CRPA = 0.49316948972528 / Current Cass Rotator Position Angle HA = '-01:33:23.08' / Telescope hour angle LT = '21:42:26.9' / Local time at start of observation TRKFRAME= 'FK5 ' / Tracking co-ordinate DECTRACK= 0. / Differential tracking rate Dec TRKEPOCH= 58703.021628 / Differential tracking reference epoch RATRACK = 0. / Differential tracking rate RA FRAME = 'FK5 ' / Target coordinate system PMDEC = -0.1615 / Proper Motion in Declination PMRA = -0.01603 / Proper Motion in RA WAVELENG= 7400. / Effective Target Wavelength RAWIQ = 'Any ' / Raw Image Quality RAWCC = '70-percentile' / Raw Cloud Cover RAWWV = 'UNKNOWN ' / Raw Water Vapour/Transparency RAWBG = 'UNKNOWN ' / Raw Background RAWPIREQ= 'YES ' / PI Requirements Met RAWGEMQA= 'USABLE ' / Gemini Quality Assessment CGUIDMOD= 'Basic ' / Driving mode for carousel UT = '00:42:27.4' / UT at observation start DATE = '2019-08-08' / UT Date of observation (YYYY-MM-DD) M2BAFFLE= 'VISIBLE ' / Position of M2 baffle M2CENBAF= 'CLOSED ' / Position of M2 central hole baffle ST = '17:04:28.7' / Sidereal time at the start of the exposure XOFFSET = 0.15432377504409 / Telescope offset in x in arcsec YOFFSET = 0.9061870598354 / Telescope offset in y in arcsec POFFSET = -0.156000000459329 / Telescope offset in p in arcsec QOFFSET = -0.905900002656847 / Telescope offset in q in arcsec RAOFFSET= -0.706532415359935 / Telescope offset in RA in arcsec DECOFFSE= 0.588049964716129 / Telescope offset in DEC in arcsec RATRGOFF= 0. / Target offset in RA in arcsec DECTRGOF= 0. / Target offset in DEC in arcsec PA = 120. / Sky Position Angle at start of exposure IAA = 359.894 / Instrument Alignment Angle SFRT2 = -0.417 / Science fold rotation angle (degrees) SFTILT = 44.94 / Science fold tilt angle (degrees) SFLINEAR= -3. / Science fold linear position (mm) AOFOLD = 'park-pos.' / AO Pick-Off Mirror Position PWFS1_ST= 'parked ' / PWFS1 probe state (frozen,guiding,parked) PWFS2_ST= 'parked ' / PWFS2 probe state (frozen,guiding,parked) OIWFS_ST= 'guiding ' / OIWFS probe state (frozen,guiding,parked) AOWFS_ST= 'parked ' / AOWFS probe state (frozen,guiding,parked) SCIBAND = 3 / Science Ranking Band REQIQ = 'Any ' / Requested Image Quality REQCC = 'Any ' / Requested Cloud Cover REQBG = 'Any ' / Requested Background REQWV = 'Any ' / Requested Water Vapour NUMREQTW= 0 / Number of Requested Timing Window REQTW entriesOIARA = 279.16629167 / RA of OIWFS guide star OIARV = 0. / OIWFS Heliocentric Radial Velocity OIAWAVEL= 6500. / OIWFS Effective Target Wavelength OIADEC = -44.3175 / Declination of OIWFS guide star OIAEPOCH= 2000. / Epoch for OIWFS guide star coordinates OIAEQUIN= 2000. / Equinox for OIWFS guide star coordinates OIAFRAME= 'FK5 ' / OIWFS Target co-ordinate system OIAOBJEC= 'GSC0791402580' / Object Name for OIWFS, Chop A OIAPMDEC= 0. / OIWFS Proper Motion in Declination OIAPMRA = 0. / OIWFS Proper Motion in RA OIAPARAL= 0. / OIWFS Parallax of Target OIFREQ = 200. / OIWFS sampling frequency (Hz) HUMIDITY= 23. / The Relative Humidity (fraction, 0..101). TAMBIENT= 4.3 / The ambient temp (C). TAMBIEN2= 39.74 / The ambient temp (F). PRESSURE= 544.70328 / The atmospheric pressure (mm Hg). PRESSUR2= 72600. / The atmospheric pressure (Pa). DEWPOINT= -15.3 / The dew point (C). DEWPOIN2= 4.46 / The dew point (F). WINDSPEE= 14.1 / The wind speed (m/s). WINDSPE2= 31.5417 / The wind speed (mph). WINDDIRE= 301. / The wind direction (degrees). INPORT = 3 / Number of ISS port where GMOS was located GMOSCC = 'GMOS-CP (V6-9)' / GMOS components controller s/w TIME-OBS= '00:42:27.4' / Time of observation PREIMAGE= F / MOS pre-imaging CONID = 'ARC-III ' / Detector controller ID DETECTOR= 'GMOS + Hamamatsu_new' / Detector name DEWAR = 'Lab Cryostat' / Dewar name ARRYTMPD= -100.998 / Array temperature D (Celsius) ARRYTMPA= -94.113 / Array temperature A (Celsius) ARRYTMPB= -94.379 / Array temperature B (Celsius) ARRYTMPC= -94.095 / Array temperature C (Celsius) ARRYTSET= -101. / Array temperature Setpoint (Celsius) DETSIZE = '[1:6144,1:4224]' / Detector size NCCDS = 3 / Number of CCD chips NAMPS = 4 / Number of amplifiers SHUTTER = 'OPEN ' / Shutter state during observation AMPINTEG= 11880 / Amplifier integration time OBSEPOCH= 2019.59898560676 / Epoch at start of exposure TIMESYS = 'UTC ' / Time system used DATE-OBS= '2019-08-08' / UT Date of observation (YYYY-MM-DD) GMOSTHT = 'WARNING ' / Shutter health NSUBEXP = 1 / Number of sub exposures UTSTART = '00:42:29.7167' / UT at observation start UTEND = '00:43:59.7167' / UT at observation end EXPTIME = 90. / Exposure time in seconds ELAPSED = 90. / Elapsed observation time in seconds DARKTIME= 98.5500249862671 / Dark current integration in seconds MASKID = 10005374 / Mask/IFU barcode MASKNAME= '1.0arcsec' / Mask name MASKTYP = 1 / Mask/IFU type (0=none/-1=IFU/1=mask) MASKLOC = 0 / Mask/IFU location (-1=unknown/0=FP/1=cassette) FILTER1 = 'GG455_G0329' / Filter 1 name FILTID1 = 20000044 / Filter 1 barcode FILTER2 = 'open2-8 ' / Filter 2 name FILTID2 = 20000041 / Filter 2 barcode GRATING = 'R400+_G5325' / Grating name GRATID = 30000019 / Grating barcode GRWLEN = 740. / Grating wavelength at slit (nm) CENTWAVE= 740. / Central wavelength (nm) GRORDER = 1 / Grating order GRTILT = 55.6015 / Grating tilt angle (degrees) GRSTEP = 5891.3684 / Requested grating motor step position DTAX = 42. / Detector translation X position (microns) DTAY = 127.68 / Detector translation Y position (microns) DTAZ = 1068. / Detector translation Z position (microns) DTAZST = 1068. / Focus at observation start (microns) DTAZEN = 1068. / Focus at observation end (microns) DTAZME = 1650. / Mean focus during observation (microns) DTMODE = 'FOLLOW ' / Detector translation stage mode ADCMODE = ' ' / ADC mode GMOSDC = 'gmosdc-6.4AT1.6' / GMOS detector controller s/w DETTYPE = 'S10892 ' / Detector array type DETID = 'BI5-36-4k-2,BI11-33-4k-1,BI12-34-4k-1' / Chip IDs EXPOSURE= 90. / Requested exposure time in seconds ADCUSED = 1 / ADC used? (0=yes/1=no) DETNROI = 1 / No. regions of interest ADCENPST= 0. / Start entrance prism angle of ADC ADCENPEN= 0. / End entrance prism angle of ADC ADCENPME= 0. / Mean entrance prism angle of ADC ADCEXPST= 0. / Start exit prism angle of ADC ADCEXPEN= 0. / End exit prism angle of ADC ADCEXPME= 0. / Mean exit prism angle of ADC ADCWLEN1= 0. / Lower wavelength for ADC calculation ADCWLEN2= 0. / Upper wavelength for ADC calculation DETRO1X = 1 / ROI 1 X start DETRO1XS= 3072 / ROI 1 X size DETRO1Y = 1625 / ROI 1 Y start DETRO1YS= 512 / ROI 1 Y size AIRMASS = 1.086 / Mean airmass for the observation AMSTART = 1.087 / Airmass at start of exposure AMEND = 1.085 / Airmass at end of exposure PROP_MD = F / Proprietary Metadata RELEASE = '2019-08-08' / End of proprietary period YYY-MM-DD ORIGNAME= 'S20190808S0048.fits' / Original filename prior to processing GEM-TLM = '2020-10-28T11:30:19' / UT last modification with GEMINI VALDATA = '2020-10-28T11:30:18' / UT time stamp for validateData ADDMDF = '2020-10-28T11:30:18' / UT time stamp for addMDF SDZSTRUC= '2020-10-28T11:30:18' / UT time stamp for standardizeStructure NSCIEXT = 12 / Number of science extensions SDZHDRSG= '2020-10-28T11:30:18' / UT time stamp for standardizeObservatoryHeaderSDZHDRSI= '2020-10-28T11:30:18' / UT time stamp for standardizeInstrumentHeadersSDZWCS = '2020-10-28T11:30:18' / UT time stamp for standardizeWCS PREPARE = '2020-10-28T11:30:18' / UT time stamp for PREPARE ADDDQ = '2020-10-28T11:30:18' / UT time stamp for addDQ ADDVAR = '2020-10-28T11:30:19' / UT time stamp for addVAR SUBOVER = '2020-10-28T11:30:19' / UT time stamp for subtractOverscan TRIMMED = 'yes ' / Overscan section trimmed TRIMOVER= '2020-10-28T11:30:19' / UT time stamp for trimOverscan ADUTOELE= '2020-10-28T11:30:19' / UT time stamp for ADUToElectrons MOSAIC = '2020-10-28T11:30:19' / UT time stamp for mosaicDetectors END XTENSION= 'IMAGE ' / Image extension BITPIX = -32 / array data type NAXIS = 2 / number of array dimensions NAXIS1 = 200 NAXIS2 = 150 PCOUNT = 0 / number of parameters GCOUNT = 1 / number of groups EXTNAME = 'SCI ' / extension name END Bà“B¯!&B£—^BTí´BPq2BcŠB‚ÓBzB4B}÷#B†w«BQß¹BN¿‚B<–ÊBQ8ÅBg;ØB…M¿BF2êBZŽÚB4ÏÙB;ÎBTfjB9r½BCÍÍBJ@Bd‘¥B>#BHˆBX:Bd?!B“B²Q2BÉ¡áBÀW»BÈlyB® BSttBr:QBn]ÜBOZBaBx¼©B˜ÊÁBŸþ€BŽâ9BP¶‰B]VBBhSBPF BYÓ9BDœwB0ž6Bv)BPÃÿB>dB2âúBeSqB_ÎòB°ÕCåiC ËÙCñ«CöBûJB…gÉBaaÔB@ÒFBmÝúB†3'B§‰¿B–}ÐB P¶B²n®B˜¨Bu*B=^ B,œ@B@¸PBB?©B>ÐÐBbOUB=äGBT,B¨.¦CH÷CÂkC(9C.NuCeRB¡~¢BŠSáBj‰BF¿”BZe_BzUPB³ÞxBµMÆB«ø[B¬L~B–BBk¹çBo¤ÉB%ñ†B5Ú—B|B†ñCô'C#œ?C/<ëCèBüùÎBª=’BAR)B;}ÛBL»B^LBDçwBiÆÝB–‡éBÛ¾Bß’B˜®ßB™½BŒõêBU´jBJ¦žBQSCBa8|BL‹:B†·ØB„Ç6B}×cBlB…ïØBˆ€“Bh6ÞBBBtãB“%BÕwhBÝbSB´-ËB¿*IB½ÎBÿ†°C
MzB\܉B~®5B›TxC 3‚C&3C"-ÿC¥SBÿdÀB‹ëÅB^̰B[.ºB4KBNmZB8Ý-B7‚Bœº)B¨žbB¡ýÁB££ÞB¥j2BŽ ˜BdxœBU"¨BUšÙBNâ©BWiYB`,œBŒ–ìB‚ÕUB¨5Bƒ™B‡STB…’JBGBT ÷B…âB»Æ8BêEBÓ [B¿ÔBÂ…Böœ3CA&ÓCEþCOçBC7¬&C BÈõBóNB-lVB@ñB)(þB+PêB/X¥BeþBL{GB5óBbVuBP¹ÐBÅ”B[bBJ¢4B(ÝþBD•+BkìLB…ÀíBu+™BrðrB„ºmB‚-BeBV EBAÉBŽCÄBÍÔSBùO‹C n4B÷¨óBÁ”FBǺB¶˜BBÚ4•Bï4ˆBÐI¥CÒ$CƒBã¸'B½sB¾ÐB£ÙBo{ÕBYl»BNÚB>WBn¸BAÏŽBN[BM5ÑBžzMBŒ\#BœúüBY=lBX§¾BqKjBŒ4ÌBŠœˆBŒ™ŠB_Ø BhûEBj±ÂBSظB>rBkfBÜAB@U B*Ê|BCÞlB2€'BYn[B€í³BJ5àBV5B@˜ÊBFšÙBF±àBN²aBS8|B¤UB¹dbB®É¤Bá´B¾â›B›†µB‚U¯Bm¶vBvéCBŒêTB•ÌØB¶)qBŸ BˆÅBf‡Bc!ÐBn9;B_ÚBRžæBFð†BFßBDðB*¶”BbÊPBkú;BDZüB`3BR*ŽB™RCašC5ŒCãQCö=Bö¡>B‚#4Bnø“BSö+B]@BŸ¥B£GQB¥•³B©v|BÃeäB=áBJüB^.‚BF²BBî‘BDuéBw[¯BfHŠBoJNB940B»wœC iyC.ðtC–C@KC´æB{}B\RB@‡.B†¼B_1)B’•ÅBµÛŽB¾}¥B·ÆkBBœ~ÈBZTïBr?ÿBEwšBmÏuBSé¬B¨P½C-âCƒCž´C ?ôC kpB–Ã{BJ‰BC B5ëB1äB2¢vBMã]B¡-ÑB-rB±ŽBÅ(ÚB¬ñYBƒ{oBZŸïB$˜=BUa¡BKÊB)¢ŸBN)B:hB‰šBxÅ9B‡ÒB]ƪBg·ÙBQ¬˜B\t3B’äžBÈBÑ¢BÖ¼\Bàö$BÄiüC /~CEIC<àCbfvCQó,C‚BÖHB8ºB@B3bÄBFÏÕB7«áBOG"BjØBiíB%ØnBFÂ_BWÂHB!ŒoB=¥¯BV\B ÈÔB39kBBwUBm{ÏBÀKB‚5yBŽ#BZË4BcÏÙB\¨ BO^6BÈBψ"BìÏOBýCýˆB¸,ÓB€‚aBÊaÞBÛŽBêôOBÖøtBÿ!3CÌ