fix(nmNum): 修复数值面板初始化和多段压裂水平井适配

- 补充数值面板初始化失败提示和空数据保护
- 统一使用 HorizontalMultiFracturedWell 井型
- 防止求解结果为空时发生越界
- 优化 Release 下左侧面板高度分配
- 同步中文翻译
feature/Merge-Framework-20260721
lh 1 week ago
parent d7fa5676db
commit 4deee62207

Binary file not shown.

@ -16,6 +16,18 @@
&apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Numerical Panel Initialization Failed</source>
<translation></translation>
</message>
<message>
<source>The numerical panels could not be opened.
Reason: %1</source>
<translation>
%1</translation>
</message>
</context>
<context>
<name>iWxBase</name>
@ -2841,6 +2853,50 @@
Supported types: Vertical, Vertical Fractured, and Horizontal Multi-Fractured Wells.</source>
<translation>%1 </translation>
</message>
<message>
<source>The current window is not a flow-segment analysis window.</source>
<translation></translation>
</message>
<message>
<source>The numerical panel containers have not been created.</source>
<translation></translation>
</message>
<message>
<source>No current well is available. Please select a well and try again.</source>
<translation></translation>
</message>
<message>
<source>The current well type &apos;%1&apos; is not supported. Supported types are Vertical, Vertical Fractured, and Horizontal Multi-Fractured Wells.</source>
<translation>%1</translation>
</message>
<message>
<source>The numerical data manager could not be created.</source>
<translation></translation>
</message>
<message>
<source>The numerical well data could not be initialized for well &apos;%1&apos; (type: %2). Please check the well type and its pressure, flow-rate, and flow-segment data.</source>
<translation>%1%2</translation>
</message>
<message>
<source>The analytical rectangular-boundary data is incomplete. Missing parameters: %1.</source>
<translation>%1</translation>
</message>
<message>
<source>The rectangular-boundary data could not be created.</source>
<translation></translation>
</message>
<message>
<source>The circular-boundary data could not be created.</source>
<translation></translation>
</message>
<message>
<source>The default numerical boundary could not be created.</source>
<translation></translation>
</message>
<message>
<source>The numerical panel widgets could not be attached to their containers.</source>
<translation></translation>
</message>
</context>
<context>
<name>nmSwitchOutlineConfirmationDlg</name>

@ -960,7 +960,7 @@ void nmDataAnalyzeManager::initCurWellData()
// 设置为当前查看的井
this->setCurWellData(pVFracturedWell);
} else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalFracturedWell")) {
} else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalMultiFracturedWell")) {
// 初始化多段压裂水平井默认参数
nmDataWellBase* pWell = this->createWell(NM_WELL_MODEL::Horizontal_Fractured_Well);
@ -1041,8 +1041,12 @@ void nmDataAnalyzeManager::calculationLogData(
vvecHistoryData[1].append(qpoint.y()); // y
}
// 准备流量段数据
// Prepare flow-rate segment data.
QVector<QPointF> vecTimeQ = pWellData->getFlowPoints();
if(vecPressure.isEmpty() || vecTimeQ.size() < 2) {
return;
}
int nTimeNumQ = vecTimeQ.size() - 1;
std::vector<double> timeQ(nTimeNumQ);
std::vector<double> q(nTimeNumQ);
@ -1068,10 +1072,15 @@ void nmDataAnalyzeManager::calculationLogData(
return;
}
preLogFun(wellPressureData, iSectionFlowIndex, timeQ.data(), q.data(), nTimeNumQ, logPre);
bool bCalculated = preLogFun(wellPressureData, iSectionFlowIndex,
timeQ.data(), q.data(), nTimeNumQ, logPre);
if(!bCalculated || logPre.empty()) {
FreeLibrary(hMod_solver);
return;
}
// 不添加最后一个元素
for(uint i = 0; i < logPre.size() - 1; i++) {
// The solver's final point is not part of the plotted result.
for(std::vector<Point>::size_type i = 0; i + 1 < logPre.size(); ++i) {
//logFile << logPre[i].x << "\t" << logPre[i].y << "\t" << logPre[i].z << "\t" << std::endl;
vvecLogPreData[0].append(logPre[i].x); // x
vvecLogPreData[1].append(logPre[i].y); // y
@ -1213,7 +1222,7 @@ void nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
pVFracturedWell->setFracs();
// 设置流量段索引
pVFracturedWell->setIndexF(nIndexF);
} else if(ZxBaseUtil::isSameStr(sWellClass, "HorizontalFracturedWell")) {
} else if(ZxBaseUtil::isSameStr(sWellClass, "HorizontalMultiFracturedWell")) {
// 初始化多段压裂水平井默认参数
nmDataWellBase* pWell = this->createWell(NM_WELL_MODEL::Horizontal_Fractured_Well);

@ -369,7 +369,7 @@ void nmGuiPlot::initDefultGeoObj()
// 设置为当前查看的井
nmDataAnalyzeManager::getCurrentInstance()->setCurWellData(m_VFracturedWell);
} else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalFracturedWell")) {
} else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalMultiFracturedWell")) {
// 初始化多段压裂水平井默认参数
nmDataWellBase* pWell = nmDataAnalyzeManager::getCurrentInstance()->createWell(NM_WELL_MODEL::Horizontal_Fractured_Well);

