Exemplo n.º 1
0
    def execute(self, *args, **kwargs) -> events.Event:
        if self.latest_od <= self.min_od:
            return events.NoEvent(f"latest OD less than OD to start diluting, {self.min_od:.2f}")
        else:
            fraction_of_alt_media_to_add = self.pid.update(
                self.latest_growth_rate, dt=self.duration
            )  # duration is measured in minutes, not seconds (as simple_pid would want)

            # dilute more if our OD keeps creeping up - we want to stay in the linear range.
            if self.latest_od > self.max_od:
                publish(
                    f"morbidostat/{self.unit}/{self.experiment}/log",
                    f"[{JOB_NAME}]: executing double dilution since we are above max OD, {self.max_od:.2f}.",
                    verbose=self.verbose,
                )
                volume = 2 * self.volume
            else:
                volume = self.volume

            alt_media_ml = fraction_of_alt_media_to_add * volume
            media_ml = (1 - fraction_of_alt_media_to_add) * volume

            self.execute_io_action(alt_media_ml=alt_media_ml, media_ml=media_ml, waste_ml=volume)
            event = events.AltMediaEvent(
                f"PID output={fraction_of_alt_media_to_add:.2f}, alt_media_ml={alt_media_ml:.2f}mL, media_ml={media_ml:.2f}mL"
            )
            event.media_ml = media_ml  # can be used for testing later
            event.alt_media_ml = alt_media_ml
            return event
Exemplo n.º 2
0
    def execute(self, *args, **kwargs) -> events.Event:
        if self.latest_od <= self.min_od:
            return events.NoEvent(f"current OD, {self.latest_od:.2f}, less than OD to start diluting, {self.min_od:.2f}")
        else:
            output = self.pid.update(self.latest_od, dt=self.duration)

            volume_to_cycle = output * self.volume

            if volume_to_cycle < 0.01:
                return events.NoEvent(f"PID output={output:.2f}, so practically no volume to cycle")
            else:
                self.execute_io_action(media_ml=volume_to_cycle, waste_ml=volume_to_cycle)
                e = events.DilutionEvent(f"PID output={output:.2f}, volume to cycle={volume_to_cycle:.2f}mL")
                e.volume_to_cycle = volume_to_cycle
                e.pid_output = output
                return e
Exemplo n.º 3
0
    def run(self, counter=None):
        if (self.latest_growth_rate is None) or (self.latest_od is None):
            time.sleep(10)  # wait some time for data to arrive, and try again.
            return self.run(counter=counter)

        if self.state != self.READY:
            event = events.NoEvent(f"currently in state {self.state}")

        elif (time.time() - self.most_stale_time) > 5 * 60:
            event = events.NoEvent(
                "readings are too stale (over 5 minutes old) - are `Optical density job` and `Growth rate job` running?"
            )
        else:
            event = self.execute(counter)

        publish(f"morbidostat/{self.unit}/{self.experiment}/log", f"[{JOB_NAME}]: triggered {event}.", verbose=self.verbose)
        return event
Exemplo n.º 4
0
 def execute(self, *args, **kwargs) -> events.Event:
     """
     morbidostat mode - keep cell density below and threshold using chemical means. The conc.
     of the chemical is diluted slowly over time, allowing the microbes to recover.
     """
     if self.previous_od is None:
         return events.NoEvent("skip first event to wait for OD readings.")
     elif self.latest_od >= self.target_od and self.latest_od >= self.previous_od:
         # if we are above the threshold, and growth rate is greater than dilution rate
         # the second condition is an approximation of this.
         self.execute_io_action(alt_media_ml=self.volume, waste_ml=self.volume)
         return events.AltMediaEvent(
             f"latest OD, {self.latest_od:.2f} >= Target OD, {self.target_od:.2f} and Latest OD, {self.latest_od:.2f} >= Previous OD, {self.previous_od:.2f}"
         )
     else:
         self.execute_io_action(media_ml=self.volume, waste_ml=self.volume)
         return events.DilutionEvent(
             f"latest OD, {self.latest_od:.2f} < Target OD, {self.target_od:.2f} or Latest OD, {self.latest_od:.2f} < Previous OD, {self.previous_od:.2f}"
         )
Exemplo n.º 5
0
 def execute(self, *args, **kwargs) -> events.Event:
     if self.latest_od >= self.target_od:
         self.execute_io_action(media_ml=self.volume, waste_ml=self.volume)
         return events.DilutionEvent(f"latest OD={self.latest_od:.2f}V >= target OD={self.target_od:.2f}V")
     else:
         return events.NoEvent(f"latest OD={self.latest_od:.2f}V < target OD={self.target_od:.2f}V")
Exemplo n.º 6
0
 def execute(self, *args, **kwargs) -> events.Event:
     return events.NoEvent("never execute IO events in Silent mode")