HPInc / HP-Digital-Microfluidics

HP Digital Microfluidics Software Platform and Libraries
MIT License
3 stars 1 forks source link

Add generic "interactive" exerciser #176

Closed EvanKirshenbaum closed 8 months ago

EvanKirshenbaum commented 8 months ago

When I first designed the Exerciser framework, there was no macro language (or even a simple "walk this path" text box (#50)), and you couldn't really interact with the monitor, and I expected that testing the boards would be a matter of writing tasks in Python and choosing which one to run.

With the macro language, pretty much everybody just runs the display task and types in commands and clicks on the board. This is great, but it does mean that we have a bunch of exercisers (wombat, joey, bilby) that have to be kept in sync, where only the display task is used for each.

With the addition of single-task Exercisers (#175), it would be straightforward to create a new one for each, but what I think I'd like to do instead is to create a single "interactive" Exerciser whose Tasks are wombat, joey, and bilby, with wombat and bilby being subclasses of joey and joey being derived from Display.

The only thing that should be hard about this is that make_board() and available_wells() are methods on Exerciser, so we'll probably have to add a subclass of Exerciser that delegates the calls to its chosen Task.

Ideally, we wouldn't hard-code in Display, but rather have a general PlatformChoiceTask, with concrete (and hierarchical) implementations in the various device modules (e.g., bilby.PlatformTask). Then this Exerciser subclass could take a Task (or maybe a type[Task]) and a list of PlatformChoiceTasks (ditto) and wire everything together.

Migrated from internal repository. Originally created by @EvanKirshenbaum on Jun 16, 2022 at 11:23 AM PDT. Closed on Jun 18, 2022 at 9:40 PM PDT.
EvanKirshenbaum commented 8 months ago

This issue was referenced by the following commits before migration:

EvanKirshenbaum commented 8 months ago

Okay, I went a step further and added an Exerciser subclass, PlatformChoiceExerciser, and a Task subclass, PlatformChoiceTask (with each platform having its own subclass) so that you can easily create a script that runs a Task on any platform you choose. The interactive script then becomes simply

    platforms = (
                bilby.PlatformTask,
                joey.PlatformTask,
                opendrop.PlatformTask,
                wombat.PlatformTask,
                wombat.YaminonPlatformTask,
                )
    pipettors = (opentrons.PipettorConfig,)
    default_pipettor = manual_pipettor.PipettorConfig
    # exerciser = InteractiveExerciser(platforms=platforms, pipettors=pipettors)
    exerciser = PlatformChoiceExerciser.for_task(DisplayOnly, 
                                                 "Interact with a DMF board",
                                                 platforms=platforms,
                                                 pipettors=pipettors,
                                                 default_pipettor=default_pipettor)
    exerciser.parse_args_and_run()

Each type of pipettor defines a PipettorConfig (and I added a ManualPipettor, which just tells the user what to do and tell it when they're done). The PlatformChoiceExerciser adds a --pipettor argument, with choices selected from the provided pipettors. If you don't specify, the default pipettor, which defaults to DummyPipettor, is used.

The combinatorial synthesis script is essentially the same, except for using pcr.CombSynth as the Task, only allowing joey and bilby platforms (since it needs the whole board), and allowing DummyPipettor to be the default.

This whole thing should make maintenance much easier, as when there's a new argument needed for a platform or a pipettor, it only needs to be added in one place (the PlatformChoiceTask or PipettorConfig).

I'm calling the old form of multi-task exercisers deprecated, but leaving it in place until there isn't anybody using the old scripts. When we can retire them, I'd like to simplify the Exerciser framework, renaming things like add_device_specific_common_args(), which assumed that we would have one exerciser per platform and really didn't even make sense for things like pcr. If we do that, we can change PlatformChoiceTask to simply Platform and break the dependency with Task and assume that all Exercisers have the behavior of PlatformChoiceExerciser.

I'm going to open a new issue for that and close this one, as it will probably be a little while before we get to that.

Migrated from internal repository. Originally created by @EvanKirshenbaum on Jun 18, 2022 at 9:39 PM PDT.