mirror of
https://github.com/deepmodeling/Uni-Lab-OS
synced 2026-03-25 14:33:09 +00:00
- 统一debug_print为共享import,移除14个本地定义 - 移除重复工具函数(find_connected_stirrer, get_vessel_liquid_volume等) - 精简装饰性日志(emoji分隔线、进度提示),保留关键决策点 - 删除evacuateandrefill_protocol_old.py死代码 - 涉及文件:add, adjustph, clean_vessel, dissolve, dry, evacuateandrefill, evaporate, filter, pump, recrystallize, reset_handling, run_column, stir, wash_solid Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
371 lines
14 KiB
Python
371 lines
14 KiB
Python
from typing import List, Dict, Any, Union
|
||
import networkx as nx
|
||
import logging
|
||
|
||
from .utils.unit_parser import parse_time_input
|
||
from .utils.resource_helper import get_resource_id, get_resource_display_info
|
||
from .utils.logger_util import debug_print
|
||
from .utils.vessel_parser import find_connected_stirrer
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
def validate_and_fix_params(stir_time: float, stir_speed: float, settling_time: float) -> tuple:
|
||
"""验证和修正参数"""
|
||
# ⏰ 搅拌时间验证
|
||
if stir_time < 0:
|
||
debug_print(f"⚠️ 搅拌时间 {stir_time}s 无效,修正为 100s 🕐")
|
||
stir_time = 100.0
|
||
elif stir_time > 100: # 限制为100s
|
||
debug_print(f"⚠️ 搅拌时间 {stir_time}s 过长,仿真运行时,修正为 100s 🕐")
|
||
stir_time = 100.0
|
||
else:
|
||
debug_print(f"✅ 搅拌时间 {stir_time}s ({stir_time/60:.1f}分钟) 有效 ⏰")
|
||
|
||
# 🌪️ 搅拌速度验证
|
||
if stir_speed < 10.0 or stir_speed > 1500.0:
|
||
debug_print(f"⚠️ 搅拌速度 {stir_speed} RPM 超出范围,修正为 300 RPM 🌪️")
|
||
stir_speed = 300.0
|
||
else:
|
||
debug_print(f"✅ 搅拌速度 {stir_speed} RPM 在正常范围内 🌪️")
|
||
|
||
# ⏱️ 沉降时间验证
|
||
if settling_time < 0 or settling_time > 600: # 限制为10分钟
|
||
debug_print(f"⚠️ 沉降时间 {settling_time}s 超出范围,修正为 60s ⏱️")
|
||
settling_time = 60.0
|
||
else:
|
||
debug_print(f"✅ 沉降时间 {settling_time}s 在正常范围内 ⏱️")
|
||
|
||
return stir_time, stir_speed, settling_time
|
||
|
||
def extract_vessel_id(vessel) -> str:
|
||
"""从vessel参数中提取vessel_id,兼容 str / dict / ResourceDictInstance"""
|
||
return get_resource_id(vessel)
|
||
|
||
def get_vessel_display_info(vessel) -> str:
|
||
"""获取容器的显示信息(用于日志),兼容 str / dict / ResourceDictInstance"""
|
||
return get_resource_display_info(vessel)
|
||
|
||
def generate_stir_protocol(
|
||
G: nx.DiGraph,
|
||
vessel: Union[str, dict], # 支持vessel字典或字符串
|
||
time: Union[str, float, int] = "300",
|
||
stir_time: Union[str, float, int] = "0",
|
||
time_spec: str = "",
|
||
event: str = "",
|
||
stir_speed: float = 300.0,
|
||
settling_time: Union[str, float] = "60",
|
||
**kwargs
|
||
) -> List[Dict[str, Any]]:
|
||
"""生成搅拌操作的协议序列 - 修复vessel参数传递"""
|
||
|
||
# 🔧 核心修改:正确处理vessel参数
|
||
vessel_id = extract_vessel_id(vessel)
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
|
||
# 🔧 关键修复:确保vessel_resource是完整的Resource对象
|
||
if isinstance(vessel, dict):
|
||
vessel_resource = vessel # 已经是完整的Resource字典
|
||
debug_print(f"✅ 使用传入的vessel Resource对象")
|
||
else:
|
||
# 如果只是字符串,构建一个基本的Resource对象
|
||
vessel_resource = {
|
||
"id": vessel,
|
||
"name": "",
|
||
"category": "",
|
||
"children": [],
|
||
"config": "",
|
||
"data": "",
|
||
"parent": "",
|
||
"pose": {
|
||
"orientation": {"w": 1.0, "x": 0.0, "y": 0.0, "z": 0.0},
|
||
"position": {"x": 0.0, "y": 0.0, "z": 0.0}
|
||
},
|
||
"sample_id": "",
|
||
"type": ""
|
||
}
|
||
debug_print(f"🔧 构建了基本的vessel Resource对象: {vessel}")
|
||
|
||
debug_print(f"开始生成搅拌协议: vessel={vessel_id}, time={time}, "
|
||
f"stir_time={stir_time}, stir_speed={stir_speed}RPM, settling={settling_time}")
|
||
|
||
# 参数验证
|
||
if not vessel_id:
|
||
raise ValueError("vessel 参数不能为空")
|
||
|
||
if vessel_id not in G.nodes():
|
||
raise ValueError(f"容器 '{vessel_id}' 不存在于系统中")
|
||
|
||
# 参数解析 — 确定实际时间(优先级:time_spec > stir_time > time)
|
||
if time_spec:
|
||
parsed_time = parse_time_input(time_spec)
|
||
elif stir_time not in ["0", 0, 0.0]:
|
||
parsed_time = parse_time_input(stir_time)
|
||
else:
|
||
parsed_time = parse_time_input(time)
|
||
|
||
# 解析沉降时间
|
||
parsed_settling_time = parse_time_input(settling_time)
|
||
|
||
# 模拟运行时间优化
|
||
original_stir_time = parsed_time
|
||
original_settling_time = parsed_settling_time
|
||
|
||
# 搅拌时间限制为60秒
|
||
stir_time_limit = 60.0
|
||
if parsed_time > stir_time_limit:
|
||
parsed_time = stir_time_limit
|
||
|
||
# 沉降时间限制为30秒
|
||
settling_time_limit = 30.0
|
||
if parsed_settling_time > settling_time_limit:
|
||
parsed_settling_time = settling_time_limit
|
||
|
||
# 参数修正
|
||
parsed_time, stir_speed, parsed_settling_time = validate_and_fix_params(
|
||
parsed_time, stir_speed, parsed_settling_time
|
||
)
|
||
|
||
debug_print(f"最终参数: time={parsed_time}s, speed={stir_speed}RPM, settling={parsed_settling_time}s")
|
||
|
||
# 查找设备
|
||
try:
|
||
stirrer_id = find_connected_stirrer(G, vessel_id)
|
||
except Exception as e:
|
||
raise ValueError(f"无法找到搅拌设备: {str(e)}")
|
||
|
||
# 生成动作
|
||
|
||
action_sequence = []
|
||
stir_action = {
|
||
"device_id": stirrer_id,
|
||
"action_name": "stir",
|
||
"action_kwargs": {
|
||
# 🔧 关键修复:传递vessel_id字符串,而不是完整的Resource对象
|
||
"vessel": {"id": vessel_id}, # 传递字符串ID,不是Resource对象
|
||
"time": str(time),
|
||
"event": event,
|
||
"time_spec": time_spec,
|
||
"stir_time": float(parsed_time),
|
||
"stir_speed": float(stir_speed),
|
||
"settling_time": float(parsed_settling_time)
|
||
}
|
||
}
|
||
action_sequence.append(stir_action)
|
||
|
||
# 时间优化信息
|
||
if original_stir_time != parsed_time or original_settling_time != parsed_settling_time:
|
||
debug_print(f"模拟优化: 搅拌 {original_stir_time/60:.1f}min→{parsed_time/60:.1f}min, "
|
||
f"沉降 {original_settling_time/60:.1f}min→{parsed_settling_time/60:.1f}min")
|
||
|
||
debug_print(f"搅拌协议生成完成: {vessel_display}, {stir_speed}RPM, "
|
||
f"{parsed_time}s, 沉降{parsed_settling_time}s, 总{(parsed_time + parsed_settling_time)/60:.1f}min")
|
||
|
||
return action_sequence
|
||
|
||
def generate_start_stir_protocol(
|
||
G: nx.DiGraph,
|
||
vessel: Union[str, dict],
|
||
stir_speed: float = 300.0,
|
||
purpose: str = "",
|
||
**kwargs
|
||
) -> List[Dict[str, Any]]:
|
||
"""生成开始搅拌操作的协议序列 - 修复vessel参数传递"""
|
||
|
||
# 🔧 核心修改:正确处理vessel参数
|
||
vessel_id = extract_vessel_id(vessel)
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
|
||
# 🔧 关键修复:确保vessel_resource是完整的Resource对象
|
||
if isinstance(vessel, dict):
|
||
vessel_resource = vessel # 已经是完整的Resource字典
|
||
debug_print(f"✅ 使用传入的vessel Resource对象")
|
||
else:
|
||
# 如果只是字符串,构建一个基本的Resource对象
|
||
vessel_resource = {
|
||
"id": vessel,
|
||
"name": "",
|
||
"category": "",
|
||
"children": [],
|
||
"config": "",
|
||
"data": "",
|
||
"parent": "",
|
||
"pose": {
|
||
"orientation": {"w": 1.0, "x": 0.0, "y": 0.0, "z": 0.0},
|
||
"position": {"x": 0.0, "y": 0.0, "z": 0.0}
|
||
},
|
||
"sample_id": "",
|
||
"type": ""
|
||
}
|
||
debug_print(f"构建了基本的vessel Resource对象: {vessel}")
|
||
|
||
debug_print(f"启动搅拌协议: vessel={vessel_id}, speed={stir_speed}RPM, purpose='{purpose}'")
|
||
|
||
# 基础验证
|
||
if not vessel_id or vessel_id not in G.nodes():
|
||
raise ValueError("vessel 参数无效")
|
||
|
||
# 参数修正
|
||
if stir_speed < 10.0 or stir_speed > 1500.0:
|
||
stir_speed = 300.0
|
||
|
||
# 查找设备
|
||
stirrer_id = find_connected_stirrer(G, vessel_id)
|
||
|
||
# 🔧 关键修复:传递vessel_id字符串
|
||
action_sequence = [{
|
||
"device_id": stirrer_id,
|
||
"action_name": "start_stir",
|
||
"action_kwargs": {
|
||
# 🔧 关键修复:传递vessel_id字符串,而不是完整的Resource对象
|
||
"vessel": {"id": vessel_id}, # 传递字符串ID,不是Resource对象
|
||
"stir_speed": stir_speed,
|
||
"purpose": purpose or f"启动搅拌 {stir_speed} RPM"
|
||
}
|
||
}]
|
||
|
||
debug_print(f"启动搅拌协议生成完成: {stirrer_id}")
|
||
return action_sequence
|
||
|
||
def generate_stop_stir_protocol(
|
||
G: nx.DiGraph,
|
||
vessel: Union[str, dict],
|
||
**kwargs
|
||
) -> List[Dict[str, Any]]:
|
||
"""生成停止搅拌操作的协议序列 - 修复vessel参数传递"""
|
||
|
||
# 🔧 核心修改:正确处理vessel参数
|
||
vessel_id = extract_vessel_id(vessel)
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
|
||
# 🔧 关键修复:确保vessel_resource是完整的Resource对象
|
||
if isinstance(vessel, dict):
|
||
vessel_resource = vessel # 已经是完整的Resource字典
|
||
debug_print(f"✅ 使用传入的vessel Resource对象")
|
||
else:
|
||
# 如果只是字符串,构建一个基本的Resource对象
|
||
vessel_resource = {
|
||
"id": vessel,
|
||
"name": "",
|
||
"category": "",
|
||
"children": [],
|
||
"config": "",
|
||
"data": "",
|
||
"parent": "",
|
||
"pose": {
|
||
"orientation": {"w": 1.0, "x": 0.0, "y": 0.0, "z": 0.0},
|
||
"position": {"x": 0.0, "y": 0.0, "z": 0.0}
|
||
},
|
||
"sample_id": "",
|
||
"type": ""
|
||
}
|
||
debug_print(f"构建了基本的vessel Resource对象: {vessel}")
|
||
|
||
debug_print(f"停止搅拌协议: vessel={vessel_id}")
|
||
|
||
# 基础验证
|
||
if not vessel_id or vessel_id not in G.nodes():
|
||
raise ValueError("vessel 参数无效")
|
||
|
||
# 查找设备
|
||
stirrer_id = find_connected_stirrer(G, vessel_id)
|
||
|
||
# 🔧 关键修复:传递vessel_id字符串
|
||
action_sequence = [{
|
||
"device_id": stirrer_id,
|
||
"action_name": "stop_stir",
|
||
"action_kwargs": {
|
||
# 🔧 关键修复:传递vessel_id字符串,而不是完整的Resource对象
|
||
"vessel": {"id": vessel_id}, # 传递字符串ID,不是Resource对象
|
||
}
|
||
}]
|
||
|
||
debug_print(f"停止搅拌协议生成完成: {stirrer_id}")
|
||
return action_sequence
|
||
|
||
# 便捷函数
|
||
def stir_briefly(G: nx.DiGraph, vessel: Union[str, dict],
|
||
speed: float = 300.0) -> List[Dict[str, Any]]:
|
||
"""短时间搅拌(30秒)"""
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
debug_print(f"⚡ 短时间搅拌: {vessel_display} @ {speed}RPM (30s)")
|
||
return generate_stir_protocol(G, vessel, time="30", stir_speed=speed)
|
||
|
||
def stir_slowly(G: nx.DiGraph, vessel: Union[str, dict],
|
||
time: Union[str, float] = "10 min") -> List[Dict[str, Any]]:
|
||
"""慢速搅拌"""
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
debug_print(f"🐌 慢速搅拌: {vessel_display} @ 150RPM")
|
||
return generate_stir_protocol(G, vessel, time=time, stir_speed=150.0)
|
||
|
||
def stir_vigorously(G: nx.DiGraph, vessel: Union[str, dict],
|
||
time: Union[str, float] = "5 min") -> List[Dict[str, Any]]:
|
||
"""剧烈搅拌"""
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
debug_print(f"💨 剧烈搅拌: {vessel_display} @ 800RPM")
|
||
return generate_stir_protocol(G, vessel, time=time, stir_speed=800.0)
|
||
|
||
def stir_for_reaction(G: nx.DiGraph, vessel: Union[str, dict],
|
||
time: Union[str, float] = "1 h") -> List[Dict[str, Any]]:
|
||
"""反应搅拌(标准速度,长时间)"""
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
debug_print(f"🧪 反应搅拌: {vessel_display} @ 400RPM")
|
||
return generate_stir_protocol(G, vessel, time=time, stir_speed=400.0)
|
||
|
||
def stir_for_dissolution(G: nx.DiGraph, vessel: Union[str, dict],
|
||
time: Union[str, float] = "15 min") -> List[Dict[str, Any]]:
|
||
"""溶解搅拌(中等速度)"""
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
debug_print(f"💧 溶解搅拌: {vessel_display} @ 500RPM")
|
||
return generate_stir_protocol(G, vessel, time=time, stir_speed=500.0)
|
||
|
||
def stir_gently(G: nx.DiGraph, vessel: Union[str, dict],
|
||
time: Union[str, float] = "30 min") -> List[Dict[str, Any]]:
|
||
"""温和搅拌"""
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
debug_print(f"🍃 温和搅拌: {vessel_display} @ 200RPM")
|
||
return generate_stir_protocol(G, vessel, time=time, stir_speed=200.0)
|
||
|
||
def stir_overnight(G: nx.DiGraph, vessel: Union[str, dict]) -> List[Dict[str, Any]]:
|
||
"""过夜搅拌(模拟时缩短为2小时)"""
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
debug_print(f"🌙 过夜搅拌(模拟2小时): {vessel_display} @ 300RPM")
|
||
return generate_stir_protocol(G, vessel, time="2 h", stir_speed=300.0)
|
||
|
||
def start_continuous_stirring(G: nx.DiGraph, vessel: Union[str, dict],
|
||
speed: float = 300.0, purpose: str = "continuous stirring") -> List[Dict[str, Any]]:
|
||
"""开始连续搅拌"""
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
debug_print(f"🔄 开始连续搅拌: {vessel_display} @ {speed}RPM")
|
||
return generate_start_stir_protocol(G, vessel, stir_speed=speed, purpose=purpose)
|
||
|
||
def stop_all_stirring(G: nx.DiGraph, vessel: Union[str, dict]) -> List[Dict[str, Any]]:
|
||
"""停止所有搅拌"""
|
||
vessel_display = get_vessel_display_info(vessel)
|
||
debug_print(f"🛑 停止搅拌: {vessel_display}")
|
||
return generate_stop_stir_protocol(G, vessel)
|
||
|
||
# 测试函数
|
||
def test_stir_protocol():
|
||
"""测试搅拌协议"""
|
||
debug_print("🧪 === STIR PROTOCOL 测试 === ✨")
|
||
|
||
# 测试vessel参数处理
|
||
debug_print("🔧 测试vessel参数处理...")
|
||
|
||
# 测试字典格式
|
||
vessel_dict = {"id": "flask_1", "name": "反应瓶1"}
|
||
vessel_id = extract_vessel_id(vessel_dict)
|
||
vessel_display = get_vessel_display_info(vessel_dict)
|
||
debug_print(f" 字典格式: {vessel_dict} → ID: {vessel_id}, 显示: {vessel_display}")
|
||
|
||
# 测试字符串格式
|
||
vessel_str = "flask_2"
|
||
vessel_id = extract_vessel_id(vessel_str)
|
||
vessel_display = get_vessel_display_info(vessel_str)
|
||
debug_print(f" 字符串格式: {vessel_str} → ID: {vessel_id}, 显示: {vessel_display}")
|
||
|
||
debug_print("✅ 测试完成 🎉")
|
||
|
||
if __name__ == "__main__":
|
||
test_stir_protocol()
|