Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Have wells use pipettor to automatically refill and empty #42

Closed
EvanKirshenbaum opened this issue Jan 29, 2024 · 3 comments
Closed

Have wells use pipettor to automatically refill and empty #42

EvanKirshenbaum opened this issue Jan 29, 2024 · 3 comments
Labels
4 imporant Important issue in: MPAM API Issue relates to the MPAM API is: feature Issue proposes a new feature

Comments

@EvanKirshenbaum
Copy link

As currently implemented, if you try to dispense a drop from an empty well (or one with insufficient volume) or try to have a drop enter a well that doesn't have room for it, it calls an error handler which, by default, just prints a message.

Now that I have pipettors modeled, it would be useful if the operations on wells could use them to automatically refill and empty as needed. ExtractionPoints are associated with an optional PipettingArm and transfers out (and, m/m, in) are implemented in terms of them:

    def transfer_out(self, *,
                     liquid: Optional[Liquid] = None,
                     on_no_sink: ErrorHandler = PRINT
                     ) -> Delayed[Liquid]:
        arm = self.pipetting_arm()
        assert arm is not None, f"{self} has no pipetting arm and transfer_out() not overridden"
        if liquid is None:
            drop = not_None(self.pad.drop)
            liquid = drop.liquid
        arm_future = arm.schedule(arm.Extract(liquid.volume, self,
                                             on_no_sink = on_no_sink))
        return arm_future

For PCR (#31), I implemented an explicit check on the waste well to use the board's arm to empty it if it was full, but it would be nice if that happened automatically (and the same for when wells are empty).

Some notes:

  • Probably want to be able to externally specify the level at which to empty (default is insufficient space) and refill (default is insufficient content)
  • Probably also want to be able to specify the refill amount, although this may be best specified as a callback function to dynamically compute this so that we don't wind up pulling in more than is needed.
  • For emptying, at least (and maybe for filling), we'll want to go through the extraction state of the well group. In any case, we won't want to allow this well to be reserved (and its gate used) until the pipettor activity is done.
  • As with extraction points, the board's well implementation should be able to override some function when the default pipettor-based implementation isn't right.

Also, for both wells and extraction points, at some point we may want to have them associated with more than one arm (maybe the Pipettor itself?) so that it can use the most convenient arm when there's more than one. But that will almost certainly mean more complicated scheduling, so I'll start with a single arm.

Migrated from internal repository. Originally created by @EvanKirshenbaum on Jul 23, 2021 at 3:51 PM PDT. Closed on Aug 02, 2021 at 12:56 PM PDT.
@EvanKirshenbaum EvanKirshenbaum added 4 imporant Important issue in: MPAM API Issue relates to the MPAM API is: feature Issue proposes a new feature labels Jan 29, 2024
@EvanKirshenbaum
Copy link
Author

This issue was referenced by the following commits before migration:

@EvanKirshenbaum
Copy link
Author

Wells now automatically fill before dispensing when empty and empty before absorbing when full. Each well is associated with

  • min_fill: Refill the well if dispensing would get it below this level. Defaults to empty.
  • max_fill: Empty the well if absorbing would get it above this level. Defaults to the well's capacity.
  • fill_to: When refilling, fill to this level. Defaults to the well's capacity.
  • empty_to: When emptying, empty to this level. Defaults to empty.

All of these can be specified as a volume, as None (indicating to use the default), or as a Callable returning a volume. The last is useful when (as with the PCR task), you know how many drops you'll need, but it changes over time.

Note that while everything works fine if you say

    WellVolumeSpec = Union[Volume, Callable[[], Volume]]

    # refill if dispensing would take you to this level
    _min_fill: Optional[WellVolumeSpec] = None
    
    @property
    def min_fill(self) -> Volume:
        return self.volume_from_spec(self._min_fill, lambda: Volume.ZERO())
    
    @min_fill.setter
    def min_fill(self, volume: Optional[WellVolumeSpec]) -> None:
        self._min_fill = volume

MyPy complains if you actually do an assignment of a value that's incompatible with the type of the getter (not the setter argument). This is apparently a known issue (python/mypy#3004), one they agree should be fixed, but hasn't been. So I added a set of functions (e.g., compute_min_fill) that take the same argument.

Migrated from internal repository. Originally created by @EvanKirshenbaum on Aug 02, 2021 at 12:50 PM PDT.

@EvanKirshenbaum
Copy link
Author

In order to get the logic right (so that the filling/emptying happened only once and based on the right current level), I added an optional guard to WellMotion and WellGroup.TransitionTo. This is an Iterator[bool] and, if provided, the WellMotion iterates (one per tick) until it yields False. For dispensing, this iterates until it can reserve the exit pad (this is necessary to avoid having multiple dispense requests asking to refill) and then checks and iterates until any necessary refill is done. For absorbing, only the latter part is needed (because nobody will ask the well to absorb until they get a drop in place).

The guard is processed before locking the WellGroup and trying to get adopted by an in-progress motion, so one well won't hold up others.

Migrated from internal repository. Originally created by @EvanKirshenbaum on Aug 02, 2021 at 12:56 PM PDT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
4 imporant Important issue in: MPAM API Issue relates to the MPAM API is: feature Issue proposes a new feature
Projects
None yet
Development

No branches or pull requests

1 participant