Proposed upcoming changes and additions to experiment profiles

:wave: for the many of you of have used (or looked at) experiment profiles, we’re proposing some changes to the specification that aren’t backwards compatible. We’re also adding an exciting new addition: an if directive!

Let’s start with the fun stuff. We are adding an if directive to optionally perform an action. For example, you may want to increase stirring or bubbling if the OD reading is above some target. This example action looks like:

pioreactors:
  pio1:
    jobs:
      stirring:
        actions:
          - type: start
            hours_elapsed: 0.0
            options:
              target_rpm: 400.0
          - update:
            hours_elapsed: 10.0
            if: pio1:od_reading:od1.od >= 1.5  # here's the if statement!
            options:
               target_rpm: 600.0

And yes, you can use boolean operators like and, or, brackets, and not to chain boolean expressions. The idea is to be able to reference any published_setting from any job in these expressions. For example: the string pio1:od_reading:od1.od reads: “look at the published setting od1 from job od_reading on pio1 Pioreactor. That’s a json-blob. Look inside at field od and compare it to 1.5”.

I may change how this syntax looks.


Next, we are changing the labels stanza. Previously it was defined like:

labels:
   pio1: hot
   pio2: cold

Now it’s going to be defined in the pioreactors block:

pioreactors:
  pio1:
    label: hot 
    jobs:  ...
  pio2:
    label: cold
    jobs: ...

Finally, the common block now requires a jobs field, like the pioreactors block does:

Previously:

common:
  stirring:
    actions:
      - type: start
        hours_elapsed: 0.0
        options:
          target_rpm: 400.0

Now:

common:
  jobs:  # here is the change
    stirring:
      actions:
        - type: start
          hours_elapsed: 0.0
          options:
            target_rpm: 400.0

This is so we can define other metadata in the common section, and to introduce symmetry between the sections.


Any feedback? Let us know below!

2 Likes

Brilliant - will your GPT work with these?

I presume we couldn’t use this to schedule things with some sort of :

if: hours_elapsed % cycle < duration
options:
   relay: true

I’ve been thinking about this. I’m considering a repeat directive for these kinds of tasks (your “run the bubbler for 10s every hour” is my canonical example).

Here’s a sketch for the following: start the relay. After an hour, start a cycle that turns on the relay for 10s every hour. Turn off the relay after 12 hours.

common:
  jobs:
    relay:
      actions:
        - type: start
          hours_elapsed: 0.0
          options:
            is_relay_on: False
        - type: repeat
          hours_elapsed: 1.0
          every: 1.0  # 1h
          actions:
            - type: update
              hours_elapsed: 0.0  # relative to the repeat loop, 1h
              options:
                is_relay_on: True
            - type: update:
              hours_elapsed: 0.002
              options:
                is_relay_on: False
            - type: stop
              if: hours_elapsed >= 10  # however this doesn't work yet
              hours_elapsed: 0.1
1 Like

Certainly easier to get ones head round than the current system…

It wasn’t much more work to add expressions (what we are calling the string to the right of if) to options too. So you can do things like:


pioreactors:
  worker1:
    jobs:
      stirring:
        actions:
          - type: start
            hours_elapsed: 0
            options:
              target_rpm: 500
          - type: update
            hours_elapsed: 12
            options:
              target_rpm: ${{ worker1:stirring:target_rpm + worker1:od_reading:od1.od * 10 }}

Note that these expressions need to be surrounded by ${{ ... }} to distinguish them from regular strings. if statements can use ${{ ... }} or not (they are always evaluated as expressions)