photutilsImagePSF¶
- class snappl.psf.photutilsImagePSF(peakx=None, peaky=None, oversample_factor=1, data=None, enforce_odd=True, normalize=False, _parent_class=False, **kwargs)[source]¶
Bases:
PSFWraps a photutils.psf.ImagePSF. Sort of.
Create a photutilsImagePSF.
WARNING: x and y have a different meaning from OversampledImagePSF constructor in the case where they have non-zero fractional parts! TODO: fix this…. but then also fix any code that depends on that behavior.
WARNING: If you do get_stamp() for one of these PSFs, if your PSF is intrinsically undersampled on the image, the PSF you get back will probably not be properly normalized! This is the PSF you want to use with photutils photometry (I THINK… VERIFY THIS), but it’s NOT the PSF that you want to use for things like scene modelling. For scene modelling, use OversampledImagePSF, which convoles before downsampling.
See Issue #157.
Parmaeters¶
- data2d numpy array; required
The oversampled PSF. data.sum() should be equal to the fraction of the PSF flux captured within the boundarys of the data array. (However, see “normalize” below.) The data array must be square, and (unless enforced_odd is false) must have an odd side length.
The peak* of the PSF in the passed data array must be at position (peakx,peaky) in pixel coordinates of the passed data array. If you leave those at default (None), then the PSF must be perfectly centered on the passed data array. (For an odd side-length, which is normal, that means the center of the PSF is at the center of the center pixel.)
For “peak” vs. “center” vs. “fiducial point”, see the caveats in the PSF.get_stamp docstring.
- oversample_factor: integer
Must be an integer for photutilsImagePSF. There are this many pixels along one axis in the past data array in one pixel on the original image that the PSF is for.
- peakx, peaky: float, float
The position in oversampled pixel coordinates on the data array where the peak is found. If these values are not, then we assume the peak is at (data.shape[1]//2, data.shape[0]//2) (i.e. the center of the center pixel). (If you pass an even-length data array, and there is no “center pixel”, then expect everything to go wrong and the world to end.) See (x, y) below for some examples of passing peakx and peaky.
The safest thing to do is to leave peakx and peaky at their defaults of None and make sure that the PSF is centered on the passed data array.
- x, yfloat, float
Position on the original source image (i.e. the astronomical image for which this object is the PSF) that corresponds to the center of the data array.
WARNING: this is not the same as the x and y parameters given to the OversampledImagePSF constructor! If the PSF is centered, and x and y have a zero fractional part, then the numbers will be the same for both classes. But, for an off-center PSF, the numbers will be different in the two cases! Use intrinsically off-center PSFs at your own peril. (Note that you can always render stamps with off-centered PSFs in get_stamp(), regardless of whether the PSF itself is intrinsically centered or not.) (TODO: figure out why this is different and fix that.)
Usually you want x and y to have no fractional part, you want peakx and peaky to be None, and you want the oversampled PSF to be centered on the passed data array.
data must be consistent with these numbers. Supposed you have an 11×11 PSF oversampled by a factor of 3 that is centered on the original image at 1023, 511. In this case, the data array should be 33×33 in size (11 times 3). If the PSF is centered on the data array (i.e. on the center of pixel (16,16)), then you would pass x=1023, y=511.
If your PSF is centered on the original image at 1023.5, 511.5, but you pass x=1023, y=511, that means that the PSF needs to be shifted half a pixel to the right and up on the (non-oversampled) stamp, or 1.5 pixels right and up on the oversampled data array. The peak of the PSF on the passed data array should be at (17.5,17.5), and you must pass peakx=17.5 and peaky=17.5
If your PSF is centered on the original image at 1023., 511., but for some reason you pass x=1020, y=512, that means that the center of the data array is three (non-oversampled) pixels to the left and one (non-oversampled) pixel above the peak of the PSF, or 9 oversampled left and 3 oversampled above. In this case, the passed data array should have its peak (assuming a symmetric PSF) at the center of pixel (13,17), and you must pass peakx=13 and peaky=17.
CHECK THESE NUMBERS IN THESE EXAMPLES TO VERIFY I DID IT RIGHT.
- enforce_odd: bool, default True
Scream and yell if data doesn’t have odd side-lengths. You probably do not want to set this to False.
- normalize: bool, default False
If this is True, then the constructor will divide data by data.sum() (WARNING: which modifies the passed array!). Do this if you are very confident that, for your purposes, close enough to 100% of the PSF flux falls within the boundaries of the passed data array. Better, ensure that the sum of the passed data array equals the fraction of the PSF flux that falls within its boundaries, and leave normalize to False.
- _parent_class: bool, default False
Used internally, do not use.
Attributes Summary
The size of the PSF image stamp at image resolution.
Methods Summary
getImagePSF([imagesampled])Return a photutils.psf.ImagePSF model.
get_stamp([x, y, x0, y0, flux])See PSF.get_stamp for documentation.
Attributes Documentation
- oversample_factor¶
- oversampled_data¶
- stamp_size¶
The size of the PSF image stamp at image resolution. Is always odd.
Methods Documentation
- get_stamp(x=None, y=None, x0=None, y0=None, flux=1.0)[source]¶
See PSF.get_stamp for documentation.
–> CURRENTLY BROKEN FOR UNDERSAMPLED PSFs. See Issue #30.
Everything below is implementation notes, which can be ignored by people just using the class, but which will be useful for people reading the source code.
photutils has a somewhat different way of thinking about PSF positioning on stamps than we do in OversampledImagePSF. When you make an OversampledImagePSF, you give it the x and y on the original image where you evaluated the original PSF, and you give it an image with the PSF centered on the passed data array (or, within 0.5*oversampling_factor pixels of the center of the passed data array if the fractional parts of x and/or y are not 0).
In contrast, when you make a photutils ImagePSF, you pass it the x and y that correspond to the center pixel of the passed array.
IF x and y have no fraction part, AND the PSF is centered on the passed data array, then you would pass the same values of x and y when constructing an OversampledImagePSF and a photutilsImagePSF. Hopefully, this is the most common case, so confusion will be kept to a minimim.
However, when that’s not true, we have to make sure we interpret all the variables right when rendering a photUtilsImagePSF.
According to the PSF.get_stamp documentation, if x0 and y0 are None, then you will always get a stamp with a PSF centered within 0.5 pixels of the center of the stamp; it will be offset from the center of the stamp by the fractional part of x and y. This means we can’t just blithely pass the x and y passed to get_stamp on to the photutils.ImagePSF evaluator to get the PSF stamp, but have to do some arithmetic on it to make sure we’ll get back what PSF.get_stamp promises.
If x0 and y0 are passed to get_stamp here, then that is the position on the center of the original array that corresponds to the center of the returned stamp. The peak of the PSF on the returned stamp needs to be at (x-x0,y-y0).