|
|
|
|
@ -112,6 +112,23 @@ namespace
|
|
|
|
|
QPointer<nmCalculationDllPebiSolverTask> s_pRunningSolverTask;
|
|
|
|
|
QPointer<nmSubWndMain> s_pPendingSolverWindow;
|
|
|
|
|
|
|
|
|
|
void clearResultCurveDataTables(iGuiPlot* plot)
|
|
|
|
|
{
|
|
|
|
|
// 框架弹出的表格是独立顶层窗口;刷新前清除本图的旧表,仍由框架管理其生命周期。
|
|
|
|
|
foreach(QWidget* window, QApplication::topLevelWidgets()) {
|
|
|
|
|
iGuiPlotTableHelper* table = qobject_cast<iGuiPlotTableHelper*>(window);
|
|
|
|
|
if(!table) continue;
|
|
|
|
|
for(int i = 0; i < plot->m_pPlot->getObjCount(); ++i) {
|
|
|
|
|
ZxObjCurve* curve = qobject_cast<ZxObjCurve*>(plot->m_pPlot->getObjByIndex(i));
|
|
|
|
|
if(curve && table->getMapTableViews()->contains(curve)) {
|
|
|
|
|
table->resetTableHelpers();
|
|
|
|
|
table->hide();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QSet<QString> hiddenSensitiveCurves(iGuiPlot* plot)
|
|
|
|
|
{
|
|
|
|
|
// 刷新同一批次或重新打开窗口时保留本图的显示选择。
|
|
|
|
|
@ -1948,11 +1965,16 @@ void nmSubWndMain::onShowForecastResult(const QString& wellName, const QVector<d
|
|
|
|
|
iGuiPlot* plot = new iGuiPlot(true, charts);
|
|
|
|
|
plot->setObjectName(i == 0 ? "nmForecastRate" : "nmForecastPressure");
|
|
|
|
|
plot->initUI(i == 0 ? tr("Production rate") : tr("Bottomhole pressure"));
|
|
|
|
|
connect(plot, SIGNAL(sigDoubleClicked(ZxPlot*,ZxObjBase*,const QPointF&,bool&)),
|
|
|
|
|
this, SLOT(onReadonlyCurveDoubleClicked(ZxPlot*,ZxObjBase*,const QPointF&,bool&)));
|
|
|
|
|
plot->m_pPlotView->setSimpleMode(true);
|
|
|
|
|
plot->setDropEnabled(false);
|
|
|
|
|
plot->setAxisX(tr("Time"), "hr");
|
|
|
|
|
plot->setAxisY(i == 0 ? tr("Production rate") : tr("Bottomhole pressure"), i == 0 ? "m^3/D" : "MPa");
|
|
|
|
|
plot->setAxisY(i == 0 ? tr("Flow") : tr("Pressure"), i == 0 ? "m^3/D" : "MPa");
|
|
|
|
|
plot->setAxisY(i == 0 ? tr("Cumulative production") : QString(), i == 0 ? "m^3" : "", true);
|
|
|
|
|
// 两侧纵轴适当加宽,留出数字与名称的间距,上下图采用相同宽度保持对齐。
|
|
|
|
|
plot->getAxisOf(1)->setSpan(16.0);
|
|
|
|
|
plot->getAxisOf(2)->setSpan(16.0);
|
|
|
|
|
for(int axis = 0; axis < 3; ++axis) plot->setAxisXYLog(false, axis);
|
|
|
|
|
plot->getAxisOf(2)->setVisible(true);
|
|
|
|
|
// 下图右侧保留空轴位,确保两张图的时间刻度在水平方向对齐。
|
|
|
|
|
@ -1974,12 +1996,16 @@ void nmSubWndMain::onShowForecastResult(const QString& wellName, const QVector<d
|
|
|
|
|
|
|
|
|
|
// 压力直接取求解器结果;阶梯产量及累计量按本次输入制度精确构造。
|
|
|
|
|
QVector<double> rateTimes, rateValues, cumulativeTimes, cumulativeValues;
|
|
|
|
|
double time = 0.0, cumulative = 0.0;
|
|
|
|
|
double time = 0.0, cumulative = 0.0, maximumRate = 0.0;
|
|
|
|
|
// 零时刻先画关井基线,再接首段产量,显示开始生产时的竖直跳变。
|
|
|
|
|
rateTimes.append(0.0);
|
|
|
|
|
rateValues.append(0.0);
|
|
|
|
|
cumulativeTimes.append(0.0);
|
|
|
|
|
cumulativeValues.append(0.0);
|
|
|
|
|
for(int i = 0; i < durations.size(); ++i) {
|
|
|
|
|
rateTimes << time << time + durations[i];
|
|
|
|
|
rateValues << rates[i] << rates[i];
|
|
|
|
|
maximumRate = qMax(maximumRate, rates[i]);
|
|
|
|
|
time += durations[i];
|
|
|
|
|
cumulative += rates[i] * durations[i] / 24.0;
|
|
|
|
|
cumulativeTimes.append(time);
|
|
|
|
|
@ -2003,6 +2029,8 @@ void nmSubWndMain::onShowForecastResult(const QString& wellName, const QVector<d
|
|
|
|
|
window->findChild<iGuiPlot*>("nmForecastPressure")};
|
|
|
|
|
for(int i = 0; i < 2; ++i) {
|
|
|
|
|
iGuiPlot* plot = plots[i];
|
|
|
|
|
// 表格引用本批曲线,替换图元前关闭旧表,避免显示过期数据。
|
|
|
|
|
clearResultCurveDataTables(plot);
|
|
|
|
|
// 重复生成只替换曲线,清理旧图元和撤销记录,保留上下图窗口。
|
|
|
|
|
for(int j = plot->m_pPlot->getObjCount() - 1; j >= 0; --j)
|
|
|
|
|
if(qobject_cast<ZxObjCurve*>(plot->m_pPlot->getObjByIndex(j))) plot->m_pPlot->removeObjByIndex(j);
|
|
|
|
|
@ -2011,12 +2039,24 @@ void nmSubWndMain::onShowForecastResult(const QString& wellName, const QVector<d
|
|
|
|
|
plot->runUpdate();
|
|
|
|
|
plot->setReadOnly(true);
|
|
|
|
|
plot->freshAxisScales(true, true);
|
|
|
|
|
if(i == 0) {
|
|
|
|
|
// 产量和累计量均从零起算,顶部留少量空白;全程关井保留有效轴范围。
|
|
|
|
|
const double rateTop = maximumRate > 0.0 ? maximumRate : 1.0;
|
|
|
|
|
const double cumulativeTop = cumulative > 0.0 ? cumulative : 1.0;
|
|
|
|
|
VecDouble rateTicks, cumulativeTicks;
|
|
|
|
|
for(int tick = 0; tick <= 5; ++tick) {
|
|
|
|
|
rateTicks.append(rateTop * tick / 5.0);
|
|
|
|
|
cumulativeTicks.append(cumulativeTop * tick / 5.0);
|
|
|
|
|
}
|
|
|
|
|
plot->setAxisScaleY(0.0, rateTop * 1.05, rateTicks);
|
|
|
|
|
plot->setAxisScaleY2(0.0, cumulativeTop * 1.05, cumulativeTicks);
|
|
|
|
|
}
|
|
|
|
|
// 自动定标会压缩没有曲线的右轴,下图需要保留这块空白以对齐上图。
|
|
|
|
|
plot->getAxisOf(2)->setMinimizeAxis(false);
|
|
|
|
|
// 两张图都以完整预测时长为基准,缩放复原时也回到同一时间范围。
|
|
|
|
|
// 两张图共用时间范围,零时刻左侧留白,避免起始竖线与纵轴重叠。
|
|
|
|
|
VecDouble ticks;
|
|
|
|
|
for(int tick = 0; tick <= 5; ++tick) ticks.append(time * tick / 5.0);
|
|
|
|
|
plot->setAxisScaleX(0.0, time, ticks);
|
|
|
|
|
plot->setAxisScaleX(-time * 0.05, time, ticks);
|
|
|
|
|
// 时间刻度及标题只在下图显示,上图仍保留横轴数据与同步关系。
|
|
|
|
|
plot->getAxisOf(0)->setMinimizeAxis(i == 0);
|
|
|
|
|
}
|
|
|
|
|
@ -2029,6 +2069,27 @@ void nmSubWndMain::onShowForecastResult(const QString& wellName, const QVector<d
|
|
|
|
|
QTimer::singleShot(0, this, SLOT(fitForecastViews()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmSubWndMain::onReadonlyCurveDoubleClicked(
|
|
|
|
|
ZxPlot* plot, ZxObjBase*, const QPointF& point, bool& processed)
|
|
|
|
|
{
|
|
|
|
|
iGuiPlot* widget = qobject_cast<iGuiPlot*>(sender());
|
|
|
|
|
if(!widget || !plot || processed) return;
|
|
|
|
|
for(int i = plot->getObjCount() - 1; i >= 0; --i) {
|
|
|
|
|
ZxObjCurve* curve = qobject_cast<ZxObjCurve*>(plot->getObjByIndex(i));
|
|
|
|
|
if(!curve || !curve->isVisible()) continue;
|
|
|
|
|
// 框架忽略只读曲线的命中,仅检查双击位置时临时解除,打开表格前恢复保护。
|
|
|
|
|
const bool readonly = curve->isReadOnly();
|
|
|
|
|
curve->setReadOnly(false);
|
|
|
|
|
int option = -1, index = -1;
|
|
|
|
|
const bool hit = curve->_runHitTest(point, option, index);
|
|
|
|
|
curve->setReadOnly(readonly);
|
|
|
|
|
if(!hit) continue;
|
|
|
|
|
processed = true;
|
|
|
|
|
widget->slotShowCurveData(curve);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nmSubWndMain::eventFilter(QObject* watched, QEvent* event)
|
|
|
|
|
{
|
|
|
|
|
// 子窗口缩放、重新显示均在内部控件完成尺寸更新后再适配。
|
|
|
|
|
@ -2091,6 +2152,7 @@ void nmSubWndMain::onShowSensitiveResults()
|
|
|
|
|
updateSensitiveHistogramPlot();
|
|
|
|
|
QSharedPointer<nmDataSensitive::BatchResult> result = manager->getSensitiveData()->getResults();
|
|
|
|
|
iGuiPlot* plot = fitting->getPlotByTag(s_Tag_ChartSensitivity);
|
|
|
|
|
if(plot) clearResultCurveDataTables(plot);
|
|
|
|
|
if(result.isNull()) {
|
|
|
|
|
// 新模型已丢弃旧批次,同时清除图元与撤销记录,避免窗口恢复或保存后残留旧曲线。
|
|
|
|
|
if(plot) {
|
|
|
|
|
@ -2118,6 +2180,8 @@ void nmSubWndMain::onShowSensitiveResults()
|
|
|
|
|
tr("Failed to create sensitivity plot."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
connect(plot, SIGNAL(sigDoubleClicked(ZxPlot*,ZxObjBase*,const QPointF&,bool&)),
|
|
|
|
|
this, SLOT(onReadonlyCurveDoubleClicked(ZxPlot*,ZxObjBase*,const QPointF&,bool&)), Qt::UniqueConnection);
|
|
|
|
|
installSensitiveShow(plot);
|
|
|
|
|
const QSet<QString> hidden = sender() == manager ? QSet<QString>() : hiddenSensitiveCurves(plot);
|
|
|
|
|
QVector<iCurveDesc> curves;
|
|
|
|
|
@ -2288,6 +2352,12 @@ void nmSubWndMain::updateSensitiveHistoryPlot()
|
|
|
|
|
iGuiPlot* plots[] = {history->m_pWxPlotP, history->m_pWxPlotF};
|
|
|
|
|
for(int i = 0; i < 2; ++i) {
|
|
|
|
|
iGuiPlot* plot = plots[i];
|
|
|
|
|
// 只读历史结果不进入 PF 的流动段编辑处理,双击统一打开框架数据表。
|
|
|
|
|
disconnect(plot, SIGNAL(sigDoubleClicked(ZxPlot*,ZxObjBase*,const QPointF&,bool&)),
|
|
|
|
|
history, SLOT(slotSubDoubleClicked(ZxPlot*,ZxObjBase*,const QPointF&,bool&)));
|
|
|
|
|
connect(plot, SIGNAL(sigDoubleClicked(ZxPlot*,ZxObjBase*,const QPointF&,bool&)),
|
|
|
|
|
this, SLOT(onReadonlyCurveDoubleClicked(ZxPlot*,ZxObjBase*,const QPointF&,bool&)), Qt::UniqueConnection);
|
|
|
|
|
clearResultCurveDataTables(plot);
|
|
|
|
|
const QSet<QString> hidden = sender() == manager ? QSet<QString>() : hiddenSensitiveCurves(plot);
|
|
|
|
|
for(int j = plot->m_pPlot->getObjCount() - 1; j >= 0; --j)
|
|
|
|
|
if(qobject_cast<ZxObjCurve*>(plot->m_pPlot->getObjByIndex(j))) plot->m_pPlot->removeObjByIndex(j);
|
|
|
|
|
|