|
|
|
|
@ -39,6 +39,7 @@
|
|
|
|
|
|
|
|
|
|
#include "nmDataPvtParaForPebi.h"
|
|
|
|
|
#include "ZxDataWell.h"
|
|
|
|
|
#include "ZxDataGaugeBase.h"
|
|
|
|
|
#include "ZxDataGaugeP.h"
|
|
|
|
|
#include "ZxDataGaugeF.h"
|
|
|
|
|
#include "zxSysUtils.h"
|
|
|
|
|
@ -124,7 +125,8 @@ static bool isWellParaOf(const WellParaDesc& desc, NM_WELL_MODEL eWellType)
|
|
|
|
|
// 当前 PEBI 网格只支持这三类数值井。Map 中其他类型的图元不能进入求解井集合。
|
|
|
|
|
static bool isSupportedNumericalWell(const nmDataWellBase* pWellData)
|
|
|
|
|
{
|
|
|
|
|
if(pWellData == nullptr || pWellData->getWellCode().isEmpty()) {
|
|
|
|
|
if(pWellData == nullptr || pWellData->getWellCode().isEmpty() ||
|
|
|
|
|
!nmIsValidWellCategory(pWellData->getWellCategory())) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -134,6 +136,85 @@ static bool isSupportedNumericalWell(const nmDataWellBase* pWellData)
|
|
|
|
|
eWellType == NM_WELL_MODEL::Horizontal_Fractured_Well;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将工程井井别转换为数值模块的稳定枚举。枚举值同时就是流量大字段索引。
|
|
|
|
|
static NM_WELL_CATEGORY frameworkWellCategory(const ZxDataWell* pWellData)
|
|
|
|
|
{
|
|
|
|
|
if(pWellData == nullptr) {
|
|
|
|
|
return NM_WellCategory_Unknown;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const NM_WELL_CATEGORY eWellCategory =
|
|
|
|
|
static_cast<NM_WELL_CATEGORY>(pWellData->getWellTypeIndex());
|
|
|
|
|
return nmIsValidWellCategory(eWellCategory)
|
|
|
|
|
? eWellCategory : NM_WellCategory_Unknown;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 从一条测量数据中复制二维点。流量调用方必须显式传入油、气、水井别索引。
|
|
|
|
|
static bool readGaugePoints(ZxDataGaugeBase* pGaugeData,
|
|
|
|
|
int nObjectIndex,
|
|
|
|
|
QVector<QPointF>& vecPoints)
|
|
|
|
|
{
|
|
|
|
|
vecPoints.clear();
|
|
|
|
|
if(pGaugeData == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VecDouble vecX;
|
|
|
|
|
VecDouble vecY;
|
|
|
|
|
if(!pGaugeData->getDataVecXY(vecX, vecY, nObjectIndex)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int nPointCount = qMin(
|
|
|
|
|
static_cast<int>(vecX.size()),
|
|
|
|
|
static_cast<int>(vecY.size()));
|
|
|
|
|
vecPoints.reserve(nPointCount);
|
|
|
|
|
for(int nIndex = 0; nIndex < nPointCount; ++nIndex) {
|
|
|
|
|
vecPoints.append(QPointF(vecX[nIndex], vecY[nIndex]));
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取工程井的第一条压力和流量数据;井别是流量相别的唯一事实来源。
|
|
|
|
|
static bool readFrameworkWellCurves(
|
|
|
|
|
ZxDataWell* pWellData,
|
|
|
|
|
QVector<QPointF>& vecPressurePoints,
|
|
|
|
|
QVector<QPointF>& vecFlowPoints,
|
|
|
|
|
NM_WELL_CATEGORY& eWellCategory)
|
|
|
|
|
{
|
|
|
|
|
vecPressurePoints.clear();
|
|
|
|
|
vecFlowPoints.clear();
|
|
|
|
|
eWellCategory = frameworkWellCategory(pWellData);
|
|
|
|
|
if(pWellData == nullptr || !nmIsValidWellCategory(eWellCategory)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ZxDataGaugeP* pGaugeP = nullptr;
|
|
|
|
|
const ZxDataObjectList listGaugeP =
|
|
|
|
|
pWellData->getChildren(iDataModelType::sTypeDataGaugeP);
|
|
|
|
|
for(int nIndex = 0; nIndex < listGaugeP.size(); ++nIndex) {
|
|
|
|
|
pGaugeP = dynamic_cast<ZxDataGaugeP*>(listGaugeP[nIndex]);
|
|
|
|
|
if(pGaugeP != nullptr) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ZxDataGaugeF* pGaugeF = nullptr;
|
|
|
|
|
const ZxDataObjectList listGaugeF =
|
|
|
|
|
pWellData->getChildren(iDataModelType::sTypeDataGaugeF);
|
|
|
|
|
for(int nIndex = 0; nIndex < listGaugeF.size(); ++nIndex) {
|
|
|
|
|
pGaugeF = dynamic_cast<ZxDataGaugeF*>(listGaugeF[nIndex]);
|
|
|
|
|
if(pGaugeF != nullptr) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 压力数据仍读取二维主对象;流量必须使用井别对应的 0/1/2 大字段索引。
|
|
|
|
|
readGaugePoints(pGaugeP, 0, vecPressurePoints);
|
|
|
|
|
readGaugePoints(pGaugeF, static_cast<int>(eWellCategory), vecFlowPoints);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isWellParaAttrName(const QString& name)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < WELL_PARA_DESC_COUNT; ++i) {
|
|
|
|
|
@ -1363,61 +1444,14 @@ void nmDataAnalyzeManager::initCurWellData()
|
|
|
|
|
// 判断是哪一种井类型,初始化对应的参数
|
|
|
|
|
QString wellClass = pWellData->getWellClassEn();
|
|
|
|
|
|
|
|
|
|
// 获取当前井的压力、流量数据
|
|
|
|
|
ZxDataObjectList m_listGaugeP = pWellData->getChildren(iDataModelType::sTypeDataGaugeP);
|
|
|
|
|
ZxDataObjectList m_listGaugeF = pWellData->getChildren(iDataModelType::sTypeDataGaugeF);
|
|
|
|
|
|
|
|
|
|
ZxDataGaugeP* pGaugeP = nullptr;
|
|
|
|
|
ZxDataGaugeF* pGaugeF = nullptr;
|
|
|
|
|
|
|
|
|
|
// 遍历压力数据列表
|
|
|
|
|
for(int i = 0; i < m_listGaugeP.size(); ++i) {
|
|
|
|
|
if(pGaugeP = dynamic_cast<ZxDataGaugeP * >(m_listGaugeP[i])) { // 拿到第一条压力数据
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 遍历流量数据列表
|
|
|
|
|
for(int i = 0; i < m_listGaugeF.size(); ++i) {
|
|
|
|
|
if(pGaugeF = dynamic_cast<ZxDataGaugeF * >(m_listGaugeF[i])) { // 拿到第一条流量数据
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取的压力、流量数据
|
|
|
|
|
QVector<QPointF> vecPtsP, vecPtsF;
|
|
|
|
|
// 临时存储x,y坐标
|
|
|
|
|
VecDouble vecX, vecY;
|
|
|
|
|
|
|
|
|
|
if(pGaugeP != nullptr) {
|
|
|
|
|
// 获取压力数据
|
|
|
|
|
if(pGaugeP->getDataVecXY(vecX, vecY)) {
|
|
|
|
|
int pointCount = vecX.size();
|
|
|
|
|
if(pointCount > vecY.size()) {
|
|
|
|
|
pointCount = vecY.size();
|
|
|
|
|
}
|
|
|
|
|
for(int i = 0; i < pointCount; ++i) {
|
|
|
|
|
QPointF pt(vecX[i], vecY[i]);
|
|
|
|
|
vecPtsP.append(pt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(pGaugeF != nullptr) {
|
|
|
|
|
vecX.clear();
|
|
|
|
|
vecY.clear();
|
|
|
|
|
|
|
|
|
|
// 获取流量数据
|
|
|
|
|
if(pGaugeF->getDataVecXY(vecX, vecY)) {
|
|
|
|
|
int pointCount = vecX.size();
|
|
|
|
|
if(pointCount > vecY.size()) {
|
|
|
|
|
pointCount = vecY.size();
|
|
|
|
|
}
|
|
|
|
|
for(int i = 0; i < pointCount; ++i) {
|
|
|
|
|
QPointF pt(vecX[i], vecY[i]);
|
|
|
|
|
vecPtsF.append(pt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
QVector<QPointF> vecPtsP;
|
|
|
|
|
QVector<QPointF> vecPtsF;
|
|
|
|
|
NM_WELL_CATEGORY eWellCategory = NM_WellCategory_Unknown;
|
|
|
|
|
if(!readFrameworkWellCurves(pWellData, vecPtsP, vecPtsF,
|
|
|
|
|
eWellCategory)) {
|
|
|
|
|
qWarning() << "Cannot import numerical well with invalid category:"
|
|
|
|
|
<< pWellData->getCode();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(ZxBaseUtil::isSameStr(wellClass, "VerticalWell")) {
|
|
|
|
|
@ -1430,6 +1464,7 @@ void nmDataAnalyzeManager::initCurWellData()
|
|
|
|
|
|
|
|
|
|
pVerticalWell->setWellName(pWellData->getName());
|
|
|
|
|
pVerticalWell->setWellCode(pWellData->getCode());
|
|
|
|
|
pVerticalWell->setWellCategory(eWellCategory);
|
|
|
|
|
nmDataAttribute tempAttr = pVerticalWell->getX();
|
|
|
|
|
tempAttr.setValue(pWellData->getLocationX());
|
|
|
|
|
pVerticalWell->setX(tempAttr);
|
|
|
|
|
@ -1468,6 +1503,7 @@ void nmDataAnalyzeManager::initCurWellData()
|
|
|
|
|
|
|
|
|
|
pVFracturedWell->setWellName(pWellData->getName());
|
|
|
|
|
pVFracturedWell->setWellCode(pWellData->getCode());
|
|
|
|
|
pVFracturedWell->setWellCategory(eWellCategory);
|
|
|
|
|
nmDataAttribute tempAttr = pVFracturedWell->getX();
|
|
|
|
|
tempAttr.setValue(pWellData->getLocationX());
|
|
|
|
|
pVFracturedWell->setX(tempAttr);
|
|
|
|
|
@ -1509,6 +1545,7 @@ void nmDataAnalyzeManager::initCurWellData()
|
|
|
|
|
|
|
|
|
|
pHFracturedWell->setWellName(pWellData->getName());
|
|
|
|
|
pHFracturedWell->setWellCode(pWellData->getCode());
|
|
|
|
|
pHFracturedWell->setWellCategory(eWellCategory);
|
|
|
|
|
nmDataAttribute tempAttr = pHFracturedWell->getX();
|
|
|
|
|
tempAttr.setValue(pWellData->getLocationX());
|
|
|
|
|
pHFracturedWell->setX(tempAttr);
|
|
|
|
|
@ -1549,7 +1586,7 @@ void nmDataAnalyzeManager::initCurWellData()
|
|
|
|
|
const QString sPrimaryWellCode = m_pCurDataWell->getWellCode();
|
|
|
|
|
m_oNumericalAnalysisCase.setPrimaryWellCode(sPrimaryWellCode);
|
|
|
|
|
m_oNumericalAnalysisCase.setPrimaryWellMode(
|
|
|
|
|
m_pCurDataWell->getFlowPoints().size() >= 2
|
|
|
|
|
m_pCurDataWell->getFlowSegmentCount() > 0
|
|
|
|
|
? NM_CaseWell_RateControlled
|
|
|
|
|
: NM_CaseWell_Observation);
|
|
|
|
|
}
|
|
|
|
|
@ -1593,23 +1630,20 @@ 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) {
|
|
|
|
|
// 流动段索引采用一基;这里只使用去除可选 (0,0) 占位点后的真实段。
|
|
|
|
|
const QVector<QPointF> vecTimeQ = pWellData->getFlowSegmentPoints();
|
|
|
|
|
if(vecPressure.isEmpty() || vecTimeQ.isEmpty() ||
|
|
|
|
|
!pWellData->hasValidFlowSectionIndex()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nTimeNumQ = vecTimeQ.size() - 1;
|
|
|
|
|
if (nTimeNumQ <= 0) {
|
|
|
|
|
// 没有流量段数据,无法计算双对数/半对数曲线
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const int nTimeNumQ = vecTimeQ.size();
|
|
|
|
|
std::vector<double> timeQ(nTimeNumQ);
|
|
|
|
|
std::vector<double> q(nTimeNumQ);
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < nTimeNumQ; ++i) {
|
|
|
|
|
timeQ[i] = vecTimeQ[i + 1].x();
|
|
|
|
|
q[i] = vecTimeQ[i + 1].y();
|
|
|
|
|
timeQ[i] = vecTimeQ[i].x();
|
|
|
|
|
q[i] = vecTimeQ[i].y();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 调用 DLL 计算双对数曲线
|
|
|
|
|
@ -1666,71 +1700,18 @@ nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
|
|
|
|
|
return pExistingWell;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 判断是哪一种井类型,初始化对应的参数
|
|
|
|
|
QString sWellClass = pWellData->getWellClassEn();
|
|
|
|
|
|
|
|
|
|
// 获取当前井的压力、流量数据
|
|
|
|
|
ZxDataObjectList m_listGaugeP = pWellData->getChildren(iDataModelType::sTypeDataGaugeP);
|
|
|
|
|
ZxDataObjectList m_listGaugeF = pWellData->getChildren(iDataModelType::sTypeDataGaugeF);
|
|
|
|
|
|
|
|
|
|
ZxDataGaugeP* pGaugeP = nullptr;
|
|
|
|
|
ZxDataGaugeF* pGaugeF = nullptr;
|
|
|
|
|
|
|
|
|
|
// 遍历压力数据列表
|
|
|
|
|
for(int i = 0; i < m_listGaugeP.size(); ++i) {
|
|
|
|
|
if(pGaugeP = dynamic_cast<ZxDataGaugeP * >(m_listGaugeP[i])) { // 拿到第一条压力数据
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 遍历流量数据列表
|
|
|
|
|
for(int i = 0; i < m_listGaugeF.size(); ++i) {
|
|
|
|
|
if(pGaugeF = dynamic_cast<ZxDataGaugeF * >(m_listGaugeF[i])) { // 拿到第一条流量数据
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取的压力、流量数据
|
|
|
|
|
QVector<QPointF> vecPtsP, vecPtsF;
|
|
|
|
|
// 临时存储x,y坐标
|
|
|
|
|
VecDouble vecX, vecY;
|
|
|
|
|
|
|
|
|
|
if(pGaugeP != nullptr) {
|
|
|
|
|
// 获取压力数据
|
|
|
|
|
if(pGaugeP->getDataVecXY(vecX, vecY)) {
|
|
|
|
|
int pointCount = vecX.size();
|
|
|
|
|
if(pointCount > vecY.size()) {
|
|
|
|
|
pointCount = vecY.size();
|
|
|
|
|
}
|
|
|
|
|
for(int i = 0; i < pointCount; ++i) {
|
|
|
|
|
QPointF pt(vecX[i], vecY[i]);
|
|
|
|
|
vecPtsP.append(pt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(pGaugeF != nullptr) {
|
|
|
|
|
vecX.clear();
|
|
|
|
|
vecY.clear();
|
|
|
|
|
|
|
|
|
|
// 获取流量数据
|
|
|
|
|
if(pGaugeF->getDataVecXY(vecX, vecY)) {
|
|
|
|
|
int pointCount = vecX.size();
|
|
|
|
|
if(pointCount > vecY.size()) {
|
|
|
|
|
pointCount = vecY.size();
|
|
|
|
|
}
|
|
|
|
|
for(int i = 0; i < pointCount; ++i) {
|
|
|
|
|
QPointF pt(vecX[i], vecY[i]);
|
|
|
|
|
vecPtsF.append(pt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 井别决定流量大字段;压力仍读取第一条压力数据的主对象。
|
|
|
|
|
const QString sWellClass = pWellData->getWellClassEn();
|
|
|
|
|
QVector<QPointF> vecPtsP;
|
|
|
|
|
QVector<QPointF> vecPtsF;
|
|
|
|
|
NM_WELL_CATEGORY eWellCategory = NM_WellCategory_Unknown;
|
|
|
|
|
if(!readFrameworkWellCurves(pWellData, vecPtsP, vecPtsF,
|
|
|
|
|
eWellCategory)) {
|
|
|
|
|
qWarning() << "Cannot append numerical well with invalid category:"
|
|
|
|
|
<< pWellData->getCode();
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nIndexF; //当前井的流动段索引
|
|
|
|
|
|
|
|
|
|
// 更新当前井的流动段的索引,默认为最后一段
|
|
|
|
|
nIndexF = vecPtsF.count() - 1;
|
|
|
|
|
|
|
|
|
|
nmDataWellBase* pAddedWell = nullptr;
|
|
|
|
|
if(ZxBaseUtil::isSameStr(sWellClass, "VerticalWell")) {
|
|
|
|
|
// 初始化直井默认参数
|
|
|
|
|
@ -1742,7 +1723,8 @@ nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
|
|
|
|
|
pAddedWell = pVerticalWell;
|
|
|
|
|
|
|
|
|
|
pVerticalWell->setWellName(pWellData->getName());
|
|
|
|
|
pVerticalWell->setWellCode(pWellData->getCode());
|
|
|
|
|
pVerticalWell->setWellCode(pWellData->getCode());
|
|
|
|
|
pVerticalWell->setWellCategory(eWellCategory);
|
|
|
|
|
nmDataAttribute tempAttr = pVerticalWell->getX();
|
|
|
|
|
tempAttr.setValue(pWellData->getLocationX());
|
|
|
|
|
pVerticalWell->setX(tempAttr);
|
|
|
|
|
@ -1757,8 +1739,8 @@ nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
|
|
|
|
|
pVerticalWell->setPressurePoints(vecPtsP);
|
|
|
|
|
pVerticalWell->setFlowPoints(vecPtsF);
|
|
|
|
|
|
|
|
|
|
// 设置流量段索引
|
|
|
|
|
pVerticalWell->setIndexF(nIndexF);
|
|
|
|
|
// 其他井默认选择最后一个真实流动段,索引保持一基。
|
|
|
|
|
pVerticalWell->setIndexF(pVerticalWell->getFlowSegmentCount());
|
|
|
|
|
} else if(ZxBaseUtil::isSameStr(sWellClass, "VerticalFracturedWell")) {
|
|
|
|
|
|
|
|
|
|
// 初始化垂直裂缝井默认参数
|
|
|
|
|
@ -1770,7 +1752,8 @@ nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
|
|
|
|
|
pAddedWell = pVFracturedWell;
|
|
|
|
|
|
|
|
|
|
pVFracturedWell->setWellName(pWellData->getName());
|
|
|
|
|
pVFracturedWell->setWellCode(pWellData->getCode());
|
|
|
|
|
pVFracturedWell->setWellCode(pWellData->getCode());
|
|
|
|
|
pVFracturedWell->setWellCategory(eWellCategory);
|
|
|
|
|
nmDataAttribute tempAttr = pVFracturedWell->getX();
|
|
|
|
|
tempAttr.setValue(pWellData->getLocationX());
|
|
|
|
|
pVFracturedWell->setX(tempAttr);
|
|
|
|
|
@ -1787,8 +1770,8 @@ nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
|
|
|
|
|
|
|
|
|
|
// 更新裂缝位置信息
|
|
|
|
|
pVFracturedWell->setFracs();
|
|
|
|
|
// 设置流量段索引
|
|
|
|
|
pVFracturedWell->setIndexF(nIndexF);
|
|
|
|
|
// 其他井默认选择最后一个真实流动段,索引保持一基。
|
|
|
|
|
pVFracturedWell->setIndexF(pVFracturedWell->getFlowSegmentCount());
|
|
|
|
|
} else if(ZxBaseUtil::isSameStr(sWellClass, "HorizontalMultiFracturedWell")) {
|
|
|
|
|
|
|
|
|
|
// 初始化多段压裂水平井默认参数
|
|
|
|
|
@ -1800,7 +1783,8 @@ nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
|
|
|
|
|
pAddedWell = pHFracturedWell;
|
|
|
|
|
|
|
|
|
|
pHFracturedWell->setWellName(pWellData->getName());
|
|
|
|
|
pHFracturedWell->setWellCode(pWellData->getCode());
|
|
|
|
|
pHFracturedWell->setWellCode(pWellData->getCode());
|
|
|
|
|
pHFracturedWell->setWellCategory(eWellCategory);
|
|
|
|
|
nmDataAttribute tempAttr = pHFracturedWell->getX();
|
|
|
|
|
tempAttr.setValue(pWellData->getLocationX());
|
|
|
|
|
pHFracturedWell->setX(tempAttr);
|
|
|
|
|
@ -1818,8 +1802,8 @@ nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
|
|
|
|
|
// 计算裂缝数据
|
|
|
|
|
pHFracturedWell->setFracs();
|
|
|
|
|
|
|
|
|
|
// 设置流量段索引
|
|
|
|
|
pHFracturedWell->setIndexF(nIndexF);
|
|
|
|
|
// 其他井默认选择最后一个真实流动段,索引保持一基。
|
|
|
|
|
pHFracturedWell->setIndexF(pHFracturedWell->getFlowSegmentCount());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 第二步:不支持的项目井型不进入 Map,也不发送伪造的新增井通知。
|
|
|
|
|
@ -3655,7 +3639,8 @@ void nmDataAnalyzeManager::setIncludedCalculationWells(
|
|
|
|
|
nmDataWellBase* pWellData = findWellByCode(oWellRef.m_sWellCode);
|
|
|
|
|
if(isSupportedNumericalWell(pWellData) &&
|
|
|
|
|
oWellRef.m_sWellCode != getPrimaryWellCode() &&
|
|
|
|
|
pWellData->getFlowPoints().size() >= 2) {
|
|
|
|
|
nmIsValidWellCategory(pWellData->getWellCategory()) &&
|
|
|
|
|
pWellData->getFlowSegmentCount() > 0) {
|
|
|
|
|
vecValidWells.append(nmCalculationWellRef(
|
|
|
|
|
oWellRef.m_sWellCode,
|
|
|
|
|
NM_CaseWell_RateControlled));
|
|
|
|
|
@ -3725,7 +3710,9 @@ nmDataAnalyzeManager::getEffectiveCalculationWells() const
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool bHasValidRate = pWellData->getFlowPoints().size() >= 2;
|
|
|
|
|
const bool bHasValidRate =
|
|
|
|
|
nmIsValidWellCategory(pWellData->getWellCategory()) &&
|
|
|
|
|
pWellData->getFlowSegmentCount() > 0;
|
|
|
|
|
if(!bHasValidRate) {
|
|
|
|
|
vecEffectiveWells.append(nmCalculationWellRef(
|
|
|
|
|
pWellData->getWellCode(),
|
|
|
|
|
@ -3998,6 +3985,7 @@ bool nmDataAnalyzeManager::commitPebiResultSnapshot(
|
|
|
|
|
findWellByCode(pWell->m_sWellCode);
|
|
|
|
|
if(pWell == NULL || pLiveWell == NULL ||
|
|
|
|
|
pLiveWell->getWellInstanceId() != pWell->m_sWellInstanceId ||
|
|
|
|
|
pLiveWell->getWellCategory() != pWell->m_eWellCategory ||
|
|
|
|
|
setWellInstanceIds.contains(pWell->m_sWellInstanceId))
|
|
|
|
|
{
|
|
|
|
|
sError = "PEBI result well identity is stale.";
|
|
|
|
|
@ -4470,7 +4458,8 @@ bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 新数据模型不兼容旧项目。明确校验版本,避免按井名或对象顺序猜测关联关系。
|
|
|
|
|
const int nSupportedProjectVersion = 3;
|
|
|
|
|
const int nSupportedProjectVersion =
|
|
|
|
|
nmNumericalResultPersistence::projectVersion();
|
|
|
|
|
if(!doc.HasMember("NumericalProjectVersion") ||
|
|
|
|
|
!doc["NumericalProjectVersion"].IsInt() ||
|
|
|
|
|
doc["NumericalProjectVersion"].GetInt() != nSupportedProjectVersion) {
|
|
|
|
|
@ -4483,7 +4472,7 @@ bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
|
|
|
|
|
quint64 nSavedResultInputRevision = 0;
|
|
|
|
|
if(!doc.HasMember("InputRevisions") ||
|
|
|
|
|
!doc["InputRevisions"].IsObject()) {
|
|
|
|
|
qWarning() << "Numerical v3 project has no input revisions:" << filePath;
|
|
|
|
|
qWarning() << "Numerical v4 project has no input revisions:" << filePath;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
const rapidjson::Value& oRevisionJson = doc["InputRevisions"];
|
|
|
|
|
@ -4493,7 +4482,7 @@ bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
|
|
|
|
|
!oRevisionJson["BuiltGridRevision"].IsUint64() ||
|
|
|
|
|
!oRevisionJson.HasMember("ResultInputRevision") ||
|
|
|
|
|
!oRevisionJson["ResultInputRevision"].IsUint64()) {
|
|
|
|
|
qWarning() << "Numerical v3 project contains invalid input revisions:"
|
|
|
|
|
qWarning() << "Numerical v4 project contains invalid input revisions:"
|
|
|
|
|
<< filePath;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@ -4506,7 +4495,7 @@ bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
|
|
|
|
|
if(nSavedGridInputRevision == 0 || nSavedResultInputRevision == 0 ||
|
|
|
|
|
(nSavedBuiltGridRevision != 0 &&
|
|
|
|
|
nSavedBuiltGridRevision != nSavedGridInputRevision)) {
|
|
|
|
|
qWarning() << "Numerical v3 project input revision values are invalid:"
|
|
|
|
|
qWarning() << "Numerical v4 project input revision values are invalid:"
|
|
|
|
|
<< filePath;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@ -4518,7 +4507,7 @@ bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
|
|
|
|
|
QVector<nmCalculationWellRef> vecSavedIncludedWells;
|
|
|
|
|
QVector<nmSolverWellRef> vecSavedSolverOrder;
|
|
|
|
|
|
|
|
|
|
// 第一步:v3 必须完整保存当前分析方案,缺字段时不按旧项目规则猜测。
|
|
|
|
|
// 第一步:v4 必须完整保存当前分析方案,缺字段时不按旧项目规则猜测。
|
|
|
|
|
if(!doc.HasMember("NumericalAnalysisCase") ||
|
|
|
|
|
!doc["NumericalAnalysisCase"].IsObject() ||
|
|
|
|
|
!doc.HasMember("Wells") ||
|
|
|
|
|
@ -4574,7 +4563,9 @@ bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
|
|
|
|
|
!oWellJson.HasMember("WellInstanceId") ||
|
|
|
|
|
!oWellJson["WellInstanceId"].IsString() ||
|
|
|
|
|
!oWellJson.HasMember("WellType") ||
|
|
|
|
|
!oWellJson["WellType"].IsInt()) {
|
|
|
|
|
!oWellJson["WellType"].IsInt() ||
|
|
|
|
|
!oWellJson.HasMember("WellCategory") ||
|
|
|
|
|
!oWellJson["WellCategory"].IsInt()) {
|
|
|
|
|
qWarning() << "Numerical project contains an invalid well entry:" << filePath;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@ -4588,11 +4579,15 @@ bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
|
|
|
|
|
oWellInstanceUuid.toString().remove('{').remove('}');
|
|
|
|
|
const NM_WELL_MODEL eWellType = static_cast<NM_WELL_MODEL>(
|
|
|
|
|
oWellJson["WellType"].GetInt());
|
|
|
|
|
const NM_WELL_CATEGORY eWellCategory =
|
|
|
|
|
static_cast<NM_WELL_CATEGORY>(
|
|
|
|
|
oWellJson["WellCategory"].GetInt());
|
|
|
|
|
const bool bSupportedWellType =
|
|
|
|
|
eWellType == NM_WELL_MODEL::Vertical_Well ||
|
|
|
|
|
eWellType == NM_WELL_MODEL::Vertical_Fractured_Well ||
|
|
|
|
|
eWellType == NM_WELL_MODEL::Horizontal_Fractured_Well;
|
|
|
|
|
if(sWellCode.isEmpty() || !bSupportedWellType ||
|
|
|
|
|
!nmIsValidWellCategory(eWellCategory) ||
|
|
|
|
|
mapSavedWellTypes.contains(sWellCode) ||
|
|
|
|
|
oWellInstanceUuid.isNull() ||
|
|
|
|
|
sNormalizedWellInstanceId != sWellInstanceId ||
|
|
|
|
|
@ -4713,7 +4708,7 @@ bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 前置校验已完成,从这里开始替换当前输入。旧快照要到全部 v3 载荷
|
|
|
|
|
// 前置校验已完成,从这里开始替换当前输入。旧快照要到全部当前版本载荷
|
|
|
|
|
// 成功后才替换,加载失败或内存不足时仍保留上一套已发布快照。
|
|
|
|
|
// 清空现有数据,确保从头加载新数据
|
|
|
|
|
foreach(nmDataFracture* pFractureData, m_vFractureData) {
|
|
|
|
|
@ -5134,7 +5129,7 @@ bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
|
|
|
|
|
nSavedGridInputRevision,
|
|
|
|
|
nSavedBuiltGridRevision,
|
|
|
|
|
nSavedResultInputRevision)) {
|
|
|
|
|
qWarning() << "Failed to restore numerical v3 input revisions:"
|
|
|
|
|
qWarning() << "Failed to restore numerical v4 input revisions:"
|
|
|
|
|
<< filePath;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@ -5148,7 +5143,7 @@ bool nmDataAnalyzeManager::WriteProjectData(
|
|
|
|
|
const nmNumericalWindowPayloadReferences* pPayloadReferences)
|
|
|
|
|
{
|
|
|
|
|
if(pPayloadReferences == NULL) {
|
|
|
|
|
qWarning() << "Numerical v3 project requires explicit payload references.";
|
|
|
|
|
qWarning() << "Numerical v4 project requires explicit payload references.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// 第一步:保存前校验 Map 井目录,持久化身份只允许非空且唯一的 WellCode。
|
|
|
|
|
@ -5163,6 +5158,7 @@ bool nmDataAnalyzeManager::WriteProjectData(
|
|
|
|
|
const QString sNormalizedWellInstanceId =
|
|
|
|
|
oWellInstanceUuid.toString().remove('{').remove('}');
|
|
|
|
|
if(pWellData == nullptr || pWellData->getWellCode().isEmpty() ||
|
|
|
|
|
!nmIsValidWellCategory(pWellData->getWellCategory()) ||
|
|
|
|
|
setWellCodes.contains(pWellData->getWellCode()) ||
|
|
|
|
|
oWellInstanceUuid.isNull() ||
|
|
|
|
|
sNormalizedWellInstanceId != sWellInstanceId ||
|
|
|
|
|
@ -5238,7 +5234,8 @@ bool nmDataAnalyzeManager::WriteProjectData(
|
|
|
|
|
doc.SetObject(); // 根节点是对象
|
|
|
|
|
rapidjson::Document::AllocatorType& allocator = doc.GetAllocator(); // 获取内存分配器
|
|
|
|
|
|
|
|
|
|
doc.AddMember("NumericalProjectVersion", 3, allocator);
|
|
|
|
|
doc.AddMember("NumericalProjectVersion",
|
|
|
|
|
nmNumericalResultPersistence::projectVersion(), allocator);
|
|
|
|
|
rapidjson::Value oRevisionJson(rapidjson::kObjectType);
|
|
|
|
|
oRevisionJson.AddMember("GridInputRevision",
|
|
|
|
|
m_oNumericalAnalysisCase.getGridInputRevision(), allocator);
|
|
|
|
|
@ -5879,18 +5876,40 @@ bool nmDataAnalyzeManager::loadNmResultV3InPlace(
|
|
|
|
|
pWell->setHistorySemiLog(oHistory.m_vecSemiLog);
|
|
|
|
|
}
|
|
|
|
|
if(!mapLoadedHistories.isEmpty()) {
|
|
|
|
|
qWarning() << "Numerical v3 project contains unreferenced well histories.";
|
|
|
|
|
qWarning() << "Numerical v4 project contains unreferenced well histories.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loadWellPreAndFlow();
|
|
|
|
|
if(!loadWellPreAndFlow()) {
|
|
|
|
|
qWarning() << "Failed to reload numerical well pressure/rate data.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// 结果快照保存的是求解时井别;加载时必须与当前工程井保持一致。
|
|
|
|
|
if(!pLoadedCandidate.isNull()) {
|
|
|
|
|
for(int nIndex = 0;
|
|
|
|
|
nIndex < pLoadedCandidate->getWellCount(); ++nIndex) {
|
|
|
|
|
const nmPebiResultWellSnapshot* pSavedWell =
|
|
|
|
|
pLoadedCandidate->getWellAt(nIndex);
|
|
|
|
|
nmDataWellBase* pLiveWell = pSavedWell == nullptr
|
|
|
|
|
? nullptr : findWellByCode(pSavedWell->m_sWellCode);
|
|
|
|
|
if(pSavedWell == nullptr || pLiveWell == nullptr ||
|
|
|
|
|
pLiveWell->getWellInstanceId() !=
|
|
|
|
|
pSavedWell->m_sWellInstanceId ||
|
|
|
|
|
pLiveWell->getWellCategory() !=
|
|
|
|
|
pSavedWell->m_eWellCategory) {
|
|
|
|
|
qWarning() << "Loaded PEBI result well category is stale.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const QVector<nmCalculationWellRef> vecIncludedWells =
|
|
|
|
|
getIncludedCalculationWells();
|
|
|
|
|
for(int nIndex = 0; nIndex < vecIncludedWells.size(); ++nIndex) {
|
|
|
|
|
nmDataWellBase* pWell = findWellByCode(
|
|
|
|
|
vecIncludedWells[nIndex].m_sWellCode);
|
|
|
|
|
if(!isSupportedNumericalWell(pWell) ||
|
|
|
|
|
pWell->getFlowPoints().size() < 2) {
|
|
|
|
|
!nmIsValidWellCategory(pWell->getWellCategory()) ||
|
|
|
|
|
pWell->getFlowSegmentCount() <= 0) {
|
|
|
|
|
qWarning() << "Failed to restore included numerical well:"
|
|
|
|
|
<< vecIncludedWells[nIndex].m_sWellCode;
|
|
|
|
|
return false;
|
|
|
|
|
@ -6026,98 +6045,51 @@ bool nmDataAnalyzeManager::ensureDirectoryExists(const QString & dirPath)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmDataAnalyzeManager::loadWellPreAndFlow()
|
|
|
|
|
bool nmDataAnalyzeManager::loadWellPreAndFlow()
|
|
|
|
|
{
|
|
|
|
|
// 获取当前工区里所有的ZxDataWell井
|
|
|
|
|
// 当前项目文件只保存井别和井身份,压力/流量仍从工程井节点重新读取。
|
|
|
|
|
if(zxCurProject == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ZxDataObjectList wellList = zxCurProject->getChildren(iDataModelType::sTypeWell);
|
|
|
|
|
|
|
|
|
|
foreach(nmDataWellBase* pWell, m_vWellData) {
|
|
|
|
|
if(pWell == nullptr) {
|
|
|
|
|
const ZxDataObjectList listWells =
|
|
|
|
|
zxCurProject->getChildren(iDataModelType::sTypeWell);
|
|
|
|
|
QHash<QString, ZxDataWell*> mapFrameworkWells;
|
|
|
|
|
for(int nIndex = 0; nIndex < listWells.size(); ++nIndex) {
|
|
|
|
|
ZxDataWell* pFrameworkWell =
|
|
|
|
|
dynamic_cast<ZxDataWell*>(listWells[nIndex]);
|
|
|
|
|
if(pFrameworkWell == nullptr ||
|
|
|
|
|
pFrameworkWell->getCode().isEmpty() ||
|
|
|
|
|
mapFrameworkWells.contains(pFrameworkWell->getCode())) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
mapFrameworkWells.insert(pFrameworkWell->getCode(), pFrameworkWell);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString sWellCode = pWell->getWellCode();
|
|
|
|
|
|
|
|
|
|
ZxDataWell* pWellData = nullptr;
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < wellList.size(); i++) {
|
|
|
|
|
ZxDataWell* pCandidateWell = dynamic_cast<ZxDataWell*>(wellList[i]);
|
|
|
|
|
|
|
|
|
|
if(pCandidateWell != nullptr &&
|
|
|
|
|
pCandidateWell->getCode() == sWellCode) {
|
|
|
|
|
pWellData = pCandidateWell;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
foreach(nmDataWellBase* pWell, m_vWellData) {
|
|
|
|
|
if(pWell == nullptr || pWell->getWellCode().isEmpty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 拿到了井的数据
|
|
|
|
|
if(pWellData) {
|
|
|
|
|
// 获取当前井的压力、流量数据
|
|
|
|
|
ZxDataObjectList m_listGaugeP = pWellData->getChildren(iDataModelType::sTypeDataGaugeP);
|
|
|
|
|
ZxDataObjectList m_listGaugeF = pWellData->getChildren(iDataModelType::sTypeDataGaugeF);
|
|
|
|
|
|
|
|
|
|
ZxDataGaugeP* pGaugeP = nullptr;
|
|
|
|
|
ZxDataGaugeF* pGaugeF = nullptr;
|
|
|
|
|
|
|
|
|
|
// 遍历压力数据列表
|
|
|
|
|
for(int i = 0; i < m_listGaugeP.size(); ++i) {
|
|
|
|
|
if(pGaugeP = dynamic_cast<ZxDataGaugeP * >(m_listGaugeP[i])) { // 拿到第一条压力数据
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 遍历流量数据列表
|
|
|
|
|
for(int i = 0; i < m_listGaugeF.size(); ++i) {
|
|
|
|
|
if(pGaugeF = dynamic_cast<ZxDataGaugeF * >(m_listGaugeF[i])) { // 拿到第一条流量数据
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取的压力、流量数据
|
|
|
|
|
QVector<QPointF> vecPtsP, vecPtsF;
|
|
|
|
|
// 临时存储x,y坐标
|
|
|
|
|
VecDouble vecX, vecY;
|
|
|
|
|
|
|
|
|
|
if(pGaugeP != nullptr) {
|
|
|
|
|
// 获取压力数据
|
|
|
|
|
if(pGaugeP->getDataVecXY(vecX, vecY)) {
|
|
|
|
|
int pointCount = vecX.size();
|
|
|
|
|
if(pointCount > vecY.size()) {
|
|
|
|
|
pointCount = vecY.size();
|
|
|
|
|
}
|
|
|
|
|
for(int i = 0; i < pointCount; ++i) {
|
|
|
|
|
QPointF pt(vecX[i], vecY[i]);
|
|
|
|
|
vecPtsP.append(pt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(pGaugeF != nullptr) {
|
|
|
|
|
vecX.clear();
|
|
|
|
|
vecY.clear();
|
|
|
|
|
|
|
|
|
|
// 获取流量数据
|
|
|
|
|
if(pGaugeF->getDataVecXY(vecX, vecY)) {
|
|
|
|
|
int pointCount = vecX.size();
|
|
|
|
|
if(pointCount > vecY.size()) {
|
|
|
|
|
pointCount = vecY.size();
|
|
|
|
|
}
|
|
|
|
|
for(int i = 0; i < pointCount; ++i) {
|
|
|
|
|
QPointF pt(vecX[i], vecY[i]);
|
|
|
|
|
vecPtsF.append(pt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置井的压力数据、流量数据
|
|
|
|
|
pWell->setPressurePoints(vecPtsP);
|
|
|
|
|
pWell->setFlowPoints(vecPtsF);
|
|
|
|
|
ZxDataWell* pFrameworkWell =
|
|
|
|
|
mapFrameworkWells.value(pWell->getWellCode(), nullptr);
|
|
|
|
|
QVector<QPointF> vecPressurePoints;
|
|
|
|
|
QVector<QPointF> vecFlowPoints;
|
|
|
|
|
NM_WELL_CATEGORY eFrameworkCategory = NM_WellCategory_Unknown;
|
|
|
|
|
if(!readFrameworkWellCurves(pFrameworkWell,
|
|
|
|
|
vecPressurePoints,
|
|
|
|
|
vecFlowPoints,
|
|
|
|
|
eFrameworkCategory) ||
|
|
|
|
|
pWell->getWellCategory() != eFrameworkCategory) {
|
|
|
|
|
qWarning() << "Numerical well category does not match framework well:"
|
|
|
|
|
<< pWell->getWellCode();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pWell->setPressurePoints(vecPressurePoints);
|
|
|
|
|
pWell->setFlowPoints(vecFlowPoints);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vtkSmartPointer<vtkUnstructuredGrid> nmDataAnalyzeManager::getUnstructuredGrid() const
|
|
|
|
|
|