Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

CI Coverage PyPI License

dls_va_ioc_sim

Simulate a DLS vacuum IOC, and the PLC behind it.

Everything a PLC would decide — valve interlocking, combining a gauge pair, the pressure itself — is decided here instead, and served over Channel Access so that a screen, an archiver or another IOC cannot tell it apart from the real thing. The PV interface mirrors the DLS support-module templates device for device.

An instance is generated from the builder XML the real IOC is built from, so simulating a cell is a one-liner rather than a writing job.

What Where
Source https://github.com/DiamondLightSource/dls-va-ioc-sim
PyPI pip install dls-va-ioc-sim
Docker docker run ghcr.io/diamondlightsource/dls-va-ioc-sim:latest
Releases https://github.com/DiamondLightSource/dls-va-ioc-sim/releases

Generating a simulation

$ dls-va-ioc-sim generate .../SR-BUILDER/etc/makeIocs/SR03C-VA-IOC-01.xml 99
wrote sr99c-va-ioc-01.py

One file, named after the IOC in lower case, and it is the IOC and its launcher both. The 99 rewrites the cell number in every device name, so SR03C comes up as SR99C and the simulation cannot be taken for the real machine — as does the non-standard Channel Access port it serves on, which is set at the top of the file itself.

$ ./sr99c-va-ioc-01.py

A PEP 723 header names the version of this package that wrote it and a uv run --script shebang starts it, so an instance runs wherever uv does with nothing installed first, and goes on running when the framework moves on. In an environment that already has the package, python sr99c-va-ioc-01.py is the same thing.

Two simulations at once want two ports, and the environment still wins:

$ EPICS_CA_SERVER_PORT=6066 EPICS_CA_REPEATER_PORT=6067 ./sr99c-va-ioc-01.py

Then drive it over Channel Access. Stopping pumps makes the pressure rise, starting them brings it back, and opening a valve equalises two volumes:

$ caput SR99A-VA-GIONP-01:STOP 1        # a whole group of supplies
$ camonitor SR99A-VA-GAUGE-01:P         # watch it come up

A whole ring at once

start serves any number of written instances as a single IOC, on one port — which is what a container wants, and the only shape that works where every pod shares a node's network stack:

$ dls-va-ioc-sim start sr*.py --no-interactive
24 instance(s), 49920 records, 1032 devices: sr01c-va-ioc-01.py, …

One instance behaves exactly as running that instance does. Generate each cell with its own number: distinct PV names are what let them share one database.

To look at a cell without committing to a file, run builds the same devices straight from the XML:

$ dls-va-ioc-sim run .../SR03C-VA-IOC-01.xml 99

The one thing the XML cannot say

A builder XML says which devices exist and which groups they are in. It says nothing about the beam pipe — which valve stands between which two lengths of it, how many litres a section holds, what it outgasses. On the real machine that comes off a P&ID.

So the generated file carries a vacuum layout marked *** EDIT ME ***: one volume per domain, joined by nothing, with capacities and gas loads guessed from the installed pumping speed. It runs out of the box and it is not the beam pipe. Making it the machine means splitting a domain where a valve really divides it and putting a gate() between the halves:

vacuum = vacuumLayout(
    straight,
    gate("SR99A-VA-VALVE-01"),
    arc,
)

A gate's neighbours are simply the entries either side of it, so there is no second place for the topology to disagree with itself.

Generate, then edit. The generator refuses to overwrite an existing pair without --force, because the layout in the one you have is the only part that took any thought.

Three layers

The thing to hold onto is that "space" and "volume" are different concepts that used to share a name:

  • A volume is a length of beam pipe: it holds gas, it has a capacity in litres, and pumps and gauges sit on it. It publishes nothing — no real IOC has a record for how many litres a section holds.
  • A group (GIONP-nn, GVALV-nn, …) is a device standing for several others. Writing to GIONP-01:START starts every pump underneath it, and a group's members may themselves be groups.
  • A space (SPACE-nn) is what an operator is shown: a pressure, a status lamp and controls. It owns nothing — every record either reads a group or writes to one.

Pressure belongs to a volume, not to a device. A group of volumes settles where its total gas load balances its total pumping speed, so the interesting behaviour is emergent rather than scripted: opening a valve onto a vented section spoils the good side and trips its ion pumps on high pressure, and a tripped pump stays latched until its volume is back below its setpoint.

Verifying a change

Build the database and diff it against the version before your change:

$ dls-va-ioc-sim dbdump sr99c-va-ioc-01.py before.db
$ # ...make the change...
$ dls-va-ioc-sim dbdump sr99c-va-ioc-01.py after.db
$ diff before.db after.db

For a change to how an instance is assembled, expect that diff to be empty — byte identical, not shape identical. For a change to a device class it is meant to be non-empty, and is then the record-by-record statement of what you changed. That is a far stronger check than running the IOC and a far cheaper one. Diff before you run.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dls_va_ioc_sim-1.0.0b6.tar.gz (211.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dls_va_ioc_sim-1.0.0b6-py3-none-any.whl (92.1 kB view details)

Uploaded Python 3

File details

Details for the file dls_va_ioc_sim-1.0.0b6.tar.gz.

File metadata

  • Download URL: dls_va_ioc_sim-1.0.0b6.tar.gz
  • Upload date:
  • Size: 211.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for dls_va_ioc_sim-1.0.0b6.tar.gz
Algorithm Hash digest
SHA256 468051a2ac9a752bc8e7387e825e9b1793de86e9396b7c0256cfae97bbe748cc
MD5 be564683d9411a35822092a3631b075f
BLAKE2b-256 a9786d27d89bc28362f459c2e33df750a4088adcda39fc3aed1727337104b0b6

See more details on using hashes here.

File details

Details for the file dls_va_ioc_sim-1.0.0b6-py3-none-any.whl.

File metadata

File hashes

Hashes for dls_va_ioc_sim-1.0.0b6-py3-none-any.whl
Algorithm Hash digest
SHA256 36296f7d1bf4d5de59f669327c79981e89dd0147e798ddb9c952f1fd2f90e96c
MD5 dc07ca4a81a940423bff4822c22b5886
BLAKE2b-256 45c05d51b158cb19887bfd0fe6354efb2747364b1d3f3498b563b014fcf83b20

See more details on using hashes here.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page