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/Src/nmNum/nmData/nmDataAnalyzeManager.cpp

4140 lines
127 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.

#include "nmDataAnalyzeManager.h"
#include "nmDataAnalyzeContext.h"
#include "nmDataAnalyzeContextProvider.h"
#include "nmDataPlotContext.h"
#include "nmDataPlotContextProvider.h"
#include "nmDataWellBase.h"
#include "nmDataVerticalWell.h"
#include "nmDataVerticalFracturedWell.h"
#include "nmDataHorizontalFracturedWell.h"
#include "ZxDataWell.h"
#include "ZxBaseUtil.h"
#include "zxLogInstance.h"
#include "nmDataReservoir.h"
#include "nmDataRegionMark.h"
#include "nmDataOutline.h"
#include "nmDataRegion.h"
#include "nmDataFracture.h"
#include "nmDataFault.h"
#include "nmDataMeasuringScale.h"
#include "nmDataMeasure.h"
#include "nmDataAxis.h"
#include "nmDataGeoRef.h"
#include "nmDataDiagnostic.h"
#include "nmDataForecast.h"
#include "nmDataAutomaticFitting.h"
#include "nmDataSensitive.h"
#include "nmDataPvtParaForPebi.h"
#include "ZxDataWell.h"
#include "ZxDataGaugeP.h"
#include "ZxDataGaugeF.h"
#include "zxSysUtils.h"
#include "ZxDataProject.h"
#include "nmDataMixedResults.h"
#include "nmDataLayer.h"
#include "nmDataUtils.h"
#include "mAlgDefines.h"
#include "nmDataJsonTools.h" // JSON工具类
#include "nmTranslationManager.h"
#include "iAnalRun.h"
#include "ZxDataAnalRun.h"
#include <Windows.h>
#include <iostream>
#include <vector>
#include "singlePhaseSolver.h"
#include <vtkUnstructuredGridReader.h>
#include <vtkXMLUnstructuredGridReader.h>
#include <vtkUnstructuredGridWriter.h>
#include <vtkXMLUnstructuredGridWriter.h>
#include <vtkNew.h>
#include "nmDataTimeStepSetting.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QMessageBox>
namespace {
// 清空指定目录下的所有旧文件和子目录,但保留目录本身
bool clearDirectoryContents(const QString& dirPath)
{
if(dirPath.trimmed().isEmpty()) {
return false;
}
QDir dir(dirPath);
if(dir.isRoot()) {
qDebug() << QString("Refuse to clear root directory: %1").arg(dirPath);
return false;
}
if(!dir.exists()) {
return true;
}
QFileInfoList entries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden | QDir::System);
for(int i = 0; i < entries.size(); ++i) {
const QFileInfo& entry = entries.at(i);
bool bRemoved = false;
if(entry.isDir() && !entry.isSymLink()) {
bRemoved = clearDirectoryContents(entry.absoluteFilePath()) && dir.rmdir(entry.fileName());
} else {
bRemoved = QFile::remove(entry.absoluteFilePath());
}
if(!bRemoved) {
qDebug() << QString("Failed to remove old result item: %1").arg(entry.absoluteFilePath());
return false;
}
}
return true;
}
// 多条PVT曲线都可能带压力横坐标只保存第一次读到的有效横坐标
void setPebiPressureIfEmpty(nmDataPvtParaForPebi* pPvtPara, const QVector<double>& vecX)
{
if(pPvtPara != nullptr && pPvtPara->getPressure().isEmpty() && !vecX.isEmpty()) {
pPvtPara->setPressure(vecX);
}
}
// 从Diffusion右侧结果表中提取指定列数据
bool extractDiffusionColumn(const VVecDouble& vvec, int nColumn, QVector<double>& vecValues)
{
vecValues.clear();
if(vvec.isEmpty() || nColumn < 0) {
return false;
}
if(vvec.size() > nColumn && vvec[nColumn].size() > 4 && vvec[nColumn].size() > vvec.size()) {
vecValues = vvec[nColumn];
return !vecValues.isEmpty();
}
// Diffusion结果表通常按行保存[自变量, 结果1, 结果2]
for(int i = 0; i < vvec.size(); ++i) {
if(vvec[i].size() > nColumn) {
vecValues.append(vvec[i][nColumn]);
}
}
if(!vecValues.isEmpty()) {
return true;
}
// 兼容少量按列缓存的数据
if(vvec.size() > nColumn) {
vecValues = vvec[nColumn];
}
return !vecValues.isEmpty();
}
// 根据饱和度坐标计算互补饱和度例如油水相渗中由Sw得到So
QVector<double> complementSaturation(const QVector<double>& vecSaturation)
{
QVector<double> vecResult;
vecResult.reserve(vecSaturation.size());
for(int i = 0; i < vecSaturation.size(); ++i) {
vecResult.append(1.0 - vecSaturation[i]);
}
return vecResult;
}
// 将数组顺序反转用于把Diffusion中按Sw递增的数据整理为按So递增的数据
QVector<double> reversedVector(const QVector<double>& vecValues)
{
QVector<double> vecResult;
vecResult.reserve(vecValues.size());
for(int i = vecValues.size(); i > 0; --i) {
vecResult.append(vecValues[i - 1]);
}
return vecResult;
}
// 将油水两相Diffusion相渗结果映射到PEBI求解器需要的饱和度和相对渗透率字段
void applyDiffusionKkToPebiPvt(nmDataPvtParaForPebi* pPvtPara, const VVecDouble& vvecKK)
{
if(vvecKK.isEmpty()) {
return;
}
QVector<double> vecS;
QVector<double> vecKr1;
QVector<double> vecKr2;
if(!extractDiffusionColumn(vvecKK, 0, vecS)) {
return;
}
extractDiffusionColumn(vvecKK, 1, vecKr1);
extractDiffusionColumn(vvecKK, 2, vecKr2);
// 油水第一列为SwSo按1-Sw生成后续列为Kro/Krw
// PEBI默认相渗以So为横坐标Diffusion表按Sw递增保存这里整体转为So递增方向
pPvtPara->setSo(reversedVector(complementSaturation(vecS)));
if(!vecKr1.isEmpty()) {
pPvtPara->setKro(reversedVector(vecKr1));
}
if(!vecKr2.isEmpty()) {
pPvtPara->setKrw(reversedVector(vecKr2));
}
}
/// @brief 尝试获取某相态的3条PVT曲线B/C/Miu全部成功则写入pebiPvtPara
/// @param pCtx 上下文提供者用于读取PVT结果页
/// @param pSubWnd 当前流动段分析窗口
/// @param pftContext getPvtRstOf需要的相态参数
/// @param sBName 体积系数参数名("Bo"/"Bg"/"Bw"
/// @param sCName 压缩系数参数名("Co"/"Cg"/"Cw"
/// @param sMiuName 粘度参数名("Miuo"/"Miug"/"Miuw"
/// @param pPvt 输出的PEBI PVT参数对象
/// @param vecPressure 压力横坐标(首次成功时写入,后续复用)
/// @return 三条曲线全部获取成功返回true否则返回false且不写入pPvt
bool tryFetchPhasePvtCurves(
nmDataAnalyzeContextProvider* pCtx,
iSubWndFitting* pSubWnd,
PvtFluidType pftContext,
const QString& sBName,
const QString& sCName,
const QString& sMiuName,
nmDataPvtParaForPebi* pPvt,
QVector<double>& vecPressure)
{
// 分别获取体积系数、压缩系数、粘度三条曲线
QVector<double> vecB, vecC, vecMiu, vecX;
bool bB = pCtx->getPvtRstOf(pSubWnd, pftContext, sBName, vecX, vecB);
bool bC = pCtx->getPvtRstOf(pSubWnd, pftContext, sCName, vecX, vecC);
bool bMiu = pCtx->getPvtRstOf(pSubWnd, pftContext, sMiuName, vecX, vecMiu);
// 任一曲线缺失则视为该相态PVT数据不完整不写入
if(!(bB && bC && bMiu)) {
return false;
}
// 首次成功时保存压力横坐标
if(vecPressure.isEmpty() && !vecX.isEmpty()) {
vecPressure = vecX;
}
// 按相态名称写入对应的setter油气水各自独立字段
if(sBName == "Bo") pPvt->setBo(vecB);
else if(sBName == "Bg") pPvt->setBg(vecB);
else if(sBName == "Bw") pPvt->setBw(vecB);
if(sCName == "Co") pPvt->setCo(vecC);
else if(sCName == "Cg") pPvt->setCg(vecC);
else if(sCName == "Cw") pPvt->setCw(vecC);
if(sMiuName == "Miuo") pPvt->setMiuo(vecMiu);
else if(sMiuName == "Miug") pPvt->setMiug(vecMiu);
else if(sMiuName == "Miuw") pPvt->setMiuw(vecMiu);
return true;
}
/// @brief 设置油藏属性的简化辅助,消除 tempAttr=getX(); tempAttr.setValue(); setX(tempAttr) 三行重复模式
/// @param attr 油藏属性引用
/// @param dValue 属性值
void setReservoirAttr(nmDataAttribute& attr, double dValue)
{
attr.setValue(dValue);
}
/// @brief 设置油藏属性的简化辅助QString版本
void setReservoirAttr(nmDataAttribute& attr, const QString& sValue)
{
attr.setValue(sValue);
}
/// @brief 从界面读取PVT单值参数
/// @param pCtx 上下文提供者
/// @param pSubWnd 当前流动段分析窗口
/// @param eType 相态类型
/// @return 参数名到值的映射
QMap<QString, double> readPvtSingleValues(
nmDataAnalyzeContextProvider* pCtx,
iSubWndFitting* pSubWnd,
PvtFluidType eType)
{
// 按相态构建需要读取的参数列表
QStringList listParas;
switch(eType) {
case WFT_Oil: listParas << "Bo" << "Miuo"; break;
case WFT_Gas: listParas << "Bg" << "Miug"; break;
case WFT_Water: listParas << "Bw" << "Miuw"; break;
case WFT_Oil_Water: listParas << "Bo" << "Miuo" << "Bw" << "Miuw"; break;
default: break;
}
// 综合压缩系数Ct不区分模式统一读取
listParas << "Ct";
// 调用接口读取参数值
QMap<QString, double> mapPvtValues;
if(!listParas.isEmpty()) {
pCtx->getPvtParaValues(pSubWnd, listParas, mapPvtValues);
}
return mapPvtValues;
}
/// @brief 按相态填充油藏PVT字段和压缩系数
/// @param pRes 油藏数据对象
/// @param eType 相态类型
/// @param mapPvtValues 从界面读取的PVT单值参数
/// @param dCf 岩石压缩系数(来自分层数据)
void populateReservoirByPhase(
nmDataReservoir* pRes,
PvtFluidType eType,
const QMap<QString, double>& mapPvtValues,
double dCf)
{
// 按相态设置多相流类型和对应的B/Miu字段
switch(eType) {
case WFT_Oil:
pRes->setPhaseType(PHASE_Oil);
setReservoirAttr(pRes->getBo(), mapPvtValues.value("Bo", 1.5));
setReservoirAttr(pRes->getMiuo(), mapPvtValues.value("Miuo", 1.0));
break;
case WFT_Gas:
pRes->setPhaseType(PHASE_Gas);
setReservoirAttr(pRes->getBg(), mapPvtValues.value("Bg", 1.0));
setReservoirAttr(pRes->getMiug(), mapPvtValues.value("Miug", 1.0));
break;
case WFT_Water:
pRes->setPhaseType(PHASE_Water);
setReservoirAttr(pRes->getBw(), mapPvtValues.value("Bw", 1.0));
setReservoirAttr(pRes->getMiuw(), mapPvtValues.value("Miuw", 1.0));
break;
case WFT_Oil_Water:
pRes->setPhaseType(PHASE_Oil_Water);
setReservoirAttr(pRes->getBo(), mapPvtValues.value("Bo", 1.5));
setReservoirAttr(pRes->getMiuo(), mapPvtValues.value("Miuo", 1.0));
setReservoirAttr(pRes->getBw(), mapPvtValues.value("Bw", 1.0));
setReservoirAttr(pRes->getMiuw(), mapPvtValues.value("Miuw", 1.0));
break;
default:
pRes->setPhaseType(PHASE_UNKNOWN);
break;
}
// 压缩系数Ct来自PVT参数界面Cf来自分层数据不区分模式统一设置
setReservoirAttr(pRes->getCt(), mapPvtValues.value("Ct", 0.1));
setReservoirAttr(pRes->getCf(), dCf);
}
/// @brief 创建默认分层
/// @param dThickness 储层厚度
/// @param vecLayers 分层数据列表(输出)
void createDefaultLayer(double dThickness, QVector<nmDataLayer*>& vecLayers)
{
// 清空现有分层数据
qDeleteAll(vecLayers);
vecLayers.clear();
// 创建一个默认分层
nmDataLayer* pDefaultLayer = new nmDataLayer();
pDefaultLayer->setTop(6000.0); // 默认顶深
pDefaultLayer->setThickness(dThickness); // 使用从界面获取的厚度值
pDefaultLayer->setBottom(6000.0 + dThickness); // 计算底深
pDefaultLayer->setIsChecked(false); // 默认未选中
pDefaultLayer->setColor(QColor(0, 255, 0)); // 设置默认颜色(绿色)
// 将默认分层添加到分层列表
vecLayers.append(pDefaultLayer);
}
}
ZX_DEFINE_DYNAMIC(DataAnalyzeManager, nmDataAnalyzeManager)
nmDataAnalyzeManager::nmDataAnalyzeManager(): ZxDataObjectBin(0)
{
m_reservoirData = nullptr;
m_outlineData = nullptr;
m_pMeasuringScaleData = nullptr;
m_pebiPvtPara = nullptr;
m_pMixedResults = nullptr;
m_pLayerData = nullptr;
m_pCurDataWell = nullptr;
m_pMeasureData = nullptr;
m_axisData = nullptr;
m_pNmGuiPlot = nullptr;
m_pGeoRefData = nullptr;
m_pTimeStep = nullptr;
//m_pPerCloData = nullptr;
m_pAutomaticFittingData = nullptr;
m_pDiagnosticData = nullptr;
//m_pSkinVsRateData = nullptr;
//m_pFlowSegmentData = nullptr;
m_pForecastData = nullptr;
m_pSensitiveData = nullptr;
m_backgroundImageInfo.bIsVisible = false;
m_dScalarRangeP[0] = 0.0;
m_dScalarRangeP[1] = 0.0;
// 初始化混合参数数据(Temp)
//m_pMixedResults = new nmDataMixedResults;
// 初始化储层数据
m_pLayerData = new nmDataLayer;
m_eGridType = NM_Grid_Type::NM_Grid_PEBI; //默认网格类型为PEBI
m_eSolverModelType = NM_SOLVER_MODEL_TYPE::SMT_Oil_ConstPvt;
this->initDefaultDisplaySettings();
// 初始化中英文翻译映射
nmTranslationManager::initTranslations();
m_bIsLoadData = false;
// 获取完整路径
//QString appPath = QCoreApplication::applicationFilePath();
//qDebug() << "完整应用路径:" << appPath;
// 许可证路径
//m_licensePath = appPath + "/../../3rd/Pebi/license/HXNWTM_license.dat";
// 获取完整路径
QString appPath = QCoreApplication::applicationFilePath();
// 获取应用程序所在的目录
QString appDir = QFileInfo(appPath).absolutePath();
// 定义从应用程序目录到许可证目录的相对路径
QString relativeJump = "/../Res/license/HXNWTM_license.dat";
// 将目录和相对跳转路径拼接
m_licensePath = appDir + relativeJump;
}
// 初始化静态成员
nmDataAnalyzeManager::~nmDataAnalyzeManager()
{
// 图元只引用数据数据统一由DataManager释放。
// 关闭成果或流动段分析后,清理该分析窗口对应的全部数据。
// 这两个成员是借用引用或容器内对象的别名不单独delete。
m_pCurDataWell = nullptr;
m_pNmGuiPlot = nullptr;
// 先释放容器中的数据对象,再释放其余独占的单对象数据。
qDeleteAll(m_vWellData);
m_vWellData.clear();
qDeleteAll(m_vFaultData);
m_vFaultData.clear();
qDeleteAll(m_vFractureData);
m_vFractureData.clear();
qDeleteAll(m_vRegionData);
m_vRegionData.clear();
qDeleteAll(m_vRegionMarkData);
m_vRegionMarkData.clear();
qDeleteAll(m_vecLayers);
m_vecLayers.clear();
delete m_outlineData;
m_outlineData = nullptr;
delete m_axisData;
m_axisData = nullptr;
delete m_pAutomaticFittingData;
m_pAutomaticFittingData = nullptr;
delete m_reservoirData;
m_reservoirData = nullptr;
delete m_pMeasuringScaleData;
m_pMeasuringScaleData = nullptr;
delete m_pMeasureData;
m_pMeasureData = nullptr;
delete m_pGeoRefData;
m_pGeoRefData = nullptr;
delete m_pForecastData;
m_pForecastData = nullptr;
delete m_pSensitiveData;
m_pSensitiveData = nullptr;
delete m_pDiagnosticData;
m_pDiagnosticData = nullptr;
delete m_pebiPvtPara;
m_pebiPvtPara = nullptr;
delete m_pMixedResults;
m_pMixedResults = nullptr;
delete m_pLayerData;
m_pLayerData = nullptr;
delete m_pTimeStep;
m_pTimeStep = nullptr;
}
QMap<iSubWndFitting*, nmDataAnalyzeManager*> nmDataAnalyzeManager::s_mapDataAnalManager;
iSubWndFitting* nmDataAnalyzeManager::s_pCurSubWndFitting = nullptr;
nmDataAnalyzeManager* nmDataAnalyzeManager::getInstanceByFitting(iSubWndFitting* pSubWndF)
{
if(s_mapDataAnalManager.contains(pSubWndF)) {
return s_mapDataAnalManager[pSubWndF];
}
nmDataAnalyzeManager* pInstance = new nmDataAnalyzeManager();
s_mapDataAnalManager[pSubWndF] = pInstance;
return pInstance;
}
void nmDataAnalyzeManager::removeInstanceByFitting(iSubWndFitting* pSubWndF)
{
if(pSubWndF == nullptr) {
return;
}
// take()先解除窗口和manager的映射避免析构期间再次找到待释放对象。
nmDataAnalyzeManager* pInstance = s_mapDataAnalManager.take(pSubWndF);
if(s_pCurSubWndFitting == pSubWndF) {
s_pCurSubWndFitting = nullptr;
}
delete pInstance;
}
nmDataAnalyzeManager* nmDataAnalyzeManager::getCurrentInstance()
{
if(s_mapDataAnalManager.contains(s_pCurSubWndFitting)) {
return s_mapDataAnalManager[s_pCurSubWndFitting];
} else {
return nullptr;
}
}
nmDataWellBase *nmDataAnalyzeManager::createWell(NM_WELL_MODEL eWellType)
{
// 根据当前Fitting窗口来获取对应的井相关数据
iSubWndFitting* pSubWndFitting = nmDataAnalyzeManager::getCurrentFitting();
nmDataAnalyzeContextProvider* pContextProvider = nmDataAnalyzeContext::provider();
Q_ASSERT(nullptr != pSubWndFitting);
Q_ASSERT(nullptr != pContextProvider);
nmDataWellBase* pWellData = nullptr;
// 新建一口井,默认直井
if(eWellType == NM_WELL_MODEL::Vertical_Well) {
// 直接使用子类指针创建对象
nmDataVerticalWell* verticalWell = new nmDataVerticalWell;
pWellData = static_cast<nmDataWellBase*>(verticalWell);
} else if(eWellType == NM_WELL_MODEL::Vertical_Fractured_Well) {
// 直接使用子类指针创建对象
nmDataVerticalFracturedWell* vFracturedWell = new nmDataVerticalFracturedWell;
pWellData = static_cast<nmDataWellBase*>(vFracturedWell);
} else if(eWellType == NM_WELL_MODEL::Horizontal_Fractured_Well) {
// 直接使用子类指针创建对象
nmDataHorizontalFracturedWell* hFracturedWell = new nmDataHorizontalFracturedWell;
pWellData = static_cast<nmDataWellBase*>(hFracturedWell);
}
// 默认井才可以选择当前流动段,其余井默认选择最后一段
if(pWellData == nullptr) {
return nullptr;
}
if(m_vWellData.count() == 0) {
int nIndexF = -1;
// 第一口井就选择界面上的流动段索引
// 流动段索引由窗口层上下文提供,数据层不直接访问窗口对象
if(pSubWndFitting != nullptr && pContextProvider != nullptr) {
if(pContextProvider->getCurrentSegmentIndex(pSubWndFitting, nIndexF)) {
// 设置当前流动段索引
pWellData->setIndexF(nIndexF);
}
}
}
m_vWellData.append(pWellData);
emit dataChanged();
return pWellData;
}
// 实现 changeWellType 函数
nmDataWellBase* nmDataAnalyzeManager::changeWellType(nmDataWellBase* pOldWellData, NM_WELL_MODEL eTargetWellType)
{
if(pOldWellData == nullptr) {
return nullptr;
}
if(!removeWell(pOldWellData)) {
return nullptr;
}
nmDataWellBase* pNewWellData = createWell(eTargetWellType);
if(pNewWellData == nullptr) {
return nullptr;
}
return pNewWellData;
}
// 实现 removeWell 函数
bool nmDataAnalyzeManager::removeWell(nmDataWellBase* pWellData)
{
if(pWellData == nullptr) {
return false;
}
const QString removedWellName = pWellData->getWellName();
const bool isCurrentWell = (m_pCurDataWell == pWellData);
// 删除井对象前,先移除仍然引用这口井的状态。
for(int i = m_vecCalculationWells.size() - 1; i >= 0; --i) {
if(m_vecCalculationWells[i].second == removedWellName) {
m_vecCalculationWells.remove(i);
}
}
// 如果删的是当前井,切换到其他有效井;如果没有,则清空当前井指针。
if(isCurrentWell) {
m_pCurDataWell = nullptr;
for(int i = 0; i < m_vWellData.size(); ++i) {
nmDataWellBase* pCandidate = m_vWellData[i];
if(pCandidate != nullptr && pCandidate != pWellData) {
m_pCurDataWell = pCandidate;
break;
}
}
}
// 遍历 m_vWellData找到并移除指定的井对象
for(auto it = m_vWellData.begin(); it != m_vWellData.end(); ++it) {
if(*it == pWellData) {
m_vWellData.erase(it);
delete pWellData;
pWellData = nullptr;
emit dataChanged();
return true; // 成功移除并删除井对象
}
}
return false; // 如果未找到该井对象,返回 false
}
void nmDataAnalyzeManager::removeWellDataAndPlot(nmDataWellBase* pWellData)
{
// 参数校验
if(pWellData == nullptr) {
return;
}
// 公共删井入口中不允许删除当前井,避免活动井引用失效
if(pWellData == getCurWellData()) {
return;
}
nmDataPlotContextProvider* pPlotContextProvider = nmDataPlotContext::provider();
if (m_pNmGuiPlot != nullptr && pPlotContextProvider != nullptr)
{
// 移除所有井图元
pPlotContextProvider->removeWellPlotByData(m_pNmGuiPlot, pWellData);
removeWell(pWellData);
}
}
void nmDataAnalyzeManager::clearAllWellData()
{
// 遍历并删除所有井对象
foreach(nmDataWellBase* pWell, m_vWellData) {
if(pWell != nullptr) {
delete pWell;
pWell = nullptr;
}
}
// 清空数组
m_vWellData.clear();
}
QVector<nmDataWellBase*> nmDataAnalyzeManager::getWellDataList() const
{
return m_vWellData;
}
//QVector<nmDataWellBase> nmDataAnalyzeManager::getWellDataListCopy() const
//{
// QVector<nmDataWellBase> result;
// result.reserve(m_vWellData.size());
//
// foreach(const nmDataWellBase* well, m_vWellData) {
// if(well) {
// result.append(*well); // 调用拷贝构造函数
// }
// }
//
// return result;
//}
//void nmDataAnalyzeManager::updateWellData(const QVector<nmDataWellBase>& newData)
//{
//
// // 确保数量一致
// if (newData.size() != m_vWellData.size()) {
// return;
// }
//
// for (int i = 0; i < newData.size(); ++i) {
// nmDataWellBase* existingWell = m_vWellData[i];
// const nmDataWellBase& newWell = newData[i];
//
// if (existingWell && existingWell->getWellName() == newWell.getWellName()) {
// // 根据类型更新数据
// if (auto existingVFractured = dynamic_cast<nmDataVerticalFracturedWell*>(existingWell)) {
// if (auto newVFractured = dynamic_cast<const nmDataVerticalFracturedWell*>(&newWell)) {
// *existingVFractured = *newVFractured;
// }
// }
// else if (auto existingHFractured = dynamic_cast<nmDataHorizontalFracturedWell*>(existingWell)) {
// if (auto newHFractured = dynamic_cast<const nmDataHorizontalFracturedWell*>(&newWell)) {
// *existingHFractured = *newHFractured;
// }
// } else if (auto existingVertical = dynamic_cast<nmDataVerticalWell*>(existingWell)) {
// if (auto newVertical = dynamic_cast<const nmDataVerticalWell*>(&newWell)) {
// *existingVertical = *newVertical; // 调用赋值运算符
// }
// }
// }
// }
//
//}
void nmDataAnalyzeManager::updateVerticalWells(const QVector<nmDataVerticalWell>& wells)
{
foreach(const auto& newWell, wells) {
foreach(auto* existingWell, m_vWellData) {
if(auto * vWell = dynamic_cast<nmDataVerticalWell * >(existingWell)) {
if(vWell->getWellName() == newWell.getWellName()) {
*vWell = newWell; // 调用赋值运算符
break;
}
}
}
}
}
void nmDataAnalyzeManager::updateVerticalFracturedWells(const QVector<nmDataVerticalFracturedWell>& wells)
{
foreach(const auto& newWell, wells) {
foreach(auto* existingWell, m_vWellData) {
if(auto * vWell = dynamic_cast<nmDataVerticalFracturedWell * >(existingWell)) {
if(vWell->getWellName() == newWell.getWellName()) {
*vWell = newWell; // 调用赋值运算符
break;
}
}
}
}
}
void nmDataAnalyzeManager::updateHorizontalFracturedWells(const QVector<nmDataHorizontalFracturedWell>& wells)
{
foreach(const auto& newWell, wells) {
foreach(auto* existingWell, m_vWellData) {
if(auto * vWell = dynamic_cast<nmDataHorizontalFracturedWell * >(existingWell)) {
if(vWell->getWellName() == newWell.getWellName()) {
*vWell = newWell; // 调用赋值运算符
break;
}
}
}
}
}
// 获取所有直井数据
QVector<nmDataVerticalWell*> nmDataAnalyzeManager::getVerticalWellData() const
{
QVector<nmDataVerticalWell*> verticalWells;
foreach(nmDataWellBase* well, m_vWellData) {
nmDataVerticalWell* vWell = dynamic_cast<nmDataVerticalWell*>(well);
if(vWell && !dynamic_cast<nmDataVerticalFracturedWell * >(well)) {
// 确保不是垂直裂缝井
verticalWells.append(vWell);
}
}
return verticalWells;
}
// 获取所有垂直裂缝井数据
QVector<nmDataVerticalFracturedWell*> nmDataAnalyzeManager::getVerticalFracturedWellData() const
{
QVector<nmDataVerticalFracturedWell*> vFracturedWells;
foreach(nmDataWellBase* well, m_vWellData) {
nmDataVerticalFracturedWell* vFracturedWell = dynamic_cast<nmDataVerticalFracturedWell*>(well);
if(vFracturedWell) {
vFracturedWells.append(vFracturedWell);
}
}
return vFracturedWells;
}
// 获取所有多段压裂水平井数据
QVector<nmDataHorizontalFracturedWell*> nmDataAnalyzeManager::getHorizontalFracturedWellData() const
{
QVector<nmDataHorizontalFracturedWell*> hFracturedWells;
foreach(nmDataWellBase* well, m_vWellData) {
nmDataHorizontalFracturedWell* hFracturedWell = dynamic_cast<nmDataHorizontalFracturedWell*>(well);
if(hFracturedWell) {
hFracturedWells.append(hFracturedWell);
}
}
return hFracturedWells;
}
nmDataWellBase* nmDataAnalyzeManager::findWellByName(QString wellName) const
{
foreach(nmDataWellBase* pWell, m_vWellData) {
if(pWell && pWell->getWellName() == wellName) {
return pWell; // 找到匹配的井,返回指针
}
}
return nullptr; // 未找到匹配的井,返回 nullptr
}
void nmDataAnalyzeManager::initCurWellData()
{
// 获取当前默认井数据
ZxDataWell* pWellData = zxCurWell;
if(pWellData == nullptr) {
return;
}
// 判断是哪一种井类型,初始化对应的参数
QString wellClass = pWellData->getWellClassEn();
// 获取当前井的压力、流量数据
ZxDataObjectList m_listGaugeP = pWellData->getChildren(iDataModelType::sTypeDataGaugeP);
ZxDataObjectList m_listGaugeF = pWellData->getChildren(iDataModelType::sTypeDataGaugeF);
ZxDataGaugeP* pGaugeP = nullptr;
ZxDataGaugeF* pGaugeF = nullptr;
// 遍历压力数据列表
for(int i = 0; i < m_listGaugeP.size(); ++i) {
if(pGaugeP = dynamic_cast<ZxDataGaugeP * >(m_listGaugeP[i])) { // 拿到第一条压力数据
break;
}
}
// 遍历流量数据列表
for(int i = 0; i < m_listGaugeF.size(); ++i) {
if(pGaugeF = dynamic_cast<ZxDataGaugeF * >(m_listGaugeF[i])) { // 拿到第一条流量数据
break;
}
}
// 获取的压力、流量数据
QVector<QPointF> vecPtsP, vecPtsF;
// 临时存储xy坐标
VecDouble vecX, vecY;
if(pGaugeP != nullptr) {
// 获取压力数据
if(pGaugeP->getDataVecXY(vecX, vecY)) {
int pointCount = vecX.size();
if(pointCount > vecY.size()) {
pointCount = vecY.size();
}
for(int i = 0; i < pointCount; ++i) {
QPointF pt(vecX[i], vecY[i]);
vecPtsP.append(pt);
}
}
}
if(pGaugeF != nullptr) {
vecX.clear();
vecY.clear();
// 获取流量数据
if(pGaugeF->getDataVecXY(vecX, vecY)) {
int pointCount = vecX.size();
if(pointCount > vecY.size()) {
pointCount = vecY.size();
}
for(int i = 0; i < pointCount; ++i) {
QPointF pt(vecX[i], vecY[i]);
vecPtsF.append(pt);
}
}
}
if(ZxBaseUtil::isSameStr(wellClass, "VerticalWell")) {
// 初始化直井默认参数
nmDataWellBase* pWell = this->createWell(NM_WELL_MODEL::Vertical_Well);
nmDataVerticalWell* pVerticalWell = dynamic_cast<nmDataVerticalWell*>(pWell);
if(pVerticalWell == nullptr) {
return;
}
pVerticalWell->setWellName(pWellData->getName());
nmDataAttribute tempAttr = pVerticalWell->getX();
tempAttr.setValue(pWellData->getLocationX());
pVerticalWell->setX(tempAttr);
tempAttr = pVerticalWell->getY();
tempAttr.setValue(pWellData->getLocationY());
pVerticalWell->setY(tempAttr);
tempAttr = pVerticalWell->getRadius();
tempAttr.setValue(pWellData->getWellRadius());
pVerticalWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pVerticalWell->setPressurePoints(vecPtsP);
pVerticalWell->setFlowPoints(vecPtsF);
QVector<QVector<double>> vvecHistoryPressureData; //压力历史数据
QVector<QVector<double>> vvecHistoryLogData; // 历史双对数曲线数据
QVector<QVector<double>> vvecHistorySemiLogData; // 历史半对数曲线数据
this->calculationLogData(pVerticalWell, vvecHistoryPressureData, vvecHistoryLogData, vvecHistorySemiLogData);
// 使用setter方法存储历史数据到井对象中
pVerticalWell->setHistoryPressure(vvecHistoryPressureData);
pVerticalWell->setHistoryLogLog(vvecHistoryLogData);
pVerticalWell->setHistorySemiLog(vvecHistorySemiLogData);
// 设置为当前查看的井
this->setCurWellData(pVerticalWell);
} else if(ZxBaseUtil::isSameStr(wellClass, "VerticalFracturedWell")) {
// 初始化垂直裂缝井默认参数
nmDataWellBase* pWell = this->createWell(NM_WELL_MODEL::Vertical_Fractured_Well);
nmDataVerticalFracturedWell* pVFracturedWell = dynamic_cast<nmDataVerticalFracturedWell*>(pWell);
if(pVFracturedWell == nullptr) {
return;
}
pVFracturedWell->setWellName(pWellData->getName());
nmDataAttribute tempAttr = pVFracturedWell->getX();
tempAttr.setValue(pWellData->getLocationX());
pVFracturedWell->setX(tempAttr);
tempAttr = pVFracturedWell->getY();
tempAttr.setValue(pWellData->getLocationY());
pVFracturedWell->setY(tempAttr);
tempAttr = pVFracturedWell->getRadius();
tempAttr.setValue(pWellData->getWellRadius());
pVFracturedWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pVFracturedWell->setPressurePoints(vecPtsP);
pVFracturedWell->setFlowPoints(vecPtsF);
QVector<QVector<double>> vvecHistoryPressureData; //压力历史数据
QVector<QVector<double>> vvecHistoryLogData; // 历史双对数曲线数据
QVector<QVector<double>> vvecHistorySemiLogData; // 历史半对数曲线数据
this->calculationLogData(pVFracturedWell, vvecHistoryPressureData, vvecHistoryLogData, vvecHistorySemiLogData);
// 使用setter方法存储历史数据到井对象中
pVFracturedWell->setHistoryPressure(vvecHistoryPressureData);
pVFracturedWell->setHistoryLogLog(vvecHistoryLogData);
pVFracturedWell->setHistorySemiLog(vvecHistorySemiLogData);
// 更新裂缝位置信息
pVFracturedWell->setFracs();
// 设置为当前查看的井
this->setCurWellData(pVFracturedWell);
} else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalFracturedWell")) {
// 初始化多段压裂水平井默认参数
nmDataWellBase* pWell = this->createWell(NM_WELL_MODEL::Horizontal_Fractured_Well);
nmDataHorizontalFracturedWell* pHFracturedWell = dynamic_cast<nmDataHorizontalFracturedWell*>(pWell);
if(pHFracturedWell == nullptr) {
return;
}
pHFracturedWell->setWellName(pWellData->getName());
nmDataAttribute tempAttr = pHFracturedWell->getX();
tempAttr.setValue(pWellData->getLocationX());
pHFracturedWell->setX(tempAttr);
tempAttr = pHFracturedWell->getY();
tempAttr.setValue(pWellData->getLocationY());
pHFracturedWell->setY(tempAttr);
tempAttr = pHFracturedWell->getRadius();
tempAttr.setValue(pWellData->getWellRadius());
pHFracturedWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pHFracturedWell->setPressurePoints(vecPtsP);
pHFracturedWell->setFlowPoints(vecPtsF);
QVector<QVector<double>> vvecHistoryPressureData; //压力历史数据
QVector<QVector<double>> vvecHistoryLogData; // 历史双对数曲线数据
QVector<QVector<double>> vvecHistorySemiLogData; // 历史半对数曲线数据
this->calculationLogData(pHFracturedWell, vvecHistoryPressureData, vvecHistoryLogData, vvecHistorySemiLogData);
//使用setter方法存储历史数据到井对象中
pHFracturedWell->setHistoryPressure(vvecHistoryPressureData);
pHFracturedWell->setHistoryLogLog(vvecHistoryLogData);
pHFracturedWell->setHistorySemiLog(vvecHistorySemiLogData);
// 计算裂缝数据
pHFracturedWell->setFracs();
// 设置为当前查看的井
this->setCurWellData(pHFracturedWell);
}
}
void nmDataAnalyzeManager::calculationLogData(
nmDataWellBase* pWellData,
QVector<QVector<double>>& vvecHistoryData,
QVector<QVector<double>>& vvecLogPreData,
QVector<QVector<double>>& vvecSemiLogPreData)
{
// 清空输出参数
vvecHistoryData.clear();
vvecLogPreData.clear();
vvecSemiLogPreData.clear();
if(pWellData == nullptr) {
return;
}
// 初始化二维数组结构
vvecHistoryData.resize(2); // [0]=x, [1]=y
vvecLogPreData.resize(3); // [0]=x, [1]=y, [2]=z
vvecSemiLogPreData.resize(2); // [0]=x, [1]=pointData[0]
// 准备压力数据
QVector<QPointF> vecPressure = pWellData->getPressurePoints();
std::vector<Point> wellPressureData;
// 填充 wellPressureData 和 vvecHistoryData
foreach(const QPointF& qpoint, vecPressure) {
// wellPressureData
Point pt;
pt.x = qpoint.x();
pt.y = qpoint.y();
pt.z = 0.0;
wellPressureData.push_back(pt);
// vvecHistoryData
vvecHistoryData[0].append(qpoint.x()); // x
vvecHistoryData[1].append(qpoint.y()); // y
}
// 准备流量段数据
QVector<QPointF> vecTimeQ = pWellData->getFlowPoints();
int nTimeNumQ = vecTimeQ.size() - 1;
std::vector<double> timeQ(nTimeNumQ);
std::vector<double> q(nTimeNumQ);
for(int i = 0; i < nTimeNumQ; ++i) {
timeQ[i] = vecTimeQ[i + 1].x();
q[i] = vecTimeQ[i + 1].y();
}
// 调用 DLL 计算双对数曲线
std::vector<Point> logPre;
int iSectionFlowIndex = pWellData->getIndexF();
HMODULE hMod_solver = LoadLibrary(L"singlePhaseSolverDll.dll");
if(hMod_solver) {
typedef bool (*PreLog)(const std::vector<Point>&, const int&, double*, double*, int, std::vector<Point>&);
PreLog preLogFun = (PreLog)GetProcAddress(hMod_solver, "logLogPre");
if(nullptr == preLogFun) {
FreeLibrary(hMod_solver);
std::cout << "preLogFun failed!\n";
return;
}
preLogFun(wellPressureData, iSectionFlowIndex, timeQ.data(), q.data(), nTimeNumQ, logPre);
// 不添加最后一个元素
for(uint i = 0; i < logPre.size() - 1; i++) {
//logFile << logPre[i].x << "\t" << logPre[i].y << "\t" << logPre[i].z << "\t" << std::endl;
vvecLogPreData[0].append(logPre[i].x); // x
vvecLogPreData[1].append(logPre[i].y); // y
vvecLogPreData[2].append(logPre[i].z); // z
}
// 填充半对数曲线数据 (x, pointData[0])
foreach(const auto& point, logPre) {
vvecSemiLogPreData[0].append(point.x); // x
double y_value = point.pointData.empty() ? 0.0 : point.pointData[0];
vvecSemiLogPreData[1].append(y_value); // pointData[0] 或默认值
}
FreeLibrary(hMod_solver);
}
}
void nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
{
if(pWellData == nullptr) {
return;
}
// 判断是哪一种井类型,初始化对应的参数
QString sWellClass = pWellData->getWellClassEn();
// 获取当前井的压力、流量数据
ZxDataObjectList m_listGaugeP = pWellData->getChildren(iDataModelType::sTypeDataGaugeP);
ZxDataObjectList m_listGaugeF = pWellData->getChildren(iDataModelType::sTypeDataGaugeF);
ZxDataGaugeP* pGaugeP = nullptr;
ZxDataGaugeF* pGaugeF = nullptr;
// 遍历压力数据列表
for(int i = 0; i < m_listGaugeP.size(); ++i) {
if(pGaugeP = dynamic_cast<ZxDataGaugeP * >(m_listGaugeP[i])) { // 拿到第一条压力数据
break;
}
}
// 遍历流量数据列表
for(int i = 0; i < m_listGaugeF.size(); ++i) {
if(pGaugeF = dynamic_cast<ZxDataGaugeF * >(m_listGaugeF[i])) { // 拿到第一条流量数据
break;
}
}
// 获取的压力、流量数据
QVector<QPointF> vecPtsP, vecPtsF;
// 临时存储xy坐标
VecDouble vecX, vecY;
if(pGaugeP != nullptr) {
// 获取压力数据
if(pGaugeP->getDataVecXY(vecX, vecY)) {
int pointCount = vecX.size();
if(pointCount > vecY.size()) {
pointCount = vecY.size();
}
for(int i = 0; i < pointCount; ++i) {
QPointF pt(vecX[i], vecY[i]);
vecPtsP.append(pt);
}
}
}
if(pGaugeF != nullptr) {
vecX.clear();
vecY.clear();
// 获取流量数据
if(pGaugeF->getDataVecXY(vecX, vecY)) {
int pointCount = vecX.size();
if(pointCount > vecY.size()) {
pointCount = vecY.size();
}
for(int i = 0; i < pointCount; ++i) {
QPointF pt(vecX[i], vecY[i]);
vecPtsF.append(pt);
}
}
}
int nIndexF; //当前井的流动段索引
// 更新当前井的流动段的索引,默认为最后一段
nIndexF = vecPtsF.count() - 1;
if(ZxBaseUtil::isSameStr(sWellClass, "VerticalWell")) {
// 初始化直井默认参数
nmDataWellBase* pWell = this->createWell(NM_WELL_MODEL::Vertical_Well);
nmDataVerticalWell* pVerticalWell = dynamic_cast<nmDataVerticalWell*>(pWell);
if(pVerticalWell == nullptr) {
return;
}
pVerticalWell->setWellName(pWellData->getName());
nmDataAttribute tempAttr = pVerticalWell->getX();
tempAttr.setValue(pWellData->getLocationX());
pVerticalWell->setX(tempAttr);
tempAttr = pVerticalWell->getY();
tempAttr.setValue(pWellData->getLocationY());
pVerticalWell->setY(tempAttr);
tempAttr = pVerticalWell->getRadius();
tempAttr.setValue(pWellData->getWellRadius());
pVerticalWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pVerticalWell->setPressurePoints(vecPtsP);
pVerticalWell->setFlowPoints(vecPtsF);
// 设置流量段索引
pVerticalWell->setIndexF(nIndexF);
} else if(ZxBaseUtil::isSameStr(sWellClass, "VerticalFracturedWell")) {
// 初始化垂直裂缝井默认参数
nmDataWellBase* pWell = this->createWell(NM_WELL_MODEL::Vertical_Fractured_Well);
nmDataVerticalFracturedWell* pVFracturedWell = dynamic_cast<nmDataVerticalFracturedWell*>(pWell);
if(pVFracturedWell == nullptr) {
return;
}
pVFracturedWell->setWellName(pWellData->getName());
nmDataAttribute tempAttr = pVFracturedWell->getX();
tempAttr.setValue(pWellData->getLocationX());
pVFracturedWell->setX(tempAttr);
tempAttr = pVFracturedWell->getY();
tempAttr.setValue(pWellData->getLocationY());
pVFracturedWell->setY(tempAttr);
tempAttr = pVFracturedWell->getRadius();
tempAttr.setValue(pWellData->getWellRadius());
pVFracturedWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pVFracturedWell->setPressurePoints(vecPtsP);
pVFracturedWell->setFlowPoints(vecPtsF);
// 更新裂缝位置信息
pVFracturedWell->setFracs();
// 设置流量段索引
pVFracturedWell->setIndexF(nIndexF);
} else if(ZxBaseUtil::isSameStr(sWellClass, "HorizontalFracturedWell")) {
// 初始化多段压裂水平井默认参数
nmDataWellBase* pWell = this->createWell(NM_WELL_MODEL::Horizontal_Fractured_Well);
nmDataHorizontalFracturedWell* pHFracturedWell = dynamic_cast<nmDataHorizontalFracturedWell*>(pWell);
if(pHFracturedWell == nullptr) {
return;
}
pHFracturedWell->setWellName(pWellData->getName());
nmDataAttribute tempAttr = pHFracturedWell->getX();
tempAttr.setValue(pWellData->getLocationX());
pHFracturedWell->setX(tempAttr);
tempAttr = pHFracturedWell->getY();
tempAttr.setValue(pWellData->getLocationY());
pHFracturedWell->setY(tempAttr);
tempAttr = pHFracturedWell->getRadius();
tempAttr.setValue(pWellData->getWellRadius());
pHFracturedWell->setRadius(tempAttr);
// 设置井的压力数据、流量数据
pHFracturedWell->setPressurePoints(vecPtsP);
pHFracturedWell->setFlowPoints(vecPtsF);
// 计算裂缝数据
pHFracturedWell->setFracs();
// 设置流量段索引
pHFracturedWell->setIndexF(nIndexF);
}
}
void nmDataAnalyzeManager::appendNmWellData(nmDataWellBase* pWellData)
{
if (pWellData == nullptr)
return;
m_vWellData.append(pWellData);
}
/// @brief 创建油藏数据对象从界面读取PVT单值和分层数据构建reservoir对象
void nmDataAnalyzeManager::createReservoir()
{
// 1. 获取上下文
iSubWndFitting* pSubWndFitting = nmDataAnalyzeManager::getCurrentFitting();
nmDataAnalyzeContextProvider* pCtx = nmDataAnalyzeContext::provider();
Q_ASSERT(nullptr != pSubWndFitting);
Q_ASSERT(nullptr != pCtx);
PvtFluidType eType = WFT_Null;
pCtx->getBasicPft(pSubWndFitting, eType);
// 2. 读取PVT单值参数
QMap<QString, double> mapPvtValues = readPvtSingleValues(pCtx, pSubWndFitting, eType);
// 3. 读取分层数据,提取储层基础参数
VVecVariant vvecLayerData;
pCtx->getBasicDataLayers(pSubWndFitting, vvecLayerData);
double dThickness = 10;
double dPorosity = 0.5;
double dCf = 1.0;
double dInitialPre = 30.0;
if(!vvecLayerData.isEmpty() && vvecLayerData[0].size() >= 5) {
dThickness = vvecLayerData[0][1].toDouble();
dPorosity = vvecLayerData[0][2].toDouble();
dCf = vvecLayerData[0][3].toDouble();
dInitialPre = vvecLayerData[0][4].toDouble();
}
// 4. 构建油藏对象
if(m_reservoirData != nullptr) {
delete m_reservoirData;
m_reservoirData = nullptr;
}
m_reservoirData = new nmDataReservoir;
// 按相态填充PVT字段和压缩系数
populateReservoirByPhase(m_reservoirData, eType, mapPvtValues, dCf);
// 设置基础属性
setReservoirAttr(m_reservoirData->getInitialPressure(), dInitialPre);
setReservoirAttr(m_reservoirData->getReservoirType(), QString("Homogeneous"));
setReservoirAttr(m_reservoirData->getThickness(), dThickness);
setReservoirAttr(m_reservoirData->getPorosity(), dPorosity);
// 5. 创建默认分层
createDefaultLayer(dThickness, m_vecLayers);
}
nmDataAxis* nmDataAnalyzeManager::getAxisData() const
{
return m_axisData;
}
void nmDataAnalyzeManager::setAxisData(nmDataAxis* pAxisData)
{
if(pAxisData != nullptr) {
m_axisData = pAxisData;
}
}
nmDataReservoir* nmDataAnalyzeManager::getReservoirData() const
{
return m_reservoirData;
}
nmDataReservoir nmDataAnalyzeManager::getReservoirDataCopy() const
{
if(m_reservoirData) {
return *m_reservoirData; // 调用拷贝构造函数
}
return nmDataReservoir(); // 返回默认构造对象
}
void nmDataAnalyzeManager::updateReservoirData(const nmDataReservoir& newData)
{
if(m_reservoirData) {
*m_reservoirData = newData; // 调用赋值运算符
}
}
nmDataGeoRef* nmDataAnalyzeManager::createGeoRefData()
{
if(m_pGeoRefData != nullptr) {
delete m_pGeoRefData;
m_pGeoRefData = nullptr;
}
m_pGeoRefData = new nmDataGeoRef;
return m_pGeoRefData;
}
nmDataGeoRef* nmDataAnalyzeManager::getGeoRefData() const
{
return m_pGeoRefData;
}
nmDataGeoRef nmDataAnalyzeManager::getGeoRefDataCopy() const
{
if(m_pGeoRefData) {
return *m_pGeoRefData; // 调用拷贝构造函数
}
return nmDataGeoRef(); // 返回默认构造对象
}
void nmDataAnalyzeManager::updateGeoRefData(const nmDataGeoRef& newData)
{
if(m_pGeoRefData == nullptr) {
m_pGeoRefData = new nmDataGeoRef;
}
*m_pGeoRefData = newData; // 调用赋值运算符
}
nmDataForecast* nmDataAnalyzeManager::createForecastData()
{
if(m_pForecastData != nullptr) {
delete m_pForecastData;
m_pForecastData = nullptr;
}
m_pForecastData = new nmDataForecast;
return m_pForecastData;
}
nmDataForecast* nmDataAnalyzeManager::getForecastData() const
{
return m_pForecastData;
}
nmDataForecast nmDataAnalyzeManager::getForecastDataCopy() const
{
if(m_pForecastData) {
return *m_pForecastData; // 调用拷贝构造函数
}
return nmDataForecast(); // 返回默认构造对象
}
void nmDataAnalyzeManager::updateForecastData(const nmDataForecast& newData)
{
if(m_pForecastData == nullptr) {
m_pForecastData = new nmDataForecast;
}
*m_pForecastData = newData; // 调用赋值运算符
}
nmDataSensitive* nmDataAnalyzeManager::createSensitiveData()
{
// 如果已有数据,先删除再创建
if (m_pSensitiveData != nullptr) {
delete m_pSensitiveData;
m_pSensitiveData = nullptr;
}
// 创建一个新的 nmDataSensitive 对象
m_pSensitiveData = new nmDataSensitive();
// 初始化 Calculation Type
m_pSensitiveData->setCalculationType(nmDataSensitive::CALC_DETERMINISTIC);
// 设置总模型数为 0后面可以通过 setTotalModelCount 修改
m_pSensitiveData->setTotalModelCount(0);
// 创建变量列表
QList<nmDataSensitive::VariableSampling> vars;
// 定义一个通用的添加变量的辅助函数
auto addVar = [&](const QString& group,
const QString& name,
double model, double min, double max,
const QString& unit)
{
nmDataSensitive::VariableSampling vs;
vs.setVarGroup(group); // 设置变量组
vs.setVarName(name); // 设置变量名
vs.setEnabled(false); // 默认不勾选
vs.setMode(nmDataSensitive::VariableSampling::MODE_AUTOMATIC); // 自动模式
vs.setLog(false); // 默认不选 Log
vs.setNumber(5); // 默认 Number 为 5
// 设置 modelValue、minValue、maxValue 和单位
nmDataAttribute& modelValue = vs.getModelValue();
modelValue.setName(name + " Model");
modelValue.setUnit(unit);
modelValue.setValue(model);
nmDataAttribute& minValue = vs.getMinValue();
minValue.setName(name + " Min");
minValue.setUnit(unit);
minValue.setValue(min);
nmDataAttribute& maxValue = vs.getMaxValue();
maxValue.setName(name + " Max");
maxValue.setUnit(unit);
maxValue.setValue(max);
vars.append(vs); // 将变量添加到变量列表中
};
// 初始化变量组和每个变量
// === Tested Well ===
addVar("Tested Well", "Zw", 15.0, 7.5, 30.0, "ft");
addVar("Tested Well", "Hw", 10.0, 5.0, 20.0, "ft");
addVar("Tested Well", "Lw", 12.0, 6.0, 18.0, "ft");
addVar("Tested Well", "Skin", 1.0, 0.5, 1.5, "dimensionless");
addVar("Tested Well", "C", 0.3, 0.1, 1.0, "dimensionless");
// === Reservoir ===
addVar("Reservoir", "Pi", 1000.0, 800.0, 1200.0, "psi");
addVar("Reservoir", "k", 150.0, 100.0, 200.0, "mD");
addVar("Reservoir", "h", 50.0, 30.0, 70.0, "ft");
addVar("Reservoir", "φ", 0.2, 0.1, 0.4, "dimensionless");
addVar("Reservoir", "ntg", 0.9, 0.7, 1.0, "dimensionless");
addVar("Reservoir", "kz/kr", 1.0, 0.5, 1.5, "dimensionless");
// === Pvt ===
addVar("Pvt", "Total compressibility", 5e-6, 2e-6, 8e-6, "1/psi");
// 将变量列表设置到敏感性数据对象中
m_pSensitiveData->setVariables(vars);
// 返回已初始化的敏感性数据对象
return m_pSensitiveData;
}
nmDataSensitive* nmDataAnalyzeManager::getSensitiveData() const
{
return m_pSensitiveData;
}
nmDataSensitive nmDataAnalyzeManager::getSensitiveDataCopy() const
{
if(m_pSensitiveData) {
return *m_pSensitiveData; // 调用拷贝构造函数
}
return nmDataSensitive(); // 返回默认构造对象
}
void nmDataAnalyzeManager::updateSensitiveData(const nmDataSensitive& newData)
{
if(m_pSensitiveData == nullptr) {
m_pSensitiveData = new nmDataSensitive();
}
*m_pSensitiveData = newData; // 调用赋值运算符
}
nmDataDiagnostic* nmDataAnalyzeManager::getDiagnosticData() const {
return m_pDiagnosticData;
}
bool nmDataAnalyzeManager::resetFromDiagnostic()
{
// 获取当前井和储层数据
nmDataWellBase* pCurrentWell = getCurWellData();
nmDataReservoir* pReservoirData = getReservoirData();
if(!pCurrentWell || !pReservoirData) {
return false;
}
// 获取"双对数"线性数据
QVector<QVector<double>> rawData = pCurrentWell->getHistoryLogLog();
if(rawData.isEmpty() || rawData.size() != 3) {
return false;
}
try {
// 创建诊断对象并使用修正后的数据
if(!m_pDiagnosticData) {
m_pDiagnosticData = new nmDataDiagnostic();
}
m_pDiagnosticData->resetFromDiagnostic(rawData, pCurrentWell, pReservoirData);
// 应用诊断结果到相应参数
applyDiagnosticResults(m_pDiagnosticData, pCurrentWell, pReservoirData);
return true;
}
catch(...) {
return false;
}
}
bool nmDataAnalyzeManager::resetFromAnalytical()
{
// 获取当前井和储层数据
nmDataWellBase* pCurrentWell = getCurWellData();
nmDataReservoir* pReservoirData = getReservoirData();
if(!pCurrentWell || !pReservoirData) {
return false;
}
try {
// 重置储层参数为默认值
pReservoirData->resetToDefaults();
// 重置井参数为默认值
pCurrentWell->resetToDefaults();
return true;
}
catch(...) {
return false;
}
}
// 应用诊断结果
void nmDataAnalyzeManager::applyDiagnosticResults(nmDataDiagnostic* diagnostic, nmDataWellBase* wellData, nmDataReservoir* reservoirData)
{
if(!diagnostic || !wellData || !reservoirData) return;
// 获取诊断结果
double diagnosticPerm = diagnostic->getDiagnosticPermeability().getValue().toDouble();
double diagnosticStorage = diagnostic->getDiagnosticWellboreStorage().getValue().toDouble();
double diagnosticTrans = diagnostic->getDiagnosticTransmissibility().getValue().toDouble();
double diagnosticSkin = diagnostic->getDiagnosticSkin().getValue().toDouble();
// 应用渗透率到储层数据
nmDataAttribute& reservoirPerm = reservoirData->getPermeability();
reservoirPerm.setValue(diagnosticPerm);
// 应用井筒储存到井数据
nmDataAttribute& wellStorage = wellData->getWellboreStorage();
wellStorage.setValue(diagnosticStorage);
// 应用导流能力到储层数据
nmDataAttribute& reservoirTrans = reservoirData->getTransmissibility();
reservoirTrans.setValue(diagnosticTrans);
// 应用皮损系数到井的第一段射孔
if(wellData->getPerforationCount() > 0) {
nmDataPerforation* firstPerforation = wellData->getPerforation(0);
if(firstPerforation) {
firstPerforation->getSkin().setValue(diagnosticSkin);
}
}
}
nmDataAutomaticFitting* nmDataAnalyzeManager::createAutomaticFittingData()
{
if(m_pAutomaticFittingData != nullptr) {
delete m_pAutomaticFittingData;
m_pAutomaticFittingData = nullptr;
}
m_pAutomaticFittingData = new nmDataAutomaticFitting;
return m_pAutomaticFittingData;
}
nmDataAutomaticFitting* nmDataAnalyzeManager::getAutomaticFittingData() const
{
return m_pAutomaticFittingData;
}
nmDataAutomaticFitting nmDataAnalyzeManager::getAutomaticFittingDataCopy() const
{
if(m_pAutomaticFittingData) {
return *m_pAutomaticFittingData; // 调用拷贝构造函数
}
return nmDataAutomaticFitting(); // 返回默认构造对象
}
void nmDataAnalyzeManager::updateAutomaticFittingData(const nmDataAutomaticFitting& newData)
{
if(m_pAutomaticFittingData == nullptr) {
m_pAutomaticFittingData = new nmDataAutomaticFitting;
}
*m_pAutomaticFittingData = newData; // 调用赋值运算符
}
/// @brief 从PVT结果页读取曲线数组确定求解器模型类型
/// 按相态获取PVT数组参数获取不到则回退到常数PVT模型Gas除外弹警告
void nmDataAnalyzeManager::initPvtParaFromSubFit()
{
// 1. 获取上下文
iSubWndFitting* pSubWndFitting = nmDataAnalyzeManager::getCurrentFitting();
nmDataAnalyzeContextProvider* pCtx = nmDataAnalyzeContext::provider();
Q_ASSERT(nullptr != pSubWndFitting);
Q_ASSERT(nullptr != pCtx);
if(nullptr == pSubWndFitting || nullptr == pCtx) {
return;
}
PvtFluidType eType = WFT_Null;
pCtx->getBasicPft(pSubWndFitting, eType);
// 2. 清理旧的PVT参数对象新建空对象
if(m_pebiPvtPara != nullptr) {
delete m_pebiPvtPara;
m_pebiPvtPara = nullptr;
}
m_pebiPvtPara = new nmDataPvtParaForPebi;
// 压力横坐标,首次成功读取时赋值
QVector<double> vecPressure;
// 3. 按相态分支获取PVT曲线并确定求解器类型
switch(eType) {
case WFT_Oil:
// 油相获取到变量PVT曲线则升级模型否则保持常数PVT
if(tryFetchPhasePvtCurves(pCtx, pSubWndFitting, WFT_Oil,
"Bo", "Co", "Miuo", m_pebiPvtPara, vecPressure)) {
setSolverModelType(SMT_Oil_VariablePvt);
} else {
setSolverModelType(SMT_Oil_ConstPvt);
}
break;
case WFT_Water:
// 水相获取到变量PVT曲线则升级模型否则保持常数PVT
if(tryFetchPhasePvtCurves(pCtx, pSubWndFitting, WFT_Water,
"Bw", "Cw", "Miuw", m_pebiPvtPara, vecPressure)) {
setSolverModelType(SMT_Water_VariablePvt);
} else {
setSolverModelType(SMT_Water_ConstPvt);
}
break;
case WFT_Gas:
// 气相必须获取到全部PVT曲线否则弹警告并返回
setSolverModelType(SMT_Gas_VariablePvt);
if(!tryFetchPhasePvtCurves(pCtx, pSubWndFitting, WFT_Gas,
"Bg", "Cg", "Miug", m_pebiPvtPara, vecPressure)) {
QMessageBox::warning(nullptr, tr("Warning"), tr("Please select all gas PVT parameters."));
return;
}
break;
case WFT_Oil_Water: {
// 油水两相油、水PVT曲线必须全部获取否则返回
setSolverModelType(SMT_Oil_Water_TwoPhase);
bool bOilOk = tryFetchPhasePvtCurves(pCtx, pSubWndFitting, WFT_Oil_Water,
"Bo", "Co", "Miuo", m_pebiPvtPara, vecPressure);
bool bWaterOk = tryFetchPhasePvtCurves(pCtx, pSubWndFitting, WFT_Oil_Water,
"Bw", "Cw", "Miuw", m_pebiPvtPara, vecPressure);
if(!(bOilOk && bWaterOk)) {
return;
}
// Diffusion相渗数据来自Diffusion页面
VVecDouble vvecDiffusionKK;
if(pCtx->getDiffusionRstOf(pSubWndFitting, DSO_KK, vvecDiffusionKK)) {
applyDiffusionKkToPebiPvt(m_pebiPvtPara, vvecDiffusionKK);
}
break;
}
default:
break;
}
// 4. 统一设置压力横坐标
setPebiPressureIfEmpty(m_pebiPvtPara, vecPressure);
}
nmDataRegionMark *nmDataAnalyzeManager::createRegionMark()
{
nmDataRegionMark* regionMarkData = new nmDataRegionMark;
m_vRegionMarkData.append(regionMarkData);
return regionMarkData;
}
QVector<nmDataRegionMark*> nmDataAnalyzeManager::getRegionMarkDataList() const
{
return m_vRegionMarkData;
}
bool nmDataAnalyzeManager::removeRegionMarkData(nmDataRegionMark * pData)
{
if(pData) {
// 遍历 m_vRegionMarkData 数组,找到并移除对应的对象
for(int i = 0; i < m_vRegionMarkData.size(); ++i) {
if(m_vRegionMarkData[i] == pData) {
delete m_vRegionMarkData[i]; // 释放内存
m_vRegionMarkData.remove(i);
return true; // 移除成功,返回 true
}
}
}
return false; // 未找到或移除失败,返回 false
}
QVector<nmDataRegionMark> nmDataAnalyzeManager::getRegionMarkDataListCopy() const
{
QVector<nmDataRegionMark> result;
result.reserve(m_vRegionMarkData.size());
foreach(const nmDataRegionMark* regionMark, m_vRegionMarkData) {
if(regionMark) {
result.append(*regionMark); // 调用拷贝构造函数
}
}
return result;
}
void nmDataAnalyzeManager::updateRegionMarkData(const QVector<nmDataRegionMark>& newData)
{
// 确保数量一致
if(newData.size() != m_vRegionMarkData.size()) {
return;
}
for(int i = 0; i < newData.size(); ++i) {
if(m_vRegionMarkData[i]) {
// 只更新内容,不改变指针
*m_vRegionMarkData[i] = newData[i]; // 调用赋值运算符
}
}
}
nmDataOutline *nmDataAnalyzeManager::createOutline()
{
if(m_outlineData != nullptr) {
delete m_outlineData;
m_outlineData = nullptr;
}
m_outlineData = new nmDataOutline;
return m_outlineData;
}
nmDataOutline* nmDataAnalyzeManager::getOutlineData()
{
return m_outlineData;
}
bool nmDataAnalyzeManager::removeOutlineData()
{
if(m_outlineData) {
delete m_outlineData; // 删除边界数据对象
m_outlineData = nullptr;
return true; // 移除成功,返回 true
}
return false; // 未找到或移除失败,返回 false
}
nmDataOutline nmDataAnalyzeManager::getOutlineDataCopy() const
{
if(m_outlineData) {
return *m_outlineData; // 调用拷贝构造函数
}
nmDataOutline obj;
return obj; // 返回默认构造对象
}
void nmDataAnalyzeManager::updateOutlineData(const nmDataOutline & newData)
{
if(m_outlineData) {
*m_outlineData = newData; // 调用赋值运算符
}
}
nmDataRegion *nmDataAnalyzeManager::createRegion()
{
nmDataRegion* regionData = new nmDataRegion;
m_vRegionData.append(regionData);
return regionData;
}
QVector<nmDataRegion*> nmDataAnalyzeManager::getRegionDataList() const
{
return m_vRegionData;
}
bool nmDataAnalyzeManager::removeRegionData(nmDataRegion * pData)
{
if(pData) {
// 遍历 m_vRegionData 数组,找到并移除对应的对象
for(int i = 0; i < m_vRegionData.size(); ++i) {
if(m_vRegionData[i] == pData) {
delete m_vRegionData[i]; // 释放内存
m_vRegionData.remove(i);
return true; // 移除成功,返回 true
}
}
}
return false; // 未找到或移除失败,返回 false
}
QVector<nmDataRegion> nmDataAnalyzeManager::getRegionDataListCopy() const
{
QVector<nmDataRegion> result;
result.reserve(m_vRegionData.size());
foreach(const nmDataRegion* region, m_vRegionData) {
if(region) {
result.append(*region); // 调用拷贝构造函数
}
}
return result;
}
void nmDataAnalyzeManager::updateRegionData(const QVector<nmDataRegion>& newData)
{
// 确保数量一致
if(newData.size() != m_vRegionData.size()) {
return;
}
for(int i = 0; i < newData.size(); ++i) {
if(m_vRegionData[i]) {
// 只更新内容,不改变指针
*m_vRegionData[i] = newData[i]; // 调用赋值运算符
}
}
}
nmDataFracture *nmDataAnalyzeManager::createFracture()
{
nmDataFracture* fractureData = new nmDataFracture;
m_vFractureData.append(fractureData);
return fractureData;
}
QVector<nmDataFracture*> nmDataAnalyzeManager::getFractureDataList() const
{
return m_vFractureData;
}
QVector<nmDataFracture*> nmDataAnalyzeManager::getDFNFractureDataList() const
{
QVector<nmDataFracture*> vecDFNs;
// 遍历 m_vFractureData 数组,找到并移除对应的对象
for(int i = 0; i < m_vFractureData.size(); ++i) {
if(m_vFractureData[i]->getFractureType().getValue() == tr("DFN")) {
vecDFNs.append(m_vFractureData[i]);
}
}
return vecDFNs;
}
bool nmDataAnalyzeManager::removeFractureData(nmDataFracture * pData)
{
if(pData) {
// 遍历 m_vFractureData 数组,找到并移除对应的对象
for(int i = 0; i < m_vFractureData.size(); ++i) {
if(m_vFractureData[i] == pData) {
delete m_vFractureData[i]; // 释放内存
m_vFractureData.remove(i);
emit dataChanged();
return true; // 移除成功,返回 true
}
}
}
return false; // 未找到或移除失败,返回 false
}
QVector<nmDataFracture> nmDataAnalyzeManager::getFractureDataListCopy() const
{
QVector<nmDataFracture> result;
result.reserve(m_vFractureData.size());
foreach(const nmDataFracture* fracture, m_vFractureData) {
if(fracture) {
result.append(*fracture); // 调用拷贝构造函数
}
}
return result;
}
void nmDataAnalyzeManager::updateFractureData(const QVector<nmDataFracture>& newData)
{
// 确保数量一致
if(newData.size() != m_vFractureData.size()) {
return;
}
for(int i = 0; i < newData.size(); ++i) {
if(m_vFractureData[i]) {
// 只更新内容,不改变指针
*m_vFractureData[i] = newData[i]; // 调用赋值运算符
}
}
}
nmDataFault *nmDataAnalyzeManager::createFault()
{
nmDataFault* faultData = new nmDataFault;
m_vFaultData.append(faultData);
return faultData;
}
QVector<nmDataFault*> nmDataAnalyzeManager::getFaultDataList() const
{
return m_vFaultData;
}
bool nmDataAnalyzeManager::removeFaultData(nmDataFault * pData)
{
if(pData) {
// 遍历 m_vFaultData 数组,找到并移除对应的对象
for(int i = 0; i < m_vFaultData.size(); ++i) {
if(m_vFaultData[i] == pData) {
delete m_vFaultData[i]; // 释放内存
m_vFaultData.remove(i);
emit dataChanged();
return true; // 移除成功,返回 true
}
}
}
return false; // 未找到或移除失败,返回 false
}
QVector<nmDataFault> nmDataAnalyzeManager::getFaultDataListCopy() const
{
QVector<nmDataFault> result;
result.reserve(m_vFaultData.size());
foreach(const nmDataFault* fault, m_vFaultData) {
if(fault) {
result.append(*fault); // 调用拷贝构造函数
}
}
return result;
}
void nmDataAnalyzeManager::updateFaultData(const QVector<nmDataFault>& newData)
{
// 确保数量一致
if(newData.size() != m_vFaultData.size()) {
return;
}
for(int i = 0; i < newData.size(); ++i) {
if(m_vFaultData[i]) {
// 只更新内容,不改变指针
*m_vFaultData[i] = newData[i]; // 调用赋值运算符
}
}
}
nmGuiPlot* nmDataAnalyzeManager::getPlot() const
{
return m_pNmGuiPlot;
}
void nmDataAnalyzeManager::setPlot(nmGuiPlot * plot)
{
m_pNmGuiPlot = plot;
}
void nmDataAnalyzeManager::updateWellPlotByDataManager()
{
nmDataPlotContextProvider* pPlotContextProvider = nmDataPlotContext::provider();
if (m_pNmGuiPlot != nullptr && pPlotContextProvider != nullptr)
{
pPlotContextProvider->updateWellPlots(m_pNmGuiPlot, this);
}
}
QVector<QPointF> nmDataAnalyzeManager::getValueAllConnectablePoints()
{
QVector<QPointF> vecAllPoints;
// 遍历所有断层数据
foreach(nmDataFault* fault, m_vFaultData) {
if(fault) {
QVector<QPointF> faultPoints = fault->getFaultPoints();
foreach(const QPointF& point, faultPoints) {
vecAllPoints.append(point);
}
}
}
// 遍历所有裂缝数据
foreach(nmDataFracture* fracture, m_vFractureData) {
if(fracture) {
QVector<QPointF> fracturePoints = fracture->getFracturePoints();
foreach(const QPointF& point, fracturePoints) {
vecAllPoints.append(point);
}
}
}
// 遍历所有复合区数据
foreach(nmDataRegion* region, m_vRegionData) {
if(region) {
QVector<QPointF> regionPoints = region->getVecPts();
foreach(const QPointF& point, regionPoints) {
vecAllPoints.append(point);
}
}
}
// 处理边界数据
if(m_outlineData) {
QVector<QPointF> outlinePoints = m_outlineData->getOutlinePoints();
// 圆形边界,特殊处理
if(m_outlineData->getOutlineType() == NM_Round_Outline_Type) {
outlinePoints.remove(0); // 圆心
outlinePoints.remove(0); // 半径
}
foreach(const QPointF& point, outlinePoints) {
vecAllPoints.append(point);
}
}
// 垂直裂缝井的裂缝两个端点
// 遍历所有井数据
foreach(nmDataWellBase* well, m_vWellData) {
if(well == nullptr) {
continue;
}
if(well->getWellType() == NM_WELL_MODEL::Vertical_Fractured_Well) {
nmDataVerticalFracturedWell* pVFwell = dynamic_cast<nmDataVerticalFracturedWell*>(well);
if(pVFwell == nullptr) {
continue;
}
QVector<QPointF> fracsPoints = pVFwell->getFracs();
foreach(const QPointF& point, fracsPoints) {
vecAllPoints.append(point);
}
}
}
return vecAllPoints;
}
QVector<QPointF> nmDataAnalyzeManager::getPosAllConnectablePoints()
{
// 将绘图坐标系转为qt坐标系
QVector<QPointF> vecValues = this->getValueAllConnectablePoints();
QVector<QPointF> vecPos;
Q_ASSERT(m_pNmGuiPlot != nullptr);
nmDataPlotContextProvider* pPlotContextProvider = nmDataPlotContext::provider();
if(m_pNmGuiPlot == nullptr || pPlotContextProvider == nullptr) {
return vecPos;
}
pPlotContextProvider->getPosForValue(m_pNmGuiPlot, vecValues, vecPos);
// TODO:没有m_pNmGuiPlot的情况下怎么办也就是加载的时候
return vecPos;
}
QVector<QPointF> nmDataAnalyzeManager::removePosByObject(QObject * obj)
{
// 获取所有可连接的点(屏幕坐标)
QVector<QPointF> vecAllPoints = this->getPosAllConnectablePoints();
// 创建一个临时容器用于存储要移除的点
QVector<QPointF> pointsToRemove;
// 检查传入的对象类型并收集相关点
if(nmDataFault * fault = dynamic_cast<nmDataFault * >(obj)) {
QVector<QPointF> faultPoints = fault->getFaultPoints();
foreach(const QPointF& point, faultPoints) {
pointsToRemove.append(point);
}
} else if(nmDataFracture * fracture = dynamic_cast<nmDataFracture * >(obj)) {
QVector<QPointF> fracturePoints = fracture->getFracturePoints();
foreach(const QPointF& point, fracturePoints) {
pointsToRemove.append(point);
}
} else if(nmDataRegion * region = dynamic_cast<nmDataRegion * >(obj)) {
QVector<QPointF> regionPoints = region->getVecPts();
foreach(const QPointF& point, regionPoints) {
pointsToRemove.append(point);
}
} else if(nmDataVerticalFracturedWell * well = dynamic_cast<nmDataVerticalFracturedWell * >(obj)) {
QVector<QPointF> fracsPoints = well->getFracs();
foreach(const QPointF& point, fracsPoints) {
pointsToRemove.append(point);
}
} else if(m_outlineData == obj) {
QVector<QPointF> outlinePoints = m_outlineData->getOutlinePoints();
if(m_outlineData->getOutlineType() == NM_Round_Outline_Type) {
outlinePoints.remove(0); // 圆心
outlinePoints.remove(0); // 半径
}
foreach(const QPointF& point, outlinePoints) {
pointsToRemove.append(point);
}
}
// change to Pos
QVector<QPointF> vecPosRemove;
nmDataPlotContextProvider* pPlotContextProvider = nmDataPlotContext::provider();
if(m_pNmGuiPlot && pPlotContextProvider) {
pPlotContextProvider->getPosForValue(m_pNmGuiPlot, pointsToRemove, vecPosRemove);
}
// 移除与特定对象相关的点
QVector<QPointF>::iterator itRemove;
for(itRemove = vecPosRemove.begin(); itRemove != vecPosRemove.end(); ++itRemove) {
QPointF pointToRemove = *itRemove;
for(int i = 0; i < vecAllPoints.size(); ++i) {
if(vecAllPoints[i] == pointToRemove) {
vecAllPoints.remove(i);
break; // 只移除第一个匹配的点
}
}
}
return vecAllPoints;
}
nmDataMeasuringScale *nmDataAnalyzeManager::getMeasuringScaleData()
{
if(m_pMeasuringScaleData == nullptr) {
m_pMeasuringScaleData = new nmDataMeasuringScale;
}
return m_pMeasuringScaleData;
}
void nmDataAnalyzeManager::setMeasuringScaleData(nmDataMeasuringScale * pMeasuringScaleData)
{
if(m_pMeasuringScaleData != nullptr) {
delete m_pMeasuringScaleData;
m_pMeasuringScaleData = nullptr;
}
m_pMeasuringScaleData = pMeasuringScaleData;
}
nmDataMeasure *nmDataAnalyzeManager::getMeasureData()
{
if(m_pMeasureData == nullptr) {
m_pMeasureData = new nmDataMeasure;
}
return m_pMeasureData;
}
void nmDataAnalyzeManager::setMeasureData(nmDataMeasure * pMeasureData)
{
if(m_pMeasureData != nullptr) {
delete m_pMeasureData;
m_pMeasureData = nullptr;
}
m_pMeasureData = pMeasureData;
}
bool nmDataAnalyzeManager::removeMeasureData()
{
if(m_pMeasureData) {
delete m_pMeasureData;
m_pMeasureData = nullptr;
return true; // 移除成功,返回 true
}
return false; // 未找到或移除失败,返回 false
}
NM_Grid_Type nmDataAnalyzeManager::getGridType()
{
return m_eGridType;
}
void nmDataAnalyzeManager::setGridType(NM_Grid_Type newGridType)
{
m_eGridType = newGridType;
}
NM_SOLVER_MODEL_TYPE nmDataAnalyzeManager::getSolverModelType() const
{
return m_eSolverModelType;
}
void nmDataAnalyzeManager::setSolverModelType(NM_SOLVER_MODEL_TYPE newSolverModelType)
{
m_eSolverModelType = newSolverModelType;
}
// 获取Pebi网格求解数据接口
// 获取压力历史数据
QVector<QVector<double>> nmDataAnalyzeManager::getPebiSolverHistoryDataByName(const QString & wellName)
{
QVector<QVector<double>> vvecHisotryData;
QVector<double> vX;
QVector<double> vY;
// 验证井名有效性
if(wellName.isEmpty()) {
return vvecHisotryData;
}
// 从结果文件中读取数据
QString sHistoryDataFilePath = ZxBaseUtil::getCurWellDirOf("Nm/Solver") + "output/Pebi/" + wellName + "/Pressure.txt";
if(!QFile::exists(sHistoryDataFilePath)) {
return vvecHisotryData;
}
QStringList sContent = nmDataUtils::readNmDataFile(sHistoryDataFilePath);
QRegExp regex("\\s+");
for(int i = 0; i < sContent.size(); i++) {
QString sData = sContent[i].trimmed();
if(sData.isEmpty()) continue;
QStringList sXY = sData.split(regex, QString::SkipEmptyParts);
if(sXY.size() == 2) {
bool okX, okY;
double x = sXY[0].toDouble(&okX);
double y = sXY[1].toDouble(&okY);
if(okX && okY) {
vX.append(x);
vY.append(y);
}
}
}
vvecHisotryData.append(vX);
vvecHisotryData.append(vY);
return vvecHisotryData;
}
QVector<QVector<double>> nmDataAnalyzeManager::getPebiSolverLogPreDataByName(const QString & wellName)
{
QVector<QVector<double>> vvecLogPreData;
QVector<double> vX;
QVector<double> vY;
QVector<double> vZ;
// 验证井名有效性
if(wellName.isEmpty()) {
return vvecLogPreData;
}
// 从结果文件中读取数据
QString sLogPreDataFilePath = ZxBaseUtil::getCurWellDirOf("Nm/Solver") + "output/Pebi/" + wellName + "/Loglog.txt";
if(!QFile::exists(sLogPreDataFilePath)) {
return vvecLogPreData;
}
QStringList sContent = nmDataUtils::readNmDataFile(sLogPreDataFilePath);
QRegExp regex("\\s+");
for(int i = 0; i < sContent.size() - 1; i++) {
QString sData = sContent[i].trimmed();
if(sData.isEmpty()) continue;
QStringList sXYZ = sData.split(regex, QString::SkipEmptyParts);
if(sXYZ.size() == 3) {
bool okX, okY, okZ;
double x = sXYZ[0].toDouble(&okX);
double y = sXYZ[1].toDouble(&okY);
double z = sXYZ[2].toDouble(&okZ);
if(okX && okY && okZ) {
vX.append(x);
vY.append(y);
vZ.append(z);
}
}
}
vvecLogPreData.append(vX);
vvecLogPreData.append(vY);
vvecLogPreData.append(vZ);
return vvecLogPreData;
}
QVector<QVector<double>> nmDataAnalyzeManager::getPebiSolverSemiLogPreDataByName(const QString & wellName)
{
QVector<QVector<double>> vvecSemiLogPreData;
QVector<double> vX;
QVector<double> vY;
// 验证井名有效性
if(wellName.isEmpty()) {
return vvecSemiLogPreData;
}
// 从结果文件中读取数据
QString sSemiLogPreDataFilePath = ZxBaseUtil::getCurWellDirOf("Nm/Solver") + "output/Pebi/" + wellName + "/SemiLog.txt";
if(!QFile::exists(sSemiLogPreDataFilePath)) {
return vvecSemiLogPreData;
}
QStringList sContent = nmDataUtils::readNmDataFile(sSemiLogPreDataFilePath);
QRegExp regex("\\s+");
for(int i = 0; i < sContent.size(); i++) {
QString sData = sContent[i].trimmed();
if(sData.isEmpty()) continue;
QStringList sXY = sData.split(regex, QString::SkipEmptyParts);
if(sXY.size() == 2) {
bool okX, okY;
double x = sXY[0].toDouble(&okX);
double y = sXY[1].toDouble(&okY);
if(okX && okY) {
vX.append(x);
vY.append(y);
}
}
}
vvecSemiLogPreData.append(vX);
vvecSemiLogPreData.append(vY);
return vvecSemiLogPreData;
}
nmDataPvtParaForPebi* nmDataAnalyzeManager::getPebiPvtPara()
{
return m_pebiPvtPara;
}
nmDataMixedResults* nmDataAnalyzeManager::getMixedResults()
{
return m_pMixedResults;
}
nmDataMixedResults* nmDataAnalyzeManager::createMixedResult()
{
if(m_pMixedResults != nullptr) {
delete m_pMixedResults;
m_pMixedResults = nullptr;
}
m_pMixedResults = new nmDataMixedResults;
return m_pMixedResults;
}
nmDataLayer* nmDataAnalyzeManager::getLayerData()
{
// 1. 删除 m_vecLayers 中当前存储的所有 nmDataLayer 对象,释放内存
qDeleteAll(m_vecLayers);
// 2. 清空 m_vecLayers 自身,移除所有指针
m_vecLayers.clear();
return m_pLayerData;
}
void nmDataAnalyzeManager::setLayers(QVector<nmDataLayer*> vecLayers)
{
m_vecLayers = vecLayers;
}
QVector<nmDataLayer*> nmDataAnalyzeManager::getLayers()
{
return m_vecLayers;
}
double nmDataAnalyzeManager::getMinLayerTop()
{
// 在计算前初始化边界值
double m_dMinLayerTop = DBL_MAX;
// 复制新数据并计算边界
foreach(const nmDataLayer* layer , m_vecLayers) {
if(layer) {
// 更新缓存的最小顶深度
m_dMinLayerTop = qMin(m_dMinLayerTop, layer->getTop());
}
}
// 如果 m_vecLayers 为空,可以设置默认值
if(m_vecLayers.isEmpty()) {
m_dMinLayerTop = 0.0;
}
return m_dMinLayerTop;
}
// 新增的实现:返回存储的最大底深度
double nmDataAnalyzeManager::getMaxLayerBottom()
{
// 在计算前初始化边界值
double m_dMaxLayerBottom = DBL_MIN;
// 复制新数据并计算边界
foreach(const nmDataLayer* layer , m_vecLayers) {
if(layer) {
// 更新缓存的最大顶深度
m_dMaxLayerBottom = qMax(m_dMaxLayerBottom, layer->getBottom());
}
}
// 如果 m_vecLayers 为空,可以设置默认值
if(m_vecLayers.isEmpty()) {
m_dMaxLayerBottom = 0.0;
}
return m_dMaxLayerBottom;
}
void nmDataAnalyzeManager::appendCalculationWell(const QPair<NM_WELL_MODEL, QString>& well)
{
m_vecCalculationWells.append(well);
}
void nmDataAnalyzeManager::insertCalculationWell(int index, const QPair<NM_WELL_MODEL, QString>& well)
{
if(index < 0 || index > m_vecCalculationWells.size()) {
return; // 索引无效,不执行插入操作
}
m_vecCalculationWells.insert(index, well);
}
bool nmDataAnalyzeManager::removeCalculationWell(int index)
{
if(index < 0 || index >= m_vecCalculationWells.size()) {
return false; // 索引无效,返回 false
}
m_vecCalculationWells.remove(index);
return true;
}
void nmDataAnalyzeManager::clearCalculationWells()
{
m_vecCalculationWells.clear();
}
QVector<QPair<NM_WELL_MODEL, QString>> nmDataAnalyzeManager::getCalculationWells() const
{
return m_vecCalculationWells;
}
bool nmDataAnalyzeManager::isContainsWellName(const QString & wellName) const
{
for(int i = 0; i < m_vecCalculationWells.size(); ++i) {
const QPair<NM_WELL_MODEL, QString>& well = m_vecCalculationWells[i];
if(well.first == NM_WELL_MODEL::Unknow_Well) {
continue;
}
if(well.second == wellName) {
return true;
}
}
return false;
}
// 设置当前查看井
void nmDataAnalyzeManager::setCurWellData(nmDataWellBase * wellData)
{
m_pCurDataWell = wellData;
}
// 获取当前查看井
nmDataWellBase* nmDataAnalyzeManager::getCurWellData()
{
return m_pCurDataWell;
}
void nmDataAnalyzeManager::notifyDataChanged()
{
emit dataChanged();
}
void nmDataAnalyzeManager::setDisplaySettings(const QVector<DisplaySetting>& displaySettings)
{
m_vecDisplaySettings = displaySettings;
}
QVector<DisplaySetting> nmDataAnalyzeManager::getDisplaySettings() const
{
return m_vecDisplaySettings;
}
bool nmDataAnalyzeManager::updateCategoryDisplaySetting(const QString & categoryName, const CategoryDisplayInfo & info)
{
for(int i = 0; i < m_vecDisplaySettings.size(); ++i) {
if(m_vecDisplaySettings[i].key == categoryName) {
m_vecDisplaySettings[i].value = info;
return true;
}
}
return false;
}
void nmDataAnalyzeManager::initDefaultDisplaySettings()
{
m_vecDisplaySettings.clear();
// Contour
DisplaySetting contourSetting;
contourSetting.key = tr("Contour");
contourSetting.value.isRootChecked = true; // 默认选中
m_vecDisplaySettings.append(contourSetting);
// Faults
DisplaySetting faultsSetting;
faultsSetting.key = tr("Faults");
faultsSetting.value.isRootChecked = true;
m_vecDisplaySettings.append(faultsSetting);
// Images
DisplaySetting imagesSetting;
imagesSetting.key = tr("Images");
imagesSetting.value.isRootChecked = true;
m_vecDisplaySettings.append(imagesSetting);
// Wells
DisplaySetting wellsSetting;
wellsSetting.key = tr("Wells");
wellsSetting.value.isRootChecked = true;
m_vecDisplaySettings.append(wellsSetting);
// Fractures
DisplaySetting fracturesSetting;
fracturesSetting.key = tr("Fractures");
fracturesSetting.value.isRootChecked = true;
m_vecDisplaySettings.append(fracturesSetting);
// Limits
DisplaySetting limitsSetting;
limitsSetting.key = tr("Regions");
limitsSetting.value.isRootChecked = true;
m_vecDisplaySettings.append(limitsSetting);
// RegionMarks
DisplaySetting regionsSetting;
regionsSetting.key = tr("RegionMarks");
regionsSetting.value.isRootChecked = true;
m_vecDisplaySettings.append(regionsSetting);
}
CategoryDisplayInfo* nmDataAnalyzeManager::findCategoryDisplayInfo(const QString & categoryName)
{
for(int i = 0; i < m_vecDisplaySettings.size(); ++i) {
if(m_vecDisplaySettings[i].key == categoryName) {
return &m_vecDisplaySettings[i].value;
}
}
return nullptr;
}
bool nmDataAnalyzeManager::appendDisplaySetting(const DisplaySetting & displaySetting)
{
// 检查是否已存在相同key的设置
foreach(const auto& setting, m_vecDisplaySettings) {
if(setting.key == displaySetting.key) {
return false; // 已存在相同key添加失败
}
}
// 添加新的显示设置
m_vecDisplaySettings.append(displaySetting);
return true;
}
bool nmDataAnalyzeManager::removeDisplaySetting(const QString & categoryName)
{
// 遍历查找并删除指定key的设置
for(int i = 0; i < m_vecDisplaySettings.size(); ++i) {
if(m_vecDisplaySettings[i].key == categoryName) {
m_vecDisplaySettings.remove(i);
return true; // 删除成功
}
}
return false; // 未找到指定key的设置删除失败
}
bool nmDataAnalyzeManager::addChildItemsToCategory(const QString & parentCategory,
const QStringList & childNames,
bool defaultChecked)
{
// 查找父类别
for(int i = 0; i < m_vecDisplaySettings.size(); ++i) {
if(m_vecDisplaySettings[i].key == parentCategory) {
// 为每个子项名称创建ChildCategoryDisplayInfo并添加到父类别
for(int j = 0; j < childNames.size(); ++j) {
ChildCategoryDisplayInfo childInfo;
childInfo.name = childNames.at(j);
childInfo.isChecked = defaultChecked;
childInfo.isEnabled = m_vecDisplaySettings[i].value.isRootChecked; // 子项启用状态取决于父项
m_vecDisplaySettings[i].value.childItems.append(childInfo);
}
return true;
}
}
return false;
}
void nmDataAnalyzeManager::refreshChildItemsDisplay()
{
// 步骤1: 清空所有父节点的子节点
for(int i = 0; i < m_vecDisplaySettings.size(); ++i) {
m_vecDisplaySettings[i].value.childItems.clear();
}
// 更新边界和位图
CategoryDisplayInfo outlineInfo, imageInfo;
outlineInfo.isRootChecked = m_outlineData->getPlotVisible();
imageInfo.isRootChecked = this->m_backgroundImageInfo.bIsVisible;
this->updateCategoryDisplaySetting(tr("Contour"), outlineInfo);
this->updateCategoryDisplaySetting(tr("Images"), imageInfo);
// 步骤2: 重新添加子节点,根据不同数据容器中的对象名称生成子节点
// 为 "Wells" 分类添加子节点
addWellChildItemsToCategory(tr("Wells"));
// 为 "Faults" 分类添加子节点
addFaultChildItemsToCategory(tr("Faults"));
// 为 "Fractures" 分类添加子节点
addFractureChildItemsToCategory(tr("Fractures"));
// 为 "Regions" 分类添加子节点
addRegionChildItemsToCategory(tr("Regions"));
// 为 "RegionMarks" 分类添加子节点
addRegionMarkChildItemsToCategory(tr("RegionMarks"));
}
// 为Wells分类添加子节点
void nmDataAnalyzeManager::addWellChildItemsToCategory(const QString & parentCategory)
{
// 查找父类别
for(int i = 0; i < m_vecDisplaySettings.size(); ++i) {
if(m_vecDisplaySettings[i].key == parentCategory) {
// 为每个井对象创建子节点
for(int j = 0; j < m_vWellData.size(); ++j) {
if(m_vWellData[j]) {
ChildCategoryDisplayInfo childInfo;
childInfo.name = m_vWellData[j]->getWellName();
childInfo.isChecked = m_vWellData[j]->getPlotVisible();
childInfo.isEnabled = m_vecDisplaySettings[i].value.isRootChecked;
m_vecDisplaySettings[i].value.childItems.append(childInfo);
}
}
return;
}
}
}
// 为Faults分类添加子节点
void nmDataAnalyzeManager::addFaultChildItemsToCategory(const QString & parentCategory)
{
// 查找父类别
for(int i = 0; i < m_vecDisplaySettings.size(); ++i) {
if(m_vecDisplaySettings[i].key == parentCategory) {
// 为每个断层对象创建子节点
for(int j = 0; j < m_vFaultData.size(); ++j) {
if(m_vFaultData[j]) {
ChildCategoryDisplayInfo childInfo;
childInfo.name = m_vFaultData[j]->getFaultName();
childInfo.isChecked = m_vFaultData[j]->getPlotVisible();
childInfo.isEnabled = m_vecDisplaySettings[i].value.isRootChecked;
m_vecDisplaySettings[i].value.childItems.append(childInfo);
}
}
return;
}
}
}
// 为Fractures分类添加子节点
void nmDataAnalyzeManager::addFractureChildItemsToCategory(const QString & parentCategory)
{
// 查找父类别
for(int i = 0; i < m_vecDisplaySettings.size(); ++i) {
if(m_vecDisplaySettings[i].key == parentCategory) {
// 为每个裂缝对象创建子节点
for(int j = 0; j < m_vFractureData.size(); ++j) {
if(m_vFractureData[j]) {
ChildCategoryDisplayInfo childInfo;
childInfo.name = m_vFractureData[j]->getFractureName();
childInfo.isChecked = m_vFractureData[j]->getPlotVisible();
childInfo.isEnabled = m_vecDisplaySettings[i].value.isRootChecked;
m_vecDisplaySettings[i].value.childItems.append(childInfo);
}
}
return;
}
}
}
// 为Regions分类添加子节点
void nmDataAnalyzeManager::addRegionChildItemsToCategory(const QString & parentCategory)
{
// 查找父类别
for(int i = 0; i < m_vecDisplaySettings.size(); ++i) {
if(m_vecDisplaySettings[i].key == parentCategory) {
// 为每个复合区对象创建子节点
for(int j = 0; j < m_vRegionData.size(); ++j) {
if(m_vRegionData[j]) {
ChildCategoryDisplayInfo childInfo;
childInfo.name = m_vRegionData[j]->getRegoinName();
childInfo.isChecked = m_vRegionData[j]->getPlotVisible();
childInfo.isEnabled = m_vecDisplaySettings[i].value.isRootChecked;
m_vecDisplaySettings[i].value.childItems.append(childInfo);
}
}
return;
}
}
}
// 为RegionMarks分类添加子节点
void nmDataAnalyzeManager::addRegionMarkChildItemsToCategory(const QString & parentCategory)
{
// 查找父类别
for(int i = 0; i < m_vecDisplaySettings.size(); ++i) {
if(m_vecDisplaySettings[i].key == parentCategory) {
// 为每个区域标记对象创建子节点
for(int j = 0; j < m_vRegionMarkData.size(); ++j) {
if(m_vRegionMarkData[j]) {
ChildCategoryDisplayInfo childInfo;
childInfo.name = m_vRegionMarkData[j]->getRegionMarkName();
childInfo.isChecked = m_vRegionMarkData[j]->getPlotVisible();
childInfo.isEnabled = m_vecDisplaySettings[i].value.isRootChecked;
m_vecDisplaySettings[i].value.childItems.append(childInfo);
}
}
return;
}
}
}
void nmDataAnalyzeManager::setAllCategoriesRootVisibility(bool bIsVisible)
{
for(int i = 0; i < m_vecDisplaySettings.size(); ++i) {
m_vecDisplaySettings[i].value.isRootChecked = bIsVisible;
}
}
void nmDataAnalyzeManager::setBackgroundImageInfo(const BackgroundImageInfo & info)
{
m_backgroundImageInfo = info;
}
const BackgroundImageInfo& nmDataAnalyzeManager::getBackgroundImageInfo() const
{
return m_backgroundImageInfo;
}
// 从 JSON 文件读取数据到 C++ 对象
bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
{
rapidjson::Document doc;
// 调用 nmDataJsonTools 读取 JSON 文件到 Document
if(!nmDataJsonTools::ReadDomFromFile(filePath, doc)) {
qDebug() << "Error: Failed to read DOM from file:" << filePath;
return false;
}
// 读取已保存的成果井名称,待井数据加载完成后恢复。
QString sSavedCurWellName;
if(doc.HasMember("CurrentResultWellName") && doc["CurrentResultWellName"].IsString()) {
sSavedCurWellName = QString::fromUtf8(doc["CurrentResultWellName"].GetString());
}
// 清空现有数据,确保从头加载新数据
foreach(nmDataFracture* pFractureData, m_vFractureData) {
delete pFractureData; // 释放堆上分配的 nmDataFracture 对象
}
m_vFractureData.clear();
foreach(nmDataFault* pFaultData, m_vFaultData) {
delete pFaultData; // 释放堆上分配的 nmDataFault 对象
}
m_vFaultData.clear();
foreach(nmDataRegion* pRegionData, m_vRegionData) {
delete pRegionData; // 释放堆上分配的 nmDataRegion 对象
}
m_vRegionData.clear();
foreach(nmDataRegionMark* pRegionMarkData, m_vRegionMarkData) {
delete pRegionMarkData; // 释放堆上分配的 nmDataRegionMark 对象
}
m_vRegionMarkData.clear();
foreach(nmDataLayer* pLayerData, m_vecLayers) {
delete pLayerData; // 释放堆上分配的 nmDataLayer 对象
}
m_vecLayers.clear();
if(m_reservoirData) {
delete m_reservoirData;
m_reservoirData = nullptr;
}
if(m_axisData) {
delete m_axisData;
m_axisData = nullptr;
}
if(m_outlineData) {
delete m_outlineData;
m_outlineData = nullptr;
}
if(m_pMixedResults) {
delete m_pMixedResults;
m_pMixedResults = nullptr;
}
if(m_pGeoRefData) {
delete m_pGeoRefData;
m_pGeoRefData = nullptr;
}
if(m_pTimeStep) {
delete m_pTimeStep;
m_pTimeStep = nullptr;
}
if(m_pSensitiveData) {
delete m_pSensitiveData;
m_pSensitiveData = nullptr;
}
//if(m_pPerCloData) {
// delete m_pPerCloData;
// m_pPerCloData = nullptr;
//}
if(m_pAutomaticFittingData) {
delete m_pAutomaticFittingData;
m_pAutomaticFittingData = nullptr;
}
//if(m_pebiPvtPara) {
// delete m_pebiPvtPara;
// m_pebiPvtPara = nullptr;
//}
foreach(nmDataWellBase* pWellData, m_vWellData) {
delete pWellData; // 释放堆上分配的 nmDataWellBase 对象
}
m_vWellData.clear();
// 解析 "Fractures" 数组
if(doc.HasMember("Fractures") && doc["Fractures"].IsArray()) {
const rapidjson::Value& fracturesJson = doc["Fractures"];
for(rapidjson::SizeType i = 0; i < fracturesJson.Size(); ++i) {
// 动态创建 nmDataFracture 对象,并获取其指针
nmDataFracture* fracture = new nmDataFracture();
fracture->FromJsonValue(fracturesJson[i]); // 调用 nmDataFracture 自身的反序列化方法
m_vFractureData.append(fracture); // 将指针添加到 QVector
}
}
// 解析 "Faults" 数组
if(doc.HasMember("Faults") && doc["Faults"].IsArray()) {
const rapidjson::Value& faultsJson = doc["Faults"];
for(rapidjson::SizeType i = 0; i < faultsJson.Size(); ++i) {
// 动态创建 nmDataFault 对象,并获取其指针
nmDataFault* fault = new nmDataFault();
fault->FromJsonValue(faultsJson[i]); // 调用 nmDataFault 自身的反序列化方法
m_vFaultData.append(fault); // 将指针添加到 QVector
}
}
// 解析 "Regions" 数组
if(doc.HasMember("Regions") && doc["Regions"].IsArray()) {
const rapidjson::Value& regionsJson = doc["Regions"];
for(rapidjson::SizeType i = 0; i < regionsJson.Size(); ++i) {
// 动态创建 nmDataRegion 对象,并获取其指针
nmDataRegion* region = new nmDataRegion(); // 传入this作为父对象
region->FromJsonValue(regionsJson[i]); // 调用 nmDataRegion 自身的反序列化方法
m_vRegionData.append(region); // 将指针添加到 QVector
}
}
// 解析 "RegionMarks" 数组
if(doc.HasMember("RegionMarks") && doc["RegionMarks"].IsArray()) {
const rapidjson::Value& regionMarksJson = doc["RegionMarks"];
for(rapidjson::SizeType i = 0; i < regionMarksJson.Size(); ++i) {
// 动态创建 nmDataRegionMark 对象,并获取其指针
nmDataRegionMark* regionMark = new nmDataRegionMark(); // 传入this作为父对象
regionMark->FromJsonValue(regionMarksJson[i]); // 调用 nmDataRegion 自身的反序列化方法
m_vRegionMarkData.append(regionMark); // 将指针添加到 QVector
}
}
// 解析 "Layers" 数组
if(doc.HasMember("Layers") && doc["Layers"].IsArray()) {
const rapidjson::Value& layersJson = doc["Layers"];
for(rapidjson::SizeType i = 0; i < layersJson.Size(); ++i) {
// 动态创建 nmDataRegion 对象,并获取其指针
nmDataLayer* layer = new nmDataLayer(); // 传入this作为父对象
layer->FromJsonValue(layersJson[i]); // 调用 nmDataLayer 自身的反序列化方法
m_vecLayers.append(layer); // 将指针添加到 QVector
}
}
// 解析 "Reservoir" 对象
if(doc.HasMember("Reservoir") && doc["Reservoir"].IsObject()) {
m_reservoirData = new nmDataReservoir;
m_reservoirData->FromJsonValue(doc["Reservoir"]);
}
// 解析 "Axis" 对象
if(doc.HasMember("Axis") && doc["Axis"].IsObject()) {
m_axisData = new nmDataAxis;
m_axisData->FromJsonValue(doc["Axis"]);
}
// 解析 "Outline" 对象
if(doc.HasMember("Outline") && doc["Outline"].IsObject()) {
m_outlineData = new nmDataOutline;
m_outlineData->FromJsonValue(doc["Outline"]);
}
// 解析 "GeoRef" 对象
if(doc.HasMember("GeoReference") && doc["GeoReference"].IsObject()) {
m_pGeoRefData = new nmDataGeoRef;
m_pGeoRefData->FromJsonValue(doc["GeoReference"]);
}
// 解析 "AutomaticFitting" 对象
if(doc.HasMember("AutomaticFitting") && doc["AutomaticFitting"].IsObject()) {
m_pAutomaticFittingData = new nmDataAutomaticFitting;
m_pAutomaticFittingData->FromJsonValue(doc["AutomaticFitting"]);
}
// 解析 "Sensitive" 对象
if(doc.HasMember("Sensitive") && doc["Sensitive"].IsObject()) {
m_pSensitiveData = new nmDataSensitive;
m_pSensitiveData->FromJsonValue(doc["Sensitive"]);
}
// 解析 "PVT" 对象
//if(doc.HasMember("PVT") && doc["PVT"].IsObject()) {
// m_pebiPvtPara = new nmDataPvtParaForPebi;
// m_pebiPvtPara->FromJsonValue(doc["PVT"]);
//}
// 解析 "MixResult" 对象
if(doc.HasMember("MixResult") && doc["MixResult"].IsObject()) {
m_pMixedResults = new nmDataMixedResults;
m_pMixedResults->FromJsonValue(doc["MixResult"]);
}
// 解析 "Wells" 数组
if(doc.HasMember("Wells") && doc["Wells"].IsArray()) {
const rapidjson::Value& wellsJson = doc["Wells"];
for(rapidjson::SizeType i = 0; i < wellsJson.Size(); ++i) {
//// 动态创建 nmDataFault 对象,并获取其指针
//nmDataWellBase* well = new nmDataWellBase(); // 传入this作为父对象
//well->FromJsonValue(wellsJson[i]); // 调用 nmDataFault 自身的反序列化方法
//m_vWellData.append(well); // 将指针添加到 QVector
// 获取当前井的JSON对象
const rapidjson::Value& wellItemJson = wellsJson[i];
// 临时指针,用于指向新创建的井对象
nmDataWellBase* pWell = nullptr;
// 井类型
NM_WELL_MODEL eWellType = NM_WELL_MODEL::Unknow_Well;
// 1. 读取 wellType
if(wellItemJson.HasMember("WellType") && wellItemJson["WellType"].IsInt()) {
eWellType = static_cast<NM_WELL_MODEL>(wellItemJson["WellType"].GetInt());
}
// 2. 根据 eWellType 动态创建不同的井类型实例
switch(eWellType) {
case NM_WELL_MODEL::Vertical_Well:
pWell = new nmDataVerticalWell;
break;
case NM_WELL_MODEL::Vertical_Fractured_Well:
pWell = new nmDataVerticalFracturedWell;
break;
case NM_WELL_MODEL::Horizontal_Fractured_Well:
pWell = new nmDataHorizontalFracturedWell;
break;
// TODO: 添加其他具体的井类型
default:
break;
}
// 3. 调用具体井类型的 FromJsonValue 方法进行反序列化
if(pWell) { // 确保 well 对象已成功创建
pWell->FromJsonValue(wellItemJson); // 调用其自身的反序列化方法
m_vWellData.append(pWell); // 将指针添加到 QVector
// TODO将最后一口井设置为当前井(临时)
//this->setCurWellData(pWell);
}
}
}
// 设置当前井
// 获取当前默认井数据
ZxDataWell* pWellData = zxCurWell;
// 查找是否有当前井的数据
nmDataWellBase* pCurWell = nullptr;
if(!sSavedCurWellName.isEmpty()) {
pCurWell = this->findWellByName(sSavedCurWellName);
}
if(pCurWell == nullptr && pWellData != nullptr) {
pCurWell = this->findWellByName(pWellData->getName());
}
if (pCurWell != nullptr)
{
this->setCurWellData(pCurWell);
} else {
// 设置第一口井为当前井
if (m_vWellData.size() > 0)
{
this->setCurWellData(m_vWellData[0]);
}
}
// 解析 时间步 对象
if(doc.HasMember("TimeStep") && doc["TimeStep"].IsObject()) {
m_pTimeStep = new nmDataTimeStepSetting;
m_pTimeStep->FromJsonValue(doc["TimeStep"]);
}
return true;
}
// 将 C++ 对象数据写入 JSON 文件
bool nmDataAnalyzeManager::WriteProjectData(const QString & filePath)
{
rapidjson::Document doc;
doc.SetObject(); // 根节点是对象
rapidjson::Document::AllocatorType& allocator = doc.GetAllocator(); // 获取内存分配器
// 构建 "Fractures" 数组的 JSON Value
rapidjson::Value fracturesJsonArray(rapidjson::kArrayType);
// 遍历存储 nmDataFracture 指针的 QVector并解引用指针来调用 ToJsonValue 方法
foreach(nmDataFracture* pFractureData, m_vFractureData) {
if(pFractureData) { // 检查指针是否有效
fracturesJsonArray.PushBack(pFractureData->ToJsonValue(allocator), allocator);
}
}
doc.AddMember("Fractures", fracturesJsonArray, allocator);
// 构建 "Faults" 数组的 JSON Value
rapidjson::Value faultsJsonArray(rapidjson::kArrayType);
// 遍历存储 nmDataFault 指针的 QVector并解引用指针来调用 ToJsonValue 方法
foreach(nmDataFault* pFaultData, m_vFaultData) {
if(pFaultData) { // 检查指针是否有效
faultsJsonArray.PushBack(pFaultData->ToJsonValue(allocator), allocator);
}
}
doc.AddMember("Faults", faultsJsonArray, allocator);
// 构建 "Regions" 数组的 JSON Value
rapidjson::Value regionsJsonArray(rapidjson::kArrayType);
// 遍历存储 nmDataRegion 指针的 QVector并解引用指针来调用 ToJsonValue 方法
foreach(nmDataRegion* pRegionData, m_vRegionData) {
if(pRegionData) { // 检查指针是否有效
regionsJsonArray.PushBack(pRegionData->ToJsonValue(allocator), allocator);
}
}
doc.AddMember("Regions", regionsJsonArray, allocator);
// 构建 "RegionMarks" 数组的 JSON Value
rapidjson::Value regionMarksJsonArray(rapidjson::kArrayType);
// 遍历存储 nmDataRegionMark 指针的 QVector并解引用指针来调用 ToJsonValue 方法
foreach(nmDataRegionMark* pRegionMarkData, m_vRegionMarkData) {
if(pRegionMarkData) { // 检查指针是否有效
regionMarksJsonArray.PushBack(pRegionMarkData->ToJsonValue(allocator), allocator);
}
}
doc.AddMember("RegionMarks", regionMarksJsonArray, allocator);
// 构建 "Layers" 数组的 JSON Value
rapidjson::Value layersJsonArray(rapidjson::kArrayType);
// 遍历存储 nmDataLayer 指针的 QVector并解引用指针来调用 ToJsonValue 方法
foreach(nmDataLayer* pLayerData, m_vecLayers) {
if(pLayerData) { // 检查指针是否有效
layersJsonArray.PushBack(pLayerData->ToJsonValue(allocator), allocator);
}
}
doc.AddMember("Layers", layersJsonArray, allocator);
// 序列化 "Reservoir"
if(m_reservoirData) {
rapidjson::Value reservoirJson(rapidjson::kObjectType);
reservoirJson = m_reservoirData->ToJsonValue(allocator);
doc.AddMember("Reservoir", reservoirJson, allocator);
}
// 序列化 "Axis"
if(m_axisData) {
rapidjson::Value axisJson(rapidjson::kObjectType);
axisJson = m_axisData->ToJsonValue(allocator);
doc.AddMember("Axis", axisJson, allocator);
}
// 序列化 "Outline"
if(m_outlineData) {
rapidjson::Value outlineJson(rapidjson::kObjectType);
outlineJson = m_outlineData->ToJsonValue(allocator);
doc.AddMember("Outline", outlineJson, allocator);
}
// 序列化 "Reservoir"
if(m_pGeoRefData) {
rapidjson::Value geoRefJson(rapidjson::kObjectType);
geoRefJson = m_pGeoRefData->ToJsonValue(allocator);
doc.AddMember("GeoReference", geoRefJson, allocator);
}
//// 序列化 "PerforationClosing"
//if(m_pPerCloData) {
// rapidjson::Value perCloJson(rapidjson::kObjectType);
// perCloJson = m_pPerCloData->ToJsonValue(allocator);
// doc.AddMember("PerforationClosing", perCloJson, allocator);
//}
//// 序列化 "SkinVsRate"
//if(m_pSkinVsRateData) {
// rapidjson::Value skinJson(rapidjson::kObjectType);
// skinJson = m_pSkinVsRateData->ToJsonValue(allocator);
// doc.AddMember("SkinVsRate", skinJson, allocator);
//}
// 序列化 "AutomaticFitting"
if(m_pAutomaticFittingData) {
rapidjson::Value autofitJson(rapidjson::kObjectType);
autofitJson = m_pAutomaticFittingData->ToJsonValue(allocator);
doc.AddMember("AutomaticFitting", autofitJson, allocator);
}
// 序列化 "PVT"
//if(m_pebiPvtPara) {
// rapidjson::Value pvtJson(rapidjson::kObjectType);
// pvtJson = m_pebiPvtPara->ToJsonValue(allocator);
// doc.AddMember("PVT", pvtJson, allocator);
//}
// 序列化 "MixResult"
if(m_pMixedResults) {
rapidjson::Value mixResultsJson(rapidjson::kObjectType);
mixResultsJson = m_pMixedResults->ToJsonValue(allocator);
doc.AddMember("MixResult", mixResultsJson, allocator);
}
// 序列化 "Sensitive"
if(m_pSensitiveData) {
rapidjson::Value sensitiveJson(rapidjson::kObjectType);
sensitiveJson = m_pSensitiveData->ToJsonValue(allocator);
doc.AddMember("Sensitive", sensitiveJson, allocator);
}
// 构建 "Wells" 数组的 JSON Value
rapidjson::Value wellsJsonArray(rapidjson::kArrayType);
// 遍历存储 nmDataWellBase 指针的 QVector并解引用指针来调用 ToJsonValue 方法
foreach(nmDataWellBase* pWellData, m_vWellData) {
if(nmDataVerticalFracturedWell * pVerticalFracturedWell = dynamic_cast<nmDataVerticalFracturedWell * >(pWellData)) { // 检查指针是否有效
wellsJsonArray.PushBack(pVerticalFracturedWell->ToJsonValue(allocator), allocator);
} else if(nmDataHorizontalFracturedWell * pHorizontalFracturedWell = dynamic_cast<nmDataHorizontalFracturedWell * >(pWellData)) { // 检查指针是否有效
wellsJsonArray.PushBack(pHorizontalFracturedWell->ToJsonValue(allocator), allocator);
} else if(nmDataHorizontalWell * pHorizontalWell = dynamic_cast<nmDataHorizontalWell * >(pWellData)) { // 检查指针是否有效
wellsJsonArray.PushBack(pHorizontalWell->ToJsonValue(allocator), allocator);
} else if(nmDataVerticalWell * pVerticalWell = dynamic_cast<nmDataVerticalWell * >(pWellData)) { // 检查指针是否有效
wellsJsonArray.PushBack(pVerticalWell->ToJsonValue(allocator), allocator);
}
}
doc.AddMember("Wells", wellsJsonArray, allocator);
// 保存当前成果井名称,供下次加载成果时恢复。
if(m_pCurDataWell != nullptr) {
QString sCurrentResultWellName = m_pCurDataWell->getWellName();
doc.AddMember("CurrentResultWellName",
rapidjson::Value(sCurrentResultWellName.toStdString().c_str(), allocator).Move(),
allocator);
}
// 序列化 时间步数据
if(m_pTimeStep) {
rapidjson::Value timeStepJson(rapidjson::kObjectType);
timeStepJson = m_pTimeStep->ToJsonValue(allocator);
doc.AddMember("TimeStep", timeStepJson, allocator);
}
// 将最终构建好的 Document 写入文件
if(!nmDataJsonTools::WriteDomToFile(doc, filePath)) {
qDebug() << "Error: Failed to write DOM to file:" << filePath;
return false;
}
return true;
}
bool nmDataAnalyzeManager::saveNmResult(QString sRstCode, iSubWndFitting* pSubWndF)
{
Q_ASSERT(nullptr != pSubWndF);
// 通过窗口层上下文获取保存目录
nmDataAnalyzeContextProvider* pContextProvider = nmDataAnalyzeContext::provider();
Q_ASSERT(nullptr != pContextProvider);
QString sDir;
if(pContextProvider == nullptr || !pContextProvider->getSaveResultDir(pSubWndF, sRstCode, sDir)) {
return false;
}
// sDir为当前成果窗口目录
// 保存前先清空成果ID目录下的旧内容避免旧RstWnd目录或残留文件继续被加载
QString sResultRootPath = QFileInfo(sDir).dir().absolutePath();
if(!clearDirectoryContents(sResultRootPath)) {
return false;
}
QString sResultPath = sDir + "/Results";
this->ensureDirectoryExists(sResultPath);
// 将数据写入Json文件
this->WriteProjectData(sResultPath + "/Numerical_Parameters.json");
// --- 保存所有井的历史数据到独立目录 /WellHistory ---
QString sWellHistoryDataPath = sDir + "/WellHistory";
this->ensureDirectoryExists(sWellHistoryDataPath);
QVector<nmDataWellBase*> vecAllWells = nmDataAnalyzeManager::getCurrentInstance()->getWellDataList(); // 获取所有井
// 遍历所有井,保存历史数据
for(int wellIdx = 0; wellIdx < vecAllWells.size(); ++wellIdx) {
nmDataWellBase* pWellData = vecAllWells[wellIdx];
if(pWellData) {
this->saveWellHistoryData(sWellHistoryDataPath, pWellData);
}
}
// 保存非结构化网格数据
QString sGridPath = sDir + "/Grid";
if(!m_pVtkUnstructuredGrid) {
// 如果没有网格对象,说明没有生成网格,直接返回
return true;
}
this->ensureDirectoryExists(sGridPath);
// 将实时划分出来的网格写入文件
this->writeUnstructuredGridToFile(m_pVtkUnstructuredGrid, sGridPath + "/CurrentGrid.vtu");
// 保存结果里的基础网格
if(!m_pResultBaseGrid) {
// 无基础网格对象,说明没有进行计算,返回
return true;
}
// 保存场图里的基础网格
this->writeUnstructuredGridToFile(m_pResultBaseGrid, sGridPath + "/ResultGrid.vtu");
// 保存场图中的井位置相关信息
this->saveWellLocations(sGridPath + "/ResultWellLocations.bin");
// --- 保存时间步压力数据 (m_mapTimeStepDataP) ---
QString sTimeStepDataFilePath = sDir + "/TimeStepData/PressureTimeSteps.bin"; // 单个二进制文件路径
QString sTimeStepDataDirPath = sDir + "/TimeStepData"; // 确保目录存在
this->ensureDirectoryExists(sTimeStepDataDirPath);
// 将时间步数据写入二进制文件中
if(!writeTimeStepDataMapToBinaryFile(sTimeStepDataFilePath)) {
qDebug() << QString("Failed to save all time step data map to binary file: %1").arg(sTimeStepDataFilePath);
return false; // 返回失败
}
// 保存参与计算井的结果数据
QString sWellRstDataPath = sDir + "/WellRst";
this->ensureDirectoryExists(sWellRstDataPath);
QVector<QPair<NM_WELL_MODEL, QString>> vecWells = nmDataAnalyzeManager::getCurrentInstance()->getCalculationWells();
// 遍历每口井,保存里面计算出来的数据
for(int wellIdx = 0; wellIdx < vecWells.size(); ++wellIdx) {
NM_WELL_MODEL wellType = vecWells[wellIdx].first; // 获取井的类型
QString wellName = vecWells[wellIdx].second; // 获取井的名称
// 跳过裂缝(或未知井类型)
if(wellType == NM_WELL_MODEL::Unknow_Well) {
continue;
}
nmDataWellBase* pWellData = nmDataAnalyzeManager::getCurrentInstance()->findWellByName(wellName);
if(pWellData) {
this->saveWellCalRstData(sWellRstDataPath, pWellData);
}
}
return true;
}
bool nmDataAnalyzeManager::loadNmResult(QString sLoadAnalDir)
{
// 将Json文件内容读取出来
QString sResultPath = sLoadAnalDir + "/Results/Numerical_Parameters.json";
this->ReadProjectData(sResultPath);
// 读取当前网格文件
QString sCurrentGridPath = sLoadAnalDir + "/Grid/CurrentGrid.vtu";
this->readUnstructuredGridFromFile(m_pVtkUnstructuredGrid, sCurrentGridPath);
// 读取结果基础网格文件
QString sResultGridPath = sLoadAnalDir + "/Grid/ResultGrid.vtu";
this->readUnstructuredGridFromFile(m_pResultBaseGrid, sResultGridPath);
// 加载场图中的井位置相关信息
QString sResultWellLocationPath = sLoadAnalDir + "/Grid/ResultWellLocations.bin";
this->loadWellLocations(sResultWellLocationPath);
// --- 加载时间步压力数据 (m_mapTimeStepDataP) ---
QString sTimeStepDataFilePath = sLoadAnalDir + "/TimeStepData/PressureTimeSteps.bin";
// 读取时间步数据
if(!readTimeStepDataMapFromBinaryFile(sTimeStepDataFilePath)) {
qDebug() << QString("Failed to load all time step data map from binary file: %1").arg(sTimeStepDataFilePath);
}
// --- 加载所有井的历史数据从独立目录 /WellHistory ---
QString sWellHistoryDataPath = sLoadAnalDir + "/WellHistory";
this->ensureDirectoryExists(sWellHistoryDataPath);
// 遍历所有井,尝试加载历史数据
for(int i = 0; i < m_vWellData.size(); i++) {
this->loadWellHistoryData(sWellHistoryDataPath, m_vWellData[i]);
}
// 获取参与计算井的结果数据
QString sWellRstDataPath = sLoadAnalDir + "/WellRst";
this->ensureDirectoryExists(sWellRstDataPath);
for(int i = 0; i < m_vWellData.size(); i++) {
this->loadWellCalRstData(sWellRstDataPath, m_vWellData[i]);
}
// 读完后加载井的压力、流量数据
this->loadWellPreAndFlow();
if (m_pVtkUnstructuredGrid != nullptr)
m_bIsLoadData = true;
return true;
}
bool nmDataAnalyzeManager::ensureDirectoryExists(const QString & dirPath)
{
QDir dir(dirPath);
if(!dir.exists()) {
qDebug() << QString("Directory does not exist, attempting to create: %1").arg(dirPath);
if(!dir.mkpath(dirPath)) {
qDebug() << QString("Failed to create directory: %1").arg(dirPath);
return false;
}
qDebug() << QString("Directory created successfully: %1").arg(dirPath);
} else {
qDebug() << QString("Directory already exists: %1").arg(dirPath);
}
return true;
}
void nmDataAnalyzeManager::loadWellPreAndFlow()
{
// 获取当前工区里所有的ZxDataWell井
if(zxCurProject == nullptr) {
return;
}
ZxDataObjectList wellList = zxCurProject->getChildren(iDataModelType::sTypeWell);
foreach(nmDataWellBase* pWell, m_vWellData) {
if(pWell == nullptr) {
continue;
}
QString sWellName = pWell->getWellName();
ZxDataWell* pWellData = nullptr;
for(int i = 0; i < wellList.size(); i++) {
ZxDataWell* pCandidateWell = dynamic_cast<ZxDataWell*>(wellList[i]);
if(pCandidateWell != nullptr && pCandidateWell->getName() == sWellName) {
pWellData = pCandidateWell;
break;
}
}
// 拿到了井的数据
if(pWellData) {
// 获取当前井的压力、流量数据
ZxDataObjectList m_listGaugeP = pWellData->getChildren(iDataModelType::sTypeDataGaugeP);
ZxDataObjectList m_listGaugeF = pWellData->getChildren(iDataModelType::sTypeDataGaugeF);
ZxDataGaugeP* pGaugeP = nullptr;
ZxDataGaugeF* pGaugeF = nullptr;
// 遍历压力数据列表
for(int i = 0; i < m_listGaugeP.size(); ++i) {
if(pGaugeP = dynamic_cast<ZxDataGaugeP * >(m_listGaugeP[i])) { // 拿到第一条压力数据
break;
}
}
// 遍历流量数据列表
for(int i = 0; i < m_listGaugeF.size(); ++i) {
if(pGaugeF = dynamic_cast<ZxDataGaugeF * >(m_listGaugeF[i])) { // 拿到第一条流量数据
break;
}
}
// 获取的压力、流量数据
QVector<QPointF> vecPtsP, vecPtsF;
// 临时存储xy坐标
VecDouble vecX, vecY;
if(pGaugeP != nullptr) {
// 获取压力数据
if(pGaugeP->getDataVecXY(vecX, vecY)) {
int pointCount = vecX.size();
if(pointCount > vecY.size()) {
pointCount = vecY.size();
}
for(int i = 0; i < pointCount; ++i) {
QPointF pt(vecX[i], vecY[i]);
vecPtsP.append(pt);
}
}
}
if(pGaugeF != nullptr) {
vecX.clear();
vecY.clear();
// 获取流量数据
if(pGaugeF->getDataVecXY(vecX, vecY)) {
int pointCount = vecX.size();
if(pointCount > vecY.size()) {
pointCount = vecY.size();
}
for(int i = 0; i < pointCount; ++i) {
QPointF pt(vecX[i], vecY[i]);
vecPtsF.append(pt);
}
}
}
// 设置井的压力数据、流量数据
pWell->setPressurePoints(vecPtsP);
pWell->setFlowPoints(vecPtsF);
}
}
}
vtkSmartPointer<vtkUnstructuredGrid> nmDataAnalyzeManager::getUnstructuredGrid() const
{
return m_pVtkUnstructuredGrid;
}
void nmDataAnalyzeManager::setUnstructuredGrid(vtkSmartPointer<vtkUnstructuredGrid> grid)
{
m_pVtkUnstructuredGrid = grid;
}
void nmDataAnalyzeManager::clearUnstructuredGrid()
{
// 释放当前分析持有的实时VTK网格对象关闭网格窗口后不再保留旧网格。
m_pVtkUnstructuredGrid = nullptr;
}
vtkSmartPointer<vtkUnstructuredGrid> nmDataAnalyzeManager::getUnstructuredGridCopy() const
{
vtkSmartPointer<vtkUnstructuredGrid> pCopyGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
if(m_pVtkUnstructuredGrid) {
// 执行深拷贝:复制网格的所有几何和拓扑信息
pCopyGrid->DeepCopy(m_pVtkUnstructuredGrid);
}
return pCopyGrid;
}
vtkSmartPointer<vtkUnstructuredGrid> nmDataAnalyzeManager::getResultBaseGrid() const
{
return m_pResultBaseGrid;
}
void nmDataAnalyzeManager::setResultBaseGrid(vtkSmartPointer<vtkUnstructuredGrid> grid)
{
m_pResultBaseGrid = grid;
}
vtkSmartPointer<vtkUnstructuredGrid> nmDataAnalyzeManager::getResultBaseGridCopy() const
{
vtkSmartPointer<vtkUnstructuredGrid> pCopyGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
if(m_pResultBaseGrid) {
// 执行深拷贝:复制网格的所有几何和拓扑信息
pCopyGrid->DeepCopy(m_pResultBaseGrid);
}
return pCopyGrid;
}
bool nmDataAnalyzeManager::writeUnstructuredGridToFile(vtkSmartPointer<vtkUnstructuredGrid> grid, const QString& filePath)
{
// 检查是否存在有效的网格数据
if(!grid) {
return false;
}
// 根据文件扩展名决定使用哪种格式
if(filePath.endsWith(".vtu", Qt::CaseInsensitive)) {
// 使用XML格式推荐格式
vtkNew<vtkXMLUnstructuredGridWriter> writer;
writer->SetInputData(grid); // 设置输入数据
writer->SetFileName(filePath.toStdString().c_str()); // 设置输出文件名
writer->SetDataModeToBinary(); // 设置为二进制模式也可以用SetDataModeToAscii()设为文本模式
writer->Write(); // 执行写入操作
} else if(filePath.endsWith(".vtk", Qt::CaseInsensitive)) {
// 使用传统的VTK格式
vtkNew<vtkUnstructuredGridWriter> writer;
writer->SetInputData(grid); // 设置输入数据
writer->SetFileName(filePath.toStdString().c_str()); // 设置输出文件名
writer->SetFileTypeToBinary(); // 设置为二进制模式也可以用SetFileTypeToASCII()设为文本模式
writer->Write(); // 执行写入操作
} else {
return false; // 不支持的文件扩展名
}
return true; // 写入成功
}
bool nmDataAnalyzeManager::readUnstructuredGridFromFile(vtkSmartPointer<vtkUnstructuredGrid>& grid, const QString& filePath)
{
// 检查文件是否存在
if(!QFile::exists(filePath)) {
return false;
}
// 根据文件扩展名选择不同的读取器
if(filePath.endsWith(".vtu", Qt::CaseInsensitive)) {
// 使用XML格式读取器
vtkNew<vtkXMLUnstructuredGridReader> reader;
reader->SetFileName(filePath.toStdString().c_str()); // 设置输入文件名
reader->Update(); // 执行读取操作
grid = reader->GetOutput(); // 获取读取的数据
} else if(filePath.endsWith(".vtk", Qt::CaseInsensitive)) {
// 使用传统VTK格式读取器
vtkNew<vtkUnstructuredGridReader> reader;
reader->SetFileName(filePath.toStdString().c_str()); // 设置输入文件名
reader->Update(); // 执行读取操作
grid = reader->GetOutput(); // 获取读取的数据
} else {
return false; // 不支持的文件扩展名
}
// 检查是否成功读取了有效的网格数据
if(grid && grid->GetNumberOfPoints() > 0) {
return true;
}
return false; // 读取失败
}
void nmDataAnalyzeManager::addTimeStep(double time, vtkSmartPointer<vtkDoubleArray> data)
{
if(!data || data->GetNumberOfTuples() == 0) return;
m_mapTimeStepDataP.insert(time, data);
}
vtkSmartPointer<vtkDoubleArray> nmDataAnalyzeManager::getTimeStepData(double time) const
{
if(m_mapTimeStepDataP.contains(time)) {
return m_mapTimeStepDataP.value(time);
}
return nullptr;
}
QList<double> nmDataAnalyzeManager::getTimeStepKeys()
{
return m_mapTimeStepDataP.keys();
}
bool nmDataAnalyzeManager::isTimeStepDataEmpty()
{
return m_mapTimeStepDataP.isEmpty();
}
/**
* @brief 辅助函数将整个时间步数据QMap保存到单个二进制文件。
* 文件中依次存储QMap大小、每个时间键、每个vtkDoubleArray的大小、每个vtkDoubleArray的数据。
* @param filePath 文件保存的完整路径。
* @return 写入成功返回true否则返回false。
*/
bool nmDataAnalyzeManager::writeTimeStepDataMapToBinaryFile(const QString& filePath)
{
QFile file(filePath);
// 使用 Truncate 模式确保如果文件已存在,会被清空并覆盖
if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qDebug() << QString("Failed to open file for writing (TimeStepDataMap): %1").arg(filePath);
return false;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_8); // 当前项目Qt版本
// 1. 写入 QMap 的元素数量
out << (qint32)m_mapTimeStepDataP.size();
// 2. 遍历 QMap依次写入每个时间键和对应的 vtkDoubleArray 数据
for(auto it = m_mapTimeStepDataP.constBegin(); it != m_mapTimeStepDataP.constEnd(); ++it) {
double time = it.key();
vtkSmartPointer<vtkDoubleArray> data = it.value();
// 写入时间键
out << time;
// 写入 vtkDoubleArray 的元素数量
qint64 numberOfTuples = data ? data->GetNumberOfTuples() : 0;
out << numberOfTuples;
// 写入 vtkDoubleArray 的数据
if(data && numberOfTuples > 0) {
for(qint64 i = 0; i < numberOfTuples; ++i) {
out << data->GetValue(i);
}
}
}
file.close();
return true;
}
/**
* @brief 辅助函数从单个二进制文件加载整个时间步数据QMap。
* @param filePath 文件所在的完整路径。
* @return 加载成功返回true否则返回false。
*/
bool nmDataAnalyzeManager::readTimeStepDataMapFromBinaryFile(const QString& filePath)
{
m_mapTimeStepDataP.clear(); // 清空现有数据,准备加载新数据
m_dScalarRangeP[0] = DBL_MAX; // 初始化最小值为最大浮点数
m_dScalarRangeP[1] = -DBL_MAX; // 初始化最大值为最小浮点数
QFile file(filePath);
if(!file.open(QIODevice::ReadOnly)) {
qDebug() << QString("Failed to open file for reading (TimeStepDataMap): %1").arg(filePath);
return false;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_8); // 必须与写入时的版本一致
// 1. 读取 QMap 的元素数量
qint32 mapSize;
in >> mapSize;
if(mapSize < 0) { // 简单校验
qDebug() << QString("Invalid map size read from binary file: %1").arg(filePath);
file.close();
return false;
}
// 2. 循环读取每个时间键和对应的 vtkDoubleArray 数据
for(qint32 k = 0; k < mapSize; ++k) {
double time;
in >> time; // 读取时间键
qint64 numberOfTuples;
in >> numberOfTuples; // 读取 vtkDoubleArray 的元素数量
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
data->SetNumberOfComponents(1); // 假设是单分量数组
data->SetNumberOfTuples(numberOfTuples); // 设置数组大小
// 设置数组名称
data->SetName("p");
if(numberOfTuples > 0) {
double currentMin = DBL_MAX;
double currentMax = -DBL_MAX;
for(qint64 i = 0; i < numberOfTuples; ++i) {
double value;
in >> value;
data->SetValue(i, value);
// 更新当前时间步的范围
currentMin = qMin(currentMin, value);
currentMax = qMax(currentMax, value);
}
// 更新全局范围
m_dScalarRangeP[0] = qMin(m_dScalarRangeP[0], currentMin);
m_dScalarRangeP[1] = qMax(m_dScalarRangeP[1], currentMax);
}
m_mapTimeStepDataP.insert(time, data);
}
file.close();
return true;
}
bool nmDataAnalyzeManager::saveWellHistoryData(QString sDir, nmDataWellBase* pWellData)
{
Q_ASSERT(nullptr != pWellData);
if(nullptr == pWellData) {
return false;
}
// 构建文件路径,文件名为:[WellName]_History.bin
QString wellName = pWellData->getWellName();
if(wellName.isEmpty()) {
return false;
}
QString filePath = sDir + "/" + wellName + "_History.bin";
QFile file(filePath);
if(!file.open(QIODevice::WriteOnly)) {
return false;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_8);
// 只写入历史数据
out << pWellData->getHistoryPressure();
out << pWellData->getHistoryLogLog();
out << pWellData->getHistorySemiLog();
file.close();
return true;
}
bool nmDataAnalyzeManager::loadWellHistoryData(QString sDir, nmDataWellBase* pWellData)
{
Q_ASSERT(nullptr != pWellData);
if(nullptr == pWellData) {
return false;
}
QString sWellName = pWellData->getWellName();
if(sWellName.isEmpty()) {
return false;
}
// 文件名为:[WellName]_History.bin
QString filePath = sDir + "/" + sWellName + "_History.bin";
QFile file(filePath);
if(!file.open(QIODevice::ReadOnly)) {
return false;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_8);
// 只需要读取历史数据
QVector<QVector<double>> historyPressureData;
QVector<QVector<double>> historyLoglogData;
QVector<QVector<double>> historySemiLogData;
// 只读取历史数据
in >> historyPressureData;
in >> historyLoglogData;
in >> historySemiLogData;
pWellData->setHistoryPressure(historyPressureData);
pWellData->setHistoryLogLog(historyLoglogData);
pWellData->setHistorySemiLog(historySemiLogData);
file.close();
return true;
}
bool nmDataAnalyzeManager::saveWellCalRstData(QString sDir, nmDataWellBase* pWellData)
{
Q_ASSERT(nullptr != pWellData);
if(nullptr == pWellData) {
return false;
}
// 构建文件路径,为每口井的结果创建一个独立文件
QString wellName = pWellData->getWellName();
if(wellName.isEmpty()) {
return false;
}
QString filePath = sDir + "/" + wellName + "_Results.bin"; //
QFile file(filePath);
if(!file.open(QIODevice::WriteOnly)) {
return false;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_8); // 设置数据流版本,保证未来兼容性
// 写入数据
// QDataStream 可以直接序列化 QVector<QVector<double>>
out << pWellData->getResultPressure();
out << pWellData->getResultLogLog();
out << pWellData->getResultSemiLog();
file.close();
return true;
}
bool nmDataAnalyzeManager::loadWellCalRstData(QString sDir, nmDataWellBase* pWellData)
{
Q_ASSERT(nullptr != pWellData);
if(nullptr == pWellData) {
return false;
}
QString sWellName = pWellData->getWellName();
if(sWellName.isEmpty()) {
return false;
}
QString filePath = sDir + "/" + sWellName + "_Results.bin";
QFile file(filePath);
if(!file.open(QIODevice::ReadOnly)) {
return false;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_8); // 确保与写入时版本一致
// 读取数据到 pWellData 的成员变量
QVector<QVector<double>> pressureData;
QVector<QVector<double>> loglogData;
QVector<QVector<double>> semiLogData;
in >> pressureData;
in >> loglogData;
in >> semiLogData;
pWellData->setResultPressure(pressureData);
pWellData->setResultLogLog(loglogData);
pWellData->setResultSemiLog(semiLogData);
//// 存储当前井名称和二维位置到映射
//QPointF ptWellCoords(pWellData->getX().getValue().toDouble(), pWellData->getY().getValue().toDouble());
//addWellLocation(sWellName, ptWellCoords);
// 将当前井添加到参与计算井列表中
this->appendCalculationWell(QPair<NM_WELL_MODEL, QString>(pWellData->getWellType(), pWellData->getWellName()));
file.close();
return true;
}
void nmDataAnalyzeManager::getScalarRangeP(double range[2]) const
{
range[0] = m_dScalarRangeP[0];
range[1] = m_dScalarRangeP[1];
}
void nmDataAnalyzeManager::setScalarRangeP(double min, double max)
{
m_dScalarRangeP[0] = min;
m_dScalarRangeP[1] = max;
}
void nmDataAnalyzeManager::addWellLocation(const QString& wellName, const QPointF& location)
{
m_mapWellLocations.insert(wellName, location);
}
QPointF nmDataAnalyzeManager::getWellLocation(const QString& wellName) const
{
return m_mapWellLocations.value(wellName, QPointF()); // 如果未找到返回默认的QPointF(0,0)
}
bool nmDataAnalyzeManager::removeWellLocation(const QString& wellName)
{
return m_mapWellLocations.remove(wellName) > 0;
}
void nmDataAnalyzeManager::clearWellLocations()
{
m_mapWellLocations.clear();
}
QMap<QString, QPointF> nmDataAnalyzeManager::getAllWellLocations() const
{
return m_mapWellLocations;
}
bool nmDataAnalyzeManager::saveWellLocations(const QString& filePath)
{
QFile file(filePath);
if(!file.open(QIODevice::WriteOnly)) {
return false;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_8);
qDebug() << "Map size before writting:" << m_mapWellLocations.size();
out << m_mapWellLocations;
file.close();
return true;
}
bool nmDataAnalyzeManager::loadWellLocations(const QString& filePath)
{
QFile file(filePath);
if(!file.open(QIODevice::ReadOnly)) {
return false;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_8);
in >> m_mapWellLocations;
qDebug() << "Map size after reading:" << m_mapWellLocations.size();
file.close();
return true;
}
//void nmDataAnalyzeManager::createTimeStep()
//{
// if (m_pTimeStep != nullptr)
// {
// delete m_pTimeStep;
// m_pTimeStep = nullptr;
// }
//
// // 获取当前井下流量的时间范围
// QVector<QPointF> vecFlowPoints;
// if (m_pCurDataWell){
// vecFlowPoints = m_pCurDataWell->getFlowPoints();
// }
//
// // 计算起始时间和终止时间
// // 检查坐标数组是否为空,以防止访问越界
// if (!vecFlowPoints.isEmpty()) {
// // 起始时间就是第一个点的横坐标
// double dStartTime = vecFlowPoints.first().x();
//
// // 终止时间是所有点的横坐标之和
// double dEndTime = 0.0;
// foreach (const QPointF& point, vecFlowPoints) {
// dEndTime += point.x();
// }
//
// m_pTimeStep = new nmDataTimeStepSetting(dStartTime,dEndTime);
// }
//}
nmDataTimeStepSetting* nmDataAnalyzeManager::createTimeStep()
{
if (m_pTimeStep != nullptr)
{
delete m_pTimeStep;
m_pTimeStep = nullptr;
}
m_pTimeStep = new nmDataTimeStepSetting;
return m_pTimeStep;
}
nmDataTimeStepSetting* nmDataAnalyzeManager::getTimeStep()
{
return m_pTimeStep;
}
// 获取许可证路径
void nmDataAnalyzeManager::setLicensePath(const QString& licensePath)
{
m_licensePath = licensePath;
}
QString nmDataAnalyzeManager::getLicensePath() const
{
return m_licensePath;
}