Getting Started

The best way to learn MechWolf is by example. In the spirit of reproducibility, we are going to go through the process of setting up and running our peptoid synthesizer step-by-step.

Create Components

Let's start from square one (or zero, if you're counting like a programmer). We first need to import MechWolf:

import mechwolf as mw

The next thing that we need to do is to define the components of our synthesizer. It will consist of vessels containing reagents:

# define vessels
coupling_agent = mw.Vessel("DCC", name="coupling_agent")
acid = mw.Vessel("bromoacetic acid", name="acid")
solvent = mw.Vessel("solvent", name="solvent")
output = mw.Vessel("waste", name="output")

And the amines:

# define amines
amine_1 = mw.Vessel("amine_1", name="amine_1")
amine_2 = mw.Vessel("amine_2", name="amine_2")
amine_3 = mw.Vessel("amine_3", name="amine_3")
amine_4 = mw.Vessel("amine_4", name="amine_4")
amine_5 = mw.Vessel("amine_5", name="amine_5")
amine_6 = mw.Vessel("amine_6", name="amine_6")
amine_7 = mw.Vessel("amine_7", name="amine_7")
amine_8 = mw.Vessel("amine_8", name="amine_8")

What we have so far are a bunch of vessel objects. Note that when we instantiate them we give them two arguments. The first, required argument is what's in it. The second name keyword is the name the we'll be using to refer to it. Consider the name to be like a unique identifier. In most if not all cases it should match the variable name. However, note that the name of the vessel does not need to match what's inside it.

Now, we'll define the pumps that will drive the system:

# define pumps
coupling_pump = mw.VarianPump(name="pump_3")
amine_pump = mw.VarianPump(name="pump_2")
mixer = mw.TMixer()

Note that the names of the objects don't match the variables! Why? Each physical device has a unique name that is associated with it. In one apparatus, the pump named pump_3 might be the coupling pump, but in a completely different apparatus might be something entirely different. However, we need a way uniquely identify it so that we can send it commands during execution. It would be annoying to have to remember the name of the phyiscal device and the device's variable name, so you only need to associate them once (at definition) and MechWolf will take care of making sure that commands get to the right place during execution.

# define valve
amine_mapping = dict(
    amine_1=1,
    amine_2=2,
    amine_3=3,
    amine_4=4,
    amine_5=5,
    amine_6=6,
    amine_7=7,
    amine_8=8,
    acid=9,
    solvent=10,
)
valve = mw.ViciValve(name="valve", mapping=amine_mapping)
coupling_valve = mw.ViciValve(
    name="coupling_valve", mapping=dict(coupling_agent=1, solvent=10)
)
fat_tube = mw.Tube(length="2 foot", ID="1/16 in", OD="1/8 in", material="PFA")
thin_tube = mw.Tube(length="2 foot", ID="0.04 in", OD="1/16 in", material="PFA")

Create the Apparatus

Now that we have our components defined, we need to tell Mechwolf how they are connected. The Apparatus object will do just that. First, we create the object (calling it A for brevity) and give it a name as the only argument.

A = mw.Apparatus("Automated Fast Flow Peptoid Synthesizer")

We now need to tell Mechwolf what components make up the apparatus. We do that with the add() function, which takes three arguments: from component(s), to component, and tube.

A.add(
    coupling_agent,
    coupling_valve,
    mw.Tube(length="130 cm", ID="1/16 in", OD="1/8 in", material="PFA"),
)
A.add(solvent, coupling_valve, fat_tube)
A.add(coupling_valve, coupling_pump, fat_tube)
A.add(coupling_pump, mixer, thin_tube)
A.add(
    [
        amine_1,
        amine_2,
        amine_3,
        amine_4,
        amine_5,
        amine_6,
        amine_7,
        amine_8,
        solvent,
        acid,
    ],
    valve,
    fat_tube,
)
A.add(valve, amine_pump, fat_tube)
A.add(amine_pump, mixer, thin_tube)
A.visualize()
A.summarize()
P = mw.Protocol(A, duration="auto")
from datetime import timedelta

# let's start at the very beginning (a very good place to start)
start = timedelta(seconds=0)

# how much time to leave the pumps off before and after switching the valve
switching_time = timedelta(seconds=1)
coupling_duration = timedelta(minutes=1, seconds=30)
amine_addition_duration = timedelta(minutes=1, seconds=30)
def add_rinse():
    global start
    rinse_duration = timedelta(minutes=2)

    P.add(
        [valve, coupling_valve], start=start, duration=rinse_duration, setting="solvent"
    )

    P.add(
        [amine_pump, coupling_pump],
        start=start + switching_time,
        duration=rinse_duration - 2 * switching_time,
        rate="5 mL/min",
    )

    start += rinse_duration
peptoid = [
    "amine_2",
    "amine_2",
    "amine_1",
    "amine_2",
    "amine_1",
    "amine_3",
    "amine_2",
    "amine_1",
    "amine_3",
    "amine_3",
]

We now define

for amine in peptoid:

    # initial rinse
    add_rinse()

    # perform acid coupling, first setting valve positions
    P.add(valve, start=start, duration=coupling_duration, setting="acid")
    P.add(
        coupling_valve,
        start=start,
        duration=coupling_duration,
        setting="coupling_agent",
    )
    # then turn on the pumps for the duration, leaving time on both ends for valve switching
    P.add(
        [amine_pump, coupling_pump],
        start=start + switching_time,
        duration=coupling_duration - 2 * switching_time,
        rate="5 mL/min",
    )
    start += coupling_duration

    # another rise
    add_rinse()

    # now onto amine addition, setting the main valve to the amine
    P.add(valve, start=start, duration=amine_addition_duration, setting=amine)
    # move the coupling valve to the solvent position
    P.add(
        coupling_valve, start=start, duration=amine_addition_duration, setting="solvent"
    )
    # only turn on the amine pump now, again leaving switching time
    P.add(
        amine_pump,
        start=start + switching_time,
        duration=amine_addition_duration - 2 * switching_time,
        rate="5 mL/min",
    )
    start += amine_addition_duration

    # after amine addition, wash out with just the amine pump
    P.add(valve, start=start, duration=amine_addition_duration, setting="solvent")
    P.add(
        coupling_valve, start=start, duration=amine_addition_duration, setting="solvent"
    )
    P.add(
        amine_pump,
        start=start + switching_time,
        duration=amine_addition_duration - 2 * switching_time,
        rate="5 mL/min",
    )
    start += amine_addition_duration
add_rinse()
add_rinse()
P.visualize()