fix(nmNum): 补齐气井目标历史曲线的拟压力转换

- 复用框架 calPS 接口和所属分析窗口配置,转换气井目标曲线的双对数、半对数计算输入
- 生成结果及开始自动拟合前刷新气井历史缓存,避免继续使用未转换的目标曲线
- 保留原始历史压力,转换失败时清除旧曲线有效标记,无曲线计算条件时跳过转换
develop
lvjunjie 3 weeks ago
parent 13a7318267
commit 4583e657cf

@ -54,4 +54,8 @@ class NM_DATA_EXPORT nmDataAnalyzeContextProvider {
// 获取当前结果窗口对应的数值结果保存目录 // 获取当前结果窗口对应的数值结果保存目录
virtual bool getSaveResultDir(void* pFitting, const QString& sRstCode, QString& sDir) = 0; virtual bool getSaveResultDir(void* pFitting, const QString& sRstCode, QString& sDir) = 0;
// 使用所属分析窗口的配置,将原始压力逐点转换为拟压力。
virtual bool convertPressureToPseudoPressure(
void* pFitting, const VecDouble& vecPressure, VecDouble& vecPseudoPressure) = 0;
}; };

@ -49,6 +49,10 @@ class NM_SUB_WND_EXPORT nmSubWndDataAnalyzeController : public nmDataAnalyzeCont
// 获取当前结果窗口对应的数值结果保存目录 // 获取当前结果窗口对应的数值结果保存目录
bool getSaveResultDir(void* pFitting, const QString& sRstCode, QString& sDir); bool getSaveResultDir(void* pFitting, const QString& sRstCode, QString& sDir);
// 复用框架转换器,供气井历史曲线计算使用。
bool convertPressureToPseudoPressure(
void* pFitting, const VecDouble& vecPressure, VecDouble& vecPseudoPressure);
private: private:
nmSubWndDataAnalyzeController() {} nmSubWndDataAnalyzeController() {}
}; };

