|
|
|
|
@ -6,6 +6,7 @@
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <float.h>
|
|
|
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
|
#include "DatasetIO.h"
|
|
|
|
|
@ -34,6 +35,69 @@ static std::string getExeDir()
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isFiniteNumber(double value)
|
|
|
|
|
{
|
|
|
|
|
return _finite(value) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool hasValidPseudoPressureTable(const PebiScene& scene)
|
|
|
|
|
{
|
|
|
|
|
// 插值要求压力列严格单调,并且压力与拟压力逐点对应。
|
|
|
|
|
const std::vector<double>& p = scene.PVT.pseudoPressureP;
|
|
|
|
|
const std::vector<double>& ps = scene.PVT.pseudoPressurePs;
|
|
|
|
|
if (p.size() < 2 || p.size() != ps.size()) return false;
|
|
|
|
|
|
|
|
|
|
if (!isFiniteNumber(p[0]) || !isFiniteNumber(ps[0]) || p[0] == p[1]) return false;
|
|
|
|
|
const bool ascending = p[1] > p[0];
|
|
|
|
|
for (size_t i = 1; i < p.size(); ++i) {
|
|
|
|
|
if (!isFiniteNumber(p[i]) || !isFiniteNumber(ps[i])) return false;
|
|
|
|
|
if (ascending ? p[i] <= p[i - 1] : p[i] >= p[i - 1]) return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool interpolatePseudoPressure(const PebiScene& scene, double pressure, double& pseudoPressure)
|
|
|
|
|
{
|
|
|
|
|
// 使用相邻两个表格点做线性插值;超出表格范围时沿首尾区间线性外推。
|
|
|
|
|
if (!isFiniteNumber(pressure)) return false;
|
|
|
|
|
|
|
|
|
|
const std::vector<double>& p = scene.PVT.pseudoPressureP;
|
|
|
|
|
const std::vector<double>& ps = scene.PVT.pseudoPressurePs;
|
|
|
|
|
const bool ascending = p[1] > p[0];
|
|
|
|
|
|
|
|
|
|
// 二分查找第一个到达或越过目标压力的表格点。
|
|
|
|
|
size_t first = 0;
|
|
|
|
|
size_t count = p.size();
|
|
|
|
|
while (count > 0) {
|
|
|
|
|
const size_t step = count / 2;
|
|
|
|
|
const size_t index = first + step;
|
|
|
|
|
const bool before = ascending ? p[index] < pressure : p[index] > pressure;
|
|
|
|
|
if (before) {
|
|
|
|
|
first = index + 1;
|
|
|
|
|
count -= step + 1;
|
|
|
|
|
} else {
|
|
|
|
|
count = step;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t left = 0;
|
|
|
|
|
size_t right = 1;
|
|
|
|
|
if (first == 0) {
|
|
|
|
|
left = 0;
|
|
|
|
|
right = 1;
|
|
|
|
|
} else if (first >= p.size()) {
|
|
|
|
|
left = p.size() - 2;
|
|
|
|
|
right = p.size() - 1;
|
|
|
|
|
} else {
|
|
|
|
|
left = first - 1;
|
|
|
|
|
right = first;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const double ratio = (pressure - p[left]) / (p[right] - p[left]);
|
|
|
|
|
pseudoPressure = ps[left] + ratio * (ps[right] - ps[left]);
|
|
|
|
|
return isFiniteNumber(pseudoPressure);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// =============== 组装模型输入 ===============
|
|
|
|
|
static HX_NWTM_MODEL_INPUT buildModelInputFromDataset(const PebiScene& scene, const HX_NWTM_GRID_OUTPUT2& gridOutput2)
|
|
|
|
|
{
|
|
|
|
|
@ -196,13 +260,23 @@ static bool computeLogLogCurves(RunnerResult& rr, const PebiScene& scene, const
|
|
|
|
|
return true; // 没 dll:loglog 为空,但结构正确
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool usePseudoPressure = (scene.solverType == 5);
|
|
|
|
|
if (usePseudoPressure && !hasValidPseudoPressureTable(scene)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned int w = 0; w < rr.nWells; ++w)
|
|
|
|
|
{
|
|
|
|
|
std::vector<Point> wellPressureData;
|
|
|
|
|
wellPressureData.resize(rr.nSteps);
|
|
|
|
|
for (unsigned int i = 0; i < rr.nSteps; ++i) {
|
|
|
|
|
wellPressureData[i].x = rr.t[i];
|
|
|
|
|
wellPressureData[i].y = rr.pw[w][i];
|
|
|
|
|
double pressureForLog = rr.pw[w][i];
|
|
|
|
|
if (usePseudoPressure
|
|
|
|
|
&& !interpolatePseudoPressure(scene, pressureForLog, pressureForLog)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
wellPressureData[i].y = pressureForLog;
|
|
|
|
|
wellPressureData[i].z = 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -280,6 +354,10 @@ static int runServer(const std::string& datasetPath,
|
|
|
|
|
std::cerr << "ERROR: loadDataset failed\n";
|
|
|
|
|
return 30;
|
|
|
|
|
}
|
|
|
|
|
if (scene.solverType == 5 && !hasValidPseudoPressureTable(scene)) {
|
|
|
|
|
std::cerr << "ERROR: T5 dataset has no valid gas pseudo-pressure table; rebuild scene and dataset\n";
|
|
|
|
|
return 31;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2) prepare base input once
|
|
|
|
|
HX_NWTM_MODEL_INPUT modelInput = buildModelInputFromDataset(scene, gridOutput2);
|
|
|
|
|
@ -401,6 +479,10 @@ int main(int argc, char** argv)
|
|
|
|
|
std::cerr << "ERROR: loadDataset failed\n";
|
|
|
|
|
return 30;
|
|
|
|
|
}
|
|
|
|
|
if (scene.solverType == 5 && !hasValidPseudoPressureTable(scene)) {
|
|
|
|
|
std::cerr << "ERROR: T5 dataset has no valid gas pseudo-pressure table; rebuild scene and dataset\n";
|
|
|
|
|
return 31;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HX_NWTM_MODEL_INPUT modelInput = buildModelInputFromDataset(scene, gridOutput2);
|
|
|
|
|
applySampledParamsAndMaybeOverrideRate(modelInput, params);
|
|
|
|
|
|