refactor: 14个协议编译器去重精简,删除死代码

- 统一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>
This commit is contained in:
Junhan Chang
2026-03-25 13:12:10 +08:00
parent 5f36b6c04b
commit 0ab4027de7
15 changed files with 1018 additions and 3461 deletions

View File

@@ -1,14 +1,12 @@
from functools import partial
import networkx as nx
import logging
from typing import List, Dict, Any, Union
from .utils.vessel_parser import get_vessel
from .utils.vessel_parser import get_vessel, find_connected_stirrer
from .utils.logger_util import action_log, debug_print
from .pump_protocol import generate_pump_protocol_with_rinsing
logger = logging.getLogger(__name__)
def debug_print(message):
"""调试输出"""
logger.info(f"[ADJUST_PH] {message}")
create_action_log = partial(action_log, prefix="[ADJUST_PH]")
def find_acid_base_vessel(G: nx.DiGraph, reagent: str) -> str:
"""
@@ -100,52 +98,11 @@ def find_acid_base_vessel(G: nx.DiGraph, reagent: str) -> str:
return node_id
# 列出可用容器帮助调试
debug_print(f"📊 列出可用容器帮助调试...")
available_containers = []
for node_id in G.nodes():
if G.nodes[node_id].get('type') == 'container':
vessel_data = G.nodes[node_id].get('data', {})
liquids = vessel_data.get('liquid', [])
liquid_types = [liquid.get('liquid_type', '') or liquid.get('name', '')
for liquid in liquids if isinstance(liquid, dict)]
available_containers.append({
'id': node_id,
'name': G.nodes[node_id].get('name', ''),
'liquids': liquid_types,
'reagent_name': vessel_data.get('reagent_name', '')
})
debug_print(f"📋 可用容器列表:")
for container in available_containers:
debug_print(f" - 🧪 {container['id']}: {container['name']}")
debug_print(f" 💧 液体: {container['liquids']}")
debug_print(f" 🏷️ 试剂: {container['reagent_name']}")
debug_print(f"❌ 所有匹配方法都失败了")
available_containers = [node_id for node_id in G.nodes()
if G.nodes[node_id].get('type') == 'container']
debug_print(f"所有匹配方法失败,可用容器: {available_containers}")
raise ValueError(f"找不到试剂 '{reagent}' 对应的容器。尝试了: {possible_names[:10]}...")
def find_connected_stirrer(G: nx.DiGraph, vessel: str) -> str:
"""查找与容器相连的搅拌器"""
debug_print(f"🔍 查找连接到容器 '{vessel}' 的搅拌器...")
stirrer_nodes = [node for node in G.nodes()
if (G.nodes[node].get('class') or '') == 'virtual_stirrer']
debug_print(f"📊 发现 {len(stirrer_nodes)} 个搅拌器: {stirrer_nodes}")
for stirrer in stirrer_nodes:
if G.has_edge(stirrer, vessel) or G.has_edge(vessel, stirrer):
debug_print(f"✅ 找到连接的搅拌器: {stirrer} 🔗")
return stirrer
if stirrer_nodes:
debug_print(f"⚠️ 未找到直接连接的搅拌器,使用第一个: {stirrer_nodes[0]} 🔄")
return stirrer_nodes[0]
debug_print(f"❌ 未找到任何搅拌器")
return None
def calculate_reagent_volume(target_ph_value: float, reagent: str, vessel_volume: float = 100.0) -> float:
"""
估算需要的试剂体积来调节pH
@@ -158,44 +115,30 @@ def calculate_reagent_volume(target_ph_value: float, reagent: str, vessel_volume
Returns:
float: 估算的试剂体积 (mL)
"""
debug_print(f"🧮 计算试剂体积...")
debug_print(f" 📍 目标pH: {target_ph_value}")
debug_print(f" 🧪 试剂: {reagent}")
debug_print(f" 📏 容器体积: {vessel_volume}mL")
# 简化的pH调节体积估算实际应用中需要更精确的计算
debug_print(f"计算试剂体积: pH={target_ph_value}, reagent={reagent}, vessel={vessel_volume}mL")
# 简化的pH调节体积估算
if "acid" in reagent.lower() or "hcl" in reagent.lower():
debug_print(f"🍋 检测到酸性试剂")
# 酸性试剂pH越低需要的体积越大
if target_ph_value < 3:
volume = vessel_volume * 0.05 # 5%
debug_print(f" 💪 强酸性 (pH<3): 使用 5% 体积")
volume = vessel_volume * 0.05
elif target_ph_value < 5:
volume = vessel_volume * 0.02 # 2%
debug_print(f" 🔸 中酸性 (pH<5): 使用 2% 体积")
volume = vessel_volume * 0.02
else:
volume = vessel_volume * 0.01 # 1%
debug_print(f" 🔹 弱酸性 (pH≥5): 使用 1% 体积")
volume = vessel_volume * 0.01
elif "hydroxide" in reagent.lower() or "naoh" in reagent.lower():
debug_print(f"🧂 检测到碱性试剂")
# 碱性试剂pH越高需要的体积越大
if target_ph_value > 11:
volume = vessel_volume * 0.05 # 5%
debug_print(f" 💪 强碱性 (pH>11): 使用 5% 体积")
volume = vessel_volume * 0.05
elif target_ph_value > 9:
volume = vessel_volume * 0.02 # 2%
debug_print(f" 🔸 中碱性 (pH>9): 使用 2% 体积")
volume = vessel_volume * 0.02
else:
volume = vessel_volume * 0.01 # 1%
debug_print(f" 🔹 弱碱性 (pH≤9): 使用 1% 体积")
volume = vessel_volume * 0.01
else:
# 未知试剂,使用默认值
volume = vessel_volume * 0.01
debug_print(f"❓ 未知试剂类型,使用默认 1% 体积")
debug_print(f"📊 计算结果: {volume:.2f}mL")
debug_print(f"估算试剂体积: {volume:.2f}mL")
return volume
def generate_adjust_ph_protocol(
@@ -220,96 +163,67 @@ def generate_adjust_ph_protocol(
"""
vessel_id, vessel_data = get_vessel(vessel)
if not vessel_id:
debug_print(f"❌ vessel 参数无效必须包含id字段或直接提供容器ID. vessel: {vessel}")
raise ValueError("vessel 参数无效必须包含id字段或直接提供容器ID")
debug_print("=" * 60)
debug_print("🧪 开始生成pH调节协议")
debug_print(f"📋 原始参数:")
debug_print(f" 🥼 vessel: {vessel} (ID: {vessel_id})")
debug_print(f" 📊 ph_value: {ph_value}")
debug_print(f" 🧪 reagent: '{reagent}'")
debug_print(f" 📦 kwargs: {kwargs}")
debug_print("=" * 60)
debug_print(f"开始生成pH调节协议: vessel={vessel_id}, ph={ph_value}, reagent='{reagent}'")
action_sequence = []
# 从kwargs中获取可选参数,如果没有则使用默认值
volume = kwargs.get('volume', 0.0) # 自动估算体积
stir = kwargs.get('stir', True) # 默认搅拌
stir_speed = kwargs.get('stir_speed', 300.0) # 默认搅拌速度
stir_time = kwargs.get('stir_time', 60.0) # 默认搅拌时间
settling_time = kwargs.get('settling_time', 30.0) # 默认平衡时间
debug_print(f"🔧 处理后的参数:")
debug_print(f" 📏 volume: {volume}mL (0.0表示自动估算)")
debug_print(f" 🌪️ stir: {stir}")
debug_print(f" 🔄 stir_speed: {stir_speed}rpm")
debug_print(f" ⏱️ stir_time: {stir_time}s")
debug_print(f" ⏳ settling_time: {settling_time}s")
# 从kwargs中获取可选参数
volume = kwargs.get('volume', 0.0)
stir = kwargs.get('stir', True)
stir_speed = kwargs.get('stir_speed', 300.0)
stir_time = kwargs.get('stir_time', 60.0)
settling_time = kwargs.get('settling_time', 30.0)
# 开始处理
action_sequence.append(create_action_log(f"开始调节pH至 {ph_value}", "🧪"))
action_sequence.append(create_action_log(f"目标容器: {vessel_id}", "🥼"))
action_sequence.append(create_action_log(f"使用试剂: {reagent}", "⚗️"))
# 1. 验证目标容器存在
debug_print(f"🔍 步骤1: 验证目标容器...")
if vessel_id not in G.nodes():
debug_print(f"❌ 目标容器 '{vessel_id}' 不存在于系统中")
raise ValueError(f"目标容器 '{vessel_id}' 不存在于系统中")
debug_print(f"✅ 目标容器验证通过")
action_sequence.append(create_action_log("目标容器验证通过", ""))
# 2. 查找酸碱试剂容器
debug_print(f"🔍 步骤2: 查找试剂容器...")
action_sequence.append(create_action_log("正在查找试剂容器...", "🔍"))
try:
reagent_vessel = find_acid_base_vessel(G, reagent)
debug_print(f"✅ 找到试剂容器: {reagent_vessel}")
action_sequence.append(create_action_log(f"找到试剂容器: {reagent_vessel}", "🧪"))
except ValueError as e:
debug_print(f"❌ 无法找到试剂容器: {str(e)}")
action_sequence.append(create_action_log(f"试剂容器查找失败: {str(e)}", ""))
raise ValueError(f"无法找到试剂 '{reagent}': {str(e)}")
# 3. 体积估算
debug_print(f"🔍 步骤3: 体积处理...")
if volume <= 0:
action_sequence.append(create_action_log("开始自动估算试剂体积", "🧮"))
# 获取目标容器的体积信息
vessel_data = G.nodes[vessel_id].get('data', {})
vessel_volume = vessel_data.get('max_volume', 100.0) # 默认100mL
debug_print(f"📏 容器最大体积: {vessel_volume}mL")
vessel_volume = vessel_data.get('max_volume', 100.0)
estimated_volume = calculate_reagent_volume(ph_value, reagent, vessel_volume)
volume = estimated_volume
debug_print(f"✅ 自动估算试剂体积: {volume:.2f} mL")
action_sequence.append(create_action_log(f"估算试剂体积: {volume:.2f}mL", "📊"))
else:
debug_print(f"📏 使用指定体积: {volume}mL")
action_sequence.append(create_action_log(f"使用指定体积: {volume}mL", "📏"))
# 4. 验证路径存在
debug_print(f"🔍 步骤4: 路径验证...")
action_sequence.append(create_action_log("验证转移路径...", "🛤️"))
try:
path = nx.shortest_path(G, source=reagent_vessel, target=vessel_id)
debug_print(f"找到路径: {' '.join(path)}")
action_sequence.append(create_action_log(f"找到转移路径: {''.join(path)}", "🛤️"))
action_sequence.append(create_action_log(f"找到转移路径: {' -> '.join(path)}", "🛤️"))
except nx.NetworkXNoPath:
debug_print(f"❌ 无法找到转移路径")
action_sequence.append(create_action_log("转移路径不存在", ""))
raise ValueError(f"从试剂容器 '{reagent_vessel}' 到目标容器 '{vessel_id}' 没有可用路径")
# 5. 搅拌器设置
debug_print(f"🔍 步骤5: 搅拌器设置...")
stirrer_id = None
if stir:
action_sequence.append(create_action_log("准备启动搅拌器", "🌪️"))
@@ -318,7 +232,6 @@ def generate_adjust_ph_protocol(
stirrer_id = find_connected_stirrer(G, vessel_id)
if stirrer_id:
debug_print(f"✅ 找到搅拌器 {stirrer_id},启动搅拌")
action_sequence.append(create_action_log(f"启动搅拌器 {stirrer_id} (速度: {stir_speed}rpm)", "🔄"))
action_sequence.append({
@@ -338,23 +251,18 @@ def generate_adjust_ph_protocol(
"action_kwargs": {"time": 5}
})
else:
debug_print(f"⚠️ 未找到搅拌器,继续执行")
action_sequence.append(create_action_log("未找到搅拌器,跳过搅拌", "⚠️"))
except Exception as e:
debug_print(f"❌ 搅拌器配置出错: {str(e)}")
action_sequence.append(create_action_log(f"搅拌器配置失败: {str(e)}", ""))
else:
debug_print(f"📋 跳过搅拌设置")
action_sequence.append(create_action_log("跳过搅拌设置", "⏭️"))
# 6. 试剂添加
debug_print(f"🔍 步骤6: 试剂添加...")
action_sequence.append(create_action_log(f"开始添加试剂 {volume:.2f}mL", "🚰"))
# 计算添加时间pH调节需要缓慢添加
addition_time = max(30.0, volume * 2.0) # 至少30秒每mL需要2秒
debug_print(f"⏱️ 计算添加时间: {addition_time}s (缓慢注入)")
addition_time = max(30.0, volume * 2.0)
action_sequence.append(create_action_log(f"设置添加时间: {addition_time:.0f}s (缓慢注入)", "⏱️"))
try:
@@ -377,11 +285,9 @@ def generate_adjust_ph_protocol(
)
action_sequence.extend(pump_actions)
debug_print(f"✅ 泵协议生成完成,添加了 {len(pump_actions)} 个动作")
action_sequence.append(create_action_log(f"试剂转移完成 ({len(pump_actions)} 个操作)", ""))
# 🔧 修复体积运算 - 试剂添加成功后更新容器液体体积
debug_print(f"🔧 更新容器液体体积...")
# 体积运算 - 试剂添加成功后更新容器液体体积
if "data" in vessel and "liquid_volume" in vessel["data"]:
current_volume = vessel["data"]["liquid_volume"]
debug_print(f"📊 添加前容器体积: {current_volume}")