Examples
The repository ships one worked example — TSTINS — as a standalone
waf project under ifw-iptool/example/tstins/. TSTINS is a fictitious
“test instrument” whose purpose is to exercise every shape defined by
the OTTO IP schemata, so that the example doubles as a coverage suite
for the compiler. The IpTool YAML sources live under
example/tstins/ipt/resource/ipt/tstins/.
The example contains four templates:
File |
OTTO type |
What it covers |
|---|---|---|
|
|
non-P1 template, |
|
|
P1 acquisition + |
|
|
non-P1 science, |
|
|
P1 science + |
In addition, the example ships one IP-wide metadata file,
tstins.meta.ipt.yaml, which carries all 9 OTTO constraints, all 5
checklist types, and a full laser block.
Parameter library (keys)
Excerpt from include/det.keys.ipt.yaml — each parameter is a
top-level typed instance:
!cfg.include schema/ifw/iptool/iptool.schema.yaml:
DET/READ/CLKIND: !cfg.type:IpToolParameter
type: keyword
label: CCD Read-out
domain:
keyword_values:
- 100kHz,1x1,high
- 100kHz,2x2,high
- 200kHz,1x1,low
- 200kHz,2x2,low
initial_value: {string: '200kHz,2x2,low'}
hide: [P1Setup, P1Observation, ETC, P2, SEQ]
(The / separator is the IpTool authoring convention; OTTO sees
this parameter as DET.READ.CLKIND after the compiler runs. See
Schema for why.)
Templates explicitly !cfg.include each per-prefix file they
need — there is no umbrella “include everything” aggregator. The
choice is deliberate: each template declares its own parameter
universe locally, so a reader knows immediately which prefixes
contribute, and the compiler does not pull in keys files the
template does not use.
Non-P1 calib template
tstins_img_cal_bias.tpl.ipt.yaml:
!cfg.include schema/ifw/iptool/iptool.schema.yaml:
!cfg.include ipt/tstins/include/det.keys.ipt.yaml:
!cfg.include ipt/tstins/include/seq.keys.ipt.yaml:
!cfg.include ipt/tstins/include/dpr.keys.ipt.yaml:
!cfg.merge DET/READ/CLKIND:
initial_value: {string: '100kHz,2x2,high'}
hide: [P1Setup, P1Observation, ETC]
!cfg.merge DPR/TYPE:
initial_value: {string: BIAS}
tstins_img_cal_bias: !cfg.type:IpToolTemplate
type: calib
instrument: TSTINS
label: TSTINS imaging bias
description: Bias frames for TSTINS imaging
parameters:
- DET/WIN1/ST
- DET/WIN1/STRX
- DET/WIN1/STRY
- DET/WIN1/NX
- DET/WIN1/NY
- DET/READ/CLKIND
- SEQ/NEXPO
- DPR/CATG
- DPR/TECH
- DPR/TYPE
P1 acquisition template
tstins_img_acq.tpl.ipt.yaml — exercises Phase1VLT.json and
Phase1ReferenceTargets.json (the reference_targets block, which
the compiler pivots from a list to the OTTO patternProperties map at
emit time):
tstins_img_acq: !cfg.type:IpToolTemplate
type: acquisition
instrument: TSTINS
label: TSTINS imaging acquisition
description: Target acquisition for TSTINS imaging observations
phase1:
label: TSTINS imaging acquisition
description: Target acquisition for TSTINS imaging in Phase 1
reference_targets:
- kind: NGS
label: Natural Guide Star
min: 1
max: 1
- kind: TTS
label: Tip-Tilt Star
min: 0
max: 2
parameters: [SEQ/PRESET, TEL/TARG/ALPHA, TEL/TARG/DELTA, ...]
P1 science template (full type coverage)
tstins_spec_obs_mos.tpl.ipt.yaml rounds out the parameter-type
coverage that the calib/acq/crsplit templates do not exercise. It is a
science template with a non-VLT phase1: block (just
label + description; no reference_targets, since those are
reserved for acquisition templates):
tstins_spec_obs_mos: !cfg.type:IpToolTemplate
type: science
instrument: TSTINS
label: TSTINS MOS spectroscopy
description: Multi-object spectroscopy observation for TSTINS
phase1:
label: TSTINS MOS spectroscopy
description: MOS science observation in Phase 1
parameters:
- DET/WIN1/UIT1
- DET/NDIT # int values-domain
- DET/GAIN # num values-domain
- DET/WIN/STRIPES # intlist
- DET/BAD/PIXMAP # binfile
- DET/CALIB/SCRIPT # textfile
- SEQ/NEXPO
- SEQ/CATG
- INS/FILTSET/NAMES # keywordlist
- TEL/TARG/MAIN # targetref
- TEL/TARG/MOSLIST # targetreflist
- DPR/CATG
- DPR/TECH
- DPR/TYPE
IP-wide metadata
tstins.meta.ipt.yaml — the conventional ip_metadata instance.
This file exercises the full OTTO surface: all 9 constraint names
(7 interval-style + skyTransparency + turbulence), all 5
checklist types (text/boolean/2-state/3-state/
list), and a non-empty laser block:
ip_metadata: !cfg.type:IpToolIpMetadata
format:
format: 2
instrument: TSTINS
version: '1.00'
constraints:
# interval-style
- {name: seeing, type: number, label: Seeing,
initial_value: {number: 1.0}, hide: [ETC],
interval: {min: 0.2, max: 2.0}}
- {name: airmass, ...}
- {name: moonDistance, ...}
- {name: pwv, ...}
- {name: fli, ...}
- {name: strehlRatio, ...}
- {name: twilight, ...}
# keyword-style
- name: skyTransparency
type: keyword
label: Sky Transparency
initial_value: {string: CLR}
hide: []
values:
- {value: PHO, label: Photometric}
- {value: CLR, label: Clear}
...
- {name: turbulence, ...}
checklist:
- {name: notes, type: text, compulsory: false, max_length: 500, ...}
- {name: autoguiding, type: boolean, compulsory: true, ...}
- {name: weather_ok, type: 2-state, compulsory: true, choices: [No, Yes]}
- {name: dome_status, type: 3-state, compulsory: true, choices: [Closed, Open, Moving]}
- {name: detector_mode, type: list, compulsory: true, choices: [Science, Engineering, Standby]}
laser:
fov: 7.5
laser_using_templates: [tstins_spec_obs_mos]
always_sensitive_templates: [tstins_img_acq]
maybe_sensitive_templates: [tstins_img_obs_crsplit]
checked_parameters: [INS.FILT1.NAME]
checked_values:
- {value: H_Alpha+83, sensitive: true}
- {value: GG435+81, sensitive: false}
...
Compile it
The example is a standalone waf project — the recommended flow is:
cd ifw-iptool/example/tstins
waf configure
waf build
waf install
waf validate-ip
That places the IP under $PREFIX/resource/ip/tstins/ and the
Sequencer stubs under
$PREFIX/lib/python3.12/site-packages/tstins/stubs/.
Alternatively, run the compiler directly against the YAML sources from the repository root:
ifwIpToolCompiler \\
-f example/tstins/ipt/resource/ipt/tstins/tstins.meta.ipt.yaml \\
example/tstins/ipt/resource/ipt/tstins/*.tpl.ipt.yaml \\
-o tmp
Then validate:
ifwIpToolValidator -i tmp/resource/ip/tstins/ip
The same compile also writes a Template Reference Manual (LaTeX + PDF)
under tmp/resource/doc/tstins/ip/; pass --omit-pdf to skip the
PDF build. See CLI for details.
A second, minimal example: TSTNLS (no laser)
The repository also ships a tiny companion example,
ifw-iptool/example/tstnls/. TSTNLS is a fictitious
“test instrument, no laser” whose sole purpose is to exercise the
no-laser path: an ip_metadata block with no laser: field
must compile cleanly, and the compiler must NOT emit laser.json.
Together with TSTINS (full laser block), the two examples cover both
branches of OTTO Laser.json optionality.
TSTNLS is standalone — it ships its own minimal 5-parameter library
(DET/WIN1/NX, DET/WIN1/NY, SEQ/NEXPO, DPR/CATG,
DPR/TYPE) under example/tstnls/ipt/resource/ipt/tstnls/include/.
It contains just one minimal calib template.
To build the standalone waf project:
cd ifw-iptool/example/tstnls
waf configure
waf build
waf install
waf validate-ip
Or run the compiler directly:
ifwIpToolCompiler \\
-f example/tstnls/ipt/resource/ipt/tstnls/tstnls.meta.ipt.yaml \\
example/tstnls/ipt/resource/ipt/tstnls/*.tpl.ipt.yaml \\
-o tmp
After compilation, tmp/resource/ip/tstnls/ip/laser.json should
not exist while format.json, templates.json,
constraints.json and checklist.json should.
Real-world example: FORS3 IPT
For a fully-fledged real-instrument IP that mirrors what an instrument team actually delivers, see:
ifw-iptool/example/fors3ipt/
fors3ipt is a complete standalone project (not part of
ifw-iptool’s build) at real-instrument scale: 77 templates, 5
prefix-based parameter library files, a portable ipt/ module,
own waf build, role-based install layout. It serves as the
reference for what a real-instrument IP looks like end-to-end.
Build it independently from inside its own directory:
cd ifw-iptool/example/fors3ipt
waf configure
waf build
waf install
waf validate-ip
What follows is the conceptual tour — patterns an author will
reuse at any real-instrument scale. The project’s own README.md
covers the project’s own heritage (it is a port of a pre-existing
JSON prototype prepared by the FORS3 consortium) and any
adaptations that were applied during the port.
What it covers
77 templates spanning every FORS3 observing mode — imaging (img),
imaging polarimetry (ipol), long-slit (lss), multi-object
(mos), mask-exchange-unit (mxu), polarimetric MOS (pmos),
spectrophotometry (specphot) — plus the generic technical
templates (gen_tec, hit_tec, spec_tec) and per-mode
calibrations. Five categories of OBD shape are exercised:
Acquisition templates with a
Phase1VLTblock carryingreference_targets(NGS / TTS).Phase-1 science templates with a
Phase1block but no reference targets.Non-Phase-1 science templates.
Calibration templates with per-template lamp / filter / grism
!cfg.mergeoverrides.Technical templates (
_tec_) with nichelistItems-bound list parameters and one-off keywords.
This is 5× more of IpTool’s surface area than the bundled TSTINS example exercises.
Library organisation: one file per FITS prefix
The parameter library lives at
ipt/resource/ipt/fors3/include/ and is split into five files,
one per FITS prefix:
include/
dpr.keys.ipt.yaml # DPR.CATG, DPR.TECH, DPR.TYPE
det.keys.ipt.yaml # DET.WIN1.*, DET.READ.CLKIND, DET.FIELD.UIT1, DET.FOCF.UIT1
seq.keys.ipt.yaml # SEQ.PRESET, SEQ.NEXPO, SEQ.NOFF, SEQ.CATG, SEQ.CCD,
# SEQ.POL.*, SEQ.RRM.*, SEQ.ACQMODE, SEQ.SPEC.*, ...
tel.keys.ipt.yaml # TEL.TARG.*, TEL.ROT.OFFANGLE, TEL.AG.*, TEL.GS1.*, TEL.ADC.TYPE
ins.keys.ipt.yaml # INS.COLL.NAID, INS.FILT1/2.NAME, INS.GRIS.NAME,
# INS.SLIT.NAID, INS.WOLL.NAID, INS.LAMP1..6.{NAID,TIME},
# INS.MASK.NAID, INS.MOS10.WID, ...
# plus INS1.*/INS2.* families for the daycalib templates
The convention is simple: a parameter’s keys file is determined by its FITS prefix. There is no “aux” or “common” file — every parameter belongs to exactly one prefix file, regardless of how many templates use it. This makes the library predictable to navigate (you know where to look) and easy to extend (new parameters slot in next to their prefix-mates).
Templates use !cfg.include to pull in the keys files they need.
Most templates include all five; minimal test templates may
include only one or two.
Per-template overrides: !cfg.merge discipline
Every divergence from a library default is expressed as a
!cfg.merge. There are no inline parameter declarations in
template files (the compiler enforces this — see the file-role
rule in Overview).
A typical bias template:
!cfg.include ipt/fors3/include/dpr.keys.ipt.yaml:
!cfg.include ipt/fors3/include/det.keys.ipt.yaml:
!cfg.include ipt/fors3/include/seq.keys.ipt.yaml:
!cfg.merge DET/READ/CLKIND:
initial_value: {string: '100kHz,2x2,high'}
hide: [P1Setup, P1Observation, ETC]
fors3_img_cal_bias: !cfg.type:IpToolTemplate
type: calib
instrument: FORS3
label: FORS3 imaging bias
description: Bias frames for FORS3 imaging
parameters: [DET/WIN1/ST, ..., DPR/TYPE]
This is the same shape TSTINS uses, just operated at scale: 77
templates × an average of ~3 merges per template = ~230 targeted
overrides expressed across the project. A given parameter (e.g.
DET/READ/CLKIND) ends up declared once and overridden
distinctly per template — exactly the value of a parameter library.
Type-changing !cfg.merge (advanced)
!cfg.merge is not limited to changing values within the same
type — the same OTTO parameter name can carry a different
declared type in two templates by merging type + domain +
initial_value together. In fors3ipt, SEQ/POL/ANGLES is
declared as keywordlist in the library and !cfg.merge-ed
to numlist in the fors3_ipol_obs_off_fast template. Both
templates emit a Template Signature whose SEQ.POL.ANGLES
parameter is the type the template needs. Use sparingly — most
parameters have a single stable type across an instrument.
Portable ipt/ layout
The project is split into a portable module plus a dev wrapper:
example/fors3ipt/
├── wscript # standalone-build shell (dev wrapper)
├── README.md # human entry point (dev wrapper)
├── .gitignore # standard waf .gitignore (dev wrapper)
└── ipt/ # portable IPT module — the deliverable
├── wscript # all build/install logic
└── resource/ipt/fors3/ # the IpTool sources
The ipt/ directory is the complete portable module that can
be dropped into another source tree (typically the instrument’s
control-software repository). It carries all the build/install
logic and produces the correct role-based output layout
independently. The top-level wscript, README.md, and
.gitignore are convenience wrappers that let the example build
and validate cleanly on its own inside ifw-iptool; they are
not part of the portable deliverable.
This is the recommended layout for any IP project: keep the
deliverable inside a single ipt/ subdirectory so the move into
the instrument’s own repository is a single cp -r operation.
Compile performance
With the parallelisation enabled by default
(see CLI, --jobs), the fors3ipt full
waf install validate-ip cycle completes in ~5 seconds for the
77-template compile itself (plus LaTeX + zip/tar/install overhead).
The serial fallback (--jobs 1) takes ~28 seconds. The 5× factor
matters in practice: instrument-team authoring is iterative, and a
5-second feedback loop keeps the inner loop fluid.
How to start your own instrument project
Recommended seed: TSTINS, not fors3ipt. TSTINS is small (4 templates), canonical (designed to exercise every OTTO shape), and carries no consortium-specific values that a new instrument team would have to discard. The fors3ipt example is the at-scale reference — useful to look at when your project starts growing — but not the right starting point for a fresh instrument.
The minimum-effort adoption path from TSTINS:
Copy
ifw-iptool/example/tstins/to your project tree.Rename the directory (
tstins→<yourinstr>).Rename the
INSTRUMENT = "tstins"constant inipt/wscriptto your instrument code (lowercased).Rename
ipt/resource/ipt/tstins/toipt/resource/ipt/<yourinstr>/.Update the
instrument:field in<yourinstr>.meta.ipt.yamland every<yourinstr>_<purpose>.tpl.ipt.yamlto your uppercase instrument code.Replace the TSTINS templates with your own. Keep the per-FITS-prefix keys-file convention; add new keys files only when your instrument introduces a genuinely new FITS prefix.
These are mechanical edits today; a future IpTool Organiser “New instrument project” action will automate steps 2-5 in one dialog. Until that ships, the manual approach above is the path.
Once your project starts growing past ~10 templates, the fors3ipt
example becomes useful to look at: the 5-prefix library
organisation, the !cfg.include / !cfg.merge discipline at
scale, the type-changing merge trick, the standalone
ipt/ handoff layout — all techniques that pay off at
real-instrument size.