|
|
|
|
@ -13,13 +13,75 @@
|
|
|
|
|
#include "nmGUIComponentLineEdit.h"
|
|
|
|
|
#include "nmPebiResultSnapshot.h"
|
|
|
|
|
#include "ZxBaseUtil.h"
|
|
|
|
|
#include "iUnitGroup.h"
|
|
|
|
|
#include "iUnitHelper.h"
|
|
|
|
|
#include "iUnitWxBinder.h"
|
|
|
|
|
#include "nmTranslationManager.h"
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
iUnitGroup* forecastUnitGroup(UnitType type)
|
|
|
|
|
{
|
|
|
|
|
// 与参数面板共用底层时间、绝对压力和体积流量单位组。
|
|
|
|
|
return iUnitHelper::getUnitGroupByUnit(type == UNIT_TYPE_TIME ? "s" :
|
|
|
|
|
type == UNIT_TYPE_PRESSURE ? "MPa" : "stb/d");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString forecastUnitName(iUnitGroup* group, QString unit)
|
|
|
|
|
{
|
|
|
|
|
// 只统一旧数据的名称写法,倍率仍由底层单位组提供。
|
|
|
|
|
unit.replace("^", "").replace(QChar(0x00b3), "3");
|
|
|
|
|
unit.replace("/D", "/d").replace("sec", "s").replace("hr", "h");
|
|
|
|
|
if(unit == "day" || unit == "Day") unit = "d";
|
|
|
|
|
if(unit == "psia") unit = "psi";
|
|
|
|
|
if(unit == "bara") unit = "bar";
|
|
|
|
|
if(unit == "KPa") unit = "kPa";
|
|
|
|
|
if(unit == "B/d") unit = "stb/d";
|
|
|
|
|
if(group) {
|
|
|
|
|
foreach(const QString& name, group->getAllUnitNames()) {
|
|
|
|
|
if(forecastUnitName(NULL, name) == unit) return name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return unit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList forecastUnits(const nmDataAttribute& attribute)
|
|
|
|
|
{
|
|
|
|
|
// 下拉选项直接取软件单位配置。
|
|
|
|
|
iUnitGroup* group = forecastUnitGroup(attribute.getAttributeUnitType());
|
|
|
|
|
return group ? group->getAllUnitNames() : attribute.getListUnitSelections();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double convertForecastValue(const nmDataAttribute& attribute, double value,
|
|
|
|
|
const QString& fromUnit, const QString& toUnit)
|
|
|
|
|
{
|
|
|
|
|
if(fromUnit == toUnit) return value;
|
|
|
|
|
iUnitGroup* group = forecastUnitGroup(attribute.getAttributeUnitType());
|
|
|
|
|
if(!group) return attribute.convertValueByUnitType(value, fromUnit, toUnit);
|
|
|
|
|
QString source = forecastUnitName(group, fromUnit);
|
|
|
|
|
const QString destination = forecastUnitName(group, toUnit);
|
|
|
|
|
// 旧项目可能保存了周、月或旧流量前缀,先按原定义转入底层支持的单位。
|
|
|
|
|
if(group->indexOf(source) < 0 && (attribute.getListUnitSelections().contains(fromUnit) ||
|
|
|
|
|
nmDataAttribute::detectUnitType(fromUnit) == attribute.getAttributeUnitType())) {
|
|
|
|
|
const QString bridge = attribute.getAttributeUnitType() == UNIT_TYPE_TIME ? "sec" :
|
|
|
|
|
attribute.getAttributeUnitType() == UNIT_TYPE_PRESSURE ? "MPa" : "m^3/D";
|
|
|
|
|
value = attribute.convertValueByUnitType(value, fromUnit, bridge);
|
|
|
|
|
source = forecastUnitName(group, bridge);
|
|
|
|
|
}
|
|
|
|
|
double converted = 0.0;
|
|
|
|
|
int digits = 6;
|
|
|
|
|
return group->convert(source, value, destination, converted, digits) ? converted : qQNaN();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nmWxForecast::nmWxForecast(QWidget *parent, nmDataAnalyzeManager* manager)
|
|
|
|
|
: iDlgBase(parent)
|
|
|
|
|
, m_manager(manager ? manager : nmDataAnalyzeManager::getCurrentInstance())
|
|
|
|
|
, m_task(NULL)
|
|
|
|
|
, m_calculationRunning(false)
|
|
|
|
|
, m_initialPressureComponent(nullptr)
|
|
|
|
|
, m_initialPressureEdit(nullptr)
|
|
|
|
|
, m_initialPressureUnit(nullptr)
|
|
|
|
|
, m_initialPressure(nullptr)
|
|
|
|
|
, m_pressureUnitBinder(nullptr)
|
|
|
|
|
, m_abandonmentRateComponent(nullptr)
|
|
|
|
|
, m_maximumRateComponent(nullptr)
|
|
|
|
|
, m_forecastDurationComponent(nullptr)
|
|
|
|
|
@ -44,11 +106,11 @@ nmWxForecast::nmWxForecast(QWidget *parent, nmDataAnalyzeManager* manager)
|
|
|
|
|
new nmDialogPreviewGuard(this);
|
|
|
|
|
|
|
|
|
|
PressureRow tempDefaults;
|
|
|
|
|
m_currentDurationUnit = tempDefaults.duration.getUnit();
|
|
|
|
|
m_currentPressureUnit = tempDefaults.pressure.getUnit();
|
|
|
|
|
m_currentDurationUnit = forecastUnitName(forecastUnitGroup(UNIT_TYPE_TIME), tempDefaults.duration.getUnit());
|
|
|
|
|
m_currentPressureUnit = forecastUnitName(forecastUnitGroup(UNIT_TYPE_PRESSURE), tempDefaults.pressure.getUnit());
|
|
|
|
|
|
|
|
|
|
FlowRow tempFlowDefaults;
|
|
|
|
|
m_currentRateUnit = tempFlowDefaults.q0.getUnit();
|
|
|
|
|
m_currentRateUnit = forecastUnitName(forecastUnitGroup(UNIT_TYPE_FLOW_RATE), tempFlowDefaults.q0.getUnit());
|
|
|
|
|
|
|
|
|
|
// 先构建UI
|
|
|
|
|
setupUI();
|
|
|
|
|
@ -59,12 +121,6 @@ nmWxForecast::nmWxForecast(QWidget *parent, nmDataAnalyzeManager* manager)
|
|
|
|
|
|
|
|
|
|
// 根据加载的数据更新界面
|
|
|
|
|
updateParametersForOption();
|
|
|
|
|
// 编辑内容保留在窗口中,点击生成后再提交到数据中心。
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
if(m_manager) {
|
|
|
|
|
connect(m_manager, SIGNAL(sigPebiResultSnapshotChanged()), this, SLOT(onModelChanged()));
|
|
|
|
|
connect(m_manager, SIGNAL(sigPebiResultSnapshotChanged()), this, SLOT(reloadInputData()));
|
|
|
|
|
@ -92,18 +148,20 @@ 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;
|
|
|
|
|
const QString durationUnit = forecastUnitName(forecastUnitGroup(UNIT_TYPE_TIME), data.durationUnit);
|
|
|
|
|
const QString rateUnit = forecastUnitName(forecastUnitGroup(UNIT_TYPE_FLOW_RATE), data.rateUnit);
|
|
|
|
|
m_currentDurationUnit = m_rDurationUnitCombo->findText(durationUnit) >= 0 ? durationUnit :
|
|
|
|
|
forecastUnitName(forecastUnitGroup(UNIT_TYPE_TIME), "hr");
|
|
|
|
|
m_currentRateUnit = m_rRateUnitCombo->findText(rateUnit) >= 0 ? rateUnit :
|
|
|
|
|
forecastUnitName(forecastUnitGroup(UNIT_TYPE_FLOW_RATE), "B/D");
|
|
|
|
|
nmDataAttribute& pressure = m_forecastData.getMultipleRatesData().getInitialPressure();
|
|
|
|
|
if(m_manager && m_forecastData.getForecastOption() != nmDataForecast::MultipleRatesOption) {
|
|
|
|
|
const QSharedPointer<const nmPebiResultSnapshot> solved = m_manager->getPebiResultSnapshot();
|
|
|
|
|
if(!solved.isNull()) {
|
|
|
|
|
pressure.setValue(pressure.convertValueByUnitType(
|
|
|
|
|
solved->getReservoirParameters().m_dInitialPressure, "MPa", pressure.getUnit()));
|
|
|
|
|
pressure.setUnit("MPa");
|
|
|
|
|
pressure.setValue(solved->getReservoirParameters().m_dInitialPressure);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 本页使用绝对压力,避免通用单位控件把表压当作绝压换算。
|
|
|
|
|
pressure.setListUnitSelections(QStringList() << "MPa" << "psia" << "kPa" << "bara");
|
|
|
|
|
m_forecastData.setForecastOption(nmDataForecast::MultipleRatesOption);
|
|
|
|
|
m_multipleRatesRadio->blockSignals(true);
|
|
|
|
|
m_multipleRatesRadio->setChecked(true);
|
|
|
|
|
@ -123,9 +181,7 @@ 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();
|
|
|
|
|
m_forecastData.getMultipleRatesData().pressureUnit = m_initialPressureUnit->currentText();
|
|
|
|
|
|
|
|
|
|
// 保存到数据中心
|
|
|
|
|
nmDataAnalyzeManager* pManager = m_manager.data();
|
|
|
|
|
@ -206,28 +262,24 @@ void nmWxForecast::setupUI()
|
|
|
|
|
|
|
|
|
|
// (row 0) Initial pressure
|
|
|
|
|
ConstantPressure& constantPressureData = m_forecastData.getConstantPressureData();
|
|
|
|
|
m_initialPressureComponent = new nmGUIComponentLineEdit(
|
|
|
|
|
&constantPressureData.getInitialPressure(),
|
|
|
|
|
true,
|
|
|
|
|
this
|
|
|
|
|
);
|
|
|
|
|
// 标签按内容占宽,数值和单位按储层参数页的比例铺满剩余空间。
|
|
|
|
|
QLabel* pressureLabel = m_initialPressureComponent->findChild<QLabel*>();
|
|
|
|
|
// 先解除通用控件的 200 像素标签限制,再由布局按实际文字宽度分配。
|
|
|
|
|
pressureLabel->setMinimumWidth(0);
|
|
|
|
|
pressureLabel->setMaximumWidth(QWIDGETSIZE_MAX);
|
|
|
|
|
// 保持原布局,用底层绑定器管理初始压力的数值和单位。
|
|
|
|
|
QWidget* pressureWidget = new QWidget(this);
|
|
|
|
|
QHBoxLayout* pressureLayout = new QHBoxLayout(pressureWidget);
|
|
|
|
|
pressureLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
pressureLayout->setSpacing(5);
|
|
|
|
|
QLabel* pressureLabel = new QLabel(nmTranslationManager::mapToChinese("Initial pressure"), pressureWidget);
|
|
|
|
|
pressureLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
|
|
|
|
|
QLineEdit* pressureEdit = m_initialPressureComponent->findChild<QLineEdit*>();
|
|
|
|
|
QComboBox* pressureUnit = m_initialPressureComponent->findChild<QComboBox*>();
|
|
|
|
|
pressureEdit->setMinimumWidth(140);
|
|
|
|
|
pressureEdit->setMaximumWidth(QWIDGETSIZE_MAX);
|
|
|
|
|
pressureUnit->setMinimumWidth(86);
|
|
|
|
|
pressureUnit->setMaximumWidth(QWIDGETSIZE_MAX);
|
|
|
|
|
QHBoxLayout* pressureLayout = static_cast<QHBoxLayout*>(m_initialPressureComponent->layout());
|
|
|
|
|
delete pressureLayout->takeAt(1); // 移除标签后的弹性留白。
|
|
|
|
|
pressureLayout->setStretchFactor(pressureEdit, 8);
|
|
|
|
|
pressureLayout->setStretchFactor(pressureUnit, 5);
|
|
|
|
|
m_parametersLayout->addWidget(m_initialPressureComponent, row, 0, 1, 2);
|
|
|
|
|
m_initialPressureEdit = new QLineEdit(pressureWidget);
|
|
|
|
|
m_initialPressureUnit = new QComboBox(pressureWidget);
|
|
|
|
|
m_initialPressureEdit->setMinimumWidth(140);
|
|
|
|
|
m_initialPressureUnit->setMinimumWidth(86);
|
|
|
|
|
m_initialPressureUnit->addItem("MPa");
|
|
|
|
|
m_pressureUnitBinder = new iUnitWxBinder(this);
|
|
|
|
|
m_pressureUnitBinder->registerUnitGroup(m_initialPressureEdit, m_initialPressureUnit);
|
|
|
|
|
pressureLayout->addWidget(pressureLabel);
|
|
|
|
|
pressureLayout->addWidget(m_initialPressureEdit, 8);
|
|
|
|
|
pressureLayout->addWidget(m_initialPressureUnit, 5);
|
|
|
|
|
m_parametersLayout->addWidget(pressureWidget, row, 0, 1, 2);
|
|
|
|
|
row++;
|
|
|
|
|
|
|
|
|
|
// (row 1) Abandonment rate
|
|
|
|
|
@ -282,6 +334,45 @@ void nmWxForecast::setupUI()
|
|
|
|
|
m_extMultiR = buildExtMultiRatePage();
|
|
|
|
|
m_extMultiR->setMinimumHeight(80);
|
|
|
|
|
|
|
|
|
|
// 制度表沿用敏感性分析和编辑井的表头、行号、隔行底色及网格样式。
|
|
|
|
|
QTableWidget* scheduleTables[] = {m_pressureTableWidget, m_rateTableWidget};
|
|
|
|
|
for(int i = 0; i < 2; ++i) {
|
|
|
|
|
QTableWidget* table = scheduleTables[i];
|
|
|
|
|
table->verticalHeader()->setVisible(true);
|
|
|
|
|
table->verticalHeader()->setMovable(false);
|
|
|
|
|
table->verticalHeader()->setDefaultAlignment(Qt::AlignCenter);
|
|
|
|
|
table->verticalHeader()->setMinimumWidth(18);
|
|
|
|
|
table->horizontalHeader()->setHighlightSections(false);
|
|
|
|
|
table->setAlternatingRowColors(true);
|
|
|
|
|
table->setShowGrid(true);
|
|
|
|
|
table->setStyleSheet(
|
|
|
|
|
"QTableWidget {"
|
|
|
|
|
" background-color: palette(base);"
|
|
|
|
|
" alternate-background-color: rgb(232, 232, 232);"
|
|
|
|
|
" gridline-color: palette(midlight);"
|
|
|
|
|
" border: 1px solid palette(mid);"
|
|
|
|
|
"}"
|
|
|
|
|
"QHeaderView {"
|
|
|
|
|
" background-color: palette(button);"
|
|
|
|
|
" color: palette(button-text);"
|
|
|
|
|
"}"
|
|
|
|
|
"QHeaderView::section {"
|
|
|
|
|
" background-color: palette(button);"
|
|
|
|
|
" color: palette(button-text);"
|
|
|
|
|
" border: none;"
|
|
|
|
|
" border-right: 1px solid palette(mid);"
|
|
|
|
|
" border-bottom: 1px solid palette(mid);"
|
|
|
|
|
"}"
|
|
|
|
|
"QTableCornerButton::section {"
|
|
|
|
|
" background-color: palette(base);"
|
|
|
|
|
" border: none;"
|
|
|
|
|
" border-right: 1px solid palette(mid);"
|
|
|
|
|
" border-bottom: 1px solid palette(mid);"
|
|
|
|
|
"}");
|
|
|
|
|
// 第零行只显示单位,不参与制度行编号。
|
|
|
|
|
table->setVerticalHeaderItem(0, new QTableWidgetItem(""));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- 2. 创建一个空页面---
|
|
|
|
|
m_extEmpty = buildExtEmptyPage("");
|
|
|
|
|
|
|
|
|
|
@ -405,8 +496,8 @@ QWidget* nmWxForecast::buildExtMultiPressurePage()
|
|
|
|
|
m_pressureTableWidget->setRowHeight(0, 24); // 设置一个合适的高度
|
|
|
|
|
|
|
|
|
|
PressureRow tempDefaults; // 用于获取单位列表
|
|
|
|
|
QStringList durationUnits = tempDefaults.duration.getListUnitSelections();
|
|
|
|
|
QStringList pressureUnits = tempDefaults.pressure.getListUnitSelections();
|
|
|
|
|
QStringList durationUnits = forecastUnits(tempDefaults.duration);
|
|
|
|
|
QStringList pressureUnits = forecastUnits(tempDefaults.pressure);
|
|
|
|
|
|
|
|
|
|
// --- 第0列:Duration 单位下拉框 ---
|
|
|
|
|
m_pDurationUnitCombo = new QComboBox(m_pressureTableWidget);
|
|
|
|
|
@ -473,8 +564,8 @@ QWidget* nmWxForecast::buildExtMultiRatePage()
|
|
|
|
|
m_rateTableWidget->setRowHeight(0, 24);
|
|
|
|
|
|
|
|
|
|
FlowRow tempDefaults; // 使用 FlowRow 获取单位
|
|
|
|
|
QStringList durationUnits = tempDefaults.duration.getListUnitSelections();
|
|
|
|
|
QStringList rateUnits = tempDefaults.q0.getListUnitSelections(); // 获取速率单位
|
|
|
|
|
QStringList durationUnits = forecastUnits(tempDefaults.duration);
|
|
|
|
|
QStringList rateUnits = forecastUnits(tempDefaults.q0); // 获取速率单位
|
|
|
|
|
|
|
|
|
|
// --- 第0列:Duration 单位下拉框 ---
|
|
|
|
|
m_rDurationUnitCombo = new QComboBox(m_rateTableWidget);
|
|
|
|
|
@ -694,8 +785,7 @@ void nmWxForecast::updateParametersForOption()
|
|
|
|
|
if(option == nmDataForecast::ConstantPressureOption) {
|
|
|
|
|
ConstantPressure& cpData = m_forecastData.getConstantPressureData();
|
|
|
|
|
|
|
|
|
|
if(m_initialPressureComponent)
|
|
|
|
|
m_initialPressureComponent->setOriginValue(&cpData.getInitialPressure());
|
|
|
|
|
m_initialPressure = &cpData.getInitialPressure();
|
|
|
|
|
if(m_abandonmentRateComponent)
|
|
|
|
|
m_abandonmentRateComponent->setOriginValue(&cpData.getAbandonmentRate());
|
|
|
|
|
if(m_maximumRateComponent)
|
|
|
|
|
@ -709,8 +799,7 @@ void nmWxForecast::updateParametersForOption()
|
|
|
|
|
} else if(option == nmDataForecast::DecliningPressureOption) {
|
|
|
|
|
DecliningPressure& dpData = m_forecastData.getDecliningPressureData();
|
|
|
|
|
|
|
|
|
|
if(m_initialPressureComponent)
|
|
|
|
|
m_initialPressureComponent->setOriginValue(&dpData.getInitialPressure());
|
|
|
|
|
m_initialPressure = &dpData.getInitialPressure();
|
|
|
|
|
if(m_abandonmentRateComponent)
|
|
|
|
|
m_abandonmentRateComponent->setOriginValue(&dpData.getAbandonmentRate());
|
|
|
|
|
if(m_maximumRateComponent)
|
|
|
|
|
@ -725,8 +814,7 @@ void nmWxForecast::updateParametersForOption()
|
|
|
|
|
} else if(option == nmDataForecast::MultiplePressuresOption) {
|
|
|
|
|
MultiplePressures& mpData = m_forecastData.getMultiplePressuresData();
|
|
|
|
|
|
|
|
|
|
if(m_initialPressureComponent)
|
|
|
|
|
m_initialPressureComponent->setOriginValue(&mpData.getInitialPressure());
|
|
|
|
|
m_initialPressure = &mpData.getInitialPressure();
|
|
|
|
|
if(m_abandonmentRateComponent)
|
|
|
|
|
m_abandonmentRateComponent->setOriginValue(&mpData.getAbandonmentRate());
|
|
|
|
|
if(m_maximumRateComponent)
|
|
|
|
|
@ -746,8 +834,7 @@ void nmWxForecast::updateParametersForOption()
|
|
|
|
|
} else if(option == nmDataForecast::MultipleRatesOption) {
|
|
|
|
|
MultipleRates& mrData = m_forecastData.getMultipleRatesData();
|
|
|
|
|
|
|
|
|
|
if(m_initialPressureComponent)
|
|
|
|
|
m_initialPressureComponent->setOriginValue(&mrData.getInitialPressure());
|
|
|
|
|
m_initialPressure = &mrData.getInitialPressure();
|
|
|
|
|
|
|
|
|
|
if (m_abandonmentRateCheck) m_abandonmentRateCheck->setVisible(false);
|
|
|
|
|
if (m_abandonmentStack) m_abandonmentStack->setCurrentIndex(1);
|
|
|
|
|
@ -816,8 +903,14 @@ void nmWxForecast::updateUIFromData()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 刷新所有组件的显示值
|
|
|
|
|
if(m_initialPressureComponent)
|
|
|
|
|
m_initialPressureComponent->updateValueFromOrigin();
|
|
|
|
|
// 基准值交给绑定器,显示单位恢复为上次保存的选项。
|
|
|
|
|
QString pressureUnit = forecastUnitName(forecastUnitGroup(UNIT_TYPE_PRESSURE),
|
|
|
|
|
option == nmDataForecast::MultipleRatesOption ? m_forecastData.getMultipleRatesData().pressureUnit : m_initialPressure->getUnit());
|
|
|
|
|
if(m_initialPressureUnit->findText(pressureUnit) < 0)
|
|
|
|
|
pressureUnit = forecastUnitName(forecastUnitGroup(UNIT_TYPE_PRESSURE), m_initialPressure->getUnit());
|
|
|
|
|
m_pressureUnitBinder->setCurrentUnit(m_initialPressureEdit, pressureUnit);
|
|
|
|
|
m_pressureUnitBinder->setBaseValue(m_initialPressureEdit, convertForecastValue(*m_initialPressure,
|
|
|
|
|
m_initialPressure->getValue().toDouble(), m_initialPressure->getUnit(), "MPa"));
|
|
|
|
|
|
|
|
|
|
if(m_abandonmentRateComponent)
|
|
|
|
|
m_abandonmentRateComponent->updateValueFromOrigin();
|
|
|
|
|
@ -860,6 +953,8 @@ void nmWxForecast::updateUIFromData()
|
|
|
|
|
int displayRowCount = (dataSize == 0) ? 1 : dataSize;
|
|
|
|
|
|
|
|
|
|
m_pressureTableWidget->setRowCount(1 + displayRowCount + 1);
|
|
|
|
|
// 末尾空行用于继续输入,填入内容后再显示编号。
|
|
|
|
|
m_pressureTableWidget->setVerticalHeaderItem(displayRowCount + 1, new QTableWidgetItem(""));
|
|
|
|
|
|
|
|
|
|
if(m_pDurationUnitCombo) m_pDurationUnitCombo->setCurrentIndex(m_pDurationUnitCombo->findText(m_currentDurationUnit));
|
|
|
|
|
|
|
|
|
|
@ -870,15 +965,16 @@ void nmWxForecast::updateUIFromData()
|
|
|
|
|
const PressureRow& rowData = (i < dataSize) ? tableData.at(i) : tempDefaults;
|
|
|
|
|
|
|
|
|
|
int tableRow = i + 1;
|
|
|
|
|
m_pressureTableWidget->setVerticalHeaderItem(tableRow, new QTableWidgetItem(QString::number(tableRow)));
|
|
|
|
|
|
|
|
|
|
// 转换值:从 "数据的基础单位" 转换为 "当前显示的单位"
|
|
|
|
|
double baseDurValue = rowData.duration.getValue().toDouble();
|
|
|
|
|
QString baseDurUnit = rowData.duration.getUnit();
|
|
|
|
|
double displayDurValue = tempDefaults.duration.convertValueByUnitType(baseDurValue, baseDurUnit, m_currentDurationUnit);
|
|
|
|
|
double displayDurValue = convertForecastValue(tempDefaults.duration, baseDurValue, baseDurUnit, m_currentDurationUnit);
|
|
|
|
|
|
|
|
|
|
double basePresValue = rowData.pressure.getValue().toDouble();
|
|
|
|
|
QString basePresUnit = rowData.pressure.getUnit();
|
|
|
|
|
double displayPresValue = tempDefaults.pressure.convertValueByUnitType(basePresValue, basePresUnit, m_currentPressureUnit);
|
|
|
|
|
double displayPresValue = convertForecastValue(tempDefaults.pressure, basePresValue, basePresUnit, m_currentPressureUnit);
|
|
|
|
|
|
|
|
|
|
QTableWidgetItem* durationItem = new QTableWidgetItem(QString::number(displayDurValue, 'g', 15));
|
|
|
|
|
durationItem->setTextAlignment(Qt::AlignCenter);
|
|
|
|
|
@ -916,6 +1012,8 @@ void nmWxForecast::updateUIFromData()
|
|
|
|
|
|
|
|
|
|
// 设置行数: 1(单位) + N(数据) + 1(空白)
|
|
|
|
|
m_rateTableWidget->setRowCount(1 + displayRowCount + 1);
|
|
|
|
|
// 单位行和末尾输入空行不编号,数据行从一开始。
|
|
|
|
|
m_rateTableWidget->setVerticalHeaderItem(displayRowCount + 1, new QTableWidgetItem(""));
|
|
|
|
|
|
|
|
|
|
// 设置下拉框为当前单位
|
|
|
|
|
if(m_rDurationUnitCombo) m_rDurationUnitCombo->setCurrentIndex(m_rDurationUnitCombo->findText(m_currentDurationUnit));
|
|
|
|
|
@ -926,23 +1024,28 @@ void nmWxForecast::updateUIFromData()
|
|
|
|
|
const FlowRow& rowData = (i < dataSize) ? tableData.at(i) : tempDefaults;
|
|
|
|
|
|
|
|
|
|
int tableRow = i + 1;
|
|
|
|
|
m_rateTableWidget->setVerticalHeaderItem(tableRow, new QTableWidgetItem(QString::number(tableRow)));
|
|
|
|
|
|
|
|
|
|
// 转换值:从 "数据的基础单位" 转换为 "当前显示的单位"
|
|
|
|
|
double baseDurValue = rowData.duration.getValue().toDouble();
|
|
|
|
|
bool durationOK = false;
|
|
|
|
|
double baseDurValue = rowData.duration.getValue().toString().toDouble(&durationOK);
|
|
|
|
|
QString baseDurUnit = rowData.duration.getUnit();
|
|
|
|
|
double displayDurValue = tempDefaults.duration.convertValueByUnitType(baseDurValue, baseDurUnit, m_currentDurationUnit);
|
|
|
|
|
double displayDurValue = convertForecastValue(tempDefaults.duration, baseDurValue, baseDurUnit, m_currentDurationUnit);
|
|
|
|
|
|
|
|
|
|
double baseRateValue = rowData.q0.getValue().toDouble();
|
|
|
|
|
bool rateOK = false;
|
|
|
|
|
double baseRateValue = rowData.q0.getValue().toString().toDouble(&rateOK);
|
|
|
|
|
QString baseRateUnit = rowData.q0.getUnit();
|
|
|
|
|
double displayRateValue = tempDefaults.q0.convertValueByUnitType(baseRateValue, baseRateUnit, m_currentRateUnit);
|
|
|
|
|
double displayRateValue = convertForecastValue(tempDefaults.q0, baseRateValue, baseRateUnit, m_currentRateUnit);
|
|
|
|
|
|
|
|
|
|
// 同单位直接恢复原输入文本,半空行不能补成默认数值。
|
|
|
|
|
QTableWidgetItem* durationItem = new QTableWidgetItem(baseDurUnit == m_currentDurationUnit && rowData.duration.getValue().type() == QVariant::String
|
|
|
|
|
QTableWidgetItem* durationItem = new QTableWidgetItem(rowData.duration.getValue().type() == QVariant::String &&
|
|
|
|
|
(baseDurUnit == m_currentDurationUnit || !durationOK)
|
|
|
|
|
? rowData.duration.getValue().toString() : QString::number(displayDurValue, 'g', 15));
|
|
|
|
|
durationItem->setTextAlignment(Qt::AlignCenter);
|
|
|
|
|
m_rateTableWidget->setItem(tableRow, 0, durationItem);
|
|
|
|
|
|
|
|
|
|
QTableWidgetItem* rateItem = new QTableWidgetItem(baseRateUnit == m_currentRateUnit && rowData.q0.getValue().type() == QVariant::String
|
|
|
|
|
QTableWidgetItem* rateItem = new QTableWidgetItem(rowData.q0.getValue().type() == QVariant::String &&
|
|
|
|
|
(baseRateUnit == m_currentRateUnit || !rateOK)
|
|
|
|
|
? rowData.q0.getValue().toString() : QString::number(displayRateValue, 'g', 15));
|
|
|
|
|
rateItem->setTextAlignment(Qt::AlignCenter);
|
|
|
|
|
m_rateTableWidget->setItem(tableRow, 1, rateItem);
|
|
|
|
|
@ -959,8 +1062,9 @@ void nmWxForecast::updateUIFromData()
|
|
|
|
|
void nmWxForecast::updateDataFromUI()
|
|
|
|
|
{
|
|
|
|
|
// 将界面数据写回到数据模型
|
|
|
|
|
if(m_initialPressureComponent)
|
|
|
|
|
m_initialPressureComponent->updateValueToOrigin();
|
|
|
|
|
// 存储绝对压力,界面单位单独保存,不改变求解器所需的 MPa 数值。
|
|
|
|
|
m_initialPressure->setValue(m_pressureUnitBinder->getBaseValue(m_initialPressureEdit));
|
|
|
|
|
m_initialPressure->setUnit("MPa");
|
|
|
|
|
|
|
|
|
|
if(m_abandonmentRateComponent)
|
|
|
|
|
m_abandonmentRateComponent->updateValueToOrigin();
|
|
|
|
|
@ -1010,13 +1114,13 @@ void nmWxForecast::updateDataFromUI()
|
|
|
|
|
if(!durationEmpty) {
|
|
|
|
|
double displayVal = durationItem->text().toDouble();
|
|
|
|
|
// 转换值:从 "当前显示的单位" 转换回 "数据的基础单位"
|
|
|
|
|
double storageVal = tempDefaults.duration.convertValueByUnitType(displayVal, m_currentDurationUnit, baseDurUnit);
|
|
|
|
|
double storageVal = convertForecastValue(tempDefaults.duration, displayVal, m_currentDurationUnit, baseDurUnit);
|
|
|
|
|
newRow.duration.setValue(storageVal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!pressureEmpty) {
|
|
|
|
|
double displayVal = pressureItem->text().toDouble();
|
|
|
|
|
double storageVal = tempDefaults.pressure.convertValueByUnitType(displayVal, m_currentPressureUnit, basePresUnit);
|
|
|
|
|
double storageVal = convertForecastValue(tempDefaults.pressure, displayVal, m_currentPressureUnit, basePresUnit);
|
|
|
|
|
newRow.pressure.setValue(storageVal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1085,12 +1189,14 @@ void nmWxForecast::onGenerateClicked()
|
|
|
|
|
QMessageBox::warning(this, tr("Forecast"), error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
nmDataAttribute& pressure = m_forecastData.getMultipleRatesData().getInitialPressure();
|
|
|
|
|
if(!m_initialPressureComponent->updateValueToOrigin()) {
|
|
|
|
|
// 校验当前文本,计算取绑定器保存的精确基准值,避免显示舍入影响压力。
|
|
|
|
|
bool pressureOK = false;
|
|
|
|
|
const double inputPressure = m_initialPressureEdit->text().toDouble(&pressureOK);
|
|
|
|
|
const double pi = m_pressureUnitBinder->getBaseValue(m_initialPressureEdit);
|
|
|
|
|
if(!pressureOK || !qIsFinite(inputPressure) || inputPressure <= 0.0 || !qIsFinite(pi) || pi <= 0.0) {
|
|
|
|
|
QMessageBox::warning(this, tr("Forecast"), tr("Enter a positive initial pressure."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const double pi = pressure.convertValueByUnitType(pressure.getValue().toDouble(), pressure.getUnit(), "MPa");
|
|
|
|
|
// 与主界面的结果井选择保持一致,预测制度只替换当前井,其他井共同参与求解。
|
|
|
|
|
const nmPebiResultWellSnapshot* well = solved->findWell(m_manager->getCurrentResultWellInstanceId());
|
|
|
|
|
if(!well) {
|
|
|
|
|
@ -1171,8 +1277,8 @@ bool nmWxForecast::readRateSchedule(QVector<double>& durations, QVector<double>&
|
|
|
|
|
bool durationOk = false, rateOk = false;
|
|
|
|
|
double duration = durationText.toDouble(&durationOk);
|
|
|
|
|
double rate = rateText.toDouble(&rateOk);
|
|
|
|
|
duration = units.duration.convertValueByUnitType(duration, m_currentDurationUnit, "hr");
|
|
|
|
|
rate = units.q0.convertValueByUnitType(rate, m_currentRateUnit, "m^3/D");
|
|
|
|
|
duration = convertForecastValue(units.duration, duration, m_currentDurationUnit, "hr");
|
|
|
|
|
rate = convertForecastValue(units.q0, rate, m_currentRateUnit, "m^3/D");
|
|
|
|
|
if(!durationOk || !rateOk || !qIsFinite(duration) || duration <= 0.0 ||
|
|
|
|
|
!qIsFinite(rate) || rate < 0.0) {
|
|
|
|
|
error = tr("Row %1: enter a positive duration and a non-negative production rate (0 for shut-in).").arg(row);
|
|
|
|
|
@ -1265,6 +1371,9 @@ void nmWxForecast::onPressureCellChanged(int row, int column)
|
|
|
|
|
|
|
|
|
|
int newRow = m_pressureTableWidget->rowCount();
|
|
|
|
|
m_pressureTableWidget->insertRow(newRow);
|
|
|
|
|
// 原空行成为制度行,新追加的输入行暂不编号。
|
|
|
|
|
m_pressureTableWidget->setVerticalHeaderItem(row, new QTableWidgetItem(QString::number(row)));
|
|
|
|
|
m_pressureTableWidget->setVerticalHeaderItem(newRow, new QTableWidgetItem(""));
|
|
|
|
|
|
|
|
|
|
// 给新行两列预置空 item,这样用户一输入就居中
|
|
|
|
|
m_pressureTableWidget->setItem(newRow, 0, makeCenteredEmptyItem());
|
|
|
|
|
@ -1294,7 +1403,7 @@ void nmWxForecast::onPressureUnitChanged(const QString& unit)
|
|
|
|
|
if(dataItem && !dataItem->text().isEmpty()) {
|
|
|
|
|
|
|
|
|
|
double oldDisplayValue = dataItem->text().toDouble();
|
|
|
|
|
double newDisplayValue = tempDefaults.pressure.convertValueByUnitType(oldDisplayValue, oldUnit, unit);
|
|
|
|
|
double newDisplayValue = convertForecastValue(tempDefaults.pressure, oldDisplayValue, oldUnit, unit);
|
|
|
|
|
dataItem->setText(QString::number(newDisplayValue));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1322,6 +1431,9 @@ void nmWxForecast::onRateCellChanged(int row, int column)
|
|
|
|
|
|
|
|
|
|
int newRow = m_rateTableWidget->rowCount();
|
|
|
|
|
m_rateTableWidget->insertRow(newRow);
|
|
|
|
|
// 原空行成为制度行,新追加的输入行暂不编号。
|
|
|
|
|
m_rateTableWidget->setVerticalHeaderItem(row, new QTableWidgetItem(QString::number(row)));
|
|
|
|
|
m_rateTableWidget->setVerticalHeaderItem(newRow, new QTableWidgetItem(""));
|
|
|
|
|
|
|
|
|
|
m_rateTableWidget->setItem(newRow, 0, makeCenteredEmptyItem());
|
|
|
|
|
m_rateTableWidget->setItem(newRow, 1, makeCenteredEmptyItem());
|
|
|
|
|
@ -1351,7 +1463,7 @@ void nmWxForecast::onSharedDurationUnitChanged(const QString& unit)
|
|
|
|
|
if(dataItem && !dataItem->text().isEmpty()) {
|
|
|
|
|
double oldDisplayValue = dataItem->text().toDouble();
|
|
|
|
|
// 转换值
|
|
|
|
|
double newDisplayValue = tempDefaults.duration.convertValueByUnitType(oldDisplayValue, oldUnit, unit);
|
|
|
|
|
double newDisplayValue = convertForecastValue(tempDefaults.duration, oldDisplayValue, oldUnit, unit);
|
|
|
|
|
dataItem->setText(QString::number(newDisplayValue));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1373,7 +1485,7 @@ void nmWxForecast::onSharedDurationUnitChanged(const QString& unit)
|
|
|
|
|
double oldDisplayValue = dataItem->text().toDouble(&ok);
|
|
|
|
|
if(!ok || !qIsFinite(oldDisplayValue)) continue;
|
|
|
|
|
// 转换值
|
|
|
|
|
double newDisplayValue = tempDefaults.duration.convertValueByUnitType(oldDisplayValue, oldUnit, unit);
|
|
|
|
|
double newDisplayValue = convertForecastValue(tempDefaults.duration, oldDisplayValue, oldUnit, unit);
|
|
|
|
|
dataItem->setText(QString::number(newDisplayValue, 'g', 15));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1414,7 +1526,7 @@ void nmWxForecast::onRateUnitChanged(const QString& unit)
|
|
|
|
|
double oldDisplayValue = dataItem->text().toDouble(&ok);
|
|
|
|
|
if(!ok || !qIsFinite(oldDisplayValue)) continue;
|
|
|
|
|
// 使用 q0 (FlowRate) 进行单位转换
|
|
|
|
|
double newDisplayValue = tempDefaults.q0.convertValueByUnitType(oldDisplayValue, oldUnit, unit);
|
|
|
|
|
double newDisplayValue = convertForecastValue(tempDefaults.q0, oldDisplayValue, oldUnit, unit);
|
|
|
|
|
dataItem->setText(QString::number(newDisplayValue, 'g', 15));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|