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

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

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

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

@ -6,7 +6,8 @@
#include <vtkCellData.h>
#include <vtkDataArray.h>
#include <vtkFieldData.h>
#include <vtkIdTypeArray.h>
#include <vtkIntArray.h>
#include <vtkMath.h>
#include <vtkPointData.h>
#include <vtkSmartPointer.h>
#include <vtkUnstructuredGrid.h>
@ -34,6 +35,36 @@ nmPebiCellMapping::MappingStatus failRead(
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(
const QVector<vtkIdType>& vecVtkToOriginal,
vtkIdType nOriginalCellCount,
@ -135,8 +166,8 @@ bool nmPebiCellMapping::attach(
return false;
}
vtkSmartPointer<vtkIdTypeArray> pOriginalCellIds =
vtkSmartPointer<vtkIdTypeArray>::New();
vtkSmartPointer<vtkIntArray> pOriginalCellIds =
vtkSmartPointer<vtkIntArray>::New();
pOriginalCellIds->SetName(originalCellIdArrayName());
pOriginalCellIds->SetNumberOfComponents(1);
pOriginalCellIds->SetNumberOfTuples(
@ -145,15 +176,15 @@ bool nmPebiCellMapping::attach(
nVtkCellId < vecVtkToOriginal.size(); ++nVtkCellId) {
pOriginalCellIds->SetValue(
static_cast<vtkIdType>(nVtkCellId),
vecVtkToOriginal[nVtkCellId]);
static_cast<int>(vecVtkToOriginal[nVtkCellId]));
}
vtkSmartPointer<vtkIdTypeArray> pOriginalCellCount =
vtkSmartPointer<vtkIdTypeArray>::New();
vtkSmartPointer<vtkIntArray> pOriginalCellCount =
vtkSmartPointer<vtkIntArray>::New();
pOriginalCellCount->SetName(originalCellCountArrayName());
pOriginalCellCount->SetNumberOfComponents(1);
pOriginalCellCount->SetNumberOfTuples(1);
pOriginalCellCount->SetValue(0, nOriginalCellCount);
pOriginalCellCount->SetValue(0, static_cast<int>(nOriginalCellCount));
vtkDataArray* pPreviousScalars = pCellData->GetScalars();
if(pCellData->AddArray(pOriginalCellIds) < 0) {
@ -236,13 +267,14 @@ nmPebiCellMapping::MappingStatus nmPebiCellMapping::read(
"PEBI grid contains an incomplete cell mapping.");
}
vtkIdTypeArray* pOriginalCellIds =
vtkIdTypeArray::SafeDownCast(pOriginalCellIdsAbstract);
vtkIdTypeArray* pOriginalCellCount =
vtkIdTypeArray::SafeDownCast(pOriginalCellCountAbstract);
if(pOriginalCellIds == NULL || pOriginalCellCount == NULL) {
vtkDataArray* pOriginalCellIds =
vtkDataArray::SafeDownCast(pOriginalCellIdsAbstract);
vtkDataArray* pOriginalCellCount =
vtkDataArray::SafeDownCast(pOriginalCellCountAbstract);
if(!isSupportedMappingArray(pOriginalCellIds) ||
!isSupportedMappingArray(pOriginalCellCount)) {
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();
@ -259,13 +291,23 @@ nmPebiCellMapping::MappingStatus nmPebiCellMapping::read(
"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(
static_cast<int>(nVtkCellCount));
for(vtkIdType nVtkCellId = 0;
nVtkCellId < nVtkCellCount; ++nVtkCellId) {
vecVtkToOriginal[static_cast<int>(nVtkCellId)] =
pOriginalCellIds->GetValue(nVtkCellId);
vtkIdType nOriginalCellId = 0;
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;

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

Loading…
Cancel
Save