opentrons 8.6.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of opentrons might be problematic. Click here for more details.
- opentrons/__init__.py +150 -0
- opentrons/_version.py +34 -0
- opentrons/calibration_storage/__init__.py +54 -0
- opentrons/calibration_storage/deck_configuration.py +62 -0
- opentrons/calibration_storage/encoder_decoder.py +31 -0
- opentrons/calibration_storage/file_operators.py +142 -0
- opentrons/calibration_storage/helpers.py +103 -0
- opentrons/calibration_storage/ot2/__init__.py +34 -0
- opentrons/calibration_storage/ot2/deck_attitude.py +85 -0
- opentrons/calibration_storage/ot2/mark_bad_calibration.py +27 -0
- opentrons/calibration_storage/ot2/models/__init__.py +0 -0
- opentrons/calibration_storage/ot2/models/v1.py +149 -0
- opentrons/calibration_storage/ot2/pipette_offset.py +129 -0
- opentrons/calibration_storage/ot2/tip_length.py +281 -0
- opentrons/calibration_storage/ot3/__init__.py +31 -0
- opentrons/calibration_storage/ot3/deck_attitude.py +83 -0
- opentrons/calibration_storage/ot3/gripper_offset.py +156 -0
- opentrons/calibration_storage/ot3/models/__init__.py +0 -0
- opentrons/calibration_storage/ot3/models/v1.py +122 -0
- opentrons/calibration_storage/ot3/module_offset.py +138 -0
- opentrons/calibration_storage/ot3/pipette_offset.py +95 -0
- opentrons/calibration_storage/types.py +45 -0
- opentrons/cli/__init__.py +21 -0
- opentrons/cli/__main__.py +5 -0
- opentrons/cli/analyze.py +501 -0
- opentrons/config/__init__.py +631 -0
- opentrons/config/advanced_settings.py +871 -0
- opentrons/config/defaults_ot2.py +214 -0
- opentrons/config/defaults_ot3.py +499 -0
- opentrons/config/feature_flags.py +86 -0
- opentrons/config/gripper_config.py +55 -0
- opentrons/config/reset.py +203 -0
- opentrons/config/robot_configs.py +187 -0
- opentrons/config/types.py +183 -0
- opentrons/drivers/__init__.py +0 -0
- opentrons/drivers/absorbance_reader/__init__.py +11 -0
- opentrons/drivers/absorbance_reader/abstract.py +72 -0
- opentrons/drivers/absorbance_reader/async_byonoy.py +352 -0
- opentrons/drivers/absorbance_reader/driver.py +81 -0
- opentrons/drivers/absorbance_reader/hid_protocol.py +161 -0
- opentrons/drivers/absorbance_reader/simulator.py +84 -0
- opentrons/drivers/asyncio/__init__.py +0 -0
- opentrons/drivers/asyncio/communication/__init__.py +22 -0
- opentrons/drivers/asyncio/communication/async_serial.py +183 -0
- opentrons/drivers/asyncio/communication/errors.py +88 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +552 -0
- opentrons/drivers/command_builder.py +102 -0
- opentrons/drivers/flex_stacker/__init__.py +13 -0
- opentrons/drivers/flex_stacker/abstract.py +214 -0
- opentrons/drivers/flex_stacker/driver.py +768 -0
- opentrons/drivers/flex_stacker/errors.py +68 -0
- opentrons/drivers/flex_stacker/simulator.py +309 -0
- opentrons/drivers/flex_stacker/types.py +367 -0
- opentrons/drivers/flex_stacker/utils.py +19 -0
- opentrons/drivers/heater_shaker/__init__.py +5 -0
- opentrons/drivers/heater_shaker/abstract.py +76 -0
- opentrons/drivers/heater_shaker/driver.py +204 -0
- opentrons/drivers/heater_shaker/simulator.py +94 -0
- opentrons/drivers/mag_deck/__init__.py +6 -0
- opentrons/drivers/mag_deck/abstract.py +44 -0
- opentrons/drivers/mag_deck/driver.py +208 -0
- opentrons/drivers/mag_deck/simulator.py +63 -0
- opentrons/drivers/rpi_drivers/__init__.py +33 -0
- opentrons/drivers/rpi_drivers/dev_types.py +94 -0
- opentrons/drivers/rpi_drivers/gpio.py +282 -0
- opentrons/drivers/rpi_drivers/gpio_simulator.py +127 -0
- opentrons/drivers/rpi_drivers/interfaces.py +15 -0
- opentrons/drivers/rpi_drivers/types.py +364 -0
- opentrons/drivers/rpi_drivers/usb.py +102 -0
- opentrons/drivers/rpi_drivers/usb_simulator.py +22 -0
- opentrons/drivers/serial_communication.py +151 -0
- opentrons/drivers/smoothie_drivers/__init__.py +4 -0
- opentrons/drivers/smoothie_drivers/connection.py +51 -0
- opentrons/drivers/smoothie_drivers/constants.py +121 -0
- opentrons/drivers/smoothie_drivers/driver_3_0.py +1933 -0
- opentrons/drivers/smoothie_drivers/errors.py +49 -0
- opentrons/drivers/smoothie_drivers/parse_utils.py +143 -0
- opentrons/drivers/smoothie_drivers/simulator.py +99 -0
- opentrons/drivers/smoothie_drivers/types.py +16 -0
- opentrons/drivers/temp_deck/__init__.py +10 -0
- opentrons/drivers/temp_deck/abstract.py +54 -0
- opentrons/drivers/temp_deck/driver.py +197 -0
- opentrons/drivers/temp_deck/simulator.py +57 -0
- opentrons/drivers/thermocycler/__init__.py +12 -0
- opentrons/drivers/thermocycler/abstract.py +99 -0
- opentrons/drivers/thermocycler/driver.py +395 -0
- opentrons/drivers/thermocycler/simulator.py +126 -0
- opentrons/drivers/types.py +107 -0
- opentrons/drivers/utils.py +222 -0
- opentrons/execute.py +742 -0
- opentrons/hardware_control/__init__.py +65 -0
- opentrons/hardware_control/__main__.py +77 -0
- opentrons/hardware_control/adapters.py +98 -0
- opentrons/hardware_control/api.py +1347 -0
- opentrons/hardware_control/backends/__init__.py +7 -0
- opentrons/hardware_control/backends/controller.py +400 -0
- opentrons/hardware_control/backends/errors.py +9 -0
- opentrons/hardware_control/backends/estop_state.py +164 -0
- opentrons/hardware_control/backends/flex_protocol.py +497 -0
- opentrons/hardware_control/backends/ot3controller.py +1930 -0
- opentrons/hardware_control/backends/ot3simulator.py +900 -0
- opentrons/hardware_control/backends/ot3utils.py +664 -0
- opentrons/hardware_control/backends/simulator.py +442 -0
- opentrons/hardware_control/backends/status_bar_state.py +240 -0
- opentrons/hardware_control/backends/subsystem_manager.py +431 -0
- opentrons/hardware_control/backends/tip_presence_manager.py +173 -0
- opentrons/hardware_control/backends/types.py +14 -0
- opentrons/hardware_control/constants.py +6 -0
- opentrons/hardware_control/dev_types.py +125 -0
- opentrons/hardware_control/emulation/__init__.py +0 -0
- opentrons/hardware_control/emulation/abstract_emulator.py +21 -0
- opentrons/hardware_control/emulation/app.py +56 -0
- opentrons/hardware_control/emulation/connection_handler.py +38 -0
- opentrons/hardware_control/emulation/heater_shaker.py +150 -0
- opentrons/hardware_control/emulation/magdeck.py +60 -0
- opentrons/hardware_control/emulation/module_server/__init__.py +8 -0
- opentrons/hardware_control/emulation/module_server/client.py +78 -0
- opentrons/hardware_control/emulation/module_server/helpers.py +130 -0
- opentrons/hardware_control/emulation/module_server/models.py +31 -0
- opentrons/hardware_control/emulation/module_server/server.py +110 -0
- opentrons/hardware_control/emulation/parser.py +74 -0
- opentrons/hardware_control/emulation/proxy.py +241 -0
- opentrons/hardware_control/emulation/run_emulator.py +68 -0
- opentrons/hardware_control/emulation/scripts/__init__.py +0 -0
- opentrons/hardware_control/emulation/scripts/run_app.py +54 -0
- opentrons/hardware_control/emulation/scripts/run_module_emulator.py +72 -0
- opentrons/hardware_control/emulation/scripts/run_smoothie.py +37 -0
- opentrons/hardware_control/emulation/settings.py +119 -0
- opentrons/hardware_control/emulation/simulations.py +133 -0
- opentrons/hardware_control/emulation/smoothie.py +192 -0
- opentrons/hardware_control/emulation/tempdeck.py +69 -0
- opentrons/hardware_control/emulation/thermocycler.py +128 -0
- opentrons/hardware_control/emulation/types.py +10 -0
- opentrons/hardware_control/emulation/util.py +38 -0
- opentrons/hardware_control/errors.py +43 -0
- opentrons/hardware_control/execution_manager.py +164 -0
- opentrons/hardware_control/instruments/__init__.py +5 -0
- opentrons/hardware_control/instruments/instrument_abc.py +39 -0
- opentrons/hardware_control/instruments/ot2/__init__.py +0 -0
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +152 -0
- opentrons/hardware_control/instruments/ot2/pipette.py +777 -0
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +995 -0
- opentrons/hardware_control/instruments/ot3/__init__.py +0 -0
- opentrons/hardware_control/instruments/ot3/gripper.py +420 -0
- opentrons/hardware_control/instruments/ot3/gripper_handler.py +173 -0
- opentrons/hardware_control/instruments/ot3/instrument_calibration.py +214 -0
- opentrons/hardware_control/instruments/ot3/pipette.py +858 -0
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +1030 -0
- opentrons/hardware_control/module_control.py +332 -0
- opentrons/hardware_control/modules/__init__.py +69 -0
- opentrons/hardware_control/modules/absorbance_reader.py +373 -0
- opentrons/hardware_control/modules/errors.py +7 -0
- opentrons/hardware_control/modules/flex_stacker.py +948 -0
- opentrons/hardware_control/modules/heater_shaker.py +426 -0
- opentrons/hardware_control/modules/lid_temp_status.py +35 -0
- opentrons/hardware_control/modules/magdeck.py +233 -0
- opentrons/hardware_control/modules/mod_abc.py +245 -0
- opentrons/hardware_control/modules/module_calibration.py +93 -0
- opentrons/hardware_control/modules/plate_temp_status.py +61 -0
- opentrons/hardware_control/modules/tempdeck.py +299 -0
- opentrons/hardware_control/modules/thermocycler.py +731 -0
- opentrons/hardware_control/modules/types.py +417 -0
- opentrons/hardware_control/modules/update.py +255 -0
- opentrons/hardware_control/modules/utils.py +73 -0
- opentrons/hardware_control/motion_utilities.py +318 -0
- opentrons/hardware_control/nozzle_manager.py +422 -0
- opentrons/hardware_control/ot3_calibration.py +1171 -0
- opentrons/hardware_control/ot3api.py +3227 -0
- opentrons/hardware_control/pause_manager.py +31 -0
- opentrons/hardware_control/poller.py +112 -0
- opentrons/hardware_control/protocols/__init__.py +106 -0
- opentrons/hardware_control/protocols/asyncio_configurable.py +11 -0
- opentrons/hardware_control/protocols/calibratable.py +45 -0
- opentrons/hardware_control/protocols/chassis_accessory_manager.py +90 -0
- opentrons/hardware_control/protocols/configurable.py +48 -0
- opentrons/hardware_control/protocols/event_sourcer.py +18 -0
- opentrons/hardware_control/protocols/execution_controllable.py +33 -0
- opentrons/hardware_control/protocols/flex_calibratable.py +96 -0
- opentrons/hardware_control/protocols/flex_instrument_configurer.py +52 -0
- opentrons/hardware_control/protocols/gripper_controller.py +55 -0
- opentrons/hardware_control/protocols/hardware_manager.py +51 -0
- opentrons/hardware_control/protocols/identifiable.py +16 -0
- opentrons/hardware_control/protocols/instrument_configurer.py +206 -0
- opentrons/hardware_control/protocols/liquid_handler.py +266 -0
- opentrons/hardware_control/protocols/module_provider.py +16 -0
- opentrons/hardware_control/protocols/motion_controller.py +243 -0
- opentrons/hardware_control/protocols/position_estimator.py +45 -0
- opentrons/hardware_control/protocols/simulatable.py +10 -0
- opentrons/hardware_control/protocols/stoppable.py +9 -0
- opentrons/hardware_control/protocols/types.py +27 -0
- opentrons/hardware_control/robot_calibration.py +224 -0
- opentrons/hardware_control/scripts/README.md +28 -0
- opentrons/hardware_control/scripts/__init__.py +1 -0
- opentrons/hardware_control/scripts/gripper_control.py +208 -0
- opentrons/hardware_control/scripts/ot3gripper +7 -0
- opentrons/hardware_control/scripts/ot3repl +7 -0
- opentrons/hardware_control/scripts/repl.py +187 -0
- opentrons/hardware_control/scripts/tc_control.py +97 -0
- opentrons/hardware_control/simulator_setup.py +260 -0
- opentrons/hardware_control/thread_manager.py +431 -0
- opentrons/hardware_control/threaded_async_lock.py +97 -0
- opentrons/hardware_control/types.py +792 -0
- opentrons/hardware_control/util.py +234 -0
- opentrons/legacy_broker.py +53 -0
- opentrons/legacy_commands/__init__.py +1 -0
- opentrons/legacy_commands/commands.py +483 -0
- opentrons/legacy_commands/helpers.py +153 -0
- opentrons/legacy_commands/module_commands.py +215 -0
- opentrons/legacy_commands/protocol_commands.py +54 -0
- opentrons/legacy_commands/publisher.py +155 -0
- opentrons/legacy_commands/robot_commands.py +51 -0
- opentrons/legacy_commands/types.py +1115 -0
- opentrons/motion_planning/__init__.py +32 -0
- opentrons/motion_planning/adjacent_slots_getters.py +168 -0
- opentrons/motion_planning/deck_conflict.py +396 -0
- opentrons/motion_planning/errors.py +35 -0
- opentrons/motion_planning/types.py +42 -0
- opentrons/motion_planning/waypoints.py +218 -0
- opentrons/ordered_set.py +138 -0
- opentrons/protocol_api/__init__.py +105 -0
- opentrons/protocol_api/_liquid.py +157 -0
- opentrons/protocol_api/_liquid_properties.py +814 -0
- opentrons/protocol_api/_nozzle_layout.py +31 -0
- opentrons/protocol_api/_parameter_context.py +300 -0
- opentrons/protocol_api/_parameters.py +31 -0
- opentrons/protocol_api/_transfer_liquid_validation.py +108 -0
- opentrons/protocol_api/_types.py +43 -0
- opentrons/protocol_api/config.py +23 -0
- opentrons/protocol_api/core/__init__.py +23 -0
- opentrons/protocol_api/core/common.py +33 -0
- opentrons/protocol_api/core/core_map.py +74 -0
- opentrons/protocol_api/core/engine/__init__.py +22 -0
- opentrons/protocol_api/core/engine/_default_labware_versions.py +179 -0
- opentrons/protocol_api/core/engine/deck_conflict.py +348 -0
- opentrons/protocol_api/core/engine/exceptions.py +19 -0
- opentrons/protocol_api/core/engine/instrument.py +2391 -0
- opentrons/protocol_api/core/engine/labware.py +238 -0
- opentrons/protocol_api/core/engine/load_labware_params.py +73 -0
- opentrons/protocol_api/core/engine/module_core.py +1025 -0
- opentrons/protocol_api/core/engine/overlap_versions.py +20 -0
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +358 -0
- opentrons/protocol_api/core/engine/point_calculations.py +64 -0
- opentrons/protocol_api/core/engine/protocol.py +1153 -0
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/stringify.py +74 -0
- opentrons/protocol_api/core/engine/transfer_components_executor.py +990 -0
- opentrons/protocol_api/core/engine/well.py +241 -0
- opentrons/protocol_api/core/instrument.py +459 -0
- opentrons/protocol_api/core/labware.py +151 -0
- opentrons/protocol_api/core/legacy/__init__.py +11 -0
- opentrons/protocol_api/core/legacy/_labware_geometry.py +37 -0
- opentrons/protocol_api/core/legacy/deck.py +369 -0
- opentrons/protocol_api/core/legacy/labware_offset_provider.py +108 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +709 -0
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +235 -0
- opentrons/protocol_api/core/legacy/legacy_module_core.py +592 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +612 -0
- opentrons/protocol_api/core/legacy/legacy_well_core.py +162 -0
- opentrons/protocol_api/core/legacy/load_info.py +67 -0
- opentrons/protocol_api/core/legacy/module_geometry.py +547 -0
- opentrons/protocol_api/core/legacy/well_geometry.py +148 -0
- opentrons/protocol_api/core/legacy_simulator/__init__.py +16 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +624 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +85 -0
- opentrons/protocol_api/core/module.py +484 -0
- opentrons/protocol_api/core/protocol.py +311 -0
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/core/well.py +116 -0
- opentrons/protocol_api/core/well_grid.py +45 -0
- opentrons/protocol_api/create_protocol_context.py +177 -0
- opentrons/protocol_api/deck.py +223 -0
- opentrons/protocol_api/disposal_locations.py +244 -0
- opentrons/protocol_api/instrument_context.py +3212 -0
- opentrons/protocol_api/labware.py +1579 -0
- opentrons/protocol_api/module_contexts.py +1425 -0
- opentrons/protocol_api/module_validation_and_errors.py +61 -0
- opentrons/protocol_api/protocol_context.py +1688 -0
- opentrons/protocol_api/robot_context.py +303 -0
- opentrons/protocol_api/validation.py +761 -0
- opentrons/protocol_engine/__init__.py +155 -0
- opentrons/protocol_engine/actions/__init__.py +65 -0
- opentrons/protocol_engine/actions/action_dispatcher.py +30 -0
- opentrons/protocol_engine/actions/action_handler.py +13 -0
- opentrons/protocol_engine/actions/actions.py +302 -0
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/__init__.py +5 -0
- opentrons/protocol_engine/clients/sync_client.py +174 -0
- opentrons/protocol_engine/clients/transports.py +197 -0
- opentrons/protocol_engine/commands/__init__.py +757 -0
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +61 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +154 -0
- opentrons/protocol_engine/commands/absorbance_reader/common.py +6 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +151 -0
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +154 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +226 -0
- opentrons/protocol_engine/commands/air_gap_in_place.py +162 -0
- opentrons/protocol_engine/commands/aspirate.py +244 -0
- opentrons/protocol_engine/commands/aspirate_in_place.py +184 -0
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +211 -0
- opentrons/protocol_engine/commands/blow_out.py +146 -0
- opentrons/protocol_engine/commands/blow_out_in_place.py +119 -0
- opentrons/protocol_engine/commands/calibration/__init__.py +60 -0
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +166 -0
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +117 -0
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +96 -0
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +156 -0
- opentrons/protocol_engine/commands/command.py +308 -0
- opentrons/protocol_engine/commands/command_unions.py +974 -0
- opentrons/protocol_engine/commands/comment.py +57 -0
- opentrons/protocol_engine/commands/configure_for_volume.py +108 -0
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +115 -0
- opentrons/protocol_engine/commands/custom.py +67 -0
- opentrons/protocol_engine/commands/dispense.py +194 -0
- opentrons/protocol_engine/commands/dispense_in_place.py +179 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
- opentrons/protocol_engine/commands/drop_tip.py +232 -0
- opentrons/protocol_engine/commands/drop_tip_in_place.py +205 -0
- opentrons/protocol_engine/commands/flex_stacker/__init__.py +64 -0
- opentrons/protocol_engine/commands/flex_stacker/common.py +900 -0
- opentrons/protocol_engine/commands/flex_stacker/empty.py +293 -0
- opentrons/protocol_engine/commands/flex_stacker/fill.py +281 -0
- opentrons/protocol_engine/commands/flex_stacker/retrieve.py +339 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +328 -0
- opentrons/protocol_engine/commands/flex_stacker/store.py +326 -0
- opentrons/protocol_engine/commands/generate_command_schema.py +61 -0
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +87 -0
- opentrons/protocol_engine/commands/hash_command_params.py +38 -0
- opentrons/protocol_engine/commands/heater_shaker/__init__.py +102 -0
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +83 -0
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +82 -0
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +84 -0
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +110 -0
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +125 -0
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +90 -0
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +102 -0
- opentrons/protocol_engine/commands/home.py +100 -0
- opentrons/protocol_engine/commands/identify_module.py +86 -0
- opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
- opentrons/protocol_engine/commands/liquid_probe.py +464 -0
- opentrons/protocol_engine/commands/load_labware.py +210 -0
- opentrons/protocol_engine/commands/load_lid.py +154 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +272 -0
- opentrons/protocol_engine/commands/load_liquid.py +95 -0
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +223 -0
- opentrons/protocol_engine/commands/load_pipette.py +167 -0
- opentrons/protocol_engine/commands/magnetic_module/__init__.py +32 -0
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +97 -0
- opentrons/protocol_engine/commands/magnetic_module/engage.py +119 -0
- opentrons/protocol_engine/commands/move_labware.py +546 -0
- opentrons/protocol_engine/commands/move_relative.py +102 -0
- opentrons/protocol_engine/commands/move_to_addressable_area.py +176 -0
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +198 -0
- opentrons/protocol_engine/commands/move_to_coordinates.py +107 -0
- opentrons/protocol_engine/commands/move_to_well.py +119 -0
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +241 -0
- opentrons/protocol_engine/commands/pipetting_common.py +443 -0
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +121 -0
- opentrons/protocol_engine/commands/pressure_dispense.py +155 -0
- opentrons/protocol_engine/commands/reload_labware.py +90 -0
- opentrons/protocol_engine/commands/retract_axis.py +75 -0
- opentrons/protocol_engine/commands/robot/__init__.py +70 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +96 -0
- opentrons/protocol_engine/commands/robot/common.py +18 -0
- opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
- opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
- opentrons/protocol_engine/commands/robot/move_to.py +94 -0
- opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +86 -0
- opentrons/protocol_engine/commands/save_position.py +109 -0
- opentrons/protocol_engine/commands/seal_pipette_to_tip.py +353 -0
- opentrons/protocol_engine/commands/set_rail_lights.py +67 -0
- opentrons/protocol_engine/commands/set_status_bar.py +89 -0
- opentrons/protocol_engine/commands/temperature_module/__init__.py +46 -0
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +86 -0
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +97 -0
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +104 -0
- opentrons/protocol_engine/commands/thermocycler/__init__.py +152 -0
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +87 -0
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +80 -0
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +80 -0
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +87 -0
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +171 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +124 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +140 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +100 -0
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +93 -0
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +89 -0
- opentrons/protocol_engine/commands/touch_tip.py +189 -0
- opentrons/protocol_engine/commands/unsafe/__init__.py +161 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +100 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +121 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +82 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_close_latch.py +94 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_manual_retrieve.py +295 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_open_latch.py +91 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_prepare_shuttle.py +136 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +90 -0
- opentrons/protocol_engine/commands/unseal_pipette_from_tip.py +153 -0
- opentrons/protocol_engine/commands/verify_tip_presence.py +100 -0
- opentrons/protocol_engine/commands/wait_for_duration.py +76 -0
- opentrons/protocol_engine/commands/wait_for_resume.py +75 -0
- opentrons/protocol_engine/create_protocol_engine.py +193 -0
- opentrons/protocol_engine/engine_support.py +28 -0
- opentrons/protocol_engine/error_recovery_policy.py +81 -0
- opentrons/protocol_engine/errors/__init__.py +191 -0
- opentrons/protocol_engine/errors/error_occurrence.py +182 -0
- opentrons/protocol_engine/errors/exceptions.py +1308 -0
- opentrons/protocol_engine/execution/__init__.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +216 -0
- opentrons/protocol_engine/execution/create_queue_worker.py +102 -0
- opentrons/protocol_engine/execution/door_watcher.py +119 -0
- opentrons/protocol_engine/execution/equipment.py +819 -0
- opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
- opentrons/protocol_engine/execution/gantry_mover.py +686 -0
- opentrons/protocol_engine/execution/hardware_stopper.py +147 -0
- opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +207 -0
- opentrons/protocol_engine/execution/labware_movement.py +297 -0
- opentrons/protocol_engine/execution/movement.py +349 -0
- opentrons/protocol_engine/execution/pipetting.py +607 -0
- opentrons/protocol_engine/execution/queue_worker.py +86 -0
- opentrons/protocol_engine/execution/rail_lights.py +25 -0
- opentrons/protocol_engine/execution/run_control.py +33 -0
- opentrons/protocol_engine/execution/status_bar.py +34 -0
- opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +188 -0
- opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +81 -0
- opentrons/protocol_engine/execution/tip_handler.py +550 -0
- opentrons/protocol_engine/labware_offset_standardization.py +194 -0
- opentrons/protocol_engine/notes/__init__.py +17 -0
- opentrons/protocol_engine/notes/notes.py +59 -0
- opentrons/protocol_engine/plugins.py +104 -0
- opentrons/protocol_engine/protocol_engine.py +683 -0
- opentrons/protocol_engine/resources/__init__.py +26 -0
- opentrons/protocol_engine/resources/deck_configuration_provider.py +232 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +94 -0
- opentrons/protocol_engine/resources/file_provider.py +161 -0
- opentrons/protocol_engine/resources/fixture_validation.py +58 -0
- opentrons/protocol_engine/resources/labware_data_provider.py +106 -0
- opentrons/protocol_engine/resources/labware_validation.py +73 -0
- opentrons/protocol_engine/resources/model_utils.py +32 -0
- opentrons/protocol_engine/resources/module_data_provider.py +44 -0
- opentrons/protocol_engine/resources/ot3_validation.py +21 -0
- opentrons/protocol_engine/resources/pipette_data_provider.py +379 -0
- opentrons/protocol_engine/slot_standardization.py +128 -0
- opentrons/protocol_engine/state/__init__.py +1 -0
- opentrons/protocol_engine/state/_abstract_store.py +27 -0
- opentrons/protocol_engine/state/_axis_aligned_bounding_box.py +50 -0
- opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
- opentrons/protocol_engine/state/_move_types.py +83 -0
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +699 -0
- opentrons/protocol_engine/state/command_history.py +309 -0
- opentrons/protocol_engine/state/commands.py +1158 -0
- opentrons/protocol_engine/state/config.py +39 -0
- opentrons/protocol_engine/state/files.py +57 -0
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/geometry.py +2359 -0
- opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
- opentrons/protocol_engine/state/labware.py +1459 -0
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +73 -0
- opentrons/protocol_engine/state/module_substates/__init__.py +45 -0
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +35 -0
- opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +112 -0
- opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +115 -0
- opentrons/protocol_engine/state/module_substates/magnetic_block_substate.py +17 -0
- opentrons/protocol_engine/state/module_substates/magnetic_module_substate.py +65 -0
- opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +67 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +163 -0
- opentrons/protocol_engine/state/modules.py +1500 -0
- opentrons/protocol_engine/state/motion.py +373 -0
- opentrons/protocol_engine/state/pipettes.py +905 -0
- opentrons/protocol_engine/state/state.py +421 -0
- opentrons/protocol_engine/state/state_summary.py +36 -0
- opentrons/protocol_engine/state/tips.py +420 -0
- opentrons/protocol_engine/state/update_types.py +904 -0
- opentrons/protocol_engine/state/wells.py +290 -0
- opentrons/protocol_engine/types/__init__.py +308 -0
- opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
- opentrons/protocol_engine/types/command_annotations.py +53 -0
- opentrons/protocol_engine/types/deck_configuration.py +81 -0
- opentrons/protocol_engine/types/execution.py +96 -0
- opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
- opentrons/protocol_engine/types/instrument.py +47 -0
- opentrons/protocol_engine/types/instrument_sensors.py +47 -0
- opentrons/protocol_engine/types/labware.py +131 -0
- opentrons/protocol_engine/types/labware_movement.py +22 -0
- opentrons/protocol_engine/types/labware_offset_location.py +111 -0
- opentrons/protocol_engine/types/labware_offset_vector.py +16 -0
- opentrons/protocol_engine/types/liquid.py +40 -0
- opentrons/protocol_engine/types/liquid_class.py +59 -0
- opentrons/protocol_engine/types/liquid_handling.py +13 -0
- opentrons/protocol_engine/types/liquid_level_detection.py +191 -0
- opentrons/protocol_engine/types/location.py +194 -0
- opentrons/protocol_engine/types/module.py +303 -0
- opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
- opentrons/protocol_engine/types/run_time_parameters.py +133 -0
- opentrons/protocol_engine/types/tip.py +18 -0
- opentrons/protocol_engine/types/util.py +21 -0
- opentrons/protocol_engine/types/well_position.py +124 -0
- opentrons/protocol_reader/__init__.py +37 -0
- opentrons/protocol_reader/extract_labware_definitions.py +66 -0
- opentrons/protocol_reader/file_format_validator.py +152 -0
- opentrons/protocol_reader/file_hasher.py +27 -0
- opentrons/protocol_reader/file_identifier.py +284 -0
- opentrons/protocol_reader/file_reader_writer.py +90 -0
- opentrons/protocol_reader/input_file.py +16 -0
- opentrons/protocol_reader/protocol_files_invalid_error.py +6 -0
- opentrons/protocol_reader/protocol_reader.py +188 -0
- opentrons/protocol_reader/protocol_source.py +124 -0
- opentrons/protocol_reader/role_analyzer.py +86 -0
- opentrons/protocol_runner/__init__.py +26 -0
- opentrons/protocol_runner/create_simulating_orchestrator.py +118 -0
- opentrons/protocol_runner/json_file_reader.py +55 -0
- opentrons/protocol_runner/json_translator.py +314 -0
- opentrons/protocol_runner/legacy_command_mapper.py +848 -0
- opentrons/protocol_runner/legacy_context_plugin.py +116 -0
- opentrons/protocol_runner/protocol_runner.py +530 -0
- opentrons/protocol_runner/python_protocol_wrappers.py +179 -0
- opentrons/protocol_runner/run_orchestrator.py +496 -0
- opentrons/protocol_runner/task_queue.py +95 -0
- opentrons/protocols/__init__.py +6 -0
- opentrons/protocols/advanced_control/__init__.py +0 -0
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +60 -0
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +180 -0
- opentrons/protocols/advanced_control/transfers/transfer.py +972 -0
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +231 -0
- opentrons/protocols/api_support/__init__.py +0 -0
- opentrons/protocols/api_support/constants.py +8 -0
- opentrons/protocols/api_support/deck_type.py +110 -0
- opentrons/protocols/api_support/definitions.py +18 -0
- opentrons/protocols/api_support/instrument.py +151 -0
- opentrons/protocols/api_support/labware_like.py +233 -0
- opentrons/protocols/api_support/tip_tracker.py +175 -0
- opentrons/protocols/api_support/types.py +32 -0
- opentrons/protocols/api_support/util.py +403 -0
- opentrons/protocols/bundle.py +89 -0
- opentrons/protocols/duration/__init__.py +4 -0
- opentrons/protocols/duration/errors.py +5 -0
- opentrons/protocols/duration/estimator.py +628 -0
- opentrons/protocols/execution/__init__.py +0 -0
- opentrons/protocols/execution/dev_types.py +181 -0
- opentrons/protocols/execution/errors.py +40 -0
- opentrons/protocols/execution/execute.py +84 -0
- opentrons/protocols/execution/execute_json_v3.py +275 -0
- opentrons/protocols/execution/execute_json_v4.py +359 -0
- opentrons/protocols/execution/execute_json_v5.py +28 -0
- opentrons/protocols/execution/execute_python.py +169 -0
- opentrons/protocols/execution/json_dispatchers.py +87 -0
- opentrons/protocols/execution/types.py +7 -0
- opentrons/protocols/geometry/__init__.py +0 -0
- opentrons/protocols/geometry/planning.py +297 -0
- opentrons/protocols/labware.py +312 -0
- opentrons/protocols/models/__init__.py +0 -0
- opentrons/protocols/models/json_protocol.py +679 -0
- opentrons/protocols/parameters/__init__.py +0 -0
- opentrons/protocols/parameters/csv_parameter_definition.py +77 -0
- opentrons/protocols/parameters/csv_parameter_interface.py +96 -0
- opentrons/protocols/parameters/exceptions.py +34 -0
- opentrons/protocols/parameters/parameter_definition.py +272 -0
- opentrons/protocols/parameters/types.py +17 -0
- opentrons/protocols/parameters/validation.py +267 -0
- opentrons/protocols/parse.py +671 -0
- opentrons/protocols/types.py +159 -0
- opentrons/py.typed +0 -0
- opentrons/resources/scripts/lpc21isp +0 -0
- opentrons/resources/smoothie-edge-8414642.hex +23010 -0
- opentrons/simulate.py +1065 -0
- opentrons/system/__init__.py +6 -0
- opentrons/system/camera.py +51 -0
- opentrons/system/log_control.py +59 -0
- opentrons/system/nmcli.py +856 -0
- opentrons/system/resin.py +24 -0
- opentrons/system/smoothie_update.py +15 -0
- opentrons/system/wifi.py +204 -0
- opentrons/tools/__init__.py +0 -0
- opentrons/tools/args_handler.py +22 -0
- opentrons/tools/write_pipette_memory.py +157 -0
- opentrons/types.py +618 -0
- opentrons/util/__init__.py +1 -0
- opentrons/util/async_helpers.py +166 -0
- opentrons/util/broker.py +84 -0
- opentrons/util/change_notifier.py +47 -0
- opentrons/util/entrypoint_util.py +278 -0
- opentrons/util/get_union_elements.py +26 -0
- opentrons/util/helpers.py +6 -0
- opentrons/util/linal.py +178 -0
- opentrons/util/logging_config.py +265 -0
- opentrons/util/logging_queue_handler.py +61 -0
- opentrons/util/performance_helpers.py +157 -0
- opentrons-8.6.0a1.dist-info/METADATA +37 -0
- opentrons-8.6.0a1.dist-info/RECORD +600 -0
- opentrons-8.6.0a1.dist-info/WHEEL +4 -0
- opentrons-8.6.0a1.dist-info/entry_points.txt +3 -0
- opentrons-8.6.0a1.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
"""Helper functions for liquid-level related calculations inside a given frustum."""
|
|
2
|
+
from typing import List, Tuple
|
|
3
|
+
from numpy import pi, iscomplex, roots, real
|
|
4
|
+
from math import isclose
|
|
5
|
+
|
|
6
|
+
from ..errors.exceptions import InvalidLiquidHeightFound, InvalidUserDefinedVolumesError
|
|
7
|
+
|
|
8
|
+
from opentrons.protocol_engine.types.liquid_level_detection import (
|
|
9
|
+
LiquidTrackingType,
|
|
10
|
+
SimulatedProbeResult,
|
|
11
|
+
)
|
|
12
|
+
from opentrons_shared_data.labware.labware_definition import (
|
|
13
|
+
InnerWellGeometry,
|
|
14
|
+
WellSegment,
|
|
15
|
+
SphericalSegment,
|
|
16
|
+
ConicalFrustum,
|
|
17
|
+
CuboidalFrustum,
|
|
18
|
+
SquaredConeSegment,
|
|
19
|
+
UserDefinedVolumes,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _reject_unacceptable_heights(
|
|
24
|
+
potential_heights: List[float], max_height: float
|
|
25
|
+
) -> float:
|
|
26
|
+
"""Reject any solutions to a polynomial equation that cannot be the height of a frustum."""
|
|
27
|
+
valid_heights: List[float] = []
|
|
28
|
+
for root in potential_heights:
|
|
29
|
+
# reject any heights that are negative or greater than the max height
|
|
30
|
+
if not iscomplex(root):
|
|
31
|
+
# take only the real component of the root and round to 4 decimal places
|
|
32
|
+
rounded_root = round(real(root), 4)
|
|
33
|
+
if (rounded_root <= max_height) and (rounded_root >= 0):
|
|
34
|
+
if not any([isclose(rounded_root, height) for height in valid_heights]):
|
|
35
|
+
valid_heights.append(rounded_root)
|
|
36
|
+
if len(valid_heights) != 1:
|
|
37
|
+
raise InvalidLiquidHeightFound(
|
|
38
|
+
message="Unable to estimate valid liquid height from volume."
|
|
39
|
+
)
|
|
40
|
+
return valid_heights[0]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _cross_section_area_circular(diameter: float) -> float:
|
|
44
|
+
"""Get the area of a circular cross-section."""
|
|
45
|
+
radius = diameter / 2
|
|
46
|
+
return pi * (radius**2)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _cross_section_area_rectangular(x_dimension: float, y_dimension: float) -> float:
|
|
50
|
+
"""Get the area of a rectangular cross-section."""
|
|
51
|
+
return x_dimension * y_dimension
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _rectangular_frustum_polynomial_roots(
|
|
55
|
+
bottom_length: float,
|
|
56
|
+
bottom_width: float,
|
|
57
|
+
top_length: float,
|
|
58
|
+
top_width: float,
|
|
59
|
+
total_frustum_height: float,
|
|
60
|
+
) -> Tuple[float, float, float]:
|
|
61
|
+
"""Polynomial representation of the volume of a rectangular frustum."""
|
|
62
|
+
# roots of the polynomial with shape ax^3 + bx^2 + cx
|
|
63
|
+
a = (
|
|
64
|
+
(top_length - bottom_length)
|
|
65
|
+
* (top_width - bottom_width)
|
|
66
|
+
/ (3 * total_frustum_height**2)
|
|
67
|
+
)
|
|
68
|
+
b = (
|
|
69
|
+
(bottom_length * (top_width - bottom_width))
|
|
70
|
+
+ (bottom_width * (top_length - bottom_length))
|
|
71
|
+
) / (2 * total_frustum_height)
|
|
72
|
+
c = bottom_length * bottom_width
|
|
73
|
+
return a, b, c
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _circular_frustum_polynomial_roots(
|
|
77
|
+
bottom_radius: float,
|
|
78
|
+
top_radius: float,
|
|
79
|
+
total_frustum_height: float,
|
|
80
|
+
) -> Tuple[float, float, float]:
|
|
81
|
+
"""Polynomial representation of the volume of a circular frustum."""
|
|
82
|
+
# roots of the polynomial with shape ax^3 + bx^2 + cx
|
|
83
|
+
a = pi * ((top_radius - bottom_radius) ** 2) / (3 * total_frustum_height**2)
|
|
84
|
+
b = pi * bottom_radius * (top_radius - bottom_radius) / total_frustum_height
|
|
85
|
+
c = pi * bottom_radius**2
|
|
86
|
+
return a, b, c
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _volume_from_height_circular(
|
|
90
|
+
target_height: float, segment: ConicalFrustum
|
|
91
|
+
) -> float:
|
|
92
|
+
return segment.volume_from_height_circular(
|
|
93
|
+
top_radius=segment.topDiameter / 2,
|
|
94
|
+
bottom_radius=segment.bottomDiameter / 2,
|
|
95
|
+
target_height=target_height,
|
|
96
|
+
total_height=segment.topHeight - segment.bottomHeight,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _volume_from_height_rectangular(
|
|
101
|
+
target_height: float,
|
|
102
|
+
total_frustum_height: float,
|
|
103
|
+
bottom_length: float,
|
|
104
|
+
bottom_width: float,
|
|
105
|
+
top_length: float,
|
|
106
|
+
top_width: float,
|
|
107
|
+
) -> float:
|
|
108
|
+
"""Find the volume given a height within a rectangular frustum."""
|
|
109
|
+
a, b, c = _rectangular_frustum_polynomial_roots(
|
|
110
|
+
bottom_length=bottom_length,
|
|
111
|
+
bottom_width=bottom_width,
|
|
112
|
+
top_length=top_length,
|
|
113
|
+
top_width=top_width,
|
|
114
|
+
total_frustum_height=total_frustum_height,
|
|
115
|
+
)
|
|
116
|
+
volume = a * (target_height**3) + b * (target_height**2) + c * target_height
|
|
117
|
+
return volume
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _volume_from_height_spherical(
|
|
121
|
+
target_height: float,
|
|
122
|
+
radius_of_curvature: float,
|
|
123
|
+
) -> float:
|
|
124
|
+
"""Find the volume given a height within a spherical frustum."""
|
|
125
|
+
volume = (
|
|
126
|
+
(1 / 3) * pi * (target_height**2) * (3 * radius_of_curvature - target_height)
|
|
127
|
+
)
|
|
128
|
+
return volume
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _volume_from_height_squared_cone(
|
|
132
|
+
target_height: float, segment: SquaredConeSegment
|
|
133
|
+
) -> float:
|
|
134
|
+
"""Find the volume given a height within a squared cone segment."""
|
|
135
|
+
heights = segment.height_to_volume_table.keys()
|
|
136
|
+
best_fit_height = min(heights, key=lambda x: abs(x - target_height))
|
|
137
|
+
return segment.height_to_volume_table[best_fit_height]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _height_from_volume_circular(
|
|
141
|
+
target_volume: float, segment: ConicalFrustum
|
|
142
|
+
) -> float:
|
|
143
|
+
"""Find the height given a volume within a squared cone segment."""
|
|
144
|
+
return segment.height_from_volume_search(target_volume)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _height_from_volume_rectangular(
|
|
148
|
+
volume: float,
|
|
149
|
+
total_frustum_height: float,
|
|
150
|
+
bottom_length: float,
|
|
151
|
+
bottom_width: float,
|
|
152
|
+
top_length: float,
|
|
153
|
+
top_width: float,
|
|
154
|
+
) -> float:
|
|
155
|
+
"""Find the height given a volume within a rectangular frustum."""
|
|
156
|
+
a, b, c = _rectangular_frustum_polynomial_roots(
|
|
157
|
+
bottom_length=bottom_length,
|
|
158
|
+
bottom_width=bottom_width,
|
|
159
|
+
top_length=top_length,
|
|
160
|
+
top_width=top_width,
|
|
161
|
+
total_frustum_height=total_frustum_height,
|
|
162
|
+
)
|
|
163
|
+
d = volume * -1
|
|
164
|
+
x_intercept_roots = (a, b, c, d)
|
|
165
|
+
|
|
166
|
+
height_from_volume_roots = roots(x_intercept_roots)
|
|
167
|
+
height = _reject_unacceptable_heights(
|
|
168
|
+
potential_heights=list(height_from_volume_roots),
|
|
169
|
+
max_height=total_frustum_height,
|
|
170
|
+
)
|
|
171
|
+
return height
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _height_from_volume_spherical(
|
|
175
|
+
volume: float,
|
|
176
|
+
radius_of_curvature: float,
|
|
177
|
+
total_frustum_height: float,
|
|
178
|
+
) -> float:
|
|
179
|
+
"""Find the height given a volume within a spherical frustum."""
|
|
180
|
+
a = -1 * pi / 3
|
|
181
|
+
b = pi * radius_of_curvature
|
|
182
|
+
c = 0.0
|
|
183
|
+
d = volume * -1
|
|
184
|
+
x_intercept_roots = (a, b, c, d)
|
|
185
|
+
|
|
186
|
+
height_from_volume_roots = roots(x_intercept_roots)
|
|
187
|
+
height = _reject_unacceptable_heights(
|
|
188
|
+
potential_heights=list(height_from_volume_roots),
|
|
189
|
+
max_height=total_frustum_height,
|
|
190
|
+
)
|
|
191
|
+
return height
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _height_from_volume_squared_cone(
|
|
195
|
+
target_volume: float, segment: SquaredConeSegment
|
|
196
|
+
) -> float:
|
|
197
|
+
"""Find the height given a volume within a squared cone segment."""
|
|
198
|
+
volumes = segment.volume_to_height_table.keys()
|
|
199
|
+
best_fit_volume = min(volumes, key=lambda x: abs(x - target_volume))
|
|
200
|
+
return segment.volume_to_height_table[best_fit_volume]
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _get_segment_capacity(segment: WellSegment) -> float:
|
|
204
|
+
section_height = segment.topHeight - segment.bottomHeight
|
|
205
|
+
match segment:
|
|
206
|
+
case SphericalSegment():
|
|
207
|
+
return (
|
|
208
|
+
_volume_from_height_spherical(
|
|
209
|
+
target_height=segment.topHeight,
|
|
210
|
+
radius_of_curvature=segment.radiusOfCurvature,
|
|
211
|
+
)
|
|
212
|
+
* segment.count
|
|
213
|
+
)
|
|
214
|
+
case CuboidalFrustum():
|
|
215
|
+
return (
|
|
216
|
+
_volume_from_height_rectangular(
|
|
217
|
+
target_height=section_height,
|
|
218
|
+
bottom_length=segment.bottomYDimension,
|
|
219
|
+
bottom_width=segment.bottomXDimension,
|
|
220
|
+
top_length=segment.topYDimension,
|
|
221
|
+
top_width=segment.topXDimension,
|
|
222
|
+
total_frustum_height=section_height,
|
|
223
|
+
)
|
|
224
|
+
* segment.count
|
|
225
|
+
)
|
|
226
|
+
case ConicalFrustum():
|
|
227
|
+
return (
|
|
228
|
+
_volume_from_height_circular(
|
|
229
|
+
target_height=section_height,
|
|
230
|
+
segment=segment,
|
|
231
|
+
)
|
|
232
|
+
* segment.count
|
|
233
|
+
)
|
|
234
|
+
case SquaredConeSegment():
|
|
235
|
+
return (
|
|
236
|
+
_volume_from_height_squared_cone(section_height, segment)
|
|
237
|
+
* segment.count
|
|
238
|
+
)
|
|
239
|
+
case _:
|
|
240
|
+
# TODO: implement volume calculations for truncated circular and rounded rectangular segments
|
|
241
|
+
raise NotImplementedError(
|
|
242
|
+
f"volume calculation for shape: {segment.shape} not yet implemented."
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def get_well_volumetric_capacity(
|
|
247
|
+
well_geometry: InnerWellGeometry,
|
|
248
|
+
) -> List[Tuple[float, float]]:
|
|
249
|
+
"""Return the volumetric capacity of a well as a list of pairs relating segment heights to volumes."""
|
|
250
|
+
# [(top_height_0, section_0_volume), (top_height_1, section_1_volume), ...]
|
|
251
|
+
well_volume = []
|
|
252
|
+
|
|
253
|
+
# get the well segments sorted in ascending order
|
|
254
|
+
sorted_well = sorted(well_geometry.sections, key=lambda section: section.topHeight)
|
|
255
|
+
|
|
256
|
+
for segment in sorted_well:
|
|
257
|
+
section_volume = _get_segment_capacity(segment)
|
|
258
|
+
well_volume.append((segment.topHeight, section_volume))
|
|
259
|
+
return well_volume
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def height_at_volume_within_section(
|
|
263
|
+
section: WellSegment,
|
|
264
|
+
target_volume_relative: float,
|
|
265
|
+
section_height: float,
|
|
266
|
+
) -> float:
|
|
267
|
+
"""Calculate a height within a bounded section according to geometry."""
|
|
268
|
+
target_volume_relative = target_volume_relative / section.count
|
|
269
|
+
match section:
|
|
270
|
+
case SphericalSegment():
|
|
271
|
+
return _height_from_volume_spherical(
|
|
272
|
+
volume=target_volume_relative,
|
|
273
|
+
total_frustum_height=section_height,
|
|
274
|
+
radius_of_curvature=section.radiusOfCurvature,
|
|
275
|
+
)
|
|
276
|
+
case ConicalFrustum():
|
|
277
|
+
return _height_from_volume_circular(target_volume_relative, section)
|
|
278
|
+
case CuboidalFrustum():
|
|
279
|
+
return _height_from_volume_rectangular(
|
|
280
|
+
volume=target_volume_relative,
|
|
281
|
+
total_frustum_height=section_height,
|
|
282
|
+
bottom_width=section.bottomXDimension,
|
|
283
|
+
bottom_length=section.bottomYDimension,
|
|
284
|
+
top_width=section.topXDimension,
|
|
285
|
+
top_length=section.topYDimension,
|
|
286
|
+
)
|
|
287
|
+
case SquaredConeSegment():
|
|
288
|
+
return _height_from_volume_squared_cone(target_volume_relative, section)
|
|
289
|
+
case _:
|
|
290
|
+
raise NotImplementedError(
|
|
291
|
+
"Height from volume calculation not yet implemented for this well shape."
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def volume_at_height_within_section(
|
|
296
|
+
section: WellSegment,
|
|
297
|
+
target_height_relative: float,
|
|
298
|
+
section_height: float,
|
|
299
|
+
) -> float:
|
|
300
|
+
"""Calculate a volume within a bounded section according to geometry."""
|
|
301
|
+
match section:
|
|
302
|
+
case SphericalSegment():
|
|
303
|
+
return (
|
|
304
|
+
_volume_from_height_spherical(
|
|
305
|
+
target_height=target_height_relative,
|
|
306
|
+
radius_of_curvature=section.radiusOfCurvature,
|
|
307
|
+
)
|
|
308
|
+
* section.count
|
|
309
|
+
)
|
|
310
|
+
case ConicalFrustum():
|
|
311
|
+
return (
|
|
312
|
+
_volume_from_height_circular(
|
|
313
|
+
target_height=target_height_relative, segment=section
|
|
314
|
+
)
|
|
315
|
+
* section.count
|
|
316
|
+
)
|
|
317
|
+
case CuboidalFrustum():
|
|
318
|
+
return (
|
|
319
|
+
_volume_from_height_rectangular(
|
|
320
|
+
target_height=target_height_relative,
|
|
321
|
+
total_frustum_height=section_height,
|
|
322
|
+
bottom_width=section.bottomXDimension,
|
|
323
|
+
bottom_length=section.bottomYDimension,
|
|
324
|
+
top_width=section.topXDimension,
|
|
325
|
+
top_length=section.topYDimension,
|
|
326
|
+
)
|
|
327
|
+
* section.count
|
|
328
|
+
)
|
|
329
|
+
case SquaredConeSegment():
|
|
330
|
+
return (
|
|
331
|
+
_volume_from_height_squared_cone(target_height_relative, section)
|
|
332
|
+
* section.count
|
|
333
|
+
)
|
|
334
|
+
case _:
|
|
335
|
+
# TODO(cm): this would be the NEST-96 2uL wells referenced in EXEC-712
|
|
336
|
+
# we need to input the math attached to that issue
|
|
337
|
+
raise NotImplementedError(
|
|
338
|
+
"Height from volume calculation not yet implemented for this well shape."
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def _find_volume_in_partial_frustum(
|
|
343
|
+
sorted_well: List[WellSegment],
|
|
344
|
+
target_height: float,
|
|
345
|
+
) -> float:
|
|
346
|
+
"""Look through a sorted list of frusta for a target height, and find the volume at that height."""
|
|
347
|
+
for segment in sorted_well:
|
|
348
|
+
if segment.bottomHeight <= target_height <= segment.topHeight:
|
|
349
|
+
relative_target_height = target_height - segment.bottomHeight
|
|
350
|
+
section_height = segment.topHeight - segment.bottomHeight
|
|
351
|
+
return volume_at_height_within_section(
|
|
352
|
+
section=segment,
|
|
353
|
+
target_height_relative=relative_target_height,
|
|
354
|
+
section_height=section_height,
|
|
355
|
+
)
|
|
356
|
+
# if we've looked through all sections and can't find the target volume, raise an error
|
|
357
|
+
# this code should never be reached- an error should be raised by find_volume_at_well_height
|
|
358
|
+
raise InvalidLiquidHeightFound(
|
|
359
|
+
f"Target height {target_height} mm exceeds the well height."
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def _linear_interpolation(
|
|
364
|
+
interpolating_from: List[float], to_interpolate: List[float], target_val: float
|
|
365
|
+
) -> float:
|
|
366
|
+
if len(interpolating_from) != len(to_interpolate):
|
|
367
|
+
raise InvalidUserDefinedVolumesError(
|
|
368
|
+
"Height and volume data have unequal sizes"
|
|
369
|
+
)
|
|
370
|
+
if not (interpolating_from[0] == to_interpolate[0] == 0.0):
|
|
371
|
+
raise ValueError("linear interpolation datasets must start with 0.0")
|
|
372
|
+
|
|
373
|
+
if target_val == 0.0:
|
|
374
|
+
return 0.0
|
|
375
|
+
for i in range(1, len(interpolating_from)):
|
|
376
|
+
if target_val == interpolating_from[i]:
|
|
377
|
+
return to_interpolate[i]
|
|
378
|
+
if interpolating_from[i - 1] < target_val < interpolating_from[i]:
|
|
379
|
+
proportional_diff = (target_val - interpolating_from[i - 1]) / (
|
|
380
|
+
interpolating_from[i] - interpolating_from[i - 1]
|
|
381
|
+
)
|
|
382
|
+
addend = proportional_diff * (to_interpolate[i] - to_interpolate[i - 1])
|
|
383
|
+
result = to_interpolate[i - 1] + addend
|
|
384
|
+
return result
|
|
385
|
+
raise ValueError("linear interpolation failed")
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def find_volume_user_defined_volumes(
|
|
389
|
+
target_height: LiquidTrackingType, well_geometry: UserDefinedVolumes
|
|
390
|
+
) -> LiquidTrackingType:
|
|
391
|
+
"""Return a linear interpolation of volume based on target height."""
|
|
392
|
+
if isinstance(target_height, SimulatedProbeResult):
|
|
393
|
+
return target_height
|
|
394
|
+
sorted_volume_map = sorted(
|
|
395
|
+
well_geometry.heightToVolumeMap, key=lambda section: section.height
|
|
396
|
+
)
|
|
397
|
+
max_height = sorted_volume_map[-1].height
|
|
398
|
+
if target_height < 0 or target_height > max_height:
|
|
399
|
+
raise InvalidLiquidHeightFound(
|
|
400
|
+
f"Invalid target height {target_height} mm; greatest well height in InnerLabwareGeometry is {max_height} mm."
|
|
401
|
+
)
|
|
402
|
+
volumes = [0.0]
|
|
403
|
+
heights = [0.0]
|
|
404
|
+
for pair in sorted_volume_map:
|
|
405
|
+
volumes.append(pair.volume)
|
|
406
|
+
heights.append(pair.height)
|
|
407
|
+
|
|
408
|
+
try:
|
|
409
|
+
return _linear_interpolation(
|
|
410
|
+
interpolating_from=heights, to_interpolate=volumes, target_val=target_height
|
|
411
|
+
)
|
|
412
|
+
except ValueError:
|
|
413
|
+
raise InvalidLiquidHeightFound(
|
|
414
|
+
f"Unable to find volume at target volume {target_height}."
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def find_height_user_defined_volumes(
|
|
419
|
+
target_volume: LiquidTrackingType,
|
|
420
|
+
well_geometry: UserDefinedVolumes,
|
|
421
|
+
) -> LiquidTrackingType:
|
|
422
|
+
"""Return a linear interpolation of height based on target volume."""
|
|
423
|
+
if isinstance(target_volume, SimulatedProbeResult):
|
|
424
|
+
return target_volume
|
|
425
|
+
sorted_volume_map = sorted(
|
|
426
|
+
well_geometry.heightToVolumeMap, key=lambda section: section.height
|
|
427
|
+
)
|
|
428
|
+
max_volume = sorted_volume_map[-1].volume
|
|
429
|
+
if target_volume < 0 or target_volume > max_volume:
|
|
430
|
+
raise InvalidLiquidHeightFound(
|
|
431
|
+
f"Invalid target volume {target_volume}µL; greatest well volume in InnerLabwareGeometry is {max_volume}µL."
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
volumes = [0.0]
|
|
435
|
+
heights = [0.0]
|
|
436
|
+
for pair in sorted_volume_map:
|
|
437
|
+
volumes.append(pair.volume)
|
|
438
|
+
heights.append(pair.height)
|
|
439
|
+
|
|
440
|
+
try:
|
|
441
|
+
return _linear_interpolation(
|
|
442
|
+
interpolating_from=volumes, to_interpolate=heights, target_val=target_volume
|
|
443
|
+
)
|
|
444
|
+
except ValueError:
|
|
445
|
+
raise InvalidLiquidHeightFound(
|
|
446
|
+
f"Unable to find volume at target volume {target_volume}."
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def find_volume_inner_well_geometry(
|
|
451
|
+
target_height: LiquidTrackingType,
|
|
452
|
+
well_geometry: InnerWellGeometry,
|
|
453
|
+
) -> LiquidTrackingType:
|
|
454
|
+
"""Find the volume within a well, at a known height."""
|
|
455
|
+
# comparisons with SimulatedProbeResult objects aren't meaningful, just return
|
|
456
|
+
if isinstance(target_height, SimulatedProbeResult):
|
|
457
|
+
return target_height
|
|
458
|
+
volumetric_capacity = get_well_volumetric_capacity(well_geometry)
|
|
459
|
+
max_height = volumetric_capacity[-1][0]
|
|
460
|
+
if target_height < 0 or target_height > max_height:
|
|
461
|
+
raise InvalidLiquidHeightFound(
|
|
462
|
+
f"Invalid target height {target_height} mm; max well height is {max_height} mm."
|
|
463
|
+
)
|
|
464
|
+
# volumes in volumetric_capacity are relative to each frustum,
|
|
465
|
+
# so we have to find the volume of all the full sections enclosed
|
|
466
|
+
# beneath the target height
|
|
467
|
+
closed_section_volume = 0.0
|
|
468
|
+
for boundary_height, section_volume in volumetric_capacity:
|
|
469
|
+
if boundary_height > target_height:
|
|
470
|
+
break
|
|
471
|
+
closed_section_volume += section_volume
|
|
472
|
+
# if target height is a boundary cross-section, we already know the volume
|
|
473
|
+
if target_height == boundary_height:
|
|
474
|
+
return closed_section_volume
|
|
475
|
+
# find the section the target height is in and compute the volume
|
|
476
|
+
|
|
477
|
+
sorted_well = sorted(well_geometry.sections, key=lambda section: section.topHeight)
|
|
478
|
+
partial_volume = _find_volume_in_partial_frustum(
|
|
479
|
+
sorted_well=sorted_well,
|
|
480
|
+
target_height=target_height,
|
|
481
|
+
)
|
|
482
|
+
return partial_volume + closed_section_volume
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def _find_height_in_partial_frustum(
|
|
486
|
+
sorted_well: List[WellSegment],
|
|
487
|
+
volumetric_capacity: List[Tuple[float, float]],
|
|
488
|
+
target_volume: float,
|
|
489
|
+
) -> float:
|
|
490
|
+
"""Look through a sorted list of frusta for a target volume, and find the height at that volume."""
|
|
491
|
+
bottom_section_volume = 0.0
|
|
492
|
+
if target_volume == 0.0:
|
|
493
|
+
return 0.0
|
|
494
|
+
for section, capacity in zip(sorted_well, volumetric_capacity):
|
|
495
|
+
section_top_height, section_volume = capacity
|
|
496
|
+
if target_volume == section_volume + bottom_section_volume:
|
|
497
|
+
return section_top_height
|
|
498
|
+
if (
|
|
499
|
+
bottom_section_volume
|
|
500
|
+
<= target_volume
|
|
501
|
+
<= (bottom_section_volume + section_volume)
|
|
502
|
+
):
|
|
503
|
+
relative_target_volume = target_volume - bottom_section_volume
|
|
504
|
+
section_height = section.topHeight - section.bottomHeight
|
|
505
|
+
partial_height = height_at_volume_within_section(
|
|
506
|
+
section=section,
|
|
507
|
+
target_volume_relative=relative_target_volume,
|
|
508
|
+
section_height=section_height,
|
|
509
|
+
)
|
|
510
|
+
return partial_height + section.bottomHeight
|
|
511
|
+
# bottom section volume should always be the volume enclosed in the previously
|
|
512
|
+
# viewed section
|
|
513
|
+
bottom_section_volume += section_volume
|
|
514
|
+
|
|
515
|
+
# if we finish looping through the whole well, bottom_section will be the well's volume
|
|
516
|
+
total_well_volume = bottom_section_volume
|
|
517
|
+
# if we've looked through all sections and can't find the target volume, raise an error
|
|
518
|
+
# also this code should never be reached bc an invalid target volume should be changed
|
|
519
|
+
# by find_height_at_well_volume
|
|
520
|
+
raise InvalidLiquidHeightFound(
|
|
521
|
+
f"Target volume {target_volume}µL exceeds the well volume {total_well_volume}µL."
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
def find_height_inner_well_geometry(
|
|
526
|
+
target_volume: LiquidTrackingType,
|
|
527
|
+
well_geometry: InnerWellGeometry,
|
|
528
|
+
) -> LiquidTrackingType:
|
|
529
|
+
"""Find the height within a well, at a known volume."""
|
|
530
|
+
# comparisons with SimulatedProbeResult objects aren't meaningful, just
|
|
531
|
+
# return if we have one of those
|
|
532
|
+
if isinstance(target_volume, SimulatedProbeResult):
|
|
533
|
+
return target_volume
|
|
534
|
+
|
|
535
|
+
volumetric_capacity = get_well_volumetric_capacity(well_geometry)
|
|
536
|
+
max_volume = sum(row[1] for row in volumetric_capacity)
|
|
537
|
+
|
|
538
|
+
if target_volume < 0:
|
|
539
|
+
target_volume = 0
|
|
540
|
+
elif target_volume > max_volume:
|
|
541
|
+
target_volume = max_volume
|
|
542
|
+
sorted_well = sorted(well_geometry.sections, key=lambda section: section.topHeight)
|
|
543
|
+
# find the section the target volume is in and compute the height
|
|
544
|
+
return _find_height_in_partial_frustum(
|
|
545
|
+
sorted_well=sorted_well,
|
|
546
|
+
volumetric_capacity=volumetric_capacity,
|
|
547
|
+
target_volume=target_volume,
|
|
548
|
+
)
|