Welcome to SimCADocs!

The (slowly expanding) documentation base for SimCADO, the instrument data simulation package for MICADO at the ELT.

Important

SimCADO is currently under active development. The current version of SimCADO (dubbed v0.7) is however capable to answer many questions about the future performance of MICADO imaging mode and your favorite science case. For the spectroscopic mode, please consult SpecCADO.

In this latest version SimCADO is able to correctly simulate DIT and NDITs. Accordingly, the keyword OBS_EXPTIME has been replaced by OBS_DIT, with total observing time given by OBS_DIT*OBS_NDIT. Please update your scripts and configuration files after downloading the latest version.

SimCADO in a nutshell

SimCADO is a python package designed to simulate the effects of the Atmosphere, E-ELT, and MICADO instrument on incoming light. The current version (v0.7) can simulate the MICADO imaging mode (4mas and 1.5mas per pixel in the wavelength range 0.7µm to 2.5µm).

_images/simcado_in_30_secs.gif

A simple simulation in 30 seconds with SimCADO.

Reference Material

Downloading and Installing

For more information, see the Download section

SimCADO has only been tested in Python 3.x.

It is hightly recommended to use Python 3, however the basics of generating images will still work in Python 2.7. We cannot guarantee this though.

The quick way:

$ pip install SimCADO

We also recomend to install SimCADO in an anaconda/miniconda/etc python distributions as it is much easier to keep control over your python environment.

The first time in python you should update the SimCADO data directory with get_extras():

>>> import simcado
>>> simcado.get_extras()
>>>
>>> # !! Only works in Python 3 - See Downloads section
>>> simcado.install_noise_cube()

If you running Python 3, it would be helpful to expand the internal detector noise cube with install_noise_cube().

Keeping SimCADO updated

As MICADO developes, the data files that SimCADO uses will also be updated. Therefore before you do any major work with SimCADO we HIGHLY recommend calling get_extras():

>>> simcado.get_extras()

iPython/Jupyter notebooks

A (continualy expanding) series of iPython Notebooks detailing how to use SimCADO are available here in the Notebooks section.

Hint

Don’t feel like sifting through documentation? Common commands and examples are on the SimCADO cheat-sheet:

Running a simulation in 3 lines

The easiest way to run a simulation is to create, or load, a Source object and then call the run() command. If you specify a filename, the resulting image will be output to a FITS file under that name. If you do not specify a filename, the output will be returned to the console/notebook as an HDUList object.

To begin, we will import the simcado module (assuming it is already installed).:

>>> import simcado

At the very least, we need to create a Source object which contains both spatial and spectral information on our object of interest. Here we use the built-in command simcado.source.cluster() to create a Source object for a 10000-Msun stellar cluster. (Creating Sources for more information).:

>>> src = simcado.source.cluster()

We now pass the Source object through SimCADO. This is as easy as calling run(). If we specify a filename, SimCADO will write the output to disk in the form of a FITS file. If no filename is given, then SimCADO returns an astropy fits object to the console or notebook.:

>>> simcado.run(src, filename="my_first_sim.fits")

Changing simulation parameters

The run() also takes any configuration keywords as parameters for running the simulation. For example, the default exposure time for the simulation is 60 seconds, however this can be increased of decreased by using the keyword OBS_EXPTIME (and/or combining it with OBS_NDIT). A stacked 6x 10 minute observation sequence would look like:

>>> simcado.run(src, filename="my_first_sim.fits", OBS_DIT=600, OBS_NDIT=6)

That’s it. Of course SimCADO can also go in the other direction, providing many more levels of complexity, but for that the reader is directed to the examples pages and/or the API documentation.

SimCADO building blocks

For a brief explanation of how SimCADO works and which classes are relevant, please see either the GettingStarted or SimCADO in depth section.

Using SimCADO

Getting Started with SimCADO

SimCADO can be super easy to use, or super complicated. The level of complexity is completely up to the user. A basic simulation involves only 1 thing: a Source object to describe the observable object. Once the user has created this object, the function simcado.simulation.run() is all that needs to be called. Controlling the parameters of the simulation can be done either by passing keyword-value pairs, or my using a UserCommands dictionary.

Note

Even though this documentation is not yet complete (it is a very big job), lots more information is included in the docstrings of every SimCADO function and class. These can be easily viewed in the interactive python interface (iPython, or Jupyter Notebook) with either the question mark operator or by using SHIFT+TAB with the cursor over the function name.

Doing this in iPython will call up the docstring:

>>> simcado.Source?

Source

For full details, please see the API and examples of Source Objects

The Source class is probably the most important class for testing science cases. Therefore spending time on creating accurate Source representations of the object of interest is key to getting good results with SimCADO. Source objects can be created from scratch, with functions provided by SimCADO, or by loading in a pre-existing Source-FITS file.

Note

SimCADO is CaSe SensITIVe! SimCADO has the class simcado.Source() and the module simcado.source. These should not be confused. simcado.source is the module which contains the class Source and all the helper functions for creating various types of Source objects. The source code for the class Source is actually in simcado.source.Source, however to make things easy, Source is available directly as simcado.Source(). Be careful and remember simcado.Source != simcado.source.

For a description of the Source object, and the source module, see How SimCADO works.

Loading a pre-existing Source object

To load in a pre-existing Source (i.e. one that you saved earlier), specify the keyword filename= when initialising the Source object.:

>>> import simcado as sim
>>> my_src = sim.Source(filename="star_grid.fits")

Source-FITS files have a very specific file format, so it’s best to only import files that were generated directly from other Source objects. It’s a chicken/egg scenario, which is why the next section deals with creating Source objects in memory. For a description of the file format for saved Source objects, see “File Format of saved Source objects”.

Making a Source with SimCADO’s in-built functions

The simcado.source module provides an ever-increasing series of functions to create Source objects in memory. These include, (from simcado.source)

Two useful functions here are stars() and source_from_image()

  • stars() takes a list of magnitudes (and optionally spectral types) and positions for a common broad-band filter (default is “K”) and generates a Source object with those stars in the field.

    >>> x, y = [-2.5, 0.7, 16.3], [3.3, -0.2, 25.1]
    >>> mags, spec_types = [25,21,28], ["K0V", "A0III", "G2V"]
    >>> filt = "H"
    >>>
    >>> my_src = sim.source.stars(mags=mags, x=x, y=y, filter_name=filt,
                                                    spec_types=spec_types)
    
  • source_from_image() creates a Source based on a 2D numpy array provided by the user. The 2D array can come from anywhere, e.g. the data from a FITS image, a BITMAP image, from memory, etc. Alongside the image, the user must provide a spectrum (plus a vector with the bin centres) and the pixel field of view (e.g. 0.004 arcsec for MICADO). SimCADO then extracts all pixels from the image which have values above flux_threshold (defualt is 0) and saves these pixel coordinates. The spectrum provided is then connected to these pixel, and scaled by the pixel value.

    >>> # ... Create an image - a circle with a radius of 20 pixels on a
    >>> # ... grid 200 pixel wide
    >>> XX = np.array([np.arange(-100,101)]*201)
    >>> im = np.sqrt(XX**2 + XX.transpose()**2)
    >>> im[im>20] = 0; im[im>0] = 1
    >>>
    >>> # ... Pull in the spectrum for a G2V star with K=20
    >>> lam, spec = simcado.source.SED("G2V", filter_name="K", magnitude=20)
    >>>
    >>> # ... Make the source object
    >>> my_src = sim.source.source_from_image(images=im, lam=lam, spectra=spec, plate_scale=0.004)
    

SimCADO also provides a series of spectra for stars and galaxies, however these are meant as a guide to those who are just starting out. For serious work, the user is encouraged to provide their own spectra. More information on the in-built spectra can be found in the Source Objects example section.

Simulating with SimCADO

The quick, the dirty and the ugly

As seen on the index page, a simulation can be run using 3 lines of code:

>>> import simcado
>>> src = simcado.Source(filename="my_source.fits")
>>> simcado.run(src, filename="my_image.fits")

The run() function is quite powerful. Many users may find that they don’t need anything else to run the simulations they need. The full function call looks like this:

simcado.run(src, filename=None,
            mode="wide", detector_layout="small",
            cmds=None, opt_train=None, fpa=None,
            return_internals=False,
            **kwargs)

Lets pull this function call apart in order of importance to the simulation:

  1. src: Obviously the more important aspect is the Source object. Without a Source these is nothing to observe

  2. filename: Where to save the output FITS file. If None is provided (or the parameter is ignored), the output is returned to the user. This comes in handy if you are working in a Jupyter Notebook and wand to play with the output data immediately. Or if you are scripting with SimCADO and don’t want to be slowed down by writing all images to disk

  3. Two important parameters here are mode and detector_layout: These two define the MICADO observing modes.

Currently mode can be either "wide" (4mas/pixel) or "zoom" (1.5mas/pixel).

The detector_layout can also be changed to speed up simulations of single objects. For example if the galaxy you’re interested in is at z=5, you don’t need to read out all 9 MICADO chips for each observation. In fact, a 1024x1024 window at the centre of the middle chip will probably be enough. Therefore SimCADO offers the following “layouts” for the detector - “small”, “wide”, “full”. The default is “small”.

  • small - 1x 1k-detector centred in the FoV

  • centre - 1x 4k-detector centred in the FoV

  • full - 9x 4k-detector as described by the keyword FPA_CHIP_LAYOUT

  1. cmds, opt_train, fpa are all parameters that allow you to provide custom built parts of the machinary. Say you have a set of commands saved from a previous simulation run which differ from the default values, then you can use these by passing a UserCommands object via the cmd parameter. The same goes for passing an custom OpticalTrain object to opt_train and a custom Detector object to fpa. For more information see the relevant examples sections - UserCommands examples, OpticalTrain examples, Detector examples.

  2. return_internals allows you to do the opposite of the previous three parameters. If you would like to save the UserCommands, Detector and/or OpticalTrain from your simulation run, the by setting return_internals=True, SimCADO will return these along with the simulated imagery. Note that this only works if filename=None.

  3. **kwargs: Although kwargs is the last parameter, it actually allows you to control every aspect of the simulation. kwargs takes any keyword-value pair that exist in the SimCADO configuration file, and so you can control single aspects of the simulation by passing these keyword-value pairs to run(). For example, you can increase the exposure time of the image by passing

    simcado.run(src, … , OBS_DIT=600, INST_FILTER_TC=“J”, …)
    

A list of all the available keyword-value pairs can be found in the Keywords section .

Alternatively you can dump a copy of the default parameters by calling simcado.commands.dump_defaults().

Changing Filters

The keyword INST_FILTER_TC allows you to supply either the name of a filter (i.e. “Ks”, “PaBeta”) or a path to an ASCII file containing a filter curve. INST_FILTER_TC can be passed to run() just like any other SimCADO configuration keyword:

>>> simcado.run(src, INST_FILTER_TC="J")
>>> simcado.run(src, INST_FILTER_TC="path/to/my_filter_curve.txt")

SimCADO has some generic filters built in. These include all the regular NIR broadband filters (I, z, Y, J, H, K, Ks). There are also some narrow band filter. As the MICADO filter set is expected to change, we will not list the SimCADO filter set here. Instead the user can find out which filters are available by calling the function (as of Nov 2016):

>>> print(sim.optics.get_filter_set())
['B', 'BrGamma', 'CH4_169', 'CH4_227', 'FeII_166', 'H', 'H2O_204', 'H2_212',
 'Hcont_158', 'I', 'J', 'K', 'Ks', 'NH3_153', 'PaBeta', 'R', 'U', 'V', 'Y',
 'z']

If you’d like to use your own filter curve, note that the ASCII file should contain two columns - the first holds the wavelength values and the second hold the transmission values between 0 and 1.

Setting the observation sequence

