7
7
from typing import Optional , List , Tuple , Union , cast , TypeVar , Dict , Set
8
8
from dataclasses import dataclass
9
9
from functools import cached_property
10
- from math import isclose
11
10
12
11
from opentrons .types import (
13
12
Point ,
33
32
LabwareNotLoadedOnLabwareError ,
34
33
LabwareNotLoadedOnModuleError ,
35
34
LabwareMovementNotAllowedError ,
36
- OperationLocationNotInWellError ,
37
35
InvalidLabwarePositionError ,
38
36
LabwareNotOnDeckError ,
39
37
)
@@ -522,39 +520,23 @@ def get_labware_position(self, labware_id: str) -> Point:
522
520
z = origin_pos .z + cal_offset .z ,
523
521
)
524
522
525
- def validate_well_position (
523
+ def _validate_well_position (
526
524
self ,
527
- well_location : WellLocationType ,
528
- z_offset : float ,
529
- pipette_id : Optional [str ] = None ,
530
- ) -> None :
531
- """Raise exception if operation location is not within well.
532
-
533
- Primarily this checks if there is not enough liquid in a well to do meniscus-relative static aspiration.
534
- """
535
- if well_location .origin == WellOrigin .MENISCUS :
536
- assert pipette_id is not None , "pipette id is None"
537
- lld_min_height = self ._pipettes .get_current_tip_lld_settings (
538
- pipette_id = pipette_id
539
- )
540
- if z_offset < lld_min_height :
541
- if isinstance (well_location , LiquidHandlingWellLocation ):
542
- raise OperationLocationNotInWellError (
543
- f"Specifying { well_location .origin } with a height offset of { well_location .offset .z } results in a height of { z_offset } mm; the minimum allowed height for liquid tracking is { lld_min_height } mm"
544
- )
545
- else :
546
- raise OperationLocationNotInWellError (
547
- f"Specifying { well_location .origin } with an offset of { well_location .offset } results in an operation location that could be below the bottom of the well"
548
- )
549
- elif z_offset < 0 and not isclose (z_offset , 0 , abs_tol = 0.0000001 ):
550
- if isinstance (well_location , LiquidHandlingWellLocation ):
551
- raise OperationLocationNotInWellError (
552
- f"Specifying { well_location .origin } with an offset of { well_location .offset } and a volume offset of { well_location .volumeOffset } results in an operation location below the bottom of the well"
553
- )
554
- else :
555
- raise OperationLocationNotInWellError (
556
- f"Specifying { well_location .origin } with an offset of { well_location .offset } results in an operation location below the bottom of the well"
557
- )
525
+ target_height : LiquidTrackingType , # height in mm inside a well relative to the bottom
526
+ well_max_height : float ,
527
+ pipette_id : str ,
528
+ ) -> LiquidTrackingType :
529
+ """If well offset would be outside the bounds of a well, silently bring it back to the boundary."""
530
+ if isinstance (target_height , SimulatedProbeResult ):
531
+ return target_height
532
+ lld_min_height = self ._pipettes .get_current_tip_lld_settings (
533
+ pipette_id = pipette_id
534
+ )
535
+ if target_height < lld_min_height :
536
+ target_height = lld_min_height
537
+ elif target_height > well_max_height :
538
+ target_height = well_max_height
539
+ return target_height
558
540
559
541
def validate_probed_height (
560
542
self ,
@@ -595,7 +577,7 @@ def get_well_position(
595
577
596
578
offset = WellOffset (x = 0 , y = 0 , z = well_depth )
597
579
if well_location is not None :
598
- offset = well_location .offset
580
+ offset = well_location .offset # location of the bottom of the well
599
581
offset_adjustment = self .get_well_offset_adjustment (
600
582
labware_id = labware_id ,
601
583
well_name = well_name ,
@@ -606,11 +588,6 @@ def get_well_position(
606
588
)
607
589
if not isinstance (offset_adjustment , SimulatedProbeResult ):
608
590
offset = offset .model_copy (update = {"z" : offset .z + offset_adjustment })
609
- self .validate_well_position (
610
- well_location = well_location ,
611
- z_offset = offset .z ,
612
- pipette_id = pipette_id ,
613
- )
614
591
return Point (
615
592
x = labware_pos .x + offset .x + well_def .x ,
616
593
y = labware_pos .y + offset .y + well_def .y ,
@@ -2107,6 +2084,8 @@ def get_well_height_after_liquid_handling(
2107
2084
2108
2085
This is given an initial handling height, with reference to the well bottom.
2109
2086
"""
2087
+ well_def = self ._labware .get_well_definition (labware_id , well_name )
2088
+ well_depth = well_def .depth
2110
2089
well_geometry = self ._labware .get_well_geometry (
2111
2090
labware_id = labware_id , well_name = well_name
2112
2091
)
@@ -2122,49 +2101,17 @@ def get_well_height_after_liquid_handling(
2122
2101
pipette_id = pipette_id ,
2123
2102
)
2124
2103
)
2125
- return find_height_at_well_volume (
2104
+ # NOTE(cm): if final_volume is outside the bounds of the well, it will get
2105
+ # adjusted inside find_height_at_well_volume to accomodate well the height
2106
+ # calculation.
2107
+ height_inside_well = find_height_at_well_volume (
2126
2108
target_volume = final_volume , well_geometry = well_geometry
2127
2109
)
2128
- except InvalidLiquidHeightFound as _exception :
2129
- raise InvalidLiquidHeightFound (
2130
- message = _exception .message
2131
- + f"for well { well_name } of { self ._labware .get_display_name (labware_id )} on slot { self .get_ancestor_slot_name (labware_id )} "
2132
- )
2133
-
2134
- def get_well_height_after_liquid_handling_no_error (
2135
- self ,
2136
- labware_id : str ,
2137
- well_name : str ,
2138
- pipette_id : str ,
2139
- initial_height : LiquidTrackingType ,
2140
- volume : float ,
2141
- ) -> LiquidTrackingType :
2142
- """Return what the height of liquid in a labware well after liquid handling will be.
2143
-
2144
- This raises no error if the value returned is an invalid physical location, so it should never be
2145
- used for navigation, only for a pre-emptive estimate.
2146
- """
2147
- well_geometry = self ._labware .get_well_geometry (
2148
- labware_id = labware_id , well_name = well_name
2149
- )
2150
- try :
2151
- initial_volume = find_volume_at_well_height (
2152
- target_height = initial_height , well_geometry = well_geometry
2153
- )
2154
- final_volume = initial_volume + (
2155
- volume
2156
- * self .get_nozzles_per_well (
2157
- labware_id = labware_id ,
2158
- target_well_name = well_name ,
2159
- pipette_id = pipette_id ,
2160
- )
2161
- )
2162
- well_volume = find_height_at_well_volume (
2163
- target_volume = final_volume ,
2164
- well_geometry = well_geometry ,
2165
- raise_error_if_result_invalid = False ,
2110
+ return self ._validate_well_position (
2111
+ target_height = height_inside_well ,
2112
+ well_max_height = well_depth ,
2113
+ pipette_id = pipette_id ,
2166
2114
)
2167
- return well_volume
2168
2115
except InvalidLiquidHeightFound as _exception :
2169
2116
raise InvalidLiquidHeightFound (
2170
2117
message = _exception .message
0 commit comments