feat(numerical): 支持多记录压力/流量数据读取与三相流量拆分

- 枚举工程井下全部压力、流量测量记录,不再只取第一条
- 新增 NM_GAUGE_RECORD_STATUS 记录可用状态:Usable/Empty/Corrupt/InvalidIdentity
- 新增 nmPressureGaugeRecord/nmFlowGaugeRecord 记录结构,压力/流量、单相/多相字节块统一解析判定
- 单条记录损坏或为空不再阻止建井,仅工程井对象为空或井别无效时才放弃
- nmDataWellBase 改为存储记录列表 + 选中 Gauge Code,getPressurePoints/getFlowPoints 等既有接口委托到当前选中记录
- 井型切换、绘图侧重新勾选井等历史数据拷贝逻辑同步适配三相流量分别读写
feature/nmNum-multi-gauge-record
lh 4 weeks ago
parent 2d5b56fe21
commit def8b945ba

@ -12,6 +12,7 @@
#include "nmDataHorizontalFracturedWell.h"
#include "nmDataNumericalAnalysisCase.h"
#include "nmNumericalResultPersistence.h"
#include "nmDataGaugeRecord.h"
#include "nmGridDefine.h"
@ -230,6 +231,26 @@ public:
// 获取当前分析窗体下的指针
static nmDataAnalyzeManager* getCurrentInstance();
/**
* @brief 枚举工程井下全部压力、流量测量记录并逐条判定可用状态。
* @note 仅当工程井对象为空或井别无效时返回 false;单条记录损坏/为空
* 不影响返回值,只会体现为该记录的 eStatus。
*/
static bool readFrameworkWellCurves(
ZxDataWell* pWellData,
QVector<nmPressureGaugeRecord>& vecPressureRecords,
QVector<nmFlowGaugeRecord>& vecFlowRecords,
NM_WELL_CATEGORY& eWellCategory);
/**
* @brief 将枚举到的记录列表写入数值井,并按默认规则选中压力/流量记录。
* @note 找不到任何可用记录时仍会写入列表,只是选中 Code 为空,不阻止建井。
*/
static void applyGaugeRecordsToWell(
nmDataWellBase* pWellData,
const QVector<nmPressureGaugeRecord>& vecPressureRecords,
const QVector<nmFlowGaugeRecord>& vecFlowRecords);
// 井的接口
// 添加井
nmDataWellBase* createWell(NM_WELL_MODEL eWellType);

@ -0,0 +1,49 @@
#pragma once
#include "nmDefines.h"
#include <QPointF>
#include <QString>
#include <QVector>
/**
* @brief 工程井下一条压力测量记录的只读快照。
* @note 记录本身不持久化到数值项目文件,每次都从工程井节点重新读取;
* 损坏或为空的记录仍保留在列表中,只是不可被选中。
*/
struct nmPressureGaugeRecord {
QString sGaugeCode; // 对应 ZxDataGaugeP::getCode(),选择持久化键
QString sGaugeName; // 对应 ZxDataGaugeP::getGaugeName(),界面展示用
QString sGaugeTime; // 对应 ZxDataGaugeP::getGaugeTime(),界面展示用
NM_GAUGE_RECORD_STATUS eStatus; // 记录可用状态
QVector<QPointF> vecPressurePoints; // 主块解析出的压力曲线点
nmPressureGaugeRecord()
: eStatus(NM_GaugeRecord_Empty)
{
}
};
/**
* @brief 工程井下一条流量测量记录的只读快照。
* @note 单相记录只解析主块并按井别归入对应相,忽略可能残留的 Ex2/Ex3;
* 多相记录分别解析主块、Ex2、Ex3 为油、气、水三相。
*/
struct nmFlowGaugeRecord {
QString sGaugeCode; // 对应 ZxDataGaugeF::getCode(),选择持久化键
QString sGaugeName; // 对应 ZxDataGaugeF::getGaugeName(),界面展示用
QString sGaugeTime; // 对应 ZxDataGaugeF::getGaugeTime(),界面展示用
bool bMultiPhase; // 对应 ZxDataGaugeF::getMultiPhase()
NM_GAUGE_RECORD_STATUS eStatus; // 记录可用状态
QVector<QPointF> vecOilPoints; // 油相流量点,允许首项为 (0,0) 占位点
QVector<QPointF> vecGasPoints; // 气相流量点,允许首项为 (0,0) 占位点
QVector<QPointF> vecWaterPoints; // 水相流量点,允许首项为 (0,0) 占位点
int nIndexF; // 该记录自身的一基流动段索引,供后续阶段切换记录时恢复
nmFlowGaugeRecord()
: bMultiPhase(false)
, eStatus(NM_GaugeRecord_Empty)
, nIndexF(0)
{
}
};

