How to Write a Workflow
A workflow (or simulation block) is a self-contained Python script that produces all raw and calibration FITS files for a particular instrument mode. This guide walks you through creating one from scratch.
Overview
Every workflow does three things:
Lists the YAML template files that define which observations to simulate.
Provides a parameter dictionary controlling output location, calibration depth, parallelism, etc.
Calls
runSimulationBlock(yamlFiles, params)to execute everything.
Quick Start
Create a file Simulations/python/myWorkflow.py:
import runSimulationBlock as rs
if __name__ == "__main__":
params = {
"outputDir": "output/myWorkflow",
"small": False,
"doStatic": True,
"doCalib": 2,
"sequence": True,
"startMJD": "2027-03-15 00:00:00",
"calibFile": None,
"nCores": 8,
"testRun": False,
}
yamlFiles = [
"YAML/scienceLM.yaml",
"YAML/stdLM.yaml",
"YAML/distortionLM.yaml",
"YAML/detlinLM.yaml",
]
rs.runSimulationBlock(yamlFiles, params)
Run it from the Simulations/ directory:
python python/myWorkflow.py
Parameter Reference
Parameter |
Default |
Description |
|---|---|---|
|
(required) |
Directory where FITS files are written. Created automatically. |
|
|
If |
|
|
If |
|
|
Number of dark and flat frames to auto-generate per unique DIT/filter combination found in the templates. Set to 0 to skip. |
|
|
If |
|
(required) |
ISO-format start date for the observation sequence
( |
|
|
Path to a separate YAML file defining calibration parameters. Usually
left as |
|
|
Number of CPU cores for parallel execution. The framework will use at
most |
|
|
If |
Additional per-mode parameters can be added to the dict and will be forwarded:
slit_name– slit identifier for LSS modes (e.g."C-38_1").
Writing YAML Templates
YAML files live in Simulations/YAML/ and define one or more observation
templates. Each template is a YAML mapping with a unique label as key:
MY_UNIQUE_LABEL:
do.catg: LM_IMAGE_SCI_RAW
mode: "img_lm"
source:
name: star_field
kwargs: {}
properties:
dit: 0.25
ndit: 4
filter_name: "Lp"
catg: "SCIENCE"
tech: "IMAGE,LM"
type: "OBJECT"
nObs: 5
A single YAML file can contain multiple templates. They are executed in order.
Template Fields
do.catg(required)The DO category name that becomes the FITS file-name prefix, e.g.
LM_IMAGE_SCI_RAW.mode(required)The ScopeSim instrument mode:
Mode
Description
img_lm
LM-band imaging
img_n
N-band imaging
lss_l
L-band long-slit spectroscopy
lss_m
M-band long-slit spectroscopy
lss_n
N-band long-slit spectroscopy
lms
IFU (integral field unit)
source(required)The astronomical or calibration source to use. Has two sub-fields:
name– one of the source functions defined insources.pykwargs– keyword arguments passed to the source function (can be empty{})
Available sources:
Source
Description
empty_sky
Blank sky (for sky / dark frames)
flat_field
WCU lamp flat
star_field
Fixed random 20-star field
star_sky1
25-star sky field (calibration set 1)
star_sky2
25-star sky field (calibration set 2)
calib_star
Single centred point source
simple_gal
Elliptical galaxy (SED + morphology)
simple_gal1
Elliptical galaxy (variant)
pinhole_mask
WCU pinhole mask
laser_spectrum_lm
WCU laser spectrum, LM band
laser_spectrum_n
WCU laser spectrum, N band
properties(required)Observation parameters:
dit(float)Detector integration time in seconds.
ndit(int)Number of integrations per exposure.
filter_name(str)Filter wheel selection. Common values:
LM band:
Lp,short-L,Mp,L_spec,M_spec,HCI_L_short,HCI_L_long,HCI_M,Br_alpha,PAH_3.3,CO_1-0_ice,H2O-ice,IB_4.05,open,closedN band:
N1,N2,N3,N_spec,PAH_8.6,PAH_11.25,Ne_II,S_IV,open,closed
ndfilter_name(str, optional)Neutral density filter:
open,ND_OD1…ND_OD5.catg(str)DPR category:
SCIENCE,CALIB, orTECHNICAL.tech(str)DPR technique:
IMAGE,LM,IMAGE,N,LMS,LSS,LM,LSS,N,PUP,M,PUP,N,APP,LM,RAVC,LM,RAVC,IFU.type(str)DPR type:
OBJECT,SKY,STD,DARK,FLAT,LAMP,FLAT,TWILIGHT,DETLIN,DISTORTION,WAVE,PSF,OFFAXIS,PUPIL,CHOPHOME,DARK,WCUOFF,SLITLOSS,PERSIST.nObs(int)How many exposures of this template to generate.
dateobs(str, optional)Explicit date in
YYYY-MM-DD HH:MM:SSformat. Only used whensequence=False.tplname(str, optional)ESO template name string for the FITS header.
wcu(optional)Wavefront Control Unit parameters for internal calibrations:
wcu: current_lamp: "bb" # bb (blackbody) or laser current_fpmask: "open" # open, grid_lm, grid_n bb_aperture: 0.5 # blackbody aperture size bb_temp: 8000 # blackbody temperature (K) is_temp: 300 # integrating sphere temperature wcu_temp: 300 # WCU enclosure temperature xshift: 0 # pinhole mask X offset yshift: 0 # pinhole mask Y offset
Adding a New Source
Sources are defined in Simulations/python/sources.py. Each source is a
function that returns a ScopeSim-compatible source object.
Example – adding a bright point source:
def bright_star(**kwargs):
"""Single bright star at field centre."""
return sim_tp.star(
flux=1e4, # photons/s/m2
filter_curve="Ks",
spec_type="A0V",
)
After adding the function, you can reference it in YAML templates:
source:
name: bright_star
kwargs: {}
Creating a Small Variant
For CI testing, create a _small.py variant of your script that sets
small=True. This generates 32x32 pixel images that run quickly:
# myWorkflow_small.py
import runSimulationBlock as rs
if __name__ == "__main__":
params = {
"outputDir": "output/myWorkflow",
"small": True, # <-- small images
"doStatic": True,
"doCalib": 1, # fewer calibrations
"sequence": True,
"startMJD": "2027-03-15 00:00:00",
"calibFile": None,
"nCores": 4,
"testRun": False,
}
yamlFiles = [
"YAML/scienceLM.yaml",
"YAML/stdLM.yaml",
]
rs.runSimulationBlock(yamlFiles, params)
Then add a call to it in testAll.py so CI picks it up.
Tips
Reuse existing YAML files where possible. Most calibration templates (darks, detector linearity, distortion) are shared across workflows.
Start with a copy of the most similar existing workflow and modify it.
Use
testRun=Trueto validate your YAML files without running ScopeSim.Use
small=Trueduring development to iterate quickly.The
doCalibmechanism inspects your templates and auto-generates matching darks and flats – you rarely need to write dark/flat YAML by hand.Run
python/generateSummary.py output/myWorkflowafter a run to get a CSV summary of all generated FITS files.