Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V1.0 Tasks #117

Merged
merged 34 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7067a7f
image.processing: add testes for lacosmic
juliotux Aug 17, 2023
93b0b49
fix gaia property tests
juliotux Aug 17, 2023
62557e5
image.processing: add gain tests
juliotux Aug 17, 2023
79518fe
image.processing: tests from image trimming
juliotux Aug 19, 2023
5457357
rename image related tests
juliotux Aug 19, 2023
db35637
image.processing: more tests
juliotux Aug 19, 2023
a79f144
daofind: subtract background prior to detection
juliotux Sep 5, 2023
6152075
detection: improve performance of daofind morfology
juliotux Sep 5, 2023
f9771b4
aperture: ensure to use a copy of the data
juliotux Sep 5, 2023
69bf518
astrometry: ignore fits verify in create_xyls
juliotux Sep 5, 2023
ed9daee
test_detection: ensure order in a test
juliotux Sep 5, 2023
c0be1a7
test_catalogs_online: fix gaia properties
juliotux Sep 5, 2023
6affcb2
test_detection: fixed a typo
juliotux Sep 5, 2023
57427b8
test_detection: add tests for ensure image integrity
juliotux Sep 6, 2023
ed75582
aperture: test for image integrity
juliotux Sep 6, 2023
c1c1b16
background: tests for image integrity after bkg
juliotux Sep 6, 2023
87c9ddb
Merge branch 'main' into one-dot-zero
juliotux Sep 6, 2023
bbf1aae
background: use copies of the arrays
juliotux Sep 6, 2023
e942c39
qfloat: added statistical functions
juliotux Sep 6, 2023
8d57819
image.processing: typo in docs
juliotux Sep 6, 2023
ca5e971
polarimetry: fix k determination and added a lot of tests
juliotux Sep 6, 2023
219ac75
polarimetry: added tests with missing points
juliotux Sep 6, 2023
1399c0f
polarimetry: fixed some tests
juliotux Sep 6, 2023
8486f54
polarimetry: fixed more tests
juliotux Sep 6, 2023
609f46f
polarimetry: change tests
juliotux Sep 7, 2023
8e8f56b
polarimetry: fixed l/4 tests. q<0&k>1 and q>0&k<1
juliotux Sep 12, 2023
3e3d832
py_utils: remove unused indexeddict
juliotux Sep 12, 2023
6d45a6e
framedata: reworked meta handling
juliotux Sep 13, 2023
ef6e6c6
header merging: fix for the new handling
juliotux Sep 13, 2023
7206345
imarith: fixed header merging
juliotux Sep 13, 2023
06fb150
header merging: ensure comments are kept
juliotux Sep 13, 2023
e0f8145
fixed some pep8
juliotux Sep 13, 2023
c2fb0bb
fix more pep8
juliotux Sep 13, 2023
496339d
py_utils: remove indexeddict from all
juliotux Sep 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion astropop/fits_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ def string_to_header_key(string: str) -> str:
"""
# for non hierarch keys, we will use normalized keywords (uppercase)
if fits.Card._keywd_FSC_RE.match(string.upper()) and len(string) <= 8:
return string.upper()
string = string.upper()
return string

# these cases should go to hierarch
if string.casefold().startswith('hierarch '):
Expand Down
55 changes: 13 additions & 42 deletions astropop/framedata/_compat.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""Handle compatibility between FrameData and other data formats."""

import warnings
import itertools
import warnings
from os import PathLike
import copy as cp
import numpy as np
from astropy.io import fits
from astropy.io.fits.verify import VerifyWarning
from astropy.wcs import WCS, FITSFixedWarning
from astropy.io.fits.verify import VerifyWarning
from astropy.nddata.ccddata import CCDData
from astropy.nddata import StdDevUncertainty, VarianceUncertainty, \
InverseVariance
Expand All @@ -19,17 +19,17 @@
from ..fits_utils import imhdus, string_to_header_key


