splusdata 5.2__tar.gz → 5.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {splusdata-5.2/splusdata.egg-info → splusdata-5.3}/PKG-INFO +1 -1
- {splusdata-5.2 → splusdata-5.3}/pyproject.toml +3 -2
- {splusdata-5.2 → splusdata-5.3}/splusdata/core.py +33 -2
- splusdata-5.3/splusdata/features/find_pointings.py +51 -0
- splusdata-5.3/splusdata/scubes/core.py +250 -0
- splusdata-5.3/splusdata/scubes/read.py +476 -0
- splusdata-5.3/splusdata/scubes/scripts.py +248 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/vars.py +24 -0
- {splusdata-5.2 → splusdata-5.3/splusdata.egg-info}/PKG-INFO +1 -1
- {splusdata-5.2 → splusdata-5.3}/splusdata.egg-info/SOURCES.txt +3 -1
- splusdata-5.3/splusdata.egg-info/entry_points.txt +4 -0
- splusdata-5.2/splusdata/scubes/constants.py +0 -8
- splusdata-5.2/splusdata/scubes/core.py +0 -327
- splusdata-5.2/splusdata.egg-info/entry_points.txt +0 -3
- {splusdata-5.2 → splusdata-5.3}/LICENSE +0 -0
- {splusdata-5.2 → splusdata-5.3}/README.md +0 -0
- {splusdata-5.2 → splusdata-5.3}/setup.cfg +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/__init__.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/connect.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/features/__init__.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/features/extinction.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/features/filterbw.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/features/hipscat.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/features/io.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/features/zeropoints/__init__.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/features/zeropoints/zp_image.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/features/zeropoints/zp_map.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/features/zeropointsdr4.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/models/__init__.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/models/star_gal_quasar.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/readconf.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/scripts/args.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/scubes/__init__.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/vacs/__init__.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/vacs/pdfs.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/vacs/sqg.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata/variability/__init__.py +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata.egg-info/dependency_links.txt +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata.egg-info/requires.txt +0 -0
- {splusdata-5.2 → splusdata-5.3}/splusdata.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "splusdata"
|
|
7
|
-
version = "5.
|
|
7
|
+
version = "5.3"
|
|
8
8
|
description = "Download SPLUS catalogs, FITS and more"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Gustavo Schwarz", email = "gustavo.b.schwarz@gmail.com" }
|
|
@@ -32,7 +32,8 @@ dependencies = [
|
|
|
32
32
|
|
|
33
33
|
[project.scripts]
|
|
34
34
|
splusdata = "splusdata.readconf:main"
|
|
35
|
-
|
|
35
|
+
spd_scubes = "splusdata.scubes.scripts:scubes"
|
|
36
|
+
spd_scubesml = "splusdata.scubes.scripts:scubesml"
|
|
36
37
|
|
|
37
38
|
[tool.setuptools.packages.find]
|
|
38
39
|
where = ["."]
|
|
@@ -3,9 +3,11 @@ import getpass
|
|
|
3
3
|
|
|
4
4
|
from PIL import Image
|
|
5
5
|
from astropy.io import fits
|
|
6
|
+
import astropy.units as u
|
|
6
7
|
import io
|
|
7
8
|
|
|
8
9
|
from splusdata.features.io import print_level
|
|
10
|
+
from splusdata.features.find_pointings import find_pointing
|
|
9
11
|
|
|
10
12
|
class SplusdataError(Exception):
|
|
11
13
|
"""Custom exception type for S-PLUS data errors raised by this helper module.
|
|
@@ -645,13 +647,42 @@ class Core:
|
|
|
645
647
|
"""
|
|
646
648
|
stamp = self.stamp(ra, dec, size, band, weight=weight, field_name=field_name, size_unit=size_unit, data_release=data_release)
|
|
647
649
|
|
|
650
|
+
if weight:
|
|
651
|
+
return stamp
|
|
652
|
+
|
|
648
653
|
from splusdata.features.zeropoints.zp_image import calibrate_hdu_with_zpmodel
|
|
649
654
|
zp_model = self.get_zp_file(stamp[1].header["FIELD"], stamp[1].header["FILTER"], data_release=data_release)
|
|
650
655
|
|
|
651
656
|
calibrated_hdu, factor_map = calibrate_hdu_with_zpmodel(
|
|
652
657
|
stamp[1], zp_model, in_place=False, return_factor=True
|
|
653
658
|
)
|
|
659
|
+
|
|
660
|
+
stamp[1] = calibrated_hdu
|
|
661
|
+
stamp.append(fits.ImageHDU(factor_map, name="ZP_FACTOR"))
|
|
654
662
|
|
|
655
663
|
if outfile:
|
|
656
|
-
|
|
657
|
-
return
|
|
664
|
+
stamp.writeto(outfile, overwrite=True)
|
|
665
|
+
return stamp
|
|
666
|
+
|
|
667
|
+
def check_coords(self, ra, dec, radius=1 * u.degree):
|
|
668
|
+
"""Check which DR contains a pointing within `radius` of (ra, dec).
|
|
669
|
+
|
|
670
|
+
Parameters
|
|
671
|
+
----------
|
|
672
|
+
ra, dec : float
|
|
673
|
+
Coordinates in degrees.
|
|
674
|
+
radius : Astropy unit, optional
|
|
675
|
+
Search radius in degrees (default 1 deg).
|
|
676
|
+
|
|
677
|
+
Returns
|
|
678
|
+
-------
|
|
679
|
+
dict or None
|
|
680
|
+
If found, a dict with keys 'dr', 'field', and 'distance' (an astropy
|
|
681
|
+
Quantity in degrees). If not found in any DR, returns None.
|
|
682
|
+
|
|
683
|
+
Raises
|
|
684
|
+
------
|
|
685
|
+
Exception
|
|
686
|
+
Propagates any errors from `find_pointing`.
|
|
687
|
+
"""
|
|
688
|
+
return find_pointing(ra, dec, radius=radius)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from functools import lru_cache
|
|
3
|
+
from astropy.coordinates import SkyCoord
|
|
4
|
+
import astropy.units as u
|
|
5
|
+
|
|
6
|
+
from splusdata.vars import DR_POINTINGS
|
|
7
|
+
# uses your DR_POINTINGS exactly as given
|
|
8
|
+
|
|
9
|
+
@lru_cache(maxsize=None)
|
|
10
|
+
def _load_dr(dr: str):
|
|
11
|
+
"""Load and normalize a DR table once; results are cached."""
|
|
12
|
+
info = DR_POINTINGS[dr]
|
|
13
|
+
df = pd.read_csv(info["link"])
|
|
14
|
+
# keep only needed cols with consistent names
|
|
15
|
+
df = df.rename(columns={
|
|
16
|
+
info["ra_col"]: "ra",
|
|
17
|
+
info["dec_col"]: "dec",
|
|
18
|
+
info["field_col"]: "field",
|
|
19
|
+
})[["ra", "dec", "field"]].copy()
|
|
20
|
+
# make sure ra/dec are numeric; drop bad rows
|
|
21
|
+
df["ra"] = pd.to_numeric(df["ra"], errors="coerce")
|
|
22
|
+
df["dec"] = pd.to_numeric(df["dec"], errors="coerce")
|
|
23
|
+
df = df.dropna(subset=["ra", "dec"])
|
|
24
|
+
return df.reset_index(drop=True)
|
|
25
|
+
|
|
26
|
+
def find_pointing(ra, dec, radius=1*u.degree):
|
|
27
|
+
"""
|
|
28
|
+
Return the first DR (by dr_order) whose field center lies within `radius`.
|
|
29
|
+
Output: {'dr': 'dr4', 'field': '...', 'distance': <Quantity ...>}
|
|
30
|
+
"""
|
|
31
|
+
target = SkyCoord(ra=ra*u.deg, dec=dec*u.deg, frame="icrs")
|
|
32
|
+
radius = radius if isinstance(radius, u.Quantity) else radius * u.arcmin
|
|
33
|
+
|
|
34
|
+
for dr in DR_POINTINGS.keys():
|
|
35
|
+
df = _load_dr(dr)
|
|
36
|
+
coords = SkyCoord(df["ra"].values * u.deg, df["dec"].values * u.deg)
|
|
37
|
+
sep = target.separation(coords)
|
|
38
|
+
idx = int(sep.argmin())
|
|
39
|
+
if sep[idx] <= radius:
|
|
40
|
+
return {"dr": dr, "field": df["field"].iloc[idx], "distance": sep[idx]}
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
# optional helpers:
|
|
44
|
+
def warm_cache(dr_order=("dr4","dr5","dr6")):
|
|
45
|
+
"""Preload all DR tables into cache (optional)."""
|
|
46
|
+
for dr in dr_order:
|
|
47
|
+
_ = _load_dr(dr)
|
|
48
|
+
|
|
49
|
+
def clear_cache():
|
|
50
|
+
"""Clear cached tables if you need to refresh."""
|
|
51
|
+
_load_dr.cache_clear()
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
import numpy as np
|
|
3
|
+
from os import makedirs
|
|
4
|
+
import astropy.units as u
|
|
5
|
+
from tqdm.auto import tqdm
|
|
6
|
+
from astropy.io import fits
|
|
7
|
+
from astropy.wcs import WCS
|
|
8
|
+
from astropy.table import Table
|
|
9
|
+
from splusdata.core import Core
|
|
10
|
+
import astropy.constants as const
|
|
11
|
+
from os.path import join, exists
|
|
12
|
+
from astropy.wcs import FITSFixedWarning
|
|
13
|
+
from astropy.io.fits.verify import VerifyWarning
|
|
14
|
+
|
|
15
|
+
from splusdata.scubes.read import read_scube
|
|
16
|
+
from splusdata.vars import BANDS, BANDWAVEINFO, get_band_info
|
|
17
|
+
from splusdata.features.io import print_level, convert_coord_to_degrees
|
|
18
|
+
|
|
19
|
+
__scubes_author__ = 'Eduardo A. D. Lacerda <dhubax@gmail.com>'
|
|
20
|
+
__scubes_version__ = '0.1.idr6-beta'
|
|
21
|
+
|
|
22
|
+
def _getval_array(pathlist, key, ext):
|
|
23
|
+
return np.array([fits.getval(img, key, ext) for img in pathlist])
|
|
24
|
+
|
|
25
|
+
def _getdata_array(pathlist, ext):
|
|
26
|
+
return np.array([fits.getdata(img, ext=ext) for img in pathlist])
|
|
27
|
+
|
|
28
|
+
def _getheader_array(pathlist, ext):
|
|
29
|
+
return np.array([fits.getheader(img, ext=ext) for img in pathlist])
|
|
30
|
+
|
|
31
|
+
def _getval_array_mem(hdull, key, ext):
|
|
32
|
+
return np.array([hdul[ext].header.get(key) for hdul in hdull])
|
|
33
|
+
|
|
34
|
+
def _getdata_array_mem(hdull, ext):
|
|
35
|
+
return np.array([hdul[ext].data for hdul in hdull])
|
|
36
|
+
|
|
37
|
+
def _getheader_array_mem(hdull, ext):
|
|
38
|
+
return np.array([hdul[ext].header for hdul in hdull])
|
|
39
|
+
|
|
40
|
+
def _get_band_info_array(prop):
|
|
41
|
+
return np.array([get_band_info(band)[prop] for band in BANDS])
|
|
42
|
+
|
|
43
|
+
class SCubes:
|
|
44
|
+
def __init__(self, ra, dec, field, size=None, username=None, password=None, verbose=1):
|
|
45
|
+
self.conn = Core(username, password, verbose=verbose)
|
|
46
|
+
self.field = field
|
|
47
|
+
self.verbose = verbose
|
|
48
|
+
self.mem = False
|
|
49
|
+
|
|
50
|
+
if verbose == 0:
|
|
51
|
+
# dactivate warnings without verbosity
|
|
52
|
+
warnings.simplefilter('ignore', category=VerifyWarning)
|
|
53
|
+
warnings.simplefilter('ignore', category=FITSFixedWarning)
|
|
54
|
+
|
|
55
|
+
self.cubepath = None
|
|
56
|
+
self._stamp_config(ra, dec, size)
|
|
57
|
+
|
|
58
|
+
def _stamp_config(self, ra, dec, size):
|
|
59
|
+
self.ra, self.dec = convert_coord_to_degrees(ra, dec)
|
|
60
|
+
self.size = size
|
|
61
|
+
|
|
62
|
+
def _getval(self, obj, key, ext):
|
|
63
|
+
return _getval_array_mem(obj, key, ext) if self.mem else _getval_array(obj, key, ext)
|
|
64
|
+
|
|
65
|
+
def _getdata(self, obj, ext):
|
|
66
|
+
return _getdata_array_mem(obj, ext) if self.mem else _getdata_array(obj, ext)
|
|
67
|
+
|
|
68
|
+
def _getheader(self, obj, ext):
|
|
69
|
+
return _getheader_array_mem(obj, ext) if self.mem else _getheader_array(obj, ext)
|
|
70
|
+
|
|
71
|
+
def _download_calibrated_stamps(self, objname, outpath=None, force=False):
|
|
72
|
+
images = []
|
|
73
|
+
wimages = []
|
|
74
|
+
_kw_args = dict(ra=self.ra, dec=self.dec, size=self.size, field_name=self.field)
|
|
75
|
+
for b in tqdm(BANDS, desc=f'{objname} @ {self.field} - Downloading', leave=True, position=0):
|
|
76
|
+
b = b.upper().replace('J0', 'F')
|
|
77
|
+
kw_args = _kw_args.copy()
|
|
78
|
+
kw_args.update(band=b, weight=False)
|
|
79
|
+
if self.mem:
|
|
80
|
+
x = self.conn.calibrated_stamp(**kw_args)
|
|
81
|
+
images.append(x)
|
|
82
|
+
else:
|
|
83
|
+
filename = f'{objname}_{self.field}_{b}_{self.size}x{self.size}_swp.fits.fz'
|
|
84
|
+
kw_args.update(outfile=join(outpath, filename))
|
|
85
|
+
_ = self.conn.calibrated_stamp(**kw_args)
|
|
86
|
+
images.append(kw_args['outfile'])
|
|
87
|
+
# wei
|
|
88
|
+
kw_args['weight'] = True
|
|
89
|
+
if self.mem:
|
|
90
|
+
wimages.append(self.conn.calibrated_stamp(**kw_args))
|
|
91
|
+
else:
|
|
92
|
+
kw_args['outfile'] = join(outpath, filename.replace('swp', 'swpweight'))
|
|
93
|
+
_ = self.conn.calibrated_stamp(**kw_args)
|
|
94
|
+
wimages.append(kw_args['outfile'])
|
|
95
|
+
self.images = images
|
|
96
|
+
self.wimages = wimages
|
|
97
|
+
|
|
98
|
+
def _photospectra(self, flam_scale=None, ext=1):
|
|
99
|
+
flam_scale = 1e-19 if flam_scale is None else flam_scale
|
|
100
|
+
_c = const.c
|
|
101
|
+
scale = (1/flam_scale)
|
|
102
|
+
Jy2fnu = 3631e-23
|
|
103
|
+
|
|
104
|
+
self.wl__b = _get_band_info_array('pivot_wave')*u.Angstrom
|
|
105
|
+
|
|
106
|
+
self.flam_unit = u.erg / u.s / u.cm / u.cm / u.AA
|
|
107
|
+
self.fnu_unit = u.erg / u.s / u.cm / u.cm / u.Hz
|
|
108
|
+
|
|
109
|
+
# flux
|
|
110
|
+
calib_data__byx = self._getdata(self.images, ext)
|
|
111
|
+
fnu__byx = calib_data__byx*Jy2fnu*self.fnu_unit
|
|
112
|
+
flam__byx = scale*(fnu__byx*_c/self.wl__b[:, None, None]**2).to(self.flam_unit)
|
|
113
|
+
|
|
114
|
+
# error in flux
|
|
115
|
+
zp_factor__byx = self._getdata(self.images, 2)
|
|
116
|
+
absdata__byx = np.abs(calib_data__byx/zp_factor__byx)
|
|
117
|
+
gain__b = self._getval(self.images, 'GAIN', ext)
|
|
118
|
+
gain__byx = gain__b[:, None, None]
|
|
119
|
+
weidata__byx = self._getdata(self.wimages, ext)
|
|
120
|
+
absweidata__byx = np.abs(self._getdata(self.wimages, ext))
|
|
121
|
+
dataerr__byx = np.sqrt(1/absweidata__byx + absdata__byx/gain__byx)
|
|
122
|
+
f0__byx = zp_factor__byx*Jy2fnu
|
|
123
|
+
efnu__byx = dataerr__byx*f0__byx*self.fnu_unit
|
|
124
|
+
eflam__byx = scale*(efnu__byx*_c/self.wl__b[:, None, None]**2).to(self.flam_unit)
|
|
125
|
+
|
|
126
|
+
self.flam__byx = flam__byx
|
|
127
|
+
self.eflam__byx = eflam__byx
|
|
128
|
+
self.weidata__byx = weidata__byx
|
|
129
|
+
self.absweidata__byx = absweidata__byx
|
|
130
|
+
|
|
131
|
+
def _stamp_WCS_to_cube_header(self, header):
|
|
132
|
+
'''
|
|
133
|
+
Convert WCS information from stamp to cube header.
|
|
134
|
+
|
|
135
|
+
Parameters
|
|
136
|
+
----------
|
|
137
|
+
header : :class:`~astropy.io.fits.Header`
|
|
138
|
+
FITS header containing WCS information.
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
:class:`~astropy.io.fits.Header`
|
|
143
|
+
Cube header with updated WCS information.
|
|
144
|
+
'''
|
|
145
|
+
w = WCS(header)
|
|
146
|
+
nw = WCS(naxis=3)
|
|
147
|
+
nw.wcs.cdelt = [w.wcs.cdelt[0], w.wcs.cdelt[1], 1]
|
|
148
|
+
nw.wcs.crval = [w.wcs.crval[0], w.wcs.crval[1], 0]
|
|
149
|
+
nw.wcs.crpix = [w.wcs.crpix[0], w.wcs.crpix[1], 0]
|
|
150
|
+
nw.wcs.ctype = [w.wcs.ctype[0], w.wcs.ctype[1], '']
|
|
151
|
+
try:
|
|
152
|
+
nw.wcs.pc[:2, :2] = w.wcs.get_pc()
|
|
153
|
+
except:
|
|
154
|
+
pass
|
|
155
|
+
return nw.to_header()
|
|
156
|
+
|
|
157
|
+
def _weights_mask_hdu(self):
|
|
158
|
+
# WEIGHTS MASK HDU
|
|
159
|
+
w__byx = self.weidata__byx
|
|
160
|
+
wmask__byx = np.where(w__byx < 0, 1, 0)
|
|
161
|
+
wmask__yx = wmask__byx.sum(axis=0)
|
|
162
|
+
wmask_hdu = fits.ImageHDU(wmask__yx)
|
|
163
|
+
wmask_hdu.header['EXTNAME'] = ('WEIMASK', 'Sum of negative weight pixels (from 1 to 12)')
|
|
164
|
+
return wmask_hdu
|
|
165
|
+
|
|
166
|
+
def _metadata_hdu(self, ext=1):
|
|
167
|
+
# METADATA HDU
|
|
168
|
+
tab = [BANDS]
|
|
169
|
+
tab.append(_get_band_info_array('central_wave'))
|
|
170
|
+
tab.append(_get_band_info_array('pivot_wave'))
|
|
171
|
+
# PSFFWHM
|
|
172
|
+
psffwhm__b = []
|
|
173
|
+
for img in self.images:
|
|
174
|
+
if self.mem:
|
|
175
|
+
hdr = img[ext].header
|
|
176
|
+
else:
|
|
177
|
+
hdr = fits.getheader(img, ext=ext)
|
|
178
|
+
key = [k for k in hdr.keys() if 'FWHMMEAN' in k]
|
|
179
|
+
if len(key) == 1:
|
|
180
|
+
psffwhm__b.append(hdr.get(key[0]))
|
|
181
|
+
tab.append(psffwhm__b)
|
|
182
|
+
tab = Table(tab, names=['FILTER', 'CENTWAVE', 'PIVOTWAVE', 'PSFFWHM'])
|
|
183
|
+
return fits.BinTableHDU(tab, name='METADATA')
|
|
184
|
+
|
|
185
|
+
def _create_cube_hdulist(self, objname, ext=1):
|
|
186
|
+
cube_prim_hdu = fits.PrimaryHDU()
|
|
187
|
+
cube_prim_hdu.header['TILE'] = self.field
|
|
188
|
+
cube_prim_hdu.header['OBJECT'] = objname
|
|
189
|
+
cube_prim_hdu.header['SIZE'] = (self.size, 'Side of the stamp in pixels')
|
|
190
|
+
cube_prim_hdu.header['RA'] = self.ra
|
|
191
|
+
cube_prim_hdu.header['DEC'] = self.dec
|
|
192
|
+
hdr = self.images[0][ext].header if self.mem else fits.getheader(self.images[0], ext=ext)
|
|
193
|
+
cube_prim_hdu.header.update(self._stamp_WCS_to_cube_header(hdr))
|
|
194
|
+
for key in ['X0TILE', 'X01TILE', 'Y0TILE', 'Y01TILE']:
|
|
195
|
+
cube_prim_hdu.header[key] = hdr.get(key)
|
|
196
|
+
# DATA HDU
|
|
197
|
+
flam_hdu = fits.ImageHDU(self.flam__byx.value, cube_prim_hdu.header)
|
|
198
|
+
flam_hdu.header['EXTNAME'] = ('DATA', 'Name of the extension')
|
|
199
|
+
# ERRORS HDU
|
|
200
|
+
eflam_hdu = fits.ImageHDU(self.eflam__byx.value, cube_prim_hdu.header)
|
|
201
|
+
eflam_hdu.header['EXTNAME'] = ('ERRORS', 'Name of the extension')
|
|
202
|
+
hdul = [cube_prim_hdu, flam_hdu, eflam_hdu]
|
|
203
|
+
# INFO TO HEADERS
|
|
204
|
+
for hdu in hdul[1:]:
|
|
205
|
+
hdu.header['BSCALE'] = (self.flam_scale, 'Linear factor in scaling equation')
|
|
206
|
+
hdu.header['BZERO'] = (0, 'Zero point in scaling equation')
|
|
207
|
+
hdu.header['BUNIT'] = (f'{self.flam_unit}', 'Physical units of the array values')
|
|
208
|
+
hdul.append(self._weights_mask_hdu())
|
|
209
|
+
hdul.append(self._metadata_hdu(ext))
|
|
210
|
+
return fits.HDUList(hdul)
|
|
211
|
+
|
|
212
|
+
def write(self, cubepath, overwrite=False):
|
|
213
|
+
print_level(f'writting cube {cubepath}', 1, self.verbose)
|
|
214
|
+
self.cube.writeto(cubepath, overwrite=overwrite)
|
|
215
|
+
print_level(f'Cube successfully created!', 1, self.verbose)
|
|
216
|
+
|
|
217
|
+
def create_cube(self, flam_scale=None, objname=None, outpath=None, force=False, data_ext=1, write_fits=False, return_scube=False, force_mem=False):
|
|
218
|
+
self.flam_scale = 1e-19 if flam_scale is None else flam_scale
|
|
219
|
+
self.objname = 'myobj' if objname is None else objname
|
|
220
|
+
self.outpath = '.' if outpath is None else outpath
|
|
221
|
+
mkcube = True
|
|
222
|
+
|
|
223
|
+
if outpath is not None:
|
|
224
|
+
try:
|
|
225
|
+
makedirs(self.outpath)
|
|
226
|
+
except FileExistsError:
|
|
227
|
+
print_level(f'{self.outpath}: directory already exists', 1, self.verbose)
|
|
228
|
+
|
|
229
|
+
self.cubepath = join(self.outpath, f'{self.objname}_cube.fits')
|
|
230
|
+
|
|
231
|
+
if exists(self.cubepath) and not force:
|
|
232
|
+
mkcube = False
|
|
233
|
+
print_level(f'{self.cubepath}: cube already exists', 1, self.verbose)
|
|
234
|
+
else:
|
|
235
|
+
self.mem = True
|
|
236
|
+
|
|
237
|
+
if not self.mem and force_mem:
|
|
238
|
+
self.mem = True
|
|
239
|
+
|
|
240
|
+
if mkcube:
|
|
241
|
+
self._download_calibrated_stamps(objname, outpath, force=force)
|
|
242
|
+
self._photospectra(flam_scale, ext=data_ext)
|
|
243
|
+
|
|
244
|
+
self.cube = self._create_cube_hdulist(objname, ext=data_ext)
|
|
245
|
+
|
|
246
|
+
if (self.cubepath is not None) and write_fits:
|
|
247
|
+
self.write(self.cubepath, force)
|
|
248
|
+
|
|
249
|
+
if return_scube:
|
|
250
|
+
return read_scube(self.cube)
|