|
|
|
|
@ -6,6 +6,7 @@
|
|
|
|
|
#include <QLabel>
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QCloseEvent>
|
|
|
|
|
#include <QLineEdit>
|
|
|
|
|
#include <QtCore/qnumeric.h>
|
|
|
|
|
#include "nmCalculationDllPebiSolverTask.h"
|
|
|
|
|
#include "nmGUIComponentLineEdit.h"
|
|
|
|
|
@ -35,7 +36,8 @@ nmWxForecast::nmWxForecast(QWidget *parent, nmDataAnalyzeManager* manager)
|
|
|
|
|
{
|
|
|
|
|
setWindowTitle(tr("Forecast"));
|
|
|
|
|
setFixedSize(520, 560);
|
|
|
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
|
// 关闭时只隐藏,所属设计面板复用同一个输入窗口。
|
|
|
|
|
setAttribute(Qt::WA_DeleteOnClose, false);
|
|
|
|
|
|
|
|
|
|
PressureRow tempDefaults;
|
|
|
|
|
m_currentDurationUnit = tempDefaults.duration.getUnit();
|
|
|
|
|
@ -53,6 +55,19 @@ nmWxForecast::nmWxForecast(QWidget *parent, nmDataAnalyzeManager* manager)
|
|
|
|
|
|
|
|
|
|
// 根据加载的数据更新界面
|
|
|
|
|
updateParametersForOption();
|
|
|
|
|
// 初始化完成后再同步编辑,避免加载项目时被标记为修改。
|
|
|
|
|
connect(m_rateTableWidget, SIGNAL(cellChanged(int,int)), this, SLOT(saveDataToManager()));
|
|
|
|
|
connect(m_rDurationUnitCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(saveDataToManager()));
|
|
|
|
|
connect(m_rRateUnitCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(saveDataToManager()));
|
|
|
|
|
const QList<QLineEdit*> edits = m_initialPressureComponent->findChildren<QLineEdit*>();
|
|
|
|
|
foreach(QLineEdit* edit, edits)
|
|
|
|
|
connect(edit, SIGNAL(textEdited(QString)), this, SLOT(saveDataToManager()));
|
|
|
|
|
const QList<QComboBox*> units = m_initialPressureComponent->findChildren<QComboBox*>();
|
|
|
|
|
foreach(QComboBox* unit, units) {
|
|
|
|
|
const int index = unit->findData(m_forecastData.getMultipleRatesData().pressureUnit);
|
|
|
|
|
if(index >= 0) unit->setCurrentIndex(index);
|
|
|
|
|
connect(unit, SIGNAL(currentIndexChanged(QString)), this, SLOT(saveDataToManager()));
|
|
|
|
|
}
|
|
|
|
|
if(m_manager) {
|
|
|
|
|
connect(m_manager, SIGNAL(sigPebiResultSnapshotChanged()), this, SLOT(onModelChanged()));
|
|
|
|
|
connect(m_manager, SIGNAL(sigPebiResultStateChanged()), this, SLOT(onModelChanged()));
|
|
|
|
|
@ -72,8 +87,12 @@ nmWxForecast::~nmWxForecast()
|
|
|
|
|
|
|
|
|
|
void nmWxForecast::loadDataFromManager()
|
|
|
|
|
{
|
|
|
|
|
// 当前先开放分段产量,初始压力默认取已生成模型,输入只保留在内存中。
|
|
|
|
|
// 优先恢复已保存的输入,首次打开时初始压力取已生成模型。
|
|
|
|
|
if(m_manager) m_forecastData = m_manager->getForecastDataCopy();
|
|
|
|
|
m_forecastData.setResult(QSharedPointer<nmDataForecast::Result>());
|
|
|
|
|
const MultipleRates& data = m_forecastData.getMultipleRatesData();
|
|
|
|
|
if(m_rDurationUnitCombo->findText(data.durationUnit) >= 0) m_currentDurationUnit = data.durationUnit;
|
|
|
|
|
if(m_rRateUnitCombo->findText(data.rateUnit) >= 0) m_currentRateUnit = data.rateUnit;
|
|
|
|
|
nmDataAttribute& pressure = m_forecastData.getMultipleRatesData().getInitialPressure();
|
|
|
|
|
if(m_manager && m_forecastData.getForecastOption() != nmDataForecast::MultipleRatesOption) {
|
|
|
|
|
const QSharedPointer<const nmPebiResultSnapshot> solved = m_manager->getPebiResultSnapshot();
|
|
|
|
|
@ -95,6 +114,10 @@ void nmWxForecast::saveDataToManager()
|
|
|
|
|
// 先从界面更新数据
|
|
|
|
|
updateDataFromUI();
|
|
|
|
|
|
|
|
|
|
const QList<QComboBox*> units = m_initialPressureComponent->findChildren<QComboBox*>();
|
|
|
|
|
if(!units.isEmpty())
|
|
|
|
|
m_forecastData.getMultipleRatesData().pressureUnit = units.first()->itemData(units.first()->currentIndex()).toString();
|
|
|
|
|
|
|
|
|
|
// 保存到数据中心
|
|
|
|
|
nmDataAnalyzeManager* pManager = m_manager.data();
|
|
|
|
|
|
|
|
|
|
@ -842,7 +865,7 @@ void nmWxForecast::updateUIFromData()
|
|
|
|
|
FlowRow tempDefaults; // 用于获取单位列表和默认值
|
|
|
|
|
|
|
|
|
|
int dataSize = tableData.size();
|
|
|
|
|
int displayRowCount = (dataSize == 0) ? 1 : dataSize;
|
|
|
|
|
int displayRowCount = (dataSize == 0 && (!m_manager || !m_manager->getForecastData())) ? 1 : dataSize;
|
|
|
|
|
|
|
|
|
|
// 设置行数: 1(单位) + N(数据) + 1(空白)
|
|
|
|
|
m_rateTableWidget->setRowCount(1 + displayRowCount + 1);
|
|
|
|
|
@ -866,11 +889,14 @@ void nmWxForecast::updateUIFromData()
|
|
|
|
|
QString baseRateUnit = rowData.q0.getUnit();
|
|
|
|
|
double displayRateValue = tempDefaults.q0.convertValueByUnitType(baseRateValue, baseRateUnit, m_currentRateUnit);
|
|
|
|
|
|
|
|
|
|
QTableWidgetItem* durationItem = new QTableWidgetItem(QString::number(displayDurValue, 'g', 15));
|
|
|
|
|
// 同单位直接恢复原输入文本,半空行不能补成默认数值。
|
|
|
|
|
QTableWidgetItem* durationItem = new QTableWidgetItem(baseDurUnit == m_currentDurationUnit && rowData.duration.getValue().type() == QVariant::String
|
|
|
|
|
? rowData.duration.getValue().toString() : QString::number(displayDurValue, 'g', 15));
|
|
|
|
|
durationItem->setTextAlignment(Qt::AlignCenter);
|
|
|
|
|
m_rateTableWidget->setItem(tableRow, 0, durationItem);
|
|
|
|
|
|
|
|
|
|
QTableWidgetItem* rateItem = new QTableWidgetItem(QString::number(displayRateValue, 'g', 15));
|
|
|
|
|
QTableWidgetItem* rateItem = new QTableWidgetItem(baseRateUnit == m_currentRateUnit && rowData.q0.getValue().type() == QVariant::String
|
|
|
|
|
? rowData.q0.getValue().toString() : QString::number(displayRateValue, 'g', 15));
|
|
|
|
|
rateItem->setTextAlignment(Qt::AlignCenter);
|
|
|
|
|
m_rateTableWidget->setItem(tableRow, 1, rateItem);
|
|
|
|
|
}
|
|
|
|
|
@ -959,10 +985,9 @@ void nmWxForecast::updateDataFromUI()
|
|
|
|
|
QVector<FlowRow>& tableData = m_forecastData.getMultipleRatesData().getFlowTable();
|
|
|
|
|
tableData.clear();
|
|
|
|
|
|
|
|
|
|
FlowRow tempDefaults;
|
|
|
|
|
// 获取数据模型的基础单位
|
|
|
|
|
QString baseDurUnit = tempDefaults.duration.getUnit();
|
|
|
|
|
QString baseRateUnit = tempDefaults.q0.getUnit();
|
|
|
|
|
// 保留输入单位和未填完的单元格,只有生成时才校验并换算给求解器。
|
|
|
|
|
m_forecastData.getMultipleRatesData().durationUnit = m_currentDurationUnit;
|
|
|
|
|
m_forecastData.getMultipleRatesData().rateUnit = m_currentRateUnit;
|
|
|
|
|
|
|
|
|
|
// 循环到 rowCount() - 1 来跳过最后那个空白行
|
|
|
|
|
for(int i = 1; i < m_rateTableWidget->rowCount() - 1; ++i) {
|
|
|
|
|
@ -977,19 +1002,11 @@ void nmWxForecast::updateDataFromUI()
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FlowRow newRow; // newRow 将使用基础单位
|
|
|
|
|
|
|
|
|
|
if(!durationEmpty) {
|
|
|
|
|
double displayVal = durationItem->text().toDouble();
|
|
|
|
|
// 转换值:从 "当前显示的单位" 转换回 "数据的基础单位"
|
|
|
|
|
double storageVal = tempDefaults.duration.convertValueByUnitType(displayVal, m_currentDurationUnit, baseDurUnit);
|
|
|
|
|
newRow.duration.setValue(storageVal);
|
|
|
|
|
}
|
|
|
|
|
if(!rateEmpty) {
|
|
|
|
|
double displayVal = rateItem->text().toDouble();
|
|
|
|
|
double storageVal = tempDefaults.q0.convertValueByUnitType(displayVal, m_currentRateUnit, baseRateUnit);
|
|
|
|
|
newRow.q0.setValue(storageVal);
|
|
|
|
|
}
|
|
|
|
|
FlowRow newRow;
|
|
|
|
|
newRow.duration.setUnit(m_currentDurationUnit);
|
|
|
|
|
newRow.q0.setUnit(m_currentRateUnit);
|
|
|
|
|
newRow.duration.setValue(durationItem ? durationItem->text().trimmed() : QString());
|
|
|
|
|
newRow.q0.setValue(rateItem ? rateItem->text().trimmed() : QString());
|
|
|
|
|
tableData.append(newRow);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1033,8 +1050,7 @@ void nmWxForecast::onGenerateClicked()
|
|
|
|
|
QMessageBox::warning(this, tr("Forecast"), tr("The target well is unavailable."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
m_wellName = well->m_sWellName;
|
|
|
|
|
m_task = new nmCalculationDllPebiSolverTask(QString(), m_manager, m_wellName, this);
|
|
|
|
|
m_task = new nmCalculationDllPebiSolverTask(QString(), m_manager, well->m_sWellName, this);
|
|
|
|
|
if(!m_task->configureRateForecast(pi, durations, rates)) {
|
|
|
|
|
error = m_task->getFailureReason();
|
|
|
|
|
delete m_task;
|
|
|
|
|
@ -1046,6 +1062,7 @@ void nmWxForecast::onGenerateClicked()
|
|
|
|
|
m_durations = durations;
|
|
|
|
|
m_rates = rates;
|
|
|
|
|
m_sourceSnapshotId = solved->getSnapshotId();
|
|
|
|
|
m_sourceWellInstanceId = well->m_sWellInstanceId;
|
|
|
|
|
// 与敏感性分析一样,主窗口接管成功后才启动,忙碌时释放未启动任务。
|
|
|
|
|
emit sigForecastTaskReady(this, m_task);
|
|
|
|
|
if(!m_calculationRunning) {
|
|
|
|
|
@ -1132,7 +1149,8 @@ void nmWxForecast::onForecastFinished()
|
|
|
|
|
const bool cancelled = m_task->wasCancelled();
|
|
|
|
|
const bool current = m_manager && m_manager->isPebiResultSnapshotCurrent() &&
|
|
|
|
|
!m_task->hasInputChanged(m_manager) &&
|
|
|
|
|
m_manager->getPebiResultSnapshot()->getSnapshotId() == m_sourceSnapshotId;
|
|
|
|
|
m_manager->getPebiResultSnapshot()->getSnapshotId() == m_sourceSnapshotId &&
|
|
|
|
|
m_manager->getCurrentResultWellInstanceId() == m_sourceWellInstanceId;
|
|
|
|
|
const bool success = m_task->wasSuccessful();
|
|
|
|
|
const QString error = m_task->getFailureReason();
|
|
|
|
|
const QVector<QVector<double> > pressure = m_task->getRateForecastPressure();
|
|
|
|
|
@ -1141,12 +1159,27 @@ void nmWxForecast::onForecastFinished()
|
|
|
|
|
m_calculationRunning = false;
|
|
|
|
|
m_parametersGroup->setEnabled(true);
|
|
|
|
|
m_generateButton->setEnabled(true);
|
|
|
|
|
// 取消或失败后恢复同一份输入,方便直接调整后重算。
|
|
|
|
|
if(cancelled || !current || !success) {
|
|
|
|
|
show();
|
|
|
|
|
raise();
|
|
|
|
|
activateWindow();
|
|
|
|
|
}
|
|
|
|
|
if(cancelled) return;
|
|
|
|
|
if(!current || !success) {
|
|
|
|
|
QMessageBox::warning(this, tr("Forecast"), current ? error : tr("The model changed. Generate the forecast again."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
emit sigForecastReady(m_wellName, pressure[0], pressure[1], m_durations, m_rates);
|
|
|
|
|
QSharedPointer<nmDataForecast::Result> result(new nmDataForecast::Result);
|
|
|
|
|
result->snapshotId = m_sourceSnapshotId;
|
|
|
|
|
result->wellInstanceId = m_sourceWellInstanceId;
|
|
|
|
|
result->times = pressure[0];
|
|
|
|
|
result->pressures = pressure[1];
|
|
|
|
|
result->durations = m_durations;
|
|
|
|
|
result->rates = m_rates;
|
|
|
|
|
m_forecastData.setResult(result);
|
|
|
|
|
m_manager->publishForecastResult(m_forecastData);
|
|
|
|
|
m_forecastData.setResult(QSharedPointer<nmDataForecast::Result>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxForecast::onModelChanged()
|
|
|
|
|
|