@ -324,7 +324,7 @@ void nmObjPointWell::afterCreated()
} else if(ZxBaseUtil::isSameStr(wellClass, "VerticalFracturedWell")) {
// 切换当前井类型
m_enumWellType = NM_WELL_MODEL::Vertical_Fractured_Well;
} else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalFracturedWell")) {
} else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalMultiFracturedWell")) {
// 切换当前井类型
m_enumWellType = NM_WELL_MODEL::Horizontal_Fractured_Well;
} else {
@ -485,7 +485,7 @@ void nmObjPointWell::editWell()
} else if(m_enumWellType == NM_WELL_MODEL::Vertical_Fractured_Well) {
sWellClass = "VerticalFracturedWell";
} else if(m_enumWellType == NM_WELL_MODEL::Horizontal_Fractured_Well) {
sWellClass = "HorizontalFracturedWell";
sWellClass = "HorizontalMultiFracturedWell";
}
m_pWellData->setWellClassCn(sWellClass);
}
@ -627,7 +627,7 @@ void nmObjPointWell::paintBack(QPainter* painter, const ZxPaintParam& param)
painter->restore();
} else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalFracturedWell") && m_pNmWellData != nullptr) {
} else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalMultiFracturedWell") && m_pNmWellData != nullptr) {
Q_ASSERT(NULL != m_pAxisX);
Q_ASSERT(NULL != m_pAxisY);
@ -763,7 +763,7 @@ void nmObjPointWell::setNmWellData(nmDataWellBase* wellData)
m_enumWellType = NM_WELL_MODEL::Vertical_Well;
} else if(ZxBaseUtil::isSameStr(wellClass, "VerticalFracturedWell")) {
m_enumWellType = NM_WELL_MODEL::Vertical_Fractured_Well;
} else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalFracturedWell")) {
} else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalMultiFracturedWell")) {
m_enumWellType = NM_WELL_MODEL::Horizontal_Fractured_Well;
}
}

