import numpy as np
import matplotlib.pyplot as plt
import astroapers as aapQuickstart aperture sums
This notebook measures a synthetic source with exact circular aperture aperture summation. The point is to show the shortest useful workflow: create an aperture, call apsum_exact(), and interpret the returned flux and effective pixel area.
Make a small image
The source center is in (x, y) order, matching Photutils and SEP pixel coordinates.
ny, nx = 30, 40
y, x = np.mgrid[:ny, :nx]
x0, y0 = 15.2, 17.6
background = 12.0
# make a Gaussian source
amplitude = 150.0
sigma = 3.0
source = amplitude * np.exp(-0.5 * ((x - x0) ** 2 + (y - y0) ** 2) / sigma**2)
data = background + sourcefig, ax = plt.subplots(figsize=(5, 4))
ax.imshow(data, origin="lower", cmap="viridis")
ax.set_title("Synthetic image")
ax.set_xlabel("x pixel")
ax.set_ylabel("y pixel")
plt.show()
Measure an aperture sum
CircAp.apsum_exact() uses exact fractional pixel overlap for circular apertures. It returns the weighted sum and the in-frame weighted pixel count.
ap = aap.CircAp((x0, y0), r=5.0)
apsum, npix = ap.apsum_exact(data, return_npix=True)
apsum, npix, ap.area, npix == ap.area(array(7283.74585208), array(78.53981634), 78.53981633974483, np.True_)
The source flux above a known constant background is:
# Use a known background level for this synthetic example.
srcsum = apsum - background * npix
print(f"Net flux: {srcsum:.2f} = apsum({apsum:.2f}) - background({background:.2f}) * npix({npix:.2f})")Net flux: 6341.27 = apsum(7283.75) - background(12.00) * npix(78.54)
Overlay the aperture
fig, ax = plt.subplots(figsize=(5, 4))
ax.imshow(data, origin="lower", cmap="viridis")
ap.plot(ax=ax, color="r", lw=1.5)
ax.set(title="CircAp.plot()")
plt.show()
Maximum Performance
For fixed production code, import the raw Rust extension as aapr. The raw functions expect contiguous arrays and positional geometry arguments. They do not provide masks, validation, keyword arguments, or Python result shaping. For more usage patterns, inspect astroapers.kernels, which is the Python layer that calls _rust internally.
import astroapers._rust as aapr
raw_data = np.ascontiguousarray(data, dtype=np.float64)
xpos = np.ascontiguousarray([x0], dtype=np.float64)
ypos = np.ascontiguousarray([y0], dtype=np.float64)
raw_apsum, raw_npix = aapr.apsum_circ_exact(raw_data, xpos, ypos, 5.0)
raw_sum_only = aapr.apsum_circ_exact_sum(raw_data, xpos, ypos, 5.0)
assert np.allclose(raw_apsum[0], apsum)
assert np.allclose(raw_npix[0], npix)
assert np.allclose(raw_sum_only[0], apsum)
raw_apsum[0], raw_npix[0], raw_sum_only[0](7283.745852078197, 78.53981633974483, 7283.745852078197)