Skip to content

Feature/unconvolved images#209

Merged
Jammy2211 merged 8 commits intomainfrom
feature/unconvolved_images
Feb 9, 2026
Merged

Feature/unconvolved images#209
Jammy2211 merged 8 commits intomainfrom
feature/unconvolved_images

Conversation

@Jammy2211
Copy link
Owner

This pull request makes it so that images which have not been operated on (e.g. before PSF convolution) can be computed and extracted easily from inversions, with the end goal making it so that these images can be easily output to .fits files during autolens lens modling.

This pull request refactors the terminology and internal logic related to reconstructed data in the inversion modules, aiming for clearer distinctions between operated (PSF-convolved) and unoperated (unconvolved) data. The changes update property and variable names, unify implementation patterns, and improve documentation. No core algorithms are changed, but naming is clarified throughout the codebase to avoid confusion between different forms of reconstructed data.

Key changes include:

Terminology and Naming Consistency

  • Renamed properties and variables from reconstructed_image/mapped_reconstructed_image_dict to reconstructed_operated_data/mapped_reconstructed_operated_data_dict throughout the inversion modules, reflecting that these quantities represent PSF-convolved data, not just images. [1] [2] [3] [4] [5] [6]
  • Updated function names and docstrings for clarity, ensuring all references to reconstructed data specify whether they are operated (convolved) or unoperated (unconvolved). [1] [2] [3] [4]

Implementation Refactoring

  • Added shared helper methods (e.g., _mapped_reconstructed_data_dict_from) to reduce code duplication and unify how reconstructed data dictionaries are built for both operated and unoperated cases in both standard and sparse inversion classes. [1] [2]
  • Updated internal logic in the sparse and standard mapping inversion classes to use the new naming and helper patterns, and to clarify when PSF convolution is applied. [1] [2] [3]

API Additions

  • Added new properties such as mapping_matrix_list and linear_func_mapping_matrix_dict to expose both operated and unoperated mapping matrices for linear objects, supporting the new refactoring. [1] [2]

These changes improve code readability and maintainability, making it easier to understand and work with different forms of reconstructed data in inversion workflows.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors inversion “reconstructed” outputs to clearly distinguish between unoperated (e.g. unconvolved) mapped reconstructions and operated (data-frame) mapped reconstructions, enabling easy extraction of pre-operation images for downstream FITS output workflows.

Changes:

  • Renames and restructures APIs from reconstructed_image / mapped_reconstructed_image(_dict) to reconstructed_operated_data / mapped_reconstructed_operated_data(_dict).
  • Adds/threads through mapping-matrix accessors and shared helpers to build mapped reconstructed dictionaries for both operated and unoperated cases.
  • Updates plotting/config and tests to use the operated-data naming.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
test_autoarray/inversion/plot/test_inversion_plotters.py Updates plotter API usage + expected output filenames for operated reconstructed data.
test_autoarray/inversion/inversion/test_inversion_util.py Renames local variables in reconstruction mapping tests to match new “operated” terminology.
test_autoarray/inversion/inversion/test_factory.py Updates factory/inversion assertions to use mapped_reconstructed_operated_data.
test_autoarray/inversion/inversion/test_abstract.py Updates/extends abstract inversion tests for new operated-data dict/property naming.
test_autoarray/inversion/inversion/interferometer/test_interferometer.py Updates interferometer residual computation to use operated reconstructed data.
autoarray/inversion/plot/inversion_plotters.py Renames plotting switches/filenames to operated-data terminology and plots operated reconstructions.
autoarray/inversion/mock/mock_inversion.py Threads new mapped_reconstructed_operated_data_dict through the mock inversion API.
autoarray/inversion/inversion/interferometer/sparse.py Renames reconstructed visibilities dict property to mapped_reconstructed_operated_data_dict.
autoarray/inversion/inversion/interferometer/mapping.py Same operated-data dict rename for mapping-based interferometer inversions.
autoarray/inversion/inversion/interferometer/abstract.py Renames “image dict” concept to mapped_reconstructed_data_dict for real-space mapping outputs.
autoarray/inversion/inversion/imaging_numba/sparse.py Adds shared helper and introduces operated/unoperated reconstructed dict split for numba sparse inversions.
autoarray/inversion/inversion/imaging_numba/inversion_imaging_numba_util.py Internal variable naming updates in unique-mapping reconstruction utility.
autoarray/inversion/inversion/imaging/sparse.py Adds shared helper and introduces operated/unoperated reconstructed dict split for sparse inversions.
autoarray/inversion/inversion/imaging/mapping.py Adds helper to build dicts from either operated or unoperated mapping-matrix lists.
autoarray/inversion/inversion/imaging/inversion_imaging_util.py Renames sparse-operator mapping utility function (now used by new helper paths).
autoarray/inversion/inversion/imaging/abstract.py Adds mapping_matrix_list / linear_func_mapping_matrix_dict accessors to expose unoperated mapping matrices.
autoarray/inversion/inversion/abstract.py Introduces mapped_reconstructed_operated_data(_dict) alongside existing unoperated mapped reconstruction outputs.
autoarray/config/visualize/plots.yaml Updates inversion plot config key from reconstructed_image to reconstructed_operated_data.
Comments suppressed due to low confidence (2)

