Merge branch 'feature/MultiWellAutoFit-20260805' into develop

# Conflicts:
#	Bin/Config/Lang/cn/nmNum_cn.qm   resolved by feature/MultiWellAutoFit-20260805 version
feature/PebiSolver-Integration-20260818
lvjunjie 2 days ago
commit 1d5c0bfdb6

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

@ -2129,12 +2129,6 @@
<source>Normalized Gauss Newton</source>
<translation>-</translation>
</message>
<message>
<location filename="../../../../Src/iGui/iSubWxs/iWxAutoFit.cpp" line="71"/>
<location filename="../../../../Src/iGui/iSubWxs/iWxAutoFit.cpp" line="311"/>
<source>Genetic Algorithm</source>
<translation></translation>
</message>
<message>
<location filename="../../../../Src/iGui/iSubWxs/iWxAutoFit.cpp" line="138"/>
<source>Parameter</source>

@ -4715,10 +4715,6 @@ MethodID:%1</source>
<source>Normalized Gauss Newton</source>
<translation>-</translation>
</message>
<message>
<source>Genetic Algorithm</source>
<translation type="obsolete"></translation>
</message>
<message>
<location filename="../../../../Src/mGui/mSubWxs/iWxAutoFit.cpp" line="272"/>
<source>Parameter</source>

Binary file not shown.

@ -48,346 +48,19 @@ Reason: %1</source>
</message>
</context>
<context>
<name>nmCalculationAutoFitGA</name>
<message>
<source>=== GA Automatic Fitting Started ===</source>
<translation>=== GA ===</translation>
</message>
<message>
<source>Algorithm: Genetic Algorithm</source>
<translation></translation>
</message>
<message>
<source>ERROR: Failed to load configuration from data manager</source>
<translation></translation>
</message>
<message>
<source>Enabled parameters count: %1</source>
<translation>%1</translation>
</message>
<message>
<source>ERROR: No parameters enabled for optimization</source>
<translation></translation>
</message>
<message>
<source>ERROR: Target LogLog data is empty or insufficient</source>
<translation></translation>
</message>
<message>
<source>ERROR: Target LogLog data arrays have inconsistent sizes</source>
<translation></translation>
</message>
<message>
<source>Target data validation passed (%1 data points)</source>
<translation>%1 </translation>
</message>
<message>
<source>=== Evaluating Initial Solution (Elite Protection) ===</source>
<translation>=== ===</translation>
</message>
<message>
<source>Initial parameters: </source>
<translation></translation>
</message>
<message>
<source>Starting initial solution evaluation...</source>
<translation>...</translation>
</message>
<message>
<source>ERROR: m_userInitialSolution is empty!</source>
<translation></translation>
</message>
<message>
<source>Initial param[%1] = %2</source>
<translation>[%1] = %2</translation>
</message>
<message>
<source>evaluateGenes returned: %1</source>
<translation> %1</translation>
</message>
<message>
<source>Taking SUCCESS branch (fitness &lt; 1e9)</source>
<translation></translation>
</message>
<message>
<source>Initial solution evaluation successful</source>
<translation></translation>
</message>
<message>
<source>Initial fitness (error): %1</source>
<translation>%1</translation>
</message>
<message>
<source>Elite protection activated - initial solution will be preserved if no significant improvement found</source>
<translation>.</translation>
</message>
<message>
<source>Taking FAILURE branch (fitness &gt;= 1e9)</source>
<translation></translation>
</message>
<message>
<source>Initial solution evaluation failed - starting with random initialization</source>
<translation> - 使</translation>
</message>
<message>
<source>Exception during initial solution evaluation</source>
<translation></translation>
</message>
<message>
<source>Population initialized: %1 individuals, %2 dimensions</source>
<translation>%1 %2 </translation>
</message>
<message>
<source>=== Starting GA Main Loop ===</source>
<translation>=== GA ===</translation>
</message>
<message>
<source>--- Generation %1/%2 ---</source>
<translation>--- %1/%2 ---</translation>
</message>
<message>
<source>Current best error: %1</source>
<translation>%1</translation>
</message>
<message>
<source>Total evaluations: %1 (successful: %2, failures: %3)</source>
<translation>%1%2%3</translation>
</message>
<message>
<source>Optimization stopped by user request</source>
<translation></translation>
</message>
<message>
<source>Generation %1 completed: best = %2, avg = %3, worst = %4</source>
<translation> %1 = %2 = %3 = %4</translation>
</message>
<message>
<source>=== TARGET ACHIEVED ===</source>
<translation>=== ===</translation>
</message>
<message>
<source>Target error achieved! Current error: %1 &lt; Target: %2</source>
<translation>%1 &lt; %2</translation>
</message>
<message>
<source>Optimization completed successfully after %1 generations</source>
<translation>%1 &lt; %2</translation>
</message>
<message>
<source>=== TRUE CONVERGENCE DETECTED ===</source>
<translation>=== ===</translation>
</message>
<message>
<source>Algorithm has converged to a stable solution</source>
<translation></translation>
</message>
<message>
<source>Final error: %1 after %2 generations</source>
<translation>%1 %2 </translation>
</message>
<message>
<source>Solution quality: %1 (1.0 = target achieved)</source>
<translation>%1</translation>
</message>
<message>
<source>=== LOCAL OPTIMUM DETECTED ===</source>
<translation>=== ===</translation>
</message>
<message>
<source>Algorithm appears to be trapped in local optimum</source>
<translation></translation>
</message>
<message>
<source>Current error: %1 after %2 generations</source>
<translation>%1 %2 </translation>
</message>
<message>
<source>Suggestion: Try restarting with different parameters or larger search space</source>
<translation>使</translation>
</message>
<message>
<source>=== CONSECUTIVE FAILURES ===</source>
<translation>=== ===</translation>
</message>
<message>
<source>Too many consecutive failed generations (%1/%2)</source>
<translation>%1/%2</translation>
</message>
<message>
<source> Optimization status: diversity=%1</source>
<translation>=%1</translation>
</message>
<message>
<source>Generation %1 completed - Current best: %2</source>
<translation> %1 - %2</translation>
</message>
<message>
<source>CRITICAL ERROR: %1</source>
<translation>: %1</translation>
</message>
<message>
<source>CRITICAL ERROR: Unknown exception in GA main loop</source>
<translation>GA</translation>
</message>
<message>
<source>Applying optimized parameters to model...</source>
<translation>...</translation>
</message>
<message>
<source>=== Optimization Results ===</source>
<translation>=== ===</translation>
</message>
<message>
<source>Final error: %1</source>
<translation>: %1</translation>
</message>
<message>
<source>Total generations: %1</source>
<translation>%1</translation>
</message>
<message>
<source>Total evaluations: %1 (successful: %2)</source>
<translation>: %1 (: %2)</translation>
</message>
<message>
<source>Optimized parameters: </source>
<translation>:</translation>
</message>
<message>
<source>Parameters applied successfully to data manager</source>
<translation></translation>
</message>
<message>
<source>ERROR: Failed to apply final parameters: %1</source>
<translation>: : %1</translation>
</message>
<message>
<source>ERROR: Unknown error applying final parameters</source>
<translation>: </translation>
</message>
<message>
<source>=== GA OPTIMIZATION SUCCESSFUL ===</source>
<translation>=== GA ===</translation>
</message>
<message>
<source>=== GA OPTIMIZATION CONVERGED ===</source>
<translation>=== GA ===</translation>
</message>
<message>
<source>=== GA OPTIMIZATION - LOCAL OPTIMUM ===</source>
<translation>=== GA - ===</translation>
</message>
<message>
<source>=== GA OPTIMIZATION - MAX GENERATIONS ===</source>
<translation>=== GA - ===</translation>
</message>
<message>
<source>=== GA OPTIMIZATION STOPPED BY USER ===</source>
<translation>=== GA - ===</translation>
</message>
<message>
<source>=== GA OPTIMIZATION FAILED ===</source>
<translation>=== GA ===</translation>
</message>
<message>
<source>=== GA OPTIMIZATION - UNKNOWN END ===</source>
<translation>=== GA - ===</translation>
</message>
<message>
<source>Result: %1</source>
<translation>: %1</translation>
</message>
<message>
<source>=== User Stop Request Received ===</source>
<translation>=== ===</translation>
</message>
<message>
<source>Gracefully stopping GA optimization...</source>
<translation>GA...</translation>
</message>
<message>
<source>Force stopping current evaluation...</source>
<translation>...</translation>
</message>
<message>
<source>GA optimization stop request processed</source>
<translation>GA</translation>
</message>
<message>
<source>Stop request received but optimization is not running</source>
<translation></translation>
</message>
<message>
<source> Individual %1 improved: %2 -&gt; %3</source>
<translation> %1 %2 -&gt; %3</translation>
</message>
<message>
<source> Individual %1: evaluation failed</source>
<translation> %1</translation>
</message>
<message>
<source> Individual %1: Exception: %2</source>
<translation> %1%2</translation>
</message>
<message>
<source> Individual %1: Unknown exception</source>
<translation> %1</translation>
</message>
<message>
<source>WARNING: No successful evaluations in generation %1 (consecutive failures: %2)</source>
<translation> %1 %2</translation>
</message>
<message>
<source>Current generation stats: %1 successful, %2 failed out of %3 individuals (success rate: %4%)</source>
<translation>%3 %1 %2 %4%</translation>
</message>
<message>
<source>ERROR: Too many consecutive failed generations (%1/%2) - stopping optimization</source>
<translation>%1/%2- </translation>
</message>
<message>
<source>WARNING: Low success rate (%1%) in generation %2, but continuing optimization</source>
<translation> %2 %1%</translation>
</message>
<message>
<source>No initial solution for elite protection</source>
<translation></translation>
</message>
<message>
<source>=== Final Result Validation (Elite Protection) ===</source>
<translation>=== ===</translation>
</message>
<message>
<source>Comparing results: Initial=%1, Final=%2</source>
<translation>: =%1, =%2</translation>
</message>
<message>
<source>Improvement: %1 (%2%)</source>
<translation>: %1 (%2%)</translation>
</message>
<name>nmCalculationAutoFitPSO</name>
<message>
<source>Elite protection triggered: insufficient improvement</source>
<translation></translation>
<source>Effective improvement threshold: max(%1, %2% of baseline error); %3 consecutive ineffective steps trigger convergence confirmation</source>
<translation> %1 %2% %3 </translation>
</message>
<message>
<source>Threshold: %1%, Actual: %2%</source>
<translation>: %1%, : %2%</translation>
<source>No effective improvement for %1 consecutive steps; rebuilding sensitivity model for confirmation</source>
<translation> %1 </translation>
</message>
<message>
<source>Restoring initial solution as final result</source>
<translation></translation>
<source>Sensitivity rebuild produced no effective improvement; local convergence detected</source>
<translation></translation>
</message>
<message>
<source>Initial solution restored successfully</source>
<translation></translation>
</message>
<message>
<source>Final result validated - significant improvement achieved</source>
<translation> - </translation>
</message>
</context>
<context>
<name>nmCalculationAutoFitPSO</name>
<message>
<source>=== User Stop Request Received ===</source>
<translation>=== ===</translation>
@ -3698,6 +3371,38 @@ Supported types: Vertical, Vertical Fractured, and Horizontal Multi-Fractured We
<source>Warning</source>
<translation></translation>
</message>
<message>
<source>Invalid parameter range</source>
<translation></translation>
</message>
<message>
<source>The parameter table is unavailable.</source>
<translation></translation>
</message>
<message>
<source>The parameter row is invalid.</source>
<translation></translation>
</message>
<message>
<source>The range values for %1 are incomplete.</source>
<translation>%1 </translation>
</message>
<message>
<source>The minimum value, initial value, and maximum value of %1 must be finite numbers.</source>
<translation>%1 </translation>
</message>
<message>
<source>The physical range of %1 is invalid.</source>
<translation>%1 </translation>
</message>
<message>
<source>The values of %1 exceed the physical range [%2, %3].</source>
<translation>%1 [%2, %3]</translation>
</message>
<message>
<source>The values of %1 must satisfy: minimum &lt;= initial value &lt;= maximum.</source>
<translation>%1 &lt;= &lt;= </translation>
</message>
<message>
<source>Please select a target well!</source>
<translation></translation>
@ -3740,11 +3445,6 @@ Supported types: Vertical, Vertical Fractured, and Horizontal Multi-Fractured We
<source>Optimized parameters have been applied to the model.</source>
<translation></translation>
</message>
<message>
<source>GA Optimization completed:
</source>
<translation>GA</translation>
</message>
<message>
<source>Optimization Completed</source>
<translation></translation>
@ -3774,27 +3474,14 @@ Supported types: Vertical, Vertical Fractured, and Horizontal Multi-Fractured We
<source>Optimization Stopped</source>
<translation></translation>
</message>
<message>
<source>GA Optimization stopped by user:
</source>
<translation>GA</translation>
</message>
<message>
<source>PSO algorithm selected.</source>
<translation>PSO</translation>
</message>
<message>
<source>GA algorithm selected.</source>
<translation>GA</translation>
</message>
<message>
<source>PSO (Particle Swarm)</source>
<translation>PSO</translation>
</message>
<message>
<source>GA (Genetic Algorithm)</source>
<translation>GA</translation>
</message>
<message>
<source>Darcy</source>
<translation type="unfinished"></translation>
@ -3811,6 +3498,18 @@ Supported types: Vertical, Vertical Fractured, and Horizontal Multi-Fractured We
<source>On</source>
<translation></translation>
</message>
<message>
<source>Fracture conductivity</source>
<translation></translation>
</message>
<message>
<source>Fracture half length</source>
<translation></translation>
</message>
<message>
<source>The minimum value of %1 must be greater than zero for automatic fitting.</source>
<translation>%1 </translation>
</message>
</context>
<context>
<name>nmWxAutomaticfitting</name>

