Skip to content

Commit

Permalink
updates
Browse files Browse the repository at this point in the history
  • Loading branch information
CamDavidsonPilon committed May 13, 2024
1 parent e5c2463 commit 0be505a
Show file tree
Hide file tree
Showing 15 changed files with 199 additions and 53 deletions.
11 changes: 7 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#### Enhancements
- UI chart legend's will support more than 8 Pioreactors.
- UI chart colors are consistent across charts in the Overview.
- reduce the number of pop-ups in the UI, so they'll be less distractions.
- reduce the severity of some messages, so there will be less pop-ups in the UI.
- UI performance improvements.
- Upgraded to React 18
- Removed unused dependencies
Expand All @@ -13,14 +13,17 @@
- faster `pio kill`
- faster job start from UI
- more humane error messages.
- updated temperature inference model
- updated temperature inference model.
- added exponentiation `**` to profile expressions. Ex: `${{ pio1:growth_rate_calculating:growth_rate.growth_rate ** 0.5 }}`
- added `random()` to profile expressions. This returns a number between 0 and 1. Ex: `${{ 25 + 25 * random() }} `



#### Bug fixes
- fix `pio plugins` on workers
- fix `pio plugins` not working on workers.
- fix `enable_dodging_od=0` for background jobs that can dodge OD.
- fix jobs not cleaning up correctly if too many jobs try to end at the same time.
- fix `pio kill` not returning the correct count of jobs being killed.
- fix older Pioreactor HATs, with the ADS1115 chip, not have the method `from_voltage_to_raw_precise`.


### 24.5.1
Expand Down
2 changes: 1 addition & 1 deletion config.dev.ini
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ samples_per_second=0.2

pd_reference_ema=0.4

ir_led_intensity=auto
ir_led_intensity=50

