|
11 | 11 | import warnings
|
12 | 12 | from typing import (
|
13 | 13 | Any,
|
| 14 | + Awaitable, |
14 | 15 | Callable,
|
15 | 16 | Dict,
|
16 | 17 | List,
|
|
82 | 83 | logger = logging.getLogger("pylabrobot")
|
83 | 84 |
|
84 | 85 |
|
| 86 | +TipPresenceProbingMethod = Callable[ |
| 87 | + [List[TipSpot], Optional[List[int]]], |
| 88 | + Awaitable[Dict[str, bool]], |
| 89 | +] |
| 90 | + |
| 91 | + |
85 | 92 | def check_contaminated(liquid_history_tip, liquid_history_well):
|
86 | 93 | """Helper function used to check if adding a liquid to the container
|
87 | 94 | would result in cross contamination"""
|
@@ -2411,3 +2418,49 @@ async def probe_tip_presence_via_pickup(
|
2411 | 2418 | print(f"Warning: drop_tips failed for cluster at x={cluster[0][0].location.x}: {e}")
|
2412 | 2419 |
|
2413 | 2420 | return {ts.name: flag for ts, flag in zip(tip_spots, presence_flags)}
|
| 2421 | + |
| 2422 | + async def probe_tip_inventory( |
| 2423 | + self, |
| 2424 | + tip_spots: List[TipSpot], |
| 2425 | + probing_fn: Optional[TipPresenceProbingMethod] = None, |
| 2426 | + use_channels: Optional[List[int]] = None, |
| 2427 | + ) -> Dict[str, bool]: |
| 2428 | + """Probe the presence of tips in multiple tip spots. |
| 2429 | +
|
| 2430 | + The provided ``probing_fn`` is used for probing batches of tip spots. The |
| 2431 | + default uses :meth:`probe_tip_presence_via_pickup`. |
| 2432 | +
|
| 2433 | + Examples: |
| 2434 | + Probe all tip spots in one or more tip racks. |
| 2435 | +
|
| 2436 | + >>> import pylabrobot.resources.functional as F |
| 2437 | + >>> spots = F.get_all_tip_spots([tip_rack_1, tip_rack_2]) |
| 2438 | + >>> presence = await lh.probe_tip_inventory(spots) |
| 2439 | +
|
| 2440 | + Args: |
| 2441 | + tip_spots: |
| 2442 | + Tip spots to probe for presence of a tip. |
| 2443 | + probing_fn: |
| 2444 | + Function used to probe a batch of tip spots. Must accept ``tip_spots`` and |
| 2445 | + ``use_channels`` and return a mapping of tip spot names to boolean flags. |
| 2446 | +
|
| 2447 | + Returns: |
| 2448 | + Mapping from tip spot names to whether a tip is present. |
| 2449 | + """ |
| 2450 | + |
| 2451 | + if probing_fn is None: |
| 2452 | + probing_fn = self.probe_tip_presence_via_pickup |
| 2453 | + |
| 2454 | + results: Dict[str, bool] = {} |
| 2455 | + |
| 2456 | + num_channels = self.backend.num_channels |
| 2457 | + if use_channels is None: |
| 2458 | + use_channels = list(range(num_channels)) |
| 2459 | + |
| 2460 | + for i in range(0, len(tip_spots), num_channels): |
| 2461 | + subset = tip_spots[i : i + num_channels] |
| 2462 | + use_channels = list(range(len(subset))) |
| 2463 | + batch_result = await probing_fn(subset, use_channels) |
| 2464 | + results.update(batch_result) |
| 2465 | + |
| 2466 | + return results |
0 commit comments