fix(numerical): 修复自动拟合结果未刷新

- LM 和 PSO 通过正式结果快照刷新主界面
- PSO 最优参数落地后补充最终完整求解与快照提交
- 区分快照发布、结果井切换与手工生成刷新流程
feature/Adapt-Autofit-20260904
lvjunjie 6 days ago
parent 77bd6cd4e9
commit b9181b9dce

@ -164,6 +164,8 @@ private:
QVector<QVector<double> > runSolver();
QVector<QVector<double>> runSolverDll();
QVector<QVector<double>> runSolverExe();
/** @brief 使用最终最优参数执行完整求解并提交正式结果快照。 */
bool runFinalFullSolver();
// ===== 数据处理 =====
QVector<QPointF> interpolateData(const QVector<QPointF>& source,

@ -121,6 +121,10 @@ class NM_SUB_WND_EXPORT nmSubWndMain : public iSubWndBaseFit {
// 根据分析数据绘制对应的地图信息
void updateMapByDataManager(nmDataAnalyzeManager* pDataManager);
/** @brief 绑定当前数值面板所属的数据管理器和成果窗口。 */
void bindPebiResultRefreshContext(nmDataAnalyzeManager* pDataManager,
iSubWndFitting* pSubWndFitting);
signals:
void sigFreshRnStates(QStringList list);
void sigShowProgressAbout(bool);
@ -159,6 +163,8 @@ class NM_SUB_WND_EXPORT nmSubWndMain : public iSubWndBaseFit {
/** @brief 当前分析的建网提交结束后,恢复待启动或待捕获的求解流程。 */
void onPebiGridGenerationFinished(quint64 nGridInputRevision,
bool bSucceeded);
/** @brief 正式结果快照发布后刷新当前分析的曲线和结果页面。 */
void onPebiResultSnapshotChanged();
/** @brief 按快照井 UUID 切换结果曲线,不改变实时井或参数编辑井。 */
void onWellSelected(const QString& sWellInstanceId);
@ -313,6 +319,12 @@ private:
int m_nPendingSolverTimeMs; ///< 待显示的求解耗时。
bool m_bSolverStartPending; ///< 进度框已显示,输入正分批捕获或任务等待启动。
bool m_bSolverCancelRequested; ///< 已向当前任务发送停止请求,忽略后续阶段信号。
/** @brief 数值面板固定绑定的数据管理器,自动拟合刷新不依赖当前活动页签。 */
QPointer<nmDataAnalyzeManager> m_pResultRefreshDataManager;
/** @brief 数值面板固定绑定的成果窗口。 */
QPointer<iSubWndFitting> m_pResultRefreshFitting;
QString m_sObservedPebiResultSnapshotId; ///< 最近已经交给界面处理的快照 UUID。
bool m_bRefreshingPebiResultSnapshot; ///< 防止结果井校正信号造成刷新重入。
#ifdef QT_DEBUG
// 示例演示增加Dock并且追加至程序主窗口

@ -167,6 +167,7 @@ public:
// 统一装配新建、加载分析共用的数值设计与参数属性Dock控件
static void setupNumericalDockWidgets(nmDataAnalyzeManager* pDataManager,
nmSubWndMain* pSubWndMain,
iSubWndFitting* pSubWndFitting,
iDockBaseWx* pWxDockNm1,
iDockBaseWx* pWxDockNm2);

@ -3213,12 +3213,26 @@ bool nmCalculationAutoFitPSO::startAutoFitting()
}
m_isRunning = false;
bool finalFullSolverSucceeded = false;
// 应用最终参数
if(!m_globalBestPosition.isEmpty()) {
try {
emit logMessageGenerated(tr("Applying optimized parameters to model..."));
applyParametersToDataManager(m_globalBestPosition);
// 候选粒子只返回目标井曲线;最优参数确定后必须再生成并提交完整结果快照。
emit logMessageGenerated(
tr("Running final full-field calculation with optimized parameters..."));
finalFullSolverSucceeded = runFinalFullSolver();
if(finalFullSolverSucceeded) {
emit logMessageGenerated(
tr("Final full-field calculation completed successfully"));
} 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();
// 输出最终优化结果
@ -3237,7 +3251,13 @@ bool nmCalculationAutoFitPSO::startAutoFitting()
emit logMessageGenerated(finalParams);
emit logMessageGenerated(tr("Parameters applied successfully to data manager"));
if(finalFullSolverSucceeded) {
emit logMessageGenerated(
tr("Parameters and full-field results applied successfully to data manager"));
} else {
emit logMessageGenerated(
tr("Optimized parameters applied to data manager"));
}
} catch(const std::exception& e) {
emit logMessageGenerated(tr("ERROR: Failed to apply final parameters: %1").arg(e.what()));
m_lastError = QString("Failed to apply final parameters: %1").arg(e.what());
@ -3289,6 +3309,14 @@ bool nmCalculationAutoFitPSO::startAutoFitting()
emit logMessageGenerated(tr("=== PSO OPTIMIZATION - UNKNOWN END ==="));
}
// 只有正式快照已经提交,界面收到的成功信号才代表本次拟合结果完整可用。
if(success && !finalFullSolverSucceeded) {
success = false;
message = m_lastError.isEmpty()
? tr("The final full-field calculation failed")
: m_lastError;
}
emitRunSummary(success, finalReason);
// 先发送最终进度更新确保进度条达到100%
@ -5199,6 +5227,51 @@ QVector<QVector<double>> nmCalculationAutoFitPSO::runSolverDll()
return result;
}
bool nmCalculationAutoFitPSO::runFinalFullSolver()
{
// 不设置目标井名,任务按普通完整模式构建全部井、网格和压力场结果。
nmDataAnalyzeManager* pDataManager =
nmDataAnalyzeManager::getCurrentInstance();
if(pDataManager == nullptr || m_evaluationInProgress > 0) {
DEBUG_OUT("Cannot start final full-field solver");
return false;
}
++m_evaluationInProgress;
nmCalculationDllPebiSolverTask dllTask(m_tempDirectory, pDataManager);
dllTask.start();
const int maxWait = 3600000;
const int checkInterval = 50;
QTime waitTimer;
waitTimer.start();
while(waitTimer.elapsed() < maxWait) {
if(dllTask.wait(checkInterval) || !dllTask.isRunning()) {
break;
}
// 最终求解期间继续处理绘制事件,避免进度窗口看起来失去响应。
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents,
checkInterval);
}
if(dllTask.isRunning()) {
DEBUG_OUT("Final full-field solver timeout, terminating task");
dllTask.terminate();
dllTask.wait(2000);
--m_evaluationInProgress;
return false;
}
dllTask.wait();
// 后台只生成候选快照,必须回到 DataManager 所属线程一次性提交。
const bool succeeded =
dllTask.wasSuccessful() && dllTask.commitResult(pDataManager);
--m_evaluationInProgress;
return succeeded;
}
//QVector<QVector<double>> nmCalculationAutoFitPSO::runSolverExe()
//{
// DEBUG_OUT("SOLVER EXE START");

@ -145,6 +145,10 @@ nmSubWndMain::nmSubWndMain(QWidget *parent, QString sExt) :
m_nPendingSolverTimeMs = -1;
m_bSolverStartPending = false;
m_bSolverCancelRequested = false;
m_pResultRefreshDataManager = nullptr;
m_pResultRefreshFitting = nullptr;
m_sObservedPebiResultSnapshotId.clear();
m_bRefreshingPebiResultSnapshot = false;
m_pPlotToolBar = nullptr;
}
@ -221,6 +225,66 @@ nmSubWndMain::~nmSubWndMain()
}*/
}
void nmSubWndMain::bindPebiResultRefreshContext(
nmDataAnalyzeManager* pDataManager,
iSubWndFitting* pSubWndFitting)
{
// 自动拟合完成时始终刷新创建该数值面板的分析窗口,避免页签切换后取到其他分析。
m_pResultRefreshDataManager = pDataManager;
m_pResultRefreshFitting = pSubWndFitting;
QSharedPointer<const nmPebiResultSnapshot> pSnapshot =
pDataManager != nullptr
? pDataManager->getPebiResultSnapshot()
: QSharedPointer<const nmPebiResultSnapshot>();
m_sObservedPebiResultSnapshotId = pSnapshot.isNull()
? QString() : pSnapshot->getSnapshotId();
}
void nmSubWndMain::onPebiResultSnapshotChanged()
{
nmDataAnalyzeManager* pDataManager = m_pResultRefreshDataManager.data();
iSubWndFitting* pSubWndFitting = m_pResultRefreshFitting.data();
if(pDataManager == nullptr || pSubWndFitting == nullptr ||
sender() != pDataManager || m_bRefreshingPebiResultSnapshot) {
return;
}
QSharedPointer<const nmPebiResultSnapshot> pSnapshot =
pDataManager->getPebiResultSnapshot();
if(pSnapshot.isNull()) {
m_sObservedPebiResultSnapshotId.clear();
return;
}
const QString sSnapshotId = pSnapshot->getSnapshotId();
if(sSnapshotId == m_sObservedPebiResultSnapshotId) {
// 同一快照内切换结果井仍由 onWellSelected() 处理,不重复刷新全部结果页面。
return;
}
// 手工 Generate 有自己的完成和提示流程;这里只接管自动拟合提交的新快照。
if(m_pSolverTask != nullptr || m_bSolverStartPending ||
m_bSolverResultCompletionPending) {
m_sObservedPebiResultSnapshotId = sSnapshotId;
return;
}
m_bRefreshingPebiResultSnapshot = true;
QPointer<nmDataAnalyzeManager> pSavedSolverDataManager =
m_pSolverDataManager;
QPointer<iSubWndFitting> pSavedSolverFitting = m_pSolverFitting;
m_pSolverDataManager = pDataManager;
m_pSolverFitting = pSubWndFitting;
const bool bRefreshed = mergeAnaResultToFitting();
schedulePendingResultWidgets();
m_pSolverDataManager = pSavedSolverDataManager;
m_pSolverFitting = pSavedSolverFitting;
m_bRefreshingPebiResultSnapshot = false;
if(bRefreshed) {
m_sObservedPebiResultSnapshotId = sSnapshotId;
}
}
void nmSubWndMain::configWnd(QString sPrevInfo)
{
iSubWndBaseFit::configWnd(sPrevInfo);

@ -409,11 +409,13 @@ void nmSubWndUtils::connectWellListSignals(nmDataAnalyzeManager* pDataManager,
void nmSubWndUtils::setupNumericalDockWidgets(nmDataAnalyzeManager* pDataManager,
nmSubWndMain* pSubWndMain,
iSubWndFitting* pSubWndFitting,
iDockBaseWx* pWxDockNm1,
iDockBaseWx* pWxDockNm2)
{
Q_ASSERT(pDataManager != nullptr);
Q_ASSERT(pSubWndMain != nullptr);
Q_ASSERT(pSubWndFitting != nullptr);
Q_ASSERT(pWxDockNm1 != nullptr);
Q_ASSERT(pWxDockNm2 != nullptr);
@ -447,6 +449,12 @@ void nmSubWndUtils::setupNumericalDockWidgets(nmDataAnalyzeManager* pDataManager
connect(pAnalWx, SIGNAL(sigResultWellChanged(QString)),
pSubWndMain, SLOT(onWellSelected(QString)));
// 手工求解和自动拟合都发布同一种正式快照,统一复用主窗口结果刷新逻辑。
pSubWndMain->bindPebiResultRefreshContext(pDataManager, pSubWndFitting);
connect(pDataManager, SIGNAL(sigPebiResultSnapshotChanged()),
pSubWndMain, SLOT(onPebiResultSnapshotChanged()),
Qt::UniqueConnection);
connectWellListSignals(pDataManager, pParaWx);
pWxDockNm1->setWidget(pAnalWx);
@ -677,7 +685,7 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
ZxMainWindow* pMainWnd = pSubWndF->getMainWindow();
// 设置当前窗口到Map
pSubWndMain->setMainWindow(pMainWnd);
setupNumericalDockWidgets(pDataManager, pSubWndMain,
setupNumericalDockWidgets(pDataManager, pSubWndMain, pSubWndF,
pWxDockNm1, pWxDockNm2);
return true; //your own codes
@ -1067,7 +1075,7 @@ bool nmSubWndUtils::loadRsts(iSubWnd* pSubWnd, \
nmSubWndMain* pSubWndMain = new nmSubWndMain(NULL, "");
ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(pMainWnd);
pSubWndMain->setMainWindow(pMainWnd1);
setupNumericalDockWidgets(pDataManager, pSubWndMain,
setupNumericalDockWidgets(pDataManager, pSubWndMain, pSubWndF,
pWxDockNm1, pWxDockNm2);
// v3 场图只以独立快照是否存在为准,不再依赖旧时间步 Map。

Loading…
Cancel
Save