You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmSubWxs/nmReservoirParameterCatalog...

1030 lines
39 KiB
C++

#include "nmReservoirParameterCatalog.h"
#include "nmReservoirPropertiesDataSource.h"
#include "nmAttrRegistry.h"
#include "nmDataAnalyzeManager.h"
#include "nmDataAttribute.h"
#include "nmDataPerforation.h"
#include <QCoreApplication>
namespace
{
/*
* Qt 4.8lupdateeditorText()
*
*/
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<nmReservoirPropertyObjectInfo>
nmReservoirParameterCatalog::createObjectInfos(
nmReservoirPropertiesCategory eCategory,
nmReservoirPropertiesSnapshot& oSnapshot)
{
QList<nmReservoirPropertyObjectInfo> 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<nmDataReservoir&>(oSnapshot.m_oReservoir);
return enumCodeFromStoredValue(
sParameterId,
oReservoir.getReservoirType().getValue().toString());
}
QList<nmReservoirPropertyObjectInfo> listAll;
nmReservoirPropertiesSnapshot& oWritable =
const_cast<nmReservoirPropertiesSnapshot&>(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<nmReservoirPropertyObjectInfo> 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;
}