Skip to content

Commit f7173a5

Browse files
some name changes, small refactor, and tests
1 parent e4ded44 commit f7173a5

File tree

2 files changed

+74
-75
lines changed

2 files changed

+74
-75
lines changed

pioreactor/background_jobs/dosing_automation.py

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,10 @@ def update(
8383

8484

8585
class LiquidVolumeCalculator:
86-
max_volume = config.getfloat("bioreactor", "max_volume_ml")
87-
8886
@classmethod
89-
def update(cls, new_dosing_event: structs.DosingEvent, current_liquid_volume: float) -> float:
87+
def update(
88+
cls, new_dosing_event: structs.DosingEvent, current_liquid_volume: float, max_volume: float
89+
) -> float:
9090
assert current_liquid_volume >= 0
9191
volume, event = float(new_dosing_event.volume_change), new_dosing_event.event
9292
if event == "add_media":
@@ -97,14 +97,14 @@ def update(cls, new_dosing_event: structs.DosingEvent, current_liquid_volume: fl
9797
if new_dosing_event.source_of_event == "manually":
9898
# we assume the user has extracted what they want, regardless of level or tube height.
9999
return max(current_liquid_volume - volume, 0.0)
100-
elif current_liquid_volume <= cls.max_volume:
100+
elif current_liquid_volume <= max_volume:
101101
# if the current volume is less than the outflow tube, no liquid is removed
102102
return current_liquid_volume
103103
else:
104104
# since we do some additional "removing" after adding, we don't want to
105105
# count that as being removed (total volume is limited by position of outflow tube).
106106
# hence we keep an lowerbound here.
107-
return max(current_liquid_volume - volume, cls.max_volume)
107+
return max(current_liquid_volume - volume, max_volume)
108108
else:
109109
raise ValueError("Unknown event type")
110110

@@ -235,7 +235,8 @@ def __init__(
235235
initial_alt_media_fraction: float = config.getfloat(
236236
"bioreactor", "initial_alt_media_fraction", fallback=0.0
237237
),
238-
initial_liquid_volume: float = config.getfloat("bioreactor", "initial_volume_ml", fallback=14),
238+
initial_liquid_volume_ml: float = config.getfloat("bioreactor", "initial_volume_ml", fallback=14),
239+
max_volume_ml: float = config.getfloat("bioreactor", "max_volume_ml", fallback=14),
239240
**kwargs,
240241
) -> None:
241242
super(DosingAutomationJob, self).__init__(unit, experiment)
@@ -250,14 +251,15 @@ def __init__(
250251
)
251252

252253
self.skip_first_run = skip_first_run
254+
self.max_volume_ml = max_volume_ml
253255

254256
self.latest_normalized_od_at = current_utc_datetime()
255257
self.latest_growth_rate_at = current_utc_datetime()
256258
self.latest_od_at = current_utc_datetime()
257259

258260
self._init_alt_media_fraction(float(initial_alt_media_fraction))
259261
self._init_volume_throughput()
260-
self._init_liquid_volume(float(initial_liquid_volume))
262+
self._init_liquid_volume(float(initial_liquid_volume_ml))
261263

262264
self.set_duration(duration)
263265

@@ -266,6 +268,12 @@ def __init__(
266268
"It's recommended to have stirring on to improve mixing during dosing events."
267269
)
268270

271+
if self.max_volume_ml > self.MAX_VIAL_VOLUME_TO_STOP:
272+
# possibly the user messed up thier configuration. We warn them.
273+
self.logger.warning(
274+
"The parameter max_volume_ml should be less than max_volume_to_stop (otherwise your pumping will stop too soon)."
275+
)
276+
269277
def set_duration(self, duration: Optional[float]) -> None:
270278
if duration:
271279
self.duration = float(duration)
@@ -355,9 +363,7 @@ def block_until_not_sleeping(self) -> bool:
355363
def execute_io_action(
356364
self,
357365
waste_ml: float = 0.0,
358-
media_ml: float = 0.0,
359-
alt_media_ml: float = 0.0,
360-
**other_pumps_ml: float,
366+
**all_pumps_ml: float,
361367
) -> SummableDict:
362368
"""
363369
This function recursively reduces the amount to add so that we don't end up adding 5ml,
@@ -366,7 +372,7 @@ def execute_io_action(
366372
will slow dosing down.
367373
368374
369-
Users can call additional pumps (other than media and alt_media) by providing them as kwargs. Ex:
375+
Users can call additional pumps by providing them as kwargs. Ex:
370376
371377
> dc.execute_io_action(waste_ml=2, media_ml=1, salt_media_ml=0.5, media_from_sigma_ml=0.5)
372378
@@ -386,21 +392,19 @@ def execute_io_action(
386392
sub-call. This keeps the ratio of alt_media to media the same in the vial.
387393
388394
A problem is if the there is skew in the different mLs, then it's possible that one or more pumps
389-
most dose a very small amount, where our pumps have poor accuracy.
395+
must dose a very small amount, where our pumps have poor accuracy.
390396
391397
392398
Returns
393399
---------
394400
A dict of volumes that were moved, in mL. This may be different than the request mLs, if a error in a pump occurred.
395401
396402
"""
397-
if not all(other_pump_ml.endswith("_ml") for other_pump_ml in other_pumps_ml.keys()):
403+
if not all(other_pump_ml.endswith("_ml") for other_pump_ml in all_pumps_ml.keys()):
398404
raise ValueError(
399405
"all kwargs should end in `_ml`. Example: `execute_io_action(salty_media_ml=1.0)`"
400406
)
401407

402-
all_pumps_ml = {**{"media_ml": media_ml, "alt_media_ml": alt_media_ml}, **other_pumps_ml}
403-
404408
sum_of_volumes = sum(ml for ml in all_pumps_ml.values())
405409
if not (waste_ml >= sum_of_volumes - 1e-9):
406410
# why close? account for floating point imprecision, ex: .6299999999999999 != 0.63
@@ -422,13 +426,14 @@ def execute_io_action(
422426
)
423427

424428
else:
425-
# iterate through pumps, and dose required amount. First media, then alt_media, then any others, then waste.
429+
# iterate through pumps, and dose required amount. First *_media, then waste.
426430
for pump, volume_ml in all_pumps_ml.items():
427431
if (self.liquid_volume + volume_ml) >= self.MAX_VIAL_VOLUME_TO_STOP:
428432
self.logger.error(
429-
f"Stopping all pumping since {self.liquid_volume} + {volume_ml} mL is beyond safety threshold {self.MAX_VIAL_VOLUME_TO_STOP} mL."
433+
f"Pausing all pumping since {self.liquid_volume} + {volume_ml} mL is beyond safety threshold {self.MAX_VIAL_VOLUME_TO_STOP} mL."
430434
)
431435
self.set_state(self.SLEEPING)
436+
return volumes_moved
432437

433438
if (volume_ml > 0) and (self.state in (self.READY,)) and self.block_until_not_sleeping():
434439
pump_function = getattr(self, f"add_{pump.removesuffix('_ml')}_to_bioreactor")
@@ -590,7 +595,9 @@ def _update_alt_media_fraction(self, dosing_event: structs.DosingEvent) -> None:
590595
cache[self.experiment] = self.alt_media_fraction
591596

592597
def _update_liquid_volume(self, dosing_event: structs.DosingEvent) -> None:
593-
self.liquid_volume = LiquidVolumeCalculator.update(dosing_event, self.liquid_volume)
598+
self.liquid_volume = LiquidVolumeCalculator.update(
599+
dosing_event, self.liquid_volume, self.max_volume_ml
600+
)
594601

595602
# add to cache
596603
with local_persistent_storage("liquid_volume") as cache:
@@ -633,39 +640,32 @@ def _init_alt_media_fraction(self, initial_alt_media_fraction: float) -> None:
633640

634641
return
635642

636-
def _init_liquid_volume(self, initial_liquid_volume: float) -> None:
637-
assert initial_liquid_volume >= 0
643+
def _init_liquid_volume(self, initial_liquid_volume_ml: float) -> None:
644+
assert initial_liquid_volume_ml >= 0
638645

639646
self.add_to_published_settings(
640647
"liquid_volume",
641648
{
642649
"datatype": "float",
643650
"settable": False, # modify using dosing_events, ex: pio run add_media --ml 1 --manually
644651
"unit": "mL",
652+
"persist": True, # keep around so the UI can see it
645653
},
646654
)
647655

648656
with local_persistent_storage("liquid_volume") as cache:
649-
self.liquid_volume = cache.get(self.experiment, initial_liquid_volume)
657+
self.liquid_volume = cache.get(self.experiment, initial_liquid_volume_ml)
650658

651659
return
652660

653661
def _init_volume_throughput(self) -> None:
654662
self.add_to_published_settings(
655663
"alt_media_throughput",
656-
{
657-
"datatype": "float",
658-
"settable": False,
659-
"unit": "mL",
660-
},
664+
{"datatype": "float", "settable": False, "unit": "mL", "persist": True},
661665
)
662666
self.add_to_published_settings(
663667
"media_throughput",
664-
{
665-
"datatype": "float",
666-
"settable": False,
667-
"unit": "mL",
668-
},
668+
{"datatype": "float", "settable": False, "unit": "mL", "persist": True},
669669
)
670670

671671
with local_persistent_storage("alt_media_throughput") as cache:

0 commit comments

Comments
 (0)