Quick start guide
First time set-up
Note
This section assumes that tomato has been successfully installed.
To prepare tomato before its first run, a settings file containing the basic configuration for the tomato.daemon
needs to be placed in tomato’s appdir folder. By default, the appdir path is:
$env:localappdata\dgbowl\tomato\<version>
on Windows,$HOME/.config/tomato/<version>
on Linux.
The easiest way to do create this file is using the provided tomato init
command:
1 kraus@dorje:/home/kraus/$ tomato init
2 Success: wrote default settings into /home/kraus/.config/tomato/1.0a1/settings.toml
Where appdir is /home/kraus/.config/tomato/1.0a1/
. A custom appdir can be specified using the --appdir
argument to tomato.
tomato program flowchart
tomato currently contains two command line user-facing utilities/executables:
tomato
, responsible for management of the daemon process, andketchup
, responsible for job submission and management.
These two executables then internally spawn other processes, including the state daemon process tomato-daemon
, a tomato-job
process for every running job, and a tomato-driver
process for each driver type, managing all devices of a that type.
tomato concepts flowchart
The following concepts are used in tomato:
devices, which represent separately addressable (and optionally multichannel) instruments in the lab,
components, which represent the individual channels of each device, describing the role of this component and its associated capabilities,
pipelines, which represent the real world organisation of device components into independent experimental set-ups, containing components from one or more device,
jobs, which are processes that carry out a payload (i.e. a set of experimental instructions) on a pipeline by instructing its components to perform individual tasks, and
drivers, which are separate processes, each managing all defined devices of a certain driver type as well as their components:
Settings file
The settings file contains the basic information required to start the tomato-daemon
. The filename is hard-coded to be a settings.toml
file, which has to be located in the appdir. The default file generated by tomato init
looks similar to the below example:
1 datadir = '/home/kraus/.local/share/tomato/1.0a1'
2 logdir = '/home/kraus/.cache/tomato/1.0a1/log'
3
4 [jobs]
5 storage = '/home/kraus/.local/share/tomato/1.0a1/Jobs'
6 dbpath = '/home/kraus/.local/share/tomato/1.0a1/Jobs/dbpath.sqlite'
7
8 [devices]
9 config = '/home/kraus/.config/tomato/1.0a1/devices.yml'
10
11 [drivers]
12 example_counter.idle_measurement_interval = 1
In addition to the appdir, a second path, datadir, is used to specify the location of the data created by tomato. The default datadir is:
$env:localappdata\dgbowl\tomato\<version>
on Windows,$HOME/.local/share/tomato/<version>
on Linux.
Finally, another path, logdir, is used to specify where logs for tomato are placed. By default, logdir is:
$env:localappdata\dgbowl\tomato\<version>
on Windows,$HOME/.cache/tomato/<version>/log
on Linux.
In the default settings file shown above, the following entries are specified:
jobs.storage
which is the directory where the data of tomato jobs will be stored,jobs.dbpath
which is the location of thesqlite3
database used to track jobs,devices.config
which points to ayaml
-formatted devices file, defining the hardware configuration of the devices managed by tomato.
Additional, driver-specific settings may be provided in the [drivers]
section, following the example of the drivers.example_counter.idle_measurement_interval
entry. These driver-specific settings are passed to each driver when its process is launched and the DriverInterface
is initialised, and can therefore contain paths to various libraries or other files necessary for the driver to function.
Devices file
This yaml
-formatted file contains information about each device, corresponding to an individual piece of hardware managed by tomato, as well as information about the organisation of the individually-addressable components of those devices into pipelines.
When the devices file is not present, the default file shipped with tomato will be used instead:
devices section
The devices
section of the default devices file is shown below:
1 devices:
2 - name: dev-counter
3 driver: "example_counter"
4 address: "example-addr"
5 channels: ["1"]
6 pollrate: 1
Here, we define a single device using the example_counter
driver. The definition includes the address
of the device (str
type) as well as an enumeration of individually-addressable channels the device has (list[str]
).
For example, the devices shown in the concepts flowchart above would be defined as:
1 devices:
2 - name: device 1
3 driver: "driver 123"
4 address: "192.168.1.1"
5 channels: ["1", "2", "3"]
6 pollrate: 1
7 - name: device a
8 driver: "driver abc"
9 address: "COM1"
10 channels: ["100"]
11 pollrate: 5
12 - name: device b
13 driver: "driver abc"
14 address: "COM2"
15 channels: ["100"]
16 pollrate: 5
Note
The pollrate
here is an internal setting for tomato. It is the frequency with which the job interacting with the device driver asks the driver for data, not the frequency with which the driver asks the hardware for data! This latter “sampling” frequency can be defined in each individual task submitted as a payload of a job.
pipelines section
The default pipelines
section looks as follows:
1 pipelines:
2 - name: pip-counter
3 components:
4 - role: counter
5 device: dev-counter
6 channel: "1"
Here, a single pipeline called pip-counter
is defined to contain the one available channel of the dev-counter
device (defined on line 5) shown further above. For multi channel devices, it is also possible to define a pipeline for each channel automatically, e.g. using the following definition:
1 pipelines:
2 - name: pip-counter-*
3 components:
4 - role: counter
5 device: dev-counter
6 channel: each
Here, a set of pipelines would be created using each of the available channels in dev-counter
, replacing the *
in line 2 using the channel. Therefore, one pipeline with name pip-counter-1
would be created. However, if the dev-counter
were to contain more than one channel, a pipeline would be generated for each channel.
Finally, a definition for the pipelines shown in the concepts flowchart above can be defined as:
1 pipelines:
2 - name: pipeline a1
3 components:
4 - role: dev 123
5 device: device 1
6 channel: "1"
7 - role: dev abc
8 device: device a
9 channel: "100"
10 - name: pipeline b2
11 components:
12 - role: dev 123
13 device: device 1
14 channel: "2"
15 - role: dev abc
16 device: device b
17 channel: "100"
18 - name: pipeline 3
19 components:
20 - role: dev 123
21 device: device 1
22 channel: "3"
Payload file
The payload file contains all information required to enter a job into the queue and allow its assignment onto a pipeline. The overall schema of the payload is defined in the dgbowl_schemas.tomato
module, and is parsed using dgbowl_schemas.tomato.to_payload()
.
Of particular importance here is the specification of the individual Tasks
within the Payload.method
field. The Tasks
are distributed onto individual components of the pipeline (as matched by the component_role
field), and then executed in sequence. Some general Task
parameters are abstracted by tomato, such as the max_duration
, sampling_interval
and polling_interval
. The other are driver or component specific, and can be specified using the task_params
field.
Warning
Currently, tomato does not check whether the sampling_interval
is realistic. However, such validation is planned for a future release, see https://github.com/dgbowl/tomato/issues/127.
As of tomato-2.1
, execution of a certain Task
can be postponed and triggered to coincide with the start of a different Task
; for this, the start_with_task_name
attribute of the triggered Task
needs to match the task_name
of the triggering Task
. Similarly, the execution of a Task
can be stopped once a different Task
starts, by setting stop_with_task_name
accordingly.
As of tomato-2.0
, the task_params
specified in the payload are validated by the device driver. In particular, the values of all entries within task_params
are checked for compatibility with the Attr.type
and Attr.options
(if supplied), as well as against the provided Attr.minimum
and Attr.maximum
, as specified in the matching Attr
.
- pydantic model dgbowl_schemas.tomato.payload.Payload
Show JSON schema
{ "title": "Payload", "type": "object", "properties": { "version": { "const": "2.1", "title": "Version", "type": "string" }, "settings": { "$ref": "#/$defs/Settings" }, "sample": { "$ref": "#/$defs/Sample" }, "method": { "items": { "$ref": "#/$defs/Task" }, "title": "Method", "type": "array" } }, "$defs": { "Output": { "additionalProperties": false, "description": "Provide the ``path`` and ``prefix`` for the final FAIR-data archive of the *job*.", "properties": { "path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Path" }, "prefix": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Prefix" } }, "title": "Output", "type": "object" }, "Sample": { "additionalProperties": true, "description": "Additional attributes for each :class:`Sample` may be required, depending on the\nmethod within the payload.", "properties": { "name": { "title": "Name", "type": "string" } }, "required": [ "name" ], "title": "Sample", "type": "object" }, "Settings": { "additionalProperties": false, "description": "Specification of *job* configuration for tomato.", "properties": { "unlock_when_done": { "default": false, "title": "Unlock When Done", "type": "boolean" }, "verbosity": { "default": "WARNING", "enum": [ "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL" ], "title": "Verbosity", "type": "string" }, "output": { "$ref": "#/$defs/Output" }, "snapshot": { "anyOf": [ { "$ref": "#/$defs/Snapshot" }, { "type": "null" } ], "default": null } }, "title": "Settings", "type": "object" }, "Snapshot": { "additionalProperties": false, "description": "Provide the ``frequency``, ``path`` and ``prefix`` to configure the snapshotting\nfunctionality of tomato.", "properties": { "path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Path" }, "prefix": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Prefix" }, "frequency": { "default": 3600.0, "title": "Frequency", "type": "number" } }, "title": "Snapshot", "type": "object" }, "Task": { "additionalProperties": false, "description": "The :class:`Task` is a driver/device-independent abstraction describing the\nmeasurement steps. The driver-specific information for the :class:`Task` can be\nprovided via the :obj:`technique_name` and :obj:`task_params` parameters.", "properties": { "component_role": { "title": "Component Role", "type": "string" }, "max_duration": { "anyOf": [ { "type": "number" }, { "type": "string" } ], "title": "Max Duration" }, "sampling_interval": { "anyOf": [ { "type": "number" }, { "type": "string" } ], "title": "Sampling Interval" }, "polling_interval": { "anyOf": [ { "type": "number" }, { "type": "string" }, { "type": "null" } ], "default": null, "title": "Polling Interval" }, "technique_name": { "title": "Technique Name", "type": "string" }, "task_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Task Name" }, "task_params": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Task Params" }, "start_with_task_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Start With Task Name" }, "stop_with_task_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Stop With Task Name" } }, "required": [ "component_role", "max_duration", "sampling_interval", "technique_name" ], "title": "Task", "type": "object" } }, "additionalProperties": false, "required": [ "version", "sample", "method" ] }
- Config:
extra: str = forbid
- Validators:
extract_methodfile
»all fields
extract_samplefile
»all fields
- field version: Literal['2.1'] [Required]
- Validated by:
- validator extract_samplefile » all fields
If
samplefile
is provided invalues
, parse the file assample
.
- validator extract_methodfile » all fields
If
methodfile
is provided invalues
, parse the file asmethod
.
- pydantic model dgbowl_schemas.tomato.payload.Task
The
Task
is a driver/device-independent abstraction describing the measurement steps. The driver-specific information for theTask
can be provided via thetechnique_name
andtask_params
parameters.Show JSON schema
{ "title": "Task", "description": "The :class:`Task` is a driver/device-independent abstraction describing the\nmeasurement steps. The driver-specific information for the :class:`Task` can be\nprovided via the :obj:`technique_name` and :obj:`task_params` parameters.", "type": "object", "properties": { "component_role": { "title": "Component Role", "type": "string" }, "max_duration": { "anyOf": [ { "type": "number" }, { "type": "string" } ], "title": "Max Duration" }, "sampling_interval": { "anyOf": [ { "type": "number" }, { "type": "string" } ], "title": "Sampling Interval" }, "polling_interval": { "anyOf": [ { "type": "number" }, { "type": "string" }, { "type": "null" } ], "default": null, "title": "Polling Interval" }, "technique_name": { "title": "Technique Name", "type": "string" }, "task_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Task Name" }, "task_params": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Task Params" }, "start_with_task_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Start With Task Name" }, "stop_with_task_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Stop With Task Name" } }, "additionalProperties": false, "required": [ "component_role", "max_duration", "sampling_interval", "technique_name" ] }
- Config:
extra: str = forbid
- Validators:
- field component_role: str [Required]
role of the pipeline component on which this
Task
should run- Validated by:
- field max_duration: float | str [Required]
the maximum duration of this
Task
, in seconds- Validated by:
- field sampling_interval: float | str [Required]
the interval between measurements, in seconds
- Validated by:
- field polling_interval: float | str | None = None
the interval between polling for data by the
tomato-job
process, in seconds; defaults to the value in driver settings- Validated by:
- field technique_name: str [Required]
the name of the technique; has to match one of the capabilities of the component on which this
Task
will be executed- Validated by:
- field task_name: str | None = None
the (optional) name of the current
Task
; can be used for triggering otherTask
in parallel to this one viastart_with_task_name
- Validated by:
- field task_params: Dict[str, Any] | None [Optional]
a
dict
of any additional parameters required to specify the experimental technique; the key-value pairs of thisdict
will be used as attr-val pairs by theset_attr()
method of the component executing thisTask
- Validated by:
- field start_with_task_name: str | None = None
the
task_name
of theTask
that thisTask
should be started in parallel with; when set, thisTask
will wait for execution until aTask
with the matchingtask_name
is started- Validated by:
- field stop_with_task_name: str | None = None
the
task_name
of theTask
that, when started, will stop the execution of thisTask
; when set, thisTask
will execute normally, but if a aTask
with the matchingtask_name
is started, thisTask
will be stopped- Validated by:
- validator task_names_cannot_be_same » all fields
- validator convert_str_to_seconds » sampling_interval, max_duration, polling_interval