From 9655277f34db5c7bbaf640ae4d56b6a46f8fe244 Mon Sep 17 00:00:00 2001 From: Jeff Jennings Date: Tue, 31 Oct 2023 19:30:26 -0400 Subject: [PATCH 1/5] add utility function to center a numpy image --- src/mpol/utils.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/mpol/utils.py b/src/mpol/utils.py index ac8ced23..c8806bdb 100644 --- a/src/mpol/utils.py +++ b/src/mpol/utils.py @@ -10,6 +10,30 @@ def torch2npy(tensor): return tensor.detach().cpu().numpy() +def center_np_image(image): + """Wrap a numpy image array so that the 0 index is in the image center. + Adapted from frank.utilities.make_image (https://github.com/discsim/frank) + + Parameters + ---------- + image : 2D array + The numpy image with index 0 in the corner + + Returns + ------- + image_wrapped : 2D array + The numpy image with index 0 in the center + """ + tmp, image_wrapped = image.copy(), image.copy() + + Nx, Ny = tmp.shape[0], tmp.shape[1] + + tmp[:Nx//2,], tmp[Nx//2:] = image[Nx//2:], image[:Nx//2] + image_wrapped[:, :Ny//2], image_wrapped[:, Ny//2:] = tmp[:, Ny//2:], tmp[:, :Ny//2] + + return image_wrapped + + def ground_cube_to_packed_cube(ground_cube): r""" Converts a Ground Cube to a Packed Visibility Cube for visibility-plane work. See Units and Conventions for more details. From 062e2f19f4dcef8853e1317703e056ce20a31186 Mon Sep 17 00:00:00 2001 From: Jeff Jennings Date: Tue, 31 Oct 2023 19:30:50 -0400 Subject: [PATCH 2/5] add utility function to convert np to ImageCube --- src/mpol/utils.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/mpol/utils.py b/src/mpol/utils.py index c8806bdb..8ecc2df1 100644 --- a/src/mpol/utils.py +++ b/src/mpol/utils.py @@ -5,6 +5,8 @@ from .constants import arcsec, c_ms, cc, deg, kB +from mpol.images import ImageCube + def torch2npy(tensor): """Make a copy of a PyTorch tensor on the CPU in numpy format, e.g. for plotting""" return tensor.detach().cpu().numpy() @@ -34,6 +36,42 @@ def center_np_image(image): return image_wrapped +def np_to_imagecube(image, coords, nchan=1, wrap=False): + """Convenience function for converting a numpy image into an MPoL ImageCube + tensor (see mpol.images.ImageCube) + + Parameters + ---------- + image : array + An image in numpy format + coords : `mpol.coordinates.GridCoords` object + Instance of the `mpol.coordinates.GridCoords` class + nchan : int, default=1 + Number of channels in the image. Default assumes a single 2D image + wrap : bool, default=False + Whether to wrap the numpy image so that index 0 is in the image center + (FFT algorithms typically place index 0 in the image corner) + + Returns + ------- + icube : `mpol.images.ImageCube` object + The image cube tensor + """ + if wrap: + # move the 0 index to the image center + image = center_np_image(image) + + # broadcast image to (nchan, npix, npix) + img_packed_cube = np.broadcast_to(image, + (nchan, coords.npix, coords.npix)).copy() + + # convert to pytorch tensor + img_packed_tensor = torch.from_numpy(img_packed_cube) + + # insert into ImageCube layer + return ImageCube(coords=coords, nchan=nchan, cube=img_packed_tensor) + + def ground_cube_to_packed_cube(ground_cube): r""" Converts a Ground Cube to a Packed Visibility Cube for visibility-plane work. See Units and Conventions for more details. From 1b76a3242a8306e9ed65eb821dabd3801c62da93 Mon Sep 17 00:00:00 2001 From: Jeff Jennings Date: Tue, 31 Oct 2023 19:44:29 -0400 Subject: [PATCH 3/5] move np to ImageCube out of utils --- src/mpol/utils.py | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/src/mpol/utils.py b/src/mpol/utils.py index 8ecc2df1..c8806bdb 100644 --- a/src/mpol/utils.py +++ b/src/mpol/utils.py @@ -5,8 +5,6 @@ from .constants import arcsec, c_ms, cc, deg, kB -from mpol.images import ImageCube - def torch2npy(tensor): """Make a copy of a PyTorch tensor on the CPU in numpy format, e.g. for plotting""" return tensor.detach().cpu().numpy() @@ -36,42 +34,6 @@ def center_np_image(image): return image_wrapped -def np_to_imagecube(image, coords, nchan=1, wrap=False): - """Convenience function for converting a numpy image into an MPoL ImageCube - tensor (see mpol.images.ImageCube) - - Parameters - ---------- - image : array - An image in numpy format - coords : `mpol.coordinates.GridCoords` object - Instance of the `mpol.coordinates.GridCoords` class - nchan : int, default=1 - Number of channels in the image. Default assumes a single 2D image - wrap : bool, default=False - Whether to wrap the numpy image so that index 0 is in the image center - (FFT algorithms typically place index 0 in the image corner) - - Returns - ------- - icube : `mpol.images.ImageCube` object - The image cube tensor - """ - if wrap: - # move the 0 index to the image center - image = center_np_image(image) - - # broadcast image to (nchan, npix, npix) - img_packed_cube = np.broadcast_to(image, - (nchan, coords.npix, coords.npix)).copy() - - # convert to pytorch tensor - img_packed_tensor = torch.from_numpy(img_packed_cube) - - # insert into ImageCube layer - return ImageCube(coords=coords, nchan=nchan, cube=img_packed_tensor) - - def ground_cube_to_packed_cube(ground_cube): r""" Converts a Ground Cube to a Packed Visibility Cube for visibility-plane work. See Units and Conventions for more details. From efa68077b385f23c80e2785f3ed1eb6570e58842 Mon Sep 17 00:00:00 2001 From: Jeff Jennings Date: Tue, 31 Oct 2023 19:46:28 -0400 Subject: [PATCH 4/5] Move np to ImageCube into images.py --- src/mpol/images.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/mpol/images.py b/src/mpol/images.py index 0185766e..9dae120c 100644 --- a/src/mpol/images.py +++ b/src/mpol/images.py @@ -316,3 +316,39 @@ def to_FITS(self, fname="cube.fits", overwrite=False, header_kwargs=None): hdul.writeto(fname, overwrite=overwrite) hdul.close() + + +def np_to_imagecube(image, coords, nchan=1, wrap=False): + """Convenience function for converting a numpy image into an MPoL ImageCube + tensor (see mpol.images.ImageCube) + + Parameters + ---------- + image : array + An image in numpy format + coords : `mpol.coordinates.GridCoords` object + Instance of the `mpol.coordinates.GridCoords` class + nchan : int, default=1 + Number of channels in the image. Default assumes a single 2D image + wrap : bool, default=False + Whether to wrap the numpy image so that index 0 is in the image center + (FFT algorithms typically place index 0 in the image corner) + + Returns + ------- + icube : `mpol.images.ImageCube` object + The image cube tensor + """ + if wrap: + # move the 0 index to the image center + image = center_np_image(image) + + # broadcast image to (nchan, npix, npix) + img_packed_cube = np.broadcast_to(image, + (nchan, coords.npix, coords.npix)).copy() + + # convert to pytorch tensor + img_packed_tensor = torch.from_numpy(img_packed_cube) + + # insert into ImageCube layer + return ImageCube(coords=coords, nchan=nchan, cube=img_packed_tensor) From ec422f659a68ea4cf18c567487f1be2929782274 Mon Sep 17 00:00:00 2001 From: Jeff Jennings Date: Tue, 31 Oct 2023 19:47:45 -0400 Subject: [PATCH 5/5] np__to_imagecube: add import --- src/mpol/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mpol/images.py b/src/mpol/images.py index 9dae120c..b0f9b2dc 100644 --- a/src/mpol/images.py +++ b/src/mpol/images.py @@ -341,7 +341,7 @@ def np_to_imagecube(image, coords, nchan=1, wrap=False): """ if wrap: # move the 0 index to the image center - image = center_np_image(image) + image = utils.center_np_image(image) # broadcast image to (nchan, npix, npix) img_packed_cube = np.broadcast_to(image,