Keep combine result masks in the array namespace - #992
Merged
Conversation
Combiner.average_combine, median_combine and sum_combine passed mask= to the CCDData constructor, and combine() assigned ccd.mask directly, so astropy's CCDData.mask setter ran on every result and converted the mask to a numpy array. On backends whose arrays cannot be converted (a non-default array-api-strict device, a GPU) that raises; elsewhere it silently returned a numpy mask on non-numpy data. Assign the private _mask attribute instead, as ccd_process already does, and have combine() coerce the template image's mask into the data's namespace and onto its device the way Combiner.__init__ does, since a CCDData given a mask through the setter always carries a numpy mask. That also replaces the numpy-only mask.copy() in the tile loop, which only worked because the mask was always numpy, with xpx.at(...).set(copy=True). The three *_combine_uncertainty tests and test_combine_result_uncertainty_and_mask used a positional axis, xp.sqrt(3) and mask.sum(); those only passed on strict because the tests failed earlier. Strict job: 63 -> 54 failed, no new failures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S36ZzAAVXVm32vuTdtCQME
58 tasks
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #992 +/- ##
=======================================
Coverage 97.44% 97.44%
=======================================
Files 9 9
Lines 1760 1761 +1
=======================================
+ Hits 1715 1716 +1
Misses 45 45
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
mwcraig
commented
Aug 25, 2026
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S36ZzAAVXVm32vuTdtCQME
mwcraig
added a commit
that referenced
this pull request
Aug 26, 2026
…pace Three small array-API fixes recorded in #971: - combine(output_file=...) handed the namespace result straight to CCDData.write, which astropy.io.fits cannot take. Build a NumPy copy of data, mask and uncertainty for the writer and return the result unchanged in its namespace. The conversion is a new core._to_numpy helper: the deliberate host-side copy, moving the array to the namespace's default device first (array-api-strict refuses to export from its non-default devices). The numpy_copy test helper now delegates to it so the device logic lives in one place. - Combiner(dtype=) and combine(dtype=) passed the user's dtype straight to xp.asarray/xp.astype; a builtin int or a string is a valid NumPy dtype but array-api-strict rejects it. core._namespace_dtype resolves the name through numpy.dtype and looks it up on the namespace, leaving the namespace's own dtype objects untouched. - subtract_overscan sized the model fit with len(oscan); use shape[0]. test_combiner_result_dtype compared an integer result with a float reference, which the standard does not promote; compare with a Python int instead. Escape baseline: _to_numpy is the new (BOUNDARY) site; the average/median/sum_combine entries no longer fire since #992 and are dropped as the file's own instructions ask. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S36ZzAAVXVm32vuTdtCQME
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #971 (section 1, "combine methods pass
mask=toCCDData(...)" — the largest remaining bucket on the strict job).Combiner.average_combine,median_combineandsum_combinebuilt their result withCCDData(..., mask=mask), andcombine()assignedccd.mask = ...at several points, so astropy'sCCDData.masksetter (np.asarray(value, dtype=np.bool_)) ran on every result. On backends whose arrays cannot be converted to NumPy (a non-defaultarray-api-strictdevice, a GPU) that raises; on jax/dask it silently handed back a NumPy mask on non-NumPy data.Changes
*_combinemethods assigncombined_image._mask = maskafter construction, the same workaroundccd_processalready uses (core.py:381), with the same TODO.combine()does the same at its own mask sites, and coerces the template image's mask into the data's namespace and onto its device the wayCombiner.__init__does — aCCDDatathat received its mask through the setter always carries a NumPy mask, so without this the tile loop fails with "Multiple namespaces for array inputs" once the tiles' masks are no longer NumPy.ccd.mask.copy()(NumPy-only; it only worked because the mask was always NumPy) is replaced byxpx.at(...).set(..., copy=True).axis,xp.sqrt(3)→math.sqrt(3),mask.sum()→xp.count_nonzero.Results
tox -e strict): 63 → 54 failed, 418 → 427 passed, no new failures.JAX_ENABLE_X64=1)test_combiner.py: all green.median_combineuses the defaultsigma_func→astropy.stats.median_absolute_deviation(Array API: Combiner.sigma_clipping and the default sigma_func densify via astropy.stats #929, section 3), andtest_writeable_after_combinewrites adevice1array to FITS, which belongs with the section-2 "write a NumPy copy" tests.🤖 Generated with Claude Code
https://claude.ai/code/session_01S36ZzAAVXVm32vuTdtCQME