1.流量为空时,流量段数量设为 0,不会出现 -1 被转换成巨大数组长度的问题。

2.计算误差时跳过目标曲线第一个点,修复公共时间轴端点的浮点误差
feature/AutoFit-Optimize-20260821
lvjunjie 3 weeks ago
parent 8b7f63f063
commit c210cd7b39

@ -6568,15 +6568,17 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
// 无法比较的采样行先跳过;有限但非正的导数无法进入双对数空间, // 无法比较的采样行先跳过;有限但非正的导数无法进入双对数空间,
// 当前数据又没有逐点有效掩码,因此遇到这种导数时判本次评价无效。 // 当前数据又没有逐点有效掩码,因此遇到这种导数时判本次评价无效。
auto prepareCurve = [valueFloor](const QVector<QVector<double> >& data, auto prepareCurve = [valueFloor](const QVector<QVector<double> >& data,
int firstIndex,
QVector<QPointF>* pressure, QVector<QPointF>* pressure,
QVector<QPointF>* derivative) -> bool { QVector<QPointF>* derivative) -> bool {
if(!pressure || !derivative || data.size() < 3 || if(!pressure || !derivative || data.size() < 3 ||
data[0].size() != data[1].size() || 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; 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]) || if(!isFiniteNumber(data[0][i]) ||
!isFiniteNumber(data[1][i]) || !isFiniteNumber(data[1][i]) ||
!isFiniteNumber(data[2][i]) || !isFiniteNumber(data[2][i]) ||
@ -6624,8 +6626,9 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
QVector<QPointF> targetDerivative; QVector<QPointF> targetDerivative;
QVector<QPointF> resultPressure; QVector<QPointF> resultPressure;
QVector<QPointF> resultDerivative; QVector<QPointF> resultDerivative;
if(!prepareCurve(target, &targetPressure, &targetDerivative) || // 模拟结果已跳过 DLL 首点,因此误差计算同步忽略目标曲线首点。
!prepareCurve(result, &resultPressure, &resultDerivative)) { if(!prepareCurve(target, 1, &targetPressure, &targetDerivative) ||
!prepareCurve(result, 0, &resultPressure, &resultDerivative)) {
return invalidLoss; return invalidLoss;
} }
@ -6721,7 +6724,14 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
(targetLogMaxX - targetLogMinX) / (targetLogMaxX - targetLogMinX) /
(numPoints - 1); (numPoints - 1);
commonLogX[i] = logX; 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( if(!interpolateLogValue(
targetPressure, commonX[i], targetPressure, commonX[i],
@ -7017,10 +7027,14 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
return false; return false;
} }
double shiftedX = qExp( // 对数时间还原后再次限制到原始端点,避免 exp(log(t)) 的
qBound(resultLogMinX, // 舍入误差越过严格插值边界。
shiftedLogX, double shiftedX = qBound(
resultLogMaxX)); resultMinX,
qExp(qBound(resultLogMinX,
shiftedLogX,
resultLogMaxX)),
resultMaxX);
double resultLogPressure = 0.0; double resultLogPressure = 0.0;
double resultLogDerivative = 0.0; double resultLogDerivative = 0.0;
if(!interpolateLogValue( if(!interpolateLogValue(

@ -887,7 +887,8 @@ bool nmCalculationDllPebiSolverTask::savePebiModeResult(
// 准备流量段数据 // 准备流量段数据
QVector<QPointF> vecTimeQ = pWellData->getFlowPoints(); QVector<QPointF> vecTimeQ = pWellData->getFlowPoints();
int nTimeNumQ = vecTimeQ.size() - 1; // 移除第一个 0 点 // 无流量井保持空数组,避免将 -1 作为 vector 长度。
int nTimeNumQ = qMax(0, vecTimeQ.size() - 1); // 移除第一个 0 点
std::vector<double> timeQ(nTimeNumQ); std::vector<double> timeQ(nTimeNumQ);
std::vector<double> q(nTimeNumQ); std::vector<double> q(nTimeNumQ);
@ -899,10 +900,21 @@ bool nmCalculationDllPebiSolverTask::savePebiModeResult(
// 调用外部 DLL 计算双对数曲线 // 调用外部 DLL 计算双对数曲线
std::vector<Point> logPreResultFromDll; // 存储 DLL 的计算结果 std::vector<Point> logPreResultFromDll; // 存储 DLL 的计算结果
int iSectionFlowIndex = pWellData->getIndexF(); int iSectionFlowIndex = pWellData->getIndexF();
// 无流量井仍保留压力结果,但没有流量制度时无法计算双对数和半对数。
HMODULE hMod_solver = LoadLibrary(L"singlePhaseSolverDll.dll"); HMODULE hMod_solver = nTimeNumQ > 0
? LoadLibrary(L"singlePhaseSolverDll.dll")
if(hMod_solver) { : nullptr;
if(nTimeNumQ <= 0) {
vvecLogLog.clear();
vvecLogLog.append(QVector<double>());
vvecLogLog.append(QVector<double>());
vvecLogLog.append(QVector<double>());
vvecSemiLog.clear();
vvecSemiLog.append(QVector<double>());
vvecSemiLog.append(QVector<double>());
} else if(hMod_solver) {
typedef bool (*PreLog)(const std::vector<Point>&, const int&, double*, double*, int, std::vector<Point>&); typedef bool (*PreLog)(const std::vector<Point>&, const int&, double*, double*, int, std::vector<Point>&);
PreLog preLogFun = (PreLog)GetProcAddress(hMod_solver, "logLogPre"); PreLog preLogFun = (PreLog)GetProcAddress(hMod_solver, "logLogPre");

Loading…
Cancel
Save