Skip to content

Commit eb16cee

Browse files
authored
feat: Cytiva Biacore Insight - initial implementation (#1066)
1 parent d96eb9a commit eb16cee

21 files changed

Lines changed: 39702 additions & 55 deletions

File tree

SUPPORTED_INSTRUMENT_SOFTWARE.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ The parsers follow maturation levels of: Recommended, Candidate Release, Working
1515
[cols="4*^.^"]
1616
|===
1717
|Instrument Category|Instrument Software|Release Status|Exported ASM Schema
18-
.1+|Binding Affinity Analyzer|Cytiva Biacore T200 Control|Recommended|WD/2024/12
18+
.2+|Binding Affinity Analyzer|Cytiva Biacore Insight|Recommended|WD/2024/12
19+
|Cytiva Biacore T200 Control|Recommended|WD/2024/12
1920
.6+|Cell Counting|Beckman Coulter Vi-Cell BLU|Recommended|REC/2024/09
2021
|Beckman Coulter Vi-Cell XR|Recommended|REC/2024/09
2122
|ChemoMetec NC View|Recommended|REC/2024/09

src/allotropy/allotrope/models/adm/binding_affinity_analyzer/wd/_2024/_12/binding_affinity_analyzer.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# generated by datamodel-codegen:
22
# filename: binding-affinity-analyzer.schema.json
3-
# timestamp: 2025-02-26T19:19:58+00:00
3+
# timestamp: 2025-08-29T17:23:20+00:00
44

55
from __future__ import annotations
66

@@ -14,10 +14,10 @@
1414
TQuantityValueMolar,
1515
TQuantityValueNanomolar,
1616
TQuantityValuePercent,
17+
TQuantityValuePerMolarPerSecond,
1718
TQuantityValuePerSecond,
1819
TQuantityValueResonanceUnits,
1920
TQuantityValueSecondTime,
20-
TQuantityValueTODO,
2121
)
2222
from allotropy.allotrope.models.shared.definitions.definitions import (
2323
TBooleanValue,
@@ -268,10 +268,12 @@ class ProcessedDataDocumentItem:
268268
field_index: int | None = None
269269
POSIX_path: TStringValue | None = None
270270
identifier: TStringValue | None = None
271-
binding_on_rate_measurement_datum__kon_: TQuantityValueTODO | None = None
271+
binding_on_rate_measurement_datum__kon_: TQuantityValuePerMolarPerSecond | None = (
272+
None
273+
)
272274
binding_off_rate_measurement_datum__koff_: TQuantityValuePerSecond | None = None
273275
equilibrium_dissociation_constant__KD_: TQuantityValueMolar | None = None
274-
maximum_binding_capacity__Rmax_: TQuantityValueTODO | None = None
276+
maximum_binding_capacity__Rmax_: TQuantityValueResonanceUnits | None = None
275277
report_point_aggregate_document: ReportPointAggregateDocument | None = None
276278

277279

src/allotropy/allotrope/models/shared/definitions/custom.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
SeimensPerMeter,
7272
SquareCentimetersPerGram,
7373
SquareCentimetersPerMole,
74+
SquareResonanceUnits,
7475
TODO,
7576
Unitless,
7677
UnitPerLiter,
@@ -807,6 +808,18 @@ class TNullableQuantityValueSquareCentimetersPerMole(
807808
pass
808809

809810

811+
@dataclass(frozen=True, kw_only=True)
812+
class TQuantityValueSquareResonanceUnits(SquareResonanceUnits, TQuantityValue):
813+
pass
814+
815+
816+
@dataclass(frozen=True, kw_only=True)
817+
class TNullableQuantityValueSquareResonanceUnits(
818+
SquareResonanceUnits, TNullableQuantityValue
819+
):
820+
pass
821+
822+
810823
@dataclass(frozen=True, kw_only=True)
811824
class TQuantityValueTODO(TODO, TQuantityValue):
812825
pass

src/allotropy/allotrope/models/shared/definitions/units.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,11 @@ class SquareCentimetersPerMole(HasUnit):
334334
unit: str = "cm^2/mol"
335335

336336

337+
@dataclass(frozen=True, kw_only=True)
338+
class SquareResonanceUnits(HasUnit):
339+
unit: str = "RU^2"
340+
341+
337342
@dataclass(frozen=True, kw_only=True)
338343
class TODO(HasUnit):
339344
unit: str = "TODO"

src/allotropy/allotrope/schema_mappers/adm/binding_affinity_analyzer/benchling/_2024/_12/binding_affinity_analyzer.py

Lines changed: 99 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@
2828
from allotropy.allotrope.models.shared.definitions.custom import (
2929
TQuantityValueDegreeCelsius,
3030
TQuantityValueMicroliterPerMinute,
31+
TQuantityValueMolar,
3132
TQuantityValueNanomolar,
3233
TQuantityValuePercent,
34+
TQuantityValuePerMolarPerSecond,
35+
TQuantityValuePerSecond,
3336
TQuantityValueResonanceUnits,
3437
TQuantityValueSecondTime,
3538
)
@@ -41,7 +44,7 @@
4144
from allotropy.parsers.utils.calculated_data_documents.definition import (
4245
CalculatedDocument,
4346
)
44-
from allotropy.parsers.utils.values import assert_not_none, quantity_or_none
47+
from allotropy.parsers.utils.values import assert_not_none, has_value, quantity_or_none
4548
from allotropy.types import DictType
4649

4750

@@ -87,33 +90,49 @@ class ReportPoint:
8790
custom_info: DictType | None = None
8891

8992

93+
@dataclass(frozen=True)
94+
class DeviceControlDocument:
95+
device_type: str
96+
flow_cell_identifier: str | None = None
97+
flow_path: str | None = None
98+
flow_rate: float | None = None
99+
contact_time: float | None = None
100+
dilution: float | None = None
101+
sample_temperature_setting: float | None = None
102+
device_control_custom_info: DictType | None = None
103+
104+
90105
@dataclass(frozen=True)
91106
class Measurement:
92107
identifier: str
93108
sample_identifier: str
94-
device_type: str
95109
type_: MeasurementType
110+
device_control_document: list[DeviceControlDocument]
96111
location_identifier: str | None = None
97112
batch_identifier: str | None = None
98113
well_plate_identifier: str | None = None
99114
sample_role_type: str | None = None
100115
concentration: float | None = None
101116
method_name: str | None = None
102117
ligand_identifier: str | None = None
103-
flow_cell_identifier: str | None = None
104-
flow_path: str | None = None
105-
flow_rate: float | None = None
106-
contact_time: float | None = None
107-
dilution: float | None = None
108-
device_control_custom_info: DictType | None = None
109118
sample_custom_info: DictType | None = None
110119

111120
# Sensorgram
112121
sensorgram_data_cube: DataCube | None = None
113122

123+
# Processed Data
124+
binding_on_rate_measurement_datum__kon_: float | None = None
125+
binding_off_rate_measurement_datum__koff_: float | None = None
126+
equilibrium_dissociation_constant__kd_: float | None = None
127+
maximum_binding_capacity__rmax_: float | None = None
128+
processed_data_custom_info: DictType | None = None
129+
114130
# Report point
115131
report_point_data: list[ReportPoint] | None = None
116132

133+
# Data processing
134+
data_processing_document: DictType | None = None
135+
117136

118137
@dataclass(frozen=True)
119138
class MeasurementGroup:
@@ -153,6 +172,7 @@ def map_model(self, data: Data) -> Model:
153172
model_number=data.metadata.model_number,
154173
brand_name=data.metadata.brand_name,
155174
product_manufacturer=data.metadata.product_manufacturer,
175+
equipment_serial_number=data.metadata.equipment_serial_number,
156176
device_document=(
157177
[
158178
DeviceDocumentItem(
@@ -213,6 +233,60 @@ def _get_measurement_document_item(
213233
def _get_surface_plasmon_resonance_measurement_document(
214234
self, measurement: Measurement, metadata: Metadata
215235
) -> MeasurementDocument:
236+
processed_data_document = ProcessedDataDocumentItem(
237+
data_processing_document=(
238+
{
239+
key: value
240+
for key, value in measurement.data_processing_document.items()
241+
if value is not None
242+
}
243+
if measurement.data_processing_document
244+
else None
245+
),
246+
binding_on_rate_measurement_datum__kon_=quantity_or_none(
247+
TQuantityValuePerMolarPerSecond,
248+
measurement.binding_on_rate_measurement_datum__kon_,
249+
),
250+
binding_off_rate_measurement_datum__koff_=quantity_or_none(
251+
TQuantityValuePerSecond,
252+
measurement.binding_off_rate_measurement_datum__koff_,
253+
),
254+
equilibrium_dissociation_constant__KD_=quantity_or_none(
255+
TQuantityValueMolar,
256+
measurement.equilibrium_dissociation_constant__kd_,
257+
),
258+
maximum_binding_capacity__Rmax_=quantity_or_none(
259+
TQuantityValueResonanceUnits,
260+
measurement.maximum_binding_capacity__rmax_,
261+
),
262+
report_point_aggregate_document=(
263+
ReportPointAggregateDocument(
264+
report_point_document=[
265+
add_custom_information_document(
266+
ReportPointDocumentItem(
267+
report_point_identifier=report_point.identifier,
268+
identifier_role=report_point.identifier_role,
269+
absolute_resonance=TQuantityValueResonanceUnits(
270+
value=report_point.absolute_resonance
271+
),
272+
relative_resonance=quantity_or_none(
273+
TQuantityValueResonanceUnits,
274+
report_point.relative_resonance,
275+
),
276+
time_setting=TQuantityValueSecondTime(
277+
value=report_point.time_setting
278+
),
279+
),
280+
custom_info_doc=report_point.custom_info,
281+
)
282+
for report_point in measurement.report_point_data
283+
]
284+
)
285+
if measurement.report_point_data
286+
else None
287+
),
288+
)
289+
216290
return MeasurementDocument(
217291
measurement_identifier=measurement.identifier,
218292
sample_document=add_custom_information_document(
@@ -245,55 +319,39 @@ def _get_surface_plasmon_resonance_measurement_document(
245319
device_control_document=[
246320
add_custom_information_document(
247321
DeviceControlDocumentItem(
248-
flow_cell_identifier=measurement.flow_cell_identifier,
249-
flow_path=measurement.flow_path,
322+
sample_temperature_setting=quantity_or_none(
323+
TQuantityValueDegreeCelsius,
324+
device_control.sample_temperature_setting,
325+
),
326+
flow_cell_identifier=device_control.flow_cell_identifier,
327+
flow_path=device_control.flow_path,
250328
flow_rate=quantity_or_none(
251329
TQuantityValueMicroliterPerMinute,
252-
measurement.flow_rate,
330+
device_control.flow_rate,
253331
),
254332
contact_time=quantity_or_none(
255-
TQuantityValueSecondTime, measurement.contact_time
333+
TQuantityValueSecondTime, device_control.contact_time
256334
),
257335
dilution_factor=quantity_or_none(
258-
TQuantityValuePercent, measurement.dilution
336+
TQuantityValuePercent, device_control.dilution
259337
),
260-
device_type=measurement.device_type,
338+
device_type=device_control.device_type,
261339
),
262-
custom_info_doc=measurement.device_control_custom_info,
340+
custom_info_doc=device_control.device_control_custom_info,
263341
)
342+
for device_control in measurement.device_control_document
264343
]
265344
),
266345
processed_data_aggregate_document=(
267346
ProcessedDataAggregateDocument(
268347
processed_data_document=[
269-
ProcessedDataDocumentItem(
270-
report_point_aggregate_document=ReportPointAggregateDocument(
271-
report_point_document=[
272-
add_custom_information_document(
273-
ReportPointDocumentItem(
274-
report_point_identifier=report_point.identifier,
275-
identifier_role=report_point.identifier_role,
276-
absolute_resonance=TQuantityValueResonanceUnits(
277-
value=report_point.absolute_resonance
278-
),
279-
relative_resonance=quantity_or_none(
280-
TQuantityValueResonanceUnits,
281-
report_point.relative_resonance,
282-
),
283-
time_setting=TQuantityValueSecondTime(
284-
value=report_point.time_setting
285-
),
286-
),
287-
# TODO: probably this should be at the processed document level.
288-
custom_info_doc=report_point.custom_info,
289-
)
290-
for report_point in measurement.report_point_data
291-
]
292-
)
293-
),
348+
add_custom_information_document(
349+
processed_data_document,
350+
custom_info_doc=measurement.processed_data_custom_info,
351+
)
294352
]
295353
)
296-
if measurement.report_point_data
354+
if has_value(processed_data_document)
297355
else None
298356
),
299357
)

src/allotropy/allotrope/schemas/adm/binding-affinity-analyzer/WD/2024/12/binding-affinity-analyzer.schema.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@
180180
"$ref": "http://purl.allotrope.org/json-schemas/adm/core/REC/2024/09/core.schema#/$defs/tQuantityValue"
181181
},
182182
{
183-
"$ref": "TODO"
183+
"$ref": "http://purl.allotrope.org/json-schemas/qudt/REC/2024/09/units.schema#/$defs/PerMolarPerSecond"
184184
}
185185
]
186186
},
@@ -216,7 +216,7 @@
216216
"$ref": "http://purl.allotrope.org/json-schemas/adm/core/REC/2024/09/core.schema#/$defs/tQuantityValue"
217217
},
218218
{
219-
"$ref": "TODO"
219+
"$ref": "http://purl.allotrope.org/json-schemas/qudt/REC/2024/09/units.schema#/$defs/ResonanceUnits"
220220
}
221221
]
222222
}
@@ -4521,6 +4521,18 @@
45214521
"unit"
45224522
]
45234523
},
4524+
"M-1s-1": {
4525+
"properties": {
4526+
"unit": {
4527+
"$asm.unit-iri": "http://purl.allotrope.org/ontology/qudt-ext/unit#PerMolarPerSecond",
4528+
"const": "M-1s-1",
4529+
"type": "string"
4530+
}
4531+
},
4532+
"required": [
4533+
"unit"
4534+
]
4535+
},
45244536
"MHz": {
45254537
"properties": {
45264538
"unit": {

src/allotropy/allotrope/schemas/shared/definitions/custom.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,26 @@
12991299
}
13001300
]
13011301
},
1302+
"tQuantityValueSquareResonanceUnits": {
1303+
"allOf": [
1304+
{
1305+
"$ref": "#/$defs/tQuantityValue"
1306+
},
1307+
{
1308+
"$ref": "#/$defs/SquareResonanceUnits"
1309+
}
1310+
]
1311+
},
1312+
"tNullableQuantityValueSquareResonanceUnits": {
1313+
"allOf": [
1314+
{
1315+
"$ref": "#/$defs/tNullableQuantityValue"
1316+
},
1317+
{
1318+
"$ref": "#/$defs/SquareResonanceUnits"
1319+
}
1320+
]
1321+
},
13021322
"tQuantityValueTODO": {
13031323
"allOf": [
13041324
{

src/allotropy/allotrope/schemas/shared/definitions/units.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,18 @@
779779
"unit"
780780
]
781781
},
782+
"SquareResonanceUnits": {
783+
"properties": {
784+
"unit": {
785+
"type": "string",
786+
"const": "RU^2",
787+
"$asm.unit-iri": "TODO"
788+
}
789+
},
790+
"required": [
791+
"unit"
792+
]
793+
},
782794
"TODO": {
783795
"properties": {
784796
"unit": {

0 commit comments

Comments
 (0)