You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Include/nmNum/nmCalculation/nmCalculationAutoFitPSO.h

410 lines
19 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#ifndef NMCALCULATIONAUTOFIT_H
#define NMCALCULATIONAUTOFIT_H
#include <QObject>
#include <QVector>
#include <QPointF>
#include <QString>
#include <QStringList>
#include <QMutex>
#include <QDateTime>
#include <QFile>
#include "nmCalculation_global.h"
// 前向声明
class nmCalculationDllPebiSolverTask;
class nmDataWellBase;
class QTimer;
class QProcess;
// PSO粒子结构
// 这里的 position / velocity / bestPosition 只保存“用户勾选参与拟合的参数”,
// 不是完整的 11 个储层/井筒参数。完整参数向量会在写 trace 或调用代理模型时
// 通过 buildTraceParameterVector() 重新组装。
//
// surrogate* 和 screeningDecision 是 PSO 加速筛选的辅助字段。代理模型只决定
// “这一代哪些粒子需要继续跑真实求解器”,不会直接更新 pbest / gbest。
struct AutoFitParticle {
QVector<QVector<double> > currentLogLogData;
QVector<QVector<double> > bestLogLogData;
QVector<double> position; // 当前位置(参数值)
QVector<double> velocity; // 速度
QVector<double> bestPosition; // 个体最优位置
double fitness; // 当前适应度
double bestFitness; // 个体最优适应度
bool evaluatedThisIteration;
bool lastEvaluationSuccess;
int lastEvaluationElapsedMs;
double surrogateObjective;
bool selectedForSolver;
bool selectedByAudit;
QString screeningDecision;
AutoFitParticle()
: fitness(1e10)
, bestFitness(1e10)
, evaluatedThisIteration(false)
, lastEvaluationSuccess(false)
, lastEvaluationElapsedMs(-1)
, surrogateObjective(1e10)
, selectedForSolver(true)
, selectedByAudit(false)
, screeningDecision("full_solver")
{}
};
// PSO停止原因。主循环每一代结束时会根据目标误差、收敛历史、粒子群多样性、
// 连续失败次数等状态给出一个停止判断。
enum StopReasonPSO {
PSO_CONTINUE_OPTIMIZATION = 0, // 继续优化
PSO_TARGET_ACHIEVED = 1, // 达到目标精度
PSO_TRUE_CONVERGENCE = 2, // 真正收敛
PSO_LOCAL_OPTIMUM = 3, // 陷入局部最优
PSO_MAX_ITERATIONS = 4, // 达到最大迭代数
PSO_USER_STOPPED = 5, // 用户停止
PSO_CONSECUTIVE_FAILURES = 6, // 连续失败停止
PSO_OPTIMIZATION_FAILED = 7 // 优化失败
};
class NMCALCULATION_EXPORT nmCalculationAutoFitPSO : public QObject
{
Q_OBJECT
public:
// 构造函数和析构函数
explicit nmCalculationAutoFitPSO(QObject* parent = 0);
~nmCalculationAutoFitPSO();
// ===== 核心接口:完全数据驱动 =====
//
// 这个类不直接读取自动拟合对话框控件。界面层 nmWxAutomaticFitting 会先把
// 用户选择的参数范围、迭代次数、误差容限、PSO acceleration 开关等保存到
// nmDataAnalyzeManager / nmDataAutomaticFitting然后本类在 startAutoFitting()
// 内部统一读取。
void setTargetLogLogData(const QVector<QVector<double> >& targetData);
bool startAutoFitting();
void stopFitting();
QVector<double> getBestSolution() const;
double getBestFitness() const;
QString getLastError() const;
bool isRunning() const;
int getCurrentIteration() const;
void resetOptimizer();
void setPSOTargetWellName(const QString& wellName);
//QString getTargetWellName() const;
public:
// 模拟拟合模式
void setSimulationMode(bool enabled);
bool isSimulationMode() const { return m_simulationMode; }
void setSimulationTargetParams(const QVector<double>& targetParams, double targetError);
private slots:
void onSimulationTimerTick();
signals:
void progressUpdated(int iteration, double bestFitness);
void fittingFinished(bool success, const QString& message);
void bestCurveUpdated(QVector<QVector<double> > targetData,
QVector<QVector<double> > bestData,
int iteration,
double fitness);
signals:
void logMessageGenerated(const QString& message);
private:
// 临时目录管理
void initializeTemporaryDirectory();
void cleanupTemporaryDirectory();
bool removeDirectoryRecursively(const QString& path);
void cleanupOldTemporaryDirectories();
// ===== 数据加载方法 =====
bool loadAllConfigFromDataManager();
void loadOptimizationConfig();
void loadParameterBounds();
// ===== PSO核心算法 =====
//
// 主流程:
// 1. extractUserInitialValues(): 从当前项目数据中取用户已有初始解;
// 2. initializeSwarm(): 根据初始解和上下界生成粒子群;
// 3. updateParticle(): 对单个粒子跑真实求解器并计算误差;
// 4. updateGlobalBest(): 只用真实求解器误差更新全局最优;
// 5. updateVelocityAndPosition(): 按 PSO 公式推进下一代粒子。
void extractUserInitialValues();
void initializeSwarm();
void updateVelocityAndPosition();
double evaluateFitness(const QVector<double>& parameters);
void updateGlobalBest();
void updateParticle(int particleIndex);
// ===== 参数应用方法 =====
//
// 每次评价粒子前,都会把该粒子的参数临时写入 DataManager
// - 储层参数写入 nmDataReservoir
// - 井参数skin / wellbore storage写入目标井。
// 求解器随后基于 DataManager 的当前状态计算模拟曲线。
void applyParametersToDataManager(const QVector<double>& parameters);
void updateReservoirParameters(const QVector<double>& parameters);
void updateWellParameters(const QVector<double>& parameters);
void updateWellToDataManager(nmDataWellBase* pWell);
// ===== 求解器相关 =====
QVector<QVector<double> > runSolver();
QVector<QVector<double>> runSolverDll();
QVector<QVector<double>> runSolverExe();
// ===== 数据处理 =====
QVector<QPointF> interpolateData(const QVector<QPointF>& source,
const QVector<double>& targetX) const;
// ===== 算法辅助 =====
void adaptiveParameterUpdate(int iteration);
void saveOptimizationResult();
void validateAndProtectFinalResult();
// 收敛判断方法
StopReasonPSO analyzeOptimizationStatus();
bool checkTrueConvergence() const;
bool checkLocalOptimumTrap() const;
// 粒子群状态分析
double calculateSwarmDiversity() const;
double calculateAverageVelocity() const;
double calculateParticleStagnationRate() const;
// 适应度稳定性分析
double calculateFitnessVariance(int windowSize) const;
double calculateLongTermImprovement(int windowSize) const;
// 工具方法
QString getStopReasonDescription(StopReasonPSO reason) const;
void updateConvergenceMetrics();
// ===== 工具方法 =====
double random01() const;
void clampToLimits(QVector<double>& parameters) const;
int getEnabledParameterCount() const;
void logDebugInfo(const QString& message) const;
// ===== Baseline trace =====
//
// trace记录每一代、每个粒子的参数、真实求解器误差、
// 代理模型误差、筛选决策、pbest 和 gbest。代理筛选质量、某个粒子为什么
// 没有跑真实求解器,都应该优先看 trace。
void initializeTraceFile();
void closeTraceFile();
void writeTraceHeader();
void writeTraceMetaFile();
void writeTraceRow(int generation,
int particleIndex,
const QString& phase,
const QVector<double>& parameters,
double solverObjective,
bool solverSuccess,
int elapsedMs,
double surrogateObjective,
const QString& screeningDecision,
const QVector<double>& pbestPosition,
double pbestObjective);
void writeIterationTraceRows();
QVector<double> buildTraceParameterVector(const QVector<double>& selectedParameters) const;
void resetRunSummary();
void captureSurrogateRunContextSummary();
void emitRunSummary(bool success, StopReasonPSO finalReason);
// ===== Surrogate screening prototype =====
//
// PSO acceleration 的核心逻辑。开启后buildSurrogateEvaluationMask() 会:
// 1. 判断当前工况是否在代理模型训练域内;
// 2. 将当代粒子候选写成 CSV
// 3. 调用 Python 代理模型输出 surrogate_objective
// 4. 选择 top-k、随机审计、fallback 和最小真实求解比例对应的粒子;
// 5. 返回 bool masktrue 表示该粒子继续跑真实求解器。
//
// 代理模型只筛选候选,不直接决定最终最优参数。
bool isSurrogateScreeningEnabled() const;
QString getMlRootPath() const;
QString getPythonExecutablePath() const;
QString getSurrogateTag() const;
QString getSurrogateStage() const;
double getSurrogateKeepFraction() const;
double getSurrogateAuditFraction() const;
double getSurrogateMinSolverFraction() const;
int getSurrogateWarmupIterations() const;
int getSurrogateFullSolverInterval() const;
QVector<bool> buildSurrogateEvaluationMask();
bool writeSurrogateCandidateCsv(const QString& candidatePath) const;
bool runSurrogateScoringProcess(const QString& candidatePath, const QString& scorePath, QString* failureReason = nullptr);
bool runSurrogateScoringScriptOnce(const QString& candidatePath, const QString& scorePath, QString* failureReason = nullptr);
bool ensureSurrogateScoringServer(QString* failureReason = nullptr);
bool requestSurrogateScoresFromServer(const QString& candidatePath, const QString& scorePath, QString* failureReason = nullptr);
void stopSurrogateScoringServer();
QVector<double> readSurrogateScores(const QString& scorePath) const;
bool forceSolverByFallbackGate(const QVector<double>& selectedParameters) const;
bool isStrongDecliningProductionSchedule(double* endStartRatio = nullptr) const;
bool isSurrogateRunContextSupported(QString* reason) const;
bool isSurrogateCandidateInDomain(const QVector<double>& selectedParameters, QString* reason) const;
// ===== 验证和处理方法 =====
bool validateParameters(const QVector<double>& parameters) const;
bool validateLogLogData(const QVector<QVector<double> >& logLogData) const;
bool validateInitialValues() const; // 验证初始值有效性
bool validateSolverResult(const QVector<QVector<double>>& result) const;
double calculateCurveError(const QVector<QPointF>& curve1, const QVector<QPointF>& curve2) const;
double calculateLogLogCurveError(const QVector<QVector<double> >& target,
const QVector<QVector<double> >& result) const;
double calculateWeightedPointError(double target, double result, double timeWeight) const;
private:
// ===== 运行状态 =====
bool m_isRunning; // 当前是否有一次自动拟合正在运行。
bool m_shouldStop; // 用户停止标志;主循环和求解器等待循环会定期检查它。
bool m_isPaused; // 预留暂停标志;主循环中有暂停等待逻辑。
int m_currentIteration; // 当前 PSO 迭代序号,从 0 开始。
QString m_lastError; // 最近一次失败原因,供 UI 展示或日志排查。
// ===== PSO数据 =====
QVector<double> m_initialValues; // 当前模型中提取的用户初始值,顺序与 m_enabledParamIndices 一致。
QVector<AutoFitParticle> m_swarm; // 粒子群,每个粒子只保存启用参数维度。
QVector<double> m_globalBestPosition; // 全局最优参数,仍是启用参数向量。
double m_globalBestFitness; // 全局最优真实误差,越小越好。
double m_previousBestFitness; // 上一轮全局最优误差,用于自适应参数更新。
QVector<QVector<double> > m_lastEvaluatedLogLogData; // 最近一次真实求解得到的 result log-log 曲线。
QVector<QVector<double> > m_globalBestLogLogData; // 当前全局最优对应的 result log-log 曲线。
QVector<QVector<double> > m_userInitialLogLogData; // 用户初始解对应的 result log-log 曲线,用于精英保护。
// ===== 优化配置 =====
//
// 参数索引约定:
// 0 k 渗透率1 skin 表皮系数2 wellboreC 井筒储集;
// 3 phi 孔隙度4 initialPressure 初始压力5 h 储层厚度;
// 6 Ct 综合压缩系数7 Cf 岩石压缩系数;
// 8 Soi 初始含油饱和度9 Swi 初始含水饱和度10 Sgi 初始含气饱和度。
// m_enabledParamIndices 保存被用户勾选的参数索引,粒子的 position 维度与它一致。
QVector<bool> m_parameterSelected; // 完整 11 个参数是否被用户勾选参与拟合。
QVector<double> m_parameterLower; // 完整 11 个参数的搜索下界。
QVector<double> m_parameterUpper; // 完整 11 个参数的搜索上界。
QVector<int> m_enabledParamIndices; // 被勾选参数在完整 11 维体系中的索引。
QVector<QVector<double> > m_targetLogLogData; // 目标井 history log-log 曲线time/pressure/derivative。
QString m_targetWellName; // 目标井名称;读写井参数和读取模拟曲线都依赖它。
// ===== 算法配置 =====
int m_swarmSize; // 粒子数量,当前默认 20。
int m_maxIterations; // 最大迭代次数,来自自动拟合配置。
double m_targetError; // 目标误差,小于该值视为达到拟合目标。
double m_inertiaWeight; // 惯性权重,控制粒子保留上一轮速度的程度。
double m_cognitiveParam; // 个体学习因子,控制粒子靠近自身 pbest 的程度。
double m_socialParam; // 群体学习因子,控制粒子靠近全局 gbest 的程度。
// ===== 统计信息 =====
int m_totalEvaluations; // 已调用真实求解器评价的粒子总数。
int m_successfulEvaluations; // 真实求解器成功且误差有效的评价次数。
QVector<double> m_convergenceHistory; // 每代全局最优误差历史,用于收敛判断。
// ===== 常量 =====
static const double MIN_FITNESS_IMPROVEMENT; // 判断误差是否有有效改善的最小阈值。
static const double VELOCITY_LIMIT_FACTOR; // 粒子速度上限占参数搜索区间的比例。
static const int CONVERGENCE_CHECK_INTERVAL; // 收敛检查的基础间隔。
// ===== 资源管理 =====
volatile int m_evaluationInProgress; // 并发控制
int m_consecutiveFailures; // 连续失败计数
// ===== 精英保护 =====
QVector<double> m_userInitialSolution; // 用户初始解参数,若最终改进不足会恢复它。
double m_userInitialFitness; // 用户初始解真实误差。
double m_improvementThreshold; // 最终结果相对初始解至少需要达到的改进阈值。
bool m_hasValidUserSolution; // 初始解是否成功跑过真实求解器。
int m_consecutiveFailedIterations; // 连续失败迭代次数
int m_maxConsecutiveFailures; // 最大允许连续失败次数
// 收敛判断相关
double m_diversityThreshold; // 多样性阈值
QVector<double> m_diversityHistory; // 粒子群多样性历史
QVector<double> m_velocityHistory; // 平均速度历史
QVector<double> m_particleStagnationHistory; // 粒子停滞率历史
// 收敛判断参数
double m_convergenceVarianceThreshold; // 收敛方差阈值
double m_velocityConvergenceThreshold; // 速度收敛阈值
int m_trueConvergenceWindow; // 真收敛观察窗口
int m_localOptimumWindow; // 局部最优观察窗口
// 质量评估参数
double m_nearTargetFactor; // 接近目标的倍数因子
double m_farTargetFactor; // 远离目标的倍数因子
// DLL求解器需要的临时目录。每个对象单独创建析构或停止时递归清理。
QString m_tempDirectory;
// ===== Trace 和代理筛选统计 =====
//
// 这些字段只描述代理筛选和运行复盘,不参与 PSO 数学更新。
bool m_traceEnabled; // 是否写出 trace CSV/meta 文件。
QString m_traceRunId; // 本次运行 ID作为 trace/candidate/score 文件名的一部分。
QString m_traceFilePath; // pso_baseline_trace_<run_id>.csv 完整路径。
QString m_traceMetaFilePath; // pso_baseline_trace_<run_id>.meta.json 完整路径。
QFile m_traceFile; // trace CSV 文件句柄。
bool m_surrogateScreeningEnabled; // 用户配置中的 PSO acceleration 开关。
unsigned int m_psoRandomSeed; // PSO 随机种子,也用于可复现 random audit。
QString m_surrogateRunContextSummary; // 本次运行代理工况 gate 的摘要。
int m_surrogateWarmupIterationCount; // warmup 全量真实评价代数。
int m_surrogatePeriodicAuditIterationCount; // 周期性全量审计代数。
int m_surrogateContextBlockedIterationCount; // 因工况不支持而全量真实评价的代数。
int m_surrogateActiveIterationCount; // 代理筛选真正参与的代数。
int m_surrogateSelectedParticleCount; // 被选中跑真实求解器的粒子累计数。
int m_surrogateScreenedParticleCount; // 被代理筛掉的粒子累计数。
int m_surrogateTopKParticleCount; // 因 surrogate top-k 被选中的粒子累计数。
int m_surrogateAuditParticleCount; // 因 random audit 被选中的粒子累计数。
int m_surrogateFallbackParticleCount; // 因 fallback gate 被选中的粒子累计数。
int m_surrogateDomainParticleCount; // 因训练域 gate 被选中的粒子累计数。
int m_surrogateMinFloorParticleCount; // 因最低真实求解比例被补选中的粒子累计数。
QProcess* m_surrogateScoringProcess; // 常驻 Python 代理评分 server 进程。
QString m_surrogateScoringServerKey; // 标识当前 server 对应的 python/script/meta/tag/stage。
private:
// 模拟拟合相关成员
bool m_simulationMode; // 是否启用仿真模式;仿真模式不调用真实求解器。
QTimer* m_simulationTimer; // 仿真日志定时器,用于分步模拟长任务。
int m_simulationIteration; // 仿真当前迭代。
int m_simulationMaxIterations; // 仿真最大迭代。
QVector<double> m_simulationTargetParams; // 仿真最终目标参数。
QVector<double> m_simulationStartParams; // 仿真起始参数。
double m_simulationTargetError; // 仿真最终目标误差。
double m_simulationStartError; // 仿真起始误差。
double m_simulationCurrentError; // 仿真当前误差。
int m_simulationLogInterval; // 仿真日志输出间隔,单位秒。
QTime m_simulationStartTime; // 仿真开始时间,用于演示节奏统计。
// 用于逐粒子输出的状态
int m_simulationCurrentParticle; // 当前正在处理的粒子索引
int m_simulationSuccessCount; // 当前迭代成功的粒子数
int m_simulationFailCount; // 当前迭代失败的粒子数
bool m_simulationIterationStarted; // 当前迭代是否已开始
double m_simulationPreviousIterError; // 上一次迭代的误差
// 模拟拟合方法
void runSimulatedFitting();
void emitSimulationLog(int iteration);
double calculateSimulatedError(int iteration);
QVector<double> calculateSimulatedParams(int iteration);
private:
void startNewSimulationIteration();
void emitParticleLog(int particleIndex);
void finishCurrentIteration();
void finishSimulation();
QVector<QVector<double> > buildSimulatedLogLogData(double progress) const;
};
#endif // NMCALCULATIONAUTOFIT_H