|
|
|
@ -77,6 +77,23 @@ bool isValidSemiLogPoint(const Point& pt)
|
|
|
|
&& isReasonableLogLogValue(pt.pointData[0]);
|
|
|
|
&& isReasonableLogLogValue(pt.pointData[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef bool (*CalPseudoPressure)(double, double&, int);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// mAlgPseudo.dll 是主界面拟压力算法所在模块.
|
|
|
|
|
|
|
|
// 此处直接解析 iAlgPseuCaller::calPS 的导出符号, 复用主界面的同一套转换实现.
|
|
|
|
|
|
|
|
// 函数参数依次为原始压力、输出拟压力和拟压力分区编号.
|
|
|
|
|
|
|
|
CalPseudoPressure getPseudoPressureConverter()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 静态保存模块和函数地址, 避免每个粒子、每个压力点重复加载和解析 DLL.
|
|
|
|
|
|
|
|
// configPsAbouts() 初始化的数据及模式也保存在同一个 mAlgPseudo.dll 模块中.
|
|
|
|
|
|
|
|
static HMODULE module = LoadLibraryW(L"mAlgPseudo.dll");
|
|
|
|
|
|
|
|
static CalPseudoPressure converter = module
|
|
|
|
|
|
|
|
? reinterpret_cast<CalPseudoPressure>(GetProcAddress(
|
|
|
|
|
|
|
|
module, "?calPS@iAlgPseuCaller@@SA_NNAANH@Z"))
|
|
|
|
|
|
|
|
: nullptr;
|
|
|
|
|
|
|
|
return converter;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// @brief 将常数PVT单值扩展为200元素数组(PEBI求解器要求数组输入)
|
|
|
|
/// @brief 将常数PVT单值扩展为200元素数组(PEBI求解器要求数组输入)
|
|
|
|
/// @param dValue 常数PVT值
|
|
|
|
/// @param dValue 常数PVT值
|
|
|
|
/// @param nSize 数组大小,默认200
|
|
|
|
/// @param nSize 数组大小,默认200
|
|
|
|
@ -186,7 +203,8 @@ nmCalculationDllPebiSolverTask::nmCalculationDllPebiSolverTask(
|
|
|
|
QString sPostprocessingDir,
|
|
|
|
QString sPostprocessingDir,
|
|
|
|
QObject *parent):
|
|
|
|
QObject *parent):
|
|
|
|
QThread(parent),
|
|
|
|
QThread(parent),
|
|
|
|
m_sPostprocessingDir(sPostprocessingDir)
|
|
|
|
m_sPostprocessingDir(sPostprocessingDir),
|
|
|
|
|
|
|
|
m_lastRunSucceeded(false)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -200,8 +218,13 @@ nmCalculationDllPebiSolverTask::~nmCalculationDllPebiSolverTask()
|
|
|
|
|
|
|
|
|
|
|
|
void nmCalculationDllPebiSolverTask::run()
|
|
|
|
void nmCalculationDllPebiSolverTask::run()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
bool result = this->execute();
|
|
|
|
m_lastRunSucceeded = this->execute();
|
|
|
|
emit sig_calculateDone(result);
|
|
|
|
emit sig_calculateDone(m_lastRunSucceeded);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool nmCalculationDllPebiSolverTask::wasSuccessful() const
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return m_lastRunSucceeded;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmCalculationDllPebiSolverTask::execute()
|
|
|
|
bool nmCalculationDllPebiSolverTask::execute()
|
|
|
|
@ -244,7 +267,8 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
|
|
|
|
HX_NWTM_MODEL_INPUT p0(pGridInstance->getGridOutput2());
|
|
|
|
HX_NWTM_MODEL_INPUT p0(pGridInstance->getGridOutput2());
|
|
|
|
nmDataReservoir* pReservoirData = pDataInstance->getReservoirData();
|
|
|
|
nmDataReservoir* pReservoirData = pDataInstance->getReservoirData();
|
|
|
|
// 根据PVT参数获取结果选择求解器模型类型
|
|
|
|
// 根据PVT参数获取结果选择求解器模型类型
|
|
|
|
p0.T = static_cast<int>(pDataInstance->getSolverModelType());
|
|
|
|
const int modelType = static_cast<int>(pDataInstance->getSolverModelType());
|
|
|
|
|
|
|
|
p0.T = modelType;
|
|
|
|
|
|
|
|
|
|
|
|
// 获取PEBI网格存入井的顺序
|
|
|
|
// 获取PEBI网格存入井的顺序
|
|
|
|
QVector<QPair<NM_WELL_MODEL, QString>> vecWellsOrder = pDataInstance->getCalculationWells();
|
|
|
|
QVector<QPair<NM_WELL_MODEL, QString>> vecWellsOrder = pDataInstance->getCalculationWells();
|
|
|
|
@ -513,7 +537,7 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存计算结果
|
|
|
|
// 保存计算结果
|
|
|
|
bool success = this->savePebiModeResult(p1);
|
|
|
|
bool success = this->savePebiModeResult(p1, modelType);
|
|
|
|
|
|
|
|
|
|
|
|
FreeLibrary(dll); // 卸载 DLL
|
|
|
|
FreeLibrary(dll); // 卸载 DLL
|
|
|
|
return success;
|
|
|
|
return success;
|
|
|
|
@ -553,13 +577,26 @@ std::vector<double> HX_logderivative(const std::vector<double>& x, const std::ve
|
|
|
|
return d;
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmCalculationDllPebiSolverTask::savePebiModeResult(HX_NWTM_MODEL_OUTPUT& p1)
|
|
|
|
bool nmCalculationDllPebiSolverTask::savePebiModeResult(
|
|
|
|
|
|
|
|
HX_NWTM_MODEL_OUTPUT& p1,
|
|
|
|
|
|
|
|
int modelType)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
nmDataAnalyzeManager* pDataInstance = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
nmDataAnalyzeManager* pDataInstance = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
|
|
|
|
|
|
|
|
QVector<QVector<double>> vvecPressure;
|
|
|
|
QVector<QVector<double>> vvecPressure;
|
|
|
|
QVector<QVector<double>> vvecLogLog;
|
|
|
|
QVector<QVector<double>> vvecLogLog;
|
|
|
|
QVector<QVector<double>> vvecSemiLog;
|
|
|
|
QVector<QVector<double>> vvecSemiLog;
|
|
|
|
|
|
|
|
// p1.pw 是求解器返回的原始井底压力, 后续仍按 MPa 保存到 vvecPressure.
|
|
|
|
|
|
|
|
// 只有气单相变化 PVT 模型的双对数和半对数计算需要改用拟压力.
|
|
|
|
|
|
|
|
const bool usePseudoPressure = (modelType == static_cast<int>(SMT_Gas_VariablePvt));
|
|
|
|
|
|
|
|
CalPseudoPressure calPseudoPressure = usePseudoPressure
|
|
|
|
|
|
|
|
? getPseudoPressureConverter()
|
|
|
|
|
|
|
|
: nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(usePseudoPressure && calPseudoPressure == nullptr) {
|
|
|
|
|
|
|
|
qWarning() << "Failed to load the gas pseudo-pressure converter.";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取参与求解的井的顺序
|
|
|
|
// 获取参与求解的井的顺序
|
|
|
|
QVector<QPair<NM_WELL_MODEL, QString>> vecWellsOrder = nmDataAnalyzeManager::getCurrentInstance()->getCalculationWells();
|
|
|
|
QVector<QPair<NM_WELL_MODEL, QString>> vecWellsOrder = nmDataAnalyzeManager::getCurrentInstance()->getCalculationWells();
|
|
|
|
@ -615,7 +652,19 @@ bool nmCalculationDllPebiSolverTask::savePebiModeResult(HX_NWTM_MODEL_OUTPUT& p1
|
|
|
|
pt.x = 0.0; // 或者进行错误处理
|
|
|
|
pt.x = 0.0; // 或者进行错误处理
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pt.y = p1.pw[wellIdx][i];
|
|
|
|
// 使用局部副本转换, 不修改 p1.pw 中需要保存和显示的原始压力.
|
|
|
|
|
|
|
|
double pressureForLog = p1.pw[wellIdx][i];
|
|
|
|
|
|
|
|
if(usePseudoPressure
|
|
|
|
|
|
|
|
&& (!isFiniteSolverNumber(pressureForLog)
|
|
|
|
|
|
|
|
// -1 与主界面调用一致, 表示使用 configPsAbouts() 配置的当前模式.
|
|
|
|
|
|
|
|
|| !calPseudoPressure(pressureForLog, pressureForLog, -1)
|
|
|
|
|
|
|
|
|| !isFiniteSolverNumber(pressureForLog))) {
|
|
|
|
|
|
|
|
qWarning() << "Failed to convert gas pressure to pseudo-pressure:"
|
|
|
|
|
|
|
|
<< p1.pw[wellIdx][i] << "well:" << sWellName;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pt.y = pressureForLog;
|
|
|
|
pt.z = 0.0; // 假设这里的 z 是 0
|
|
|
|
pt.z = 0.0; // 假设这里的 z 是 0
|
|
|
|
wellPressureDataForDll.push_back(pt);
|
|
|
|
wellPressureDataForDll.push_back(pt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -648,7 +697,17 @@ bool nmCalculationDllPebiSolverTask::savePebiModeResult(HX_NWTM_MODEL_OUTPUT& p1
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
preLogFun(wellPressureDataForDll, iSectionFlowIndex, timeQ.data(), q.data(), nTimeNumQ, logPreResultFromDll);
|
|
|
|
// 气井传入拟压力序列, 油井和水井仍传入原始压力序列.
|
|
|
|
|
|
|
|
// 计算失败必须向上返回, 避免 PSO 使用空曲线或上一粒子的旧曲线.
|
|
|
|
|
|
|
|
if(!preLogFun(wellPressureDataForDll,
|
|
|
|
|
|
|
|
iSectionFlowIndex,
|
|
|
|
|
|
|
|
timeQ.data(),
|
|
|
|
|
|
|
|
q.data(),
|
|
|
|
|
|
|
|
nTimeNumQ,
|
|
|
|
|
|
|
|
logPreResultFromDll)) {
|
|
|
|
|
|
|
|
FreeLibrary(hMod_solver);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 填充双对数曲线数据到局部变量
|
|
|
|
// 填充双对数曲线数据到局部变量
|
|
|
|
QVector<double> logX, logY, logZ;
|
|
|
|
QVector<double> logX, logY, logZ;
|
|
|
|
@ -695,6 +754,9 @@ bool nmCalculationDllPebiSolverTask::savePebiModeResult(HX_NWTM_MODEL_OUTPUT& p1
|
|
|
|
vvecSemiLog.append(semiLogY);
|
|
|
|
vvecSemiLog.append(semiLogY);
|
|
|
|
|
|
|
|
|
|
|
|
FreeLibrary(hMod_solver);
|
|
|
|
FreeLibrary(hMod_solver);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
qWarning() << "Failed to load singlePhaseSolverDll.dll.";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|