Working with Instruments

When working with multi wavelength observations (i.e. observables from a range of instruments with a range of filters, resolutions, depths etc.) we need a way to collect the diverse technical properties of instruments. This is where Instrument and InstrumentCollections come in. An Instrument contains the the techincal properties of a single instrument, e.g. NIRCam filter curves, resolution, depths, SNR, or noise maps (we’ll detail the use cases for the properties below). An InstrumentCollection is a container enabling manipulation of multiple Instruments in a single object.

For a Pipeline (see pipeline docs) InstrumentCollection objects are an important building block of automating pipelines to generate observables.

Creating an Instrument

We’ll focus on different use cases in the section below. First we’ll cover the creation of simple Instrument instances and combining them into InstrumentCollections. For this we’ll just use simple Instruments defining only the filters (which would be the case if you only want to generate photometry). We’ll begin by creating two filter collections, one for Webb’s NIRCam instrument and the other for generic UVJ top hats.

For more information on filters see the filter docs.

[1]:
from synthesizer.instruments import UVJ, FilterCollection

# Get the filters
webb_filters = FilterCollection(
    filter_codes=[
        f"JWST/NIRCam.{f}"
        for f in ["F090W", "F150W", "F200W", "F277W", "F356W", "F444W"]
    ],
)
uvj_filters = UVJ()
Calculated wavelength array:
min = 7.74e+03 Angstrom
max = 5.11e+04 Angstrom
FilterCollection.lam.size = 4763
Calculated wavelength array:
min = 3.29e+03 Angstrom
max = 1.33e+04 Angstrom
FilterCollection.lam.size = 12811

Now that we have the filters in hand we can simply instantiate the Instrument objects with the filters and a label.

[2]:
from synthesizer.instruments import Instrument

# Instatiate the instruments
webb_inst = Instrument("JWST", filters=webb_filters)
uvj_inst = Instrument("UVJ", filters=uvj_filters)

As with everything else in Synthesizer, if we want to see whats inside the instruments we just created we can print them to see a table.

[3]:
print(webb_inst)
+------------------------------------------------------------------------------------------------------------------+
|                                                    INSTRUMENT                                                    |
+------------------------------------+-----------------------------------------------------------------------------+
| Attribute                          | Value                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| label                              | 'JWST'                                                                      |
+------------------------------------+-----------------------------------------------------------------------------+
| filters                            | <synthesizer.instruments.filters.FilterCollection object at 0x7f16343233d0> |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_imaging                     | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_imaging               | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_resolved_spectroscopy | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_spectroscopy          | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_photometry                  | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_imaging                 | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_spectroscopy            | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_resolved_spectroscopy       | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_spectroscopy                | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
[4]:
print(uvj_inst)
+------------------------------------------------------------------------------------------------------------------+
|                                                    INSTRUMENT                                                    |
+------------------------------------+-----------------------------------------------------------------------------+
| Attribute                          | Value                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| label                              | 'UVJ'                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| filters                            | <synthesizer.instruments.filters.FilterCollection object at 0x7f163436b010> |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_imaging                     | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_imaging               | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_resolved_spectroscopy | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_spectroscopy          | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_photometry                  | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_imaging                 | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_spectroscopy            | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_resolved_spectroscopy       | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_spectroscopy                | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+

You can see from these print outs that we have the label and FilterCollections we passed but also a series of flags defining what the instrument can be used for. Since we only passed filters we can only generate photometry from spectra with the “default” wavelength array (the one used by the `Grid <../grids/grids.rst>`__).

Combining Instruments

If we want to combine these into a single InstrumentCollection we can simply add them together (this can be done for arbitrarily many instruments).

[5]:
instruments = webb_inst + uvj_inst
print(instruments)
+--------------------------------------+
|        INSTRUMENT COLLECTION         |
+-------------------+------------------+
| Attribute         | Value            |
+-------------------+------------------+
| ninstruments      | 2                |
+-------------------+------------------+
| instrument_labels | [JWST,  UVJ, ]   |
+-------------------+------------------+
| instruments       | JWST: Instrument |
|                   | UVJ: Instrument  |
+-------------------+------------------+

