fix(numerical): 修复停止拟合后结果未刷新

- LM 和 PSO 停止优化后保留当前最优参数并执行最终完整求解
- 最终求解成功后提交正式结果快照并刷新主界面
- 增加最终结果生成状态,避免重复停止及未提交快照时误报成功
feature/Adapt-Autofit-20260904
lvjunjie 4 weeks ago
parent b9181b9dce
commit 27256f9c59

@ -90,6 +90,8 @@ signals:
QVector<QVector<double> > bestData, QVector<QVector<double> > bestData,
int iteration, int iteration,
double fitness); double fitness);
/** @brief 优化迭代结束,开始用当前最优参数生成正式结果。 */
void finalizingStarted();
void logMessageGenerated(const QString& message); void logMessageGenerated(const QString& message);
private: private:
@ -149,6 +151,7 @@ private:
private: private:
bool m_isRunning; bool m_isRunning;
bool m_shouldStop; bool m_shouldStop;
bool m_isFinalizing;
int m_currentIteration; int m_currentIteration;
QString m_lastError; QString m_lastError;

@ -119,6 +119,8 @@ signals:
QVector<QVector<double> > bestData, QVector<QVector<double> > bestData,
int iteration, int iteration,
double fitness); double fitness);
/** @brief 优化迭代结束,开始用当前最优参数生成正式结果。 */
void finalizingStarted();
signals: signals:
@ -274,6 +276,7 @@ private:
// ===== 运行状态 ===== // ===== 运行状态 =====
bool m_isRunning; // 当前是否有一次自动拟合正在运行。 bool m_isRunning; // 当前是否有一次自动拟合正在运行。
bool m_shouldStop; // 用户停止标志;主循环和求解器等待循环会定期检查它。 bool m_shouldStop; // 用户停止标志;主循环和求解器等待循环会定期检查它。
bool m_isFinalizing; // 正在用最优参数生成正式结果,此阶段不再接受停止请求。
bool m_isPaused; // 预留暂停标志;主循环中有暂停等待逻辑。 bool m_isPaused; // 预留暂停标志;主循环中有暂停等待逻辑。
int m_currentIteration; // 当前 PSO 迭代序号,从 0 开始。 int m_currentIteration; // 当前 PSO 迭代序号,从 0 开始。
QString m_lastError; // 最近一次失败原因,供 UI 展示或日志排查。 QString m_lastError; // 最近一次失败原因,供 UI 展示或日志排查。