@ -1,4 +1,4 @@
#include "zxLogInstance.h"
#include "zxLogInstance.h"
#include "iRibbonXmlCmd.h"
#include <QEvent>
#include <QMdiArea>
@ -71,6 +71,15 @@ bool hasPvtCurve(iSubWndFitting* pSubWndF, PvtFluidType eType, const QStringList
return false;
}
bool showNmDockInitializationError(const QString& detail)
{
QMessageBox::warning(nullptr,
QObject::tr("Numerical Panel Initialization Failed"),
QObject::tr("The numerical panels could not be opened.\n\nReason: %1")
.arg(detail));
return false;
}
}
nmSubWndUtils* nmSubWndUtils::getInstance()
@ -347,10 +356,11 @@ bool nmSubWndUtils::dealwithRibbonTab(iRibbonXmlTab* pTab, \
bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
{
iSubWndFitting* pSubWndF = dynamic_cast<iSubWndFitting*>(pSubWnd);
Q_ASSERT(nullptr != pSubWndF);
if(pSubWndF == nullptr) {
return false;
return showNmDockInitializationError(
tr("The current window is not a flow-segment analysis window."));
}
Q_ASSERT(nullptr != pSubWndF);
// 如果当前分析没有对应相态的PVT相关参数提示并返回
//PvtFluidType eType = pSubWndF->getBasicPft();
@ -383,8 +393,12 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
iDockBaseWx* pWxDockNm1 = pSubWndF->getNmDockWx(0);
iDockBaseWx* pWxDockNm2 = pSubWndF->getNmDockWx(1);
Q_ASSERT (nullptr != pWxDockNm1);
Q_ASSERT (nullptr != pWxDockNm2);
if(pWxDockNm1 == nullptr || pWxDockNm2 == nullptr) {
return showNmDockInitializationError(
tr("The numerical panel containers have not been created."));
}
Q_ASSERT(nullptr != pWxDockNm1);
Q_ASSERT(nullptr != pWxDockNm2);
if (pWxDockNm1->widget() != nullptr && pWxDockNm2->widget() != nullptr)
{
return true; //已经设定的话,则不再处理
@ -393,7 +407,8 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
// 获取当前井并检查类型是否支持
ZxDataWell* pWellData = zxCurWell;
if(pWellData == nullptr) {
return false;
return showNmDockInitializationError(
tr("No current well is available. Please select a well and try again."));
}
QString wellClass = pWellData->getWellClassEn();
@ -403,21 +418,21 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
supportedTypes << "VerticalWell" << "VerticalFracturedWell" << "HorizontalMultiFracturedWell";
if (!supportedTypes.contains(wellClass)) {
QMessageBox::warning(nullptr, tr("Unsupported Well Type"),
tr("The current well type '%1' is not supported for numerical modeling.\n"
"Supported types: Vertical, Vertical Fractured, and Horizontal Multi-Fractured Wells.")
.arg(pWellData->getWellClassCn()));
return false;
return showNmDockInitializationError(
tr("The current well type '%1' is not supported. Supported types are Vertical, "
"Vertical Fractured, and Horizontal Multi-Fractured Wells.")
.arg(pWellData->getWellClassCn()));
}
// 进入到这里,说明是新打开的流动段分析,所以需要动态创建数据管理中心
// 根据分析窗口创建唯一的数据管理对象
nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::getInstanceByFitting(pSubWndF);
Q_ASSERT(nullptr != pDataManager);
if(pDataManager == nullptr) {
return false;
return showNmDockInitializationError(
tr("The numerical data manager could not be created."));
}
Q_ASSERT(nullptr != pDataManager);
// 每个成果窗口只需要绑定一次外层MDI激活信号。
// 后续切换成果窗口时,通过激活事件同步对应的数据中心和左侧面板。
@ -445,10 +460,14 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
pDataManager->initCurWellData();
// 1.4 初始化边界数据
nmDataWellBase* pCurWell = pDataManager->getCurWellData();
Q_ASSERT(nullptr != pCurWell);
if(pCurWell == nullptr) {
return false;
return showNmDockInitializationError(
tr("The numerical well data could not be initialized for well '%1' (type: %2). "
"Please check the well type and its pressure, flow-rate, and flow-segment data.")
.arg(pWellData->getName())
.arg(wellClass));
}
Q_ASSERT(nullptr != pCurWell);
double dX = pCurWell->getX().getValue().toDouble();
double dY = pCurWell->getY().getValue().toDouble();
@ -457,7 +476,6 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
QMap<QString, QVariant> mapAnaParas;
mapAnaParas.clear();
pSubWndF->getBrotherDockParas(mapAnaParas, false);
Q_ASSERT(mapAnaParas.count() > 0);
// 解析解边界类型
m_Bdy_Type oBdyType = BT_None;
@ -480,15 +498,24 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
vecBdyDiss.clear();
QStringList list;
list << "ne" << "se" << "we" << "ee";
QStringList missingKeys;
for(int i = 0; i < list.count(); i++) {
QString s = list[i];
if(mapAnaParas.contains(s)) {
vecBdyDiss << mapAnaParas[s].toDouble();
} else {
missingKeys << s;
}
}
if(!missingKeys.isEmpty()) {
return showNmDockInitializationError(
tr("The analytical rectangular-boundary data is incomplete. Missing parameters: %1.")
.arg(missingKeys.join(", ")));
}
double top_dist = vecBdyDiss[0];
double right_dist = vecBdyDiss[1];
double bottom_dist = vecBdyDiss[2];
@ -503,10 +530,11 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
vecBoundaryPoints << topLeft << topRight << bottomRight << bottomLeft;
// 创建矩形边界数据对象
nmDataOutline* pOutlineData = pDataManager->createOutline();
Q_ASSERT(pOutlineData);
if(pOutlineData == nullptr) {
return false;
return showNmDockInitializationError(
tr("The rectangular-boundary data could not be created."));
}
Q_ASSERT(pOutlineData);
// 设置默认边界名称
pOutlineData->setName("");
// 设置边界点
@ -527,10 +555,11 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
// 创建圆形边界数据对象
nmDataOutline* pOutlineData = pDataManager->createOutline();
Q_ASSERT(pOutlineData);
if(pOutlineData == nullptr) {
return false;
return showNmDockInitializationError(
tr("The circular-boundary data could not be created."));
}
Q_ASSERT(pOutlineData);
// 设置默认边界名称
pOutlineData->setName("");
// 设置半径
@ -560,10 +589,11 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
// 如果解析解这里没有设置边界,数值解设置默认边界
// 创建默认矩形边界数据对象
nmDataOutline* pDefaultOutlineData = pDataManager->createOutline();
Q_ASSERT(pDefaultOutlineData);
if(pDefaultOutlineData == nullptr) {
return false;
return showNmDockInitializationError(
tr("The default numerical boundary could not be created."));
}
Q_ASSERT(pDefaultOutlineData);
// 设置默认边界名称
pDefaultOutlineData->setName("");
// 设置边界点

Loading…
Cancel
Save