mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2026-02-05 14:05:12 +00:00
feat: 更新泵协议生成函数,统一容器参数命名并添加调试信息
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import traceback
|
||||
import numpy as np
|
||||
import networkx as nx
|
||||
import asyncio
|
||||
@@ -6,11 +7,17 @@ from typing import List, Dict, Any
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from unilabos.compile.utils.vessel_parser import get_vessel
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def debug_print(message):
|
||||
"""强制输出调试信息"""
|
||||
output = f"[TRANSFER] {message}"
|
||||
timestamp = time_module.strftime("%H:%M:%S")
|
||||
output = f"[{timestamp}] {message}"
|
||||
print(output, flush=True)
|
||||
sys.stdout.flush()
|
||||
# 同时写入日志
|
||||
logger.info(output)
|
||||
|
||||
def get_vessel_liquid_volume(G: nx.DiGraph, vessel: str) -> float:
|
||||
@@ -114,10 +121,11 @@ def find_connected_pump(G, valve_node):
|
||||
# 只有多通阀等复杂阀门才需要查找连接的泵
|
||||
if ("multiway" in node_class.lower() or "valve" in node_class.lower()):
|
||||
debug_print(f" - {valve_node} 是多通阀,查找连接的泵...")
|
||||
|
||||
return valve_node
|
||||
# 方法1:直接相邻的泵
|
||||
for neighbor in G.neighbors(valve_node):
|
||||
neighbor_class = G.nodes[neighbor].get("class", "") or ""
|
||||
# 排除非 电磁阀 和 泵 的邻居
|
||||
debug_print(f" - 检查邻居 {neighbor}, class: {neighbor_class}")
|
||||
if "pump" in neighbor_class.lower():
|
||||
debug_print(f" ✅ 找到直接相连的泵: {neighbor}")
|
||||
@@ -205,8 +213,8 @@ def build_pump_valve_maps(G, pump_backbone):
|
||||
|
||||
def generate_pump_protocol(
|
||||
G: nx.DiGraph,
|
||||
from_vessel: str,
|
||||
to_vessel: str,
|
||||
from_vessel_id: str,
|
||||
to_vessel_id: str,
|
||||
volume: float,
|
||||
flowrate: float = 2.5,
|
||||
transfer_flowrate: float = 0.5,
|
||||
@@ -232,26 +240,27 @@ def generate_pump_protocol(
|
||||
logger.warning(f"transfer_flowrate <= 0,使用默认值 {transfer_flowrate}mL/s")
|
||||
|
||||
# 验证容器存在
|
||||
if from_vessel not in G.nodes():
|
||||
logger.error(f"源容器 '{from_vessel}' 不存在")
|
||||
debug_print(f"🔍 验证源容器 '{from_vessel_id}' 和目标容器 '{to_vessel_id}' 是否存在...")
|
||||
if from_vessel_id not in G.nodes():
|
||||
logger.error(f"源容器 '{from_vessel_id}' 不存在")
|
||||
return pump_action_sequence
|
||||
|
||||
if to_vessel not in G.nodes():
|
||||
logger.error(f"目标容器 '{to_vessel}' 不存在")
|
||||
if to_vessel_id not in G.nodes():
|
||||
logger.error(f"目标容器 '{to_vessel_id}' 不存在")
|
||||
return pump_action_sequence
|
||||
|
||||
try:
|
||||
shortest_path = nx.shortest_path(G, source=from_vessel, target=to_vessel)
|
||||
debug_print(f"PUMP_TRANSFER: 路径 {from_vessel} -> {to_vessel}: {shortest_path}")
|
||||
shortest_path = nx.shortest_path(G, source=from_vessel_id, target=to_vessel_id)
|
||||
debug_print(f"PUMP_TRANSFER: 路径 {from_vessel_id} -> {to_vessel_id}: {shortest_path}")
|
||||
except nx.NetworkXNoPath:
|
||||
logger.error(f"无法找到从 '{from_vessel}' 到 '{to_vessel}' 的路径")
|
||||
logger.error(f"无法找到从 '{from_vessel_id}' 到 '{to_vessel_id}' 的路径")
|
||||
return pump_action_sequence
|
||||
|
||||
# 🔧 关键修复:正确构建泵骨架,排除容器和电磁阀
|
||||
pump_backbone = []
|
||||
for node in shortest_path:
|
||||
# 跳过起始和结束容器
|
||||
if node == from_vessel or node == to_vessel:
|
||||
if node == from_vessel_id or node == to_vessel_id:
|
||||
continue
|
||||
|
||||
# 跳过电磁阀(电磁阀不参与泵操作)
|
||||
@@ -307,7 +316,7 @@ def generate_pump_protocol(
|
||||
|
||||
repeats = int(np.ceil(volume / min_transfer_volume))
|
||||
|
||||
if repeats > 1 and (from_vessel.startswith("pump") or to_vessel.startswith("pump")):
|
||||
if repeats > 1 and (from_vessel_id.startswith("pump") or to_vessel_id.startswith("pump")):
|
||||
logger.error("Cannot transfer volume larger than min_transfer_volume between two pumps.")
|
||||
return pump_action_sequence
|
||||
|
||||
@@ -336,7 +345,7 @@ def generate_pump_protocol(
|
||||
|
||||
# 🆕 在每次循环开始时添加进度日志
|
||||
if repeats > 1:
|
||||
start_message = f"🚀 准备开始第 {i+1}/{repeats} 次转移: {current_volume:.2f}mL ({from_vessel} → {to_vessel}) 🚰"
|
||||
start_message = f"🚀 准备开始第 {i+1}/{repeats} 次转移: {current_volume:.2f}mL ({from_vessel_id} → {to_vessel_id}) 🚰"
|
||||
pump_action_sequence.append(create_progress_log_action(start_message))
|
||||
|
||||
# 🔧 修复:安全地获取边数据
|
||||
@@ -353,10 +362,10 @@ def generate_pump_protocol(
|
||||
return "default"
|
||||
|
||||
# 从源容器吸液
|
||||
if not from_vessel.startswith("pump") and pump_backbone:
|
||||
if not from_vessel_id.startswith("pump") and pump_backbone:
|
||||
first_pump_node = pump_backbone[0]
|
||||
if first_pump_node in valve_from_node and first_pump_node in pumps_from_node:
|
||||
port_command = get_safe_edge_data(first_pump_node, from_vessel, first_pump_node)
|
||||
port_command = get_safe_edge_data(first_pump_node, from_vessel_id, first_pump_node)
|
||||
pump_action_sequence.extend([
|
||||
{
|
||||
"device_id": valve_from_node[first_pump_node],
|
||||
@@ -419,10 +428,10 @@ def generate_pump_protocol(
|
||||
pump_action_sequence.append({"action_name": "wait", "action_kwargs": {"time": 3}})
|
||||
|
||||
# 排液到目标容器
|
||||
if not to_vessel.startswith("pump") and pump_backbone:
|
||||
if not to_vessel_id.startswith("pump") and pump_backbone:
|
||||
last_pump_node = pump_backbone[-1]
|
||||
if last_pump_node in valve_from_node and last_pump_node in pumps_from_node:
|
||||
port_command = get_safe_edge_data(last_pump_node, to_vessel, last_pump_node)
|
||||
port_command = get_safe_edge_data(last_pump_node, to_vessel_id, last_pump_node)
|
||||
pump_action_sequence.extend([
|
||||
{
|
||||
"device_id": valve_from_node[last_pump_node],
|
||||
@@ -459,8 +468,8 @@ def generate_pump_protocol(
|
||||
|
||||
def generate_pump_protocol_with_rinsing(
|
||||
G: nx.DiGraph,
|
||||
from_vessel: str,
|
||||
to_vessel: str,
|
||||
from_vessel_id: str,
|
||||
to_vessel_id: str,
|
||||
volume: float = 0.0,
|
||||
amount: str = "",
|
||||
time: float = 0.0, # 🔧 修复:统一使用 time
|
||||
@@ -488,7 +497,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
with generate_pump_protocol_with_rinsing._lock:
|
||||
debug_print("=" * 60)
|
||||
debug_print(f"PUMP_TRANSFER: 🚀 开始生成协议 (同步版本)")
|
||||
debug_print(f" 📍 路径: {from_vessel} -> {to_vessel}")
|
||||
debug_print(f" 📍 路径: {from_vessel_id} -> {to_vessel_id}")
|
||||
debug_print(f" 🕐 时间戳: {time_module.time()}")
|
||||
debug_print(f" 🔒 获得执行锁")
|
||||
debug_print("=" * 60)
|
||||
@@ -507,8 +516,8 @@ def generate_pump_protocol_with_rinsing(
|
||||
debug_print("🎯 检测到 volume=0.0,开始自动体积检测...")
|
||||
|
||||
# 直接从源容器读取实际体积
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel)
|
||||
debug_print(f"📖 从容器 '{from_vessel}' 读取到体积: {actual_volume}mL")
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel_id)
|
||||
debug_print(f"📖 从容器 '{from_vessel_id}' 读取到体积: {actual_volume}mL")
|
||||
|
||||
if actual_volume > 0:
|
||||
final_volume = actual_volume
|
||||
@@ -530,7 +539,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
debug_print(f"✅ 使用从 amount 解析的体积: {final_volume}mL")
|
||||
elif parsed_volume == 0.0 and amount.lower().strip() == "all":
|
||||
debug_print("🎯 检测到 amount='all',从容器读取全部体积...")
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel)
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel_id)
|
||||
if actual_volume > 0:
|
||||
final_volume = actual_volume
|
||||
debug_print(f"✅ amount='all',设置体积为: {final_volume}mL")
|
||||
@@ -593,7 +602,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
try:
|
||||
# 🆕 修复:在这里调用带有循环日志的generate_pump_protocol_with_loop_logging函数
|
||||
pump_action_sequence = generate_pump_protocol_with_loop_logging(
|
||||
G, from_vessel, to_vessel, final_volume,
|
||||
G, from_vessel_id, to_vessel_id, final_volume,
|
||||
final_flowrate, final_transfer_flowrate
|
||||
)
|
||||
|
||||
@@ -615,8 +624,8 @@ def generate_pump_protocol_with_rinsing(
|
||||
|
||||
def generate_pump_protocol_with_loop_logging(
|
||||
G: nx.DiGraph,
|
||||
from_vessel: str,
|
||||
to_vessel: str,
|
||||
from_vessel_id: str,
|
||||
to_vessel_id: str,
|
||||
volume: float,
|
||||
flowrate: float = 2.5,
|
||||
transfer_flowrate: float = 0.5,
|
||||
@@ -642,26 +651,26 @@ def generate_pump_protocol_with_loop_logging(
|
||||
logger.warning(f"transfer_flowrate <= 0,使用默认值 {transfer_flowrate}mL/s")
|
||||
|
||||
# 验证容器存在
|
||||
if from_vessel not in G.nodes():
|
||||
logger.error(f"源容器 '{from_vessel}' 不存在")
|
||||
if from_vessel_id not in G.nodes():
|
||||
logger.error(f"源容器 '{from_vessel_id}' 不存在")
|
||||
return pump_action_sequence
|
||||
|
||||
if to_vessel not in G.nodes():
|
||||
logger.error(f"目标容器 '{to_vessel}' 不存在")
|
||||
if to_vessel_id not in G.nodes():
|
||||
logger.error(f"目标容器 '{to_vessel_id}' 不存在")
|
||||
return pump_action_sequence
|
||||
|
||||
try:
|
||||
shortest_path = nx.shortest_path(G, source=from_vessel, target=to_vessel)
|
||||
debug_print(f"PUMP_TRANSFER: 路径 {from_vessel} -> {to_vessel}: {shortest_path}")
|
||||
shortest_path = nx.shortest_path(G, source=from_vessel_id, target=to_vessel_id)
|
||||
debug_print(f"PUMP_TRANSFER: 路径 {from_vessel_id} -> {to_vessel_id}: {shortest_path}")
|
||||
except nx.NetworkXNoPath:
|
||||
logger.error(f"无法找到从 '{from_vessel}' 到 '{to_vessel}' 的路径")
|
||||
logger.error(f"无法找到从 '{from_vessel_id}' 到 '{to_vessel_id}' 的路径")
|
||||
return pump_action_sequence
|
||||
|
||||
# 🔧 关键修复:正确构建泵骨架,排除容器和电磁阀
|
||||
pump_backbone = []
|
||||
for node in shortest_path:
|
||||
# 跳过起始和结束容器
|
||||
if node == from_vessel or node == to_vessel:
|
||||
if node == from_vessel_id or node == to_vessel_id:
|
||||
continue
|
||||
|
||||
# 跳过电磁阀(电磁阀不参与泵操作)
|
||||
@@ -717,7 +726,7 @@ def generate_pump_protocol_with_loop_logging(
|
||||
|
||||
repeats = int(np.ceil(volume / min_transfer_volume))
|
||||
|
||||
if repeats > 1 and (from_vessel.startswith("pump") or to_vessel.startswith("pump")):
|
||||
if repeats > 1 and (from_vessel_id.startswith("pump") or to_vessel_id.startswith("pump")):
|
||||
logger.error("Cannot transfer volume larger than min_transfer_volume between two pumps.")
|
||||
return pump_action_sequence
|
||||
|
||||
@@ -746,7 +755,7 @@ def generate_pump_protocol_with_loop_logging(
|
||||
|
||||
# 🆕 在每次循环开始时添加进度日志
|
||||
if repeats > 1:
|
||||
start_message = f"🚀 准备开始第 {i+1}/{repeats} 次转移: {current_volume:.2f}mL ({from_vessel} → {to_vessel}) 🚰"
|
||||
start_message = f"🚀 准备开始第 {i+1}/{repeats} 次转移: {current_volume:.2f}mL ({from_vessel_id} → {to_vessel_id}) 🚰"
|
||||
pump_action_sequence.append(create_progress_log_action(start_message))
|
||||
|
||||
# 🔧 修复:安全地获取边数据
|
||||
@@ -763,10 +772,10 @@ def generate_pump_protocol_with_loop_logging(
|
||||
return "default"
|
||||
|
||||
# 从源容器吸液
|
||||
if not from_vessel.startswith("pump") and pump_backbone:
|
||||
if not from_vessel_id.startswith("pump") and pump_backbone:
|
||||
first_pump_node = pump_backbone[0]
|
||||
if first_pump_node in valve_from_node and first_pump_node in pumps_from_node:
|
||||
port_command = get_safe_edge_data(first_pump_node, from_vessel, first_pump_node)
|
||||
port_command = get_safe_edge_data(first_pump_node, from_vessel_id, first_pump_node)
|
||||
pump_action_sequence.extend([
|
||||
{
|
||||
"device_id": valve_from_node[first_pump_node],
|
||||
@@ -829,10 +838,10 @@ def generate_pump_protocol_with_loop_logging(
|
||||
pump_action_sequence.append({"action_name": "wait", "action_kwargs": {"time": 3}})
|
||||
|
||||
# 排液到目标容器
|
||||
if not to_vessel.startswith("pump") and pump_backbone:
|
||||
if not to_vessel_id.startswith("pump") and pump_backbone:
|
||||
last_pump_node = pump_backbone[-1]
|
||||
if last_pump_node in valve_from_node and last_pump_node in pumps_from_node:
|
||||
port_command = get_safe_edge_data(last_pump_node, to_vessel, last_pump_node)
|
||||
port_command = get_safe_edge_data(last_pump_node, to_vessel_id, last_pump_node)
|
||||
pump_action_sequence.extend([
|
||||
{
|
||||
"device_id": valve_from_node[last_pump_node],
|
||||
@@ -869,8 +878,8 @@ def generate_pump_protocol_with_loop_logging(
|
||||
|
||||
def generate_pump_protocol_with_rinsing(
|
||||
G: nx.DiGraph,
|
||||
from_vessel: str,
|
||||
to_vessel: str,
|
||||
from_vessel_id: str,
|
||||
to_vessel_id: str,
|
||||
volume: float = 0.0,
|
||||
amount: str = "",
|
||||
time: float = 0.0, # 🔧 修复:统一使用 time
|
||||
@@ -891,7 +900,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
"""
|
||||
debug_print("=" * 60)
|
||||
debug_print(f"PUMP_TRANSFER: 🚀 开始生成协议")
|
||||
debug_print(f" 📍 路径: {from_vessel} -> {to_vessel}")
|
||||
debug_print(f" 📍 路径: {from_vessel_id} -> {to_vessel_id}")
|
||||
debug_print(f" 🕐 时间戳: {time_module.time()}")
|
||||
debug_print(f" 📊 原始参数:")
|
||||
debug_print(f" - volume: {volume} (类型: {type(volume)})")
|
||||
@@ -915,8 +924,8 @@ def generate_pump_protocol_with_rinsing(
|
||||
debug_print("🎯 检测到 volume=0.0,开始自动体积检测...")
|
||||
|
||||
# 直接从源容器读取实际体积
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel)
|
||||
debug_print(f"📖 从容器 '{from_vessel}' 读取到体积: {actual_volume}mL")
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel_id)
|
||||
debug_print(f"📖 从容器 '{from_vessel_id}' 读取到体积: {actual_volume}mL")
|
||||
|
||||
if actual_volume > 0:
|
||||
final_volume = actual_volume
|
||||
@@ -938,7 +947,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
debug_print(f"✅ 使用从 amount 解析的体积: {final_volume}mL")
|
||||
elif parsed_volume == 0.0 and amount.lower().strip() == "all":
|
||||
debug_print("🎯 检测到 amount='all',从容器读取全部体积...")
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel)
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel_id)
|
||||
if actual_volume > 0:
|
||||
final_volume = actual_volume
|
||||
debug_print(f"✅ amount='all',设置体积为: {final_volume}mL")
|
||||
@@ -1030,10 +1039,10 @@ def generate_pump_protocol_with_rinsing(
|
||||
|
||||
try:
|
||||
debug_print(f" - 调用 generate_pump_protocol...")
|
||||
debug_print(f" - 参数: G, '{from_vessel}', '{to_vessel}', {final_volume}, {final_flowrate}, {final_transfer_flowrate}")
|
||||
debug_print(f" - 参数: G, '{from_vessel_id}', '{to_vessel_id}', {final_volume}, {final_flowrate}, {final_transfer_flowrate}")
|
||||
|
||||
pump_action_sequence = generate_pump_protocol(
|
||||
G, from_vessel, to_vessel, final_volume,
|
||||
G, from_vessel_id, to_vessel_id, final_volume,
|
||||
final_flowrate, final_transfer_flowrate
|
||||
)
|
||||
|
||||
@@ -1043,12 +1052,12 @@ def generate_pump_protocol_with_rinsing(
|
||||
|
||||
if not pump_action_sequence:
|
||||
debug_print("❌ 基础转移协议生成为空,可能是路径问题")
|
||||
debug_print(f" - 源容器存在: {from_vessel in G.nodes()}")
|
||||
debug_print(f" - 目标容器存在: {to_vessel in G.nodes()}")
|
||||
debug_print(f" - 源容器存在: {from_vessel_id in G.nodes()}")
|
||||
debug_print(f" - 目标容器存在: {to_vessel_id in G.nodes()}")
|
||||
|
||||
if from_vessel in G.nodes() and to_vessel in G.nodes():
|
||||
if from_vessel_id in G.nodes() and to_vessel_id in G.nodes():
|
||||
try:
|
||||
path = nx.shortest_path(G, source=from_vessel, target=to_vessel)
|
||||
path = nx.shortest_path(G, source=from_vessel_id, target=to_vessel_id)
|
||||
debug_print(f" - 路径存在: {path}")
|
||||
except Exception as path_error:
|
||||
debug_print(f" - 无法找到路径: {str(path_error)}")
|
||||
@@ -1058,7 +1067,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
"device_id": "system",
|
||||
"action_name": "log_message",
|
||||
"action_kwargs": {
|
||||
"message": f"⚠️ 路径问题,无法转移: {final_volume}mL 从 {from_vessel} 到 {to_vessel}"
|
||||
"message": f"⚠️ 路径问题,无法转移: {final_volume}mL 从 {from_vessel_id} 到 {to_vessel_id}"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1082,7 +1091,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
"device_id": "system",
|
||||
"action_name": "log_message",
|
||||
"action_kwargs": {
|
||||
"message": f"❌ 转移失败: {final_volume}mL 从 {from_vessel} 到 {to_vessel}, 错误: {str(e)}"
|
||||
"message": f"❌ 转移失败: {final_volume}mL 从 {from_vessel_id} 到 {to_vessel_id}, 错误: {str(e)}"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1098,7 +1107,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
# if final_rinsing_solvent.strip() != "air":
|
||||
# debug_print(" - 执行液体冲洗...")
|
||||
# rinsing_actions = _generate_rinsing_sequence(
|
||||
# G, from_vessel, to_vessel, final_rinsing_solvent,
|
||||
# G, from_vessel_id, to_vessel_id, final_rinsing_solvent,
|
||||
# final_rinsing_volume, final_rinsing_repeats,
|
||||
# final_flowrate, final_transfer_flowrate
|
||||
# )
|
||||
@@ -1107,7 +1116,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
# else:
|
||||
# debug_print(" - 执行空气冲洗...")
|
||||
# air_rinsing_actions = _generate_air_rinsing_sequence(
|
||||
# G, from_vessel, to_vessel, final_rinsing_volume, final_rinsing_repeats,
|
||||
# G, from_vessel_id, to_vessel_id, final_rinsing_volume, final_rinsing_repeats,
|
||||
# final_flowrate, final_transfer_flowrate
|
||||
# )
|
||||
# pump_action_sequence.extend(air_rinsing_actions)
|
||||
@@ -1126,7 +1135,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
debug_print(f"🎉 PUMP_TRANSFER: 协议生成完成")
|
||||
debug_print(f" 📊 总动作数: {len(pump_action_sequence)}")
|
||||
debug_print(f" 📋 最终体积: {final_volume}mL")
|
||||
debug_print(f" 🚀 执行路径: {from_vessel} -> {to_vessel}")
|
||||
debug_print(f" 🚀 执行路径: {from_vessel_id} -> {to_vessel_id}")
|
||||
|
||||
# 最终验证
|
||||
if len(pump_action_sequence) == 0:
|
||||
@@ -1147,8 +1156,8 @@ def generate_pump_protocol_with_rinsing(
|
||||
|
||||
async def generate_pump_protocol_with_rinsing_async(
|
||||
G: nx.DiGraph,
|
||||
from_vessel: str,
|
||||
to_vessel: str,
|
||||
from_vessel_id: str,
|
||||
to_vessel_id: str,
|
||||
volume: float = 0.0,
|
||||
amount: str = "",
|
||||
time: float = 0.0,
|
||||
@@ -1169,7 +1178,7 @@ async def generate_pump_protocol_with_rinsing_async(
|
||||
"""
|
||||
debug_print("=" * 60)
|
||||
debug_print(f"PUMP_TRANSFER: 🚀 开始生成协议 (异步版本)")
|
||||
debug_print(f" 📍 路径: {from_vessel} -> {to_vessel}")
|
||||
debug_print(f" 📍 路径: {from_vessel_id} -> {to_vessel_id}")
|
||||
debug_print(f" 🕐 时间戳: {time_module.time()}")
|
||||
debug_print("=" * 60)
|
||||
|
||||
@@ -1179,7 +1188,7 @@ async def generate_pump_protocol_with_rinsing_async(
|
||||
|
||||
# 调用原有的同步版本
|
||||
result = generate_pump_protocol_with_rinsing(
|
||||
G, from_vessel, to_vessel, volume, amount, time, viscous,
|
||||
G, from_vessel_id, to_vessel_id, volume, amount, time, viscous,
|
||||
rinsing_solvent, rinsing_volume, rinsing_repeats, solid,
|
||||
flowrate, transfer_flowrate, rate_spec, event, through, **kwargs
|
||||
)
|
||||
@@ -1197,8 +1206,8 @@ async def generate_pump_protocol_with_rinsing_async(
|
||||
# 保持原有的同步版本兼容性
|
||||
def generate_pump_protocol_with_rinsing(
|
||||
G: nx.DiGraph,
|
||||
from_vessel: str,
|
||||
to_vessel: str,
|
||||
from_vessel_id: str,
|
||||
to_vessel_id: str,
|
||||
volume: float = 0.0,
|
||||
amount: str = "",
|
||||
time: float = 0.0,
|
||||
@@ -1226,7 +1235,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
with generate_pump_protocol_with_rinsing._lock:
|
||||
debug_print("=" * 60)
|
||||
debug_print(f"PUMP_TRANSFER: 🚀 开始生成协议 (同步版本)")
|
||||
debug_print(f" 📍 路径: {from_vessel} -> {to_vessel}")
|
||||
debug_print(f" 📍 路径: {from_vessel_id} -> {to_vessel_id}")
|
||||
debug_print(f" 🕐 时间戳: {time_module.time()}")
|
||||
debug_print(f" 🔒 获得执行锁")
|
||||
debug_print("=" * 60)
|
||||
@@ -1245,8 +1254,8 @@ def generate_pump_protocol_with_rinsing(
|
||||
debug_print("🎯 检测到 volume=0.0,开始自动体积检测...")
|
||||
|
||||
# 直接从源容器读取实际体积
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel)
|
||||
debug_print(f"📖 从容器 '{from_vessel}' 读取到体积: {actual_volume}mL")
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel_id)
|
||||
debug_print(f"📖 从容器 '{from_vessel_id}' 读取到体积: {actual_volume}mL")
|
||||
|
||||
if actual_volume > 0:
|
||||
final_volume = actual_volume
|
||||
@@ -1268,7 +1277,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
debug_print(f"✅ 使用从 amount 解析的体积: {final_volume}mL")
|
||||
elif parsed_volume == 0.0 and amount.lower().strip() == "all":
|
||||
debug_print("🎯 检测到 amount='all',从容器读取全部体积...")
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel)
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel_id)
|
||||
if actual_volume > 0:
|
||||
final_volume = actual_volume
|
||||
debug_print(f"✅ amount='all',设置体积为: {final_volume}mL")
|
||||
@@ -1360,10 +1369,10 @@ def generate_pump_protocol_with_rinsing(
|
||||
|
||||
try:
|
||||
debug_print(f" - 调用 generate_pump_protocol...")
|
||||
debug_print(f" - 参数: G, '{from_vessel}', '{to_vessel}', {final_volume}, {final_flowrate}, {final_transfer_flowrate}")
|
||||
debug_print(f" - 参数: G, '{from_vessel_id}', '{to_vessel_id}', {final_volume}, {final_flowrate}, {final_transfer_flowrate}")
|
||||
|
||||
pump_action_sequence = generate_pump_protocol(
|
||||
G, from_vessel, to_vessel, final_volume,
|
||||
G, from_vessel_id, to_vessel_id, final_volume,
|
||||
final_flowrate, final_transfer_flowrate
|
||||
)
|
||||
|
||||
@@ -1373,12 +1382,12 @@ def generate_pump_protocol_with_rinsing(
|
||||
|
||||
if not pump_action_sequence:
|
||||
debug_print("❌ 基础转移协议生成为空,可能是路径问题")
|
||||
debug_print(f" - 源容器存在: {from_vessel in G.nodes()}")
|
||||
debug_print(f" - 目标容器存在: {to_vessel in G.nodes()}")
|
||||
debug_print(f" - 源容器存在: {from_vessel_id in G.nodes()}")
|
||||
debug_print(f" - 目标容器存在: {to_vessel_id in G.nodes()}")
|
||||
|
||||
if from_vessel in G.nodes() and to_vessel in G.nodes():
|
||||
if from_vessel_id in G.nodes() and to_vessel_id in G.nodes():
|
||||
try:
|
||||
path = nx.shortest_path(G, source=from_vessel, target=to_vessel)
|
||||
path = nx.shortest_path(G, source=from_vessel_id, target=to_vessel_id)
|
||||
debug_print(f" - 路径存在: {path}")
|
||||
except Exception as path_error:
|
||||
debug_print(f" - 无法找到路径: {str(path_error)}")
|
||||
@@ -1388,7 +1397,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
"device_id": "system",
|
||||
"action_name": "log_message",
|
||||
"action_kwargs": {
|
||||
"message": f"⚠️ 路径问题,无法转移: {final_volume}mL 从 {from_vessel} 到 {to_vessel}"
|
||||
"message": f"⚠️ 路径问题,无法转移: {final_volume}mL 从 {from_vessel_id} 到 {to_vessel_id}"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1412,7 +1421,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
"device_id": "system",
|
||||
"action_name": "log_message",
|
||||
"action_kwargs": {
|
||||
"message": f"❌ 转移失败: {final_volume}mL 从 {from_vessel} 到 {to_vessel}, 错误: {str(e)}"
|
||||
"message": f"❌ 转移失败: {final_volume}mL 从 {from_vessel_id} 到 {to_vessel_id}, 错误: {str(e)}"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1428,7 +1437,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
# if final_rinsing_solvent.strip() != "air":
|
||||
# debug_print(" - 执行液体冲洗...")
|
||||
# rinsing_actions = _generate_rinsing_sequence(
|
||||
# G, from_vessel, to_vessel, final_rinsing_solvent,
|
||||
# G, from_vessel_id, to_vessel_id, final_rinsing_solvent,
|
||||
# final_rinsing_volume, final_rinsing_repeats,
|
||||
# final_flowrate, final_transfer_flowrate
|
||||
# )
|
||||
@@ -1437,7 +1446,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
# else:
|
||||
# debug_print(" - 执行空气冲洗...")
|
||||
# air_rinsing_actions = _generate_air_rinsing_sequence(
|
||||
# G, from_vessel, to_vessel, final_rinsing_volume, final_rinsing_repeats,
|
||||
# G, from_vessel_id, to_vessel_id, final_rinsing_volume, final_rinsing_repeats,
|
||||
# final_flowrate, final_transfer_flowrate
|
||||
# )
|
||||
# pump_action_sequence.extend(air_rinsing_actions)
|
||||
@@ -1456,7 +1465,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
debug_print(f"🎉 PUMP_TRANSFER: 协议生成完成")
|
||||
debug_print(f" 📊 总动作数: {len(pump_action_sequence)}")
|
||||
debug_print(f" 📋 最终体积: {final_volume}mL")
|
||||
debug_print(f" 🚀 执行路径: {from_vessel} -> {to_vessel}")
|
||||
debug_print(f" 🚀 执行路径: {from_vessel_id} -> {to_vessel_id}")
|
||||
|
||||
# 最终验证
|
||||
if len(pump_action_sequence) == 0:
|
||||
@@ -1477,8 +1486,8 @@ def generate_pump_protocol_with_rinsing(
|
||||
|
||||
async def generate_pump_protocol_with_rinsing_async(
|
||||
G: nx.DiGraph,
|
||||
from_vessel: str,
|
||||
to_vessel: str,
|
||||
from_vessel_id: str,
|
||||
to_vessel_id: str,
|
||||
volume: float = 0.0,
|
||||
amount: str = "",
|
||||
time: float = 0.0,
|
||||
@@ -1499,7 +1508,7 @@ async def generate_pump_protocol_with_rinsing_async(
|
||||
"""
|
||||
debug_print("=" * 60)
|
||||
debug_print(f"PUMP_TRANSFER: 🚀 开始生成协议 (异步版本)")
|
||||
debug_print(f" 📍 路径: {from_vessel} -> {to_vessel}")
|
||||
debug_print(f" 📍 路径: {from_vessel_id} -> {to_vessel_id}")
|
||||
debug_print(f" 🕐 时间戳: {time_module.time()}")
|
||||
debug_print("=" * 60)
|
||||
|
||||
@@ -1509,7 +1518,7 @@ async def generate_pump_protocol_with_rinsing_async(
|
||||
|
||||
# 调用原有的同步版本
|
||||
result = generate_pump_protocol_with_rinsing(
|
||||
G, from_vessel, to_vessel, volume, amount, time, viscous,
|
||||
G, from_vessel_id, to_vessel_id, volume, amount, time, viscous,
|
||||
rinsing_solvent, rinsing_volume, rinsing_repeats, solid,
|
||||
flowrate, transfer_flowrate, rate_spec, event, through, **kwargs
|
||||
)
|
||||
@@ -1527,8 +1536,8 @@ async def generate_pump_protocol_with_rinsing_async(
|
||||
# 保持原有的同步版本兼容性
|
||||
def generate_pump_protocol_with_rinsing(
|
||||
G: nx.DiGraph,
|
||||
from_vessel: str,
|
||||
to_vessel: str,
|
||||
from_vessel: dict,
|
||||
to_vessel: dict,
|
||||
volume: float = 0.0,
|
||||
amount: str = "",
|
||||
time: float = 0.0,
|
||||
@@ -1547,6 +1556,8 @@ def generate_pump_protocol_with_rinsing(
|
||||
"""
|
||||
原有的同步版本,添加防冲突机制
|
||||
"""
|
||||
from_vessel_id, _ = get_vessel(from_vessel)
|
||||
to_vessel_id, _ = get_vessel(to_vessel)
|
||||
|
||||
# 添加执行锁,防止并发调用
|
||||
import threading
|
||||
@@ -1556,7 +1567,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
with generate_pump_protocol_with_rinsing._lock:
|
||||
debug_print("=" * 60)
|
||||
debug_print(f"PUMP_TRANSFER: 🚀 开始生成协议 (同步版本)")
|
||||
debug_print(f" 📍 路径: {from_vessel} -> {to_vessel}")
|
||||
debug_print(f" 📍 路径: {from_vessel_id} -> {to_vessel_id}")
|
||||
debug_print(f" 🕐 时间戳: {time_module.time()}")
|
||||
debug_print(f" 🔒 获得执行锁")
|
||||
debug_print("=" * 60)
|
||||
@@ -1575,8 +1586,8 @@ def generate_pump_protocol_with_rinsing(
|
||||
debug_print("🎯 检测到 volume=0.0,开始自动体积检测...")
|
||||
|
||||
# 直接从源容器读取实际体积
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel)
|
||||
debug_print(f"📖 从容器 '{from_vessel}' 读取到体积: {actual_volume}mL")
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel_id)
|
||||
debug_print(f"📖 从容器 '{from_vessel_id}' 读取到体积: {actual_volume}mL")
|
||||
|
||||
if actual_volume > 0:
|
||||
final_volume = actual_volume
|
||||
@@ -1598,7 +1609,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
debug_print(f"✅ 使用从 amount 解析的体积: {final_volume}mL")
|
||||
elif parsed_volume == 0.0 and amount.lower().strip() == "all":
|
||||
debug_print("🎯 检测到 amount='all',从容器读取全部体积...")
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel)
|
||||
actual_volume = get_vessel_liquid_volume(G, from_vessel_id)
|
||||
if actual_volume > 0:
|
||||
final_volume = actual_volume
|
||||
debug_print(f"✅ amount='all',设置体积为: {final_volume}mL")
|
||||
@@ -1677,7 +1688,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
|
||||
try:
|
||||
pump_action_sequence = generate_pump_protocol(
|
||||
G, from_vessel, to_vessel, final_volume,
|
||||
G, from_vessel_id, to_vessel_id, final_volume,
|
||||
flowrate, transfer_flowrate
|
||||
)
|
||||
|
||||
@@ -1697,6 +1708,7 @@ def generate_pump_protocol_with_rinsing(
|
||||
return pump_action_sequence
|
||||
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
logger.error(f"❌ 协议生成失败: {str(e)}")
|
||||
return [
|
||||
{
|
||||
@@ -1753,7 +1765,7 @@ def _parse_amount_to_volume(amount: str) -> float:
|
||||
return 0.0
|
||||
|
||||
|
||||
def _generate_rinsing_sequence(G: nx.DiGraph, from_vessel: str, to_vessel: str,
|
||||
def _generate_rinsing_sequence(G: nx.DiGraph, from_vessel_id: str, to_vessel_id: str,
|
||||
rinsing_solvent: str, rinsing_volume: float,
|
||||
rinsing_repeats: int, flowrate: float,
|
||||
transfer_flowrate: float) -> List[Dict[str, Any]]:
|
||||
@@ -1761,7 +1773,7 @@ def _generate_rinsing_sequence(G: nx.DiGraph, from_vessel: str, to_vessel: str,
|
||||
rinsing_actions = []
|
||||
|
||||
try:
|
||||
shortest_path = nx.shortest_path(G, source=from_vessel, target=to_vessel)
|
||||
shortest_path = nx.shortest_path(G, source=from_vessel_id, target=to_vessel_id)
|
||||
pump_backbone = shortest_path[1:-1]
|
||||
|
||||
if not pump_backbone:
|
||||
@@ -1808,10 +1820,10 @@ def _generate_rinsing_sequence(G: nx.DiGraph, from_vessel: str, to_vessel: str,
|
||||
# 第一种冲洗溶剂稀释源容器和目标容器
|
||||
if solvent == rinsing_solvents[0]:
|
||||
rinsing_actions.extend(
|
||||
generate_pump_protocol(G, solvent_vessel, from_vessel, rinsing_volume, flowrate, transfer_flowrate)
|
||||
generate_pump_protocol(G, solvent_vessel, from_vessel_id, rinsing_volume, flowrate, transfer_flowrate)
|
||||
)
|
||||
rinsing_actions.extend(
|
||||
generate_pump_protocol(G, solvent_vessel, to_vessel, rinsing_volume, flowrate, transfer_flowrate)
|
||||
generate_pump_protocol(G, solvent_vessel, to_vessel_id, rinsing_volume, flowrate, transfer_flowrate)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
@@ -1820,7 +1832,7 @@ def _generate_rinsing_sequence(G: nx.DiGraph, from_vessel: str, to_vessel: str,
|
||||
return rinsing_actions
|
||||
|
||||
|
||||
def _generate_air_rinsing_sequence(G: nx.DiGraph, from_vessel: str, to_vessel: str,
|
||||
def _generate_air_rinsing_sequence(G: nx.DiGraph, from_vessel_id: str, to_vessel_id: str,
|
||||
rinsing_volume: float, repeats: int,
|
||||
flowrate: float, transfer_flowrate: float) -> List[Dict[str, Any]]:
|
||||
"""生成空气冲洗序列"""
|
||||
@@ -1835,12 +1847,12 @@ def _generate_air_rinsing_sequence(G: nx.DiGraph, from_vessel: str, to_vessel: s
|
||||
for _ in range(repeats):
|
||||
# 空气冲洗源容器
|
||||
air_rinsing_actions.extend(
|
||||
generate_pump_protocol(G, air_vessel, from_vessel, rinsing_volume, flowrate, transfer_flowrate)
|
||||
generate_pump_protocol(G, air_vessel, from_vessel_id, rinsing_volume, flowrate, transfer_flowrate)
|
||||
)
|
||||
|
||||
# 空气冲洗目标容器
|
||||
air_rinsing_actions.extend(
|
||||
generate_pump_protocol(G, air_vessel, to_vessel, rinsing_volume, flowrate, transfer_flowrate)
|
||||
generate_pump_protocol(G, air_vessel, to_vessel_id, rinsing_volume, flowrate, transfer_flowrate)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user