lightstack 0.1.1__tar.gz → 0.1.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.
- {lightstack-0.1.1/src/lightstack.egg-info → lightstack-0.1.3}/PKG-INFO +3 -1
- {lightstack-0.1.1 → lightstack-0.1.3}/README.md +2 -0
- {lightstack-0.1.1 → lightstack-0.1.3}/pyproject.toml +1 -1
- {lightstack-0.1.1 → lightstack-0.1.3}/src/lightstack/datacube.py +27 -4
- {lightstack-0.1.1 → lightstack-0.1.3}/src/lightstack/psf.py +7 -0
- {lightstack-0.1.1 → lightstack-0.1.3}/src/lightstack/utils.py +9 -1
- {lightstack-0.1.1 → lightstack-0.1.3/src/lightstack.egg-info}/PKG-INFO +3 -1
- {lightstack-0.1.1 → lightstack-0.1.3}/LICENSE +0 -0
- {lightstack-0.1.1 → lightstack-0.1.3}/setup.cfg +0 -0
- {lightstack-0.1.1 → lightstack-0.1.3}/src/lightstack/__init__.py +0 -0
- {lightstack-0.1.1 → lightstack-0.1.3}/src/lightstack/crop.py +0 -0
- {lightstack-0.1.1 → lightstack-0.1.3}/src/lightstack/plot.py +0 -0
- {lightstack-0.1.1 → lightstack-0.1.3}/src/lightstack.egg-info/SOURCES.txt +0 -0
- {lightstack-0.1.1 → lightstack-0.1.3}/src/lightstack.egg-info/dependency_links.txt +0 -0
- {lightstack-0.1.1 → lightstack-0.1.3}/src/lightstack.egg-info/requires.txt +0 -0
- {lightstack-0.1.1 → lightstack-0.1.3}/src/lightstack.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lightstack
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Tools for building and processing multi-filter astrophysical datacubes
|
|
5
5
|
Author: Andressa Wille, Thallis Pessi
|
|
6
6
|
License: MIT License
|
|
@@ -35,6 +35,8 @@ Requires-Dist: regions
|
|
|
35
35
|
Requires-Dist: scipy
|
|
36
36
|
Requires-Dist: photutils
|
|
37
37
|
|
|
38
|
+
[](https://doi.org/10.5281/zenodo.19393439)
|
|
39
|
+
|
|
38
40
|
<img src="https://raw.githubusercontent.com/AndressaWille/lightstack/master/images/logo.png" width="120">
|
|
39
41
|
|
|
40
42
|
# Lightstack
|
|
@@ -6,7 +6,7 @@ from astropy.wcs import WCS
|
|
|
6
6
|
|
|
7
7
|
from reproject import reproject_interp, reproject_exact
|
|
8
8
|
|
|
9
|
-
from .utils import find_ext, infer_filter
|
|
9
|
+
from .utils import find_ext, infer_filter, get_pixel_scale_from_wcs
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def align_reproject_fits(fits_list, ref_file, method="interp", crop=1):
|
|
@@ -24,7 +24,7 @@ def align_reproject_fits(fits_list, ref_file, method="interp", crop=1):
|
|
|
24
24
|
method : str, optional
|
|
25
25
|
Reprojection method:
|
|
26
26
|
- "interp" (default): faster, interpolates values
|
|
27
|
-
- "exact": slower
|
|
27
|
+
- "exact": slower --> but reproject_exact has precision issues with resolutions below ~0.05 arcsec, so the results may not be accurate.
|
|
28
28
|
|
|
29
29
|
crop : int, optional
|
|
30
30
|
Number of pixels to remove from each border after reprojection
|
|
@@ -36,6 +36,7 @@ def align_reproject_fits(fits_list, ref_file, method="interp", crop=1):
|
|
|
36
36
|
List in the form [(aligned_fits_path, filter_name), ...].
|
|
37
37
|
"""
|
|
38
38
|
|
|
39
|
+
|
|
39
40
|
# Choose reprojection method
|
|
40
41
|
if method == "exact":
|
|
41
42
|
reproj_func = reproject_exact
|
|
@@ -54,6 +55,9 @@ def align_reproject_fits(fits_list, ref_file, method="interp", crop=1):
|
|
|
54
55
|
ref_wcs = WCS(ref_header)
|
|
55
56
|
shape_out = hdul_ref[ext_ref].data.shape
|
|
56
57
|
|
|
58
|
+
# Pixel scale of reference
|
|
59
|
+
scale_out = get_pixel_scale_from_wcs(ref_wcs)
|
|
60
|
+
|
|
57
61
|
aligned_list = []
|
|
58
62
|
|
|
59
63
|
# Loop over all FITS
|
|
@@ -65,20 +69,30 @@ def align_reproject_fits(fits_list, ref_file, method="interp", crop=1):
|
|
|
65
69
|
print(f"No data extension found in {fpath}. Skipping.")
|
|
66
70
|
continue
|
|
67
71
|
|
|
68
|
-
data = hdul[ext].data
|
|
72
|
+
data = hdul[ext].data.astype(float)
|
|
69
73
|
header = hdul[ext].header
|
|
70
74
|
wcs_in = WCS(header)
|
|
71
75
|
|
|
72
76
|
unit = header.get('BUNIT', 'unknown')
|
|
73
77
|
print(f"Filter {filt}: unit = {unit}")
|
|
74
78
|
|
|
79
|
+
# Pixel scale of input
|
|
80
|
+
scale_in = get_pixel_scale_from_wcs(wcs_in)
|
|
81
|
+
|
|
75
82
|
# Reproject
|
|
76
83
|
data_aligned, footprint = reproj_func(
|
|
77
84
|
(data, wcs_in),
|
|
78
85
|
ref_wcs,
|
|
79
86
|
shape_out=shape_out)
|
|
80
87
|
|
|
81
|
-
#
|
|
88
|
+
# Area correction
|
|
89
|
+
area_ratio = (scale_out / scale_in)**2
|
|
90
|
+
data_aligned *= area_ratio
|
|
91
|
+
|
|
92
|
+
print(f"Pixel scale in/out: {scale_in:.4f} -> {scale_out:.4f}")
|
|
93
|
+
print(f"Applied area correction: {area_ratio:.4f}")
|
|
94
|
+
|
|
95
|
+
# Crop border
|
|
82
96
|
if crop > 0:
|
|
83
97
|
data_aligned = data_aligned[crop:-crop, crop:-crop]
|
|
84
98
|
|
|
@@ -90,10 +104,13 @@ def align_reproject_fits(fits_list, ref_file, method="interp", crop=1):
|
|
|
90
104
|
|
|
91
105
|
# Header
|
|
92
106
|
header_aligned = wcs_out.to_header()
|
|
107
|
+
header_aligned['BUNIT'] = unit
|
|
93
108
|
|
|
94
109
|
ref_filter = infer_filter(ref_file)
|
|
95
110
|
header_aligned.add_history(
|
|
96
111
|
f"Reprojected to {ref_filter} using {method} method (reproject package)")
|
|
112
|
+
header_aligned.add_history(
|
|
113
|
+
"Flux corrected by pixel area ratio")
|
|
97
114
|
|
|
98
115
|
if crop > 0:
|
|
99
116
|
header_aligned.add_history(f"Cropped {crop} pixels from each border")
|
|
@@ -105,10 +122,16 @@ def align_reproject_fits(fits_list, ref_file, method="interp", crop=1):
|
|
|
105
122
|
fits.PrimaryHDU(data_aligned, header=header_aligned).writeto(
|
|
106
123
|
out_name, overwrite=True)
|
|
107
124
|
|
|
125
|
+
# Flux sanity check
|
|
126
|
+
sum_in = np.nansum(data)
|
|
127
|
+
sum_out = np.nansum(data_aligned)
|
|
128
|
+
print(f"Flux ratio (out/in): {sum_out/sum_in:.4f}")
|
|
129
|
+
|
|
108
130
|
aligned_list.append((out_name, filt))
|
|
109
131
|
print(f"Saved: {out_name}")
|
|
110
132
|
|
|
111
133
|
return aligned_list
|
|
134
|
+
|
|
112
135
|
|
|
113
136
|
|
|
114
137
|
def build_datacube(aligned_fits_files, reference_file, output_path):
|
|
@@ -125,8 +125,14 @@ def resample_psf(
|
|
|
125
125
|
raise ValueError("Provide either zoom_factor OR both psf_pixel_scale and target_pixel_scale")
|
|
126
126
|
zoom_factor = psf_pixel_scale / target_pixel_scale
|
|
127
127
|
|
|
128
|
+
if zoom_factor > 1:
|
|
129
|
+
raise ValueError("Upsampling not recommended.")
|
|
130
|
+
|
|
128
131
|
# Resample
|
|
129
132
|
psf_resampled = zoom(psf, zoom_factor, order=order)
|
|
133
|
+
|
|
134
|
+
# Area correction
|
|
135
|
+
psf_resampled /= zoom_factor**2
|
|
130
136
|
|
|
131
137
|
# Ensure odd shape
|
|
132
138
|
if make_odd_shape:
|
|
@@ -143,6 +149,7 @@ def resample_psf(
|
|
|
143
149
|
header["HISTORY"] = "PSF resampled using scipy.ndimage.zoom"
|
|
144
150
|
if target_pixel_scale is not None:
|
|
145
151
|
header["CDELT1"] = (target_pixel_scale / 3600, "deg/pix")
|
|
152
|
+
header["CDELT2"] = (target_pixel_scale / 3600, "deg/pix")
|
|
146
153
|
|
|
147
154
|
# Save
|
|
148
155
|
fits.PrimaryHDU(psf_resampled, header=header).writeto(
|
|
@@ -210,7 +210,7 @@ def MJy_sr_to_jy(aligned_list):
|
|
|
210
210
|
|
|
211
211
|
def get_pixel_scale(fits_path):
|
|
212
212
|
"""
|
|
213
|
-
Compute pixel scale in arcsec/pixel using WCS.
|
|
213
|
+
Compute pixel scale in arcsec/pixel using WCS. Assumes square pixels and no significant distortion.
|
|
214
214
|
"""
|
|
215
215
|
with fits.open(fits_path) as hdul:
|
|
216
216
|
ext = find_ext(hdul)
|
|
@@ -221,3 +221,11 @@ def get_pixel_scale(fits_path):
|
|
|
221
221
|
|
|
222
222
|
pixscale = proj_plane_pixel_scales(wcs)[0] * 3600.0
|
|
223
223
|
return pixscale
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def get_pixel_scale_from_wcs(wcs):
|
|
227
|
+
"""
|
|
228
|
+
Compute pixel scale in arcsec/pixel from a WCS object.
|
|
229
|
+
Assumes square pixels and no significant distortion.
|
|
230
|
+
"""
|
|
231
|
+
return proj_plane_pixel_scales(wcs)[0] * 3600.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lightstack
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Tools for building and processing multi-filter astrophysical datacubes
|
|
5
5
|
Author: Andressa Wille, Thallis Pessi
|
|
6
6
|
License: MIT License
|
|
@@ -35,6 +35,8 @@ Requires-Dist: regions
|
|
|
35
35
|
Requires-Dist: scipy
|
|
36
36
|
Requires-Dist: photutils
|
|
37
37
|
|
|
38
|
+
[](https://doi.org/10.5281/zenodo.19393439)
|
|
39
|
+
|
|
38
40
|
<img src="https://raw.githubusercontent.com/AndressaWille/lightstack/master/images/logo.png" width="120">
|
|
39
41
|
|
|
40
42
|
# Lightstack
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|