fix(nmData): 修复 PEBI 映射持久化与成果加载连锁失败

- 使用 Int32 持久化单元映射并兼容旧 vtkIdType 数组
- 发布成果前真实回读并校验 CurrentGrid
- 加载失败时保留原当前分析并清理空 DataManager
- 根据真实网格状态决定直接展示或重新建网
- 更新阶段 3A 开发清单
feature/nmNum-postprocessing-view-20260910
lh 7 hours ago
parent 34977e2b67
commit bb11b64542

@ -35,8 +35,9 @@ public:
/** /**
* @brief * @brief
* *
* ID * ID
* 使 AddArray() OriginalCellId Scalars * 使 Int32使 vtkIdType使
* AddArray() OriginalCellId Scalars
*/ */
static bool attach( static bool attach(
vtkUnstructuredGrid* pGrid, vtkUnstructuredGrid* pGrid,
@ -48,7 +49,8 @@ public:
* @brief * @brief
* *
* Missing * Missing
* Invalid Valid * Invalid Int32 vtkIdType
* Valid
*/ */
static MappingStatus read( static MappingStatus read(
vtkUnstructuredGrid* pGrid, vtkUnstructuredGrid* pGrid,

@ -3162,7 +3162,8 @@ void nmDataAnalyzeManager::updateAutomaticFittingData(const nmDataAutomaticFitti
void nmDataAnalyzeManager::initPvtParaFromSubFit() void nmDataAnalyzeManager::initPvtParaFromSubFit()
{ {
// 1. 获取上下文 // 1. 获取上下文
iSubWndFitting* pSubWndFitting = nmDataAnalyzeManager::getCurrentFitting(); // PVT 必须来自本 Manager 绑定的成果窗口,不能随全局当前页签切换数据源。
iSubWndFitting* pSubWndFitting = m_pOwnerFitting;
nmDataAnalyzeContextProvider* pCtx = nmDataAnalyzeContext::provider(); nmDataAnalyzeContextProvider* pCtx = nmDataAnalyzeContext::provider();
Q_ASSERT(nullptr != pSubWndFitting); Q_ASSERT(nullptr != pSubWndFitting);
Q_ASSERT(nullptr != pCtx); Q_ASSERT(nullptr != pCtx);
@ -6562,11 +6563,16 @@ bool nmDataAnalyzeManager::validateNmResultV3Window(
return false; return false;
} }
if(oReferences.m_bHasCurrentGrid && if(oReferences.m_bHasCurrentGrid) {
!nmNumericalResultPersistence::validateFileReference( QString sCurrentGridPath;
sWindowDirectory, oReferences.m_oCurrentGrid, vtkSmartPointer<vtkUnstructuredGrid> pValidatedCurrentGrid;
NULL, pError)) { if(!nmNumericalResultPersistence::validateFileReference(
return false; sWindowDirectory, oReferences.m_oCurrentGrid,
&sCurrentGridPath, pError) ||
!nmNumericalResultPersistence::readGrid(
sCurrentGridPath, pValidatedCurrentGrid, pError)) {
return false;
}
} }
QMap<QString, nmNumericalFileReference>::const_iterator oIt = QMap<QString, nmNumericalFileReference>::const_iterator oIt =

@ -6,7 +6,8 @@
#include <vtkCellData.h> #include <vtkCellData.h>
#include <vtkDataArray.h> #include <vtkDataArray.h>
#include <vtkFieldData.h> #include <vtkFieldData.h>
#include <vtkIdTypeArray.h> #include <vtkIntArray.h>
#include <vtkMath.h>
#include <vtkPointData.h> #include <vtkPointData.h>
#include <vtkSmartPointer.h> #include <vtkSmartPointer.h>
#include <vtkUnstructuredGrid.h> #include <vtkUnstructuredGrid.h>
@ -34,6 +35,36 @@ nmPebiCellMapping::MappingStatus failRead(
return nmPebiCellMapping::MappingStatus_Invalid; return nmPebiCellMapping::MappingStatus_Invalid;
} }
bool isSupportedMappingArray(vtkDataArray* pArray)
{
if(pArray == NULL) {
return false;
}
const int nDataType = pArray->GetDataType();
return nDataType == VTK_INT || nDataType == VTK_ID_TYPE;
}
bool readMappingValue(
vtkDataArray* pArray,
vtkIdType nTupleId,
vtkIdType* pValue)
{
if(pArray == NULL || pValue == NULL) {
return false;
}
const double dValue = pArray->GetComponent(nTupleId, 0);
if(!vtkMath::IsFinite(dValue) || dValue < 0.0 ||
dValue > static_cast<double>(INT_MAX)) {
return false;
}
const vtkIdType nValue = static_cast<vtkIdType>(dValue);
if(static_cast<double>(nValue) != dValue) {
return false;
}
*pValue = nValue;
return true;
}
bool validateMappingValues( bool validateMappingValues(
const QVector<vtkIdType>& vecVtkToOriginal, const QVector<vtkIdType>& vecVtkToOriginal,
vtkIdType nOriginalCellCount, vtkIdType nOriginalCellCount,
@ -135,8 +166,8 @@ bool nmPebiCellMapping::attach(
return false; return false;
} }
vtkSmartPointer<vtkIdTypeArray> pOriginalCellIds = vtkSmartPointer<vtkIntArray> pOriginalCellIds =
vtkSmartPointer<vtkIdTypeArray>::New(); vtkSmartPointer<vtkIntArray>::New();
pOriginalCellIds->SetName(originalCellIdArrayName()); pOriginalCellIds->SetName(originalCellIdArrayName());
pOriginalCellIds->SetNumberOfComponents(1); pOriginalCellIds->SetNumberOfComponents(1);
pOriginalCellIds->SetNumberOfTuples( pOriginalCellIds->SetNumberOfTuples(
@ -145,15 +176,15 @@ bool nmPebiCellMapping::attach(
nVtkCellId < vecVtkToOriginal.size(); ++nVtkCellId) { nVtkCellId < vecVtkToOriginal.size(); ++nVtkCellId) {
pOriginalCellIds->SetValue( pOriginalCellIds->SetValue(
static_cast<vtkIdType>(nVtkCellId), static_cast<vtkIdType>(nVtkCellId),
vecVtkToOriginal[nVtkCellId]); static_cast<int>(vecVtkToOriginal[nVtkCellId]));
} }
vtkSmartPointer<vtkIdTypeArray> pOriginalCellCount = vtkSmartPointer<vtkIntArray> pOriginalCellCount =
vtkSmartPointer<vtkIdTypeArray>::New(); vtkSmartPointer<vtkIntArray>::New();
pOriginalCellCount->SetName(originalCellCountArrayName()); pOriginalCellCount->SetName(originalCellCountArrayName());
pOriginalCellCount->SetNumberOfComponents(1); pOriginalCellCount->SetNumberOfComponents(1);
pOriginalCellCount->SetNumberOfTuples(1); pOriginalCellCount->SetNumberOfTuples(1);
pOriginalCellCount->SetValue(0, nOriginalCellCount); pOriginalCellCount->SetValue(0, static_cast<int>(nOriginalCellCount));
vtkDataArray* pPreviousScalars = pCellData->GetScalars(); vtkDataArray* pPreviousScalars = pCellData->GetScalars();
if(pCellData->AddArray(pOriginalCellIds) < 0) { if(pCellData->AddArray(pOriginalCellIds) < 0) {
@ -236,13 +267,14 @@ nmPebiCellMapping::MappingStatus nmPebiCellMapping::read(
"PEBI grid contains an incomplete cell mapping."); "PEBI grid contains an incomplete cell mapping.");
} }
vtkIdTypeArray* pOriginalCellIds = vtkDataArray* pOriginalCellIds =
vtkIdTypeArray::SafeDownCast(pOriginalCellIdsAbstract); vtkDataArray::SafeDownCast(pOriginalCellIdsAbstract);
vtkIdTypeArray* pOriginalCellCount = vtkDataArray* pOriginalCellCount =
vtkIdTypeArray::SafeDownCast(pOriginalCellCountAbstract); vtkDataArray::SafeDownCast(pOriginalCellCountAbstract);
if(pOriginalCellIds == NULL || pOriginalCellCount == NULL) { if(!isSupportedMappingArray(pOriginalCellIds) ||
!isSupportedMappingArray(pOriginalCellCount)) {
return failRead(pError, return failRead(pError,
"PEBI cell mapping arrays have invalid types."); "PEBI cell mapping arrays must use Int32 or vtkIdType integers.");
} }
const vtkIdType nVtkCellCount = pGrid->GetNumberOfCells(); const vtkIdType nVtkCellCount = pGrid->GetNumberOfCells();
@ -259,13 +291,23 @@ nmPebiCellMapping::MappingStatus nmPebiCellMapping::read(
"PEBI original cell IDs must not be active scalars."); "PEBI original cell IDs must not be active scalars.");
} }
const vtkIdType nOriginalCellCount = pOriginalCellCount->GetValue(0); vtkIdType nOriginalCellCount = 0;
if(!readMappingValue(pOriginalCellCount, 0, &nOriginalCellCount) ||
nOriginalCellCount <= 0) {
return failRead(pError,
"PEBI original cell count is not a valid positive integer.");
}
QVector<vtkIdType> vecVtkToOriginal( QVector<vtkIdType> vecVtkToOriginal(
static_cast<int>(nVtkCellCount)); static_cast<int>(nVtkCellCount));
for(vtkIdType nVtkCellId = 0; for(vtkIdType nVtkCellId = 0;
nVtkCellId < nVtkCellCount; ++nVtkCellId) { nVtkCellId < nVtkCellCount; ++nVtkCellId) {
vecVtkToOriginal[static_cast<int>(nVtkCellId)] = vtkIdType nOriginalCellId = 0;
pOriginalCellIds->GetValue(nVtkCellId); if(!readMappingValue(
pOriginalCellIds, nVtkCellId, &nOriginalCellId)) {
return failRead(pError,
"PEBI mapping contains a non-integer or out-of-range ID.");
}
vecVtkToOriginal[static_cast<int>(nVtkCellId)] = nOriginalCellId;
} }
QVector<vtkIdType> vecOriginalToVtk; QVector<vtkIdType> vecOriginalToVtk;

@ -210,32 +210,26 @@ iSubWnd* nmSubWndUtils::makesureSubWnd(QString sID, QString sExt, \
} else if(nID == 5114) { } else if(nID == 5114) {
// PEBI GridControl控制参数对应HX_NWTM_GRID_INPUT::GridControl // PEBI GridControl控制参数对应HX_NWTM_GRID_INPUT::GridControl
double dPebiGridControl = 150.0; double dPebiGridControl = 150.0;
bool bGeneratePebiGrid = true; nmDataAnalyzeManager* pDataManager =
nmDataAnalyzeManager::getCurrentInstance();
if(pDataManager == nullptr) {
return NULL;
}
// 判断是否是加载进来的数据,如果不是加载进来的,则需要添加设置网格信息的对话框 // 是否需要建网只由当前输入版本的真实网格状态决定,不能依赖一次性加载标志。
if(!nmDataAnalyzeManager::getCurrentInstance()->m_bIsLoadData) { const bool bGeneratePebiGrid = !pDataManager->isPebiGridValid();
// 当前只保留PEBI网格弹窗只需要设置GridControl if(bGeneratePebiGrid) {
// 当前只保留 PEBI 网格,缺少有效网格时设置 GridControl 后正常建网。
nmWxGridDlg dlg(&dPebiGridControl); nmWxGridDlg dlg(&dPebiGridControl);
if(dlg.exec() == QDialog::Rejected) { if(dlg.exec() == QDialog::Rejected) {
return NULL; return nullptr;
} }
} else { } else {
// 更新标志
nmDataAnalyzeManager::getCurrentInstance()->m_bIsLoadData = false;
bGeneratePebiGrid = false;
}
// 创建PEBI网格窗口新建数据时生成网格加载数据时直接展示已加载结果。
nmDataAnalyzeManager* pDataManager =
nmDataAnalyzeManager::getCurrentInstance();
if(pDataManager == nullptr) {
return NULL;
}
if(!bGeneratePebiGrid) {
dPebiGridControl = pDataManager->getPebiGridControl(); dPebiGridControl = pDataManager->getPebiGridControl();
} }
// 创建 PEBI 网格窗口;已有有效网格时直接展示,否则按正常流程生成。
nmSubWndGrid* pSubWndGrid = new nmSubWndGrid( nmSubWndGrid* pSubWndGrid = new nmSubWndGrid(
NULL, sExt, dPebiGridControl, bGeneratePebiGrid, pDataManager); NULL, sExt, dPebiGridControl, bGeneratePebiGrid, pDataManager);
pSubWnd = pSubWndGrid; pSubWnd = pSubWndGrid;
@ -1024,26 +1018,36 @@ bool nmSubWndUtils::loadRsts(iSubWnd* pSubWnd, \
return true; return true;
} }
// 存在,说明保存了数值解的参数,需要解析文件里的数据到数据中心 // 先查询再按需创建,失败时只释放本次加载产生的空 Manager。
// 动态创建数据中心类 iSubWndFitting* pPreviousCurrentFitting =
nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::getInstanceByFitting(pSubWndF); nmDataAnalyzeManager::getCurrentFitting();
nmDataAnalyzeManager* pDataManager =
nmDataAnalyzeManager::findManagerByFitting(pSubWndF);
const bool bCreatedDataManager = pDataManager == nullptr;
if(bCreatedDataManager) {
pDataManager =
nmDataAnalyzeManager::getInstanceByFitting(pSubWndF);
}
if(pDataManager == nullptr) { if(pDataManager == nullptr) {
return false; return false;
} }
// 监听外层成果窗口切换,保证重新激活已经打开过的成果时可以同步数据中心。 // Manager 内部继续使用候选对象事务加载;这里在成功前不切换全局当前分析。
pUtilsInstance->connectMdiActivation(pSubWndF);
// 设置当前操作的是哪一个分析
nmDataAnalyzeManager::setCurrentFitting(pSubWndF);
// v3 在候选 Manager 中读取 PVT 和全部成果,成功后才替换当前状态。
if(!pDataManager->loadNmResult(sDir)) { if(!pDataManager->loadNmResult(sDir)) {
if(bCreatedDataManager) {
nmDataAnalyzeManager::removeInstanceByFitting(pSubWndF);
}
nmDataAnalyzeManager::setCurrentFitting(
pPreviousCurrentFitting);
QMessageBox::warning(nullptr, QMessageBox::warning(nullptr,
tr("Numerical Result Load Failed"), tr("Numerical Result Load Failed"),
tr("The numerical result is incomplete or inconsistent and could not be loaded.")); tr("The numerical result is incomplete or inconsistent and could not be loaded."));
return false; return false;
} }
// 只有成果完整加载后,才允许该窗口接管激活通知和全局当前数据源。
pUtilsInstance->connectMdiActivation(pSubWndF);
nmDataAnalyzeManager::setCurrentFitting(pSubWndF);
// 注册井参数到 nmAttrRegistry必须在 loadNmResult 之后,面板构建之前) // 注册井参数到 nmAttrRegistry必须在 loadNmResult 之后,面板构建之前)
pDataManager->syncWellAttrs(); pDataManager->syncWellAttrs();

Loading…
Cancel
Save