File diff suppressed because one or more lines are too long

@ -17,7 +17,7 @@
<ParaGroup Name="" Alias="储层参数">
<ParaItem Name="h" Alias="储层厚度" Unit="m" Default="10" Max="10000" Min="1e-05" Digit="6" Desc="reservoir thickness" />
<ParaItem Name="Pi" Alias="初始压力" Unit="MPa" Default="40" Max="500" Min="0.1" Digit="6" Desc="initial formation pressure" />
<ParaItem Name="K" Alias="渗透率" Unit="mD" Default="1" Max="10000" Min="0" Digit="6" Desc="permeability" />
<ParaItem Name="K" Alias="渗透率" Unit="Darcy" Default="0.001" Max="10" Min="0" Digit="6" Desc="permeability" />
<ParaItem Name="phi" Alias="孔隙度" Unit="" Default="0.1" Max="1" Min="1e-05" Digit="6" Desc="porosity" />
<ParaItem Name="Cti" Alias="综合压缩系数" Unit="1/MPa" Default="0.001" Max="10" Min="1e-30" Digit="10" Scientific="1" Desc="total compressibility" />
<ParaItem Name="Cf" Alias="岩石压缩系数" Unit="1/MPa" Default="0.0001" Max="10" Min="1e-30" Digit="10" Scientific="1" Desc="rock compressibility" />
@ -90,7 +90,7 @@
<ParaItem Name="Result_W_C" Alias="井筒储集系数" Unit="m^3/MPa" Default="0" Max="1000" Min="0" Digit="6" Desc="result wellbore storage coefficient" />
<ParaItem Name="Result_Pi" Alias="初始地层压力" Unit="MPa" Default="40" Max="500" Min="0.1" Digit="6" Desc="result initial formation pressure" />
<ParaItem Name="Result_K" Alias="渗透率" Unit="mD" Default="1" Max="10000" Min="0" Digit="6" Desc="result permeability" />
<ParaItem Name="Result_K" Alias="渗透率" Unit="Darcy" Default="0.001" Max="10" Min="0" Digit="6" Desc="result permeability" />
<ParaItem Name="Result_h" Alias="储层厚度" Unit="m" Default="10" Max="10000" Min="1e-05" Digit="6" Desc="result reservoir thickness" />
<ParaItem Name="Result_phi" Alias="孔隙度" Unit="" Default="0.1" Max="1" Min="1e-05" Digit="6" Desc="result porosity" />
<ParaItem Name="Result_Cti" Alias="综合压缩系数" Unit="1/MPa" Default="0.001" Max="10" Min="1e-30" Digit="10" Scientific="1" Desc="result total compressibility" />