@ -206,6 +206,7 @@ bool isDisplayResultWell(
} }
bool captureResultWellMetadata( bool captureResultWellMetadata(
nmDataAnalyzeManager* pDataManager,
nmDataWellBase* pWellData, nmDataWellBase* pWellData,
bool bDisplayResultWell, bool bDisplayResultWell,
nmPebiWellInputSnapshot& oWellInput) nmPebiWellInputSnapshot& oWellInput)
@ -219,6 +220,12 @@ bool captureResultWellMetadata(
return false; return false;
} }
// 发布结果前用当前配置重算气井历史曲线,替换旧项目中未转拟压力的缓存。
if(pDataManager->getSolverModelType() == SMT_Gas_VariablePvt
&& !pDataManager->updateWellHistoryData(pWellData)) {
return false;
}
const QString sCurrentGaugeInputSha1 = const QString sCurrentGaugeInputSha1 =
pWellData->calculateGaugeInputSha1(); pWellData->calculateGaugeInputSha1();
if(sCurrentGaugeInputSha1.isEmpty() || if(sCurrentGaugeInputSha1.isEmpty() ||
@ -862,6 +869,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep(
} }
if(m_pInputSnapshot->m_oGridInput.m_vecWellInputs.isEmpty() || if(m_pInputSnapshot->m_oGridInput.m_vecWellInputs.isEmpty() ||
!captureResultWellMetadata( !captureResultWellMetadata(
m_pDataManager,
pWellData, pWellData,
isDisplayResultWell(pAnalysisCase, isDisplayResultWell(pAnalysisCase,
pWellData->getWellCode()), pWellData->getWellCode()),
@ -1050,6 +1058,7 @@ bool nmCalculationDllPebiSolverTask::captureInputSnapshot(
mapWellsByCode.value(oWellRef.m_sWellCode, NULL); mapWellsByCode.value(oWellRef.m_sWellCode, NULL);
if(pWellData == NULL || if(pWellData == NULL ||
!captureResultWellMetadata( !captureResultWellMetadata(
m_pDataManager,
pWellData, pWellData,
isDisplayResultWell(pAnalysisCase, isDisplayResultWell(pAnalysisCase,
oWellRef.m_sWellCode), oWellRef.m_sWellCode),

@ -2186,8 +2186,9 @@ void nmDataAnalyzeManager::initCurWellData()
} }
} }
static void calculateLogDataFromGaugeInput( static bool calculateLogDataFromGaugeInput(
const nmWellGaugeInputData& oGaugeInput, const nmWellGaugeInputData& oGaugeInput,
bool bUsePseudoPressure, void* pFitting,
QVector<QVector<double>>& vvecHistoryData, QVector<QVector<double>>& vvecHistoryData,
QVector<QVector<double>>& vvecLogPreData, QVector<QVector<double>>& vvecLogPreData,
QVector<QVector<double>>& vvecSemiLogPreData) QVector<QVector<double>>& vvecSemiLogPreData)
@ -2234,9 +2235,24 @@ static void calculateLogDataFromGaugeInput(
pReferenceRates->size() != oGaugeInput.vecFlowDurations.size() || pReferenceRates->size() != oGaugeInput.vecFlowDurations.size() ||
oGaugeInput.nFlowSectionIndex < 1 || oGaugeInput.nFlowSectionIndex < 1 ||
oGaugeInput.nFlowSectionIndex > oGaugeInput.vecFlowDurations.size()) { oGaugeInput.nFlowSectionIndex > oGaugeInput.vecFlowDurations.size()) {
return; return true;
} }
// 原始历史压力保持 MPa;只有传给双对数、半对数算法的副本转换为拟压力。
if(bUsePseudoPressure && !vecPressure.isEmpty()) {
nmDataAnalyzeContextProvider* pContext = nmDataAnalyzeContext::provider();
VecDouble vecPseudoPressure;
if(pContext == nullptr
|| !pContext->convertPressureToPseudoPressure(
pFitting, vvecHistoryData[1], vecPseudoPressure)) {
qWarning() << "Failed to convert gas history pressure to pseudo-pressure.";
return false;
}
for(int i = 0; i < vecPseudoPressure.size(); ++i) {
wellPressureData[i].y = vecPseudoPressure[i];
}
}
const int nTimeNumQ = oGaugeInput.vecFlowDurations.size(); const int nTimeNumQ = oGaugeInput.vecFlowDurations.size();
std::vector<double> timeQ(nTimeNumQ); std::vector<double> timeQ(nTimeNumQ);
std::vector<double> q(nTimeNumQ); std::vector<double> q(nTimeNumQ);
@ -2259,14 +2275,14 @@ static void calculateLogDataFromGaugeInput(
if(nullptr == preLogFun) { if(nullptr == preLogFun) {
FreeLibrary(hMod_solver); FreeLibrary(hMod_solver);
std::cout << "preLogFun failed!\n"; std::cout << "preLogFun failed!\n";
return; return false;
} }
bool bCalculated = preLogFun(wellPressureData, iSectionFlowIndex, bool bCalculated = preLogFun(wellPressureData, iSectionFlowIndex,
timeQ.data(), q.data(), nTimeNumQ, logPre); timeQ.data(), q.data(), nTimeNumQ, logPre);
if(!bCalculated || logPre.empty()) { if(!bCalculated || logPre.empty()) {
FreeLibrary(hMod_solver); FreeLibrary(hMod_solver);
return; return false;
} }
// The solver's final point is not part of the plotted result. // The solver's final point is not part of the plotted result.
@ -2285,7 +2301,9 @@ static void calculateLogDataFromGaugeInput(
} }
FreeLibrary(hMod_solver); FreeLibrary(hMod_solver);
return true;
} }
return false;
} }
nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData) nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
@ -3039,7 +3057,8 @@ void nmDataAnalyzeManager::calculationLogData(
} }
nmWellGaugeInputData oGaugeInput; nmWellGaugeInputData oGaugeInput;
pWellData->buildGaugeInputData(oGaugeInput); pWellData->buildGaugeInputData(oGaugeInput);
calculateLogDataFromGaugeInput(oGaugeInput, vvecHistoryData, calculateLogDataFromGaugeInput(oGaugeInput,
getSolverModelType() == SMT_Gas_VariablePvt, m_pOwnerFitting, vvecHistoryData,
vvecLogPreData, vvecSemiLogPreData); vvecLogPreData, vvecSemiLogPreData);
} }
@ -3059,11 +3078,13 @@ bool nmDataAnalyzeManager::updateWellHistoryData(
QVector<QVector<double> > vecHistoryPressure; QVector<QVector<double> > vecHistoryPressure;
QVector<QVector<double> > vecHistoryLogLog; QVector<QVector<double> > vecHistoryLogLog;
QVector<QVector<double> > vecHistorySemiLog; QVector<QVector<double> > vecHistorySemiLog;
calculateLogDataFromGaugeInput(oGaugeInput, vecHistoryPressure, const bool bCalculated = calculateLogDataFromGaugeInput(oGaugeInput,
getSolverModelType() == SMT_Gas_VariablePvt, m_pOwnerFitting, vecHistoryPressure,
vecHistoryLogLog, vecHistorySemiLog); vecHistoryLogLog, vecHistorySemiLog);
// 转换或计算失败时清除旧曲线的有效标记,避免继续使用旧的压力曲线。
pWellData->setHistoryData(vecHistoryPressure, vecHistoryLogLog, pWellData->setHistoryData(vecHistoryPressure, vecHistoryLogLog,
vecHistorySemiLog, sGaugeInputSha1); vecHistorySemiLog, bCalculated ? sGaugeInputSha1 : QString());
return true; return bCalculated;
} }
bool nmDataAnalyzeManager::resetFromAnalytical() bool nmDataAnalyzeManager::resetFromAnalytical()