autoarray/inversion/inversion/abstract.py:533

  • mapped_reconstructed_data is now distinct from mapped_reconstructed_operated_data, but its docstring still describes the reconstructed data “which the inversion fits” (operated / data-frame). This should be updated to explicitly state that mapped_reconstructed_data is the unoperated (e.g. unconvolved) mapped reconstruction.
    def mapped_reconstructed_data(self) -> Union[Array2D, Visibilities]:
        """
        Using the reconstructed source pixel fluxes we map each source pixel flux back to the image plane and
        reconstruct the image data.

        This uses the unique mappings of every source pixel to image pixels, which is a quantity that is already
        computed when using the w-tilde formalism.

        Returns
        -------
        Array2D
            The reconstructed image data which the inversion fits.
        """

autoarray/inversion/inversion/imaging/inversion_imaging_util.py:302

  • mapped_reconstructed_operated_data_via_sparse_operator_from appears to only apply the sparse mapping (no explicit PSF convolution), and callers apply the PSF separately depending on whether operated outputs are requested. The function name is therefore misleading; consider renaming it to reflect that it returns the unoperated mapped values (or update its docstring to clarify what “operated” means here).
def mapped_reconstructed_operated_data_via_sparse_operator_from(
    reconstruction,  # (S,)
    rows,
    cols,
    vals,  # (nnz,)
    fft_index_for_masked_pixel,
    data_shape: int,  # y_shape * x_shape
):
    import jax.numpy as jnp
    from jax.ops import segment_sum

    reconstruction = jnp.asarray(reconstruction, dtype=jnp.float64)
    rows = jnp.asarray(rows, dtype=jnp.int32)
    cols = jnp.asarray(cols, dtype=jnp.int32)
    vals = jnp.asarray(vals, dtype=jnp.float64)

    contrib = vals * reconstruction[cols]  # (nnz,)
    image_rect = segment_sum(
        contrib, rows, num_segments=data_shape[0] * data_shape[1]
    )  # (M_rect,)

    image_slim = image_rect[fft_index_for_masked_pixel]  # (M_pix,)
    return image_slim

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 69 to 88
@@ -75,23 +75,23 @@ def figures_2d(self, reconstructed_image: bool = False):

