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 {