LSST Applications g042eb84c57+730a74494b,g04e9c324dd+8c5ae1fdc5,g134cb467dc+1f1e3e7524,g199a45376c+0ba108daf9,g1fd858c14a+fa7d31856b,g210f2d0738+f66ac109ec,g262e1987ae+83a3acc0e5,g29ae962dfc+d856a2cb1f,g2cef7863aa+aef1011c0b,g35bb328faa+8c5ae1fdc5,g3fd5ace14f+a1e0c9f713,g47891489e3+0d594cb711,g4d44eb3520+c57ec8f3ed,g4d7b6aa1c5+f66ac109ec,g53246c7159+8c5ae1fdc5,g56a1a4eaf3+fd7ad03fde,g64539dfbff+f66ac109ec,g67b6fd64d1+0d594cb711,g67fd3c3899+f66ac109ec,g6985122a63+0d594cb711,g74acd417e5+3098891321,g786e29fd12+668abc6043,g81db2e9a8d+98e2ab9f28,g87389fa792+8856018cbb,g89139ef638+0d594cb711,g8d7436a09f+80fda9ce03,g8ea07a8fe4+760ca7c3fc,g90f42f885a+033b1d468d,g97be763408+a8a29bda4b,g99822b682c+e3ec3c61f9,g9d5c6a246b+0d5dac0c3d,ga41d0fce20+9243b26dd2,gbf99507273+8c5ae1fdc5,gd7ef33dd92+0d594cb711,gdab6d2f7ff+3098891321,ge410e46f29+0d594cb711,geaed405ab2+c4bbc419c6,gf9a733ac38+8c5ae1fdc5,w.2025.38
LSST Data Management Base Package
Loading...
Searching...
No Matches
lsst.scarlet.lite.observation.Observation Class Reference
Inheritance diagram for lsst.scarlet.lite.observation.Observation:
lsst.scarlet.lite.models.fit_psf.FittedPsfObservation

Public Member Functions

 __init__ (self, np.ndarray|Image images, np.ndarray|Image variance, np.ndarray|Image weights, np.ndarray psfs, np.ndarray|None model_psf=None, np.ndarray|None noise_rms=None, Box|None bbox=None, tuple|None bands=None, int padding=3, str convolution_mode="fft")
 
tuple bands (self)
 
Box bbox (self)
 
Image convolve (self, Image image, str|None mode=None, bool grad=False)
 
float log_likelihood (self, Image model)
 
Observation __getitem__ (self, Any indices)
 
Observation __copy__ (self, bool deep=False)
 
Observation copy (self, bool deep=False)
 
tuple[int, int, int] shape (self)
 
int n_bands (self)
 
npt.DTypeLike dtype (self)
 
tuple[int, int, int, int] convolution_bounds (self)
 

Static Public Member Functions

Observation empty (tuple[Any] bands, np.ndarray psfs, np.ndarray model_psf, Box bbox, npt.DTypeLike dtype)
 

Public Attributes

 images = images
 
 variance = _set_image_like(variance, bands, bbox)
 
 weights = _set_image_like(weights, bands, bbox)
 
 psfs = psfs
 
 mode = convolution_mode
 
 noise_rms = noise_rms
 
 model_psf = model_psf
 
 padding = padding
 
Fourier|None diff_kernel = cast(Fourier, match_kernel(psfs, model_psf, padding=padding))
 
Fourier|None grad_kernel = Fourier(diff_img[:, ::-1, ::-1])
 

Protected Attributes

tuple[int, int, int, int]|None _convolution_bounds = None
 

Detailed Description

A single observation

This class contains all of the observed images and derived
properties, like PSFs, variance map, and weight maps,
required for most optimizers.
This includes methods to match a scarlet model PSF to the oberved PSF
in each band.

Notes
-----
This is effectively a combination of the `Observation` and
`Renderer` class from scarlet main, greatly simplified due
to the assumptions that the observations are all resampled
onto the same pixel grid and that the `images` contain all
of the information for all of the model bands.

Parameters
----------
images:
    (bands, y, x) array of observed images.
variance:
    (bands, y, x) array of variance for each image pixel.
weights:
    (bands, y, x) array of weights to use when calculate the
    likelihood of each pixel.
psfs:
    (bands, y, x) array of the PSF image in each band.
model_psf:
    (bands, y, x) array of the model PSF image in each band.
    If `model_psf` is `None` then convolution is performed,
    which should only be done when the observation is a
    PSF matched coadd, and the scarlet model has the same PSF.
noise_rms:
    Per-band average noise RMS. If `noise_rms` is `None` then the mean
    of the sqrt of the variance is used.
