|
|
@@ -33,17 +33,39 @@ class CIPAnalysisLogger:
|
|
|
- 生成分析图表和报告
|
|
|
"""
|
|
|
|
|
|
- def __init__(self, log_dir="analysis_logs"):
|
|
|
+ def __init__(self, log_dir="analysis_logs", unit_filter=None):
|
|
|
"""
|
|
|
初始化日志记录器
|
|
|
|
|
|
Args:
|
|
|
log_dir: str,日志目录路径,默认"analysis_logs"
|
|
|
+ unit_filter: str,机组过滤器,如'RO1',用于目录命名
|
|
|
+
|
|
|
+ 目录结构(优化后):
|
|
|
+ analysis_logs/
|
|
|
+ CIP_RO1_20251105_155542/ # 类别_机组_时间
|
|
|
+ CIP_Analysis_20251105_155542.log
|
|
|
+ data/
|
|
|
+ plots/
|
|
|
+ reports/
|
|
|
+ CIP_ALL_20251105_160000/ # 全机组分析
|
|
|
"""
|
|
|
- self.log_dir = Path(log_dir)
|
|
|
+ # 生成会话ID和时间戳
|
|
|
+ self.timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
|
+ self.session_id = f"CIP_Analysis_{self.timestamp}"
|
|
|
+
|
|
|
+ # 创建按类别和时间分组的会话目录
|
|
|
+ base_log_dir = Path(log_dir)
|
|
|
+ base_log_dir.mkdir(exist_ok=True)
|
|
|
+
|
|
|
+ # 目录命名:CIP_机组_时间
|
|
|
+ unit_name = unit_filter if unit_filter else "ALL"
|
|
|
+ dir_name = f"CIP_{unit_name}_{self.timestamp}"
|
|
|
+
|
|
|
+ self.log_dir = base_log_dir / dir_name
|
|
|
self.log_dir.mkdir(exist_ok=True)
|
|
|
|
|
|
- # 创建子目录结构
|
|
|
+ # 创建子目录结构(放在会话目录下)
|
|
|
self.data_dir = self.log_dir / "data"
|
|
|
self.plots_dir = self.log_dir / "plots"
|
|
|
self.reports_dir = self.log_dir / "reports"
|
|
|
@@ -51,10 +73,6 @@ class CIPAnalysisLogger:
|
|
|
for dir_path in [self.data_dir, self.plots_dir, self.reports_dir]:
|
|
|
dir_path.mkdir(exist_ok=True)
|
|
|
|
|
|
- # 生成会话ID
|
|
|
- self.timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
|
- self.session_id = f"CIP_Analysis_{self.timestamp}"
|
|
|
-
|
|
|
# 初始化日志
|
|
|
self.setup_logging()
|
|
|
|
|
|
@@ -73,7 +91,7 @@ class CIPAnalysisLogger:
|
|
|
"performance_metrics": {}
|
|
|
}
|
|
|
|
|
|
- self.logger.info(f"开始CIP分析会话: {self.session_id}")
|
|
|
+ self.logger.info(f"CIP分析会话: {self.session_id}, 目录: {self.log_dir}")
|
|
|
|
|
|
def setup_logging(self):
|
|
|
"""设置日志配置"""
|
|
|
@@ -83,6 +101,15 @@ class CIPAnalysisLogger:
|
|
|
self.logger = logging.getLogger(self.session_id)
|
|
|
self.logger.setLevel(logging.INFO)
|
|
|
|
|
|
+ # 禁止日志传播到父logger,避免重复输出
|
|
|
+ self.logger.propagate = False
|
|
|
+
|
|
|
+ # 清除已有的所有处理器(防止重复添加)
|
|
|
+ if self.logger.handlers:
|
|
|
+ for handler in self.logger.handlers[:]:
|
|
|
+ handler.close()
|
|
|
+ self.logger.removeHandler(handler)
|
|
|
+
|
|
|
# 创建文件处理器
|
|
|
file_handler = logging.FileHandler(log_file, encoding='utf-8')
|
|
|
file_handler.setLevel(logging.INFO)
|
|
|
@@ -101,9 +128,8 @@ class CIPAnalysisLogger:
|
|
|
console_handler.setFormatter(formatter)
|
|
|
|
|
|
# 添加处理器
|
|
|
- if not self.logger.handlers:
|
|
|
- self.logger.addHandler(file_handler)
|
|
|
- self.logger.addHandler(console_handler)
|
|
|
+ self.logger.addHandler(file_handler)
|
|
|
+ self.logger.addHandler(console_handler)
|
|
|
|
|
|
def log_input_parameters(self, strategy, start_date, prediction_start_date=None):
|
|
|
"""
|
|
|
@@ -123,11 +149,8 @@ class CIPAnalysisLogger:
|
|
|
|
|
|
self.analysis_data["input_parameters"] = params
|
|
|
|
|
|
- self.logger.info("输入参数:")
|
|
|
- self.logger.info(f" 策略: {strategy}")
|
|
|
- self.logger.info(f" 起始时间: {start_date}")
|
|
|
- if prediction_start_date:
|
|
|
- self.logger.info(f" 预测起始时间: {prediction_start_date}")
|
|
|
+ pred_start = f", 预测起始: {prediction_start_date}" if prediction_start_date else ""
|
|
|
+ self.logger.info(f"参数 - 策略: {strategy}, 起始: {start_date}{pred_start}")
|
|
|
|
|
|
def log_prediction_data(self, all_data):
|
|
|
"""
|
|
|
@@ -150,15 +173,10 @@ class CIPAnalysisLogger:
|
|
|
|
|
|
self.analysis_data["prediction_data"] = data_info
|
|
|
|
|
|
- self.logger.info("预测数据概况:")
|
|
|
- self.logger.info(f" 数据形状: {data_info['shape']}")
|
|
|
- self.logger.info(f" 时间范围: {data_info['time_range']['start']} 到 {data_info['time_range']['end']}")
|
|
|
- self.logger.info(f" 总数据点: {data_info['data_points']}")
|
|
|
-
|
|
|
# 保存数据到文件
|
|
|
data_file = self.data_dir / f"{self.session_id}_prediction_data.csv"
|
|
|
all_data.to_csv(data_file)
|
|
|
- self.logger.info(f" 数据已保存: {data_file}")
|
|
|
+ self.logger.info(f"预测数据 - 形状: {data_info['shape']}, 点数: {data_info['data_points']}, 已保存: {data_file.name}")
|
|
|
|
|
|
except Exception as e:
|
|
|
self.logger.error(f"记录预测数据失败: {e}")
|
|
|
@@ -172,9 +190,8 @@ class CIPAnalysisLogger:
|
|
|
"""
|
|
|
self.analysis_data["unit_days"] = unit_days_dict
|
|
|
|
|
|
- self.logger.info("各机组预测天数:")
|
|
|
- for unit_id, days in unit_days_dict.items():
|
|
|
- self.logger.info(f" RO{unit_id}: {days}天")
|
|
|
+ days_str = ", ".join([f"RO{uid}:{days}天" for uid, days in unit_days_dict.items()])
|
|
|
+ self.logger.info(f"预测天数 - {days_str}")
|
|
|
|
|
|
def log_unit_analysis_start(self, unit_id, predict_days):
|
|
|
"""
|
|
|
@@ -184,8 +201,7 @@ class CIPAnalysisLogger:
|
|
|
unit_id: int,机组ID
|
|
|
predict_days: int,预测天数
|
|
|
"""
|
|
|
- self.logger.info(f"\n开始分析机组 RO{unit_id}")
|
|
|
- self.logger.info(f" 预测周期: {predict_days}天")
|
|
|
+ self.logger.info(f"[RO{unit_id}] 开始分析, 预测周期: {predict_days}天")
|
|
|
|
|
|
if unit_id not in self.analysis_data["unit_analysis"]:
|
|
|
self.analysis_data["unit_analysis"][unit_id] = {}
|
|
|
@@ -214,9 +230,8 @@ class CIPAnalysisLogger:
|
|
|
|
|
|
self.analysis_data["unit_analysis"][unit_id]["pressure_data"] = unit_data
|
|
|
|
|
|
- self.logger.info(f" 找到RO{unit_id}压差列: {len(pressure_columns)}个")
|
|
|
- for col in pressure_columns:
|
|
|
- self.logger.info(f" {col}")
|
|
|
+ cols_str = ", ".join(pressure_columns)
|
|
|
+ self.logger.info(f"[RO{unit_id}] 压差列: {len(pressure_columns)}个 ({cols_str})")
|
|
|
|
|
|
# 保存数据文件
|
|
|
unit_data_file = self.data_dir / f"{self.session_id}_RO{unit_id}_pressure_data.csv"
|
|
|
@@ -227,13 +242,13 @@ class CIPAnalysisLogger:
|
|
|
|
|
|
def log_cip_analysis_result(self, unit_id, column, optimal_time, analysis):
|
|
|
"""
|
|
|
- 记录CIP分析结果
|
|
|
+ 记录CIP分析结果(增强版,包含诊断信息)
|
|
|
|
|
|
Args:
|
|
|
unit_id: int,机组ID
|
|
|
column: str,压差列名
|
|
|
optimal_time: pd.Timestamp,最优CIP时间
|
|
|
- analysis: dict,分析结果
|
|
|
+ analysis: dict,分析结果(可能包含诊断信息)
|
|
|
"""
|
|
|
try:
|
|
|
if "cip_results" not in self.analysis_data["unit_analysis"][unit_id]:
|
|
|
@@ -252,7 +267,18 @@ class CIPAnalysisLogger:
|
|
|
if optimal_time:
|
|
|
self.logger.info(f" {column}: {optimal_time} (第{analysis['delay_days']}天, k={analysis['best_k']:.6f})")
|
|
|
else:
|
|
|
- self.logger.info(f" {column}: 未找到CIP时机 - {analysis.get('error', '未知原因')}")
|
|
|
+ error_msg = analysis.get('error', '未知原因')
|
|
|
+ self.logger.info(f" {column}: 未找到CIP时机 - {error_msg}")
|
|
|
+
|
|
|
+ # 记录详细诊断信息
|
|
|
+ if 'hint' in analysis:
|
|
|
+ self.logger.info(f" 提示: {analysis['hint']}")
|
|
|
+ if 'valid_k_count' in analysis:
|
|
|
+ self.logger.info(f" 有效k值数量: {analysis['valid_k_count']}")
|
|
|
+ if 'rising_periods_count' in analysis:
|
|
|
+ self.logger.info(f" 上升趋势段数: {analysis['rising_periods_count']}")
|
|
|
+ if 'data_days' in analysis:
|
|
|
+ self.logger.info(f" 数据覆盖天数: {analysis['data_days']}天")
|
|
|
|
|
|
except Exception as e:
|
|
|
self.logger.error(f"记录CIP分析结果失败: {e}")
|
|
|
@@ -275,8 +301,7 @@ class CIPAnalysisLogger:
|
|
|
|
|
|
self.analysis_data["unit_analysis"][unit_id]["strategy_result"] = strategy_result
|
|
|
|
|
|
- self.logger.info(f"RO{unit_id}最优CIP时机: {optimal_time}")
|
|
|
- self.logger.info(f" 策略: {strategy_desc}")
|
|
|
+ self.logger.info(f"[RO{unit_id}] 最优CIP时机: {optimal_time}, 策略: {strategy_desc}")
|
|
|
|
|
|
except Exception as e:
|
|
|
self.logger.error(f"记录RO{unit_id}策略结果失败: {e}")
|
|
|
@@ -301,15 +326,12 @@ class CIPAnalysisLogger:
|
|
|
|
|
|
self.analysis_data["final_results"] = final_results
|
|
|
|
|
|
- self.logger.info("\n最终分析结果:")
|
|
|
- for result in final_results:
|
|
|
- self.logger.info(f" {result['unit']}: {result['cip_time'] or 'N/A'}")
|
|
|
- self.logger.info(f" 策略: {result['strategy_description']}")
|
|
|
-
|
|
|
# 保存结果文件
|
|
|
result_file = self.data_dir / f"{self.session_id}_final_results.csv"
|
|
|
result_df.to_csv(result_file, index=False, encoding='utf-8')
|
|
|
- self.logger.info(f" 结果已保存: {result_file}")
|
|
|
+
|
|
|
+ results_summary = ", ".join([f"{r['unit']}: {r['cip_time'] or 'N/A'}" for r in final_results])
|
|
|
+ self.logger.info(f"最终结果 - {results_summary}, 已保存: {result_file.name}")
|
|
|
|
|
|
except Exception as e:
|
|
|
self.logger.error(f"记录最终结果失败: {e}")
|
|
|
@@ -325,8 +347,6 @@ class CIPAnalysisLogger:
|
|
|
unit_days_dict: dict,各机组预测天数
|
|
|
"""
|
|
|
try:
|
|
|
- self.logger.info("\n生成分析图表...")
|
|
|
-
|
|
|
# 创建压差趋势总览图
|
|
|
fig, axes = plt.subplots(2, 2, figsize=(20, 12))
|
|
|
fig.suptitle(f'RO膜污染分析总览 - {self.session_id}', fontsize=16, fontweight='bold')
|
|
|
@@ -371,10 +391,10 @@ class CIPAnalysisLogger:
|
|
|
plt.savefig(plot_file, dpi=300, bbox_inches='tight')
|
|
|
plt.close()
|
|
|
|
|
|
- self.logger.info(f" 压差趋势图已保存: {plot_file}")
|
|
|
-
|
|
|
# 创建机组对比图
|
|
|
- self._create_unit_comparison_plot(unit_days_dict)
|
|
|
+ comparison_plot = self._create_unit_comparison_plot(unit_days_dict)
|
|
|
+
|
|
|
+ self.logger.info(f"分析图表 - 已保存: {plot_file.name}, {comparison_plot}")
|
|
|
|
|
|
except Exception as e:
|
|
|
self.logger.error(f"创建分析图表失败: {e}")
|
|
|
@@ -442,10 +462,11 @@ class CIPAnalysisLogger:
|
|
|
plt.savefig(comparison_file, dpi=300, bbox_inches='tight')
|
|
|
plt.close()
|
|
|
|
|
|
- self.logger.info(f" 机组对比图已保存: {comparison_file}")
|
|
|
+ return comparison_file.name
|
|
|
|
|
|
except Exception as e:
|
|
|
self.logger.error(f"创建机组对比图失败: {e}")
|
|
|
+ return None
|
|
|
|
|
|
def generate_analysis_report(self):
|
|
|
"""
|
|
|
@@ -457,8 +478,6 @@ class CIPAnalysisLogger:
|
|
|
3. 输出会话总结
|
|
|
"""
|
|
|
try:
|
|
|
- self.logger.info("\n生成分析报告...")
|
|
|
-
|
|
|
# 记录结束时间
|
|
|
self.analysis_data["session_info"]["end_time"] = datetime.now().isoformat()
|
|
|
|
|
|
@@ -473,8 +492,7 @@ class CIPAnalysisLogger:
|
|
|
with open(html_file, 'w', encoding='utf-8') as f:
|
|
|
f.write(html_report)
|
|
|
|
|
|
- self.logger.info(f" JSON数据已保存: {json_file}")
|
|
|
- self.logger.info(f" HTML报告已保存: {html_file}")
|
|
|
+ self.logger.info(f"分析报告 - 已保存: {json_file.name}, {html_file.name}")
|
|
|
|
|
|
# 生成会话总结
|
|
|
self._log_session_summary()
|
|
|
@@ -606,30 +624,17 @@ class CIPAnalysisLogger:
|
|
|
end_time = datetime.fromisoformat(session_info["end_time"])
|
|
|
duration = end_time - start_time
|
|
|
|
|
|
- self.logger.info(f"\n分析会话总结:")
|
|
|
- self.logger.info(f" 会话ID: {session_info['session_id']}")
|
|
|
- self.logger.info(f" 总耗时: {duration.total_seconds():.2f}秒")
|
|
|
-
|
|
|
# 统计分析结果
|
|
|
final_results = self.analysis_data.get("final_results", [])
|
|
|
success_count = sum(1 for r in final_results if r["cip_time"])
|
|
|
total_count = len(final_results)
|
|
|
-
|
|
|
- self.logger.info(f" 分析机组: {total_count}个")
|
|
|
- self.logger.info(f" 成功预测: {success_count}个")
|
|
|
- if total_count > 0:
|
|
|
- self.logger.info(f" 成功率: {success_count/total_count*100:.1f}%")
|
|
|
- else:
|
|
|
- self.logger.info(f" 成功率: N/A")
|
|
|
+ success_rate = f"{success_count/total_count*100:.1f}%" if total_count > 0 else "N/A"
|
|
|
|
|
|
# 统计生成的文件
|
|
|
data_files = len(list(self.data_dir.glob(f"{self.session_id}_*.csv")))
|
|
|
plot_files = len(list(self.plots_dir.glob(f"{self.session_id}_*.png")))
|
|
|
|
|
|
- self.logger.info(f" 生成数据文件: {data_files}个")
|
|
|
- self.logger.info(f" 生成图表文件: {plot_files}个")
|
|
|
-
|
|
|
- self.logger.info(f"分析会话结束: {self.session_id}")
|
|
|
+ self.logger.info(f"会话结束 - ID: {session_info['session_id']}, 耗时: {duration.total_seconds():.2f}秒, 机组: {total_count}个, 成功: {success_count}个({success_rate}), 文件: {data_files}数据+{plot_files}图表")
|
|
|
|
|
|
def close(self):
|
|
|
"""关闭日志记录器"""
|