diff --git a/Include/nmNum/nmSubWnd/nmSubWndMain.h b/Include/nmNum/nmSubWnd/nmSubWndMain.h index e4513bd4..ba0288e3 100644 --- a/Include/nmNum/nmSubWnd/nmSubWndMain.h +++ b/Include/nmNum/nmSubWnd/nmSubWndMain.h @@ -276,6 +276,8 @@ class NM_SUB_WND_EXPORT nmSubWndMain : public iSubWndBaseFit { bool initloglog(QVector> & vvecLogPreData, QVector& vecDescs,bool isHistoryData); // 压力历史曲线数据 bool initPreHistory(QVector> & vvecHistoryData, QVector& vecDescs,bool isHistoryData); + // 在分析页面内同步敏感性压力/流量历史图。 + void updateSensitiveHistoryPlot(); // 根据原始压力数据、计算出半对数、双对数数据 //void calculationLogData(nmDataWellBase* pWellData,QVector>& vvecHistoryData,QVector>& vvecLogPreData,QVector>& vvecSemiLogPreData); diff --git a/Src/nmNum/nmSubWnd/nmSubWndMain.cpp b/Src/nmNum/nmSubWnd/nmSubWndMain.cpp index cafd5f3a..aa6c3e9c 100644 --- a/Src/nmNum/nmSubWnd/nmSubWndMain.cpp +++ b/Src/nmNum/nmSubWnd/nmSubWndMain.cpp @@ -65,6 +65,7 @@ #include "iSubWndFitting.h" #include "iGuiPlotPF.h" +#include "iGuiPlotTableHelper.h" #include "iGuiPlot.h" #include "ZxObjCurveFlow.h" #include "iAnalRun.h" @@ -1873,6 +1874,7 @@ void nmSubWndMain::onShowSensitiveResults() nmDataAnalyzeManager* manager = m_pResultRefreshDataManager.data(); iSubWndFitting* fitting = m_pResultRefreshFitting.data(); if(!manager || !fitting || !manager->getSensitiveData()) return; + updateSensitiveHistoryPlot(); QSharedPointer result = manager->getSensitiveData()->getResults(); iGuiPlot* plot = fitting->getPlotByTag(s_Tag_ChartSensitivity); if(result.isNull()) { @@ -1987,6 +1989,106 @@ void nmSubWndMain::onShowSensitiveResults() if(sender() == manager) fitting->setModified(true); } +void nmSubWndMain::updateSensitiveHistoryPlot() +{ + // 复用框架的上下压力/流量控件,作为同一分析页面中的独立 MDI 子窗口。 + iSubWndFitting* fitting = m_pResultRefreshFitting.data(); + nmDataAnalyzeManager* manager = m_pResultRefreshDataManager.data(); + if(!fitting || !fitting->m_pMdiArea || !manager || !manager->getSensitiveData()) return; + ZxMdiArea* area = fitting->m_pMdiArea; + QMdiSubWindow* window = area->findChild("nmSensitivityHistory"); + const QSharedPointer batch = manager->getSensitiveData()->getResults(); + if(batch.isNull()) { + // 新模型丢弃旧批次时一并销毁窗口,曲线和撤销记录不再残留。 + if(window) { + area->removeSubWindow(window); + delete window; + } + return; + } + const bool created = window == nullptr; + if(created) { + // PF 继承对话框,用普通页面承载,关闭子窗口时不进入其对话框关闭流程。 + QWidget* page = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(page); + layout->setContentsMargins(0, 0, 0, 0); + iGuiPlotPF* history = new iGuiPlotPF(s_Tag_HIST_PF, true, true, page); + history->setWindowFlags(Qt::Widget); + history->initUI(tr("Sensitivity history plot")); + history->setTableHelperVisible(false); + layout->addWidget(history); + window = area->addSubWindow(page); + window->setObjectName("nmSensitivityHistory"); + window->setWindowTitle(tr("Sensitivity history plot")); + window->setAttribute(Qt::WA_DeleteOnClose, false); + } + iGuiPlotPF* history = window->findChild(); + QVector curves; + // 基准压力、实测压力和流量均取成功求解快照,未求解的参数或制度编辑不参与绘图。 + const QSharedPointer snapshot = manager->getPebiResultSnapshot(); + for(int i = 0; !snapshot.isNull() && i < snapshot->getWellCount(); ++i) { + const nmPebiResultWellSnapshot* well = snapshot->getWellAt(i); + if(well->m_sWellCode != batch->m_sWellCode) continue; + QVector > measured = well->m_oCurves.m_vecHistoryPressure; + QVector > base = well->m_oCurves.m_vecResultPressure; + if(measured.size() == 2) initPreHistory(measured, curves, true); + if(base.size() == 2) { + initPreHistory(base, curves, false); + curves.last().m_sCurveName = nmWxSensitive::tr("Base model - Pressure"); + } + const QVector* rates = resultReferenceRatesOf(well); + if(rates && rates->size() == well->m_vecFlowDurations.size()) { + iCurveDesc flow; + flow.m_oCurveType = POT_CurveFlow; + flow.m_sCurveName = s_HistorySouce_CurveF; + flow.m_bLineVisible = true; + flow.m_bPointVisible = false; + flow.m_oPen.setColor(Qt::red); + // 与普通历史图一致,流量使用段时长并保留框架的首行占位点。 + flow.m_vecX = well->m_vecFlowDurations; + flow.m_vecY = *rates; + flow.m_vecX.prepend(0.0); + flow.m_vecY.prepend(0.0); + curves.append(flow); + } + break; + } + for(size_t i = 0; i < batch->m_runs.size(); ++i) { + const nmDataSensitive::RunResult& run = batch->m_runs[i]; + if(!run.m_bSucceeded || run.m_bCancelled || !run.m_bVisible || run.m_vecPressure.size() != 2) continue; + QVector > pressure = run.m_vecPressure; + initPreHistory(pressure, curves, false); + curves.last().m_sCurveName = nmWxSensitive::tr("Run %1 - Pressure").arg(run.m_nRunIndex + 1); + curves.last().m_oPen.setColor(QColor::fromHsv(int((run.m_nRunIndex % 360) * 137 % 360), 190, 190)); + } + // 框架不会删除本次未传入的曲线,刷新前清除旧图元,保证 Results 勾选同步生效。 + iGuiPlot* plots[] = {history->m_pWxPlotP, history->m_pWxPlotF}; + for(int i = 0; i < 2; ++i) { + iGuiPlot* plot = plots[i]; + for(int j = plot->m_pPlot->getObjCount() - 1; j >= 0; --j) + if(qobject_cast(plot->m_pPlot->getObjByIndex(j))) plot->m_pPlot->removeObjByIndex(j); + plot->clearUndoStack(); + plot->setDropEnabled(false); + plot->setAxisXYLog(false, 0); + plot->setAxisXYLog(false, 1); + // PF 的统一分配面向普通历史曲线;多组结果直接交给对应的上下绘图控件。 + QVector data; + for(int j = 0; j < curves.size(); ++j) + if((curves[j].m_oCurveType == POT_CurveFlow) == (i == 1)) data.append(curves[j]); + plot->setCurveData(data); + plot->runUpdate(); + plot->setReadOnly(true); + plot->freshAxisScales(true, true); + } + const bool restore = window->isHidden(); + history->show(); + window->widget()->show(); + window->show(); + // 历史图只显示曲线,隐藏框架默认的空数据表侧栏。 + history->m_pTableHelper->hide(); + if(created || restore) area->relayoutSubWnds(); +} + void nmSubWndMain::startSolverTask() { if(!m_bSolverStartPending) {