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.
getPhotutilsPSF([x, y, imagesampled])Return a photutils.psf.SOMETHING that can be the psf_model parameter of photutils.psf.PSFPhotometry
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
- getPhotutilsPSF(x=None, y=None, imagesampled=True)[source]¶
Return a photutils.psf.SOMETHING that can be the psf_model parameter of photutils.psf.PSFPhotometry
You really only want to use the result of this for feeding to photutils. If what you want is an image of the PSF, use get_stamp() instead.
Unless the subclass implementes something else, this will be a photutils.psf.ImagePSF, and will be just for one position. If you don’t give x and y here, it will use the x and y that were given to construct the PSF object.
Some subclasses will ignore x, y and return a Photutils PSF object that can be used at any x, y. Read the subclass documentation to find out what is what. If you’re writing code to work with all subclasses, and you are dealing with a spatially variable PSF, then be careful with what you do with the return here.
NOTE AND WORRY : photutils uses the term PSF to mean both PSF and PRF in different places. Just like everyboyd else. THIS is returning a PRF (if the code is right), that is, a thing that has been convolved with a tophat pixel (or, ideally, something even more sophisticated, but no promises). However, we call it a PSF, because it’s the thing you give to photutils PSF photometry. But photutils has started to try to distinguish, so their documentaiton is going to be scary and inconsistent and we’ll have to think.
Subclasses may want to override this.
- Parameters:
x (float, default None) – Position on the original image to render the PSF for. If not given, uses the x and y that the PSF object was initialized with. Because photutils expects PSFs centered on a pixel, x and y should have no fractional part. (The default implementation explicitly rounds (sort of…) to the nearest whole number for both x and y; properly written subclasses will do the same thing.
y (float, default None) – Position on the original image to render the PSF for. If not given, uses the x and y that the PSF object was initialized with. Because photutils expects PSFs centered on a pixel, x and y should have no fractional part. (The default implementation explicitly rounds (sort of…) to the nearest whole number for both x and y; properly written subclasses will do the same thing.
imagesampled (bool, default True) – This one is a bit complicated. It’s ignored by some subclasses. The default implementation is to return an ImagePSF sampled at the image scale, and to ignore imagesample. Some subclasses (e.g., OversampledImagePSF) will return an oversampled photutils.psf.ImagePSF if you set imagesampled to false. Other subclasses return other things for which image scale may or may not be relevant. And, it’s possible that other subclasse will return something oversampled even if you say imagesampled=True. In any event, because what you get back is intended to be fed to photutils, you probably shouldn’t think about it too hard. (TODO: we might want to set imagesampled to False so that classes don’t by default make something that will make photutils behavior worse! This may cause a bunch of code to break, maybe quietly, because the assumed default changed.)
- 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).