bbox:
    The bounding box containing the model. If `bbox` is `None` then
    a `Box` is created that is the shape of `images` with an origin
    at `(0, 0)`.
padding:
    Padding to use when performing an FFT convolution.
convolution_mode:
    The method of convolution. This should be either "fft" or "real".

Definition at line 166 of file observation.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.scarlet.lite.observation.Observation.__init__ ( self,
np.ndarray | Image images,
np.ndarray | Image variance,
np.ndarray | Image weights,
np.ndarray psfs,
np.ndarray | None model_psf = None,
np.ndarray | None noise_rms = None,
Box | None bbox = None,
tuple | None bands = None,
int padding = 3,
str convolution_mode = "fft" )

Definition at line 212 of file observation.py.

224 ):
225 # Convert the images to a multi-band `Image` and use the resulting
226 # bbox and bands.
227 images = _set_image_like(images, bands, bbox)
228 bands = images.bands
229 bbox = images.bbox
230 self.images = images
231 self.variance = _set_image_like(variance, bands, bbox)
232 self.weights = _set_image_like(weights, bands, bbox)
233 # make sure that the images and psfs have the same dtype
234 if psfs.dtype != images.dtype:
235 psfs = psfs.astype(images.dtype)
236 self.psfs = psfs
237
238 if convolution_mode not in [
239 "fft",
240 "real",
241 ]:
242 raise ValueError("convolution_mode must be either 'fft' or 'real'")
243 self.mode = convolution_mode
244 if noise_rms is None:
245 noise_rms = np.array([np.mean(np.sqrt(v[np.isfinite(v)])) for v in self.variance.data])
246 self.noise_rms = noise_rms
247
248 # Create a difference kernel to convolve the model to the PSF
249 # in each band
250 self.model_psf = model_psf
251 self.padding = padding
252 if model_psf is not None:
253 if model_psf.dtype != images.dtype:
254 self.model_psf = model_psf.astype(images.dtype)
255 self.diff_kernel: Fourier | None = cast(Fourier, match_kernel(psfs, model_psf, padding=padding))
256 # The gradient of a convolution is another convolution,
257 # but with the flipped and transposed kernel.
258 diff_img = self.diff_kernel.image
259 self.grad_kernel: Fourier | None = Fourier(diff_img[:, ::-1, ::-1])
260 else:
261 self.diff_kernel = None
262 self.grad_kernel = None
263
264 self._convolution_bounds: tuple[int, int, int, int] | None = None
265

Member Function Documentation

◆ __copy__()

Observation lsst.scarlet.lite.observation.Observation.__copy__ ( self,
bool deep = False )
Create a copy of the observation

Parameters
----------
deep:
    Whether to perform a deep copy or not.

Returns
-------
result:
    The copy of the observation.

Definition at line 393 of file observation.py.

393 def __copy__(self, deep: bool = False) -> Observation:
394 """Create a copy of the observation
395
396 Parameters
397 ----------
398 deep:
399 Whether to perform a deep copy or not.
400
401 Returns
402 -------
403 result:
404 The copy of the observation.
405 """
406 if deep:
407 if self.model_psf is None:
408 model_psf = None
409 else:
410 model_psf = self.model_psf.copy()
411
412 if self.noise_rms is None:
413 noise_rms = None
414 else:
415 noise_rms = self.noise_rms.copy()
416
417 if self.bands is None:
418 bands = None
419 else:
420 bands = tuple([b for b in self.bands])
421 else:
422 model_psf = self.model_psf
423 noise_rms = self.noise_rms
424 bands = self.bands
425
426 return Observation(
427 images=self.images.copy(),
428 variance=self.variance.copy(),
429 weights=self.weights.copy(),
430 psfs=self.psfs.copy(),
431 model_psf=model_psf,
432 noise_rms=noise_rms,
433 bands=bands,
434 padding=self.padding,
435 convolution_mode=self.mode,
436 )
437

◆ __getitem__()

Observation lsst.scarlet.lite.observation.Observation.__getitem__ ( self,
Any indices )
Get a view for the subset of an image

Parameters
----------
indices:
    The indices to select a subsection of the image.

Returns
-------
result:
    The resulting image obtained by selecting subsets of the iamge
    based on the `indices`.

Definition at line 351 of file observation.py.

