From c210cd7b39619af5ae0cc4963eb7081c0db79df0 Mon Sep 17 00:00:00 2001 From: lvjunjie Date: Fri, 21 Aug 2026 15:58:27 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=B5=81=E9=87=8F=E4=B8=BA=E7=A9=BA=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E6=B5=81=E9=87=8F=E6=AE=B5=E6=95=B0=E9=87=8F=E8=AE=BE?= =?UTF-8?q?=E4=B8=BA=200=EF=BC=8C=E4=B8=8D=E4=BC=9A=E5=87=BA=E7=8E=B0=20-1?= =?UTF-8?q?=20=E8=A2=AB=E8=BD=AC=E6=8D=A2=E6=88=90=E5=B7=A8=E5=A4=A7?= =?UTF-8?q?=E6=95=B0=E7=BB=84=E9=95=BF=E5=BA=A6=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E3=80=82=202.=E8=AE=A1=E7=AE=97=E8=AF=AF=E5=B7=AE=E6=97=B6?= =?UTF-8?q?=E8=B7=B3=E8=BF=87=E7=9B=AE=E6=A0=87=E6=9B=B2=E7=BA=BF=E7=AC=AC?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E7=82=B9=EF=BC=8C=E4=BF=AE=E5=A4=8D=E5=85=AC?= =?UTF-8?q?=E5=85=B1=E6=97=B6=E9=97=B4=E8=BD=B4=E7=AB=AF=E7=82=B9=E7=9A=84?= =?UTF-8?q?=E6=B5=AE=E7=82=B9=E8=AF=AF=E5=B7=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nmCalculation/nmCalculationAutoFitPSO.cpp | 32 +++++++++++++------ .../nmCalculationDllPebiSolverTask.cpp | 22 ++++++++++--- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/Src/nmNum/nmCalculation/nmCalculationAutoFitPSO.cpp b/Src/nmNum/nmCalculation/nmCalculationAutoFitPSO.cpp index cb510f6..6f0bd52 100644 --- a/Src/nmNum/nmCalculation/nmCalculationAutoFitPSO.cpp +++ b/Src/nmNum/nmCalculation/nmCalculationAutoFitPSO.cpp @@ -6568,15 +6568,17 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError( // 无法比较的采样行先跳过;有限但非正的导数无法进入双对数空间, // 当前数据又没有逐点有效掩码,因此遇到这种导数时判本次评价无效。 auto prepareCurve = [valueFloor](const QVector >& data, + int firstIndex, QVector* pressure, QVector* derivative) -> bool { if(!pressure || !derivative || data.size() < 3 || data[0].size() != data[1].size() || - data[0].size() != data[2].size()) { + data[0].size() != data[2].size() || + firstIndex < 0 || firstIndex >= data[0].size()) { return false; } - for(int i = 0; i < data[0].size(); ++i) { + for(int i = firstIndex; i < data[0].size(); ++i) { if(!isFiniteNumber(data[0][i]) || !isFiniteNumber(data[1][i]) || !isFiniteNumber(data[2][i]) || @@ -6624,8 +6626,9 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError( QVector targetDerivative; QVector resultPressure; QVector resultDerivative; - if(!prepareCurve(target, &targetPressure, &targetDerivative) || - !prepareCurve(result, &resultPressure, &resultDerivative)) { + // 模拟结果已跳过 DLL 首点,因此误差计算同步忽略目标曲线首点。 + if(!prepareCurve(target, 1, &targetPressure, &targetDerivative) || + !prepareCurve(result, 0, &resultPressure, &resultDerivative)) { return invalidLoss; } @@ -6721,7 +6724,14 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError( (targetLogMaxX - targetLogMinX) / (numPoints - 1); commonLogX[i] = logX; - commonX[i] = qExp(logX); + // 首尾直接使用原始端点,避免 exp(log(t)) 的舍入误差越过严格插值边界。 + if(i == 0) { + commonX[i] = targetMinX; + } else if(i == numPoints - 1) { + commonX[i] = targetMaxX; + } else { + commonX[i] = qExp(logX); + } if(!interpolateLogValue( targetPressure, commonX[i], @@ -7017,10 +7027,14 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError( return false; } - double shiftedX = qExp( - qBound(resultLogMinX, - shiftedLogX, - resultLogMaxX)); + // 对数时间还原后再次限制到原始端点,避免 exp(log(t)) 的 + // 舍入误差越过严格插值边界。 + double shiftedX = qBound( + resultMinX, + qExp(qBound(resultLogMinX, + shiftedLogX, + resultLogMaxX)), + resultMaxX); double resultLogPressure = 0.0; double resultLogDerivative = 0.0; if(!interpolateLogValue( diff --git a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp index 601ed8b..d2fde5d 100644 --- a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp +++ b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp @@ -887,7 +887,8 @@ bool nmCalculationDllPebiSolverTask::savePebiModeResult( // 准备流量段数据 QVector vecTimeQ = pWellData->getFlowPoints(); - int nTimeNumQ = vecTimeQ.size() - 1; // 移除第一个 0 点 + // 无流量井保持空数组,避免将 -1 作为 vector 长度。 + int nTimeNumQ = qMax(0, vecTimeQ.size() - 1); // 移除第一个 0 点 std::vector timeQ(nTimeNumQ); std::vector q(nTimeNumQ); @@ -899,10 +900,21 @@ bool nmCalculationDllPebiSolverTask::savePebiModeResult( // 调用外部 DLL 计算双对数曲线 std::vector logPreResultFromDll; // 存储 DLL 的计算结果 int iSectionFlowIndex = pWellData->getIndexF(); - - HMODULE hMod_solver = LoadLibrary(L"singlePhaseSolverDll.dll"); - - if(hMod_solver) { + // 无流量井仍保留压力结果,但没有流量制度时无法计算双对数和半对数。 + HMODULE hMod_solver = nTimeNumQ > 0 + ? LoadLibrary(L"singlePhaseSolverDll.dll") + : nullptr; + + if(nTimeNumQ <= 0) { + vvecLogLog.clear(); + vvecLogLog.append(QVector()); + vvecLogLog.append(QVector()); + vvecLogLog.append(QVector()); + + vvecSemiLog.clear(); + vvecSemiLog.append(QVector()); + vvecSemiLog.append(QVector()); + } else if(hMod_solver) { typedef bool (*PreLog)(const std::vector&, const int&, double*, double*, int, std::vector&); PreLog preLogFun = (PreLog)GetProcAddress(hMod_solver, "logLogPre");