You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/3rd/meshgen/example/solver_example.cpp

347 lines
11 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// netgen-2010.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "singlePhaseSolver.h"
#include "windows.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <stdexcept>
#include "iterator"
using namespace std;
void Ng2VTKWithData(Ng_Mesh *mesh, std::vector<double> vecField, std::string filename)
{
std::cout << "Convert Ng_Mesh to vtk legacy file version of 4.2" << std::endl;
int i, nseg, ne, np, matnum;
int nodes[3];
double point[2];
// int *EleNodeNum;
// double *NodeCoors;
np = Ng_GetNP_2D(mesh);
ne = Ng_GetNE_2D(mesh);
nseg = Ng_GetNSeg_2D(mesh);
std::ofstream vtkFile;
vtkFile.open(filename);
if (!vtkFile.is_open())
{
std::cerr << "Error opening file: " << "mesh.vtk" << std::endl;
return;
}
// Write VTK file header
vtkFile << "# vtk DataFile Version 4.1" << std::endl;
vtkFile << "Mesh data" << std::endl;
vtkFile << "ASCII" << std::endl;
vtkFile << "DATASET UNSTRUCTURED_GRID" << std::endl;
// Write points
vtkFile << "POINTS " << np << " float" << std::endl;
for (i = 1; i <= np; i++)
{
Ng_GetPoint_2D(mesh, i, point);
vtkFile << point[0] << " " << point[1] << " " << 0 << std::endl;
}
// Write cells
vtkFile << "CELLS " << ne << " " << ne * 4 << std::endl;
std::vector<int> vecMater;
for (int i = 1; i <= ne; i++)
{
Ng_GetElement_2D(mesh, i, nodes, &matnum);
vecMater.emplace_back(matnum);
vtkFile << 3 << " " << nodes[0] - 1 << " " << nodes[1] - 1 << " " << nodes[2] - 1 << std::endl;
}
// Write cell types
vtkFile << "CELL_TYPES " << ne << std::endl;
for (int i = 1; i <= ne; i++)
{
vtkFile << 5 << std::endl; // Assuming getCellType is a method that returns the VTK cell type
}
// Write cell data
vtkFile << "CELL_DATA " << ne << std::endl;
vtkFile << "SCALARS Material int 1" << std::endl;
vtkFile << "LOOKUP_TABLE default" << std::endl;
for (int i = 0; i < vecMater.size(); i++)
{
vtkFile << vecMater[i] << std::endl;
}
// Write point data
vtkFile << "POINT_DATA " << np << std::endl;
vtkFile << "SCALARS Pressure double 1" << std::endl;
vtkFile << "LOOKUP_TABLE default" << std::endl;
for (int i = 0; i < vecField.size(); i++)
{
vtkFile << vecField[i] << std::endl;
}
vtkFile.close();
}
int _tmain(int argc, _TCHAR *argv[])
{
/************************************************************************/
/* prepare data for mesh generation */
/************************************************************************/
// 多边形外边界,通过指定四条边来定义
CBoundShape shape;
shape.boundShape = POLYGON;
shape.nNumSegs = 4;
Segment seg1;
seg1.p1 = Point(-1500, -1500);
seg1.p2 = Point(1500, -1500);
Segment seg2;
seg2.p1 = Point(1500, -1500);
seg2.p2 = Point(1500, 1500);
Segment seg3;
seg3.p1 = Point(1500, 1500);
seg3.p2 = Point(-1500, 1500);
Segment seg4;
seg4.p1 = Point(-1500, 1500);
seg4.p2 = Point(-1500, -1500);
shape.vecSegments.push_back(seg1);
shape.vecSegments.push_back(seg2);
shape.vecSegments.push_back(seg3);
shape.vecSegments.push_back(seg4);
// shape.cCenter = Point(0, 0);
// shape.dRadius = 1000;
CBoundWell w1, w2;
// 第一口井为直井(默认为直井)
w1.cCenter = Point(0, 0); // 井中心坐标(0,0)
w1.dRadius = 0.09144; // 井半径0.09144
// 第二口井为垂直裂缝井
w2.wellType = VERTICAL_FRACTURED;
w2.dHf = 20; // 裂缝半长20米
w2.dTheata = 30; // 裂缝角度30°
w2.cCenter = Point(50, 0); // 井的中心位置500
w2.dRadius = 0.1; // 井的半径0.1
// 第三口井为多段压裂水平井
CBoundWell w3;
w3.wellType = MULTI_FRACED_HORIZONTAL;
w3.cCenter = Point(142, -226); // 中心点位置
w3.dRadius = 0.1; // 半径
w3.dBeta = 20; // 水平井角度
w3.dLength = 200; // 水平井长度
w3.nFracNum = 10; // 裂缝数量
w3.dHf = 20; // 裂缝半长
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// 在该参数设置条件下,一次只能添加一口井进行计算求解
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
std::vector<CBoundWell> wells;
// wells.push_back(w1);
// wells.push_back(w2);
wells.push_back(w3);
CBoundPolygon limit;
limit.boundShape = POLYGON;
limit.nNumSegs = 5;
// 通过指定的边来定义多边形
limit.vecSegments.push_back(Segment(Point(-516.2335347838829, -58.37577524138442), Point(-592.72401802758, -180.9965861656542)));
limit.vecSegments.push_back(Segment(Point(-592.72401802758, -180.9965861656542), Point(-485.12090993338666, -280.2195626173259)));
limit.vecSegments.push_back(Segment(Point(-485.12090993338666, -280.2195626173259), Point(-328.9162066043042, -229.04373034669038)));
limit.vecSegments.push_back(Segment(Point(-328.9162066043042, -229.04373034669038), Point(-376.36137535544276, -90.33591813134171)));
limit.vecSegments.push_back(Segment(Point(-376.36137535544276, -90.33591813134171), Point(-516.2335347838829, -58.37577524138442)));
limit.bAnchor = true;
// 通过指定的点来定义多边形,逆时针排列
std::vector<Point> points;
points.emplace_back(Point(-9.23023, 31.1986));
points.emplace_back(Point(-27.0886, 11.26));
points.emplace_back(Point(-23.5281, -14.9567));
points.emplace_back(Point(10.0862, -27.2422));
points.emplace_back(Point(39.6129, -1.9348));
points.emplace_back(Point(32.122, 15.5807));
points.emplace_back(Point(22.0438, 31.371));
CBoundPolygon limit1(points);
std::vector<Point> points2;
points2.emplace_back(Point(250.074, -101.492));
points2.emplace_back(Point(-44, -204.034));
points2.emplace_back(Point(7, -336.098));
points2.emplace_back(Point(312.333, -234.724));
CBoundPolygon limit2(points2);
std::vector<CBoundPolygon> limits;
limits.push_back(limit);
limits.push_back(limit1);
limits.push_back(limit2);
std::vector<Frac> faults;
faults.push_back(Frac(Point(-267.3, 120), Point(316.7, 150)));
faults.push_back(Frac(Point(316.7, 150), Point(316.7, -50)));
std::vector<Frac> fracs;
fracs.push_back(Frac(Point(-326.159, 460.059), Point(165.83631, 459.085)));
fracs.push_back(Frac(Point(50, -350), Point(358.840, -289.811)));
/************************************************************************/
/* load netgen mesh generation library and generate mesh */
/************************************************************************/
HMODULE hMod = LoadLibrary("meshgene.dll");
if (NULL == hMod)
{
std::cout << "meshgene.dll加载失败\n";
return 1;
}
typedef Ng_Mesh *(*NgMeshGen2DByIn2d)(std::vector<CBoundWell> &wells, const std::vector<CBoundPolygon> limits, const std::vector<Frac> &faults, const std::vector<Frac> &fracs, const CBoundShape &shape);
typedef Ng_Mesh *(*NgMeshGen2D)(std::string strFileIn2D);
typedef void *(*Ng2VTK)(Ng_Mesh *mesh);
// Get the address of the Ng_Mesh function
NgMeshGen2DByIn2d meshgene1 = (NgMeshGen2DByIn2d)GetProcAddress(hMod, "NgMeshGen2DByIn2d");
NgMeshGen2D meshgene2 = (NgMeshGen2D)GetProcAddress(hMod, "NgMeshGen2D");
if (NULL == meshgene1)
{
FreeLibrary(hMod);
std::cout << "meshgene文件加载函数地址获取失败\n";
return 1;
}
Ng_Mesh *mesh = meshgene1(wells, limits, faults, fracs, shape);
Ng2VTK ng = (Ng2VTK)GetProcAddress(hMod, "Ng2VTK");
ng(mesh);
/************************************************************************/
/* solve the equation by calling the singlephasesolver */
/************************************************************************/
// Prepare the reservoir base data
double pBaseData[8];
pBaseData[0] = 30.47;
pBaseData[1] = 15.1454;
pBaseData[2] = 30.48;
pBaseData[3] = 1.5;
pBaseData[4] = 1;
pBaseData[5] = 0.23;
pBaseData[6] = 0.00043511;
pBaseData[7] = 1;
// prepare the well data
// well w1
// w1.dRc=0.01;
wells[0].dSkin = 0;
wells[0].dC = 0.0232056;
wells[0].bisMultFlow = true;
wells[0].nTimeNumQ = 5;
wells[0].pdTimeQ[0] = 12;
wells[0].pdQ[0] = 158.987;
wells[0].pdTimeQ[1] = 12;
wells[0].pdQ[1] = 190.785;
wells[0].pdTimeQ[2] = 12;
wells[0].pdQ[2] = 222.582;
wells[0].pdTimeQ[3] = 48;
wells[0].pdQ[3] = 238.481;
wells[0].pdTimeQ[4] = 72;
wells[0].pdQ[4] = 0;
// 裂缝井必须指定裂缝的导流能力通过wFrac变量设置
wells[0].wFrac[0].dFc = 1000;
wells[0].wFrac[1].dFc = 1000;
// 多段压裂水平井必须指定裂缝的导流能力1000
// 导流能力的设置需要在网格划分后完成
for (int i = 0; i < wells[0].vecFracs.size(); ++i)
{
wells[0].vecFracs[i].dFc = 1000; //
}
// prepare the data for limits
limits[0].dComKr = 1;
limits[0].dComW = 1;
HMODULE hMod_solver = LoadLibrary("singlePhaseSolverDll.dll");
if (NULL == hMod_solver)
{
std::cout << "singlePhaseSolverDll.dll加载失败\n";
return 1;
}
TimeDis timeDis;
timeDis.dTB = 1.0e-5; //
typedef int (*Solver)(const TimeDis time, double *m_pBaseData, nglib::Ng_Mesh *mesh, std::vector<CBoundWell> &m_wWell, const std::vector<CBoundPolygon> &comPolygon, const std::vector<Frac> &faultPolygon, std::vector<Frac> &fracs, CBoundShape &outBound, std::vector<std::pair<double, std::vector<double>>> &vecNodePre);
Solver solverFun = (Solver)GetProcAddress(hMod_solver, "singlePhaseSolverNgmesh");
if (NULL == solverFun)
{
FreeLibrary(hMod_solver);
std::cout << "singlePhaseSolverNgmesh failed!\n";
return 1;
}
// std::vector<std::vector<Point>> vecBP;
std::vector<std::pair<double, std::vector<double>>> vecFieldPre;
solverFun(timeDis, pBaseData, mesh, wells, limits, faults, fracs, shape, vecFieldPre);
// export bottom hole pressure history
std::cout << "Export log-log plot and history plot data to files\n";
std::ofstream historyFile;
historyFile.precision(8);
historyFile.open("output/history.txt");
if (!historyFile.is_open())
{
std::cerr << "Error opening file: " << "history.txt" << std::endl;
return 1;
}
int nWell = 0;
for (int i = 0; i < wells[nWell].m_PressureData.size(); i++)
{
historyFile << wells[nWell].m_PressureData[i].x << "\t" << wells[nWell].m_PressureData[i].y << std::endl;
}
historyFile.close();
// calculate the pressure derivative
typedef bool (*PreLog)(const std::vector<Point> &pressure, const int &nSection, double *TimeQ, double *dQ, int nTimeQ, std::vector<Point> &logPre);
PreLog preLogFun = (PreLog)GetProcAddress(hMod_solver, "logLogPre");
if (NULL == preLogFun)
{
FreeLibrary(hMod_solver);
std::cout << "preLogFun failed!\n";
return 1;
}
std::vector<Point> logPre;
preLogFun(wells[0].m_PressureData, 5, wells[0].pdTimeQ, wells[0].pdQ, wells[0].nTimeNumQ, logPre);
// export the pressure derivative
std::ofstream logFile;
logFile.precision(8);
logFile.open("output/logPre.txt");
if (!logFile.is_open())
{
std::cerr << "Error opening file: " << "logPre.txt" << std::endl;
return 1;
}
for (int i = 0; i < logPre.size(); i++)
{
logFile << logPre[i].x << "\t" << logPre[i].y << "\t" << logPre[i].z << "\t" << std::endl;
}
logFile.close();
// export with pressure field with vtk format (version 4.2)
for (int i = 0; i < vecFieldPre.size(); ++i)
{
if (i % 10 == 0)
{
Ng2VTKWithData(mesh, vecFieldPre[i].second, "output/" + std::to_string(long double(i)) + ".vtk");
}
}
FreeLibrary(hMod);
FreeLibrary(hMod_solver);
}