351 def __getitem__(self, indices: Any) -> Observation:
352 """Get a view for the subset of an image
353
354 Parameters
355 ----------
356 indices:
357 The indices to select a subsection of the image.
358
359 Returns
360 -------
361 result:
362 The resulting image obtained by selecting subsets of the iamge
363 based on the `indices`.
364 """
365 new_image = self.images[indices]
366 new_variance = self.variance[indices]
367 new_weights = self.weights[indices]
368
369 # Extract the appropriate bands from the PSF
370 bands = self.images.bands
371 new_bands = new_image.bands
372 if bands != new_bands:
373 band_indices = self.images.spectral_indices(new_bands)
374 psfs = self.psfs[band_indices,]
375 noise_rms = self.noise_rms[band_indices,]
376 else:
377 psfs = self.psfs
378 noise_rms = self.noise_rms
379
380 return Observation(
381 images=new_image,
382 variance=new_variance,
383 weights=new_weights,
384 psfs=psfs,
385 model_psf=self.model_psf,
386 noise_rms=noise_rms,
387 bbox=new_image.bbox,
388 bands=self.bands,
389 padding=self.padding,
390 convolution_mode=self.mode,
391 )
392

◆ bands()

tuple lsst.scarlet.lite.observation.Observation.bands ( self)
The bands in the observations.

Definition at line 267 of file observation.py.

267 def bands(self) -> tuple:
268 """The bands in the observations."""
269 return self.images.bands
270

◆ bbox()

Box lsst.scarlet.lite.observation.Observation.bbox ( self)
The bounding box for the full observation.

Definition at line 272 of file observation.py.

272 def bbox(self) -> Box:
273 """The bounding box for the full observation."""
274 return self.images.bbox
275

◆ convolution_bounds()

tuple[int, int, int, int] lsst.scarlet.lite.observation.Observation.convolution_bounds ( self)
Build the slices needed for convolution in real space

Definition at line 469 of file observation.py.

469 def convolution_bounds(self) -> tuple[int, int, int, int]:
470 """Build the slices needed for convolution in real space"""
471 if self._convolution_bounds is None:
472 coords = get_filter_coords(cast(Fourier, self.diff_kernel).image[0])
473 self._convolution_bounds = get_filter_bounds(coords.reshape(-1, 2))
474 return self._convolution_bounds
475

◆ convolve()

Image lsst.scarlet.lite.observation.Observation.convolve ( self,
Image image,
str | None mode = None,
bool grad = False )
Convolve the model into the observed seeing in each band.

Parameters
----------
image:
    The 3D image to convolve.
mode:
    The convolution mode to use.
    This should be "real" or "fft" or `None`,
    where `None` will use the default `convolution_mode`
    specified during init.
grad:
    Whether this is a backward gradient convolution
    (`grad==True`) or a pure convolution with the PSF.

Returns
-------
result:
    The convolved image.

Reimplemented in lsst.scarlet.lite.models.fit_psf.FittedPsfObservation.

Definition at line 276 of file observation.py.

276 def convolve(self, image: Image, mode: str | None = None, grad: bool = False) -> Image:
277 """Convolve the model into the observed seeing in each band.
278
279 Parameters
280 ----------
281 image:
282 The 3D image to convolve.
283 mode:
284 The convolution mode to use.
285 This should be "real" or "fft" or `None`,
286 where `None` will use the default `convolution_mode`
287 specified during init.
288 grad:
289 Whether this is a backward gradient convolution
290 (`grad==True`) or a pure convolution with the PSF.
291
292 Returns
293 -------
294 result:
295 The convolved image.
296 """
297 if grad:
298 kernel = self.grad_kernel
299 else:
300 kernel = self.diff_kernel
301
302 if kernel is None:
303 return image
304
305 if mode is None:
306 mode = self.mode
307 if mode == "fft":
308 result = fft_convolve(
309 Fourier(image.data),
310 kernel,
311 axes=(1, 2),
312 return_fourier=False,
313 )
314 elif mode == "real":
315 dy = image.shape[1] - kernel.image.shape[1]
316 dx = image.shape[2] - kernel.image.shape[2]
317 if dy < 0 or dx < 0:
318 # The image needs to be padded because it is smaller than
319 # the psf kernel
320 _image = image.data
321 newshape = list(_image.shape)
322 if dy < 0:
323 newshape[1] += kernel.image.shape[1] - image.shape[1]
324 if dx < 0:
325 newshape[2] += kernel.image.shape[2] - image.shape[2]
326 _image = _pad(_image, newshape)
327 result = convolve(_image, kernel.image, self.convolution_bounds)
328 result = centered(result, image.data.shape) # type: ignore
329 else:
330 result = convolve(image.data, kernel.image, self.convolution_bounds)
331 else:
332 raise ValueError(f"mode must be either 'fft' or 'real', got {mode}")
333 return Image(cast(np.ndarray, result), bands=image.bands, yx0=image.yx0)
334

◆ copy()

Observation lsst.scarlet.lite.observation.Observation.copy ( self,
bool deep = False )
Create a copy of the observation

