|
|
|
|
@ -301,7 +301,7 @@ void nmWxAutomaticFitting::updateRangeForParameter(int parameterIndex,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 首次进入自动范围模式时,按当前表格中的初值为所有参数建立建议范围。
|
|
|
|
|
// 按当前表格中的初值为所有参数建立建议范围,首次加载和拟合完成后共用。
|
|
|
|
|
void nmWxAutomaticFitting::initializeSuggestedParameterRanges()
|
|
|
|
|
{
|
|
|
|
|
if(!m_parameterTable) {
|
|
|
|
|
@ -484,25 +484,6 @@ nmWxAutomaticFitting::nmWxAutomaticFitting(QWidget *parent)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_UI(QString("AutoFitting Constructor: this=0x%1").arg((quintptr)this, 0, 16));
|
|
|
|
|
|
|
|
|
|
// 加载已有井数据
|
|
|
|
|
QVector<nmDataWellBase*> listWellData = nmDataAnalyzeManager::getCurrentInstance()->getWellDataList();
|
|
|
|
|
|
|
|
|
|
// 遍历并分类井数据
|
|
|
|
|
foreach (nmDataWellBase* well, listWellData) {
|
|
|
|
|
if (auto vfWell = dynamic_cast<nmDataVerticalFracturedWell*>(well)) {
|
|
|
|
|
m_verticalFracturedWells.append(*vfWell);
|
|
|
|
|
}
|
|
|
|
|
else if (auto hfWell = dynamic_cast<nmDataHorizontalFracturedWell*>(well)) {
|
|
|
|
|
m_horizontalFracturedWells.append(*hfWell);
|
|
|
|
|
}
|
|
|
|
|
else if (auto vWell = dynamic_cast<nmDataVerticalWell*>(well)) {
|
|
|
|
|
m_verticalWells.append(*vWell);
|
|
|
|
|
}
|
|
|
|
|
else if (auto hWell = dynamic_cast<nmDataHorizontalWell*>(well)) {
|
|
|
|
|
m_horizontalWells.append(*hWell);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取数据
|
|
|
|
|
nmDataAnalyzeManager* pManager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
|
reservoirData = pManager->getReservoirDataCopy();
|
|
|
|
|
@ -902,7 +883,7 @@ void nmWxAutomaticFitting::onParameterTableItemChanged(QTableWidgetItem* item)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 用户改动范围后,切井和拟合结果不再自动覆盖这组手工范围。
|
|
|
|
|
// 手工范围用于本轮拟合,切井时保留;拟合完成后再按最新参数自动生成范围。
|
|
|
|
|
if(item->column() == 2 || item->column() == 4) {
|
|
|
|
|
m_autoParameterRanges = false;
|
|
|
|
|
}
|
|
|
|
|
@ -1030,105 +1011,55 @@ void nmWxAutomaticFitting::onReject()
|
|
|
|
|
|
|
|
|
|
void nmWxAutomaticFitting::onWellSelected(int index)
|
|
|
|
|
{
|
|
|
|
|
// 获取选中的井名
|
|
|
|
|
QString selectedWellName = m_targetWellCombo->itemText(index);
|
|
|
|
|
|
|
|
|
|
// 在分类的井数据中查找匹配的井
|
|
|
|
|
bool found = false;
|
|
|
|
|
bool fracturedWell = false;
|
|
|
|
|
double skinValue = 0.0;
|
|
|
|
|
double wellboreStorageValue = 0.0;
|
|
|
|
|
double fractureConductivityValue = 0.0;
|
|
|
|
|
double fractureHalfLengthValue = 0.0;
|
|
|
|
|
|
|
|
|
|
// 查找垂直井
|
|
|
|
|
for(int i = 0; i < m_verticalWells.size(); ++i) {
|
|
|
|
|
if(m_verticalWells[i].getWellName() == selectedWellName) {
|
|
|
|
|
skinValue = m_verticalWells[i].getPerforation(0)->getSkin().getValue().toDouble();
|
|
|
|
|
wellboreStorageValue = m_verticalWells[i].getWellboreStorage().getValue().toDouble();
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// 每次都读取模型实际保留的井参数,避免拟合结束后切井又恢复到打开窗口时的旧副本。
|
|
|
|
|
nmDataAnalyzeManager* manager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
|
if(!manager) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 查找水平井
|
|
|
|
|
if (!found) {
|
|
|
|
|
for(int i = 0; i < m_horizontalWells.size(); ++i) {
|
|
|
|
|
if(m_horizontalWells[i].getWellName() == selectedWellName) {
|
|
|
|
|
skinValue = m_horizontalWells[i].getPerforation(0)->getSkin().getValue().toDouble();
|
|
|
|
|
wellboreStorageValue = m_horizontalWells[i].getWellboreStorage().getValue().toDouble();
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
nmDataWellBase* targetWell = manager->findWellByName(m_targetWellCombo->itemText(index));
|
|
|
|
|
if(!targetWell) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 查找垂直压裂井
|
|
|
|
|
if (!found) {
|
|
|
|
|
for(int i = 0; i < m_verticalFracturedWells.size(); ++i) {
|
|
|
|
|
if(m_verticalFracturedWells[i].getWellName() == selectedWellName) {
|
|
|
|
|
skinValue = m_verticalFracturedWells[i].getPerforation(0)->getSkin().getValue().toDouble();
|
|
|
|
|
wellboreStorageValue = m_verticalFracturedWells[i].getWellboreStorage().getValue().toDouble();
|
|
|
|
|
fractureConductivityValue = m_verticalFracturedWells[i].getDfc().getValue().toDouble();
|
|
|
|
|
fractureHalfLengthValue = m_verticalFracturedWells[i].getFractureHalfLength().getValue().toDouble();
|
|
|
|
|
fracturedWell = true;
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const bool wasUpdatingRanges = m_updatingParameterRanges;
|
|
|
|
|
m_updatingParameterRanges = true;
|
|
|
|
|
updateParameterVisibility(m_parameterTable, manager->getSolverModelType());
|
|
|
|
|
|
|
|
|
|
// 查找水平压裂井
|
|
|
|
|
if (!found) {
|
|
|
|
|
for(int i = 0; i < m_horizontalFracturedWells.size(); ++i) {
|
|
|
|
|
if(m_horizontalFracturedWells[i].getWellName() == selectedWellName) {
|
|
|
|
|
skinValue = m_horizontalFracturedWells[i].getPerforation(0)->getSkin().getValue().toDouble();
|
|
|
|
|
wellboreStorageValue = m_horizontalFracturedWells[i].getWellboreStorage().getValue().toDouble();
|
|
|
|
|
fractureConductivityValue = m_horizontalFracturedWells[i].getDfc().getValue().toDouble();
|
|
|
|
|
fractureHalfLengthValue = m_horizontalFracturedWells[i].getFractureHalfLength().getValue().toDouble();
|
|
|
|
|
fracturedWell = true;
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
nmDataPerforation* perforation = targetWell->getPerforation(0);
|
|
|
|
|
if(perforation) {
|
|
|
|
|
const double skin = perforation->getSkin().getValue().toDouble();
|
|
|
|
|
m_parameterTable->item(1, 3)->setText(QString::number(skin, 'g', 10));
|
|
|
|
|
if(m_autoParameterRanges) {
|
|
|
|
|
updateRangeForParameter(1, skin);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const double storage = targetWell->getWellboreStorage().getValue().toDouble();
|
|
|
|
|
m_parameterTable->item(2, 3)->setText(QString::number(storage, 'g', 10));
|
|
|
|
|
if(m_autoParameterRanges) {
|
|
|
|
|
updateRangeForParameter(2, storage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (found) {
|
|
|
|
|
// 先按目标井类型刷新可见行,再写入当前井的井级初值。
|
|
|
|
|
nmDataAnalyzeManager* manager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
|
if(manager) {
|
|
|
|
|
updateParameterVisibility(m_parameterTable, manager->getSolverModelType());
|
|
|
|
|
}
|
|
|
|
|
// 更新表格数据
|
|
|
|
|
// 确保表格项存在
|
|
|
|
|
if(!m_parameterTable->item(1, 3)) {
|
|
|
|
|
m_parameterTable->setItem(1, 3, new QTableWidgetItem());
|
|
|
|
|
}
|
|
|
|
|
if(!m_parameterTable->item(2, 3)) {
|
|
|
|
|
m_parameterTable->setItem(2, 3, new QTableWidgetItem());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置皮肤系数(Skin)
|
|
|
|
|
m_parameterTable->item(1, 3)->setText(QString::number(skinValue));
|
|
|
|
|
|
|
|
|
|
// 设置井筒储集系数(Wellbore storage)
|
|
|
|
|
m_parameterTable->item(2, 3)->setText(QString::number(wellboreStorageValue));
|
|
|
|
|
if(fracturedWell && m_parameterTable->item(5, 3)) {
|
|
|
|
|
m_parameterTable->item(5, 3)->setText(QString::number(fractureConductivityValue));
|
|
|
|
|
}
|
|
|
|
|
if(fracturedWell && m_parameterTable->item(6, 3)) {
|
|
|
|
|
m_parameterTable->item(6, 3)->setText(QString::number(fractureHalfLengthValue));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool fracturedWell = false;
|
|
|
|
|
double conductivity = 0.0;
|
|
|
|
|
double halfLength = 0.0;
|
|
|
|
|
if(nmDataVerticalFracturedWell* well = dynamic_cast<nmDataVerticalFracturedWell*>(targetWell)) {
|
|
|
|
|
conductivity = well->getDfc().getValue().toDouble();
|
|
|
|
|
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(6, 3)->setText(QString::number(halfLength, 'g', 10));
|
|
|
|
|
if(m_autoParameterRanges) {
|
|
|
|
|
updateRangeForParameter(1, skinValue);
|
|
|
|
|
updateRangeForParameter(2, wellboreStorageValue);
|
|
|
|
|
if(fracturedWell) {
|
|
|
|
|
updateRangeForParameter(5, fractureConductivityValue);
|
|
|
|
|
updateRangeForParameter(6, fractureHalfLengthValue);
|
|
|
|
|
}
|
|
|
|
|
updateRangeForParameter(5, conductivity);
|
|
|
|
|
updateRangeForParameter(6, halfLength);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_updatingParameterRanges = wasUpdatingRanges;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxAutomaticFitting::setAutomaticFittingValue()
|
|
|
|
|
@ -1361,10 +1292,9 @@ void nmWxAutomaticFitting::onFittingFinished(bool success, const QString& messag
|
|
|
|
|
if(manager && manager->getAttrRegistry()) {
|
|
|
|
|
manager->getAttrRegistry()->refreshAll();
|
|
|
|
|
}
|
|
|
|
|
// 失败状态不代表参数未写回;初值与范围始终以模型实际保留的数据为准。
|
|
|
|
|
refreshParametersFromModel();
|
|
|
|
|
if(success) {
|
|
|
|
|
// 只有成功拟合的结果才用于生成下一轮范围,失败结果不污染当前配置。
|
|
|
|
|
updateBestParametersToTable();
|
|
|
|
|
|
|
|
|
|
QString resultInfo;
|
|
|
|
|
|
|
|
|
|
if(m_autoFitterPSO || m_autoFitterLM) {
|
|
|
|
|
@ -1479,47 +1409,32 @@ void nmWxAutomaticFitting::cleanupFitting()
|
|
|
|
|
DEBUG_UI("=== CLEANUP FITTING END ===");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxAutomaticFitting::updateBestParametersToTable()
|
|
|
|
|
void nmWxAutomaticFitting::refreshParametersFromModel()
|
|
|
|
|
{
|
|
|
|
|
QVector<double> bestSolution;
|
|
|
|
|
|
|
|
|
|
// 获取最佳解决方案
|
|
|
|
|
if (m_autoFitterPSO) {
|
|
|
|
|
bestSolution = m_autoFitterPSO->getBestSolution();
|
|
|
|
|
} else if(m_autoFitterLM) {
|
|
|
|
|
bestSolution = m_autoFitterLM->getBestSolution();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bestSolution.isEmpty()) return;
|
|
|
|
|
|
|
|
|
|
// 获取启用的参数索引
|
|
|
|
|
QVector<int> enabledParams;
|
|
|
|
|
if(m_kCheckBox->isChecked()) enabledParams.append(0); // 渗透率
|
|
|
|
|
if(m_sCheckBox->isChecked()) enabledParams.append(1); // 表皮系数
|
|
|
|
|
if(m_cCheckBox->isChecked()) enabledParams.append(2); // 井筒储集系数
|
|
|
|
|
if(m_phiCheckBox->isChecked()) enabledParams.append(3); // 孔隙度
|
|
|
|
|
if(m_swiCheckBox->isChecked()) enabledParams.append(4); // 初始含水饱和度
|
|
|
|
|
if(m_dfcCheckBox->isChecked()) enabledParams.append(5); // 裂缝导流能力
|
|
|
|
|
if(m_fractureHalfLengthCheckBox->isChecked()) enabledParams.append(6); // 裂缝半长
|
|
|
|
|
|
|
|
|
|
// 更新参数值和范围
|
|
|
|
|
for (int i = 0; i < bestSolution.size() && i < enabledParams.size(); ++i) {
|
|
|
|
|
int paramIndex = enabledParams[i];
|
|
|
|
|
double bestValue = bestSolution[i];
|
|
|
|
|
if(!nmAutoFitUiIsFinite(bestValue)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新初始值
|
|
|
|
|
m_parameterTable->item(paramIndex, 3)->setText(QString::number(bestValue, 'g', 4));
|
|
|
|
|
// 自动范围模式下,以拟合结果为中心复用首次建范围的规则;手工范围由用户保留。
|
|
|
|
|
if(m_autoParameterRanges) {
|
|
|
|
|
updateRangeForParameter(paramIndex, bestValue);
|
|
|
|
|
}
|
|
|
|
|
nmDataAnalyzeManager* manager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
|
if(!manager) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保存更新
|
|
|
|
|
nmDataAnalyzeManager::getCurrentInstance()->updateAutomaticFittingData(automaticFittingData);
|
|
|
|
|
// 更新完成后,通知参数界面刷新
|
|
|
|
|
// 同步储层副本,避免下一次保存设置时把未拟合的储层属性覆盖成旧值。
|
|
|
|
|
reservoirData = manager->getReservoirDataCopy();
|
|
|
|
|
const bool wasUpdatingRanges = m_updatingParameterRanges;
|
|
|
|
|
m_updatingParameterRanges = true;
|
|
|
|
|
m_parameterTable->item(0, 3)->setText(QString::number(
|
|
|
|
|
reservoirData.getPermeability().getValue().toDouble(), 'g', 10));
|
|
|
|
|
m_parameterTable->item(3, 3)->setText(QString::number(
|
|
|
|
|
reservoirData.getPorosity().getValue().toDouble(), 'g', 10));
|
|
|
|
|
m_parameterTable->item(4, 3)->setText(QString::number(
|
|
|
|
|
reservoirData.getSwi().getValue().toDouble(), 'g', 10));
|
|
|
|
|
|
|
|
|
|
// 成功或失败都从当前目标井读取已落地的参数,不采用优化器尚未写回的最佳候选。
|
|
|
|
|
// 先刷新全部初值,再统一重建范围,避免即时校验读到新旧值混合的表格。
|
|
|
|
|
m_autoParameterRanges = false;
|
|
|
|
|
onWellSelected(m_targetWellCombo->currentIndex());
|
|
|
|
|
m_autoParameterRanges = true;
|
|
|
|
|
initializeSuggestedParameterRanges();
|
|
|
|
|
m_updatingParameterRanges = wasUpdatingRanges;
|
|
|
|
|
|
|
|
|
|
manager->updateAutomaticFittingData(automaticFittingData);
|
|
|
|
|
nmWxParameterProperty::notifyUpdateTable();
|
|
|
|
|
}
|
|
|
|
|
|