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/nmSubWnd/nmSubWndDataAnalyzeControll...

344 lines
12 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 "nmSubWndDataAnalyzeController.h"
#include "iSubWndFitting.h"
#include "iWxDataBasicEx.h"
#include "SubMLs/tLayerDesc.h"
#include "iAnalRun.h"
#include "nmDataAnalyzeContext.h"
#include "ZxBaseUtil.h"
#include "ZxDataWell.h"
#include "ZxRstWnd.h"
#include "ZxSegmentInfo.h"
#include <Windows.h>
#include <QSet>
namespace {
// 将数据层保存的窗口指针还原为窗口层接口指针
iSubWndFitting* toFitting(void* pFitting)
{
return static_cast<iSubWndFitting*>(pFitting);
}
typedef bool (*CalPseudoPressure)(double, double&, int);
CalPseudoPressure getPseudoPressureConverter()
{
static HMODULE module = LoadLibraryW(L"mAlgPseudo.dll");
static CalPseudoPressure converter = module
? reinterpret_cast<CalPseudoPressure>(GetProcAddress(
module, "?calPS@iAlgPseuCaller@@SA_NNAANH@Z"))
: nullptr;
return converter;
}
// nmSubWnd模块加载时注册上下文提供者,避免在nmSubWndUtils中增加初始化代码
struct nmSubWndDataAnalyzeControllerRegistrar {
nmSubWndDataAnalyzeControllerRegistrar()
{
nmDataAnalyzeContext::setProvider(nmSubWndDataAnalyzeController::instance());
}
};
nmSubWndDataAnalyzeControllerRegistrar s_registrar;
}
// 获取窗口层上下文控制器单例
nmSubWndDataAnalyzeController* nmSubWndDataAnalyzeController::instance()
{
static nmSubWndDataAnalyzeController s_controller;
return &s_controller;
}
// 获取界面当前选择的流动段索引
bool nmSubWndDataAnalyzeController::getCurrentSegmentIndex(void* pFitting, int& nIndexF)
{
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
if(pSubWndFitting == nullptr) {
return false;
}
ZxSegmentInfo* pSegInfo = pSubWndFitting->getSegmentInfo();
if(pSegInfo == nullptr) {
return false;
}
nIndexF = pSegInfo->m_nIndexF;
return true;
}
// 复制当前流动段绑定的压力、流量曲线 Code,供数值井恢复实际使用的记录。
bool nmSubWndDataAnalyzeController::getCurrentSegmentGaugeCodes(
void* pFitting,
QString& sPressureCurveName,
QString& sFlowCurveName)
{
sPressureCurveName.clear();
sFlowCurveName.clear();
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
if(pSubWndFitting == nullptr) {
return false;
}
ZxSegmentInfo* pSegInfo = pSubWndFitting->getSegmentInfo();
if(pSegInfo == nullptr) {
return false;
}
sPressureCurveName = pSegInfo->m_sCurveNameP;
sFlowCurveName = pSegInfo->m_sCurveNameF;
return true;
}
// 复制当前流动段分析的多相流量快照,保持 nmData 与具体窗口类之间的模块边界。
bool nmSubWndDataAnalyzeController::getCurrentSegmentMultiPhaseData(
void* pFitting,
QString& sFlowCurveName,
VVecDouble& vvecMultiPhaseData)
{
sFlowCurveName.clear();
vvecMultiPhaseData.clear();
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
if(pSubWndFitting == nullptr) {
return false;
}
ZxSegmentInfo* pSegInfo = pSubWndFitting->getSegmentInfo();
if(pSegInfo == nullptr) {
return false;
}
sFlowCurveName = pSegInfo->m_sCurveNameF;
vvecMultiPhaseData = pSegInfo->m_vvecMpData;
return true;
}
// 获取基础数据中的PVT相态类型
bool nmSubWndDataAnalyzeController::getBasicPft(void* pFitting, PvtFluidType& eType)
{
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
if(pSubWndFitting == nullptr) {
return false;
}
eType = pSubWndFitting->getBasicPft();
return true;
}
// 按参数名获取PVT基础参数值
bool nmSubWndDataAnalyzeController::getPvtParaValues(void* pFitting, const QStringList& listParas, QMap<QString, double>& mapValues)
{
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
if(pSubWndFitting == nullptr) {
return false;
}
return pSubWndFitting->getPvtParaValues(listParas, mapValues);
}
// 获取基础数据分层数据
bool nmSubWndDataAnalyzeController::getBasicDataLayers(void* pFitting, VVecVariant& vvecLayerData)
{
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
if(pSubWndFitting == nullptr) {
return false;
}
return pSubWndFitting->getBasicDataLayers(vvecLayerData);
}
bool nmSubWndDataAnalyzeController::getBasicLayerColors(
void* pFitting, const QStringList& listLayerNames, QVector<QColor>& vecColors)
{
vecColors.clear();
iSubWndFitting* pSubWndFitting = toFitting(pFitting); // 借用指定分析窗口,不能回退到当前激活分析。
if (pSubWndFitting == nullptr) return false;
// 使用框架公开的页面列表,读取的正是新建分析/基础参数中的多层颜色设置。
QVector<iWxBase*>* pPages = pSubWndFitting->getAllWxPtr(); // 框架拥有的页面容器,不修改、不释放。
if (pPages == nullptr) return false;
for (int nPage = 0; nPage < pPages->size(); ++nPage) {
iWxDataBasicEx* pBasicPage = qobject_cast<iWxDataBasicEx*>(pPages->at(nPage)); // 借用所属基础页面。
if (pBasicPage == nullptr) continue;
bool bMultiLayer = false; // 框架返回的多层选项,防止使用已退出多层模式后残留的描述。
QVector<tLayerDesc*> vecDescriptions; // 框架拥有的层描述指针,只在本次调用中读取,不接管所有权。
pBasicPage->slotGetMultiLayerOptions(bMultiLayer, &vecDescriptions);
if (!bMultiLayer || vecDescriptions.isEmpty()) return false;
QVector<QColor> vecMatchedColors(listLayerNames.size()); // 按请求行排列,未匹配项保留无效 QColor。
QSet<int> setUsedDescriptions; // 已使用的描述索引,重复层名也不能反复使用同一条描述。
for (int nRow = 0; nRow < listLayerNames.size(); ++nRow) {
int nMatchedIndex = -1; // 本行匹配到的描述索引,-1 表示没有对应层。
// 同名层按描述中的出现顺序逐一匹配;名称不一致时不按位置套用其他层的颜色。
for (int nDesc = 0; nDesc < vecDescriptions.size(); ++nDesc) {
const tLayerDesc* pDescription = vecDescriptions.at(nDesc); // 借用当前候选层描述。
if (pDescription != nullptr && !setUsedDescriptions.contains(nDesc)
&& pDescription->m_sLayerName == listLayerNames.at(nRow)) {
nMatchedIndex = nDesc;
break;
}
}
if (nMatchedIndex >= 0) {
vecMatchedColors[nRow] = vecDescriptions.at(nMatchedIndex)->m_clr;
setUsedDescriptions.insert(nMatchedIndex);
}
}
vecColors = vecMatchedColors;
return true;
}
return false;
}
// 获取指定相态和参数名对应的PVT曲线结果
bool nmSubWndDataAnalyzeController::getPvtRstOf(void* pFitting, PvtFluidType eType, const QString& sPara, VecDouble& vecX, VecDouble& vecY)
{
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
if(pSubWndFitting == nullptr) {
return false;
}
return pSubWndFitting->getPvtRstOf(eType, sPara, vecX, vecY);
}
// 获取Diffusion页面中某个参数的具体数值
bool nmSubWndDataAnalyzeController::getDiffusionParaOf(void* pFitting, DiffusionSubOption dso, const QString& sPara, double& d)
{
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
if(pSubWndFitting == nullptr) {
return false;
}
return pSubWndFitting->getDiffusionParaOf(dso, sPara, d);
}
// 获取Diffusion页面中指定子项的计算结果
bool nmSubWndDataAnalyzeController::getDiffusionRstOf(void* pFitting, DiffusionSubOption dso, VVecDouble& vvec)
{
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
if(pSubWndFitting == nullptr) {
return false;
}
return pSubWndFitting->getDiffusionRstOf(dso, vvec);
}
bool nmSubWndDataAnalyzeController::convertPressureToPseudoPressure(
void* pFitting, const VecDouble& vecPressure, VecDouble& vecPseudoPressure)
{
vecPseudoPressure.clear();
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
iAnalRun* pAnalRun = pSubWndFitting ? pSubWndFitting->getAnalRun() : nullptr;
// 与模拟曲线保持一致,初始化所属窗口的配置后直接调用 calPS,不另做插值。
if(pAnalRun == nullptr
|| !pAnalRun->configPsAbouts(true, pSubWndFitting->getModelOption(),
false, pSubWndFitting->getAllWxPtr())) {
return false;
}
CalPseudoPressure converter = getPseudoPressureConverter();
if(converter == nullptr) {
return false;
}
VecDouble vecConverted;
vecConverted.reserve(vecPressure.size());
for(int i = 0; i < vecPressure.size(); ++i) {
double ps = 0.0;
if(!qIsFinite(vecPressure[i])
|| !converter(vecPressure[i], ps, -1) || !qIsFinite(ps)) {
return false;
}
vecConverted.append(ps);
}
vecPseudoPressure.swap(vecConverted);
return true;
}
bool nmSubWndDataAnalyzeController::getPseuRstOf(void* pFitting, VVecDouble& vvec)
{
// 先按当前井和相态配置拟压力算法,确保转换规则与自动拟合界面一致。
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
if(pSubWndFitting == nullptr) {
return false;
}
iAnalRun* pAnalRun = pSubWndFitting->getAnalRun();
if(pAnalRun == nullptr
|| !pAnalRun->configPsAbouts(true,
pSubWndFitting->getModelOption(),
false,
pSubWndFitting->getAllWxPtr())) {
return false;
}
VVecDouble source;
if(!pSubWndFitting->getPseuRstOf(source)
|| source.size() < 2
|| source[0].size() < 2) {
return false;
}
double minPressure = source[0][0];
double maxPressure = source[0][0];
for(int i = 1; i < source[0].size(); ++i) {
minPressure = qMin(minPressure, source[0][i]);
maxPressure = qMax(maxPressure, source[0][i]);
}
if(minPressure >= maxPressure) {
return false;
}
// 在原始压力范围内建立稠密转换表,Runner 后续通过线性插值转换每个求解压力点。
const int sampleCount = 4096;
CalPseudoPressure converter = getPseudoPressureConverter();
if(converter == nullptr) {
return false;
}
VecDouble pressureTable;
VecDouble pseudoPressureTable;
pressureTable.reserve(sampleCount);
pseudoPressureTable.reserve(sampleCount);
for(int i = 0; i < sampleCount; ++i) {
const double ratio = static_cast<double>(i) / (sampleCount - 1);
const double pressure = minPressure + ratio * (maxPressure - minPressure);
double pseudoPressure = 0.0;
if(!converter(pressure, pseudoPressure, -1)) {
return false;
}
pressureTable.append(pressure);
pseudoPressureTable.append(pseudoPressure);
}
vvec.clear();
vvec.append(pressureTable);
vvec.append(pseudoPressureTable);
return true;
}
// 组装当前井和当前结果窗口对应的数值结果保存目录
bool nmSubWndDataAnalyzeController::getSaveResultDir(void* pFitting, const QString& sRstCode, QString& sDir)
{
iSubWndFitting* pSubWndFitting = toFitting(pFitting);
if(pSubWndFitting == nullptr) {
return false;
}
ZxRstWnd* pRstWnd = pSubWndFitting->getRstUtilWnd();
if(pRstWnd == nullptr) {
return false;
}
ZxDataWell* pDataWell = pSubWndFitting->getDataWell();
if(pDataWell == nullptr) {
return false;
}
sDir = ZxBaseUtil::getWellDirOf(pDataWell->getName(), "Nm");
sDir += sRstCode + "/" + pRstWnd->getCode();
return true;
}