fix: 修复打包后exe程序在无控制台模式下运行时的uvicorn日志配置错误

通过检测sys.frozen判断运行环境,只在打包后的exe程序中禁用日志配置,
避免AttributeError: 'NoneType' object has no attribute 'isatty'错误。
普通Python运行环境保留完整日志功能,方便调试。
This commit is contained in:
dmy
2026-01-05 09:52:51 +08:00
parent 2ec763b86a
commit a5b46529da
4 changed files with 214 additions and 113 deletions

77
main.py
View File

@@ -199,7 +199,39 @@ def load_data_from_excel(file_path):
if cable_specs:
print(f"成功加载: {len(cable_specs)} 种电缆规格")
return turbines, substation, cable_specs
# 读取参数数据 (如果存在)
system_params = {}
param_sheet_name = None
if 'Parameters' in xl.sheet_names:
param_sheet_name = 'Parameters'
elif '参数' in xl.sheet_names:
param_sheet_name = '参数'
if param_sheet_name:
try:
params_df = pd.read_excel(xl, param_sheet_name)
# 假设格式为两列Parameter (参数名), Value (值)
if len(params_df.columns) >= 2:
for _, row in params_df.iterrows():
key = str(row[0]).strip().lower()
try:
val = float(row[1])
if 'voltage' in key or '电压' in key:
# 检测是否为kV单位
if 'kv' in key:
system_params['voltage'] = val * 1000
else:
system_params['voltage'] = val
elif 'factor' in key or '功率因数' in key:
system_params['power_factor'] = val
except ValueError:
pass
if system_params:
print(f"成功加载系统参数: {system_params}")
except Exception as e:
print(f"读取参数Sheet失败: {e}")
return turbines, substation, cable_specs, system_params
except Exception as e:
print(f"读取Excel文件失败: {str(e)}")
@@ -315,7 +347,7 @@ def design_with_kmeans(turbines, substation, n_clusters=3):
return cluster_connections + substation_connections, turbines
# 3.5 带容量约束的扇区扫描算法 (Capacitated Sweep) - 基础版
def design_with_capacitated_sweep(turbines, substation, cable_specs=None):
def design_with_capacitated_sweep(turbines, substation, cable_specs=None, voltage=VOLTAGE_LEVEL, power_factor=POWER_FACTOR):
"""
使用带容量约束的扇区扫描算法设计集电线路 (基础版:单次扫描)
原理:
@@ -325,10 +357,9 @@ def design_with_capacitated_sweep(turbines, substation, cable_specs=None):
4. 满载后开启新回路。
"""
# 1. 获取电缆最大容量
max_mw = get_max_cable_capacity_mw(cable_specs)
substation_coord = substation[0]
max_mw = get_max_cable_capacity_mw(cable_specs, voltage=voltage, power_factor=power_factor)
substation_coord = substation[0]
# 2. 计算角度 (使用 arctan2 返回 -pi 到 pi)
work_df = turbines.copy()
dx = work_df['x'] - substation_coord[0]
@@ -417,7 +448,7 @@ def design_with_capacitated_sweep(turbines, substation, cable_specs=None):
return cluster_connections + substation_connections, turbines
# 3.6 旋转扫描算法 (Rotational Sweep) - 优化版
def design_with_rotational_sweep(turbines, substation, cable_specs=None):
def design_with_rotational_sweep(turbines, substation, cable_specs=None, voltage=VOLTAGE_LEVEL, power_factor=POWER_FACTOR):
"""
使用带容量约束的扇区扫描算法设计集电线路 (优化版:旋转扫描)
原理:
@@ -427,7 +458,7 @@ def design_with_rotational_sweep(turbines, substation, cable_specs=None):
4. 对每种分组方案计算MST成本选出总成本最低的方案。
"""
# 1. 获取电缆最大容量
max_mw = get_max_cable_capacity_mw(cable_specs)
max_mw = get_max_cable_capacity_mw(cable_specs, voltage=voltage, power_factor=power_factor)
substation_coord = substation[0]
@@ -541,7 +572,7 @@ def design_with_rotational_sweep(turbines, substation, cable_specs=None):
return final_connections, turbines
def get_max_cable_capacity_mw(cable_specs=None):
def get_max_cable_capacity_mw(cable_specs=None, voltage=VOLTAGE_LEVEL, power_factor=POWER_FACTOR):
"""
计算给定电缆规格中能够承载的最大功率 (单位: MW)。
@@ -549,6 +580,8 @@ def get_max_cable_capacity_mw(cable_specs=None):
参数:
cable_specs (list, optional): 电缆规格列表。每个元素应包含 (截面积, 额定电流, 单价, 损耗系数)。
voltage (float): 系统电压 (V), 默认 66000
power_factor (float): 功率因数, 默认 0.95
返回:
float: 最大功率承载能力 (MW)。
@@ -576,13 +609,13 @@ def get_max_cable_capacity_mw(cable_specs=None):
# 计算最大功率P = √3 * U * I * cosφ
# 这里假设降额系数为 1 (不降额)
max_current = max_current_capacity * 1
max_power_w = np.sqrt(3) * VOLTAGE_LEVEL * max_current * POWER_FACTOR
max_power_w = np.sqrt(3) * voltage * max_current * power_factor
# 将单位从 W 转换为 MW
return max_power_w / 1e6
# 5. 计算集电线路方案成本
def evaluate_design(turbines, connections, substation, cable_specs=None, is_offshore=False, method_name="Unknown Method"):
def evaluate_design(turbines, connections, substation, cable_specs=None, is_offshore=False, method_name="Unknown Method", voltage=VOLTAGE_LEVEL, power_factor=POWER_FACTOR):
"""评估设计方案的总成本和损耗"""
total_cost = 0
total_loss = 0
@@ -685,7 +718,7 @@ def evaluate_design(turbines, connections, substation, cable_specs=None, is_offs
cable_specs_to_use = cable_specs
# 估算电流
current = (power * 1e6) / (np.sqrt(3) * VOLTAGE_LEVEL * POWER_FACTOR)
current = (power * 1e6) / (np.sqrt(3) * voltage * power_factor)
# 选择满足载流量的最小电缆
selected_spec = None
@@ -1055,10 +1088,12 @@ def compare_design_methods(excel_path=None, n_clusters_override=None, interactiv
:param plot_results: 是否生成和保存对比图表
"""
cable_specs = None
system_params = {}
if excel_path:
print(f"正在从 {excel_path} 读取坐标数据...")
try:
turbines, substation, cable_specs = load_data_from_excel(excel_path)
turbines, substation, cable_specs, system_params = load_data_from_excel(excel_path)
scenario_title = "Offshore Wind Farm (Imported Data)"
except Exception:
print("回退到自动生成数据模式...")
@@ -1070,6 +1105,10 @@ def compare_design_methods(excel_path=None, n_clusters_override=None, interactiv
is_offshore = True
voltage = system_params.get('voltage', VOLTAGE_LEVEL)
power_factor = system_params.get('power_factor', POWER_FACTOR)
print(f"使用的系统参数: 电压={voltage} V, 功率因数={power_factor}")
# 准备三种电缆方案
# 原始 specs 是 5 元素元组: (section, capacity, resistance, cost, is_optional)
# 下游函数期望 4 元素元组: (section, capacity, resistance, cost)
@@ -1114,7 +1153,7 @@ def compare_design_methods(excel_path=None, n_clusters_override=None, interactiv
# 1. MST 方法作为基准 (使用 Scenario 1)
mst_connections = design_with_mst(turbines, substation)
mst_evaluation = evaluate_design(turbines, mst_connections, substation, cable_specs=specs_1, is_offshore=is_offshore, method_name="MST Method")
mst_evaluation = evaluate_design(turbines, mst_connections, substation, cable_specs=specs_1, is_offshore=is_offshore, method_name="MST Method", voltage=voltage, power_factor=power_factor)
# 准备画布 2x2
fig = None
@@ -1152,7 +1191,7 @@ def compare_design_methods(excel_path=None, n_clusters_override=None, interactiv
# 计算参数
total_power = turbines['power'].sum()
max_cable_mw = get_max_cable_capacity_mw(cable_specs=current_specs)
max_cable_mw = get_max_cable_capacity_mw(cable_specs=current_specs, voltage=voltage, power_factor=power_factor)
# 确定簇数 (针对 Base 算法)
if n_clusters_override is not None:
@@ -1172,11 +1211,11 @@ def compare_design_methods(excel_path=None, n_clusters_override=None, interactiv
# --- Run 1: Base Algorithm (Capacitated Sweep) ---
base_name = f"{name} (Base)"
conns_base, turbines_base = design_with_capacitated_sweep(
turbines.copy(), substation, cable_specs=current_specs
turbines.copy(), substation, cable_specs=current_specs, voltage=voltage, power_factor=power_factor
)
eval_base = evaluate_design(
turbines, conns_base, substation, cable_specs=current_specs,
is_offshore=is_offshore, method_name=base_name
is_offshore=is_offshore, method_name=base_name, voltage=voltage, power_factor=power_factor
)
comparison_results.append({
@@ -1192,11 +1231,11 @@ def compare_design_methods(excel_path=None, n_clusters_override=None, interactiv
# --- Run 2: Rotational Algorithm (Optimization) ---
rot_name = f"{name} (Rotational)"
conns_rot, turbines_rot = design_with_rotational_sweep(
turbines.copy(), substation, cable_specs=current_specs
turbines.copy(), substation, cable_specs=current_specs, voltage=voltage, power_factor=power_factor
)
eval_rot = evaluate_design(
turbines, conns_rot, substation, cable_specs=current_specs,
is_offshore=is_offshore, method_name=rot_name
is_offshore=is_offshore, method_name=rot_name, voltage=voltage, power_factor=power_factor
)
comparison_results.append({
@@ -1216,7 +1255,7 @@ def compare_design_methods(excel_path=None, n_clusters_override=None, interactiv
)
eval_ew = evaluate_design(
turbines, conns_ew, substation, cable_specs=current_specs,
is_offshore=is_offshore, method_name=ew_name
is_offshore=is_offshore, method_name=ew_name, voltage=voltage, power_factor=power_factor
)
comparison_results.append({