From 4583e657cfa9766f7d7c4d799d142b81e240644b Mon Sep 17 00:00:00 2001 From: lvjunjie Date: Mon, 14 Sep 2026 10:26:43 +0800 Subject: [PATCH] =?UTF-8?q?fix(nmNum):=20=E8=A1=A5=E9=BD=90=E6=B0=94?= =?UTF-8?q?=E4=BA=95=E7=9B=AE=E6=A0=87=E5=8E=86=E5=8F=B2=E6=9B=B2=E7=BA=BF?= =?UTF-8?q?=E7=9A=84=E6=8B=9F=E5=8E=8B=E5=8A=9B=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 复用框架 calPS 接口和所属分析窗口配置,转换气井目标曲线的双对数、半对数计算输入 - 生成结果及开始自动拟合前刷新气井历史缓存,避免继续使用未转换的目标曲线 - 保留原始历史压力,转换失败时清除旧曲线有效标记,无曲线计算条件时跳过转换 --- .../nmData/nmDataAnalyzeContextProvider.h | 4 ++ .../nmSubWnd/nmSubWndDataAnalyzeController.h | 4 ++ .../nmCalculationDllPebiSolverTask.cpp | 9 +++++ Src/nmNum/nmData/nmDataAnalyzeManager.cpp | 37 +++++++++++++++---- .../nmSubWndDataAnalyzeController.cpp | 30 +++++++++++++++ Src/nmNum/nmSubWxs/nmWxAutomaticFitting.cpp | 7 ++++ 6 files changed, 83 insertions(+), 8 deletions(-) diff --git a/Include/nmNum/nmData/nmDataAnalyzeContextProvider.h b/Include/nmNum/nmData/nmDataAnalyzeContextProvider.h index 63f8770f..4b713e83 100644 --- a/Include/nmNum/nmData/nmDataAnalyzeContextProvider.h +++ b/Include/nmNum/nmData/nmDataAnalyzeContextProvider.h @@ -54,4 +54,8 @@ class NM_DATA_EXPORT nmDataAnalyzeContextProvider { // 获取当前结果窗口对应的数值结果保存目录 virtual bool getSaveResultDir(void* pFitting, const QString& sRstCode, QString& sDir) = 0; + + // 使用所属分析窗口的配置,将原始压力逐点转换为拟压力。 + virtual bool convertPressureToPseudoPressure( + void* pFitting, const VecDouble& vecPressure, VecDouble& vecPseudoPressure) = 0; }; diff --git a/Include/nmNum/nmSubWnd/nmSubWndDataAnalyzeController.h b/Include/nmNum/nmSubWnd/nmSubWndDataAnalyzeController.h index 6df95781..5739493b 100644 --- a/Include/nmNum/nmSubWnd/nmSubWndDataAnalyzeController.h +++ b/Include/nmNum/nmSubWnd/nmSubWndDataAnalyzeController.h @@ -49,6 +49,10 @@ class NM_SUB_WND_EXPORT nmSubWndDataAnalyzeController : public nmDataAnalyzeCont // 获取当前结果窗口对应的数值结果保存目录 bool getSaveResultDir(void* pFitting, const QString& sRstCode, QString& sDir); + // 复用框架转换器,供气井历史曲线计算使用。 + bool convertPressureToPseudoPressure( + void* pFitting, const VecDouble& vecPressure, VecDouble& vecPseudoPressure); + private: nmSubWndDataAnalyzeController() {} }; diff --git a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp index 3c49f3a1..3220d85b 100644 --- a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp +++ b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp @@ -206,6 +206,7 @@ bool isDisplayResultWell( } bool captureResultWellMetadata( + nmDataAnalyzeManager* pDataManager, nmDataWellBase* pWellData, bool bDisplayResultWell, nmPebiWellInputSnapshot& oWellInput) @@ -219,6 +220,12 @@ bool captureResultWellMetadata( return false; } + // 发布结果前用当前配置重算气井历史曲线,替换旧项目中未转拟压力的缓存。 + if(pDataManager->getSolverModelType() == SMT_Gas_VariablePvt + && !pDataManager->updateWellHistoryData(pWellData)) { + return false; + } + const QString sCurrentGaugeInputSha1 = pWellData->calculateGaugeInputSha1(); if(sCurrentGaugeInputSha1.isEmpty() || @@ -862,6 +869,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep( } if(m_pInputSnapshot->m_oGridInput.m_vecWellInputs.isEmpty() || !captureResultWellMetadata( + m_pDataManager, pWellData, isDisplayResultWell(pAnalysisCase, pWellData->getWellCode()), @@ -1050,6 +1058,7 @@ bool nmCalculationDllPebiSolverTask::captureInputSnapshot( mapWellsByCode.value(oWellRef.m_sWellCode, NULL); if(pWellData == NULL || !captureResultWellMetadata( + m_pDataManager, pWellData, isDisplayResultWell(pAnalysisCase, oWellRef.m_sWellCode), diff --git a/Src/nmNum/nmData/nmDataAnalyzeManager.cpp b/Src/nmNum/nmData/nmDataAnalyzeManager.cpp index 6d30f50f..eb8b2fe1 100644 --- a/Src/nmNum/nmData/nmDataAnalyzeManager.cpp +++ b/Src/nmNum/nmData/nmDataAnalyzeManager.cpp @@ -2186,8 +2186,9 @@ void nmDataAnalyzeManager::initCurWellData() } } -static void calculateLogDataFromGaugeInput( +static bool calculateLogDataFromGaugeInput( const nmWellGaugeInputData& oGaugeInput, + bool bUsePseudoPressure, void* pFitting, QVector>& vvecHistoryData, QVector>& vvecLogPreData, QVector>& vvecSemiLogPreData) @@ -2234,9 +2235,24 @@ static void calculateLogDataFromGaugeInput( pReferenceRates->size() != oGaugeInput.vecFlowDurations.size() || oGaugeInput.nFlowSectionIndex < 1 || 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(); std::vector timeQ(nTimeNumQ); std::vector q(nTimeNumQ); @@ -2259,14 +2275,14 @@ static void calculateLogDataFromGaugeInput( if(nullptr == preLogFun) { FreeLibrary(hMod_solver); std::cout << "preLogFun failed!\n"; - return; + return false; } bool bCalculated = preLogFun(wellPressureData, iSectionFlowIndex, timeQ.data(), q.data(), nTimeNumQ, logPre); if(!bCalculated || logPre.empty()) { FreeLibrary(hMod_solver); - return; + return false; } // The solver's final point is not part of the plotted result. @@ -2285,7 +2301,9 @@ static void calculateLogDataFromGaugeInput( } FreeLibrary(hMod_solver); + return true; } + return false; } nmDataWellBase* nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData) @@ -3039,7 +3057,8 @@ void nmDataAnalyzeManager::calculationLogData( } nmWellGaugeInputData oGaugeInput; pWellData->buildGaugeInputData(oGaugeInput); - calculateLogDataFromGaugeInput(oGaugeInput, vvecHistoryData, + calculateLogDataFromGaugeInput(oGaugeInput, + getSolverModelType() == SMT_Gas_VariablePvt, m_pOwnerFitting, vvecHistoryData, vvecLogPreData, vvecSemiLogPreData); } @@ -3059,11 +3078,13 @@ bool nmDataAnalyzeManager::updateWellHistoryData( QVector > vecHistoryPressure; QVector > vecHistoryLogLog; QVector > vecHistorySemiLog; - calculateLogDataFromGaugeInput(oGaugeInput, vecHistoryPressure, + const bool bCalculated = calculateLogDataFromGaugeInput(oGaugeInput, + getSolverModelType() == SMT_Gas_VariablePvt, m_pOwnerFitting, vecHistoryPressure, vecHistoryLogLog, vecHistorySemiLog); + // 转换或计算失败时清除旧曲线的有效标记,避免继续使用旧的压力曲线。 pWellData->setHistoryData(vecHistoryPressure, vecHistoryLogLog, - vecHistorySemiLog, sGaugeInputSha1); - return true; + vecHistorySemiLog, bCalculated ? sGaugeInputSha1 : QString()); + return bCalculated; } bool nmDataAnalyzeManager::resetFromAnalytical() diff --git a/Src/nmNum/nmSubWnd/nmSubWndDataAnalyzeController.cpp b/Src/nmNum/nmSubWnd/nmSubWndDataAnalyzeController.cpp index d56701ea..f6fa5cfc 100644 --- a/Src/nmNum/nmSubWnd/nmSubWndDataAnalyzeController.cpp +++ b/Src/nmNum/nmSubWnd/nmSubWndDataAnalyzeController.cpp @@ -181,6 +181,36 @@ bool nmSubWndDataAnalyzeController::getDiffusionRstOf(void* pFitting, DiffusionS 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) { // 先按当前井和相态配置拟压力算法,确保转换规则与自动拟合界面一致。 diff --git a/Src/nmNum/nmSubWxs/nmWxAutomaticFitting.cpp b/Src/nmNum/nmSubWxs/nmWxAutomaticFitting.cpp index 32684d4b..09a85b59 100644 --- a/Src/nmNum/nmSubWxs/nmWxAutomaticFitting.cpp +++ b/Src/nmNum/nmSubWxs/nmWxAutomaticFitting.cpp @@ -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 > targetLogLogData = pTargetWell->getHistoryLogLog();