@ -3,6 +3,7 @@
#include "nmData_global.h"
#include "nmDefines.h"
#include "nmDataAttribute.h"
#include "nmDataGaugeRecord.h"
#include "ZxDataObjectDbl.h"
#include "nmDataPerforation.h"
@ -63,7 +64,7 @@ public:
/** @brief 保存工程井的油井、气井或水井井别;该值不由数值井编辑器修改。 */
void setWellCategory(NM_WELL_CATEGORY eWellCategory);
/** @brief 返回工程井井别,用于选择流量大字段及求解器相别数组。 */
/** @brief 返回工程井井别,用于选择历史曲线的参考流量相。 */
NM_WELL_CATEGORY getWellCategory() const;
/** @brief 返回井对象的稳定实例标识,与可编辑井编码相互独立。 */
@ -134,17 +135,48 @@ public:
QVector<QPointF> getPressurePoints() const;
// 设置压力曲线点数据
void setPressurePoints(const QVector<QPointF>& points);
// 获取流量曲线点数据
// 获取井别对应相的流量曲线点数据,供现有历史曲线逻辑使用
QVector<QPointF> getFlowPoints() const;
// 设置流量曲线点数据
// 设置井别对应相的流量曲线点数据
void setFlowPoints(const QVector<QPointF>& points);
/** @brief 返回去除可选 (0,0) 占位点后的真实流动段。 */
/** @brief 返回工程井别对应的历史曲线参考相。 */
NM_PHASE_TYPE getReferenceFlowPhase() const;
/** @brief 获取或设置指定油、气、水相的原始流量点。 */
QVector<QPointF> getFlowPoints(NM_PHASE_TYPE eFlowPhase) const;
void setFlowPoints(NM_PHASE_TYPE eFlowPhase,
const QVector<QPointF>& points);
/** @brief 返回指定相去除可选 (0,0) 占位点后的真实流动段。 */
QVector<QPointF> getFlowSegmentPoints(NM_PHASE_TYPE eFlowPhase) const;
/** @brief 返回指定相的真实流动段数量。 */
int getFlowSegmentCount(NM_PHASE_TYPE eFlowPhase) const;
/** @brief 指定相是否至少包含一个真实流动段。 */
bool hasFlowPhaseData(NM_PHASE_TYPE eFlowPhase) const;
/** @brief 油、气、水中是否至少有一相包含真实流动段。 */
bool hasAnyFlowData() const;
/** @brief 返回井别对应相去除可选 (0,0) 占位点后的真实流动段。 */
QVector<QPointF> getFlowSegmentPoints() const;
/** @brief 返回真实流动段数量,不把首个 (0,0) 占位点计入。 */
/** @brief 返回井别对应相的真实流动段数量。 */
int getFlowSegmentCount() const;
/** @brief 校验当前流动段索引是否位于一基的真实流动段范围内。 */
bool hasValidFlowSectionIndex() const;
/** @brief 设置全部压力记录列表(不改变当前选中 Code)。 */
void setPressureRecords(const QVector<nmPressureGaugeRecord>& vecRecords);
/** @brief 设置全部流量记录列表(不改变当前选中 Code)。 */
void setFlowRecords(const QVector<nmFlowGaugeRecord>& vecRecords);
/** @brief 按 Gauge Code 选中一条压力记录;传入空字符串表示无选中。 */
void selectPressureGaugeCode(const QString& sGaugeCode);
/** @brief 按 Gauge Code 选中一条流量记录;传入空字符串表示无选中。 */
void selectFlowGaugeCode(const QString& sGaugeCode);
/** @brief 返回当前选中的压力记录 Gauge Code,未选中时为空。 */
QString getSelectedPressureGaugeCode() const;
/** @brief 返回当前选中的流量记录 Gauge Code,未选中时为空。 */
QString getSelectedFlowGaugeCode() const;
/** @brief 返回全部压力记录(包含损坏/空/身份无效记录)。 */
QVector<nmPressureGaugeRecord> getPressureRecords() const;
/** @brief 返回全部流量记录(包含损坏/空/身份无效记录)。 */
QVector<nmFlowGaugeRecord> getFlowRecords() const;
int getIndexF() const;
void setIndexF(const int newIndex);
@ -276,8 +308,10 @@ protected:
// Bottomhole conditions---井底条件
nmDataAttribute m_bottomholeMD; // 井底测量深度
QVector<QPointF> m_vecPtsP; // 压力曲线点数据
QVector<QPointF> m_vecPtsF; // 流量曲线点数据,允许首项为 (0,0) 占位点
QVector<nmPressureGaugeRecord> m_vecPressureRecords; // 全部压力测量记录(可能包含损坏/空/身份无效记录)
QVector<nmFlowGaugeRecord> m_vecFlowRecords; // 全部流量测量记录(可能包含损坏/空/身份无效记录)
QString m_sSelectedPressureGaugeCode; // 当前选中的压力记录 Gauge Code,为空表示未选中
QString m_sSelectedFlowGaugeCode; // 当前选中的流量记录 Gauge Code,为空表示未选中
int m_nIndexF; // 当前流量段的索引

