|
|
|
|
@ -1812,15 +1812,13 @@ bool nmCalculationDllPebiSolverTask::configureRateForecast(
|
|
|
|
|
return fail(tr("Rate forecast currently supports single-phase models only."));
|
|
|
|
|
}
|
|
|
|
|
int target = -1;
|
|
|
|
|
int wellCount = 0;
|
|
|
|
|
for(int i = 0; i < grid.m_vecWellInputs.size(); ++i) {
|
|
|
|
|
const nmPebiWellInputSnapshot& well = grid.m_vecWellInputs[i];
|
|
|
|
|
if(!well.m_bRealWell) continue;
|
|
|
|
|
++wellCount;
|
|
|
|
|
if(well.m_sWellCode == m_sAutoFitTargetWellCode && well.m_bRateControlled) target = i;
|
|
|
|
|
}
|
|
|
|
|
if(wellCount != 1 || target < 0) {
|
|
|
|
|
return fail(tr("Rate forecast currently requires one rate-controlled well."));
|
|
|
|
|
if(target < 0) {
|
|
|
|
|
return fail(tr("The forecast well must be rate-controlled."));
|
|
|
|
|
}
|
|
|
|
|
if(!isFiniteSolverNumber(initialPressure) || initialPressure <= 0.0 ||
|
|
|
|
|
durations.isEmpty() || durations.size() != rates.size()) {
|
|
|
|
|
@ -1849,12 +1847,7 @@ bool nmCalculationDllPebiSolverTask::configureRateForecast(
|
|
|
|
|
solverDurations.append(durations[0] - solverDurations[0]);
|
|
|
|
|
solverRates.append(rates[0]);
|
|
|
|
|
}
|
|
|
|
|
// 外层数组保持网格槽位顺序;手工裂缝不施加流量,单相流量只填入对应相。
|
|
|
|
|
const int slotCount = grid.m_vecWellInputs.size();
|
|
|
|
|
scene.Rate.t.assign(slotCount, std::vector<double>());
|
|
|
|
|
scene.Rate.qo.assign(slotCount, std::vector<double>());
|
|
|
|
|
scene.Rate.qg.assign(slotCount, std::vector<double>());
|
|
|
|
|
scene.Rate.qw.assign(slotCount, std::vector<double>());
|
|
|
|
|
// 只替换当前井的制度,保留其他井及手工裂缝槽位,沿用普通多井求解计算井间干扰。
|
|
|
|
|
scene.Rate.t[target].assign(solverDurations.constBegin(), solverDurations.constEnd());
|
|
|
|
|
scene.Rate.qo[target].assign(solverRates.size(), 0.0);
|
|
|
|
|
scene.Rate.qg[target].assign(solverRates.size(), 0.0);
|
|
|
|
|
@ -2252,28 +2245,22 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
|
|
|
|
|
p1.pw[target].size() != p1.t.size()) {
|
|
|
|
|
return fail(tr("The solver returned incomplete forecast pressure data."));
|
|
|
|
|
}
|
|
|
|
|
double endTime = 0.0;
|
|
|
|
|
for(size_t i = 0; i < grid.m_oScene.Rate.t[target].size(); ++i)
|
|
|
|
|
endTime += grid.m_oScene.Rate.t[target][i];
|
|
|
|
|
const double tolerance = qMax(1.0, endTime) * 1.0e-8;
|
|
|
|
|
QVector<QVector<double> > pressure(2);
|
|
|
|
|
if(p1.t[0] > 0.0) {
|
|
|
|
|
pressure[0].append(0.0);
|
|
|
|
|
pressure[1].append(grid.m_oScene.Base.Pi);
|
|
|
|
|
}
|
|
|
|
|
// 与普通多井求解一致,保留 DLL 返回的完整时间轴,不按当前井制度截断结果。
|
|
|
|
|
for(size_t i = 0; i < p1.t.size(); ++i) {
|
|
|
|
|
if(isCancelRequested()) return false;
|
|
|
|
|
if(!isFiniteSolverNumber(p1.t[i]) || p1.t[i] < 0.0 ||
|
|
|
|
|
p1.t[i] > endTime + tolerance || (i > 0 && p1.t[i] <= p1.t[i - 1]) ||
|
|
|
|
|
(i > 0 && p1.t[i] <= p1.t[i - 1]) ||
|
|
|
|
|
!isFiniteSolverNumber(p1.pw[target][i]) || p1.pw[target][i] <= 0.0) {
|
|
|
|
|
return fail(tr("Invalid forecast pressure or time. Check the rate schedule and model."));
|
|
|
|
|
}
|
|
|
|
|
pressure[0].append(p1.t[i]);
|
|
|
|
|
pressure[1].append(p1.pw[target][i]);
|
|
|
|
|
}
|
|
|
|
|
if(qAbs(p1.t.back() - endTime) > tolerance) {
|
|
|
|
|
return fail(tr("The solver did not reach the end of the forecast schedule."));
|
|
|
|
|
}
|
|
|
|
|
m_autoFitResultPressure = pressure;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|