The important keywords here are: OBS_DIT, OBS_NDIT

  • OBS_DIT [in seconds] sets the length of a single exposure. The default setting is for a 60s exposure

  • OBS_NDIT sets how many exposures are taken. The default is 1.

Depending on what your intended use for SimCADO is, the keyword OBS_SAVE_ALL_FRAMES=["no", "yes"] could also be useful. The default is to not save all the individual exposures, but stack them and return a single HDU object (or save to a single FITS file). If OBS_SAVE_ALL_FRAMES="yes", then a filename must also be given so that each and every DIT can be saved to disk.

Reading out the detector

Warning: running a full simulation could take ~10 minutes, depending on how much RAM you have available:

>>> simcado.run(detector_layout="small"")

The detector_layout keyword is key:

detector_layout : str, optional
    ["small", "centre", "full"] Default is "small".

Where each of the strings means:

  • "small" - 1x 1k-detector centred in the FoV

  • "centre" - 1x 4k-detector centred in the FoV

  • "full" - 9x 4k-detector as per MICADO imaging mode (either 4mas or 1.5mas)

  • "default" - depends on “mode” keyword. Full MICADO 9 chip detector array for either 4mas or 1.5mas modes

PSF utilities in SimCADO

In SimCADO we have pre-packaged some simulated PSFs which match the expectations of the different AO modes of MICADO. As new simulations of the AO capabilities become available we will include these new PSFs in SimCADO. The available PSFs are

  • PSF_SCAO.fits

  • PSF_MCAO.fits

which are the AO modes available. Additionally we provide a LTAO PSF (PSF_LTAO.fits) and a EELT diffraction limited PSF (PSF_POPPY.fits) calculated with poppy

For the moment, the PSF is assumed constant accross the field. The new (refractored) version will be capable to deal with field varying PSFs in a realistic manner.

SimCADO also provides utility functions that are able to produce analytic PSFs to be used in the simulation in adition to the pre-calculated PSFs. Please check the simcado.psf module. The most important functions are the following:

All these functions can save the computed PSFs in fits format by specifying a filename. That file can be later used in the simulations as a parameter in simcado.simulation.run() using the SCOPE_PSF_FILE=filename keyword.

In the notebook section you can find a few detailed examples how to create and work with these PSFs.

Saving and reusing commands

The UserCommands object

Passing more than a few keyword-value pairs to the simcado.run() becomes tedious. SimCADO therefore provides a dictionary of commands so that you can keep track of everthing that is happening in a simulation.

>>> my_cmds = simcado.UserCommands()
>>> simcado.run(my_src, cmds=my_cmds)

When initialised the UserCommands object contains all the default values for MICADO, as given in Keywords. The UserCommands object is used just like a normal python dictionary:

>>> my_cmds["OBS_DIT"] = 180
>>> my_cmds["OBS_DIT"]
180.0

It can be saved to disk and re-read later on:

>>> my_cmds.writeto("path/to/new_cmds.txt")
>>> new_cmds = simcado.UserCommands("path/to/new_cmds.txt")
>>> new_cmds["OBS_DIT"]
180.0

If you prefer not to use interactive python and just want to dump a commands file to edit in your favourite text editor:

>>> simcado.commands.dump_defaults("path/to/cmds_file.txt")

More information on the UserCommands object is given in the Examples Section

Behind the scenes of SimCADO

SimCADO uses 4 main classes during a simulation:

  • Source holds spatial and spectral information about the astronomical source of photons, e.g. galaxy, star cluster, etc.

  • OpticalTrain contains information on the various elements along the optical path, e.g. mirrors reflectivity curves, PSFs, instrumental distortion, etc.

  • Detector represents the focal plane detector array and contains information on the electronic characteristics of the detector chips and their physical positions.

  • UserCommands is a dictionary of all the important keywords needed by SimCADO to run the simultationm, e.g. OBS_DIT (exposure time) or INST_FILTER_TC (filter curve)

For more information on how SimCADO works please see the SimCADO in Depth section.

Things to watch out for

This space. It will soon expand!

Installation

The latest stable version of SimCADO can be installed from PyPI with

pip install simcado

If you have SimCADO already installed and you want to install the latest version, please type

pip install --upgrade simcado

Please do not forget to obtain the latest data file package as explained in the section below

The latest development version of SimCADO can be found on GitHub:

https://github.com/astronomyk/SimCADO

Python 3 vs Python 2

Note

SimCADO has been programmed in Python 3.

While most of the basic functionality for SimCADO will work with Python 2.7, we haven’t tested it properly. For example, the function simcado.install_noise_cube() only works in Python 3. This isn’t critical - it just means that if you want to have read noise variations in your images, you need to use Python 3. However it won’t crash SimCADO for single images.

Note

A side note: Astropy will stop supporting Python 2.7 in 2019 and the official End-of-Life for Python 2.7 is 2020, i.e. no more maintainance. We are running under the assumption that SimCADO will (hopefully) still be around after 2020, hence why we have concentrated our efforts on developing in Python 3.

Note

SimCADO will need to download several hundreds of MBs of instrument data into the install directory. Hence why we use the –user flag when installing via pip. If you want to keep SimCADO in your normal packages directory, then you will need to give python root access while updating SimCADO’s data files.

Dependencies

Required

Package

Version

numpy

>1.10.4

scipy

>0.17

astropy

>1.1.2

wget

>3.0

requests

>2.0

synphot

>0.1

pyyaml

Optional

Package

Version

matplotlib

>1.5.0

poppy

>0.4

All dependencies should be automatically installed when typing the pip command above. In case of any error message you can try to install them manually:

$ pip install numpy scipy astropy wget matplotlib poppy pyyaml synphot requests

We really recomend to install SimCADO in a python distribution like anaconda or miniconda as they allow to have full control over your python environment without interfering with your system instalation.

Getting up-to-date data for SimCADO

SimCADO is being developed along side MICADO. To keep the files that SimCADO uses as fresh as possible, you should run the following command, at the very least the first time you start SimCADO:

>>> import simcado
>>> simcado.get_extras()

This downloads the latest versions of all the files SimCADO uses behind the scenes, e.g. PSF files, transmission curves etc. If you haven’t used SimCADO for several months, chances are there are new data available. It is therefore advantageous to run this command periodically.

Adding variation to the Detector noise

Note

Currently only available for Python 3.

By default SimCADO only supplies a single H4RG noise frame. Hence if you plan on generating a series of images, all images will have the same detector noise pattern. Don’t worry, photon shot noise is still completely random, however if you stack 1000s of simulated images with the same detector noise frame, this pattern will show through. This problem can be avoided by running the following function the first time you run simcado:

We recommend running this command in a separate Python session as it can take up to 10 minutes depending on your computer.:

>>> simcado.install_noise_cube(n=25)

SimCADO contains the code to generate unique detector noise images (Rauscher 2015), however creating a 4k detector noise frame takes about 20 seconds. In order to avoid wasting time by generating noise for each frame every time SimCADO is run, .install_noise_cube(n) generates n noise frames and saves them in the SimCADO data directory. In future simulation one of these detector noise frames are picked at random whenever a <Detector>.read_out() is called.

Obviously a trade-off has to be made when running .install_noise_cube(n). The more noise frames available, the less systematic noise is visible in the read noise of stacked images. However, the more frames are generated, the longer it takes. A good solution is to open a separate window and have SimCADO generate frames in the background.

SimCADO FAQs

Here are some answers to known issues with SimCADO.

Work around for failing install_noise_cube() with Python 2.7

The problem lies with Python 2.7. The noise cube code is 3rd party code that only works on Python 3 and I haven’t had a chance to dig into that code yet to find the problem

Generate a noise cube in Python 3. First install python3:

$ pip install simcado
$ python3

Then create the noise cube:

>>> import simcado
>>> sim.detector.make_noise_cube(num_layers=25, filename='FPA_noise.fits', multicore=True)

Note

Your simcado/data folder can be found by printing the __pkg_dir__ variable:

>>> simcado.utils.__pkg_dir__
Copy the new noise cube into the Python 2.7 simcado/data folder.

By default SimCADO looks for the noise cube in its data directory - <Your Python 2.7 Directory>/lib/python/site-packages/simcado/data/:

$ cp ./FPA_noise.fits  <Your Python 2.7 Directory>/lib/python/site-packages/simcado/data/FPA_noise.fits
No access to the simcado/data folder?

If you can’t save files into the simcado/data directory (or you can’t be bothered finding it), you can use the FPA_NOISE_PATH keyword when running a simulation to point simcado to the new noise cube file:

>>> simcado.run(my_source, ..... , FPA_NOISE_PATH="<path/to/new>/FPA_noise.fits")

or if you’re using a UserCommands object to control the simulation:

>>> cmds = simcado.UserCommands()
>>> cmds["FPA_NOISE_PATH"] = "<path/to/new>/FPA_noise.fits"

Surface brightness scaling in SimCADO

Question

Is it true that if the array that I pass to simcado has a value of 1, then simcado will simulate exactly a SB = m mag/sq.arcsec pixel? What happens if the passed numpy array has a different pixel size. Are the counts in each pixel then scaled according to their different surface area?

To answer the question on scaling we need look at the docstring for source_from_image:

source_from_image(images, lam, spectra, plate_scale, oversample=1,
                  units="ph/s/m2", flux_threshold=0,
                  center_pixel_offset=(0, 0),
                  conserve_flux=True)

The 3 parameters of interest here are plate_scale, oversample and conserve_flux.

  • plate_scale is the plate scale of the image. So if we take a HAWK-I image, we have a plate_scale of 0.106 arcsec. SimCADO needs this so that it can work out how many photons are coming in per pixel in the image you provide.

  • oversample. If oversample stays at 1 (default), then SimCADO will generate a “point source” for each pixel - i.e. every 0.106 arcsec there will be one source emitting with the intensity of that pixel. This is sub-optimal if we want to use an extended object, as SimCADO will turn the image into a grid of point sources with a spacing equal to plate_scale. Therefore we need to over sample the image so that SimCADO makes at least 1 light source per pixel. Hence to get down to 4mas for the SimCADO wide field mode, we would need to oversample the HAWK-I image by a factor of 0.106/0.004 = 26.5. I.e. oversample=26.5.

  • conserve_flux. If this is True (default), then when SimCADO oversamples the image, it multiplies the new image by a scaling factor = sum(orig_image) / sum(new_image). Thus a pixel with the value 1 in the original image will now have a value=(1 / 26.5)^2. Ifconserve_flux=False`, this scaling factor is not applied. Note: The scaling doesn’t affect the spectrum associated with the image at all.

Sub-pixel accuracy with SimCADO

There are two ways to go about getting SimCADO to simulate at the sub-pixel level (Nov 2016, only one is working so far):

  • Turn on SimCADO’s oversample mode with the keyword SIM_OVERSAMPLING:

    simcado.run(my\_src, ... , SIM\_OVERSAMPLING=4)
    

If SimCADO is using the 0.004 arcsec mode, then it will calculate everything based on a 0.001 arcsec grid. It resamples back up to 0.004 when passing the image to the detector module. Depending on the level of accuracy you need (and the computer power you have available), you can oversample as much as you’d like. Be careful with this - it uses lots of RAM.

  • SimCADO also has a sub-pixel mode built into the method <Source>.apply_optical_train(... ,sub_pixel=False), - (very slow if there are >100 stars, it doesn’t use FFTs) - however I’ve only done a quick tests to make sure the code works. I can’t guarantee it’s accurate though. I’ll put that on my list of things to do this week (22 Nov 2016)

I have many PSFs in a FITS Cube. How do I use just one layer

To extract a slice from the cube, we use astropy. Here i is the layer we want to extract:

from astropy.io import fits

f = fits.open("path/to/my/psf_cube.fits")

i = 24     # which ever layer from the cube that you want
psf = f[0].data[i, :,:]
hdr = f[0].header

hdu = fits.PrimaryHDU(data=psf, header=hdr)

hdu.header["CDELT1"] = 0.002    # whatever the plate scale of the PSF file is in arcsec
hdu.header["WAVELENG"] = 2.16   # whatever the wavelength of that layer is in micron

hdu.writeto("my_psf_layer.fits")

To use this PSF with SimCADO, we use the keyword SCOPE_PSF_FILE and pass the filename of the saved PSF slice:

simcado.run( ... , SCOPE_PSF_FILE="my_psf_layer.fits", ...)

Which filters are included in my version of SimCADO?

SimCADO provides a function to list all the filter curves contained in the simcado/data install directory:

>>> simcado.optics.get_filter_set()

The files containing the spectral response of the curves are located in the simcado/data install directory, which can be found by calling:

>>> simcado.__data_dir__

These files following the naming convention: TC_filter_<name>.dat. They contain two columns Wavelength [um] and Transmission [0..1]

Plotting Filter Transmission curves

To access a transmission curve, use the get_filter_curve() function:

>>> T_curve = simcado.optics.get_filter_curve(<FilterName>)

The returned TransmissionCurve object contains two arrays: .lam (wavelength) and .val (transmission). To access the numpy arrays:

>>> wavelength = Tcurve.lam
>>> transmission = Tcurve.val

Each TransmissionCurve object can be plotted by calling the internal method .plot(). The method uses matplotlib``s current axis (``plt.gca()), so if you are not using an iPython notebook, you will still need to call the plt.show() function afterwards. E.g.:

>>> import matplotlib.pyplot as plt
>>> T_curve.plot()
>>> plt.show()

SimCADO also has a somewhat inflexible function to plot all filter transmission curves which are in the simcado/data directory. Basically it loops over all names returned by get_filter_set() and plots them. It also applies a nice colour scheme.

>>> plot_filter_set()

I can also accept a custom list of filter names, if you don’t want to plot absolutely everything in the `simcado/data`directory (fyi, in early versions of simcado this includes many useless files - sorry)

>>> plot_filter_set(filters=("J","PaBeta","Ks"),savefig="filters.png")

What SimCADO can do?

Many things. Chances are it can do what you’d like, however you may need some patience, and or help from the held desk - see the contact section for who to contact if you have any questions.

What SimCADO can’t yet do?

Coronography, Spectroscopy

For the current version of the MICADO spectroscopy simulator see SpecCADO

https://github.com/oczoske/SpecCADO/

We are still working on incorporating SpecCADO into SimCADO, however as the SimCADO <=0.5 was primarily focused on imaging, we need to refactor the core code somewhat in order to achieve this.

Updates to SimCADO

Data updates

The data files used by SimCADO are continually being updated to reflect the newest information coming from the MICADO work packages.

To update your version of SimCADO, use the simcado.get_extras() command.

2019-09-18
  • SimCADO can now correctly perform DITs and NDITS

  • Accordingly, OBS_EXPTIME keyword in now OBS_DIT

  • Documents updated

2019-07-30
  • Several examples added to the notebooks

  • Bug fixes to source.elliptical

2019-03-26
  • SimCADO can now simulate a field varying PSF. See updated docs

2019-03-14
  • pip friendly setup.py

2019-02-19
  • Documentation Updated

  • Reference spectrum now based on synphot

2018-11-23
  • Moved the documentation to ReadTheDocs (finally)

  • Added filter plotting functionality

2017-01-31

New stable version available: SimCADO 0.4

2017-01-18
  • Added E-ELT mirror transmission curve TC_mirror_EELT.dat

2017-01-05
  • VLT mirror coating TC_aluminium.dat

  • HAWK-I filter curves: TC_filter_J.dat TC_filter_H.dat TC_filter_Ks.dat TC_filter_Y.dat

  • Updated detector layout FPA_chip_layout.dat

2016-11-12
  • TC_surface.dat Updated with more optimistic Strehl values for JHK central wavelengths

  • TC_mirror_gold.dat Added a reflectivity curve for an unprotected gold coating

  • default.config Changed INST_MIRROR_TC to reference TC_mirror_gold.dat

Source Code updates

The current stable version is SimCADO v0.4. The current development version is SimCADO v0.5dev

Development version

2017-01-05 * SimCADO now preloads the transmission curves. Generating an OpticalTrain now only takes ~2 seconds (compared to 20 previously)

2016-12-06 * Added functionality to generate “ideal” AO PSFs using POPPY for the diffraction limited core and added a Seeing halo

2016-11-12 * Bug fix in simcado.psf - psf.lam_bin_centers was taking opt_train.lam_bin_centers instead of using the “WAVE0” keywords in the FITS header * Bug fix in source.psf - apply_optical_train() was asking for PSFs outisde of the opt.train.psf range. related to the point above

Examples and Tutorials

Here are a list of scripts andnotebooks detailing how to use SimCADO. If you would like to add a notebook to this collection, please email it to Kieran Leschinski.

Cheat Sheet

Hint

If you don’t like sifting through documentation, try looking through the cheat sheet at some common commands and examples. If you find what you need, then you’ll know exactly what to look for in the simcado package

Tutorials

  • my_first_sim.ipynb

    An introductory notebook to SimCADO. Topics include: first steps with SimCADO, creating Source objects and customising simulations.

  • stars_anisocado.ipynb

    A example of how stars looks like with a field changing PSF as expected in the SCAO mode. Here, a bunch of stars are observed at 0, 7, 14 and 21 arcsec off-axis. Also available as a stand-alone script (stars_anisocado.py)

  • star_cluster_fullarray.ipynb

    This example simulates a star cluster filling the whole MICADO array with a MAORY-like PSF in the J-band. For that a new J-band PSF was generated with a Strehl of 7%. This PSF can be downloaded from the data directory (as well as others in H and Ks). Also available as stand-alone script (star_cluster_fullarray.py)

Science Cases

  • Betelgeuse.ipynb

    A quick look at whether it would be possible to observe Betelgeuse (J = -3 mag) with SimCADO without destroying the detectors. Short answer: yes.

  • StarDestroyer.ipynb

    If General Tarkin were to attack Earth and has hidding in orbit around the moon in his spaceship, could the E-ELT see it, and would we we know what it was?

PSF experiments

  • SimCADO_PSF_examples.ipynb

    A notebook showing the different PSFs available in SimCADO and doing a bit of analysis of their characteristics.

  • E-ELT_2-Phase_Mirror.ipynb

    As the primary mirror of the E-ELT was innitially thought to be built in 2 phases, this notebook uses SimCADO to have a look at what that means for the resulting E-ELT PSF.

Note

the PSFs generated here are only approximations based on a diffraction limited core combined with a Seeing Halo. These are meant only as a guide.

Workshop notebooks

  1. Setting up SimCADO

    Some basics about running SimCADO

  1. Working with point sources

    The basics for making and combining point source objects

  1. Notes on simulation with sub-pixel resolution

    A couple of examples on how to get SimCADO to do sub-pixel scale simulations

  2. Working with extended sources

    Creating a galaxy field with a large galaxy (the Antennae) and adding a series of background galaxies Here are the FITS file used in the simulation

Using PSFs with SimCADO

Point spread function (PSF) kernels are used by SimCADO to mimic the spread in the beam due to the specific optical configuration of the ELT+MAORY+MICADO optical system.

A PSF kernel is in essence a two dimensional array which describes how the light from a point source is spread out over the detector plane. While SimCADO can accept 2D numpy arrays as input directly from the user, more often than not the user will probably want to use a set of pre-calculated PSFs.

Default PSFs for MICADO

Warning

The default PSFs are approaching their expiry date

The PSF files described below are useful for quick simulations which don’t require a super accurate PSF. Furthermore they were generated in 2015 (MCAO, NOVA), and 2016 (SCAO, LESIA), and only cover a single set of atmospheric parameters.

For newer PSFs, see the section on SCAO PSFs (from AnisoCADO) or contact the SimCADO team about MCAO PSFs (from MAROY)

By default the MICADO instrument package includes PSF kernels (arrays) in FITS format for the MCAO and SCAO observing modes. These default kernel FITS files are found in the MICADO data folder under the names: PSF_MCAO.fits, PSF_SCAO.fits.

SimCADO can be told to use either one of these PSFs by passing the SCOPE_PSF_FILE keyword to either the simcado.run function, or to a UserCommands dictionary:

hdu = simcado.run(... , SCOPE_PSF_FILE="PSF_MCAO.fits")

or:

cmds = simcado.UserCommands()
cmds["SCOPE_PSF_FILE"] = "PSF_MCAO.fits"

Note

The default PSFs are field-constant.

This means that they do not vary over the field of view. For the MCAO option this is the optimal case - a constant AO correction everywhere in the field - however for the SCAO case, this is only valid for the central ~2x2 arcsec.

If we are interested in simulating the full MICADO field of view, it will be unrealistic to use the PSF_SCAO.fits file. More on this below.

Both the MCAO and SCAO files were generated for reasonably good conditions and should be understood as offering an optimistic view of how MICADO will perform.

Field varying SCAO PSF

As stated above the default PSFs contained in the MICADO package are for the case where the PSF doesn’t vary over the field. For the SCAO observation modes this is an unrealistic assumption unless one is only interested in the central ~2x2 arcsec or so. SimCADO (v0.6 and above) accepts a so-called FV-PSF file (field-varying PSF file) in order to simulate the degredation of the PSF over the field of view.

FV-PSF files are quite large (several 100 MB to GB) as they contain PSF kernels for many different positions over the field (and generally for several different wavelengths).

We have generated SCAO FV-PSF files for three observing conditions which roughly correspond to “good”, “median”, and “bad” atmospheric conditions.

Warning

These files are ~1 GB in size.

Profile

Seeing

Zenith Distance

Wind Speed

Turbulence Profile

File Link

Good

0.4

0

8.8

ESO Quartile 1

AnisoCADO_Q1

Median

0.67

30

10

ESO Median

AnisoCADO_Median

Bad

1.0

60

13

ESO Quartile 4

AnisoCADO_Q4

This FV-PSFs were generated by AnisoCADO. AnisoCADO is python package derived from Eric Gendron’s code for generating SCAO PSFs for the ELT+MICADO for any wavelength and off-axis guide star position. To generate custom FV-PSF kernels, see AnisoCADO’s documentation for how to make SimCADO-readable FV-PSF FITS files.

Images and profiles of the central PSF from each of these files can be found here:

To use these PSF files we simply pass the filename to SimCADO (as with the other PSF), and SimCADO (! >=v0.6) does the rest:

fvpsf_path = "path/to/AnisoCADO_SCAO_FVPSF_4mas_EsoQ1_20190328.fits"
simcado.run(... , SCOPE_PSF_FILE=fvpsf_path)

Warning

SimCADO will (probably) run slower when using a FV-PSF file.

This is because SimCADO convolves the FOV of each detector with each PSF kernel that is present inside the borders of that FOV. This means, e.g., if there are 9 different PSFs to be used in the region covered by the central detector chip, then this region will be convolved 9 times with different PSFs (and masked accordingly 9 times). Hence simulating the central chip will take 9 times as long as when using a field-constant PSF.

Custom instrument packages for SimCADO

Warning

This format will only work with SimCADO v0.4 and later versions

This way of specifying files and parameters has been depreciated for newer versions of SimCADO. A new API description will be available by June 2019.

SimCADO is a (reasonably) flexible framework for simulating telescope and instrument optical trains. It was primarily developed for use with the ELT telescope and the MICADO / MAORY instrument, however many other instruments can be simulated with SimCADO if the proper configuration files are provided.

This page aims to give a short overview of which files SimCADO needs in order to simulate a custom optical train.

Note

We’re happy to help implement other instruments with SimCADO

If you would like to use SimCADO to model another telescope / instrument system, and would like some help with how to do this, please contact the SimCADO team. We’re more that happy to help out.

Config Files

The default SimCADO configuration file can be found in the data folder of the installation directory: simcado/data/default.config. This folder can be found by calling:

import simcado
simcado.__data_dir__

To create a custom instrument package, we will need to create our own .config file. We can dump the default file by calling:

simcado.commands.dump_defaults("my_new_instrument.config", selection="all")

Next we will need to alter the values to fit our instrument. For some keywords we will need to provide file paths to a (correctly formatted) file describing the given effect. The most important files are described below.

File paths

Note

Use simcado.__search_path__ to store files in multiple places

SimCADO contains a function (find_file) which looks for file names in the directories contained in the list simcado.__search_path__. By default this list contains the working directory, and the two main folders in the installation directory:

>>> simcado.__search_path__
['./', '<pkg_dir>/simcado', '<pkg_dir>/simcado/data']

By adding directory names to the __search_path__ list at the beginning of a python script/session, we can tell SimCADO to look in other directories for the relevant files.

Required Files

PSF files

Keywords : SCOPE_PSF_FILE

This file should contain a (series of) PSF kernel(s) as FITS image extensions. Each extension must contain the keyword WAVE0 which tells SimCADO the wavelength for which the PSF kernel is relevant (in m or in um).

For MICADO, the default PSF FITS file contains extensions for each of the major broadband filters: I [0.87um], z [1.05um], J [1.25um], H [1.65um], Ks [2.15um]. For filters with central wavelengths which fall between these PSF kernels, SimCADO takes the extension with the closest wavelength.

In case we need to include field-variations in the PSF cube, the new PSF format is also accepted by SimCADO. It’s description can be found here :

Mirror transmission curves

Keywords : SCOPE_M1_TC, INST_MIRROR_AO_TC, INST_MIRROR_TC, INST_FILTER_TC

TC (transmission curve) files are ASCII table files with two columns. The transmission profile can be as simple or as detailed as we want. Here is an example of a very simple filter transmission file:

# TC_filter_Ks.dat
Wavelength  Transmission
0.1         0
1.89        0
1.9         1
2.4         1
2.41        0
3.0         0

SimCADO uses astropy.table to read the file, so if astropy can read it, SimCADO can too.

Mirror lists

Keywords : SCOPE_MIRROR_LIST, INST_MIRROR_AO_LIST

These list files contain information on the geometry of the mirrors included in either the telescope section, or AO section of the optical system. Below we have the first 3 lines of the ELT’s mirror list file:

# EC_mirrors_scope.tbl
Mirror      Outer   Inner   Angle  Temp    Coating
M1          37.3    11.1    0.     0.      TC_mirror_mgf2agal.dat

where Outer, Inner [m] refer to the diameter of the mirror, Angle [deg] is the angle at which the plane of the mirror differs from that of the light beam, Temp [deg C] is the mirror temperature for determining the thermal background, and Coating is the filename of the Transmission Curve (TC) file describing the spectral response of the mirror coating material (see above: Mirror transmission curves).

The internal mirror configuration of the actual instrument is a special case. It is assumed that the cryostat temperature is sufficiently low that the blackbody emission from the internal mirrors is negligible. Hence only the mirror transmission is important and can therefore be described with the following two parameters:

INST_NUM_MIRRORS
INST_MIRROR_TC

For instruments without AO module, we can force SimCADO to ignore the AO components by setting the following keyword:

INST_USE_AO_MIRROR_BG = False
Wavefront errors

Keywords : INST_WFE

The current version of SimCADO (v0.6) includes only the reduction in strehl ratio induced by wave front error. It does this by calculating the peak of a normalised 2D Gaussian kernel (i.e. between 1 and 0) for each wavelength in the final system transmission curve, and applying an effective transmission loss based on the Gaussian peak value. This is very much a ‘first order approximation’ to including wavefront errors in the optical train. It should be noted that this has been improved upon in SimCADO v1.0.

The file passed to FPA_QE should follow this table format (taken from the MICADO+ELT INST_wfe.tbl file):

# wfe_rms   no_surfaces     material    optics
# [nm]      [#]             [str]       [str]
20          11              gold        mirror
10          4               glass       entrance_window
10          2               glass       filter
10          8               glass       ADC

Optional files

Atmospheric spectra

Keywords : ATMO_TC, ATMO_EC

By default SimCADO uses precalculated output from the ESO skycalc tool for the atmospheric emission and transmission curves. The default tables (EC_sky_25.tbl and TC_sky_25.tbl) are for PWV = 2.5mm and include columns for various airmasses over a wavelength range or [0.3, 3.0]um.

Additional transmission curves

Keywords : INST_DICHROIC_TC, INST_ENTR_WINDOW_TC, INST_PUPIL_TC

In case the transmission properties of any dichroics, entrance windows or pupil optics need to be included. The file format is the same as above for Mirror transmission curves

Detector noise images

Keywords : FPA_NOISE_PATH

By default SimCADO uses a FITS file containing an image of the detector noise pattern for the HAWAII-4RG detectors. We can include pre-calculated noise maps by passing a FITS file to FPA_NOISE_PATH. No special header keywords are needed.

Detector linearity curve

Keywords : FPA_LINEARITY_CURVE

Detector linearity can be included by passing an ASCII table with two columns which relate the real incoming flux to the measured photon flux as measured by the read-out electronics. The table should look like this:

# real_flux measured_flux
0           0
1           1
1000        998
3500        3200
...         ...
200000      180000
1000000     180000

Note

Linearity is applied to any imaging observation, regardless of length

Yes, this shouldn’t be, but we haven’t got around to fixing that yet. Hence to model long exposure observations (i.e. >1 min), it’s best just to set FPA_LINEARITY_CURVE = False

Simulation Building Blocks

SimCADO objects

Source

The Source class is probably the most important class for testing science cases. Therefore spending time on creating accurate Source representations of the object of interest is key to getting good results with SimCADO.

Basically a Source object represents photon sources using lists of positions (.x, .y), a list of unique spectra (.spectra) and a list of references which match each photon source to a spectrum in the list of spectra (.ref). All sources (extended and point source) can be decomposed into these lists. The advantage of using this approach is that objects with highly similar spectra can both reference the same position in .spectra, thereby reducing the number of spectra that need to be manipulated during a simulation.

File Format of saved Source objects

Source objects are stored as FITS files with 2 extensions. The first (ext=0) contains an image with dimensions (n, 4) where n is the number of positions for which there exists a spectrum - i.e. non-empty space. The 4 rows of the image correspond to the .x, .y, .ref, .weight arrays. The second extension (ext=1) contains another image with dimensions (m+1, len(lam)), where m is the number of unique spectra and len(lam) is the length of the .lam array containing the centres of all wavelength bins. The first row in the second extension is the .lam array.

Todo

describe how Source is linked to OpticalTrain, Detector and UserCommands

OpticalTrain

Todo

describe how OpticalTrain is linked to Source, Detector and UserCommands

Detector

Todo

describe how Detector is linked to Source, OpticalTrain and UserCommands

UserCommands

Todo

descript how UserCommands is linked to Source, OpticalTrain and Detector

SimCADO methods

Method behind applying an OpticalTrain to a Source object

(Taken from Leschinski et al. 2016)

In an ideal world, SimCADO would apply all spectral and spatial changes at the resolution of the input data. However, the memory requirements to do this are well outside the limits of a personal computer. The solution to this problem is to split the effects based on dimensionality. For certain elements in the optical train, the spectral and spatial effects can be decoupled (e.g. purely transmissive elements like the filters versus purely spatial effects like telescope vibration). For other elements, most notably the PSF and ADC, all three dimensions must be considered simultaneously. When applying an OpticalTrain, SimCADO follows the procedure described graphically in Figure 1. The example used in Figure 1 is for a simplified stellar cluster with only two different stellar types - A0V and K5V type stars.

_images/apply_optical_train.png

Figure 1 - The steps involved in applying an OpticalTrain object to a Source object. The example used here is for a simplified stellar cluster with only two different stellar types - A0V and K5V type stars.

  • A. The original Source object includes an array of spectra for each unique photon source (in the case of Figure 1, there are only two unique spectra) and four vectors: x, y, ref, weight. x and y hold the spatial information for each photon source, ref connects each source to a spectrum in the array of spectra and weight allows the spectrum to be scaled.

  • Spectral-effects. The first step in apply_optical_train() is to combine all optical elements which only act in the wavelength domain (e.g. filters, mirrors, etc.) into a single effect, then apply that effect to the array of spectra in the Source object.

  • B. The spectra in the Source object are now representative of the photo-electron count at the detector, assuming a perfect optical train and at the internal spatial resolution of the simulation, i.e. not at the pixel scale of the detector. The position vectors are converted into a two-dimensional “image” of the Source.

  • Spectrospatial-effects. The second step includes creating “slices” through the data. The spectra are binned according to several criteria (ADC shift, PSF FWHM difference, etc) with a spectral resolution anywhere from R=1 to R>100, and the number of photons per source in each wavelength bin is calculated. The sources in each “slice” are scaled according to the number of photons in each bin. The relevant spatial effects (atmospheric dispersion, convolution with PSF kernel, etc.) are then applied to each slice in turn.

  • C. At this stage, the Source object contains many spectral slices. Each is essentially the equivalent of a (very) narrow-band filter image.

  • D. All spectral effects have been taken into account, and so the binning in the spectral domain is no longer needed. The third step in apply_optical_train() is to add all the slices together to create a single monochrome image.

  • Spatial-effects. Fourth in the series of operations is to apply the purely spatial effects (e.g. telescope jitter, field rotation, etc) to the monochrome image.

  • E. The resulting image represents how the incoming photons from the source would be distributed on the focal plane after travelling through the entire optical train. At this point the background photons are also added to the image. Because SimCADO doesn’t take into account the changing sky background, the sky emission is approximated as a constant background photon count determined from an atmospheric emission curve (either provided by the user or generated by SkyCalc [Noll et al. 2012, Jones et al. 2013]). The mirror blackbody emission is also approximated as spatially constant. For all filters, with the exception of K, the amount of additional photons due to the mirror is close to negligible.

  • Detector-effects. The image is resampled down from the internally oversampled grid down to the pixel scale of the detector chips - in the case of MICADO either 4 mas or 1.5 mas, depending on mode. The final step is to add noise in all its forms to the image. Various aspects of the detector noise (correlated and uncorrelated white and pink noise read-out (see Rauscher 2015), dead pixels, etc.), as well as photon shot noise for both the atmospheric and object photons are taken into account. Further effects (e.g. detector persistence, cross-talk, etc) are also added to the image at this point.

  • F. The final image represents the spatial distribution of all photo-electrons (from the source object + atmosphere + primary mirror) plus the electronic noise generated by reading out the detector chips. The images from all the chips considered in a simulation are packed into a FITS extension and the FITS file is either written out to disk, or returned to the user if generated during an interactive Python session.

Method behind reading out a Detector object

Todo

add in a description of how Detectoctor.read_out() works

Controlling simulations

This page describes two ways of simulating: the quick and the repeatable. More about how SimCADO deals with commands can be found in the section on the UserCommands object.

Simulating the quick way

The function run() runs a simulation with all the default parameters. That said, SimCADO has a safety switch to stop you wasting 10 minutes on a Source that will be invisible, or so bright that it saturates the detector completely.

To get the full detector array, we set detector_array="full":

>>> im = sim.run(src, detector_array="full")

Note

Note, by patient! Simulating 9x 4k detectors is heavy lifting. Remember to use the internals if you don’t plan on changing the optical train.

Notes on simcado.run()

There are two parameters still to be covered in detail. Please see the documention (or read the docstring by using sim.run?). They are:

  • filename= : instead of returning the FITS object to the console, save it to disk under this name

  • mode= : default is “wide” for 4mas imaging. Also accepts “zoom” for 1.5mas imaging mode.

Viewing a full detector read out

Each chip read-out is stored in a FITS extension. There are 3 options to view the images:

  1. Save the FITS object to disk and use DS9, etc:

    >>> im.writeto("full_detector.fits")
    
  2. Use the filename= in simcado.run() to save directly to disk, and bypass the console. This is useful for scripting with SimCADO.

    >>> simcado.run(src, filename="full_detector.fits")
    
  3. Use the SimCADO function .plot_detector() from the .detector module:

    >>> im, (cmd, opt, fpa) = simcado.run(src, filename="full_detector.fits",
                                          return_internals=True)
    >>> simcado.detector.plot_detector(fpa)
    

The 3rd option is probably the least favourable as there are no options available, but it allows you to see what the readout will look like in a mosaic mode.

Using KEYWORD=VALUE pairs from the configuration file

SimCADO is controlled with a series of keyword-value pairs contained in a configuration file. The defaults are the best approximation to MICADO so changing them is not recommended if you want to simulate MICADO images. There are however some which are useful to play around with.

Note

SimCADO is CAsE sEnsiTIve**. All KEYWORDS are writen with capital letters.

Similar to SExtractor, SimCADO provides a way to dump both commonly used and less-common keywords to a file with command sim.commands.dump_defaults():

>>> sim.commands.dump_defaults()
#########################################################
##            FREQUENTLY USED KEYWORDS                 ##
#########################################################

#-------------------------------------------------------#
# To dump a file with all keywords, use:                #
# >>>  sim.commands.dump_defaults(filename, type="all") #
#-------------------------------------------------------#

OBS_DIT                 60          # [sec] simulated exposure time
OBS_NDIT                1           # [#] number of exposures taken
INST_FILTER_TC          Ks          # [<filename>, string(filter name)] List acceptable filters with >>> simcado.optics.get_filter_set()

ATMO_USE_ATMO_BG        yes         # [yes/no]
SCOPE_USE_MIRROR_BG     yes         # [yes/no]
INST_USE_AO_MIRROR_BG   yes         # [yes/no]
FPA_USE_NOISE           yes         # [yes/no]

FPA_CHIP_LAYOUT         small       # [small/centre/full] description of the chip layout on the detector array.
SCOPE_PSF_FILE          scao        # ["scao" (default), <filename>, "ltao", "mcao", "poppy"] import a PSF from a file. Default is <pkg_dir>/data/PSF_SCAO.fits

SIM_DETECTOR_PIX_SCALE  0.004       # [arcsec] plate scale of the detector
SIM_VERBOSE             yes         # [yes/no] print information on the simulation run

OBS_ZENITH_DIST         60          # [deg] from zenith
INST_ADC_PERFORMANCE    100         # [%] how well the ADC does its job

To list all keyword-value pairs, use:

>>>  sim.commands.dump_defaults(filename, type="all")

Any of the KEYWORD=VALUE pairs can be passed as extras to :func:.run`. For example if we wanted to observe in J-band for 60 minutes, we would pass:

src = sim.source.source_1E4_Msun_cluster()
im = sim.run(src, OBS_EXPTIME=3600, INST_FILTER_TC="J")

The jupyter notebook my_first_sim.ipynb has more exmples of this.

The UserCommands object

Behind the scenes of the simcado.run() command, three objects are created:

  • a UserCommands object - for holding all the information on how a simulation should be run

  • an OpticalTrain object - which contains the models to describe each effect that needs to be simulated

  • a Detector object - commonly referred to as an fpa or Focal Plane Array. It describes the layout of the detectros and holds the observed images.

The UserCommands object is arguably the most important of these three, because the other two need the keyword-value pairs contained within the UserCommands object to correctly describe the optical train and detector for the simulation.

A UserCommands object is created by reading in the defaults conifg file (defaults.config) and then updating any of the keywords that the user (or function) provides. For example, we can see all the default keyword-value pairs by calling:

>>> cmd = sim.UserCommands()

The UserCommands object contains 7 ordered dictionaries, one for each topic and one general dictionary. Each can be referenced individually, however all are updated when a value changes.

  1. cmd.cmds - contains all keyword-value pairs

  2. cmd.atmo - keyword-value pairs for the atmosphere

  3. cmd.scope - keyword-value pairs for the telescope

  4. cmd.inst - keyword-value pairs for the instrument (plus AO system)

  5. cmd.fpa - keyword-value pairs for the dector array

  6. cmd.obs - keyword-value pairs for the observation

  7. cmd.sim - keyword-value pairs for the simulation

A UserCommands object can be used as a dictionary itself, although technically all that happens is that it references the general dictionary cmd.cmds. For example

>>> cmd["OBS_DIT"] = 60

is exactly the same as either of the following two expressions

>>> cmd.cmds["OBS_DIT"] = 60
>>> cmd.obs["OBS_DIT"] = 60

Therefore for the sake of ease, we recommoned treating the UserCommands object as a dictionary and just using the default syntax: cmd["..."] = xxx

Saving and loading a UserCommands object
Saving

In case you have made changes to the values in a UserCommands object that you would like to keep for next time, a UserCommands object can be saved to disk with the following command:

>>> cmd = sim.UserCommands()
>>> cmd.writeto(filename="my_cmds.txt")

SimCADO writes out the dictionary in ASCII format.

Loading

Creating a UserCommands object based on a text file is as simple as passing the file path:

>>> cmd = sim.UserCommands("my_cmds.txt")
Special attributes

A UserCommands object not only contains a dictionary of keyword-value pairs, but also a select number of parameters pertaining to the optical train for quick access. These include values for:

  • the exposure time for simulations: cmd.exptime

  • the primary mirror: cmd.area, cmd.diameter

  • the wavelength vector for purely spectral data (i.e. transmission curves): cmd.lam

  • the wavelength centres and edges for each spectral bin: cmd.lam_bin_centres, cmd.lam_bin_edges

  • the mirror configuration: cmd.mirrors_telescope, cmd.mirrors_ao

  • the detector plate scale and internal sampling resolutions: cmd.fpa_res, cmd.pix_res

Mirror and Detector configuration files

A quick note on the other files that SimCADO uses when creating an optical train and the appropriate keywords

The detector array

The detector array is described by a text file containing information on the plate scale and the positions of the detector chips:

>>> sim.commands.dump_chip_layout(path=None)
#  id    x_cen    y_cen   x_len   y_len
#        arcsec   arcsec   pixel  pixel
    4        0        0    4096    4096
    0  -17.084  -17.084    4096    4096
    1        0  -17.084    4096    4096
    2   17.084  -17.084    4096    4096
    3  -21.484        0    4096    4096
    5   17.084        0    4096    4096
    6  -17.084   17.084    4096    4096
    7        0   17.084    4096    4096
    8   17.084   17.084    4096    4096

This small file can be saved to disk by passing a filename to the path= parameters

>>> sim.commands.dump_chip_layout(path="my_fpa.txt")

Any detector array can be provided to SimCADO, as long as the text file follows this format. For example the HAWK-I detector array (4x HAWAII-2RG) would look like this:

#  id    x_cen    y_cen    x_len   y_len
#        arcsec   arcsec   pixel   pixel
    0      -116     -116    2048    2048
    1       116     -116    2048    2048
    2      -116      116    2048    2048
    3       116      116    2048    2048

To pass a detector array description to SimCADO, use the FPA_CHIP_LAYOUT keyword:

>>> cmd = sim.UserCommands()
>>> cmd["FPA_CHIP_LAYOUT"] = "hawki_chip_layout.txt"

or pass is directly to the :func:.run` command:

>>> sim.run(... , FPA_CHIP_LAYOUT="hawki_chip_layout.txt", ...)
The mirror configurations

The mirror configuration can be dumped either to the screen or to disk by using:

>>> dump_mirror_config(path=None, what="scope")
#Mirror     Outer   Inner   Temp
M1          37.3    11.1    0.
M2          4.2     0.545   0.
M3          3.8     0.14    0.
M4          2.4     0.      0.
M5          2.4     0.      0.

If path=None the contents of the default file are printed to the screen. The parameter what is for the section of the optical train that should be shown - either scope for the telescope, or ao of the AO system. For most existing telescope, this parameter is irrelevant. For the MICADO/MAORY setup however another six optical surfaces are introduced into the system.

It is possible to specifiy different mirror configurations using a text file with the same format as above. For example the VLT unit telescope mirror config files would look like this:

#Mirror Outer   Inner   Temp
M1      8.2     1.0     0.
M2      1.116   0.05    0.
M3      1.0     0.      0.

To use this mirro config file in SimCADO use the keywords SCOPE_MIRROR_LIST and INST_MIRROR_AO_LIST

>>> cmd = sim.UserCommands()
>>> cmd["SCOPE_MIRROR_LIST"] = "vlt_mirrors.txt"
>>> cmd["INST_MIRROR_AO_LIST"] = "none"

Examples with the Source object

The Source class is probably the most important class for testing science cases. Therefore spending time on creating accurate Source representations of the object of interest is key to getting good results with SimCADO.

Basically a Source object represents photon sources using lists of positions (.x, .y), a list of unique spectra (.spectra) and a list of references which match each photon source to a spectrum in the list of spectra (.ref). All sources (extended and point source) can be decomposed into these lists. The advantage of using this approach is that objects with highly similar spectra can both reference the same position in .spectra, thereby reducing the number of spectra that need to be manipulated during a simulation.

My first Source object

To begin with it is probably easiest to let SimCADO generate a Source object. The convenience function simcado.source.star() will generate a Source object containing a single star. In this case, we’ll choose an G2V star with a K-band magnitude of 20, placed 5 arcsec above the centre of the focal plane:

>>> star_1 = simcado.source.star(mag=20, filter_name="K", spec_type="G2V", x=5, y=0))

star_1 the coordinates of the star are held in the arrays .x and .y, and the G2V spectrum in `.spectra´:

>>> star_1.x[0], star_1.y[0]
(5, 0)

The spectrum for star_1 is held in .spectra and the central wavelength of each of the spectral bins is in .lam.

>>> star_1.lam, star_1.spectra[0]
<insert output here>

Note

.lam is a (1,n) array where as .spectra is a (m,n) array where n is the number of bins in the spectra and m is the number of unique spectra in the Source object. If the Source only contains a single unique spectrum, then .spectra will be a (1,n) array too.

Combining Source objects

Because a Source object is just a collection of arrays, it is easy to add many together with the + operator:

>>> star_2 = simcado.source.star(mag=22, filter_name="K", spec_type="A0V", x=2, y=-2)
>>> two_stars = star_1 + star_2
>>> two_stars.x, two_stars.y
((5, 2), (0, -2))

Note

this is a very trivial example (for which SimCADO has a more elegant function: simcado.source.stars()), but it serves to illustrate the main idea. The overloaded + operator is very useful for combining objects, e.g. forground stars and background galaxies, in order to get a better representation of the sky.

Note

if you are planning on creating sources for large numbers of stars (e.g. >>10 stars), using the plural function stars() will save you a lot of time.

Point sources

For generating a field of stars, SimCADO offers a series of convenience functions. Please see the docstring or API documentation for more information on how best to use them.

  • simcado.source.star()

  • simcado.source.stars()

  • simcado.source.star_grid()

  • simcado.source.cluster()

SimCADO’s in-built example spectra

Add a section on this

  • Stellar templates from Pickles (1998)

    • simcado.source.SED()

    • simcado.source.empty_sky()

  • Galaxy templates from STSCI

Each of these functions returns two arrays: lam and spec

Using an image as a template for a Source object

If we have an extended source that we wish to simulate, e.g. a galaxy, a nebula, etc. we can use the function simcado.source.source_from_image(). The image must be a 2D numpy.ndarray, but it can come from anywhere, e.g. a FITS file, generated my another function, or even a MS Paint bitmap image.

>>> image_1 = astropy.io.fits.getdata("orion.fits")
>>> image_1
array([[0.0, ... 0.0],
       ... ,
       [0.0, ... 0.0]])

Here SimCADO takes a the pixel coordinates of the image and converts them to positions on the focal plane.

Note

the user must specify a plate-scale in arcseconds (pix_res=) for the image. Each pixel with a value above a certain threshold (default flux_threshold=0) will be used in the Source object. The coordinates of these pixels are added to the arrays .x and .y.

We also need to provide a spectrum for the image. This spectrum is assumed to be the only spectrum for each pixel in the image. The pixel values are then the intensity assigned to that spectrum at that pixel position.

SimCADO provides the pickles library for stellar spectra. Unfortunately there aren’t any built-in galactic spectra yet - for this the user will need to provide their own spectrum.

>>> lam, spec_1 = simcado.source.SED("G2V", "K", magnitude=20)
>>> lam, spec_1
(array([0.7 ... 2.5]), array([0.0 ... 0.0]))

With image_1, lam and spec_1 we can now build a Source object for an orion-like nebula that has the spectrum of a sun-like star.

>>> simcado.source.source_from_image(image_1, lam, spec_1, pix_res=0.004, flux_threshold=0)

While this example is physically unrealistic, it serves the purpose of showing how to build a Source object from an image. The user is

Images with multipe spectra

In reality assigning a single spectrum to an extended object is of limited use. For a Source to be realistic is should contain multiple spectra for objects in different locations. The best way to simulate this with SimCADO is to create a Source object for each unique group of objects (e.g. old stellar population, star forming regions, AGN, etc) and then combine them into a single Source object with the + operator.

As a worked example, lets create a “first-order” approximation to a star forming galaxy. The two major components of this source are 1. the aged stellar population and, 2. the star forming regions.

In our (very) crude model the aged stellar population can be approximated by an ellipse with Gaussian light distribution. As M stars make up the majority of this population, we can assign a M0V spectrum to this population.

>>> from astropy.convolution import Gaussian2DKernel
>>> from simcado.source import SED
>>>
>>> old_pop = Gaussian2DKernel(128).array[::3,:]
>>> m0v_spec = SED()

To illustrate (very crudely) the star forming regions we can create a random distribution of elliptical Gaussians using the astropy function Gasussian2DKernel:

Creating a Source object from scratch

To create a Source object from scratch, we initialise the object by passing 5 (or 6) arrays. All the parameter names must be specified.

sim.Source(lam=, spectra=, x=, y=, ref=, [weight=])

where: + x, y - [each a numpy.ndarray]. Coordinates for each point source in the image in units of [arcsec] from the focal plane centre

  • lam - [numpy.ndarray]. An array with the centre of the wavelength bins in [um] for each unique spectrum

  • spectra - [numpy.ndarray]. An (n, m) array holding n spectra, each with m values. Default units are [ph/s] Note - lam and spectra should use a constant bin width. Variable bin widths leads to unpredictable results.

  • ref - [numpy.ndarray]. An array to connect the point source at x[i], y[i] to a unique spectrum at spectra[j], i.e. ref[i] = j

Optional keywords can be specified:

  • weight - [numpy.ndarray], optional. If two sources share the same spectrum, but are at different distances or have different luminosities a scaling factor can be specified to the spectrum when applied to each specific point source.

  • units [default "ph/s"] is the units for the spectra, i.e. n phontons per second per spectral bin. The size of the spectral bins is resolution of the .lam array.

Combining two (or more) Source objects

Source objects can be created in different ways, but the underlying table-structure is the same. Therefore adding Source objects together means simply combining tables. The mathematical operator + can be used to do this:

>>> # ... create a A0V star at (0,0) and a G2V star at (5,-5)
>>> star_A0V = sim.source.star(20, spec_type="A0V", x=0, y=0)
>>> star_G2V = sim.source.star(20, spec_type="G2V", x=5, y=-5)
>>>
>>> src_combi = star_A0V + star_G2V
>>>
>>> print(src_combi.x, src_combi.y)
[0 5] [ 0 -5]

By adding different Source objects together, it is possible to build up complex objects that will be representative of the observed sky, e.g. old + new galaxy stellar population + gas emission + foreground stars

See examples for how to use the * and - operators with a Source object

Saving a Source object to disk

The Source object is saved as a FITS file with two extensions. See How SimCADO works for more on the file structure.

>>> src_combi.write("my_src.fits")

The file can be read in at a later time by specifying filename= when initialising a Source object - as stated above

>>> my_src = sim.Source(filename="my_src.fits")
In-built Source object for a star cluster

As a test object, SimCADO provides the function, with all distances in parsecs

sim.source.cluster(mass=1E4, distance=50000, half_light_radius=1)

SimCADO convenience functions

Keywords for Controlling SimCADO

Observation Parameters

Keyword                 Default     [units] Explanation
-----------------------------------------------------------------------------------------------

OBS_DATE                0                       # [dd/mm/yyyy] Date of the observation [not yet implemented]
OBS_TIME                0                       # [hh:mm:ss] Time of the observation [not yet implemented]
OBS_RA                  90.                     # [deg] RA of the object
OBS_DEC                 -30.                    # [deg] Dec of the object
OBS_ALT                 0                       # [deg] Altitude of the object [not yet implemented]
OBS_AZ                  0                       # [deg] Azimuth of the object [not yet implemented]
OBS_ZENITH_DIST         0                       # [deg] from zenith
OBS_PARALLACTIC_ANGLE   0                       # [deg] rotation of the source relative to the zenith
OBS_SEEING              0.6                     # [arcsec]

OBS_FIELD_ROTATION      0                       # [deg] field rotation with respect to the detector array

OBS_DIT                 60                      # [sec] simulated exposure time
OBS_NDIT                1                       # [#] number of exposures taken
OBS_NONDESTRUCT_TRO     2.6                     # [sec] time between non-destructive readouts in the detector
OBS_REMOVE_CONST_BG     no                      # remove the median background value
OBS_READ_MODE           single                  # [single, fowler, ramp] Only single is implemented at the moment
OBS_SAVE_ALL_FRAMES     no                      # yes/no to saving all DITs in an NDIT sequence

OBS_INPUT_SOURCE_PATH   none                    # Path to input Source FITS file
OBS_FITS_EXT            0                       # the extension number where the useful data cube is

OBS_OUTPUT_DIR          "./output.fits"         # [filename] Path to save output in.

Simulation Parameters

Keyword                 Default     [units] Explanation
-----------------------------------------------------------------------------------------------

SIM_DETECTOR_PIX_SCALE  0.004                   # [arcsec] plate scale of the detector
SIM_OVERSAMPLING        1                       # The factor of oversampling inside the simulation
SIM_PIXEL_THRESHOLD     1                       # photons per pixel summed over the wavelength range. Values less than this are assumed to be zero

SIM_LAM_TC_BIN_WIDTH    0.001                   # [um] wavelength resolution of spectral curves
SIM_SPEC_MIN_STEP       1E-4                    # [um] minimum step size where resampling spectral curves

SIM_FILTER_THRESHOLD    1E-9                    # transmission below this threshold is assumed to be 0
SIM_USE_FILTER_LAM      yes                     # [yes/no] to basing the wavelength range off the filter non-zero range - if no, specify LAM_MIN, LAM_MAX
# if "no"
SIM_LAM_MIN             1.9                     # [um] lower wavelength range of observation
SIM_LAM_MAX             2.41                    # [um] upper wavelength range of observation
SIM_LAM_PSF_BIN_WIDTH   0.1                     # [um] wavelength resolution of the PSF layers
SIM_ADC_SHIFT_THRESHOLD 1                       # [pixel] the spatial shift before a new spectral layer is added (i.e. how often the spectral domain is sampled for an under-performing ADC)

SIM_PSF_SIZE            1024                    # size of PSF
SIM_PSF_OVERSAMPLE      no                      # use astropy's inbuilt oversampling technique when generating the PSFs. Kills memory for PSFs over 511 x 511
SIM_VERBOSE             no                      # [yes/no] print information on the simulation run
SIM_SIM_MESSAGE_LEVEL   3                       # the amount of information printed [5-everything, 0-nothing]

SIM_OPT_TRAIN_IN_PATH   none                    # Options for saving and reusing optical trains. If "none": "./"
SIM_OPT_TRAIN_OUT_PATH  none                    # Options for saving and reusing optical trains. If "none": "./"
SIM_DETECTOR_IN_PATH    none                    # Options for saving and reusing detector objects. If "none": "./"
SIM_DETECTOR_OUT_PATH   none                    # Options for saving and reusing detector objects. If "none": "./"

Atmospheric Parameters

Keyword                 Default     [units] Explanation
-----------------------------------------------------------------------------------------------

ATMO_USE_ATMO_BG        yes                     # [yes/no]

ATMO_TC                 TC_sky_25.tbl           # [filename] for atmospheric transmission curve. Default: <pkg_dir>/data/TC_sky_25.tbl
ATMO_EC                 EC_sky_25.tbl           # [filename, "none"] for atmospheric emission curve. Default: <pkg_dir>/data/EC_sky_25.tbl
# If ATMO_EC is "none": set ATMO_BG_MAGNITUDE for the simulation filter.
ATMO_BG_MAGNITUDE       13.6                    # [ph/s] background photons for the bandpass. If set to None, the ATMO_EC spectrum is assumed to return the needed number of photons

ATMO_TEMPERATURE        0                       # deg Celcius
ATMO_PRESSURE           750                     # millibar
ATMO_REL_HUMIDITY       60                      # %
ATMO_PWV                2.5                     # [mm] Paranal standard value

Telescope Parameters

Keyword                 Default     [units] Explanation
-----------------------------------------------------------------------------------------------

SCOPE_ALTITUDE          3060                    # meters above sea level
SCOPE_LATITUDE          -24.589167              # decimal degrees
SCOPE_LONGITUDE         -70.192222              # decimal degrees

SCOPE_PSF_FILE          scao                    # [scao (default), <filename>, ltao, mcao, poppy] import a PSF from a file.
SCOPE_STREHL_RATIO      1                       # [0..1] defines the strength of the seeing halo if SCOPE_PSF_FILE is "default"
SCOPE_AO_EFFECTIVENESS  100                     # [%] percentage of seeing PSF corrected by AO - 100% = diff limited, 0% = 0.8" seeing
SCOPE_JITTER_FWHM       0.001                   # [arcsec] gaussian telescope jitter (wind, tracking)
SCOPE_DRIFT_DISTANCE    0                       # [arcsec/sec] the drift in tracking by the telescope
SCOPE_DRIFT_PROFILE     linear                  # [linear, gaussian] the drift profile. If linear, simulates when tracking is off. If gaussian, simulates rms distance of tracking errors

SCOPE_USE_MIRROR_BG     yes                     # [yes/no]

SCOPE_NUM_MIRRORS       5                       # number of reflecting surfaces
SCOPE_TEMP              0                       # deg Celsius - temperature of mirror
SCOPE_M1_TC             TC_mirror_EELT.dat      # [filename] Mirror reflectance curve. Default: <pkg_dir>/data/TC_mirror_EELT.dat
SCOPE_MIRROR_LIST       EC_mirrors_EELT_SCAO.tbl    # [filename] List of mirror sizes.     Default: <pkg_dir>/data/EC_mirrors_EELT_SCAO.tbl

Instrument Parameters

Keyword                 Default     [units] Explanation
-----------------------------------------------------------------------------------------------

INST_TEMPERATURE        -190                    # deg Celsius - inside temp of instrument

INST_ENTR_NUM_SURFACES  4                       # number of surfaces on the entrance window
INST_ENTR_WINDOW_TC     TC_window.dat           # [filename] Default: <pkg_dir>/data/TC_window.dat --> transmission = 0.98 per surface

INST_DICHROIC_NUM_SURFACES  2                   # number of surfaces on the entrance window
INST_DICHROIC_TC        TC_dichroic.dat         # [filename] Default: <pkg_dir>/data/TC_dichroic.dat --> transmission = 1 per surface

INST_FILTER_TC          Ks                      # [filename, string(filter name)] List acceptable filters with >>> simcado.optics.get_filter_set()

INST_PUPIL_NUM_SURFACES 2                       # number of surfaces on the pupil window
INST_PUPIL_TC           TC_pupil.dat            # [filename] Default: <pkg_dir>/data/TC_pupil.dat --> transmission = 1 per surface

# MICADO, collimator 5x, wide-field 2x (zoom 4x), camera 4x
INST_NUM_MIRRORS        11                      # number of reflecting surfaces in MICADO
INST_MIRROR_TC          TC_mirror_gold.dat      # [filename, "default"] If "default": INST_MIRROR_TC = SCOPE_M1_TC

INST_USE_AO_MIRROR_BG   yes                     # [yes/no]
INST_AO_TEMPERATURE     0                       # deg Celsius - inside temp of AO module
INST_NUM_AO_MIRRORS     7                       # number of reflecting surfaces between telescope and instrument (i.e. MAORY)
INST_MIRROR_AO_TC       TC_mirror_gold.dat      # [filename, "default"] If "default": INST_MIRROR_AO_TC = INST_MIRROR_TC
INST_MIRROR_AO_LIST     EC_mirrors_ao.tbl       # List of mirrors in the AO. Default: <pkg_dir>/data/EC_mirrors_ao.tbl

INST_ADC_PERFORMANCE    100                     # [%] how well the ADC does its job
INST_ADC_NUM_SURFACES   8                       # number of surfaces in the ADC
INST_ADC_TC             TC_ADC.dat              # [filename] Default: <pkg_dir>/data/TC_ADC.dat --> transmission = 0.98 per surface

INST_DEROT_PERFORMANCE  100                     # [%] how well the derotator derotates
INST_DEROT_PROFILE      linear                  # [linear, gaussian] the profile with which it does it's job

INST_DISTORTION_MAP     none                    # path to distortion map
INST_WFE                data/INST_wfe.tbl       # [nm] (float or filename) A single number for the total WFE of a table of wavefront errors for each surface in the instrument
INST_FLAT_FIELD         none                    # path to a FITS file containing a flat field (median = 1) for each chip.

Spectroscopy parameters

Keyword                 Default     [units] Explanation
-----------------------------------------------------------------------------------------------

SPEC_ORDER_SORT         HK                      # Order-sorting filter: "HK" or "IJ"
SPEC_SLIT_WIDTH         narrow                  # Slit width: "narrow" or "wide"

Detector parameters

Keyword                 Default     [units] Explanation
-----------------------------------------------------------------------------------------------

FPA_USE_NOISE           yes                     # [yes/no]

FPA_READOUT_MEDIAN      4                       # e-/px
FPA_READOUT_STDEV       1                       # e-/px
FPA_DARK_MEDIAN         0.01                    # e-/s/px
FPA_DARK_STDEV          0.01                    # e-/s/px

FPA_QE                  TC_detector_H2RG.dat    # [filename] Quantum efficiency of detector.
FPA_NOISE_PATH          FPA_noise.fits          # [filename, "generate"] if "generate": use NGHxRG to create a noise frame.
FPA_GAIN                1                       # e- to ADU conversion
FPA_LINEARITY_CURVE     FPA_linearity.dat       # [filename, "none"]
FPA_FULL_WELL_DEPTH     1E5                     # [e-] The level where saturation occurs

FPA_PIXEL_MAP           none                    # path to a FITS file with the pixel sensitivity map
# if FPA_PIXEL_MAP == none
FPA_DEAD_PIXELS         1                       # [%] if FPA_PIXEL_MAP=none, a percentage of detector pixel which are dead
FPA_DEAD_LINES          1                       # [%] if FPA_PIXEL_MAP=none, a percentage of detector lines which are dead

FPA_CHIP_LAYOUT         centre                    # ["tiny", "small", "centre", "full", <filename>] description of the chip layout on the detector array.
FPA_PIXEL_READ_TIME     1E-5                    # [s] read time for y pixel - typically ~10 us
FPA_READ_OUT_SCHEME     double_corr             # "double_corr", "up-the-ramp", "fowler"

NXRG Noise Generator package parameters

Keyword                 Default     [units] Explanation
-----------------------------------------------------------------------------------------------
# See Rauscher (2015) for details
# http://arxiv.org/pdf/1509.06264.pdf

HXRG_NUM_OUTPUTS        64                      # Number of
HXRG_NUM_ROW_OH         8                       # Number of row overheads
HXRG_PCA0_FILENAME      FPA_nirspec_pca0.fits   # if "default": <pkg_dir>/data/
HXRG_OUTPUT_PATH        none                    # Path to save the detector noise
HXRG_PEDESTAL           4                       # Pedestal noise
HXRG_CORR_PINK          3                       # Correlated Pink noise
HXRG_UNCORR_PINK        1                       # Uncorrelated Pink noise
HXRG_ALT_COL_NOISE      0.5                     # Alternating Column noise

HXRG_NAXIS1             4096                    # Size of the HAWAII 4RG detectors
HXRG_NAXIS2             4096
HXRG_NUM_NDRO           1                       # Number of non-destructive readouts to add to a noise cube

SimCADO Package

simcado.commands module

simcado.commands Module
Functions

dump_defaults([filename, selection])

Dump the frequent.config file to a path specified by the user

dump_chip_layout([path])

Dump the FPA_chip_layout.dat file to a path specified by the user

dump_mirror_config([path, what])

Dump the EC_mirrors_scope.tbl or the EC_mirrors_ao.tbl to disk

read_config(config_file)

Read in a SimCADO configuration file

update_config(config_file, config_dict)

Update a SimCADO configuration dictionary

Classes

UserCommands([filename, sim_data_dir])

An extended dictionary with the parameters needed for running a simulation

simcado.detector module

simcado.detector Module

A description of the Chip noise properties and their positions on the Detector

Module Summary

This module holds three classes: Detector, Chip and HXRGNoise.

Chip Everything to do with photons and electrons happens in the Chip class. Each Chip is initialised with a position relative to the centre of the detector array, a size [in pixels] and a resolution [in arcsec]. Photons fall onto the Chip s and are read out together with the read noise characteristics of the Chip.

Detector The Detector holds the information on where the Chip s are placed on the focal plane. Focal plane coordinates are in [arcsec]. These coordinates are either read in from a default file or determined by the user. The Detector object is an intermediary - it only passes information on the photons to the Chip s. It is mainly a convenience class so that the user can read out all Chip s at the same time.

Classes
Detector

builds an array of Chip objects based on a UserCommands object

Chip

converts incoming photons into ADUs and adds in read-out noise

See Also

simcado.optics.OpticalTrain, simcado.source.Source

Notes
References

[1] Bernhard Rauscher’s HxRG Noise Generator script

Examples

The Detector can be used in stand-alone mode. In this case it outputs only the noise that a sealed-off detector would generate:

>>> import simcado
>>> fpa = simcado.Detector(simcado.UserCommands())
>>> fpa.read_out(output=True, chips=[0])

The Detector is more useful if we combine it with a Source object and an OpticalTrain. Here we create a Source object for an open cluster in the LMC and pass the photons arriving from it through the E-ELT and MICADO. The photons are then cast onto the detector array. Each Chip converts the photons to ADUs and adds the resulting image to an Astropy HDUList. The HDUList is then written to disk.

>>> # Create a set of commands, optical train and detector
>>>
>>> import simcado
>>> cmds = simcado.UserCommands()
>>> opt_train = simcado.OpticalTrain(cmds)
>>> fpa = simcado.Detector(cmds)
>>>
>>> # Pass photons from a 10^4 Msun open cluster in the LMC through to the detector
>>>
>>> src = sim.source.source_1E4_Msun_cluster()
>>> src.apply_optical_train(opt_train, fpa)
>>>
>>># Read out the detector array to a FITS file
>>>
>>> fpa.read_out(filename="my_raw_image.fits")
Functions

open(self, filename)

Opens a saved Detector file.

plot_detector(detector)

Plot the contents of a detector array

plot_detector_layout(detector[, plane, fmt, …])

Plot the detector layout

make_noise_cube([num_layers, filename, …])

Create a large noise cube with many separate readout frames.

install_noise_cube([n])

Install a noise cube in the package directory

Classes

Detector(cmds[, small_fov])

Generate a series of Chip objects for a focal plane array

Chip(x_cen, y_cen, x_len, y_len, pix_res[, …])

Holds the “image” as seen by a single chip in the focal plane

simcado.nghxrg module

simcado.nghxrg Module

NGHXRG by Bernard Rauscher see the paper: http://arxiv.org/abs/1509.06264 downloaded from: http://jwst.nasa.gov/publications.html

Classes

HXRGNoise([naxis1, naxis2, naxis3, n_out, …])

A class to generate HxRG noise frames

simcado.optics module

simcado.optics Module

optics.py

Functions

get_filter_curve(filter_name)

Return a Vis/NIR broadband filter TransmissionCurve object

get_filter_set([path])

Return a list of the filters installed in the package directory

Classes

OpticalTrain(cmds, **kwargs)

The OpticalTrain object reads in or generates the information necessary to model the optical path for all (3) sources of photons: the astronomical source, the atmosphere and the primary mirror.

simcado.psf module

simcado.psf Module
PSFs and PSFCubes

Todo

revise this opening text

Description

Car Sagan said

“If you want to bake an apple pie from scratch,

first you must create the universe”

Single PSFs

We need to start by generating a single PSF in order to generate a PSFCube. We need to know the spatial characteristics of the PSF: The commonalities of all PSFs are:

  • pix_width

  • pix_height

  • pix_res

  • type

The types of PSF offered: Moffat, Gaussian2D, Airy, Delta, Line, User For each of the PSF types we need to create a subclass of PSF. Each subclass takes its own list of parameters:

  • MoffatPSF (alpha, beta)

  • GaussianPSF (fwhm, eccentricity=0, angle=0)

  • AiryPSF (first_zero, eccentricity=0, angle=0)

  • DeltaPSF (x=0, y=0)

  • LinePSF (x0, x1, y0, y1, angle=0)

  • UserPSFCube (filename, ext_no=0)

Multiple PSFs in a Cube

To generate a PSF cube we need to know the spectral bins and the type of PSF. The bins are defined by a central wavelength, however a cube should also contain the edges of each bin so that transmission and emission can be re-binned properly. - lam_bin_centers - lam_bin_edges - lam_res

A PSF instance will have these additional arguments: - array … a 2D array to hold the PSF image

A psf instance will have these additional arguments: - cube … a (l,x,y) 3D array to hold the PSF cube

As far as input goes, psf should be able to accept a dictionary with the keywords necessary to build the cube.

Notes

All wavelength values are given in [um] All pixel dimensions are given in [arcsec] All angles are given in [deg]

Classes

PSF(object) psf(object)

Subclasses

MoffatPSF(PSF) GaussianPSF(PSF) AiryPSF(PSF) DeltaPSF(PSF) LinePSF(PSF) UserPSFCube(PSF)

Deltapsf(psf) Airypsf(psf) Gaussianpsf(psf) Moffatpsf(psf) CombinedPSFCube(psf) UserPSFCube(psf) ADC_psf(psf)

There are two types of psf object here: - a cube - a single psf image

The cube is essentially a list of psf images, homogenized in size Should we have separate classes for these?

Both PSF and psf can be created from a single model or through convolution of a list of PSF components

Functions

poppy_eelt_psf([plan, wavelength, mode, …])

Generate a PSF for the E-ELT for plan A or B with POPPY

poppy_ao_psf(strehl[, mode, plan, size, …])

Create a diffraction limited E-ELT PSF with a Seeing halo

seeing_psf([fwhm, psf_type, size, pix_res, …])

Return a seeing limited PSF

get_eelt_segments([plan, missing, …])

Generate a list of segments for POPPY for the E-ELT

make_foreign_PSF_cube(fnames[, out_name, …])

Combine several PSF FITS images into a single PSF FITS file

Classes

PSF(size, pix_res)

Point spread function (single layer) base class

PSFCube(lam_bin_centers)

Class holding wavelength dependent point spread function.

MoffatPSF(fwhm, **kwargs)

Generate a PSF for a Moffat function.

MoffatPSFCube(lam_bin_centers[, fwhm])

Generate a list of MoffatPSFs for wavelengths defined in lam_bin_centers

AiryPSF(fwhm[, obscuration, size, pix_res])

Generate a PSF for an Airy function with an equivalent FWHM

AiryPSFCube(lam_bin_centers[, fwhm])

Generate a list of AiryPSFs for wavelengths defined in lam_bin_centers

GaussianPSF(fwhm, **kwargs)

Generate a PSF for an Gaussian function

GaussianPSFCube(lam_bin_centers[, fwhm])

Generate a list of GaussianPSFs for wavelengths defined in lam_bin_centers

DeltaPSF(**kwargs)

Generate a PSF with a delta function at position (x,y)

DeltaPSFCube(lam_bin_centers[, positions])

Generate a list of DeltaPSFs for wavelengths defined in lam_bin_centers

CombinedPSF(psf_list, **kwargs)

Generate a PSF from a collection of several PSFs.

CombinedPSFCube(psf_list, **kwargs)

Generate a list of CombinedPSFCubes from the list of psfs in psf_list

UserPSF(filename, **kwargs)

Import a PSF from a FITS file.

UserPSFCube(filename, lam_bin_centers)

Read in a psf previously saved as a FITS file

FieldVaryingPSF(**kwargs)

simcado.simulation module

simcado.simulation Module

simulation.py

Functions

run(src[, mode, cmds, opt_train, fpa, …])

Run a MICADO simulation with default parameters

snr(exptimes, mags[, filter_name, cmds])

Returns the signal-to-noise ratio(s) for given exposure times and magnitudes

check_chip_positions([filename, x_cen, …])

Creates a series of grids of stars and generates the output images

limiting_mags([exptimes, filter_names, …])

Return or plot a graph of the limiting magnitudes for MICADO

zeropoint([filter_name])

Returns the zero point magnitude for a SimCADO filter

simcado.source module

simcado.source Module

The module that contains the functionality to create Source objects

Module Summary

The Source is essentially a list of spectra and a list of positions. The list of positions contains a reference to the relevant spectra. The advantage here is that if there are repeated spectra in a data cube, we can reduce the amount of calculations needed. Furthermore, if the input is originally a list of stars, etc., where the position of a star is not always an integer multiple of the plate scale, we can keep the information until the PSFs are needed.

Classes

Source

Functions

Functions to create Source objects

empty_sky()
star(mag, filter_name="Ks", spec_type="A0V", x=0, y=0)
stars(mags, filter_name="Ks", spec_types=["A0V"], x=[0], y=[0])
star_grid(n, mag_min, mag_max, filter_name="Ks", separation=1, area=1,
          spec_type="A0V")
source_from_image(images, lam, spectra, pix_res, oversample=1,
                  units="ph/s/m2", flux_threshold=0,
                  center_pixel_offset=(0, 0))
source_1E4_Msun_cluster(distance=50000, half_light_radius=1)

Functions for manipulating spectra for a Source object

scale_spectrum(lam, spec, mag, filter_name="Ks", return_ec=False)
scale_spectrum_sb(lam, spec, mag_per_arcsec, pix_res=0.004,
                  filter_name="Ks", return_ec=False)
flat_spectrum(mag, filter_name="Ks", return_ec=False)
flat_spectrum_sb(mag_per_arcsec, filter_name="Ks", pix_res=0.004,
                 return_ec=False)

Functions regarding photon flux and magnitudes

zero_magnitude_photon_flux(filter_name)
_get_stellar_properties(spec_type, cat=None, verbose=False)
_get_stellar_mass(spec_type)
_get_stellar_Mv(spec_type)
_get_pickles_curve(spec_type, cat=None, verbose=False)

Helper functions

value_at_lambda(lam_i, lam, val, return_index=False)
SED(spec_type, filter_name="V", magnitude=0.)
Functions

star([spec_type, mag, filter_name, x, y])

Creates a simcado.Source object for a star with a given magnitude

stars([spec_types, mags, filter_name, x, y])

Creates a simcado.Source object for a bunch of stars.

cluster([mass, distance, half_light_radius])

Generate a source object for a cluster

point_source([spectrum, mag, filter_name, x, y])

Creates a simcado.Source object for a point source with a given magnitude

spiral(half_light_radius, plate_scale[, …])

Create a extended Source object for a “Galaxy”

spiral_profile(r_eff[, ellipticity, angle, …])

Creates a spiral profile with arbitary parameters

elliptical(half_light_radius, plate_scale[, …])

Create a extended Source object for a “Galaxy”

sersic_profile([r_eff, n, ellipticity, …])

Returns a 2D array with a normalised Sersic profile

source_from_image(images, lam, spectra, …)

Create a Source object from an image or a list of images.

star_grid(n, mag_min, mag_max[, …])

Creates a square grid of A0V stars at equal magnitude intervals

empty_sky()

Returns an empty source so that instrumental fluxes can be simulated

SED(spec_type[, filter_name, magnitude])

Return a scaled SED for a star or type of galaxy

redshift_SED(z, spectrum, mag[, filter_name])

Redshift a SimCADO SED and scale it to a magnitude in a user specified filter

sie_grad(x, y, par)

Compute the deflection of an SIE (singular isothermal ellipsoid) potential

apply_grav_lens(image[, x_cen, y_cen, …])

Apply a singular isothermal ellipsoid (SIE) gravitational lens to an image

get_SED_names([path])

Return a list of the SEDs installed in the package directory

scale_spectrum(lam, spec, mag[, …])

Scale a spectrum to be a certain magnitude

scale_spectrum_sb(lam, spec, mag_per_arcsec)

Scale a spectrum to be a certain magnitude per arcsec2

flat_spectrum(mag[, filter_name, return_ec])

Return a flat spectrum scaled to a certain magnitude

flat_spectrum_sb(mag_per_arcsec[, …])

Return a flat spectrum for a certain magnitude per arcsec

value_at_lambda(lam_i, lam, val[, return_index])

Return the value at a certain wavelength - i.e.

BV_to_spec_type(B_V)

Returns the latest main sequence spectral type(s) for (a) B-V colour

zero_magnitude_photon_flux(filter_name)

Return the number of photons for a m=0 star for a filter with synphot

mag_to_photons(filter_name[, magnitude])

Return the number of photons for a certain filter and magnitude

photons_to_mag(filter_name[, photons])

Return the number of photons for a certain filter and magnitude

_get_pickles_curve(spec_type[, cat, verbose])

Returns the emission curve for a single or list of spec_type, normalised to 5556A

_get_stellar_properties(spec_type[, cat, …])

Returns an astropy.Table with the list of properties for the star(s) in spec_type

_get_stellar_Mv(spec_type)

Returns a single (or list of) float(s) with the V-band absolute magnitude(s)

_get_stellar_mass(spec_type)

Returns a single (or list of) float(s) with the stellar mass(es)

Classes

Source([filename, lam, spectra, x, y, ref, …])

Create a source object from a file or from arrays

simcado.spatial module

simcado.spatial Module

TODO: Insert docstring

Functions

tracking(arr, cmds)

A method to simulate tracking errors ===== Currently a place holder with minimum functionality ========= !! TODO, work out the shift during the DIT for the object RA, DEC etc !!

derotator(arr, cmds)

A method to simulate field rotation in case the derotator is <100% effective ===== Currently a place holder with minimum functionality ========= !! TODO, work out the rotation during the DIT for the object RA, DEC etc !!

wind_jitter(arr, cmds)

A method to simulate wind jitter ===== Currently a place holder with minimum functionality ========= !! TODO, get the read spectrum for wind jitter !! !! Add in an angle parameter for the ellipse !!

adc_shift(cmds)

Generates a list of x and y shifts from a commands object

make_distortion_maps(real_xy, detector_xy[, …])

Generate distortion maps based on star positions.

get_distorion_offsets(x, y, dist_map_hdus, …)

Returns the distortion offsets for position relative to the FoV centre

simcado.spectral module

simcado.spectral Module

Classes for spectral curves

Functions

get_sky_spectrum(fname, airmass[, return_type])

Return a spectral curve for the sky for a certain airmass

Classes

TransmissionCurve([filename, lam, val])

Very basic class to either read in a text file for a transmission curve or take two vectors to make a transmission curve

EmissionCurve([filename])

Class for emission curves

BlackbodyCurve(lam, temp, **kwargs)

Blackbody emission curve

UnityCurve([lam, val])

Constant transmission curve

simcado.utils module

simcado.utils Module

Helper functions for SimCADO

Functions

add_SED_to_simcado(file_in[, file_out, …])

Adds the SED given in file_in to the SimCADO data directory

add_keyword(filename, keyword, value[, …])

Add a keyword, value pair to an extension header in a FITS file

add_mags(mags)

Returns a combined magnitude for a group of objects with mags

airmass2zendist(airmass)

Convert airmass to zenith distance

airmass_to_zenith_dist(airmass)

returns zenith distance in degrees

angle_in_arcseconds(distance, width)

Returns the angular distance of an object in arcseconds.

atmospheric_refraction(lam[, z0, temp, …])

Compute atmospheric refraction

bug_report()

Get versions of dependencies for inclusion in bug report

deriv_polynomial2d(poly)

Derivatives (gradient) of a Polynomial2D model

dist_mod_from_distance(d)

mu = 5 * np.log10(d) - 5

distance_from_dist_mod(mu)

d = 10**(1 + mu / 5)

download_file(url[, save_dir])

Download the extra data that aren’t in the SimCADO package

find_file(filename[, path, silent])

Find a file in search path

get_extras()

Downloads large files that SimCADO needs to simulate MICADO

is_fits(filename)

Checks if file is a FITS file based on extension

moffat(r, alpha, beta)

!!Unfinished!! Return a Moffat function

msg(cmds, message[, level])

Prints a message based on the level of verbosity given in cmds

nearest(arr, val)

Return the index of the value from ‘arr’ which is closest to ‘val’

parallactic_angle(ha, de[, lat])

Compute the parallactic angle

poissonify(arr)

Add a realisation of the poisson process to the array ‘arr’.

quantify(item, unit)

Ensure an item is a Quantity

seq(start, stop[, step])

Replacement for numpy.arange modelled after R’s seq function

telescope_diffraction_limit(aperture_size, …)

Returns the diffraction limit of a telescope

transverse_distance(angle, distance)

Turn an angular distance into a proper transverse distance

unify(x, unit[, length])

Convert all types of input to an astropy array/unit pair

zendist2airmass(zendist)

Convert zenith distance to airmass

zenith_dist_to_airmass(zenith_dist)

zenith_dist is in degrees

Bugs and Issues

We freely admit that there may still be several bugs that we have not found. If you come across an buggy part of SimCADO, please please tell us. We can’t make SimCADO better if we don’t know about things.

The preferable option is to open an issue on our Github page: astronomyk/SimCADO/issues, or you can contact one of us directly.

Contact

For questions and complaints alike, please contact the authors:

Developers (Vienna): Kieran Leschinski, Oliver Czoske, Miguel Verdugo

Data Flow Team Leader (Gronigen): Gijs Verdoes Kleijn

MICADO home office (MPE): http://www.mpe.mpg.de/ir/micado