From 8c90dffadd58c4ea6d5bc94e34e2c57fdb1b748c Mon Sep 17 00:00:00 2001 From: lvjunjie Date: Fri, 17 Jul 2026 10:40:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E7=9B=B8=E6=80=81=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ML/Training/Training/Training.cpp | 69 +++++-- .../nmCalculation/nmCalculationPebiGrid.cpp | 178 +++++++++++++----- 2 files changed, 185 insertions(+), 62 deletions(-) diff --git a/ML/Training/Training/Training.cpp b/ML/Training/Training/Training.cpp index 945b845..f661cc2 100644 --- a/ML/Training/Training/Training.cpp +++ b/ML/Training/Training/Training.cpp @@ -28,6 +28,43 @@ static std::string getExeDir() return path; } +static std::string getParentDir(const std::string& path) +{ + size_t pos = path.find_last_of("\\/"); + return (pos == std::string::npos ? std::string(".") : path.substr(0, pos)); +} + +static std::string getFileStem(const std::string& path) +{ + size_t slash = path.find_last_of("\\/"); + size_t begin = (slash == std::string::npos ? 0 : slash + 1); + size_t dot = path.find_last_of('.'); + if (dot == std::string::npos || dot < begin) { + dot = path.size(); + } + return path.substr(begin, dot - begin); +} + +static std::string joinPath(const std::string& dir, const std::string& filename) +{ + if (dir.empty() || dir == ".") { + return filename; + } + char last = dir[dir.size() - 1]; + return dir + (last == '\\' || last == '/' ? "" : "\\") + filename; +} + +static std::string deriveSceneSiblingPath(const std::string& scenePath, const std::string& prefix) +{ + std::string stem = getFileStem(scenePath); + std::string suffix; + if (stem.size() > 6 && stem.compare(0, 6, "scene_") == 0) { + suffix = stem.substr(6); + } + std::string filename = prefix + (suffix.empty() ? "" : "_" + suffix) + ".bin"; + return joinPath(getParentDir(scenePath), filename); +} + // 从 scene 重建 GRID 输入(与之前一致) static HX_NWTM_GRID_INPUT rebuildGridInput(const PebiScene& scene) { @@ -133,9 +170,13 @@ static void printInputSummary(const PebiScene& scene) << std::endl; } -int main() +int main(int argc, char* argv[]) { std::cout << "=== PEBI Scene Processor (Dataset First) ===" << std::endl; + if (argc > 4) { + std::cerr << "Usage: training.exe [scene.bin] [dataset.bin] [grid_cache.bin]" << std::endl; + return 1; + } // 按需开关:发布版保持 true(因为 dataset 是后续批量采样的核心) const bool ENABLE_DATASET_FIRST = true; @@ -153,9 +194,13 @@ int main() //std::string datasetPath = dataDir + "\\dataset.bin"; //std::string gridCachePath= dataDir + "\\grid_cache.bin"; std::string dataDir = exeDir + "\\..\\..\\nmWTAI-ML\\data\\temp"; - std::string scenePath = dataDir + "\\scene.bin"; - std::string datasetPath = dataDir + "\\dataset.bin"; - std::string gridCachePath= dataDir + "\\grid_cache.bin"; + std::string scenePath = (argc >= 2 ? argv[1] : dataDir + "\\scene.bin"); + std::string datasetPath = (argc >= 3 ? argv[2] : deriveSceneSiblingPath(scenePath, "dataset")); + std::string gridCachePath = (argc >= 4 ? argv[3] : deriveSceneSiblingPath(scenePath, "grid_cache")); + + std::cout << "Scene: " << scenePath << std::endl; + std::cout << "Dataset: " << datasetPath << std::endl; + std::cout << "Grid cache: " << gridCachePath << std::endl; // 1) 加载 DLL HMODULE hx = LoadLibraryW(L"HX_NWTM.dll"); @@ -181,7 +226,7 @@ int main() } std::cout << "License OK: " << lic << std::endl; - // 3) dataset 优先尝试(但如果 scene.bin 存在,会做 sceneKey 串场景校验) + // 3) dataset 优先尝试(但如果对应 scene 存在,会做 sceneKey 串场景校验) PebiScene scene; HX_NWTM_GRID_OUTPUT2 gridOutput2; bool gotFromDataset = false; @@ -197,11 +242,11 @@ int main() bool headerOK = DatasetIO::readDatasetSceneKey(datasetPath, dsKey, dsCells, dsWells, dsSolver); - // 如果 scene.bin 存在,我们就顺便做一次“串场景保护”:sceneKey 不匹配就不用 dataset + // 如果对应 scene 存在,我们就顺便做一次“串场景保护”:sceneKey 不匹配就不用 dataset bool sceneKeyMatch = true; if (headerOK && DatasetIO::fileExists(scenePath)) { - std::cout << "\n加载 scene.bin(仅用于串场景校验)..." << std::endl; + std::cout << "\n加载 scene(仅用于串场景校验): " << scenePath << std::endl; if (SceneIO::loadScene(scenePath, scene)) { HX_NWTM_GRID_INPUT gi = rebuildGridInput(scene); unsigned long long expected = DatasetIO::computeSceneKey64(gi); @@ -210,7 +255,7 @@ int main() std::cout << "dataset sceneKey 不匹配(串场景保护触发),忽略 dataset,准备重建..." << std::endl; } } else { - std::cout << "scene.bin 加载失败,跳过串场景校验,直接尝试 dataset 自检..." << std::endl; + std::cout << "scene 加载失败,跳过串场景校验,直接尝试 dataset 自检..." << std::endl; sceneKeyMatch = true; } } @@ -233,17 +278,17 @@ int main() } } - // 4) 如果没有拿到 dataset,就走 scene.bin + grid_cache.bin(带串场景保护) + // 4) 如果没有拿到 dataset,就走 scene + grid_cache(带串场景保护) if (!gotFromDataset) { - std::cout << "\n加载 scene.bin..." << std::endl; + std::cout << "\n加载 scene: " << scenePath << std::endl; if (!SceneIO::loadScene(scenePath, scene)) { - std::cerr << "scene.bin 读取失败: " << scenePath << std::endl; + std::cerr << "scene 读取失败: " << scenePath << std::endl; FreeLibrary(hx); return 4; } // 输入摘要:帮助你定位 “为什么 steps 变了” - std::cout << "scene.bin 读取成功:Wells=" << (unsigned int)scene.wellName.size() + std::cout << "scene 读取成功:Wells=" << (unsigned int)scene.wellName.size() << ", PVT点=" << (unsigned int)scene.PVT.p.size() << ", Solver=" << scene.solverType << std::endl; printInputSummary(scene); diff --git a/Src/nmNum/nmCalculation/nmCalculationPebiGrid.cpp b/Src/nmNum/nmCalculation/nmCalculationPebiGrid.cpp index 1a90978..187d608 100644 --- a/Src/nmNum/nmCalculation/nmCalculationPebiGrid.cpp +++ b/Src/nmNum/nmCalculation/nmCalculationPebiGrid.cpp @@ -30,6 +30,114 @@ #include #include +namespace { + +const int CONST_PVT_POINT_COUNT = 200; + +std::vector buildConstantPvtVector(double value) +{ + return std::vector(CONST_PVT_POINT_COUNT, value); +} + +std::vector buildConstantPvtPressure() +{ + std::vector pressure(CONST_PVT_POINT_COUNT, 0.0); + for(int i = 0; i < CONST_PVT_POINT_COUNT; ++i) { + pressure[i] = i + 1.0; + } + return pressure; +} + +QString solverModelFileTag(NM_SOLVER_MODEL_TYPE modelType) +{ + switch(modelType) { + case SMT_Oil_ConstPvt: + return "T1_oil_const_pvt"; + case SMT_Oil_VariablePvt: + return "T2_oil_variable_pvt"; + case SMT_Water_ConstPvt: + return "T3_water_const_pvt"; + case SMT_Water_VariablePvt: + return "T4_water_variable_pvt"; + case SMT_Gas_VariablePvt: + return "T5_gas_variable_pvt"; + case SMT_Oil_Water_TwoPhase: + return "T8_oil_water_two_phase"; + default: + return QString("T%1_unsupported").arg(static_cast(modelType)); + } +} + +void fillScenePvtByModel(nmDataBinaryTools::NM_PEBI_SCENE& scene, + NM_SOLVER_MODEL_TYPE modelType, + nmDataPvtParaForPebi* pvt, + nmDataReservoir* reservoir) +{ + switch(modelType) { + case SMT_Oil_ConstPvt: + scene.PVT.p = buildConstantPvtPressure(); + if(reservoir != nullptr) { + scene.PVT.Bo = buildConstantPvtVector(reservoir->getBo().getValue().toDouble()); + scene.PVT.miuo = buildConstantPvtVector(reservoir->getMiuo().getValue().toDouble()); + } + break; + + case SMT_Oil_VariablePvt: + if(pvt != nullptr) { + scene.PVT.p = pvt->getPressure().toStdVector(); + scene.PVT.Bo = pvt->getBo().toStdVector(); + scene.PVT.Co = pvt->getCo().toStdVector(); + scene.PVT.miuo = pvt->getMiuo().toStdVector(); + } + break; + + case SMT_Water_ConstPvt: + scene.PVT.p = buildConstantPvtPressure(); + if(reservoir != nullptr) { + scene.PVT.Bw = buildConstantPvtVector(reservoir->getBw().getValue().toDouble()); + scene.PVT.miuw = buildConstantPvtVector(reservoir->getMiuw().getValue().toDouble()); + } + break; + + case SMT_Water_VariablePvt: + if(pvt != nullptr) { + scene.PVT.p = pvt->getPressure().toStdVector(); + scene.PVT.Bw = pvt->getBw().toStdVector(); + scene.PVT.Cw = pvt->getCw().toStdVector(); + scene.PVT.miuw = pvt->getMiuw().toStdVector(); + } + break; + + case SMT_Gas_VariablePvt: + case SMT_Gas_PseudoPressure: + if(pvt != nullptr) { + scene.PVT.p = pvt->getPressure().toStdVector(); + scene.PVT.Bg = pvt->getBg().toStdVector(); + scene.PVT.Cg = pvt->getCg().toStdVector(); + scene.PVT.miug = pvt->getMiug().toStdVector(); + } + break; + + case SMT_Oil_Water_TwoPhase: + if(pvt != nullptr) { + scene.PVT.p = pvt->getPressure().toStdVector(); + scene.PVT.Bo = pvt->getBo().toStdVector(); + scene.PVT.miuo = pvt->getMiuo().toStdVector(); + scene.PVT.Bw = pvt->getBw().toStdVector(); + scene.PVT.miuw = pvt->getMiuw().toStdVector(); + scene.PVT.So = pvt->getSo().toStdVector(); + scene.PVT.Kro = pvt->getKro().toStdVector(); + scene.PVT.Krw = pvt->getKrw().toStdVector(); + } + break; + + default: + break; + } +} + +} + #ifdef Q_OS_WIN #include #define DEBUG_OUT(msg) OutputDebugStringA(QString("[Mesh] %1\n").arg(msg).toLocal8Bit().data()) @@ -814,18 +922,10 @@ bool nmCalculationPebiGrid::generateOutputPara() // ===== 3. 求解器参数 ===== - // 3.1 求解器类型 + // 3.1 求解器类型:与真实求解器使用同一个模型类型,不再根据相态推断。 nmDataReservoir* pReservoirData = dm->getReservoirData(); - - if(pReservoirData) { - if(pReservoirData->getPhaseType() == PHASE_Oil) { - scene.solverType = 2; // 油单相变化PVT - } else if(pReservoirData->getPhaseType() == PHASE_Gas) { - scene.solverType = 5; // 气单相变化PVT - } else { - scene.solverType = 1; // 默认油单相 - } - } + NM_SOLVER_MODEL_TYPE solverModelType = dm->getSolverModelType(); + scene.solverType = static_cast(solverModelType); // 3.2 Rate流量数据 scene.Rate.t.resize(order.size()); @@ -925,42 +1025,9 @@ bool nmCalculationPebiGrid::generateOutputPara() } } - // 3.5 PVT数据 + // 3.5 PVT数据:常数PVT和变化PVT采用与真实求解器相同的填充方式。 nmDataPvtParaForPebi* pvt = dm->getPebiPvtPara(); - - if(pvt) { - scene.PVT.p = pvt->getPressure().toStdVector(); - scene.PVT.Rso = pvt->getRso().toStdVector(); - scene.PVT.pb = pvt->getPb().getValue().toDouble(); - scene.PVT.Bo = pvt->getBo().toStdVector(); - scene.PVT.Co = pvt->getCo().toStdVector(); - scene.PVT.miuo = pvt->getMiuo().toStdVector(); - scene.PVT.rouo = pvt->getRouo().toStdVector(); - - scene.PVT.Rv = pvt->getRv().toStdVector(); - scene.PVT.Bg = pvt->getBg().toStdVector(); - scene.PVT.Cg = pvt->getCg().toStdVector(); - scene.PVT.miug = pvt->getMiug().toStdVector(); - scene.PVT.roug = pvt->getRoug().toStdVector(); - scene.PVT.Z = pvt->getZ().toStdVector(); - - scene.PVT.Rsw = pvt->getRsw().toStdVector(); - scene.PVT.Bw = pvt->getBw().toStdVector(); - scene.PVT.Cw = pvt->getCw().toStdVector(); - scene.PVT.miuw = pvt->getMiuw().toStdVector(); - scene.PVT.rouw = pvt->getRouw().toStdVector(); - - scene.PVT.V = pvt->getV().toStdVector(); - scene.PVT.k_kinitial = pvt->getKKinitial().toStdVector(); - scene.PVT.Cf_Cfinitial = pvt->getCfCfinitial().toStdVector(); - - scene.PVT.So = pvt->getSo().toStdVector(); - scene.PVT.Kro = pvt->getKro().toStdVector(); - scene.PVT.Sg = pvt->getSg().toStdVector(); - scene.PVT.Krg = pvt->getKrg().toStdVector(); - scene.PVT.Sw = pvt->getSw().toStdVector(); - scene.PVT.Krw = pvt->getKrw().toStdVector(); - } + fillScenePvtByModel(scene, solverModelType, pvt, pReservoirData); // 3.6 Base储层参数 if(pReservoirData) { @@ -996,16 +1063,27 @@ bool nmCalculationPebiGrid::generateOutputPara() dataDir.mkpath("."); // 确保 Data 目录存在 } - QString outPath = dataDir.filePath("scene.bin"); - bool ok = nmDataBinaryTools::savePebiSceneBin(outPath, scene); + QString typedFileName = QString("scene_%1.bin").arg(solverModelFileTag(solverModelType)); + QString typedOutPath = dataDir.filePath(typedFileName); + bool ok = nmDataBinaryTools::savePebiSceneBin(typedOutPath, scene); if(!ok) { zxLogInstance::getInstance()->writeLogF("savePebiSceneBin failed: " + nmDataBinaryTools::getLastError()); FreeLibrary(dll); return false; - } else { - zxLogInstance::getInstance()->writeLogF("scene.bin exported: " + outPath); } + + // 保留固定文件名作为当前场景入口,兼容现有Training和Python数据生成流程。 + QString latestOutPath = dataDir.filePath("scene.bin"); + ok = nmDataBinaryTools::savePebiSceneBin(latestOutPath, scene); + if(!ok) { + zxLogInstance::getInstance()->writeLogF("savePebiSceneBin failed: " + nmDataBinaryTools::getLastError()); + FreeLibrary(dll); + return false; + } + + zxLogInstance::getInstance()->writeLogF("scene exported: " + typedOutPath); + zxLogInstance::getInstance()->writeLogF("latest scene exported: " + latestOutPath); } // ===== 导出所有井:loglog + rate + pressure 到 temp 目录 =====