import networkx as nx from .logger_util import debug_print def get_vessel(vessel): """ 统一处理vessel参数,返回vessel_id和vessel_data。 Args: vessel: 可以是一个字典或字符串,表示vessel的ID或数据。 Returns: tuple: 包含vessel_id和vessel_data。 """ if isinstance(vessel, dict): if "id" not in vessel: vessel_id = list(vessel.values())[0].get("id", "") else: vessel_id = vessel.get("id", "") vessel_data = vessel.get("data", {}) else: vessel_id = str(vessel) vessel_data = {} return vessel_id, vessel_data def find_reagent_vessel(G: nx.DiGraph, reagent: str) -> str: """增强版试剂容器查找,支持固体和液体""" debug_print(f"🔍 开始查找试剂 '{reagent}' 的容器...") # 🔧 方法1:直接搜索 data.reagent_name 和 config.reagent debug_print(f"📋 方法1: 搜索reagent字段...") for node in G.nodes(): node_data = G.nodes[node].get('data', {}) node_type = G.nodes[node].get('type', '') config_data = G.nodes[node].get('config', {}) # 只搜索容器类型的节点 if node_type == 'container': reagent_name = node_data.get('reagent_name', '').lower() config_reagent = config_data.get('reagent', '').lower() # 精确匹配 if reagent_name == reagent.lower() or config_reagent == reagent.lower(): debug_print(f"✅ 通过reagent字段精确匹配到容器: {node} 🎯") return node # 模糊匹配 if (reagent.lower() in reagent_name and reagent_name) or \ (reagent.lower() in config_reagent and config_reagent): debug_print(f"✅ 通过reagent字段模糊匹配到容器: {node} 🔍") return node # 🔧 方法2:常见的容器命名规则 debug_print(f"📋 方法2: 使用命名规则查找...") reagent_clean = reagent.lower().replace(' ', '_').replace('-', '_') possible_names = [ reagent_clean, f"flask_{reagent_clean}", f"bottle_{reagent_clean}", f"vessel_{reagent_clean}", f"{reagent_clean}_flask", f"{reagent_clean}_bottle", f"reagent_{reagent_clean}", f"reagent_bottle_{reagent_clean}", f"solid_reagent_bottle_{reagent_clean}", f"reagent_bottle_1", # 通用试剂瓶 f"reagent_bottle_2", f"reagent_bottle_3" ] debug_print(f"🔍 尝试的容器名称: {possible_names[:5]}... (共{len(possible_names)}个)") for name in possible_names: if name in G.nodes(): node_type = G.nodes[name].get('type', '') if node_type == 'container': debug_print(f"✅ 通过命名规则找到容器: {name} 📝") return name # 🔧 方法3:节点名称模糊匹配 debug_print(f"📋 方法3: 节点名称模糊匹配...") for node_id in G.nodes(): node_data = G.nodes[node_id] if node_data.get('type') == 'container': # 检查节点名称是否包含试剂名称 if reagent_clean in node_id.lower(): debug_print(f"✅ 通过节点名称模糊匹配到容器: {node_id} 🔍") return node_id # 检查液体类型匹配 vessel_data = node_data.get('data', {}) liquids = vessel_data.get('liquid', []) for liquid in liquids: if isinstance(liquid, dict): liquid_type = liquid.get('liquid_type') or liquid.get('name', '') if liquid_type.lower() == reagent.lower(): debug_print(f"✅ 通过液体类型匹配到容器: {node_id} 💧") return node_id # 🔧 方法4:使用第一个试剂瓶作为备选 debug_print(f"📋 方法4: 查找备选试剂瓶...") for node_id in G.nodes(): node_data = G.nodes[node_id] if (node_data.get('type') == 'container' and ('reagent' in node_id.lower() or 'bottle' in node_id.lower())): debug_print(f"⚠️ 未找到专用容器,使用备选试剂瓶: {node_id} 🔄") return node_id debug_print(f"❌ 所有方法都失败了,无法找到容器!") raise ValueError(f"找不到试剂 '{reagent}' 对应的容器") def find_solvent_vessel(G: nx.DiGraph, solvent: str) -> str: """ 查找溶剂容器 Args: G: 网络图 solvent: 溶剂名称 Returns: str: 溶剂容器ID """ debug_print(f"🔍 正在查找溶剂 '{solvent}' 的容器... 🧪") # 第四步:通过数据中的试剂信息匹配 debug_print(" 🧪 步骤1: 数据试剂信息匹配...") for node_id in G.nodes(): debug_print(f"查找 id {node_id}, type={G.nodes[node_id].get('type')}, data={G.nodes[node_id].get('data', {})} 的容器...") if G.nodes[node_id].get('type') == 'container': vessel_data = G.nodes[node_id].get('data', {}) # 检查 data 中的 reagent_name 字段 reagent_name = vessel_data.get('reagent_name', '').lower() if reagent_name and solvent.lower() == reagent_name: debug_print(f" 🎉 通过data.reagent_name匹配找到容器: {node_id} (试剂: {reagent_name}) ✨") return node_id # 检查 data 中的液体信息 liquids = vessel_data.get('liquid', []) or vessel_data.get('liquids', []) for liquid in liquids: if isinstance(liquid, dict): liquid_type = (liquid.get('liquid_type') or liquid.get('name', '')).lower() if solvent.lower() == liquid_type or solvent.lower() in liquid_type: debug_print(f" 🎉 通过液体类型匹配找到容器: {node_id} (液体类型: {liquid_type}) ✨") return node_id # 构建可能的容器名称 possible_names = [ f"flask_{solvent}", f"bottle_{solvent}", f"reagent_{solvent}", f"reagent_bottle_{solvent}", f"{solvent}_flask", f"{solvent}_bottle", f"{solvent}", f"vessel_{solvent}", ] debug_print(f"📋 候选容器名称: {possible_names[:3]}... (共{len(possible_names)}个) 📝") # 第一步:通过容器名称匹配 debug_print(" 🎯 步骤2: 精确名称匹配...") for vessel_name in possible_names: if vessel_name in G.nodes(): debug_print(f" 🎉 通过名称匹配找到容器: {vessel_name} ✨") return vessel_name # 第二步:通过模糊匹配(节点ID和名称) debug_print(" 🔍 步骤3: 模糊名称匹配...") for node_id in G.nodes(): if G.nodes[node_id].get('type') == 'container': node_name = G.nodes[node_id].get('name', '').lower() if solvent.lower() in node_id.lower() or solvent.lower() in node_name: debug_print(f" 🎉 通过模糊匹配找到容器: {node_id} (名称: {node_name}) ✨") return node_id # 第三步:通过配置中的试剂信息匹配 debug_print(" 🧪 步骤4: 配置试剂信息匹配...") for node_id in G.nodes(): if G.nodes[node_id].get('type') == 'container': # 检查 config 中的 reagent 字段 node_config = G.nodes[node_id].get('config', {}) config_reagent = node_config.get('reagent', '').lower() if config_reagent and solvent.lower() == config_reagent: debug_print(f" 🎉 通过config.reagent匹配找到容器: {node_id} (试剂: {config_reagent}) ✨") return node_id # 第五步:部分匹配(如果前面都没找到) debug_print(" 🔍 步骤5: 部分匹配...") for node_id in G.nodes(): if G.nodes[node_id].get('type') == 'container': node_config = G.nodes[node_id].get('config', {}) node_data = G.nodes[node_id].get('data', {}) node_name = G.nodes[node_id].get('name', '').lower() config_reagent = node_config.get('reagent', '').lower() data_reagent = node_data.get('reagent_name', '').lower() # 检查是否包含溶剂名称 if (solvent.lower() in config_reagent or solvent.lower() in data_reagent or solvent.lower() in node_name or solvent.lower() in node_id.lower()): debug_print(f" 🎉 通过部分匹配找到容器: {node_id} ✨") debug_print(f" - 节点名称: {node_name}") debug_print(f" - 配置试剂: {config_reagent}") debug_print(f" - 数据试剂: {data_reagent}") return node_id # 调试信息:列出所有容器 debug_print(" 🔎 调试信息:列出所有容器...") container_list = [] for node_id in G.nodes(): if G.nodes[node_id].get('type') == 'container': node_config = G.nodes[node_id].get('config', {}) node_data = G.nodes[node_id].get('data', {}) node_name = G.nodes[node_id].get('name', '') container_info = { 'id': node_id, 'name': node_name, 'config_reagent': node_config.get('reagent', ''), 'data_reagent': node_data.get('reagent_name', '') } container_list.append(container_info) debug_print( f" - 容器: {node_id}, 名称: {node_name}, config试剂: {node_config.get('reagent', '')}, data试剂: {node_data.get('reagent_name', '')}") debug_print(f"❌ 找不到溶剂 '{solvent}' 对应的容器 😭") debug_print(f"🔍 查找的溶剂: '{solvent}' (小写: '{solvent.lower()}')") debug_print(f"📊 总共发现 {len(container_list)} 个容器") raise ValueError(f"找不到溶剂 '{solvent}' 对应的容器") def find_connected_stirrer(G: nx.DiGraph, vessel: str) -> str: """查找连接到指定容器的搅拌器""" debug_print(f"🔍 查找连接到容器 '{vessel}' 的搅拌器...") stirrer_nodes = [] for node in G.nodes(): node_class = G.nodes[node].get('class', '').lower() if 'stirrer' in node_class: stirrer_nodes.append(node) debug_print(f"📋 发现搅拌器: {node}") debug_print(f"📊 共找到 {len(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 "" def find_solid_dispenser(G: nx.DiGraph) -> str: """查找固体加样器""" debug_print(f"🔍 查找固体加样器...") for node in G.nodes(): node_class = G.nodes[node].get('class', '').lower() if 'solid_dispenser' in node_class or 'dispenser' in node_class: debug_print(f"✅ 找到固体加样器: {node} 🥄") return node debug_print(f"❌ 未找到固体加样器") return ""