Here we can see the ImageCollection contains both the instruments as expected.

Working with InstrumentCollections

If we want to extract a specific instrument from an InstrumentCollection we can treat it exactly as we would a dictionary by indexing with the label.

[6]:
print(instruments["JWST"].label)
JWST

If we want to loop through Instruments in the collection we can treat it as an iterable.

[7]:
for inst in instruments:
    print(inst.label)
JWST
UVJ

We can write an InstrumentCollection to a HDF5 file to reload it later by calling the write_instruments method. This simply requires a filepath for where to save the InstrumentCollection.

[8]:
instruments.write_instruments("instruments.hdf5")

We can then use this file later rather than making and combining all the individual Instruments but passing the filepath to an InstrumentCollection at instantiation.

[9]:
from synthesizer.instruments import InstrumentCollection

instruments = InstrumentCollection(filepath="instruments.hdf5")

Instrument Use Cases

We’ve already seen the pure photometry use case where you only need to include a FilterCollection on your Instrument. However, that is the tip of the iceberg. Below each section details what is needed for different observables.

Spectroscopy

It’s entirely possible to generate spectra for a galaxy without an Instrument, instead using the Grid wavelengths (see the spectra docs), but if you want to match observations by a particular instrument (e.g. LSST, DESI) you’ll need the specific wavelength array for that instrument.

[10]:
import numpy as np
from unyt import angstrom

lsst_inst = Instrument("LSST", lam=np.linspace(10**3, 10**4, 100) * angstrom)
print(lsst_inst)
+----------------------------------------------------------------------------------+
|                                    INSTRUMENT                                    |
+------------------------------------+---------------------------------------------+
| Attribute                          | Value                                       |
+------------------------------------+---------------------------------------------+
| label                              | 'LSST'                                      |
+------------------------------------+---------------------------------------------+
| can_do_imaging                     | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_imaging               | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_resolved_spectroscopy | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_spectroscopy          | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_photometry                  | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_psf_imaging                 | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_psf_spectroscopy            | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_resolved_spectroscopy       | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_spectroscopy                | True                                        |
+------------------------------------+---------------------------------------------+
| lam (100,)                         | 1.00e+03 Å -> 1.00e+04 Å (Mean: 5.50e+03 Å) |
+------------------------------------+---------------------------------------------+

You can also include a SNR and depth in apparent magnitude to parametrise any noise contribution to the resultant spectra.

[11]:
desi_inst = Instrument(
    "LSST", lam=np.linspace(10**3, 10**4, 100) * angstrom, snrs=5, depth=28
)
print(desi_inst)
+----------------------------------------------------------------------------------+
|                                    INSTRUMENT                                    |
+------------------------------------+---------------------------------------------+
| Attribute                          | Value                                       |
+------------------------------------+---------------------------------------------+
| label                              | 'LSST'                                      |
+------------------------------------+---------------------------------------------+
| depth                              | 28                                          |
+------------------------------------+---------------------------------------------+
| snrs                               | 5                                           |
+------------------------------------+---------------------------------------------+
| can_do_imaging                     | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_imaging               | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_resolved_spectroscopy | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_spectroscopy          | True                                        |
+------------------------------------+---------------------------------------------+
| can_do_photometry                  | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_psf_imaging                 | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_psf_spectroscopy            | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_resolved_spectroscopy       | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_spectroscopy                | True                                        |
+------------------------------------+---------------------------------------------+
| lam (100,)                         | 1.00e+03 Å -> 1.00e+04 Å (Mean: 5.50e+03 Å) |
+------------------------------------+---------------------------------------------+

Imaging

For imaging we need to be able to first make the photometry so we need a FilterCollection, but then for simple images without observational effects all we need is the resolution with units.

[12]:
from unyt import kpc

webb_inst = Instrument("JWST", filters=webb_filters, resolution=0.1 * kpc)
print(webb_inst)
+------------------------------------------------------------------------------------------------------------------+
|                                                    INSTRUMENT                                                    |
+------------------------------------+-----------------------------------------------------------------------------+
| Attribute                          | Value                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| label                              | 'JWST'                                                                      |
+------------------------------------+-----------------------------------------------------------------------------+
| filters                            | <synthesizer.instruments.filters.FilterCollection object at 0x7f16343233d0> |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_imaging                     | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_imaging               | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_resolved_spectroscopy | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_spectroscopy          | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_photometry                  | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_imaging                 | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_spectroscopy            | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_resolved_spectroscopy       | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_spectroscopy                | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| resolution                         | 0.1 kpc                                                                     |
+------------------------------------+-----------------------------------------------------------------------------+

If we want to include the effects of an instruments point spread function (PSF) we can pass a dictionary of PSF arrays with one for each filter.

[13]:
# Generate a dictionary of FAKE PSFs, importantly with a PSF for each filter
psfs = {f: np.ones((100, 100)) for f in webb_filters.filters}

webb_inst = Instrument(
    "JWST", filters=webb_filters, resolution=0.1 * kpc, psfs=psfs
)
print(webb_inst)
+------------------------------------------------------------------------------------------------------------------+
|                                                    INSTRUMENT                                                    |
+------------------------------------+-----------------------------------------------------------------------------+
| Attribute                          | Value                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| label                              | 'JWST'                                                                      |
+------------------------------------+-----------------------------------------------------------------------------+
| filters                            | <synthesizer.instruments.filters.FilterCollection object at 0x7f16343233d0> |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_imaging                     | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_imaging               | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_resolved_spectroscopy | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_spectroscopy          | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_photometry                  | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_imaging                 | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_spectroscopy            | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_resolved_spectroscopy       | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_spectroscopy                | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| resolution                         | 0.1 kpc                                                                     |
+------------------------------------+-----------------------------------------------------------------------------+
| psfs                               | JWST/NIRCam.F090W: ndarray                                                  |
|                                    | JWST/NIRCam.F150W: ndarray                                                  |
|                                    | JWST/NIRCam.F200W: ndarray                                                  |
|                                    | JWST/NIRCam.F277W: ndarray                                                  |
|                                    | JWST/NIRCam.F356W: ndarray                                                  |
|                                    | JWST/NIRCam.F444W: ndarray                                                  |
+------------------------------------+-----------------------------------------------------------------------------+

If we want to include noise there’s a couple of different approaches.

We can either pass the depth and Signal-to-Noise Ratio (SNR) for each filter.

[14]:
# Generate depths and snrs, again there must be one for each filter
depths = {f: 28.0 for f in webb_filters.filters}
snrs = {f: 5.0 for f in webb_filters.filters}

webb_inst = Instrument(
    "JWST",
    filters=webb_filters,
    resolution=0.1 * kpc,
    psfs=psfs,
    depth=depths,
    snrs=snrs,
)
print(webb_inst)
+------------------------------------------------------------------------------------------------------------------+
|                                                    INSTRUMENT                                                    |
+------------------------------------+-----------------------------------------------------------------------------+
| Attribute                          | Value                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| label                              | 'JWST'                                                                      |
+------------------------------------+-----------------------------------------------------------------------------+
| filters                            | <synthesizer.instruments.filters.FilterCollection object at 0x7f16343233d0> |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_imaging                     | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_imaging               | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_resolved_spectroscopy | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_spectroscopy          | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_photometry                  | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_imaging                 | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_spectroscopy            | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_resolved_spectroscopy       | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_spectroscopy                | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| resolution                         | 0.1 kpc                                                                     |
+------------------------------------+-----------------------------------------------------------------------------+
| depth                              | JWST/NIRCam.F090W: float                                                    |
|                                    | JWST/NIRCam.F150W: float                                                    |
|                                    | JWST/NIRCam.F200W: float                                                    |
|                                    | JWST/NIRCam.F277W: float                                                    |
|                                    | JWST/NIRCam.F356W: float                                                    |
|                                    | JWST/NIRCam.F444W: float                                                    |
+------------------------------------+-----------------------------------------------------------------------------+
| snrs                               | JWST/NIRCam.F090W: float                                                    |
|                                    | JWST/NIRCam.F150W: float                                                    |
|                                    | JWST/NIRCam.F200W: float                                                    |
|                                    | JWST/NIRCam.F277W: float                                                    |
|                                    | JWST/NIRCam.F356W: float                                                    |
|                                    | JWST/NIRCam.F444W: float                                                    |
+------------------------------------+-----------------------------------------------------------------------------+
| psfs                               | JWST/NIRCam.F090W: ndarray                                                  |
|                                    | JWST/NIRCam.F150W: ndarray                                                  |
|                                    | JWST/NIRCam.F200W: ndarray                                                  |
|                                    | JWST/NIRCam.F277W: ndarray                                                  |
|                                    | JWST/NIRCam.F356W: ndarray                                                  |
|                                    | JWST/NIRCam.F444W: ndarray                                                  |
+------------------------------------+-----------------------------------------------------------------------------+

If we already have noise maps for each filter we can instead pass a noise map per filter.

[15]:
# Generate FAKE noise maps, again there must be one for each filter
noise_maps = {f: np.random.rand(100, 100) for f in webb_filters.filters}

webb_inst = Instrument(
    "JWST", filters=webb_filters, resolution=0.1 * kpc, noise_maps=noise_maps
)
print(webb_inst)
+------------------------------------------------------------------------------------------------------------------+
|                                                    INSTRUMENT                                                    |
+------------------------------------+-----------------------------------------------------------------------------+
| Attribute                          | Value                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| label                              | 'JWST'                                                                      |
+------------------------------------+-----------------------------------------------------------------------------+
| filters                            | <synthesizer.instruments.filters.FilterCollection object at 0x7f16343233d0> |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_imaging                     | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_imaging               | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_resolved_spectroscopy | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_noisy_spectroscopy          | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_photometry                  | True                                                                        |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_imaging                 | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_psf_spectroscopy            | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_resolved_spectroscopy       | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| can_do_spectroscopy                | False                                                                       |
+------------------------------------+-----------------------------------------------------------------------------+
| resolution                         | 0.1 kpc                                                                     |
+------------------------------------+-----------------------------------------------------------------------------+
| noise_maps                         | JWST/NIRCam.F090W: ndarray                                                  |
|                                    | JWST/NIRCam.F150W: ndarray                                                  |
|                                    | JWST/NIRCam.F200W: ndarray                                                  |
|                                    | JWST/NIRCam.F277W: ndarray                                                  |
|                                    | JWST/NIRCam.F356W: ndarray                                                  |
|                                    | JWST/NIRCam.F444W: ndarray                                                  |
+------------------------------------+-----------------------------------------------------------------------------+

Resolved Spectroscopy

As well as producing integrated spectroscopy we can also use an Instrument for resolved spectroscopy. For this we need the wavelength array for the Instrument and the resolution of the spaxels.

[16]:
nirspec = Instrument(
    "NIRSpec",
    lam=np.linspace(10**3, 10**4, 100) * angstrom,
    resolution=0.1 * kpc,
)
print(nirspec)
+----------------------------------------------------------------------------------+
|                                    INSTRUMENT                                    |
+------------------------------------+---------------------------------------------+
| Attribute                          | Value                                       |
+------------------------------------+---------------------------------------------+
| label                              | 'NIRSpec'                                   |
+------------------------------------+---------------------------------------------+
| can_do_imaging                     | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_imaging               | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_resolved_spectroscopy | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_spectroscopy          | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_photometry                  | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_psf_imaging                 | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_psf_spectroscopy            | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_resolved_spectroscopy       | True                                        |
+------------------------------------+---------------------------------------------+
| can_do_spectroscopy                | True                                        |
+------------------------------------+---------------------------------------------+
| resolution                         | 0.1 kpc                                     |
+------------------------------------+---------------------------------------------+
| lam (100,)                         | 1.00e+03 Å -> 1.00e+04 Å (Mean: 5.50e+03 Å) |
+------------------------------------+---------------------------------------------+