Parameters
----------
reconstructed_image
reconstructed_operated_data
Whether to make a 2D plot (via `imshow`) of the reconstructed image data.
"""
if reconstructed_image:
if reconstructed_operated_data:
self.mat_plot_2d.plot_array(
array=self.inversion.mapped_reconstructed_image,
array=self.inversion.mapped_reconstructed_operated_data,
visuals_2d=self.visuals_2d,
auto_labels=AutoLabels(
title="Reconstructed Image", filename="reconstructed_image"
title="Reconstructed Image", filename="reconstructed_operated_data"
),
)
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plotting parameter/filename is now reconstructed_operated_data, but the plot title and docstring still refer to “Reconstructed Image” / “reconstructed image data” without indicating it’s the operated (e.g. PSF-convolved) quantity. Updating the label text would avoid confusing operated vs unoperated outputs in generated figures.

Copilot uses AI. Check for mistakes.
Comment on lines +112 to 115
def mapped_reconstructed_operated_data_dict(
self,
) -> Dict[LinearObj, Visibilities]:
"""
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mapped_reconstructed_operated_data_dict returns reconstructed visibilities (operated data), but the accompanying docstring below still refers to “reconstructed images”. Please update that docstring to consistently describe visibilities/data-frame outputs vs real-space images.

Copilot uses AI. Check for mistakes.
Comment on lines +82 to +90
the linear objects model, before a operation like a convolution is applied.

This is used to construct the simultaneous linear equations which reconstruct the data.

This property returns the a list of each linear object's blurred mapping matrix, which is computed by
blurring each linear object's `mapping_matrix` property with the `psf` operator.

A linear object may have a `operated_mapping_matrix_override` property, which bypasses the `mapping_matrix`
computation and convolution operator and is directly placed in the `operated_mapping_matrix_list`.
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mapping_matrix_list returns the unoperated (unconvolved) mapping_matrix for each linear object, but the docstring currently says it returns a blurred/PSF-convolved matrix and discusses operated_mapping_matrix_override. This is misleading and should be updated to describe the unblurred matrices and remove/relocate the operated-matrix override wording (which belongs to operated_mapping_matrix_list).

Suggested change
the linear objects model, before a operation like a convolution is applied.
This is used to construct the simultaneous linear equations which reconstruct the data.
This property returns the a list of each linear object's blurred mapping matrix, which is computed by
blurring each linear object's `mapping_matrix` property with the `psf` operator.
A linear object may have a `operated_mapping_matrix_override` property, which bypasses the `mapping_matrix`
computation and convolution operator and is directly placed in the `operated_mapping_matrix_list`.
the linear object's model, before an operation like a convolution is applied.
This is used to construct the simultaneous linear equations which reconstruct the data.
This property returns a list containing each linear object's unoperated (unconvolved) `mapping_matrix`
as defined on the corresponding `LinearObj` instance.

Copilot uses AI. Check for mistakes.
Comment on lines +137 to +148
The `operated_mapping_matrix` of a linear object describes the mappings between the observed data's values and
the linear objects model, including a 2D convolution operation. It is described fully in the method
`operated_mapping_matrix`.

This property returns a dictionary mapping every linear func object to its corresponded operated mapping
matrix, which is used for constructing the matrices that perform the linear inversion in an efficent way
for the psf precision operator calculation.

