Files
Uni-Lab-OS/unilabos/compile/wash_solid_protocol.py
KCFeng425 4c6e437eb1 修复了部分的protocol因为XDL更新导致的问题
但是pumptransfer,add,dissolve,separate还没修,后续还需要写virtual固体加料器
2025-07-06 19:21:53 +08:00

317 lines
9.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from typing import List, Dict, Any
import networkx as nx
import logging
import sys
logger = logging.getLogger(__name__)
def debug_print(message):
"""调试输出"""
print(f"[WASH_SOLID] {message}", flush=True)
logger.info(f"[WASH_SOLID] {message}")
def find_solvent_source(G: nx.DiGraph, solvent: str) -> str:
"""查找溶剂源容器"""
debug_print(f"查找溶剂 '{solvent}' 的源容器...")
# 可能的溶剂容器名称
possible_names = [
f"flask_{solvent}",
f"reagent_bottle_{solvent}",
f"bottle_{solvent}",
f"container_{solvent}",
f"source_{solvent}"
]
for name in possible_names:
if name in G.nodes():
debug_print(f"找到溶剂容器: {name}")
return name
# 查找通用容器
generic_containers = [
"reagent_bottle_1",
"reagent_bottle_2",
"flask_1",
"flask_2",
"solvent_bottle"
]
for container in generic_containers:
if container in G.nodes():
debug_print(f"使用通用容器: {container}")
return container
debug_print("未找到溶剂容器,使用默认容器")
return f"flask_{solvent}"
def find_filtrate_vessel(G: nx.DiGraph, filtrate_vessel: str = "") -> str:
"""查找滤液收集容器"""
debug_print(f"查找滤液收集容器,指定容器: '{filtrate_vessel}'")
# 如果指定了容器且存在,直接使用
if filtrate_vessel and filtrate_vessel.strip():
if filtrate_vessel in G.nodes():
debug_print(f"使用指定的滤液容器: {filtrate_vessel}")
return filtrate_vessel
else:
debug_print(f"指定的滤液容器 '{filtrate_vessel}' 不存在,查找默认容器")
# 自动查找滤液容器
possible_names = [
"waste_workup", # 废液收集
"filtrate_vessel", # 标准滤液容器
"collection_bottle_1", # 收集瓶
"collection_bottle_2", # 收集瓶
"rotavap", # 旋蒸仪
"waste_flask", # 废液瓶
"flask_1", # 通用烧瓶
"flask_2" # 通用烧瓶
]
for vessel_name in possible_names:
if vessel_name in G.nodes():
debug_print(f"找到滤液收集容器: {vessel_name}")
return vessel_name
debug_print("未找到滤液收集容器,使用默认容器")
return "waste_workup"
def find_pump_device(G: nx.DiGraph) -> str:
"""查找转移泵设备"""
debug_print("查找转移泵设备...")
pump_devices = []
for node in G.nodes():
node_data = G.nodes[node]
node_class = node_data.get('class', '') or ''
if 'transfer_pump' in node_class or 'virtual_transfer_pump' in node_class:
pump_devices.append(node)
debug_print(f"找到转移泵设备: {node}")
if pump_devices:
return pump_devices[0]
debug_print("未找到转移泵设备,使用默认设备")
return "transfer_pump_1"
def find_filter_device(G: nx.DiGraph) -> str:
"""查找过滤器设备"""
debug_print("查找过滤器设备...")
filter_devices = []
for node in G.nodes():
node_data = G.nodes[node]
node_class = node_data.get('class', '') or ''
if 'filter' in node_class.lower() or 'virtual_filter' in node_class:
filter_devices.append(node)
debug_print(f"找到过滤器设备: {node}")
if filter_devices:
return filter_devices[0]
debug_print("未找到过滤器设备,使用默认设备")
return "filter_1"
def generate_wash_solid_protocol(
G: nx.DiGraph,
vessel: str,
solvent: str,
volume: float,
filtrate_vessel: str = "",
temp: float = 25.0,
stir: bool = False,
stir_speed: float = 0.0,
time: float = 0.0,
repeats: int = 1,
**kwargs # 🔧 接受额外参数,增强兼容性
) -> List[Dict[str, Any]]:
"""
生成固体清洗操作的协议序列 - 简化版本
Args:
G: 设备图
vessel: 装有固体的容器名称(必需)
solvent: 清洗溶剂名称(必需)
volume: 清洗溶剂体积(必需)
filtrate_vessel: 滤液收集容器(可选,自动查找)
temp: 清洗温度默认25°C
stir: 是否搅拌默认False
stir_speed: 搅拌速度默认0
time: 清洗时间默认0
repeats: 重复次数默认1
**kwargs: 其他参数(兼容性)
Returns:
List[Dict[str, Any]]: 固体清洗操作的动作序列
"""
debug_print("=" * 50)
debug_print("开始生成固体清洗协议")
debug_print(f"输入参数:")
debug_print(f" - vessel: {vessel}")
debug_print(f" - solvent: {solvent}")
debug_print(f" - volume: {volume}mL")
debug_print(f" - filtrate_vessel: {filtrate_vessel}")
debug_print(f" - temp: {temp}°C")
debug_print(f" - stir: {stir}")
debug_print(f" - stir_speed: {stir_speed} RPM")
debug_print(f" - time: {time}s")
debug_print(f" - repeats: {repeats}")
debug_print(f" - 其他参数: {kwargs}")
debug_print("=" * 50)
action_sequence = []
# === 参数验证 ===
debug_print("步骤1: 参数验证...")
# 验证必需参数
if not vessel:
raise ValueError("vessel 参数不能为空")
if not solvent:
raise ValueError("solvent 参数不能为空")
if volume <= 0:
raise ValueError("volume 必须大于0")
if vessel not in G.nodes():
raise ValueError(f"容器 '{vessel}' 不存在于系统中")
# 修正参数范围
if temp < 0 or temp > 200:
debug_print(f"温度 {temp}°C 超出范围,修正为 25°C")
temp = 25.0
if stir_speed < 0 or stir_speed > 500:
debug_print(f"搅拌速度 {stir_speed} RPM 超出范围,修正为 0")
stir_speed = 0.0
if time < 0:
debug_print(f"时间 {time}s 无效,修正为 0")
time = 0.0
if repeats < 1:
debug_print(f"重复次数 {repeats} 无效,修正为 1")
repeats = 1
elif repeats > 10:
debug_print(f"重复次数 {repeats} 过多,修正为 10")
repeats = 10
debug_print(f"✅ 参数验证通过")
# === 查找设备 ===
debug_print("步骤2: 查找设备...")
try:
solvent_source = find_solvent_source(G, solvent)
actual_filtrate_vessel = find_filtrate_vessel(G, filtrate_vessel)
pump_device = find_pump_device(G)
filter_device = find_filter_device(G)
debug_print(f"设备配置:")
debug_print(f" - 溶剂源: {solvent_source}")
debug_print(f" - 滤液容器: {actual_filtrate_vessel}")
debug_print(f" - 转移泵: {pump_device}")
debug_print(f" - 过滤器: {filter_device}")
except Exception as e:
debug_print(f"❌ 设备查找失败: {str(e)}")
raise ValueError(f"设备查找失败: {str(e)}")
# === 执行清洗循环 ===
debug_print("步骤3: 执行清洗循环...")
for cycle in range(repeats):
debug_print(f"=== 第 {cycle+1}/{repeats} 次清洗 ===")
# 添加清洗溶剂
debug_print(f"添加清洗溶剂: {solvent_source} -> {vessel}")
wash_action = {
"device_id": filter_device,
"action_name": "wash_solid",
"action_kwargs": {
"vessel": vessel,
"solvent": solvent,
"volume": volume,
"filtrate_vessel": actual_filtrate_vessel,
"temp": temp,
"stir": stir,
"stir_speed": stir_speed,
"time": time,
"repeats": 1 # 每次循环只做1次
}
}
action_sequence.append(wash_action)
# 等待清洗完成
action_sequence.append({
"action_name": "wait",
"action_kwargs": {"time": max(10.0, time * 0.1)}
})
# === 总结 ===
debug_print("=" * 50)
debug_print(f"固体清洗协议生成完成")
debug_print(f"总动作数: {len(action_sequence)}")
debug_print(f"清洗容器: {vessel}")
debug_print(f"使用溶剂: {solvent}")
debug_print(f"清洗体积: {volume}mL")
debug_print(f"重复次数: {repeats}")
debug_print("=" * 50)
return action_sequence
# === 便捷函数 ===
def generate_quick_wash_protocol(
G: nx.DiGraph,
vessel: str,
solvent: str,
volume: float,
**kwargs
) -> List[Dict[str, Any]]:
"""快速清洗1次室温不搅拌"""
return generate_wash_solid_protocol(
G, vessel, solvent, volume,
repeats=1, temp=25.0, stir=False, **kwargs
)
def generate_thorough_wash_protocol(
G: nx.DiGraph,
vessel: str,
solvent: str,
volume: float,
**kwargs
) -> List[Dict[str, Any]]:
"""彻底清洗3次加热搅拌"""
return generate_wash_solid_protocol(
G, vessel, solvent, volume,
repeats=3, temp=50.0, stir=True, stir_speed=200.0, time=300.0, **kwargs
)
def generate_gentle_wash_protocol(
G: nx.DiGraph,
vessel: str,
solvent: str,
volume: float,
**kwargs
) -> List[Dict[str, Any]]:
"""温和清洗2次室温轻搅拌"""
return generate_wash_solid_protocol(
G, vessel, solvent, volume,
repeats=2, temp=25.0, stir=True, stir_speed=100.0, time=180.0, **kwargs
)
# 测试函数
def test_wash_solid_protocol():
"""测试固体清洗协议"""
debug_print("=== WASH SOLID PROTOCOL 测试 ===")
debug_print("✅ 测试完成")
if __name__ == "__main__":
test_wash_solid_protocol()