# use the most recent calibration file, if available
use_calibration=1
Expand Down
10 changes: 5 additions & 5 deletions pioreactor/actions/self_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def test_all_positive_correlations_between_pds_and_leds(
# the problem is that if an LED is directly across from a PD, a high intensity will quickly
# saturate it and fail the test. So we try low intensities first, and if we exceed some threshold
# we exit before moving to the high intensities.
INTENSITIES = [32, 35, 53, 44, 38, 47, 50, 41, 56, 59, 62, 65]
INTENSITIES = (32, 35, 53, 44, 38, 47, 50, 41, 56, 59, 62, 65)

results: dict[tuple[LedChannel, PdChannel], float] = {}

Expand Down Expand Up @@ -458,20 +458,20 @@ def click_self_test(k: Optional[str]) -> int:
experiment = get_assigned_experiment_name(unit)
logger = create_logger("self_test", unit=unit, experiment=experiment)

A_TESTS = [
A_TESTS = (
test_pioreactor_HAT_present,
test_detect_heating_pcb,
test_positive_correlation_between_temperature_and_heating,
test_aux_power_is_not_too_high,
]
B_TESTS = [
)
B_TESTS = (
test_all_positive_correlations_between_pds_and_leds,
test_ambient_light_interference,
test_REF_is_lower_than_0_dot_256_volts,
test_REF_is_in_correct_position,
test_PD_is_near_0_volts_for_blank,
test_positive_correlation_between_rpm_and_stirring,
]
)

with managed_lifecycle(unit, testing_experiment, "self_test") as state:
client = state.mqtt_client
Expand Down
2 changes: 2 additions & 0 deletions pioreactor/background_jobs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1079,8 +1079,10 @@ def _listen_for_od_reading(self) -> None:
def set_enable_dodging_od(self, value: bool) -> None:
self.enable_dodging_od = value
if self.enable_dodging_od:
self.logger.info("Will attempt to stop during OD readings.")
self._listen_for_od_reading()
else:
self.logger.info("Running continuously through OD readings.")
if hasattr(self, "sneak_in_timer"):
self.sneak_in_timer.cancel()
try:
Expand Down
17 changes: 6 additions & 11 deletions pioreactor/background_jobs/od_reading.py
Original file line number Diff line number Diff line change
Expand Up @@ -697,17 +697,12 @@ def get_models_from_disk(
msg = f"The calibration `{name}` was calibrated with a different PD channel ({calibration_data.pd_channel} vs current: {channel})."
self.logger.error(msg)
raise exc.CalibrationError(msg)
else:
models[channel] = self._hydrate_model(calibration_data)
self.logger.debug(
f"Using calibration `{name}` for channel {channel}, {calibration_data.curve_type=}, {calibration_data.curve_data_=}"
)

# confirm that PD channel is the same as when calibration was performed
if calibration_data.pd_channel != channel:
msg = f"The calibration `{name}` was calibrated with a different PD channel ({calibration_data.pd_channel} vs current: {channel})."
self.logger.error(msg)
raise exc.CalibrationError(msg)
models[channel] = self._hydrate_model(calibration_data)
self.logger.info(f"Using OD calibration `{name}` for channel {channel}.")
self.logger.debug(
f"Using OD calibration `{name}` for channel {channel}, {calibration_data.curve_type=}, {calibration_data.curve_data_=}"
)

else:
self.logger.debug(
Expand Down Expand Up @@ -839,7 +834,7 @@ class ODReader(BackgroundJob):
if whoami.get_pioreactor_version() == (1, 0):
TARGET_REF_VOLTAGE = 0.10
elif whoami.get_pioreactor_version() >= (1, 1):
TARGET_REF_VOLTAGE = 0.04
TARGET_REF_VOLTAGE = 0.50

def __init__(
self,
Expand Down
13 changes: 13 additions & 0 deletions pioreactor/background_jobs/temperature_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from pioreactor import hardware
from pioreactor import whoami
from pioreactor.background_jobs.base import BackgroundJob
from pioreactor.config import config
from pioreactor.structs import Temperature
from pioreactor.structs import TemperatureAutomation
from pioreactor.utils import clamp
Expand All @@ -45,6 +46,7 @@
from pioreactor.utils.timing import current_utc_timestamp
from pioreactor.utils.timing import RepeatedTimer
from pioreactor.utils.timing import to_datetime
from pioreactor.version import rpi_version_info


class TemperatureController(BackgroundJob):
Expand Down Expand Up @@ -406,12 +408,23 @@ def infer_temperature(self) -> None:
previous_heater_dc = self.heater_duty_cycle

features: dict[str, Any] = {}

# add how much heat/energy we just applied
features["previous_heater_dc"] = previous_heater_dc

# figure out a better way to estimate this... luckily inference is not too sensitive to this parameter.
# users can override this function with something more accurate later.
features["room_temp"] = self._get_room_temperature()

# B models have a hotter ambient env. TODO: what about As?
features["is_rpi_zero"] = rpi_version_info.startswith("Raspberry Pi Zero")

# the amount of liquid in the vial is a factor!
features["volume"] = 0.5 * (
config.getfloat("bioreactor", "initial_volume_ml")
+ config.getfloat("bioreactor", "max_volume_ml")
)

# turn off active heating, and start recording decay
self._update_heater(0)
time_series_of_temp = []
Expand Down
22 changes: 9 additions & 13 deletions pioreactor/cli/pio.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,14 @@
from pioreactor.utils.timing import current_utc_timestamp
from pioreactor.whoami import am_I_leader

lazy_subcommands = {
"run": "pioreactor.cli.run.run",
"plugins": "pioreactor.cli.plugins.plugins",
}

if am_I_leader():
lazy_subcommands = {
"workers": "pioreactor.cli.workers.workers",
"run": "pioreactor.cli.run.run",
"plugins": "pioreactor.cli.plugins.plugins",
}
else:
lazy_subcommands = {
"run": "pioreactor.cli.run.run",
"plugins": "pioreactor.cli.plugins.plugins",
}
# add in ability to control workers
lazy_subcommands["workers"] = "pioreactor.cli.workers.workers"


@click.group(
Expand Down Expand Up @@ -175,9 +172,8 @@ def kill(name: str | None, experiment: str | None, job_source: str | None, all_j
if not (name or experiment or job_source or all_jobs):
raise click.Abort("Provide an option to kill.")
with JobManager() as jm:
count = jm.count_jobs(all_jobs=all_jobs, name=name, experiment=experiment, job_source=job_source)
jm.kill_jobs(all_jobs=all_jobs, name=name, experiment=experiment, job_source=job_source)
click.echo(f"Killed {count} job(s).")
count = jm.kill_jobs(all_jobs=all_jobs, name=name, experiment=experiment, job_source=job_source)
click.echo(f"Killed {count} job{'s' if count > 1 else ''}.")


@pio.command(name="version", short_help="print the Pioreactor software version")
Expand Down
2 changes: 1 addition & 1 deletion pioreactor/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def voltage_in_aux(precision: float = 0.1) -> float:

slope = 0.134 # from schematic

adc = ADC_class()
adc = ADC_class() # type: ignore
return round_to_precision(
adc.from_raw_to_voltage(adc.read_from_channel(ADC_CHANNEL_FUNCS["aux"])) / slope,
p=precision,
Expand Down
4 changes: 2 additions & 2 deletions pioreactor/plugin_management/install_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
def install_plugin(name_of_plugin: str, source: str | None = None) -> None:
logger = create_logger("install_plugin", experiment=UNIVERSAL_EXPERIMENT)
logger.debug(f"Installing plugin {name_of_plugin}.")
command = [
command = (
"bash",
"/usr/local/bin/install_pioreactor_plugin.sh",
quote(name_of_plugin),
source or "",
]
)
logger.debug(" ".join(command))

result = subprocess.run(command, capture_output=True)
Expand Down
32 changes: 23 additions & 9 deletions pioreactor/tests/test_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,36 @@ def test_run_job_with_monitor() -> None:
def test_job_options_and_args_to_shell_command() -> None:
m = Monitor
assert (
m._job_options_and_args_to_shell_command("stirring", [], {"target_rpm": 400})
== "JOB_SOURCE=user nohup pio run stirring --target-rpm 400 >/dev/null 2>&1 &"
m._job_options_and_args_to_shell_command("stirring", "Exp001", [], {"target_rpm": 400})
== "JOB_SOURCE=user EXPERIMENT=Exp001 nohup pio run stirring --target-rpm 400 >/dev/null 2>&1 &"
)
assert (
m._job_options_and_args_to_shell_command("stirring", [], {"ignore_rpm": None})
== "JOB_SOURCE=user nohup pio run stirring --ignore-rpm >/dev/null 2>&1 &"
m._job_options_and_args_to_shell_command("stirring", "Exp001", [], {"ignore_rpm": None})
== "JOB_SOURCE=user EXPERIMENT=Exp001 nohup pio run stirring --ignore-rpm >/dev/null 2>&1 &"
)
assert (
m._job_options_and_args_to_shell_command("stirring", [], {})
== "JOB_SOURCE=user nohup pio run stirring >/dev/null 2>&1 &"
m._job_options_and_args_to_shell_command("stirring", "Exp001", [], {})
== "JOB_SOURCE=user EXPERIMENT=Exp001 nohup pio run stirring >/dev/null 2>&1 &"
)
assert (
m._job_options_and_args_to_shell_command("od_calibration", ["list"], {})
== "JOB_SOURCE=user nohup pio run od_calibration list >/dev/null 2>&1 &"
m._job_options_and_args_to_shell_command("od_calibration", "Exp001", ["list"], {})
== "JOB_SOURCE=user EXPERIMENT=Exp001 nohup pio run od_calibration list >/dev/null 2>&1 &"
)
assert (
m._job_options_and_args_to_shell_command("stirring", [], {"job_source": "experiment_profile"})
m._job_options_and_args_to_shell_command(
"stirring", "Exp001", [], {"job_source": "experiment_profile"}
)
== "JOB_SOURCE=experiment_profile EXPERIMENT=Exp001 nohup pio run stirring >/dev/null 2>&1 &"
)

assert (
m._job_options_and_args_to_shell_command("stirring", None, [], {"job_source": "experiment_profile"})
== "JOB_SOURCE=experiment_profile nohup pio run stirring >/dev/null 2>&1 &"
)

assert (
m._job_options_and_args_to_shell_command(
"stirring", "white space", [], {"job_source": "experiment_profile"}
)
== "JOB_SOURCE=experiment_profile EXPERIMENT='white space' nohup pio run stirring >/dev/null 2>&1 &"
)
113 changes: 113 additions & 0 deletions pioreactor/tests/test_od_reading.py
Original file line number Diff line number Diff line change
Expand Up @@ -974,3 +974,116 @@ def test_auto_ir_led_intensity() -> None:
assert od.ir_led_intensity == 20.0

config["od_config"]["ir_led_intensity"] = existing_intensity


def test_CachedCalibrationTransformer_with_real_calibration():
calibration = structs.OD90Calibration(
angle="90",
maximum_od600=1.0,
minimum_od600=0.0,
minimum_voltage=0.044709852782465254,
maximum_voltage=1.359234153183015,
curve_type="poly",
curve_data_=[
-0.9876751958847302,
1.2023377416112089,
0.2591472668916862,
0.8385902257553322,
0.0445071255201746,
],
voltages=[
1.359234153183015,
1.1302469550069834,
0.9620188870414657,
0.8276740491499182,
0.7190293946984384,
0.7476589503369395,
0.566173065500996,
0.46932081671790027,
0.40529520650943107,
0.35571051870062176,
0.3671813602478582,
0.30365395611828694,
0.2546057746249075,
0.22793433386962852,
0.20673156637999296,
0.21349869357483414,
0.182990681059356,
0.15688343308939462,
0.1576635057554899,
0.12760694773293027,
0.1334217593444793,
0.12112005296098335,
0.10527636587260703,
0.10005326421654448,
0.08968165025432195,
0.0934433078631241,
0.08568480676160387,
0.07354768447704799,
0.07012049853534189,
0.06976807020449396,
0.0692776692431696,
0.06519934195388995,
0.05689993752281371,
0.06139548846791462,
0.05434995401134063,
0.058377357520436435,
0.05744855604656168,
0.051622250927144994,
0.04809794996045024,
0.044709852782465254,
],
od600s=[
1.0,
0.8333333333333334,
0.7142857142857143,
0.625,
0.5555555555555556,
0.58,
0.48333333333333334,
0.41428571428571426,
0.3625,
0.3222222222222222,
0.3,
0.25,
0.21428571428571427,
0.1875,
0.16666666666666666,
0.18,
0.15,
0.12857142857142856,
0.11249999999999999,
0.09999999999999999,
0.1,
0.08333333333333333,
0.07142857142857142,
0.0625,
0.05555555555555555,
0.065,
0.05416666666666667,
0.04642857142857143,
0.040625,
0.036111111111111115,
0.04,
0.03333333333333333,
0.028571428571428574,
0.025,
0.022222222222222223,
0.03,
0.024999999999999998,
0.02142857142857143,
0.01875,
0.0,
],
ir_led_intensity=50,
pd_channel="2",
created_at="2024-05-10T14:13:20.698706Z",
pioreactor_unit="pio1",
name="test",
)
with local_persistant_storage("current_od_calibration") as cc:
cc[calibration.angle] = encode(calibration)

cal_transformer = CachedCalibrationTransformer({"2": "90"})

assert abs(cal_transformer({"2": 0.096})["2"] - 0.06) < 0.01
Loading

0 comments on commit 0be505a

Please sign in to comment.