@ -18,7 +18,7 @@
<ParaGroup Name="" Alias="Reservoir Parameters">
<ParaItem Name="h" Alias="Reservoir Thickness" Unit="m" Default="10" Max="10000" Min="1e-05" Digit="3" Desc="reservoir thickness" />
<ParaItem Name="Pi" Alias="Initial Pressure" Unit="MPa" Default="40" Max="500" Min="0.1" Digit="5" Desc="initial formation pressure" />
<ParaItem Name="K" Alias="Permeability" Unit="mD" Default="1" Max="10000" Min="0" Digit="6" Desc="permeability" />
<ParaItem Name="K" Alias="Permeability" Unit="Darcy" Default="0.001" Max="10" Min="0" Digit="6" Desc="permeability" />
<ParaItem Name="phi" Alias="Porosity" Unit="" Default="0.1" Max="1" Min="1e-05" Digit="4" Desc="porosity" />
<ParaItem Name="Cti" Alias="Total Compressibility" Unit="1/MPa" Default="0.001" Max="10" Min="1e-30" Digit="10" Scientific="1" Desc="total compressibility" />
<ParaItem Name="Cf" Alias="Rock Compressibility" Unit="1/MPa" Default="0.0001" Max="10" Min="1e-30" Digit="10" Scientific="1" Desc="rock compressibility" />
@ -91,7 +91,7 @@
<ParaItem Name="Result_W_C" Alias="Wellbore Storage Coeff" Unit="m^3/MPa" Default="0" Max="1000" Min="0" Digit="6" Desc="result wellbore storage coefficient" />
<ParaItem Name="Result_Pi" Alias="Initial Formation Pressure" Unit="MPa" Default="40" Max="500" Min="0.1" Digit="6" Desc="result initial formation pressure" />
<ParaItem Name="Result_K" Alias="Permeability" Unit="mD" Default="1" Max="10000" Min="0" Digit="6" Desc="result permeability" />
<ParaItem Name="Result_K" Alias="Permeability" Unit="Darcy" Default="0.001" Max="10" Min="0" Digit="6" Desc="result permeability" />
<ParaItem Name="Result_h" Alias="Reservoir Thickness" Unit="m" Default="10" Max="10000" Min="1e-05" Digit="6" Desc="result reservoir thickness" />
<ParaItem Name="Result_phi" Alias="Porosity" Unit="" Default="0.1" Max="1" Min="1e-05" Digit="6" Desc="result porosity" />
<ParaItem Name="Result_Cti" Alias="Total Compressibility" Unit="1/MPa" Default="0.001" Max="10" Min="1e-30" Digit="10" Scientific="1" Desc="result total compressibility" />

@ -166,7 +166,7 @@
<!-- ==================== 第15组渗透率 ==================== -->
<UnitGroup Type="permeability" Name="permeability">
<Unit ID="U1501" Unit="D" k="1" Digit="4" Remark="base unit"/>
<Unit ID="U1501" Unit="Darcy" k="1" Digit="4" Remark="base unit"/>
<Unit ID="U1502" Unit="mD" k="0.001" Digit="4" />
<Unit ID="U1503" Unit="1/cm²" k="9.81e+07" Digit="2"/>

@ -46,7 +46,7 @@
<Unit Remark=" " Unit="fraction" k="100"/>
</UnitGroup>
<UnitGroup Type="permeability" Name="permeability">
<Unit Remark=" " Unit="D" k="1"/>
<Unit Remark=" " Unit="Darcy" k="1"/>
<Unit Remark=" " Unit="mD" k="0.001"/>
<Unit Remark=" " Unit="cm^-2" k="9.81e+07"/>
</UnitGroup>

@ -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
};

@ -1,267 +0,0 @@
#ifndef NMCALCULATIONAUTOFITGA_H
#define NMCALCULATIONAUTOFITGA_H
#include <QObject>
#include <QVector>
#include <QPointF>
#include <QString>
#include <QTimer>
#include <QApplication>
#include <QDateTime>
#include <QCoreApplication>
#include <QDir>
#include <QDebug>
#include <QTime>
#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<double> 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<QVector<double>>& targetData);
bool startAutoFitting();
void stopFitting();
bool isRunning() const;
int getCurrentGeneration() const;
QVector<double> 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<double>& 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<GAIndividual>& 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<double>& parameters) const;
// 双对数数据验证
bool validateLogLogData(const QVector<QVector<double>>& logLogData) const;
// 初始值验证
bool validateInitialValues() const;
// 应用参数到数据管理器
void applyParametersToDataManager(const QVector<double>& parameters);
// 更新储层参数
void updateReservoirParameters(const QVector<double>& parameters);
// 更新井参数
void updateWellParameters(const QVector<double>& parameters);
// 更新井到数据管理器
void updateWellToDataManager(nmDataWellBase* pWell);
// 参数边界约束
void clampToLimits(QVector<double>& parameters) const;
// ==================== 求解器相关方法 ====================
// 运行求解器
QVector<QVector<double>> runSolver();
// 运行EXE求解器
QVector<QVector<double>> runSolverExe();
// 运行Dll求解器
QVector<QVector<double>> runSolverDll();
// 验证求解器结果
bool validateSolverResult(const QVector<QVector<double>>& result) const;
// ==================== 数据处理方法 ====================
// 插值数据
QVector<QPointF> interpolateData(const QVector<QPointF>& source,
const QVector<double>& targetX) const;
// 计算双对数曲线误差
double calculateLogLogCurveError(const QVector<QVector<double>>& target,
const QVector<QVector<double>>& result) const;
// 计算曲线误差
double calculateCurveError(const QVector<QPointF>& curve1,
const QVector<QPointF>& 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<GAIndividual> m_population; // 当前种群
QVector<GAIndividual> m_eliteIndividuals; // 精英个体
GAIndividual m_bestIndividual; // 全局最优个体
// ==================== 评估统计 ====================
int m_totalEvaluations; // 总评估次数
int m_successfulEvaluations; // 成功评估次数
int m_evaluationInProgress; // 正在进行的评估计数
int m_consecutiveFailures; // 连续失败次数
// ==================== 精英保护相关 ====================
QVector<double> m_initialValues; // 用户初始参数值
QVector<double> 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<double> m_convergenceHistory; // 收敛历史
QVector<double> m_diversityHistory; // 多样性历史
// ==================== 参数配置 ====================
QVector<bool> m_parameterSelected; // 参数选择状态
QVector<double> m_parameterLower; // 参数下界
QVector<double> m_parameterUpper; // 参数上界
QVector<int> m_enabledParamIndices; // 启用参数索引
// ==================== 目标数据 ====================
QVector<QVector<double>> m_targetLogLogData; // 目标双对数数据
// ==================== 其他 ====================
QString m_lastError; // 最后错误信息
QTimer* m_progressTimer; // 进度更新定时器
// DLL求解器需要的临时目录
QString m_tempDirectory;
QString m_targetWellName;// 目标井名称
};
#endif // NMCALCULATIONAUTOFITGA_H

