From e81c9e0b4190b3e2cffa4256b96c293310ba802f Mon Sep 17 00:00:00 2001 From: lh <2334563547@qq.com> Date: Fri, 12 Jun 2026 14:12:49 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84PVT=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E9=80=BB=E8=BE=91=EF=BC=8C=E6=8C=89=E7=9B=B8?= =?UTF-8?q?=E6=80=81=E8=8E=B7=E5=8F=96=E5=8F=82=E6=95=B0=E5=B9=B6=E7=AE=80?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. nmDataReservoir新增Gas/Water独立字段(Bg/Miug/Bw/Miuw),消除复用Bo/Miuo的语义混淆 2. nmDataReservoir成员变量按相态分组排列(油/气/水),构造/拷贝/序列化/getter-setter顺序同步 3. 重构initPvtParaFromSubFit:提取tryFetchPhasePvtCurves辅助函数,234行→~80行 4. 重构createReservoir:拆分为readPvtSingleValues/populateReservoirByPhase/createDefaultLayer,206行→~50行 5. solver task新增fillPvtInputByModel,ConstPvt从reservoir单值扩展为200元素数组 6. Ct/Cf统一获取,不再按ConstPvt/VariablePvt互斥 7. 移除油水两相多余的PVT.Sw传递,与PEBI示例对齐 --- Include/nmNum/nmData/nmDataReservoir.h | 74 +- .../nmCalculationDllPebiSolverTask.cpp | 161 +++-- Src/nmNum/nmData/nmDataAnalyzeManager.cpp | 654 +++++++----------- Src/nmNum/nmData/nmDataReservoir.cpp | 243 +++++-- 4 files changed, 576 insertions(+), 556 deletions(-) diff --git a/Include/nmNum/nmData/nmDataReservoir.h b/Include/nmNum/nmData/nmDataReservoir.h index d03b703..1c14245 100644 --- a/Include/nmNum/nmData/nmDataReservoir.h +++ b/Include/nmNum/nmData/nmDataReservoir.h @@ -43,16 +43,10 @@ public: virtual QIcon getIcon(bool expanded) const; public: - // 属性的 set 和 get 方法 + // 基础属性 void setInitialPressure(const nmDataAttribute& attr); nmDataAttribute& getInitialPressure(); - void setReservoirType(const nmDataAttribute& attr); - nmDataAttribute& getReservoirType(); - - void setBo(const nmDataAttribute& attr); - nmDataAttribute& getBo(); - void setPermeability(const nmDataAttribute& attr); nmDataAttribute& getPermeability(); @@ -62,27 +56,45 @@ public: void setPorosity(const nmDataAttribute& attr); nmDataAttribute& getPorosity(); - void setCt(const nmDataAttribute& attr); - nmDataAttribute& getCt(); - void setKxKy(const nmDataAttribute& attr); nmDataAttribute& getKxKy(); - void setCf(const nmDataAttribute& attr); - nmDataAttribute& getCf(); + // 油相PVT单值参数 + void setBo(const nmDataAttribute& attr); + nmDataAttribute& getBo(); void setMiuo(const nmDataAttribute& attr); nmDataAttribute& getMiuo(); - void setTempGasRe(double temp); - double getTempGasRe() const; + // 气相PVT单值参数 + void setBg(const nmDataAttribute& attr); + nmDataAttribute& getBg(); - void setPhaseType(NM_PHASE_TYPE phaseType); - NM_PHASE_TYPE getPhaseType() const; + void setMiug(const nmDataAttribute& attr); + nmDataAttribute& getMiug(); + + // 水相PVT单值参数 + void setBw(const nmDataAttribute& attr); + nmDataAttribute& getBw(); + + void setMiuw(const nmDataAttribute& attr); + nmDataAttribute& getMiuw(); + + // 压缩系数 + void setCt(const nmDataAttribute& attr); + nmDataAttribute& getCt(); + + void setCf(const nmDataAttribute& attr); + nmDataAttribute& getCf(); + + // 储层类型与传导率 + void setReservoirType(const nmDataAttribute& attr); + nmDataAttribute& getReservoirType(); void setTransmissibility(const nmDataAttribute& attr); nmDataAttribute& getTransmissibility(); + // 初始饱和度 void setSoi(const nmDataAttribute& attr); nmDataAttribute& getSoi(); @@ -92,28 +104,48 @@ public: void setSwi(const nmDataAttribute& attr); nmDataAttribute& getSwi(); + // 气藏温度与相态 + void setTempGasRe(double temp); + double getTempGasRe() const; + + void setPhaseType(NM_PHASE_TYPE phaseType); + NM_PHASE_TYPE getPhaseType() const; + void resetToDefaults(); // 重置所有参数为构造函数默认值 protected: nmDataAttribute m_initialPressure; // 初始地层压力 nmDataAttribute m_permeability; // 渗透率 nmDataAttribute m_thickness; // 储层厚度 - nmDataAttribute m_Miuo; // 流体粘度 (pvt参数中有) - nmDataAttribute m_Bo; // 体积系数 (pvt参数中有) nmDataAttribute m_porosity; // 孔隙度 - nmDataAttribute m_Ct; // 综合压缩系数 nmDataAttribute m_kxKy; // 各项性系数 (求解器中没有用到) + + // 油相PVT单值 + nmDataAttribute m_Bo; // 油体积系数 + nmDataAttribute m_Miuo; // 油相粘度 + + // 气相PVT单值 + nmDataAttribute m_Bg; // 气体积系数 + nmDataAttribute m_Miug; // 气相粘度 + + // 水相PVT单值 + nmDataAttribute m_Bw; // 水体积系数 + nmDataAttribute m_Miuw; // 水相粘度 + + // 压缩系数 + nmDataAttribute m_Ct; // 综合压缩系数 nmDataAttribute m_Cf; // 岩石压缩系数 nmDataAttribute m_reservoirType; // 储层类型 (求解器中没有用到) nmDataAttribute m_transmissibility; // 传导率 (求解器中没有用到) + // 初始饱和度 nmDataAttribute m_Soi; // 初始含油饱和度 nmDataAttribute m_Sgi; // 初始含气饱和度 nmDataAttribute m_Swi; // 初始含水饱和度 - double m_dTempGasRe; //气藏温度 (求解器中没有用到) - NM_PHASE_TYPE m_ePhaseType; //多相流类型 + double m_dTempGasRe; // 气藏温度 (求解器中没有用到) + NM_PHASE_TYPE m_ePhaseType; // 多相流类型 static nmDataReservoir* s_instance; }; diff --git a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp index a375443..265193d 100644 --- a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp +++ b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp @@ -77,6 +77,97 @@ bool isValidSemiLogPoint(const Point& pt) && isReasonableLogLogValue(pt.pointData[0]); } +/// @brief 将常数PVT单值扩展为200元素数组(PEBI求解器要求数组输入) +/// @param dValue 常数PVT值 +/// @param nSize 数组大小,默认200 +/// @return 包含nSize个dValue元素的dVec1数组 +dVec1 expandConstPvt(double dValue, int nSize = 200) +{ + return dVec1(nSize, dValue); +} + +/// @brief 根据求解器模型类型填充PVT输入数据 +/// 常数PVT模型从 reservoir 读单值并扩展为200元素数组 +/// 变化PVT模型从 pebiPvtPara 读曲线数组 +/// @param input PEBI求解器输入结构 +/// @param eModelType 求解器模型类型 +/// @param pPvt PEBI PVT参数对象(变化PVT时提供曲线数组) +/// @param pRes 油藏数据对象(常数PVT时提供单值) +void fillPvtInputByModel(HX_NWTM_MODEL_INPUT& input, + NM_SOLVER_MODEL_TYPE eModelType, + nmDataPvtParaForPebi* pPvt, + nmDataReservoir* pRes) +{ + // 压力横坐标始终从 pebiPvtPara 读取 + if(pPvt != nullptr) { + assignPvtVectorIfNotEmpty(input.PVT.p, pPvt->getPressure()); + } + + switch(eModelType) { + case SMT_Oil_ConstPvt: + // 油相常数PVT:单值扩展为200元素数组 + if(pRes != nullptr) { + input.PVT.Bo = expandConstPvt(pRes->getBo().getValue().toDouble()); + input.PVT.miuo = expandConstPvt(pRes->getMiuo().getValue().toDouble()); + } + break; + + case SMT_Oil_VariablePvt: + // 油相变化PVT:从 pebiPvtPara 读曲线数组 + if(pPvt != nullptr) { + assignPvtVectorIfNotEmpty(input.PVT.Bo, pPvt->getBo()); + assignPvtVectorIfNotEmpty(input.PVT.Co, pPvt->getCo()); + assignPvtVectorIfNotEmpty(input.PVT.miuo, pPvt->getMiuo()); + } + break; + + case SMT_Water_ConstPvt: + // 水相常数PVT:单值扩展为200元素数组 + if(pRes != nullptr) { + input.PVT.Bw = expandConstPvt(pRes->getBw().getValue().toDouble()); + input.PVT.miuw = expandConstPvt(pRes->getMiuw().getValue().toDouble()); + } + break; + + case SMT_Water_VariablePvt: + // 水相变化PVT:从 pebiPvtPara 读曲线数组 + if(pPvt != nullptr) { + assignPvtVectorIfNotEmpty(input.PVT.Bw, pPvt->getBw()); + assignPvtVectorIfNotEmpty(input.PVT.Cw, pPvt->getCw()); + assignPvtVectorIfNotEmpty(input.PVT.miuw, pPvt->getMiuw()); + } + break; + + case SMT_Gas_VariablePvt: + case SMT_Gas_PseudoPressure: + // 气相变化PVT/拟压力:从 pebiPvtPara 读曲线数组 + if(pPvt != nullptr) { + assignPvtVectorIfNotEmpty(input.PVT.Bg, pPvt->getBg()); + assignPvtVectorIfNotEmpty(input.PVT.Cg, pPvt->getCg()); + assignPvtVectorIfNotEmpty(input.PVT.miug, pPvt->getMiug()); + } + break; + + case SMT_Oil_Water_TwoPhase: + // 油水两相:从 pebiPvtPara 读油+水曲线数组 + 相渗数据 + if(pPvt != nullptr) { + assignPvtVectorIfNotEmpty(input.PVT.Bo, pPvt->getBo()); + assignPvtVectorIfNotEmpty(input.PVT.miuo, pPvt->getMiuo()); + assignPvtVectorIfNotEmpty(input.PVT.Bw, pPvt->getBw()); + assignPvtVectorIfNotEmpty(input.PVT.miuw, pPvt->getMiuw()); + + // 相渗与饱和度数据(PEBI油水两相不需要PVT.Sw数组,初始含水饱和度通过Base.Swi传递) + assignPvtVectorIfNotEmpty(input.PVT.So, pPvt->getSo()); + assignPvtVectorIfNotEmpty(input.PVT.Kro, pPvt->getKro()); + assignPvtVectorIfNotEmpty(input.PVT.Krw, pPvt->getKrw()); + } + break; + + default: + break; + } +} + } @@ -110,7 +201,6 @@ bool nmCalculationDllPebiSolverTask::execute() bool nmCalculationDllPebiSolverTask::execPebiMode() { - //emit sigResSolverProgressUpdated(1); nmDataAnalyzeManager* pDataInstance = nmDataAnalyzeManager::getCurrentInstance(); nmCalculationPebiGrid* pGridInstance = nmCalculationPebiGrid::getInstance(); if(pDataInstance == nullptr || pGridInstance == nullptr) { @@ -156,8 +246,6 @@ bool nmCalculationDllPebiSolverTask::execPebiMode() p0.Rate.qw.resize(vecWellsOrder.size()); p0.Rate.qg.resize(vecWellsOrder.size()); - //emit sigResSolverProgressUpdated(2); - // 遍历井数据 for(int i = 0; i < vecWellsOrder.size(); ++i) { NM_WELL_MODEL wellType = vecWellsOrder[i].first; // 获取井的类型 @@ -342,56 +430,10 @@ bool nmCalculationDllPebiSolverTask::execPebiMode() } } - //emit sigResSolverProgressUpdated(3); - - // PVT数据 + // PVT数据:根据求解器模型类型填充PVT输入数据 nmDataPvtParaForPebi* pebiPvtPara = pDataInstance->getPebiPvtPara(); + fillPvtInputByModel(p0, static_cast(p0.T), pebiPvtPara, pReservoirData); - if(pebiPvtPara != nullptr) { - // p0构造时已有默认PVT数据,这里只用读到的参数覆盖 - // 压力与饱和压力 - assignPvtVectorIfNotEmpty(p0.PVT.p, pebiPvtPara->getPressure()); - if(pebiPvtPara->getPb().getValue().isValid()) { - p0.PVT.pb = pebiPvtPara->getPb().getValue().toDouble(); - } - - // 读取PVT数据 - 油相参数 - assignPvtVectorIfNotEmpty(p0.PVT.Rso, pebiPvtPara->getRso()); - assignPvtVectorIfNotEmpty(p0.PVT.Bo, pebiPvtPara->getBo()); - assignPvtVectorIfNotEmpty(p0.PVT.Co, pebiPvtPara->getCo()); - assignPvtVectorIfNotEmpty(p0.PVT.miuo, pebiPvtPara->getMiuo()); - assignPvtVectorIfNotEmpty(p0.PVT.rouo, pebiPvtPara->getRouo()); - - // 读取PVT数据 - 气相参数 - assignPvtVectorIfNotEmpty(p0.PVT.Rv, pebiPvtPara->getRv()); - assignPvtVectorIfNotEmpty(p0.PVT.Bg, pebiPvtPara->getBg()); - assignPvtVectorIfNotEmpty(p0.PVT.Cg, pebiPvtPara->getCg()); - assignPvtVectorIfNotEmpty(p0.PVT.miug, pebiPvtPara->getMiug()); - assignPvtVectorIfNotEmpty(p0.PVT.roug, pebiPvtPara->getRoug()); - assignPvtVectorIfNotEmpty(p0.PVT.Z, pebiPvtPara->getZ()); - - // 读取PVT数据 - 水相参数 - assignPvtVectorIfNotEmpty(p0.PVT.Rsw, pebiPvtPara->getRsw()); - assignPvtVectorIfNotEmpty(p0.PVT.Bw, pebiPvtPara->getBw()); - assignPvtVectorIfNotEmpty(p0.PVT.Cw, pebiPvtPara->getCw()); - assignPvtVectorIfNotEmpty(p0.PVT.miuw, pebiPvtPara->getMiuw()); - assignPvtVectorIfNotEmpty(p0.PVT.rouw, pebiPvtPara->getRouw()); - - // 读取PVT数据 - 其他参数 - assignPvtVectorIfNotEmpty(p0.PVT.V, pebiPvtPara->getV()); - assignPvtVectorIfNotEmpty(p0.PVT.k_kinitial, pebiPvtPara->getKKinitial()); - assignPvtVectorIfNotEmpty(p0.PVT.Cf_Cfinitial, pebiPvtPara->getCfCfinitial()); - - // 读取PVT数据 - 饱和度与相对渗透率 - assignPvtVectorIfNotEmpty(p0.PVT.So, pebiPvtPara->getSo()); - assignPvtVectorIfNotEmpty(p0.PVT.Kro, pebiPvtPara->getKro()); - assignPvtVectorIfNotEmpty(p0.PVT.Sg, pebiPvtPara->getSg()); - assignPvtVectorIfNotEmpty(p0.PVT.Krg, pebiPvtPara->getKrg()); - assignPvtVectorIfNotEmpty(p0.PVT.Sw, pebiPvtPara->getSw()); - assignPvtVectorIfNotEmpty(p0.PVT.Krw, pebiPvtPara->getKrw()); - } - - //emit sigResSolverProgressUpdated(4); // 基础数据(储层参数?) if(pReservoirData != nullptr) { @@ -416,21 +458,6 @@ bool nmCalculationDllPebiSolverTask::execPebiMode() p0.Base.dt_Max = pTimeStepSetting->getMaxDeltaTAttribute().getValue().toDouble(); } - //emit sigResSolverProgressUpdated(5); - - // 模拟进度条更新 - - // 在调用 HX_NWTM_MODEL 前启动一个线程或 QFutureWatcher 模拟进度 - //QFuture future = QtConcurrent::run([this]() { - // for(int i = 6; i <= 95; ++i) { - // QThread::msleep(500); // 模拟耗时 - // if (!isRunning()){ - // return; - // } - // emit sigResSolverProgressUpdated(i); - // } - //}); - try { nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::getCurrentInstance(); QString licensePath = pDataManager->getLicensePath(); @@ -474,8 +501,6 @@ bool nmCalculationDllPebiSolverTask::execPebiMode() return false; } - // 求解完成后停止定时器并直接设置进度到% - //emit sigResSolverProgressUpdated(97); // 保存计算结果 bool success = this->savePebiModeResult(p1); diff --git a/Src/nmNum/nmData/nmDataAnalyzeManager.cpp b/Src/nmNum/nmData/nmDataAnalyzeManager.cpp index ea01bfc..e0d94de 100644 --- a/Src/nmNum/nmData/nmDataAnalyzeManager.cpp +++ b/Src/nmNum/nmData/nmDataAnalyzeManager.cpp @@ -192,7 +192,6 @@ void applyDiffusionKkToPebiPvt(nmDataPvtParaForPebi* pPvtPara, const VVecDouble& extractDiffusionColumn(vvecKK, 2, vecKr2); // 油水:第一列为Sw,So按1-Sw生成,后续列为Kro/Krw - pPvtPara->setSw(vecS); // PEBI默认相渗以So为横坐标,Diffusion表按Sw递增保存,这里整体转为So递增方向 pPvtPara->setSo(reversedVector(complementSaturation(vecS))); if(!vecKr1.isEmpty()) { @@ -203,6 +202,169 @@ void applyDiffusionKkToPebiPvt(nmDataPvtParaForPebi* pPvtPara, const VVecDouble& } } +/// @brief 尝试获取某相态的3条PVT曲线(B/C/Miu),全部成功则写入pebiPvtPara +/// @param pCtx 上下文提供者,用于读取PVT结果页 +/// @param pSubWnd 当前流动段分析窗口 +/// @param pftContext getPvtRstOf需要的相态参数 +/// @param sBName 体积系数参数名("Bo"/"Bg"/"Bw") +/// @param sCName 压缩系数参数名("Co"/"Cg"/"Cw") +/// @param sMiuName 粘度参数名("Miuo"/"Miug"/"Miuw") +/// @param pPvt 输出的PEBI PVT参数对象 +/// @param vecPressure 压力横坐标(首次成功时写入,后续复用) +/// @return 三条曲线全部获取成功返回true,否则返回false且不写入pPvt +bool tryFetchPhasePvtCurves( + nmDataAnalyzeContextProvider* pCtx, + iSubWndFitting* pSubWnd, + PvtFluidType pftContext, + const QString& sBName, + const QString& sCName, + const QString& sMiuName, + nmDataPvtParaForPebi* pPvt, + QVector& vecPressure) +{ + // 分别获取体积系数、压缩系数、粘度三条曲线 + QVector vecB, vecC, vecMiu, vecX; + bool bB = pCtx->getPvtRstOf(pSubWnd, pftContext, sBName, vecX, vecB); + bool bC = pCtx->getPvtRstOf(pSubWnd, pftContext, sCName, vecX, vecC); + bool bMiu = pCtx->getPvtRstOf(pSubWnd, pftContext, sMiuName, vecX, vecMiu); + + // 任一曲线缺失则视为该相态PVT数据不完整,不写入 + if(!(bB && bC && bMiu)) { + return false; + } + + // 首次成功时保存压力横坐标 + if(vecPressure.isEmpty() && !vecX.isEmpty()) { + vecPressure = vecX; + } + + // 按相态名称写入对应的setter(油气水各自独立字段) + if(sBName == "Bo") pPvt->setBo(vecB); + else if(sBName == "Bg") pPvt->setBg(vecB); + else if(sBName == "Bw") pPvt->setBw(vecB); + + if(sCName == "Co") pPvt->setCo(vecC); + else if(sCName == "Cg") pPvt->setCg(vecC); + else if(sCName == "Cw") pPvt->setCw(vecC); + + if(sMiuName == "Miuo") pPvt->setMiuo(vecMiu); + else if(sMiuName == "Miug") pPvt->setMiug(vecMiu); + else if(sMiuName == "Miuw") pPvt->setMiuw(vecMiu); + + return true; +} + +/// @brief 设置油藏属性的简化辅助,消除 tempAttr=getX(); tempAttr.setValue(); setX(tempAttr) 三行重复模式 +/// @param attr 油藏属性引用 +/// @param dValue 属性值 +void setReservoirAttr(nmDataAttribute& attr, double dValue) +{ + attr.setValue(dValue); +} + +/// @brief 设置油藏属性的简化辅助(QString版本) +void setReservoirAttr(nmDataAttribute& attr, const QString& sValue) +{ + attr.setValue(sValue); +} + +/// @brief 从界面读取PVT单值参数 +/// @param pCtx 上下文提供者 +/// @param pSubWnd 当前流动段分析窗口 +/// @param eType 相态类型 +/// @return 参数名到值的映射 +QMap readPvtSingleValues( + nmDataAnalyzeContextProvider* pCtx, + iSubWndFitting* pSubWnd, + PvtFluidType eType) +{ + // 按相态构建需要读取的参数列表 + QStringList listParas; + switch(eType) { + case WFT_Oil: listParas << "Bo" << "Miuo"; break; + case WFT_Gas: listParas << "Bg" << "Miug"; break; + case WFT_Water: listParas << "Bw" << "Miuw"; break; + case WFT_Oil_Water: listParas << "Bo" << "Miuo" << "Bw" << "Miuw"; break; + default: break; + } + + // 综合压缩系数Ct,不区分模式统一读取 + listParas << "Ct"; + + // 调用接口读取参数值 + QMap mapPvtValues; + if(!listParas.isEmpty()) { + pCtx->getPvtParaValues(pSubWnd, listParas, mapPvtValues); + } + return mapPvtValues; +} + +/// @brief 按相态填充油藏PVT字段和压缩系数 +/// @param pRes 油藏数据对象 +/// @param eType 相态类型 +/// @param mapPvtValues 从界面读取的PVT单值参数 +/// @param dCf 岩石压缩系数(来自分层数据) +void populateReservoirByPhase( + nmDataReservoir* pRes, + PvtFluidType eType, + const QMap& mapPvtValues, + double dCf) +{ + // 按相态设置多相流类型和对应的B/Miu字段 + switch(eType) { + case WFT_Oil: + pRes->setPhaseType(PHASE_Oil); + setReservoirAttr(pRes->getBo(), mapPvtValues.value("Bo", 1.5)); + setReservoirAttr(pRes->getMiuo(), mapPvtValues.value("Miuo", 1.0)); + break; + case WFT_Gas: + pRes->setPhaseType(PHASE_Gas); + setReservoirAttr(pRes->getBg(), mapPvtValues.value("Bg", 1.0)); + setReservoirAttr(pRes->getMiug(), mapPvtValues.value("Miug", 1.0)); + break; + case WFT_Water: + pRes->setPhaseType(PHASE_Water); + setReservoirAttr(pRes->getBw(), mapPvtValues.value("Bw", 1.0)); + setReservoirAttr(pRes->getMiuw(), mapPvtValues.value("Miuw", 1.0)); + break; + case WFT_Oil_Water: + pRes->setPhaseType(PHASE_Oil_Water); + setReservoirAttr(pRes->getBo(), mapPvtValues.value("Bo", 1.5)); + setReservoirAttr(pRes->getMiuo(), mapPvtValues.value("Miuo", 1.0)); + setReservoirAttr(pRes->getBw(), mapPvtValues.value("Bw", 1.0)); + setReservoirAttr(pRes->getMiuw(), mapPvtValues.value("Miuw", 1.0)); + break; + default: + pRes->setPhaseType(PHASE_UNKNOWN); + break; + } + + // 压缩系数:Ct来自PVT参数界面,Cf来自分层数据,不区分模式统一设置 + setReservoirAttr(pRes->getCt(), mapPvtValues.value("Ct", 0.1)); + setReservoirAttr(pRes->getCf(), dCf); +} + +/// @brief 创建默认分层 +/// @param dThickness 储层厚度 +/// @param vecLayers 分层数据列表(输出) +void createDefaultLayer(double dThickness, QVector& vecLayers) +{ + // 清空现有分层数据 + qDeleteAll(vecLayers); + vecLayers.clear(); + + // 创建一个默认分层 + nmDataLayer* pDefaultLayer = new nmDataLayer(); + pDefaultLayer->setTop(6000.0); // 默认顶深 + pDefaultLayer->setThickness(dThickness); // 使用从界面获取的厚度值 + pDefaultLayer->setBottom(6000.0 + dThickness); // 计算底深 + pDefaultLayer->setIsChecked(false); // 默认未选中 + pDefaultLayer->setColor(QColor(0, 255, 0)); // 设置默认颜色(绿色) + + // 将默认分层添加到分层列表 + vecLayers.append(pDefaultLayer); +} + } ZX_DEFINE_DYNAMIC(DataAnalyzeManager, nmDataAnalyzeManager) @@ -1090,211 +1252,54 @@ void nmDataAnalyzeManager::appendNmWellData(nmDataWellBase* pWellData) m_vWellData.append(pWellData); } +/// @brief 创建油藏数据对象,从界面读取PVT单值和分层数据,构建reservoir对象 void nmDataAnalyzeManager::createReservoir() { - // 根据当前Fitting窗口来获取对应的井相关数据 + // 1. 获取上下文 iSubWndFitting* pSubWndFitting = nmDataAnalyzeManager::getCurrentFitting(); - nmDataAnalyzeContextProvider* pContextProvider = nmDataAnalyzeContext::provider(); + nmDataAnalyzeContextProvider* pCtx = nmDataAnalyzeContext::provider(); Q_ASSERT(nullptr != pSubWndFitting); - Q_ASSERT(nullptr != pContextProvider); + Q_ASSERT(nullptr != pCtx); - // 定义获取的分层数据 - VVecVariant vvecLayerData; - // 定义返回结果的 QMap - QMap mapParaValues; - // 相态类型 PvtFluidType eType = WFT_Null; + pCtx->getBasicPft(pSubWndFitting, eType); - // initPvtParaFromSubFit先根据PVT数据确定求解器类型,这里按PEBI算例选择需要覆盖的Base字段 - NM_SOLVER_MODEL_TYPE eSolverModelType = getSolverModelType(); - bool bNeedCti = false; - bool bNeedCf = false; - - switch(eSolverModelType) { - case SMT_Oil_ConstPvt: - case SMT_Water_ConstPvt: - bNeedCti = true; - break; - case SMT_Oil_VariablePvt: - case SMT_Water_VariablePvt: - case SMT_Gas_VariablePvt: - case SMT_Oil_Water_TwoPhase: - bNeedCf = true; - break; - default: - break; - } - - if(nullptr != pSubWndFitting && nullptr != pContextProvider) { - - // 读取界面选择的PVT相态类型 - pContextProvider->getBasicPft(pSubWndFitting, eType); - - //QString sMainPft =pSubWndFitting->getBasicMainPft(); - //QString sPftDesc = pSubWndFitting->getBasicPftDesc(); - // 只读取当前相态存在的PVT页,避免PVT工具输出PhaseGas/PhaseWater缺失日志 - QStringList listParas; - // 储层基础数据这里只需要体积系数和粘度;不属于当前相态的参数继续走默认值 - switch(eType) { - case WFT_Oil: - listParas << "Bo" << "Miuo"; - break; - case WFT_Gas: - listParas << "Bg" << "Miug"; - break; - case WFT_Water: - listParas << "Bw" << "Miuw"; - break; - case WFT_Oil_Water: - listParas << "Bo" << "Miuo" << "Bw" << "Miuw"; - break; - default: - break; - } - - //油、水单相常数pvt需要Ct - if(bNeedCti) { - listParas << "Ct"; - } - if(!listParas.isEmpty()) { - pContextProvider->getPvtParaValues(pSubWndFitting, listParas, mapParaValues); - } - - // 读取分层数据 - pContextProvider->getBasicDataLayers(pSubWndFitting, vvecLayerData); - } + // 2. 读取PVT单值参数 + QMap mapPvtValues = readPvtSingleValues(pCtx, pSubWndFitting, eType); - // 获取油体积系数和油相粘度 - double dBo = mapParaValues.value("Bo", 1.5); // 如果键不存在,返回默认值 1.5 - double dMiuo = mapParaValues.value("Miuo", 1); // 如果键不存在,返回默认值 1 - - // 获取气体积系数和气相粘度 - double dBg = mapParaValues.value("Bg", 1); // 如果键不存在,返回默认值 1.5 - double dMiug = mapParaValues.value("Miug", 1); // 如果键不存在,返回默认值 1 - - // 获取水体积系数和水相粘度 - double dBw = mapParaValues.value("Bw", 1); - double dMiuw = mapParaValues.value("Miuw", 1); - - // 获取综合压缩系数 - double dCt = mapParaValues.value("Ct", 0.1); - - // 获取初始油、气、水饱和度---------王老师那的是临时数据,没法获取 - //double dSo = mapParaValues.value("Ko", 1); - //double dSg = mapParaValues.value("Sg", 0); - //double dSw = mapParaValues.value("Sw", 0); + // 3. 读取分层数据,提取储层基础参数 + VVecVariant vvecLayerData; + pCtx->getBasicDataLayers(pSubWndFitting, vvecLayerData); - // 检查 vvecLayerData 是否有效,有效重新赋值,无效设置默认值 double dThickness = 10; double dPorosity = 0.5; - double dCf = 1.00; // 岩石压缩系数 + double dCf = 1.0; double dInitialPre = 30.0; - if(!vvecLayerData.isEmpty() && vvecLayerData[0].size() >= 5) { - dThickness = vvecLayerData[0][1].toDouble(); - dPorosity = vvecLayerData[0][2].toDouble(); - dCf = vvecLayerData[0][3].toDouble(); - dInitialPre = vvecLayerData[0][4].toDouble(); + dThickness = vvecLayerData[0][1].toDouble(); + dPorosity = vvecLayerData[0][2].toDouble(); + dCf = vvecLayerData[0][3].toDouble(); + dInitialPre = vvecLayerData[0][4].toDouble(); } - // 判断是否已有油藏参数数据 + // 4. 构建油藏对象 if(m_reservoirData != nullptr) { delete m_reservoirData; m_reservoirData = nullptr; } - m_reservoirData = new nmDataReservoir; - nmDataAttribute tempAttr; - - // 将界面相态转换为内部储层相态,后续再映射为求解器T - if(eType == WFT_Oil) { - m_reservoirData->setPhaseType(PHASE_Oil); - tempAttr = m_reservoirData->getBo();// 油体积系数 - tempAttr.setValue(dBo); - m_reservoirData->setBo(tempAttr); - - tempAttr = m_reservoirData->getMiuo();// 油相黏度 - tempAttr.setValue(dMiuo); - m_reservoirData->setMiuo(tempAttr); - - } else if(eType == WFT_Gas) { - m_reservoirData->setPhaseType(PHASE_Gas); - // TODO:这里先使用用一个变量,后续根据需求再进行分类 - tempAttr = m_reservoirData->getBo();// 气体积系数 - tempAttr.setValue(dBg); - m_reservoirData->setBo(tempAttr); - - tempAttr = m_reservoirData->getMiuo();// 气相黏度 - tempAttr.setValue(dMiug); - m_reservoirData->setMiuo(tempAttr); - - } else if(eType == WFT_Water) { - m_reservoirData->setPhaseType(PHASE_Water); - tempAttr = m_reservoirData->getBo();// 水体积系数 - tempAttr.setValue(dBw); - m_reservoirData->setBo(tempAttr); - - tempAttr = m_reservoirData->getMiuo();// 水相黏度 - tempAttr.setValue(dMiuw); - m_reservoirData->setMiuo(tempAttr); - } else if(eType == WFT_Oil_Water) { - m_reservoirData->setPhaseType(PHASE_Oil_Water); - tempAttr = m_reservoirData->getBo();// 油体积系数 - tempAttr.setValue(dBo); - m_reservoirData->setBo(tempAttr); - - tempAttr = m_reservoirData->getMiuo();// 油相黏度 - tempAttr.setValue(dMiuo); - m_reservoirData->setMiuo(tempAttr); - } else { - m_reservoirData->setPhaseType(PHASE_UNKNOWN); - } - - tempAttr = m_reservoirData->getInitialPressure();//初始压力 - tempAttr.setValue(dInitialPre); - m_reservoirData->setInitialPressure(tempAttr); - - tempAttr = m_reservoirData->getReservoirType(); - tempAttr.setValue("Homogeneous"); - m_reservoirData->setReservoirType(tempAttr); - - tempAttr = m_reservoirData->getThickness();// 储层厚度 - tempAttr.setValue(dThickness); - m_reservoirData->setThickness(tempAttr); - - tempAttr = m_reservoirData->getCt(); // 综合压缩系数 - if(bNeedCti) { - tempAttr.setValue(dCt); - } - m_reservoirData->setCt(tempAttr); - - tempAttr = m_reservoirData->getPorosity();// 孔隙度 - tempAttr.setValue(dPorosity); - m_reservoirData->setPorosity(tempAttr); - - tempAttr = m_reservoirData->getCf();// 岩石压缩系数 - // 变化PVT、气单相和油水两相需要Cf,值来自基础分层数据 - if(bNeedCf) { - tempAttr.setValue(dCf); - } - m_reservoirData->setCf(tempAttr); - - // 清空现有分层数据 - qDeleteAll(m_vecLayers); - m_vecLayers.clear(); - // 创建一个默认分层 - nmDataLayer* defaultLayer = new nmDataLayer(); + // 按相态填充PVT字段和压缩系数 + populateReservoirByPhase(m_reservoirData, eType, mapPvtValues, dCf); - // 设置默认分层参数 - defaultLayer->setTop(6000.0); // 默认顶深 - defaultLayer->setThickness(dThickness); // 使用从框架获取的厚度值 - defaultLayer->setBottom(6000.0 + dThickness); // 计算底深 - defaultLayer->setIsChecked(false); // 默认未选中 - defaultLayer->setColor(QColor(0, 255, 0)); // 设置默认颜色(绿色) + // 设置基础属性 + setReservoirAttr(m_reservoirData->getInitialPressure(), dInitialPre); + setReservoirAttr(m_reservoirData->getReservoirType(), QString("Homogeneous")); + setReservoirAttr(m_reservoirData->getThickness(), dThickness); + setReservoirAttr(m_reservoirData->getPorosity(), dPorosity); - // 将默认分层添加到分层列表 - m_vecLayers.append(defaultLayer); + // 5. 创建默认分层 + createDefaultLayer(dThickness, m_vecLayers); } nmDataAxis* nmDataAnalyzeManager::getAxisData() const @@ -1628,239 +1633,90 @@ void nmDataAnalyzeManager::updateAutomaticFittingData(const nmDataAutomaticFitti *m_pAutomaticFittingData = newData; // 调用赋值运算符 } +/// @brief 从PVT结果页读取曲线数组,确定求解器模型类型 +/// 按相态获取PVT数组参数,获取不到则回退到常数PVT模型(Gas除外弹警告) void nmDataAnalyzeManager::initPvtParaFromSubFit() { - // 根据当前Fitting窗口来获取对应的井相关数据 + // 1. 获取上下文 iSubWndFitting* pSubWndFitting = nmDataAnalyzeManager::getCurrentFitting(); - nmDataAnalyzeContextProvider* pContextProvider = nmDataAnalyzeContext::provider(); + nmDataAnalyzeContextProvider* pCtx = nmDataAnalyzeContext::provider(); Q_ASSERT(nullptr != pSubWndFitting); - Q_ASSERT(nullptr != pContextProvider); + Q_ASSERT(nullptr != pCtx); - if(nullptr != pSubWndFitting && nullptr != pContextProvider) { - PvtFluidType eType = WFT_Null; - pContextProvider->getBasicPft(pSubWndFitting, eType); - - //QVector vecPressure; // 压力, MPa - QVector vecBo; // 油体积系数, m^3/m^3 - QVector vecCo; // 油压缩系数, 1/MPa - QVector vecMiuo; // 油粘度, mPa·s - QVector vecBg; // 气体积系数, m^3/m^3 - QVector vecCg; // 气压缩系数, 1/MPa - QVector vecMiug; // 气粘度, mPa·s - QVector vecBw; // 水体积系数, m^3/m^3 - QVector vecCw; // 水压缩系数, 1/MPa - QVector vecMiuw; // 水粘度, mPa·s - - VecDouble vecX; - - // 判断是否已有PebiPvt参数数据 - if(m_pebiPvtPara != nullptr) { - delete m_pebiPvtPara; - m_pebiPvtPara = nullptr; - } + if(nullptr == pSubWndFitting || nullptr == pCtx) { + return; + } - m_pebiPvtPara = new nmDataPvtParaForPebi; - setSolverModelType(SMT_Oil_ConstPvt); - - bool bFetchedBo = false; - bool bFetchedCo = false; - bool bFetchedMiuo = false; - bool bFetchedBg = false; - bool bFetchedCg = false; - bool bFetchedMiug = false; - bool bFetchedBw = false; - bool bFetchedCw = false; - bool bFetchedMiuw = false; - - // PVT结果曲线直接按当前相态分支读取,任一必要曲线缺失则保留PEBI默认数据 - switch(eType) { - case WFT_Oil: - // 单油相需要体积系数、压缩系数和粘度全部可获取 - bFetchedBo = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Oil, "Bo", vecX, vecBo); - bFetchedCo = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Oil, "Co", vecX, vecCo); - bFetchedMiuo = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Oil, "Miuo", vecX, vecMiuo); - if(!(bFetchedBo && bFetchedCo && bFetchedMiuo)) { - return; - } + PvtFluidType eType = WFT_Null; + pCtx->getBasicPft(pSubWndFitting, eType); - // 油体积系数 - m_pebiPvtPara->setBo(vecBo); + // 2. 清理旧的PVT参数对象,新建空对象 + if(m_pebiPvtPara != nullptr) { + delete m_pebiPvtPara; + m_pebiPvtPara = nullptr; + } + m_pebiPvtPara = new nmDataPvtParaForPebi; - // 油压缩系数 - m_pebiPvtPara->setCo(vecCo); + // 压力横坐标,首次成功读取时赋值 + QVector vecPressure; - // 油粘度 - m_pebiPvtPara->setMiuo(vecMiuo); - setPebiPressureIfEmpty(m_pebiPvtPara, vecX); + // 3. 按相态分支获取PVT曲线并确定求解器类型 + switch(eType) { + case WFT_Oil: + // 油相:获取到变量PVT曲线则升级模型,否则保持常数PVT + if(tryFetchPhasePvtCurves(pCtx, pSubWndFitting, WFT_Oil, + "Bo", "Co", "Miuo", m_pebiPvtPara, vecPressure)) { setSolverModelType(SMT_Oil_VariablePvt); - break; - case WFT_Gas: - setSolverModelType(SMT_Gas_VariablePvt); - - // 气相缺少任一PVT曲线时提醒用户补齐参数勾选 - bFetchedBg = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Gas, "Bg", vecX, vecBg); - bFetchedCg = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Gas, "Cg", vecX, vecCg); - bFetchedMiug = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Gas, "Miug", vecX, vecMiug); - if(!(bFetchedBg && bFetchedCg && bFetchedMiug)) { - QMessageBox::warning(nullptr, tr("Warning"), tr("Please select all gas PVT parameters.")); - return; - } - - // 气体积系数 - m_pebiPvtPara->setBg(vecBg); - - // 气压缩系数 - m_pebiPvtPara->setCg(vecCg); - - // 气粘度 - m_pebiPvtPara->setMiug(vecMiug); - setPebiPressureIfEmpty(m_pebiPvtPara, vecX); - break; - case WFT_Water: - // 单水相需要体积系数、压缩系数和粘度全部可获取 - bFetchedBw = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Water, "Bw", vecX, vecBw); - bFetchedCw = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Water, "Cw", vecX, vecCw); - bFetchedMiuw = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Water, "Miuw", vecX, vecMiuw); - if(!(bFetchedBw && bFetchedCw && bFetchedMiuw)) { - setSolverModelType(SMT_Water_ConstPvt); - return; - } - - // 水体积系数 - m_pebiPvtPara->setBw(vecBw); - - // 水压缩系数 - m_pebiPvtPara->setCw(vecCw); + } else { + setSolverModelType(SMT_Oil_ConstPvt); + } + break; - // 水粘度 - m_pebiPvtPara->setMiuw(vecMiuw); - setPebiPressureIfEmpty(m_pebiPvtPara, vecX); + case WFT_Water: + // 水相:获取到变量PVT曲线则升级模型,否则保持常数PVT + if(tryFetchPhasePvtCurves(pCtx, pSubWndFitting, WFT_Water, + "Bw", "Cw", "Miuw", m_pebiPvtPara, vecPressure)) { setSolverModelType(SMT_Water_VariablePvt); - break; - case WFT_Oil_Water: { - setSolverModelType(SMT_Oil_Water_TwoPhase); - - // 油水两相需要油、水两相体积系数和粘度全部可获取 - bFetchedBo = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Oil_Water, "Bo", vecX, vecBo); - bFetchedMiuo = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Oil_Water, "Miuo", vecX, vecMiuo); - bFetchedBw = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Oil_Water, "Bw", vecX, vecBw); - bFetchedMiuw = pContextProvider->getPvtRstOf(pSubWndFitting, WellFluidType::WFT_Oil_Water, "Miuw", vecX, vecMiuw); - if(!(bFetchedBo && bFetchedMiuo && bFetchedBw && bFetchedMiuw)) { - return; - } - - // 油体积系数 - m_pebiPvtPara->setBo(vecBo); - - // 油粘度 - m_pebiPvtPara->setMiuo(vecMiuo); - - // 水体积系数 - m_pebiPvtPara->setBw(vecBw); + } else { + setSolverModelType(SMT_Water_ConstPvt); + } + break; - // 水粘度 - m_pebiPvtPara->setMiuw(vecMiuw); - setPebiPressureIfEmpty(m_pebiPvtPara, vecX); + case WFT_Gas: + // 气相:必须获取到全部PVT曲线,否则弹警告并返回 + setSolverModelType(SMT_Gas_VariablePvt); + if(!tryFetchPhasePvtCurves(pCtx, pSubWndFitting, WFT_Gas, + "Bg", "Cg", "Miug", m_pebiPvtPara, vecPressure)) { + QMessageBox::warning(nullptr, tr("Warning"), tr("Please select all gas PVT parameters.")); + return; + } + break; - // Diffusion相关数据来自Diffusion页面,只在油水两相时读取 - // DSO_KK:相渗结果,主要用于So/Kro/Sw/Krw - VVecDouble vvecDiffusionKK; - if(pContextProvider->getDiffusionRstOf(pSubWndFitting, DSO_KK, vvecDiffusionKK)) { - applyDiffusionKkToPebiPvt(m_pebiPvtPara, vvecDiffusionKK); - } - break; + case WFT_Oil_Water: { + // 油水两相:油、水PVT曲线必须全部获取,否则返回 + setSolverModelType(SMT_Oil_Water_TwoPhase); + bool bOilOk = tryFetchPhasePvtCurves(pCtx, pSubWndFitting, WFT_Oil_Water, + "Bo", "Co", "Miuo", m_pebiPvtPara, vecPressure); + bool bWaterOk = tryFetchPhasePvtCurves(pCtx, pSubWndFitting, WFT_Oil_Water, + "Bw", "Cw", "Miuw", m_pebiPvtPara, vecPressure); + if(!(bOilOk && bWaterOk)) { + return; } - default: - break; + + // Diffusion相渗数据来自Diffusion页面 + VVecDouble vvecDiffusionKK; + if(pCtx->getDiffusionRstOf(pSubWndFitting, DSO_KK, vvecDiffusionKK)) { + applyDiffusionKkToPebiPvt(m_pebiPvtPara, vvecDiffusionKK); } + break; } - //// 吸附气量,王老师界面没有,油相暂时不需要 - //m_pebiPvtPara->setV(vecV); - // - //// 渗透率比,王老师界面没有,油相暂时不需要 - //m_pebiPvtPara->setKKinitial(vecKKinitial); - - //// 岩石压缩系数比,王老师界面没有,油相暂时不需要 - //m_pebiPvtPara->setCfCfinitial(vecCfCfinitial); - - //// 相渗,单相暂时用不到 - ////QVector< QVector > vvec; - ////pSubWndFitting->getDiffusionRstOf(DiffusionSubOption::DSO_KK, vvec); - - ////QVector vecSw; - ////QVector vecKro; - ////QVector vecKrw; - - //// 遍历 vvec 中的每个子向量 - ////foreach (const QVector& innerVec , vvec) { - //// // 确保每个子向量确实有3个元素 - //// if (innerVec.size() >= 3) { - //// vecSw.append(innerVec[0]); // 第一个元素是 Sw - //// vecKro.append(innerVec[1]); // 第二个元素是 Kro - //// vecKrw.append(innerVec[2]); // 第三个元素是 Krw - //// } - ////} - - //// 油饱和度 - //m_pebiPvtPara->setSo(vecSo); - - //// 油相对渗透率 - //m_pebiPvtPara->setKro(vecKro); - - //// 气饱和度 - //m_pebiPvtPara->setSg(vecSg); - - //// 气相对渗透率 - //m_pebiPvtPara->setKrg(vecKrg); - - //// 水饱和度 - //m_pebiPvtPara->setSw(vecSw); - - //// 水相对渗透率 - //m_pebiPvtPara->setKrw(vecKrw); - - // 调用 getPvtParaValues 函数获取参数值 - //pSubWndFitting->getPvtParaValues(listPvtParas, mapPebiPvtPara); - - //m_pebiPvtPara->setZ(mapPebiPvtPara.contains("Zg") ? - // QVector(200, mapPebiPvtPara["Zg"]) : - //QVector(200, 1)); - - // 下面参数单项流不需要 - - //m_pebiPvtPara->setRv(mapPebiPvtPara.contains("Rv") ? - // QVector(200, mapPebiPvtPara["Rv"]) : - //QVector(200, 0)); - - //m_pebiPvtPara->setV(mapPebiPvtPara.contains("V") ? - // QVector(200, mapPebiPvtPara["V"]) : - //QVector(200, 0)); - //m_pebiPvtPara->setKKinitial(mapPebiPvtPara.contains("k_kinitial") ? - // QVector(200, mapPebiPvtPara["k_kinitial"]) : - //QVector(200, 1)); - //m_pebiPvtPara->setCfCfinitial(mapPebiPvtPara.contains("Cf_Cfinitial") ? - // QVector(200, mapPebiPvtPara["Cf_Cfinitial"]) : - //QVector(200, 1)); - - //// 饱和度与相对渗透率(大小为100) - //m_pebiPvtPara->setSo(mapPebiPvtPara.contains("So") ? - //QVector(100, mapPebiPvtPara["So"]) : - //QVector(100, 0)); - //m_pebiPvtPara->setKro(mapPebiPvtPara.contains("Kro") ? - // QVector(100, mapPebiPvtPara["Kro"]) : - //QVector(100, 0)); - //m_pebiPvtPara->setSg(mapPebiPvtPara.contains("Sg") ? - // QVector(100, mapPebiPvtPara["Sg"]) : - //QVector(100, 0)); - //m_pebiPvtPara->setKrg(mapPebiPvtPara.contains("Krg") ? - // QVector(100, mapPebiPvtPara["Krg"]) : - //QVector(100, 0)); - //m_pebiPvtPara->setSw(mapPebiPvtPara.contains("Sw") ? - // QVector(100, mapPebiPvtPara["Sw"]) : - //QVector(100, 0)); - //m_pebiPvtPara->setKrw(mapPebiPvtPara.contains("Krw") ? - // QVector(100, mapPebiPvtPara["Krw"]) : - //QVector(100, 0)); + + default: + break; + } + + // 4. 统一设置压力横坐标 + setPebiPressureIfEmpty(m_pebiPvtPara, vecPressure); } nmDataRegionMark *nmDataAnalyzeManager::createRegionMark() diff --git a/Src/nmNum/nmData/nmDataReservoir.cpp b/Src/nmNum/nmData/nmDataReservoir.cpp index 4432c88..0994a48 100644 --- a/Src/nmNum/nmData/nmDataReservoir.cpp +++ b/Src/nmNum/nmData/nmDataReservoir.cpp @@ -2,17 +2,33 @@ #include "ZxSerializer.h" nmDataReservoir::nmDataReservoir() { + // 基础属性 m_initialPressure = nmDataAttribute("Initial Pressure",40.0, "MPa", UNIT_TYPE_PRESSURE, QStringList(), QStringList() << "psia" << "Pa" << "kPa" << "atm" << "bara" << "kg/cm^2" << "m" << "psig" << "bar" << "MPa" << "kPag"); - m_reservoirType = nmDataAttribute("Reservoir type", "Homogeneous", "", UNIT_TYPE_DIMENSIONLESS, QStringList() << "Homogeneous" << "Dual porosity pseudo steady state", QStringList()); - m_Bo = nmDataAttribute("Bo", 1.2, ""); m_permeability = nmDataAttribute("Permeability", 0.001, "Darcy", UNIT_TYPE_PERMEABILITY, QStringList(), QStringList() << "md" << "Darcy" << "m^2" << "cm^2" << "um^2"); m_thickness = nmDataAttribute("Thickness", 10.0, "m", UNIT_TYPE_LENGTH, QStringList(), QStringList() << "ft" << "m" << "cm" << "mm" << "in" << "0.1 in" << "mile" << "km"); m_porosity = nmDataAttribute("Porosity", 0.1, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); - m_Ct = nmDataAttribute("Ct", 0.001, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); m_kxKy = nmDataAttribute("Kx/Ky", 1.0, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); - m_Cf = nmDataAttribute("Cf", 0.0001, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); + + // 油相PVT单值 + m_Bo = nmDataAttribute("Bo", 1.2, ""); m_Miuo = nmDataAttribute("Miuo", 0.5, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); + // 气相PVT单值 + m_Bg = nmDataAttribute("Bg", 1.0, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); + m_Miug = nmDataAttribute("Miug", 1.0, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); + + // 水相PVT单值 + m_Bw = nmDataAttribute("Bw", 1.0, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); + m_Miuw = nmDataAttribute("Miuw", 1.0, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); + + // 压缩系数 + m_Ct = nmDataAttribute("Ct", 0.001, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); + m_Cf = nmDataAttribute("Cf", 0.0001, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); + + // 储层类型与传导率 + m_reservoirType = nmDataAttribute("Reservoir type", "Homogeneous", "", UNIT_TYPE_DIMENSIONLESS, QStringList() << "Homogeneous" << "Dual porosity pseudo steady state", QStringList()); + m_transmissibility = nmDataAttribute("Transmissibility", 1000.0, "md.m", UNIT_TYPE_CONDUCTIVITY, QStringList(), QStringList()<< "md.ft" << "md.m" << "m^3"); + // 初始饱和度 m_Soi = nmDataAttribute("Soi", 0.8, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); m_Sgi = nmDataAttribute("Sgi", 0.0, "", UNIT_TYPE_DIMENSIONLESS, QStringList(), QStringList()); @@ -20,7 +36,6 @@ nmDataReservoir::nmDataReservoir() { m_dTempGasRe = 100; m_ePhaseType = PHASE_Oil; - m_transmissibility = nmDataAttribute("Transmissibility", 1000.0, "md.m", UNIT_TYPE_CONDUCTIVITY, QStringList(), QStringList()<< "md.ft" << "md.m" << "m^3"); } void nmDataReservoir::resetToDefaults() @@ -42,20 +57,34 @@ nmDataReservoir& nmDataReservoir::operator=(const nmDataReservoir& other) { // 复制所有成员变量 m_initialPressure = other.m_initialPressure; - m_reservoirType = other.m_reservoirType; - m_Bo = other.m_Bo; m_permeability = other.m_permeability; m_thickness = other.m_thickness; m_porosity = other.m_porosity; - m_Ct = other.m_Ct; m_kxKy = other.m_kxKy; - m_Cf = other.m_Cf; + + // 油相PVT单值 + m_Bo = other.m_Bo; m_Miuo = other.m_Miuo; + + // 气相PVT单值 + m_Bg = other.m_Bg; + m_Miug = other.m_Miug; + + // 水相PVT单值 + m_Bw = other.m_Bw; + m_Miuw = other.m_Miuw; + + // 压缩系数 + m_Ct = other.m_Ct; + m_Cf = other.m_Cf; + + m_reservoirType = other.m_reservoirType; + m_transmissibility = other.m_transmissibility; + m_Soi = other.m_Soi; m_Sgi = other.m_Sgi; m_Swi = other.m_Swi; m_dTempGasRe = other.m_dTempGasRe; - m_transmissibility = other.m_transmissibility; m_ePhaseType = other.m_ePhaseType; } return *this; @@ -73,19 +102,34 @@ rapidjson::Value nmDataReservoir::ToJsonValue(rapidjson::Document::AllocatorType // 序列化 nmDataAttribute 类型的成员 // 调用 nmDataAttribute 自身的 ToJsonValue 方法进行递归序列化 reservoirObject.AddMember("InitialPressure", m_initialPressure.ToJsonValue(allocator), allocator); - reservoirObject.AddMember("ReservoirType", m_reservoirType.ToJsonValue(allocator), allocator); - reservoirObject.AddMember("Bo", m_Bo.ToJsonValue(allocator), allocator); reservoirObject.AddMember("Permeability", m_permeability.ToJsonValue(allocator), allocator); reservoirObject.AddMember("Thickness", m_thickness.ToJsonValue(allocator), allocator); reservoirObject.AddMember("Porosity", m_porosity.ToJsonValue(allocator), allocator); - reservoirObject.AddMember("Ct", m_Ct.ToJsonValue(allocator), allocator); reservoirObject.AddMember("Kx/Ky", m_kxKy.ToJsonValue(allocator), allocator); - reservoirObject.AddMember("Cf", m_Cf.ToJsonValue(allocator), allocator); + + // 油相PVT单值 + reservoirObject.AddMember("Bo", m_Bo.ToJsonValue(allocator), allocator); reservoirObject.AddMember("Miuo", m_Miuo.ToJsonValue(allocator), allocator); + + // 气相PVT单值 + reservoirObject.AddMember("Bg", m_Bg.ToJsonValue(allocator), allocator); + reservoirObject.AddMember("Miug", m_Miug.ToJsonValue(allocator), allocator); + + // 水相PVT单值 + reservoirObject.AddMember("Bw", m_Bw.ToJsonValue(allocator), allocator); + reservoirObject.AddMember("Miuw", m_Miuw.ToJsonValue(allocator), allocator); + + // 压缩系数 + reservoirObject.AddMember("Ct", m_Ct.ToJsonValue(allocator), allocator); + reservoirObject.AddMember("Cf", m_Cf.ToJsonValue(allocator), allocator); + + reservoirObject.AddMember("ReservoirType", m_reservoirType.ToJsonValue(allocator), allocator); + reservoirObject.AddMember("Transmissibility", m_transmissibility.ToJsonValue(allocator), allocator); + + // 初始饱和度 reservoirObject.AddMember("Soi", m_Soi.ToJsonValue(allocator), allocator); reservoirObject.AddMember("Sgi", m_Sgi.ToJsonValue(allocator), allocator); reservoirObject.AddMember("Swi", m_Swi.ToJsonValue(allocator), allocator); - reservoirObject.AddMember("Transmissibility", m_transmissibility.ToJsonValue(allocator), allocator); return reservoirObject; // 返回序列化后的 RapidJSON Value } @@ -98,12 +142,6 @@ void nmDataReservoir::FromJsonValue(const rapidjson::Value& jsonValue) if (jsonValue.HasMember("InitialPressure") && jsonValue["InitialPressure"].IsObject()) { m_initialPressure.FromJsonValue(jsonValue["InitialPressure"]); } - if (jsonValue.HasMember("ReservoirType") && jsonValue["ReservoirType"].IsObject()) { - m_reservoirType.FromJsonValue(jsonValue["ReservoirType"]); - } - if (jsonValue.HasMember("Bo") && jsonValue["Bo"].IsObject()) { - m_Bo.FromJsonValue(jsonValue["Bo"]); - } if (jsonValue.HasMember("Permeability") && jsonValue["Permeability"].IsObject()) { m_permeability.FromJsonValue(jsonValue["Permeability"]); } @@ -113,18 +151,50 @@ void nmDataReservoir::FromJsonValue(const rapidjson::Value& jsonValue) if (jsonValue.HasMember("Porosity") && jsonValue["Porosity"].IsObject()) { m_porosity.FromJsonValue(jsonValue["Porosity"]); } - if (jsonValue.HasMember("Ct") && jsonValue["Ct"].IsObject()) { - m_Ct.FromJsonValue(jsonValue["Ct"]); - } if (jsonValue.HasMember("Kx/Ky") && jsonValue["Kx/Ky"].IsObject()) { m_kxKy.FromJsonValue(jsonValue["Kx/Ky"]); } - if (jsonValue.HasMember("Cf") && jsonValue["Cf"].IsObject()) { - m_Cf.FromJsonValue(jsonValue["Cf"]); + + // 油相PVT单值 + if (jsonValue.HasMember("Bo") && jsonValue["Bo"].IsObject()) { + m_Bo.FromJsonValue(jsonValue["Bo"]); } if (jsonValue.HasMember("Miuo") && jsonValue["Miuo"].IsObject()) { m_Miuo.FromJsonValue(jsonValue["Miuo"]); } + + // 气相PVT单值 + if (jsonValue.HasMember("Bg") && jsonValue["Bg"].IsObject()) { + m_Bg.FromJsonValue(jsonValue["Bg"]); + } + if (jsonValue.HasMember("Miug") && jsonValue["Miug"].IsObject()) { + m_Miug.FromJsonValue(jsonValue["Miug"]); + } + + // 水相PVT单值 + if (jsonValue.HasMember("Bw") && jsonValue["Bw"].IsObject()) { + m_Bw.FromJsonValue(jsonValue["Bw"]); + } + if (jsonValue.HasMember("Miuw") && jsonValue["Miuw"].IsObject()) { + m_Miuw.FromJsonValue(jsonValue["Miuw"]); + } + + // 压缩系数 + if (jsonValue.HasMember("Ct") && jsonValue["Ct"].IsObject()) { + m_Ct.FromJsonValue(jsonValue["Ct"]); + } + if (jsonValue.HasMember("Cf") && jsonValue["Cf"].IsObject()) { + m_Cf.FromJsonValue(jsonValue["Cf"]); + } + + if (jsonValue.HasMember("ReservoirType") && jsonValue["ReservoirType"].IsObject()) { + m_reservoirType.FromJsonValue(jsonValue["ReservoirType"]); + } + if (jsonValue.HasMember("Transmissibility") && jsonValue["Transmissibility"].IsObject()) { + m_transmissibility.FromJsonValue(jsonValue["Transmissibility"]); + } + + // 初始饱和度 if (jsonValue.HasMember("Soi") && jsonValue["Soi"].IsObject()) { m_Soi.FromJsonValue(jsonValue["Soi"]); } @@ -134,9 +204,6 @@ void nmDataReservoir::FromJsonValue(const rapidjson::Value& jsonValue) if (jsonValue.HasMember("Swi") && jsonValue["Swi"].IsObject()) { m_Swi.FromJsonValue(jsonValue["Swi"]); } - if (jsonValue.HasMember("Transmissibility") && jsonValue["Transmissibility"].IsObject()) { - m_transmissibility.FromJsonValue(jsonValue["Transmissibility"]); - } } @@ -217,7 +284,9 @@ QIcon nmDataReservoir::getIcon(bool expanded) const { return zxLoadIcon("Reservoir"); } -// Getters and Setters +// ===== Getters and Setters ===== + +// 基础属性 void nmDataReservoir::setInitialPressure(const nmDataAttribute& attr) { m_initialPressure = attr; } @@ -226,22 +295,6 @@ nmDataAttribute& nmDataReservoir::getInitialPressure() { return m_initialPressure; } -void nmDataReservoir::setReservoirType(const nmDataAttribute& attr) { - m_reservoirType = attr; -} - -nmDataAttribute& nmDataReservoir::getReservoirType() { - return m_reservoirType; -} - -void nmDataReservoir::setBo(const nmDataAttribute& attr) { - m_Bo = attr; -} - -nmDataAttribute& nmDataReservoir::getBo() { - return m_Bo; -} - void nmDataReservoir::setPermeability(const nmDataAttribute& attr) { m_permeability = attr; } @@ -266,14 +319,6 @@ nmDataAttribute& nmDataReservoir::getPorosity() { return m_porosity; } -void nmDataReservoir::setCt(const nmDataAttribute& attr) { - m_Ct = attr; -} - -nmDataAttribute& nmDataReservoir::getCt() { - return m_Ct; -} - void nmDataReservoir::setKxKy(const nmDataAttribute& attr) { m_kxKy = attr; } @@ -282,12 +327,13 @@ nmDataAttribute& nmDataReservoir::getKxKy() { return m_kxKy; } -void nmDataReservoir::setCf(const nmDataAttribute& attr) { - m_Cf = attr; +// 油相PVT单值参数 +void nmDataReservoir::setBo(const nmDataAttribute& attr) { + m_Bo = attr; } -nmDataAttribute& nmDataReservoir::getCf() { - return m_Cf; +nmDataAttribute& nmDataReservoir::getBo() { + return m_Bo; } void nmDataReservoir::setMiuo(const nmDataAttribute& attr) { @@ -298,22 +344,64 @@ nmDataAttribute& nmDataReservoir::getMiuo() { return m_Miuo; } -// 气藏温度的 getter 和 setter -void nmDataReservoir::setTempGasRe(double temp) { - m_dTempGasRe = temp; +// 气相PVT单值参数 +void nmDataReservoir::setBg(const nmDataAttribute& attr) { + m_Bg = attr; } -double nmDataReservoir::getTempGasRe() const { - return m_dTempGasRe; +nmDataAttribute& nmDataReservoir::getBg() { + return m_Bg; } -// 多相流类型的 getter 和 setter -void nmDataReservoir::setPhaseType(NM_PHASE_TYPE phaseType) { - m_ePhaseType = phaseType; +void nmDataReservoir::setMiug(const nmDataAttribute& attr) { + m_Miug = attr; } -NM_PHASE_TYPE nmDataReservoir::getPhaseType() const { - return m_ePhaseType; +nmDataAttribute& nmDataReservoir::getMiug() { + return m_Miug; +} + +// 水相PVT单值参数 +void nmDataReservoir::setBw(const nmDataAttribute& attr) { + m_Bw = attr; +} + +nmDataAttribute& nmDataReservoir::getBw() { + return m_Bw; +} + +void nmDataReservoir::setMiuw(const nmDataAttribute& attr) { + m_Miuw = attr; +} + +nmDataAttribute& nmDataReservoir::getMiuw() { + return m_Miuw; +} + +// 压缩系数 +void nmDataReservoir::setCt(const nmDataAttribute& attr) { + m_Ct = attr; +} + +nmDataAttribute& nmDataReservoir::getCt() { + return m_Ct; +} + +void nmDataReservoir::setCf(const nmDataAttribute& attr) { + m_Cf = attr; +} + +nmDataAttribute& nmDataReservoir::getCf() { + return m_Cf; +} + +// 储层类型与传导率 +void nmDataReservoir::setReservoirType(const nmDataAttribute& attr) { + m_reservoirType = attr; +} + +nmDataAttribute& nmDataReservoir::getReservoirType() { + return m_reservoirType; } void nmDataReservoir::setTransmissibility(const nmDataAttribute &attr) { @@ -324,6 +412,7 @@ nmDataAttribute& nmDataReservoir::getTransmissibility() { return m_transmissibility; } +// 初始饱和度 void nmDataReservoir::setSoi(const nmDataAttribute &attr) { m_Soi = attr; } @@ -347,3 +436,21 @@ void nmDataReservoir::setSwi(const nmDataAttribute &attr) { nmDataAttribute& nmDataReservoir::getSwi() { return m_Swi; } + +// 气藏温度 +void nmDataReservoir::setTempGasRe(double temp) { + m_dTempGasRe = temp; +} + +double nmDataReservoir::getTempGasRe() const { + return m_dTempGasRe; +} + +// 多相流类型 +void nmDataReservoir::setPhaseType(NM_PHASE_TYPE phaseType) { + m_ePhaseType = phaseType; +} + +NM_PHASE_TYPE nmDataReservoir::getPhaseType() const { + return m_ePhaseType; +}