|
|
#include "nmReservoirParameterCatalog.h"
|
|
|
|
|
|
#include "nmReservoirPropertiesDataSource.h"
|
|
|
#include "nmAttrRegistry.h"
|
|
|
#include "nmDataAttribute.h"
|
|
|
#include "nmDataPerforation.h"
|
|
|
|
|
|
#include <QCoreApplication>
|
|
|
|
|
|
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", "Region flow model"),
|
|
|
QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Leaky"),
|
|
|
QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Composite limit"),
|
|
|
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 properties"),
|
|
|
QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Fluid parameters"),
|
|
|
QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Compression 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", "Dual-medium parameters"),
|
|
|
QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Geometry"),
|
|
|
QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Flow properties"),
|
|
|
QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Conductivity properties"),
|
|
|
QT_TRANSLATE_NOOP("nmWxReservoirPropertiesEditor", "Region 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)
|
|
|
{
|
|
|
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", "Leaky"));
|
|
|
oField.m_listOptions.append(enumOption(
|
|
|
"composite_limit", "Composite limit"));
|
|
|
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;
|
|
|
return oGroup;
|
|
|
}
|
|
|
|
|
|
/** @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_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("Swi", &oSnapshot.m_oReservoir.getSwi());
|
|
|
pRegistry->regAttr("Bo", &oSnapshot.m_oReservoir.getBo());
|
|
|
pRegistry->regAttr("Miuo", &oSnapshot.m_oReservoir.getMiuo());
|
|
|
pRegistry->regAttr("KxKy", &oSnapshot.m_oReservoir.getKxKy());
|
|
|
|
|
|
// 第二步:注册求解器支持的三类井及其压裂参数。
|
|
|
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");
|
|
|
|
|
|
nmReservoirParameterGroupInfo oBasic =
|
|
|
parameterGroup("Basic 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("Fluid parameters", 0, 1, 1);
|
|
|
oFluid.m_listFields
|
|
|
<< reservoirModelField("ReservoirType")
|
|
|
<< numericField("Miuo", "Miuo")
|
|
|
<< unitlessNumericField("Bo", "Bo")
|
|
|
<< numericField("KxKy", "KxKy");
|
|
|
|
|
|
nmReservoirParameterGroupInfo oCompression =
|
|
|
parameterGroup("Compression and saturation", 1, 1, 1);
|
|
|
oCompression.m_listFields
|
|
|
<< numericField("Cti", "Cti")
|
|
|
<< numericField("Cf", "Cf")
|
|
|
<< numericField("Soi", "Soi")
|
|
|
<< numericField("Swi", "Swi");
|
|
|
oInfo.m_listGroups << oBasic << oFluid << 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("Dual-medium parameters", 0, 0, 2);
|
|
|
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_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")
|
|
|
<< 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_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("Region properties", 0, 0, 2);
|
|
|
oRegion.m_listFields
|
|
|
<< leakageModelField(prefixed(
|
|
|
oInfo.m_sObjectCode, "R_FlowModel"),
|
|
|
"Region flow model")
|
|
|
<< 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;
|
|
|
}
|