Parameters
----------
deep:
    Whether to perform a deep copy or not.

Returns
-------
result:
    The copy of the observation.

Definition at line 438 of file observation.py.

438 def copy(self, deep: bool = False) -> Observation:
439 """Create a copy of the observation
440
441 Parameters
442 ----------
443 deep:
444 Whether to perform a deep copy or not.
445
446 Returns
447 -------
448 result:
449 The copy of the observation.
450 """
451 return self.__copy__(deep)
452

◆ dtype()

npt.DTypeLike lsst.scarlet.lite.observation.Observation.dtype ( self)
The dtype of the observation is the dtype of the images

Definition at line 464 of file observation.py.

464 def dtype(self) -> npt.DTypeLike:
465 """The dtype of the observation is the dtype of the images"""
466 return self.images.dtype
467

◆ empty()

Observation lsst.scarlet.lite.observation.Observation.empty ( tuple[Any] bands,
np.ndarray psfs,
np.ndarray model_psf,
Box bbox,
npt.DTypeLike dtype )
static

Definition at line 477 of file observation.py.

479 ) -> Observation:
480 dummy_image = np.zeros((len(bands),) + bbox.shape, dtype=dtype)
481
482 return Observation(
483 images=dummy_image,
484 variance=dummy_image,
485 weights=dummy_image,
486 psfs=psfs,
487 model_psf=model_psf,
488 noise_rms=np.zeros((len(bands),), dtype=dtype),
489 bbox=bbox,
490 bands=bands,
491 convolution_mode="real",
492 )

◆ log_likelihood()

float lsst.scarlet.lite.observation.Observation.log_likelihood ( self,
Image model )
Calculate the log likelihood of the given model

Parameters
----------
model:
    Model to compare with the observed images.

Returns
-------
result:
    The log-likelihood of the given model.

Definition at line 335 of file observation.py.

335 def log_likelihood(self, model: Image) -> float:
336 """Calculate the log likelihood of the given model
337
338 Parameters
339 ----------
340 model:
341 Model to compare with the observed images.
342
343 Returns
344 -------
345 result:
346 The log-likelihood of the given model.
347 """
348 result = 0.5 * -np.sum((self.weights * (self.images - model) ** 2).data)
349 return result
350

◆ n_bands()

int lsst.scarlet.lite.observation.Observation.n_bands ( self)
The number of bands in the observation

Definition at line 459 of file observation.py.

459 def n_bands(self) -> int:
460 """The number of bands in the observation"""
461 return self.images.shape[0]
462

◆ shape()

tuple[int, int, int] lsst.scarlet.lite.observation.Observation.shape ( self)
The shape of the images, variance, etc.

Definition at line 454 of file observation.py.

454 def shape(self) -> tuple[int, int, int]:
455 """The shape of the images, variance, etc."""
456 return cast(tuple[int, int, int], self.images.shape)
457

Member Data Documentation

◆ _convolution_bounds

tuple[int, int, int, int] | None lsst.scarlet.lite.observation.Observation._convolution_bounds = None
protected

Definition at line 264 of file observation.py.

◆ diff_kernel

Fourier | None lsst.scarlet.lite.observation.Observation.diff_kernel = cast(Fourier, match_kernel(psfs, model_psf, padding=padding))

Definition at line 255 of file observation.py.

◆ grad_kernel

Fourier | None lsst.scarlet.lite.observation.Observation.grad_kernel = Fourier(diff_img[:, ::-1, ::-1])

Definition at line 259 of file observation.py.

◆ images

lsst.scarlet.lite.observation.Observation.images = images

Definition at line 230 of file observation.py.

◆ mode

lsst.scarlet.lite.observation.Observation.mode = convolution_mode

Definition at line 243 of file observation.py.

◆ model_psf

lsst.scarlet.lite.observation.Observation.model_psf = model_psf

Definition at line 250 of file observation.py.

◆ noise_rms

lsst.scarlet.lite.observation.Observation.noise_rms = noise_rms

Definition at line 246 of file observation.py.

◆ padding

lsst.scarlet.lite.observation.Observation.padding = padding

Definition at line 251 of file observation.py.

◆ psfs

lsst.scarlet.lite.observation.Observation.psfs = psfs

Definition at line 236 of file observation.py.

◆ variance

lsst.scarlet.lite.observation.Observation.variance = _set_image_like(variance, bands, bbox)

Definition at line 231 of file observation.py.

◆ weights

lsst.scarlet.lite.observation.Observation.weights = _set_image_like(weights, bands, bbox)

Definition at line 232 of file observation.py.


The documentation for this class was generated from the following file: