Simulation of CCD images

Contents

Simulation of CCD images#

With the goal of making it easier to generate simulated astronomical images, teareduce provides a class called SimulateCCDExposure that simplifies this task.

import astropy.units as u
import matplotlib.pyplot as plt
import numpy as np
import teareduce as tea
help(tea.SimulateCCDExposure)
Help on class SimulateCCDExposure in module teareduce.simulateccdexposure:

class SimulateCCDExposure(builtins.object)
 |  SimulateCCDExposure(naxis1=None, naxis2=None, bitpix=None, bias=<Quantity nan adu>, gain=<Quantity nan electron / adu>, readout_noise=<Quantity nan adu>, dark=<Quantity nan adu>, flatfield=nan, data_model=<Quantity nan adu>, seed=None)
 |
 |  Simulated image generator from first principles.
 |
 |  CCD exposures are simulated making use of basic CCD parameters,
 |  such as gain, readout noise, bias, dark and flat field.
 |  A data model can also be employed to simulate more realistic
 |  CCD exposures.
 |
 |  The saturated pixels in 'data_model' are returned as 2**bitpix - 1
 |  in the simulated image (for instance, 65535 when bitpix=16).
 |
 |  By initializing the seed of the random number generator
 |  when instantiating this class, there is in principle no need to
 |  use another seed for the run() method. This is useful for
 |  generating reproducible sets of consecutive exposures. In any case,
 |  it is also possible to provide a particular seed to the run()
 |  method in order to initialize the execution of single exposures.
 |
 |  Attributes
 |  ----------
 |  naxis1 : int
 |      NAXIS1 value.
 |  naxis2 : int
 |      NAXIS2 value.
 |  bitpix : int
 |      BITPIX value.
 |  bias : Quantity
 |      Numpy array with the detector bias level (ADU).
 |  gain : Quantity
 |      Numpy array with the detector gain (electrons/ADU).
 |  readout_noise : Quantity
 |      Numpy array with the readout noise (ADU).
 |  dark : Quantity
 |      Numpy array with the total dark current (ADU) for each pixel.
 |      These numbers should not be the dark current rate (ADU/s).
 |      The provided numbers must correspond to the total dark current
 |      since the exposure time is not defined.
 |  flatfield : numpy.ndarray
 |      Numpy array with the pixel to pixel sensitivity (without units).
 |  data_model : Quantity
 |      Numpy array with the model of the source to be simulated (ADU).
 |      Note that this is the model before applying the flatfield.
 |      The values in this array must be the total ADU for each pixel.
 |  seed : int or None
 |      Random number generator seed.
 |  _rng : np.random.RandomState
 |      Random number generator.
 |
 |  Methods
 |  -------
 |  set_constant(parameter, value, region)
 |      Set the value of a particular CCD parameter to a constant
 |      value. The parameter can be any of VALID_PARAMETERS. The
 |      constant value can be employed for all pixels or in a specific
 |      region.
 |  set_array2d(parameter, value, region)
 |      Set the value of a particular CCD parameter to a 2D array.
 |      The parameter can be any of VALID_PARAMETERS. The 2D array
 |      may correspond to the whole simulated array or to a specific
 |      region.
 |  run(imgtype, seed, method)
 |      Execute the generation of the simulated CCD exposure of
 |      type 'imgtype', where 'imgtype' is one of VALID_IMAGE_TYPES.
 |      The signal can be generated using either method: Poisson
 |      or Gaussian. It is possible to set the seed in order to
 |      initialize the random number generator.
 |
 |  Methods defined here:
 |
 |  __init__(self, naxis1=None, naxis2=None, bitpix=None, bias=<Quantity nan adu>, gain=<Quantity nan electron / adu>, readout_noise=<Quantity nan adu>, dark=<Quantity nan adu>, flatfield=nan, data_model=<Quantity nan adu>, seed=None)
 |      Initialize the class attributes.
 |
 |      The simulated array dimensions are mandatory. If any additional
 |      parameter is not provided, all the pixel values are set to NaN.
 |      The values of each parameter can be subsequently modified using
 |      methods that allow these values to be changed in specific regions
 |      of the CCD.
 |
 |      The input parameters must be a Quantity whose value is either
 |      a single number, which is expanded to fill the numpy.array,
 |      or a numpy.array with the expected shape (NAXIS2, NAXIS1).
 |
 |      Parameters
 |      ----------
 |      naxis1 : int
 |          NAXIS1 value.
 |      naxis2 : int
 |          NAXIS2 value.
 |      bitpix : int
 |          BITPIX value.
 |      bias : Quantity
 |          Detector bias level (ADU).
 |      gain : Quantity
 |          Detector gain (electrons/ADU).
 |      readout_noise : Quantity
 |          Readout noise (ADU).
 |      dark : Quantity
 |          Total dark current (ADU). This number should not be the
 |          dark current rate (ADU/s). The provided number must
 |          be the total dark current since the exposure time is not
 |          defined.
 |      flatfield : float or numpy.ndarray
 |          Pixel to pixel sensitivity (without units).
 |      data_model : Quantity
 |          Model of the source to be simulated (ADU).
 |      seed : int or None
 |          Random number generator seed.
 |
 |  __repr__(self)
 |      Return repr(self).
 |
 |  run(self, imgtype, method='Poisson', seed=None)
 |      Execute the generation of the simulated CCD exposure.
 |
 |      This function generates an image of type 'imgtype', which must
 |      be one of VALID_IMAGE_TYPES. The signal can be generated using
 |      either method: Poisson or Gaussian. It is possible to set the
 |      seed in order to initialize the random number generator.
 |
 |      Parameters
 |      ----------
 |      imgtype : str
 |          Type of image to be generated. It must be one of
 |          VALID_IMAGE_TYPES.
 |      method : str
 |          Method to generate the simulated data. It must be one of
 |          VALID_METHODS.
 |      seed : int, optional
 |          Seed for the random number generator. The default is None.
 |
 |      Returns
 |      -------
 |      result : SimulatedCCDResult
 |          Instance of SimulatedCCDResult to store the simulated image
 |          and the associated parameters employed to define how to
 |          generate the simulated CCD exposure.
 |
 |  set_array2d(self, parameter, array2d, region=None)
 |      Set the value of a particular parameter to a 2D array.
 |
 |      The parameter can be any of VALID_PARAMETERS. The 2D array
 |      may correspond to the whole simulated array or to a specific
 |      region.
 |
 |      Parameters
 |      ----------
 |      parameter : str
 |          CCD parameter to set. It must be any of VALID_PARAMETERS.
 |      array2d : Quantity
 |          Array of values to be used to define 'parameter'.
 |      region : SliceRegion2D
 |          Region in which to define de parameter. When it is None, it
 |          indicates that 'quantity' has the same shape as the simulated
 |          image.
 |
 |  set_constant(self, parameter, constant, region=None)
 |      Set the value of a particular parameter to a constant value.
 |
 |      The parameter can be any of VALID_PARAMETERS. The constant
 |      value can be employed for all pixels or in a specific region.
 |
 |      Parameters
 |      ----------
 |      parameter : str
 |          CCD parameter to set. It must be any of VALID_PARAMETERS.
 |      constant : Quantity or float
 |          Constant value for the parameter.
 |      region : SliceRegion2D or None
 |          Region in which to define de parameter. When it is None, it
 |          indicates that 'value' should be set for all pixels.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables
 |
 |  __weakref__
 |      list of weak references to the object

Simple usage#

Define image basic parameters (dimensions, BITPIX)

naxis1, naxis2 = 5, 5
bitpix = 16

Each instance of the SimulateCCDExposure class becomes an image generator with the specified properties.

generator = tea.SimulateCCDExposure(
    naxis1=naxis1,
    naxis2=naxis2,
    bitpix=bitpix
)

The generator we have just created contains information about the image dimensions and the BITPIX value, but there are still many attributes left undefined:

generator
SimulateCCDExposure(
    naxis1=5,
    naxis2=5,
    bitpix=16,
    bias=<Quantity [[nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan]] adu>,
    gain=<Quantity [[nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan]] electron / adu>,
    readout_noise=<Quantity [[nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan]] adu>,
    dark=<Quantity [[nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan]] adu>,
    flatfield=array([[nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan]]),
    data_model=<Quantity [[nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan]] adu>,
    seed=None,
)

If we try to use the generator as defined so far to create a bias image, we should encounter an error message.

exposure_bias = generator.run(imgtype='bias')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[6], line 1
----> 1 exposure_bias = generator.run(imgtype='bias')

File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/teareduce/simulateccdexposure.py:589, in SimulateCCDExposure.run(self, imgtype, method, seed)
    587 # BIAS and Readout Noise
    588 if np.isnan(self.bias.value).any():
--> 589     raise ValueError("The parameter 'bias' contains NaN")
    590 if np.isnan(self.readout_noise.value).any():
    591     raise ValueError("The parameter 'readout_noise' contains NaN")

ValueError: The parameter 'bias' contains NaN

We can see, then, that to generate a BIAS image we need to construct a generator that includes this information. For example, we can define the generator by specifying, in addition to the dimensions and BITPIX, the bias signal and the readout noise.

generator = tea.SimulateCCDExposure(
    naxis1=naxis1, naxis2=naxis2, bitpix=bitpix,
    bias=np.ones((naxis2, naxis1))*1000*u.adu,
    readout_noise=5*u.adu
)

generator
SimulateCCDExposure(
    naxis1=5,
    naxis2=5,
    bitpix=16,
    bias=<Quantity [[1000., 1000., 1000., 1000., 1000.],
           [1000., 1000., 1000., 1000., 1000.],
           [1000., 1000., 1000., 1000., 1000.],
           [1000., 1000., 1000., 1000., 1000.],
           [1000., 1000., 1000., 1000., 1000.]] adu>,
    gain=<Quantity [[nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan]] electron / adu>,
    readout_noise=<Quantity [[5., 5., 5., 5., 5.],
           [5., 5., 5., 5., 5.],
           [5., 5., 5., 5., 5.],
           [5., 5., 5., 5., 5.],
           [5., 5., 5., 5., 5.]] adu>,
    dark=<Quantity [[nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan]] adu>,
    flatfield=array([[nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan]]),
    data_model=<Quantity [[nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan]] adu>,
    seed=None,
)

We can then generate a simulated BIAS image using the method run(imgtype='bias'):

exposure_bias = generator.run(imgtype='bias')

The result is an object of type SimulatedCCDResult, which contains not only the simulated image but also all the information used to define the generator that was employed.

type(exposure_bias)
teareduce.simulateccdexposure.SimulatedCCDResult
exposure_bias
SimulatedCCDResult(
    data=array([[1006.41310634,  999.89282835,  997.47739168, 1003.0014571 ,
        1003.03928802],
       [ 997.6205595 , 1005.68069342,  997.11808332,  989.94005427,
         996.35279372],
       [ 995.19625567, 1002.12071912, 1003.26954726,  999.41479604,
        1013.95074569],
       [ 999.91572402,  990.75529148,  996.14262845,  994.66398263,
        1003.76820732],
       [ 995.15649853,  993.78725863, 1000.87915961, 1000.36789148,
         994.96179569]]),
    unit=Unit("adu"),
    imgtype='bias',
    method='poisson',
    origin=SimulateCCDExposure(
    naxis1=5,
    naxis2=5,
    bitpix=16,
    bias=<Quantity [[1000., 1000., 1000., 1000., 1000.],
           [1000., 1000., 1000., 1000., 1000.],
           [1000., 1000., 1000., 1000., 1000.],
           [1000., 1000., 1000., 1000., 1000.],
           [1000., 1000., 1000., 1000., 1000.]] adu>,
    gain=<Quantity [[nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan]] electron / adu>,
    readout_noise=<Quantity [[5., 5., 5., 5., 5.],
           [5., 5., 5., 5., 5.],
           [5., 5., 5., 5., 5.],
           [5., 5., 5., 5., 5.],
           [5., 5., 5., 5., 5.]] adu>,
    dark=<Quantity [[nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan]] adu>,
    flatfield=array([[nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan]]),
    data_model=<Quantity [[nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan],
           [nan, nan, nan, nan, nan]] adu>,
    seed=None,
),
    seed=None,
)

The .data attribute contains the NumPy array with the simulated image.

type(exposure_bias.data)
numpy.ndarray
tea.imshowme(exposure_bias.data, ds9mode=True)
plt.tight_layout()
../../_images/fc8435a3ac5b1fd4697102b166d71462c4cc77c87b20f0f10218cc72d241155a.png

Documentation pending update from this point