Skip to content

Commit 38676d6

Browse files
committed
feat: add latest patch
1 parent bd7d9ce commit 38676d6

File tree

1 file changed

+42
-235
lines changed

1 file changed

+42
-235
lines changed

piff_package/apodize.patch

Lines changed: 42 additions & 235 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,20 @@ index 4f4c623a..c1ba101f 100644
55
@@ -12,5 +12,5 @@
66
# this list of conditions and the disclaimer given in the documentation
77
# and/or other materials provided with the distribution.
8-
8+
99
-__version__ = '1.3.3'
1010
+__version__ = '1.3.3.1'
1111
__version_info__ = tuple(map(int, __version__.split('.')))
12-
diff --git a/piff/psf.py b/piff/psf.py
13-
index f1b526d5..d1a2d9ef 100644
14-
--- a/piff/psf.py
15-
+++ b/piff/psf.py
16-
@@ -24,6 +24,24 @@
17-
from .star import Star, StarData
18-
from .util import write_kwargs, read_kwargs
19-
12+
diff --git a/piff/pixelgrid.py b/piff/pixelgrid.py
13+
index 4d113c77..0c10bb8c 100644
14+
--- a/piff/pixelgrid.py
15+
+++ b/piff/pixelgrid.py
16+
@@ -25,6 +25,26 @@
17+
from .model import Model
18+
from .star import Star, StarData, StarFit
19+
20+
+APODIZE_PARAMS = (1.0 * 0.263, 4.25 * 0.263)
21+
+
2022
+
2123
+def _ap_kern_kern(x, m, h):
2224
+ # cumulative triweight kernel
@@ -35,68 +37,31 @@ index f1b526d5..d1a2d9ef 100644
3537
+ return apval
3638
+
3739
+
38-
class PSF(object):
39-
"""The base class for describing a PSF model across a field of view.
40-
41-
@@ -99,7 +117,7 @@ def parseKwargs(cls, config_psf, logger=None):
42-
raise NotImplementedError("Derived classes must define the parseKwargs function")
43-
44-
def draw(self, x, y, chipnum=None, flux=1.0, center=None, offset=None, stamp_size=48,
45-
- image=None, logger=None, **kwargs):
46-
+ image=None, logger=None, apodize=(1.0, 4.25), **kwargs):
47-
r"""Draws an image of the PSF at a given location.
48-
49-
The normal usage would be to specify (chipnum, x, y), in which case Piff will use the
50-
@@ -161,6 +179,11 @@ def draw(self, x, y, chipnum=None, flux=1.0, center=None, offset=None, stamp_siz
51-
[default: 48]
52-
:param image: An existing image on which to draw, if desired. [default: None]
53-
:param logger: A logger object for logging debug info. [default: None]
54-
+ :param apodize: Optional parameter to set apodizatoon. If a float/int, gives the
55-
+ number of half light radii after which the profile is smoothy apodized
56-
+ to zero a width of ~2.55 half light radii. If a tuple/list, gives
57-
+ the apodization width and the apodization radius in pixels.
58-
+ [default: (1.0, 4.25), which means a width of 1 pixel and radius of 4.25 pixels.]
59-
:param \**kwargs: Any additional properties required for the interpolation.
60-
61-
:returns: A GalSim Image of the PSF
62-
@@ -201,6 +224,37 @@ def draw(self, x, y, chipnum=None, flux=1.0, center=None, offset=None, stamp_siz
63-
64-
prof.drawImage(image, method=method, center=center)
65-
66-
+ if apodize:
67-
+ xpix, ypix = image.get_pixel_centers()
68-
+ dx = xpix - center[0]
69-
+ dy = ypix - center[1]
40+
class PixelGrid(Model):
41+
"""A PSF modeled as interpolation between a grid of points.
42+
43+
@@ -445,6 +465,21 @@ def getProfile(self, params):
44+
:returns: a galsim.GSObject instance
45+
"""
46+
im = galsim.Image(params.reshape(self.size,self.size), scale=self.scale)
47+
+
48+
+ if APODIZE_PARAMS is not None:
49+
+ xpix, ypix = im.get_pixel_centers()
50+
+ # use_true_center = False below
51+
+ dx = xpix - im.center.x
52+
+ dy = ypix - im.center.y
7053
+ r2 = dx**2 + dy**2
7154
+
72-
+ if isinstance(apodize, (tuple, list)):
73-
+ apwidth, aprad = apodize
74-
+ else:
75-
+ wcs = image.wcs
76-
+ try:
77-
+ image.wcs = None
78-
+ image.scale = 1.0
79-
+ hlr = image.calculateHLR(center=galsim.PositionD(center))
80-
+ finally:
81-
+ image.wcs = wcs
82-
+ aprad = apodize * hlr
83-
+ msk_nonzero = image.array != 0
84-
+ max_r = min(
85-
+ np.abs(dx[(dx < 0) & msk_nonzero].min()),
86-
+ np.abs(dx[(dx > 0) & msk_nonzero].max()),
87-
+ np.abs(dy[(dy < 0) & msk_nonzero].min()),
88-
+ np.abs(dy[(dy > 0) & msk_nonzero].max()),
89-
+ )
90-
+ apwidth = np.abs(hlr) / 2.355
91-
+ apwidth = min(max(apwidth, 0.5), 5.0)
92-
+ aprad = max(min(aprad, max_r - 6 * apwidth - 1), 2 * apwidth)
55+
+ apwidth, aprad = APODIZE_PARAMS # in arcsec
56+
+ _apwidth = apwidth / self.scale # convert to pixels
57+
+ _aprad = aprad / self.scale # convert to pixels
9358
+
94-
+ apim = image._array * _ap_kern_kern(aprad, np.sqrt(r2), apwidth)
95-
+ image._array = apim / np.sum(apim) * np.sum(image._array)
59+
+ apim = im._array * _ap_kern_kern(_aprad, np.sqrt(r2), _apwidth)
60+
+ im._array = apim / np.sum(apim) * np.sum(im._array)
9661
+
97-
return image
98-
99-
def get_profile(self, x, y, chipnum=None, flux=1.0, logger=None, **kwargs):
62+
return galsim.InterpolatedImage(im, x_interpolant=self.interp,
63+
use_true_center=False, flux=1.)
64+
10065
diff --git a/requirements.txt b/requirements.txt
10166
index d03b7b19..cfd6693b 100644
10267
--- a/requirements.txt
@@ -114,171 +79,13 @@ index d03b7b19..cfd6693b 100644
11479
+galsim>=2.3,<2.5
11580
treegp>=0.6
11681
threadpoolctl>=3.1
117-
diff --git a/tests/test_pixel.py b/tests/test_pixel.py
118-
index 2cd33e73..d0b4fc22 100644
119-
--- a/tests/test_pixel.py
120-
+++ b/tests/test_pixel.py
121-
@@ -1531,7 +1531,7 @@ def test_color():
122-
# Check the convenience function that an end user would typically use
123-
offset = s.center_to_offset(s.fit.center)
124-
image = psf.draw(x=s['x'], y=s['y'], color=s['color'],
125-
- stamp_size=32, flux=s.fit.flux, offset=offset)
126-
+ stamp_size=32, flux=s.fit.flux, offset=offset, apodize=None)
127-
# They may be up to 1 pixel off in either direction, so find the common bounds.
128-
b = image.bounds & fit_stamp.bounds
129-
np.testing.assert_allclose(image[b].array, fit_stamp[b].array, rtol=1.e-6, atol=1.e-4)
130-
diff --git a/tests/test_simple.py b/tests/test_simple.py
131-
index 57e23910..51c85be8 100644
132-
--- a/tests/test_simple.py
133-
+++ b/tests/test_simple.py
134-
@@ -309,12 +309,12 @@ def test_single_image():
135-
136-
# test that draw works
137-
test_image = psf.draw(x=target['x'], y=target['y'], stamp_size=config['input']['stamp_size'],
138-
- flux=target.fit.flux, offset=target.fit.center)
139-
+ flux=target.fit.flux, offset=target.fit.center, apodize=None)
140-
# this image should be the same values as test_star
141-
assert test_image == test_star.image
142-
# test that draw does not copy the image
143-
image_ref = psf.draw(x=target['x'], y=target['y'], stamp_size=config['input']['stamp_size'],
144-
- flux=target.fit.flux, offset=target.fit.center, image=test_image)
145-
+ flux=target.fit.flux, offset=target.fit.center, image=test_image, apodize=None)
146-
image_ref.array[0,0] = 123456789
147-
assert test_image.array[0,0] == image_ref.array[0,0]
148-
assert test_star.image.array[0,0] != test_image.array[0,0]
149-
@@ -743,7 +743,7 @@ def test_draw():
150-
151-
# Now use the regular PSF.draw() command. This version is equivalent to the above.
152-
# (It's not equal all the way to machine precision, but pretty close.)
153-
- im1 = psf.draw(x, y, chipnum, stamp_size=48)
154-
+ im1 = psf.draw(x, y, chipnum, stamp_size=48, apodize=None)
155-
np.testing.assert_allclose(im1.array, star.data.image.array, rtol=1.e-14, atol=1.e-14)
156-
157-
# The wcs in the image is the wcs of the original image
158-
@@ -768,13 +768,13 @@ def test_draw():
159-
# We can center the star at an arbitrary location on the image.
160-
# The default is equivalent to center=(x,y). So check that this is equivalent.
161-
# Also, 48 is the default stamp size, so that can be omitted here.
162-
- im2 = psf.draw(x, y, chipnum, center=(x,y))
163-
+ im2 = psf.draw(x, y, chipnum, center=(x,y), apodize=None)
164-
assert im2.bounds == im1.bounds
165-
np.testing.assert_allclose(im2.array, im1.array, rtol=1.e-14, atol=1.e-14)
166-
167-
# Moving by an integer number of pixels should be very close to the same image
168-
# over a different slice of the array.
169-
- im3 = psf.draw(x, y, chipnum, center=(x+1, y+3))
170-
+ im3 = psf.draw(x, y, chipnum, center=(x+1, y+3), apodize=None)
171-
assert im3.bounds == im1.bounds
172-
# (Remember -- numpy indexing is y,x!)
173-
# Also, the FFTs will be different in detail, so only match to 1.e-6.
174-
@@ -788,14 +788,14 @@ def test_draw():
175-
# Can center at other locations, and the hsm centroids should come out centered pretty
176-
# close to that location.
177-
# (Of course the array will be different here, so can't test that.)
178-
- im4 = psf.draw(x, y, chipnum, center=(x+1.3,y-0.8))
179-
+ im4 = psf.draw(x, y, chipnum, center=(x+1.3,y-0.8), apodize=None)
180-
assert im4.bounds == im1.bounds
181-
hsm = im4.FindAdaptiveMom()
182-
np.testing.assert_allclose(hsm.moments_centroid.x, x+1.3, atol=0.01)
183-
np.testing.assert_allclose(hsm.moments_centroid.y, y-0.8, atol=0.01)
184-
185-
# Also allowed is center=True to place in the center of the image.
186-
- im5 = psf.draw(x, y, chipnum, center=True)
187-
+ im5 = psf.draw(x, y, chipnum, center=True, apodize=None)
188-
assert im5.bounds == im1.bounds
189-
assert im5.array.shape == (48,48)
190-
np.testing.assert_allclose(im5.bounds.true_center.x, x, atol=0.5)
191-
@@ -814,7 +814,7 @@ def test_draw():
192-
# then center=True works fine to draw in the center of that image.
193-
im6 = im5.copy()
194-
im6.setCenter(0,0)
195-
- psf.draw(x, y, chipnum, center=True, image=im6)
196-
+ psf.draw(x, y, chipnum, center=True, image=im6, apodize=None)
197-
assert im6.bounds.center == galsim.PositionI(0,0)
198-
np.testing.assert_allclose(im6.array.sum(), 1., rtol=1.e-3)
199-
hsm = im6.FindAdaptiveMom()
200-
@@ -824,7 +824,7 @@ def test_draw():
201-
np.testing.assert_allclose(im6.array, im5.array, rtol=1.e-14, atol=1.e-14)
202-
203-
# Check non-even stamp size. Also, not unit flux while we're at it.
204-
- im7 = psf.draw(x, y, chipnum, center=(x+1.3,y-0.8), stamp_size=43, flux=23.7)
205-
+ im7 = psf.draw(x, y, chipnum, center=(x+1.3,y-0.8), stamp_size=43, flux=23.7, apodize=None)
206-
assert im7.array.shape == (43,43)
207-
np.testing.assert_allclose(im7.bounds.true_center.x, x, atol=0.5)
208-
np.testing.assert_allclose(im7.bounds.true_center.y, y, atol=0.5)
209-
@@ -836,7 +836,7 @@ def test_draw():
210-
# Can't do mixed even/odd shape with stamp_size, but it will respect a provided image.
211-
im8 = galsim.Image(43,44)
212-
im8.setCenter(x,y) # It will respect the given bounds, so put it near the right place.
213-
- psf.draw(x, y, chipnum, center=(x+1.3,y-0.8), image=im8, flux=23.7)
214-
+ psf.draw(x, y, chipnum, center=(x+1.3,y-0.8), image=im8, flux=23.7, apodize=None)
215-
assert im8.array.shape == (44,43)
216-
np.testing.assert_allclose(im8.array.sum(), 23.7, rtol=1.e-3)
217-
hsm = im8.FindAdaptiveMom()
218-
@@ -845,7 +845,7 @@ def test_draw():
219-
220-
# The offset parameter can add an additional to whatever center is used.
221-
# Here center=None, so this is equivalent to im4 above.
222-
- im9 = psf.draw(x, y, chipnum, offset=(1.3,-0.8))
223-
+ im9 = psf.draw(x, y, chipnum, offset=(1.3,-0.8), apodize=None)
224-
assert im9.bounds == im1.bounds
225-
hsm = im9.FindAdaptiveMom()
226-
np.testing.assert_allclose(im9.array, im4.array, rtol=1.e-14, atol=1.e-14)
227-
@@ -854,7 +854,7 @@ def test_draw():
228-
# use for this, but it's allowed. (The above with default center is used in unit
229-
# tests a number of times, so that version at least is useful if only for us.
230-
# I'm hard pressed to imaging end users wanting to specify things this way though.)
231-
- im10 = psf.draw(x, y, chipnum, center=(x+0.8, y-0.3), offset=(0.5,-0.5))
232-
+ im10 = psf.draw(x, y, chipnum, center=(x+0.8, y-0.3), offset=(0.5,-0.5), apodize=None)
233-
assert im10.bounds == im1.bounds
234-
np.testing.assert_allclose(im10.array, im4.array, rtol=1.e-14, atol=1.e-14)
235-
236-
diff --git a/tests/test_wcs.py b/tests/test_wcs.py
237-
index 2a373671..eaed388e 100644
238-
--- a/tests/test_wcs.py
239-
+++ b/tests/test_wcs.py
240-
@@ -366,7 +366,7 @@ def test_single():
241-
242-
# This is the more user-friendly way to do this.
243-
# Equivalent to ~machine precision.
244-
- im = psf.draw(x, y, chipnum=chipnum)
245-
+ im = psf.draw(x, y, chipnum=chipnum, apodize=None)
246-
print('im = ',im)
247-
print('star im = ',star.data.image)
248-
print('max diff = ',np.max(np.abs(im.array - star.data.image.array)))
249-
@@ -612,7 +612,7 @@ def test_olddes():
250-
print('area at 0,0 = ',psf.wcs[0].pixelArea(galsim.PositionD(0,0)),' = %f**2'%(
251-
psf.wcs[0].pixelArea(galsim.PositionD(0,0))**0.5))
252-
assert np.isclose(psf.wcs[0].pixelArea(galsim.PositionD(0,0)), 0.2628**2, rtol=1.e-3)
253-
- image = psf.draw(x=103.3, y=592.0, logger=logger)
254-
+ image = psf.draw(x=103.3, y=592.0, logger=logger, apodize=None)
255-
print('image shape = ',image.array.shape)
256-
print('image near center = ',image.array[23:26,23:26])
257-
print('image sum = ',image.array.sum())
258-
@@ -628,7 +628,7 @@ def test_olddes():
259-
260-
# Also check that it is picklable.
261-
psf2 = copy.deepcopy(psf)
262-
- image2 = psf2.draw(x=103.3, y=592.0)
263-
+ image2 = psf2.draw(x=103.3, y=592.0, apodize=None)
264-
np.testing.assert_equal(image2.array, image.array)
265-
266-
@timer
267-
@@ -668,7 +668,7 @@ def test_newdes():
268-
print('area at 0,0 = ',psf.wcs[0].pixelArea(galsim.PositionD(0,0)),' = %f**2'%(
269-
psf.wcs[0].pixelArea(galsim.PositionD(0,0))**0.5))
270-
assert np.isclose(psf.wcs[0].pixelArea(galsim.PositionD(0,0)), 0.263021**2, rtol=1.e-3)
271-
- image = psf.draw(x=103.3, y=592.0, logger=logger)
272-
+ image = psf.draw(x=103.3, y=592.0, logger=logger, apodize=None)
273-
print('image shape = ',image.array.shape)
274-
print('image near center = ',image.array[23:26,23:26])
275-
print('image sum = ',image.array.sum())
276-
@@ -684,7 +684,7 @@ def test_newdes():
277-
278-
# Also check that it is picklable.
279-
psf2 = copy.deepcopy(psf)
280-
- image2 = psf2.draw(x=103.3, y=592.0)
281-
+ image2 = psf2.draw(x=103.3, y=592.0, apodize=None)
282-
np.testing.assert_equal(image2.array, image.array)
283-
284-
@timer
82+
diff --git a/tests/conftest.py b/tests/conftest.py
83+
new file mode 100644
84+
index 00000000..079d67ae
85+
--- /dev/null
86+
+++ b/tests/conftest.py
87+
@@ -0,0 +1,4 @@
88+
+# turn off apodization
89+
+import piff.pixelgrid
90+
+
91+
+piff.pixelgrid.APODIZE_PARAMS = None

0 commit comments

Comments
 (0)