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

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

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

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

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

@ -389,6 +389,7 @@ nmWxAutomaticfittingStart::nmWxAutomaticfittingStart(QWidget *parent)
, m_targetError(0.001)
, m_wellName("")
, m_isFinished(false)
, m_isFinalizing(false)
, m_bestFitnessEver(1e10)
, m_startTime()
{
@ -592,6 +593,8 @@ void nmWxAutomaticfittingStart::setAutoFitter(nmCalculationAutoFitPSO* autoFitte
this, SLOT(onFittingProgress(int, double)));//更新进度条、当前迭代数、当前误差
connect(m_autoFitterPSO, SIGNAL(fittingFinished(bool, QString)),
this, SLOT(onFittingFinished(bool, QString)));//显示结束状态
connect(m_autoFitterPSO, SIGNAL(finalizingStarted()),
this, SLOT(onFinalizingStarted()));
connect(m_autoFitterPSO, SIGNAL(logMessageGenerated(QString)),
this, SLOT(onLogMessageReceived(QString)));//把 PSO 内部日志显示到窗口
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)));
connect(m_autoFitterLM, SIGNAL(fittingFinished(bool, QString)),
this, SLOT(onFittingFinished(bool, QString)));
connect(m_autoFitterLM, SIGNAL(finalizingStarted()),
this, SLOT(onFinalizingStarted()));
connect(m_autoFitterLM, SIGNAL(logMessageGenerated(QString)),
this, SLOT(onLogMessageReceived(QString)));
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)
{
m_isFinished = true;
m_isFinalizing = false;
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()
{
const bool isRunning = (m_autoFitterPSO && m_autoFitterPSO->isRunning()) ||
@ -814,6 +829,9 @@ void nmWxAutomaticfittingStart::onStopButtonClicked()
QMessageBox::No);
if (ret == QMessageBox::Yes) {
// 先锁定按钮,等优化循环退出后由 finalizingStarted() 切换到最终求解状态。
stopButton->setEnabled(false);
stopButton->setText(tr("Stopping..."));
if (m_autoFitterPSO) {
m_autoFitterPSO->stopFitting();
} else if (m_autoFitterLM) {
@ -885,6 +903,14 @@ void nmWxAutomaticfittingStart::closeEvent(QCloseEvent *event)
const bool isRunning = (m_autoFitterPSO && m_autoFitterPSO->isRunning()) ||
(m_autoFitterLM && m_autoFitterLM->isRunning());
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) {
int ret = QMessageBox::question(this, tr("Confirm Close"),

Loading…
Cancel
Save