@ -181,6 +181,36 @@ bool nmSubWndDataAnalyzeController::getDiffusionRstOf(void* pFitting, DiffusionS
return pSubWndFitting->getDiffusionRstOf(dso, vvec); return pSubWndFitting->getDiffusionRstOf(dso, vvec);
} }
bool nmSubWndDataAnalyzeController::convertPressureToPseudoPressure(
void* pFitting, const VecDouble& vecPressure, VecDouble& vecPseudoPressure)
{
vecPseudoPressure.clear();
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
iAnalRun* pAnalRun = pSubWndFitting ? pSubWndFitting->getAnalRun() : nullptr;
// 与模拟曲线保持一致,初始化所属窗口的配置后直接调用 calPS,不另做插值。
if(pAnalRun == nullptr
|| !pAnalRun->configPsAbouts(true, pSubWndFitting->getModelOption(),
false, pSubWndFitting->getAllWxPtr())) {
return false;
}
CalPseudoPressure converter = getPseudoPressureConverter();
if(converter == nullptr) {
return false;
}
VecDouble vecConverted;
vecConverted.reserve(vecPressure.size());
for(int i = 0; i < vecPressure.size(); ++i) {
double ps = 0.0;
if(!qIsFinite(vecPressure[i])
|| !converter(vecPressure[i], ps, -1) || !qIsFinite(ps)) {
return false;
}
vecConverted.append(ps);
}
vecPseudoPressure.swap(vecConverted);
return true;
}
bool nmSubWndDataAnalyzeController::getPseuRstOf(void* pFitting, VVecDouble& vvec) bool nmSubWndDataAnalyzeController::getPseuRstOf(void* pFitting, VVecDouble& vvec)
{ {
// 先按当前井和相态配置拟压力算法,确保转换规则与自动拟合界面一致。 // 先按当前井和相态配置拟压力算法,确保转换规则与自动拟合界面一致。

@ -968,6 +968,13 @@ void nmWxAutomaticFitting::onAccept()
} }
} }
// 开始拟合前重算气井目标,避免旧缓存或已修改的拟压力配置造成量纲不一致。
if(usePseudoPressure && !pManager->updateWellHistoryData(pTargetWell)) {
QMessageBox::warning(this, tr("Warning"),
tr("Gas pseudo-pressure data is unavailable or invalid."));
return;
}
// 油、气、水井统一读取所选目标井的历史曲线,不依赖主界面显示的结果井。 // 油、气、水井统一读取所选目标井的历史曲线,不依赖主界面显示的结果井。
QVector<QVector<double> > targetLogLogData = pTargetWell->getHistoryLogLog(); QVector<QVector<double> > targetLogLogData = pTargetWell->getHistoryLogLog();

Loading…
Cancel
Save