@ -93,6 +93,7 @@ public:
public slots: public slots:
void onFittingProgress(int iteration, double fitness); void onFittingProgress(int iteration, double fitness);
void onFittingFinished(bool success, const QString& message); void onFittingFinished(bool success, const QString& message);
void onFinalizingStarted();
void onStopButtonClicked(); void onStopButtonClicked();
void onLogMessageReceived(const QString& message); void onLogMessageReceived(const QString& message);
void onBestCurveUpdated(QVector<QVector<double> > targetData, void onBestCurveUpdated(QVector<QVector<double> > targetData,
@ -163,6 +164,7 @@ private:
QString m_wellName; QString m_wellName;
QStringList m_selectedParameters; QStringList m_selectedParameters;
bool m_isFinished; bool m_isFinished;
bool m_isFinalizing;
double m_bestFitnessEver; double m_bestFitnessEver;
QDateTime m_startTime; QDateTime m_startTime;

@ -470,6 +470,7 @@ nmCalculationAutoFitLM::nmCalculationAutoFitLM(QObject* parent)
: QObject(parent) : QObject(parent)
, m_isRunning(false) , m_isRunning(false)
, m_shouldStop(false) , m_shouldStop(false)
, m_isFinalizing(false)
, m_currentIteration(0) , m_currentIteration(0)
, m_globalBestFitness(1e10) , m_globalBestFitness(1e10)
, m_maxIterations(100) , m_maxIterations(100)
@ -568,6 +569,12 @@ void nmCalculationAutoFitLM::setTargetLogLogData(const QVector<QVector<double> >
void nmCalculationAutoFitLM::stopFitting() void nmCalculationAutoFitLM::stopFitting()
{ {
if(m_isFinalizing) {
emit logMessageGenerated(
tr("The final full-field calculation is already running"));
return;
}
// 用户点击停止时只设置请求标志,让 LM 主循环和求解器等待逻辑自然退出。 // 用户点击停止时只设置请求标志,让 LM 主循环和求解器等待逻辑自然退出。
if(m_isRunning) { if(m_isRunning) {
emit logMessageGenerated(tr("=== User Stop Request Received ===")); emit logMessageGenerated(tr("=== User Stop Request Received ==="));
@ -659,6 +666,7 @@ void nmCalculationAutoFitLM::resetOptimizer()
m_userInitialFitness = 1e10; m_userInitialFitness = 1e10;
m_hasValidUserSolution = false; m_hasValidUserSolution = false;
m_traceMetaFilePath.clear(); m_traceMetaFilePath.clear();
m_isFinalizing = false;
DEBUG_OUT("LM optimizer reset"); DEBUG_OUT("LM optimizer reset");
} }
@ -1132,6 +1140,7 @@ bool nmCalculationAutoFitLM::startAutoFitting()
} }
m_isRunning = true; m_isRunning = true;
m_shouldStop = false; m_shouldStop = false;
m_isFinalizing = false;
m_currentIteration = 0; m_currentIteration = 0;
m_consecutiveFailures = 0; m_consecutiveFailures = 0;
m_initialValues = savedInitialValues; m_initialValues = savedInitialValues;
@ -1213,7 +1222,8 @@ bool nmCalculationAutoFitLM::startAutoFitting()
&m_globalBestObjectiveBreakdown); &m_globalBestObjectiveBreakdown);
} }
if(m_globalBestFitness < m_targetError) { if(finalReason != LM_USER_STOPPED &&
m_globalBestFitness < m_targetError) {
finalReason = LM_TARGET_ACHIEVED; finalReason = LM_TARGET_ACHIEVED;
} }
} catch(const std::exception& e) { } catch(const std::exception& e) {
@ -1221,6 +1231,7 @@ bool nmCalculationAutoFitLM::startAutoFitting()
emit logMessageGenerated(tr("CRITICAL ERROR: %1").arg(e.what())); emit logMessageGenerated(tr("CRITICAL ERROR: %1").arg(e.what()));
closeTraceFile(); closeTraceFile();
cleanupTemporaryDirectory(); cleanupTemporaryDirectory();
m_isFinalizing = false;
m_isRunning = false; m_isRunning = false;
emit fittingFinished(false, m_lastError); emit fittingFinished(false, m_lastError);
return false; return false;
@ -1229,16 +1240,21 @@ bool nmCalculationAutoFitLM::startAutoFitting()
emit logMessageGenerated(tr("CRITICAL ERROR: Unknown exception in automatic fitting")); emit logMessageGenerated(tr("CRITICAL ERROR: Unknown exception in automatic fitting"));
closeTraceFile(); closeTraceFile();
cleanupTemporaryDirectory(); cleanupTemporaryDirectory();
m_isFinalizing = false;
m_isRunning = false; m_isRunning = false;
emit fittingFinished(false, m_lastError); emit fittingFinished(false, m_lastError);
return false; return false;
} }
bool finalFullSolverSucceeded = true; // 只有最终完整求解实际执行并提交快照后才能置为成功。
bool finalFullSolverSucceeded = false;
bool finalFullSolverExecuted = false; bool finalFullSolverExecuted = false;
if(!m_globalBestPosition.isEmpty()) { if(!m_globalBestPosition.isEmpty()) {
try { try {
// Stop 只结束优化迭代;从这里开始必须用当前最优参数生成并发布正式快照。
m_isFinalizing = true;
emit finalizingStarted();
emit logMessageGenerated(tr("Applying optimized parameters to model...")); emit logMessageGenerated(tr("Applying optimized parameters to model..."));
applyParametersToDataManager(m_globalBestPosition); applyParametersToDataManager(m_globalBestPosition);
@ -1255,10 +1271,6 @@ bool nmCalculationAutoFitLM::startAutoFitting()
dataManager->invalidatePebiGrid(); dataManager->invalidatePebiGrid();
} }
if(m_shouldStop) {
emit logMessageGenerated(
tr("Final full-field calculation skipped after user stop"));
} else {
emit logMessageGenerated( emit logMessageGenerated(
tr("Running final full-field calculation with optimized parameters...")); tr("Running final full-field calculation with optimized parameters..."));
finalFullSolverExecuted = true; finalFullSolverExecuted = true;
@ -1267,18 +1279,12 @@ bool nmCalculationAutoFitLM::startAutoFitting()
if(finalFullSolverSucceeded) { if(finalFullSolverSucceeded) {
emit logMessageGenerated( emit logMessageGenerated(
tr("Final full-field calculation completed successfully")); tr("Final full-field calculation completed successfully"));
} else if(m_shouldStop) {
finalFullSolverExecuted = false;
finalFullSolverSucceeded = true;
emit logMessageGenerated(
tr("Final full-field calculation stopped by user"));
} else { } else {
m_lastError = m_lastError =
tr("Optimized parameters were found, but the final full-field calculation failed"); tr("Optimized parameters were found, but the final full-field calculation failed");
emit logMessageGenerated( emit logMessageGenerated(
tr("ERROR: Final full-field calculation failed")); tr("ERROR: Final full-field calculation failed"));
} }
}
saveOptimizationResult(); saveOptimizationResult();
emit logMessageGenerated(tr("=== Optimization Results ===")); emit logMessageGenerated(tr("=== Optimization Results ==="));
@ -1317,6 +1323,7 @@ bool nmCalculationAutoFitLM::startAutoFitting()
} }
} }
m_isFinalizing = false;
m_isRunning = false; m_isRunning = false;
bool success = false; bool success = false;
QString message; QString message;
@ -1349,7 +1356,7 @@ bool nmCalculationAutoFitLM::startAutoFitting()
emit logMessageGenerated(tr("=== LM AUTOMATIC FITTING - MAX ITERATIONS ===")); emit logMessageGenerated(tr("=== LM AUTOMATIC FITTING - MAX ITERATIONS ==="));
} else if(finalReason == LM_USER_STOPPED) { } else if(finalReason == LM_USER_STOPPED) {
success = true; success = true;
message = QString(tr("Best error: %1, Iterations: %2")) message = QString(tr("Stopped by user. Best error: %1, Iterations: %2"))
.arg(m_globalBestFitness, 0, 'e', 4) .arg(m_globalBestFitness, 0, 'e', 4)
.arg(m_currentIteration + 1); .arg(m_currentIteration + 1);
emit logMessageGenerated(tr("=== LM AUTOMATIC FITTING STOPPED BY USER ===")); emit logMessageGenerated(tr("=== LM AUTOMATIC FITTING STOPPED BY USER ==="));
@ -4138,13 +4145,6 @@ bool nmCalculationAutoFitLM::runFinalFullSolver()
break; break;
} }
if(m_shouldStop) {
DEBUG_OUT("Final full-field solver terminated by user");
dllTask.terminate();
dllTask.wait(2000);
--m_evaluationInProgress;
return false;
}
} }
if(dllTask.isRunning()) { if(dllTask.isRunning()) {

@ -447,6 +447,7 @@ nmCalculationAutoFitPSO::nmCalculationAutoFitPSO(QObject* parent)
: QObject(parent) : QObject(parent)
, m_isRunning(false) , m_isRunning(false)
, m_shouldStop(false) , m_shouldStop(false)
, m_isFinalizing(false)
, m_isPaused(false) , m_isPaused(false)
, m_currentIteration(0) , m_currentIteration(0)
, m_globalBestFitness(1e10) , m_globalBestFitness(1e10)
@ -612,6 +613,12 @@ void nmCalculationAutoFitPSO::setTargetLogLogData(const QVector<QVector<double>
void nmCalculationAutoFitPSO::stopFitting() void nmCalculationAutoFitPSO::stopFitting()
{ {
if(m_isFinalizing) {
emit logMessageGenerated(
tr("The final full-field calculation is already running"));
return;
}
// 用户点击停止时走这里。停止策略是“请求式停止”: // 用户点击停止时走这里。停止策略是“请求式停止”:
// 先置 m_shouldStop,让主循环/求解器等待逻辑自然退出;短时间内还在评价时再重置计数。 // 先置 m_shouldStop,让主循环/求解器等待逻辑自然退出;短时间内还在评价时再重置计数。
// 这样可以减少 DLL 任务被硬中断导致的数据状态残留。 // 这样可以减少 DLL 任务被硬中断导致的数据状态残留。
@ -718,6 +725,7 @@ void nmCalculationAutoFitPSO::resetOptimizer()
m_particleStagnationHistory.clear(); m_particleStagnationHistory.clear();
m_traceMetaFilePath.clear(); m_traceMetaFilePath.clear();
m_surrogateContextFilePath.clear(); m_surrogateContextFilePath.clear();
m_isFinalizing = false;
resetRunSummary(); resetRunSummary();
DEBUG_OUT("Optimizer reset"); DEBUG_OUT("Optimizer reset");
@ -2834,6 +2842,7 @@ bool nmCalculationAutoFitPSO::startAutoFitting()
} }
m_isRunning = true; m_isRunning = true;
m_shouldStop = false; m_shouldStop = false;
m_isFinalizing = false;
m_isPaused = false; m_isPaused = false;
m_currentIteration = 0; m_currentIteration = 0;
m_consecutiveFailures = 0; m_consecutiveFailures = 0;
@ -3199,6 +3208,7 @@ bool nmCalculationAutoFitPSO::startAutoFitting()
emit logMessageGenerated(tr("CRITICAL ERROR: %1").arg(e.what())); emit logMessageGenerated(tr("CRITICAL ERROR: %1").arg(e.what()));
closeTraceFile(); closeTraceFile();
cleanupTemporaryDirectory(); cleanupTemporaryDirectory();
m_isFinalizing = false;
m_isRunning = false; m_isRunning = false;
emit fittingFinished(false, m_lastError); emit fittingFinished(false, m_lastError);
return false; return false;
@ -3207,17 +3217,20 @@ bool nmCalculationAutoFitPSO::startAutoFitting()
emit logMessageGenerated(tr("CRITICAL ERROR: Unknown exception in PSO main loop")); emit logMessageGenerated(tr("CRITICAL ERROR: Unknown exception in PSO main loop"));
closeTraceFile(); closeTraceFile();
cleanupTemporaryDirectory(); cleanupTemporaryDirectory();
m_isFinalizing = false;
m_isRunning = false; m_isRunning = false;
emit fittingFinished(false, m_lastError); emit fittingFinished(false, m_lastError);
return false; return false;
} }
m_isRunning = false;
bool finalFullSolverSucceeded = false; bool finalFullSolverSucceeded = false;
// 应用最终参数 // 应用最终参数
if(!m_globalBestPosition.isEmpty()) { if(!m_globalBestPosition.isEmpty()) {
try { try {
// Stop 只结束优化迭代;从这里开始必须用当前最优参数生成并发布正式快照。
m_isFinalizing = true;
emit finalizingStarted();
emit logMessageGenerated(tr("Applying optimized parameters to model...")); emit logMessageGenerated(tr("Applying optimized parameters to model..."));
applyParametersToDataManager(m_globalBestPosition); applyParametersToDataManager(m_globalBestPosition);
@ -3267,6 +3280,9 @@ bool nmCalculationAutoFitPSO::startAutoFitting()
} }
} }
m_isFinalizing = false;
m_isRunning = false;
// 判断系统确定最终结果 // 判断系统确定最终结果
bool success; bool success;
QString message; QString message;
@ -3294,7 +3310,7 @@ bool nmCalculationAutoFitPSO::startAutoFitting()
emit logMessageGenerated(tr("=== PSO OPTIMIZATION - MAX ITERATIONS ===")); emit logMessageGenerated(tr("=== PSO OPTIMIZATION - MAX ITERATIONS ==="));
} else if(finalReason == PSO_USER_STOPPED) { } else if(finalReason == PSO_USER_STOPPED) {
success = true; success = true;
message = QString(tr("Best error: %1, Iterations: %2")) message = QString(tr("Stopped by user. Best error: %1, Iterations: %2"))
.arg(m_globalBestFitness, 0, 'e', 4).arg(m_currentIteration + 1); .arg(m_globalBestFitness, 0, 'e', 4).arg(m_currentIteration + 1);
emit logMessageGenerated(tr("=== PSO OPTIMIZATION STOPPED BY USER ===")); emit logMessageGenerated(tr("=== PSO OPTIMIZATION STOPPED BY USER ==="));
} else if(finalReason == PSO_CONSECUTIVE_FAILURES) { } else if(finalReason == PSO_CONSECUTIVE_FAILURES) {

@ -389,6 +389,7 @@ nmWxAutomaticfittingStart::nmWxAutomaticfittingStart(QWidget *parent)
, m_targetError(0.001) , m_targetError(0.001)
, m_wellName("") , m_wellName("")
, m_isFinished(false) , m_isFinished(false)
, m_isFinalizing(false)
, m_bestFitnessEver(1e10) , m_bestFitnessEver(1e10)
, m_startTime() , m_startTime()
{ {
@ -592,6 +593,8 @@ void nmWxAutomaticfittingStart::setAutoFitter(nmCalculationAutoFitPSO* autoFitte
this, SLOT(onFittingProgress(int, double)));//更新进度条、当前迭代数、当前误差 this, SLOT(onFittingProgress(int, double)));//更新进度条、当前迭代数、当前误差
connect(m_autoFitterPSO, SIGNAL(fittingFinished(bool, QString)), connect(m_autoFitterPSO, SIGNAL(fittingFinished(bool, QString)),
this, SLOT(onFittingFinished(bool, QString)));//显示结束状态 this, SLOT(onFittingFinished(bool, QString)));//显示结束状态
connect(m_autoFitterPSO, SIGNAL(finalizingStarted()),
this, SLOT(onFinalizingStarted()));
connect(m_autoFitterPSO, SIGNAL(logMessageGenerated(QString)), connect(m_autoFitterPSO, SIGNAL(logMessageGenerated(QString)),
this, SLOT(onLogMessageReceived(QString)));//把 PSO 内部日志显示到窗口 this, SLOT(onLogMessageReceived(QString)));//把 PSO 内部日志显示到窗口
connect(m_autoFitterPSO, SIGNAL(bestCurveUpdated(QVector<QVector<double> >,QVector<QVector<double> >,int,double)), connect(m_autoFitterPSO, SIGNAL(bestCurveUpdated(QVector<QVector<double> >,QVector<QVector<double> >,int,double)),
@ -618,6 +621,8 @@ void nmWxAutomaticfittingStart::setAutoFitter(nmCalculationAutoFitLM* autoFitter
this, SLOT(onFittingProgress(int, double))); this, SLOT(onFittingProgress(int, double)));
connect(m_autoFitterLM, SIGNAL(fittingFinished(bool, QString)), connect(m_autoFitterLM, SIGNAL(fittingFinished(bool, QString)),
this, SLOT(onFittingFinished(bool, QString))); this, SLOT(onFittingFinished(bool, QString)));
connect(m_autoFitterLM, SIGNAL(finalizingStarted()),
this, SLOT(onFinalizingStarted()));
connect(m_autoFitterLM, SIGNAL(logMessageGenerated(QString)), connect(m_autoFitterLM, SIGNAL(logMessageGenerated(QString)),
this, SLOT(onLogMessageReceived(QString))); this, SLOT(onLogMessageReceived(QString)));
connect(m_autoFitterLM, SIGNAL(bestCurveUpdated(QVector<QVector<double> >,QVector<QVector<double> >,int,double)), connect(m_autoFitterLM, SIGNAL(bestCurveUpdated(QVector<QVector<double> >,QVector<QVector<double> >,int,double)),
@ -714,6 +719,7 @@ void nmWxAutomaticfittingStart::onFittingProgress(int iteration, double fitness)
void nmWxAutomaticfittingStart::onFittingFinished(bool success, const QString& message) void nmWxAutomaticfittingStart::onFittingFinished(bool success, const QString& message)
{ {
m_isFinished = true; m_isFinished = true;
m_isFinalizing = false;
const QString algorithmName = m_algorithmName; const QString algorithmName = m_algorithmName;
@ -801,6 +807,15 @@ void nmWxAutomaticfittingStart::onFittingFinished(bool success, const QString& m
} }
void nmWxAutomaticfittingStart::onFinalizingStarted()
{
// 最终完整求解负责生成正式快照,此阶段不能再次停止或关闭进度窗口。
m_isFinalizing = true;
stopButton->setEnabled(false);
stopButton->setText(tr("Finalizing..."));
addLogMessage(tr("Generating the final result with the current best parameters..."));
}
void nmWxAutomaticfittingStart::onStopButtonClicked() void nmWxAutomaticfittingStart::onStopButtonClicked()
{ {
const bool isRunning = (m_autoFitterPSO && m_autoFitterPSO->isRunning()) || const bool isRunning = (m_autoFitterPSO && m_autoFitterPSO->isRunning()) ||
@ -814,6 +829,9 @@ void nmWxAutomaticfittingStart::onStopButtonClicked()
QMessageBox::No); QMessageBox::No);
if (ret == QMessageBox::Yes) { if (ret == QMessageBox::Yes) {
// 先锁定按钮,等优化循环退出后由 finalizingStarted() 切换到最终求解状态。
stopButton->setEnabled(false);
stopButton->setText(tr("Stopping..."));
if (m_autoFitterPSO) { if (m_autoFitterPSO) {
m_autoFitterPSO->stopFitting(); m_autoFitterPSO->stopFitting();
} else if (m_autoFitterLM) { } else if (m_autoFitterLM) {
@ -885,6 +903,14 @@ void nmWxAutomaticfittingStart::closeEvent(QCloseEvent *event)
const bool isRunning = (m_autoFitterPSO && m_autoFitterPSO->isRunning()) || const bool isRunning = (m_autoFitterPSO && m_autoFitterPSO->isRunning()) ||
(m_autoFitterLM && m_autoFitterLM->isRunning()); (m_autoFitterLM && m_autoFitterLM->isRunning());
const QString algorithmName = m_algorithmName; const QString algorithmName = m_algorithmName;
if(m_isFinalizing && !m_isFinished) {
QMessageBox::information(
this,
tr("Finalizing"),
tr("The final result is being generated. Please wait for the calculation to finish."));
event->ignore();
return;
}
if (isRunning && !m_isFinished) { if (isRunning && !m_isFinished) {
int ret = QMessageBox::question(this, tr("Confirm Close"), int ret = QMessageBox::question(this, tr("Confirm Close"),

Loading…
Cancel
Save