@ -9,6 +9,7 @@
#include <QMutex>
#include <QDateTime>
#include <QFile>
#include <limits>
#include "nmCalculation_global.h"
@ -19,6 +20,69 @@ class nmDataWellBase;
class QTimer;
class QProcess;
// 双对数曲线误差分解。该结构同时保存用于候选排序的主目标,以及用于判断
// 曲线上下、左右和形状偏差的诊断量。total 是唯一的接受和排序依据,诊断量
// 只参与信赖域选参,不能再次叠加到 total否则会重复计算同一批曲线残差。
struct AutoFitObjectiveBreakdown {
// valid 表示本次曲线评价完整有效;无效评价统一保留 total=1e10。
// pressureLoss 和 derivativeLoss 均在 log(value) 空间按固定网格计算。
bool valid;
double total;
double pressureLoss;
double derivativeLoss;
// 固定目标网格上的普通对数残差。非代理搜索使用它建立完整 Jacobian
// 向量平方和与 total 的平方一致。
QVector<double> residualVector;
// 上下偏差使用压力和导数残差共享的算术平均中心。
// verticalCommonBias 为正表示模拟曲线整体偏高,为负表示整体偏低;
// verticalReliable=false 时仍保留数值,但不能据此确定参数调整方向。
double verticalCommonBias;
double verticalLoss;
bool verticalReliable;
// 水平偏差在 log(time) 坐标中计算。physicalShift 为正表示模拟曲线相对
// 目标偏右,即相同曲线特征在模拟结果中出现得更晚。
double horizontalPhysicalShift;
double horizontalLoss;
bool horizontalReliable;
// true 表示当前曲线无法可靠区分上下和左右误差;此时禁止使用两类有符号
// 诊断量选参,但去除公共中心后的 shapeLoss 仍可用于局部选参。
bool registrationAmbiguous;
// 去除公共均值中心和可信左右偏差后剩余的整体形状误差verticalReliable
// 只控制能否把公共中心解释为上下参数方向,不改变 shape 的中心化公式。
double shapeLoss;
// 兼容现有 trace 列。当前非代理搜索不再单独识别或调度晚期分量。
double lateDerivativeSlopeBias;
double lateDerivativeTrendLoss;
bool lateDerivativeTrendReliable;
// 模拟曲线对目标固定网格的有效覆盖率,取覆盖点比例与连续 log-time
// 跨度比例中的较小值。低于损失函数门槛时本次评价直接无效。
double coverage;
AutoFitObjectiveBreakdown()
: valid(false)
, total(1.0e10)
, pressureLoss(std::numeric_limits<double>::quiet_NaN())
, derivativeLoss(std::numeric_limits<double>::quiet_NaN())
, verticalCommonBias(std::numeric_limits<double>::quiet_NaN())
, verticalLoss(std::numeric_limits<double>::quiet_NaN())
, verticalReliable(false)
, horizontalPhysicalShift(std::numeric_limits<double>::quiet_NaN())
, horizontalLoss(std::numeric_limits<double>::quiet_NaN())
, horizontalReliable(false)
, registrationAmbiguous(false)
, shapeLoss(std::numeric_limits<double>::quiet_NaN())
, lateDerivativeSlopeBias(std::numeric_limits<double>::quiet_NaN())
, lateDerivativeTrendLoss(std::numeric_limits<double>::quiet_NaN())
, lateDerivativeTrendReliable(false)
, coverage(std::numeric_limits<double>::quiet_NaN())
{}
};
// PSO粒子结构
// 这里的 position / velocity / bestPosition 只保存“用户勾选参与拟合的参数”,
// 不是完整的 11 个储层/井筒参数。完整参数向量会在写 trace 或调用代理模型时
@ -33,6 +97,8 @@ struct AutoFitParticle {
QVector<double> velocity; // 速度
QVector<double> bestPosition; // 真实求解器确认的个体最优位置
QVector<double> guideBestPosition; // 仅用于速度更新的引导位置;不会参与真实 gbest/最终结果
AutoFitObjectiveBreakdown currentObjectiveBreakdown; // 当前真实评价对应的误差分解
AutoFitObjectiveBreakdown bestObjectiveBreakdown; // pbest 对应的误差分解
double fitness; // 当前适应度
double bestFitness; // 真实求解器确认的个体最优适应度
double guideBestObjective; // guideBestPosition 对应的真实或代理目标值
@ -96,6 +162,7 @@ public:
void stopFitting();
QVector<double> getBestSolution() const;
double getBestFitness() const;
AutoFitObjectiveBreakdown getLastObjectiveBreakdown() const;
QString getLastError() const;
bool isRunning() const;
int getCurrentIteration() const;
@ -137,20 +204,26 @@ private:
void loadOptimizationConfig();
void loadParameterBounds();
// ===== PSO核心算法 =====
// ===== 自动拟合核心算法 =====
//
// 主流程:
// 1. extractUserInitialValues(): 从当前项目数据中取用户已有初始解;
// 2. initializeSwarm(): 根据初始解和上下界生成粒子群;
// 3. updateParticle(): 对单个粒子跑真实求解器并计算误差;
// 4. updateGlobalBest(): 只用真实求解器误差更新全局最优;
// 5. updateVelocityAndPosition(): 按 PSO 公式推进下一代粒子。
// 代理开启时保留原 PSO 筛选流程;代理关闭时使用真实求解器驱动的
// 诊断灵敏度信赖域搜索,不依赖 pbest/gbest 速度公式。
void extractUserInitialValues();
void initializeSwarm();
void updateVelocityAndPosition();
double evaluateFitness(const QVector<double>& parameters);
void updateGlobalBest();
void updateParticle(int particleIndex);
// 非代理拟合入口:建立有限差分灵敏度,按诊断分量选择参数,再用有界
// LM/信赖域产生候选;所有候选最终都由真实求解器总误差决定是否接受。
StopReasonPSO runTrustRegionFitting();
// 对一个信赖域候选执行完整真实评价,并一次性返回误差、诊断量、曲线和耗时。
// 返回 false 表示求解失败、损失无效或用户已请求停止。
bool evaluateTrustRegionPoint(const QVector<double>& parameters,
double* fitness,
AutoFitObjectiveBreakdown* breakdown,
QVector<QVector<double> >* curve,
int* elapsedMs);
// ===== 参数应用方法 =====
//
@ -166,6 +239,7 @@ private:
// ===== 求解器相关 =====
QVector<QVector<double> > runSolver();
QVector<QVector<double>> runSolverDll();
bool runFinalFullSolver();
QVector<QVector<double>> runSolverExe();
// ===== 数据处理 =====
@ -220,7 +294,8 @@ private:
double surrogateObjective,
const QString& screeningDecision,
const QVector<double>& pbestPosition,
double pbestObjective);
double pbestObjective,
const AutoFitObjectiveBreakdown* objectiveBreakdown = nullptr);
void writeIterationTraceRows();
QVector<double> buildTraceParameterVector(const QVector<double>& selectedParameters) const;
void resetRunSummary();
@ -276,30 +351,34 @@ private:
bool m_isRunning; // 当前是否有一次自动拟合正在运行。
bool m_shouldStop; // 用户停止标志;主循环和求解器等待循环会定期检查它。
bool m_isPaused; // 预留暂停标志;主循环中有暂停等待逻辑。
int m_currentIteration; // 当前 PSO 迭代序号,从 0 开始。
int m_currentIteration; // 当前自动拟合迭代序号,从 0 开始。
QString m_lastError; // 最近一次失败原因,供 UI 展示或日志排查。
// ===== PSO数据 =====
// ===== 优化状态数据 =====
QVector<double> m_initialValues; // 当前模型中提取的用户初始值,顺序与 m_enabledParamIndices 一致。
QVector<AutoFitParticle> m_swarm; // 粒子群,每个粒子只保存启用参数维度。
QVector<double> m_globalBestPosition; // 全局最优参数,仍是启用参数向量
QVector<double> m_globalBestPosition; // 真实求解器确认的当前最优参数
double m_globalBestFitness; // 全局最优真实误差,越小越好。
double m_previousBestFitness; // 上一轮全局最优误差,用于自适应参数更新。
AutoFitObjectiveBreakdown m_globalBestObjectiveBreakdown; // 真实 gbest 对应的误差分解。
QVector<QVector<double> > m_lastEvaluatedLogLogData; // 最近一次真实求解得到的 result log-log 曲线。
QVector<QVector<double> > m_globalBestLogLogData; // 当前全局最优对应的 result log-log 曲线。
mutable AutoFitObjectiveBreakdown m_lastObjectiveBreakdown; // 最近一次损失评价的误差分解。
QVector<QVector<double> > m_userInitialLogLogData; // 用户初始解对应的 result log-log 曲线,用于精英保护。
AutoFitObjectiveBreakdown m_userInitialObjectiveBreakdown; // 用户初始解对应的误差分解。
// ===== 优化配置 =====
//
// 参数索引约定:
// 0 k 渗透率1 skin 表皮系数2 wellboreC 井筒储集;
// 3 phi 孔隙度4 h 储层厚度5 Ct 综合压缩系数;
// 6 Cf 岩石压缩系数7 Swi 初始含水饱和度。
// 6 Cf 岩石压缩系数7 Swi 初始含水饱和度;
// 8 Dfc 裂缝导流能力9 fractureHalfLength 裂缝半长。
// m_enabledParamIndices 保存被用户勾选的参数索引,粒子的 position 维度与它一致。
QVector<bool> m_parameterSelected; // 完整 8 个参数是否被用户勾选参与拟合。
QVector<double> m_parameterLower; // 完整 8 个参数的搜索下界。
QVector<double> m_parameterUpper; // 完整 8 个参数的搜索上界。
QVector<int> m_enabledParamIndices; // 被勾选参数在完整 8 维体系中的索引。
QVector<bool> m_parameterSelected; // 完整 10 个参数是否被用户勾选参与拟合。
QVector<double> m_parameterLower; // 完整 10 个参数的搜索下界。
QVector<double> m_parameterUpper; // 完整 10 个参数的搜索上界。
QVector<int> m_enabledParamIndices; // 被勾选参数在完整 10 维体系中的索引。
QVector<QVector<double> > m_targetLogLogData; // 目标井 history log-log 曲线time/pressure/derivative。
QString m_targetWellName; // 目标井名称;读写井参数和读取模拟曲线都依赖它。
@ -312,7 +391,7 @@ private:
double m_socialParam; // 群体学习因子,控制粒子靠近全局 gbest 的程度。
// ===== 统计信息 =====
int m_totalEvaluations; // 已调用真实求解器评价的粒子总数
int m_totalEvaluations; // 真实求解器评价总次数,包含粒子评价和方向试算
int m_successfulEvaluations; // 真实求解器成功且误差有效的评价次数。
QVector<double> m_convergenceHistory; // 每代全局最优误差历史,用于收敛判断。
@ -328,7 +407,7 @@ private:
// ===== 精英保护 =====
QVector<double> m_userInitialSolution; // 用户初始解参数,若最终改进不足会恢复它。
double m_userInitialFitness; // 用户初始解真实误差。
double m_improvementThreshold; // 最终结果相对初始解至少需要达到的改进阈值
double m_improvementThreshold; // 仅用于日志区分显著改进和微小改进
bool m_hasValidUserSolution; // 初始解是否成功跑过真实求解器。
int m_consecutiveFailedIterations; // 连续失败迭代次数
@ -357,8 +436,8 @@ private:
// 这些字段只描述代理筛选和运行复盘,不参与 PSO 数学更新。
bool m_traceEnabled; // 是否写出 trace CSV/meta 文件。
QString m_traceRunId; // 本次运行 ID作为 trace/candidate/score 文件名的一部分。
QString m_traceFilePath; // pso_baseline_trace_<run_id>.csv 完整路径。
QString m_traceMetaFilePath; // pso_baseline_trace_<run_id>.meta.json 完整路径。
QString m_traceFilePath; // 本次自动拟合 trace CSV 的完整路径。
QString m_traceMetaFilePath; // 与 trace 匹配的 meta JSON 完整路径。
QFile m_traceFile; // trace CSV 文件句柄。
bool m_surrogateScreeningEnabled; // 用户配置中的 PSO acceleration 开关。
unsigned int m_psoRandomSeed; // PSO 随机种子,也用于可复现 random audit。

@ -2,6 +2,8 @@
#define NMCALCULATIONDLLPEBISOLVERTASK_H
#include <QThread>
#include <QString>
#include <QVector>
#include <iostream>
#include <vector>
#include <Windows.h>
@ -22,6 +24,13 @@ class NMCALCULATION_EXPORT nmCalculationDllPebiSolverTask : public QThread {
// 返回 false 时调用方会丢弃本次结果, 防止复用上一粒子留下的旧曲线.
bool wasSuccessful() const;
// 自动拟合粒子评价只提取目标井曲线,不写回共享数据和网格压力场。
// 井名为空时保持原有完整结果保存模式。
void setAutoFitTargetWell(const QString& wellName);
QVector<QVector<double> > getAutoFitResultPressure() const;
QVector<QVector<double> > getAutoFitResultLogLog() const;
QVector<QVector<double> > getAutoFitResultSemiLog() const;
private:
bool execute();
@ -37,6 +46,10 @@ class NMCALCULATION_EXPORT nmCalculationDllPebiSolverTask : public QThread {
QString m_sPostprocessingDir;
// run() 在线程内保存 execute() 结果, 等待线程结束的调用方只读取该状态.
bool m_lastRunSucceeded;
QString m_autoFitTargetWellName;
QVector<QVector<double> > m_autoFitResultPressure;
QVector<QVector<double> > m_autoFitResultLogLog;
QVector<QVector<double> > m_autoFitResultSemiLog;
private slots:
//void slotTaskUpdateProgress();

@ -75,6 +75,20 @@ public:
nmDataAttribute& getSwiMin();
void setSwiMin(const nmDataAttribute& swiMin);
// Getter and Setter for fractureConductivityMax
nmDataAttribute& getFractureConductivityMax();
void setFractureConductivityMax(const nmDataAttribute& fractureConductivityMax);
// Getter and Setter for fractureConductivityMin
nmDataAttribute& getFractureConductivityMin();
void setFractureConductivityMin(const nmDataAttribute& fractureConductivityMin);
// Getter and Setter for fractureHalfLengthMax
nmDataAttribute& getFractureHalfLengthMax();
void setFractureHalfLengthMax(const nmDataAttribute& fractureHalfLengthMax);
// Getter and Setter for fractureHalfLengthMin
nmDataAttribute& getFractureHalfLengthMin();
void setFractureHalfLengthMin(const nmDataAttribute& fractureHalfLengthMin);
// Getter and Setter for iteration count
nmDataAttribute& getIterationCount();
void setIterationCount(const nmDataAttribute& iterationCount);
@ -114,6 +128,12 @@ public:
bool getSwiSelected() const;
void setSwiSelected(bool selected);
bool getFractureConductivitySelected() const;
void setFractureConductivitySelected(bool selected);
bool getFractureHalfLengthSelected() const;
void setFractureHalfLengthSelected(bool selected);
private:
// 参数最大值
nmDataAttribute m_permeabilityMax;
@ -124,6 +144,8 @@ private:
nmDataAttribute m_ctMax;
nmDataAttribute m_cfMax;
nmDataAttribute m_swiMax;
nmDataAttribute m_fractureConductivityMax;
nmDataAttribute m_fractureHalfLengthMax;
// 参数最小值
nmDataAttribute m_permeabilityMin;
@ -134,6 +156,8 @@ private:
nmDataAttribute m_ctMin;
nmDataAttribute m_cfMin;
nmDataAttribute m_swiMin;
nmDataAttribute m_fractureConductivityMin;
nmDataAttribute m_fractureHalfLengthMin;
// 迭代参数
nmDataAttribute m_iterationCount; // 迭代步数
@ -150,6 +174,8 @@ private:
bool m_ctSelected; // 是否选择综合压缩系数进行拟合
bool m_cfSelected; // 是否选择岩石压缩系数进行拟合
bool m_swiSelected; // 是否选择初始含水饱和度进行拟合
bool m_fractureConductivitySelected; // 是否选择裂缝导流能力进行拟合
bool m_fractureHalfLengthSelected; // 是否选择裂缝半长进行拟合
};
#endif // NMDATAAUTOMATICFITTING_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);
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<QVector<double>>& targetData, const QStringList& selectedParams, const QString& targetWellName);
void cleanupFitting();
@ -92,6 +91,8 @@ private:
QCheckBox* m_ctCheckBox; // 综合压缩系数
QCheckBox* m_cfCheckBox; // 岩石压缩系数
QCheckBox* m_swiCheckBox; // 初始含水饱和度
QCheckBox* m_dfcCheckBox; // 裂缝导流能力
QCheckBox* m_fractureHalfLengthCheckBox; // 裂缝半长
// 按钮
QPushButton* m_reverseBtn;
@ -108,10 +109,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;

@ -22,12 +22,10 @@
#include <QRectF>
#include <QSplitter>
#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;

@ -5,6 +5,7 @@
class nmGridRowUtils;
class nmDataAnalyzeManager;
class QTimer;
/// @brief PEBI求解器专用的参数输入/编辑属性对话框窗体
/// @note 与 nmWxParaProperty 结构一致,区别在于内部使用 nmGridRowUtilsNM子类
@ -76,6 +77,8 @@ public slots:
void slotWellRemoved(QString wellCode, QString wellName);
/// @brief 几何对象新增、删除或改名后重建参数面板
void slotGeometryListChanged();
/// @brief 合并同一轮事件中的多次井列表变化,只重建一次参数面板
void slotDeferredWellListRebuild();
protected:
@ -93,6 +96,13 @@ protected:
// 数据管理器引用(用于全量重建面板时获取井和几何对象列表)
nmDataAnalyzeManager* m_pDataManager;
// 批量增删井时合并参数面板刷新
QTimer* m_pWellListRebuildTimer;
private:
void scheduleWellListRebuild();
signals:
/// @brief 参数值变更信号(由 slotParaCtrlValueChanged 转发)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -333,6 +333,26 @@ bool nmCalculationDllPebiSolverTask::wasSuccessful() const
return m_lastRunSucceeded;
}
void nmCalculationDllPebiSolverTask::setAutoFitTargetWell(const QString& wellName)
{
m_autoFitTargetWellName = wellName;
}
QVector<QVector<double> > nmCalculationDllPebiSolverTask::getAutoFitResultPressure() const
{
return m_autoFitResultPressure;
}
QVector<QVector<double> > nmCalculationDllPebiSolverTask::getAutoFitResultLogLog() const
{
return m_autoFitResultLogLog;
}
QVector<QVector<double> > nmCalculationDllPebiSolverTask::getAutoFitResultSemiLog() const
{
return m_autoFitResultSemiLog;
}
bool nmCalculationDllPebiSolverTask::execute()
{
return this->execPebiMode();
@ -703,6 +723,15 @@ bool nmCalculationDllPebiSolverTask::savePebiModeResult(
int modelType)
{
nmDataAnalyzeManager* pDataInstance = nmDataAnalyzeManager::getCurrentInstance();
if(pDataInstance == nullptr) {
return false;
}
const bool autoFitTargetOnly = !m_autoFitTargetWellName.isEmpty();
bool autoFitTargetFound = false;
m_autoFitResultPressure.clear();
m_autoFitResultLogLog.clear();
m_autoFitResultSemiLog.clear();
QVector<QVector<double>> vvecPressure;
QVector<QVector<double>> vvecLogLog;
@ -720,16 +749,22 @@ bool nmCalculationDllPebiSolverTask::savePebiModeResult(
}
// 获取参与求解的井的顺序
QVector<QPair<NM_WELL_MODEL, QString>> vecWellsOrder = nmDataAnalyzeManager::getCurrentInstance()->getCalculationWells();
QVector<QPair<NM_WELL_MODEL, QString>> vecWellsOrder = pDataInstance->getCalculationWells();
// 清空井名和二维位置的映射
pDataInstance->clearWellLocations();
// 粒子评价不修改全局井位置,完整求解仍按原流程重建映射.
if(!autoFitTargetOnly) {
pDataInstance->clearWellLocations();
}
// 遍历每口井,处理其数据
for(int wellIdx = 0; wellIdx < vecWellsOrder.size(); ++wellIdx) {
NM_WELL_MODEL eWellType = vecWellsOrder[wellIdx].first; // 获取井的类型
QString sWellName = vecWellsOrder[wellIdx].second; // 获取井的名称
if(autoFitTargetOnly && sWellName != m_autoFitTargetWellName) {
continue;
}
// 跳过裂缝(或未知井类型)
if(eWellType == NM_WELL_MODEL::Unknow_Well) {
continue;
@ -881,17 +916,34 @@ bool nmCalculationDllPebiSolverTask::savePebiModeResult(
}
}
// 将计算结果保存到对应的井数据里
// 压力
pWellData->setResultPressure(vvecPressure);
// 双对数
pWellData->setResultLogLog(vvecLogLog);
// 半对数
pWellData->setResultSemiLog(vvecSemiLog);
// 存储当前井名称和二维位置到映射
QPointF ptWellCoords(pWellData->getX().getValue().toDouble(), pWellData->getY().getValue().toDouble());
pDataInstance->addWellLocation(sWellName, ptWellCoords);
if(autoFitTargetOnly) {
// 粒子评价结果保存在任务对象内,避免反复改写 DataManager.
m_autoFitResultPressure = vvecPressure;
m_autoFitResultLogLog = vvecLogLog;
m_autoFitResultSemiLog = vvecSemiLog;
autoFitTargetFound = true;
break;
} else {
// 完整模式保持原行为:写入全部井曲线和井位置.
pWellData->setResultPressure(vvecPressure);
pWellData->setResultLogLog(vvecLogLog);
pWellData->setResultSemiLog(vvecSemiLog);
QPointF ptWellCoords(pWellData->getX().getValue().toDouble(), pWellData->getY().getValue().toDouble());
pDataInstance->addWellLocation(sWellName, ptWellCoords);
}
}
if(autoFitTargetOnly) {
const bool pressureValid = autoFitTargetFound
&& m_autoFitResultPressure.size() >= 2
&& !m_autoFitResultPressure[0].isEmpty()
&& m_autoFitResultPressure[0].size() == m_autoFitResultPressure[1].size();
const bool logLogValid = m_autoFitResultLogLog.size() >= 3
&& !m_autoFitResultLogLog[0].isEmpty()
&& m_autoFitResultLogLog[0].size() == m_autoFitResultLogLog[1].size()
&& m_autoFitResultLogLog[0].size() == m_autoFitResultLogLog[2].size();
return pressureValid && logLogValid;
}
// 计算有效单元数量

@ -11,26 +11,31 @@ nmDataAutomaticFitting::nmDataAutomaticFitting()
m_ctSelected = true; // 默认选中
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_fractureConductivitySelected = false; // 仅压裂井可用,默认不选中
m_fractureHalfLengthSelected = false; // 仅压裂井可用,默认不选中
// 拟合上下界不再使用固定默认值,由自动拟合窗口按数据对象初值和物理边界生成。
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_fractureConductivityMax = nmDataAttribute("Fracture Conductivity Max", QVariant(), "md.m");
m_fractureHalfLengthMax = nmDataAttribute("Fracture Half Length Max", QVariant(), "m");
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_fractureConductivityMin = nmDataAttribute("Fracture Conductivity Min", QVariant(), "md.m");
m_fractureHalfLengthMin = nmDataAttribute("Fracture Half Length Min", QVariant(), "m");
// 初始化迭代参数
m_iterationCount = nmDataAttribute("Iteration Count", 20, "");
@ -60,6 +65,8 @@ nmDataAutomaticFitting& nmDataAutomaticFitting::operator=(const nmDataAutomaticF
m_ctSelected = other.m_ctSelected;
m_cfSelected = other.m_cfSelected;
m_swiSelected = other.m_swiSelected;
m_fractureConductivitySelected = other.m_fractureConductivitySelected;
m_fractureHalfLengthSelected = other.m_fractureHalfLengthSelected;
// 复制参数最大值
m_permeabilityMax = other.m_permeabilityMax;
@ -70,6 +77,8 @@ nmDataAutomaticFitting& nmDataAutomaticFitting::operator=(const nmDataAutomaticF
m_ctMax = other.m_ctMax;
m_cfMax = other.m_cfMax;
m_swiMax = other.m_swiMax;
m_fractureConductivityMax = other.m_fractureConductivityMax;
m_fractureHalfLengthMax = other.m_fractureHalfLengthMax;
// 复制参数最小值
m_permeabilityMin = other.m_permeabilityMin;
@ -80,6 +89,8 @@ nmDataAutomaticFitting& nmDataAutomaticFitting::operator=(const nmDataAutomaticF
m_ctMin = other.m_ctMin;
m_cfMin = other.m_cfMin;
m_swiMin = other.m_swiMin;
m_fractureConductivityMin = other.m_fractureConductivityMin;
m_fractureHalfLengthMin = other.m_fractureHalfLengthMin;
// 复制迭代参数
m_iterationCount = other.m_iterationCount;
@ -103,6 +114,8 @@ rapidjson::Value nmDataAutomaticFitting::ToJsonValue(rapidjson::Document::Alloca
fittingObject.AddMember("CtSelected", m_ctSelected, allocator);
fittingObject.AddMember("CfSelected", m_cfSelected, allocator);
fittingObject.AddMember("SwiSelected", m_swiSelected, allocator);
fittingObject.AddMember("FractureConductivitySelected", m_fractureConductivitySelected, allocator);
fittingObject.AddMember("FractureHalfLengthSelected", m_fractureHalfLengthSelected, allocator);
// 序列化参数最大值
fittingObject.AddMember("PermeabilityMax", m_permeabilityMax.ToJsonValue(allocator), allocator);
@ -113,6 +126,8 @@ rapidjson::Value nmDataAutomaticFitting::ToJsonValue(rapidjson::Document::Alloca
fittingObject.AddMember("CtMax", m_ctMax.ToJsonValue(allocator), allocator);
fittingObject.AddMember("CfMax", m_cfMax.ToJsonValue(allocator), allocator);
fittingObject.AddMember("SwiMax", m_swiMax.ToJsonValue(allocator), allocator);
fittingObject.AddMember("FractureConductivityMax", m_fractureConductivityMax.ToJsonValue(allocator), allocator);
fittingObject.AddMember("FractureHalfLengthMax", m_fractureHalfLengthMax.ToJsonValue(allocator), allocator);
// 序列化参数最小值
fittingObject.AddMember("PermeabilityMin", m_permeabilityMin.ToJsonValue(allocator), allocator);
@ -123,6 +138,8 @@ rapidjson::Value nmDataAutomaticFitting::ToJsonValue(rapidjson::Document::Alloca
fittingObject.AddMember("CtMin", m_ctMin.ToJsonValue(allocator), allocator);
fittingObject.AddMember("CfMin", m_cfMin.ToJsonValue(allocator), allocator);
fittingObject.AddMember("SwiMin", m_swiMin.ToJsonValue(allocator), allocator);
fittingObject.AddMember("FractureConductivityMin", m_fractureConductivityMin.ToJsonValue(allocator), allocator);
fittingObject.AddMember("FractureHalfLengthMin", m_fractureHalfLengthMin.ToJsonValue(allocator), allocator);
// 序列化迭代参数
fittingObject.AddMember("IterationCount", m_iterationCount.ToJsonValue(allocator), allocator);
@ -160,6 +177,12 @@ void nmDataAutomaticFitting::FromJsonValue(const rapidjson::Value& jsonValue)
if (jsonValue.HasMember("SwiSelected") && jsonValue["SwiSelected"].IsBool()) {
m_swiSelected = jsonValue["SwiSelected"].GetBool();
}
if (jsonValue.HasMember("FractureConductivitySelected") && jsonValue["FractureConductivitySelected"].IsBool()) {
m_fractureConductivitySelected = jsonValue["FractureConductivitySelected"].GetBool();
}
if (jsonValue.HasMember("FractureHalfLengthSelected") && jsonValue["FractureHalfLengthSelected"].IsBool()) {
m_fractureHalfLengthSelected = jsonValue["FractureHalfLengthSelected"].GetBool();
}
// 反序列化参数最大值
if (jsonValue.HasMember("PermeabilityMax") && jsonValue["PermeabilityMax"].IsObject()) {
@ -186,6 +209,12 @@ void nmDataAutomaticFitting::FromJsonValue(const rapidjson::Value& jsonValue)
if (jsonValue.HasMember("SwiMax") && jsonValue["SwiMax"].IsObject()) {
m_swiMax.FromJsonValue(jsonValue["SwiMax"]);
}
if (jsonValue.HasMember("FractureConductivityMax") && jsonValue["FractureConductivityMax"].IsObject()) {
m_fractureConductivityMax.FromJsonValue(jsonValue["FractureConductivityMax"]);
}
if (jsonValue.HasMember("FractureHalfLengthMax") && jsonValue["FractureHalfLengthMax"].IsObject()) {
m_fractureHalfLengthMax.FromJsonValue(jsonValue["FractureHalfLengthMax"]);
}
// 反序列化参数最小值
if (jsonValue.HasMember("PermeabilityMin") && jsonValue["PermeabilityMin"].IsObject()) {
@ -212,6 +241,12 @@ void nmDataAutomaticFitting::FromJsonValue(const rapidjson::Value& jsonValue)
if (jsonValue.HasMember("SwiMin") && jsonValue["SwiMin"].IsObject()) {
m_swiMin.FromJsonValue(jsonValue["SwiMin"]);
}
if (jsonValue.HasMember("FractureConductivityMin") && jsonValue["FractureConductivityMin"].IsObject()) {
m_fractureConductivityMin.FromJsonValue(jsonValue["FractureConductivityMin"]);
}
if (jsonValue.HasMember("FractureHalfLengthMin") && jsonValue["FractureHalfLengthMin"].IsObject()) {
m_fractureHalfLengthMin.FromJsonValue(jsonValue["FractureHalfLengthMin"]);
}
// 反序列化迭代参数
if (jsonValue.HasMember("IterationCount") && jsonValue["IterationCount"].IsObject()) {
@ -254,6 +289,12 @@ void nmDataAutomaticFitting::setCfSelected(bool selected) { m_cfSelected = selec
bool nmDataAutomaticFitting::getSwiSelected() const { return m_swiSelected; }
void nmDataAutomaticFitting::setSwiSelected(bool selected) { m_swiSelected = selected; }
bool nmDataAutomaticFitting::getFractureConductivitySelected() const { return m_fractureConductivitySelected; }
void nmDataAutomaticFitting::setFractureConductivitySelected(bool selected) { m_fractureConductivitySelected = selected; }
bool nmDataAutomaticFitting::getFractureHalfLengthSelected() const { return m_fractureHalfLengthSelected; }
void nmDataAutomaticFitting::setFractureHalfLengthSelected(bool selected) { m_fractureHalfLengthSelected = selected; }
// Getter and Setter implementations for Max values
nmDataAttribute& nmDataAutomaticFitting::getPermeabilityMax() { return m_permeabilityMax; }
@ -280,6 +321,12 @@ void nmDataAutomaticFitting::setCfMax(const nmDataAttribute& cfMax) { m_cfMax =
nmDataAttribute& nmDataAutomaticFitting::getSwiMax() { return m_swiMax; }
void nmDataAutomaticFitting::setSwiMax(const nmDataAttribute& swiMax) { m_swiMax = swiMax; }
nmDataAttribute& nmDataAutomaticFitting::getFractureConductivityMax() { return m_fractureConductivityMax; }
void nmDataAutomaticFitting::setFractureConductivityMax(const nmDataAttribute& fractureConductivityMax) { m_fractureConductivityMax = fractureConductivityMax; }
nmDataAttribute& nmDataAutomaticFitting::getFractureHalfLengthMax() { return m_fractureHalfLengthMax; }
void nmDataAutomaticFitting::setFractureHalfLengthMax(const nmDataAttribute& fractureHalfLengthMax) { m_fractureHalfLengthMax = fractureHalfLengthMax; }
// Getter and Setter implementations for Min values
nmDataAttribute& nmDataAutomaticFitting::getPermeabilityMin() { return m_permeabilityMin; }
void nmDataAutomaticFitting::setPermeabilityMin(const nmDataAttribute& permeabilityMin) { m_permeabilityMin = permeabilityMin; }
@ -305,6 +352,12 @@ void nmDataAutomaticFitting::setCfMin(const nmDataAttribute& cfMin) { m_cfMin =
nmDataAttribute& nmDataAutomaticFitting::getSwiMin() { return m_swiMin; }
void nmDataAutomaticFitting::setSwiMin(const nmDataAttribute& swiMin) { m_swiMin = swiMin; }
nmDataAttribute& nmDataAutomaticFitting::getFractureConductivityMin() { return m_fractureConductivityMin; }
void nmDataAutomaticFitting::setFractureConductivityMin(const nmDataAttribute& fractureConductivityMin) { m_fractureConductivityMin = fractureConductivityMin; }
nmDataAttribute& nmDataAutomaticFitting::getFractureHalfLengthMin() { return m_fractureHalfLengthMin; }
void nmDataAutomaticFitting::setFractureHalfLengthMin(const nmDataAttribute& fractureHalfLengthMin) { m_fractureHalfLengthMin = fractureHalfLengthMin; }
// Getter and Setter implementations for iteration parameters
nmDataAttribute& nmDataAutomaticFitting::getIterationCount() { return m_iterationCount; }
void nmDataAutomaticFitting::setIterationCount(const nmDataAttribute& iterationCount) { m_iterationCount = iterationCount; }

@ -65,6 +65,7 @@
#include "iAnalRun.h"
#include <QVector>
#include <QSet>
#include "nmSingalCenter.h"
@ -995,8 +996,18 @@ void nmSubWndMain::updateSelectedWells(QList<ZxDataWell *> wellObjList)
}
}
// 当前在画布上的所有 ZxDataWell* 数据列表 (Key Set)
// 用集合保存当前井和选中井,避免井数增加后反复调用 QList::contains 造成平方级查找。
QList<ZxDataWell*> pWellPlotDataList = pWellDataToPlotMap.keys();
QSet<ZxDataWell*> pWellPlotDataSet;
for(int i = 0; i < pWellPlotDataList.count(); ++i) {
pWellPlotDataSet.insert(pWellPlotDataList[i]);
}
QSet<ZxDataWell*> selectedWellDataSet;
for(int i = 0; i < wellObjList.count(); ++i) {
if(wellObjList[i] != nullptr) {
selectedWellDataSet.insert(wellObjList[i]);
}
}
// setp 2找出需要 REMOVE (删除) 的图元
QVector<nmObjPointWell*> vDeleteWellPlotList;
@ -1005,7 +1016,7 @@ void nmSubWndMain::updateSelectedWells(QList<ZxDataWell *> wellObjList)
for(int i = 0; i < pWellPlotDataList.count(); ++i) {
ZxDataWell *pWellDataOnPlot = pWellPlotDataList[i];
// 如果该井数据不在用户选中的列表 wellObjList 中,则需要删除
if (!wellObjList.contains(pWellDataOnPlot)) {
if (!selectedWellDataSet.contains(pWellDataOnPlot)) {
// 从 Map 中获取对应的图元对象
vDeleteWellPlotList.append(pWellDataToPlotMap.value(pWellDataOnPlot));
}
@ -1018,12 +1029,16 @@ void nmSubWndMain::updateSelectedWells(QList<ZxDataWell *> wellObjList)
for(int i = 0; i < wellObjList.count(); ++i) {
ZxDataWell *pWellDataSelected = wellObjList[i];
// 确保井数据有效
if (pWellDataSelected && !pWellPlotDataList.contains(pWellDataSelected)) {
if (pWellDataSelected && !pWellPlotDataSet.contains(pWellDataSelected)) {
// 如果该井数据不在当前画布上的数据列表中,则需要添加
vAddWellPlotList.append(pWellDataSelected);
}
}
// 单井增删过程中会多次请求重绘;批量阶段先暂停,全部处理完成后再统一刷新。
const bool updatesEnabled = m_pWxPlot->updatesEnabled();
m_pWxPlot->setUpdatesEnabled(false);
// setp 4执行删除操作
for(int i = 0; i < vDeleteWellPlotList.count(); ++i) {
nmObjPointWell* pWellPlot = vDeleteWellPlotList[i];
@ -1065,7 +1080,10 @@ void nmSubWndMain::updateSelectedWells(QList<ZxDataWell *> wellObjList)
// 添加完毕后,重新渲染
m_pWxPlot->update();
m_pWxPlot->setUpdatesEnabled(updatesEnabled);
if(updatesEnabled) {
m_pWxPlot->update();
}
}
// 地质图导入

File diff suppressed because it is too large Load Diff

@ -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<double> bestSolution = m_autoFitterPSO->getBestSolution();
if (i < bestSolution.size()) {
valueText = formatScientific(bestSolution[i]);
}
} else if (m_algorithmType == FITTING_ALGORITHM_GA && m_autoFitterGA) {
QVector<double> 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 {

@ -23,6 +23,7 @@
#include <QCoreApplication>
#include <QSet>
#include <QTimer>
#include "nmWxParaPropertyPebi.h"
@ -194,6 +195,11 @@ nmWxParaPropertyPebi::nmWxParaPropertyPebi(QWidget* parent) :
m_listParas.clear();
m_pGridItemUtils = nullptr;
m_pDataManager = nullptr;
// 0ms 单次定时器用于合并同一轮事件中的多次井增删通知。
m_pWellListRebuildTimer = new QTimer(this);
m_pWellListRebuildTimer->setSingleShot(true);
connect(m_pWellListRebuildTimer, SIGNAL(timeout()),
this, SLOT(slotDeferredWellListRebuild()));
setWindowTitle(tr("Numerical para property"));
}
@ -357,6 +363,12 @@ void nmWxParaPropertyPebi::slotParaCtrlValueChanged(QString sPara, QVariant o)
void nmWxParaPropertyPebi::rebuildAllParas()
{
// 已有显式全量重建时,取消尚未执行的延迟刷新,避免重复重建面板。
if (m_pWellListRebuildTimer != nullptr && m_pWellListRebuildTimer->isActive())
{
m_pWellListRebuildTimer->stop();
}
if (m_pMainLayout == nullptr || m_pDataManager == nullptr)
return;
@ -746,13 +758,27 @@ void nmWxParaPropertyPebi::slotWellAdded(QString wellCode, QString wellName, QSt
Q_UNUSED(wellCode);
Q_UNUSED(wellName);
Q_UNUSED(paras);
rebuildAllParas();
scheduleWellListRebuild();
}
void nmWxParaPropertyPebi::slotWellRemoved(QString wellCode, QString wellName)
{
Q_UNUSED(wellCode);
Q_UNUSED(wellName);
scheduleWellListRebuild();
}
void nmWxParaPropertyPebi::scheduleWellListRebuild()
{
if (m_pWellListRebuildTimer != nullptr)
{
// 批量循环内重复 start 会重置同一个单次定时器,返回事件循环后只触发一次。
m_pWellListRebuildTimer->start(0);
}
}
void nmWxParaPropertyPebi::slotDeferredWellListRebuild()
{
rebuildAllParas();
}

Loading…
Cancel
Save