|
|
#include "nmCalculationPebiGrid.h"
|
|
|
#include <Windows.h>
|
|
|
#include <QApplication>
|
|
|
#include <QDebug>
|
|
|
#include <QDir>
|
|
|
#include <cmath>
|
|
|
#include <QSet>
|
|
|
|
|
|
#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 <vtkPoints.h>
|
|
|
#include <vtkCellArray.h>
|
|
|
#include <vtkType.h>
|
|
|
#include <vtkUnsignedCharArray.h>
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
#include <windows.h>
|
|
|
#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<vtkUnstructuredGrid> 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<QPointF> 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<nmDataWellBase*> 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<nmDataVerticalWell*> verticalWells = pDataManager->getVerticalWellData();
|
|
|
// 获取垂直裂缝井数据
|
|
|
QVector<nmDataVerticalFracturedWell*> vFracturedWells = pDataManager->getVerticalFracturedWellData();
|
|
|
// 获取多段压裂水平井数据
|
|
|
QVector<nmDataHorizontalFracturedWell*> 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, QString>(NM_WELL_MODEL::Vertical_Well, pVerticalWell->getWellName()));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 处理垂直裂缝井数据
|
|
|
foreach(nmDataVerticalFracturedWell* pVerticalFracturedWell, vFracturedWells) {
|
|
|
if(pVerticalFracturedWell != nullptr) {
|
|
|
QVector<QPointF> 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, QString>(NM_WELL_MODEL::Vertical_Fractured_Well, pVerticalFracturedWell->getWellName()));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 处理多段压裂水平井数据
|
|
|
foreach(nmDataHorizontalFracturedWell* pHorizontalFracturedWell, hFracturedWells) {
|
|
|
if(pHorizontalFracturedWell != nullptr) {
|
|
|
QVector<QPair<QPointF, QPointF>> vvecFracPoints = pHorizontalFracturedWell->getFracs();
|
|
|
std::vector<std::vector<double>> 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, QString>(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<nmDataVerticalFracturedWell*>(pWellData);
|
|
|
// if (pVerticalFracturedWell != nullptr) {
|
|
|
// dVec1 crack(5);
|
|
|
// QVector<QPointF> 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<double>(static_cast<int>(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<nmDataHorizontalFracturedWell*>(pWellData);
|
|
|
// if (pHorizontalFracturedWell != nullptr) {
|
|
|
// QVector<QPair<QPointF, QPointF>> vvecFracPoints = pHorizontalFracturedWell->getFracs();
|
|
|
// std::vector<std::vector<double>> 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<nmDataVerticalWell*>(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<nmDataFault*> vecDataFault = nmDataAnalyzeManager::getCurrentInstance()->getFaultDataList();
|
|
|
inputObj.Fault.clear();
|
|
|
|
|
|
// 断层,没有宽度
|
|
|
for(int i = 0; i < vecDataFault.size(); i++) {
|
|
|
nmDataFault* pFault = vecDataFault[i];
|
|
|
QVector<QPointF> 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<nmDataFracture*> vecDataFracture = nmDataAnalyzeManager::getCurrentInstance()->getFractureDataList();
|
|
|
|
|
|
// 裂缝,将所有裂缝当一个 裂缝直井来处理
|
|
|
for(int i = 0; i < vecDataFracture.size(); i++) {
|
|
|
nmDataFracture* pFrac = vecDataFracture[i];
|
|
|
QVector<QPointF> 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, QString>(NM_WELL_MODEL::Unknow_Well, ""));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void nmCalculationPebiGrid::genPebiVTK(const HX_NWTM_GRID_OUTPUT1 &P1, QString vtkDir)
|
|
|
{
|
|
|
// 1. 提取所有点数据
|
|
|
QVector<QPair<double, double> > vPoints;
|
|
|
|
|
|
for(size_t i = 0; i < P1.PEBI_cell.p.size(); ++i) {
|
|
|
vPoints.append(QPair<double, double>(P1.PEBI_cell.p[i].x, P1.PEBI_cell.p[i].y));
|
|
|
}
|
|
|
|
|
|
// 2. 预处理单元数据 - 只处理isplot为1的单元
|
|
|
QVector<QVector<int> > vCells;
|
|
|
QVector<int> 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<int>& 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<int> 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<int>& 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<vtkUnstructuredGrid> nmCalculationPebiGrid::createPebiUnstructuredGrid(const HX_NWTM_GRID_OUTPUT1& P1)
|
|
|
{
|
|
|
vtkSmartPointer<vtkUnstructuredGrid> pUnstructuredGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
|
|
|
vtkSmartPointer<vtkPoints> pPoints = vtkSmartPointer<vtkPoints>::New();
|
|
|
|
|
|
// 用于存储所有有效单元引用的唯一点索引
|
|
|
QSet<int> 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<int>& 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<int, vtkIdType> 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<int>& 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<QPair<NM_WELL_MODEL, QString>> 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<QPointF> vecTimeQ = pWellData->getFlowPoints();
|
|
|
|
|
|
// 移除第一个点(0,0)
|
|
|
if(!vecTimeQ.isEmpty() && vecTimeQ[0].x() == 0 && vecTimeQ[0].y() == 0) {
|
|
|
vecTimeQ.remove(0);
|
|
|
}
|
|
|
|
|
|
// 提取时间和流量
|
|
|
std::vector<double> timeData;
|
|
|
std::vector<double> 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<nmDataVerticalWell*> verticalWells = dm->getVerticalWellData();
|
|
|
for(int i = 0; i < verticalWells.size(); ++i) {
|
|
|
exportOne(verticalWells[i]);
|
|
|
}
|
|
|
|
|
|
// 2) 垂直裂缝井
|
|
|
QVector<nmDataVerticalFracturedWell*> vfWells = dm->getVerticalFracturedWellData();
|
|
|
for(int i = 0; i < vfWells.size(); ++i) {
|
|
|
exportOne(vfWells[i]);
|
|
|
}
|
|
|
|
|
|
// 3) 多段压裂水平井
|
|
|
QVector<nmDataHorizontalFracturedWell*> 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;
|
|
|
}
|