Returns
-------
A dictionary mapping every linear function object to its operated mapping matrix.
"""
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linear_func_mapping_matrix_dict docstring describes operated (PSF-convolved) mapping matrices, but the implementation returns each linear func’s unoperated mapping_matrix. Please update the docstring (and fix typos like “corresponded/efficent”) so it clearly distinguishes this from linear_func_operated_mapping_matrix_dict.

Copilot uses AI. Check for mistakes.
Comment on lines +154 to 157
with PSF operations removed.

To perform this mapping the `mapping_matrix` is used, which straightforwardly describes how every value of
the `reconstruction` maps to pixels in the data-frame after the 2D convolution operation has been performed.
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In mapped_reconstructed_data_dict the docstring says the mapping_matrix maps to the data-frame “after the 2D convolution operation has been performed”, but this property now uses mapping_matrix_list (unoperated matrices). The description should be updated to reflect that these mapped values are before PSF convolution (and reserve the “after convolution” wording for mapped_reconstructed_operated_data_dict).

Suggested change
with PSF operations removed.
To perform this mapping the `mapping_matrix` is used, which straightforwardly describes how every value of
the `reconstruction` maps to pixels in the data-frame after the 2D convolution operation has been performed.
with PSF operations removed (that is, before any PSF / 2D convolution is applied).
To perform this mapping the (unoperated) `mapping_matrix` is used, which straightforwardly describes how every
value of the `reconstruction` maps to pixels in the data-frame prior to the 2D convolution operation.

Copilot uses AI. Check for mistakes.
Comment on lines +567 to +568
the reconstruction's values to the image-plane. Instead, the unique data-to-pixelization mappings are used,
including the 2D convolution operation after mapping is complete.
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mapped_reconstructed_data_dict is documented as “unconvolved … with PSF operations removed” but then says the w-tilde mapping uses unique mappings “including the 2D convolution operation after mapping is complete”. In this implementation the PSF convolution is only applied in mapped_reconstructed_operated_data_dict, so the unconvolved docstring should not claim convolution is included.

Suggested change
the reconstruction's values to the image-plane. Instead, the unique data-to-pixelization mappings are used,
including the 2D convolution operation after mapping is complete.
the reconstruction's values to the image-plane. Instead, for this unconvolved variant, the unique
data-to-pixelization mappings are used without applying the 2D PSF convolution (which is only included in
`mapped_reconstructed_operated_data_dict`).

Copilot uses AI. Check for mistakes.
Comment on lines 544 to 545
the reconstruction's values to the image-plane. Instead, the unique data-to-pixelization mappings are used,
including the 2D convolution operation after mapping is complete.
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mapped_reconstructed_data_dict is documented as returning unconvolved values, but the docstring also says mapping uses unique mappings “including the 2D convolution operation after mapping is complete”. The code only convolves when use_operated_for_linear_func=True (i.e. in mapped_reconstructed_operated_data_dict), so the unconvolved docstring should be corrected to avoid stating that convolution is applied.

Suggested change
the reconstruction's values to the image-plane. Instead, the unique data-to-pixelization mappings are used,
including the 2D convolution operation after mapping is complete.
the reconstruction's values to the image-plane. Instead, the unique data-to-pixelization mappings are used
without applying the 2D convolution / PSF operation.

Copilot uses AI. Check for mistakes.
Comment on lines 537 to 549
@@ -563,7 +547,7 @@ def mapped_reconstructed_image(self) -> Array2D:
Array2D
The reconstructed image data which the inversion fits.
"""
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mapped_reconstructed_operated_data docstring is currently identical to mapped_reconstructed_data and does not explain what operation(s) are included (e.g. PSF convolution for imaging, NUFFT for interferometer). Please update it to clearly define “operated” so users know this is the data-frame model used for fitting.

Copilot uses AI. Check for mistakes.
Comment on lines +478 to +479
- AbstractMapper: uses unique mappings (w-tilde compatible) + PSF convolution.
- Linear-func: uses either operated or unoperated mapping matrix dict.
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In _mapped_reconstructed_data_dict_from, the docstring says the AbstractMapper path always includes PSF convolution, but convolution is conditional on use_operated_for_linear_func. Also, the flag name suggests it only affects linear-func objects, yet it also toggles PSF convolution for mappers. Renaming the flag to something like apply_psf/operated and updating the docstring would make the control-flow intent clearer.

Suggested change
- AbstractMapper: uses unique mappings (w-tilde compatible) + PSF convolution.
- Linear-func: uses either operated or unoperated mapping matrix dict.
Behaviour:
- AbstractMapper: uses unique mappings (w-tilde compatible). If
``use_operated_for_linear_func`` is True, the mapped image is then
convolved with the PSF.
- Linear-func: uses the operated mapping-matrix dict when
``use_operated_for_linear_func`` is True, otherwise the
unoperated mapping-matrix dict.
Note that the ``use_operated_for_linear_func`` flag therefore controls
both PSF convolution of mapper outputs and the operated/unoperated
choice for linear-func objects.

Copilot uses AI. Check for mistakes.
Jammy2211 and others added 2 commits February 9, 2026 16:11
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@Jammy2211 Jammy2211 merged commit 2788bcb into main Feb 9, 2026
0 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants