ScopeSim Sources#

ScopeSim Source and SourceField Overview#

What is a Source?#

Source is the top-level target container passed into OpticalTrain.observe(). It combines:

  • Spatial information: where light is on sky (source.fields)

  • Spectral information: what spectrum each component has (source.spectra)

  • Metadata: extra context (source.meta)

A single Source can hold multiple components (e.g., stars + diffuse background + cube).


What is a SourceField?#

Source.fields is a list that stores SourceField objects representing one spatial/spectral component.

Available field types (subclasses of SourceField):

  1. ``TableSourceField``

    • Stores an astropy.table.Table with point-source rows.

    • Typical columns: x, y, ref, weight.

    • ref maps each row to an entry in source.spectra.

  2. ``ImageSourceField``

    • Stores a 2D fits.ImageHDU (surface-brightness map).

    • Uses WCS in header for sky-to-pixel mapping.

    • Usually linked to one spectrum via header metadata (e.g., SPEC_REF).

  3. ``CubeSourceField``

    • Stores a 3D cube (fits.ImageHDU) with spatial + wavelength axes.

    • Contains its own spectral axis (not just one average spectrum).


[1]:
import numpy as np
import astropy.units as u
from astropy.table import Table
from astropy.io import fits

import scopesim_templates as sim_tp
from scopesim.source.source import Source
import scopesim.source.source_templates  as source_templates

from zs_scopesim_tools.plots import PlotScene
plotter = PlotScene()

How to create Source objects#

A) From a point-source table + spectra#

[2]:
# Two point sources at (0,0) & (1.2,-0.5), both their spectra at index 0 in spectra list
tbl = Table(
    data=[[0.0, 1.2], [0.0, -0.5], [0, 0], [1.0, 0.7]],
    names=["x", "y", "ref", "weight"],
)
tbl["x"].unit = u.arcsec
tbl["y"].unit = u.arcsec

ps = Source(table=tbl, spectra=[source_templates.vega_spectrum(10)], name="Stars")
ps.fields
[2]:
[TableSourceField(field=<Table length=2>
    x       y     ref   weight
  arcsec  arcsec
 float64 float64 int64 float64
 ------- ------- ----- -------
     0.0     0.0     0     1.0
     1.2    -0.5     0     0.7, spectra={0: <synphot.spectrum.SourceSpectrum object at 0x11602b320>})]
[3]:
fig, axs = plotter.from_source(ps)
../../../_images/_staged_sim_notebooks_ii_ScopeSim_Sources_4_0.png

B) From an image HDU + spectrum#

[4]:
img = np.ones((60, 60), dtype=float)
hdr = fits.Header(cards={'CUNIT1':'arcsec', 'CUNIT2':'arcsec', 'CDELT1':1, 'CDELT2':1, 'CRVAL1':0, 'CRVAL2':0}) # need to include this minimal header
hdu = fits.ImageHDU(data=img, header=hdr)

im = Source(image_hdu=hdu, spectra=[source_templates.ab_spectrum(mag=20)]) # ab_spectrum creates a spectrum with constant flux in magnitude space of given mag (which does not mean constant in erg/s/cm2/Angstrom)
print(im.fields)
fig, axs = plotter.from_source(im, pixel_scale=0.1)  # 0.1 arcsec/pixel for plotting
[ImageSourceField(field=<astropy.io.fits.hdu.image.ImageHDU object at 0x11778d340>, wcs=WCS Keywords

Number of WCS axes: 2
CTYPE : '' ''
CUNIT : 'deg' 'deg'
CRVAL : 0.0 0.0
CRPIX : 0.0 0.0
PC1_1 PC1_2  : 1.0 0.0
PC2_1 PC2_2  : 0.0 1.0
CDELT : 0.000277777777777777 0.000277777777777777
NAXIS : 60  60, spectra={0: <synphot.spectrum.SourceSpectrum object at 0x117779e20>})]
../../../_images/_staged_sim_notebooks_ii_ScopeSim_Sources_6_1.png

NOTE: Can also use src.source_templates.uniform_source() to create the above source in one step as shown below. The default spatial sampling is 1 arcsec/pixel.

[5]:
im2 = source_templates.uniform_source(source_templates.ab_spectrum(mag=20), extent=64)
print(im2.fields)
fig, axs = plotter.from_source(im2)
[ImageSourceField(field=<astropy.io.fits.hdu.image.ImageHDU object at 0x1179cb350>, wcs=WCS Keywords

Number of WCS axes: 2
CTYPE : 'RA---TAN' 'DEC--TAN'
CUNIT : 'deg' 'deg'
CRVAL : 0.0 0.0
CRPIX : 32.5 32.5
PC1_1 PC1_2  : 1.0 0.0
PC2_1 PC2_2  : 0.0 1.0
CDELT : -0.00027777777777778 0.00027777777777778
NAXIS : 64  64, spectra={0: <synphot.spectrum.SourceSpectrum object at 0x116ccfd10>})]
../../../_images/_staged_sim_notebooks_ii_ScopeSim_Sources_8_1.png

To create a uniform source use ConstFlux1D with the appropriate amplitude. Default amplitude unit is assumed to be PHOTLAM (photon/s/cm^2/Angstrom) if not supplied, but if another unit is supplied it will be converted to PHOTLAM. Constant flux in another unit may not be constant in PHOTLAM, so be careful in usage.

[6]:
model = source_templates.ConstFlux1D(amplitude=0.001) # synphot model, default unit is photon/s/cm^2/Angstrom
waves = np.geomspace(100, 300000, 50000)
spectrum = source_templates.SourceSpectrum(source_templates.Empirical1D, points=waves, lookup_table=model(waves))
im3 = source_templates.uniform_source(spectrum, extent=60)
fig, axs = plotter.from_source(im3)
../../../_images/_staged_sim_notebooks_ii_ScopeSim_Sources_10_0.png

C) From helper templates (quick start) available in scopesim_templates package#

[7]:
# star
star = sim_tp.star(filter_name='V', amplitude=10*u.ABmag) # spectra taken from 'spextra' package
_, _ = plotter.from_source(star)
../../../_images/_staged_sim_notebooks_ii_ScopeSim_Sources_12_0.png
[8]:
# Galaxy, loaded from saved fits template of NGC1232L
gal = sim_tp.extragalactic.galaxies.spiral_two_component(extent=200*u.arcsec, fluxes=(15, 15)*u.mag)
_ = plotter.from_source(gal)
../../../_images/_staged_sim_notebooks_ii_ScopeSim_Sources_13_0.png

Other available galaxy models include galaxy, galaxy3d, and elliptical. See scopesim_templates.extragalactic.galaxies for details.

Some realistic examples of sources#

A uniform source to simulate dome flats#

[9]:
# Let's say we want a high-power halogen bulb emitting a 3000 K blackbody spectrum, uniformly illuminating a 1 arcmin x 1 arcmin area on the sky. We can create this source as follows:
domeflat = sim_tp.calibration.flat_field(temperature=3000*u.K, amplitude=8*u.ABmag, filter_curve='V', extend=60)
_ = plotter.from_source(domeflat)
../../../_images/_staged_sim_notebooks_ii_ScopeSim_Sources_17_0.png

Arc lamps for wavelength calibration#

lamp_flat() is a provided wrapper function that creates a uniform source with a line spectrum from given line list(s). Look at its implementation in zs_scopesim_tools.sources for details. The default lines are that of ThAr, Ne and Ar lamps.

[10]:
from zs_scopesim_tools.sources import lamp_flat
lamp = lamp_flat()
_ = plotter.from_source(lamp)
../../../_images/_staged_sim_notebooks_ii_ScopeSim_Sources_20_0.png
[10]:

Extragalactic transient: Supernova#

Template spectra can be pulled from A-star Vienna’s spextra package library: https://scopesim.univie.ac.at/spextra/database/libraries/

from spextra import Spextrum
sed = Spextrum('brown/NGC3870')

sed = Spextrum('sne/sn1a').redshift(0.02) # redshift it to match the host galaxy
spec = sed.scale_to_magnitude(14*u.ABmag, 'g')

Or you can use your own (wave, flux) Quantity arrays to create a SourceSpectrum object using zs_scopesim_tools.sources.empirical_spectrum().

NOTE: Make sure your spectrum has appropriate resolution and wavelength coverage for your simulation.

[11]:
# base galaxy centered at 0, 0 arcsec
gal = sim_tp.galaxy(sed='brown/NGC3870', z=0.02, amplitude=15, filter_curve='g', pixel_scale=1, r_eff=2.5, n=1., ellip=0.3, theta=90, extend=5)
# shift galaxy 2" up in y
gal.shift(dy=2 * u.arcsec)

from zs_scopesim_tools.sources import transient
sn = transient(x=0, y=0, spextrum_template='sne/sn1a', scale_to_redshift=0.02, scale_to_mag=14*u.ABmag, filter_curve='g',
               name='SNIa')
# add sn at center
gal.append(sn)

_ = plotter.from_source(gal, pixel_scale=1.0)
../../../_images/_staged_sim_notebooks_ii_ScopeSim_Sources_24_0.png
[ ]: