diff --git a/.gitignore b/.gitignore index bbbe536..0afd505 100644 --- a/.gitignore +++ b/.gitignore @@ -137,3 +137,4 @@ piff_package/* !piff_package/apodize.patch !piff_package/README.md !piff_package/Piff-1.3.3.tar.gz +!piff_package/LICENSE diff --git a/piff_package/LICENSE b/piff_package/LICENSE new file mode 100644 index 0000000..e37e374 --- /dev/null +++ b/piff_package/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2016 by Mike Jarvis and the other collaborators on GitHub at +https://github.com/rmjarvis/Piff All rights reserved. + +Piff is free software: Redistribution and use in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/piff_package/Piff-1.3.3.tar.gz b/piff_package/Piff-1.3.3.tar.gz new file mode 100644 index 0000000..3a1be01 Binary files /dev/null and b/piff_package/Piff-1.3.3.tar.gz differ diff --git a/piff_package/README.md b/piff_package/README.md new file mode 100644 index 0000000..1d335bf --- /dev/null +++ b/piff_package/README.md @@ -0,0 +1,5 @@ +# Piff for DES + +Piff has been vendored into eastlake in order to add apodization support to avoid square stamps. + +The code in this directory is unpacked and then installed as a package after the patch has been applied. diff --git a/piff_package/apodize.patch b/piff_package/apodize.patch new file mode 100644 index 0000000..7d7c89f --- /dev/null +++ b/piff_package/apodize.patch @@ -0,0 +1,88 @@ +diff --git a/piff/psf.py b/piff/psf.py +index fbb4ccd6..baf89d8d 100644 +--- a/piff/psf.py ++++ b/piff/psf.py +@@ -24,6 +24,24 @@ + from .star import Star, StarData + from .util import write_kwargs, read_kwargs + ++ ++def _ap_kern_kern(x, m, h): ++ # cumulative triweight kernel ++ y = (x - m) / h + 3 ++ apval = np.zeros_like(m) ++ msk = y > 3 ++ apval[msk] = 1 ++ msk = (y > -3) & (~msk) ++ apval[msk] = ( ++ -5 * y[msk] ** 7 / 69984 ++ + 7 * y[msk] ** 5 / 2592 ++ - 35 * y[msk] ** 3 / 864 ++ + 35 * y[msk] / 96 ++ + 1 / 2 ++ ) ++ return apval ++ ++ + class PSF(object): + """The base class for describing a PSF model across a field of view. + +@@ -442,7 +460,7 @@ def fit(self, stars, wcs, pointing, logger=None, convert_funcs=None, draw_method + logger.warning("PSF fit did not converge. Max iterations = %d reached.",self.max_iter) + + def draw(self, x, y, chipnum=None, flux=1.0, center=None, offset=None, stamp_size=48, +- image=None, logger=None, **kwargs): ++ image=None, logger=None, apodize=(1.0, 4.25), **kwargs): + r"""Draws an image of the PSF at a given location. + + The normal usage would be to specify (chipnum, x, y), in which case Piff will use the +@@ -504,6 +522,11 @@ def draw(self, x, y, chipnum=None, flux=1.0, center=None, offset=None, stamp_siz + [default: 48] + :param image: An existing image on which to draw, if desired. [default: None] + :param logger: A logger object for logging debug info. [default: None] ++ :param apodize: Optional parameter to set apodizatoon. If a float/int, gives the ++ number of half light radii after which the profile is smoothy apodized ++ to zero a width of ~2.55 half light radii. If a tuple/list, gives ++ the apodization width and the apodization radius in pixels. ++ [default: (1.0, 4.25), which means a width of 1 pixel and radius of 4.25 pixels.] + :param \**kwargs: Any additional properties required for the interpolation. + + :returns: A GalSim Image of the PSF +@@ -544,6 +567,37 @@ def draw(self, x, y, chipnum=None, flux=1.0, center=None, offset=None, stamp_siz + + prof.drawImage(image, method=method, center=center) + ++ if apodize: ++ xpix, ypix = image.get_pixel_centers() ++ dx = xpix - center[0] ++ dy = ypix - center[1] ++ r2 = dx**2 + dy**2 ++ ++ if isinstance(apodize, (tuple, list)): ++ apwidth, aprad = apodize ++ else: ++ wcs = image.wcs ++ try: ++ image.wcs = None ++ image.scale = 1.0 ++ hlr = image.calculateHLR(center=galsim.PositionD(center)) ++ finally: ++ image.wcs = wcs ++ aprad = apodize * hlr ++ msk_nonzero = image.array != 0 ++ max_r = min( ++ np.abs(dx[(dx < 0) & msk_nonzero].min()), ++ np.abs(dx[(dx > 0) & msk_nonzero].max()), ++ np.abs(dy[(dy < 0) & msk_nonzero].min()), ++ np.abs(dy[(dy > 0) & msk_nonzero].max()), ++ ) ++ apwidth = np.abs(hlr) / 2.355 ++ apwidth = min(max(apwidth, 0.5), 5.0) ++ aprad = max(min(aprad, max_r - 6 * apwidth - 1), 2 * apwidth) ++ ++ apim = image._array * _ap_kern_kern(aprad, np.sqrt(r2), apwidth) ++ image._array = apim / np.sum(apim) * np.sum(image._array) ++ + return image + + def get_profile(self, x, y, chipnum=None, flux=1.0, logger=None, **kwargs): diff --git a/setup.py b/setup.py index 3e040ad..a9f2c9c 100644 --- a/setup.py +++ b/setup.py @@ -181,6 +181,30 @@ def run(self): _build_src_ext() super().run() +# unpack and patch Piff +for fname in os.listdir("piff_package"): + if fname not in ["Piff-1.3.3.tar.gz", "apodize.patch", "README.md"]: + subprocess.run( + ["rm", "-rf", fname], + check=True, + cwd="piff_package", + ) + +subprocess.run( + ["tar", "--strip-components=1", "-xzvf", "Piff-1.3.3.tar.gz"], + check=True, + cwd="piff_package", +) +subprocess.run( + ["patch", "-p1", "-i", "apodize.patch"], + check=True, + cwd="piff_package", +) +subprocess.run( + ["rm", "-f", "piff/psf.py.orig"], + check=True, + cwd="piff_package", +) scripts = glob.glob('./bin/*') scripts = [os.path.basename(f) for f in scripts if f[-1] != '~']