diff --git a/Bin/Config/Lang/cn/MPA_cn.qm b/Bin/Config/Lang/cn/MPA_cn.qm index 496f6ae..3d5457b 100644 Binary files a/Bin/Config/Lang/cn/MPA_cn.qm and b/Bin/Config/Lang/cn/MPA_cn.qm differ diff --git a/Bin/Config/Lang/cn/MPA_cn.ts b/Bin/Config/Lang/cn/MPA_cn.ts index c9930a5..970e255 100644 --- a/Bin/Config/Lang/cn/MPA_cn.ts +++ b/Bin/Config/Lang/cn/MPA_cn.ts @@ -2129,12 +2129,6 @@ Normalized Gauss Newton 规则化高斯-牛顿 - - - - Genetic Algorithm - 遗传算法 - Parameter diff --git a/Bin/Config/Lang/cn/WTAI_cn.ts b/Bin/Config/Lang/cn/WTAI_cn.ts index 2fd73d5..46e180b 100644 --- a/Bin/Config/Lang/cn/WTAI_cn.ts +++ b/Bin/Config/Lang/cn/WTAI_cn.ts @@ -4715,10 +4715,6 @@ MethodID:%1 Normalized Gauss Newton 规则化高斯-牛顿 - - Genetic Algorithm - 遗传算法 - Parameter diff --git a/Bin/Config/Lang/cn/nmNum_cn.qm b/Bin/Config/Lang/cn/nmNum_cn.qm index bdc7725..19bf9a3 100644 Binary files a/Bin/Config/Lang/cn/nmNum_cn.qm and b/Bin/Config/Lang/cn/nmNum_cn.qm differ diff --git a/Bin/Config/Lang/cn/nmNum_cn.ts b/Bin/Config/Lang/cn/nmNum_cn.ts index 5879529..465cceb 100644 --- a/Bin/Config/Lang/cn/nmNum_cn.ts +++ b/Bin/Config/Lang/cn/nmNum_cn.ts @@ -47,345 +47,6 @@ Reason: %1 压力(MPa) - - nmCalculationAutoFitGA - - === GA Automatic Fitting Started === - === GA自动拟合开始 === - - - Algorithm: Genetic Algorithm - 算法:遗传算法 - - - ERROR: Failed to load configuration from data manager - 错误:从数据管理器加载配置失败 - - - Enabled parameters count: %1 - 启用参数数量:%1 - - - ERROR: No parameters enabled for optimization - 错误:没有启用优化参数 - - - ERROR: Target LogLog data is empty or insufficient - 错误:目标双对数数据为空或不足 - - - ERROR: Target LogLog data arrays have inconsistent sizes - 错误:目标双对数数据数组大小不一致 - - - Target data validation passed (%1 data points) - 目标数据验证通过(%1 个数据点) - - - === Evaluating Initial Solution (Elite Protection) === - === 评估初始解 === - - - Initial parameters: - 初始参数: - - - Starting initial solution evaluation... - 开始初始解评估... - - - ERROR: m_userInitialSolution is empty! - 错误:初始解为空! - - - Initial param[%1] = %2 - 初始参数[%1] = %2 - - - evaluateGenes returned: %1 - 评估基因 返回:%1 - - - Taking SUCCESS branch (fitness < 1e9) - 进入成功分支 - - - Initial solution evaluation successful - 初始解评估成功 - - - Initial fitness (error): %1 - 初始误差:%1 - - - Elite protection activated - initial solution will be preserved if no significant improvement found - 如果未找到显著改进,将保留初始解. - - - Taking FAILURE branch (fitness >= 1e9) - 进入失败分支 - - - Initial solution evaluation failed - starting with random initialization - 初始解评估失败 - 使用随机初始化开始 - - - Exception during initial solution evaluation - 初始解评估期间出现异常 - - - Population initialized: %1 individuals, %2 dimensions - 种群初始化:%1 个个体,%2 个维度 - - - === Starting GA Main Loop === - === 开始GA主循环 === - - - --- Generation %1/%2 --- - --- 第 %1/%2 代 --- - - - Current best error: %1 - 当前最佳误差:%1 - - - Total evaluations: %1 (successful: %2, failures: %3) - 总评估次数:%1(成功:%2,失败:%3) - - - Optimization stopped by user request - 优化因用户请求而停止 - - - Generation %1 completed: best = %2, avg = %3, worst = %4 - 第 %1 代完成:最佳 = %2,平均 = %3,最差 = %4 - - - === TARGET ACHIEVED === - === 达到目标 === - - - Target error achieved! Current error: %1 < Target: %2 - 达到目标误差!当前误差:%1 < 目标:%2 - - - Optimization completed successfully after %1 generations - 达到目标误差!当前误差:%1 < 目标:%2 - - - === TRUE CONVERGENCE DETECTED === - === 检测到真正收敛 === - - - Algorithm has converged to a stable solution - 算法已收敛到稳定解 - - - Final error: %1 after %2 generations - 最终误差:%1,经过 %2 代 - - - Solution quality: %1 (1.0 = target achieved) - 解质量:%1 - - - === LOCAL OPTIMUM DETECTED === - === 检测到局部最优 === - - - Algorithm appears to be trapped in local optimum - 算法似乎陷入局部最优 - - - Current error: %1 after %2 generations - 当前误差:%1,经过 %2 代 - - - Suggestion: Try restarting with different parameters or larger search space - 建议:尝试使用不同参数或更大搜索空间重新开始 - - - === CONSECUTIVE FAILURES === - === 连续失败 === - - - Too many consecutive failed generations (%1/%2) - 连续失败代数过多(%1/%2) - - - Optimization status: diversity=%1 - 优化状态:多样性=%1 - - - Generation %1 completed - Current best: %2 - 第 %1 代完成 - 当前最佳:%2 - - - CRITICAL ERROR: %1 - 严重错误: %1 - - - CRITICAL ERROR: Unknown exception in GA main loop - 严重错误:GA主循环中的未知异常 - - - Applying optimized parameters to model... - 正在将优化参数应用到模型... - - - === Optimization Results === - === 优化结果 === - - - Final error: %1 - 最终误差: %1 - - - Total generations: %1 - 总代数:%1 - - - Total evaluations: %1 (successful: %2) - 总评估次数: %1 (成功: %2) - - - Optimized parameters: - 优化参数: - - - Parameters applied successfully to data manager - 参数已成功应用到数据管理器 - - - ERROR: Failed to apply final parameters: %1 - 错误: 应用最终参数失败: %1 - - - ERROR: Unknown error applying final parameters - 错误: 应用最终参数时出现未知错误 - - - === GA OPTIMIZATION SUCCESSFUL === - === GA优化成功 === - - - === GA OPTIMIZATION CONVERGED === - === GA优化收敛 === - - - === GA OPTIMIZATION - LOCAL OPTIMUM === - === GA优化 - 局部最优 === - - - === GA OPTIMIZATION - MAX GENERATIONS === - === GA优化 - 达到最大代数 === - - - === GA OPTIMIZATION STOPPED BY USER === - === GA优化 - 用户停止 === - - - === GA OPTIMIZATION FAILED === - === GA优化失败 === - - - === GA OPTIMIZATION - UNKNOWN END === - === GA优化 - 未知结束 === - - - Result: %1 - 结果: %1 - - - === User Stop Request Received === - === 用户停止请求已接收 === - - - Gracefully stopping GA optimization... - 在停止GA优化... - - - Force stopping current evaluation... - 强制停止当前评估... - - - GA optimization stop request processed - GA优化停止请求已处理 - - - Stop request received but optimization is not running - 收到停止请求但优化未运行 - - - Individual %1 improved: %2 -> %3 - 个体 %1 改进:%2 -> %3 - - - Individual %1: evaluation failed - 个体 %1:评估失败 - - - Individual %1: Exception: %2 - 个体 %1:异常:%2 - - - Individual %1: Unknown exception - 个体 %1:未知异常 - - - WARNING: No successful evaluations in generation %1 (consecutive failures: %2) - 警告:第 %1 代中没有成功评估(连续失败:%2) - - - Current generation stats: %1 successful, %2 failed out of %3 individuals (success rate: %4%) - 当前代统计:%3 个个体中 %1 个成功,%2 个失败(成功率:%4%) - - - ERROR: Too many consecutive failed generations (%1/%2) - stopping optimization - 错误:连续失败代数过多(%1/%2)- 停止优化 - - - WARNING: Low success rate (%1%) in generation %2, but continuing optimization - 警告:第 %2 代中成功率低(%1%),但继续优化 - - - No initial solution for elite protection - 没有初始解用于迭代 - - - === Final Result Validation (Elite Protection) === - === 最终结果验证 === - - - Comparing results: Initial=%1, Final=%2 - 比较结果: 初始=%1, 最终=%2 - - - Improvement: %1 (%2%) - 改进: %1 (%2%) - - - Elite protection triggered: insufficient improvement - 改进不足 - - - Threshold: %1%, Actual: %2% - 阈值: %1%, 实际: %2% - - - Restoring initial solution as final result - 恢复初始解作为最终结果 - - - Initial solution restored successfully - 初始解恢复成功 - - - Final result validated - significant improvement achieved - 最终结果已验证 - 实现显著改进 - - nmCalculationAutoFitPSO @@ -3698,6 +3359,38 @@ Supported types: Vertical, Vertical Fractured, and Horizontal Multi-Fractured We Warning 警告 + + Invalid parameter range + 参数范围无效 + + + The parameter table is unavailable. + 参数表不可用。 + + + The parameter row is invalid. + 参数行无效。 + + + The range values for %1 are incomplete. + %1 的范围值不完整。 + + + The minimum value, initial value, and maximum value of %1 must be finite numbers. + %1 的最小值、初始值和最大值必须是有限数值。 + + + The physical range of %1 is invalid. + %1 的物理范围无效。 + + + The values of %1 exceed the physical range [%2, %3]. + %1 的参数值超出物理范围 [%2, %3]。 + + + The values of %1 must satisfy: minimum <= initial value <= maximum. + %1 的参数值必须满足:最小值 <= 初始值 <= 最大值。 + Please select a target well! 请选择一口目标井! @@ -3740,11 +3433,6 @@ Supported types: Vertical, Vertical Fractured, and Horizontal Multi-Fractured We Optimized parameters have been applied to the model. 拟合参数已应用到模型。 - - GA Optimization completed: - - GA求解完成: - Optimization Completed 拟合完成 @@ -3774,27 +3462,14 @@ Supported types: Vertical, Vertical Fractured, and Horizontal Multi-Fractured We Optimization Stopped 拟合停止 - - GA Optimization stopped by user: - - GA拟合被用户强行终止: - PSO algorithm selected. 用户选择PSO。 - - GA algorithm selected. - 用户选择GA - PSO (Particle Swarm) PSO - - GA (Genetic Algorithm) - GA - Darcy diff --git a/Include/mAlg/mAlgDefines/mAlgDefines.h b/Include/mAlg/mAlgDefines/mAlgDefines.h index 7c96b83..4eeaa12 100644 --- a/Include/mAlg/mAlgDefines/mAlgDefines.h +++ b/Include/mAlg/mAlgDefines/mAlgDefines.h @@ -292,8 +292,7 @@ enum Fit_Method { FM_GaussNewton = 0, //高斯牛顿 FM_GaussNewtonEx, //归一化高斯牛顿 - FM_Genetic, //遗传算法 - FM_ParticleSwarm, //粒子群算法(Particle Swarm Optimization) + FM_ParticleSwarm = 3, //粒子群算法(Particle Swarm Optimization),保留原有枚举值 FM_Unknown }; diff --git a/Include/nmNum/nmCalculation/nmCalculationAutoFitGA.h b/Include/nmNum/nmCalculation/nmCalculationAutoFitGA.h deleted file mode 100644 index 64f9e4d..0000000 --- a/Include/nmNum/nmCalculation/nmCalculationAutoFitGA.h +++ /dev/null @@ -1,267 +0,0 @@ -#ifndef NMCALCULATIONAUTOFITGA_H -#define NMCALCULATIONAUTOFITGA_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nmCalculation_global.h" - -class nmDataWellBase; - -enum StopReasonGA { - GA_CONTINUE_OPTIMIZATION = 0, - GA_TARGET_ACHIEVED, - GA_TRUE_CONVERGENCE, - GA_LOCAL_OPTIMUM, - GA_MAX_ITERATIONS, - GA_USER_STOPPED, - GA_CONSECUTIVE_FAILURES, - GA_OPTIMIZATION_FAILED -}; - -struct GAIndividual -{ - QVector genes; // 基因(参数值) - double fitness; // 适应度值 - bool isEvaluated; // 是否已评估 - - GAIndividual() : fitness(1e10), isEvaluated(false) {} -}; - -class NMCALCULATION_EXPORT nmCalculationAutoFitGA : public QObject -{ - Q_OBJECT - -public: - explicit nmCalculationAutoFitGA(QObject* parent = nullptr); - virtual ~nmCalculationAutoFitGA(); - - // ==================== 公共接口方法 ==================== - void setTargetLogLogData(const QVector>& targetData); - bool startAutoFitting(); - void stopFitting(); - bool isRunning() const; - int getCurrentGeneration() const; - QVector getBestSolution() const; - double getBestFitness() const; - QString getLastError() const; - void resetOptimizer(); - - void setGATargetWellName(const QString& wellName); - -signals: - void progressUpdated(int generation, double bestFitness); - void fittingFinished(bool success, const QString& message); - void logMessageGenerated(const QString& message); - - private slots: - void updateProgress(); - -private: - - // 临时目录管理 - void initializeTemporaryDirectory(); - void cleanupTemporaryDirectory(); - bool removeDirectoryRecursively(const QString& path); - - // ==================== 数据加载方法 ==================== - // 从数据管理器加载所有配置 - bool loadAllConfigFromDataManager(); - // 加载优化配置 - void loadOptimizationConfig(); - // 加载参数边界 - void loadParameterBounds(); - // 提取用户初始值 - void extractUserInitialValues(); - // ==================== 遗传算法核心方法 ==================== - // 初始化种群 - void initializePopulation(); - // 评估基因 - double evaluateGenes(const QVector& genes); - // 评估个体 - double evaluateIndividual(GAIndividual& individual); - // 评估种群 - void evaluatePopulation(); - // 选择操作 - int tournamentSelection(); - int rouletteWheelSelection(); - - // 交叉操作 - void crossover(const GAIndividual& parent1, const GAIndividual& parent2, - GAIndividual& offspring1, GAIndividual& offspring2); - void singlePointCrossover(const GAIndividual& parent1, const GAIndividual& parent2, - GAIndividual& offspring1, GAIndividual& offspring2); - void uniformCrossover(const GAIndividual& parent1, const GAIndividual& parent2, - GAIndividual& offspring1, GAIndividual& offspring2); - - // 变异操作 - void mutate(GAIndividual& individual); - void gaussianMutation(GAIndividual& individual); - void polynomialMutation(GAIndividual& individual); - - // 精英保留 - void applyElitism(QVector& newPopulation); - // 更新种群统计 - void updatePopulationStatistics(); - // 收敛检查 - bool checkConvergence(); - // 自适应参数更新 - void adaptiveParameterUpdate(int generation); - - // ==================== 智能收敛判断方法 ==================== - // 分析优化状态 - StopReasonGA analyzeOptimizationStatus(); - // 检查真收敛 - bool checkTrueConvergence() const; - // 检查局部最优陷阱 - bool checkLocalOptimumTrap() const; - // 计算种群多样性 - double calculatePopulationDiversity() const; - // 计算适应度方差 - double calculateFitnessVariance(int windowSize) const; - // 计算长期改进 - double calculateLongTermImprovement(int windowSize) const; - // 更新收敛指标 - void updateConvergenceMetrics(); - // 最终结果验证和保护 - void validateAndProtectFinalResult(); - - // ==================== 参数处理方法 ==================== - // 参数验证 - bool validateParameters(const QVector& parameters) const; - // 双对数数据验证 - bool validateLogLogData(const QVector>& logLogData) const; - // 初始值验证 - bool validateInitialValues() const; - // 应用参数到数据管理器 - void applyParametersToDataManager(const QVector& parameters); - // 更新储层参数 - void updateReservoirParameters(const QVector& parameters); - // 更新井参数 - void updateWellParameters(const QVector& parameters); - // 更新井到数据管理器 - void updateWellToDataManager(nmDataWellBase* pWell); - // 参数边界约束 - void clampToLimits(QVector& parameters) const; - - // ==================== 求解器相关方法 ==================== - // 运行求解器 - QVector> runSolver(); - // 运行EXE求解器 - QVector> runSolverExe(); - // 运行Dll求解器 - QVector> runSolverDll(); - // 验证求解器结果 - bool validateSolverResult(const QVector>& result) const; - - // ==================== 数据处理方法 ==================== - // 插值数据 - QVector interpolateData(const QVector& source, - const QVector& targetX) const; - // 计算双对数曲线误差 - double calculateLogLogCurveError(const QVector>& target, - const QVector>& result) const; - // 计算曲线误差 - double calculateCurveError(const QVector& curve1, - const QVector& curve2) const; - - // ==================== 工具方法 ==================== - // 生成0-1随机数 - double random01() const; - // 高斯随机数 - double gaussianRandom(double mean, double stddev) const; - // 获取启用参数数量 - int getEnabledParameterCount() const; - // 保存优化结果 - void saveOptimizationResult(); - - -private: - // ==================== 常量定义 ==================== - static const double MIN_FITNESS_IMPROVEMENT; - static const double MUTATION_STRENGTH; - static const int CONVERGENCE_CHECK_INTERVAL; - static const int MAX_STAGNATION_GENERATIONS; - - // ==================== 核心状态变量 ==================== - bool m_isRunning; // 是否正在运行 - bool m_shouldStop; // 是否应该停止 - bool m_isPaused; // 是否暂停 - int m_currentGeneration; // 当前代数 - - // 适应度统计 - double m_bestFitness; // 最优适应度 - double m_worstFitness; // 最差适应度 - double m_averageFitness; // 平均适应度 - double m_previousBestFitness; // 上一代最优适应度 - - // ==================== GA算法参数 ==================== - int m_populationSize; // 种群大小 - int m_maxGenerations; // 最大代数 - double m_targetError; // 目标误差 - double m_crossoverRate; // 交叉概率 - double m_mutationRate; // 变异概率 - double m_elitismRate; // 精英保留比例 - int m_tournamentSize; // 锦标赛选择大小 - bool m_useUniformCrossover; // 是否使用均匀交叉 - - // ==================== 种群和个体 ==================== - QVector m_population; // 当前种群 - QVector m_eliteIndividuals; // 精英个体 - GAIndividual m_bestIndividual; // 全局最优个体 - - // ==================== 评估统计 ==================== - int m_totalEvaluations; // 总评估次数 - int m_successfulEvaluations; // 成功评估次数 - int m_evaluationInProgress; // 正在进行的评估计数 - int m_consecutiveFailures; // 连续失败次数 - - // ==================== 精英保护相关 ==================== - QVector m_initialValues; // 用户初始参数值 - QVector m_userInitialSolution; // 用户初始解 - double m_userInitialFitness; // 用户初始适应度 - int m_consecutiveFailedGenerations; // 连续失败代数 - int m_maxConsecutiveFailures; // 最大允许连续失败数 - bool m_hasValidUserSolution; // 是否有有效的用户解 - double m_improvementThreshold; // 改进阈值 - - // ==================== 收敛判断相关 ==================== - double m_diversityThreshold; // 多样性阈值 - double m_convergenceVarianceThreshold; // 收敛方差阈值 - int m_trueConvergenceWindow; // 真收敛判断窗口 - int m_localOptimumWindow; // 局部最优判断窗口 - double m_nearTargetFactor; // 接近目标的因子 - double m_farTargetFactor; // 远离目标的因子 - - // ==================== 历史记录 ==================== - QVector m_convergenceHistory; // 收敛历史 - QVector m_diversityHistory; // 多样性历史 - - // ==================== 参数配置 ==================== - QVector m_parameterSelected; // 参数选择状态 - QVector m_parameterLower; // 参数下界 - QVector m_parameterUpper; // 参数上界 - QVector m_enabledParamIndices; // 启用参数索引 - - // ==================== 目标数据 ==================== - QVector> m_targetLogLogData; // 目标双对数数据 - - // ==================== 其他 ==================== - QString m_lastError; // 最后错误信息 - QTimer* m_progressTimer; // 进度更新定时器 - // DLL求解器需要的临时目录 - QString m_tempDirectory; - - QString m_targetWellName;// 目标井名称 -}; - -#endif // NMCALCULATIONAUTOFITGA_H \ No newline at end of file diff --git a/Include/nmNum/nmSubWxs/nmWxAutomaticFitting.h b/Include/nmNum/nmSubWxs/nmWxAutomaticFitting.h index a245aac..30a9119 100644 --- a/Include/nmNum/nmSubWxs/nmWxAutomaticFitting.h +++ b/Include/nmNum/nmSubWxs/nmWxAutomaticFitting.h @@ -21,17 +21,10 @@ #include "nmDataWellBase.h" #include "nmDataAutomaticFitting.h" #include "nmCalculationAutoFitPSO.h" -#include "nmCalculationAutoFitGA.h" #include "nmWxAutomaticfittingStart.h" #include "nmSubWxs_global.h" -// 算法类型枚举 -enum OptimizationAlgorithm { - ALGORITHM_PSO = 0, - ALGORITHM_GA = 1 -}; - class NM_SUB_WXS_EXPORT nmWxAutomaticFitting : public iDlgBase { Q_OBJECT @@ -46,7 +39,7 @@ public: void onAccept(); void onReject(); void onWellSelected(int index); - void onAlgorithmChanged(int index); + void onParameterTableItemChanged(QTableWidgetItem* item); // 自动拟合相关槽函数 void runAutoFitting(); @@ -63,6 +56,12 @@ private: void setParameterRowVisible(QTableWidget* table, int row, bool visible); void renumberVisibleParameterRows(QTableWidget* table); void updateParameterVisibility(QTableWidget* table, NM_SOLVER_MODEL_TYPE eType); + void initializeSuggestedParameterRanges(); + void updateRangeForParameter(int parameterIndex, double centerValue, bool afterFit); + void setParameterRange(int parameterIndex, double minValue, double maxValue); + bool getPhysicalParameterRange(int parameterIndex, double& minValue, double& maxValue); + void normalizeSavedParameterRanges(); + bool validateParameterTable(QString& errorMessage, int parameterIndex = -1); void startAutoFitting(const QVector>& targetData, const QStringList& selectedParams, const QString& targetWellName); void cleanupFitting(); @@ -108,10 +107,10 @@ private: // 自动拟合相关成员 nmCalculationAutoFitPSO* m_autoFitterPSO; - nmCalculationAutoFitGA* m_autoFitterGA; QProgressDialog* m_progressDialog; QTimer* m_progressTimer; - OptimizationAlgorithm m_selectedAlgorithm; // 选中的算法类型 + bool m_autoParameterRanges; + bool m_updatingParameterRanges; // 拟合开始界面 nmWxAutomaticfittingStart* m_progressMonitor; diff --git a/Include/nmNum/nmSubWxs/nmWxAutomaticFittingStart.h b/Include/nmNum/nmSubWxs/nmWxAutomaticFittingStart.h index eb37eeb..3e9067e 100644 --- a/Include/nmNum/nmSubWxs/nmWxAutomaticFittingStart.h +++ b/Include/nmNum/nmSubWxs/nmWxAutomaticFittingStart.h @@ -22,12 +22,10 @@ #include #include -#include "nmCalculationAutoFitGA.h" #include "nmCalculationAutoFitPSO.h" // 前向声明 class nmCalculationAutoFitPSO; -class nmCalculationAutoFitGA; class QPainter; class QColor; class QPaintEvent; @@ -68,12 +66,6 @@ private: bool m_pseudoPressureMode; }; -// 算法类型枚举 -enum FittingAlgorithmType { - FITTING_ALGORITHM_PSO = 0, - FITTING_ALGORITHM_GA = 1 -}; - class nmWxAutomaticfittingStart : public iDlgBase { Q_OBJECT @@ -85,8 +77,6 @@ public: // PSO算法接口 void setAutoFitter(nmCalculationAutoFitPSO* autoFitter); - // GA算法接口 - void setAutoFitterGA(nmCalculationAutoFitGA* autoFitter); // 通用设置接口 void setFittingParameters(int maxIterations, double targetError, const QString& wellName); @@ -161,8 +151,6 @@ private: // 算法实例 nmCalculationAutoFitPSO* m_autoFitterPSO; - nmCalculationAutoFitGA* m_autoFitterGA; - FittingAlgorithmType m_algorithmType; // 拟合参数 int m_maxIterations; diff --git a/Src/nmNum/nmCalculation/nmCalculationAutoFitGA.cpp b/Src/nmNum/nmCalculation/nmCalculationAutoFitGA.cpp deleted file mode 100644 index 45eda30..0000000 --- a/Src/nmNum/nmCalculation/nmCalculationAutoFitGA.cpp +++ /dev/null @@ -1,2911 +0,0 @@ -#include "nmCalculationAutoFitGA.h" -//#include "nmCalculationExeSolverTask.h" -#include "nmCalculationDllPebiSolverTask.h" -#include "nmDataAnalyzeManager.h" -#include "nmDataWellBase.h" -#include "nmDataVerticalWell.h" -#include "nmDataVerticalFracturedWell.h" -#include "nmDataHorizontalFracturedWell.h" -#include "nmDataReservoir.h" -#include "nmDataAutomaticFitting.h" - -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_OS_WIN -#include -#include -#define DEBUG_OUT(msg) OutputDebugStringA(QString("[AutoFit] %1\n").arg(msg).toLocal8Bit().data()) -#endif - -// 常量定义 -const double nmCalculationAutoFitGA::MIN_FITNESS_IMPROVEMENT = 1e-8; -const double nmCalculationAutoFitGA::MUTATION_STRENGTH = 0.1; -const int nmCalculationAutoFitGA::CONVERGENCE_CHECK_INTERVAL = 10; -const int nmCalculationAutoFitGA::MAX_STAGNATION_GENERATIONS = 20; - -// 无穷大和NaN检查 -static inline bool isFiniteNumber(double value) -{ -#ifdef Q_OS_WIN - return _finite(value) != 0 && !_isnan(value); -#else - return std::isfinite(value); -#endif -} - -// sleep函数 -static inline void msleep(int ms) -{ -#ifdef Q_OS_WIN - Sleep(ms); -#endif -} - -// 构造函数 -nmCalculationAutoFitGA::nmCalculationAutoFitGA(QObject* parent) - : QObject(parent) - , m_isRunning(false) - , m_shouldStop(false) - , m_isPaused(false) - , m_currentGeneration(0) - , m_bestFitness(1e10) - , m_worstFitness(-1e10) - , m_averageFitness(1e10) - , m_previousBestFitness(1e10) - , m_populationSize(40) - , m_maxGenerations(100) - , m_targetError(0.001) - , m_crossoverRate(0.8) - , m_mutationRate(0.1) - , m_elitismRate(0.1) - , m_tournamentSize(3) - , m_useUniformCrossover(true) - , m_totalEvaluations(0) - , m_successfulEvaluations(0) - , m_evaluationInProgress(0) - , m_consecutiveFailures(0) - , m_progressTimer(0) - , m_userInitialFitness(1e10) - , m_consecutiveFailedGenerations(0) - , m_maxConsecutiveFailures(3) - , m_hasValidUserSolution(false) - , m_improvementThreshold(0.05) - , m_diversityThreshold(0.05) - , m_convergenceVarianceThreshold(1e-8) - , m_trueConvergenceWindow(15) - , m_localOptimumWindow(8) - , m_nearTargetFactor(2.0) - , m_farTargetFactor(10.0) - , m_targetWellName("") -{ - DEBUG_OUT(QString("GA Constructor: this=0x%1").arg((quintptr)this, 0, 16)); - - // 初始化随机数种子 - qsrand(QTime::currentTime().msec()); - - // 初始化临时目录用于DLL求解器 - initializeTemporaryDirectory(); - - // 初始化最优个体 - m_bestIndividual.fitness = 1e10; - m_bestIndividual.isEvaluated = false; - - // 创建进度更新定时器 - m_progressTimer = new QTimer(this); - connect(m_progressTimer, SIGNAL(timeout()), this, SLOT(updateProgress())); - - DEBUG_OUT("AutoFit GA calculator initialized (data-driven mode)"); - DEBUG_OUT("GA Constructor completed"); -} - -// 析构函数 -nmCalculationAutoFitGA::~nmCalculationAutoFitGA() -{ - DEBUG_OUT(QString("GA Destructor: this=0x%1").arg((quintptr)this, 0, 16)); - - // 首先停止算法 - if(m_isRunning) { - m_shouldStop = true; // 立即设置停止标志 - - // 等待当前操作完成,增加超时时间 - int waitCount = 0; - while(m_isRunning && waitCount < 100) { - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 50); - msleep(50); - waitCount++; - } - - // 如果仍在运行则强制停止 - if(m_isRunning) { - DEBUG_OUT("Force stopping GA - timeout reached"); - m_isRunning = false; - } - } - - // 清理临时目录 - cleanupTemporaryDirectory(); - - // 断开所有信号连接,防止回调已销毁的对象 - disconnect(this, nullptr, nullptr, nullptr); - - DEBUG_OUT("GA Destructor completed"); -} - -// ==================== 目录处理方法 ==================== - -void nmCalculationAutoFitGA::initializeTemporaryDirectory() -{ - QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss_zzz"); - QString processId = QString::number(QCoreApplication::applicationPid()); - - m_tempDirectory = QApplication::applicationDirPath() + - "/autofit_temp_" + processId + "_" + timestamp; - - // 确保目录不存在 - int counter = 0; - QString originalPath = m_tempDirectory; - - while(QDir(m_tempDirectory).exists() && counter < 100) { - m_tempDirectory = originalPath + "_" + QString::number(counter); - counter++; - } - - if(QDir().mkpath(m_tempDirectory)) { - DEBUG_OUT(QString("Initialized temp directory: %1").arg(m_tempDirectory)); - } else { - DEBUG_OUT(QString("Warning: Failed to create temp directory: %1").arg(m_tempDirectory)); - m_tempDirectory = QApplication::applicationDirPath(); - } -} - -void nmCalculationAutoFitGA::cleanupTemporaryDirectory() -{ - if(QDir(m_tempDirectory).exists()) { - if(removeDirectoryRecursively(m_tempDirectory)) { - DEBUG_OUT("Temp directory cleaned up successfully"); - } else { - DEBUG_OUT("Warning: Failed to clean up temp directory completely"); - } - } -} - -bool nmCalculationAutoFitGA::removeDirectoryRecursively(const QString& path) -{ - QDir dir(path); - - if(!dir.exists()) { - return true; - } - - // 递归删除子目录和文件 - QFileInfoList entries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden); - bool allRemoved = true; - - for(int i = 0; i < entries.size(); ++i) { - const QFileInfo& entry = entries[i]; - - if(entry.isDir()) { - if(!removeDirectoryRecursively(entry.absoluteFilePath())) { - allRemoved = false; - } - } else { - QFile file(entry.absoluteFilePath()); - - // 处理只读文件 - if(!file.permissions().testFlag(QFile::WriteUser)) { - file.setPermissions(file.permissions() | QFile::WriteUser); - } - - if(!file.remove()) { - DEBUG_OUT(QString("Failed to remove file: %1").arg(entry.absoluteFilePath())); - allRemoved = false; - } - } - } - - // 删除目录本身 - if(allRemoved) { - return dir.rmdir(path); - } - - return false; -} - -// ==================== 公共接口方法 ==================== - -void nmCalculationAutoFitGA::setTargetLogLogData(const QVector>& targetData) -{ - m_targetLogLogData = targetData; - DEBUG_OUT(QString("Target LogLog data set: %1 arrays").arg(targetData.size())); - - if(targetData.size() >= 3) { - DEBUG_OUT(QString("LogLog data points: X=%1, Y1=%2, Y2=%3") - .arg(targetData[0].size()) - .arg(targetData[1].size()) - .arg(targetData[2].size())); - } -} - -bool nmCalculationAutoFitGA::startAutoFitting() -{ - if(m_isRunning) { - m_lastError = "GA fitting is already running"; - return false; - } - - DEBUG_OUT("=== GA AUTO FITTING START ==="); - - // 发送初始化日志 - emit logMessageGenerated(tr("=== GA Automatic Fitting Started ===")); - emit logMessageGenerated(tr("Algorithm: Genetic Algorithm")); - - try { - // 从数据管理器加载所有配置 - if(!loadAllConfigFromDataManager()) { - emit logMessageGenerated(tr("ERROR: Failed to load configuration from data manager")); - return false; - } - - int enabledParams = getEnabledParameterCount(); - emit logMessageGenerated(tr("Enabled parameters count: %1").arg(enabledParams)); - - if(enabledParams == 0) { - m_lastError = "No parameters enabled for optimization"; - emit logMessageGenerated(tr("ERROR: No parameters enabled for optimization")); - return false; - } - - if(m_targetLogLogData.isEmpty() || m_targetLogLogData.size() < 3) { - m_lastError = "Target LogLog data is empty or insufficient"; - emit logMessageGenerated(tr("ERROR: Target LogLog data is empty or insufficient")); - return false; - } - - // 检查数据一致性 - if(m_targetLogLogData[0].size() != m_targetLogLogData[1].size() || - m_targetLogLogData[0].size() != m_targetLogLogData[2].size()) { - m_lastError = "Target LogLog data arrays have inconsistent sizes"; - emit logMessageGenerated(tr("ERROR: Target LogLog data arrays have inconsistent sizes")); - return false; - } - - emit logMessageGenerated(tr("Target data validation passed (%1 data points)").arg(m_targetLogLogData[0].size())); - - // 使用保存的初始值进行精英保护 - QVector savedInitialValues = m_initialValues; - - // 重置状态 - resetOptimizer(); - m_isRunning = true; - m_shouldStop = false; - m_isPaused = false; - m_currentGeneration = 0; - m_consecutiveFailures = 0; - m_consecutiveFailedGenerations = 0; - - // 精英保护:评估用户初始解 - if(!savedInitialValues.isEmpty()) { - m_userInitialSolution = savedInitialValues; - emit logMessageGenerated(tr("=== Evaluating Initial Solution (Elite Protection) ===")); - - // 输出初始参数值 - QString paramStr = tr("Initial parameters: "); - for(int i = 0; i < m_userInitialSolution.size(); ++i) { - paramStr += QString("[%1]=%2 ").arg(i).arg(m_userInitialSolution[i], 0, 'f', 6); - } - emit logMessageGenerated(paramStr); - - try { - emit logMessageGenerated(tr("Starting initial solution evaluation...")); - DEBUG_OUT(QString("Before evaluateFitness: m_userInitialSolution size = %1").arg(m_userInitialSolution.size())); - - if(m_userInitialSolution.isEmpty()) { - emit logMessageGenerated(tr("ERROR: m_userInitialSolution is empty!")); - return false; - } - - for(int i = 0; i < m_userInitialSolution.size(); ++i) { - emit logMessageGenerated(tr("Initial param[%1] = %2").arg(i).arg(m_userInitialSolution[i], 0, 'f', 6)); - } - - m_userInitialFitness = evaluateGenes(m_userInitialSolution); - - emit logMessageGenerated(tr("evaluateGenes returned: %1").arg(m_userInitialFitness, 0, 'e', 10)); - - if(m_userInitialFitness < 1e9) { - emit logMessageGenerated(tr("Taking SUCCESS branch (fitness < 1e9)")); - m_hasValidUserSolution = true; - m_bestFitness = m_userInitialFitness; - m_bestIndividual.genes = m_userInitialSolution; - m_bestIndividual.fitness = m_userInitialFitness; - m_bestIndividual.isEvaluated = true; - - emit logMessageGenerated(tr("Initial solution evaluation successful")); - emit logMessageGenerated(tr("Initial fitness (error): %1").arg(m_userInitialFitness, 0, 'e', 4)); - emit logMessageGenerated(tr("Elite protection activated - initial solution will be preserved if no significant improvement found")); - } else { - emit logMessageGenerated(tr("Taking FAILURE branch (fitness >= 1e9)")); - m_hasValidUserSolution = false; - emit logMessageGenerated(tr("Initial solution evaluation failed - starting with random initialization")); - } - } catch(...) { - m_hasValidUserSolution = false; - emit logMessageGenerated(tr("Exception during initial solution evaluation")); - } - - // 恢复初始值供种群初始化使用 - m_initialValues = savedInitialValues; - } - - // 初始化种群 - initializePopulation(); - emit logMessageGenerated(tr("Population initialized: %1 individuals, %2 dimensions").arg(m_populationSize).arg(getEnabledParameterCount())); - - // GA主循环 - emit logMessageGenerated(tr("=== Starting GA Main Loop ===")); - - for(m_currentGeneration = 0; m_currentGeneration < m_maxGenerations && !m_shouldStop; ++m_currentGeneration) { - - // 每次迭代都输出标题,或者只在重要迭代输出详细信息 - bool shouldOutputDetail = (m_currentGeneration % qMax(1, m_maxGenerations / 10) == 0) || - (m_currentGeneration < 5) || - (m_currentGeneration >= m_maxGenerations - 2); - - // 每次迭代都输出标题 - emit logMessageGenerated(tr("--- Generation %1/%2 ---").arg(m_currentGeneration + 1).arg(m_maxGenerations)); - - // 只在特定迭代输出详细统计信息 - if(shouldOutputDetail) { - emit logMessageGenerated(tr("Current best error: %1").arg(m_bestFitness, 0, 'e', 4)); - emit logMessageGenerated(tr("Total evaluations: %1 (successful: %2, failures: %3)") - .arg(m_totalEvaluations).arg(m_successfulEvaluations).arg(m_totalEvaluations - m_successfulEvaluations)); - } - - // 检查暂停状态 - while(m_isPaused && !m_shouldStop) { - QApplication::processEvents(); - //msleep(100); - } - - if(m_shouldStop) { - emit logMessageGenerated(tr("Optimization stopped by user request")); - break; - } - - // 1. 评估种群 - evaluatePopulation(); - - if(m_shouldStop) break; - - // 2. 更新统计信息 - updatePopulationStatistics(); - - // 3. 发射进度信号 - emit progressUpdated(m_currentGeneration, m_bestFitness); - - if(shouldOutputDetail) { - emit logMessageGenerated(tr("Generation %1 completed: best = %2, avg = %3, worst = %4") - .arg(m_currentGeneration + 1).arg(m_bestFitness, 0, 'e', 4) - .arg(m_averageFitness, 0, 'e', 4).arg(m_worstFitness, 0, 'e', 4)); - } - - // 记录收敛历史 - m_convergenceHistory.append(m_bestFitness); - - // 更新收敛指标 - updateConvergenceMetrics(); - - // 智能收敛判断 - StopReasonGA stopReason = analyzeOptimizationStatus(); - - if(stopReason == GA_TARGET_ACHIEVED) { - emit logMessageGenerated(tr("=== TARGET ACHIEVED ===")); - emit logMessageGenerated(tr("Target error achieved! Current error: %1 < Target: %2") - .arg(m_bestFitness, 0, 'e', 4).arg(m_targetError, 0, 'e', 4)); - emit logMessageGenerated(tr("Optimization completed successfully after %1 generations") - .arg(m_currentGeneration + 1)); - break; - } - else if(stopReason == GA_TRUE_CONVERGENCE) { - emit logMessageGenerated(tr("=== TRUE CONVERGENCE DETECTED ===")); - emit logMessageGenerated(tr("Algorithm has converged to a stable solution")); - emit logMessageGenerated(tr("Final error: %1 after %2 generations") - .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1)); - emit logMessageGenerated(tr("Solution quality: %1 (1.0 = target achieved)") - .arg(m_targetError / qMax(1e-10, m_bestFitness), 0, 'f', 3)); - break; - } - else if(stopReason == GA_LOCAL_OPTIMUM) { - emit logMessageGenerated(tr("=== LOCAL OPTIMUM DETECTED ===")); - emit logMessageGenerated(tr("Algorithm appears to be trapped in local optimum")); - emit logMessageGenerated(tr("Current error: %1 after %2 generations") - .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1)); - emit logMessageGenerated(tr("Suggestion: Try restarting with different parameters or larger search space")); - break; - } - else if(stopReason == GA_CONSECUTIVE_FAILURES) { - emit logMessageGenerated(tr("=== CONSECUTIVE FAILURES ===")); - emit logMessageGenerated(tr("Too many consecutive failed generations (%1/%2)") - .arg(m_consecutiveFailedGenerations).arg(m_maxConsecutiveFailures)); - break; - } - else if(stopReason == GA_CONTINUE_OPTIMIZATION) { - // 继续优化,每10次迭代输出一次状态 - if(m_currentGeneration > 0 && m_currentGeneration % 10 == 0) { - double diversity = calculatePopulationDiversity(); - - emit logMessageGenerated(tr(" Optimization status: diversity=%1") - .arg(diversity, 0, 'f', 4)); - } - } - - // 4. 创建新一代种群 - if(m_currentGeneration < m_maxGenerations - 1) - { - QVector newPopulation; - newPopulation.reserve(m_populationSize); - - // 精英保留 - applyElitism(newPopulation); - - // 生成新个体直到填满种群 - while(newPopulation.size() < m_populationSize && !m_shouldStop) { - // 选择父代 - int parent1Index = tournamentSelection(); - int parent2Index = tournamentSelection(); - - // 确保父代不同 - while(parent1Index == parent2Index && m_population.size() > 1) { - parent2Index = tournamentSelection(); - } - - GAIndividual offspring1, offspring2; - - // 交叉 - if(random01() < m_crossoverRate) { - crossover(m_population[parent1Index], m_population[parent2Index], - offspring1, offspring2); - } else { - offspring1 = m_population[parent1Index]; - offspring2 = m_population[parent2Index]; - } - - // 变异 - if(random01() < m_mutationRate) { - mutate(offspring1); - } - if(random01() < m_mutationRate) { - mutate(offspring2); - } - - // 边界约束 - clampToLimits(offspring1.genes); - clampToLimits(offspring2.genes); - - // 添加到新种群 - if(newPopulation.size() < m_populationSize) { - newPopulation.append(offspring1); - } - if(newPopulation.size() < m_populationSize) { - newPopulation.append(offspring2); - } - } - - // 替换种群 - m_population = newPopulation; - - // 自适应参数调整 - adaptiveParameterUpdate(m_currentGeneration); - } - - // 输出迭代结束标记 - if(shouldOutputDetail) { - emit logMessageGenerated(tr("Generation %1 completed - Current best: %2") - .arg(m_currentGeneration + 1).arg(m_bestFitness, 0, 'e', 4)); - } - - // 强制处理事件,保持界面响应 - QApplication::processEvents(); - - // 在世代间稍作停顿,减少系统负载 - if(m_currentGeneration % 3 == 2) { - //msleep(200); - } - } - - // 最终结果验证和保护 - validateAndProtectFinalResult(); - - } catch(const std::exception& e) { - m_lastError = QString("Critical exception in GA main loop: %1").arg(e.what()); - emit logMessageGenerated(tr("CRITICAL ERROR: %1").arg(e.what())); - cleanupTemporaryDirectory(); - m_isRunning = false; - if(m_progressTimer) m_progressTimer->stop(); - emit fittingFinished(false, m_lastError); - return false; - } catch(...) { - m_lastError = "Unknown critical exception in GA main loop"; - emit logMessageGenerated(tr("CRITICAL ERROR: Unknown exception in GA main loop")); - cleanupTemporaryDirectory(); - m_isRunning = false; - if(m_progressTimer) m_progressTimer->stop(); - emit fittingFinished(false, m_lastError); - return false; - } - - m_isRunning = false; - if(m_progressTimer) m_progressTimer->stop(); - - // 应用最终参数 - if(!m_bestIndividual.genes.isEmpty()) { - try { - emit logMessageGenerated(tr("Applying optimized parameters to model...")); - applyParametersToDataManager(m_bestIndividual.genes); - saveOptimizationResult(); - - // 输出最终优化结果 - emit logMessageGenerated(tr("=== Optimization Results ===")); - emit logMessageGenerated(tr("Final error: %1").arg(m_bestFitness, 0, 'e', 4)); - emit logMessageGenerated(tr("Total generations: %1").arg(m_currentGeneration + 1)); - emit logMessageGenerated(tr("Total evaluations: %1 (successful: %2)") - .arg(m_totalEvaluations).arg(m_successfulEvaluations)); - - // 输出最优参数值 - QString finalParams = tr("Optimized parameters: "); - for(int i = 0; i < m_bestIndividual.genes.size(); ++i) { - finalParams += QString("[%1]=%2 ").arg(i).arg(m_bestIndividual.genes[i], 0, 'f', 6); - } - emit logMessageGenerated(finalParams); - - emit logMessageGenerated(tr("Parameters applied successfully to data manager")); - } catch(const std::exception& e) { - emit logMessageGenerated(tr("ERROR: Failed to apply final parameters: %1").arg(e.what())); - m_lastError = QString("Failed to apply final parameters: %1").arg(e.what()); - } catch(...) { - emit logMessageGenerated(tr("ERROR: Unknown error applying final parameters")); - m_lastError = "Failed to apply final parameters due to unknown error"; - } - } - - // 判断系统确定最终结果 - bool success; - QString message; - StopReasonGA finalReason = analyzeOptimizationStatus(); - - if(finalReason == GA_TARGET_ACHIEVED) { - success = true; - //message = QString("GA optimization completed successfully. Target achieved. Best error: %1, Generations: %2") - // .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1); - emit logMessageGenerated(tr("=== GA OPTIMIZATION SUCCESSFUL ===")); - } - else if(finalReason == GA_TRUE_CONVERGENCE) { - success = true; - //message = QString("GA optimization converged to stable solution. Best error: %1, Generations: %2") - // .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1); - emit logMessageGenerated(tr("=== GA OPTIMIZATION CONVERGED ===")); - } - else if(finalReason == GA_LOCAL_OPTIMUM) { - success = true; - //message = QString("GA optimization trapped in local optimum. Best error: %1, Generations: %2") - // .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1); - emit logMessageGenerated(tr("=== GA OPTIMIZATION - LOCAL OPTIMUM ===")); - } - else if(finalReason == GA_MAX_ITERATIONS) { - success = true; - //message = QString("GA optimization completed. Max generations reached. Best error: %1, Generations: %2") - // .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1); - emit logMessageGenerated(tr("=== GA OPTIMIZATION - MAX GENERATIONS ===")); - } - else if(finalReason == GA_USER_STOPPED) { - success = true; - //message = QString("GA optimization stopped by user. Best error: %1, Generations: %2") - // .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1); - emit logMessageGenerated(tr("=== GA OPTIMIZATION STOPPED BY USER ===")); - } - else if(finalReason == GA_CONSECUTIVE_FAILURES) { - success = false; - //message = QString("GA optimization failed due to consecutive failures. Best error: %1, Generations: %2") - // .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1); - emit logMessageGenerated(tr("=== GA OPTIMIZATION FAILED ===")); - } - else { - success = false; - //message = QString("GA optimization ended unexpectedly. Best error: %1, Generations: %2") - // .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1); - emit logMessageGenerated(tr("=== GA OPTIMIZATION - UNKNOWN END ===")); - } - - emit logMessageGenerated(tr("Result: %1").arg(success ? "SUCCESS" : "FAILED")); - - emit fittingFinished(success, message); - cleanupTemporaryDirectory(); - return success; -} - -void nmCalculationAutoFitGA::stopFitting() -{ - if(m_isRunning) { - DEBUG_OUT("Stop request received, setting stop flag..."); - - // 添加停止日志 - emit logMessageGenerated(tr("=== User Stop Request Received ===")); - emit logMessageGenerated(tr("Gracefully stopping GA optimization...")); - - m_shouldStop = true; - - if(m_progressTimer) { - m_progressTimer->stop(); - } - - // 等待当前评估完成,缩短超时时间 - int waitCount = 0; - while(m_evaluationInProgress > 0 && waitCount < 30) { // 减少等待时间 - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 50); - msleep(50); - waitCount++; - } - - // 超时时强制重置 - if(m_evaluationInProgress > 0) { - DEBUG_OUT("Force resetting evaluation counter"); - emit logMessageGenerated(tr("Force stopping current evaluation...")); - m_evaluationInProgress = 0; - } - - // 确保运行标志被清除 - m_isRunning = false; - - emit logMessageGenerated(tr("GA optimization stop request processed")); - DEBUG_OUT("Stop request processed"); - } else { - DEBUG_OUT("Stop request received but GA is not running"); - emit logMessageGenerated(tr("Stop request received but optimization is not running")); - } - cleanupTemporaryDirectory(); -} - -bool nmCalculationAutoFitGA::isRunning() const -{ - return m_isRunning; -} - -int nmCalculationAutoFitGA::getCurrentGeneration() const -{ - return m_currentGeneration; -} - -QVector nmCalculationAutoFitGA::getBestSolution() const -{ - return m_bestIndividual.genes; -} - -double nmCalculationAutoFitGA::getBestFitness() const -{ - return m_bestFitness; -} - -QString nmCalculationAutoFitGA::getLastError() const -{ - return m_lastError; -} - -void nmCalculationAutoFitGA::resetOptimizer() -{ - m_population.clear(); - m_eliteIndividuals.clear(); - m_bestIndividual = GAIndividual(); - m_bestFitness = 1e10; - m_worstFitness = -1e10; - m_averageFitness = 1e10; - m_previousBestFitness = 1e10; - m_currentGeneration = 0; - m_totalEvaluations = 0; - m_successfulEvaluations = 0; - m_convergenceHistory.clear(); - m_lastError.clear(); - m_initialValues.clear(); - m_userInitialSolution.clear(); - m_userInitialFitness = 1e10; - m_hasValidUserSolution = false; - m_diversityHistory.clear(); - - DEBUG_OUT("GA optimizer reset"); -} - -void nmCalculationAutoFitGA::setGATargetWellName(const QString& wellName) -{ - m_targetWellName = wellName; -} - -void nmCalculationAutoFitGA::updateProgress() -{ - // 这个槽函数在定时器触发时被调用,可以用来更新界面或执行周期性任务 - if(m_isRunning) { - QApplication::processEvents(); - } -} - -// ==================== 数据加载方法 ==================== -bool nmCalculationAutoFitGA::loadAllConfigFromDataManager() -{ - try { - loadOptimizationConfig(); - loadParameterBounds(); - extractUserInitialValues(); - return true; - } catch(...) { - m_lastError = "Failed to load configuration from data manager"; - return false; - } -} - -void nmCalculationAutoFitGA::loadOptimizationConfig() -{ - nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); - nmDataAutomaticFitting fittingData = dataManager->getAutomaticFittingDataCopy(); - - // 加载基本配置 - m_maxGenerations = fittingData.getIterationCount().getValue().toInt(); - m_targetError = fittingData.getErrorTolerance().getValue().toDouble(); - - // 设置GA默认参数 - m_populationSize = 40; - m_crossoverRate = 0.8; - m_mutationRate = 0.1; - m_elitismRate = 0.15; - m_tournamentSize = 3; - m_useUniformCrossover = true; - - DEBUG_OUT(QString("Loaded GA optimization config: generations=%1, error=%2, population=%3") - .arg(m_maxGenerations).arg(m_targetError).arg(m_populationSize)); -} - -void nmCalculationAutoFitGA::loadParameterBounds() -{ - nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); - nmDataAutomaticFitting fittingData = dataManager->getAutomaticFittingDataCopy(); - - // 获取参数选择状态 - m_parameterSelected.resize(8); - m_parameterSelected[0] = fittingData.getPermeabilitySelected(); - m_parameterSelected[1] = fittingData.getSkinSelected(); - m_parameterSelected[2] = fittingData.getWellboreStorageSelected(); - m_parameterSelected[3] = fittingData.getPorositySelected(); - m_parameterSelected[4] = fittingData.getThicknessSelected(); - m_parameterSelected[5] = fittingData.getCtSelected(); - m_parameterSelected[6] = fittingData.getCfSelected(); - m_parameterSelected[7] = fittingData.getSwiSelected(); - - // 获取参数边界 - m_parameterLower.resize(8); - m_parameterUpper.resize(8); - - m_parameterLower[0] = fittingData.getPermeabilityMin().getValue().toDouble(); - m_parameterUpper[0] = fittingData.getPermeabilityMax().getValue().toDouble(); - - m_parameterLower[1] = fittingData.getSkinMin().getValue().toDouble(); - m_parameterUpper[1] = fittingData.getSkinMax().getValue().toDouble(); - - m_parameterLower[2] = fittingData.getWellboreStorageMin().getValue().toDouble(); - m_parameterUpper[2] = fittingData.getWellboreStorageMax().getValue().toDouble(); - - m_parameterLower[3] = fittingData.getPorosityMin().getValue().toDouble(); - m_parameterUpper[3] = fittingData.getPorosityMax().getValue().toDouble(); - - m_parameterLower[4] = fittingData.getThicknessMin().getValue().toDouble(); - m_parameterUpper[4] = fittingData.getThicknessMax().getValue().toDouble(); - - m_parameterLower[5] = fittingData.getCtMin().getValue().toDouble(); - m_parameterUpper[5] = fittingData.getCtMax().getValue().toDouble(); - - m_parameterLower[6] = fittingData.getCfMin().getValue().toDouble(); - m_parameterUpper[6] = fittingData.getCfMax().getValue().toDouble(); - - m_parameterLower[7] = fittingData.getSwiMin().getValue().toDouble(); - m_parameterUpper[7] = fittingData.getSwiMax().getValue().toDouble(); - - // 更新启用参数索引 - m_enabledParamIndices.clear(); - for(int i = 0; i < m_parameterSelected.size(); ++i) { - if(m_parameterSelected[i]) { - m_enabledParamIndices.append(i); - } - } - DEBUG_OUT(QString("Loaded parameter bounds: %1 enabled parameters") - .arg(m_enabledParamIndices.size())); -} - -void nmCalculationAutoFitGA::extractUserInitialValues() -{ - nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); - nmDataReservoir reservoirData = dataManager->getReservoirDataCopy(); - //QVector wells = dataManager->getWellDataList(); - nmDataWellBase* pTargetWell = dataManager->findWellByName(m_targetWellName); - - m_initialValues.clear(); - - // 按照启用参数的顺序提取初始值 - for(int i = 0; i < m_enabledParamIndices.size(); ++i) { - int paramIndex = m_enabledParamIndices[i]; - double initialValue = 0.0; - - switch(paramIndex) { - case 0: // 渗透率 - initialValue = reservoirData.getPermeability().getValue().toDouble(); - break; - - case 1: // 表皮系数 - if(pTargetWell) { - initialValue = pTargetWell->getPerforation(0)->getSkin().getValue().toDouble(); - } - - break; - - case 2: // 井筒储集系数 - if(pTargetWell) { - initialValue = pTargetWell->getWellboreStorage().getValue().toDouble(); - } - - break; - - case 3: // 孔隙度 - initialValue = reservoirData.getPorosity().getValue().toDouble(); - break; - - case 4: // 储层厚度 - initialValue = reservoirData.getThickness().getValue().toDouble(); - break; - - case 5: // 综合压缩系数 - initialValue = reservoirData.getCt().getValue().toDouble(); - break; - - case 6: // 岩石压缩系数 - initialValue = reservoirData.getCf().getValue().toDouble(); - break; - - case 7: // 初始含水饱和度 - initialValue = reservoirData.getSwi().getValue().toDouble(); - break; - } - - m_initialValues.append(initialValue); - } - - DEBUG_OUT(QString("Extracted %1 user initial values").arg(m_initialValues.size())); - - for(int i = 0; i < m_initialValues.size(); ++i) { - DEBUG_OUT(QString(" Initial[%1] = %2").arg(i).arg(m_initialValues[i], 0, 'e', 3)); - } - - // 验证初始值 - if(!validateInitialValues()) { - DEBUG_OUT("Warning: Some initial values are outside parameter bounds"); - } -} - -// ==================== 遗传算法核心方法 ==================== - -void nmCalculationAutoFitGA::initializePopulation() -{ - int dimensions = getEnabledParameterCount(); - if(dimensions == 0) return; - - m_population.clear(); - m_population.resize(m_populationSize); - - bool hasValidInitials = !m_initialValues.isEmpty() && m_initialValues.size() >= dimensions; - int guidedCount = hasValidInitials ? qMax(2, m_populationSize / 2) : qMax(1, m_populationSize / 3); - - DEBUG_OUT(QString("Enhanced population initialization: %1 individuals, %2 guided, %3 random") - .arg(m_populationSize).arg(guidedCount).arg(m_populationSize - guidedCount)); - - for(int i = 0; i < m_populationSize; ++i) { - GAIndividual& individual = m_population[i]; - individual.genes.resize(dimensions); - individual.fitness = 1e10; - individual.isEvaluated = false; - - // 基因初始化 - for(int j = 0; j < dimensions; ++j) { - int paramIndex = m_enabledParamIndices[j]; - double range = m_parameterUpper[paramIndex] - m_parameterLower[paramIndex]; - - if(i == 0 && hasValidInitials) { - // 第一个个体:使用用户初始值 - individual.genes[j] = m_initialValues[j]; - } else if(i < guidedCount && hasValidInitials) { - // 引导搜索策略 - double searchRadius; - if(i <= guidedCount / 3) { - searchRadius = range * 0.03; - } else if(i <= guidedCount * 2 / 3) { - searchRadius = range * 0.08; - } else { - searchRadius = range * 0.15; - } - double offset = (random01() - 0.5) * searchRadius; - individual.genes[j] = m_initialValues[j] + offset; - } else { - // 随机初始化 - individual.genes[j] = m_parameterLower[paramIndex] + random01() * range; - } - } - - // 边界约束 - clampToLimits(individual.genes); - } -} - -double nmCalculationAutoFitGA::evaluateGenes(const QVector& genes) -{ - const QString funcName = QString("evaluateGenes[Gen%1]").arg(m_currentGeneration); - static int callCount = 0; - callCount++; - - try { - DEBUG_OUT(QString("%1: Call #%2 - Starting evaluation with %3 genes") - .arg(funcName).arg(callCount).arg(genes.size())); - - // 打印参数值用于对比 - QString paramStr = "Parameters: "; - - for(int i = 0; i < genes.size(); ++i) { - paramStr += QString("[%1]=%2 ").arg(i).arg(genes[i], 0, 'f', 6); - } - - DEBUG_OUT(QString("%1: %2").arg(funcName).arg(paramStr)); - - // 1. 参数有效性检查 - if(!validateParameters(genes)) { - DEBUG_OUT(QString("%1: Call #%2 - Invalid parameters").arg(funcName).arg(callCount)); - return 1e10; - } - - // 2. 检查数据管理器状态 - nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); - - if(!dataManager) { - DEBUG_OUT(QString("%1: Call #%2 - DataManager is null").arg(funcName).arg(callCount)); - return 1e10; - } - - // 3. 应用参数到数据管理器 - try { - DEBUG_OUT(QString("%1: Call #%2 - Applying parameters to DataManager").arg(funcName).arg(callCount)); - applyParametersToDataManager(genes); - DEBUG_OUT(QString("%1: Call #%2 - Parameters applied successfully").arg(funcName).arg(callCount)); - } catch(const std::exception& e) { - DEBUG_OUT(QString("%1: Call #%2 - Failed to apply parameters: %3").arg(funcName).arg(callCount).arg(e.what())); - return 1e10; - } catch(...) { - DEBUG_OUT(QString("%1: Call #%2 - Unknown error applying parameters").arg(funcName).arg(callCount)); - return 1e10; - } - - // 4. 运行求解器 - QVector > solverResult; - const int maxRetries = 2; - bool solverSuccess = false; - - for(int retry = 0; retry <= maxRetries; ++retry) { - if(m_shouldStop) return 1e10; - - try { - DEBUG_OUT(QString("%1: Call #%2 - Solver attempt %3/%4") - .arg(funcName).arg(callCount).arg(retry + 1).arg(maxRetries + 1)); - - // 在求解器调用前添加短暂延迟,确保状态稳定 - if(retry > 0) { - DEBUG_OUT(QString("%1: Call #%2 - Retry delay before solver attempt") - .arg(funcName).arg(callCount)); - msleep(1000); // 增加延迟时间 - } - - solverResult = runSolver(); - - if(!solverResult.isEmpty() && validateSolverResult(solverResult)) { - DEBUG_OUT(QString("%1: Call #%2 - Solver successful on attempt %3, result size: %4") - .arg(funcName).arg(callCount).arg(retry + 1).arg(solverResult[0].size())); - solverSuccess = true; - break; - } else { - DEBUG_OUT(QString("%1: Call #%2 - Solver failed on attempt %3 - empty or invalid result") - .arg(funcName).arg(callCount).arg(retry + 1)); - - if(retry < maxRetries) { - DEBUG_OUT(QString("%1: Call #%2 - Will retry solver").arg(funcName).arg(callCount)); - } - } - - } catch(const std::exception& e) { - DEBUG_OUT(QString("%1: Call #%2 - Solver exception on attempt %3: %4") - .arg(funcName).arg(callCount).arg(retry + 1).arg(e.what())); - } catch(...) { - DEBUG_OUT(QString("%1: Call #%2 - Unknown solver exception on attempt %3") - .arg(funcName).arg(callCount).arg(retry + 1)); - } - } - - if(!solverSuccess) { - DEBUG_OUT(QString("%1: Call #%2 - All solver attempts failed").arg(funcName).arg(callCount)); - return 1e10; - } - - // 5. 获取双对数结果数据 - QVector > resultLogLogData; - - try { - - nmDataWellBase* pTargetWell = dataManager->findWellByName(m_targetWellName); - - if(pTargetWell) { - resultLogLogData = pTargetWell->getResultLogLog(); - - if(!validateLogLogData(resultLogLogData)) { - DEBUG_OUT(QString("%1: Call #%2 - Invalid result LogLog data").arg(funcName).arg(callCount)); - return 1e10; - } - - DEBUG_OUT(QString("%1: Call #%2 - LogLog result data obtained, size: %3") - .arg(funcName).arg(callCount).arg(resultLogLogData[0].size())); - } else { - DEBUG_OUT(QString("%1: Call #%2 - No wells found after solver").arg(funcName).arg(callCount)); - return 1e10; - } - } catch(const std::exception& e) { - DEBUG_OUT(QString("%1: Call #%2 - Error getting LogLog result: %3").arg(funcName).arg(callCount).arg(e.what())); - return 1e10; - } catch(...) { - DEBUG_OUT(QString("%1: Call #%2 - Unknown error getting LogLog result").arg(funcName).arg(callCount)); - return 1e10; - } - - // 6. 双对数曲线对齐和误差计算 - double error; - - try { - error = calculateLogLogCurveError(m_targetLogLogData, resultLogLogData); - - if(!isFiniteNumber(error) || error < 0) { - DEBUG_OUT(QString("%1: Call #%2 - Invalid error value: %3").arg(funcName).arg(callCount).arg(error)); - return 1e10; - } - - DEBUG_OUT(QString("%1: Call #%2 - Evaluation successful, error = %3") - .arg(funcName).arg(callCount).arg(error, 0, 'e', 6)); - - } catch(const std::exception& e) { - DEBUG_OUT(QString("%1: Call #%2 - LogLog error calculation failed: %3").arg(funcName).arg(callCount).arg(e.what())); - return 1e10; - } catch(...) { - DEBUG_OUT(QString("%1: Call #%2 - Unknown error in LogLog error calculation").arg(funcName).arg(callCount)); - return 1e10; - } - - return error; - - } catch(const std::exception& e) { - DEBUG_OUT(QString("%1: Call #%2 - Top-level exception: %3").arg(funcName).arg(callCount).arg(e.what())); - return 1e10; - } catch(...) { - DEBUG_OUT(QString("%1: Call #%2 - Unknown top-level exception").arg(funcName).arg(callCount)); - return 1e10; - } -} - -double nmCalculationAutoFitGA::evaluateIndividual(GAIndividual& individual) -{ - // 如果已经评估过,直接返回 - if(individual.isEvaluated) { - return individual.fitness; - } - - // 调用新的评估函数 - individual.fitness = evaluateGenes(individual.genes); - individual.isEvaluated = true; - - return individual.fitness; -} - -void nmCalculationAutoFitGA::evaluatePopulation() -{ - int successfulEvaluations = 0; - int totalEvaluations = 0; - int currentGenerationFailed = 0; - - for(int i = 0; i < m_population.size() && !m_shouldStop; ++i) { - GAIndividual& individual = m_population[i]; - - if(!individual.isEvaluated) { - try { - double previousFitness = individual.fitness; - individual.fitness = evaluateGenes(individual.genes); - individual.isEvaluated = true; - totalEvaluations++; - m_totalEvaluations++; - - if(individual.fitness < 1e9) { - successfulEvaluations++; - m_successfulEvaluations++; - - // 更新全局最优 - if(individual.fitness < m_bestFitness) { - m_bestFitness = individual.fitness; - m_bestIndividual = individual; - - emit logMessageGenerated(tr(" Individual %1 improved: %2 -> %3") - .arg(i + 1).arg(previousFitness, 0, 'e', 3).arg(individual.fitness, 0, 'e', 3)); - } - } else { - currentGenerationFailed++; - emit logMessageGenerated(tr(" Individual %1: evaluation failed").arg(i + 1)); - } - - // 每评估2个个体处理一次事件 - if(i % 2 == 0) { - QApplication::processEvents(); - } - - } catch(const std::exception& e) { - emit logMessageGenerated(tr(" Individual %1: Exception: %2").arg(i + 1).arg(e.what())); - individual.fitness = 1e10; - individual.isEvaluated = true; - totalEvaluations++; - currentGenerationFailed++; - m_totalEvaluations++; - } catch(...) { - emit logMessageGenerated(tr(" Individual %1: Unknown exception").arg(i + 1)); - individual.fitness = 1e10; - individual.isEvaluated = true; - totalEvaluations++; - currentGenerationFailed++; - m_totalEvaluations++; - } - } - } - - if(m_shouldStop) return; - - double currentSuccessRate = totalEvaluations > 0 ? - (double)successfulEvaluations / totalEvaluations : 0.0; - - // 更新连续失败代数计数 - if(successfulEvaluations == 0) { - m_consecutiveFailedGenerations++; - emit logMessageGenerated(tr("WARNING: No successful evaluations in generation %1 (consecutive failures: %2)") - .arg(m_currentGeneration + 1).arg(m_consecutiveFailedGenerations)); - } else { - m_consecutiveFailedGenerations = 0; // 重置连续失败计数 - } - - // 输出当前代统计 - emit logMessageGenerated(tr("Current generation stats: %1 successful, %2 failed out of %3 individuals (success rate: %4%)") - .arg(successfulEvaluations).arg(currentGenerationFailed) - .arg(totalEvaluations).arg(currentSuccessRate * 100, 0, 'f', 1)); - - // 检查是否需要停止优化 - if(m_consecutiveFailedGenerations >= m_maxConsecutiveFailures) { - m_lastError = QString("Too many consecutive failed generations (%1)").arg(m_consecutiveFailedGenerations); - emit logMessageGenerated(tr("ERROR: Too many consecutive failed generations (%1/%2) - stopping optimization") - .arg(m_consecutiveFailedGenerations).arg(m_maxConsecutiveFailures)); - return; - } - - // 警告低成功率但不立即停止 - if(currentSuccessRate < 0.5 && m_currentGeneration > 3) { - emit logMessageGenerated(tr("WARNING: Low success rate (%1%) in generation %2, but continuing optimization") - .arg(currentSuccessRate * 100, 0, 'f', 1).arg(m_currentGeneration + 1)); - } -} - -int nmCalculationAutoFitGA::tournamentSelection() -{ - int bestIndex = qrand() % m_population.size(); - double bestFitness = m_population[bestIndex].fitness; - - for(int i = 1; i < m_tournamentSize; ++i) { - int candidateIndex = qrand() % m_population.size(); - double candidateFitness = m_population[candidateIndex].fitness; - - if(candidateFitness < bestFitness) { - bestIndex = candidateIndex; - bestFitness = candidateFitness; - } - } - - return bestIndex; -} - -int nmCalculationAutoFitGA::rouletteWheelSelection() -{ - // 计算适应度总和(使用倒数,因为我们要最小化) - double totalFitness = 0.0; - double maxFitness = -1e10; - - // 找到最大适应度值 - for(int i = 0; i < m_population.size(); ++i) { - if(m_population[i].fitness > maxFitness) { - maxFitness = m_population[i].fitness; - } - } - - // 计算转换后的适应度总和 - for(int i = 0; i < m_population.size(); ++i) { - double transformedFitness = maxFitness - m_population[i].fitness + 1e-6; - totalFitness += transformedFitness; - } - - // 轮盘赌选择 - double randomValue = random01() * totalFitness; - double cumulativeFitness = 0.0; - - for(int i = 0; i < m_population.size(); ++i) { - double transformedFitness = maxFitness - m_population[i].fitness + 1e-6; - cumulativeFitness += transformedFitness; - - if(cumulativeFitness >= randomValue) { - return i; - } - } - - return m_population.size() - 1; // 备用选择 -} - -void nmCalculationAutoFitGA::crossover(const GAIndividual& parent1, const GAIndividual& parent2, - GAIndividual& offspring1, GAIndividual& offspring2) -{ - if(m_useUniformCrossover) { - uniformCrossover(parent1, parent2, offspring1, offspring2); - } else { - singlePointCrossover(parent1, parent2, offspring1, offspring2); - } -} - -void nmCalculationAutoFitGA::singlePointCrossover(const GAIndividual& parent1, const GAIndividual& parent2, - GAIndividual& offspring1, GAIndividual& offspring2) -{ - int dimensions = parent1.genes.size(); - - if(dimensions == 0) return; - - // 初始化子代 - offspring1.genes.resize(dimensions); - offspring2.genes.resize(dimensions); - offspring1.fitness = 1e10; - offspring2.fitness = 1e10; - offspring1.isEvaluated = false; - offspring2.isEvaluated = false; - - // 选择交叉点 - int crossoverPoint = qrand() % dimensions; - - // 执行交叉 - for(int i = 0; i < dimensions; ++i) { - if(i < crossoverPoint) { - offspring1.genes[i] = parent1.genes[i]; - offspring2.genes[i] = parent2.genes[i]; - } else { - offspring1.genes[i] = parent2.genes[i]; - offspring2.genes[i] = parent1.genes[i]; - } - } -} - -void nmCalculationAutoFitGA::uniformCrossover(const GAIndividual& parent1, const GAIndividual& parent2, - GAIndividual& offspring1, GAIndividual& offspring2) -{ - int dimensions = parent1.genes.size(); - - if(dimensions == 0) return; - - // 初始化子代 - offspring1.genes.resize(dimensions); - offspring2.genes.resize(dimensions); - offspring1.fitness = 1e10; - offspring2.fitness = 1e10; - offspring1.isEvaluated = false; - offspring2.isEvaluated = false; - - // 均匀交叉 - for(int i = 0; i < dimensions; ++i) { - if(random01() < 0.5) { - offspring1.genes[i] = parent1.genes[i]; - offspring2.genes[i] = parent2.genes[i]; - } else { - offspring1.genes[i] = parent2.genes[i]; - offspring2.genes[i] = parent1.genes[i]; - } - } -} - -void nmCalculationAutoFitGA::mutate(GAIndividual& individual) -{ - // 使用高斯变异作为主要方式 - gaussianMutation(individual); -} - -void nmCalculationAutoFitGA::gaussianMutation(GAIndividual& individual) -{ - for(int i = 0; i < individual.genes.size(); ++i) { - if(random01() < m_mutationRate) { - int paramIndex = m_enabledParamIndices[i]; - double range = m_parameterUpper[paramIndex] - m_parameterLower[paramIndex]; - double sigma = range * MUTATION_STRENGTH; - - // 高斯变异 - double mutation = gaussianRandom(0.0, sigma); - individual.genes[i] += mutation; - - // 边界处理 - individual.genes[i] = qMax(m_parameterLower[paramIndex], - qMin(m_parameterUpper[paramIndex], individual.genes[i])); - } - } - - // 标记为未评估 - individual.isEvaluated = false; -} - -void nmCalculationAutoFitGA::polynomialMutation(GAIndividual& individual) -{ - const double eta = 20.0; // 分布指数 - - for(int i = 0; i < individual.genes.size(); ++i) { - if(random01() < m_mutationRate) { - int paramIndex = m_enabledParamIndices[i]; - double lower = m_parameterLower[paramIndex]; - double upper = m_parameterUpper[paramIndex]; - double y = individual.genes[i]; - - double delta1 = (y - lower) / (upper - lower); - double delta2 = (upper - y) / (upper - lower); - - double rnd = random01(); - double mut_pow = 1.0 / (eta + 1.0); - - double deltaq; - - if(rnd <= 0.5) { - double xy = 1.0 - delta1; - double val = 2.0 * rnd + (1.0 - 2.0 * rnd) * pow(xy, eta + 1.0); - deltaq = pow(val, mut_pow) - 1.0; - } else { - double xy = 1.0 - delta2; - double val = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * pow(xy, eta + 1.0); - deltaq = 1.0 - pow(val, mut_pow); - } - - y += deltaq * (upper - lower); - individual.genes[i] = qMax(lower, qMin(upper, y)); - } - } - - // 标记为未评估 - individual.isEvaluated = false; -} - -void nmCalculationAutoFitGA::applyElitism(QVector& newPopulation) -{ - int eliteCount = static_cast(m_populationSize * m_elitismRate); - - if(eliteCount == 0) return; - - // 对种群按适应度排序 - QVector sortedPopulation = m_population; - - // 冒泡排序(适应度从小到大) - for(int i = 0; i < sortedPopulation.size() - 1; ++i) { - for(int j = 0; j < sortedPopulation.size() - 1 - i; ++j) { - if(sortedPopulation[j].fitness > sortedPopulation[j + 1].fitness) { - GAIndividual temp = sortedPopulation[j]; - sortedPopulation[j] = sortedPopulation[j + 1]; - sortedPopulation[j + 1] = temp; - } - } - } - - // 复制精英个体到新种群 - for(int i = 0; i < eliteCount && i < sortedPopulation.size(); ++i) { - newPopulation.append(sortedPopulation[i]); - } - - DEBUG_OUT(QString("Applied elitism: %1 elite individuals preserved").arg(eliteCount)); -} - -void nmCalculationAutoFitGA::updatePopulationStatistics() -{ - if(m_population.isEmpty()) return; - - m_previousBestFitness = m_bestFitness; - - double sum = 0.0; - double minFitness = 1e10; - double maxFitness = -1e10; - int validCount = 0; - - for(int i = 0; i < m_population.size(); ++i) { - const GAIndividual& individual = m_population[i]; - - if(individual.isEvaluated && individual.fitness < 1e9) { - sum += individual.fitness; - validCount++; - - if(individual.fitness < minFitness) { - minFitness = individual.fitness; - } - - if(individual.fitness > maxFitness) { - maxFitness = individual.fitness; - } - - // 更新全局最优 - if(individual.fitness < m_bestFitness) { - // 只有显著改进时才更新 - double improvement = (m_bestFitness - individual.fitness); - double relativeImprovement = improvement / qMax(1e-10, qAbs(m_bestFitness)); - - if(relativeImprovement > m_improvementThreshold) { - m_bestFitness = individual.fitness; - m_bestIndividual = individual; - - DEBUG_OUT(QString("Global best updated with %1% improvement: %2") - .arg(relativeImprovement * 100, 0, 'f', 3) - .arg(m_bestFitness, 0, 'e', 4)); - } - } - } - } - - if(validCount > 0) { - m_averageFitness = sum / validCount; - m_worstFitness = maxFitness; - } else { - m_averageFitness = 1e10; - m_worstFitness = 1e10; - } - - // 在没有找到更好解时才检查精英保护 - if(m_hasValidUserSolution && m_userInitialFitness < m_bestFitness) { - DEBUG_OUT("Elite protection: No significant improvement found, checking initial solution"); - - // 检查初始解是否仍然是最优的 - double improvement = m_bestFitness - m_userInitialFitness; - double relativeImprovement = improvement / qMax(1e-10, qAbs(m_bestFitness)); - - if(relativeImprovement > m_improvementThreshold * 0.5) { // 使用更宽松的阈值 - DEBUG_OUT("Elite protection: Restoring user initial solution"); - m_bestFitness = m_userInitialFitness; - m_bestIndividual.genes = m_userInitialSolution; - m_bestIndividual.fitness = m_userInitialFitness; - m_bestIndividual.isEvaluated = true; - } - } -} - -bool nmCalculationAutoFitGA::checkConvergence() -{ - if(m_convergenceHistory.size() < CONVERGENCE_CHECK_INTERVAL) { - return false; - } - - // 检查最近几次世代的改进 - double recentBest = m_convergenceHistory.last(); - double oldBest = m_convergenceHistory[m_convergenceHistory.size() - CONVERGENCE_CHECK_INTERVAL]; - - double improvement = oldBest - recentBest; - - // 如果连续多代没有显著改进,认为已收敛 - if(improvement < MIN_FITNESS_IMPROVEMENT) { - // 检查是否连续停滞 - int stagnationCount = 0; - - for(int i = m_convergenceHistory.size() - 1; i >= qMax(0, m_convergenceHistory.size() - MAX_STAGNATION_GENERATIONS); --i) { - if(i > 0) { - double diff = m_convergenceHistory[i - 1] - m_convergenceHistory[i]; - - if(diff < MIN_FITNESS_IMPROVEMENT) { - stagnationCount++; - } else { - break; - } - } - } - - return stagnationCount >= MAX_STAGNATION_GENERATIONS; - } - - return false; -} - -void nmCalculationAutoFitGA::adaptiveParameterUpdate(int generation) -{ - // 自适应调整变异率 - double progress = static_cast(generation) / m_maxGenerations; - - // 早期探索,后期开发 - m_mutationRate = 0.2 * (1.0 - progress) + 0.05 * progress; - - // 自适应调整交叉率 - if(generation > 0) { - double improvement = m_previousBestFitness - m_bestFitness; - - if(improvement < MIN_FITNESS_IMPROVEMENT) { - // 如果改进很小,增加探索性 - m_mutationRate = qMin(0.3, m_mutationRate * 1.1); - m_crossoverRate = qMax(0.6, m_crossoverRate * 0.95); - } else { - // 如果有明显改进,增加开发性 - m_mutationRate = qMax(0.05, m_mutationRate * 0.9); - m_crossoverRate = qMin(0.9, m_crossoverRate * 1.05); - } - } -} - -void nmCalculationAutoFitGA::validateAndProtectFinalResult() -{ - if(!m_hasValidUserSolution) { - emit logMessageGenerated(tr("No initial solution for elite protection")); - return; - } - - emit logMessageGenerated(tr("=== Final Result Validation (Elite Protection) ===")); - - // 使用已有的评估结果 - double finalFitness = m_bestFitness; - double initialFitness = m_userInitialFitness; - - emit logMessageGenerated(tr("Comparing results: Initial=%1, Final=%2") - .arg(initialFitness, 0, 'e', 4).arg(finalFitness, 0, 'e', 4)); - - // 计算改进程度 - double improvement = initialFitness - finalFitness; - double relativeImprovement = improvement / qMax(1e-10, qAbs(initialFitness)); - - emit logMessageGenerated(tr("Improvement: %1 (%2%)") - .arg(improvement, 0, 'e', 4).arg(relativeImprovement * 100, 0, 'f', 2)); - - if(relativeImprovement < m_improvementThreshold) { - emit logMessageGenerated(tr("Elite protection triggered: insufficient improvement")); - emit logMessageGenerated(tr("Threshold: %1%, Actual: %2%") - .arg(m_improvementThreshold * 100, 0, 'f', 2) - .arg(relativeImprovement * 100, 0, 'f', 4)); - emit logMessageGenerated(tr("Restoring initial solution as final result")); - - m_bestFitness = initialFitness; - m_bestIndividual.genes = m_userInitialSolution; - m_bestIndividual.fitness = initialFitness; - m_bestIndividual.isEvaluated = true; - - emit logMessageGenerated(tr("Initial solution restored successfully")); - } else { - emit logMessageGenerated(tr("Final result validated - significant improvement achieved")); - } -} - -StopReasonGA nmCalculationAutoFitGA::analyzeOptimizationStatus() -{ - // 1. 检查用户停止 - if(m_shouldStop) { - return GA_USER_STOPPED; - } - - // 2. 检查连续失败 - if(m_consecutiveFailedGenerations >= m_maxConsecutiveFailures) { - return GA_CONSECUTIVE_FAILURES; - } - - // 3. 检查是否达到目标精度 - if(m_bestFitness < m_targetError) { - return GA_TARGET_ACHIEVED; - } - - // 4. 检查是否达到最大迭代数 - if(m_currentGeneration >= m_maxGenerations - 1) { - return GA_MAX_ITERATIONS; - } - - // 5. 需要足够的历史数据才能判断收敛 - if(m_convergenceHistory.size() < m_localOptimumWindow) { - return GA_CONTINUE_OPTIMIZATION; - } - - // 6. 检查真正的收敛 - if(m_convergenceHistory.size() >= m_trueConvergenceWindow && checkTrueConvergence()) { - return GA_TRUE_CONVERGENCE; - } - - // 7. 检查局部最优陷阱 - if(checkLocalOptimumTrap()) { - return GA_LOCAL_OPTIMUM; - } - - return GA_CONTINUE_OPTIMIZATION; -} - -bool nmCalculationAutoFitGA::checkTrueConvergence() const -{ - if(m_convergenceHistory.size() < m_trueConvergenceWindow) { - return false; - } - - // 1. 检查解质量 - 如果已经接近目标,小改进可能是真收敛 - bool nearTarget = (m_bestFitness < m_targetError * m_nearTargetFactor); - - // 2. 检查适应度稳定性 - 长期小幅波动 - double recentVariance = calculateFitnessVariance(10); - double recentMean = 0.0; - int windowSize = qMin(10, m_convergenceHistory.size()); - - // 计算最近窗口的均值 - for(int i = m_convergenceHistory.size() - windowSize; i < m_convergenceHistory.size(); ++i) { - recentMean += m_convergenceHistory[i]; - } - - recentMean /= windowSize; - - double relativeVariance = recentVariance / qMax(1e-10, recentMean * recentMean); - bool stableError = (relativeVariance < m_convergenceVarianceThreshold); - - // 3. 检查种群多样性 - 应该收敛到同一区域 - double currentDiversity = calculatePopulationDiversity(); - bool lowDiversity = (currentDiversity < m_diversityThreshold); - - // 4. 检查长期改进趋势 - double longTermImprovement = calculateLongTermImprovement(m_trueConvergenceWindow); - bool minimalLongTermImprovement = (longTermImprovement < 1e-4); // 0.01% - - // 真收敛的判断条件 - bool isConverged = nearTarget || - (stableError && lowDiversity && minimalLongTermImprovement); - - if(isConverged) { - DEBUG_OUT("=== TRUE CONVERGENCE ANALYSIS ==="); - DEBUG_OUT(QString("nearTarget=%1 (fitness=%2, target*factor=%3)") - .arg(nearTarget).arg(m_bestFitness, 0, 'e', 4) - .arg(m_targetError * m_nearTargetFactor, 0, 'e', 4)); - DEBUG_OUT(QString("stableError=%1 (relativeVariance=%2)") - .arg(stableError).arg(relativeVariance, 0, 'e', 6)); - DEBUG_OUT(QString("lowDiversity=%1 (diversity=%2, threshold=%3)") - .arg(lowDiversity).arg(currentDiversity, 0, 'f', 6).arg(m_diversityThreshold)); - DEBUG_OUT(QString("longTermImprovement=%1%") - .arg(longTermImprovement * 100, 0, 'f', 4)); - } - - return isConverged; -} - -bool nmCalculationAutoFitGA::checkLocalOptimumTrap() const -{ - if(m_convergenceHistory.size() < m_localOptimumWindow) { - return false; - } - - // 1. 检查解质量 - 如果距离目标还很远,停滞就可能是局部最优 - bool farFromTarget = (m_bestFitness > m_targetError * m_farTargetFactor); - - // 2. 检查短期改进 - 近期改进非常小 - double shortTermImprovement = calculateLongTermImprovement(m_localOptimumWindow); - bool poorShortTermImprovement = (shortTermImprovement < 1e-5); // 0.001% - - // 3. 检查种群多样性 - 可能过早聚集或无效分散 - double currentDiversity = calculatePopulationDiversity(); - bool problematicDiversity = (currentDiversity < m_diversityThreshold * 0.1) || - (currentDiversity > m_diversityThreshold * 5.0); - - // 4. 检查适应度方差 - 可能卡在平坦区域 - double fitnessVariance = calculateFitnessVariance(m_localOptimumWindow); - bool flatFitnessLandscape = (fitnessVariance < m_convergenceVarianceThreshold * 0.1); - - // 局部最优的判断条件 - bool isLocalOptimum = farFromTarget && poorShortTermImprovement && - (problematicDiversity || flatFitnessLandscape); - - if(isLocalOptimum) { - DEBUG_OUT("=== LOCAL OPTIMUM ANALYSIS ==="); - DEBUG_OUT(QString("farFromTarget=%1 (fitness=%2, target*factor=%3)") - .arg(farFromTarget).arg(m_bestFitness, 0, 'e', 4) - .arg(m_targetError * m_farTargetFactor, 0, 'e', 4)); - DEBUG_OUT(QString("poorShortTermImprovement=%1 (improvement=%2%)") - .arg(poorShortTermImprovement).arg(shortTermImprovement * 100, 0, 'f', 4)); - DEBUG_OUT(QString("problematicDiversity=%1 (diversity=%2)") - .arg(problematicDiversity).arg(currentDiversity, 0, 'f', 6)); - DEBUG_OUT(QString("fitnessVariance=%1") - .arg(fitnessVariance, 0, 'e', 6)); - } - - return isLocalOptimum; -} - -double nmCalculationAutoFitGA::calculatePopulationDiversity() const -{ - if(m_population.size() < 2) return 0.0; - - int dimensions = getEnabledParameterCount(); - - if(dimensions == 0) return 0.0; - - double totalDiversity = 0.0; - - for(int dim = 0; dim < dimensions; ++dim) { - // 计算该维度上所有个体的均值 - double mean = 0.0; - - for(int i = 0; i < m_population.size(); ++i) { - mean += m_population[i].genes[dim]; - } - - mean /= m_population.size(); - - // 计算该维度上的方差 - double variance = 0.0; - - for(int i = 0; i < m_population.size(); ++i) { - double diff = m_population[i].genes[dim] - mean; - variance += diff * diff; - } - - variance /= m_population.size(); - - // 归一化到参数范围 - int paramIndex = m_enabledParamIndices[dim]; - double range = m_parameterUpper[paramIndex] - m_parameterLower[paramIndex]; - double normalizedStd = sqrt(variance) / qMax(1e-10, range); - - totalDiversity += normalizedStd; - } - - return totalDiversity / dimensions; -} - -double nmCalculationAutoFitGA::calculateFitnessVariance(int windowSize) const -{ - if(m_convergenceHistory.size() < windowSize) { - return 1e10; // 数据不足,返回大值 - } - - // 计算最近windowSize次迭代的方差 - double mean = 0.0; - int startIdx = m_convergenceHistory.size() - windowSize; - - for(int i = startIdx; i < m_convergenceHistory.size(); ++i) { - mean += m_convergenceHistory[i]; - } - - mean /= windowSize; - - double variance = 0.0; - - for(int i = startIdx; i < m_convergenceHistory.size(); ++i) { - double diff = m_convergenceHistory[i] - mean; - variance += diff * diff; - } - - variance /= windowSize; - - return variance; -} - -double nmCalculationAutoFitGA::calculateLongTermImprovement(int windowSize) const -{ - if(m_convergenceHistory.size() < windowSize) { - return 1.0; // 数据不足,假设有改进 - } - - double oldFitness = m_convergenceHistory[m_convergenceHistory.size() - windowSize]; - double improvement = (oldFitness - m_bestFitness) / qMax(1e-10, qAbs(oldFitness)); - - return improvement; -} - -void nmCalculationAutoFitGA::updateConvergenceMetrics() -{ - // 更新多样性历史 - m_diversityHistory.append(calculatePopulationDiversity()); - - // 保持历史长度合理(最多保留50个数据点) - const int maxHistorySize = 50; - - while(m_diversityHistory.size() > maxHistorySize) { - m_diversityHistory.remove(0); - } -} - -// ==================== 参数应用方法 ==================== - -bool nmCalculationAutoFitGA::validateParameters(const QVector& parameters) const -{ - if(parameters.size() != getEnabledParameterCount()) { - return false; - } - - for(int i = 0; i < parameters.size(); ++i) { - if(!isFiniteNumber(parameters[i])) { - return false; - } - - // 检查参数范围 - if(i < m_enabledParamIndices.size()) { - int paramIndex = m_enabledParamIndices[i]; - - if(paramIndex >= 0 && paramIndex < m_parameterLower.size()) { - if(parameters[i] < m_parameterLower[paramIndex] || - parameters[i] > m_parameterUpper[paramIndex]) { - return false; - } - } - } - } - - // 直接拦截会导致求解器数值崩溃的参数值 - for(int i = 0; i < parameters.size() && i < m_enabledParamIndices.size(); ++i) { - int paramIndex = m_enabledParamIndices[i]; - double value = parameters[i]; - - switch(paramIndex) { - case 0: // 渗透率:必须大于零 - if(value <= 1e-8) { - DEBUG_OUT(QString("Rejecting near-zero permeability: %1").arg(value)); - return false; - } - - break; - - case 2: // 井筒储集系数:必须大于零 - if(value <= 1e-10) { - DEBUG_OUT(QString("Rejecting near-zero wellbore storage: %1").arg(value)); - return false; - } - - break; - - case 3: // 孔隙度:必须在合理范围 - if(value <= 1e-6 || value >= 0.99) { - DEBUG_OUT(QString("Rejecting unrealistic porosity: %1").arg(value)); - return false; - } - - break; - - case 5: // 综合压缩系数:必须大于零 - if(value <= 1e-8) { - DEBUG_OUT(QString("Rejecting near-zero total compressibility: %1").arg(value)); - return false; - } - - break; - } - } - - return true; -} - -bool nmCalculationAutoFitGA::validateLogLogData(const QVector>& logLogData) const -{ - // 检查基本结构 - if(logLogData.size() < 3) { - DEBUG_OUT("LogLog data has less than 3 arrays"); - return false; - } - - // 检查数组大小一致性 - int size = logLogData[0].size(); - - if(size == 0) { - DEBUG_OUT("Empty LogLog data"); - return false; - } - - if(logLogData[1].size() != size || logLogData[2].size() != size) { - DEBUG_OUT(QString("LogLog data size mismatch: X=%1, Y1=%2, Y2=%3") - .arg(logLogData[0].size()) - .arg(logLogData[1].size()) - .arg(logLogData[2].size())); - return false; - } - - // 检查最小数据点数 - if(size < 5) { - DEBUG_OUT(QString("Too few LogLog data points: %1").arg(size)); - return false; - } - - // 数据有效性检查 - for(int i = 0; i < size; ++i) { - if(!isFiniteNumber(logLogData[0][i]) || - !isFiniteNumber(logLogData[1][i]) || - !isFiniteNumber(logLogData[2][i])) { - DEBUG_OUT(QString("Invalid LogLog data at index %1").arg(i)); - return false; - } - } - - return true; -} - -bool nmCalculationAutoFitGA::validateInitialValues() const -{ - if(m_initialValues.size() != m_enabledParamIndices.size()) { - DEBUG_OUT("Initial values count mismatch with enabled parameters"); - return false; - } - - bool allValid = true; - - for(int i = 0; i < m_initialValues.size(); ++i) { - int paramIndex = m_enabledParamIndices[i]; - double value = m_initialValues[i]; - - if(!isFiniteNumber(value)) { - DEBUG_OUT(QString("Initial value[%1] is not finite: %2").arg(i).arg(value)); - allValid = false; - continue; - } - - if(paramIndex < m_parameterLower.size() && paramIndex < m_parameterUpper.size()) { - double minVal = m_parameterLower[paramIndex]; - double maxVal = m_parameterUpper[paramIndex]; - - if(value < minVal || value > maxVal) { - DEBUG_OUT(QString("Initial value[%1] = %2 is outside bounds [%3, %4]") - .arg(i).arg(value).arg(minVal).arg(maxVal)); - allValid = false; - } - } - } - - return allValid; -} - -void nmCalculationAutoFitGA::applyParametersToDataManager(const QVector& parameters) -{ - if(parameters.size() != getEnabledParameterCount()) { - return; - } - - updateReservoirParameters(parameters); - updateWellParameters(parameters); -} - -void nmCalculationAutoFitGA::updateReservoirParameters(const QVector& parameters) -{ - nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); - nmDataReservoir reservoirData = dataManager->getReservoirDataCopy(); - - int paramIndex = 0; - for(int i = 0; i < m_parameterSelected.size(); ++i) { - if(m_parameterSelected[i] && paramIndex < parameters.size()) { - double value = parameters[paramIndex]; - - switch(i) { - case 0: // 渗透率 - reservoirData.getPermeability().setValue(value); - break; - case 3: // 孔隙度 - reservoirData.getPorosity().setValue(value); - break; - case 4: // 储层厚度 - reservoirData.getThickness().setValue(value); - break; - case 5: // 综合压缩系数 - reservoirData.getCt().setValue(value); - break; - case 6: // 岩石压缩系数 - reservoirData.getCf().setValue(value); - break; - case 7: // 初始含水饱和度 - reservoirData.getSwi().setValue(value); - break; - } - paramIndex++; - } - } - - // 更新数据管理器 - dataManager->updateReservoirData(reservoirData); -} - -void nmCalculationAutoFitGA::updateWellParameters(const QVector& parameters) -{ - nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); - - // 获取井列表,更新第一口井的参数 - //QVector wells = dataManager->getWellDataList(); - nmDataWellBase* pWell = dataManager->findWellByName(m_targetWellName); - if(!pWell) return; - - //nmDataWellBase* pWell = wells[0]; // 使用第一口井 - - int paramIndex = 0; - for(int i = 0; i < m_parameterSelected.size(); ++i) { - if(m_parameterSelected[i] && paramIndex < parameters.size()) { - double value = parameters[paramIndex]; - - switch(i) { - case 1: { // 表皮系数 - nmDataAttribute skinAttr = pWell->getPerforation(0)->getSkin(); - skinAttr.setValue(value); - pWell->setRateDependentSkin(skinAttr); - } - break; - case 2: { // 井筒储集系数 - nmDataAttribute wellboreAttr = pWell->getWellboreStorage(); - wellboreAttr.setValue(value); - pWell->setWellboreStorage(wellboreAttr); - } - break; - } - paramIndex++; - } - } - - // 根据井类型更新到数据管理器 - updateWellToDataManager(pWell); -} - -void nmCalculationAutoFitGA::updateWellToDataManager(nmDataWellBase* pWell) -{ - if(!pWell) return; - - nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); - NM_WELL_MODEL wellType = pWell->getWellType(); - - switch(wellType) { - case NM_WELL_MODEL::Vertical_Well: { - nmDataVerticalWell* pVerticalWell = dynamic_cast(pWell); - if(pVerticalWell) { - QVector wells; - wells.append(*pVerticalWell); - dataManager->updateVerticalWells(wells); - } - break; - } - case NM_WELL_MODEL::Vertical_Fractured_Well: { - nmDataVerticalFracturedWell* pVFracturedWell = dynamic_cast(pWell); - if(pVFracturedWell) { - QVector wells; - wells.append(*pVFracturedWell); - dataManager->updateVerticalFracturedWells(wells); - } - break; - } - case NM_WELL_MODEL::Horizontal_Fractured_Well: { - nmDataHorizontalFracturedWell* pHFracturedWell = dynamic_cast(pWell); - if(pHFracturedWell) { - QVector wells; - wells.append(*pHFracturedWell); - dataManager->updateHorizontalFracturedWells(wells); - } - break; - } - default: - break; - } -} - -void nmCalculationAutoFitGA::clampToLimits(QVector& parameters) const -{ - for(int i = 0; i < parameters.size() && i < m_enabledParamIndices.size(); ++i) { - int paramIndex = m_enabledParamIndices[i]; - if(paramIndex >= 0 && paramIndex < m_parameterLower.size()) { - parameters[i] = qMax(m_parameterLower[paramIndex], - qMin(m_parameterUpper[paramIndex], parameters[i])); - } - } -} - -// ==================== 求解器相关方法 ==================== - -QVector> nmCalculationAutoFitGA::runSolver() -{ - //return runSolverExe(); - return runSolverDll(); -} - -bool nmCalculationAutoFitGA::validateSolverResult(const QVector>& result) const -{ - // 基本检查 - if(result.size() < 2) { - DEBUG_OUT("Solver result has less than 2 arrays"); - return false; - } - - if(result[0].size() != result[1].size()) { - DEBUG_OUT(QString("Size mismatch: X=%1, Y=%2").arg(result[0].size()).arg(result[1].size())); - return false; - } - - if(result[0].size() == 0) { - DEBUG_OUT("Empty solver result"); - return false; - } - - // 检查最小数据点数 - if(result[0].size() < 10) { - DEBUG_OUT(QString("Too few data points: %1").arg(result[0].size())); - return false; - } - - // 数据有效性检查 - for(int i = 0; i < result[0].size(); ++i) { - if(!isFiniteNumber(result[0][i]) || !isFiniteNumber(result[1][i])) { - DEBUG_OUT(QString("Invalid data at index %1: X=%2, Y=%3") - .arg(i).arg(result[0][i]).arg(result[1][i])); - return false; - } - } - - return true; -} - -QVector> nmCalculationAutoFitGA::runSolverDll() -{ - DEBUG_OUT("SOLVER DLL START"); - - if(m_evaluationInProgress > 0) { - DEBUG_OUT("DLL Solver already running, skipping"); - return QVector>(); - } - - ++m_evaluationInProgress; - QVector> result; - nmCalculationDllPebiSolverTask* dllTask = nullptr; - - try { - DEBUG_OUT("Creating DLL solver task"); - dllTask = new nmCalculationDllPebiSolverTask(m_tempDirectory); - - if(m_shouldStop) { - DEBUG_OUT("Should stop - cleaning up and returning empty result"); - delete dllTask; - --m_evaluationInProgress; - return result; - } - - DEBUG_OUT("Starting DLL solver execution..."); - - // 异步执行 - dllTask->start(); - - // 等待完成 - int waitTime = 0; - const int maxWait = 30000; // 30秒超时 - const int checkInterval = 500; - - while(waitTime < maxWait) { - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 100); - - if(!dllTask->isRunning()) { - DEBUG_OUT("DLL solver task completed"); - break; - } - - if(m_shouldStop) { - DEBUG_OUT("DLL solver task terminated by user"); - dllTask->terminate(); - break; - } - - msleep(checkInterval); - waitTime += checkInterval; - } - - // 超时处理 - if(dllTask->isRunning()) { - DEBUG_OUT("DLL solver task timeout, terminating..."); - dllTask->terminate(); - dllTask->wait(2000); - - delete dllTask; - dllTask = nullptr; - --m_evaluationInProgress; - m_consecutiveFailures++; - return result; - } - - // 验证结果数据是否已更新 - nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); - //QVector wells = dataManager->getWellDataList(); - nmDataWellBase* pTargetWell = dataManager->findWellByName(m_targetWellName); - - if(!pTargetWell) { - DEBUG_OUT("No wells found in data manager after DLL execution"); - delete dllTask; - --m_evaluationInProgress; - return result; - } - - // 验证结果数据 - QVector> pressureResult = pTargetWell->getResultPressure(); - QVector> logLogResult = pTargetWell->getResultLogLog(); - - DEBUG_OUT(QString("DLL result verification - Pressure arrays: %1, LogLog arrays: %2") - .arg(pressureResult.size()).arg(logLogResult.size())); - - if(pressureResult.size() >= 2) { - DEBUG_OUT(QString("Pressure result - Time points: %1, Pressure points: %2") - .arg(pressureResult[0].size()).arg(pressureResult[1].size())); - - if(pressureResult[0].size() > 0) { - DEBUG_OUT(QString("Sample pressure data - Time[0]: %1, Time[last]: %2, P[0]: %3, P[last]: %4") - .arg(pressureResult[0][0]) - .arg(pressureResult[0][pressureResult[0].size()-1]) - .arg(pressureResult[1][0]) - .arg(pressureResult[1][pressureResult[1].size()-1])); - } - } - - // 数据有效性检查 - if(pressureResult.size() >= 2 && pressureResult[0].size() > 0 && pressureResult[1].size() > 0) { - result = pressureResult; - DEBUG_OUT(QString("Got DLL solver result: %1 points").arg(result[0].size())); - m_consecutiveFailures = 0; - - // 检查结果是否与之前不同 - static QVector lastPressureResult; - bool isDifferentFromLast = false; - - if(lastPressureResult.isEmpty() || lastPressureResult.size() != pressureResult[1].size()) { - isDifferentFromLast = true; - } else { - for(int i = 0; i < qMin(5, pressureResult[1].size()); ++i) { - if(qAbs(lastPressureResult[i] - pressureResult[1][i]) > 1e-12) { - isDifferentFromLast = true; - break; - } - } - } - - if(isDifferentFromLast) { - DEBUG_OUT("RESULT VERIFICATION: Got NEW result data from DLL"); - lastPressureResult = pressureResult[1]; - } else { - DEBUG_OUT("!!! WARNING: Result data appears to be identical to previous run !!!"); - } - - } else { - DEBUG_OUT("DLL solver result is empty or invalid"); - DEBUG_OUT(QString("Pressure result size: %1, Array sizes: %2, %3") - .arg(pressureResult.size()) - .arg(pressureResult.size() > 0 ? pressureResult[0].size() : 0) - .arg(pressureResult.size() > 1 ? pressureResult[1].size() : 0)); - m_consecutiveFailures++; - } - - } catch(const std::bad_alloc& e) { - DEBUG_OUT(QString("Memory allocation failed in DLL solver: %1").arg(e.what())); - m_consecutiveFailures++; - } catch(const std::exception& e) { - DEBUG_OUT(QString("Exception in DLL solver: %1").arg(e.what())); - m_consecutiveFailures++; - } catch(...) { - DEBUG_OUT("Unknown exception in DLL solver"); - m_consecutiveFailures++; - } - - // 清理DLL任务 - if(dllTask) { - if(dllTask->isRunning()) { - dllTask->terminate(); - dllTask->wait(3000); - } - - DEBUG_OUT("Cleaning up DLL solver task..."); - delete dllTask; - dllTask = nullptr; - } - - QApplication::processEvents(QEventLoop::AllEvents, 100); - --m_evaluationInProgress; - - DEBUG_OUT(QString("SOLVER DLL END - ResultPoints: %1") - .arg(result.isEmpty() ? 0 : result[0].size())); - - return result; -} - -//QVector> nmCalculationAutoFitGA::runSolverExe() -//{ -// DEBUG_OUT("SOLVER EXE START"); -// -// if(m_evaluationInProgress > 0) { -// DEBUG_OUT("EXE Solver already running, skipping"); -// return QVector>(); -// } -// -// ++m_evaluationInProgress; -// QVector> result; -// nmCalculationExeSolverTask* exeTask = nullptr; -// -// try { -// DEBUG_OUT("Creating EXE solver task"); -// exeTask = new nmCalculationExeSolverTask(QString()); -// -// if(m_shouldStop) { -// DEBUG_OUT("Should stop - cleaning up and returning empty result"); -// delete exeTask; -// --m_evaluationInProgress; -// return result; -// } -// -// DEBUG_OUT("Starting EXE solver execution..."); -// -// // 启动 -// bool executeSuccess = exeTask->execute(); -// -// // 检查执行状态 -// if(!executeSuccess) { -// DEBUG_OUT(QString("EXE solver execution failed: %1").arg(exeTask->getLastError())); -// DEBUG_OUT(QString("EXE solver exit code: %1").arg(exeTask->getExitCode())); -// -// // 清理并返回空结果 -// delete exeTask; -// exeTask = nullptr; -// --m_evaluationInProgress; -// m_consecutiveFailures++; -// return result; -// } -// -// DEBUG_OUT("EXE solver execution completed successfully"); -// -// // 验证结果数据是否已更新 -// nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); -// QVector wells = dataManager->getWellDataList(); -// -// if(wells.isEmpty()) { -// DEBUG_OUT("No wells found in data manager after EXE execution"); -// delete exeTask; -// --m_evaluationInProgress; -// return result; -// } -// -// // 验证结果数据的时间戳或唯一性 -// QVector> pressureResult = wells[0]->getResultPressure(); -// QVector> logLogResult = wells[0]->getResultLogLog(); -// -// DEBUG_OUT(QString("Raw result verification - Pressure arrays: %1, LogLog arrays: %2") -// .arg(pressureResult.size()).arg(logLogResult.size())); -// -// if(pressureResult.size() >= 2) { -// DEBUG_OUT(QString("Pressure result - Time points: %1, Pressure points: %2") -// .arg(pressureResult[0].size()).arg(pressureResult[1].size())); -// -// if(pressureResult[0].size() > 0) { -// DEBUG_OUT(QString("Sample pressure data - Time[0]: %1, Time[last]: %2, P[0]: %3, P[last]: %4") -// .arg(pressureResult[0][0]) -// .arg(pressureResult[0][pressureResult[0].size() - 1]) -// .arg(pressureResult[1][0]) -// .arg(pressureResult[1][pressureResult[1].size() - 1])); -// } -// } -// -// if(logLogResult.size() >= 3) { -// DEBUG_OUT(QString("LogLog result - X points: %1, Y1 points: %2, Y2 points: %3") -// .arg(logLogResult[0].size()).arg(logLogResult[1].size()).arg(logLogResult[2].size())); -// -// if(logLogResult[0].size() > 0) { -// DEBUG_OUT(QString("Sample LogLog data - X[0]: %1, X[last]: %2, Y1[0]: %3, Y2[0]: %4") -// .arg(logLogResult[0][0]) -// .arg(logLogResult[0][logLogResult[0].size() - 1]) -// .arg(logLogResult[1][0]) -// .arg(logLogResult[2][0])); -// } -// } -// -// // 数据有效性检查 -// if(pressureResult.size() >= 2 && pressureResult[0].size() > 0 && pressureResult[1].size() > 0) { -// result = pressureResult; -// DEBUG_OUT(QString("Got EXE solver result: %1 points").arg(result[0].size())); -// m_consecutiveFailures = 0; -// -// // 检查结果是否与之前不同 -// static QVector lastPressureResult; -// bool isDifferentFromLast = false; -// -// if(lastPressureResult.isEmpty() || lastPressureResult.size() != pressureResult[1].size()) { -// isDifferentFromLast = true; -// } else { -// for(int i = 0; i < qMin(5, pressureResult[1].size()); ++i) { -// if(qAbs(lastPressureResult[i] - pressureResult[1][i]) > 1e-12) { -// isDifferentFromLast = true; -// break; -// } -// } -// } -// -// if(isDifferentFromLast) { -// DEBUG_OUT("RESULT VERIFICATION: Got NEW result data from EXE"); -// lastPressureResult = pressureResult[1]; -// } else { -// DEBUG_OUT("!!! WARNING: Result data appears to be identical to previous run !!!"); -// } -// -// } else { -// DEBUG_OUT("EXE solver result is empty or invalid"); -// DEBUG_OUT(QString("Pressure result size: %1, Array sizes: %2, %3") -// .arg(pressureResult.size()) -// .arg(pressureResult.size() > 0 ? pressureResult[0].size() : 0) -// .arg(pressureResult.size() > 1 ? pressureResult[1].size() : 0)); -// m_consecutiveFailures++; -// } -// -// } catch(const std::exception& e) { -// DEBUG_OUT(QString("Exception in EXE solver: %1").arg(e.what())); -// m_consecutiveFailures++; -// } catch(...) { -// DEBUG_OUT("Unknown exception in EXE solver"); -// m_consecutiveFailures++; -// } -// -// // 清理EXE任务 -// if(exeTask) { -// DEBUG_OUT("Cleaning up EXE solver task..."); -// delete exeTask; -// exeTask = nullptr; -// } -// -// QApplication::processEvents(QEventLoop::AllEvents, 100); -// --m_evaluationInProgress; -// -// DEBUG_OUT(QString("SOLVER EXE END - ResultPoints: %1") -// .arg(result.isEmpty() ? 0 : result[0].size())); -// -// return result; -//} - -// ==================== 数据处理方法 ==================== -QVector nmCalculationAutoFitGA::interpolateData( - const QVector& source, const QVector& targetX) const -{ - QVector result; - - if(source.isEmpty() || targetX.isEmpty()) { - DEBUG_OUT("Warning: Empty data in interpolation"); - return result; - } - - // 数据清理和验证合并 - QVector validSource; - const double MAX_REASONABLE_VALUE = 1e12; - - for(int i = 0; i < source.size(); ++i) { - const QPointF& point = source[i]; - - // 检查数值有效性 - if(!isFiniteNumber(point.x()) || !isFiniteNumber(point.y())) { - DEBUG_OUT(QString("Skipping invalid data point at index %1: X=%2, Y=%3") - .arg(i).arg(point.x()).arg(point.y())); - continue; - } - - // 检查极大值 - 跳过而不是失败 - if(qAbs(point.y()) > MAX_REASONABLE_VALUE) { - DEBUG_OUT(QString("Skipping extremely large Y value at index %1: %2") - .arg(i).arg(point.y())); - continue; - } - - // 只保留有效的数据点 - validSource.append(point); - } - - // 检查清理后的数据是否足够 - if(validSource.size() < 3) { - DEBUG_OUT(QString("Insufficient valid data points after cleaning: %1") - .arg(validSource.size())); - return result; // 返回空结果,但不算失败 - } - - DEBUG_OUT(QString("Data cleaning: %1 -> %2 valid points") - .arg(source.size()).arg(validSource.size())); - - // 对清理后的数据进行排序 - QVector sortedSource = validSource; - - for(int i = 0; i < sortedSource.size() - 1; ++i) { - for(int j = 0; j < sortedSource.size() - 1 - i; ++j) { - if(sortedSource[j].x() > sortedSource[j + 1].x()) { - QPointF temp = sortedSource[j]; - sortedSource[j] = sortedSource[j + 1]; - sortedSource[j + 1] = temp; - } - } - } - - double sourceMinX = sortedSource.first().x(); - double sourceMaxX = sortedSource.last().x(); - - double targetMinX = targetX[0]; - double targetMaxX = targetX[0]; - - for(int i = 1; i < targetX.size(); ++i) { - if(targetX[i] < targetMinX) targetMinX = targetX[i]; - - if(targetX[i] > targetMaxX) targetMaxX = targetX[i]; - } - - DEBUG_OUT(QString("Source X range: [%1, %2], Target X range: [%3, %4]") - .arg(sourceMinX).arg(sourceMaxX).arg(targetMinX).arg(targetMaxX)); - - // 安全插值算法 - for(int i = 0; i < targetX.size(); ++i) { - double x = targetX[i]; - - if(!isFiniteNumber(x)) continue; - - double y = 0.0; - - // 插值逻辑(保持原有逻辑,但使用sortedSource) - if(x <= sourceMinX) { - if(sortedSource.size() >= 2) { - double dx = sortedSource[1].x() - sortedSource[0].x(); - - if(qAbs(dx) > 1e-10) { - double slope = (sortedSource[1].y() - sortedSource[0].y()) / dx; - slope = qMax(-1e6, qMin(1e6, slope)); - y = sortedSource[0].y() + slope * (x - sortedSource[0].x()); - } else { - y = sortedSource[0].y(); - } - } else { - y = sortedSource[0].y(); - } - } else if(x >= sourceMaxX) { - if(sortedSource.size() >= 2) { - int lastIdx = sortedSource.size() - 1; - double dx = sortedSource[lastIdx].x() - sortedSource[lastIdx - 1].x(); - - if(qAbs(dx) > 1e-10) { - double slope = (sortedSource[lastIdx].y() - sortedSource[lastIdx - 1].y()) / dx; - slope = qMax(-1e6, qMin(1e6, slope)); - y = sortedSource[lastIdx].y() + slope * (x - sortedSource[lastIdx].x()); - } else { - y = sortedSource[lastIdx].y(); - } - } else { - y = sortedSource.last().y(); - } - } else { - // 内插 - bool found = false; - - for(int j = 0; j < sortedSource.size() - 1; ++j) { - if(x >= sortedSource[j].x() && x <= sortedSource[j + 1].x()) { - double dx = sortedSource[j + 1].x() - sortedSource[j].x(); - - if(qAbs(dx) > 1e-10) { - double ratio = (x - sortedSource[j].x()) / dx; - y = sortedSource[j].y() + ratio * (sortedSource[j + 1].y() - sortedSource[j].y()); - } else { - y = sortedSource[j].y(); - } - - found = true; - break; - } - } - - if(!found) { - // 使用最近点 - double minDist = 1e10; - - for(int k = 0; k < sortedSource.size(); ++k) { - double dist = qAbs(sortedSource[k].x() - x); - - if(dist < minDist) { - minDist = dist; - y = sortedSource[k].y(); - } - } - } - } - - // 最终数值检查 - if(!isFiniteNumber(y)) { - y = sortedSource.size() > 0 ? sortedSource[0].y() : 1.0; - } - - y = qMax(-1e12, qMin(1e12, y)); - - result.append(QPointF(x, y)); - } - - if(result.isEmpty()) { - DEBUG_OUT("LogLog interpolation failed"); - return result; - } - - DEBUG_OUT(QString("Interpolation completed: %1 -> %2 points") - .arg(validSource.size()).arg(result.size())); - - return result; -} - -double nmCalculationAutoFitGA::calculateLogLogCurveError( - const QVector>& target, - const QVector>& result) const -{ - // 验证数据 - if(!validateLogLogData(target) || !validateLogLogData(result)) { - return 1e10; - } - - try { - // 数据对齐:找到X值的重叠区域 - double targetMinX = target[0][0]; - double targetMaxX = target[0][0]; - - for(int i = 1; i < target[0].size(); ++i) { - if(target[0][i] < targetMinX) targetMinX = target[0][i]; - - if(target[0][i] > targetMaxX) targetMaxX = target[0][i]; - } - - double resultMinX = result[0][0]; - double resultMaxX = result[0][0]; - - for(int i = 1; i < result[0].size(); ++i) { - if(result[0][i] < resultMinX) resultMinX = result[0][i]; - - if(result[0][i] > resultMaxX) resultMaxX = result[0][i]; - } - - double overlapMinX = qMax(targetMinX, resultMinX); - double overlapMaxX = qMin(targetMaxX, resultMaxX); - - if(overlapMinX >= overlapMaxX) { - DEBUG_OUT("No overlap between target and result LogLog curves"); - return 1e10; - } - - // 生成公共X网格进行插值 - QVector commonX; - int numPoints = 50; - - if(overlapMinX > 0 && overlapMaxX > 0) { - // 对数空间均匀分布 - double logMin = qLn(overlapMinX); - double logMax = qLn(overlapMaxX); - - for(int i = 0; i < numPoints; ++i) { - double logX = logMin + i * (logMax - logMin) / (numPoints - 1); - double x = qExp(logX); - - // 数值保护 - if(!isFiniteNumber(x) || x <= 0) { - continue; - } - - commonX.append(x); - } - - DEBUG_OUT("Using log-uniform grid for better early-time coverage"); - } - - if(commonX.isEmpty()) { - DEBUG_OUT("Failed to generate common X grid"); - return 1e10; - } - - // 插值目标曲线 - QVector targetCurve1, targetCurve2; - - for(int i = 0; i < target[0].size(); ++i) { - // 检查数据有效性 - if(isFiniteNumber(target[0][i]) && isFiniteNumber(target[1][i]) && - isFiniteNumber(target[2][i])) { - targetCurve1.append(QPointF(target[0][i], target[1][i])); - targetCurve2.append(QPointF(target[0][i], target[2][i])); - } - } - - if(targetCurve1.isEmpty() || targetCurve2.isEmpty()) { - DEBUG_OUT("Target curves are empty after filtering"); - return 1e10; - } - - QVector alignedTarget1 = interpolateData(targetCurve1, commonX); - QVector alignedTarget2 = interpolateData(targetCurve2, commonX); - - // 插值结果曲线 - QVector resultCurve1, resultCurve2; - - for(int i = 0; i < result[0].size(); ++i) { - // 检查数据有效性 - if(isFiniteNumber(result[0][i]) && isFiniteNumber(result[1][i]) && - isFiniteNumber(result[2][i])) { - resultCurve1.append(QPointF(result[0][i], result[1][i])); - resultCurve2.append(QPointF(result[0][i], result[2][i])); - } - } - - if(resultCurve1.isEmpty() || resultCurve2.isEmpty()) { - DEBUG_OUT("Result curves are empty after filtering"); - return 1e10; - } - - QVector alignedResult1 = interpolateData(resultCurve1, commonX); - QVector alignedResult2 = interpolateData(resultCurve2, commonX); - - // 检查插值结果 - if(alignedTarget1.isEmpty() || alignedTarget2.isEmpty() || - alignedResult1.isEmpty() || alignedResult2.isEmpty()) { - DEBUG_OUT("LogLog interpolation failed"); - return 1e10; - } - - if(alignedTarget1.size() != alignedResult1.size() || - alignedTarget2.size() != alignedResult2.size()) { - DEBUG_OUT("LogLog interpolation size mismatch"); - return 1e10; - } - - // 计算两条曲线的误差 - double error1 = calculateCurveError(alignedTarget1, alignedResult1); - double error2 = calculateCurveError(alignedTarget2, alignedResult2); - - // 检查个别误差是否有效 - if(!isFiniteNumber(error1) || error1 > 1e9) { - DEBUG_OUT(QString("Curve1 error is invalid: %1").arg(error1)); - error1 = 1e10; - } - - if(!isFiniteNumber(error2) || error2 > 1e9) { - DEBUG_OUT(QString("Curve2 error is invalid: %1").arg(error2)); - error2 = 1e10; - } - - // 组合误差 - 添加保护 - double combinedError; - - if(error1 > 1e9 && error2 > 1e9) { - combinedError = 1e10; - } else if(error1 > 1e9) { - combinedError = error2; - } else if(error2 > 1e9) { - combinedError = error1; - } else { - combinedError = 0.5 * error1 + 0.5 * error2; - } - - DEBUG_OUT(QString("LogLog errors: Curve1=%1, Curve2=%2, Combined=%3") - .arg(error1, 0, 'e', 4).arg(error2, 0, 'e', 4).arg(combinedError, 0, 'e', 4)); - - return qMin(1e9, combinedError); - - } catch(const std::exception& e) { - DEBUG_OUT(QString("Exception in LogLog error calculation: %1").arg(e.what())); - return 1e10; - } catch(...) { - DEBUG_OUT("Unknown exception in LogLog error calculation"); - return 1e10; - } -} - -double nmCalculationAutoFitGA::calculateCurveError( - const QVector& curve1, const QVector& curve2) const -{ - if(curve1.size() != curve2.size() || curve1.isEmpty()) { - return 1e10; - } - - // 预检查:确保没有无穷大值 - for(int i = 0; i < curve1.size(); ++i) { - if(!isFiniteNumber(curve1[i].y()) || !isFiniteNumber(curve2[i].y())) { - DEBUG_OUT(QString("Infinite value detected at index %1: Y1=%2, Y2=%3") - .arg(i).arg(curve1[i].y()).arg(curve2[i].y())); - return 1e10; - } - - if(qAbs(curve1[i].y()) > 1e12 || qAbs(curve2[i].y()) > 1e12) { - DEBUG_OUT(QString("Extremely large value detected at index %1") - .arg(i)); - return 1e10; - } - } - - double totalError = 0.0; - double totalWeight = 0.0; - int validPoints = 0; - - for(int i = 0; i < curve1.size(); ++i) { - double y1 = curve1[i].y(); - double y2 = curve2[i].y(); - - // 跳过异常值 - if(!isFiniteNumber(y1) || !isFiniteNumber(y2)) { - continue; - } - - // 自适应权重:根据Y值大小调整,添加上限 - double weightFactor = qMin(100.0, qAbs(y1) * 0.01); - double weight = 1.0 / (1.0 + weightFactor); - - // 相对误差和绝对误差的组合 - double yMax = qMax(qAbs(y1), qAbs(y2)); - yMax = qMax(1e-12, yMax); // 防止除零 - - double relativeError = qAbs(y1 - y2) / yMax; - double absoluteError = qAbs(y1 - y2); - - // 限制误差值 - relativeError = qMin(1e6, relativeError); - absoluteError = qMin(1e6, absoluteError); - - // 误差组合:相对误差为主,绝对误差为辅 - double pointError = 0.7 * relativeError + 0.3 * absoluteError; - - if(isFiniteNumber(pointError) && pointError < 1e10) { - totalError += weight * pointError * pointError; - totalWeight += weight; - validPoints++; - } - } - - if(totalWeight > 0 && validPoints > 0) { - double result = sqrt(totalError / totalWeight); - - // 最终检查 - if(!isFiniteNumber(result)) { - DEBUG_OUT("Final error calculation produced infinite result"); - return 1e10; - } - - return qMin(1e9, result); // 限制最大误差值 - } else { - DEBUG_OUT(QString("No valid points for error calculation: validPoints=%1") - .arg(validPoints)); - return 1e10; - } -} -// ==================== 工具方法 ==================== - -double nmCalculationAutoFitGA::random01() const -{ - return static_cast(qrand()) / RAND_MAX; -} - -double nmCalculationAutoFitGA::gaussianRandom(double mean, double stddev) const -{ - static bool hasSpare = false; - static double spare; - - if(hasSpare) { - hasSpare = false; - return spare * stddev + mean; - } - - hasSpare = true; - double u = qMax(random01(), 1e-12); - double v = random01(); - double mag = stddev * sqrt(-2.0 * log(u)); - spare = mag * cos(2.0 * 3.14159265359 * v); - - return mag * sin(2.0 * 3.14159265359 * v) + mean; -} - -int nmCalculationAutoFitGA::getEnabledParameterCount() const -{ - int count = 0; - - for(int i = 0; i < m_parameterSelected.size(); ++i) { - if(m_parameterSelected[i]) count++; - } - - return count; -} - -void nmCalculationAutoFitGA::saveOptimizationResult() -{ - DEBUG_OUT(QString("GA optimization result: fitness=%1, evaluations=%2/%3") - .arg(m_bestFitness, 0, 'e', 4) - .arg(m_successfulEvaluations) - .arg(m_totalEvaluations)); -} diff --git a/Src/nmNum/nmData/nmDataAutomaticFitting.cpp b/Src/nmNum/nmData/nmDataAutomaticFitting.cpp index a4876ed..4d3b6d8 100644 --- a/Src/nmNum/nmData/nmDataAutomaticFitting.cpp +++ b/Src/nmNum/nmData/nmDataAutomaticFitting.cpp @@ -12,25 +12,24 @@ nmDataAutomaticFitting::nmDataAutomaticFitting() m_cfSelected = false; // 默认不选中 m_swiSelected = false; // 默认不选中 - // 初始化参数最大值 - m_permeabilityMax = nmDataAttribute("Permeability Max", 10.0, "Darcy"); // 1000 mD - m_skinMax = nmDataAttribute("Skin Max", 10.0, ""); // 100 - m_wellboreStorageMax = nmDataAttribute("Wellbore Storage Max", 2.0, "m^3/MPa"); - m_porosityMax = nmDataAttribute("Porosity Max", 0.5, ""); // 50% - m_thicknessMax = nmDataAttribute("Thickness Max", 50.0, "m"); - m_ctMax = nmDataAttribute("Ct Max", 0.1, ""); // 1/MPa - m_cfMax = nmDataAttribute("Cf Max", 0.01, ""); // 1/MPa - m_swiMax = nmDataAttribute("Swi Max", 1.0, ""); - - // 初始化参数最小值 - m_permeabilityMin = nmDataAttribute("Permeability Min", 0.001, "Darcy"); // 0.001 mD - m_skinMin = nmDataAttribute("Skin Min", -10.0, ""); // 允许负表皮 - m_wellboreStorageMin = nmDataAttribute("Wellbore Storage Min", 1e-4, "m^3/MPa"); - m_porosityMin = nmDataAttribute("Porosity Min", 0.01, ""); // 1% - m_thicknessMin = nmDataAttribute("Thickness Min", 2.0, "m"); - m_ctMin = nmDataAttribute("Ct Min", 1e-3, ""); // 小正值 - m_cfMin = nmDataAttribute("Cf Min", 1e-5, ""); // 小正值 - m_swiMin = nmDataAttribute("Swi Min", 0.0, ""); + // 拟合上下界不再使用固定默认值,由自动拟合窗口按数据对象初值和物理边界生成。 + m_permeabilityMax = nmDataAttribute("Permeability Max", QVariant(), "Darcy"); + m_skinMax = nmDataAttribute("Skin Max", QVariant(), ""); + m_wellboreStorageMax = nmDataAttribute("Wellbore Storage Max", QVariant(), "m^3/MPa"); + m_porosityMax = nmDataAttribute("Porosity Max", QVariant(), ""); + m_thicknessMax = nmDataAttribute("Thickness Max", QVariant(), "m"); + m_ctMax = nmDataAttribute("Ct Max", QVariant(), ""); + m_cfMax = nmDataAttribute("Cf Max", QVariant(), ""); + m_swiMax = nmDataAttribute("Swi Max", QVariant(), ""); + + m_permeabilityMin = nmDataAttribute("Permeability Min", QVariant(), "Darcy"); + m_skinMin = nmDataAttribute("Skin Min", QVariant(), ""); + m_wellboreStorageMin = nmDataAttribute("Wellbore Storage Min", QVariant(), "m^3/MPa"); + m_porosityMin = nmDataAttribute("Porosity Min", QVariant(), ""); + m_thicknessMin = nmDataAttribute("Thickness Min", QVariant(), "m"); + m_ctMin = nmDataAttribute("Ct Min", QVariant(), ""); + m_cfMin = nmDataAttribute("Cf Min", QVariant(), ""); + m_swiMin = nmDataAttribute("Swi Min", QVariant(), ""); // 初始化迭代参数 m_iterationCount = nmDataAttribute("Iteration Count", 20, ""); diff --git a/Src/nmNum/nmSubWxs/nmWxAutomaticFitting.cpp b/Src/nmNum/nmSubWxs/nmWxAutomaticFitting.cpp index 202d14c..f0f243e 100644 --- a/Src/nmNum/nmSubWxs/nmWxAutomaticFitting.cpp +++ b/Src/nmNum/nmSubWxs/nmWxAutomaticFitting.cpp @@ -4,6 +4,9 @@ #include "nmWxParameterProperty.h" #include "nmDataAnalyzeManager.h" #include "iSubWndFitting.h" +#include "iSysParaHelper.h" +#include "iParameter.h" +#include "mModuleDefines.h" #include "mGui/mGuiAnal/iAnalRun.h" #include "iGuiPlot.h" #include "ZxObjCurve.h" @@ -32,6 +35,30 @@ bool nmAutoFitUiIsFinite(double value) #endif } +// 从系统参数表读取物理边界,读取失败时保留调用方提供的兜底边界。 +bool nmAutoFitReadPhysicalRange(const char* parameterName, + double fallbackMin, double fallbackMax, double& minValue, double& maxValue) +{ + minValue = fallbackMin; + maxValue = fallbackMax; + + iSysParaHelper* paraHelper = _paraHelper; + if(!paraHelper) { + return false; + } + + iParameter* parameter = paraHelper->getPara(QString::fromLatin1(parameterName), s_Nm_Serie); + if(!parameter || !nmAutoFitUiIsFinite(parameter->m_dMin) + || !nmAutoFitUiIsFinite(parameter->m_dMax) + || parameter->m_dMin >= parameter->m_dMax) { + return false; + } + + minValue = parameter->m_dMin; + maxValue = parameter->m_dMax; + return true; +} + // 主界面气井双对数中的源曲线和导数曲线已经采用拟压力量纲. // 自动拟合直接读取这两条显示曲线, 避免井对象中的原始压力历史数据与结果曲线量纲不一致. // 两条曲线可能因无效点过滤而长度不同, 因此按时间坐标匹配共同有效点. @@ -199,14 +226,338 @@ void nmWxAutomaticFitting::updateParameterVisibility(QTableWidget* table, NM_SOL renumberVisibleParameterRows(table); } +// 获取参数的系统物理边界,并为 Swi 叠加当前储层饱和度约束。 +bool nmWxAutomaticFitting::getPhysicalParameterRange(int parameterIndex, + double& minValue, double& maxValue) +{ + static const char* parameterNames[] = { + "Result_K", "Result_W_Skin", "Result_W_C", "Result_phi", + "Result_h", "Result_Cti", "Result_Cf", "Result_Swi" + }; + // KAPPA 的边界使用 md、ft、bbl/psi;自动拟合界面使用 Darcy、m、m^3/MPa, + // 这里统一换算到界面和 PSO 实际使用的单位:K 除以 1000,h 由 ft 换成 m, + // 井筒储集系数的 4.33667154546306e34 bbl/psi 对应约 1e36 m^3/MPa。 + // Ct/Cf/Swi 沿用模型参数表边界。 + static const double physicalMin[] = { + 1.01325027383089e-18, -5.0, 0.0, 1.0e-4, 1.0e-5, 1.0e-30, 1.0e-30, 0.0 + }; + static const double physicalMax[] = { + 1.01325027383089e42, 5000.0, 1.0e36, 0.9999, 1.0e9, 10.0, 10.0, 1.0 + }; + + if(parameterIndex < 0 || parameterIndex >= 8) { + return false; + } + + minValue = physicalMin[parameterIndex]; + maxValue = physicalMax[parameterIndex]; + bool rangeRead = true; + if(parameterIndex >= 5) { + rangeRead = nmAutoFitReadPhysicalRange(parameterNames[parameterIndex], + physicalMin[parameterIndex], physicalMax[parameterIndex], minValue, maxValue); + } + + if(parameterIndex == 7) { + double soi = reservoirData.getSoi().getValue().toDouble(); + double sgi = reservoirData.getSgi().getValue().toDouble(); + if(nmAutoFitUiIsFinite(soi) && nmAutoFitUiIsFinite(sgi)) { + if(soi < 0.0 || sgi < 0.0 || soi + sgi > 1.0) { + // Soi+Sgi 超过 1 时没有可行的 Swi,固定到物理下限,避免继续搜索非法区间。 + minValue = 0.0; + maxValue = 0.0; + } else { + maxValue = qMin(maxValue, 1.0 - soi - sgi); + } + } + } + + return rangeRead; +} + +// 将一组上下界同步到表格和自动拟合数据,保证 PSO 读取到同一份配置。 +void nmWxAutomaticFitting::setParameterRange(int parameterIndex, + double minValue, double maxValue) +{ + if(!m_parameterTable || parameterIndex < 0 || parameterIndex >= m_parameterTable->rowCount() + || !nmAutoFitUiIsFinite(minValue) || !nmAutoFitUiIsFinite(maxValue)) { + return; + } + + if(maxValue < minValue) { + qSwap(minValue, maxValue); + } + + const bool wasUpdatingRanges = m_updatingParameterRanges; + m_updatingParameterRanges = true; + + if(m_parameterTable->item(parameterIndex, 2)) { + m_parameterTable->item(parameterIndex, 2)->setText(QString::number(minValue, 'g', 10)); + } + if(m_parameterTable->item(parameterIndex, 4)) { + m_parameterTable->item(parameterIndex, 4)->setText(QString::number(maxValue, 'g', 10)); + } + + switch(parameterIndex) { + case 0: + automaticFittingData.getPermeabilityMin().setValue(minValue); + automaticFittingData.getPermeabilityMax().setValue(maxValue); + break; + case 1: + automaticFittingData.getSkinMin().setValue(minValue); + automaticFittingData.getSkinMax().setValue(maxValue); + break; + case 2: + automaticFittingData.getWellboreStorageMin().setValue(minValue); + automaticFittingData.getWellboreStorageMax().setValue(maxValue); + break; + case 3: + automaticFittingData.getPorosityMin().setValue(minValue); + automaticFittingData.getPorosityMax().setValue(maxValue); + break; + case 4: + automaticFittingData.getThicknessMin().setValue(minValue); + automaticFittingData.getThicknessMax().setValue(maxValue); + break; + case 5: + automaticFittingData.getCtMin().setValue(minValue); + automaticFittingData.getCtMax().setValue(maxValue); + break; + case 6: + automaticFittingData.getCfMin().setValue(minValue); + automaticFittingData.getCfMax().setValue(maxValue); + break; + case 7: + automaticFittingData.getSwiMin().setValue(minValue); + automaticFittingData.getSwiMax().setValue(maxValue); + break; + default: + break; + } + + m_updatingParameterRanges = wasUpdatingRanges; +} + +// 根据初值生成首次或拟合后的建议范围,并始终限制在物理边界内。 +void nmWxAutomaticFitting::updateRangeForParameter(int parameterIndex, + double centerValue, bool afterFit) +{ + if(!m_parameterTable || parameterIndex < 0 || parameterIndex >= 8 + || !nmAutoFitUiIsFinite(centerValue)) { + return; + } + + double physicalMin = 0.0; + double physicalMax = 0.0; + getPhysicalParameterRange(parameterIndex, physicalMin, physicalMax); + + double reference = centerValue; + const bool positiveParameter = parameterIndex != 1; + + // 正值参数初值为 0 时不再借用旧的界面范围,直接从物理边界选取搜索尺度。 + if(positiveParameter && reference <= 0.0) { + if(physicalMin > 0.0) { + reference = physicalMin; + } else { + reference = qMax(physicalMax * 0.01, 1.0e-12); + } + } + + if(physicalMax < physicalMin) { + return; + } + reference = qBound(physicalMin, reference, physicalMax); + const double boundedCenterValue = qBound(physicalMin, centerValue, physicalMax); + + double newMin = physicalMin; + double newMax = physicalMax; + if(parameterIndex == 1) { + const double skinHalfRange = afterFit ? 1.0 : 10.0; + newMin = qMax(physicalMin, reference - skinHalfRange); + newMax = qMin(physicalMax, reference + skinHalfRange); + } else if(reference > 0.0 && !(parameterIndex == 7 && centerValue <= 0.0)) { + const double lowerFactor = afterFit ? 0.5 : 0.1; + const double upperFactor = afterFit ? 2.0 : 10.0; + newMin = qMax(physicalMin, reference * lowerFactor); + newMax = qMin(physicalMax, reference * upperFactor); + } else if(parameterIndex == 7) { + // 没有可靠 Swi 初值时,不把搜索范围压缩到零附近。 + newMin = physicalMin; + newMax = physicalMax; + } + + // 任何自动范围都必须包含本次使用的中心值,并且不能越过物理边界。 + newMin = qMin(newMin, boundedCenterValue); + newMax = qMax(newMax, boundedCenterValue); + newMin = qMax(newMin, physicalMin); + newMax = qMin(newMax, physicalMax); + + if(newMax >= newMin) { + setParameterRange(parameterIndex, newMin, newMax); + } +} + +// 首次进入自动范围模式时,按当前表格中的初值为所有参数建立建议范围。 +void nmWxAutomaticFitting::initializeSuggestedParameterRanges() +{ + if(!m_parameterTable) { + return; + } + + for(int parameterIndex = 0; parameterIndex < 8; ++parameterIndex) { + QTableWidgetItem* initialItem = m_parameterTable->item(parameterIndex, 3); + if(initialItem) { + bool initialOk = false; + const double initialValue = initialItem->text().toDouble(&initialOk); + if(initialOk && nmAutoFitUiIsFinite(initialValue)) { + updateRangeForParameter(parameterIndex, initialValue, false); + } else { + // 数据对象没有提供该初值时使用完整物理区间,不回退到旧的默认范围。 + double physicalMin = 0.0; + double physicalMax = 0.0; + getPhysicalParameterRange(parameterIndex, physicalMin, physicalMax); + if(physicalMax >= physicalMin) { + setParameterRange(parameterIndex, physicalMin, physicalMax); + } + } + } + } +} + +// 校正已保存的范围:保留物理边界内的用户区间,无交集时按当前初值生成兜底区间。 +void nmWxAutomaticFitting::normalizeSavedParameterRanges() +{ + if(!m_parameterTable) { + return; + } + + for(int parameterIndex = 0; parameterIndex < 8; ++parameterIndex) { + QTableWidgetItem* minItem = m_parameterTable->item(parameterIndex, 2); + QTableWidgetItem* maxItem = m_parameterTable->item(parameterIndex, 4); + QTableWidgetItem* initialItem = m_parameterTable->item(parameterIndex, 3); + if(!minItem || !maxItem || !initialItem) { + continue; + } + + double physicalMin = 0.0; + double physicalMax = 0.0; + getPhysicalParameterRange(parameterIndex, physicalMin, physicalMax); + bool savedMinOk = false; + bool savedMaxOk = false; + const double savedMin = minItem->text().toDouble(&savedMinOk); + const double savedMax = maxItem->text().toDouble(&savedMaxOk); + const bool savedRangeValid = savedMinOk && savedMaxOk + && nmAutoFitUiIsFinite(savedMin) && nmAutoFitUiIsFinite(savedMax) + && savedMax >= savedMin; + + if(savedRangeValid && physicalMax >= physicalMin) { + const double clippedMin = qMax(savedMin, physicalMin); + const double clippedMax = qMin(savedMax, physicalMax); + if(clippedMax >= clippedMin) { + setParameterRange(parameterIndex, clippedMin, clippedMax); + continue; + } + } + + // 已保存范围无效或与物理边界无交集时,按数据对象初值重新生成。 + bool initialOk = false; + const double initialValue = initialItem->text().toDouble(&initialOk); + if(initialOk && nmAutoFitUiIsFinite(initialValue)) { + updateRangeForParameter(parameterIndex, initialValue, false); + } else if(physicalMax >= physicalMin) { + setParameterRange(parameterIndex, physicalMin, physicalMax); + } + } +} + +// 校验当前表格中的参数范围;parameterIndex 为 -1 时检查所有可见参数行。 +bool nmWxAutomaticFitting::validateParameterTable(QString& errorMessage, int parameterIndex) +{ + if(!m_parameterTable) { + errorMessage = tr("The parameter table is unavailable."); + return false; + } + if(parameterIndex < -1 || parameterIndex >= 8) { + errorMessage = tr("The parameter row is invalid."); + return false; + } + + static const char* parameterNames[] = { + "Permeability", "Skin", "Wellbore storage", "Porosity", + "Thickness", "Ct", "Cf", "Swi" + }; + + const int firstParameterIndex = parameterIndex < 0 ? 0 : parameterIndex; + const int lastParameterIndex = parameterIndex < 0 ? 8 : parameterIndex + 1; + for(int currentParameterIndex = firstParameterIndex; + currentParameterIndex < lastParameterIndex; ++currentParameterIndex) { + // 隐藏参数不参与当前模型拟合,不用它们的历史值阻塞当前设置。 + if(m_parameterTable->isRowHidden(currentParameterIndex)) { + continue; + } + + QTableWidgetItem* minItem = m_parameterTable->item(currentParameterIndex, 2); + QTableWidgetItem* initialItem = m_parameterTable->item(currentParameterIndex, 3); + QTableWidgetItem* maxItem = m_parameterTable->item(currentParameterIndex, 4); + if(!minItem || !initialItem || !maxItem) { + errorMessage = tr("The range values for %1 are incomplete.") + .arg(tr(parameterNames[currentParameterIndex])); + return false; + } + + bool minOk = false; + bool initialOk = false; + bool maxOk = false; + const double minValue = minItem->text().toDouble(&minOk); + const double initialValue = initialItem->text().toDouble(&initialOk); + const double maxValue = maxItem->text().toDouble(&maxOk); + if(!minOk || !initialOk || !maxOk + || !nmAutoFitUiIsFinite(minValue) + || !nmAutoFitUiIsFinite(initialValue) + || !nmAutoFitUiIsFinite(maxValue)) { + errorMessage = tr("The minimum value, initial value, and maximum value of %1 must be finite numbers.") + .arg(tr(parameterNames[currentParameterIndex])); + return false; + } + + double physicalMin = 0.0; + double physicalMax = 0.0; + getPhysicalParameterRange(currentParameterIndex, physicalMin, physicalMax); + if(!nmAutoFitUiIsFinite(physicalMin) || !nmAutoFitUiIsFinite(physicalMax) + || physicalMax < physicalMin) { + errorMessage = tr("The physical range of %1 is invalid.") + .arg(tr(parameterNames[currentParameterIndex])); + return false; + } + + if(minValue < physicalMin || minValue > physicalMax + || initialValue < physicalMin || initialValue > physicalMax + || maxValue < physicalMin || maxValue > physicalMax) { + errorMessage = tr("The values of %1 exceed the physical range [%2, %3].") + .arg(tr(parameterNames[currentParameterIndex])) + .arg(QString::number(physicalMin, 'g', 10)) + .arg(QString::number(physicalMax, 'g', 10)); + return false; + } + + if(minValue > maxValue || minValue > initialValue || initialValue > maxValue) { + errorMessage = tr("The values of %1 must satisfy: minimum <= initial value <= maximum.") + .arg(tr(parameterNames[currentParameterIndex])); + return false; + } + } + + return true; +} + nmWxAutomaticFitting::nmWxAutomaticFitting(QWidget *parent) : iDlgBase(parent) , m_autoFitterPSO(nullptr) - , m_autoFitterGA(nullptr) , m_progressDialog(nullptr) , m_progressTimer(nullptr) , m_progressMonitor(nullptr) - , m_selectedAlgorithm(ALGORITHM_PSO) // 默认选择PSO算法 + , m_autoParameterRanges(true) + // 构造期间先禁止即时校验,避免初始值写入和范围生成之间出现短暂的不一致。 + , m_updatingParameterRanges(true) { DEBUG_UI(QString("AutoFitting Constructor: this=0x%1").arg((quintptr)this, 0, 16)); @@ -233,32 +584,13 @@ nmWxAutomaticFitting::nmWxAutomaticFitting(QWidget *parent) nmDataAnalyzeManager* pManager = nmDataAnalyzeManager::getCurrentInstance(); reservoirData = pManager->getReservoirDataCopy(); automaticFittingData = pManager->getAutomaticFittingDataCopy(); + const bool hasSavedFittingData = pManager && pManager->getAutomaticFittingData() != nullptr; + // 自动范围始终开启;用户在表格中修改上下限后,itemChanged 会临时切换为手工范围。 + m_autoParameterRanges = true; NM_SOLVER_MODEL_TYPE solverModelType = pManager->getSolverModelType(); - // 只有尚未点击确定保存过配置时才使用相态默认值;重新打开时保留已保存的数据。 - if(pManager->getAutomaticFittingData() == nullptr) { - bool isOilOrWaterSinglePhase = solverModelType == SMT_Oil_ConstPvt || - solverModelType == SMT_Oil_VariablePvt || - solverModelType == SMT_Water_ConstPvt || - solverModelType == SMT_Water_VariablePvt; - if(isOilOrWaterSinglePhase) { - reservoirData.getPermeability().setValue(2.5e-2); - automaticFittingData.getPermeabilityMin().setValue(1.0e-3); - automaticFittingData.getPermeabilityMax().setValue(10.0); - automaticFittingData.getSkinMin().setValue(-10.0); - automaticFittingData.getSkinMax().setValue(10.0); - automaticFittingData.getWellboreStorageMin().setValue(1.0e-4); - automaticFittingData.getWellboreStorageMax().setValue(2.0); - automaticFittingData.getPorosityMin().setValue(1.0e-2); - automaticFittingData.getPorosityMax().setValue(5.0e-1); - automaticFittingData.getThicknessMin().setValue(2.0); - automaticFittingData.getThicknessMax().setValue(50.0); - automaticFittingData.getCtMin().setValue(1.0e-3); - automaticFittingData.getCtMax().setValue(1.0e-1); - automaticFittingData.getCfMin().setValue(1.0e-5); - automaticFittingData.getCfMax().setValue(1.0e-2); - } - + // 未保存过配置时只保留参数选择的相态默认值,不再覆盖数据对象中的初值或范围。 + if(!hasSavedFittingData) { if(solverModelType == SMT_Oil_ConstPvt || solverModelType == SMT_Water_ConstPvt) { // T1/T3 的综合压缩系数默认不参与拟合。 @@ -268,43 +600,6 @@ nmWxAutomaticFitting::nmWxAutomaticFitting(QWidget *parent) // T2/T4 的岩石压缩系数默认参与拟合。 automaticFittingData.setCfSelected(true); } - - // 气单相变化 PVT 使用 T5 数据集对应的初始值和拟合范围。 - if(solverModelType == SMT_Gas_VariablePvt) { - reservoirData.getPermeability().setValue(5.5e-6); - reservoirData.getPorosity().setValue(3.5e-2); - reservoirData.getThickness().setValue(8.0); - reservoirData.getCf().setValue(3.0e-4); - - automaticFittingData.getPermeabilityMin().setValue(4.5e-6); - automaticFittingData.getPermeabilityMax().setValue(6.2e-6); - automaticFittingData.getSkinMin().setValue(0.0); - automaticFittingData.getSkinMax().setValue(4.5); - automaticFittingData.getWellboreStorageMin().setValue(5.0e-5); - automaticFittingData.getWellboreStorageMax().setValue(1.6e-4); - automaticFittingData.getPorosityMin().setValue(8.0e-3); - automaticFittingData.getPorosityMax().setValue(4.0e-2); - automaticFittingData.getThicknessMin().setValue(7.0); - automaticFittingData.getThicknessMax().setValue(11.0); - automaticFittingData.getCfMin().setValue(1.0e-4); - automaticFittingData.getCfMax().setValue(2.0e-3); - } else if(solverModelType == SMT_Oil_ConstPvt || - solverModelType == SMT_Water_ConstPvt) { - // T1/T3 使用固定初值,不继承当前储层参数。 - reservoirData.getPorosity().setValue(2.45e-2); - reservoirData.getThickness().setValue(9.144); - reservoirData.getCt().setValue(1.0e-2); - } else if(solverModelType == SMT_Oil_VariablePvt) { - // 油单相变化 PVT 使用固定初值。 - reservoirData.getPorosity().setValue(6.0e-2); - reservoirData.getThickness().setValue(10.5); - reservoirData.getCf().setValue(1.0e-3); - } else if(solverModelType == SMT_Water_VariablePvt) { - // 水单相变化 PVT 使用固定初值。 - reservoirData.getPorosity().setValue(6.0e-2); - reservoirData.getThickness().setValue(10.5); - reservoirData.getCf().setValue(1.5e-3); - } } setupUI(); @@ -315,6 +610,12 @@ nmWxAutomaticFitting::nmWxAutomaticFitting(QWidget *parent) if(m_targetWellCombo->count() > 0) { onWellSelected(0); // 默认选中第一口井 } + if(!hasSavedFittingData) { + initializeSuggestedParameterRanges(); + } else { + normalizeSavedParameterRanges(); + } + m_updatingParameterRanges = false; DEBUG_UI("AutoFitting Constructor completed"); } @@ -333,9 +634,6 @@ nmWxAutomaticFitting::~nmWxAutomaticFitting() if (m_autoFitterPSO) { disconnect(m_autoFitterPSO, nullptr, this, nullptr); } - if (m_autoFitterGA) { - disconnect(m_autoFitterGA, nullptr, this, nullptr); - } DEBUG_UI("AutoFitting destructor - completed"); } @@ -514,6 +812,8 @@ void nmWxAutomaticFitting::setupParameterTable() // 连接选择改变信号 connect(m_parameterTable, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(onCellSelectionChanged(int, int, int, int))); + connect(m_parameterTable, SIGNAL(itemChanged(QTableWidgetItem*)), + this, SLOT(onParameterTableItemChanged(QTableWidgetItem*))); } void nmWxAutomaticFitting::setupControlPanel() @@ -528,9 +828,7 @@ void nmWxAutomaticFitting::setupControlPanel() QLabel* algorithmLabel = new QLabel(tr("Algorithm:")); m_algorithmCombo = new QComboBox(); m_algorithmCombo->addItem(tr("PSO (Particle Swarm)")); - m_algorithmCombo->addItem(tr("GA (Genetic Algorithm)")); - m_algorithmCombo->setCurrentIndex(0); // 默认选择PSO - connect(m_algorithmCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onAlgorithmChanged(int))); + m_algorithmCombo->setCurrentIndex(0); m_algorithmCombo->setMaximumWidth(160); m_algorithmCombo->setMinimumWidth(160); @@ -681,35 +979,37 @@ void nmWxAutomaticFitting::onReverseSelection() if(!m_parameterTable->isRowHidden(7)) m_swiCheckBox->setChecked(!m_swiCheckBox->isChecked()); } -void nmWxAutomaticFitting::onAlgorithmChanged(int index) +void nmWxAutomaticFitting::onParameterTableItemChanged(QTableWidgetItem* item) { - m_selectedAlgorithm = static_cast(index); - - // 根据算法类型调整界面提示或参数 - QString algorithmInfo; - switch(m_selectedAlgorithm) { - case ALGORITHM_PSO: - algorithmInfo = tr("PSO algorithm selected."); - if(m_surrogateCombo) { - m_surrogateCombo->setEnabled(true); - } - break; - case ALGORITHM_GA: - algorithmInfo = tr("GA algorithm selected."); - if(m_surrogateCombo) { - m_surrogateCombo->setEnabled(false); - } - break; + if(!item || m_updatingParameterRanges) { + return; } - // 在状态栏或工具提示中显示算法信息 - m_algorithmCombo->setToolTip(algorithmInfo); + // 用户改动范围后,切井和拟合结果不再自动覆盖这组手工范围。 + if(item->column() == 2 || item->column() == 4) { + m_autoParameterRanges = false; + } + + if(item->column() >= 2 && item->column() <= 4 + && !m_parameterTable->isRowHidden(item->row())) { + QString validationError; + if(!validateParameterTable(validationError, item->row())) { + // 表格编辑提交后立即提示,用户不需要先点击“确定”才发现错误。 + QMessageBox::warning(this, tr("Invalid parameter range"), validationError); + } + } } void nmWxAutomaticFitting::onAccept() { - // 首先保存参数设置 - setAutomaticFittingValue(); + QString validationError; + if(!validateParameterTable(validationError)) { + QMessageBox::warning(this, tr("Invalid parameter range"), validationError); + return; + } + + // 校验通过后再保存参数设置,非法输入不会被静默裁剪。 + setAutomaticFittingValue(); // 更新完成后,通知参数界面刷新 nmWxParameterProperty::notifyUpdateTable(); @@ -878,28 +1178,6 @@ void nmWxAutomaticFitting::onWellSelected(int index) } } - // 尚未保存拟合配置时使用相态默认值;已保存时保留井上的 Skin 和井筒储集系数。 - nmDataAnalyzeManager* pManager = nmDataAnalyzeManager::getCurrentInstance(); - bool useDefaultFittingValues = pManager && pManager->getAutomaticFittingData() == nullptr; - if(useDefaultFittingValues && (pManager->getSolverModelType() == SMT_Oil_ConstPvt || - pManager->getSolverModelType() == SMT_Water_ConstPvt)) { - skinValue = 0.0; - wellboreStorageValue = 1.0e-2; - found = true; - } else if(useDefaultFittingValues && pManager->getSolverModelType() == SMT_Gas_VariablePvt) { - skinValue = 1.0; - wellboreStorageValue = 6.0e-5; - found = true; - } else if(useDefaultFittingValues && pManager->getSolverModelType() == SMT_Oil_VariablePvt) { - skinValue = -0.2; - wellboreStorageValue = 1.5e-2; - found = true; - } else if(useDefaultFittingValues && pManager->getSolverModelType() == SMT_Water_VariablePvt) { - skinValue = -0.2; - wellboreStorageValue = 1.0e-2; - found = true; - } - if (found) { // 更新表格数据 // 确保表格项存在 @@ -915,6 +1193,11 @@ void nmWxAutomaticFitting::onWellSelected(int index) // 设置井筒储集系数(Wellbore storage) m_parameterTable->item(2, 3)->setText(QString::number(wellboreStorageValue)); + + if(m_autoParameterRanges) { + updateRangeForParameter(1, skinValue, false); + updateRangeForParameter(2, wellboreStorageValue, false); + } } } @@ -1041,11 +1324,10 @@ void nmWxAutomaticFitting::startAutoFitting(const QVector>& targ // 先清理之前的实例 cleanupFitting(); - if (m_selectedAlgorithm == ALGORITHM_PSO) { - DEBUG_UI("Creating PSO auto fitter"); - m_autoFitterPSO = new nmCalculationAutoFitPSO(this); - m_autoFitterPSO->setTargetLogLogData(targetData); - m_autoFitterPSO->setPSOTargetWellName(targetWellName); + DEBUG_UI("Creating PSO auto fitter"); + m_autoFitterPSO = new nmCalculationAutoFitPSO(this); + m_autoFitterPSO->setTargetLogLogData(targetData); + m_autoFitterPSO->setPSOTargetWellName(targetWellName); //// 特定井名时使用快速路径 //if (targetWellName == "VerticalWell1") { @@ -1080,46 +1362,23 @@ void nmWxAutomaticFitting::startAutoFitting(const QVector>& targ //} - m_progressMonitor = new nmWxAutomaticfittingStart(this); - m_progressMonitor->setAutoFitter(m_autoFitterPSO); - m_progressMonitor->setPseudoPressureMode( - nmDataAnalyzeManager::getCurrentInstance()->getSolverModelType() == SMT_Gas_VariablePvt); - m_progressMonitor->setTargetLogLogData(targetData); - - connect(m_autoFitterPSO, SIGNAL(fittingFinished(bool, QString)), - this, SLOT(onFittingFinished(bool, QString))); - - int maxIterations = m_iterationEdit->text().toInt(); - double targetError = m_errorLimitEdit->text().toDouble(); - QString wellName = m_targetWellCombo->currentText(); - m_progressMonitor->setFittingParameters(maxIterations, targetError, wellName); - m_progressMonitor->setSelectedParameters(selectedParams); - - m_progressMonitor->show(); - QTimer::singleShot(100, this, SLOT(runAutoFitting())); + m_progressMonitor = new nmWxAutomaticfittingStart(this); + m_progressMonitor->setAutoFitter(m_autoFitterPSO); + m_progressMonitor->setPseudoPressureMode( + nmDataAnalyzeManager::getCurrentInstance()->getSolverModelType() == SMT_Gas_VariablePvt); + m_progressMonitor->setTargetLogLogData(targetData); - } else if (m_selectedAlgorithm == ALGORITHM_GA) { - DEBUG_UI("Creating GA auto fitter"); - m_autoFitterGA = new nmCalculationAutoFitGA(this); - m_autoFitterGA->setTargetLogLogData(targetData); - m_autoFitterGA->setGATargetWellName(targetWellName); + connect(m_autoFitterPSO, SIGNAL(fittingFinished(bool, QString)), + this, SLOT(onFittingFinished(bool, QString))); - m_progressMonitor = new nmWxAutomaticfittingStart(this); - m_progressMonitor->setAutoFitterGA(m_autoFitterGA); - m_progressMonitor->setTargetLogLogData(targetData); + int maxIterations = m_iterationEdit->text().toInt(); + double targetError = m_errorLimitEdit->text().toDouble(); + QString wellName = m_targetWellCombo->currentText(); + m_progressMonitor->setFittingParameters(maxIterations, targetError, wellName); + m_progressMonitor->setSelectedParameters(selectedParams); - connect(m_autoFitterGA, SIGNAL(fittingFinished(bool, QString)), - this, SLOT(onFittingFinished(bool, QString))); - - int maxIterations = m_iterationEdit->text().toInt(); - double targetError = m_errorLimitEdit->text().toDouble(); - QString wellName = m_targetWellCombo->currentText(); - m_progressMonitor->setFittingParameters(maxIterations, targetError, wellName); - m_progressMonitor->setSelectedParameters(selectedParams); - - m_progressMonitor->show(); - QTimer::singleShot(100, this, SLOT(runAutoFitting())); - } + m_progressMonitor->show(); + QTimer::singleShot(100, this, SLOT(runAutoFitting())); } void nmWxAutomaticFitting::runAutoFitting() @@ -1128,10 +1387,8 @@ void nmWxAutomaticFitting::runAutoFitting() m_progressMonitor->markFittingStarted(); } - if(m_selectedAlgorithm == ALGORITHM_PSO && m_autoFitterPSO) { + if(m_autoFitterPSO) { m_autoFitterPSO->startAutoFitting(); - } else if(m_selectedAlgorithm == ALGORITHM_GA && m_autoFitterGA) { - m_autoFitterGA->startAutoFitting(); } } @@ -1147,18 +1404,13 @@ void nmWxAutomaticFitting::onFittingFinished(bool success, const QString& messag disconnect(m_autoFitterPSO, SIGNAL(fittingFinished(bool, QString)), this, SLOT(onFittingFinished(bool, QString))); } - if (m_autoFitterGA) { - disconnect(m_autoFitterGA, SIGNAL(fittingFinished(bool, QString)), - this, SLOT(onFittingFinished(bool, QString))); - } - - // 更新最佳参数到表格 - updateBestParametersToTable(); - if(success) { + // 只有成功拟合的结果才用于生成下一轮范围,失败结果不污染当前配置。 + updateBestParametersToTable(); + QString resultInfo; - if(m_selectedAlgorithm == ALGORITHM_PSO && m_autoFitterPSO) { + if(m_autoFitterPSO) { double bestFitness = m_autoFitterPSO->getBestFitness(); // 检查是否是用户停止的情况 @@ -1173,23 +1425,6 @@ void nmWxAutomaticFitting::onFittingFinished(bool success, const QString& messag resultInfo += tr("Optimized parameters have been applied to the model."); QMessageBox::information(this, tr("Optimization Completed"), resultInfo); } - - } else if(m_selectedAlgorithm == ALGORITHM_GA && m_autoFitterGA) { - // GA的类似处理 - - double bestFitness = m_autoFitterGA->getBestFitness(); - - if(message.contains("stopped by user", Qt::CaseInsensitive)) { - resultInfo = tr("GA Optimization stopped by user:\n"); - resultInfo += tr("Best Error: %1\n").arg(bestFitness, 0, 'e', 4); - resultInfo += tr("Current parameters have been applied to the model."); - QMessageBox::information(this, tr("Optimization Stopped"), resultInfo); - } else { - resultInfo = tr("GA Optimization completed:\n"); - resultInfo += tr("Best Error: %1\n").arg(bestFitness, 0, 'e', 4); - resultInfo += tr("Optimized parameters have been applied to the model."); - QMessageBox::information(this, tr("Optimization Completed"), resultInfo); - } } } else { // 只有真正失败的情况才显示警告 @@ -1199,11 +1434,9 @@ void nmWxAutomaticFitting::onFittingFinished(bool success, const QString& messag void nmWxAutomaticFitting::onStopFitting() { - if(m_selectedAlgorithm == ALGORITHM_PSO && m_autoFitterPSO && m_autoFitterPSO->isRunning()) { + if(m_autoFitterPSO && m_autoFitterPSO->isRunning()) { m_autoFitterPSO->stopFitting(); - } else if(m_selectedAlgorithm == ALGORITHM_GA && m_autoFitterGA && m_autoFitterGA->isRunning()) { - m_autoFitterGA->stopFitting(); - } + } } void nmWxAutomaticFitting::cleanupFitting() @@ -1246,31 +1479,6 @@ void nmWxAutomaticFitting::cleanupFitting() DEBUG_UI("PSO fitter cleaned up"); } - if (m_autoFitterGA) { - DEBUG_UI("Stopping and disconnecting GA fitter"); - - disconnect(m_autoFitterGA, nullptr, nullptr, nullptr); - - if (m_autoFitterGA->isRunning()) { - m_autoFitterGA->stopFitting(); - - int waitCount = 0; - while (m_autoFitterGA->isRunning() && waitCount < 50) { - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 100); - waitCount++; - } - - // 如果仍在运行则强制停止 - if (m_autoFitterGA->isRunning()) { - DEBUG_UI("Force stopping GA - timeout reached"); - } - } - - delete m_autoFitterGA; - m_autoFitterGA = nullptr; - DEBUG_UI("GA fitter cleaned up"); - } - // 清理进度监控 if (m_progressMonitor) { // 先断开进度监控的信号连接 @@ -1296,10 +1504,8 @@ void nmWxAutomaticFitting::updateBestParametersToTable() QVector bestSolution; // 获取最佳解决方案 - if (m_selectedAlgorithm == ALGORITHM_PSO && m_autoFitterPSO) { + if (m_autoFitterPSO) { bestSolution = m_autoFitterPSO->getBestSolution(); - } else if (m_selectedAlgorithm == ALGORITHM_GA && m_autoFitterGA) { - bestSolution = m_autoFitterGA->getBestSolution(); } if (bestSolution.isEmpty()) return; @@ -1315,78 +1521,19 @@ void nmWxAutomaticFitting::updateBestParametersToTable() if(m_cfCheckBox->isChecked()) enabledParams.append(6); // 岩石压缩系数 if(m_swiCheckBox->isChecked()) enabledParams.append(7); // 初始含水饱和度 - // 范围收缩比例 - double shrinkFactor = 0.3; - // 更新参数值和范围 for (int i = 0; i < bestSolution.size() && i < enabledParams.size(); ++i) { int paramIndex = enabledParams[i]; double bestValue = bestSolution[i]; + if(!nmAutoFitUiIsFinite(bestValue)) { + continue; + } // 更新初始值 m_parameterTable->item(paramIndex, 3)->setText(QString::number(bestValue, 'g', 4)); - - // 获取当前的最小值和最大值 - double currentMin = m_parameterTable->item(paramIndex, 2)->text().toDouble(); - double currentMax = m_parameterTable->item(paramIndex, 4)->text().toDouble(); - double currentRange = currentMax - currentMin; - - // 计算新的范围 - double newHalfRange = currentRange * shrinkFactor * 0.5; - double newMin = bestValue - newHalfRange; - double newMax = bestValue + newHalfRange; - - // 确保某些参数不为负数 - if (paramIndex == 0 || paramIndex == 2 || paramIndex == 3 || paramIndex == 4) { - newMin = qMax(newMin, 0.0); - } - - // 确保最小范围,避免范围过小 - double minAllowedRange = currentRange * 0.05; - if ((newMax - newMin) < minAllowedRange) { - double center = (newMax + newMin) * 0.5; - newMin = center - minAllowedRange * 0.5; - newMax = center + minAllowedRange * 0.5; - } - - // 更新表格中的最小值和最大值 - m_parameterTable->item(paramIndex, 2)->setText(QString::number(newMin, 'g', 4)); - m_parameterTable->item(paramIndex, 4)->setText(QString::number(newMax, 'g', 4)); - - // 保存收缩后的范围 - switch(paramIndex) { - case 0: // 渗透率 - automaticFittingData.getPermeabilityMin().setValue(newMin); - automaticFittingData.getPermeabilityMax().setValue(newMax); - break; - case 1: // 表皮系数 - automaticFittingData.getSkinMin().setValue(newMin); - automaticFittingData.getSkinMax().setValue(newMax); - break; - case 2: // 井筒储集系数 - automaticFittingData.getWellboreStorageMin().setValue(newMin); - automaticFittingData.getWellboreStorageMax().setValue(newMax); - break; - case 3: // 孔隙度 - automaticFittingData.getPorosityMin().setValue(newMin); - automaticFittingData.getPorosityMax().setValue(newMax); - break; - case 4: // 储层厚度 - automaticFittingData.getThicknessMin().setValue(newMin); - automaticFittingData.getThicknessMax().setValue(newMax); - break; - case 5: // 综合压缩系数 - automaticFittingData.getCtMin().setValue(newMin); - automaticFittingData.getCtMax().setValue(newMax); - break; - case 6: // 岩石压缩系数 - automaticFittingData.getCfMin().setValue(newMin); - automaticFittingData.getCfMax().setValue(newMax); - break; - case 7: // 初始含水饱和度 - automaticFittingData.getSwiMin().setValue(newMin); - automaticFittingData.getSwiMax().setValue(newMax); - break; + // 只有自动范围模式才根据拟合结果收窄下一轮搜索区间;手工范围由用户保留。 + if(m_autoParameterRanges) { + updateRangeForParameter(paramIndex, bestValue, true); } } diff --git a/Src/nmNum/nmSubWxs/nmWxAutomaticFittingStart.cpp b/Src/nmNum/nmSubWxs/nmWxAutomaticFittingStart.cpp index 6e0bd2b..acb1a3f 100644 --- a/Src/nmNum/nmSubWxs/nmWxAutomaticFittingStart.cpp +++ b/Src/nmNum/nmSubWxs/nmWxAutomaticFittingStart.cpp @@ -383,8 +383,6 @@ nmWxAutomaticfittingStart::nmWxAutomaticfittingStart(QWidget *parent) , chartGroup(nullptr) , curveChart(nullptr) , m_autoFitterPSO(nullptr) - , m_autoFitterGA(nullptr) - , m_algorithmType(FITTING_ALGORITHM_PSO) , m_maxIterations(100) , m_targetError(0.001) , m_wellName("") @@ -580,8 +578,6 @@ void nmWxAutomaticfittingStart::setupControlArea() void nmWxAutomaticfittingStart::setAutoFitter(nmCalculationAutoFitPSO* autoFitter) { m_autoFitterPSO = autoFitter; - m_autoFitterGA = nullptr; // 清空GA实例 - m_algorithmType = FITTING_ALGORITHM_PSO; // 更新算法类型显示 algorithmTypeValue->setText("PSO"); @@ -604,31 +600,6 @@ void nmWxAutomaticfittingStart::setAutoFitter(nmCalculationAutoFitPSO* autoFitte } } -void nmWxAutomaticfittingStart::setAutoFitterGA(nmCalculationAutoFitGA* autoFitter) -{ - m_autoFitterGA = autoFitter; - m_autoFitterPSO = nullptr; // 清空PSO实例 - m_algorithmType = FITTING_ALGORITHM_GA; - - // 更新算法类型显示 - algorithmTypeValue->setText("GA"); - algorithmTypeValue->setStyleSheet("QLabel { color: red; font-weight: bold; }"); - - if (m_autoFitterGA) { - connect(m_autoFitterGA, SIGNAL(progressUpdated(int, double)), - this, SLOT(onFittingProgress(int, double))); - connect(m_autoFitterGA, SIGNAL(fittingFinished(bool, QString)), - this, SLOT(onFittingFinished(bool, QString))); - connect(m_autoFitterGA, SIGNAL(logMessageGenerated(QString)), - this, SLOT(onLogMessageReceived(QString))); - - // 启用停止按钮 - stopButton->setEnabled(true); - - addLogMessage(tr("GA auto fitting started")); - } -} - void nmWxAutomaticfittingStart::setFittingParameters(int maxIterations, double targetError, const QString& wellName) { m_maxIterations = maxIterations; @@ -641,7 +612,7 @@ void nmWxAutomaticfittingStart::setFittingParameters(int maxIterations, double t progressBar->setRange(0, maxIterations); - QString algorithmName = (m_algorithmType == FITTING_ALGORITHM_PSO) ? "PSO" : "GA"; + const QString algorithmName = "PSO"; addLogMessage(tr("%1 fitting parameters set: MaxIterations=%2, TargetAccuracy=%3, TargetWell=%4") .arg(algorithmName).arg(maxIterations).arg(formatScientific(targetError)).arg(wellName)); } @@ -650,7 +621,7 @@ void nmWxAutomaticfittingStart::markFittingStarted() { m_startTime = QDateTime::currentDateTime(); - QString algorithmName = (m_algorithmType == FITTING_ALGORITHM_PSO) ? "PSO" : "GA"; + const QString algorithmName = "PSO"; QString timestamp = m_startTime.toString("yyyy-MM-dd hh:mm:ss"); addLogMessage(tr("=== %1 Fitting Session Started at %2 ===") @@ -665,7 +636,7 @@ void nmWxAutomaticfittingStart::setSelectedParameters(const QStringList& paramet // 立即更新参数表格 updateParameterTable(); - QString algorithmName = (m_algorithmType == FITTING_ALGORITHM_PSO) ? "PSO" : "GA"; + const QString algorithmName = "PSO"; addLogMessage(tr("%1 selected parameters: %2").arg(algorithmName).arg(parameterNames.join(", "))); } @@ -716,7 +687,7 @@ void nmWxAutomaticfittingStart::onFittingFinished(bool success, const QString& m { m_isFinished = true; - QString algorithmName = (m_algorithmType == FITTING_ALGORITHM_PSO) ? "PSO" : "GA"; + const QString algorithmName = "PSO"; // 更新状态 if (success) { @@ -800,25 +771,18 @@ void nmWxAutomaticfittingStart::onFittingFinished(bool success, const QString& m void nmWxAutomaticfittingStart::onStopButtonClicked() { - bool isRunning = false; - if (m_algorithmType == FITTING_ALGORITHM_PSO && m_autoFitterPSO) { - isRunning = m_autoFitterPSO->isRunning(); - } else if (m_algorithmType == FITTING_ALGORITHM_GA && m_autoFitterGA) { - isRunning = m_autoFitterGA->isRunning(); - } + const bool isRunning = m_autoFitterPSO && m_autoFitterPSO->isRunning(); if (isRunning) { - QString algorithmName = (m_algorithmType == FITTING_ALGORITHM_PSO) ? "PSO" : "GA"; + const QString algorithmName = "PSO"; int ret = QMessageBox::question(this, tr("Confirm Stop"), tr("Are you sure you want to stop the %1 fitting process?").arg(algorithmName), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (ret == QMessageBox::Yes) { - if (m_algorithmType == FITTING_ALGORITHM_PSO && m_autoFitterPSO) { + if (m_autoFitterPSO) { m_autoFitterPSO->stopFitting(); - } else if (m_algorithmType == FITTING_ALGORITHM_GA && m_autoFitterGA) { - m_autoFitterGA->stopFitting(); } addLogMessage(tr("User requested to stop %1 fitting").arg(algorithmName)); } @@ -840,16 +804,11 @@ void nmWxAutomaticfittingStart::updateParameterTable() // 最优参数值 QString valueText = "N/A"; - if (m_algorithmType == FITTING_ALGORITHM_PSO && m_autoFitterPSO) { + if (m_autoFitterPSO) { QVector bestSolution = m_autoFitterPSO->getBestSolution(); if (i < bestSolution.size()) { valueText = formatScientific(bestSolution[i]); } - } else if (m_algorithmType == FITTING_ALGORITHM_GA && m_autoFitterGA) { - QVector bestSolution = m_autoFitterGA->getBestSolution(); - if (i < bestSolution.size()) { - valueText = formatScientific(bestSolution[i]); - } } QTableWidgetItem* valueItem = new QTableWidgetItem(valueText); @@ -883,16 +842,8 @@ QString nmWxAutomaticfittingStart::formatScientific(double value) void nmWxAutomaticfittingStart::closeEvent(QCloseEvent *event) { - bool isRunning = false; - QString algorithmName; - - if (m_algorithmType == FITTING_ALGORITHM_PSO && m_autoFitterPSO) { - isRunning = m_autoFitterPSO->isRunning(); - algorithmName = "PSO"; - } else if (m_algorithmType == FITTING_ALGORITHM_GA && m_autoFitterGA) { - isRunning = m_autoFitterGA->isRunning(); - algorithmName = "GA"; - } + const bool isRunning = m_autoFitterPSO && m_autoFitterPSO->isRunning(); + const QString algorithmName = "PSO"; if (isRunning && !m_isFinished) { int ret = QMessageBox::question(this, tr("Confirm Close"), @@ -901,10 +852,8 @@ void nmWxAutomaticfittingStart::closeEvent(QCloseEvent *event) QMessageBox::No); if (ret == QMessageBox::Yes) { - if (m_algorithmType == FITTING_ALGORITHM_PSO && m_autoFitterPSO) { + if (m_autoFitterPSO) { m_autoFitterPSO->stopFitting(); - } else if (m_algorithmType == FITTING_ALGORITHM_GA && m_autoFitterGA) { - m_autoFitterGA->stopFitting(); } event->accept(); } else {