_HDU_UNCERT = 'UNCERT'
_HDU_MASK = 'MASK'
_HDU_FLAGS = 'PIXFLAGS'
_UNIT_KEY = 'BUNIT'
_PCs = set(['PC1_1', 'PC1_2', 'PC2_1', 'PC2_2'])
_CDs = set(['CD1_1', 'CD1_2', 'CD2_1', 'CD2_2'])
_KEEP = set(['JD-OBS', 'MJD-OBS', 'DATE-OBS'])
_PROCTECTED = ["SIMPLE", "XTENSION", "BITPIX", "NAXIS", "EXTEND", "PCOUNT",
"GCOUNT", "GROUPS", "BSCALE", "BZERO", "TFIELDS"]
_PROTECTED_N = ["TFORM", "TSCAL", "TZERO", "TNULL", "TTYPE", "TUNIT", "TDISP",
"TDIM", "THEAP", "TBCOL"]
_HDU_UNCERT = 'UNCERT'
_HDU_MASK = 'MASK'
_HDU_FLAGS = 'PIXFLAGS'
_UNIT_KEY = 'BUNIT'


def _remove_sip_keys(header, wcs):
Expand Down Expand Up @@ -103,9 +103,12 @@
def _normalize_and_strip_dict(meta):
"""Normalize meta keys and remove the protected ones."""
if meta is None:
return {}, [], []
return fits.Header(), [], []

nmeta = {}
if not isinstance(meta, fits.Header):
raise TypeError('meta must be a fits.Header instance.')

nmeta = fits.Header()
history = []
comment = []

Expand All @@ -129,8 +132,8 @@
# as dicts are case sensitive, this can happen. Raise error
warnings.warn(f'Duplicated key {k}. First value will be used.')
if k not in _PROCTECTED and k != '' and k not in nmeta:
# remove protected keys
nmeta[k] = v
# keep commentaries. Do not keep protected keys
nmeta.append((k, meta[k], meta.comments[k]))

# remove protected keys with number
naxis = nmeta.get('NAXIS', 0)
Expand All @@ -146,38 +149,6 @@
return nmeta, history, comment


def _merge_and_clean_header(meta, header, wcs):
"""Merge meta and header and clean the WCS and spurious keys."""
if not isinstance(meta, (dict, fits.Header)) and meta is not None:
raise TypeError('meta must be a dict or fits.Header. '
f'Got {type(meta)}')
if not isinstance(header, fits.Header) and header is not None:
raise TypeError('header must be a fits.Header. '
f'Got {type(header)}')
if not isinstance(wcs, WCS) and wcs is not None:
raise TypeError('wcs must be a astropy.wcs.WCS. '
f'Got {type(wcs)}')

history = []
comment = []
fmeta = fits.Header()

for m in [meta, header]:
m, h, c = _normalize_and_strip_dict(m)
# extract history and comments from meta
history.extend(h)
comment.extend(c)
# merge meta and header
fmeta.update(m)

# extract wcs from header
meta, wcs_ = extract_header_wcs(fmeta)
if wcs_ and wcs:
raise ValueError('meta and wcs offer a WCS. Use only one.')
wcs = wcs_ if wcs is None else wcs
return meta, wcs, history, comment


def _extract_fits(obj, hdu=0, unit=None, hdu_uncertainty=_HDU_UNCERT,
hdu_flags=_HDU_FLAGS, hdu_mask=_HDU_MASK,
unit_key=_UNIT_KEY):
Expand Down Expand Up @@ -240,7 +211,7 @@
if isinstance(obj, (str, bytes, PathLike)):
hdul.close()

# TODO: extract flags

Check notice on line 214 in astropop/framedata/_compat.py

View check run for this annotation

codefactor.io / CodeFactor

astropop/framedata/_compat.py#L214

unresolved comment '# TODO: extract flags' (C100)

return res

Expand Down Expand Up @@ -331,7 +302,7 @@
mask_h = fits.Header()
hdul.append(fits.ImageHDU(mask, header=mask_h, name=hdu_mask))

# TODO: add flags

Check notice on line 305 in astropop/framedata/_compat.py

View check run for this annotation

codefactor.io / CodeFactor

astropop/framedata/_compat.py#L305

unresolved comment '# TODO: add flags' (C100)

return hdul

Expand Down
56 changes: 40 additions & 16 deletions astropop/framedata/framedata.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
from ..flags import mask_from_flags
from ._memmap import create_array_memmap, delete_array_memmap, \
reset_memmap_array
from ._compat import _merge_and_clean_header, _to_hdu, _to_ccddata, _write_fits
from ._compat import _to_hdu, _to_ccddata, _write_fits, \
_normalize_and_strip_dict, extract_header_wcs
from .._unit_property import unit_property


