#include "nmReservoirParameterCatalog.h" #include "nmReservoirPropertiesDataSource.h" #include "nmAttrRegistry.h" #include "nmDataAnalyzeManager.h" #include "nmDataAttribute.h" #include "nmDataPerforation.h" #include namespace { /* * Qt 4.8的lupdate无法跟踪editorText()的间接参数,以下标记只用于 * 收集中英文资源;运行时仍由同一翻译上下文返回文字。 */ static const char* const s_pCatalogTranslationMarkers[] = { QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Reservoir type"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Homogeneous"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Dual porosity pseudo steady state"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Fault flow model"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Boundary type"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Leaky"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Composite limit"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Permeable boundary"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Composite boundary"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Fracture flow model"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Finite conductivity"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Infinite conductivity"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Position and wellbore"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Wellbore storage"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Wellbore storage and fracture"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Basic and medium properties"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Fluid parameters"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Oil phase parameters"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Water phase parameters"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Compressibility"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Compressibility and saturation"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Reservoir parameters"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Vertical well"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Fractured vertical well"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Multistage fractured horizontal well"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Reservoir medium parameters"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Geometry"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Flow properties"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Conductivity properties"), QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Boundary properties") }; /** @brief 返回当前语言下的界面文字。 */ QString editorText(const char* pText) { Q_UNUSED(s_pCatalogTranslationMarkers); return QCoreApplication::translate("nmWxReservoirPropertiesEditor", pText); } /** @brief 创建一个稳定枚举选项。 */ nmReservoirEnumOption enumOption(const QString& sCode, const char* pText) { nmReservoirEnumOption oOption; oOption.m_sCode = sCode; oOption.m_sText = editorText(pText); return oOption; } /** @brief 创建一个数值字段描述。 */ nmReservoirParameterFieldInfo numericField( const QString& sParameterId, const QString& sBaseParameterId, nmReservoirParameterEditorType eEditorType) { nmReservoirParameterFieldInfo oField; oField.m_sParameterId = sParameterId; oField.m_sBaseParameterId = sBaseParameterId; oField.m_eEditorType = eEditorType; oField.m_bUnitEnabled = true; return oField; } /** @brief 创建一个浮点数字段描述。 */ nmReservoirParameterFieldInfo numericField( const QString& sParameterId, const QString& sBaseParameterId) { return numericField(sParameterId, sBaseParameterId, NM_RESERVOIR_EDITOR_NUMBER); } /** @brief 创建一个明确不显示单位的浮点数字段。 */ nmReservoirParameterFieldInfo unitlessNumericField( const QString& sParameterId, const QString& sBaseParameterId) { nmReservoirParameterFieldInfo oField = numericField(sParameterId, sBaseParameterId); oField.m_bUnitEnabled = false; return oField; } /** @brief 创建储层类型字段。 */ nmReservoirParameterFieldInfo reservoirModelField( const QString& sParameterId) { nmReservoirParameterFieldInfo oField; oField.m_sParameterId = sParameterId; oField.m_sLabel = editorText("Reservoir type"); oField.m_eEditorType = NM_RESERVOIR_EDITOR_ENUM; oField.m_bUnitEnabled = false; oField.m_listOptions.append(enumOption("homogeneous", "Homogeneous")); oField.m_listOptions.append(enumOption( "dual_porosity_pss", "Dual porosity pseudo steady state")); return oField; } /** @brief 按指定显示文字创建断层或复合区流动模型字段。 */ nmReservoirParameterFieldInfo leakageModelField( const QString& sParameterId, const char* pLabel, const char* pLeakyText, const char* pCompositeText) { nmReservoirParameterFieldInfo oField; oField.m_sParameterId = sParameterId; oField.m_sLabel = editorText(pLabel); oField.m_eEditorType = NM_RESERVOIR_EDITOR_ENUM; oField.m_bUnitEnabled = false; oField.m_listOptions.append(enumOption("leaky", pLeakyText)); oField.m_listOptions.append(enumOption( "composite_limit", pCompositeText)); return oField; } /** @brief 创建裂缝导流模型字段。 */ nmReservoirParameterFieldInfo fractureModelField( const QString& sParameterId) { nmReservoirParameterFieldInfo oField; oField.m_sParameterId = sParameterId; oField.m_sLabel = editorText("Fracture flow model"); oField.m_eEditorType = NM_RESERVOIR_EDITOR_ENUM; oField.m_bUnitEnabled = false; oField.m_listOptions.append(enumOption( "finite_conductivity", "Finite conductivity")); oField.m_listOptions.append(enumOption( "infinite_conductivity", "Infinite conductivity")); return oField; } /** @brief 创建页面上的一个参数分组。 */ nmReservoirParameterGroupInfo parameterGroup( const char* pTitle, int nRow, int nColumn, int nColumnSpan) { nmReservoirParameterGroupInfo oGroup; oGroup.m_sTitle = editorText(pTitle); oGroup.m_nRow = nRow; oGroup.m_nColumn = nColumn; oGroup.m_nRowSpan = 1; oGroup.m_nColumnSpan = nColumnSpan; oGroup.m_bValueRightAligned = false; oGroup.m_bFieldsCentered = false; return oGroup; } /** @brief 返回当前求解器模型对应的流体参数分组标题。 */ const char* solverPvtGroupTitle( int nSolverModelType, NM_PHASE_TYPE ePhaseType) { switch (nSolverModelType) { case SMT_Oil_ConstPvt: return "Oil phase parameters"; case SMT_Water_ConstPvt: return "Water phase parameters"; default: if (nSolverModelType == 0 && ePhaseType == PHASE_Oil) { return "Oil phase parameters"; } if (nSolverModelType == 0 && ePhaseType == PHASE_Water) { return "Water phase parameters"; } return "Fluid parameters"; } } /** @brief 按求解器模型向流体分组添加实际使用的PVT单值参数。 */ void appendSolverPvtFields( nmReservoirParameterGroupInfo& oGroup, int nSolverModelType, NM_PHASE_TYPE ePhaseType) { switch (nSolverModelType) { case SMT_Oil_ConstPvt: oGroup.m_listFields << numericField("Miuo", "Miuo") << unitlessNumericField("Bo", "Bo"); break; case SMT_Water_ConstPvt: oGroup.m_listFields << numericField("Miuw", "Miuw") << unitlessNumericField("Bw", "Bw"); break; default: // 自定义数据源未提供模型类型时,按单相相态保留兼容入口。 if (nSolverModelType == 0 && (ePhaseType == PHASE_Oil || ePhaseType == PHASE_UNKNOWN)) { oGroup.m_listFields << numericField("Miuo", "Miuo") << unitlessNumericField("Bo", "Bo"); } else if (nSolverModelType == 0 && ePhaseType == PHASE_Water) { oGroup.m_listFields << numericField("Miuw", "Miuw") << unitlessNumericField("Bw", "Bw"); } break; } } /** @brief 判断当前模型是否需要编辑初始含水饱和度。 */ bool solverUsesInitialWaterSaturation( int nSolverModelType, NM_PHASE_TYPE ePhaseType) { return nSolverModelType == SMT_Oil_Water_TwoPhase || (nSolverModelType == 0 && ePhaseType == PHASE_Oil_Water); } /** @brief 判断当前模型是否需要编辑初始含油饱和度。 */ bool solverUsesInitialOilSaturation( int nSolverModelType, NM_PHASE_TYPE ePhaseType) { return nSolverModelType == SMT_Oil_Water_TwoPhase || (nSolverModelType == 0 && ePhaseType == PHASE_Oil_Water); } /** @brief 判断当前模型是否需要编辑初始含气饱和度。 */ bool solverUsesInitialGasSaturation( int nSolverModelType, NM_PHASE_TYPE ePhaseType) { return nSolverModelType == SMT_Gas_VariablePvt || nSolverModelType == SMT_Gas_PseudoPressure || (nSolverModelType == 0 && ePhaseType == PHASE_Gas); } /** @brief 按求解器模型添加实际使用的压缩系数和饱和度参数。 */ void appendSolverCompressionFields( nmReservoirParameterGroupInfo& oGroup, int nSolverModelType, NM_PHASE_TYPE ePhaseType) { switch (nSolverModelType) { case SMT_Oil_ConstPvt: case SMT_Water_ConstPvt: oGroup.m_listFields.append(numericField("Cti", "Cti")); break; default: if (nSolverModelType == 0 && (ePhaseType == PHASE_Oil || ePhaseType == PHASE_Water || ePhaseType == PHASE_UNKNOWN)) { oGroup.m_listFields.append(numericField("Cti", "Cti")); } else { oGroup.m_listFields.append(numericField("Cf", "Cf")); } break; } if (solverUsesInitialOilSaturation(nSolverModelType, ePhaseType)) { oGroup.m_listFields.append(numericField("Soi", "Soi")); } if (solverUsesInitialWaterSaturation(nSolverModelType, ePhaseType)) { oGroup.m_listFields.append(numericField("Swi", "Swi")); } if (solverUsesInitialGasSaturation(nSolverModelType, ePhaseType)) { oGroup.m_listFields.append(numericField("Sgi", "Sgi")); } } /** @brief 为参数ID添加对象编码前缀。 */ QString prefixed(const QString& sObjectCode, const char* pParameterId) { return sObjectCode + "_" + QString::fromLatin1(pParameterId); } /** @brief 生成无井编码时的会话编码。 */ QString wellCode(const nmDataWellBase& oWell, const QString& sFallbackPrefix, int nIndex) { QString sCode = oWell.getWellCode(); if (sCode.isEmpty()) { sCode = QString("%1%2").arg(sFallbackPrefix) .arg(nIndex + 1, 4, 10, QChar('0')); } return sCode; } /** @brief 创建井对象的分组描述。 */ void createWellGroups(nmReservoirPropertyObjectInfo& oInfo, NM_WELL_MODEL eWellType, bool bHasPerforation) { nmReservoirParameterGroupInfo oPosition = parameterGroup("Position and wellbore", 0, 0, 1); oPosition.m_bValueRightAligned = true; oPosition.m_listFields << numericField(prefixed(oInfo.m_sObjectCode, "W_X"), "W_X") << numericField(prefixed(oInfo.m_sObjectCode, "W_Y"), "W_Y") << numericField(prefixed(oInfo.m_sObjectCode, "W_Rw"), "W_Rw"); if (bHasPerforation) { oPosition.m_listFields.append(numericField( prefixed(oInfo.m_sObjectCode, "W_Skin"), "W_Skin")); } const char* pStorageGroupTitle = eWellType == Vertical_Well ? "Wellbore storage" : "Wellbore storage and fracture"; nmReservoirParameterGroupInfo oStorage = parameterGroup(pStorageGroupTitle, 0, 1, 1); oStorage.m_listFields.append(numericField( prefixed(oInfo.m_sObjectCode, "W_C"), "W_C")); if (eWellType == Vertical_Fractured_Well) { oStorage.m_listFields << numericField(prefixed(oInfo.m_sObjectCode, "W_FractureHalfLength"), "W_FractureHalfLength") << numericField(prefixed(oInfo.m_sObjectCode, "W_FractureAngle"), "W_FractureAngle") << numericField(prefixed(oInfo.m_sObjectCode, "W_Dfc"), "W_Dfc"); } else if (eWellType == Horizontal_Fractured_Well) { oStorage.m_listFields << numericField(prefixed(oInfo.m_sObjectCode, "W_WellLength"), "W_WellLength") << numericField(prefixed(oInfo.m_sObjectCode, "W_DrainAngle"), "W_DrainAngle") << numericField(prefixed(oInfo.m_sObjectCode, "W_NumberOfFractures"), "W_NumberOfFractures", NM_RESERVOIR_EDITOR_INTEGER) << numericField(prefixed(oInfo.m_sObjectCode, "W_FractureHalfLength"), "W_FractureHalfLength") << numericField(prefixed(oInfo.m_sObjectCode, "W_FractureAngle"), "W_FractureAngle") << numericField(prefixed(oInfo.m_sObjectCode, "W_Dfc"), "W_Dfc"); } oInfo.m_listGroups << oPosition << oStorage; } /** @brief 注册一口井的全部可编辑数值属性。 */ void registerWell(nmAttrRegistry* pRegistry, nmDataWellBase& oWell, const QString& sCode) { pRegistry->regAttr(prefixed(sCode, "W_X"), &oWell.getX()); pRegistry->regAttr(prefixed(sCode, "W_Y"), &oWell.getY()); pRegistry->regAttr(prefixed(sCode, "W_Rw"), &oWell.getRadius()); pRegistry->regAttr(prefixed(sCode, "W_C"), &oWell.getWellboreStorage()); if (oWell.getPerforationCount() > 0 && oWell.getPerforation(0) != nullptr) { pRegistry->regAttr(prefixed(sCode, "W_Skin"), &oWell.getPerforation(0)->getSkin()); } } /** @brief 判断对象描述中是否包含指定枚举字段。 */ bool containsEnumField(const nmReservoirPropertyObjectInfo& oInfo, const QString& sParameterId) { for (int nGroupIndex = 0; nGroupIndex < oInfo.m_listGroups.size(); ++nGroupIndex) { const nmReservoirParameterGroupInfo& oGroup = oInfo.m_listGroups[nGroupIndex]; for (int nFieldIndex = 0; nFieldIndex < oGroup.m_listFields.size(); ++nFieldIndex) { const nmReservoirParameterFieldInfo& oField = oGroup.m_listFields[nFieldIndex]; if (oField.m_eEditorType == NM_RESERVOIR_EDITOR_ENUM && oField.m_sParameterId == sParameterId) { return true; } } } return false; } } void nmReservoirParameterCatalog::registerSnapshot( nmAttrRegistry* pRegistry, nmReservoirPropertiesSnapshot& oSnapshot) { if (pRegistry == nullptr) { return; } // 第一步:重新建立编辑会话独占的注册表,杜绝与实时数据交叉连接。 pRegistry->clear(); pRegistry->regAttr("h", &oSnapshot.m_oReservoir.getThickness()); pRegistry->regAttr("Pi", &oSnapshot.m_oReservoir.getInitialPressure()); pRegistry->regAttr("K", &oSnapshot.m_oReservoir.getPermeability()); pRegistry->regAttr("phi", &oSnapshot.m_oReservoir.getPorosity()); pRegistry->regAttr("Cti", &oSnapshot.m_oReservoir.getCt()); pRegistry->regAttr("Cf", &oSnapshot.m_oReservoir.getCf()); pRegistry->regAttr("Soi", &oSnapshot.m_oReservoir.getSoi()); pRegistry->regAttr("Sgi", &oSnapshot.m_oReservoir.getSgi()); pRegistry->regAttr("Swi", &oSnapshot.m_oReservoir.getSwi()); pRegistry->regAttr("Bo", &oSnapshot.m_oReservoir.getBo()); pRegistry->regAttr("Miuo", &oSnapshot.m_oReservoir.getMiuo()); pRegistry->regAttr("Bw", &oSnapshot.m_oReservoir.getBw()); pRegistry->regAttr("Miuw", &oSnapshot.m_oReservoir.getMiuw()); // 第二步:注册求解器支持的三类井及其压裂参数。 for (int nIndex = 0; nIndex < oSnapshot.m_vecVerticalWells.size(); ++nIndex) { nmDataVerticalWell& oWell = oSnapshot.m_vecVerticalWells[nIndex]; registerWell(pRegistry, oWell, wellCode(oWell, "VWELL", nIndex)); } for (int nIndex = 0; nIndex < oSnapshot.m_vecVerticalFracturedWells.size(); ++nIndex) { nmDataVerticalFracturedWell& oWell = oSnapshot.m_vecVerticalFracturedWells[nIndex]; QString sCode = wellCode(oWell, "VFWELL", nIndex); registerWell(pRegistry, oWell, sCode); pRegistry->regAttr(prefixed(sCode, "W_FractureHalfLength"), &oWell.getFractureHalfLength()); pRegistry->regAttr(prefixed(sCode, "W_FractureAngle"), &oWell.getFractureAngle()); pRegistry->regAttr(prefixed(sCode, "W_Dfc"), &oWell.getDfc()); } for (int nIndex = 0; nIndex < oSnapshot.m_vecHorizontalFracturedWells.size(); ++nIndex) { nmDataHorizontalFracturedWell& oWell = oSnapshot.m_vecHorizontalFracturedWells[nIndex]; QString sCode = wellCode(oWell, "HFWELL", nIndex); registerWell(pRegistry, oWell, sCode); pRegistry->regAttr(prefixed(sCode, "W_WellLength"), &oWell.getWellLength()); pRegistry->regAttr(prefixed(sCode, "W_DrainAngle"), &oWell.getDrainAngle()); pRegistry->regAttr(prefixed(sCode, "W_NumberOfFractures"), &oWell.getNumberOfFractures()); pRegistry->regAttr(prefixed(sCode, "W_FractureHalfLength"), &oWell.getFractureHalfLength()); pRegistry->regAttr(prefixed(sCode, "W_FractureAngle"), &oWell.getFractureAngle()); pRegistry->regAttr(prefixed(sCode, "W_Dfc"), &oWell.getDfc()); } // 第三步:注册区域标记和复合区数值参数。 for (int nIndex = 0; nIndex < oSnapshot.m_vecRegionMarks.size(); ++nIndex) { QString sCode = QString("RMARK%1") .arg(nIndex + 1, 4, 10, QChar('0')); nmDataRegionMark& oMark = oSnapshot.m_vecRegionMarks[nIndex]; pRegistry->regAttr(prefixed(sCode, "RM_ComW"), &oMark.getComW()); pRegistry->regAttr(prefixed(sCode, "RM_ComKr"), &oMark.getComKr()); pRegistry->regAttr(prefixed(sCode, "RM_NetToGross"), &oMark.getNetToGross()); } for (int nIndex = 0; nIndex < oSnapshot.m_vecRegions.size(); ++nIndex) { QString sCode = QString("REGION%1") .arg(nIndex + 1, 4, 10, QChar('0')); pRegistry->regAttr(prefixed(sCode, "R_Leakage"), &oSnapshot.m_vecRegions[nIndex] .getRegionLeakage()); } // 第四步:注册断层和普通裂缝;DFN由专用功能维护。 for (int nIndex = 0; nIndex < oSnapshot.m_vecFaults.size(); ++nIndex) { QString sCode = QString("FAULT%1") .arg(nIndex + 1, 4, 10, QChar('0')); nmDataFault& oFault = oSnapshot.m_vecFaults[nIndex]; pRegistry->regAttr(prefixed(sCode, "FT_X0"), &oFault.getStartX()); pRegistry->regAttr(prefixed(sCode, "FT_Y0"), &oFault.getStartY()); pRegistry->regAttr(prefixed(sCode, "FT_X1"), &oFault.getEndX()); pRegistry->regAttr(prefixed(sCode, "FT_Y1"), &oFault.getEndY()); pRegistry->regAttr(prefixed(sCode, "FT_Leakage"), &oFault.getFaultLeakage()); } int nVisibleFracture = 0; for (int nIndex = 0; nIndex < oSnapshot.m_vecFractures.size(); ++nIndex) { nmDataFracture& oFracture = oSnapshot.m_vecFractures[nIndex]; if (oFracture.getFractureType().getValue().toString() == "DFN") { continue; } QString sCode = QString("FRAC%1") .arg(++nVisibleFracture, 4, 10, QChar('0')); pRegistry->regAttr(prefixed(sCode, "F_X0"), &oFracture.getStartX()); pRegistry->regAttr(prefixed(sCode, "F_Y0"), &oFracture.getStartY()); pRegistry->regAttr(prefixed(sCode, "F_X1"), &oFracture.getEndX()); pRegistry->regAttr(prefixed(sCode, "F_Y1"), &oFracture.getEndY()); pRegistry->regAttr(prefixed(sCode, "F_FC"), &oFracture.getFractureDfc()); pRegistry->regAttr(prefixed(sCode, "F_DW"), &oFracture.getFractureDw()); } } QList nmReservoirParameterCatalog::createObjectInfos( nmReservoirPropertiesCategory eCategory, nmReservoirPropertiesSnapshot& oSnapshot) { QList listInfos; if (eCategory == NM_RESERVOIR_PAGE_RESERVOIR) { nmReservoirPropertyObjectInfo oInfo; oInfo.m_eCategory = eCategory; oInfo.m_eObjectType = NM_RESERVOIR_OBJECT_RESERVOIR; oInfo.m_nSourceIndex = 0; oInfo.m_sObjectCode = "RESERVOIR"; oInfo.m_sDisplayName = editorText("Reservoir parameters"); NM_PHASE_TYPE ePhaseType = oSnapshot.m_oReservoir.getPhaseType(); nmReservoirParameterGroupInfo oBasic = parameterGroup("Basic and medium properties", 0, 0, 1); oBasic.m_nRowSpan = 2; oBasic.m_bValueRightAligned = true; oBasic.m_listFields << numericField("Pi", "Pi") << numericField("K", "K") << numericField("h", "h") << numericField("phi", "phi"); nmReservoirParameterGroupInfo oFluid = parameterGroup(solverPvtGroupTitle( oSnapshot.m_nSolverModelType, ePhaseType), 0, 1, 1); appendSolverPvtFields(oFluid, oSnapshot.m_nSolverModelType, ePhaseType); bool bUsesSaturation = solverUsesInitialWaterSaturation( oSnapshot.m_nSolverModelType, ePhaseType) || solverUsesInitialGasSaturation( oSnapshot.m_nSolverModelType, ePhaseType); nmReservoirParameterGroupInfo oCompression = parameterGroup(bUsesSaturation ? "Compressibility and saturation" : "Compressibility", oFluid.m_listFields.isEmpty() ? 0 : 1, 1, 1); if (oFluid.m_listFields.isEmpty()) { oCompression.m_nRowSpan = 2; } appendSolverCompressionFields(oCompression, oSnapshot.m_nSolverModelType, ePhaseType); oInfo.m_listGroups.append(oBasic); if (!oFluid.m_listFields.isEmpty()) { oInfo.m_listGroups.append(oFluid); } oInfo.m_listGroups.append(oCompression); listInfos.append(oInfo); return listInfos; } if (eCategory == NM_RESERVOIR_PAGE_WELL) { for (int nIndex = 0; nIndex < oSnapshot.m_vecVerticalWells.size(); ++nIndex) { nmDataVerticalWell& oWell = oSnapshot.m_vecVerticalWells[nIndex]; nmReservoirPropertyObjectInfo oInfo; oInfo.m_eCategory = eCategory; oInfo.m_eObjectType = NM_RESERVOIR_OBJECT_VERTICAL_WELL; oInfo.m_nSourceIndex = nIndex; oInfo.m_sObjectCode = wellCode(oWell, "VWELL", nIndex); oInfo.m_sDisplayName = oWell.getWellName() + " - " + editorText("Vertical well"); createWellGroups(oInfo, Vertical_Well, oWell.getPerforationCount() > 0); listInfos.append(oInfo); } for (int nIndex = 0; nIndex < oSnapshot.m_vecVerticalFracturedWells.size(); ++nIndex) { nmDataVerticalFracturedWell& oWell = oSnapshot.m_vecVerticalFracturedWells[nIndex]; nmReservoirPropertyObjectInfo oInfo; oInfo.m_eCategory = eCategory; oInfo.m_eObjectType = NM_RESERVOIR_OBJECT_VERTICAL_FRAC_WELL; oInfo.m_nSourceIndex = nIndex; oInfo.m_sObjectCode = wellCode(oWell, "VFWELL", nIndex); oInfo.m_sDisplayName = oWell.getWellName() + " - " + editorText("Fractured vertical well"); createWellGroups(oInfo, Vertical_Fractured_Well, oWell.getPerforationCount() > 0); listInfos.append(oInfo); } for (int nIndex = 0; nIndex < oSnapshot.m_vecHorizontalFracturedWells.size(); ++nIndex) { nmDataHorizontalFracturedWell& oWell = oSnapshot.m_vecHorizontalFracturedWells[nIndex]; nmReservoirPropertyObjectInfo oInfo; oInfo.m_eCategory = eCategory; oInfo.m_eObjectType = NM_RESERVOIR_OBJECT_HORIZONTAL_FRAC_WELL; oInfo.m_nSourceIndex = nIndex; oInfo.m_sObjectCode = wellCode(oWell, "HFWELL", nIndex); oInfo.m_sDisplayName = oWell.getWellName() + " - " + editorText("Multistage fractured horizontal well"); createWellGroups(oInfo, Horizontal_Fractured_Well, oWell.getPerforationCount() > 0); listInfos.append(oInfo); } return listInfos; } if (eCategory == NM_RESERVOIR_PAGE_REGION_MARK) { for (int nIndex = 0; nIndex < oSnapshot.m_vecRegionMarks.size(); ++nIndex) { nmReservoirPropertyObjectInfo oInfo; oInfo.m_eCategory = eCategory; oInfo.m_eObjectType = NM_RESERVOIR_OBJECT_REGION_MARK; oInfo.m_nSourceIndex = nIndex; oInfo.m_sObjectCode = QString("RMARK%1") .arg(nIndex + 1, 4, 10, QChar('0')); oInfo.m_sDisplayName = oSnapshot.m_vecRegionMarks[nIndex].getRegionMarkName(); nmReservoirParameterGroupInfo oDual = parameterGroup("Reservoir medium parameters", 0, 0, 2); oDual.m_bFieldsCentered = true; oDual.m_listFields << reservoirModelField(prefixed( oInfo.m_sObjectCode, "RM_ReservoirType")) << numericField(prefixed( oInfo.m_sObjectCode, "RM_ComW"), "RM_ComW") << numericField(prefixed( oInfo.m_sObjectCode, "RM_ComKr"), "RM_ComKr") << numericField(prefixed( oInfo.m_sObjectCode, "RM_NetToGross"), "RM_NetToGross"); oInfo.m_listGroups.append(oDual); listInfos.append(oInfo); } return listInfos; } if (eCategory == NM_RESERVOIR_PAGE_FAULT) { for (int nIndex = 0; nIndex < oSnapshot.m_vecFaults.size(); ++nIndex) { nmReservoirPropertyObjectInfo oInfo; oInfo.m_eCategory = eCategory; oInfo.m_eObjectType = NM_RESERVOIR_OBJECT_FAULT; oInfo.m_nSourceIndex = nIndex; oInfo.m_sObjectCode = QString("FAULT%1") .arg(nIndex + 1, 4, 10, QChar('0')); oInfo.m_sDisplayName = oSnapshot.m_vecFaults[nIndex].getFaultName(); nmReservoirParameterGroupInfo oGeometry = parameterGroup("Geometry", 0, 0, 1); oGeometry.m_bValueRightAligned = true; oGeometry.m_listFields << numericField(prefixed( oInfo.m_sObjectCode, "FT_X0"), "FT_X0") << numericField(prefixed( oInfo.m_sObjectCode, "FT_Y0"), "FT_Y0") << numericField(prefixed( oInfo.m_sObjectCode, "FT_X1"), "FT_X1") << numericField(prefixed( oInfo.m_sObjectCode, "FT_Y1"), "FT_Y1"); nmReservoirParameterGroupInfo oFlow = parameterGroup("Flow properties", 0, 1, 1); oFlow.m_listFields << leakageModelField(prefixed( oInfo.m_sObjectCode, "FT_FlowModel"), "Fault flow model", "Leaky", "Composite limit") << numericField(prefixed( oInfo.m_sObjectCode, "FT_Leakage"), "FT_Leakage"); oInfo.m_listGroups << oGeometry << oFlow; listInfos.append(oInfo); } return listInfos; } if (eCategory == NM_RESERVOIR_PAGE_FRACTURE) { int nVisibleFracture = 0; for (int nIndex = 0; nIndex < oSnapshot.m_vecFractures.size(); ++nIndex) { nmDataFracture& oFracture = oSnapshot.m_vecFractures[nIndex]; if (oFracture.getFractureType().getValue().toString() == "DFN") { continue; } nmReservoirPropertyObjectInfo oInfo; oInfo.m_eCategory = eCategory; oInfo.m_eObjectType = NM_RESERVOIR_OBJECT_FRACTURE; oInfo.m_nSourceIndex = nIndex; oInfo.m_sObjectCode = QString("FRAC%1") .arg(++nVisibleFracture, 4, 10, QChar('0')); oInfo.m_sDisplayName = oFracture.getFractureName(); nmReservoirParameterGroupInfo oGeometry = parameterGroup("Geometry", 0, 0, 1); oGeometry.m_bValueRightAligned = true; oGeometry.m_listFields << numericField(prefixed( oInfo.m_sObjectCode, "F_X0"), "F_X0") << numericField(prefixed( oInfo.m_sObjectCode, "F_Y0"), "F_Y0") << numericField(prefixed( oInfo.m_sObjectCode, "F_X1"), "F_X1") << numericField(prefixed( oInfo.m_sObjectCode, "F_Y1"), "F_Y1"); nmReservoirParameterGroupInfo oFlow = parameterGroup("Conductivity properties", 0, 1, 1); oFlow.m_listFields << fractureModelField(prefixed( oInfo.m_sObjectCode, "F_FlowModel")) << numericField(prefixed( oInfo.m_sObjectCode, "F_FC"), "F_FC") << numericField(prefixed( oInfo.m_sObjectCode, "F_DW"), "F_DW"); oInfo.m_listGroups << oGeometry << oFlow; listInfos.append(oInfo); } return listInfos; } if (eCategory == NM_RESERVOIR_PAGE_COMPOSITE_REGION) { for (int nIndex = 0; nIndex < oSnapshot.m_vecRegions.size(); ++nIndex) { nmReservoirPropertyObjectInfo oInfo; oInfo.m_eCategory = eCategory; oInfo.m_eObjectType = NM_RESERVOIR_OBJECT_REGION; oInfo.m_nSourceIndex = nIndex; oInfo.m_sObjectCode = QString("REGION%1") .arg(nIndex + 1, 4, 10, QChar('0')); oInfo.m_sDisplayName = oSnapshot.m_vecRegions[nIndex].getRegoinName(); nmReservoirParameterGroupInfo oRegion = parameterGroup("Boundary properties", 0, 0, 2); oRegion.m_bFieldsCentered = true; oRegion.m_listFields << leakageModelField(prefixed( oInfo.m_sObjectCode, "R_FlowModel"), "Boundary type", "Permeable boundary", "Composite boundary") << numericField(prefixed( oInfo.m_sObjectCode, "R_Leakage"), "R_Leakage"); oInfo.m_listGroups.append(oRegion); listInfos.append(oInfo); } } return listInfos; } QString nmReservoirParameterCatalog::enumCodeFromStoredValue( const QString& sParameterId, const QString& sStoredValue) { QString sValue = sStoredValue.trimmed().toLower(); if (sParameterId.endsWith("ReservoirType")) { return sValue.contains("dual") ? "dual_porosity_pss" : "homogeneous"; } if (sParameterId.endsWith("F_FlowModel")) { return sValue.contains("infinite") ? "infinite_conductivity" : "finite_conductivity"; } if (sParameterId.endsWith("FlowModel")) { return sValue.contains("leaky") ? "leaky" : "composite_limit"; } return QString(); } QString nmReservoirParameterCatalog::storedValueFromEnumCode( const QString& sParameterId, const QString& sCode) { if (sParameterId.endsWith("ReservoirType")) { return sCode == "dual_porosity_pss" ? "Dual porosity pseudo steady state" : "Homogeneous"; } if (sParameterId.endsWith("F_FlowModel")) { return sCode == "infinite_conductivity" ? "Infinite Conductivity" : "Finite Conductivity"; } if (sParameterId.endsWith("FlowModel")) { return sCode == "leaky" ? "Leaky" : "Composite limit"; } return QString(); } QString nmReservoirParameterCatalog::enumCode( const nmReservoirPropertiesSnapshot& oSnapshot, const QString& sParameterId) { if (sParameterId == "ReservoirType") { nmDataReservoir& oReservoir = const_cast(oSnapshot.m_oReservoir); return enumCodeFromStoredValue( sParameterId, oReservoir.getReservoirType().getValue().toString()); } QList listAll; nmReservoirPropertiesSnapshot& oWritable = const_cast(oSnapshot); listAll << createObjectInfos(NM_RESERVOIR_PAGE_FAULT, oWritable) << createObjectInfos(NM_RESERVOIR_PAGE_FRACTURE, oWritable) << createObjectInfos(NM_RESERVOIR_PAGE_COMPOSITE_REGION, oWritable) << createObjectInfos(NM_RESERVOIR_PAGE_REGION_MARK, oWritable); for (int nInfoIndex = 0; nInfoIndex < listAll.size(); ++nInfoIndex) { const nmReservoirPropertyObjectInfo& oInfo = listAll[nInfoIndex]; if (!containsEnumField(oInfo, sParameterId)) { continue; } if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_REGION_MARK) { nmDataRegionMark& oMark = oWritable.m_vecRegionMarks[oInfo.m_nSourceIndex]; return enumCodeFromStoredValue( sParameterId, oMark.getReservoirType().getValue().toString()); } if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_FAULT) { nmDataFault& oFault = oWritable.m_vecFaults[oInfo.m_nSourceIndex]; return enumCodeFromStoredValue( sParameterId, oFault.getFaultFlowModel().getValue().toString()); } if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_FRACTURE) { nmDataFracture& oFracture = oWritable.m_vecFractures[oInfo.m_nSourceIndex]; return enumCodeFromStoredValue( sParameterId, oFracture.getFractureFlowModel() .getValue().toString()); } if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_REGION) { nmDataRegion& oRegion = oWritable.m_vecRegions[oInfo.m_nSourceIndex]; return enumCodeFromStoredValue( sParameterId, oRegion.getRegionFlowModel().getValue().toString()); } } return QString(); } bool nmReservoirParameterCatalog::setEnumCode( nmReservoirPropertiesSnapshot& oSnapshot, const QString& sParameterId, const QString& sCode) { QString sStoredValue = storedValueFromEnumCode(sParameterId, sCode); if (sStoredValue.isEmpty()) { return false; } if (sParameterId == "ReservoirType") { oSnapshot.m_oReservoir.getReservoirType() .setValue(sStoredValue); return true; } QList listAll; listAll << createObjectInfos(NM_RESERVOIR_PAGE_FAULT, oSnapshot) << createObjectInfos(NM_RESERVOIR_PAGE_FRACTURE, oSnapshot) << createObjectInfos(NM_RESERVOIR_PAGE_COMPOSITE_REGION, oSnapshot) << createObjectInfos(NM_RESERVOIR_PAGE_REGION_MARK, oSnapshot); for (int nInfoIndex = 0; nInfoIndex < listAll.size(); ++nInfoIndex) { const nmReservoirPropertyObjectInfo& oInfo = listAll[nInfoIndex]; if (!containsEnumField(oInfo, sParameterId)) { continue; } if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_REGION_MARK) { oSnapshot.m_vecRegionMarks[oInfo.m_nSourceIndex] .getReservoirType().setValue(sStoredValue); return true; } if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_FAULT) { oSnapshot.m_vecFaults[oInfo.m_nSourceIndex] .getFaultFlowModel().setValue(sStoredValue); return true; } if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_FRACTURE) { oSnapshot.m_vecFractures[oInfo.m_nSourceIndex] .getFractureFlowModel().setValue(sStoredValue); return true; } if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_REGION) { oSnapshot.m_vecRegions[oInfo.m_nSourceIndex] .getRegionFlowModel().setValue(sStoredValue); return true; } } return false; }