fix(numerical): 修复拟合后井参数无法修改

- LM 和 PSO 通过参数副本更新现有井属性
- 避免整井赋值重建射孔并导致参数绑定失效
- 保存拟合初值及拟合结束后刷新 PEBI 参数面板
feature/Adapt-Autofit-20260904
lvjunjie 1 week ago
parent 2d5b56fe21
commit 77bd6cd4e9

@ -11,8 +11,6 @@
#include "nmCalculation_global.h"
class nmDataWellBase;
// 双对数曲线误差分解。total 是 LM 候选接受和排序的唯一依据,
// 其余诊断量用于有限差分灵敏度分析和信赖域选参。
struct AutoFitObjectiveBreakdownLM {
@ -115,7 +113,6 @@ private:
void applyParametersToDataManager(const QVector<double>& parameters);
void updateReservoirParameters(const QVector<double>& parameters);
void updateWellParameters(const QVector<double>& parameters);
void updateWellToDataManager(nmDataWellBase* pWell);
QVector<QVector<double> > runSolver();
QVector<QVector<double> > runSolverDll();

@ -14,7 +14,6 @@
// 前向声明
class nmCalculationDllPebiSolverTask;
class nmDataWellBase;
class QTimer;
class QProcess;
@ -160,7 +159,6 @@ private:
void applyParametersToDataManager(const QVector<double>& parameters);
void updateReservoirParameters(const QVector<double>& parameters);
void updateWellParameters(const QVector<double>& parameters);
void updateWellToDataManager(nmDataWellBase* pWell);
// ===== 求解器相关 =====
QVector<QVector<double> > runSolver();

@ -3,7 +3,6 @@
#include "nmCalculationUtils.h"
#include "nmDataAnalyzeManager.h"
#include "nmDataWellBase.h"
#include "nmDataVerticalWell.h"
#include "nmDataVerticalFracturedWell.h"
#include "nmDataHorizontalFracturedWell.h"
#include "nmDataReservoir.h"
@ -2776,7 +2775,34 @@ void nmCalculationAutoFitLM::updateWellParameters(const QVector<double>& paramet
if(!pWell) return;
//nmDataWellBase* pWell = wells[0]; // 使用第一口井
// 先在参数副本中组装本次候选值,全部解析完成后再写回现有井对象。
// 这样不会触发整井赋值,也不会删除并重建井内已有的射孔对象。
nmDataPerforation* pPerforation = pWell->getPerforation(0);
nmDataAttribute skinAttr;
bool updateSkin = false;
if(pPerforation) {
skinAttr = pPerforation->getSkin();
}
nmDataAttribute wellboreAttr = pWell->getWellboreStorage();
bool updateWellboreStorage = false;
nmDataVerticalFracturedWell* pVerticalFracturedWell =
dynamic_cast<nmDataVerticalFracturedWell*>(pWell);
nmDataHorizontalFracturedWell* pHorizontalFracturedWell =
dynamic_cast<nmDataHorizontalFracturedWell*>(pWell);
nmDataAttribute dfcAttr;
nmDataAttribute fractureHalfLengthAttr;
if(pVerticalFracturedWell) {
dfcAttr = pVerticalFracturedWell->getDfc();
fractureHalfLengthAttr = pVerticalFracturedWell->getFractureHalfLength();
} else if(pHorizontalFracturedWell) {
dfcAttr = pHorizontalFracturedWell->getDfc();
fractureHalfLengthAttr = pHorizontalFracturedWell->getFractureHalfLength();
}
bool updateDfc = false;
bool updateFractureHalfLength = false;
int paramIndex = 0;
@ -2786,58 +2812,31 @@ void nmCalculationAutoFitLM::updateWellParameters(const QVector<double>& paramet
switch(i) {
case 1: { // 表皮系数
nmDataPerforation* perf = pWell->getPerforation(0);
if(perf) {
nmDataAttribute skinAttr = perf->getSkin();
if(pPerforation) {
skinAttr.setValue(value);
perf->setSkin(skinAttr);
updateSkin = true;
}
}
break;
case 2: { // 井筒储集系数
nmDataAttribute wellboreAttr = pWell->getWellboreStorage();
wellboreAttr.setValue(value);
pWell->setWellboreStorage(wellboreAttr);
updateWellboreStorage = true;
}
break;
case 8: { // 裂缝导流能力
if(pWell->getWellType() == NM_WELL_MODEL::Vertical_Fractured_Well) {
nmDataVerticalFracturedWell* fracturedWell =
dynamic_cast<nmDataVerticalFracturedWell*>(pWell);
if(fracturedWell) {
nmDataAttribute dfc = fracturedWell->getDfc();
dfc.setValue(value);
fracturedWell->setDfc(dfc);
}
} else if(pWell->getWellType() == NM_WELL_MODEL::Horizontal_Fractured_Well) {
nmDataHorizontalFracturedWell* fracturedWell =
dynamic_cast<nmDataHorizontalFracturedWell*>(pWell);
if(fracturedWell) {
nmDataAttribute dfc = fracturedWell->getDfc();
dfc.setValue(value);
fracturedWell->setDfc(dfc);
}
if(pVerticalFracturedWell || pHorizontalFracturedWell) {
dfcAttr.setValue(value);
updateDfc = true;
}
}
break;
case 9: { // 裂缝半长
// 直接修改井对象中的属性,复用已有信号重算裂缝端点。
if(pWell->getWellType() == NM_WELL_MODEL::Vertical_Fractured_Well) {
nmDataVerticalFracturedWell* fracturedWell =
dynamic_cast<nmDataVerticalFracturedWell*>(pWell);
if(fracturedWell) {
fracturedWell->getFractureHalfLength().setValue(value);
}
} else if(pWell->getWellType() == NM_WELL_MODEL::Horizontal_Fractured_Well) {
nmDataHorizontalFracturedWell* fracturedWell =
dynamic_cast<nmDataHorizontalFracturedWell*>(pWell);
if(fracturedWell) {
fracturedWell->getFractureHalfLength().setValue(value);
}
if(pVerticalFracturedWell || pHorizontalFracturedWell) {
fractureHalfLengthAttr.setValue(value);
updateFractureHalfLength = true;
}
}
break;
@ -2847,58 +2846,28 @@ void nmCalculationAutoFitLM::updateWellParameters(const QVector<double>& paramet
}
}
// 根据井类型更新到数据管理器
updateWellToDataManager(pWell);
if(updateSkin) {
pPerforation->getSkin().setValue(skinAttr.getValue());
}
void nmCalculationAutoFitLM::updateWellToDataManager(nmDataWellBase* pWell)
{
if(!pWell) return;
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
NM_WELL_MODEL wellType = pWell->getWellType();
// DataManager 内部按井型维护不同容器。修改基类指针后,需要根据实际井型
// 调用对应 update 接口,才能让后续求解器组装读到最新 skin / wellboreC。
switch(wellType) {
case NM_WELL_MODEL::Vertical_Well: {
nmDataVerticalWell* pVerticalWell = dynamic_cast<nmDataVerticalWell*>(pWell);
if(pVerticalWell) {
QVector<nmDataVerticalWell> wells;
wells.append(*pVerticalWell);
dataManager->updateVerticalWells(wells);
if(updateWellboreStorage) {
pWell->getWellboreStorage().setValue(wellboreAttr.getValue());
}
break;
if(pVerticalFracturedWell) {
if(updateDfc) {
pVerticalFracturedWell->getDfc().setValue(dfcAttr.getValue());
}
case NM_WELL_MODEL::Vertical_Fractured_Well: {
nmDataVerticalFracturedWell* pVFracturedWell = dynamic_cast<nmDataVerticalFracturedWell*>(pWell);
if(pVFracturedWell) {
QVector<nmDataVerticalFracturedWell> wells;
wells.append(*pVFracturedWell);
dataManager->updateVerticalFracturedWells(wells);
if(updateFractureHalfLength) {
pVerticalFracturedWell->getFractureHalfLength().setValue(
fractureHalfLengthAttr.getValue());
}
break;
} else if(pHorizontalFracturedWell) {
if(updateDfc) {
pHorizontalFracturedWell->getDfc().setValue(dfcAttr.getValue());
}
case NM_WELL_MODEL::Horizontal_Fractured_Well: {
nmDataHorizontalFracturedWell* pHFracturedWell = dynamic_cast<nmDataHorizontalFracturedWell*>(pWell);
if(pHFracturedWell) {
QVector<nmDataHorizontalFracturedWell> wells;
wells.append(*pHFracturedWell);
dataManager->updateHorizontalFracturedWells(wells);
if(updateFractureHalfLength) {
pHorizontalFracturedWell->getFractureHalfLength().setValue(
fractureHalfLengthAttr.getValue());
}
break;
}
default:
break;
}
}

@ -3,7 +3,6 @@
#include "nmCalculationUtils.h"
#include "nmDataAnalyzeManager.h"
#include "nmDataWellBase.h"
#include "nmDataVerticalWell.h"
#include "nmDataVerticalFracturedWell.h"
#include "nmDataHorizontalFracturedWell.h"
#include "nmDataReservoir.h"
@ -4209,7 +4208,17 @@ void nmCalculationAutoFitPSO::updateWellParameters(const QVector<double>& parame
if(!pWell) return;
//nmDataWellBase* pWell = wells[0]; // 使用第一口井
// 先修改独立的参数副本,解析完成后再写回原井对象中的现有属性。
// 不再整井赋值,避免拟合过程中删除并重建射孔对象。
nmDataPerforation* pPerforation = pWell->getPerforation(0);
nmDataAttribute skinAttr;
bool updateSkin = false;
if(pPerforation) {
skinAttr = pPerforation->getSkin();
}
nmDataAttribute wellboreAttr = pWell->getWellboreStorage();
bool updateWellboreStorage = false;
int paramIndex = 0;
@ -4219,20 +4228,16 @@ void nmCalculationAutoFitPSO::updateWellParameters(const QVector<double>& parame
switch(i) {
case 1: { // 表皮系数
nmDataPerforation* perf = pWell->getPerforation(0);
if(perf) {
nmDataAttribute skinAttr = perf->getSkin();
if(pPerforation) {
skinAttr.setValue(value);
perf->setSkin(skinAttr);
updateSkin = true;
}
}
break;
case 2: { // 井筒储集系数
nmDataAttribute wellboreAttr = pWell->getWellboreStorage();
wellboreAttr.setValue(value);
pWell->setWellboreStorage(wellboreAttr);
updateWellboreStorage = true;
}
break;
}
@ -4241,58 +4246,11 @@ void nmCalculationAutoFitPSO::updateWellParameters(const QVector<double>& parame
}
}
// 根据井类型更新到数据管理器
updateWellToDataManager(pWell);
}
void nmCalculationAutoFitPSO::updateWellToDataManager(nmDataWellBase* pWell)
{
if(!pWell) return;
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
NM_WELL_MODEL wellType = pWell->getWellType();
// DataManager 内部按井型维护不同容器。修改基类指针后,需要根据实际井型
// 调用对应 update 接口,才能让后续求解器组装读到最新 skin / wellboreC。
switch(wellType) {
case NM_WELL_MODEL::Vertical_Well: {
nmDataVerticalWell* pVerticalWell = dynamic_cast<nmDataVerticalWell*>(pWell);
if(pVerticalWell) {
QVector<nmDataVerticalWell> wells;
wells.append(*pVerticalWell);
dataManager->updateVerticalWells(wells);
}
break;
if(updateSkin) {
pPerforation->getSkin().setValue(skinAttr.getValue());
}
case NM_WELL_MODEL::Vertical_Fractured_Well: {
nmDataVerticalFracturedWell* pVFracturedWell = dynamic_cast<nmDataVerticalFracturedWell*>(pWell);
if(pVFracturedWell) {
QVector<nmDataVerticalFracturedWell> wells;
wells.append(*pVFracturedWell);
dataManager->updateVerticalFracturedWells(wells);
}
break;
}
case NM_WELL_MODEL::Horizontal_Fractured_Well: {
nmDataHorizontalFracturedWell* pHFracturedWell = dynamic_cast<nmDataHorizontalFracturedWell*>(pWell);
if(pHFracturedWell) {
QVector<nmDataHorizontalFracturedWell> wells;
wells.append(*pHFracturedWell);
dataManager->updateHorizontalFracturedWells(wells);
}
break;
}
default:
break;
if(updateWellboreStorage) {
pWell->getWellboreStorage().setValue(wellboreAttr.getValue());
}
}

@ -3,6 +3,7 @@
#include "nmCalculationAutoFitLM.h"
#include "nmWxAutomaticfittingStart.h"
#include "nmWxParameterProperty.h"
#include "nmAttrRegistry.h"
#include "nmDataAnalyzeManager.h"
#include "iSubWndFitting.h"
#include "iSysParaHelper.h"
@ -1384,20 +1385,19 @@ void nmWxAutomaticFitting::setAutomaticFittingValue()
nmDataWellBase* pTargetWell = manager->findWellByName(selectedWellName);
if(pTargetWell) {
// 更新Skin
// 先修改井参数副本,最后写回原对象中的现有属性,保持射孔对象地址不变。
nmDataPerforation* perf = pTargetWell->getPerforation(0);
if(perf) {
nmDataAttribute skinAttr = perf->getSkin();
skinAttr.setValue(newSkinValue);
perf->setSkin(skinAttr);
perf->getSkin().setValue(skinAttr.getValue());
}
// 更新井筒储集系数
nmDataAttribute wellboreAttr = pTargetWell->getWellboreStorage();
wellboreAttr.setValue(newWellboreStorageValue);
pTargetWell->setWellboreStorage(wellboreAttr);
pTargetWell->getWellboreStorage().setValue(wellboreAttr.getValue());
// 根据井类型单独更新这一口井
NM_WELL_MODEL wellType = pTargetWell->getWellType();
// Dfc 属于压裂井对象;只修改这一项,裂缝位置、长度和段数保持原值。
@ -1406,40 +1406,26 @@ void nmWxAutomaticFitting::setAutomaticFittingValue()
if(fracturedWell) {
nmDataAttribute dfc = fracturedWell->getDfc();
dfc.setValue(newFractureConductivityValue);
fracturedWell->setDfc(dfc);
fracturedWell->getFractureHalfLength().setValue(newFractureHalfLengthValue);
fracturedWell->getDfc().setValue(dfc.getValue());
nmDataAttribute halfLength = fracturedWell->getFractureHalfLength();
halfLength.setValue(newFractureHalfLengthValue);
fracturedWell->getFractureHalfLength().setValue(halfLength.getValue());
}
} else if(wellType == NM_WELL_MODEL::Horizontal_Fractured_Well) {
nmDataHorizontalFracturedWell* fracturedWell = dynamic_cast<nmDataHorizontalFracturedWell*>(pTargetWell);
if(fracturedWell) {
nmDataAttribute dfc = fracturedWell->getDfc();
dfc.setValue(newFractureConductivityValue);
fracturedWell->setDfc(dfc);
fracturedWell->getFractureHalfLength().setValue(newFractureHalfLengthValue);
fracturedWell->getDfc().setValue(dfc.getValue());
nmDataAttribute halfLength = fracturedWell->getFractureHalfLength();
halfLength.setValue(newFractureHalfLengthValue);
fracturedWell->getFractureHalfLength().setValue(halfLength.getValue());
}
}
if(wellType == NM_WELL_MODEL::Vertical_Well) {
nmDataVerticalWell* pVerticalWell = dynamic_cast<nmDataVerticalWell*>(pTargetWell);
if(pVerticalWell != nullptr) {
QVector<nmDataVerticalWell> wells;
wells.append(*pVerticalWell);
manager->updateVerticalWells(wells);
}
} else if(wellType == NM_WELL_MODEL::Vertical_Fractured_Well) {
nmDataVerticalFracturedWell* pVerticalFracturedWell = dynamic_cast<nmDataVerticalFracturedWell*>(pTargetWell);
if(pVerticalFracturedWell != nullptr) {
QVector<nmDataVerticalFracturedWell> wells;
wells.append(*pVerticalFracturedWell);
manager->updateVerticalFracturedWells(wells);
}
} else if(wellType == NM_WELL_MODEL::Horizontal_Fractured_Well) {
nmDataHorizontalFracturedWell* pHorizontalFracturedWell = dynamic_cast<nmDataHorizontalFracturedWell*>(pTargetWell);
if(pHorizontalFracturedWell != nullptr) {
QVector<nmDataHorizontalFracturedWell> wells;
wells.append(*pHorizontalFracturedWell);
manager->updateHorizontalFracturedWells(wells);
}
// 全部井参数落地后统一刷新一次右侧参数面板。
if(manager->getAttrRegistry()) {
manager->getAttrRegistry()->refreshAll();
}
}
}
@ -1555,6 +1541,12 @@ void nmWxAutomaticFitting::onFittingFinished(bool success, const QString& messag
disconnect(m_autoFitterLM, SIGNAL(fittingFinished(bool, QString)),
this, SLOT(onFittingFinished(bool, QString)));
}
// 拟合候选值通过参数副本写回,结束时统一把最终值同步到右侧参数面板。
nmDataAnalyzeManager* manager = nmDataAnalyzeManager::getCurrentInstance();
if(manager && manager->getAttrRegistry()) {
manager->getAttrRegistry()->refreshAll();
}
if(success) {
// 只有成功拟合的结果才用于生成下一轮范围,失败结果不污染当前配置。
updateBestParametersToTable();

Loading…
Cancel
Save