Expand Down Expand Up @@ -183,10 +184,11 @@ class FrameData:
Pixel flags for the frame. See `~astropop.FrameData.PixelMaskFlags`.
for values.
wcs : `dict`, `~astropy.fits.Header` or `~astropy.wcs.WCS` (optional)
World Coordinate System of the image.
World Coordinate System of the image. If meta or header keys already
contain WCS informations, an error will be raised.
meta or header: `dict` or `astropy.fits.Header` (optional)
Metadata (header) of the frame. If both set, they will be merged.
`header` priority.
Metadata (header) of the frame. Only one accepted. If both are passed,
error will be raised.
cache_folder : string, `~pathlib.Path` or `None` (optional)
Place to store the cached `FrameData`
cache_filename : string, `~pathlib.Path` or `None` (optional)
Expand Down Expand Up @@ -221,9 +223,9 @@ class FrameData:
cache_filename = None

def __init__(self, data, unit=None, dtype=None, uncertainty=None,
mask=None, flags=None, wcs=None, meta=None, header=None,
mask=None, flags=None, use_memmap_backend=False,
cache_folder=None, cache_filename=None, origin_filename=None,
use_memmap_backend=False):
**kwargs):
# setup names
setup_filename(self, cache_folder, cache_filename)
self._origin = origin_filename
Expand Down Expand Up @@ -268,19 +270,41 @@ def __init__(self, data, unit=None, dtype=None, uncertainty=None,
self._history = []
self._comments = []
self._meta = fits.Header()
self._header_update(header, meta, wcs)

def _header_update(self, header, meta=None, wcs=None):
# merge header and meta. meta with higher priority
meta, wcs, history, comment = _merge_and_clean_header(meta, header,
wcs)
if 'meta' in kwargs and 'header' in kwargs:
raise ValueError('Only one of meta or header can be set.')
if 'meta' not in kwargs:
kwargs['meta'] = kwargs.pop('header', None)
self._meta_update(kwargs.pop('meta', None),
kwargs.pop('wcs', None))

def _meta_update(self, meta, wcs=None):
# simplify things by enforcing meta type
if not isinstance(meta, (dict, fits.Header, type(None))):
raise TypeError('meta must be a dict, Header or None.')

# force fits compliant header
try:
if meta is not None:
hdr = fits.Header(meta)
else:
hdr = fits.Header()
except Exception as e:
raise ValueError('meta or header must be compilant with FITS '
'standard. Got error when tried to convert to '
f'fits.Header: {e}')

header, history, comment = _normalize_and_strip_dict(hdr)
if len(history) > 0:
self.history = history
if len(comment) > 0:
self.comment = comment
if wcs is not None:
self._wcs = wcs
self._meta = meta

header, _wcs = extract_header_wcs(header)
if _wcs is not None and wcs is not None:
raise ValueError('wcs and meta/wcs cannot be set at the same '
'time.')
self._wcs = _wcs or wcs
self._meta = header

@property
def origin_filename(self):
Expand Down Expand Up @@ -325,7 +349,7 @@ def meta(self):

@meta.setter
def meta(self, value):
self._header_update(None, value)
self._meta_update(value)

@property
def header(self):
Expand Down
64 changes: 30 additions & 34 deletions astropop/image/_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

from ..logger import logger
from ..framedata._compat import _normalize_and_strip_dict
from ..fits_utils import string_to_header_key

__all__ = ['merge_header', 'merge_flag']

Expand All @@ -22,8 +21,8 @@
Method to merge the headers. 'only_equal' will merge only the keywords
with the same value in all headers. 'first' will use the first
header as the result. 'selected_keys' will merge only the keywords
in the list `header_merge_keys`. 'no_merge' will return an empty
header.
in the list `header_merge_keys`, prioritizing the first appearence.
'no_merge' will return an empty header.
selected_keys: list of str
List of keywords to be merged. Used only if method is
'selected_keys'.
Expand All @@ -43,7 +42,7 @@
raise ValueError('selected_keys must be provided if method is '
'selected_keys.')

meta = {}
meta = Header()
if method == 'no_merge':
return meta

Expand All @@ -52,39 +51,36 @@
if method == 'first':
return headers[0].copy()

summary = None
first_hdr = headers[0]
if method == 'first':
return first_hdr.copy()

Check warning on line 56 in astropop/image/_tools.py

View check run for this annotation

Codecov / codecov/patch

astropop/image/_tools.py#L56

Added line #L56 was not covered by tests

for hdr in headers:
hdr, _, _ = _normalize_and_strip_dict(hdr)
hdr = Header(hdr)
if summary is None:
summary = {k: [v] for k, v in hdr.items()}
for key in hdr.keys():
if key not in summary.keys():
# avoid only_equal problems
summary[key] = [None]
if hdr[key] not in summary[key]:
summary[key].append(hdr[key])

if method == 'selected_keys':
keys = selected_keys
else:
keys = summary.keys()

for k in keys:
# do not use np.unique to avoid problems with None
k = string_to_header_key(k)
uniq = list(set(summary[k]))
if len(uniq) == 1:
meta[k] = uniq[0]
if method == 'only_equal':
# only keeps equal keys. If is the first header, add it
# to the meta. If the key is different, remove it from
# the meta.
for key in hdr:
if key not in meta and hdr == first_hdr:
meta.append((key, hdr[key], hdr.comments[key]))
continue
if key not in meta:
continue
if meta[key] != hdr[key]:
del meta[key]
# remove all keys that are not in this header, since it will be not
# equal
for key in meta:
if key not in hdr:
del meta[key]

Check warning on line 76 in astropop/image/_tools.py

View check run for this annotation

Codecov / codecov/patch

astropop/image/_tools.py#L76

Added line #L76 was not covered by tests
elif method == 'selected_keys':
logger.debug('Keyword %s is different across headers. '
'Unsing first one.', k)
meta[k] = summary[k][0]
else:
logger.debug('Keyword %s is different across headers. '
'Skipping.', k)

return dict(meta)
# only keeps the keys in the selected_keys list
for key in hdr:
if key in selected_keys and key not in meta:
meta.append((key, hdr[key], hdr.comments[key]))

return meta


def merge_flag(*flags, method='or'):
Expand Down
4 changes: 2 additions & 2 deletions astropop/image/imarith.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ def imarith(operand1, operand2, operation, inplace=False,
ccd.flags = merge_flag(f1, f2, method=merge_flags)

# Perform merging headers operation only if both operands have headers
h1 = getattr(operand1, 'header', {})
h2 = getattr(operand2, 'header', {})
h1 = getattr(operand1, 'header', None)
h2 = getattr(operand2, 'header', None)
keys = kwargs.get('selected_keys', None)
ccd.meta = merge_header(h1, h2, method=merge_headers, selected_keys=keys)

Expand Down
14 changes: 4 additions & 10 deletions astropop/image/processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
'subtract_dark', 'flat_correct', 'trim_image']


# TODO: replace ccdproc functions by built-in, skiping units

Check notice on line 17 in astropop/image/processing.py

View check run for this annotation

codefactor.io / CodeFactor

astropop/image/processing.py#L17

unresolved comment '# TODO: replace ccdproc functions by built-in, skiping units' (C100)
# block_reduce = ccdproc.block_reduce
# block_replicate = ccdproc.block_replicate

Expand All @@ -36,8 +36,7 @@
Parameters
----------
frame: `~astropop.framedata.FrameData` compatible
Values to perform the operation. `~astropy.units.Quantity`, numerical
values and `~astropy.nddata.CCDData` are also suported.
2D image to clean with LACosmic.
inplace: bool, optional
If True, the operations will be performed inplace in the `frame`.
logger: `~logging.Logger`
Expand All @@ -49,8 +48,8 @@
New cosmic-rays corrected `FrameData` instance if not `inplace`,
else the `image` `~astropop.framedata.FrameData` instance.
"""
# As lacosmic removes and replace the cosmics pixels, no need to
# update the mask
frame = check_framedata(frame)

mask, dat = astroscrappy.detect_cosmics(frame.data, **lacosmic_kwargs)

if inplace:
Expand Down Expand Up @@ -291,12 +290,7 @@

# fix WCS if existing
if image.wcs is not None:
wcs = image.wcs.copy()
wcs.wcs.crpix[0] -= x_slice.start
wcs.wcs.crpix[1] -= y_slice.start
# FIXME: this should work but is getting wrong results
# image.wcs = wcs.slice(section[::-1])
image.wcs = wcs
image.wcs = image.wcs.slice(section)

str_slice = ''
for s in section[::-1]:
Expand Down
Loading
Loading