roman-snpit-snappl 0.4.0__tar.gz → 0.5.0__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.
Potentially problematic release.
This version of roman-snpit-snappl might be problematic. Click here for more details.
- {roman_snpit_snappl-0.4.0/roman_snpit_snappl.egg-info → roman_snpit_snappl-0.5.0}/PKG-INFO +1 -1
- roman_snpit_snappl-0.5.0/changes/20.bugfix.rst +1 -0
- roman_snpit_snappl-0.5.0/changes/23.snappl.rst +1 -0
- roman_snpit_snappl-0.5.0/changes/26.feature.rst +3 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0/roman_snpit_snappl.egg-info}/PKG-INFO +1 -1
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/roman_snpit_snappl.egg-info/SOURCES.txt +3 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/snappl/_version.py +2 -2
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/snappl/psf.py +185 -39
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/snappl/wcs.py +3 -2
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.cruft.json +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/CODEOWNERS +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/ISSUE_TEMPLATE/PR_TEMPLATE.md +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/dependabot.yml +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/labeler.yml +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/workflows/changelog.yml +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/workflows/run_labeler.yml +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/workflows/run_snappl_tests.yml +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/workflows/sphinx-deploy.yml +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/workflows/sub_package_update.yml +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.gitignore +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.pre-commit-config.yaml +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/CHANGES.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/CITATION.cff +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/CODE_OF_CONDUCT.md +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/CONTRIBUTING.md +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/LICENSE +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/MANIFEST.in +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/README.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/changes/.gitkeep +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/changes/10.snappl.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/changes/13.bugfix.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/changes/14.snappl.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/changes/15.feature.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/changes/16.feature.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/changes/18.feature.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/changes/3.snappl.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/changes/5.snappl.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/changes/8.snappl.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/changes/9.snappl.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/codespell-ignore.txt +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/docs/Makefile +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/docs/_static/logo_black_filled.png +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/docs/changes.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/docs/conf.py +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/docs/index.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/docs/installation.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/docs/make.bat +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/docs/usage.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/licenses/.DS_Store +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/licenses/LICENSE.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/licenses/README.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/licenses/TEMPLATE_LICENSE.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/pyproject.toml +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/roman_snpit_snappl.egg-info/dependency_links.txt +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/roman_snpit_snappl.egg-info/not-zip-safe +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/roman_snpit_snappl.egg-info/requires.txt +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/roman_snpit_snappl.egg-info/top_level.txt +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/setup.cfg +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/setup.py +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/snappl/__init__.py +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/snappl/_dev/__init__.py +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/snappl/_dev/scm_version.py +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/snappl/data/README.rst +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/snappl/image.py +0 -0
- {roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/tox.ini +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Properly support creation of PSFs at non-integral pixel positions in OversampledImagePSF
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AstropyWCS now automatically determines appropriate frame.
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
# IMPORTS Standard
|
|
2
2
|
import base64
|
|
3
|
-
|
|
4
3
|
import numpy as np
|
|
4
|
+
import pathlib
|
|
5
|
+
import yaml
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
# IMPORTS Astro
|
|
7
8
|
import galsim
|
|
8
9
|
|
|
10
|
+
# IMPORTS Internal
|
|
11
|
+
from roman_imsim.utils import roman_utils
|
|
9
12
|
from snpit_utils.config import Config
|
|
10
13
|
from snpit_utils.logger import SNLogger
|
|
11
14
|
|
|
@@ -16,24 +19,62 @@ class PSF:
|
|
|
16
19
|
def __init__( self, *args, **kwargs ):
|
|
17
20
|
pass
|
|
18
21
|
|
|
22
|
+
# This is here for backwards compatibility
|
|
23
|
+
@property
|
|
24
|
+
def clip_size( self ):
|
|
25
|
+
return self.stamp_size
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def stamp_size( self ):
|
|
29
|
+
"""The size of the one side of a PSF image stamp at image resolution. Is always odd."""
|
|
30
|
+
raise NotImplementedError( f"{self.__class__.__name__} needs to implement stamp_size." )
|
|
31
|
+
|
|
32
|
+
|
|
19
33
|
def get_stamp( self, x, y, flux=1. ):
|
|
20
34
|
"""Return a 2d numpy image of the PSF at the image resolution.
|
|
21
35
|
|
|
36
|
+
The PSF will be centered as best possible on the stamp*. So, if
|
|
37
|
+
x ends in 0.8, it will be left of center, and if x ends in 0.2,
|
|
38
|
+
it will be right of center. If the fractional part of x or y is
|
|
39
|
+
exactly 0.5, there's an ambituity as to where on the image you
|
|
40
|
+
should place the stamp of the PSF. The position of the PSF on
|
|
41
|
+
the returned stamp will always round *down* in this case. (The
|
|
42
|
+
pixel on the image that corresponds to the center pixel on the
|
|
43
|
+
clip is at floor(x+0.5),floor(y+0.5), *not*
|
|
44
|
+
round(x+0.5),round(y+0.5). Those two things are different, and
|
|
45
|
+
round is not consistent; see the comment in
|
|
46
|
+
OversampledImagePSF.get_stamp for more if you care.)
|
|
47
|
+
|
|
48
|
+
So, for example, assuming the PSF is intrinsically centered*,
|
|
49
|
+
if the stamp size is 5×5 and you ask for the PSF at x=1023,
|
|
50
|
+
y=1023, then you're going to want to put the stamp on to the
|
|
51
|
+
image at image[1021:1026,1021:1026]. However, if you ask for
|
|
52
|
+
the PSF at x=1023.5,y=1023., you'll want to put the stamp on the
|
|
53
|
+
image at image[1021:1026,1022:1027]. (Remember that default
|
|
54
|
+
numpy arrays of astronomy images are indexed [y,x].)
|
|
55
|
+
|
|
56
|
+
* "The PSF will be centered as best possible on the stamp": this
|
|
57
|
+
is only true if the PSF itself is intrinsically centered. See
|
|
58
|
+
OversampledImagePSF.create for a discussion of
|
|
59
|
+
non-intrinsically-centered PSFs.
|
|
60
|
+
|
|
22
61
|
Parameters
|
|
23
62
|
----------
|
|
24
63
|
x: float
|
|
25
|
-
Position on the image of the center of the psf
|
|
64
|
+
Position on the image of the center of the psf. If not
|
|
65
|
+
given, defaults to something sensible that was defined when
|
|
66
|
+
the object was constructed. If you want to do sub-pixel
|
|
67
|
+
shifts, then the fractional part of x will (usually) not be
|
|
68
|
+
0.
|
|
26
69
|
|
|
27
70
|
y: float
|
|
28
|
-
Position on the image of the center of the psf
|
|
29
|
-
|
|
30
|
-
x0: float or None
|
|
31
|
-
Image position of the center of the stamp; defaults to FIGURE THIS OUT
|
|
32
|
-
|
|
33
|
-
y0: float or None
|
|
71
|
+
Position on the image of the center of the psf. Same kind
|
|
72
|
+
of default as x.
|
|
34
73
|
|
|
35
74
|
flux: float, default 1.
|
|
36
|
-
Make the sum of the clip this
|
|
75
|
+
Make the sum of the clip this. If None, just let the clip
|
|
76
|
+
be scaled however it's naturally scaled. For some
|
|
77
|
+
subclasses, that may be what you actually want.
|
|
37
78
|
|
|
38
79
|
Returns
|
|
39
80
|
-------
|
|
@@ -64,6 +105,9 @@ class PSF:
|
|
|
64
105
|
if psfclass == "YamlSerialized_OversampledImagePSF":
|
|
65
106
|
return YamlSerialized_OversampledImagePSF( **kwargs )
|
|
66
107
|
|
|
108
|
+
if psfclass == "A25ePSF":
|
|
109
|
+
return A25ePSF( **kwargs )
|
|
110
|
+
|
|
67
111
|
if psfclass == "ou24PSF":
|
|
68
112
|
return ou24PSF( **kwargs )
|
|
69
113
|
|
|
@@ -72,18 +116,42 @@ class PSF:
|
|
|
72
116
|
|
|
73
117
|
class OversampledImagePSF( PSF ):
|
|
74
118
|
@classmethod
|
|
75
|
-
def create( cls, data=None,
|
|
76
|
-
**kwargs ):
|
|
119
|
+
def create( cls, data=None, x=None, y=None, oversample_factor=1., enforce_odd=True, normalize=True, **kwargs ):
|
|
77
120
|
|
|
78
121
|
"""Parameters
|
|
79
122
|
----------
|
|
80
123
|
data: 2d numpy array
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
124
|
+
The image data of the oversampled PSF. Required.
|
|
125
|
+
|
|
126
|
+
x, y: float
|
|
127
|
+
Position on the source image where this PSF is evaluated.
|
|
128
|
+
Required. Most of the time, but not always, you probably
|
|
129
|
+
want x and y to be integer values. (As in, not integer
|
|
130
|
+
typed, but floats that satisfy x-floor(x)=0.) These are
|
|
131
|
+
also the defaults that get_stamp will use if x and y are not
|
|
132
|
+
passed to get_stamp.
|
|
133
|
+
|
|
134
|
+
If x and/or y have nonzero fractional parts, then the data
|
|
135
|
+
array must be consistent. First consider non-oversampled
|
|
136
|
+
data. Suppose you pass a 11×11 array with x=1022.5 and
|
|
137
|
+
y=1023.25. In this case, the peak of a perfectly symmetric
|
|
138
|
+
PSF image on data would be at (4.5, 5.25). (Not (5.5,
|
|
139
|
+
5.25)! If something's at *exactly* .5, always round down
|
|
140
|
+
here regardless of wheter the integer part is even or odd.)
|
|
141
|
+
The center pixel and the one to the right of it should have
|
|
142
|
+
the same brightness, and the pixel just below center should
|
|
143
|
+
be dimmer than the pixel just above center.
|
|
144
|
+
|
|
145
|
+
For oversampled psfs, the data array must be properly
|
|
146
|
+
shifted to account for non-integral x and y. The shift will
|
|
147
|
+
be as in non-oversampled data, only multiplied by the
|
|
148
|
+
oversampling factor. So, in the same example, if you
|
|
149
|
+
specify a peak of (4.5, 5.25), and you have an oversampling
|
|
150
|
+
factor of 3, you should pass a 33×33 array with the peak of
|
|
151
|
+
the PSF (assuming a symmetric PSF) at (14.5, 16.75).
|
|
84
152
|
|
|
85
153
|
oversample_factor: float, default 1.
|
|
86
|
-
There are this many pixels along one axis in data for one pixel in the original image
|
|
154
|
+
There are this many pixels along one axis in data for one pixel in the original image.
|
|
87
155
|
|
|
88
156
|
enforce_odd: bool, default True
|
|
89
157
|
Enforce x_edges and y_edges having an odd width.
|
|
@@ -106,18 +174,26 @@ class OversampledImagePSF( PSF ):
|
|
|
106
174
|
if not isinstance( data, np.ndarray ) or ( len(data.shape) != 2 ):
|
|
107
175
|
raise TypeError( "data must be a 2d numpy array" )
|
|
108
176
|
|
|
109
|
-
|
|
110
|
-
|
|
177
|
+
x = float( x )
|
|
178
|
+
y = float( y )
|
|
111
179
|
|
|
112
180
|
psf = cls()
|
|
113
181
|
psf._data = data
|
|
114
182
|
if normalize:
|
|
115
183
|
psf._data /= psf._data.sum()
|
|
116
|
-
psf.
|
|
117
|
-
psf.
|
|
184
|
+
psf._x = x
|
|
185
|
+
psf._y = y
|
|
118
186
|
psf._oversamp = oversample_factor
|
|
119
187
|
return psf
|
|
120
188
|
|
|
189
|
+
@property
|
|
190
|
+
def x( self ):
|
|
191
|
+
return self._x
|
|
192
|
+
|
|
193
|
+
@property
|
|
194
|
+
def y( self ):
|
|
195
|
+
return self._y
|
|
196
|
+
|
|
121
197
|
@property
|
|
122
198
|
def x0( self ):
|
|
123
199
|
return self._x0
|
|
@@ -135,21 +211,29 @@ class OversampledImagePSF( PSF ):
|
|
|
135
211
|
return self._data
|
|
136
212
|
|
|
137
213
|
@property
|
|
138
|
-
def
|
|
139
|
-
"""The size of the PSF image clip at image resolution."""
|
|
140
|
-
|
|
214
|
+
def stamp_size( self ):
|
|
215
|
+
"""The size of the PSF image clip at image resolution. Is always odd."""
|
|
216
|
+
sz = int( np.floor( self._data.shape[0] / self._oversamp ) )
|
|
217
|
+
sz += 1 if sz % 2 == 0 else 0
|
|
218
|
+
return sz
|
|
219
|
+
|
|
141
220
|
|
|
142
221
|
def __init__( self, *args, **kwargs ):
|
|
143
222
|
super().__init__( *args, **kwargs )
|
|
144
223
|
self._data = None
|
|
224
|
+
self._x = None
|
|
225
|
+
self._y = None
|
|
145
226
|
self._x0 = None
|
|
146
227
|
self._y0 = None
|
|
147
228
|
self._oversamp = None
|
|
148
229
|
|
|
149
|
-
def get_stamp( self, x=None, y=None,
|
|
150
|
-
|
|
151
|
-
|
|
230
|
+
def get_stamp( self, x=None, y=None, flux=1. ):
|
|
231
|
+
# (x, y) is the position on the image for which we want to render the PSF.
|
|
232
|
+
x = float(x) if x is not None else self._x
|
|
233
|
+
y = float(y) if y is not None else self._y
|
|
152
234
|
|
|
235
|
+
# (xc, yc) is the closest pixel center to (x, y) on the image--
|
|
236
|
+
#
|
|
153
237
|
# round() isn't the right thing to use here, because it will
|
|
154
238
|
# behave differently when x - round(x) = 0.5 based on whether
|
|
155
239
|
# floor(x) is even or odd. What we *want* is for the psf to
|
|
@@ -161,10 +245,22 @@ class OversampledImagePSF( PSF ):
|
|
|
161
245
|
# and to the left when the fractional part of x (and y) is
|
|
162
246
|
# exactly 0.5, whereas using round would give different
|
|
163
247
|
# results based on the integer part of x (and y).
|
|
164
|
-
|
|
165
248
|
xc = int( np.floor( x + 0.5 ) )
|
|
166
249
|
yc = int( np.floor( y + 0.5 ) )
|
|
167
250
|
|
|
251
|
+
# (natx, naty) is the "natural position" on the image for the
|
|
252
|
+
# psf. This is simply (int(x), int(y)) if the fractional part
|
|
253
|
+
# of x and y are zero. Otherwise, it rounds to the closest
|
|
254
|
+
# pixel... unless the fractional part is exactly 0.5, in which
|
|
255
|
+
# case we do floor(x+0.5) instead of round(x) as described above.
|
|
256
|
+
natx = int( np.floor( self._x + 0.5 ) )
|
|
257
|
+
naty = int( np.floor( self._y + 0.5 ) )
|
|
258
|
+
# natxfrac and natyfrac kinda the negative of the fractional
|
|
259
|
+
# part of natx and naty. They will be in the range (-0.5,
|
|
260
|
+
# 0.5]
|
|
261
|
+
natxfrac = natx - self._x
|
|
262
|
+
natyfrac = naty - self._y
|
|
263
|
+
|
|
168
264
|
# See Chapter 5, "How PSFEx Works", of the PSFEx manual
|
|
169
265
|
# https://psfex.readthedocs.io/en/latest/Working.html
|
|
170
266
|
# We're using this method for both image and psfex PSFs,
|
|
@@ -175,22 +271,23 @@ class OversampledImagePSF( PSF ):
|
|
|
175
271
|
|
|
176
272
|
psfwid = self._data.shape[0]
|
|
177
273
|
stampwid = self.clip_size
|
|
178
|
-
stampwid += 1 if stampwid % 2 == 0 else 0
|
|
179
274
|
|
|
180
275
|
psfdex1d = np.arange( -( psfwid//2), psfwid//2+1, dtype=int )
|
|
181
276
|
|
|
277
|
+
# If the returned clip is to be added to the image, it should
|
|
278
|
+
# be added to image[ymin:ymax, xmin:xmax].
|
|
182
279
|
xmin = xc - stampwid // 2
|
|
183
280
|
xmax = xc + stampwid // 2 + 1
|
|
184
281
|
ymin = yc - stampwid // 2
|
|
185
282
|
ymax = yc + stampwid // 2 + 1
|
|
186
283
|
|
|
187
284
|
psfsamp = 1. / self._oversamp
|
|
188
|
-
xs = np.
|
|
189
|
-
ys = np.
|
|
190
|
-
xsincarg = psfdex1d[:, np.newaxis] - ( xs - x ) / psfsamp
|
|
285
|
+
xs = np.arange( xmin, xmax )
|
|
286
|
+
ys = np.arange( ymin, ymax )
|
|
287
|
+
xsincarg = psfdex1d[:, np.newaxis] - ( xs - natxfrac - x ) / psfsamp
|
|
191
288
|
xsincvals = np.sinc( xsincarg ) * np.sinc( xsincarg/4. )
|
|
192
289
|
xsincvals[ ( xsincarg > 4 ) | ( xsincarg < -4 ) ] = 0.
|
|
193
|
-
ysincarg = psfdex1d[:, np.newaxis] - ( ys - y ) / psfsamp
|
|
290
|
+
ysincarg = psfdex1d[:, np.newaxis] - ( ys - natyfrac - y ) / psfsamp
|
|
194
291
|
ysincvals = np.sinc( ysincarg ) * np.sinc( ysincarg/4. )
|
|
195
292
|
ysincvals[ ( ysincarg > 4 ) | ( ysincarg < -4 ) ] = 0.
|
|
196
293
|
tenpro = np.tensordot( ysincvals[:, :, np.newaxis], xsincvals[:, :, np.newaxis], axes=0 )[ :, :, 0, :, :, 0 ]
|
|
@@ -216,8 +313,7 @@ class OversampledImagePSF( PSF ):
|
|
|
216
313
|
# * ysincvals[:, np.newaxis]
|
|
217
314
|
# * psfbase ).sum()
|
|
218
315
|
|
|
219
|
-
|
|
220
|
-
clip /= clip.sum()
|
|
316
|
+
clip *= flux / clip.sum()
|
|
221
317
|
|
|
222
318
|
return clip
|
|
223
319
|
|
|
@@ -229,15 +325,15 @@ class YamlSerialized_OversampledImagePSF( OversampledImagePSF ):
|
|
|
229
325
|
|
|
230
326
|
def read( self, filepath ):
|
|
231
327
|
y = yaml.safe_load( open( filepath ) )
|
|
232
|
-
self.
|
|
233
|
-
self.
|
|
328
|
+
self._x = y['x0']
|
|
329
|
+
self._y = y['y0']
|
|
234
330
|
self._oversamp = y['oversamp']
|
|
235
331
|
self._data = np.frombuffer( base64.b64decode( y['data'] ), dtype=y['dtype'] )
|
|
236
332
|
self._data = self._data.reshape( ( y['shape0'], y['shape1'] ) )
|
|
237
333
|
|
|
238
334
|
def write( self, filepath ):
|
|
239
|
-
out = { 'x0': float( self.
|
|
240
|
-
'y0': float( self.
|
|
335
|
+
out = { 'x0': float( self._x ),
|
|
336
|
+
'y0': float( self._y ),
|
|
241
337
|
'oversamp': self._oversamp,
|
|
242
338
|
'shape0': self._data.shape[0],
|
|
243
339
|
'shape1': self._data.shape[1],
|
|
@@ -247,6 +343,46 @@ class YamlSerialized_OversampledImagePSF( OversampledImagePSF ):
|
|
|
247
343
|
# TODO : check overwriting etc.
|
|
248
344
|
yaml.dump( out, open( filepath, 'w' ) )
|
|
249
345
|
|
|
346
|
+
class A25ePSF( YamlSerialized_OversampledImagePSF ):
|
|
347
|
+
|
|
348
|
+
def __init__( self, band, sca, x, y, *args, **kwargs ):
|
|
349
|
+
|
|
350
|
+
super().__init__( *args, **kwargs )
|
|
351
|
+
|
|
352
|
+
cfg = Config.get()
|
|
353
|
+
basepath = pathlib.Path( cfg.value( 'photometry.snappl.A25ePSF_path' ) )
|
|
354
|
+
|
|
355
|
+
"""
|
|
356
|
+
The array size is the size of one image (nx, ny).
|
|
357
|
+
The grid size is the number of times we divide that image
|
|
358
|
+
into smaller parts for the purposes of assigning the
|
|
359
|
+
correct ePSF (8 x 8 = 64 ePSFs).
|
|
360
|
+
|
|
361
|
+
4088 px/8 = 511 px. So, int(arr_size/gridsize) is just a type
|
|
362
|
+
conversion. In the future, we may have a class where these things
|
|
363
|
+
are variable, but for now, we are using only the 8 x 8 grid of
|
|
364
|
+
ePSFs from Aldoroty et al. 2025a. So, it's hardcoded.
|
|
365
|
+
|
|
366
|
+
"""
|
|
367
|
+
arr_size = 4088
|
|
368
|
+
gridsize = 8
|
|
369
|
+
cutoutsize = int(arr_size/gridsize)
|
|
370
|
+
grid_centers = np.linspace(0.5 * cutoutsize, arr_size - 0.5 * cutoutsize, gridsize)
|
|
371
|
+
|
|
372
|
+
dist_x = np.abs(grid_centers - x)
|
|
373
|
+
dist_y = np.abs(grid_centers - y)
|
|
374
|
+
|
|
375
|
+
x_idx = np.argmin(dist_x)
|
|
376
|
+
y_idx = np.argmin(dist_y)
|
|
377
|
+
|
|
378
|
+
x_cen = grid_centers[x_idx]
|
|
379
|
+
y_cen = grid_centers[y_idx]
|
|
380
|
+
|
|
381
|
+
min_mag = 19.0
|
|
382
|
+
max_mag = 21.5
|
|
383
|
+
psfpath = basepath / band / str(sca) / f'{cutoutsize}_{x_cen:.1f}_{y_cen:.1f}_-_{min_mag}_{max_mag}_-_{band}_{sca}.psf'
|
|
384
|
+
|
|
385
|
+
self.read(psfpath)
|
|
250
386
|
|
|
251
387
|
class ou24PSF( PSF ):
|
|
252
388
|
# Currently, does not support any oversampling, because SFFT doesn't
|
|
@@ -258,6 +394,10 @@ class ou24PSF( PSF ):
|
|
|
258
394
|
|
|
259
395
|
if ( pointing is None ) or ( sca is None ):
|
|
260
396
|
raise ValueError( "Need a pointing and an sca to make an ou24PSF" )
|
|
397
|
+
if ( size % 2 == 0 ) or ( int(size) != size ):
|
|
398
|
+
raise ValueError( "Size must be an odd integer." )
|
|
399
|
+
size = int( size )
|
|
400
|
+
|
|
261
401
|
if config_file is None:
|
|
262
402
|
config_file = Config.get().value( 'ou24psf.config_file' )
|
|
263
403
|
self.config_file = config_file
|
|
@@ -267,6 +407,12 @@ class ou24PSF( PSF ):
|
|
|
267
407
|
self.include_photonOps = include_photonOps
|
|
268
408
|
self._stamps = {}
|
|
269
409
|
|
|
410
|
+
|
|
411
|
+
@property
|
|
412
|
+
def stamp_size( self ):
|
|
413
|
+
return self.size
|
|
414
|
+
|
|
415
|
+
|
|
270
416
|
def get_stamp( self, x, y, flux=1., seed=None ):
|
|
271
417
|
"""Return a 2d numpy image of the PSF at the image resolution.
|
|
272
418
|
|
|
@@ -118,8 +118,9 @@ class AstropyWCS(BaseWCS):
|
|
|
118
118
|
dec = float( dec )
|
|
119
119
|
return ra, dec
|
|
120
120
|
|
|
121
|
-
def world_to_pixel( self, ra, dec
|
|
122
|
-
|
|
121
|
+
def world_to_pixel( self, ra, dec):
|
|
122
|
+
frame = self._wcs.wcs.radesys.lower() # Needs to be lowercase for SkyCoord
|
|
123
|
+
scs = SkyCoord( ra, dec, unit=(u.deg, u.deg), frame = frame)
|
|
123
124
|
x, y = self._wcs.world_to_pixel( scs )
|
|
124
125
|
if not ( isinstance( ra, collections.abc.Sequence )
|
|
125
126
|
or ( isinstance( ra, np.ndarray ) and y.size > 1 )
|
|
File without changes
|
|
File without changes
|
{roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
RENAMED
|
File without changes
|
{roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/workflows/run_snappl_tests.yml
RENAMED
|
File without changes
|
|
File without changes
|
{roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/.github/workflows/sub_package_update.yml
RENAMED
|
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
|
|
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
|
|
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
|
|
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
|
{roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/roman_snpit_snappl.egg-info/not-zip-safe
RENAMED
|
File without changes
|
{roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/roman_snpit_snappl.egg-info/requires.txt
RENAMED
|
File without changes
|
{roman_snpit_snappl-0.4.0 → roman_snpit_snappl-0.5.0}/roman_snpit_snappl.egg-info/top_level.txt
RENAMED
|
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
|