#include "nmCalculationPebiGrid.h" #include #include #include #include #include #include #include "nmCalculationUtils.h" #include "zxLogInstance.h" #include "nmDataAnalyzeManager.h" #include "nmDataWellBase.h" #include "nmDataVerticalWell.h" #include "nmDataVerticalFracturedWell.h" #include "nmDataHorizontalFracturedWell.h" #include "nmDataReservoir.h" #include "nmDataAttribute.h" #include "nmDataRegion.h" #include "nmDataRegionMark.h" #include "nmDataOutline.h" #include "nmDataFracture.h" #include "nmDataFault.h" #include "nmDataBinaryTools.h" #include "nmDataPvtParaForPebi.h" #include "nmDataTimeStepSetting.h" #include #include #include #include #ifdef Q_OS_WIN #include #define DEBUG_OUT(msg) OutputDebugStringA(QString("[Mesh] %1\n").arg(msg).toLocal8Bit().data()) #endif nmCalculationPebiGrid* nmCalculationPebiGrid::m_instance = nullptr; nmCalculationPebiGrid* nmCalculationPebiGrid::getInstance() { if(m_instance == nullptr) { m_instance = new nmCalculationPebiGrid(); } return m_instance; } nmCalculationPebiGrid::nmCalculationPebiGrid() { // 默认值来自HX_NWTM_GRID_INPUT构造函数 m_dGridControl = p0.GridControl; // 清空原有PEBI网格输出数据 p1.TRI_cell.p.clear(); p1.TRI_cell.pindex.clear(); p1.TRI_cell.isplot.clear(); // 清空 PEBI_cell p1.PEBI_cell.p.clear(); p1.PEBI_cell.pindex.clear(); p1.PEBI_cell.isplot.clear(); } nmCalculationPebiGrid::~nmCalculationPebiGrid() { } bool nmCalculationPebiGrid::meshGenPebi() { if(this->generateOutputPara() == false) { return false; } // 根据生成的p1生成VTK格式的非结构化网格 vtkSmartPointer pGrid = this->createPebiUnstructuredGrid(p1); Q_ASSERT(nullptr != pGrid); // 更新当期分析下的非结构化网格对象 nmDataAnalyzeManager* pCurDataManager = nmDataAnalyzeManager::getCurrentInstance(); Q_ASSERT(nullptr != pCurDataManager); pCurDataManager->setUnstructuredGrid(pGrid); return true; } void nmCalculationPebiGrid::setGridControl(double gridControl) { // GridControl必须为正数,非法值保持原有设置 if(gridControl > 0.0) { m_dGridControl = gridControl; } } void nmCalculationPebiGrid::clearGridData() { // 关闭网格窗口后清空PEBI单例缓存,避免后续求解误用旧网格输入输出。 p0 = HX_NWTM_GRID_INPUT(); p1 = HX_NWTM_GRID_OUTPUT1(); p2 = HX_NWTM_GRID_OUTPUT2(); m_dGridControl = p0.GridControl; } void nmCalculationPebiGrid::logInputParameters(const HX_NWTM_GRID_INPUT& input) { QString logMsg = "Input Parameters:\n"; logMsg += QString("GridControl: %1\n").arg(input.GridControl); logMsg += QString("D: %1\n").arg(input.D); // 记录边界信息 logMsg += QString("Boundary count: %1\n").arg(input.Boundary.size()); for(size_t i = 0; i < input.Boundary.size(); ++i) { const auto& line = input.Boundary[i]; if(line.size() >= 4) { logMsg += QString(" Boundary %1: (%2, %3) -> (%4, %5)\n") .arg(i).arg(line[0]).arg(line[1]).arg(line[2]).arg(line[3]); } } // 记录井信息 logMsg += QString("Vertical Wells count: %1\n").arg(input.VerticalWell.size()); for(size_t i = 0; i < input.VerticalWell.size(); ++i) { const auto& well = input.VerticalWell[i]; if(well.size() >= 3) { logMsg += QString(" Well %1: (%2, %3), radius: %4\n") .arg(i).arg(well[0]).arg(well[1]).arg(well[2]); } } // 记录垂直裂缝井以及裂缝信息 logMsg += QString("Fracture Vertical Wells And Fractures count: %1\n").arg(input.FractureVerticalWell.size()); for(size_t i = 0; i < input.FractureVerticalWell.size(); ++i) { const auto& frac = input.FractureVerticalWell[i]; if(frac.size() >= 5) { logMsg += QString(" Fracture %1: (%2, %3) -> (%4, %5), width: %6\n") .arg(i).arg(frac[0]).arg(frac[1]).arg(frac[2]).arg(frac[3]).arg(frac[4]); } } // 记录多段压裂水平井信息 logMsg += QString("Multistage Fractured Horizontal Wells count: %1\n").arg(input.MultistageFracturedHorizontalWell.size()); for(size_t i = 0; i < input.MultistageFracturedHorizontalWell.size(); ++i) { const auto& horizontalWell = input.MultistageFracturedHorizontalWell[i]; logMsg += QString(" Horizontal Fractured Well %1 (Fractures count: %2):\n").arg(i).arg(horizontalWell.size()); for(size_t j = 0; j < horizontalWell.size(); ++j) { const auto& frac = horizontalWell[j]; if(frac.size() >= 5) { logMsg += QString(" Fracture %1.%2: (%3, %4) -> (%5, %6), width: %7\n") .arg(i).arg(j).arg(frac[0]).arg(frac[1]).arg(frac[2]).arg(frac[3]).arg(frac[4]); } } } // 记录断层信息 (新增详细输出) logMsg += QString("Faults count: %1\n").arg(input.Fault.size()); for(size_t i = 0; i < input.Fault.size(); ++i) { const auto& faultSegment = input.Fault[i]; if(faultSegment.size() >= 4) { // 断层段至少有起点和终点 logMsg += QString(" Fault Segment %1: (%2, %3) -> (%4, %5)\n") .arg(i).arg(faultSegment[0]).arg(faultSegment[1]).arg(faultSegment[2]).arg(faultSegment[3]); } } qDebug() << logMsg; } void nmCalculationPebiGrid::logCurrentState() { QString stateMsg = "Current Output P1 State:\n"; // 记录一些关键状态信息 stateMsg += QString("PEBI_cell points count: %1\n").arg(p1.PEBI_cell.p.size()); stateMsg += QString("PEBI_cell pindex count: %1\n").arg(p1.PEBI_cell.pindex.size()); stateMsg += QString("PEBI_cell isplot count: %1\n").arg(p1.PEBI_cell.isplot.size()); qDebug() << stateMsg; } bool nmCalculationPebiGrid::meshGenPebiBoundary(HX_NWTM_GRID_INPUT& inputObj) { // 1、从数据中心获取边界数据 nmDataOutline* pOutlineData = nmDataAnalyzeManager::getCurrentInstance()->getOutlineData(); if(pOutlineData == nullptr) { return false; } inputObj.Boundary.clear(); // 获取边界的点 QVector vecOutlinePoints = pOutlineData->getOutlinePoints(); // 顺时针进行构建 for(int i = 0; i < vecOutlinePoints.size(); i++) { QPointF& startP = vecOutlinePoints[i]; QPointF endP; if(i == vecOutlinePoints.size() - 1) { endP = vecOutlinePoints.first(); } else { endP = vecOutlinePoints[i + 1]; } dVec1 line(4); //line[0] = (int)startP.x(); //line[1] = (int)startP.y(); //line[2] = (int)endP.x(); //line[3] = (int)endP.y(); line[0] = qRound(startP.x()); // 四舍五入 line[1] = qRound(startP.y()); // 四舍五入 line[2] = qRound(endP.x()); // 四舍五入 line[3] = qRound(endP.y()); // 四舍五入 inputObj.Boundary.push_back(line); } return true; } bool nmCalculationPebiGrid::meshGenPebiWells(HX_NWTM_GRID_INPUT& inputObj) { // 从数据中心获取井数据 //QVector vecDataWells = nmDataAnalyzeManager::getCurrentInstance()->getWellDataList(); //if (vecDataWells.size() == 0) { // return true; //} nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::getCurrentInstance(); inputObj.VerticalWell.clear(); inputObj.FractureVerticalWell.clear(); inputObj.MultistageFracturedHorizontalWell.clear(); // 水平井初始化 inputObj.HorizontalWell.clear(); // 斜井 inputObj.InclinedWell.clear(); // 清空自定义井顺序 pDataManager->clearCalculationWells(); // 获取直井数据 QVector verticalWells = pDataManager->getVerticalWellData(); // 获取垂直裂缝井数据 QVector vFracturedWells = pDataManager->getVerticalFracturedWellData(); // 获取多段压裂水平井数据 QVector hFracturedWells = pDataManager->getHorizontalFracturedWellData(); // 处理直井数据 foreach(nmDataVerticalWell* pVerticalWell, verticalWells) { if(pVerticalWell != nullptr) { dVec1 well(3); double dX = pVerticalWell->getX().getValue().toDouble(); double dY = pVerticalWell->getY().getValue().toDouble(); well[0] = dX; well[1] = dY; well[2] = pVerticalWell->getRadius().getValue().toDouble(); inputObj.VerticalWell.push_back(well); // 添加到自定义井顺序数组 pDataManager->appendCalculationWell(QPair(NM_WELL_MODEL::Vertical_Well, pVerticalWell->getWellName())); } } // 处理垂直裂缝井数据 foreach(nmDataVerticalFracturedWell* pVerticalFracturedWell, vFracturedWells) { if(pVerticalFracturedWell != nullptr) { QVector vFracPoints = pVerticalFracturedWell->getFracs(); if(vFracPoints.size() == 2) { dVec1 crack(5); crack[0] = vFracPoints[0].x(); crack[1] = vFracPoints[0].y(); crack[2] = vFracPoints[1].x(); crack[3] = vFracPoints[1].y(); crack[4] = 1; // 裂缝宽度 inputObj.FractureVerticalWell.push_back(crack); // 添加到自定义井顺序数组 pDataManager->appendCalculationWell(QPair(NM_WELL_MODEL::Vertical_Fractured_Well, pVerticalFracturedWell->getWellName())); } } } // 处理多段压裂水平井数据 foreach(nmDataHorizontalFracturedWell* pHorizontalFracturedWell, hFracturedWells) { if(pHorizontalFracturedWell != nullptr) { QVector> vvecFracPoints = pHorizontalFracturedWell->getFracs(); std::vector> vMultistageFracturedHorizontalWell; for(int j = 0; j < vvecFracPoints.size(); ++j) { dVec1 crack(5); QPointF& vStartPoint = vvecFracPoints[j].first; // 起始点 QPointF& vEndPoint = vvecFracPoints[j].second; // 终止点 crack[0] = vStartPoint.x(); crack[1] = vStartPoint.y(); crack[2] = vEndPoint.x(); crack[3] = vEndPoint.y(); crack[4] = 2; // 裂缝宽度 vMultistageFracturedHorizontalWell.push_back(crack); } inputObj.MultistageFracturedHorizontalWell.push_back(vMultistageFracturedHorizontalWell); // 添加到自定义井顺序数组 pDataManager->appendCalculationWell(QPair(NM_WELL_MODEL::Horizontal_Fractured_Well, pHorizontalFracturedWell->getWellName())); } } return true; // // 分类处理 // for (int i = 0; i < vecDataWells.size(); i++) { // nmDataWellBase* pWellData = vecDataWells[i]; // if (pWellData != nullptr) { //m_vecWellOrder.append(true); // // 垂直裂缝井 // nmDataVerticalFracturedWell* pVerticalFracturedWell = dynamic_cast(pWellData); // if (pVerticalFracturedWell != nullptr) { // dVec1 crack(5); // QVector vFracPoints = pVerticalFracturedWell->getFracs(); // if (vFracPoints.size() == 2) { // crack[0] = (int)vFracPoints[0].x(); // crack[1] = (int)vFracPoints[0].y(); // crack[2] = (int)vFracPoints[1].x(); // crack[3] = (int)vFracPoints[1].y(); // // todo,裂缝的宽度 // crack[4] = 1; // //crack[4] = QString::number(0.050000000000000000000000000000000000000000, 'f', 2).toDouble(); // // 确保裂缝宽度保留两位小数 // //crack[4] = std::round(0.05 * 100) / 100; // //crack[4] = static_cast(static_cast(0.06 * 100)) / 100; // //crack[4] = qRound(0.06 * 100) / 100.0; // qDebug() << crack[0] << crack[1] << crack[2] << crack[3] << crack[4]; // inputObj.FractureVerticalWell.push_back(crack); // /*dVec1 c(5); // c[0] = 200; c[1] = 200; c[2] = 400; c[3] = 200; c[4] = 0.05; // inputObj.FractureVerticalWell.push_back(c);*/ // } // continue; // } // // 多段压裂水平井 // nmDataHorizontalFracturedWell* pHorizontalFracturedWell = dynamic_cast(pWellData); // if (pHorizontalFracturedWell != nullptr) { // QVector> vvecFracPoints = pHorizontalFracturedWell->getFracs(); // std::vector> vMultistageFracturedHorizontalWell; // // 遍历 vvecFracPoints,每个 QPair 包含一个裂缝的起始点和终止点 // for (int j = 0; j < vvecFracPoints.size(); ++j) { // dVec1 crack(5); // QPointF& vStartPoint = vvecFracPoints[j].first; // 起始点 // QPointF& vEndPoint = vvecFracPoints[j].second; // 终止点 // crack[0] = (int)vStartPoint.x(); // crack[1] = (int)vStartPoint.y(); // crack[2] = (int)vEndPoint.x(); // crack[3] = (int)vEndPoint.y(); // // todo,裂缝的宽度 // crack[4] = 1; // vMultistageFracturedHorizontalWell.push_back(crack); // } // inputObj.MultistageFracturedHorizontalWell.push_back(vMultistageFracturedHorizontalWell); // continue; // } // // 直井 // nmDataVerticalWell* pVertialWell = dynamic_cast(pWellData); // if (pVertialWell != nullptr) { // dVec1 well(3); // double dX = pVertialWell->getX().getValue().toDouble(); // double dY = pVertialWell->getY().getValue().toDouble(); // well[0] = dX; // well[1] = dY; // well[2] = pVertialWell->getRadius().getValue().toDouble(); // inputObj.VerticalWell.push_back(well); // continue; // } // } // } //return true; } bool nmCalculationPebiGrid::meshGenPebiFault(HX_NWTM_GRID_INPUT & inputObj) { // 从数据中心获取断层数据 QVector vecDataFault = nmDataAnalyzeManager::getCurrentInstance()->getFaultDataList(); inputObj.Fault.clear(); // 断层,没有宽度 for(int i = 0; i < vecDataFault.size(); i++) { nmDataFault* pFault = vecDataFault[i]; QVector vecPlts = pFault->getFaultPoints(); // 对每个断层进行处理 // 每个断层包括 多段 if(vecPlts.size() > 0) { for(int j = 0; j < vecPlts.size() - 1; j++) { //dVec1 frac(5); dVec1 frac(4); QPointF& vStartPoint = vecPlts[j]; QPointF& vEndPoint = vecPlts[j + 1]; // 起始点、终止点,没有宽度 frac[0] = vStartPoint.x(); frac[1] = vStartPoint.y(); frac[2] = vEndPoint.x(); frac[3] = vEndPoint.y(); inputObj.Fault.push_back(frac); } } } return true; } bool nmCalculationPebiGrid::meshGenPebiCrack(HX_NWTM_GRID_INPUT &inputObj) { // 从数据中心获取裂缝几何数据 QVector vecDataFracture = nmDataAnalyzeManager::getCurrentInstance()->getFractureDataList(); // 裂缝,将所有裂缝当一个 裂缝直井来处理 for(int i = 0; i < vecDataFracture.size(); i++) { nmDataFracture* pFrac = vecDataFracture[i]; QVector vecPlts = pFrac->getFracturePoints(); // 对每个裂缝进行处理 // 每个裂缝包括 多段 if(vecPlts.size() > 0) { for(int j = 0; j < vecPlts.size() - 1; j++) { dVec1 crack(5); QPointF& vStartPoint = vecPlts[j]; QPointF& vEndPoint = vecPlts[j + 1]; // 起始点、终止点,没有宽度 crack[0] = vStartPoint.x(); crack[1] = vStartPoint.y(); crack[2] = vEndPoint.x(); crack[3] = vEndPoint.y(); // todo,裂缝的宽度 crack[4] = 1; qDebug() << crack[0] << crack[1] << crack[2] << crack[3] << crack[4]; int iIndex = inputObj.VerticalWell.size() + inputObj.FractureVerticalWell.size(); inputObj.FractureVerticalWell.push_back(crack); //int iIndex = inputObj.VerticalWell.size() + inputObj.FractureVerticalWell.size(); // 添加到自定义井顺序数组 nmDataAnalyzeManager::getCurrentInstance()->insertCalculationWell(iIndex, QPair(NM_WELL_MODEL::Unknow_Well, "")); } } } return true; } void nmCalculationPebiGrid::genPebiVTK(const HX_NWTM_GRID_OUTPUT1 &P1, QString vtkDir) { // 1. 提取所有点数据 QVector > vPoints; for(size_t i = 0; i < P1.PEBI_cell.p.size(); ++i) { vPoints.append(QPair(P1.PEBI_cell.p[i].x, P1.PEBI_cell.p[i].y)); } // 2. 预处理单元数据 - 只处理isplot为1的单元 QVector > vCells; QVector vCellTypes; // 存储每个单元的类型 int totalCellDataSize = 0; for(size_t i = 0; i < P1.PEBI_cell.pindex.size(); ++i) { // 只处理isplot为1的单元 if(i >= P1.PEBI_cell.isplot.size() || P1.PEBI_cell.isplot[i] != 1) { continue; } const std::vector& vecIndices = P1.PEBI_cell.pindex[i]; if(vecIndices.empty()) continue; // 确定实际点数(检查首尾是否相同) int numPoints = vecIndices.size(); if(numPoints > 1 && vecIndices[0] == vecIndices[numPoints - 1]) { numPoints--; } // 跳过无效单元(点数小于2) if(numPoints < 2) continue; // 确定单元类型 int cellType = 0; if(numPoints == 2) { // 线 cellType = 3; // VTK_LINE } else if(numPoints == 3) { // 三角形 cellType = 5; // VTK_TRIANGLE } else if(numPoints == 4) { // 四边形 cellType = 9; // VTK_QUAD } else { // 多边形 cellType = 7; // VTK_POLYGON } // 存储单元数据 QVector cellData; cellData.append(numPoints); for(int j = 0; j < numPoints; ++j) { cellData.append(vecIndices[j]); } vCells.append(cellData); vCellTypes.append(cellType); totalCellDataSize += (numPoints + 1); // +1 for the numPoints entry } // 3. 构建VTK文件内容 QStringList vtkContents; vtkContents.append("# vtk DataFile Version 4.0"); vtkContents.append("Unstructured Grid"); vtkContents.append("ASCII"); vtkContents.append("DATASET UNSTRUCTURED_GRID"); // 写入点数据 vtkContents.append(QString("POINTS %1 float").arg(vPoints.size())); for(int i = 0; i < vPoints.size(); ++i) { vtkContents.append(QString("%1 %2 0.0").arg(vPoints[i].first).arg(vPoints[i].second)); } // 写入单元数据 vtkContents.append(QString("\nCELLS %1 %2").arg(vCells.size()).arg(totalCellDataSize)); for(int i = 0; i < vCells.size(); ++i) { QString line; const QVector& cellData = vCells[i]; for(int j = 0; j < cellData.size(); ++j) { line += QString::number(cellData[j]); if(j < cellData.size() - 1) { line += " "; } } vtkContents.append(line); } // 写入单元类型 vtkContents.append(QString("\nCELL_TYPES %1").arg(vCellTypes.size())); for(int i = 0; i < vCellTypes.size(); ++i) { vtkContents.append(QString::number(vCellTypes[i])); } // 写入文件 nmCalculationUtils::writeFile(vtkContents, vtkDir + "/pebi.vtk"); } HX_NWTM_GRID_OUTPUT1 nmCalculationPebiGrid::getGridOutput1() { return p1; } HX_NWTM_GRID_OUTPUT2 nmCalculationPebiGrid::getGridOutput2() { return p2; } vtkSmartPointer nmCalculationPebiGrid::createPebiUnstructuredGrid(const HX_NWTM_GRID_OUTPUT1& P1) { vtkSmartPointer pUnstructuredGrid = vtkSmartPointer::New(); vtkSmartPointer pPoints = vtkSmartPointer::New(); // 用于存储所有有效单元引用的唯一点索引 QSet setUniquePointIndices; // 1. 预处理单元数据,确定哪些单元是有效的,并收集这些单元引用的所有唯一点索引 // 这一步先不向 vtkPoints 添加点,而是收集需要添加的点的索引。 for(size_t i = 0; i < P1.PEBI_cell.pindex.size(); ++i) { // 只处理 isplot 为 1 的单元 if(i >= P1.PEBI_cell.isplot.size() || P1.PEBI_cell.isplot[i] != 1) { continue; } const std::vector& vecIndices = P1.PEBI_cell.pindex[i]; if(vecIndices.empty()) continue; // 确定实际点数(检查首尾是否相同) int nPointsInCell = vecIndices.size(); if(nPointsInCell > 1 && vecIndices[0] == vecIndices[nPointsInCell - 1]) { nPointsInCell--; } if(nPointsInCell < 2) continue; // 过滤掉无效单元(点数小于2) // 将此有效单元引用的所有点索引添加到 setUniquePointIndices 集合中 for(int j = 0; j < nPointsInCell; ++j) { setUniquePointIndices.insert(vecIndices[j]); } } // 创建一个映射表,将原始点索引映射到 VTK 中的新点索引 QMap mapOriginalToVtkPointId; vtkIdType currentVtkPointId = 0; // 2. 根据收集到的唯一点索引,将这些点添加到 vtkPoints pPoints->SetNumberOfPoints(setUniquePointIndices.size()); // 遍历 setUniquePointIndices foreach(int nOriginalIdx, setUniquePointIndices) { if(nOriginalIdx >= 0 && nOriginalIdx < P1.PEBI_cell.p.size()) { pPoints->SetPoint(currentVtkPointId, P1.PEBI_cell.p[nOriginalIdx].x, P1.PEBI_cell.p[nOriginalIdx].y, 0.0); mapOriginalToVtkPointId[nOriginalIdx] = currentVtkPointId; currentVtkPointId++; } else { // 处理异常情况:如果 setUniquePointIndices 中包含了无效的原始点索引 qDebug() << "Warning: Invalid original point index" << nOriginalIdx << "found in setUniquePointIndices."; } } pUnstructuredGrid->SetPoints(pPoints); // 3. 再次遍历单元数据,这次是根据新的 VTK 点索引来插入单元 for(size_t i = 0; i < P1.PEBI_cell.pindex.size(); ++i) { // 再次检查 isplot 标志,确保只处理有效单元 if(i >= P1.PEBI_cell.isplot.size() || P1.PEBI_cell.isplot[i] != 1) { continue; } const std::vector& vecIndices = P1.PEBI_cell.pindex[i]; if(vecIndices.empty()) continue; // 检查首尾是否重复 int nPointsInCell = vecIndices.size(); if(nPointsInCell > 1 && vecIndices[0] == vecIndices[nPointsInCell - 1]) { nPointsInCell--; } if(nPointsInCell < 2) continue; // 过滤掉无效单元 int vtkCellType = 0; if(nPointsInCell == 2) { vtkCellType = VTK_LINE; } else if(nPointsInCell == 3) { vtkCellType = VTK_TRIANGLE; } else if(nPointsInCell == 4) { vtkCellType = VTK_QUAD; } else { vtkCellType = VTK_POLYGON; } // 使用映射表将原始索引转换为新的 VTK 索引 vtkIdType* pts = new vtkIdType[nPointsInCell]; for(int j = 0; j < nPointsInCell; ++j) { if(mapOriginalToVtkPointId.contains(vecIndices[j])) { // 确保点在映射表中 pts[j] = mapOriginalToVtkPointId[vecIndices[j]]; } else { qDebug() << "Error: Point" << vecIndices[j] << "for cell" << i << "not found in map. This should not happen!"; // 可以选择跳过此单元或进行其他错误处理 delete[] pts; return nullptr; } } pUnstructuredGrid->InsertNextCell(vtkCellType, nPointsInCell, pts); delete[] pts; } return pUnstructuredGrid; } //bool nmCalculationPebiGrid::generateOutputPara() { // HMODULE dll = LoadLibrary(L"HX_NWTM.dll"); // // if(!dll) { // DWORD error = GetLastError(); // printf("Failed to load DLL. Error code: %lu\n", error); // return false; // } // // // 定义函数指针类型 // typedef void (*HX_NWTM_GRID_Func)(HX_NWTM_GRID_OUTPUT1&, HX_NWTM_GRID_OUTPUT2&, const HX_NWTM_GRID_INPUT&, std::string); // //typedef void (*HX_NWTM_GRID_Func)(HX_NWTM_GRID_OUTPUT1&, HX_NWTM_GRID_OUTPUT2&, const HX_NWTM_GRID_INPUT&, std::string); // // // 获取函数地址 // HX_NWTM_GRID_Func HX_NWTM_GRID = (HX_NWTM_GRID_Func)GetProcAddress(dll, "HX_NWTM_GRID"); // // if(!HX_NWTM_GRID) { // DWORD error = GetLastError(); // printf("Failed to resolve function. Error code: %lu\n", error); // FreeLibrary(dll); // return false; // } // // try { // // 执行网格生成逻辑 // this->meshGenPebiBoundary(p0); // this->meshGenPebiWells(p0); // this->meshGenPebiFault(p0); // this->meshGenPebiCrack(p0); // // nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::getCurrentInstance(); // QString licensePath = pDataManager->getLicensePath(); // std::string licensePathStd = licensePath.toStdString(); // // // 调用DLL函数 // HX_NWTM_GRID(p1, p2, p0, licensePathStd); // // } catch(const std::exception& e) { // zxLogInstance::getInstance()->writeLogF(QString("C++ Exception: %1").arg(e.what())); // logCurrentState(); // // 记录输入参数信息 // logInputParameters(p0); // // 确保只释放一次 // FreeLibrary(dll); // return false; // } catch(...) { // // 结构化异常,需要修改项目属性,项目属性 → C/C++ → Code Generation → Enable C++ Exceptions → 选择 Yes with SEH Exceptions (/EHa) // zxLogInstance::getInstance()->writeLogF("SEH Exception Occurred"); // logCurrentState(); // // 记录输入参数信息 // logInputParameters(p0); // // 确保只释放一次 // FreeLibrary(dll); // return false; // } // // // 确保只释放一次 // FreeLibrary(dll); // return true; //} bool nmCalculationPebiGrid::generateOutputPara() { HMODULE dll = LoadLibrary(L"HX_NWTM.dll"); // 定义函数指针类型 typedef void (*HX_NWTM_GRID_Func)(HX_NWTM_GRID_OUTPUT1&, HX_NWTM_GRID_OUTPUT2&, const HX_NWTM_GRID_INPUT&, std::string); // ===== 调用网格生成器 ===== typedef void (*HX_NWTM_GRID_Func)(HX_NWTM_GRID_OUTPUT1&, HX_NWTM_GRID_OUTPUT2&, const HX_NWTM_GRID_INPUT&, std::string); HX_NWTM_GRID_Func HX_NWTM_GRID = (HX_NWTM_GRID_Func)GetProcAddress(dll, "HX_NWTM_GRID"); if(!HX_NWTM_GRID) { DWORD error = GetLastError(); printf("Failed to resolve function. Error code: %lu\n", error); FreeLibrary(dll); return false; } try { // PEBI生成器是单例,输入输出结构会保留上一次状态;重新划分前先清空,避免拖动井后复用旧网格数据 p0 = HX_NWTM_GRID_INPUT(); p1 = HX_NWTM_GRID_OUTPUT1(); p2 = HX_NWTM_GRID_OUTPUT2(); // PEBI网格划分输入参数:GridControl来自界面 p0.GridControl = m_dGridControl; // 执行网格生成逻辑 this->meshGenPebiBoundary(p0); this->meshGenPebiWells(p0); this->meshGenPebiFault(p0); this->meshGenPebiCrack(p0); // ===== 导出 scene.bin ===== { nmDataBinaryTools::NM_PEBI_SCENE scene; nmDataAnalyzeManager* dm = nmDataAnalyzeManager::getCurrentInstance(); // 1. 网格基础数据 scene.version = 1; scene.D = p0.D; scene.GridControl = p0.GridControl; scene.Boundary = p0.Boundary; scene.VerticalWell = p0.VerticalWell; scene.HorizontalWell = p0.HorizontalWell; scene.FractureVerticalWell = p0.FractureVerticalWell; scene.MultistageFracturedHorizontalWell = p0.MultistageFracturedHorizontalWell; scene.InclinedWell = p0.InclinedWell; scene.Fault = p0.Fault; // 2. 井顺序信息 QVector> order = dm->getCalculationWells(); scene.wellType.clear(); scene.wellName.clear(); scene.wellType.reserve(order.size()); scene.wellName.reserve(order.size()); for(int i = 0; i < order.size(); ++i) { scene.wellType.push_back((int)order[i].first); scene.wellName.push_back(order[i].second); } // ===== 3. 求解器参数 ===== // 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; // 默认油单相 } } // 3.2 Rate流量数据 scene.Rate.t.resize(order.size()); scene.Rate.qo.resize(order.size()); scene.Rate.qg.resize(order.size()); scene.Rate.qw.resize(order.size()); for(int wellIdx = 0; wellIdx < order.size(); ++wellIdx) { NM_WELL_MODEL eWellType = order[wellIdx].first; QString sWellName = order[wellIdx].second; // 跳过裂缝 if(eWellType == NM_WELL_MODEL::Unknow_Well) { scene.Rate.t[wellIdx].clear(); scene.Rate.qo[wellIdx].clear(); scene.Rate.qg[wellIdx].clear(); scene.Rate.qw[wellIdx].clear(); continue; } // 从井数据中提取流量曲线 nmDataWellBase* pWellData = dm->findWellByName(sWellName); if(pWellData) { QVector vecTimeQ = pWellData->getFlowPoints(); // 移除第一个点(0,0) if(!vecTimeQ.isEmpty() && vecTimeQ[0].x() == 0 && vecTimeQ[0].y() == 0) { vecTimeQ.remove(0); } // 提取时间和流量 std::vector timeData; std::vector rateData; for(size_t i = 0; i < vecTimeQ.size(); ++i) { const QPointF& pt = vecTimeQ[i]; timeData.push_back(pt.x()); rateData.push_back(pt.y()); } scene.Rate.t[wellIdx] = timeData; // TODO: 根据井类型分配到qo/qg/qw // 目前简化处理:都分配到qo scene.Rate.qo[wellIdx] = rateData; scene.Rate.qg[wellIdx] = rateData; // 气井用这个 scene.Rate.qw[wellIdx] = rateData; // 水井用这个 } } // 3.3 CS井筒参数 scene.CS.C.resize(order.size()); scene.CS.S.resize(order.size()); for(int wellIdx = 0; wellIdx < order.size(); ++wellIdx) { NM_WELL_MODEL eWellType = order[wellIdx].first; QString sWellName = order[wellIdx].second; if(eWellType == NM_WELL_MODEL::Unknow_Well) { scene.CS.C[wellIdx] = 0.0; scene.CS.S[wellIdx] = 0.0; continue; } nmDataWellBase* pWellData = dm->findWellByName(sWellName); if(pWellData) { scene.CS.C[wellIdx] = pWellData->getWellboreStorage().getValue().toDouble(); // 获取第一段射孔的表皮系数 if(pWellData->getPerforationCount() > 0) { scene.CS.S[wellIdx] = pWellData->getPerforation(0)->getSkin().getValue().toDouble(); } else { scene.CS.S[wellIdx] = 0.0; } } } // 3.4 井流量段索引 scene.wellFlowSectionIndex.resize(order.size()); for(int wellIdx = 0; wellIdx < order.size(); ++wellIdx) { NM_WELL_MODEL eWellType = order[wellIdx].first; QString sWellName = order[wellIdx].second; if(eWellType == NM_WELL_MODEL::Unknow_Well) { scene.wellFlowSectionIndex[wellIdx] = 1; // 默认值 continue; } nmDataWellBase* pWellData = dm->findWellByName(sWellName); if(pWellData) { scene.wellFlowSectionIndex[wellIdx] = pWellData->getIndexF(); } else { scene.wellFlowSectionIndex[wellIdx] = 1; // 默认值 } } // 3.5 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(); } // 3.6 Base储层参数 if(pReservoirData) { scene.Base.Pi = pReservoirData->getInitialPressure().getValue().toDouble(); scene.Base.Cti = pReservoirData->getCt().getValue().toDouble(); scene.Base.Cf = pReservoirData->getCf().getValue().toDouble(); scene.Base.Soi = pReservoirData->getSoi().getValue().toDouble(); scene.Base.Sgi = pReservoirData->getSgi().getValue().toDouble(); scene.Base.Swi = pReservoirData->getSwi().getValue().toDouble(); // 保存参考值(用于Python采样) scene.Base.k_ref = pReservoirData->getPermeability().getValue().toDouble(); scene.Base.phi_ref = pReservoirData->getPorosity().getValue().toDouble(); scene.Base.h_ref = pReservoirData->getThickness().getValue().toDouble(); } // 3.7 时间步长设置 nmDataTimeStepSetting* pTimeStepSetting = dm->getTimeStep(); if(pTimeStepSetting) { scene.Base.d = pTimeStepSetting->getTimeGrowthExponent().getValue().toDouble(); scene.Base.dt_Min = pTimeStepSetting->getMinDeltaTAttribute().getValue().toDouble(); scene.Base.dt_Max = pTimeStepSetting->getMaxDeltaTAttribute().getValue().toDouble(); } // 4. 保存到文件 QDir appDir(QCoreApplication::applicationDirPath()); //QDir dataDir(appDir.filePath("../../3rd/Data")); QDir dataDir(appDir.filePath("../../ML/nmWTAI-ML/data/temp")); if(!dataDir.exists()) { dataDir.mkpath("."); // 确保 Data 目录存在 } QString outPath = dataDir.filePath("scene.bin"); bool ok = nmDataBinaryTools::savePebiSceneBin(outPath, scene); if(!ok) { zxLogInstance::getInstance()->writeLogF("savePebiSceneBin failed: " + nmDataBinaryTools::getLastError()); FreeLibrary(dll); return false; } else { zxLogInstance::getInstance()->writeLogF("scene.bin exported: " + outPath); } } // ===== 导出所有井:loglog + rate + pressure 到 temp 目录 ===== { nmDataAnalyzeManager* dm = nmDataAnalyzeManager::getCurrentInstance(); if(dm) { QDir appDir(QCoreApplication::applicationDirPath()); QDir tempDir(appDir.filePath("../../ML/nmWTAI-ML/data/temp")); if(!tempDir.exists()) { tempDir.mkpath("."); } QString outDir = tempDir.absolutePath(); int okCount = 0; int failCount = 0; auto exportOne = [&](nmDataWellBase * w) { if(!w) return; bool ok1 = w->exportHistoryLogLogToCsv(outDir); bool ok2 = w->exportHistoryRateToCsv(outDir); bool ok3 = w->exportHistoryPressureToCsv(outDir); if(ok1 && ok2 && ok3) okCount++; else failCount++; }; // 1) 直井 QVector verticalWells = dm->getVerticalWellData(); for(int i = 0; i < verticalWells.size(); ++i) { exportOne(verticalWells[i]); } // 2) 垂直裂缝井 QVector vfWells = dm->getVerticalFracturedWellData(); for(int i = 0; i < vfWells.size(); ++i) { exportOne(vfWells[i]); } // 3) 多段压裂水平井 QVector hfWells = dm->getHorizontalFracturedWellData(); for(int i = 0; i < hfWells.size(); ++i) { exportOne(hfWells[i]); } zxLogInstance::getInstance()->writeLogF( QString("History exported to temp. ok=%1, fail=%2, dir=%3") .arg(okCount).arg(failCount).arg(outDir) ); } } nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::getCurrentInstance(); QString licensePath = pDataManager->getLicensePath(); std::string licensePathStd = licensePath.toStdString(); HX_NWTM_GRID(p1, p2, p0, licensePathStd); } catch(const std::exception& e) { zxLogInstance::getInstance()->writeLogF(QString("C++ Exception: %1").arg(e.what())); logCurrentState(); logInputParameters(p0); FreeLibrary(dll); return false; } catch(...) { zxLogInstance::getInstance()->writeLogF("SEH Exception Occurred"); logCurrentState(); logInputParameters(p0); FreeLibrary(dll); return false; } FreeLibrary(dll); return true; }