@ -57,8 +57,8 @@ enum NM_PHASE_TYPE {
PHASE_Oil_Water // 油水
};
// 工程井井别。数值模块只保存工程井井别的只读副本,流量相别由该值唯一派生。
// Oil/Gas/Water 的数值与 ZxDataWell::getWellTypeIndex() 及流量大字段索引保持一致。
// 工程井井别。数值模块保存其只读副本,并将井别对应相作为历史曲线参考相。
// Oil/Gas/Water 的数值与 ZxDataWell::getWellTypeIndex() 保持一致;真实多相流量独立保存。
enum NM_WELL_CATEGORY {
NM_WellCategory_Unknown = -1,
NM_WellCategory_Oil = 0,
@ -72,6 +72,14 @@ inline bool nmIsValidWellCategory(NM_WELL_CATEGORY eWellCategory)
eWellCategory == NM_WellCategory_Gas ||
eWellCategory == NM_WellCategory_Water;
}
// 工程压力/流量测量记录的可用状态。损坏与空记录仍保留在列表中,只是不可被选中。
enum NM_GAUGE_RECORD_STATUS {
NM_GaugeRecord_Usable, // 数据完整,可被选中使用
NM_GaugeRecord_Empty, // 主/多相字节块均为空,不算数据损坏
NM_GaugeRecord_Corrupt, // 字节块解析失败或 X/Y 长度不一致
NM_GaugeRecord_InvalidIdentity // Gauge Code 为空或在同一口井内重复
};
// 结构树节点类型
enum NM_TREE_TYPE {
TREE_OilReservoir, // 油藏节点

@ -42,6 +42,7 @@
#include "ZxDataGaugeBase.h"
#include "ZxDataGaugeP.h"
#include "ZxDataGaugeF.h"
#include "ZxBaHelper.h"
#include "zxSysUtils.h"
#include "ZxDataProject.h"
@ -152,72 +153,226 @@ static NM_WELL_CATEGORY frameworkWellCategory(const ZxDataWell* pWellData)
? eWellCategory : NM_WellCategory_Unknown;
}
// 从一条测量数据中复制二维点。流量调用方必须显式传入油、气、水井别索引。
static bool readGaugePoints(ZxDataGaugeBase* pGaugeData,
int nObjectIndex,
QVector<QPointF>& vecPoints)
// DLL 的带索引 getter 实际始终返回主块,压力和多相流量都必须直接解析指定字节块。
// 空块不算数据损坏,只有解析失败或 X/Y 长度不一致才算损坏。
static bool readFlowGaugeBlock(
const QByteArray& baGaugeData,
QVector<QPointF>& vecPoints)
{
vecPoints.clear();
if(pGaugeData == nullptr) {
return false;
if(baGaugeData.isEmpty()) {
return true;
}
QByteArray baData = baGaugeData;
VecDouble vecX;
VecDouble vecY;
if(!pGaugeData->getDataVecXY(vecX, vecY, nObjectIndex)) {
if(!ZxBaHelper::convertBa2VecXY(vecX, vecY, baData) ||
vecX.size() != vecY.size()) {
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.reserve(static_cast<int>(vecX.size()));
for(int nIndex = 0; nIndex < static_cast<int>(vecX.size()); ++nIndex) {
vecPoints.append(QPointF(vecX[nIndex], vecY[nIndex]));
}
return true;
}
// 读取工程井的第一条压力和流量数据;井别是流量相别的唯一事实来源。
static bool readFrameworkWellCurves(
// 解析单个字节块并据此判定该块自身的可用状态:空块为 Empty,解析失败为 Corrupt。
static NM_GAUGE_RECORD_STATUS readBlockAndClassify(
const QByteArray& baGaugeData,
QVector<QPointF>& vecPoints)
{
if(baGaugeData.isEmpty()) {
vecPoints.clear();
return NM_GaugeRecord_Empty;
}
return readFlowGaugeBlock(baGaugeData, vecPoints)
? NM_GaugeRecord_Usable : NM_GaugeRecord_Corrupt;
}
// 多相流量记录:主块=油、Ex2=气、Ex3=水;任一非空块损坏则整条记录损坏,三块全空才是空记录。
static NM_GAUGE_RECORD_STATUS classifyMultiPhaseFlowRecord(
ZxDataGaugeF* pGaugeF,
QVector<QPointF>& vecOilPoints,
QVector<QPointF>& vecGasPoints,
QVector<QPointF>& vecWaterPoints)
{
const QByteArray baOil = pGaugeF->getGaugeData();
const QByteArray baGas = pGaugeF->getGaugeDataEx2();
const QByteArray baWater = pGaugeF->getGaugeDataEx3();
const bool bOilOk = readFlowGaugeBlock(baOil, vecOilPoints);
const bool bGasOk = readFlowGaugeBlock(baGas, vecGasPoints);
const bool bWaterOk = readFlowGaugeBlock(baWater, vecWaterPoints);
if(!bOilOk || !bGasOk || !bWaterOk) {
return NM_GaugeRecord_Corrupt;
}
if(baOil.isEmpty() && baGas.isEmpty() && baWater.isEmpty()) {
return NM_GaugeRecord_Empty;
}
return NM_GaugeRecord_Usable;
}
// 单相流量记录:只解析主块,并按井别把数据归入油、气或水相;忽略可能残留的 Ex2/Ex3。
static NM_GAUGE_RECORD_STATUS classifySinglePhaseFlowRecord(
ZxDataGaugeF* pGaugeF,
NM_WELL_CATEGORY eWellCategory,
QVector<QPointF>& vecOilPoints,
QVector<QPointF>& vecGasPoints,
QVector<QPointF>& vecWaterPoints)
{
switch(eWellCategory) {
case NM_WellCategory_Oil:
return readBlockAndClassify(pGaugeF->getGaugeData(), vecOilPoints);
case NM_WellCategory_Gas:
return readBlockAndClassify(pGaugeF->getGaugeData(), vecGasPoints);
case NM_WellCategory_Water:
return readBlockAndClassify(pGaugeF->getGaugeData(), vecWaterPoints);
default:
// 调用方在枚举记录前已校验过井别有效性,这里不应该被触达。
return NM_GaugeRecord_Corrupt;
}
}
bool nmDataAnalyzeManager::readFrameworkWellCurves(
ZxDataWell* pWellData,
QVector<QPointF>& vecPressurePoints,
QVector<QPointF>& vecFlowPoints,
QVector<nmPressureGaugeRecord>& vecPressureRecords,
QVector<nmFlowGaugeRecord>& vecFlowRecords,
NM_WELL_CATEGORY& eWellCategory)
{
vecPressurePoints.clear();
vecFlowPoints.clear();
vecPressureRecords.clear();
vecFlowRecords.clear();
eWellCategory = frameworkWellCategory(pWellData);
if(pWellData == nullptr || !nmIsValidWellCategory(eWellCategory)) {
return false;
}
ZxDataGaugeP* pGaugeP = nullptr;
// 第一步:枚举全部压力记录,不再只取第一条。
const ZxDataObjectList listGaugeP =
pWellData->getChildren(iDataModelType::sTypeDataGaugeP);
QSet<QString> setSeenPressureCodes;
for(int nIndex = 0; nIndex < listGaugeP.size(); ++nIndex) {
pGaugeP = dynamic_cast<ZxDataGaugeP*>(listGaugeP[nIndex]);
if(pGaugeP != nullptr) {
break;
ZxDataGaugeP* pGaugeP = dynamic_cast<ZxDataGaugeP*>(listGaugeP[nIndex]);
if(pGaugeP == nullptr) {
continue;
}
nmPressureGaugeRecord oRecord;
oRecord.sGaugeCode = pGaugeP->getCode();
oRecord.sGaugeName = pGaugeP->getGaugeName();
oRecord.sGaugeTime = pGaugeP->getGaugeTime();
oRecord.eStatus = readBlockAndClassify(
pGaugeP->getGaugeData(), oRecord.vecPressurePoints);
// 空 Code 或同井重复 Code 属于身份问题,覆盖内容判定结果。
if(oRecord.sGaugeCode.isEmpty() ||
setSeenPressureCodes.contains(oRecord.sGaugeCode)) {
oRecord.eStatus = NM_GaugeRecord_InvalidIdentity;
} else {
setSeenPressureCodes.insert(oRecord.sGaugeCode);
}
vecPressureRecords.append(oRecord);
}
ZxDataGaugeF* pGaugeF = nullptr;
// 第二步:枚举全部流量记录,不再只取第一条。
const ZxDataObjectList listGaugeF =
pWellData->getChildren(iDataModelType::sTypeDataGaugeF);
QSet<QString> setSeenFlowCodes;
for(int nIndex = 0; nIndex < listGaugeF.size(); ++nIndex) {
pGaugeF = dynamic_cast<ZxDataGaugeF*>(listGaugeF[nIndex]);
if(pGaugeF != nullptr) {
break;
ZxDataGaugeF* pGaugeF = dynamic_cast<ZxDataGaugeF*>(listGaugeF[nIndex]);
if(pGaugeF == nullptr) {
continue;
}
nmFlowGaugeRecord oRecord;
oRecord.sGaugeCode = pGaugeF->getCode();
oRecord.sGaugeName = pGaugeF->getGaugeName();
oRecord.sGaugeTime = pGaugeF->getGaugeTime();
oRecord.bMultiPhase = pGaugeF->getMultiPhase();
oRecord.eStatus = oRecord.bMultiPhase
? classifyMultiPhaseFlowRecord(
pGaugeF, oRecord.vecOilPoints,
oRecord.vecGasPoints, oRecord.vecWaterPoints)
: classifySinglePhaseFlowRecord(
pGaugeF, eWellCategory,
oRecord.vecOilPoints,
oRecord.vecGasPoints, oRecord.vecWaterPoints);
// 空 Code 或同井重复 Code 属于身份问题,覆盖内容判定结果。
if(oRecord.sGaugeCode.isEmpty() ||
setSeenFlowCodes.contains(oRecord.sGaugeCode)) {
oRecord.eStatus = NM_GaugeRecord_InvalidIdentity;
} else {
setSeenFlowCodes.insert(oRecord.sGaugeCode);
}
vecFlowRecords.append(oRecord);
}
// 压力数据仍读取二维主对象;流量必须使用井别对应的 0/1/2 大字段索引。
readGaugePoints(pGaugeP, 0, vecPressurePoints);
readGaugePoints(pGaugeF, static_cast<int>(eWellCategory), vecFlowPoints);
return true;
}
// 判断某相流量点是否至少包含一个真实流动段,去除可选首个 (0,0) 占位点后非空即为真实。
static bool hasRealFlowSegment(const QVector<QPointF>& vecPoints)
{
if(vecPoints.isEmpty()) {
return false;
}
if(vecPoints.size() == 1 &&
vecPoints.first().x() == 0.0 && vecPoints.first().y() == 0.0) {
return false;
}
return true;
}
// 从压力记录列表中选出框架顺序中第一条 Usable 记录;找不到则返回空 Code。
static QString selectDefaultPressureGaugeCode(
const QVector<nmPressureGaugeRecord>& vecRecords)
{
foreach(const nmPressureGaugeRecord& oRecord, vecRecords) {
if(oRecord.eStatus == NM_GaugeRecord_Usable) {
return oRecord.sGaugeCode;
}
}
return QString();
}
// 从流量记录列表中选出框架顺序中第一条至少含一个真实相的记录;找不到则返回空 Code。
static QString selectDefaultFlowGaugeCode(
const QVector<nmFlowGaugeRecord>& vecRecords)
{
foreach(const nmFlowGaugeRecord& oRecord, vecRecords) {
if(oRecord.eStatus != NM_GaugeRecord_Usable) {
continue;
}
if(hasRealFlowSegment(oRecord.vecOilPoints) ||
hasRealFlowSegment(oRecord.vecGasPoints) ||
hasRealFlowSegment(oRecord.vecWaterPoints)) {
return oRecord.sGaugeCode;
}
}
return QString();
}
// 把枚举到的记录列表写入数值井,并按默认规则选中压力/流量记录。
// 找不到任何可用记录时仍会写入(可能为空的)列表,只是选中 Code 为空——不阻止建井。
void nmDataAnalyzeManager::applyGaugeRecordsToWell(
nmDataWellBase* pWellData,
const QVector<nmPressureGaugeRecord>& vecPressureRecords,
const QVector<nmFlowGaugeRecord>& vecFlowRecords)
{
if(pWellData == nullptr) {
return;
}
pWellData->setPressureRecords(vecPressureRecords);
pWellData->setFlowRecords(vecFlowRecords);
pWellData->selectPressureGaugeCode(
selectDefaultPressureGaugeCode(vecPressureRecords));
pWellData->selectFlowGaugeCode(
selectDefaultFlowGaugeCode(vecFlowRecords));
}
static bool isWellParaAttrName(const QString& name)
{
for (int i = 0; i < WELL_PARA_DESC_COUNT; ++i) {
@ -1447,11 +1602,11 @@ void nmDataAnalyzeManager::initCurWellData()
// 判断是哪一种井类型,初始化对应的参数
QString wellClass = pWellData->getWellClassEn();
QVector<QPointF> vecPtsP;
QVector<QPointF> vecPtsF;
QVector<nmPressureGaugeRecord> vecPressureRecords;
QVector<nmFlowGaugeRecord> vecFlowRecords;
NM_WELL_CATEGORY eWellCategory = NM_WellCategory_Unknown;
if(!readFrameworkWellCurves(pWellData, vecPtsP, vecPtsF,
eWellCategory)) {
if(!readFrameworkWellCurves(pWellData, vecPressureRecords,
vecFlowRecords, eWellCategory)) {
qWarning() << "Cannot import numerical well with invalid category:"
<< pWellData->getCode();
return;
@ -1478,9 +1633,8 @@ void nmDataAnalyzeManager::initCurWellData()
tempAttr.setValue(pWellData->getWellRadius());
pVerticalWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pVerticalWell->setPressurePoints(vecPtsP);
pVerticalWell->setFlowPoints(vecPtsF);
// 设置井的压力、流量记录列表,并按默认规则选中当前记录
applyGaugeRecordsToWell(pVerticalWell, vecPressureRecords, vecFlowRecords);
QVector<QVector<double>> vvecHistoryPressureData; //压力历史数据
QVector<QVector<double>> vvecHistoryLogData; // 历史双对数曲线数据
@ -1517,9 +1671,8 @@ void nmDataAnalyzeManager::initCurWellData()
tempAttr.setValue(pWellData->getWellRadius());
pVFracturedWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pVFracturedWell->setPressurePoints(vecPtsP);
pVFracturedWell->setFlowPoints(vecPtsF);
// 设置井的压力、流量记录列表,并按默认规则选中当前记录
applyGaugeRecordsToWell(pVFracturedWell, vecPressureRecords, vecFlowRecords);
QVector<QVector<double>> vvecHistoryPressureData; //压力历史数据
QVector<QVector<double>> vvecHistoryLogData; // 历史双对数曲线数据
@ -1559,9 +1712,8 @@ void nmDataAnalyzeManager::initCurWellData()
tempAttr.setValue(pWellData->getWellRadius());
pHFracturedWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pHFracturedWell->setPressurePoints(vecPtsP);
pHFracturedWell->setFlowPoints(vecPtsF);
// 设置井的压力、流量记录列表,并按默认规则选中当前记录
applyGaugeRecordsToWell(pHFracturedWell, vecPressureRecords, vecFlowRecords);
QVector<QVector<double>> vvecHistoryPressureData; //压力历史数据
QVector<QVector<double>> vvecHistoryLogData; // 历史双对数曲线数据
@ -1703,13 +1855,13 @@ nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
return pExistingWell;
}
// 井别决定流量大字段;压力仍读取第一条压力数据的主对象。
// 压力及流量记录统一由工程井读取入口解析。
const QString sWellClass = pWellData->getWellClassEn();
QVector<QPointF> vecPtsP;
QVector<QPointF> vecPtsF;
QVector<nmPressureGaugeRecord> vecPressureRecords;
QVector<nmFlowGaugeRecord> vecFlowRecords;
NM_WELL_CATEGORY eWellCategory = NM_WellCategory_Unknown;
if(!readFrameworkWellCurves(pWellData, vecPtsP, vecPtsF,
eWellCategory)) {
if(!readFrameworkWellCurves(pWellData, vecPressureRecords,
vecFlowRecords, eWellCategory)) {
qWarning() << "Cannot append numerical well with invalid category:"
<< pWellData->getCode();
return nullptr;
@ -1738,9 +1890,8 @@ nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
tempAttr.setValue(pWellData->getWellRadius());
pVerticalWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pVerticalWell->setPressurePoints(vecPtsP);
pVerticalWell->setFlowPoints(vecPtsF);
// 设置井的压力、流量记录列表,并按默认规则选中当前记录
applyGaugeRecordsToWell(pVerticalWell, vecPressureRecords, vecFlowRecords);
// 其他井默认选择最后一个真实流动段,索引保持一基。
pVerticalWell->setIndexF(pVerticalWell->getFlowSegmentCount());
@ -1767,9 +1918,8 @@ nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
tempAttr.setValue(pWellData->getWellRadius());
pVFracturedWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pVFracturedWell->setPressurePoints(vecPtsP);
pVFracturedWell->setFlowPoints(vecPtsF);
// 设置井的压力、流量记录列表,并按默认规则选中当前记录
applyGaugeRecordsToWell(pVFracturedWell, vecPressureRecords, vecFlowRecords);
// 更新裂缝位置信息
pVFracturedWell->setFracs();
@ -1798,9 +1948,8 @@ nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
tempAttr.setValue(pWellData->getWellRadius());
pHFracturedWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pHFracturedWell->setPressurePoints(vecPtsP);
pHFracturedWell->setFlowPoints(vecPtsF);
// 设置井的压力、流量记录列表,并按默认规则选中当前记录
applyGaugeRecordsToWell(pHFracturedWell, vecPressureRecords, vecFlowRecords);
// 计算裂缝数据
pHFracturedWell->setFracs();
@ -6151,12 +6300,12 @@ bool nmDataAnalyzeManager::loadWellPreAndFlow()
ZxDataWell* pFrameworkWell =
mapFrameworkWells.value(pWell->getWellCode(), nullptr);
QVector<QPointF> vecPressurePoints;
QVector<QPointF> vecFlowPoints;
QVector<nmPressureGaugeRecord> vecPressureRecords;
QVector<nmFlowGaugeRecord> vecFlowRecords;
NM_WELL_CATEGORY eFrameworkCategory = NM_WellCategory_Unknown;
if(!readFrameworkWellCurves(pFrameworkWell,
vecPressurePoints,
vecFlowPoints,
vecPressureRecords,
vecFlowRecords,
eFrameworkCategory) ||
pWell->getWellCategory() != eFrameworkCategory) {
qWarning() << "Numerical well category does not match framework well:"
@ -6164,8 +6313,7 @@ bool nmDataAnalyzeManager::loadWellPreAndFlow()
return false;
}
pWell->setPressurePoints(vecPressurePoints);
pWell->setFlowPoints(vecFlowPoints);
applyGaugeRecordsToWell(pWell, vecPressureRecords, vecFlowRecords);
}
return true;
}

@ -11,6 +11,43 @@
#include <QDateTime>
#include <QUuid>
/**
* @brief 按 Gauge Code 在记录列表中查找可写记录指针;Code 为空或未命中时返回 nullptr。
* @note 阶段一内部使用,不对外暴露;空 Code 统一表示“未选中”,因此不参与查找。
*/
template <typename TRecord>
static TRecord* findGaugeRecordByCode(QVector<TRecord>& vecRecords, const QString& sGaugeCode)
{
if(sGaugeCode.isEmpty()) {
return nullptr;
}
for(int i = 0; i < vecRecords.size(); ++i) {
if(vecRecords[i].sGaugeCode == sGaugeCode) {
return &vecRecords[i];
}
}
return nullptr;
}
template <typename TRecord>
static const TRecord* findGaugeRecordByCode(const QVector<TRecord>& vecRecords, const QString& sGaugeCode)
{
if(sGaugeCode.isEmpty()) {
return nullptr;
}
for(int i = 0; i < vecRecords.size(); ++i) {
if(vecRecords[i].sGaugeCode == sGaugeCode) {
return &vecRecords[i];
}
}
return nullptr;
}
// setPressurePoints/setFlowPoints 等旧接口在没有选中记录时用来创建内部占位记录的 Code。
// 使用非空占位符,避免与“空 Code = 未选中”的约定冲突;阶段二引入选择 UI 前不会对外暴露该记录。
static const QString kManualPressureGaugeCode = QString::fromLatin1("__ManualPressureRecord__");
static const QString kManualFlowGaugeCode = QString::fromLatin1("__ManualFlowRecord__");
nmDataWellBase::nmDataWellBase()
: m_eWellCategory(NM_WellCategory_Unknown)
, m_nIndexF(0)
@ -124,8 +161,10 @@ nmDataWellBase& nmDataWellBase::operator=(const nmDataWellBase& other)
m_wellboreModel = other.m_wellboreModel;
m_wellboreStorage = other.m_wellboreStorage;
m_bottomholeMD = other.m_bottomholeMD;
m_vecPtsP = other.m_vecPtsP;
m_vecPtsF = other.m_vecPtsF;
m_vecPressureRecords = other.m_vecPressureRecords;
m_vecFlowRecords = other.m_vecFlowRecords;
m_sSelectedPressureGaugeCode = other.m_sSelectedPressureGaugeCode;
m_sSelectedFlowGaugeCode = other.m_sSelectedFlowGaugeCode;
m_nIndexF = other.m_nIndexF;
m_finalWellboreStorage = other.m_finalWellboreStorage;
m_inputWellHead = other.m_inputWellHead;
@ -667,33 +706,162 @@ void nmDataWellBase::setTimeDependentSkin(bool enabled)
m_bTimeDependentSkin = enabled;
}
// 获取压力曲线点数据
// 获取压力曲线点数据:委托到当前选中的压力记录,未选中或未命中时返回空。
QVector<QPointF> nmDataWellBase::getPressurePoints() const
{
return m_vecPtsP;
const nmPressureGaugeRecord* pRecord =
findGaugeRecordByCode(m_vecPressureRecords, m_sSelectedPressureGaugeCode);
return pRecord == nullptr ? QVector<QPointF>() : pRecord->vecPressurePoints;
}
// 设置压力曲线点数据
// 设置压力曲线点数据:写入当前选中记录;若无选中记录,新建一条内部占位记录承载数据,
// 兼容井型切换等历史调用方对该 setter 的既有假设。
void nmDataWellBase::setPressurePoints(const QVector<QPointF>& points)
{
m_vecPtsP = points;
nmPressureGaugeRecord* pRecord =
findGaugeRecordByCode(m_vecPressureRecords, m_sSelectedPressureGaugeCode);
if(pRecord == nullptr) {
nmPressureGaugeRecord newRecord;
newRecord.sGaugeCode = kManualPressureGaugeCode;
m_vecPressureRecords.append(newRecord);
m_sSelectedPressureGaugeCode = kManualPressureGaugeCode;
pRecord = &m_vecPressureRecords.last();
}
pRecord->vecPressurePoints = points;
pRecord->eStatus = points.isEmpty() ? NM_GaugeRecord_Empty : NM_GaugeRecord_Usable;
}
// 获取流量曲线点数据
// 获取井别对应相的流量曲线点数据
QVector<QPointF> nmDataWellBase::getFlowPoints() const
{
return m_vecPtsF;
return getFlowPoints(getReferenceFlowPhase());
}
// 设置流量曲线点数据
// 设置井别对应相的流量曲线点数据
void nmDataWellBase::setFlowPoints(const QVector<QPointF>& points)
{
m_vecPtsF = points;
setFlowPoints(getReferenceFlowPhase(), points);
}
QVector<QPointF> nmDataWellBase::getFlowSegmentPoints() const
NM_PHASE_TYPE nmDataWellBase::getReferenceFlowPhase() const
{
switch(m_eWellCategory) {
case NM_WellCategory_Oil:
return PHASE_Oil;
case NM_WellCategory_Gas:
return PHASE_Gas;
case NM_WellCategory_Water:
return PHASE_Water;
default:
return PHASE_UNKNOWN;
}
}
// 获取指定相流量点数据:委托到当前选中的流量记录,未选中或未命中时返回空。
QVector<QPointF> nmDataWellBase::getFlowPoints(
NM_PHASE_TYPE eFlowPhase) const
{
const nmFlowGaugeRecord* pRecord =
findGaugeRecordByCode(m_vecFlowRecords, m_sSelectedFlowGaugeCode);
if(pRecord == nullptr) {
return QVector<QPointF>();
}
switch(eFlowPhase) {
case PHASE_Oil:
return pRecord->vecOilPoints;
case PHASE_Gas:
return pRecord->vecGasPoints;
case PHASE_Water:
return pRecord->vecWaterPoints;
default:
return QVector<QPointF>();
}
}
// 设置指定相流量点数据:写入当前选中记录;若无选中记录,新建一条内部占位记录承载数据,
// 兼容井型切换等历史调用方对该 setter 的既有假设。
void nmDataWellBase::setFlowPoints(
NM_PHASE_TYPE eFlowPhase,
const QVector<QPointF>& points)
{
nmFlowGaugeRecord* pRecord =
findGaugeRecordByCode(m_vecFlowRecords, m_sSelectedFlowGaugeCode);
if(pRecord == nullptr) {
nmFlowGaugeRecord newRecord;
newRecord.sGaugeCode = kManualFlowGaugeCode;
m_vecFlowRecords.append(newRecord);
m_sSelectedFlowGaugeCode = kManualFlowGaugeCode;
pRecord = &m_vecFlowRecords.last();
}
switch(eFlowPhase) {
case PHASE_Oil:
pRecord->vecOilPoints = points;
break;
case PHASE_Gas:
pRecord->vecGasPoints = points;
break;
case PHASE_Water:
pRecord->vecWaterPoints = points;
break;
default:
break;
}
pRecord->eStatus = (pRecord->vecOilPoints.isEmpty()
&& pRecord->vecGasPoints.isEmpty()
&& pRecord->vecWaterPoints.isEmpty())
? NM_GaugeRecord_Empty : NM_GaugeRecord_Usable;
}
// 设置全部压力记录列表(不改变当前选中 Code)。
void nmDataWellBase::setPressureRecords(const QVector<nmPressureGaugeRecord>& vecRecords)
{
m_vecPressureRecords = vecRecords;
}
// 设置全部流量记录列表(不改变当前选中 Code)。
void nmDataWellBase::setFlowRecords(const QVector<nmFlowGaugeRecord>& vecRecords)
{
m_vecFlowRecords = vecRecords;
}
// 按 Gauge Code 选中一条压力记录;传入空字符串表示无选中。
void nmDataWellBase::selectPressureGaugeCode(const QString& sGaugeCode)
{
m_sSelectedPressureGaugeCode = sGaugeCode;
}
// 按 Gauge Code 选中一条流量记录;传入空字符串表示无选中。
void nmDataWellBase::selectFlowGaugeCode(const QString& sGaugeCode)
{
m_sSelectedFlowGaugeCode = sGaugeCode;
}
QString nmDataWellBase::getSelectedPressureGaugeCode() const
{
return m_sSelectedPressureGaugeCode;
}
QString nmDataWellBase::getSelectedFlowGaugeCode() const
{
return m_sSelectedFlowGaugeCode;
}
QVector<nmPressureGaugeRecord> nmDataWellBase::getPressureRecords() const
{
QVector<QPointF> vecSegments = m_vecPtsF;
return m_vecPressureRecords;
}
QVector<nmFlowGaugeRecord> nmDataWellBase::getFlowRecords() const
{
return m_vecFlowRecords;
}
QVector<QPointF> nmDataWellBase::getFlowSegmentPoints(
NM_PHASE_TYPE eFlowPhase) const
{
QVector<QPointF> vecSegments = getFlowPoints(eFlowPhase);
// 工程流量数据通常以 (0,0) 作为非业务占位点;真实数据没有占位点时不得误删首段。
if(!vecSegments.isEmpty() &&
vecSegments.first().x() == 0.0 &&
@ -703,14 +871,31 @@ QVector<QPointF> nmDataWellBase::getFlowSegmentPoints() const
return vecSegments;
}
int nmDataWellBase::getFlowSegmentCount(NM_PHASE_TYPE eFlowPhase) const
{
return getFlowSegmentPoints(eFlowPhase).size();
}
bool nmDataWellBase::hasFlowPhaseData(NM_PHASE_TYPE eFlowPhase) const
{
return getFlowSegmentCount(eFlowPhase) > 0;
}
bool nmDataWellBase::hasAnyFlowData() const
{
return hasFlowPhaseData(PHASE_Oil) ||
hasFlowPhaseData(PHASE_Gas) ||
hasFlowPhaseData(PHASE_Water);
}
QVector<QPointF> nmDataWellBase::getFlowSegmentPoints() const
{
return getFlowSegmentPoints(getReferenceFlowPhase());
}
int nmDataWellBase::getFlowSegmentCount() const
{
if(m_vecPtsF.isEmpty()) {
return 0;
}
return m_vecPtsF.first().x() == 0.0 &&
m_vecPtsF.first().y() == 0.0
? m_vecPtsF.size() - 1 : m_vecPtsF.size();
return getFlowSegmentCount(getReferenceFlowPhase());
}
bool nmDataWellBase::hasValidFlowSectionIndex() const

@ -252,71 +252,19 @@ void nmGuiPlot::initDefultGeoObj()
// 判断是哪一种井类型,初始化对应的参数
QString wellClass = pWellData->getWellClassEn();
const NM_WELL_CATEGORY eWellCategory =
static_cast<NM_WELL_CATEGORY>(
pWellData->getWellTypeIndex());
if(!nmIsValidWellCategory(eWellCategory)) {
QVector<nmPressureGaugeRecord> vecPressureRecords;
QVector<nmFlowGaugeRecord> vecFlowRecords;
NM_WELL_CATEGORY eWellCategory = NM_WellCategory_Unknown;
if(!nmDataAnalyzeManager::readFrameworkWellCurves(
pWellData,
vecPressureRecords,
vecFlowRecords,
eWellCategory)) {
this->setPlotsByDataManger(pDataManager);
return;
}
// 获取当前井的压力、流量数据
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;
vecPtsP.clear();
vecPtsF.clear();
// 临时存储x,y坐标
VecDouble vecX, vecY;
if(pGaugeP != nullptr) {
// 获取压力数据
if(pGaugeP->getDataVecXY(vecX, vecY, 0)) {
for(int i = 0; i < vecX.size(); ++i) {
if(i < vecY.size()) {
QPointF pt(vecX[i], vecY[i]);
vecPtsP.append(pt);
}
}
}
}
if(pGaugeF != nullptr) {
vecX.clear();
vecY.clear();
// 获取流量数据
// 井别是流量大字段索引,单相井也不能固定读取默认的油相字段。
if(pGaugeF->getDataVecXY(
vecX, vecY, static_cast<int>(eWellCategory))) {
for(int i = 0; i < vecX.size(); ++i) {
if(i < vecY.size()) {
QPointF pt(vecX[i], vecY[i]);
vecPtsF.append(pt);
}
}
}
}
// 历史数据
QVector<QVector<double>> vvecHistoryPressureData;
QVector<QVector<double>> vvecHistoryLogData;
@ -345,9 +293,9 @@ void nmGuiPlot::initDefultGeoObj()
tempAttr.setValue(pWellData->getWellRadius());
m_VerticalWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
m_VerticalWell->setPressurePoints(vecPtsP);
m_VerticalWell->setFlowPoints(vecPtsF);
// 设置井的压力、流量记录列表,并按默认规则选中当前记录
nmDataAnalyzeManager::applyGaugeRecordsToWell(
m_VerticalWell, vecPressureRecords, vecFlowRecords);
// TODO: 计算井的历史双对数/半对数数据
pDataManager->calculationLogData(m_VerticalWell, vvecHistoryPressureData, vvecHistoryLogData, vvecHistorySemiLogData);
@ -383,9 +331,9 @@ void nmGuiPlot::initDefultGeoObj()
tempAttr.setValue(pWellData->getWellRadius());
m_VFracturedWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
m_VFracturedWell->setPressurePoints(vecPtsP);
m_VFracturedWell->setFlowPoints(vecPtsF);
// 设置井的压力、流量记录列表,并按默认规则选中当前记录
nmDataAnalyzeManager::applyGaugeRecordsToWell(
m_VFracturedWell, vecPressureRecords, vecFlowRecords);
// TODO: 计算井的历史双对数/半对数数据
pDataManager->calculationLogData(m_VFracturedWell, vvecHistoryPressureData, vvecHistoryLogData, vvecHistorySemiLogData);
@ -424,9 +372,9 @@ void nmGuiPlot::initDefultGeoObj()
tempAttr.setValue(pWellData->getWellRadius());
m_HFracturedWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
m_HFracturedWell->setPressurePoints(vecPtsP);
m_HFracturedWell->setFlowPoints(vecPtsF);
// 设置井的压力、流量记录列表,并按默认规则选中当前记录
nmDataAnalyzeManager::applyGaugeRecordsToWell(
m_HFracturedWell, vecPressureRecords, vecFlowRecords);
// TODO: 计算井的历史双对数/半对数数据
pDataManager->calculationLogData(m_HFracturedWell, vvecHistoryPressureData, vvecHistoryLogData, vvecHistorySemiLogData);

@ -1747,9 +1747,14 @@ bool nmPlotGraphicBinder::ensureSelectedWellData(nmObjPointWell* pGraphic,
return false;
}
const NM_WELL_CATEGORY eWellCategory =
static_cast<NM_WELL_CATEGORY>(pWellData->getWellTypeIndex());
if(!nmIsValidWellCategory(eWellCategory)) {
QVector<nmPressureGaugeRecord> vecPressureRecords;
QVector<nmFlowGaugeRecord> vecFlowRecords;
NM_WELL_CATEGORY eWellCategory = NM_WellCategory_Unknown;
if(!nmDataAnalyzeManager::readFrameworkWellCurves(
pWellData,
vecPressureRecords,
vecFlowRecords,
eWellCategory)) {
return false;
}
@ -1772,62 +1777,13 @@ bool nmPlotGraphicBinder::ensureSelectedWellData(nmObjPointWell* pGraphic,
tempAttr.setValue(pWellData->getWellRadius());
pData->setRadius(tempAttr);
ZxDataObjectList listGaugeP = pWellData->getChildren(iDataModelType::sTypeDataGaugeP);
ZxDataObjectList listGaugeF = pWellData->getChildren(iDataModelType::sTypeDataGaugeF);
ZxDataGaugeP* pGaugeP = nullptr;
ZxDataGaugeF* pGaugeF = nullptr;
// 设置井的压力、流量记录列表,并按默认规则选中当前记录
nmDataAnalyzeManager::applyGaugeRecordsToWell(
pData, vecPressureRecords, vecFlowRecords);
// 从工程树井节点下取第一条压力/流量数据,转换成数值井需要的曲线点。
for(int i = 0; i < listGaugeP.size(); ++i) {
if(pGaugeP = dynamic_cast<ZxDataGaugeP*>(listGaugeP[i])) {
break;
}
}
for(int i = 0; i < listGaugeF.size(); ++i) {
if(pGaugeF = dynamic_cast<ZxDataGaugeF*>(listGaugeF[i])) {
break;
}
}
QVector<QPointF> pressurePoints, flowPoints;
VecDouble vecX, vecY;
if(pGaugeP != nullptr && pGaugeP->getDataVecXY(vecX, vecY, 0)) {
for(int i = 0; i < vecX.size(); ++i) {
if(i < vecY.size()) {
pressurePoints.append(QPointF(vecX[i], vecY[i]));
}
}
}
vecX.clear();
vecY.clear();
// 流量大字段的 0/1/2 分别对应油井、气井和水井,禁止使用默认索引猜测。
if(pGaugeF != nullptr &&
pGaugeF->getDataVecXY(vecX, vecY,
static_cast<int>(eWellCategory))) {
for(int i = 0; i < vecX.size(); ++i) {
if(i < vecY.size()) {
flowPoints.append(QPointF(vecX[i], vecY[i]));
}
}
}
int nFlowSectionIndex = -2;
if(pWellData != zxCurWell) {
// 非当前查看井在设置流量点后选择最后一个真实段,索引保持一基。
nFlowSectionIndex = flowPoints.size();
if(!flowPoints.isEmpty() && flowPoints.first().x() == 0.0 &&
flowPoints.first().y() == 0.0) {
--nFlowSectionIndex;
}
}
pData->setPressurePoints(pressurePoints);
pData->setFlowPoints(flowPoints);
if(nFlowSectionIndex >= -1) {
pData->setIndexF(nFlowSectionIndex);
// 非当前查看井仍默认选择井别参考相的最后一个真实段,索引保持一基。
pData->setIndexF(pData->getFlowSegmentCount());
}
if (wellType == NM_WELL_MODEL::Vertical_Fractured_Well) {

@ -376,7 +376,12 @@ bool nmWellEditorSession::copySharedWellData(
// 第二步:保留输入历史和已有计算结果,切换井型不应丢失曲线数据。
pTarget->setPressurePoints(pSource->getPressurePoints());
pTarget->setFlowPoints(pSource->getFlowPoints());
pTarget->setFlowPoints(PHASE_Oil,
pSource->getFlowPoints(PHASE_Oil));
pTarget->setFlowPoints(PHASE_Gas,
pSource->getFlowPoints(PHASE_Gas));
pTarget->setFlowPoints(PHASE_Water,
pSource->getFlowPoints(PHASE_Water));
pTarget->setIndexF(pSource->getIndexF());
pTarget->setHistoryPressure(pSource->getHistoryPressure());
pTarget->setHistoryLogLog(pSource->getHistoryLogLog());

@ -786,8 +786,16 @@ void nmWxEditWellPlot::onWellTypeChanged(int index)
// 历史数据
pNewWellData->setPressurePoints(pOldWellData->getPressurePoints());
pNewWellData->setFlowPoints(pOldWellData->getFlowPoints());
pNewWellData->setWellCategory(pOldWellData->getWellCategory());
pNewWellData->setFlowPoints(
PHASE_Oil,
pOldWellData->getFlowPoints(PHASE_Oil));
pNewWellData->setFlowPoints(
PHASE_Gas,
pOldWellData->getFlowPoints(PHASE_Gas));
pNewWellData->setFlowPoints(
PHASE_Water,
pOldWellData->getFlowPoints(PHASE_Water));
pNewWellData->setIndexF(pOldWellData->getIndexF());
// 结果数据

Loading…
Cancel
Save