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>/logon Linux.
In the default settings file shown above, the following entries are specified:
jobs.storagewhich is the directory where the data of tomato jobs will be stored,jobs.dbpathwhich is the location of thesqlite3database used to track jobs,devices.configwhich 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.2", "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" }, "snapshot_interval": { "anyOf": [ { "type": "number" }, { "type": "string" } ], "default": 3600.0, "title": "Snapshot Interval" } }, "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 fieldsextract_samplefile»all fieldsvalidate_task_names»method
- field version: Literal['2.2'] [Required]
- Validated by:
extract_methodfileextract_samplefile
- field settings: Settings [Optional]
Additional configuration options for tomato.
- Validated by:
extract_methodfileextract_samplefile
- field sample: Sample [Required]
Specification of the experimental sample.
- Validated by:
extract_methodfileextract_samplefile
- field method: Sequence[Task] [Required]
A sequence of the experimental
Tasks.- Validated by:
extract_methodfileextract_samplefilevalidate_task_names
- validator extract_samplefile » all fields
If
samplefileis provided invalues, parse the file assample.
- validator extract_methodfile » all fields
If
methodfileis provided invalues, parse the file asmethod.
- validator validate_task_names » method
- pydantic model dgbowl_schemas.tomato.payload.Task
The
Taskis a driver/device-independent abstraction describing the measurement steps. The driver-specific information for theTaskcan be provided via thetechnique_nameandtask_paramsparameters.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:
convert_str_to_seconds»max_durationconvert_str_to_seconds»polling_intervalconvert_str_to_seconds»sampling_intervaltask_names_cannot_be_same»all fields
- field component_role: str [Required]
role of the pipeline component on which this
Taskshould run- Validated by:
task_names_cannot_be_same
- field max_duration: float | str [Required]
the maximum duration of this
Task, in seconds- Validated by:
convert_str_to_secondstask_names_cannot_be_same
- field sampling_interval: float | str [Required]
the interval between measurements, in seconds
- Validated by:
convert_str_to_secondstask_names_cannot_be_same
- field polling_interval: float | str | None = None
the interval between polling for data by the
tomato-jobprocess, in seconds; defaults to the value in driver settings- Validated by:
convert_str_to_secondstask_names_cannot_be_same
- field technique_name: str [Required]
the name of the technique; has to match one of the capabilities of the component on which this
Taskwill be executed- Validated by:
task_names_cannot_be_same
- field task_name: str | None = None
the (optional) name of the current
Task; can be used for triggering otherTaskin parallel to this one viastart_with_task_name- Validated by:
task_names_cannot_be_same
- field task_params: Dict[str, Any] | None [Optional]
a
dictof any additional parameters required to specify the experimental technique; the key-value pairs of thisdictwill be used as attr-val pairs by theset_attr()method of the component executing thisTask- Validated by:
task_names_cannot_be_same
- field start_with_task_name: str | None = None
the
task_nameof theTaskthat thisTaskshould be started in parallel with; when set, thisTaskwill wait for execution until aTaskwith the matchingtask_nameis started- Validated by:
task_names_cannot_be_same
- field stop_with_task_name: str | None = None
the
task_nameof theTaskthat, when started, will stop the execution of thisTask; when set, thisTaskwill execute normally, but if a aTaskwith the matchingtask_nameis started, thisTaskwill be stopped- Validated by:
task_names_cannot_be_same
- validator task_names_cannot_be_same » all fields
- validator convert_str_to_seconds » max_duration, polling_interval, sampling_interval