|
|
|
|
@ -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<double>& vecPressure)
|
|
|
|
|
{
|
|
|
|
|
// 分别获取体积系数、压缩系数、粘度三条曲线
|
|
|
|
|
QVector<double> 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<QString, double> 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<QString, double> 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<QString, double>& 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<nmDataLayer*>& 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<QString, double> 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<QString, double> 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<double> vecPressure; // 压力, MPa
|
|
|
|
|
QVector<double> vecBo; // 油体积系数, m^3/m^3
|
|
|
|
|
QVector<double> vecCo; // 油压缩系数, 1/MPa
|
|
|
|
|
QVector<double> vecMiuo; // 油粘度, mPa·s
|
|
|
|
|
QVector<double> vecBg; // 气体积系数, m^3/m^3
|
|
|
|
|
QVector<double> vecCg; // 气压缩系数, 1/MPa
|
|
|
|
|
QVector<double> vecMiug; // 气粘度, mPa·s
|
|
|
|
|
QVector<double> vecBw; // 水体积系数, m^3/m^3
|
|
|
|
|
QVector<double> vecCw; // 水压缩系数, 1/MPa
|
|
|
|
|
QVector<double> 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<double> 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<double> > vvec;
|
|
|
|
|
////pSubWndFitting->getDiffusionRstOf(DiffusionSubOption::DSO_KK, vvec);
|
|
|
|
|
|
|
|
|
|
////QVector<double> vecSw;
|
|
|
|
|
////QVector<double> vecKro;
|
|
|
|
|
////QVector<double> vecKrw;
|
|
|
|
|
|
|
|
|
|
//// 遍历 vvec 中的每个子向量
|
|
|
|
|
////foreach (const QVector<double>& 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<double>(200, mapPebiPvtPara["Zg"]) :
|
|
|
|
|
//QVector<double>(200, 1));
|
|
|
|
|
|
|
|
|
|
// 下面参数单项流不需要
|
|
|
|
|
|
|
|
|
|
//m_pebiPvtPara->setRv(mapPebiPvtPara.contains("Rv") ?
|
|
|
|
|
// QVector<double>(200, mapPebiPvtPara["Rv"]) :
|
|
|
|
|
//QVector<double>(200, 0));
|
|
|
|
|
|
|
|
|
|
//m_pebiPvtPara->setV(mapPebiPvtPara.contains("V") ?
|
|
|
|
|
// QVector<double>(200, mapPebiPvtPara["V"]) :
|
|
|
|
|
//QVector<double>(200, 0));
|
|
|
|
|
//m_pebiPvtPara->setKKinitial(mapPebiPvtPara.contains("k_kinitial") ?
|
|
|
|
|
// QVector<double>(200, mapPebiPvtPara["k_kinitial"]) :
|
|
|
|
|
//QVector<double>(200, 1));
|
|
|
|
|
//m_pebiPvtPara->setCfCfinitial(mapPebiPvtPara.contains("Cf_Cfinitial") ?
|
|
|
|
|
// QVector<double>(200, mapPebiPvtPara["Cf_Cfinitial"]) :
|
|
|
|
|
//QVector<double>(200, 1));
|
|
|
|
|
|
|
|
|
|
//// 饱和度与相对渗透率(大小为100)
|
|
|
|
|
//m_pebiPvtPara->setSo(mapPebiPvtPara.contains("So") ?
|
|
|
|
|
//QVector<double>(100, mapPebiPvtPara["So"]) :
|
|
|
|
|
//QVector<double>(100, 0));
|
|
|
|
|
//m_pebiPvtPara->setKro(mapPebiPvtPara.contains("Kro") ?
|
|
|
|
|
// QVector<double>(100, mapPebiPvtPara["Kro"]) :
|
|
|
|
|
//QVector<double>(100, 0));
|
|
|
|
|
//m_pebiPvtPara->setSg(mapPebiPvtPara.contains("Sg") ?
|
|
|
|
|
// QVector<double>(100, mapPebiPvtPara["Sg"]) :
|
|
|
|
|
//QVector<double>(100, 0));
|
|
|
|
|
//m_pebiPvtPara->setKrg(mapPebiPvtPara.contains("Krg") ?
|
|
|
|
|
// QVector<double>(100, mapPebiPvtPara["Krg"]) :
|
|
|
|
|
//QVector<double>(100, 0));
|
|
|
|
|
//m_pebiPvtPara->setSw(mapPebiPvtPara.contains("Sw") ?
|
|
|
|
|
// QVector<double>(100, mapPebiPvtPara["Sw"]) :
|
|
|
|
|
//QVector<double>(100, 0));
|
|
|
|
|
//m_pebiPvtPara->setKrw(mapPebiPvtPara.contains("Krw") ?
|
|
|
|
|
// QVector<double>(100, mapPebiPvtPara["Krw"]) :
|
|
|
|
|
//QVector<double>(100, 0));
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. 统一设置压力横坐标
|
|
|
|
|
setPebiPressureIfEmpty(m_pebiPvtPara, vecPressure);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nmDataRegionMark *nmDataAnalyzeManager::createRegionMark()
|
|
|
|
|
|