-
Notifications
You must be signed in to change notification settings - Fork 67
Fix the blend filter's FOV pre-filter units and bound its memory #939
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: prerelease
Are you sure you want to change the base?
Changes from 1 commit
cd62e52
1910164
e41c4ad
b812ff9
608a5c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -161,9 +161,9 @@ def filterBlendedStars(paired_stars, catalog_stars, platepar, jd, lim_mag, | |
| cos_ang_dist = np.clip(cos_ang_dist, -1, 1) | ||
| ang_dist_deg = np.degrees(np.arccos(cos_ang_dist)) | ||
|
|
||
| # Estimate FOV radius from platepar (diagonal / 2 * scale, with margin) | ||
| # Estimate FOV radius from platepar (F_scale is px/deg), with margin | ||
| fov_diagonal = np.sqrt(platepar.X_res**2 + platepar.Y_res**2) | ||
| fov_radius = (fov_diagonal / 2) * platepar.F_scale * 1.5 # 50% margin | ||
| fov_radius = (fov_diagonal / 2) / platepar.F_scale * 1.5 # 50% margin | ||
| fov_radius = min(fov_radius, 90) # Cap at 90 degrees | ||
|
|
||
| in_fov = ang_dist_deg < fov_radius | ||
|
|
@@ -198,15 +198,24 @@ def filterBlendedStars(paired_stars, catalog_stars, platepar, jd, lim_mag, | |
| np.array(matched_ra_list), np.array(matched_dec_list), jd, platepar) | ||
| blend_radii = np.array(blend_radii) | ||
|
|
||
| # Compute distance from each matched star to all bright catalog stars using broadcasting | ||
| # Shape: (n_matched, n_catalog) | ||
| dx = all_matched_x[:, np.newaxis] - catalog_x[np.newaxis, :] | ||
| dy = all_matched_y[:, np.newaxis] - catalog_y[np.newaxis, :] | ||
| dist_matrix = np.sqrt(dx**2 + dy**2) | ||
|
|
||
| # Check for neighbors within each star's blend radius (excluding self) | ||
| has_neighbor = np.any( | ||
| (dist_matrix < blend_radii[:, np.newaxis]) & (dist_matrix > 0.1), axis=1) | ||
| # Compute distance from each matched star to all bright catalog stars using | ||
| # broadcasting, in catalog chunks so peak memory stays bounded no matter how | ||
| # many catalog stars survived the pre-filters (a deep catalog fed through the | ||
| # broken FOV pre-filter above used to allocate multi-GB matrices here and get | ||
| # the process OOM-killed) | ||
| # Shape per chunk: (n_matched, chunk) | ||
| n_matched = len(check_indices) | ||
| chunk_size = max(1, int(5e6) // n_matched) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The budget counts elements, not bytes, and doesn't account for how many arrays are live at once. 5e6 float64 = 40 MB per array, but Two cheap tightenings:
Nit while you're here: |
||
| has_neighbor = np.zeros(n_matched, dtype=bool) | ||
| for c0 in range(0, len(catalog_x), chunk_size): | ||
| c1 = c0 + chunk_size | ||
| dx = all_matched_x[:, np.newaxis] - catalog_x[np.newaxis, c0:c1] | ||
| dy = all_matched_y[:, np.newaxis] - catalog_y[np.newaxis, c0:c1] | ||
| dist_matrix = np.sqrt(dx**2 + dy**2) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chunking bounds the memory but leaves the time at O(n_matched × n_catalog) — still ~10⁸ distance evaluations per call with a deep catalog even after the FOV fix, and The codebase already has the answer and documents the reasoning: tree = cKDTree(np.column_stack([catalog_x, catalog_y]))
# k=2: the star itself (d~0) plus its nearest neighbour
d, _ = tree.query(np.column_stack([all_matched_x, all_matched_y]), k=2)
has_neighbor = (d[:, 1] < blend_radii) & (d[:, 1] > 0.1)Constant memory, no chunk-size knob to tune, and it deletes the loop rather than sizing it. |
||
|
|
||
| # Check for neighbors within each star's blend radius (excluding self) | ||
| has_neighbor |= np.any( | ||
| (dist_matrix < blend_radii[:, np.newaxis]) & (dist_matrix > 0.1), axis=1) | ||
|
|
||
| for k, idx in enumerate(check_indices): | ||
| if has_neighbor[k]: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5895,8 +5895,9 @@ def count_matches_at_lm(test_lm): | |
| ang_dist_deg = np.degrees(np.arccos(cos_ang_dist)) | ||
|
|
||
| # FOV radius with margin (stars behind camera have ang_dist > 90) | ||
| # F_scale is px/deg, so divide to convert the pixel diagonal to degrees | ||
| fov_diagonal = np.sqrt(self.platepar.X_res**2 + self.platepar.Y_res**2) | ||
| fov_radius = (fov_diagonal / 2) * self.platepar.F_scale * 1.5 | ||
| fov_radius = (fov_diagonal / 2) / self.platepar.F_scale * 1.5 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same fix, correct — but this is the duplication half of the point I left on Swapping both copies for |
||
| fov_radius = min(fov_radius, 90) | ||
|
|
||
| in_fov = ang_dist_deg < fov_radius | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The units are now right, but this hand-rolled estimate doesn't need to exist —
getFOVSelectionRadius(platepar)(RMS/Astrometry/ApplyAstrometry.py:500-531) projects the four image corners through the actual platepar, distortion included, and returns the max angular separation from centre.StarFilters.py:17already imports from that module.It's the established call everywhere else in the codebase, including in SkyFit2 itself at lines 4559, 5826 and 12325, plus
CheckFit.py:133,ApplyRecalibrate.py:224,NNalign.py:133andAddCelestialGrid.py.NNalign.py:136even uses the exact idiom you'd want here:Three reasons this is more than style:
F_scaleis the central scale; the corner angle depends on the distortion polynomial, whichgetFOVSelectionRadiusevaluates rather than assumes.Utils/SkyFit2.py:5899-5921, and this PR patches both copies by hand — the same failure mode that let the units error sit in two places. Extracting one shared helper (or just callinggetFOVSelectionRadiusfrom both) makes the third copy impossible.