Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 117 additions & 26 deletions Measurement/UndersampledMoments.ipynb
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,16 +8,16 @@
"source": [
"# Biased moments of undersampled sources\n",
"<br>Owner(s): **Andrew Bradshaw** ([@andrewkbradshaw](https://github.com/LSSTScienceCollaborations/StackClub/issues/new?body=@andrewkbradshaw))\n",
"<br>Last Verified to Run: **2019-08-09**\n",
"<br>Verified Stack Release: **18.0**\n",
"<br>Last Verified to Run: **2019-08-23**\n",
"<br>Verified Stack Release: **18.1.0**\n",
"\n",
"This notebook demonstrates how the measurement of centroid, size, and orientation angles of small sources(relative to the pixel grid) are biased due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"This notebook performs measurements of the centroid, size, and orientation angles of small sources. It goes on to show how these measurements are biased (relative to the pixel grid) due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"\n",
"### Learning Objectives:\n",
"\n",
"After working through this tutorial you should be able to: \n",
"1. Simulate stars and galaxies with a variety of properties, including sub-pixel centroid, size, and orientation angle.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms (including the Stack default).\n",
"\n",
"### References:\n",
"* [galsim.Shear](http://galsim-developers.github.io/GalSim/_build/html/shear.html) - Documentation on how GalSim defines shear\n",
Expand DownExpand Up@@ -65,7 +65,7 @@
"\n",
"We start by setting up a class that uses [GalSim](http://galsim-developers.github.io/GalSim/_build/html/index.html) to generate simulated images and sources. GalSim can provide various levels of realism (e.g., readout noise, sky background, silicon sensor effects, etc.), and these are configurable during the creation of an instance. We also implement a function to use GalSim to generate a Gaussian source with a given centroid, ellipticity, and orientation.\n",
"\n",
"We break up the creation of the `undersampled_galsim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
"We break up the creation of the `UndersampledGalSim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
]
},
{
Expand DownExpand Up@@ -93,7 +93,26 @@
" diffusion_factor=0,stamp_width=31,pixel_scale=0.2,gain=1,\n",
" rngseed=8675309,do_hsm_moments_truefalse=False,sim_sensor_truefalse=False,\n",
" default_gsparams=True):\n",
" \"\"\"Initialize the imager with some basic settings\"\"\"\n",
" \"\"\"Initialize the imager with some basic settings\n",
" \n",
" Parameters\n",
" ----------\n",
" method_of_imaging: how to generate the image ('phot','fft','no_pixel')\n",
" read_noise: Gaussian std dev. of CCD readout noise\n",
" sky_level_pixel: the background noise level (subtracted off)\n",
" diffusion_factor: silicon sensor diffusion factor\n",
" stamp_width: width of each postage stamp (default: 31)\n",
" pixel_scale: pixel scale in arcsec/pixel (LSST = 0.2)\n",
" gain: CCD gain (default: 1)\n",
" rngseed: random number generator seed\n",
" do_hsm_moments_truefalse: do hsm moments measurement\n",
" sim_sensor_truefalse: whether or not to simulate the sensor & diffusion\n",
" default_gsparams: use default GalSim parameters\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" self.method = method_of_imaging # default: phot, fft; no_pixel' might take forever?\n",
" self.sensor = sim_sensor_truefalse # whether or not to simulate the sensor & diffusion\n",
" self.pixel_scale=pixel_scale # pixel scale in arcsec/pixel, LSST = 0.2\n",
Expand DownExpand Up@@ -123,7 +142,20 @@
" def draw_gaussian(self,offset=(0.0,0.0),gal_sigma_pix=1.5,gal_ellip=0,\n",
" gal_angle_deg=0,gal_flux=1e5):\n",
" \"\"\"Draw a Gauassian on the image, using the provided centroid offsets, widths, ellipticity\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\"\"\"\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\n",
" \n",
" Parameters\n",
" ----------\n",
" offset : coordinate offset (preserves sub-pixel offset in even-sized images)\n",
" gal_sigma_pix : standard deviation of Gaussian (unit: pixels)\n",
" gal_ellip : source ellipticity, e; see GalSim.Shear\n",
" gal_angle_deg : source position angle, beta; see GalSim.shear (unit: deg)\n",
" gal_flux : source flux\n",
" \n",
" Returns\n",
" -------\n",
" final,hsm : image array, hsm fit parameters\n",
" \"\"\"\n",
" gal = galsim.Gaussian(sigma = gal_sigma_pix*self.pixel_scale, gsparams=self.gsparams)\n",
" gal_shape = galsim.Shear(e=gal_ellip, beta=gal_angle_deg * galsim.degrees)\n",
" gal = gal.shear(gal_shape)\n",
Expand All@@ -150,7 +182,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Functions to compute first and second moments on images"
"## Custom calculations of first and second moments on images\n",
"\n",
"We define two custom methods to calculate first and second moments on images. These are non-adaptive methods that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor.\n"
]
},
{
Expand All@@ -162,7 +196,20 @@
"def calc_firstmoms(img,coord,winsize,thresh,gwin_sig):\n",
" #print(img[:5,:5],coord,winsize,thresh,gwin_sig)\n",
" \"\"\"Calculates the x and y first moments of the image windowed by winsize at\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\"\"\"\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
" \n",
" Returns\n",
" -------\n",
" xmom, ymom : the x and y first moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" xmom,ymom=0.,0.\n",
" thesum=0.\n",
Expand All@@ -186,7 +233,20 @@
"def calc_secmoms_gwin(img,coord,winsize,thresh,gwin_sig):\n",
" \"\"\"Calculates the x, y, xy, and radial second moments of the image windowed by\n",
" winsize at coord (x,y) and thresholded at thresh, weighted by a Gaussian of \n",
" width gwin_sig\"\"\"\n",
" width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
"\n",
" Returns\n",
" -------\n",
" rmom, xmom, ymom, xymom : radial, x, y, and xy second moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" r2mom,x2mom,y2mom,xy2mom=0.,0.,0.,0.\n",
" thesum=0.\n",
Expand DownExpand Up@@ -215,6 +275,13 @@
" return rmom, xmom, ymom, xymom\n",
"\n",
"def calc_gauss_diff(i,j,xcen,ycen,sigx,sigy):\n",
" \"\"\" \n",
" Parameters\n",
" ----------\n",
" \n",
" Returns\n",
" -------\n",
" \"\"\"\n",
" ydiff=1./24.*(((i-xcen)**2/sigx**2-1.)/sigx**2 + ((j-ycen)**2/sigy**2-1.)/sigy**2)\n",
" ygauss=np.exp(-.5*((i-xcen)**2/sigx**2))*np.exp(-.5*((j-ycen)**2/sigy**2))\n",
" return ydiff*ygauss\n",
Expand DownExpand Up@@ -272,6 +339,17 @@
"outputs": [],
"source": [
"def calc_and_print_moments(stamp,hsm):\n",
" \"\"\"Calculate and pring the first and second moments for a postage stamp with predetermined hsm measurements\n",
" \n",
" Parameters\n",
" ----------\n",
" stamp : postage stamp array\n",
" hsm : moments calculated from hsm\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" x_hsm,y_hsm,sig_hsm=hsm.moments_centroid.x,hsm.moments_centroid.y,hsm.moments_sigma\n",
" # calculate my moments\n",
" thresh=0\n",
Expand DownExpand Up@@ -330,7 +408,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Making mosaics of objects"
"## Making mosaics of objects\n",
"\n",
"Now that we have the ability to generate and measure one object, we would like to expand our analysis to a statistical set of objects. We add functionality to make a mosaic of sources on a single image."
]
},
{
Expand DownExpand Up@@ -435,7 +515,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Making a mosaic of small spots with a range of sub-pixel centroids"
"## Making a mosaic of small spots with a range of sub-pixel centroids\n",
"\n",
"We create a mosaic of small spots distributed over a range of centroids. The centroids are given sub-pixel offsets to determine the biases of our various fitting methods."
]
},
{
Expand All@@ -456,7 +538,7 @@
" angle_minmax=(0,0),flux_minmax=(1e5,1e5))\n",
"\n",
"mosaic,cat_in=ugal.make_mosaic(cat_in)\n",
"print(time.time()-tstart,\" to simulate \",str(len(cat_in)),\" galaxies\")\n",
"print(\"It took %.2fs to simulate %s spots\"%(time.time()-tstart,str(len(cat_in))))\n",
"\n",
"plt.figure(figsize=(16,16))\n",
"plt.imshow(mosaic,origin='lower',vmax=100),plt.colorbar()"
Expand DownExpand Up@@ -567,7 +649,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Merge in stack measurements to catalog"
"### Merge in stack measurements to catalog\n",
"\n",
"Now that we've run the Stack measurements, we would like to merge them into the same catalog that contains the hsm measurements performed when generating the simulated sources."
]
},
{
Expand DownExpand Up@@ -628,7 +712,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measurement using sextractor wrapper"
"## Measurement using SExtractor wrapper\n",
"\n",
"Below we include some code that can be used to install `sep`, a python wrapper around Source Extractor, and calculate the SExtractor moments."
]
},
{
Expand DownExpand Up@@ -668,7 +754,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measure moments using a non-adaptive method, radially weighting by the input Gaussian $\\sigma$ multiplied by a factor"
"## Custom moments measurement \n",
"\n",
"We now perform a first moments calculation using the method that we defined above in `calc_firstmoms`. This is a non-adaptive method that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor (we choose this factor to be 2 and 5 below)."
]
},
{
Expand DownExpand Up@@ -701,7 +789,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting the centroid bias"
"### Plot centroid bias"
]
},
{
Expand DownExpand Up@@ -741,7 +829,10 @@
},
"source": [
"# Size bias\n",
"Making a mosaic of spots with a range of input sizes $\\sigma$, takes about a minute for 100 objects with 5 million photons"
"\n",
"Make a mosaic of spots with a range of input sizes, $\\sigma$. When generating the mosaic, we also perform a simple moments calculation, which we store in the `cat_in` variable. \n",
"\n",
"This cell takes about **1 minute** to run for 100 objects with 5 million photons."
]
},
{
Expand DownExpand Up@@ -773,6 +864,13 @@
"fits.writeto(mo_dir+'mosaic_sizes.fits',mosaic,overwrite=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we run the stack on the spot mosaic. We add the Stack moment measurements (i.e., the quantities starting with `base_SdssShape`) to the catalog containing the simple moments measurements that we performed when generating the mosaic."
]
},
{
"cell_type": "code",
"execution_count": null,
Expand DownExpand Up@@ -880,7 +978,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## plotting size bias"
"### Plot size bias"
]
},
{
Expand DownExpand Up@@ -923,13 +1021,6 @@
"plt.tight_layout(),plt.subplots_adjust(wspace=.4)\n",
"plt.savefig(mo_dir+'/biased_moments-size.png',dpi=150)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 117 additions & 26 deletions Measurement/UndersampledMoments.ipynb
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,16 +8,16 @@
"source": [
"# Biased moments of undersampled sources\n",
"<br>Owner(s): **Andrew Bradshaw** ([@andrewkbradshaw](https://github.com/LSSTScienceCollaborations/StackClub/issues/new?body=@andrewkbradshaw))\n",
"<br>Last Verified to Run: **2019-08-09**\n",
"<br>Verified Stack Release: **18.0**\n",
"<br>Last Verified to Run: **2019-08-23**\n",
"<br>Verified Stack Release: **18.1.0**\n",
"\n",
"This notebook demonstrates how the measurement of centroid, size, and orientation angles of small sources(relative to the pixel grid) are biased due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"This notebook performs measurements of the centroid, size, and orientation angles of small sources. It goes on to show how these measurements are biased (relative to the pixel grid) due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"\n",
"### Learning Objectives:\n",
"\n",
"After working through this tutorial you should be able to: \n",
"1. Simulate stars and galaxies with a variety of properties, including sub-pixel centroid, size, and orientation angle.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms (including the Stack default).\n",
"\n",
"### References:\n",
"* [galsim.Shear](http://galsim-developers.github.io/GalSim/_build/html/shear.html) - Documentation on how GalSim defines shear\n",
Expand DownExpand Up@@ -65,7 +65,7 @@
"\n",
"We start by setting up a class that uses [GalSim](http://galsim-developers.github.io/GalSim/_build/html/index.html) to generate simulated images and sources. GalSim can provide various levels of realism (e.g., readout noise, sky background, silicon sensor effects, etc.), and these are configurable during the creation of an instance. We also implement a function to use GalSim to generate a Gaussian source with a given centroid, ellipticity, and orientation.\n",
"\n",
"We break up the creation of the `undersampled_galsim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
"We break up the creation of the `UndersampledGalSim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
]
},
{
Expand DownExpand Up@@ -93,7 +93,26 @@
" diffusion_factor=0,stamp_width=31,pixel_scale=0.2,gain=1,\n",
" rngseed=8675309,do_hsm_moments_truefalse=False,sim_sensor_truefalse=False,\n",
" default_gsparams=True):\n",
" \"\"\"Initialize the imager with some basic settings\"\"\"\n",
" \"\"\"Initialize the imager with some basic settings\n",
" \n",
" Parameters\n",
" ----------\n",
" method_of_imaging: how to generate the image ('phot','fft','no_pixel')\n",
" read_noise: Gaussian std dev. of CCD readout noise\n",
" sky_level_pixel: the background noise level (subtracted off)\n",
" diffusion_factor: silicon sensor diffusion factor\n",
" stamp_width: width of each postage stamp (default: 31)\n",
" pixel_scale: pixel scale in arcsec/pixel (LSST = 0.2)\n",
" gain: CCD gain (default: 1)\n",
" rngseed: random number generator seed\n",
" do_hsm_moments_truefalse: do hsm moments measurement\n",
" sim_sensor_truefalse: whether or not to simulate the sensor & diffusion\n",
" default_gsparams: use default GalSim parameters\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" self.method = method_of_imaging # default: phot, fft; no_pixel' might take forever?\n",
" self.sensor = sim_sensor_truefalse # whether or not to simulate the sensor & diffusion\n",
" self.pixel_scale=pixel_scale # pixel scale in arcsec/pixel, LSST = 0.2\n",
Expand DownExpand Up@@ -123,7 +142,20 @@
" def draw_gaussian(self,offset=(0.0,0.0),gal_sigma_pix=1.5,gal_ellip=0,\n",
" gal_angle_deg=0,gal_flux=1e5):\n",
" \"\"\"Draw a Gauassian on the image, using the provided centroid offsets, widths, ellipticity\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\"\"\"\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\n",
" \n",
" Parameters\n",
" ----------\n",
" offset : coordinate offset (preserves sub-pixel offset in even-sized images)\n",
" gal_sigma_pix : standard deviation of Gaussian (unit: pixels)\n",
" gal_ellip : source ellipticity, e; see GalSim.Shear\n",
" gal_angle_deg : source position angle, beta; see GalSim.shear (unit: deg)\n",
" gal_flux : source flux\n",
" \n",
" Returns\n",
" -------\n",
" final,hsm : image array, hsm fit parameters\n",
" \"\"\"\n",
" gal = galsim.Gaussian(sigma = gal_sigma_pix*self.pixel_scale, gsparams=self.gsparams)\n",
" gal_shape = galsim.Shear(e=gal_ellip, beta=gal_angle_deg * galsim.degrees)\n",
" gal = gal.shear(gal_shape)\n",
Expand All@@ -150,7 +182,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Functions to compute first and second moments on images"
"## Custom calculations of first and second moments on images\n",
"\n",
"We define two custom methods to calculate first and second moments on images. These are non-adaptive methods that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor.\n"
]
},
{
Expand All@@ -162,7 +196,20 @@
"def calc_firstmoms(img,coord,winsize,thresh,gwin_sig):\n",
" #print(img[:5,:5],coord,winsize,thresh,gwin_sig)\n",
" \"\"\"Calculates the x and y first moments of the image windowed by winsize at\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\"\"\"\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
" \n",
" Returns\n",
" -------\n",
" xmom, ymom : the x and y first moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" xmom,ymom=0.,0.\n",
" thesum=0.\n",
Expand All@@ -186,7 +233,20 @@
"def calc_secmoms_gwin(img,coord,winsize,thresh,gwin_sig):\n",
" \"\"\"Calculates the x, y, xy, and radial second moments of the image windowed by\n",
" winsize at coord (x,y) and thresholded at thresh, weighted by a Gaussian of \n",
" width gwin_sig\"\"\"\n",
" width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
"\n",
" Returns\n",
" -------\n",
" rmom, xmom, ymom, xymom : radial, x, y, and xy second moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" r2mom,x2mom,y2mom,xy2mom=0.,0.,0.,0.\n",
" thesum=0.\n",
Expand DownExpand Up@@ -215,6 +275,13 @@
" return rmom, xmom, ymom, xymom\n",
"\n",
"def calc_gauss_diff(i,j,xcen,ycen,sigx,sigy):\n",
" \"\"\" \n",
" Parameters\n",
" ----------\n",
" \n",
" Returns\n",
" -------\n",
" \"\"\"\n",
" ydiff=1./24.*(((i-xcen)**2/sigx**2-1.)/sigx**2 + ((j-ycen)**2/sigy**2-1.)/sigy**2)\n",
" ygauss=np.exp(-.5*((i-xcen)**2/sigx**2))*np.exp(-.5*((j-ycen)**2/sigy**2))\n",
" return ydiff*ygauss\n",
Expand DownExpand Up@@ -272,6 +339,17 @@
"outputs": [],
"source": [
"def calc_and_print_moments(stamp,hsm):\n",
" \"\"\"Calculate and pring the first and second moments for a postage stamp with predetermined hsm measurements\n",
" \n",
" Parameters\n",
" ----------\n",
" stamp : postage stamp array\n",
" hsm : moments calculated from hsm\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" x_hsm,y_hsm,sig_hsm=hsm.moments_centroid.x,hsm.moments_centroid.y,hsm.moments_sigma\n",
" # calculate my moments\n",
" thresh=0\n",
Expand DownExpand Up@@ -330,7 +408,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Making mosaics of objects"
"## Making mosaics of objects\n",
"\n",
"Now that we have the ability to generate and measure one object, we would like to expand our analysis to a statistical set of objects. We add functionality to make a mosaic of sources on a single image."
]
},
{
Expand DownExpand Up@@ -435,7 +515,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Making a mosaic of small spots with a range of sub-pixel centroids"
"## Making a mosaic of small spots with a range of sub-pixel centroids\n",
"\n",
"We create a mosaic of small spots distributed over a range of centroids. The centroids are given sub-pixel offsets to determine the biases of our various fitting methods."
]
},
{
Expand All@@ -456,7 +538,7 @@
" angle_minmax=(0,0),flux_minmax=(1e5,1e5))\n",
"\n",
"mosaic,cat_in=ugal.make_mosaic(cat_in)\n",
"print(time.time()-tstart,\" to simulate \",str(len(cat_in)),\" galaxies\")\n",
"print(\"It took %.2fs to simulate %s spots\"%(time.time()-tstart,str(len(cat_in))))\n",
"\n",
"plt.figure(figsize=(16,16))\n",
"plt.imshow(mosaic,origin='lower',vmax=100),plt.colorbar()"
Expand DownExpand Up@@ -567,7 +649,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Merge in stack measurements to catalog"
"### Merge in stack measurements to catalog\n",
"\n",
"Now that we've run the Stack measurements, we would like to merge them into the same catalog that contains the hsm measurements performed when generating the simulated sources."
]
},
{
Expand DownExpand Up@@ -628,7 +712,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measurement using sextractor wrapper"
"## Measurement using SExtractor wrapper\n",
"\n",
"Below we include some code that can be used to install `sep`, a python wrapper around Source Extractor, and calculate the SExtractor moments."
]
},
{
Expand DownExpand Up@@ -668,7 +754,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measure moments using a non-adaptive method, radially weighting by the input Gaussian $\\sigma$ multiplied by a factor"
"## Custom moments measurement \n",
"\n",
"We now perform a first moments calculation using the method that we defined above in `calc_firstmoms`. This is a non-adaptive method that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor (we choose this factor to be 2 and 5 below)."
]
},
{
Expand DownExpand Up@@ -701,7 +789,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting the centroid bias"
"### Plot centroid bias"
]
},
{
Expand DownExpand Up@@ -741,7 +829,10 @@
},
"source": [
"# Size bias\n",
"Making a mosaic of spots with a range of input sizes $\\sigma$, takes about a minute for 100 objects with 5 million photons"
"\n",
"Make a mosaic of spots with a range of input sizes, $\\sigma$. When generating the mosaic, we also perform a simple moments calculation, which we store in the `cat_in` variable. \n",
"\n",
"This cell takes about **1 minute** to run for 100 objects with 5 million photons."
]
},
{
Expand DownExpand Up@@ -773,6 +864,13 @@
"fits.writeto(mo_dir+'mosaic_sizes.fits',mosaic,overwrite=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we run the stack on the spot mosaic. We add the Stack moment measurements (i.e., the quantities starting with `base_SdssShape`) to the catalog containing the simple moments measurements that we performed when generating the mosaic."
]
},
{
"cell_type": "code",
"execution_count": null,
Expand DownExpand Up@@ -880,7 +978,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## plotting size bias"
"### Plot size bias"
]
},
{
Expand DownExpand Up@@ -923,13 +1021,6 @@
"plt.tight_layout(),plt.subplots_adjust(wspace=.4)\n",
"plt.savefig(mo_dir+'/biased_moments-size.png',dpi=150)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 117 additions & 26 deletions Measurement/UndersampledMoments.ipynb
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,16 +8,16 @@
"source": [
"# Biased moments of undersampled sources\n",
"<br>Owner(s): **Andrew Bradshaw** ([@andrewkbradshaw](https://github.com/LSSTScienceCollaborations/StackClub/issues/new?body=@andrewkbradshaw))\n",
"<br>Last Verified to Run: **2019-08-09**\n",
"<br>Verified Stack Release: **18.0**\n",
"<br>Last Verified to Run: **2019-08-23**\n",
"<br>Verified Stack Release: **18.1.0**\n",
"\n",
"This notebook demonstrates how the measurement of centroid, size, and orientation angles of small sources(relative to the pixel grid) are biased due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"This notebook performs measurements of the centroid, size, and orientation angles of small sources. It goes on to show how these measurements are biased (relative to the pixel grid) due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"\n",
"### Learning Objectives:\n",
"\n",
"After working through this tutorial you should be able to: \n",
"1. Simulate stars and galaxies with a variety of properties, including sub-pixel centroid, size, and orientation angle.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms (including the Stack default).\n",
"\n",
"### References:\n",
"* [galsim.Shear](http://galsim-developers.github.io/GalSim/_build/html/shear.html) - Documentation on how GalSim defines shear\n",
Expand DownExpand Up@@ -65,7 +65,7 @@
"\n",
"We start by setting up a class that uses [GalSim](http://galsim-developers.github.io/GalSim/_build/html/index.html) to generate simulated images and sources. GalSim can provide various levels of realism (e.g., readout noise, sky background, silicon sensor effects, etc.), and these are configurable during the creation of an instance. We also implement a function to use GalSim to generate a Gaussian source with a given centroid, ellipticity, and orientation.\n",
"\n",
"We break up the creation of the `undersampled_galsim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
"We break up the creation of the `UndersampledGalSim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
]
},
{
Expand DownExpand Up@@ -93,7 +93,26 @@
" diffusion_factor=0,stamp_width=31,pixel_scale=0.2,gain=1,\n",
" rngseed=8675309,do_hsm_moments_truefalse=False,sim_sensor_truefalse=False,\n",
" default_gsparams=True):\n",
" \"\"\"Initialize the imager with some basic settings\"\"\"\n",
" \"\"\"Initialize the imager with some basic settings\n",
" \n",
" Parameters\n",
" ----------\n",
" method_of_imaging: how to generate the image ('phot','fft','no_pixel')\n",
" read_noise: Gaussian std dev. of CCD readout noise\n",
" sky_level_pixel: the background noise level (subtracted off)\n",
" diffusion_factor: silicon sensor diffusion factor\n",
" stamp_width: width of each postage stamp (default: 31)\n",
" pixel_scale: pixel scale in arcsec/pixel (LSST = 0.2)\n",
" gain: CCD gain (default: 1)\n",
" rngseed: random number generator seed\n",
" do_hsm_moments_truefalse: do hsm moments measurement\n",
" sim_sensor_truefalse: whether or not to simulate the sensor & diffusion\n",
" default_gsparams: use default GalSim parameters\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" self.method = method_of_imaging # default: phot, fft; no_pixel' might take forever?\n",
" self.sensor = sim_sensor_truefalse # whether or not to simulate the sensor & diffusion\n",
" self.pixel_scale=pixel_scale # pixel scale in arcsec/pixel, LSST = 0.2\n",
Expand DownExpand Up@@ -123,7 +142,20 @@
" def draw_gaussian(self,offset=(0.0,0.0),gal_sigma_pix=1.5,gal_ellip=0,\n",
" gal_angle_deg=0,gal_flux=1e5):\n",
" \"\"\"Draw a Gauassian on the image, using the provided centroid offsets, widths, ellipticity\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\"\"\"\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\n",
" \n",
" Parameters\n",
" ----------\n",
" offset : coordinate offset (preserves sub-pixel offset in even-sized images)\n",
" gal_sigma_pix : standard deviation of Gaussian (unit: pixels)\n",
" gal_ellip : source ellipticity, e; see GalSim.Shear\n",
" gal_angle_deg : source position angle, beta; see GalSim.shear (unit: deg)\n",
" gal_flux : source flux\n",
" \n",
" Returns\n",
" -------\n",
" final,hsm : image array, hsm fit parameters\n",
" \"\"\"\n",
" gal = galsim.Gaussian(sigma = gal_sigma_pix*self.pixel_scale, gsparams=self.gsparams)\n",
" gal_shape = galsim.Shear(e=gal_ellip, beta=gal_angle_deg * galsim.degrees)\n",
" gal = gal.shear(gal_shape)\n",
Expand All@@ -150,7 +182,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Functions to compute first and second moments on images"
"## Custom calculations of first and second moments on images\n",
"\n",
"We define two custom methods to calculate first and second moments on images. These are non-adaptive methods that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor.\n"
]
},
{
Expand All@@ -162,7 +196,20 @@
"def calc_firstmoms(img,coord,winsize,thresh,gwin_sig):\n",
" #print(img[:5,:5],coord,winsize,thresh,gwin_sig)\n",
" \"\"\"Calculates the x and y first moments of the image windowed by winsize at\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\"\"\"\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
" \n",
" Returns\n",
" -------\n",
" xmom, ymom : the x and y first moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" xmom,ymom=0.,0.\n",
" thesum=0.\n",
Expand All@@ -186,7 +233,20 @@
"def calc_secmoms_gwin(img,coord,winsize,thresh,gwin_sig):\n",
" \"\"\"Calculates the x, y, xy, and radial second moments of the image windowed by\n",
" winsize at coord (x,y) and thresholded at thresh, weighted by a Gaussian of \n",
" width gwin_sig\"\"\"\n",
" width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
"\n",
" Returns\n",
" -------\n",
" rmom, xmom, ymom, xymom : radial, x, y, and xy second moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" r2mom,x2mom,y2mom,xy2mom=0.,0.,0.,0.\n",
" thesum=0.\n",
Expand DownExpand Up@@ -215,6 +275,13 @@
" return rmom, xmom, ymom, xymom\n",
"\n",
"def calc_gauss_diff(i,j,xcen,ycen,sigx,sigy):\n",
" \"\"\" \n",
" Parameters\n",
" ----------\n",
" \n",
" Returns\n",
" -------\n",
" \"\"\"\n",
" ydiff=1./24.*(((i-xcen)**2/sigx**2-1.)/sigx**2 + ((j-ycen)**2/sigy**2-1.)/sigy**2)\n",
" ygauss=np.exp(-.5*((i-xcen)**2/sigx**2))*np.exp(-.5*((j-ycen)**2/sigy**2))\n",
" return ydiff*ygauss\n",
Expand DownExpand Up@@ -272,6 +339,17 @@
"outputs": [],
"source": [
"def calc_and_print_moments(stamp,hsm):\n",
" \"\"\"Calculate and pring the first and second moments for a postage stamp with predetermined hsm measurements\n",
" \n",
" Parameters\n",
" ----------\n",
" stamp : postage stamp array\n",
" hsm : moments calculated from hsm\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" x_hsm,y_hsm,sig_hsm=hsm.moments_centroid.x,hsm.moments_centroid.y,hsm.moments_sigma\n",
" # calculate my moments\n",
" thresh=0\n",
Expand DownExpand Up@@ -330,7 +408,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Making mosaics of objects"
"## Making mosaics of objects\n",
"\n",
"Now that we have the ability to generate and measure one object, we would like to expand our analysis to a statistical set of objects. We add functionality to make a mosaic of sources on a single image."
]
},
{
Expand DownExpand Up@@ -435,7 +515,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Making a mosaic of small spots with a range of sub-pixel centroids"
"## Making a mosaic of small spots with a range of sub-pixel centroids\n",
"\n",
"We create a mosaic of small spots distributed over a range of centroids. The centroids are given sub-pixel offsets to determine the biases of our various fitting methods."
]
},
{
Expand All@@ -456,7 +538,7 @@
" angle_minmax=(0,0),flux_minmax=(1e5,1e5))\n",
"\n",
"mosaic,cat_in=ugal.make_mosaic(cat_in)\n",
"print(time.time()-tstart,\" to simulate \",str(len(cat_in)),\" galaxies\")\n",
"print(\"It took %.2fs to simulate %s spots\"%(time.time()-tstart,str(len(cat_in))))\n",
"\n",
"plt.figure(figsize=(16,16))\n",
"plt.imshow(mosaic,origin='lower',vmax=100),plt.colorbar()"
Expand DownExpand Up@@ -567,7 +649,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Merge in stack measurements to catalog"
"### Merge in stack measurements to catalog\n",
"\n",
"Now that we've run the Stack measurements, we would like to merge them into the same catalog that contains the hsm measurements performed when generating the simulated sources."
]
},
{
Expand DownExpand Up@@ -628,7 +712,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measurement using sextractor wrapper"
"## Measurement using SExtractor wrapper\n",
"\n",
"Below we include some code that can be used to install `sep`, a python wrapper around Source Extractor, and calculate the SExtractor moments."
]
},
{
Expand DownExpand Up@@ -668,7 +754,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measure moments using a non-adaptive method, radially weighting by the input Gaussian $\\sigma$ multiplied by a factor"
"## Custom moments measurement \n",
"\n",
"We now perform a first moments calculation using the method that we defined above in `calc_firstmoms`. This is a non-adaptive method that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor (we choose this factor to be 2 and 5 below)."
]
},
{
Expand DownExpand Up@@ -701,7 +789,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting the centroid bias"
"### Plot centroid bias"
]
},
{
Expand DownExpand Up@@ -741,7 +829,10 @@
},
"source": [
"# Size bias\n",
"Making a mosaic of spots with a range of input sizes $\\sigma$, takes about a minute for 100 objects with 5 million photons"
"\n",
"Make a mosaic of spots with a range of input sizes, $\\sigma$. When generating the mosaic, we also perform a simple moments calculation, which we store in the `cat_in` variable. \n",
"\n",
"This cell takes about **1 minute** to run for 100 objects with 5 million photons."
]
},
{
Expand DownExpand Up@@ -773,6 +864,13 @@
"fits.writeto(mo_dir+'mosaic_sizes.fits',mosaic,overwrite=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we run the stack on the spot mosaic. We add the Stack moment measurements (i.e., the quantities starting with `base_SdssShape`) to the catalog containing the simple moments measurements that we performed when generating the mosaic."
]
},
{
"cell_type": "code",
"execution_count": null,
Expand DownExpand Up@@ -880,7 +978,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## plotting size bias"
"### Plot size bias"
]
},
{
Expand DownExpand Up@@ -923,13 +1021,6 @@
"plt.tight_layout(),plt.subplots_adjust(wspace=.4)\n",
"plt.savefig(mo_dir+'/biased_moments-size.png',dpi=150)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 117 additions & 26 deletions Measurement/UndersampledMoments.ipynb
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,16 +8,16 @@
"source": [
"# Biased moments of undersampled sources\n",
"<br>Owner(s): **Andrew Bradshaw** ([@andrewkbradshaw](https://github.com/LSSTScienceCollaborations/StackClub/issues/new?body=@andrewkbradshaw))\n",
"<br>Last Verified to Run: **2019-08-09**\n",
"<br>Verified Stack Release: **18.0**\n",
"<br>Last Verified to Run: **2019-08-23**\n",
"<br>Verified Stack Release: **18.1.0**\n",
"\n",
"This notebook demonstrates how the measurement of centroid, size, and orientation angles of small sources(relative to the pixel grid) are biased due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"This notebook performs measurements of the centroid, size, and orientation angles of small sources. It goes on to show how these measurements are biased (relative to the pixel grid) due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"\n",
"### Learning Objectives:\n",
"\n",
"After working through this tutorial you should be able to: \n",
"1. Simulate stars and galaxies with a variety of properties, including sub-pixel centroid, size, and orientation angle.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms (including the Stack default).\n",
"\n",
"### References:\n",
"* [galsim.Shear](http://galsim-developers.github.io/GalSim/_build/html/shear.html) - Documentation on how GalSim defines shear\n",
Expand DownExpand Up@@ -65,7 +65,7 @@
"\n",
"We start by setting up a class that uses [GalSim](http://galsim-developers.github.io/GalSim/_build/html/index.html) to generate simulated images and sources. GalSim can provide various levels of realism (e.g., readout noise, sky background, silicon sensor effects, etc.), and these are configurable during the creation of an instance. We also implement a function to use GalSim to generate a Gaussian source with a given centroid, ellipticity, and orientation.\n",
"\n",
"We break up the creation of the `undersampled_galsim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
"We break up the creation of the `UndersampledGalSim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
]
},
{
Expand DownExpand Up@@ -93,7 +93,26 @@
" diffusion_factor=0,stamp_width=31,pixel_scale=0.2,gain=1,\n",
" rngseed=8675309,do_hsm_moments_truefalse=False,sim_sensor_truefalse=False,\n",
" default_gsparams=True):\n",
" \"\"\"Initialize the imager with some basic settings\"\"\"\n",
" \"\"\"Initialize the imager with some basic settings\n",
" \n",
" Parameters\n",
" ----------\n",
" method_of_imaging: how to generate the image ('phot','fft','no_pixel')\n",
" read_noise: Gaussian std dev. of CCD readout noise\n",
" sky_level_pixel: the background noise level (subtracted off)\n",
" diffusion_factor: silicon sensor diffusion factor\n",
" stamp_width: width of each postage stamp (default: 31)\n",
" pixel_scale: pixel scale in arcsec/pixel (LSST = 0.2)\n",
" gain: CCD gain (default: 1)\n",
" rngseed: random number generator seed\n",
" do_hsm_moments_truefalse: do hsm moments measurement\n",
" sim_sensor_truefalse: whether or not to simulate the sensor & diffusion\n",
" default_gsparams: use default GalSim parameters\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" self.method = method_of_imaging # default: phot, fft; no_pixel' might take forever?\n",
" self.sensor = sim_sensor_truefalse # whether or not to simulate the sensor & diffusion\n",
" self.pixel_scale=pixel_scale # pixel scale in arcsec/pixel, LSST = 0.2\n",
Expand DownExpand Up@@ -123,7 +142,20 @@
" def draw_gaussian(self,offset=(0.0,0.0),gal_sigma_pix=1.5,gal_ellip=0,\n",
" gal_angle_deg=0,gal_flux=1e5):\n",
" \"\"\"Draw a Gauassian on the image, using the provided centroid offsets, widths, ellipticity\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\"\"\"\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\n",
" \n",
" Parameters\n",
" ----------\n",
" offset : coordinate offset (preserves sub-pixel offset in even-sized images)\n",
" gal_sigma_pix : standard deviation of Gaussian (unit: pixels)\n",
" gal_ellip : source ellipticity, e; see GalSim.Shear\n",
" gal_angle_deg : source position angle, beta; see GalSim.shear (unit: deg)\n",
" gal_flux : source flux\n",
" \n",
" Returns\n",
" -------\n",
" final,hsm : image array, hsm fit parameters\n",
" \"\"\"\n",
" gal = galsim.Gaussian(sigma = gal_sigma_pix*self.pixel_scale, gsparams=self.gsparams)\n",
" gal_shape = galsim.Shear(e=gal_ellip, beta=gal_angle_deg * galsim.degrees)\n",
" gal = gal.shear(gal_shape)\n",
Expand All@@ -150,7 +182,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Functions to compute first and second moments on images"
"## Custom calculations of first and second moments on images\n",
"\n",
"We define two custom methods to calculate first and second moments on images. These are non-adaptive methods that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor.\n"
]
},
{
Expand All@@ -162,7 +196,20 @@
"def calc_firstmoms(img,coord,winsize,thresh,gwin_sig):\n",
" #print(img[:5,:5],coord,winsize,thresh,gwin_sig)\n",
" \"\"\"Calculates the x and y first moments of the image windowed by winsize at\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\"\"\"\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
" \n",
" Returns\n",
" -------\n",
" xmom, ymom : the x and y first moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" xmom,ymom=0.,0.\n",
" thesum=0.\n",
Expand All@@ -186,7 +233,20 @@
"def calc_secmoms_gwin(img,coord,winsize,thresh,gwin_sig):\n",
" \"\"\"Calculates the x, y, xy, and radial second moments of the image windowed by\n",
" winsize at coord (x,y) and thresholded at thresh, weighted by a Gaussian of \n",
" width gwin_sig\"\"\"\n",
" width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
"\n",
" Returns\n",
" -------\n",
" rmom, xmom, ymom, xymom : radial, x, y, and xy second moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" r2mom,x2mom,y2mom,xy2mom=0.,0.,0.,0.\n",
" thesum=0.\n",
Expand DownExpand Up@@ -215,6 +275,13 @@
" return rmom, xmom, ymom, xymom\n",
"\n",
"def calc_gauss_diff(i,j,xcen,ycen,sigx,sigy):\n",
" \"\"\" \n",
" Parameters\n",
" ----------\n",
" \n",
" Returns\n",
" -------\n",
" \"\"\"\n",
" ydiff=1./24.*(((i-xcen)**2/sigx**2-1.)/sigx**2 + ((j-ycen)**2/sigy**2-1.)/sigy**2)\n",
" ygauss=np.exp(-.5*((i-xcen)**2/sigx**2))*np.exp(-.5*((j-ycen)**2/sigy**2))\n",
" return ydiff*ygauss\n",
Expand DownExpand Up@@ -272,6 +339,17 @@
"outputs": [],
"source": [
"def calc_and_print_moments(stamp,hsm):\n",
" \"\"\"Calculate and pring the first and second moments for a postage stamp with predetermined hsm measurements\n",
" \n",
" Parameters\n",
" ----------\n",
" stamp : postage stamp array\n",
" hsm : moments calculated from hsm\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" x_hsm,y_hsm,sig_hsm=hsm.moments_centroid.x,hsm.moments_centroid.y,hsm.moments_sigma\n",
" # calculate my moments\n",
" thresh=0\n",
Expand DownExpand Up@@ -330,7 +408,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Making mosaics of objects"
"## Making mosaics of objects\n",
"\n",
"Now that we have the ability to generate and measure one object, we would like to expand our analysis to a statistical set of objects. We add functionality to make a mosaic of sources on a single image."
]
},
{
Expand DownExpand Up@@ -435,7 +515,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Making a mosaic of small spots with a range of sub-pixel centroids"
"## Making a mosaic of small spots with a range of sub-pixel centroids\n",
"\n",
"We create a mosaic of small spots distributed over a range of centroids. The centroids are given sub-pixel offsets to determine the biases of our various fitting methods."
]
},
{
Expand All@@ -456,7 +538,7 @@
" angle_minmax=(0,0),flux_minmax=(1e5,1e5))\n",
"\n",
"mosaic,cat_in=ugal.make_mosaic(cat_in)\n",
"print(time.time()-tstart,\" to simulate \",str(len(cat_in)),\" galaxies\")\n",
"print(\"It took %.2fs to simulate %s spots\"%(time.time()-tstart,str(len(cat_in))))\n",
"\n",
"plt.figure(figsize=(16,16))\n",
"plt.imshow(mosaic,origin='lower',vmax=100),plt.colorbar()"
Expand DownExpand Up@@ -567,7 +649,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Merge in stack measurements to catalog"
"### Merge in stack measurements to catalog\n",
"\n",
"Now that we've run the Stack measurements, we would like to merge them into the same catalog that contains the hsm measurements performed when generating the simulated sources."
]
},
{
Expand DownExpand Up@@ -628,7 +712,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measurement using sextractor wrapper"
"## Measurement using SExtractor wrapper\n",
"\n",
"Below we include some code that can be used to install `sep`, a python wrapper around Source Extractor, and calculate the SExtractor moments."
]
},
{
Expand DownExpand Up@@ -668,7 +754,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measure moments using a non-adaptive method, radially weighting by the input Gaussian $\\sigma$ multiplied by a factor"
"## Custom moments measurement \n",
"\n",
"We now perform a first moments calculation using the method that we defined above in `calc_firstmoms`. This is a non-adaptive method that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor (we choose this factor to be 2 and 5 below)."
]
},
{
Expand DownExpand Up@@ -701,7 +789,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting the centroid bias"
"### Plot centroid bias"
]
},
{
Expand DownExpand Up@@ -741,7 +829,10 @@
},
"source": [
"# Size bias\n",
"Making a mosaic of spots with a range of input sizes $\\sigma$, takes about a minute for 100 objects with 5 million photons"
"\n",
"Make a mosaic of spots with a range of input sizes, $\\sigma$. When generating the mosaic, we also perform a simple moments calculation, which we store in the `cat_in` variable. \n",
"\n",
"This cell takes about **1 minute** to run for 100 objects with 5 million photons."
]
},
{
Expand DownExpand Up@@ -773,6 +864,13 @@
"fits.writeto(mo_dir+'mosaic_sizes.fits',mosaic,overwrite=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we run the stack on the spot mosaic. We add the Stack moment measurements (i.e., the quantities starting with `base_SdssShape`) to the catalog containing the simple moments measurements that we performed when generating the mosaic."
]
},
{
"cell_type": "code",
"execution_count": null,
Expand DownExpand Up@@ -880,7 +978,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## plotting size bias"
"### Plot size bias"
]
},
{
Expand DownExpand Up@@ -923,13 +1021,6 @@
"plt.tight_layout(),plt.subplots_adjust(wspace=.4)\n",
"plt.savefig(mo_dir+'/biased_moments-size.png',dpi=150)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 117 additions & 26 deletions Measurement/UndersampledMoments.ipynb
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,16 +8,16 @@
"source": [
"# Biased moments of undersampled sources\n",
"<br>Owner(s): **Andrew Bradshaw** ([@andrewkbradshaw](https://github.com/LSSTScienceCollaborations/StackClub/issues/new?body=@andrewkbradshaw))\n",
"<br>Last Verified to Run: **2019-08-09**\n",
"<br>Verified Stack Release: **18.0**\n",
"<br>Last Verified to Run: **2019-08-23**\n",
"<br>Verified Stack Release: **18.1.0**\n",
"\n",
"This notebook demonstrates how the measurement of centroid, size, and orientation angles of small sources(relative to the pixel grid) are biased due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"This notebook performs measurements of the centroid, size, and orientation angles of small sources. It goes on to show how these measurements are biased (relative to the pixel grid) due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"\n",
"### Learning Objectives:\n",
"\n",
"After working through this tutorial you should be able to: \n",
"1. Simulate stars and galaxies with a variety of properties, including sub-pixel centroid, size, and orientation angle.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms (including the Stack default).\n",
"\n",
"### References:\n",
"* [galsim.Shear](http://galsim-developers.github.io/GalSim/_build/html/shear.html) - Documentation on how GalSim defines shear\n",
Expand DownExpand Up@@ -65,7 +65,7 @@
"\n",
"We start by setting up a class that uses [GalSim](http://galsim-developers.github.io/GalSim/_build/html/index.html) to generate simulated images and sources. GalSim can provide various levels of realism (e.g., readout noise, sky background, silicon sensor effects, etc.), and these are configurable during the creation of an instance. We also implement a function to use GalSim to generate a Gaussian source with a given centroid, ellipticity, and orientation.\n",
"\n",
"We break up the creation of the `undersampled_galsim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
"We break up the creation of the `UndersampledGalSim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
]
},
{
Expand DownExpand Up@@ -93,7 +93,26 @@
" diffusion_factor=0,stamp_width=31,pixel_scale=0.2,gain=1,\n",
" rngseed=8675309,do_hsm_moments_truefalse=False,sim_sensor_truefalse=False,\n",
" default_gsparams=True):\n",
" \"\"\"Initialize the imager with some basic settings\"\"\"\n",
" \"\"\"Initialize the imager with some basic settings\n",
" \n",
" Parameters\n",
" ----------\n",
" method_of_imaging: how to generate the image ('phot','fft','no_pixel')\n",
" read_noise: Gaussian std dev. of CCD readout noise\n",
" sky_level_pixel: the background noise level (subtracted off)\n",
" diffusion_factor: silicon sensor diffusion factor\n",
" stamp_width: width of each postage stamp (default: 31)\n",
" pixel_scale: pixel scale in arcsec/pixel (LSST = 0.2)\n",
" gain: CCD gain (default: 1)\n",
" rngseed: random number generator seed\n",
" do_hsm_moments_truefalse: do hsm moments measurement\n",
" sim_sensor_truefalse: whether or not to simulate the sensor & diffusion\n",
" default_gsparams: use default GalSim parameters\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" self.method = method_of_imaging # default: phot, fft; no_pixel' might take forever?\n",
" self.sensor = sim_sensor_truefalse # whether or not to simulate the sensor & diffusion\n",
" self.pixel_scale=pixel_scale # pixel scale in arcsec/pixel, LSST = 0.2\n",
Expand DownExpand Up@@ -123,7 +142,20 @@
" def draw_gaussian(self,offset=(0.0,0.0),gal_sigma_pix=1.5,gal_ellip=0,\n",
" gal_angle_deg=0,gal_flux=1e5):\n",
" \"\"\"Draw a Gauassian on the image, using the provided centroid offsets, widths, ellipticity\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\"\"\"\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\n",
" \n",
" Parameters\n",
" ----------\n",
" offset : coordinate offset (preserves sub-pixel offset in even-sized images)\n",
" gal_sigma_pix : standard deviation of Gaussian (unit: pixels)\n",
" gal_ellip : source ellipticity, e; see GalSim.Shear\n",
" gal_angle_deg : source position angle, beta; see GalSim.shear (unit: deg)\n",
" gal_flux : source flux\n",
" \n",
" Returns\n",
" -------\n",
" final,hsm : image array, hsm fit parameters\n",
" \"\"\"\n",
" gal = galsim.Gaussian(sigma = gal_sigma_pix*self.pixel_scale, gsparams=self.gsparams)\n",
" gal_shape = galsim.Shear(e=gal_ellip, beta=gal_angle_deg * galsim.degrees)\n",
" gal = gal.shear(gal_shape)\n",
Expand All@@ -150,7 +182,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Functions to compute first and second moments on images"
"## Custom calculations of first and second moments on images\n",
"\n",
"We define two custom methods to calculate first and second moments on images. These are non-adaptive methods that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor.\n"
]
},
{
Expand All@@ -162,7 +196,20 @@
"def calc_firstmoms(img,coord,winsize,thresh,gwin_sig):\n",
" #print(img[:5,:5],coord,winsize,thresh,gwin_sig)\n",
" \"\"\"Calculates the x and y first moments of the image windowed by winsize at\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\"\"\"\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
" \n",
" Returns\n",
" -------\n",
" xmom, ymom : the x and y first moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" xmom,ymom=0.,0.\n",
" thesum=0.\n",
Expand All@@ -186,7 +233,20 @@
"def calc_secmoms_gwin(img,coord,winsize,thresh,gwin_sig):\n",
" \"\"\"Calculates the x, y, xy, and radial second moments of the image windowed by\n",
" winsize at coord (x,y) and thresholded at thresh, weighted by a Gaussian of \n",
" width gwin_sig\"\"\"\n",
" width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
"\n",
" Returns\n",
" -------\n",
" rmom, xmom, ymom, xymom : radial, x, y, and xy second moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" r2mom,x2mom,y2mom,xy2mom=0.,0.,0.,0.\n",
" thesum=0.\n",
Expand DownExpand Up@@ -215,6 +275,13 @@
" return rmom, xmom, ymom, xymom\n",
"\n",
"def calc_gauss_diff(i,j,xcen,ycen,sigx,sigy):\n",
" \"\"\" \n",
" Parameters\n",
" ----------\n",
" \n",
" Returns\n",
" -------\n",
" \"\"\"\n",
" ydiff=1./24.*(((i-xcen)**2/sigx**2-1.)/sigx**2 + ((j-ycen)**2/sigy**2-1.)/sigy**2)\n",
" ygauss=np.exp(-.5*((i-xcen)**2/sigx**2))*np.exp(-.5*((j-ycen)**2/sigy**2))\n",
" return ydiff*ygauss\n",
Expand DownExpand Up@@ -272,6 +339,17 @@
"outputs": [],
"source": [
"def calc_and_print_moments(stamp,hsm):\n",
" \"\"\"Calculate and pring the first and second moments for a postage stamp with predetermined hsm measurements\n",
" \n",
" Parameters\n",
" ----------\n",
" stamp : postage stamp array\n",
" hsm : moments calculated from hsm\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" x_hsm,y_hsm,sig_hsm=hsm.moments_centroid.x,hsm.moments_centroid.y,hsm.moments_sigma\n",
" # calculate my moments\n",
" thresh=0\n",
Expand DownExpand Up@@ -330,7 +408,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Making mosaics of objects"
"## Making mosaics of objects\n",
"\n",
"Now that we have the ability to generate and measure one object, we would like to expand our analysis to a statistical set of objects. We add functionality to make a mosaic of sources on a single image."
]
},
{
Expand DownExpand Up@@ -435,7 +515,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Making a mosaic of small spots with a range of sub-pixel centroids"
"## Making a mosaic of small spots with a range of sub-pixel centroids\n",
"\n",
"We create a mosaic of small spots distributed over a range of centroids. The centroids are given sub-pixel offsets to determine the biases of our various fitting methods."
]
},
{
Expand All@@ -456,7 +538,7 @@
" angle_minmax=(0,0),flux_minmax=(1e5,1e5))\n",
"\n",
"mosaic,cat_in=ugal.make_mosaic(cat_in)\n",
"print(time.time()-tstart,\" to simulate \",str(len(cat_in)),\" galaxies\")\n",
"print(\"It took %.2fs to simulate %s spots\"%(time.time()-tstart,str(len(cat_in))))\n",
"\n",
"plt.figure(figsize=(16,16))\n",
"plt.imshow(mosaic,origin='lower',vmax=100),plt.colorbar()"
Expand DownExpand Up@@ -567,7 +649,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Merge in stack measurements to catalog"
"### Merge in stack measurements to catalog\n",
"\n",
"Now that we've run the Stack measurements, we would like to merge them into the same catalog that contains the hsm measurements performed when generating the simulated sources."
]
},
{
Expand DownExpand Up@@ -628,7 +712,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measurement using sextractor wrapper"
"## Measurement using SExtractor wrapper\n",
"\n",
"Below we include some code that can be used to install `sep`, a python wrapper around Source Extractor, and calculate the SExtractor moments."
]
},
{
Expand DownExpand Up@@ -668,7 +754,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measure moments using a non-adaptive method, radially weighting by the input Gaussian $\\sigma$ multiplied by a factor"
"## Custom moments measurement \n",
"\n",
"We now perform a first moments calculation using the method that we defined above in `calc_firstmoms`. This is a non-adaptive method that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor (we choose this factor to be 2 and 5 below)."
]
},
{
Expand DownExpand Up@@ -701,7 +789,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting the centroid bias"
"### Plot centroid bias"
]
},
{
Expand DownExpand Up@@ -741,7 +829,10 @@
},
"source": [
"# Size bias\n",
"Making a mosaic of spots with a range of input sizes $\\sigma$, takes about a minute for 100 objects with 5 million photons"
"\n",
"Make a mosaic of spots with a range of input sizes, $\\sigma$. When generating the mosaic, we also perform a simple moments calculation, which we store in the `cat_in` variable. \n",
"\n",
"This cell takes about **1 minute** to run for 100 objects with 5 million photons."
]
},
{
Expand DownExpand Up@@ -773,6 +864,13 @@
"fits.writeto(mo_dir+'mosaic_sizes.fits',mosaic,overwrite=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we run the stack on the spot mosaic. We add the Stack moment measurements (i.e., the quantities starting with `base_SdssShape`) to the catalog containing the simple moments measurements that we performed when generating the mosaic."
]
},
{
"cell_type": "code",
"execution_count": null,
Expand DownExpand Up@@ -880,7 +978,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## plotting size bias"
"### Plot size bias"
]
},
{
Expand DownExpand Up@@ -923,13 +1021,6 @@
"plt.tight_layout(),plt.subplots_adjust(wspace=.4)\n",
"plt.savefig(mo_dir+'/biased_moments-size.png',dpi=150)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 117 additions & 26 deletions Measurement/UndersampledMoments.ipynb
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,16 +8,16 @@
"source": [
"# Biased moments of undersampled sources\n",
"<br>Owner(s): **Andrew Bradshaw** ([@andrewkbradshaw](https://github.com/LSSTScienceCollaborations/StackClub/issues/new?body=@andrewkbradshaw))\n",
"<br>Last Verified to Run: **2019-08-09**\n",
"<br>Verified Stack Release: **18.0**\n",
"<br>Last Verified to Run: **2019-08-23**\n",
"<br>Verified Stack Release: **18.1.0**\n",
"\n",
"This notebook demonstrates how the measurement of centroid, size, and orientation angles of small sources(relative to the pixel grid) are biased due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"This notebook performs measurements of the centroid, size, and orientation angles of small sources. It goes on to show how these measurements are biased (relative to the pixel grid) due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"\n",
"### Learning Objectives:\n",
"\n",
"After working through this tutorial you should be able to: \n",
"1. Simulate stars and galaxies with a variety of properties, including sub-pixel centroid, size, and orientation angle.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms (including the Stack default).\n",
"\n",
"### References:\n",
"* [galsim.Shear](http://galsim-developers.github.io/GalSim/_build/html/shear.html) - Documentation on how GalSim defines shear\n",
Expand DownExpand Up@@ -65,7 +65,7 @@
"\n",
"We start by setting up a class that uses [GalSim](http://galsim-developers.github.io/GalSim/_build/html/index.html) to generate simulated images and sources. GalSim can provide various levels of realism (e.g., readout noise, sky background, silicon sensor effects, etc.), and these are configurable during the creation of an instance. We also implement a function to use GalSim to generate a Gaussian source with a given centroid, ellipticity, and orientation.\n",
"\n",
"We break up the creation of the `undersampled_galsim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
"We break up the creation of the `UndersampledGalSim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
]
},
{
Expand DownExpand Up@@ -93,7 +93,26 @@
" diffusion_factor=0,stamp_width=31,pixel_scale=0.2,gain=1,\n",
" rngseed=8675309,do_hsm_moments_truefalse=False,sim_sensor_truefalse=False,\n",
" default_gsparams=True):\n",
" \"\"\"Initialize the imager with some basic settings\"\"\"\n",
" \"\"\"Initialize the imager with some basic settings\n",
" \n",
" Parameters\n",
" ----------\n",
" method_of_imaging: how to generate the image ('phot','fft','no_pixel')\n",
" read_noise: Gaussian std dev. of CCD readout noise\n",
" sky_level_pixel: the background noise level (subtracted off)\n",
" diffusion_factor: silicon sensor diffusion factor\n",
" stamp_width: width of each postage stamp (default: 31)\n",
" pixel_scale: pixel scale in arcsec/pixel (LSST = 0.2)\n",
" gain: CCD gain (default: 1)\n",
" rngseed: random number generator seed\n",
" do_hsm_moments_truefalse: do hsm moments measurement\n",
" sim_sensor_truefalse: whether or not to simulate the sensor & diffusion\n",
" default_gsparams: use default GalSim parameters\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" self.method = method_of_imaging # default: phot, fft; no_pixel' might take forever?\n",
" self.sensor = sim_sensor_truefalse # whether or not to simulate the sensor & diffusion\n",
" self.pixel_scale=pixel_scale # pixel scale in arcsec/pixel, LSST = 0.2\n",
Expand DownExpand Up@@ -123,7 +142,20 @@
" def draw_gaussian(self,offset=(0.0,0.0),gal_sigma_pix=1.5,gal_ellip=0,\n",
" gal_angle_deg=0,gal_flux=1e5):\n",
" \"\"\"Draw a Gauassian on the image, using the provided centroid offsets, widths, ellipticity\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\"\"\"\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\n",
" \n",
" Parameters\n",
" ----------\n",
" offset : coordinate offset (preserves sub-pixel offset in even-sized images)\n",
" gal_sigma_pix : standard deviation of Gaussian (unit: pixels)\n",
" gal_ellip : source ellipticity, e; see GalSim.Shear\n",
" gal_angle_deg : source position angle, beta; see GalSim.shear (unit: deg)\n",
" gal_flux : source flux\n",
" \n",
" Returns\n",
" -------\n",
" final,hsm : image array, hsm fit parameters\n",
" \"\"\"\n",
" gal = galsim.Gaussian(sigma = gal_sigma_pix*self.pixel_scale, gsparams=self.gsparams)\n",
" gal_shape = galsim.Shear(e=gal_ellip, beta=gal_angle_deg * galsim.degrees)\n",
" gal = gal.shear(gal_shape)\n",
Expand All@@ -150,7 +182,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Functions to compute first and second moments on images"
"## Custom calculations of first and second moments on images\n",
"\n",
"We define two custom methods to calculate first and second moments on images. These are non-adaptive methods that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor.\n"
]
},
{
Expand All@@ -162,7 +196,20 @@
"def calc_firstmoms(img,coord,winsize,thresh,gwin_sig):\n",
" #print(img[:5,:5],coord,winsize,thresh,gwin_sig)\n",
" \"\"\"Calculates the x and y first moments of the image windowed by winsize at\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\"\"\"\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
" \n",
" Returns\n",
" -------\n",
" xmom, ymom : the x and y first moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" xmom,ymom=0.,0.\n",
" thesum=0.\n",
Expand All@@ -186,7 +233,20 @@
"def calc_secmoms_gwin(img,coord,winsize,thresh,gwin_sig):\n",
" \"\"\"Calculates the x, y, xy, and radial second moments of the image windowed by\n",
" winsize at coord (x,y) and thresholded at thresh, weighted by a Gaussian of \n",
" width gwin_sig\"\"\"\n",
" width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
"\n",
" Returns\n",
" -------\n",
" rmom, xmom, ymom, xymom : radial, x, y, and xy second moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" r2mom,x2mom,y2mom,xy2mom=0.,0.,0.,0.\n",
" thesum=0.\n",
Expand DownExpand Up@@ -215,6 +275,13 @@
" return rmom, xmom, ymom, xymom\n",
"\n",
"def calc_gauss_diff(i,j,xcen,ycen,sigx,sigy):\n",
" \"\"\" \n",
" Parameters\n",
" ----------\n",
" \n",
" Returns\n",
" -------\n",
" \"\"\"\n",
" ydiff=1./24.*(((i-xcen)**2/sigx**2-1.)/sigx**2 + ((j-ycen)**2/sigy**2-1.)/sigy**2)\n",
" ygauss=np.exp(-.5*((i-xcen)**2/sigx**2))*np.exp(-.5*((j-ycen)**2/sigy**2))\n",
" return ydiff*ygauss\n",
Expand DownExpand Up@@ -272,6 +339,17 @@
"outputs": [],
"source": [
"def calc_and_print_moments(stamp,hsm):\n",
" \"\"\"Calculate and pring the first and second moments for a postage stamp with predetermined hsm measurements\n",
" \n",
" Parameters\n",
" ----------\n",
" stamp : postage stamp array\n",
" hsm : moments calculated from hsm\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" x_hsm,y_hsm,sig_hsm=hsm.moments_centroid.x,hsm.moments_centroid.y,hsm.moments_sigma\n",
" # calculate my moments\n",
" thresh=0\n",
Expand DownExpand Up@@ -330,7 +408,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Making mosaics of objects"
"## Making mosaics of objects\n",
"\n",
"Now that we have the ability to generate and measure one object, we would like to expand our analysis to a statistical set of objects. We add functionality to make a mosaic of sources on a single image."
]
},
{
Expand DownExpand Up@@ -435,7 +515,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Making a mosaic of small spots with a range of sub-pixel centroids"
"## Making a mosaic of small spots with a range of sub-pixel centroids\n",
"\n",
"We create a mosaic of small spots distributed over a range of centroids. The centroids are given sub-pixel offsets to determine the biases of our various fitting methods."
]
},
{
Expand All@@ -456,7 +538,7 @@
" angle_minmax=(0,0),flux_minmax=(1e5,1e5))\n",
"\n",
"mosaic,cat_in=ugal.make_mosaic(cat_in)\n",
"print(time.time()-tstart,\" to simulate \",str(len(cat_in)),\" galaxies\")\n",
"print(\"It took %.2fs to simulate %s spots\"%(time.time()-tstart,str(len(cat_in))))\n",
"\n",
"plt.figure(figsize=(16,16))\n",
"plt.imshow(mosaic,origin='lower',vmax=100),plt.colorbar()"
Expand DownExpand Up@@ -567,7 +649,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Merge in stack measurements to catalog"
"### Merge in stack measurements to catalog\n",
"\n",
"Now that we've run the Stack measurements, we would like to merge them into the same catalog that contains the hsm measurements performed when generating the simulated sources."
]
},
{
Expand DownExpand Up@@ -628,7 +712,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measurement using sextractor wrapper"
"## Measurement using SExtractor wrapper\n",
"\n",
"Below we include some code that can be used to install `sep`, a python wrapper around Source Extractor, and calculate the SExtractor moments."
]
},
{
Expand DownExpand Up@@ -668,7 +754,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measure moments using a non-adaptive method, radially weighting by the input Gaussian $\\sigma$ multiplied by a factor"
"## Custom moments measurement \n",
"\n",
"We now perform a first moments calculation using the method that we defined above in `calc_firstmoms`. This is a non-adaptive method that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor (we choose this factor to be 2 and 5 below)."
]
},
{
Expand DownExpand Up@@ -701,7 +789,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting the centroid bias"
"### Plot centroid bias"
]
},
{
Expand DownExpand Up@@ -741,7 +829,10 @@
},
"source": [
"# Size bias\n",
"Making a mosaic of spots with a range of input sizes $\\sigma$, takes about a minute for 100 objects with 5 million photons"
"\n",
"Make a mosaic of spots with a range of input sizes, $\\sigma$. When generating the mosaic, we also perform a simple moments calculation, which we store in the `cat_in` variable. \n",
"\n",
"This cell takes about **1 minute** to run for 100 objects with 5 million photons."
]
},
{
Expand DownExpand Up@@ -773,6 +864,13 @@
"fits.writeto(mo_dir+'mosaic_sizes.fits',mosaic,overwrite=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we run the stack on the spot mosaic. We add the Stack moment measurements (i.e., the quantities starting with `base_SdssShape`) to the catalog containing the simple moments measurements that we performed when generating the mosaic."
]
},
{
"cell_type": "code",
"execution_count": null,
Expand DownExpand Up@@ -880,7 +978,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## plotting size bias"
"### Plot size bias"
]
},
{
Expand DownExpand Up@@ -923,13 +1021,6 @@
"plt.tight_layout(),plt.subplots_adjust(wspace=.4)\n",
"plt.savefig(mo_dir+'/biased_moments-size.png',dpi=150)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 117 additions & 26 deletions Measurement/UndersampledMoments.ipynb
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,16 +8,16 @@
"source": [
"# Biased moments of undersampled sources\n",
"<br>Owner(s): **Andrew Bradshaw** ([@andrewkbradshaw](https://github.com/LSSTScienceCollaborations/StackClub/issues/new?body=@andrewkbradshaw))\n",
"<br>Last Verified to Run: **2019-08-09**\n",
"<br>Verified Stack Release: **18.0**\n",
"<br>Last Verified to Run: **2019-08-23**\n",
"<br>Verified Stack Release: **18.1.0**\n",
"\n",
"This notebook demonstrates how the measurement of centroid, size, and orientation angles of small sources(relative to the pixel grid) are biased due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"This notebook performs measurements of the centroid, size, and orientation angles of small sources. It goes on to show how these measurements are biased (relative to the pixel grid) due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"\n",
"### Learning Objectives:\n",
"\n",
"After working through this tutorial you should be able to: \n",
"1. Simulate stars and galaxies with a variety of properties, including sub-pixel centroid, size, and orientation angle.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms (including the Stack default).\n",
"\n",
"### References:\n",
"* [galsim.Shear](http://galsim-developers.github.io/GalSim/_build/html/shear.html) - Documentation on how GalSim defines shear\n",
Expand DownExpand Up@@ -65,7 +65,7 @@
"\n",
"We start by setting up a class that uses [GalSim](http://galsim-developers.github.io/GalSim/_build/html/index.html) to generate simulated images and sources. GalSim can provide various levels of realism (e.g., readout noise, sky background, silicon sensor effects, etc.), and these are configurable during the creation of an instance. We also implement a function to use GalSim to generate a Gaussian source with a given centroid, ellipticity, and orientation.\n",
"\n",
"We break up the creation of the `undersampled_galsim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
"We break up the creation of the `UndersampledGalSim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
]
},
{
Expand DownExpand Up@@ -93,7 +93,26 @@
" diffusion_factor=0,stamp_width=31,pixel_scale=0.2,gain=1,\n",
" rngseed=8675309,do_hsm_moments_truefalse=False,sim_sensor_truefalse=False,\n",
" default_gsparams=True):\n",
" \"\"\"Initialize the imager with some basic settings\"\"\"\n",
" \"\"\"Initialize the imager with some basic settings\n",
" \n",
" Parameters\n",
" ----------\n",
" method_of_imaging: how to generate the image ('phot','fft','no_pixel')\n",
" read_noise: Gaussian std dev. of CCD readout noise\n",
" sky_level_pixel: the background noise level (subtracted off)\n",
" diffusion_factor: silicon sensor diffusion factor\n",
" stamp_width: width of each postage stamp (default: 31)\n",
" pixel_scale: pixel scale in arcsec/pixel (LSST = 0.2)\n",
" gain: CCD gain (default: 1)\n",
" rngseed: random number generator seed\n",
" do_hsm_moments_truefalse: do hsm moments measurement\n",
" sim_sensor_truefalse: whether or not to simulate the sensor & diffusion\n",
" default_gsparams: use default GalSim parameters\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" self.method = method_of_imaging # default: phot, fft; no_pixel' might take forever?\n",
" self.sensor = sim_sensor_truefalse # whether or not to simulate the sensor & diffusion\n",
" self.pixel_scale=pixel_scale # pixel scale in arcsec/pixel, LSST = 0.2\n",
Expand DownExpand Up@@ -123,7 +142,20 @@
" def draw_gaussian(self,offset=(0.0,0.0),gal_sigma_pix=1.5,gal_ellip=0,\n",
" gal_angle_deg=0,gal_flux=1e5):\n",
" \"\"\"Draw a Gauassian on the image, using the provided centroid offsets, widths, ellipticity\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\"\"\"\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\n",
" \n",
" Parameters\n",
" ----------\n",
" offset : coordinate offset (preserves sub-pixel offset in even-sized images)\n",
" gal_sigma_pix : standard deviation of Gaussian (unit: pixels)\n",
" gal_ellip : source ellipticity, e; see GalSim.Shear\n",
" gal_angle_deg : source position angle, beta; see GalSim.shear (unit: deg)\n",
" gal_flux : source flux\n",
" \n",
" Returns\n",
" -------\n",
" final,hsm : image array, hsm fit parameters\n",
" \"\"\"\n",
" gal = galsim.Gaussian(sigma = gal_sigma_pix*self.pixel_scale, gsparams=self.gsparams)\n",
" gal_shape = galsim.Shear(e=gal_ellip, beta=gal_angle_deg * galsim.degrees)\n",
" gal = gal.shear(gal_shape)\n",
Expand All@@ -150,7 +182,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Functions to compute first and second moments on images"
"## Custom calculations of first and second moments on images\n",
"\n",
"We define two custom methods to calculate first and second moments on images. These are non-adaptive methods that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor.\n"
]
},
{
Expand All@@ -162,7 +196,20 @@
"def calc_firstmoms(img,coord,winsize,thresh,gwin_sig):\n",
" #print(img[:5,:5],coord,winsize,thresh,gwin_sig)\n",
" \"\"\"Calculates the x and y first moments of the image windowed by winsize at\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\"\"\"\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
" \n",
" Returns\n",
" -------\n",
" xmom, ymom : the x and y first moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" xmom,ymom=0.,0.\n",
" thesum=0.\n",
Expand All@@ -186,7 +233,20 @@
"def calc_secmoms_gwin(img,coord,winsize,thresh,gwin_sig):\n",
" \"\"\"Calculates the x, y, xy, and radial second moments of the image windowed by\n",
" winsize at coord (x,y) and thresholded at thresh, weighted by a Gaussian of \n",
" width gwin_sig\"\"\"\n",
" width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
"\n",
" Returns\n",
" -------\n",
" rmom, xmom, ymom, xymom : radial, x, y, and xy second moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" r2mom,x2mom,y2mom,xy2mom=0.,0.,0.,0.\n",
" thesum=0.\n",
Expand DownExpand Up@@ -215,6 +275,13 @@
" return rmom, xmom, ymom, xymom\n",
"\n",
"def calc_gauss_diff(i,j,xcen,ycen,sigx,sigy):\n",
" \"\"\" \n",
" Parameters\n",
" ----------\n",
" \n",
" Returns\n",
" -------\n",
" \"\"\"\n",
" ydiff=1./24.*(((i-xcen)**2/sigx**2-1.)/sigx**2 + ((j-ycen)**2/sigy**2-1.)/sigy**2)\n",
" ygauss=np.exp(-.5*((i-xcen)**2/sigx**2))*np.exp(-.5*((j-ycen)**2/sigy**2))\n",
" return ydiff*ygauss\n",
Expand DownExpand Up@@ -272,6 +339,17 @@
"outputs": [],
"source": [
"def calc_and_print_moments(stamp,hsm):\n",
" \"\"\"Calculate and pring the first and second moments for a postage stamp with predetermined hsm measurements\n",
" \n",
" Parameters\n",
" ----------\n",
" stamp : postage stamp array\n",
" hsm : moments calculated from hsm\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" x_hsm,y_hsm,sig_hsm=hsm.moments_centroid.x,hsm.moments_centroid.y,hsm.moments_sigma\n",
" # calculate my moments\n",
" thresh=0\n",
Expand DownExpand Up@@ -330,7 +408,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Making mosaics of objects"
"## Making mosaics of objects\n",
"\n",
"Now that we have the ability to generate and measure one object, we would like to expand our analysis to a statistical set of objects. We add functionality to make a mosaic of sources on a single image."
]
},
{
Expand DownExpand Up@@ -435,7 +515,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Making a mosaic of small spots with a range of sub-pixel centroids"
"## Making a mosaic of small spots with a range of sub-pixel centroids\n",
"\n",
"We create a mosaic of small spots distributed over a range of centroids. The centroids are given sub-pixel offsets to determine the biases of our various fitting methods."
]
},
{
Expand All@@ -456,7 +538,7 @@
" angle_minmax=(0,0),flux_minmax=(1e5,1e5))\n",
"\n",
"mosaic,cat_in=ugal.make_mosaic(cat_in)\n",
"print(time.time()-tstart,\" to simulate \",str(len(cat_in)),\" galaxies\")\n",
"print(\"It took %.2fs to simulate %s spots\"%(time.time()-tstart,str(len(cat_in))))\n",
"\n",
"plt.figure(figsize=(16,16))\n",
"plt.imshow(mosaic,origin='lower',vmax=100),plt.colorbar()"
Expand DownExpand Up@@ -567,7 +649,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Merge in stack measurements to catalog"
"### Merge in stack measurements to catalog\n",
"\n",
"Now that we've run the Stack measurements, we would like to merge them into the same catalog that contains the hsm measurements performed when generating the simulated sources."
]
},
{
Expand DownExpand Up@@ -628,7 +712,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measurement using sextractor wrapper"
"## Measurement using SExtractor wrapper\n",
"\n",
"Below we include some code that can be used to install `sep`, a python wrapper around Source Extractor, and calculate the SExtractor moments."
]
},
{
Expand DownExpand Up@@ -668,7 +754,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measure moments using a non-adaptive method, radially weighting by the input Gaussian $\\sigma$ multiplied by a factor"
"## Custom moments measurement \n",
"\n",
"We now perform a first moments calculation using the method that we defined above in `calc_firstmoms`. This is a non-adaptive method that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor (we choose this factor to be 2 and 5 below)."
]
},
{
Expand DownExpand Up@@ -701,7 +789,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting the centroid bias"
"### Plot centroid bias"
]
},
{
Expand DownExpand Up@@ -741,7 +829,10 @@
},
"source": [
"# Size bias\n",
"Making a mosaic of spots with a range of input sizes $\\sigma$, takes about a minute for 100 objects with 5 million photons"
"\n",
"Make a mosaic of spots with a range of input sizes, $\\sigma$. When generating the mosaic, we also perform a simple moments calculation, which we store in the `cat_in` variable. \n",
"\n",
"This cell takes about **1 minute** to run for 100 objects with 5 million photons."
]
},
{
Expand DownExpand Up@@ -773,6 +864,13 @@
"fits.writeto(mo_dir+'mosaic_sizes.fits',mosaic,overwrite=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we run the stack on the spot mosaic. We add the Stack moment measurements (i.e., the quantities starting with `base_SdssShape`) to the catalog containing the simple moments measurements that we performed when generating the mosaic."
]
},
{
"cell_type": "code",
"execution_count": null,
Expand DownExpand Up@@ -880,7 +978,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## plotting size bias"
"### Plot size bias"
]
},
{
Expand DownExpand Up@@ -923,13 +1021,6 @@
"plt.tight_layout(),plt.subplots_adjust(wspace=.4)\n",
"plt.savefig(mo_dir+'/biased_moments-size.png',dpi=150)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 117 additions & 26 deletions Measurement/UndersampledMoments.ipynb
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,16 +8,16 @@
"source": [
"# Biased moments of undersampled sources\n",
"<br>Owner(s): **Andrew Bradshaw** ([@andrewkbradshaw](https://github.com/LSSTScienceCollaborations/StackClub/issues/new?body=@andrewkbradshaw))\n",
"<br>Last Verified to Run: **2019-08-09**\n",
"<br>Verified Stack Release: **18.0**\n",
"<br>Last Verified to Run: **2019-08-23**\n",
"<br>Verified Stack Release: **18.1.0**\n",
"\n",
"This notebook demonstrates how the measurement of centroid, size, and orientation angles of small sources(relative to the pixel grid) are biased due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"This notebook performs measurements of the centroid, size, and orientation angles of small sources. It goes on to show how these measurements are biased (relative to the pixel grid) due to undersampling and/or assumptions in the method of analysis. A possible improvement, in the form of a modified weight function, is shown to have a positive effect.\n",
"\n",
"### Learning Objectives:\n",
"\n",
"After working through this tutorial you should be able to: \n",
"1. Simulate stars and galaxies with a variety of properties, including sub-pixel centroid, size, and orientation angle.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms.\n",
"2. Measure the centroid, size, and orientation angle using a variety of algorithms (including the Stack default).\n",
"\n",
"### References:\n",
"* [galsim.Shear](http://galsim-developers.github.io/GalSim/_build/html/shear.html) - Documentation on how GalSim defines shear\n",
Expand DownExpand Up@@ -65,7 +65,7 @@
"\n",
"We start by setting up a class that uses [GalSim](http://galsim-developers.github.io/GalSim/_build/html/index.html) to generate simulated images and sources. GalSim can provide various levels of realism (e.g., readout noise, sky background, silicon sensor effects, etc.), and these are configurable during the creation of an instance. We also implement a function to use GalSim to generate a Gaussian source with a given centroid, ellipticity, and orientation.\n",
"\n",
"We break up the creation of the `undersampled_galsim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
"We break up the creation of the `UndersampledGalSim` class so that the various components can be explored in turn, rather than as one monolithic block. To do this, we subclass the existing class and add new methods."
]
},
{
Expand DownExpand Up@@ -93,7 +93,26 @@
" diffusion_factor=0,stamp_width=31,pixel_scale=0.2,gain=1,\n",
" rngseed=8675309,do_hsm_moments_truefalse=False,sim_sensor_truefalse=False,\n",
" default_gsparams=True):\n",
" \"\"\"Initialize the imager with some basic settings\"\"\"\n",
" \"\"\"Initialize the imager with some basic settings\n",
" \n",
" Parameters\n",
" ----------\n",
" method_of_imaging: how to generate the image ('phot','fft','no_pixel')\n",
" read_noise: Gaussian std dev. of CCD readout noise\n",
" sky_level_pixel: the background noise level (subtracted off)\n",
" diffusion_factor: silicon sensor diffusion factor\n",
" stamp_width: width of each postage stamp (default: 31)\n",
" pixel_scale: pixel scale in arcsec/pixel (LSST = 0.2)\n",
" gain: CCD gain (default: 1)\n",
" rngseed: random number generator seed\n",
" do_hsm_moments_truefalse: do hsm moments measurement\n",
" sim_sensor_truefalse: whether or not to simulate the sensor & diffusion\n",
" default_gsparams: use default GalSim parameters\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" self.method = method_of_imaging # default: phot, fft; no_pixel' might take forever?\n",
" self.sensor = sim_sensor_truefalse # whether or not to simulate the sensor & diffusion\n",
" self.pixel_scale=pixel_scale # pixel scale in arcsec/pixel, LSST = 0.2\n",
Expand DownExpand Up@@ -123,7 +142,20 @@
" def draw_gaussian(self,offset=(0.0,0.0),gal_sigma_pix=1.5,gal_ellip=0,\n",
" gal_angle_deg=0,gal_flux=1e5):\n",
" \"\"\"Draw a Gauassian on the image, using the provided centroid offsets, widths, ellipticity\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\"\"\"\n",
" angle, and flux. Returns the galsim object and HSM moments (if do_hsm is set to True)\n",
" \n",
" Parameters\n",
" ----------\n",
" offset : coordinate offset (preserves sub-pixel offset in even-sized images)\n",
" gal_sigma_pix : standard deviation of Gaussian (unit: pixels)\n",
" gal_ellip : source ellipticity, e; see GalSim.Shear\n",
" gal_angle_deg : source position angle, beta; see GalSim.shear (unit: deg)\n",
" gal_flux : source flux\n",
" \n",
" Returns\n",
" -------\n",
" final,hsm : image array, hsm fit parameters\n",
" \"\"\"\n",
" gal = galsim.Gaussian(sigma = gal_sigma_pix*self.pixel_scale, gsparams=self.gsparams)\n",
" gal_shape = galsim.Shear(e=gal_ellip, beta=gal_angle_deg * galsim.degrees)\n",
" gal = gal.shear(gal_shape)\n",
Expand All@@ -150,7 +182,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Functions to compute first and second moments on images"
"## Custom calculations of first and second moments on images\n",
"\n",
"We define two custom methods to calculate first and second moments on images. These are non-adaptive methods that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor.\n"
]
},
{
Expand All@@ -162,7 +196,20 @@
"def calc_firstmoms(img,coord,winsize,thresh,gwin_sig):\n",
" #print(img[:5,:5],coord,winsize,thresh,gwin_sig)\n",
" \"\"\"Calculates the x and y first moments of the image windowed by winsize at\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\"\"\"\n",
" coord (x,y), weighted with a Gaussian of width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
" \n",
" Returns\n",
" -------\n",
" xmom, ymom : the x and y first moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" xmom,ymom=0.,0.\n",
" thesum=0.\n",
Expand All@@ -186,7 +233,20 @@
"def calc_secmoms_gwin(img,coord,winsize,thresh,gwin_sig):\n",
" \"\"\"Calculates the x, y, xy, and radial second moments of the image windowed by\n",
" winsize at coord (x,y) and thresholded at thresh, weighted by a Gaussian of \n",
" width gwin_sig\"\"\"\n",
" width gwin_sig\n",
" \n",
" Parameters\n",
" ----------\n",
" img : input image array\n",
" coord : centroid coordinate (pixels)\n",
" winsize : window size (pixels)\n",
" thresh : threshold value for defining pixels in the source\n",
" gwin_sig : width of the Gaussian weighting function (pixels)\n",
"\n",
" Returns\n",
" -------\n",
" rmom, xmom, ymom, xymom : radial, x, y, and xy second moments of the source\n",
" \"\"\"\n",
" xc,yc=coord\n",
" r2mom,x2mom,y2mom,xy2mom=0.,0.,0.,0.\n",
" thesum=0.\n",
Expand DownExpand Up@@ -215,6 +275,13 @@
" return rmom, xmom, ymom, xymom\n",
"\n",
"def calc_gauss_diff(i,j,xcen,ycen,sigx,sigy):\n",
" \"\"\" \n",
" Parameters\n",
" ----------\n",
" \n",
" Returns\n",
" -------\n",
" \"\"\"\n",
" ydiff=1./24.*(((i-xcen)**2/sigx**2-1.)/sigx**2 + ((j-ycen)**2/sigy**2-1.)/sigy**2)\n",
" ygauss=np.exp(-.5*((i-xcen)**2/sigx**2))*np.exp(-.5*((j-ycen)**2/sigy**2))\n",
" return ydiff*ygauss\n",
Expand DownExpand Up@@ -272,6 +339,17 @@
"outputs": [],
"source": [
"def calc_and_print_moments(stamp,hsm):\n",
" \"\"\"Calculate and pring the first and second moments for a postage stamp with predetermined hsm measurements\n",
" \n",
" Parameters\n",
" ----------\n",
" stamp : postage stamp array\n",
" hsm : moments calculated from hsm\n",
" \n",
" Returns\n",
" -------\n",
" None\n",
" \"\"\"\n",
" x_hsm,y_hsm,sig_hsm=hsm.moments_centroid.x,hsm.moments_centroid.y,hsm.moments_sigma\n",
" # calculate my moments\n",
" thresh=0\n",
Expand DownExpand Up@@ -330,7 +408,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Making mosaics of objects"
"## Making mosaics of objects\n",
"\n",
"Now that we have the ability to generate and measure one object, we would like to expand our analysis to a statistical set of objects. We add functionality to make a mosaic of sources on a single image."
]
},
{
Expand DownExpand Up@@ -435,7 +515,9 @@
"toc-hr-collapsed": true
},
"source": [
"## Making a mosaic of small spots with a range of sub-pixel centroids"
"## Making a mosaic of small spots with a range of sub-pixel centroids\n",
"\n",
"We create a mosaic of small spots distributed over a range of centroids. The centroids are given sub-pixel offsets to determine the biases of our various fitting methods."
]
},
{
Expand All@@ -456,7 +538,7 @@
" angle_minmax=(0,0),flux_minmax=(1e5,1e5))\n",
"\n",
"mosaic,cat_in=ugal.make_mosaic(cat_in)\n",
"print(time.time()-tstart,\" to simulate \",str(len(cat_in)),\" galaxies\")\n",
"print(\"It took %.2fs to simulate %s spots\"%(time.time()-tstart,str(len(cat_in))))\n",
"\n",
"plt.figure(figsize=(16,16))\n",
"plt.imshow(mosaic,origin='lower',vmax=100),plt.colorbar()"
Expand DownExpand Up@@ -567,7 +649,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Merge in stack measurements to catalog"
"### Merge in stack measurements to catalog\n",
"\n",
"Now that we've run the Stack measurements, we would like to merge them into the same catalog that contains the hsm measurements performed when generating the simulated sources."
]
},
{
Expand DownExpand Up@@ -628,7 +712,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measurement using sextractor wrapper"
"## Measurement using SExtractor wrapper\n",
"\n",
"Below we include some code that can be used to install `sep`, a python wrapper around Source Extractor, and calculate the SExtractor moments."
]
},
{
Expand DownExpand Up@@ -668,7 +754,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Measure moments using a non-adaptive method, radially weighting by the input Gaussian $\\sigma$ multiplied by a factor"
"## Custom moments measurement \n",
"\n",
"We now perform a first moments calculation using the method that we defined above in `calc_firstmoms`. This is a non-adaptive method that radially weights by the standard deviation of the input Gaussian multiplied by some chosen pre-factor (we choose this factor to be 2 and 5 below)."
]
},
{
Expand DownExpand Up@@ -701,7 +789,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting the centroid bias"
"### Plot centroid bias"
]
},
{
Expand DownExpand Up@@ -741,7 +829,10 @@
},
"source": [
"# Size bias\n",
"Making a mosaic of spots with a range of input sizes $\\sigma$, takes about a minute for 100 objects with 5 million photons"
"\n",
"Make a mosaic of spots with a range of input sizes, $\\sigma$. When generating the mosaic, we also perform a simple moments calculation, which we store in the `cat_in` variable. \n",
"\n",
"This cell takes about **1 minute** to run for 100 objects with 5 million photons."
]
},
{
Expand DownExpand Up@@ -773,6 +864,13 @@
"fits.writeto(mo_dir+'mosaic_sizes.fits',mosaic,overwrite=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we run the stack on the spot mosaic. We add the Stack moment measurements (i.e., the quantities starting with `base_SdssShape`) to the catalog containing the simple moments measurements that we performed when generating the mosaic."
]
},
{
"cell_type": "code",
"execution_count": null,
Expand DownExpand Up@@ -880,7 +978,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## plotting size bias"
"### Plot size bias"
]
},
{
Expand DownExpand Up@@ -923,13 +1021,6 @@
"plt.tight_layout(),plt.subplots_adjust(wspace=.4)\n",
"plt.savefig(mo_dir+'/biased_moments-size.png',dpi=150)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down