From ab3fa23728924742925891195df21020dc1f983b Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 17 Sep 2024 12:16:52 -0400 Subject: [PATCH 1/8] chore(shared-data): create liquid class schema v1 and fixture This PR introduces the first version of an Opentrons liquid class schema. Single liquid class definitions will adhere to this schema and be keyed by pipette and tip type. --- .../fixtures/fixture_glycerol50.json | 351 +++++++++++++++++ shared-data/liquid-class/schemas/1.json | 358 ++++++++++++++++++ 2 files changed, 709 insertions(+) create mode 100644 shared-data/liquid-class/fixtures/fixture_glycerol50.json create mode 100644 shared-data/liquid-class/schemas/1.json diff --git a/shared-data/liquid-class/fixtures/fixture_glycerol50.json b/shared-data/liquid-class/fixtures/fixture_glycerol50.json new file mode 100644 index 00000000000..987d74cf6ff --- /dev/null +++ b/shared-data/liquid-class/fixtures/fixture_glycerol50.json @@ -0,0 +1,351 @@ +{ + "liquidName": "glycerol50", + "p1000_flex": { + "t20": { + "aspirate": { + "submerge": { + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": -2 + }, + "speed": 3.5, + "delay": { + "enable": true, + "duration": 1.5 + } + }, + "retract": { + "positionReference": "top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 2.0, + "airGap": 5.0, + "blowout": { + "enable": true, + "location": "trash", + "flowRate": 2.5 + }, + "delay": { + "enable": false, + "duration": 0.5 + } + }, + "touchTip": { + "enable": true, + "zOffset": 1.5, + "mmToEdge": 0.5, + "speed": 2.0 + }, + "positionReference": "meniscus", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "flowRate": 1.5, + "preWet": true, + "mix": { + "enable": true, + "repetitions": 3, + "volume": 100 + }, + "delay": { + "enable": true, + "duration": 1.0 + } + }, + "singleDispense": { + "submerge": { + "positionReference": "center", + "offset": { + "x": 0, + "y": 0, + "z": -1 + }, + "speed": 4.0, + "delay": { + "enable": true, + "duration": 2.0 + } + }, + "touchTip": { + "enable": true, + "zOffset": 2.0, + "mmToEdge": 0.2, + "speed": 1.5 + }, + "retract": { + "positionReference": "top", + "offset": { + "x": 0, + "y": 0, + "z": 1.5 + }, + "speed": 3.0, + "airGap": 2.0, + "blowout": { + "enable": true, + "location": "destination", + "flowRate": 3.5 + }, + "delay": { + "enable": true, + "duration": 1.5 + } + }, + "positionReference": "meniscus", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "flowRate": 2.0, + "mix": { + "enable": false, + "repetitions": 2, + "volume": 50 + }, + "delay": 0.5, + "pushOutVolume": 1.0 + }, + "multiDispense": { + "enable": true, + "submerge": { + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": -0.5 + }, + "speed": 2.0, + "delay": { + "enable": true, + "duration": 0.8 + } + }, + "touchTip": { + "enable": false, + "zOffset": 0.5, + "mmToEdge": 0.1, + "speed": 3.0 + }, + "retract": { + "positionReference": "center", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "speed": 4.0, + "airGap": 3.0, + "blowout": { + "enable": true, + "location": "trash", + "flowRate": 1.5 + }, + "delay": { + "enable": true, + "duration": 0.5 + } + }, + "positionReference": "top", + "offset": { + "x": 0, + "y": 0, + "z": 0.5 + }, + "flowRate": 1.0, + "mix": { + "enable": true, + "repetitions": 5, + "volume": 60 + }, + "conditioningVolume": 10, + "disposalVolume": 5, + "delay": { + "enable": false, + "duration": 0.5 + } + } + }, + "t50": { + "aspirate": { + "submerge": { + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": -2 + }, + "speed": 3.5, + "delay": { + "enable": true, + "duration": 1.5 + } + }, + "retract": { + "positionReference": "top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 2.0, + "airGap": 5.0, + "blowout": { + "enable": true, + "location": "trash", + "flowRate": 2.5 + }, + "delay": { + "enable": false, + "duration": 0.5 + } + }, + "touchTip": { + "enable": true, + "zOffset": 1.5, + "mmToEdge": 0.5, + "speed": 2.0 + }, + "positionReference": "meniscus", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "flowRate": 1.5, + "preWet": true, + "mix": { + "enable": true, + "repetitions": 3, + "volume": 100 + }, + "delay": { + "enable": true, + "duration": 1.0 + } + }, + "singleDispense": { + "submerge": { + "positionReference": "center", + "offset": { + "x": 0, + "y": 0, + "z": -1 + }, + "speed": 4.0, + "delay": { + "enable": true, + "duration": 2.0 + } + }, + "touchTip": { + "enable": true, + "zOffset": 2.0, + "mmToEdge": 0.2, + "speed": 1.5 + }, + "retract": { + "positionReference": "top", + "offset": { + "x": 0, + "y": 0, + "z": 1.5 + }, + "speed": 3.0, + "airGap": 2.0, + "blowout": { + "enable": true, + "location": "destination", + "flowRate": 3.5 + }, + "delay": { + "enable": true, + "duration": 1.5 + } + }, + "positionReference": "meniscus", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "flowRate": 2.0, + "mix": { + "enable": false, + "repetitions": 2, + "volume": 50 + }, + "delay": 0.5, + "pushOutVolume": 2.0 + }, + "multiDispense": { + "enable": true, + "submerge": { + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": -0.5 + }, + "speed": 2.0, + "delay": { + "enable": true, + "duration": 0.8 + } + }, + "touchTip": { + "enable": false, + "zOffset": 0.5, + "mmToEdge": 0.1, + "speed": 3.0 + }, + "retract": { + "positionReference": "center", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "speed": 4.0, + "airGap": 3.0, + "blowout": { + "enable": true, + "location": "trash", + "flowRate": 1.5 + }, + "delay": { + "enable": true, + "duration": 0.5 + } + }, + "positionReference": "top", + "offset": { + "x": 0, + "y": 0, + "z": 0.5 + }, + "flowRate": 1.0, + "mix": { + "enable": true, + "repetitions": 5, + "volume": 60 + }, + "conditioningVolume": 10, + "disposalVolume": 5, + "delay": { + "enable": false, + "duration": 0.5 + } + } + } + }, + "namespace": "custom", + "schemaVersion": 1 +} diff --git a/shared-data/liquid-class/schemas/1.json b/shared-data/liquid-class/schemas/1.json new file mode 100644 index 00000000000..4bd15bbb8df --- /dev/null +++ b/shared-data/liquid-class/schemas/1.json @@ -0,0 +1,358 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "opentronsLiquidClassSchemaV1", + "title": "Liquid Class Schema", + "description": "Schema for defining a single liquid class's properties for liquid handling functions.", + "type": "object", + "definitions": { + "positiveNumber": { + "type": "number", + "minimum": 0 + }, + "safeString": { + "description": "a string safe to use for namespace. Lowercase-only.", + "type": "string", + "pattern": "^[a-z0-9._]+$" + }, + "delay": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "description": "Whether delay is enabled." + }, + "duration": { + "#ref": "#/definitions/positiveNumber", + "description": "Duration of delay, in seconds." + } + }, + "description": "Delay properties." + }, + "positionReference": { + "type": "string", + "description": "Reference point for positioning (e.g., bottom, top, liquid surface).", + "enum": ["bottom", "top", "center", "meniscus"] + }, + "coordinate": { + "type": "object", + "description": "3-dimensional coordinate.", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "z": { + "type": "number" + } + }, + "required": ["x", "y", "z"] + }, + "touchTip": { + "type": "object", + "description": "Shared properties for the touch-tip function.", + "properties": { + "enable": { + "type": "boolean", + "description": "Whether touch-tip is enabled." + }, + "zOffset": { + "type": "number", + "description": "Offset from the top of the well for touch-tip, in millimeters." + }, + "mmToEdge": { + "type": "number", + "description": "Offset away from the the well edge, in millimeters." + }, + "speed": { + "$ref": "#/definitions/positiveNumber", + "description": "Touch-tip speed, in millimeters per second." + } + }, + "required": ["enable", "zOffset", "mmToEdge", "speed"] + }, + "mix": { + "type": "object", + "description": "Mixing properties.", + "properties": { + "enable": { + "type": "boolean", + "description": "Whether mix is enabled." + }, + "repetitions": { + "type": "integer", + "description": "Number of mixing repetitions.", + "minimum": 0 + }, + "volume": { + "$ref": "#/definitions/positiveNumber", + "description": "Volume used for mixing, in microliters." + } + }, + "required": ["repetitions", "volume"] + }, + "blowout": { + "type": "object", + "description": "Blowout properties.", + "properties": { + "enable": { + "type": "boolean", + "description": "Whether blow-out is enabled." + }, + "location": { + "type": "string", + "enum": ["source", "destination", "trash"], + "description": "Location well or trash entity for blow out." + }, + "flowRate": { + "$ref": "#/definitions/positiveNumber", + "description": "Flow rate for blow out, in microliters per second." + } + }, + "required": ["enable", "location", "flowRate"] + }, + "submerge": { + "type": "object", + "description": "Shared properties for the submerge function before aspiration or dispense.", + "properties": { + "positionReference": { + "$ref": "#/definitions/positionReference" + }, + "offset": { + "$ref": "#/definitions/coordinate" + }, + "speed": { + "$ref": "#/definitions/positiveNumber", + "description": "Speed of submerging, in millimeters per second." + }, + "delay": { + "$ref": "#/definitions/delay" + } + }, + "required": ["positionReference", "offset", "speed", "delay"] + }, + "retract": { + "type": "object", + "description": "Shared properties for the retract function after aspiration or dispense.", + "properties": { + "positionReference": { + "$ref": "#/definitions/positionReference" + }, + "offset": { + "$ref": "#/definitions/coordinate" + }, + "speed": { + "$ref": "#/definitions/positiveNumber", + "description": "Speed of retraction, in millimeters per second." + }, + "airGap": { + "$ref": "#/definitions/positiveNumber", + "description": "Air gap volume after retract, in microliters." + }, + "blowout": { + "$ref": "#/definitions/blowout" + }, + "delay": { + "$ref": "#/definitions/delay" + } + }, + "required": [ + "positionReference", + "offset", + "speed", + "airGap", + "blowout", + "delay" + ] + }, + "aspirateParams": { + "type": "object", + "description": "Parameters specific to the aspirate function.", + "properties": { + "submerge": { + "$ref": "#/definitions/submerge" + }, + "retract": { + "$ref": "#/definitions/retract" + }, + "touchTip": { + "$ref": "#/definitions/touchTip" + }, + "positionReference": { + "$ref": "#/definitions/positionReference" + }, + "offset": { + "$ref": "#/definitions/coordinate" + }, + "flowRate": { + "$ref": "#/definitions/positiveNumber", + "description": "Flow rate for aspirating, in microliters per second." + }, + "preWet": { + "type": "boolean", + "description": "Whether to perform a pre-wet action." + }, + "mix": { + "$ref": "#/definitions/mix" + }, + "delay": { + "$ref": "#/definitions/delay" + } + }, + "required": [ + "submerge", + "retract", + "touchTip", + "positionReference", + "offset", + "flowRate", + "preWet", + "mix", + "delay" + ] + }, + "singleDispenseParams": { + "type": "object", + "description": "Parameters specific to the single-dispense function.", + "properties": { + "submerge": { + "$ref": "#/definitions/submerge" + }, + "touchTip": { + "$ref": "#/definitions/touchTip" + }, + "retract": { + "$ref": "#/definitions/retract" + }, + "positionReference": { + "$ref": "#/definitions/positionReference" + }, + "offset": { + "$ref": "#/definitions/coordinate" + }, + "flowRate": { + "$ref": "#/definitions/positiveNumber", + "description": "Flow rate for dispense, in microliters per second." + }, + "mix": { + "$ref": "#/definitions/mix" + }, + "pushOutVolume": { + "$ref": "#/definitions/positiveNumber", + "description": "Push out volume at dispense, in microliters." + }, + "delay": { + "$ref": "#/definitions/positiveNumber", + "description": "Delay after dispense, in seconds." + } + }, + "required": [ + "submerge", + "touchTip", + "retract", + "positionReference", + "offset", + "flowRate", + "mix", + "pushOutVolume", + "delay" + ] + }, + "multiDispenseParams": { + "type": "object", + "description": "Parameters specific to the multi-dispense function.", + "properties": { + "enable": { + "type": "boolean", + "description": "Whether multi-dispense is enabled." + }, + "submerge": { + "$ref": "#/definitions/submerge" + }, + "touchTip": { + "$ref": "#/definitions/touchTip" + }, + "retract": { + "$ref": "#/definitions/retract" + }, + "positionReference": { + "$ref": "#/definitions/positionReference" + }, + "offset": { + "$ref": "#/definitions/coordinate" + }, + "flowRate": { + "$ref": "#/definitions/positiveNumber", + "description": "Flow rate for dispensing, in microliters per second." + }, + "mix": { + "$ref": "#/definitions/mix" + }, + "conditioningVolume": { + "$ref": "#/definitions/positiveNumber", + "description": "Volume used for conditioning during dispense, in microliters." + }, + "disposalVolume": { + "$ref": "#/definitions/positiveNumber", + "description": "Volume discarded during dispense, in microliters." + }, + "delay": { + "$ref": "#/definitions/delay" + } + }, + "required": [ + "enable", + "submerge", + "touchTip", + "retract", + "positionReference", + "offset", + "flowRate", + "mix", + "conditioningVolume", + "disposalVolume", + "delay" + ] + } + }, + "required": ["liquidName", "schemaVersion", "namespace"], + "properties": { + "liquidName": { + "type": "string", + "description": "The name of the liquid (e.g., water, ethanol, serum)." + }, + "schemaVersion": { + "description": "Which schema version a liquid class is using", + "type": "number", + "enum": [1] + }, + "namespace": { + "$ref": "#/definitions/safeString" + } + }, + "patternProperties": { + "^p[0-9]{2,4}": { + "patternProperties": { + "^t[0-9]{2,4}$": { + "type": "object", + "properties": { + "aspirate": { + "$ref": "#/definitions/aspirateParams" + }, + "singleDispense": { + "$ref": "#/definitions/singleDispenseParams" + }, + "multiDispense": { + "$ref": "#/definitions/multiDispenseParams" + } + }, + "required": ["aspirate", "singleDispense", "multiDispense"], + "additionalProperties": false + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false +} From 19426dc675a1678c2dee7f59efafdcb4a28d7f33 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 17 Sep 2024 12:35:48 -0400 Subject: [PATCH 2/8] add patternProperties descriptions for pipette and tip --- shared-data/liquid-class/schemas/1.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shared-data/liquid-class/schemas/1.json b/shared-data/liquid-class/schemas/1.json index 4bd15bbb8df..f2221cb7fb8 100644 --- a/shared-data/liquid-class/schemas/1.json +++ b/shared-data/liquid-class/schemas/1.json @@ -333,9 +333,12 @@ }, "patternProperties": { "^p[0-9]{2,4}": { + "type": "object", + "description": "Object containing liquid class properties specific to the pipette model", "patternProperties": { "^t[0-9]{2,4}$": { "type": "object", + "description": "Object containing liquid class properties specific to the tip type", "properties": { "aspirate": { "$ref": "#/definitions/aspirateParams" From ea481a45995b10ec5638fa86311f87be826befe1 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 17 Sep 2024 17:05:04 -0400 Subject: [PATCH 3/8] refactor schema per feedback --- .../fixtures/fixture_glycerol50.json | 521 ++++++------------ shared-data/liquid-class/schemas/1.json | 208 +++++-- 2 files changed, 322 insertions(+), 407 deletions(-) diff --git a/shared-data/liquid-class/fixtures/fixture_glycerol50.json b/shared-data/liquid-class/fixtures/fixture_glycerol50.json index 987d74cf6ff..95f9ae889e2 100644 --- a/shared-data/liquid-class/fixtures/fixture_glycerol50.json +++ b/shared-data/liquid-class/fixtures/fixture_glycerol50.json @@ -1,351 +1,180 @@ { - "liquidName": "glycerol50", - "p1000_flex": { - "t20": { - "aspirate": { - "submerge": { - "positionReference": "bottom", - "offset": { - "x": 0, - "y": 0, - "z": -2 - }, - "speed": 3.5, - "delay": { - "enable": true, - "duration": 1.5 - } - }, - "retract": { - "positionReference": "top", - "offset": { - "x": 0, - "y": 0, - "z": 2 - }, - "speed": 2.0, - "airGap": 5.0, - "blowout": { - "enable": true, - "location": "trash", - "flowRate": 2.5 - }, - "delay": { - "enable": false, - "duration": 0.5 - } - }, - "touchTip": { - "enable": true, - "zOffset": 1.5, - "mmToEdge": 0.5, - "speed": 2.0 - }, - "positionReference": "meniscus", - "offset": { - "x": 0, - "y": 0, - "z": 1 - }, - "flowRate": 1.5, - "preWet": true, - "mix": { - "enable": true, - "repetitions": 3, - "volume": 100 - }, - "delay": { - "enable": true, - "duration": 1.0 - } - }, - "singleDispense": { - "submerge": { - "positionReference": "center", - "offset": { - "x": 0, - "y": 0, - "z": -1 - }, - "speed": 4.0, - "delay": { - "enable": true, - "duration": 2.0 - } - }, - "touchTip": { - "enable": true, - "zOffset": 2.0, - "mmToEdge": 0.2, - "speed": 1.5 - }, - "retract": { - "positionReference": "top", - "offset": { - "x": 0, - "y": 0, - "z": 1.5 - }, - "speed": 3.0, - "airGap": 2.0, - "blowout": { - "enable": true, - "location": "destination", - "flowRate": 3.5 - }, - "delay": { - "enable": true, - "duration": 1.5 - } - }, - "positionReference": "meniscus", - "offset": { - "x": 0, - "y": 0, - "z": 1 - }, - "flowRate": 2.0, - "mix": { - "enable": false, - "repetitions": 2, - "volume": 50 - }, - "delay": 0.5, - "pushOutVolume": 1.0 - }, - "multiDispense": { - "enable": true, - "submerge": { - "positionReference": "bottom", - "offset": { - "x": 0, - "y": 0, - "z": -0.5 - }, - "speed": 2.0, - "delay": { - "enable": true, - "duration": 0.8 - } - }, - "touchTip": { - "enable": false, - "zOffset": 0.5, - "mmToEdge": 0.1, - "speed": 3.0 - }, - "retract": { - "positionReference": "center", - "offset": { - "x": 0, - "y": 0, - "z": 1 - }, - "speed": 4.0, - "airGap": 3.0, - "blowout": { - "enable": true, - "location": "trash", - "flowRate": 1.5 - }, - "delay": { - "enable": true, - "duration": 0.5 - } - }, - "positionReference": "top", - "offset": { - "x": 0, - "y": 0, - "z": 0.5 - }, - "flowRate": 1.0, - "mix": { - "enable": true, - "repetitions": 5, - "volume": 60 - }, - "conditioningVolume": 10, - "disposalVolume": 5, - "delay": { - "enable": false, - "duration": 0.5 - } - } - }, - "t50": { - "aspirate": { - "submerge": { - "positionReference": "bottom", - "offset": { - "x": 0, - "y": 0, - "z": -2 - }, - "speed": 3.5, - "delay": { - "enable": true, - "duration": 1.5 - } - }, - "retract": { - "positionReference": "top", - "offset": { - "x": 0, - "y": 0, - "z": 2 - }, - "speed": 2.0, - "airGap": 5.0, - "blowout": { - "enable": true, - "location": "trash", - "flowRate": 2.5 - }, - "delay": { - "enable": false, - "duration": 0.5 - } - }, - "touchTip": { - "enable": true, - "zOffset": 1.5, - "mmToEdge": 0.5, - "speed": 2.0 - }, - "positionReference": "meniscus", - "offset": { - "x": 0, - "y": 0, - "z": 1 - }, - "flowRate": 1.5, - "preWet": true, - "mix": { - "enable": true, - "repetitions": 3, - "volume": 100 - }, - "delay": { - "enable": true, - "duration": 1.0 - } - }, - "singleDispense": { - "submerge": { - "positionReference": "center", - "offset": { - "x": 0, - "y": 0, - "z": -1 - }, - "speed": 4.0, - "delay": { - "enable": true, - "duration": 2.0 - } - }, - "touchTip": { - "enable": true, - "zOffset": 2.0, - "mmToEdge": 0.2, - "speed": 1.5 - }, - "retract": { - "positionReference": "top", - "offset": { - "x": 0, - "y": 0, - "z": 1.5 - }, - "speed": 3.0, - "airGap": 2.0, - "blowout": { - "enable": true, - "location": "destination", - "flowRate": 3.5 - }, - "delay": { - "enable": true, - "duration": 1.5 - } - }, - "positionReference": "meniscus", - "offset": { - "x": 0, - "y": 0, - "z": 1 - }, - "flowRate": 2.0, - "mix": { - "enable": false, - "repetitions": 2, - "volume": 50 - }, - "delay": 0.5, - "pushOutVolume": 2.0 - }, - "multiDispense": { - "enable": true, - "submerge": { - "positionReference": "bottom", - "offset": { - "x": 0, - "y": 0, - "z": -0.5 - }, - "speed": 2.0, - "delay": { - "enable": true, - "duration": 0.8 - } - }, - "touchTip": { - "enable": false, - "zOffset": 0.5, - "mmToEdge": 0.1, - "speed": 3.0 - }, - "retract": { - "positionReference": "center", - "offset": { - "x": 0, - "y": 0, - "z": 1 - }, - "speed": 4.0, - "airGap": 3.0, - "blowout": { - "enable": true, - "location": "trash", - "flowRate": 1.5 - }, - "delay": { - "enable": true, - "duration": 0.5 + "liquidName": "water", + "schemaVersion": 1, + "namespace": "custom", + "byPipette": [ + { + "pipetteModel": "p300_single", + "byTipType": [ + { + "tipType": "opentrons_300ul_tip", + "aspirate": { + "submerge": { + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "speed": 5, + "delay": { + "enable": true, + "duration": 2 + } + }, + "retract": { + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 10, + "airGap": 10, + "touchTip": { + "enable": true, + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 50 + }, + "delay": { + "enable": true, + "duration": 1 + } + }, + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "flowRate": 50, + "preWet": true, + "mix": { + "enable": true, + "repetitions": 3, + "volume": 50 + }, + "delay": { + "enable": true, + "duration": 0.5 + } + }, + "singleDispense": { + "submerge": { + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "speed": 5, + "delay": { + "enable": true, + "duration": 2 + } + }, + "retract": { + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 10, + "airGap": 10, + "blowout": { + "enable": true, + "location": "trash", + "flowRate": 30 + }, + "touchTip": { + "enable": true, + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 50 + }, + "delay": { + "enable": true, + "duration": 1 + } + }, + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "flowRate": 100, + "mix": { + "enable": false, + "repetitions": 0, + "volume": 0 + }, + "pushOutVolume": 5, + "delay": 0.5 + }, + "multiDispense": { + "enable": true, + "submerge": { + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "speed": 5, + "delay": { + "enable": true, + "duration": 2 + } + }, + "retract": { + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 10, + "airGap": 10, + "blowout": { + "enable": true, + "location": "trash", + "flowRate": 30 + }, + "touchTip": { + "enable": true, + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 50 + }, + "delay": { + "enable": true, + "duration": 1 + } + }, + "positionReference": "bottom", + "offset": { + "x": 0, + "y": 0, + "z": 1 + }, + "flowRate": 200, + "mix": { + "enable": false, + "repetitions": 0, + "volume": 0 + }, + "conditioningVolume": 50, + "disposalVolume": 10, + "delay": { + "enable": true, + "duration": 0.5 + } } - }, - "positionReference": "top", - "offset": { - "x": 0, - "y": 0, - "z": 0.5 - }, - "flowRate": 1.0, - "mix": { - "enable": true, - "repetitions": 5, - "volume": 60 - }, - "conditioningVolume": 10, - "disposalVolume": 5, - "delay": { - "enable": false, - "duration": 0.5 } - } + ] } - }, - "namespace": "custom", - "schemaVersion": 1 + ] } diff --git a/shared-data/liquid-class/schemas/1.json b/shared-data/liquid-class/schemas/1.json index f2221cb7fb8..303a190a5e8 100644 --- a/shared-data/liquid-class/schemas/1.json +++ b/shared-data/liquid-class/schemas/1.json @@ -26,7 +26,18 @@ "description": "Duration of delay, in seconds." } }, - "description": "Delay properties." + "description": "Delay properties.", + "if": { + "properties": { + "enable": { "const": true } + } + }, + "then": { + "required": ["enable", "duration"] + }, + "else": { + "required": ["enable"] + } }, "positionReference": { "type": "string", @@ -70,7 +81,17 @@ "description": "Touch-tip speed, in millimeters per second." } }, - "required": ["enable", "zOffset", "mmToEdge", "speed"] + "if": { + "properties": { + "enable": { "const": true } + } + }, + "then": { + "required": ["enable", "zOffset", "mmToEdge", "speed"] + }, + "else": { + "required": ["enable"] + } }, "mix": { "type": "object", @@ -90,7 +111,17 @@ "description": "Volume used for mixing, in microliters." } }, - "required": ["repetitions", "volume"] + "if": { + "properties": { + "enable": { "const": true } + } + }, + "then": { + "required": ["enable", "repetitions", "volume"] + }, + "else": { + "required": ["enable"] + } }, "blowout": { "type": "object", @@ -110,7 +141,17 @@ "description": "Flow rate for blow out, in microliters per second." } }, - "required": ["enable", "location", "flowRate"] + "if": { + "properties": { + "enable": { "const": true } + } + }, + "then": { + "required": ["enable", "location", "flowRate"] + }, + "else": { + "required": ["enable"] + } }, "submerge": { "type": "object", @@ -132,7 +173,35 @@ }, "required": ["positionReference", "offset", "speed", "delay"] }, - "retract": { + "retractAspirate": { + "type": "object", + "description": "Shared properties for the retract function after aspiration or dispense.", + "properties": { + "positionReference": { + "$ref": "#/definitions/positionReference" + }, + "offset": { + "$ref": "#/definitions/coordinate" + }, + "speed": { + "$ref": "#/definitions/positiveNumber", + "description": "Speed of retraction, in millimeters per second." + }, + "airGap": { + "$ref": "#/definitions/positiveNumber", + "description": "Air gap volume after retract, in microliters." + }, + "touchTip": { + "$ref": "#/definitions/touchTip" + }, + "delay": { + "$ref": "#/definitions/delay" + } + }, + "required": ["positionReference", "offset", "speed", "airGap", "delay"], + "additionalProperties": false + }, + "retractDispense": { "type": "object", "description": "Shared properties for the retract function after aspiration or dispense.", "properties": { @@ -153,6 +222,9 @@ "blowout": { "$ref": "#/definitions/blowout" }, + "touchTip": { + "$ref": "#/definitions/touchTip" + }, "delay": { "$ref": "#/definitions/delay" } @@ -164,7 +236,8 @@ "airGap", "blowout", "delay" - ] + ], + "additionalProperties": false }, "aspirateParams": { "type": "object", @@ -174,10 +247,7 @@ "$ref": "#/definitions/submerge" }, "retract": { - "$ref": "#/definitions/retract" - }, - "touchTip": { - "$ref": "#/definitions/touchTip" + "$ref": "#/definitions/retractAspirate" }, "positionReference": { "$ref": "#/definitions/positionReference" @@ -203,14 +273,14 @@ "required": [ "submerge", "retract", - "touchTip", "positionReference", "offset", "flowRate", "preWet", "mix", "delay" - ] + ], + "additionalProperties": false }, "singleDispenseParams": { "type": "object", @@ -219,11 +289,8 @@ "submerge": { "$ref": "#/definitions/submerge" }, - "touchTip": { - "$ref": "#/definitions/touchTip" - }, "retract": { - "$ref": "#/definitions/retract" + "$ref": "#/definitions/retractDispense" }, "positionReference": { "$ref": "#/definitions/positionReference" @@ -249,7 +316,6 @@ }, "required": [ "submerge", - "touchTip", "retract", "positionReference", "offset", @@ -257,7 +323,8 @@ "mix", "pushOutVolume", "delay" - ] + ], + "additionalProperties": false }, "multiDispenseParams": { "type": "object", @@ -270,11 +337,8 @@ "submerge": { "$ref": "#/definitions/submerge" }, - "touchTip": { - "$ref": "#/definitions/touchTip" - }, "retract": { - "$ref": "#/definitions/retract" + "$ref": "#/definitions/retractDispense" }, "positionReference": { "$ref": "#/definitions/positionReference" @@ -301,22 +365,32 @@ "$ref": "#/definitions/delay" } }, - "required": [ - "enable", - "submerge", - "touchTip", - "retract", - "positionReference", - "offset", - "flowRate", - "mix", - "conditioningVolume", - "disposalVolume", - "delay" - ] + "if": { + "properties": { + "enable": { "const": true } + } + }, + "then": { + "required": [ + "enable", + "submerge", + "retract", + "positionReference", + "offset", + "flowRate", + "mix", + "conditioningVolume", + "disposalVolume", + "delay" + ] + }, + "else": { + "required": ["enable"] + }, + "additionalProperties": false } }, - "required": ["liquidName", "schemaVersion", "namespace"], + "required": ["liquidName", "schemaVersion", "namespace", "byPipette"], "properties": { "liquidName": { "type": "string", @@ -329,32 +403,44 @@ }, "namespace": { "$ref": "#/definitions/safeString" - } - }, - "patternProperties": { - "^p[0-9]{2,4}": { - "type": "object", - "description": "Object containing liquid class properties specific to the pipette model", - "patternProperties": { - "^t[0-9]{2,4}$": { - "type": "object", - "description": "Object containing liquid class properties specific to the tip type", - "properties": { - "aspirate": { - "$ref": "#/definitions/aspirateParams" - }, - "singleDispense": { - "$ref": "#/definitions/singleDispenseParams" - }, - "multiDispense": { - "$ref": "#/definitions/multiDispenseParams" - } + }, + "byPipette": { + "type": "array", + "description": "Liquid class settings by each pipette compatible with this liquid class.", + "items": { + "type": "object", + "description": "The settings for a specific kind of pipette when interacting with this liquid class", + "properties": { + "pipetteModel": { + "type": "string", + "description": "The pipette model this applies to" }, - "required": ["aspirate", "singleDispense", "multiDispense"], - "additionalProperties": false - } - }, - "additionalProperties": false + "byTipType": { + "type": "array", + "description": "Settings for each kind of tip this pipette can use", + "items": { + "type": "object", + "properties": { + "tipType": { + "type": "string", + "description": "The tip type whose properties will be used when handling this specific liquid class with this pipette" + }, + "aspirate": { + "$ref": "#/definitions/aspirateParams" + }, + "singleDispense": { + "$ref": "#/definitions/singleDispenseParams" + }, + "multiDispense": { + "$ref": "#/definitions/multiDispenseParams" + } + }, + "required": ["aspirate", "singleDispense", "multiDispense"] + } + } + }, + "required": ["pipetteModel", "byTipType"] + } } }, "additionalProperties": false From e914bbc86c18cb81e500073b8ef10a89c2bf689f Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 17 Sep 2024 17:08:55 -0400 Subject: [PATCH 4/8] add tipType property as required --- shared-data/liquid-class/schemas/1.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/shared-data/liquid-class/schemas/1.json b/shared-data/liquid-class/schemas/1.json index 303a190a5e8..b06f912f9c6 100644 --- a/shared-data/liquid-class/schemas/1.json +++ b/shared-data/liquid-class/schemas/1.json @@ -435,7 +435,12 @@ "$ref": "#/definitions/multiDispenseParams" } }, - "required": ["aspirate", "singleDispense", "multiDispense"] + "required": [ + "tipType", + "aspirate", + "singleDispense", + "multiDispense" + ] } } }, From c3b4e92b9c3e88cc6c3da6b1db82f7214a718323 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 17 Sep 2024 17:36:32 -0400 Subject: [PATCH 5/8] fix liquidName in fixture --- shared-data/liquid-class/fixtures/fixture_glycerol50.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-data/liquid-class/fixtures/fixture_glycerol50.json b/shared-data/liquid-class/fixtures/fixture_glycerol50.json index 95f9ae889e2..c09e3b8b42d 100644 --- a/shared-data/liquid-class/fixtures/fixture_glycerol50.json +++ b/shared-data/liquid-class/fixtures/fixture_glycerol50.json @@ -1,5 +1,5 @@ { - "liquidName": "water", + "liquidName": "glycerol50", "schemaVersion": 1, "namespace": "custom", "byPipette": [ From 6a7263219f3db0c24f728b724663533b5e6c16b4 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 8 Oct 2024 12:31:48 -0400 Subject: [PATCH 6/8] separate behavior params from enable param, add byVolume maps --- .../fixtures/fixture_glycerol50.json | 243 ++++++++---- shared-data/liquid-class/schemas/1.json | 345 +++++++++++------- 2 files changed, 380 insertions(+), 208 deletions(-) diff --git a/shared-data/liquid-class/fixtures/fixture_glycerol50.json b/shared-data/liquid-class/fixtures/fixture_glycerol50.json index c09e3b8b42d..a1d341fd3cf 100644 --- a/shared-data/liquid-class/fixtures/fixture_glycerol50.json +++ b/shared-data/liquid-class/fixtures/fixture_glycerol50.json @@ -1,176 +1,279 @@ { - "liquidName": "glycerol50", + "liquidName": "glycerol", "schemaVersion": 1, - "namespace": "custom", + "namespace": "opentrons", "byPipette": [ { "pipetteModel": "p300_single", "byTipType": [ { - "tipType": "opentrons_300ul_tip", + "tipType": "standard", "aspirate": { "submerge": { - "positionReference": "bottom", + "positionReference": "meniscus", "offset": { "x": 0, "y": 0, - "z": 1 + "z": -5 }, - "speed": 5, + "speed": 100, "delay": { "enable": true, - "duration": 2 + "params": { + "duration": 2 + } } }, "retract": { - "positionReference": "bottom", + "positionReference": "top", "offset": { "x": 0, "y": 0, - "z": 2 + "z": 5 }, - "speed": 10, - "airGap": 10, + "speed": 150, + "airGapByVolume": [ + { + "volume": "100", + "airGap": 10 + }, + { + "volume": "200", + "airGap": 20 + } + ], "touchTip": { "enable": true, - "zOffset": -1, - "mmToEdge": 0.5, - "speed": 50 + "params": { + "zOffset": 1, + "mmToEdge": 2, + "speed": 100 + } }, "delay": { - "enable": true, - "duration": 1 + "enable": false } }, - "positionReference": "bottom", + "positionReference": "meniscus", "offset": { "x": 0, "y": 0, - "z": 1 + "z": -5 }, - "flowRate": 50, + "flowRateByVolume": [ + { + "volume": "100", + "flowRate": 50 + }, + { + "volume": "200", + "flowRate": 100 + } + ], "preWet": true, "mix": { "enable": true, - "repetitions": 3, - "volume": 50 + "params": { + "repetitions": 3, + "volume": 50 + } }, "delay": { - "enable": true, - "duration": 0.5 + "enable": false } }, "singleDispense": { "submerge": { - "positionReference": "bottom", + "positionReference": "meniscus", "offset": { "x": 0, "y": 0, - "z": 1 + "z": -5 }, - "speed": 5, + "speed": 100, "delay": { "enable": true, - "duration": 2 + "params": { + "duration": 2 + } } }, "retract": { - "positionReference": "bottom", + "positionReference": "top", "offset": { "x": 0, "y": 0, - "z": 2 + "z": 5 }, - "speed": 10, - "airGap": 10, + "speed": 150, + "airGapByVolume": [ + { + "volume": "100", + "airGap": 10 + }, + { + "volume": "200", + "airGap": 20 + } + ], "blowout": { "enable": true, - "location": "trash", - "flowRate": 30 + "params": { + "location": "trash", + "flowRate": 100 + } }, "touchTip": { "enable": true, - "zOffset": -1, - "mmToEdge": 0.5, - "speed": 50 + "params": { + "zOffset": 1, + "mmToEdge": 2, + "speed": 100 + } }, "delay": { "enable": true, - "duration": 1 + "params": { + "duration": 1 + } } }, - "positionReference": "bottom", + "positionReference": "meniscus", "offset": { "x": 0, "y": 0, - "z": 1 + "z": -5 }, - "flowRate": 100, + "flowRateByVolume": [ + { + "volume": "100", + "flowRate": 50 + }, + { + "volume": "200", + "flowRate": 100 + } + ], "mix": { - "enable": false, - "repetitions": 0, - "volume": 0 + "enable": true, + "params": { + "repetitions": 2, + "volume": 30 + } }, - "pushOutVolume": 5, - "delay": 0.5 + "pushOutByVolume": [ + { + "volume": "100", + "pushOut": 5 + }, + { + "volume": "200", + "pushOut": 10 + } + ], + "delay": 2 }, "multiDispense": { - "enable": true, "submerge": { - "positionReference": "bottom", + "positionReference": "meniscus", "offset": { "x": 0, "y": 0, - "z": 1 + "z": -5 }, - "speed": 5, + "speed": 100, "delay": { "enable": true, - "duration": 2 + "params": { + "duration": 2 + } } }, "retract": { - "positionReference": "bottom", + "positionReference": "top", "offset": { "x": 0, "y": 0, - "z": 2 + "z": 5 }, - "speed": 10, - "airGap": 10, + "speed": 150, + "airGapByVolume": [ + { + "volume": "100", + "airGap": 10 + }, + { + "volume": "200", + "airGap": 20 + } + ], "blowout": { "enable": true, - "location": "trash", - "flowRate": 30 + "params": { + "location": "trash", + "flowRate": 100 + } }, "touchTip": { "enable": true, - "zOffset": -1, - "mmToEdge": 0.5, - "speed": 50 + "params": { + "zOffset": 1, + "mmToEdge": 2, + "speed": 100 + } }, "delay": { - "enable": true, - "duration": 1 + "enable": false } }, - "positionReference": "bottom", + "positionReference": "meniscus", "offset": { "x": 0, "y": 0, - "z": 1 + "z": -5 }, - "flowRate": 200, + "flowRateByVolume": [ + { + "volume": "100", + "flowRate": 50 + }, + { + "volume": "200", + "flowRate": 100 + } + ], "mix": { - "enable": false, - "repetitions": 0, - "volume": 0 + "enable": true, + "params": { + "repetitions": 2, + "volume": 30 + } }, - "conditioningVolume": 50, - "disposalVolume": 10, + "conditioningByVolume": [ + { + "volume": "100", + "conditioning": 5 + }, + { + "volume": "200", + "conditioning": 10 + } + ], + "disposalByVolume": [ + { + "volume": "100", + "disposal": 5 + }, + { + "volume": "200", + "disposal": 10 + } + ], "delay": { "enable": true, - "duration": 0.5 + "params": { + "duration": 1 + } } } } diff --git a/shared-data/liquid-class/schemas/1.json b/shared-data/liquid-class/schemas/1.json index b06f912f9c6..4e134e4da50 100644 --- a/shared-data/liquid-class/schemas/1.json +++ b/shared-data/liquid-class/schemas/1.json @@ -21,23 +21,20 @@ "type": "boolean", "description": "Whether delay is enabled." }, - "duration": { - "#ref": "#/definitions/positiveNumber", - "description": "Duration of delay, in seconds." - } - }, - "description": "Delay properties.", - "if": { - "properties": { - "enable": { "const": true } + "params": { + "type": "object", + "properties": { + "duration": { + "#ref": "#/definitions/positiveNumber", + "description": "Duration of delay, in seconds." + } + }, + "required": ["duration"], + "additionalProperties": false } }, - "then": { - "required": ["enable", "duration"] - }, - "else": { - "required": ["enable"] - } + "required": ["enable"], + "additionalProperties": false }, "positionReference": { "type": "string", @@ -58,7 +55,8 @@ "type": "number" } }, - "required": ["x", "y", "z"] + "required": ["x", "y", "z"], + "additionalProperties": false }, "touchTip": { "type": "object", @@ -68,31 +66,125 @@ "type": "boolean", "description": "Whether touch-tip is enabled." }, - "zOffset": { - "type": "number", - "description": "Offset from the top of the well for touch-tip, in millimeters." - }, - "mmToEdge": { - "type": "number", - "description": "Offset away from the the well edge, in millimeters." - }, - "speed": { - "$ref": "#/definitions/positiveNumber", - "description": "Touch-tip speed, in millimeters per second." + "params": { + "type": "object", + "properties": { + "zOffset": { + "type": "number", + "description": "Offset from the top of the well for touch-tip, in millimeters." + }, + "mmToEdge": { + "type": "number", + "description": "Offset away from the the well edge, in millimeters." + }, + "speed": { + "$ref": "#/definitions/positiveNumber", + "description": "Touch-tip speed, in millimeters per second." + } + }, + "required": ["zOffset", "mmToEdge", "speed"], + "additionalProperties": false } }, - "if": { + "required": ["enable"], + "additionalProperties": false + }, + "airGapByVolume": { + "type": "array", + "description": "Settings for air gap keyed by target aspiration volume.", + "items": { + "type": "object", "properties": { - "enable": { "const": true } - } - }, - "then": { - "required": ["enable", "zOffset", "mmToEdge", "speed"] - }, - "else": { - "required": ["enable"] + "volume": { + "type": "string", + "description": "Transfer volume for which to use the given airgap volume, in microliters." + }, + "airGap": { + "$ref": "#/definitions/positiveNumber", + "description": "Airgap volume after retract for the specified volume, in microliters." + } + }, + "required": ["volume", "airGap"], + "additionalProperties": false } }, + "flowRateByVolume": { + "type": "array", + "description": "Settings for flow rate keyed by target aspiration/dispense volume.", + "items": { + "type": "object", + "properties": { + "volume": { + "type": "string", + "description": "The volume whose flow rate will be used" + }, + "flowRate": { + "$ref": "#/definitions/positiveNumber", + "description": "Flow rate, in microliters per second." + } + }, + "required": ["volume", "flowRate"], + "additionalProperties": false + } + }, + "pushOutByVolume": { + "type": "array", + "description": "Settings for pushout keyed by target aspiration volume.", + "items": { + "type": "object", + "properties": { + "volume": { + "type": "string", + "description": "The volume whose pushout will be used" + }, + "pushOut": { + "$ref": "#/definitions/positiveNumber", + "description": "Pushout volume, in microliters." + } + }, + "required": ["volume", "pushOut"], + "additionalProperties": false + } + }, + "disposalByVolume": { + "type": "array", + "description": "Settings for disposal volume keyed by target dispense volume.", + "items": { + "type": "object", + "properties": { + "volume": { + "type": "string", + "description": "The volume whose disposal volume will be used" + }, + "disposal": { + "$ref": "#/definitions/positiveNumber", + "description": "Disposal volume, in microliters." + } + }, + "required": ["volume", "disposal"], + "additionalProperties": false + } + }, + "conditioningByVolume": { + "type": "array", + "description": "Settings for conditioning volume keyed by target dispense volume.", + "items": { + "type": "object", + "properties": { + "volume": { + "type": "string", + "description": "The volume whose conditioning volume will be used" + }, + "conditioning": { + "$ref": "#/definitions/positiveNumber", + "description": "Conditioning volume, in microliters." + } + }, + "required": ["volume", "conditioning"], + "additionalProperties": false + }, + "additionalProperties": false + }, "mix": { "type": "object", "description": "Mixing properties.", @@ -101,27 +193,25 @@ "type": "boolean", "description": "Whether mix is enabled." }, - "repetitions": { - "type": "integer", - "description": "Number of mixing repetitions.", - "minimum": 0 - }, - "volume": { - "$ref": "#/definitions/positiveNumber", - "description": "Volume used for mixing, in microliters." - } - }, - "if": { - "properties": { - "enable": { "const": true } + "params": { + "type": "object", + "properties": { + "repetitions": { + "type": "integer", + "description": "Number of mixing repetitions.", + "minimum": 0 + }, + "volume": { + "$ref": "#/definitions/positiveNumber", + "description": "Volume used for mixing, in microliters." + } + }, + "required": ["repetitions", "volume"], + "additionalProperties": false } }, - "then": { - "required": ["enable", "repetitions", "volume"] - }, - "else": { - "required": ["enable"] - } + "required": ["enable"], + "additionalProperties": false }, "blowout": { "type": "object", @@ -131,27 +221,24 @@ "type": "boolean", "description": "Whether blow-out is enabled." }, - "location": { - "type": "string", - "enum": ["source", "destination", "trash"], - "description": "Location well or trash entity for blow out." - }, - "flowRate": { - "$ref": "#/definitions/positiveNumber", - "description": "Flow rate for blow out, in microliters per second." - } - }, - "if": { - "properties": { - "enable": { "const": true } + "params": { + "type": "object", + "properties": { + "location": { + "type": "string", + "enum": ["source", "destination", "trash"], + "description": "Location well or trash entity for blow out." + }, + "flowRate": { + "$ref": "#/definitions/positiveNumber", + "description": "Flow rate for blow out, in microliters per second." + } + }, + "required": ["location", "flowRate"] } }, - "then": { - "required": ["enable", "location", "flowRate"] - }, - "else": { - "required": ["enable"] - } + "required": ["enable"], + "additionalProperties": false }, "submerge": { "type": "object", @@ -171,7 +258,8 @@ "$ref": "#/definitions/delay" } }, - "required": ["positionReference", "offset", "speed", "delay"] + "required": ["positionReference", "offset", "speed", "delay"], + "additionalProperties": false }, "retractAspirate": { "type": "object", @@ -187,9 +275,8 @@ "$ref": "#/definitions/positiveNumber", "description": "Speed of retraction, in millimeters per second." }, - "airGap": { - "$ref": "#/definitions/positiveNumber", - "description": "Air gap volume after retract, in microliters." + "airGapByVolume": { + "$ref": "#/definitions/airGapByVolume" }, "touchTip": { "$ref": "#/definitions/touchTip" @@ -198,7 +285,13 @@ "$ref": "#/definitions/delay" } }, - "required": ["positionReference", "offset", "speed", "airGap", "delay"], + "required": [ + "positionReference", + "offset", + "speed", + "airGapByVolume", + "delay" + ], "additionalProperties": false }, "retractDispense": { @@ -215,9 +308,8 @@ "$ref": "#/definitions/positiveNumber", "description": "Speed of retraction, in millimeters per second." }, - "airGap": { - "$ref": "#/definitions/positiveNumber", - "description": "Air gap volume after retract, in microliters." + "airGapByVolume": { + "$ref": "#/definitions/airGapByVolume" }, "blowout": { "$ref": "#/definitions/blowout" @@ -233,8 +325,9 @@ "positionReference", "offset", "speed", - "airGap", + "airGapByVolume", "blowout", + "touchTip", "delay" ], "additionalProperties": false @@ -255,9 +348,8 @@ "offset": { "$ref": "#/definitions/coordinate" }, - "flowRate": { - "$ref": "#/definitions/positiveNumber", - "description": "Flow rate for aspirating, in microliters per second." + "flowRateByVolume": { + "$ref": "#/definitions/flowRateByVolume" }, "preWet": { "type": "boolean", @@ -275,7 +367,7 @@ "retract", "positionReference", "offset", - "flowRate", + "flowRateByVolume", "preWet", "mix", "delay" @@ -298,16 +390,14 @@ "offset": { "$ref": "#/definitions/coordinate" }, - "flowRate": { - "$ref": "#/definitions/positiveNumber", - "description": "Flow rate for dispense, in microliters per second." + "flowRateByVolume": { + "$ref": "#/definitions/flowRateByVolume" }, "mix": { "$ref": "#/definitions/mix" }, - "pushOutVolume": { - "$ref": "#/definitions/positiveNumber", - "description": "Push out volume at dispense, in microliters." + "pushOutByVolume": { + "$ref": "#/definitions/pushOutByVolume" }, "delay": { "$ref": "#/definitions/positiveNumber", @@ -319,9 +409,9 @@ "retract", "positionReference", "offset", - "flowRate", + "flowRateByVolume", "mix", - "pushOutVolume", + "pushOutByVolume", "delay" ], "additionalProperties": false @@ -330,10 +420,6 @@ "type": "object", "description": "Parameters specific to the multi-dispense function.", "properties": { - "enable": { - "type": "boolean", - "description": "Whether multi-dispense is enabled." - }, "submerge": { "$ref": "#/definitions/submerge" }, @@ -346,51 +432,36 @@ "offset": { "$ref": "#/definitions/coordinate" }, - "flowRate": { - "$ref": "#/definitions/positiveNumber", - "description": "Flow rate for dispensing, in microliters per second." + "flowRateByVolume": { + "$ref": "#/definitions/flowRateByVolume" }, "mix": { "$ref": "#/definitions/mix" }, - "conditioningVolume": { - "$ref": "#/definitions/positiveNumber", - "description": "Volume used for conditioning during dispense, in microliters." + "conditioningByVolume": { + "$ref": "#/definitions/conditioningByVolume" }, - "disposalVolume": { - "$ref": "#/definitions/positiveNumber", - "description": "Volume discarded during dispense, in microliters." + "disposalByVolume": { + "$ref": "#/definitions/disposalByVolume" }, "delay": { "$ref": "#/definitions/delay" } }, - "if": { - "properties": { - "enable": { "const": true } - } - }, - "then": { - "required": [ - "enable", - "submerge", - "retract", - "positionReference", - "offset", - "flowRate", - "mix", - "conditioningVolume", - "disposalVolume", - "delay" - ] - }, - "else": { - "required": ["enable"] - }, + "required": [ + "submerge", + "retract", + "positionReference", + "offset", + "flowRateByVolume", + "mix", + "conditioningByVolume", + "disposalByVolume", + "delay" + ], "additionalProperties": false } }, - "required": ["liquidName", "schemaVersion", "namespace", "byPipette"], "properties": { "liquidName": { "type": "string", @@ -435,18 +506,16 @@ "$ref": "#/definitions/multiDispenseParams" } }, - "required": [ - "tipType", - "aspirate", - "singleDispense", - "multiDispense" - ] + "required": ["tipType", "aspirate", "singleDispense"], + "additionalProperties": false } } }, - "required": ["pipetteModel", "byTipType"] + "required": ["pipetteModel", "byTipType"], + "additionalProperties": false } } }, + "required": ["liquidName", "schemaVersion", "namespace", "byPipette"], "additionalProperties": false } From 392099ddc8d6d6c32c9e5335bde485ee1e3c753d Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 8 Oct 2024 14:25:28 -0400 Subject: [PATCH 7/8] refine byVolume properties from arrays to volume-keyed objects --- .../fixtures/fixture_glycerol50.json | 206 +++++++----------- shared-data/liquid-class/schemas/1.json | 119 ++++------ 2 files changed, 121 insertions(+), 204 deletions(-) diff --git a/shared-data/liquid-class/fixtures/fixture_glycerol50.json b/shared-data/liquid-class/fixtures/fixture_glycerol50.json index a1d341fd3cf..b5bc9225dfc 100644 --- a/shared-data/liquid-class/fixtures/fixture_glycerol50.json +++ b/shared-data/liquid-class/fixtures/fixture_glycerol50.json @@ -1,13 +1,13 @@ { - "liquidName": "glycerol", + "liquidName": "Glycerol 50%", "schemaVersion": 1, "namespace": "opentrons", "byPipette": [ { - "pipetteModel": "p300_single", + "pipetteModel": "p20_single_gen2", "byTipType": [ { - "tipType": "standard", + "tipType": "p20_tip", "aspirate": { "submerge": { "positionReference": "meniscus", @@ -20,7 +20,7 @@ "delay": { "enable": true, "params": { - "duration": 2 + "duration": 1.5 } } }, @@ -31,55 +31,51 @@ "y": 0, "z": 5 }, - "speed": 150, - "airGapByVolume": [ - { - "volume": "100", - "airGap": 10 - }, - { - "volume": "200", - "airGap": 20 - } - ], + "speed": 100, + "airGapByVolume": { + "default": 2, + "5": 3, + "10": 4 + }, "touchTip": { "enable": true, "params": { - "zOffset": 1, - "mmToEdge": 2, - "speed": 100 + "zOffset": 2, + "mmToEdge": 1, + "speed": 50 } }, "delay": { - "enable": false + "enable": true, + "params": { + "duration": 1 + } } }, - "positionReference": "meniscus", + "positionReference": "bottom", "offset": { "x": 0, "y": 0, "z": -5 }, - "flowRateByVolume": [ - { - "volume": "100", - "flowRate": 50 - }, - { - "volume": "200", - "flowRate": 100 - } - ], + "flowRateByVolume": { + "default": 50, + "10": 40, + "20": 30 + }, "preWet": true, "mix": { "enable": true, "params": { "repetitions": 3, - "volume": 50 + "volume": 15 } }, "delay": { - "enable": false + "enable": true, + "params": { + "duration": 2 + } } }, "singleDispense": { @@ -94,7 +90,7 @@ "delay": { "enable": true, "params": { - "duration": 2 + "duration": 1.5 } } }, @@ -105,17 +101,12 @@ "y": 0, "z": 5 }, - "speed": 150, - "airGapByVolume": [ - { - "volume": "100", - "airGap": 10 - }, - { - "volume": "200", - "airGap": 20 - } - ], + "speed": 100, + "airGapByVolume": { + "default": 2, + "5": 3, + "10": 4 + }, "blowout": { "enable": true, "params": { @@ -126,9 +117,9 @@ "touchTip": { "enable": true, "params": { - "zOffset": 1, - "mmToEdge": 2, - "speed": 100 + "zOffset": 2, + "mmToEdge": 1, + "speed": 50 } }, "delay": { @@ -138,40 +129,30 @@ } } }, - "positionReference": "meniscus", + "positionReference": "bottom", "offset": { "x": 0, "y": 0, "z": -5 }, - "flowRateByVolume": [ - { - "volume": "100", - "flowRate": 50 - }, - { - "volume": "200", - "flowRate": 100 - } - ], + "flowRateByVolume": { + "default": 50, + "10": 40, + "20": 30 + }, "mix": { "enable": true, "params": { - "repetitions": 2, - "volume": 30 + "repetitions": 3, + "volume": 15 } }, - "pushOutByVolume": [ - { - "volume": "100", - "pushOut": 5 - }, - { - "volume": "200", - "pushOut": 10 - } - ], - "delay": 2 + "pushOutByVolume": { + "default": 5, + "10": 7, + "20": 10 + }, + "delay": 1 }, "multiDispense": { "submerge": { @@ -185,7 +166,7 @@ "delay": { "enable": true, "params": { - "duration": 2 + "duration": 1.5 } } }, @@ -196,79 +177,56 @@ "y": 0, "z": 5 }, - "speed": 150, - "airGapByVolume": [ - { - "volume": "100", - "airGap": 10 - }, - { - "volume": "200", - "airGap": 20 - } - ], - "blowout": { + "speed": 100, + "airGapByVolume": { + "default": 2, + "5": 3, + "10": 4 + }, + "touchTip": { "enable": true, "params": { - "location": "trash", - "flowRate": 100 + "zOffset": 2, + "mmToEdge": 1, + "speed": 50 } }, - "touchTip": { + "delay": { "enable": true, "params": { - "zOffset": 1, - "mmToEdge": 2, - "speed": 100 + "duration": 1 } }, - "delay": { + "blowout": { "enable": false } }, - "positionReference": "meniscus", + "positionReference": "bottom", "offset": { "x": 0, "y": 0, "z": -5 }, - "flowRateByVolume": [ - { - "volume": "100", - "flowRate": 50 - }, - { - "volume": "200", - "flowRate": 100 - } - ], + "flowRateByVolume": { + "default": 50, + "10": 40, + "20": 30 + }, "mix": { "enable": true, "params": { - "repetitions": 2, - "volume": 30 + "repetitions": 3, + "volume": 15 } }, - "conditioningByVolume": [ - { - "volume": "100", - "conditioning": 5 - }, - { - "volume": "200", - "conditioning": 10 - } - ], - "disposalByVolume": [ - { - "volume": "100", - "disposal": 5 - }, - { - "volume": "200", - "disposal": 10 - } - ], + "conditioningByVolume": { + "default": 10, + "5": 5 + }, + "disposalByVolume": { + "default": 2, + "5": 3 + }, "delay": { "enable": true, "params": { diff --git a/shared-data/liquid-class/schemas/1.json b/shared-data/liquid-class/schemas/1.json index 4e134e4da50..4df3d5ff138 100644 --- a/shared-data/liquid-class/schemas/1.json +++ b/shared-data/liquid-class/schemas/1.json @@ -90,100 +90,59 @@ "additionalProperties": false }, "airGapByVolume": { - "type": "array", + "type": "object", "description": "Settings for air gap keyed by target aspiration volume.", - "items": { - "type": "object", - "properties": { - "volume": { - "type": "string", - "description": "Transfer volume for which to use the given airgap volume, in microliters." - }, - "airGap": { - "$ref": "#/definitions/positiveNumber", - "description": "Airgap volume after retract for the specified volume, in microliters." - } - }, - "required": ["volume", "airGap"], - "additionalProperties": false - } + "properties": { + "default": { "$ref": "#/definitions/positiveNumber" } + }, + "patternProperties": { + "d+": { "$ref": "#/definitions/positiveNumber" } + }, + "required": ["default"] }, "flowRateByVolume": { - "type": "array", + "type": "object", "description": "Settings for flow rate keyed by target aspiration/dispense volume.", - "items": { - "type": "object", - "properties": { - "volume": { - "type": "string", - "description": "The volume whose flow rate will be used" - }, - "flowRate": { - "$ref": "#/definitions/positiveNumber", - "description": "Flow rate, in microliters per second." - } - }, - "required": ["volume", "flowRate"], - "additionalProperties": false - } + "properties": { + "default": { "$ref": "#/definitions/positiveNumber" } + }, + "patternProperties": { + "d+": { "$ref": "#/definitions/positiveNumber" } + }, + "required": ["default"] }, "pushOutByVolume": { - "type": "array", + "type": "object", "description": "Settings for pushout keyed by target aspiration volume.", - "items": { - "type": "object", - "properties": { - "volume": { - "type": "string", - "description": "The volume whose pushout will be used" - }, - "pushOut": { - "$ref": "#/definitions/positiveNumber", - "description": "Pushout volume, in microliters." - } - }, - "required": ["volume", "pushOut"], - "additionalProperties": false - } + "properties": { + "default": { "$ref": "#/definitions/positiveNumber" } + }, + "patternProperties": { + "d+": { "$ref": "#/definitions/positiveNumber" } + }, + "required": ["default"] }, "disposalByVolume": { - "type": "array", + "type": "object", "description": "Settings for disposal volume keyed by target dispense volume.", - "items": { - "type": "object", - "properties": { - "volume": { - "type": "string", - "description": "The volume whose disposal volume will be used" - }, - "disposal": { - "$ref": "#/definitions/positiveNumber", - "description": "Disposal volume, in microliters." - } - }, - "required": ["volume", "disposal"], - "additionalProperties": false - } + "properties": { + "default": { "$ref": "#/definitions/positiveNumber" } + }, + "patternProperties": { + "d+": { "$ref": "#/definitions/positiveNumber" } + }, + "required": ["default"] }, "conditioningByVolume": { - "type": "array", + "type": "object", "description": "Settings for conditioning volume keyed by target dispense volume.", - "items": { - "type": "object", - "properties": { - "volume": { - "type": "string", - "description": "The volume whose conditioning volume will be used" - }, - "conditioning": { - "$ref": "#/definitions/positiveNumber", - "description": "Conditioning volume, in microliters." - } - }, - "required": ["volume", "conditioning"], - "additionalProperties": false + "properties": { + "default": { "$ref": "#/definitions/positiveNumber" } }, - "additionalProperties": false + "patternProperties": { + "d+": { "$ref": "#/definitions/positiveNumber" } + }, + "required": ["default"] }, "mix": { "type": "object", From 404f9b6ca7c349504230bc0ce25b47d22ff7cd90 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 8 Oct 2024 14:38:37 -0400 Subject: [PATCH 8/8] fix nits --- .../fixtures/fixture_glycerol50.json | 18 +++++++++--------- shared-data/liquid-class/schemas/1.json | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/shared-data/liquid-class/fixtures/fixture_glycerol50.json b/shared-data/liquid-class/fixtures/fixture_glycerol50.json index b5bc9225dfc..fd655c66a61 100644 --- a/shared-data/liquid-class/fixtures/fixture_glycerol50.json +++ b/shared-data/liquid-class/fixtures/fixture_glycerol50.json @@ -10,7 +10,7 @@ "tipType": "p20_tip", "aspirate": { "submerge": { - "positionReference": "meniscus", + "positionReference": "liquid-meniscus", "offset": { "x": 0, "y": 0, @@ -25,7 +25,7 @@ } }, "retract": { - "positionReference": "top", + "positionReference": "well-top", "offset": { "x": 0, "y": 0, @@ -52,7 +52,7 @@ } } }, - "positionReference": "bottom", + "positionReference": "well-bottom", "offset": { "x": 0, "y": 0, @@ -80,7 +80,7 @@ }, "singleDispense": { "submerge": { - "positionReference": "meniscus", + "positionReference": "liquid-meniscus", "offset": { "x": 0, "y": 0, @@ -95,7 +95,7 @@ } }, "retract": { - "positionReference": "top", + "positionReference": "well-top", "offset": { "x": 0, "y": 0, @@ -129,7 +129,7 @@ } } }, - "positionReference": "bottom", + "positionReference": "well-bottom", "offset": { "x": 0, "y": 0, @@ -156,7 +156,7 @@ }, "multiDispense": { "submerge": { - "positionReference": "meniscus", + "positionReference": "liquid-meniscus", "offset": { "x": 0, "y": 0, @@ -171,7 +171,7 @@ } }, "retract": { - "positionReference": "top", + "positionReference": "well-top", "offset": { "x": 0, "y": 0, @@ -201,7 +201,7 @@ "enable": false } }, - "positionReference": "bottom", + "positionReference": "well-bottom", "offset": { "x": 0, "y": 0, diff --git a/shared-data/liquid-class/schemas/1.json b/shared-data/liquid-class/schemas/1.json index 4df3d5ff138..6af0ff9babe 100644 --- a/shared-data/liquid-class/schemas/1.json +++ b/shared-data/liquid-class/schemas/1.json @@ -10,7 +10,7 @@ "minimum": 0 }, "safeString": { - "description": "a string safe to use for namespace. Lowercase-only.", + "description": "A string safe to use for namespace. Lowercase-only.", "type": "string", "pattern": "^[a-z0-9._]+$" }, @@ -38,8 +38,8 @@ }, "positionReference": { "type": "string", - "description": "Reference point for positioning (e.g., bottom, top, liquid surface).", - "enum": ["bottom", "top", "center", "meniscus"] + "description": "Reference point for positioning.", + "enum": ["well-bottom", "well-top", "well-center", "liquid-meniscus"] }, "coordinate": { "type": "object",