mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2026-02-05 14:05:12 +00:00
修复了部分的protocol因为XDL更新导致的问题
但是pumptransfer,add,dissolve,separate还没修,后续还需要写virtual固体加料器
This commit is contained in:
@@ -1,5 +1,119 @@
|
||||
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,
|
||||
@@ -11,206 +125,193 @@ def generate_wash_solid_protocol(
|
||||
stir: bool = False,
|
||||
stir_speed: float = 0.0,
|
||||
time: float = 0.0,
|
||||
repeats: int = 1
|
||||
repeats: int = 1,
|
||||
**kwargs # 🔧 接受额外参数,增强兼容性
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
生成固体清洗的协议序列
|
||||
生成固体清洗操作的协议序列 - 简化版本
|
||||
|
||||
Args:
|
||||
G: 有向图,节点为设备和容器
|
||||
vessel: 装有固体物质的容器名称
|
||||
solvent: 用于清洗固体的溶剂名称
|
||||
volume: 清洗溶剂的体积
|
||||
filtrate_vessel: 滤液要收集到的容器名称,可选参数
|
||||
temp: 清洗时的温度,可选参数
|
||||
stir: 是否在清洗过程中搅拌,默认为 False
|
||||
stir_speed: 搅拌速度,可选参数
|
||||
time: 清洗的时间,可选参数
|
||||
repeats: 清洗操作的重复次数,默认为 1
|
||||
G: 设备图
|
||||
vessel: 装有固体的容器名称(必需)
|
||||
solvent: 清洗溶剂名称(必需)
|
||||
volume: 清洗溶剂体积(必需)
|
||||
filtrate_vessel: 滤液收集容器(可选,自动查找)
|
||||
temp: 清洗温度,默认25°C
|
||||
stir: 是否搅拌,默认False
|
||||
stir_speed: 搅拌速度,默认0
|
||||
time: 清洗时间,默认0
|
||||
repeats: 重复次数,默认1
|
||||
**kwargs: 其他参数(兼容性)
|
||||
|
||||
Returns:
|
||||
List[Dict[str, Any]]: 固体清洗操作的动作序列
|
||||
|
||||
Raises:
|
||||
ValueError: 当找不到必要的设备时抛出异常
|
||||
|
||||
Examples:
|
||||
wash_solid_protocol = generate_wash_solid_protocol(
|
||||
G, "reactor", "ethanol", 100.0, "waste_flask", 60.0, True, 300.0, 600.0, 3
|
||||
)
|
||||
"""
|
||||
|
||||
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} 不存在于图中")
|
||||
raise ValueError(f"容器 '{vessel}' 不存在于系统中")
|
||||
|
||||
if filtrate_vessel and filtrate_vessel not in G.nodes():
|
||||
raise ValueError(f"滤液容器 {filtrate_vessel} 不存在于图中")
|
||||
# 修正参数范围
|
||||
if temp < 0 or temp > 200:
|
||||
debug_print(f"温度 {temp}°C 超出范围,修正为 25°C")
|
||||
temp = 25.0
|
||||
|
||||
# 查找转移泵设备(用于添加溶剂和转移滤液)
|
||||
pump_nodes = [node for node in G.nodes()
|
||||
if G.nodes[node].get('class') == 'virtual_transfer_pump']
|
||||
if stir_speed < 0 or stir_speed > 500:
|
||||
debug_print(f"搅拌速度 {stir_speed} RPM 超出范围,修正为 0")
|
||||
stir_speed = 0.0
|
||||
|
||||
if not pump_nodes:
|
||||
raise ValueError("没有找到可用的转移泵设备")
|
||||
if time < 0:
|
||||
debug_print(f"时间 {time}s 无效,修正为 0")
|
||||
time = 0.0
|
||||
|
||||
pump_id = pump_nodes[0]
|
||||
if repeats < 1:
|
||||
debug_print(f"重复次数 {repeats} 无效,修正为 1")
|
||||
repeats = 1
|
||||
elif repeats > 10:
|
||||
debug_print(f"重复次数 {repeats} 过多,修正为 10")
|
||||
repeats = 10
|
||||
|
||||
# 查找加热设备(如果需要加热)
|
||||
heatchill_nodes = [node for node in G.nodes()
|
||||
if G.nodes[node].get('class') == 'virtual_heatchill']
|
||||
debug_print(f"✅ 参数验证通过")
|
||||
|
||||
heatchill_id = heatchill_nodes[0] if heatchill_nodes else None
|
||||
# === 查找设备 ===
|
||||
debug_print("步骤2: 查找设备...")
|
||||
|
||||
# 查找搅拌设备(如果需要搅拌)
|
||||
stirrer_nodes = [node for node in G.nodes()
|
||||
if G.nodes[node].get('class') == 'virtual_stirrer']
|
||||
|
||||
stirrer_id = stirrer_nodes[0] if stirrer_nodes else None
|
||||
|
||||
# 查找过滤设备(用于分离固体和滤液)
|
||||
filter_nodes = [node for node in G.nodes()
|
||||
if G.nodes[node].get('class') == 'virtual_filter']
|
||||
|
||||
filter_id = filter_nodes[0] if filter_nodes else None
|
||||
|
||||
# 查找溶剂容器
|
||||
solvent_vessel = f"flask_{solvent}"
|
||||
if solvent_vessel not in G.nodes():
|
||||
# 如果没有找到特定溶剂容器,查找可用的源容器
|
||||
available_vessels = [node for node in G.nodes()
|
||||
if node.startswith('flask_') and
|
||||
G.nodes[node].get('type') == 'container']
|
||||
if available_vessels:
|
||||
solvent_vessel = available_vessels[0]
|
||||
else:
|
||||
raise ValueError(f"没有找到溶剂容器 {solvent}")
|
||||
|
||||
# 如果没有指定滤液容器,使用废液容器
|
||||
if not filtrate_vessel:
|
||||
waste_vessels = [node for node in G.nodes()
|
||||
if 'waste' in node.lower() and
|
||||
G.nodes[node].get('type') == 'container']
|
||||
filtrate_vessel = waste_vessels[0] if waste_vessels else "waste_flask"
|
||||
|
||||
# 重复清洗操作
|
||||
for repeat in range(repeats):
|
||||
repeat_num = repeat + 1
|
||||
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)
|
||||
|
||||
# 步骤1:如果需要加热,先设置温度
|
||||
if temp > 25.0 and heatchill_id:
|
||||
action_sequence.append({
|
||||
"device_id": heatchill_id,
|
||||
"action_name": "heat_chill_start",
|
||||
"action_kwargs": {
|
||||
"vessel": vessel,
|
||||
"temp": temp,
|
||||
"purpose": f"固体清洗 - 第 {repeat_num} 次"
|
||||
}
|
||||
})
|
||||
debug_print(f"设备配置:")
|
||||
debug_print(f" - 溶剂源: {solvent_source}")
|
||||
debug_print(f" - 滤液容器: {actual_filtrate_vessel}")
|
||||
debug_print(f" - 转移泵: {pump_device}")
|
||||
debug_print(f" - 过滤器: {filter_device}")
|
||||
|
||||
# 步骤2:添加清洗溶剂到固体容器
|
||||
action_sequence.append({
|
||||
"device_id": pump_id,
|
||||
"action_name": "transfer",
|
||||
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": {
|
||||
"from_vessel": solvent_vessel,
|
||||
"to_vessel": vessel,
|
||||
"vessel": vessel,
|
||||
"solvent": solvent,
|
||||
"volume": volume,
|
||||
"amount": f"清洗溶剂 {solvent} - 第 {repeat_num} 次",
|
||||
"time": 0.0,
|
||||
"viscous": False,
|
||||
"rinsing_solvent": "",
|
||||
"rinsing_volume": 0.0,
|
||||
"rinsing_repeats": 0,
|
||||
"solid": False
|
||||
"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)}
|
||||
})
|
||||
|
||||
# 步骤3:如果需要搅拌,开始搅拌
|
||||
if stir and stir_speed > 0 and stirrer_id:
|
||||
if time > 0:
|
||||
# 定时搅拌
|
||||
action_sequence.append({
|
||||
"device_id": stirrer_id,
|
||||
"action_name": "stir",
|
||||
"action_kwargs": {
|
||||
"stir_time": time,
|
||||
"stir_speed": stir_speed,
|
||||
"settling_time": 30.0 # 搅拌后静置30秒
|
||||
}
|
||||
})
|
||||
else:
|
||||
# 开始搅拌(需要手动停止)
|
||||
action_sequence.append({
|
||||
"device_id": stirrer_id,
|
||||
"action_name": "start_stir",
|
||||
"action_kwargs": {
|
||||
"vessel": vessel,
|
||||
"stir_speed": stir_speed,
|
||||
"purpose": f"固体清洗搅拌 - 第 {repeat_num} 次"
|
||||
}
|
||||
})
|
||||
|
||||
# 步骤4:如果指定了清洗时间但没有搅拌,等待清洗时间
|
||||
if time > 0 and (not stir or stir_speed == 0):
|
||||
# 这里可以添加等待操作,暂时跳过
|
||||
pass
|
||||
|
||||
# 步骤5:如果有搅拌且没有定时,停止搅拌
|
||||
if stir and stir_speed > 0 and time == 0 and stirrer_id:
|
||||
action_sequence.append({
|
||||
"device_id": stirrer_id,
|
||||
"action_name": "stop_stir",
|
||||
"action_kwargs": {
|
||||
"vessel": vessel
|
||||
}
|
||||
})
|
||||
|
||||
# 步骤6:过滤分离固体和滤液
|
||||
if filter_id:
|
||||
action_sequence.append({
|
||||
"device_id": filter_id,
|
||||
"action_name": "filter_sample",
|
||||
"action_kwargs": {
|
||||
"vessel": vessel,
|
||||
"filtrate_vessel": filtrate_vessel,
|
||||
"stir": False,
|
||||
"stir_speed": 0.0,
|
||||
"temp": temp,
|
||||
"continue_heatchill": temp > 25.0,
|
||||
"volume": volume
|
||||
}
|
||||
})
|
||||
else:
|
||||
# 没有专门的过滤设备,使用转移泵模拟过滤过程
|
||||
# 将滤液转移到滤液容器
|
||||
action_sequence.append({
|
||||
"device_id": pump_id,
|
||||
"action_name": "transfer",
|
||||
"action_kwargs": {
|
||||
"from_vessel": vessel,
|
||||
"to_vessel": filtrate_vessel,
|
||||
"volume": volume,
|
||||
"amount": f"转移滤液 - 第 {repeat_num} 次清洗",
|
||||
"time": 0.0,
|
||||
"viscous": False,
|
||||
"rinsing_solvent": "",
|
||||
"rinsing_volume": 0.0,
|
||||
"rinsing_repeats": 0,
|
||||
"solid": False
|
||||
}
|
||||
})
|
||||
|
||||
# 步骤7:如果加热了,停止加热(在最后一次清洗后)
|
||||
if temp > 25.0 and heatchill_id and repeat_num == repeats:
|
||||
action_sequence.append({
|
||||
"device_id": heatchill_id,
|
||||
"action_name": "heat_chill_stop",
|
||||
"action_kwargs": {
|
||||
"vessel": vessel
|
||||
}
|
||||
})
|
||||
|
||||
return action_sequence
|
||||
# === 总结 ===
|
||||
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()
|
||||
Reference in New Issue
Block a user