|
|
|
@ -1,6 +1,7 @@
|
|
|
|
#include "nmWxAutomaticFitting.h"
|
|
|
|
#include "nmWxAutomaticFitting.h"
|
|
|
|
#include "nmCalculationAutoFitPSO.h"
|
|
|
|
#include "nmCalculationAutoFitPSO.h"
|
|
|
|
#include "nmCalculationAutoFitLM.h"
|
|
|
|
#include "nmCalculationAutoFitLM.h"
|
|
|
|
|
|
|
|
#include "nmCalculationDllPebiSolverTask.h"
|
|
|
|
#include "nmWxAutomaticfittingStart.h"
|
|
|
|
#include "nmWxAutomaticfittingStart.h"
|
|
|
|
#include "nmWxParameterProperty.h"
|
|
|
|
#include "nmWxParameterProperty.h"
|
|
|
|
#include "nmAttrRegistry.h"
|
|
|
|
#include "nmAttrRegistry.h"
|
|
|
|
@ -132,16 +133,8 @@ void nmWxAutomaticFitting::updateParameterVisibility(QTableWidget* table, NM_SOL
|
|
|
|
// Dfc 只属于垂直压裂井和多段压裂水平井。普通井隐藏并取消勾选,
|
|
|
|
// Dfc 只属于垂直压裂井和多段压裂水平井。普通井隐藏并取消勾选,
|
|
|
|
// 防止切换目标井后不可见的裂缝参数仍进入拟合参数向量。
|
|
|
|
// 防止切换目标井后不可见的裂缝参数仍进入拟合参数向量。
|
|
|
|
bool showFractureConductivity = false;
|
|
|
|
bool showFractureConductivity = false;
|
|
|
|
nmDataAnalyzeManager* manager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
const nmPebiResultWellSnapshot* well = solvedWell(m_targetWellCombo->currentIndex());
|
|
|
|
if(manager && m_targetWellCombo) {
|
|
|
|
if(well) showFractureConductivity = well->m_bHasDfc;
|
|
|
|
nmDataWellBase* targetWell = manager->findWellByName(m_targetWellCombo->currentText());
|
|
|
|
|
|
|
|
if(targetWell) {
|
|
|
|
|
|
|
|
NM_WELL_MODEL wellType = targetWell->getWellType();
|
|
|
|
|
|
|
|
showFractureConductivity =
|
|
|
|
|
|
|
|
wellType == NM_WELL_MODEL::Vertical_Fractured_Well ||
|
|
|
|
|
|
|
|
wellType == NM_WELL_MODEL::Horizontal_Fractured_Well;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
setParameterRowVisible(table, 5, showFractureConductivity); // Dfc
|
|
|
|
setParameterRowVisible(table, 5, showFractureConductivity); // Dfc
|
|
|
|
setParameterRowVisible(table, 6, showFractureConductivity); // 裂缝半长
|
|
|
|
setParameterRowVisible(table, 6, showFractureConductivity); // 裂缝半长
|
|
|
|
|
|
|
|
|
|
|
|
@ -430,6 +423,12 @@ nmWxAutomaticFitting::nmWxAutomaticFitting(QWidget *parent, nmSensitivityFitSett
|
|
|
|
// 获取数据
|
|
|
|
// 获取数据
|
|
|
|
nmDataAnalyzeManager* pManager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
nmDataAnalyzeManager* pManager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
reservoirData = pManager->getReservoirDataCopy();
|
|
|
|
reservoirData = pManager->getReservoirDataCopy();
|
|
|
|
|
|
|
|
// 初值来自最后成功模型;当前储层副本只保留原有属性及单位。
|
|
|
|
|
|
|
|
m_solvedSnapshot = pManager->getPebiResultSnapshot();
|
|
|
|
|
|
|
|
if(!m_solvedSnapshot.isNull()) {
|
|
|
|
|
|
|
|
reservoirData.getPermeability().setValue(m_solvedSnapshot->getReservoirParameters().m_dPermeability);
|
|
|
|
|
|
|
|
reservoirData.getPorosity().setValue(m_solvedSnapshot->getReservoirParameters().m_dPorosity);
|
|
|
|
|
|
|
|
}
|
|
|
|
automaticFittingData = pManager->getAutomaticFittingDataCopy();
|
|
|
|
automaticFittingData = pManager->getAutomaticFittingDataCopy();
|
|
|
|
// 自动范围始终开启;用户在表格中修改上下限后,itemChanged 会临时切换为手工范围。
|
|
|
|
// 自动范围始终开启;用户在表格中修改上下限后,itemChanged 会临时切换为手工范围。
|
|
|
|
m_autoParameterRanges = true;
|
|
|
|
m_autoParameterRanges = true;
|
|
|
|
@ -447,7 +446,9 @@ nmWxAutomaticFitting::nmWxAutomaticFitting(QWidget *parent, nmSensitivityFitSett
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 每次打开都按当前模型参数生成范围,不沿用上次的上下限。
|
|
|
|
// 每次打开都按当前模型参数生成范围,不沿用上次的上下限。
|
|
|
|
initializeSuggestedParameterRanges();
|
|
|
|
initializeSuggestedParameterRanges();
|
|
|
|
if(m_sensitivitySettings && m_sensitivitySettings->confirmed) loadSensitivitySettings();
|
|
|
|
// 新模型重新初始化范围,同一模型才恢复上次确认的拟合设置。
|
|
|
|
|
|
|
|
if(m_sensitivitySettings && m_sensitivitySettings->confirmed && !m_solvedSnapshot.isNull() &&
|
|
|
|
|
|
|
|
m_sensitivitySettings->snapshotId == m_solvedSnapshot->getSnapshotId()) loadSensitivitySettings();
|
|
|
|
m_updatingParameterRanges = false;
|
|
|
|
m_updatingParameterRanges = false;
|
|
|
|
|
|
|
|
|
|
|
|
DEBUG_UI("AutoFitting Constructor completed");
|
|
|
|
DEBUG_UI("AutoFitting Constructor completed");
|
|
|
|
@ -455,7 +456,7 @@ nmWxAutomaticFitting::nmWxAutomaticFitting(QWidget *parent, nmSensitivityFitSett
|
|
|
|
|
|
|
|
|
|
|
|
void nmWxAutomaticFitting::loadSensitivitySettings()
|
|
|
|
void nmWxAutomaticFitting::loadSensitivitySettings()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// 先恢复目标井,再覆盖默认范围与初值,保留上次确认的完整设置。
|
|
|
|
// 同一次模型的拟合设置仍恢复用户确认的范围与初值。
|
|
|
|
m_targetWellCombo->setCurrentIndex(m_targetWellCombo->findText(m_sensitivitySettings->targetWell));
|
|
|
|
m_targetWellCombo->setCurrentIndex(m_targetWellCombo->findText(m_sensitivitySettings->targetWell));
|
|
|
|
automaticFittingData = m_sensitivitySettings->parameters;
|
|
|
|
automaticFittingData = m_sensitivitySettings->parameters;
|
|
|
|
m_autoParameterRanges = false;
|
|
|
|
m_autoParameterRanges = false;
|
|
|
|
@ -727,28 +728,13 @@ void nmWxAutomaticFitting::setupControlPanel()
|
|
|
|
m_targetWellCombo = new QComboBox();
|
|
|
|
m_targetWellCombo = new QComboBox();
|
|
|
|
|
|
|
|
|
|
|
|
// 目标井先加入当前分析主井,再加入已勾选且具备流量、压力数据的包含井。
|
|
|
|
// 目标井先加入当前分析主井,再加入已勾选且具备流量、压力数据的包含井。
|
|
|
|
nmDataAnalyzeManager* pManager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
// 井列表也取自求解快照,未求解的新井不作为旧模型的拟合目标。
|
|
|
|
if(pManager != nullptr) {
|
|
|
|
for(int i = 0; !m_solvedSnapshot.isNull() && i < m_solvedSnapshot->getWellCount(); ++i) {
|
|
|
|
const QString sPrimaryWellCode = pManager->getPrimaryWellCode();
|
|
|
|
const nmPebiResultWellSnapshot* well = m_solvedSnapshot->getWellAt(i);
|
|
|
|
nmDataWellBase* pPrimaryWell = pManager->findWellByCode(sPrimaryWellCode);
|
|
|
|
if(well->m_sWellCode == m_solvedSnapshot->getSensitivityWellCode())
|
|
|
|
if(pPrimaryWell != nullptr) {
|
|
|
|
m_targetWellCombo->insertItem(0, well->m_sWellName, well->m_sWellInstanceId);
|
|
|
|
m_targetWellCombo->addItem(pPrimaryWell->getWellName());
|
|
|
|
else if(well->m_eWellMode == NM_CaseWell_RateControlled && !well->m_oCurves.m_vecHistoryPressure.isEmpty())
|
|
|
|
}
|
|
|
|
m_targetWellCombo->addItem(well->m_sWellName, well->m_sWellInstanceId);
|
|
|
|
|
|
|
|
|
|
|
|
if(pManager->getIncludeOtherWells()) {
|
|
|
|
|
|
|
|
const QVector<nmCalculationWellRef> vecIncludedWells =
|
|
|
|
|
|
|
|
pManager->getIncludedCalculationWells();
|
|
|
|
|
|
|
|
for(int nIndex = 0; nIndex < vecIncludedWells.size(); ++nIndex) {
|
|
|
|
|
|
|
|
const QString& sWellCode = vecIncludedWells[nIndex].m_sWellCode;
|
|
|
|
|
|
|
|
nmDataWellBase* pWellData = pManager->findWellByCode(sWellCode);
|
|
|
|
|
|
|
|
if(pWellData == nullptr || sWellCode == sPrimaryWellCode ||
|
|
|
|
|
|
|
|
pWellData->getFlowSegmentCount() <= 0 ||
|
|
|
|
|
|
|
|
pWellData->getPressurePoints().size() < 2) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
m_targetWellCombo->addItem(pWellData->getWellName());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
connect(m_targetWellCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onWellSelected(int)));
|
|
|
|
connect(m_targetWellCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onWellSelected(int)));
|
|
|
|
@ -883,6 +869,7 @@ void nmWxAutomaticFitting::onAccept()
|
|
|
|
// 仅提交给敏感性窗口;取消、关闭及普通拟合均不经过此分支。
|
|
|
|
// 仅提交给敏感性窗口;取消、关闭及普通拟合均不经过此分支。
|
|
|
|
m_sensitivitySettings->parameters = automaticFittingData;
|
|
|
|
m_sensitivitySettings->parameters = automaticFittingData;
|
|
|
|
m_sensitivitySettings->targetWell = m_targetWellCombo->currentText();
|
|
|
|
m_sensitivitySettings->targetWell = m_targetWellCombo->currentText();
|
|
|
|
|
|
|
|
m_sensitivitySettings->snapshotId = m_solvedSnapshot->getSnapshotId();
|
|
|
|
m_sensitivitySettings->initialValues.clear();
|
|
|
|
m_sensitivitySettings->initialValues.clear();
|
|
|
|
const int rows[] = {0, 1, 2, 3, 5, 6};
|
|
|
|
const int rows[] = {0, 1, 2, 3, 5, 6};
|
|
|
|
for(int i = 0; i < 6; ++i)
|
|
|
|
for(int i = 0; i < 6; ++i)
|
|
|
|
@ -991,49 +978,43 @@ void nmWxAutomaticFitting::onReject()
|
|
|
|
reject();
|
|
|
|
reject();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const nmPebiResultWellSnapshot* nmWxAutomaticFitting::solvedWell(int index) const
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 用快照中的稳定标识定位井,不依赖后来编辑的井名称或参数。
|
|
|
|
|
|
|
|
return m_solvedSnapshot.isNull() ? nullptr :
|
|
|
|
|
|
|
|
m_solvedSnapshot->findWell(m_targetWellCombo->itemData(index).toString());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWxAutomaticFitting::onWellSelected(int index)
|
|
|
|
void nmWxAutomaticFitting::onWellSelected(int index)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// 每次都读取模型实际保留的井参数,避免拟合结束后切井又恢复到打开窗口时的旧副本。
|
|
|
|
// 切井也读取同一次成功模型,默认范围继续使用原有生成及物理限制逻辑。
|
|
|
|
nmDataAnalyzeManager* manager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
const nmPebiResultWellSnapshot* targetWell = solvedWell(index);
|
|
|
|
if(!manager) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
nmDataWellBase* targetWell = manager->findWellByName(m_targetWellCombo->itemText(index));
|
|
|
|
|
|
|
|
if(!targetWell) {
|
|
|
|
if(!targetWell) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const bool wasUpdatingRanges = m_updatingParameterRanges;
|
|
|
|
const bool wasUpdatingRanges = m_updatingParameterRanges;
|
|
|
|
m_updatingParameterRanges = true;
|
|
|
|
m_updatingParameterRanges = true;
|
|
|
|
updateParameterVisibility(m_parameterTable, manager->getSolverModelType());
|
|
|
|
updateParameterVisibility(m_parameterTable,
|
|
|
|
|
|
|
|
static_cast<NM_SOLVER_MODEL_TYPE>(m_solvedSnapshot->getSolverSettings().m_nSolverModelType));
|
|
|
|
|
|
|
|
|
|
|
|
nmDataPerforation* perforation = targetWell->getPerforation(0);
|
|
|
|
if(targetWell->m_bHasSkin) {
|
|
|
|
if(perforation) {
|
|
|
|
const double skin = targetWell->m_dSkin;
|
|
|
|
const double skin = perforation->getSkin().getValue().toDouble();
|
|
|
|
|
|
|
|
m_parameterTable->item(1, 3)->setText(QString::number(skin, 'g', 10));
|
|
|
|
m_parameterTable->item(1, 3)->setText(QString::number(skin, 'g', 10));
|
|
|
|
if(m_autoParameterRanges) {
|
|
|
|
if(m_autoParameterRanges) {
|
|
|
|
updateRangeForParameter(1, skin);
|
|
|
|
updateRangeForParameter(1, skin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const double storage = targetWell->getWellboreStorage().getValue().toDouble();
|
|
|
|
const double storage = targetWell->m_dWellboreStorage;
|
|
|
|
m_parameterTable->item(2, 3)->setText(QString::number(storage, 'g', 10));
|
|
|
|
m_parameterTable->item(2, 3)->setText(QString::number(storage, 'g', 10));
|
|
|
|
if(m_autoParameterRanges) {
|
|
|
|
if(m_autoParameterRanges) {
|
|
|
|
updateRangeForParameter(2, storage);
|
|
|
|
updateRangeForParameter(2, storage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool fracturedWell = false;
|
|
|
|
const double conductivity = targetWell->m_dDfc;
|
|
|
|
double conductivity = 0.0;
|
|
|
|
|
|
|
|
double halfLength = 0.0;
|
|
|
|
double halfLength = 0.0;
|
|
|
|
if(nmDataVerticalFracturedWell* well = dynamic_cast<nmDataVerticalFracturedWell*>(targetWell)) {
|
|
|
|
if(targetWell->m_bHasDfc && nmCalculationDllPebiSolverTask::getSolvedFractureHalfLength(
|
|
|
|
conductivity = well->getDfc().getValue().toDouble();
|
|
|
|
m_solvedSnapshot->getSensitivityInput(), targetWell->m_sWellCode, halfLength)) {
|
|
|
|
halfLength = well->getFractureHalfLength().getValue().toDouble();
|
|
|
|
|
|
|
|
fracturedWell = true;
|
|
|
|
|
|
|
|
} else if(nmDataHorizontalFracturedWell* well = dynamic_cast<nmDataHorizontalFracturedWell*>(targetWell)) {
|
|
|
|
|
|
|
|
conductivity = well->getDfc().getValue().toDouble();
|
|
|
|
|
|
|
|
halfLength = well->getFractureHalfLength().getValue().toDouble();
|
|
|
|
|
|
|
|
fracturedWell = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if(fracturedWell) {
|
|
|
|
|
|
|
|
m_parameterTable->item(5, 3)->setText(QString::number(conductivity, 'g', 10));
|
|
|
|
m_parameterTable->item(5, 3)->setText(QString::number(conductivity, 'g', 10));
|
|
|
|
m_parameterTable->item(6, 3)->setText(QString::number(halfLength, 'g', 10));
|
|
|
|
m_parameterTable->item(6, 3)->setText(QString::number(halfLength, 'g', 10));
|
|
|
|
if(m_autoParameterRanges) {
|
|
|
|
if(m_autoParameterRanges) {
|
|
|
|
@ -1406,8 +1387,12 @@ void nmWxAutomaticFitting::refreshParametersFromModel()
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 同步储层副本,避免下一次保存设置时把未拟合的储层属性覆盖成旧值。
|
|
|
|
// 拟合结束后重新取得最后成功快照,失败时仍沿用之前成功模型的初值。
|
|
|
|
reservoirData = manager->getReservoirDataCopy();
|
|
|
|
reservoirData = manager->getReservoirDataCopy();
|
|
|
|
|
|
|
|
m_solvedSnapshot = manager->getPebiResultSnapshot();
|
|
|
|
|
|
|
|
if(m_solvedSnapshot.isNull()) return;
|
|
|
|
|
|
|
|
reservoirData.getPermeability().setValue(m_solvedSnapshot->getReservoirParameters().m_dPermeability);
|
|
|
|
|
|
|
|
reservoirData.getPorosity().setValue(m_solvedSnapshot->getReservoirParameters().m_dPorosity);
|
|
|
|
const bool wasUpdatingRanges = m_updatingParameterRanges;
|
|
|
|
const bool wasUpdatingRanges = m_updatingParameterRanges;
|
|
|
|
m_updatingParameterRanges = true;
|
|
|
|
m_updatingParameterRanges = true;
|
|
|
|
m_parameterTable->item(0, 3)->setText(QString::number(
|
|
|
|
m_parameterTable->item(0, 3)->setText(QString::number(
|
|
|
|
@ -1415,8 +1400,7 @@ void nmWxAutomaticFitting::refreshParametersFromModel()
|
|
|
|
m_parameterTable->item(3, 3)->setText(QString::number(
|
|
|
|
m_parameterTable->item(3, 3)->setText(QString::number(
|
|
|
|
reservoirData.getPorosity().getValue().toDouble(), 'g', 10));
|
|
|
|
reservoirData.getPorosity().getValue().toDouble(), 'g', 10));
|
|
|
|
|
|
|
|
|
|
|
|
// 成功或失败都从当前目标井读取已落地的参数,不采用优化器尚未写回的最佳候选。
|
|
|
|
// 先刷新快照初值,再统一重建范围,避免即时校验读到新旧值混合的表格。
|
|
|
|
// 先刷新全部初值,再统一重建范围,避免即时校验读到新旧值混合的表格。
|
|
|
|
|
|
|
|
m_autoParameterRanges = false;
|
|
|
|
m_autoParameterRanges = false;
|
|
|
|
onWellSelected(m_targetWellCombo->currentIndex());
|
|
|
|
onWellSelected(m_targetWellCombo->currentIndex());
|
|
|
|
m_autoParameterRanges = true;
|
|
|
|
m_autoParameterRanges = true;
|
|
|
|
|