Like with imaging we can also pass a PSF to include its effects but here we only need one since we don’t have individual filters.

[17]:
nirspec = Instrument(
    "NIRSpec",
    lam=np.linspace(10**3, 10**4, 100) * angstrom,
    resolution=0.1 * kpc,
    psfs=np.ones((100, 100)),
)
print(nirspec)
+----------------------------------------------------------------------------------+
|                                    INSTRUMENT                                    |
+------------------------------------+---------------------------------------------+
| Attribute                          | Value                                       |
+------------------------------------+---------------------------------------------+
| label                              | 'NIRSpec'                                   |
+------------------------------------+---------------------------------------------+
| can_do_imaging                     | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_imaging               | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_resolved_spectroscopy | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_spectroscopy          | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_photometry                  | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_psf_imaging                 | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_psf_spectroscopy            | True                                        |
+------------------------------------+---------------------------------------------+
| can_do_resolved_spectroscopy       | True                                        |
+------------------------------------+---------------------------------------------+
| can_do_spectroscopy                | True                                        |
+------------------------------------+---------------------------------------------+
| resolution                         | 0.1 kpc                                     |
+------------------------------------+---------------------------------------------+
| lam (100,)                         | 1.00e+03 Å -> 1.00e+04 Å (Mean: 5.50e+03 Å) |
+------------------------------------+---------------------------------------------+
| psfs (100, 100)                    | 1.00e+00 -> 1.00e+00 (Mean: 1.00e+00)       |
+------------------------------------+---------------------------------------------+

We can also apply noise to the spectrum by passing the noise as a function of wavelength to the noise_maps argument.

[18]:
nirspec = Instrument(
    "NIRSpec",
    lam=np.linspace(10**3, 10**4, 100) * angstrom,
    resolution=0.1 * kpc,
    psfs=np.ones((100, 100)),
    noise_maps=np.random.rand(100, 100),
)
print(nirspec)
+----------------------------------------------------------------------------------+
|                                    INSTRUMENT                                    |
+------------------------------------+---------------------------------------------+
| Attribute                          | Value                                       |
+------------------------------------+---------------------------------------------+
| label                              | 'NIRSpec'                                   |
+------------------------------------+---------------------------------------------+
| can_do_imaging                     | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_imaging               | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_noisy_resolved_spectroscopy | True                                        |
+------------------------------------+---------------------------------------------+
| can_do_noisy_spectroscopy          | True                                        |
+------------------------------------+---------------------------------------------+
| can_do_photometry                  | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_psf_imaging                 | False                                       |
+------------------------------------+---------------------------------------------+
| can_do_psf_spectroscopy            | True                                        |
+------------------------------------+---------------------------------------------+
| can_do_resolved_spectroscopy       | True                                        |
+------------------------------------+---------------------------------------------+
| can_do_spectroscopy                | True                                        |
+------------------------------------+---------------------------------------------+
| resolution                         | 0.1 kpc                                     |
+------------------------------------+---------------------------------------------+
| lam (100,)                         | 1.00e+03 Å -> 1.00e+04 Å (Mean: 5.50e+03 Å) |
+------------------------------------+---------------------------------------------+
| psfs (100, 100)                    | 1.00e+00 -> 1.00e+00 (Mean: 1.00e+00)       |
+------------------------------------+---------------------------------------------+
| noise_maps (100, 100)              | 1.46e-04 -> 1.00e+00 (Mean: 5.00e-01)       |
+------------------------------------+---------------------------------------------+