|
|
|
|
@ -125,6 +125,8 @@ nmSubWndMain::nmSubWndMain(QWidget *parent, QString sExt) :
|
|
|
|
|
m_openDialogCmdIds.clear();
|
|
|
|
|
m_pProgressDlg = nullptr;
|
|
|
|
|
m_pSolverTask = nullptr;
|
|
|
|
|
m_pSolverDataManager = nullptr;
|
|
|
|
|
m_pSolverFitting = nullptr;
|
|
|
|
|
m_pFakeProgressTimer = nullptr;
|
|
|
|
|
m_nVirtualProgress = 0;
|
|
|
|
|
m_nSlowDownCounter = 0;
|
|
|
|
|
@ -181,14 +183,18 @@ nmSubWndMain::~nmSubWndMain()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_pSolverTask) {
|
|
|
|
|
// 窗口销毁时只解除本窗口的回调;若线程仍在运行,让线程自己结束后释放。
|
|
|
|
|
// 第一步:停止向正在析构的窗口投递完成回调。
|
|
|
|
|
disconnect(m_pSolverTask, SIGNAL(sig_calculateDone(bool)), this, SLOT(on_solverTaskFinished(bool)));
|
|
|
|
|
if (m_pSolverTask == s_pRunningSolverTask && !m_pSolverTask->isRunning()) {
|
|
|
|
|
s_pRunningSolverTask = nullptr;
|
|
|
|
|
// 第二步:DataManager 会在成果窗口销毁后释放,而任务仍读取该对象。
|
|
|
|
|
// Qt 4.8 下只能等待外部 DLL 正常返回,绝不能让裸指针越过管理器生命周期。
|
|
|
|
|
if(m_pSolverTask->isRunning()) {
|
|
|
|
|
m_pSolverTask->wait();
|
|
|
|
|
}
|
|
|
|
|
if (!m_pSolverTask->isRunning()) {
|
|
|
|
|
m_pSolverTask->deleteLater();
|
|
|
|
|
if (m_pSolverTask == s_pRunningSolverTask) {
|
|
|
|
|
s_pRunningSolverTask = nullptr;
|
|
|
|
|
}
|
|
|
|
|
// 第三步:线程已经停止,当前窗口仍是任务的明确所有者,可直接释放。
|
|
|
|
|
delete m_pSolverTask;
|
|
|
|
|
m_pSolverTask = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1241,54 +1247,60 @@ void nmSubWndMain::selectWell()
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 先获取已经添加到的界面中井
|
|
|
|
|
QStringList wellPlotNameList = m_pWxPlot->getWellNames();
|
|
|
|
|
// 先找到所有的井
|
|
|
|
|
// 第一步:Map 当前选择状态使用 WellCode 保存,井名只用于界面显示。
|
|
|
|
|
QList<QVariant> selectedWellCodes;
|
|
|
|
|
QVector<ZxDataWell*> vecMapWells = m_pWxPlot->getWellDatas();
|
|
|
|
|
for(int nIndex = 0; nIndex < vecMapWells.size(); ++nIndex) {
|
|
|
|
|
ZxDataWell* pMapWell = vecMapWells[nIndex];
|
|
|
|
|
if(pMapWell != nullptr && !pMapWell->getCode().isEmpty()) {
|
|
|
|
|
selectedWellCodes.append(pMapWell->getCode());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 第二步:读取项目井库,并建立 WellCode 到项目井对象的稳定映射。
|
|
|
|
|
int wellCount = zxCurProject->getChildrenCount(iDataModelType::sTypeWell);
|
|
|
|
|
ZxDataObjectList wellList = zxCurProject->getChildren(iDataModelType::sTypeWell);
|
|
|
|
|
nmDataLogFile::getInstance()->writeLog(QString(" %1 %2").arg(wellCount).arg(wellList.size()));
|
|
|
|
|
// 井的名字
|
|
|
|
|
QStringList listWellNames;
|
|
|
|
|
// 井的code
|
|
|
|
|
QList<QVariant> wellCodes;
|
|
|
|
|
// 井的名字到井数据指针的Map
|
|
|
|
|
QMap<QString, ZxDataWell*> wellNameToObjMap;
|
|
|
|
|
// 数据整理
|
|
|
|
|
QMap<QString, ZxDataWell*> wellCodeToObjMap;
|
|
|
|
|
for(int i = 0; i < wellList.size(); i++) {
|
|
|
|
|
ZxDataWell* wellObj = (ZxDataWell*)wellList[i];
|
|
|
|
|
ZxDataWell* wellObj = dynamic_cast<ZxDataWell*>(wellList[i]);
|
|
|
|
|
if(wellObj == nullptr || wellObj->getCode().isEmpty()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
nmDataLogFile::getInstance()->writeLog(wellObj->getName() + " " + wellObj->getCode());
|
|
|
|
|
listWellNames.append(wellObj->getName());
|
|
|
|
|
wellCodes.append(wellObj->getCode());
|
|
|
|
|
wellNameToObjMap.insert(wellObj->getName(), wellObj);
|
|
|
|
|
wellCodeToObjMap.insert(wellObj->getCode(), wellObj);
|
|
|
|
|
}
|
|
|
|
|
// 展示dialog供选择
|
|
|
|
|
|
|
|
|
|
// 第三步:恢复 Map 中已有井的勾选状态,允许用户增删其他项目井。
|
|
|
|
|
nmWxSelectWellsDlg dlg;
|
|
|
|
|
nmWxSelectWellsWidget wellListWidget;
|
|
|
|
|
wellListWidget.setSelectedItems(wellPlotNameList);
|
|
|
|
|
wellListWidget.setSelectedValues(selectedWellCodes);
|
|
|
|
|
wellListWidget.addItems(listWellNames, wellCodes);
|
|
|
|
|
dlg.setWidget(&wellListWidget);
|
|
|
|
|
if(dlg.exec() == QDialog::Accepted) {
|
|
|
|
|
// 用户点击了"确定"按钮
|
|
|
|
|
nmDataLogFile::getInstance()->writeLog(" OK ");
|
|
|
|
|
QStringList wellNames = wellListWidget.getItems();
|
|
|
|
|
QList<QVariant> selectedValues = wellListWidget.getSelectedValues();
|
|
|
|
|
QList<ZxDataWell*> selectWellList;
|
|
|
|
|
|
|
|
|
|
// 找出新选中的井
|
|
|
|
|
for(int i = 0; i < wellNames.count(); i++) {
|
|
|
|
|
QString wellName = wellNames[i];
|
|
|
|
|
if (!wellName.isEmpty()) { // 确保井名不为空
|
|
|
|
|
// 仅将有效的井对象添加到 selectWellList
|
|
|
|
|
selectWellList.append(wellNameToObjMap.value(wellName));
|
|
|
|
|
// 第四步:按 WellCode 解析选择结果,避免同名井或井名修改导致关联错误。
|
|
|
|
|
QStringList selectedCodeTexts;
|
|
|
|
|
for(int i = 0; i < selectedValues.count(); i++) {
|
|
|
|
|
const QString sWellCode = selectedValues[i].toString();
|
|
|
|
|
ZxDataWell* pSelectedWell = wellCodeToObjMap.value(sWellCode, nullptr);
|
|
|
|
|
if(pSelectedWell != nullptr) {
|
|
|
|
|
selectWellList.append(pSelectedWell);
|
|
|
|
|
selectedCodeTexts.append(sWellCode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->updateSelectedWells(selectWellList);
|
|
|
|
|
// 更新完成后,通知参数界面刷新
|
|
|
|
|
//nmWxParameterProperty::notifyUpdateTable();
|
|
|
|
|
|
|
|
|
|
nmDataLogFile::getInstance()->writeLog("===" + wellNames.join(";") + "===");
|
|
|
|
|
nmDataLogFile::getInstance()->writeLog(
|
|
|
|
|
"===" + selectedCodeTexts.join(";") + "===");
|
|
|
|
|
} else {
|
|
|
|
|
// 用户点击了"取消"按钮
|
|
|
|
|
nmDataLogFile::getInstance()->writeLog(" Cancel ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1512,6 +1524,10 @@ void nmSubWndMain::solveAndAnalyze()
|
|
|
|
|
m_pProgressDlg = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 新一次启动前清空旧上下文;后续所有检查通过后再成对写入。
|
|
|
|
|
m_pSolverDataManager = nullptr;
|
|
|
|
|
m_pSolverFitting = nullptr;
|
|
|
|
|
|
|
|
|
|
// 根据当前数据中心的分析切换到对应的流动段分析窗口
|
|
|
|
|
ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(m_pMainWindow);
|
|
|
|
|
|
|
|
|
|
@ -1525,13 +1541,54 @@ void nmSubWndMain::solveAndAnalyze()
|
|
|
|
|
if(pSubWndFit == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(pTabWx == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pTabWx->setCurrentWidget(pSubWndFit);
|
|
|
|
|
|
|
|
|
|
nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
|
nmDataAnalyzeManager* pDataManager =
|
|
|
|
|
nmDataAnalyzeManager::findManagerByFitting(pSubWndFit);
|
|
|
|
|
if(pDataManager == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 第一步:求解时间轴必须由至少一口主动井的产注制度驱动。
|
|
|
|
|
// 观察井可以完全不传产量,但不能在所有井都是观察井时启动无源汇计算。
|
|
|
|
|
QVector<nmCalculationWellRef> vecEffectiveWells =
|
|
|
|
|
pDataManager->getEffectiveCalculationWells();
|
|
|
|
|
bool bHasRateControlledWell = false;
|
|
|
|
|
for(int nIndex = 0; nIndex < vecEffectiveWells.size(); ++nIndex) {
|
|
|
|
|
const nmCalculationWellRef& oWellRef = vecEffectiveWells[nIndex];
|
|
|
|
|
nmDataWellBase* pWellData =
|
|
|
|
|
pDataManager->findWellByCode(oWellRef.m_sWellCode);
|
|
|
|
|
if(pWellData == nullptr) {
|
|
|
|
|
QMessageBox::warning(this, tr("solver error"),
|
|
|
|
|
tr("A selected well is missing from the map."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(oWellRef.m_eMode != NM_CaseWell_RateControlled) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bHasRateControlledWell = true;
|
|
|
|
|
if(pWellData->getFlowPoints().size() < 2) {
|
|
|
|
|
QMessageBox::warning(
|
|
|
|
|
this,
|
|
|
|
|
tr("solver error"),
|
|
|
|
|
tr("Rate-controlled well '%1' has no valid rate schedule.")
|
|
|
|
|
.arg(pWellData->getWellName()));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!bHasRateControlledWell) {
|
|
|
|
|
QMessageBox::warning(
|
|
|
|
|
this,
|
|
|
|
|
tr("solver error"),
|
|
|
|
|
tr("At least one active production or injection well is required."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 手动求解可能直接启动, 因此必须在创建求解线程前初始化拟压力转换器.
|
|
|
|
|
// pSubWndFit 保存的是当前拟合窗口克隆后的 PVT、拟压力及模型选项数据.
|
|
|
|
|
// configPsAbouts() 会据此初始化常规、三区或组分转换器并设置当前模式.
|
|
|
|
|
@ -1552,7 +1609,7 @@ void nmSubWndMain::solveAndAnalyze()
|
|
|
|
|
QString sPostprocessingPath = "";
|
|
|
|
|
|
|
|
|
|
// 获取计算类型
|
|
|
|
|
NM_Grid_Type gridType = nmDataAnalyzeManager::getCurrentInstance()->getGridType();
|
|
|
|
|
NM_Grid_Type gridType = pDataManager->getGridType();
|
|
|
|
|
|
|
|
|
|
// PEBI求解直接使用当前后处理目录
|
|
|
|
|
if(gridType == NM_Grid_PEBI) {
|
|
|
|
|
@ -1571,11 +1628,15 @@ void nmSubWndMain::solveAndAnalyze()
|
|
|
|
|
m_pSolverTask = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 直接创建真正执行DLL计算的PEBI线程任务,替代原来的中间转发层。
|
|
|
|
|
m_pSolverTask = new nmCalculationDllPebiSolverTask(sPostprocessingPath);
|
|
|
|
|
// 第一步:捕获本次求解的完整窗口上下文,完成回调不得再读取全局当前窗口。
|
|
|
|
|
m_pSolverDataManager = pDataManager;
|
|
|
|
|
m_pSolverFitting = pSubWndFit;
|
|
|
|
|
|
|
|
|
|
// 第二步:直接创建真正执行 DLL 计算的 PEBI 线程任务。
|
|
|
|
|
m_pSolverTask = new nmCalculationDllPebiSolverTask(sPostprocessingPath,
|
|
|
|
|
pDataManager);
|
|
|
|
|
s_pRunningSolverTask = m_pSolverTask;
|
|
|
|
|
connect(m_pSolverTask, SIGNAL(sig_calculateDone(bool)), this, SLOT(on_solverTaskFinished(bool)));
|
|
|
|
|
connect(m_pSolverTask, SIGNAL(finished()), m_pSolverTask, SLOT(deleteLater()));
|
|
|
|
|
|
|
|
|
|
// 1. 创建并配置进度对话框
|
|
|
|
|
if (m_pProgressDlg == nullptr)
|
|
|
|
|
@ -1583,7 +1644,9 @@ void nmSubWndMain::solveAndAnalyze()
|
|
|
|
|
// TODO:关联到父窗口
|
|
|
|
|
m_pProgressDlg = new QProgressDialog(tr("Calculating, please wait..."), QString(), 0, 100, getMainWindow());
|
|
|
|
|
m_pProgressDlg->setWindowTitle(tr("Solver Progress"));
|
|
|
|
|
m_pProgressDlg->setWindowModality(Qt::NonModal); // 模态,锁定父窗口
|
|
|
|
|
// 后台只读取任务值快照;应用级模态仍用于阻止重复启动、切换成果等会让
|
|
|
|
|
// 用户误判当前计算归属的操作,数据安全不再依赖该对话框冻结界面。
|
|
|
|
|
m_pProgressDlg->setWindowModality(Qt::ApplicationModal);
|
|
|
|
|
|
|
|
|
|
// 某些系统下,对话框右上角的关闭按钮可能仍存
|
|
|
|
|
// 使用 WindowFlags 彻底禁用关闭按钮
|
|
|
|
|
@ -1643,7 +1706,8 @@ void nmSubWndMain::mergeAnaResultToFitting()
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iSubWndFitting* pSubWndFit = nmDataAnalyzeManager::getCurrentFitting();
|
|
|
|
|
iSubWndFitting* pSubWndFit = !m_pSolverFitting.isNull()
|
|
|
|
|
? m_pSolverFitting.data() : nmDataAnalyzeManager::getCurrentFitting();
|
|
|
|
|
Q_ASSERT(pSubWndFit != nullptr);
|
|
|
|
|
if(pSubWndFit == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
@ -1656,53 +1720,64 @@ void nmSubWndMain::mergeAnaResultToFitting()
|
|
|
|
|
// 半对数数据
|
|
|
|
|
QVector<QVector<double >> vvecSemiLogPreData;
|
|
|
|
|
|
|
|
|
|
nmDataAnalyzeManager* pInstance = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
|
nmDataAnalyzeManager* pInstance = !m_pSolverDataManager.isNull()
|
|
|
|
|
? m_pSolverDataManager.data()
|
|
|
|
|
: nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
|
if(pInstance == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取参与计算的井
|
|
|
|
|
QVector<QPair<NM_WELL_MODEL, QString>> vecWellsOrder = pInstance->getCalculationWells();
|
|
|
|
|
|
|
|
|
|
// 获取当前查看井的井名
|
|
|
|
|
nmDataWellBase* pCurWellData = pInstance->getCurWellData();
|
|
|
|
|
QString currentWellName;
|
|
|
|
|
|
|
|
|
|
if(pCurWellData != nullptr) {
|
|
|
|
|
currentWellName = pCurWellData->getWellName();
|
|
|
|
|
// 捕获的拟合窗口和数据管理器必须仍保持原来的映射关系。
|
|
|
|
|
if(nmDataAnalyzeManager::findManagerByFitting(pSubWndFit) != pInstance) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 判断当前井是否参与计算
|
|
|
|
|
if(!pInstance->isContainsWellName(currentWellName)) {
|
|
|
|
|
for(int i = 0; i < vecWellsOrder.size(); i++) {
|
|
|
|
|
// 跳过裂缝
|
|
|
|
|
if(vecWellsOrder[i].first == NM_WELL_MODEL::Unknow_Well) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
QVector<nmSolverWellRef> vecWellsOrder = pInstance->getSolverWellOrder();
|
|
|
|
|
QString sCurrentResultWellCode = pInstance->getCurrentResultWellCode();
|
|
|
|
|
|
|
|
|
|
// 未参与计算,选择展示第一口计算井的数据
|
|
|
|
|
currentWellName = vecWellsOrder[i].second;
|
|
|
|
|
// 当前结果井必须同时位于本次求解顺序并具备结果展示资格。
|
|
|
|
|
// 无流量观察井虽然有内部压力结果,但不能成为曲线窗口的当前结果井。
|
|
|
|
|
const bool bResultWellAvailable =
|
|
|
|
|
pInstance->isWellAvailableForResult(sCurrentResultWellCode);
|
|
|
|
|
bool bResultWellFound = false;
|
|
|
|
|
for(int nIndex = 0; nIndex < vecWellsOrder.size(); ++nIndex) {
|
|
|
|
|
const nmSolverWellRef& oWellRef = vecWellsOrder[nIndex];
|
|
|
|
|
if(oWellRef.m_eEntryKind != NM_SolverEntry_Well) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if(bResultWellAvailable &&
|
|
|
|
|
oWellRef.m_sWellCode == sCurrentResultWellCode) {
|
|
|
|
|
bResultWellFound = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PEBI结果按井名保存,直接读取当前井的三条结果曲线
|
|
|
|
|
if(!bResultWellFound) {
|
|
|
|
|
for(int nIndex = 0; nIndex < vecWellsOrder.size(); ++nIndex) {
|
|
|
|
|
if(vecWellsOrder[nIndex].m_eEntryKind == NM_SolverEntry_Well &&
|
|
|
|
|
pInstance->isWellAvailableForResult(
|
|
|
|
|
vecWellsOrder[nIndex].m_sWellCode)) {
|
|
|
|
|
sCurrentResultWellCode = vecWellsOrder[nIndex].m_sWellCode;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nmDataWellBase* pWellData = NULL;
|
|
|
|
|
if(pInstance->getGridType() == NM_Grid_PEBI) {
|
|
|
|
|
pWellData = pInstance->findWellByName(currentWellName);
|
|
|
|
|
pWellData = pInstance->findWellByCode(sCurrentResultWellCode);
|
|
|
|
|
if(pWellData == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 同步当前查看井,保证保存成果时记录的是当前显示的结果井。
|
|
|
|
|
pInstance->setCurWellData(pWellData);
|
|
|
|
|
pInstance->setCurrentResultWellCode(sCurrentResultWellCode);
|
|
|
|
|
// 获取该井下存储的三条数据
|
|
|
|
|
vvecHistoryData = pWellData->getResultPressure();
|
|
|
|
|
vvecLogPreData = pWellData->getResultLogLog();
|
|
|
|
|
vvecSemiLogPreData = pWellData->getResultSemiLog();
|
|
|
|
|
}
|
|
|
|
|
// 计算完成后同步查看井下拉框选中项
|
|
|
|
|
nmWxNumericalDesign::notifyResultWellSelectorChanged(currentWellName);
|
|
|
|
|
nmWxNumericalDesign::notifyResultWellSelectorChanged(
|
|
|
|
|
pInstance,
|
|
|
|
|
sCurrentResultWellCode);
|
|
|
|
|
|
|
|
|
|
// 半对数
|
|
|
|
|
QVector<iCurveDesc> vecHalfLog;
|
|
|
|
|
@ -1733,7 +1808,7 @@ void nmSubWndMain::mergeAnaResultToFitting()
|
|
|
|
|
nmWxPostprocessingAnimationWidget* vtkWidget = nullptr;
|
|
|
|
|
|
|
|
|
|
if(pInstance->getGridType() == NM_Grid_PEBI) {
|
|
|
|
|
vtkWidget = new nmWxPostprocessingAnimationWidget(NULL);
|
|
|
|
|
vtkWidget = new nmWxPostprocessingAnimationWidget(NULL, pInstance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(widget1 == nullptr || vtkWidget == nullptr) {
|
|
|
|
|
@ -1978,6 +2053,13 @@ bool nmSubWndMain::initPreHistory(QVector<QVector<double> > &vvecHistoryData, QV
|
|
|
|
|
|
|
|
|
|
bool nmSubWndMain::onConfirmClosing()
|
|
|
|
|
{
|
|
|
|
|
// 正常关闭入口在求解结束前保持当前成果和 DataManager 存活;应用退出等绕过
|
|
|
|
|
// 该确认流程的路径仍由析构函数 wait() 兜底。
|
|
|
|
|
if(m_pSolverTask != nullptr && m_pSolverTask->isRunning()) {
|
|
|
|
|
QMessageBox::information(this, tr("solver error"), tr("task is running!"));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return iSubWndBaseAF::onConfirmClosing();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -2059,21 +2141,34 @@ void nmSubWndMain::on_calculationFinished(NM_Calculation_Result result)
|
|
|
|
|
|
|
|
|
|
void nmSubWndMain::on_solverTaskFinished(bool isSuccessed)
|
|
|
|
|
{
|
|
|
|
|
// 线程完成后清空两个持有点:当前窗口指针和全局运行中指针。
|
|
|
|
|
// 第一步:只接受当前窗口实际启动的任务,忽略已经失效的旧回调。
|
|
|
|
|
nmCalculationDllPebiSolverTask* pTask = qobject_cast<nmCalculationDllPebiSolverTask*>(sender());
|
|
|
|
|
if(pTask == nullptr || pTask != m_pSolverTask) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nPebiCount = pTask != nullptr ? pTask->getPebiCount() : -1;
|
|
|
|
|
int nSolveTimeMs = pTask != nullptr ? pTask->getSolveTimeMs() : -1;
|
|
|
|
|
if(pTask == m_pSolverTask) {
|
|
|
|
|
m_pSolverTask = nullptr;
|
|
|
|
|
// 后台线程只生成局部结果快照。回到主线程后先验证所属 DataManager 和
|
|
|
|
|
// 输入版本,再整体替换旧成果;提交失败与求解失败使用同一条错误路径。
|
|
|
|
|
if(isSuccessed) {
|
|
|
|
|
isSuccessed = pTask->commitResult(m_pSolverDataManager.data());
|
|
|
|
|
}
|
|
|
|
|
m_pSolverTask = nullptr;
|
|
|
|
|
if(pTask == s_pRunningSolverTask) {
|
|
|
|
|
s_pRunningSolverTask = nullptr;
|
|
|
|
|
}
|
|
|
|
|
// 正常完成路径由主线程延迟释放任务;析构路径则会等待并直接释放。
|
|
|
|
|
pTask->deleteLater();
|
|
|
|
|
|
|
|
|
|
// 保持旧流程不变:bool结果转换为计算结果枚举,再交给原来的统一后处理函数。
|
|
|
|
|
// 第二步:在清空捕获上下文前完成结果合并,确保始终回写原拟合窗口。
|
|
|
|
|
NM_Calculation_Result result = isSuccessed ? NM_Calculation_Result_Success : NM_Calculation_Result_Fail;
|
|
|
|
|
this->on_calculationFinished(result);
|
|
|
|
|
|
|
|
|
|
// 第三步:结果处理结束后释放非拥有型上下文引用。
|
|
|
|
|
m_pSolverDataManager = nullptr;
|
|
|
|
|
m_pSolverFitting = nullptr;
|
|
|
|
|
|
|
|
|
|
if(isSuccessed && nPebiCount >= 0 && nSolveTimeMs >= 0) {
|
|
|
|
|
QMessageBox::information(this, tr("Solver completed"),
|
|
|
|
|
tr("Grid count: %1\nSolve time: %2 ms")
|
|
|
|
|
@ -2247,31 +2342,20 @@ void nmSubWndMain::onProgressUpdated(int progress)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmSubWndMain::onWellSelected(const QString& wellName)
|
|
|
|
|
void nmSubWndMain::onWellSelected(const QString& sWellCode)
|
|
|
|
|
{
|
|
|
|
|
nmDataAnalyzeManager* pInstance = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
|
if(pInstance == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新数据中心的当前查看井数据
|
|
|
|
|
nmDataWellBase* pCurWellData = pInstance->getCurWellData();
|
|
|
|
|
|
|
|
|
|
if(pCurWellData == nullptr)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// 查找切换后的井数据
|
|
|
|
|
|
|
|
|
|
nmDataWellBase* pWellData = NULL;
|
|
|
|
|
pWellData = pInstance->findWellByName(wellName);
|
|
|
|
|
nmDataWellBase* pWellData = pInstance->findWellByCode(sWellCode);
|
|
|
|
|
|
|
|
|
|
if(pWellData == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if(pCurWellData->getWellName() != wellName) {
|
|
|
|
|
// 设置为当前查看井数据
|
|
|
|
|
pInstance->setCurWellData(pWellData);
|
|
|
|
|
}
|
|
|
|
|
// 切换结果井只影响曲线展示,不再改变参数编辑井或主分析井。
|
|
|
|
|
pInstance->setCurrentResultWellCode(sWellCode);
|
|
|
|
|
|
|
|
|
|
// 1.获取流动段分析窗口
|
|
|
|
|
iSubWndFitting* pSubWndFit = nmDataAnalyzeManager::getCurrentFitting();
|
|
|
|
|
@ -2437,18 +2521,9 @@ void nmSubWndMain::onWellSelected(const QString& wellName)
|
|
|
|
|
|
|
|
|
|
void nmSubWndMain::onGenerateButtonClicked()
|
|
|
|
|
{
|
|
|
|
|
//QString sDir = ZxBaseUtil::getCurWellDirOf("Nm/PreProcessing");
|
|
|
|
|
|
|
|
|
|
if(nmDataAnalyzeManager::getCurrentInstance()->getGridType() == NM_Grid_PEBI) {
|
|
|
|
|
nmCalculationPebiGrid* pPebiGridGeneratorInstance = nmCalculationPebiGrid::getInstance();
|
|
|
|
|
if(pPebiGridGeneratorInstance->getGridOutput2().Trinodexy.size() <= 0) {
|
|
|
|
|
// 没有可用PEBI网格时才重新生成
|
|
|
|
|
if(!pPebiGridGeneratorInstance->meshGenPebi()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 求解计算
|
|
|
|
|
// 求解任务创建时会捕获完整输入。网格无效时,工作线程只基于值快照生成
|
|
|
|
|
// 一次局部网格,求解成功后再和全部结果一起回主线程提交。
|
|
|
|
|
this->solveAndAnalyze();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|