feat(nmCalculation): 补充数值求解失败原因提示

- 记录输入捕获、网格生成、DLL 调用及结果处理等失败原因
- 将任务侧失败原因传递至求解完成提示
- 区分求解失败、用户取消和输入变化导致的结果丢弃
- 补充中文翻译并更新语言包
feature/nmNum-multi-gauge-record
lh 2 days ago
parent 755ed34b17
commit 45ee68645b

Binary file not shown.

@ -2846,10 +2846,8 @@ Reason: %1</source>
<source>The solver currently supports oil, gas, and water single-phase models and the oil-water two-phase model only.</source>
<translation></translation>
</message>
<message>
<source>solver failed!</source>
<translation></translation>
</message>
<message><source>Solver failed</source><translation></translation></message>
<message><source>No specific failure reason is available.</source><translation></translation></message>
<message>
<source>Progress:</source>
<translation>:</translation>
@ -5230,6 +5228,10 @@ Please check your input coordinates.</source>
<message><source>Segment %1</source><translation> %1 </translation></message>
<message><source>No eligible wells</source><translation></translation></message>
<message><source>Select at least one production record first.</source><translation></translation></message>
<message>
<source>Help</source>
<translation></translation>
</message>
<message>
<source>OK</source>
<translation></translation>
@ -7145,6 +7147,43 @@ Average pressure in contour: %2 MPa</source>
<source>Capturing solver settings...</source>
<translation>...</translation>
</message>
<message><source>Insufficient memory to prepare solver input.</source><translation></translation></message>
<message><source>Insufficient memory to process solver results.</source><translation></translation></message>
<message><source>Solver input is unavailable.</source><translation></translation></message>
<message><source>Failed to capture solver input.</source><translation></translation></message>
<message><source>The well configuration is invalid.</source><translation></translation></message>
<message><source>No valid wells are available for solving.</source><translation></translation></message>
<message><source>Failed to capture well data.</source><translation></translation></message>
<message><source>Failed to finalize solver input.</source><translation></translation></message>
<message><source>Failed to capture solver settings.</source><translation></translation></message>
<message><source>The target well is unavailable.</source><translation></translation></message>
<message><source>Solver input snapshot is invalid.</source><translation></translation></message>
<message><source>Failed to prepare solver input.</source><translation></translation></message>
<message><source>The prepared result grid is invalid.</source><translation></translation></message>
<message><source>Grid generation failed.</source><translation></translation></message>
<message><source>The generated grid is invalid.</source><translation></translation></message>
<message><source>Property interpolation failed.</source><translation></translation></message>
<message><source>Failed to load HX_NWTM.dll.</source><translation> HX_NWTM.dll</translation></message>
<message><source>The solver interface is incomplete.</source><translation></translation></message>
<message><source>An exception occurred while calling the solver.</source><translation></translation></message>
<message><source>The solver result data is invalid.</source><translation></translation></message>
<message><source>Failed to load the gas pseudo-pressure converter.</source><translation></translation></message>
<message><source>The solver returned incomplete result data.</source><translation></translation></message>
<message><source>The solver returned invalid time data.</source><translation></translation></message>
<message><source>The solver returned incomplete well pressure data.</source><translation></translation></message>
<message><source>The solver returned invalid well pressure data.</source><translation></translation></message>
<message><source>Failed to convert gas pressure to pseudo-pressure.</source><translation></translation></message>
<message><source>The pressure curve interface is incomplete.</source><translation>线</translation></message>
<message><source>Failed to calculate pressure curves.</source><translation>线</translation></message>
<message><source>Failed to load singlePhaseSolverDll.dll.</source><translation> singlePhaseSolverDll.dll</translation></message>
<message><source>The calculated pressure curves are invalid.</source><translation>线</translation></message>
<message><source>The solver returned incomplete field pressure data.</source><translation></translation></message>
<message><source>The solver returned invalid field pressure data.</source><translation></translation></message>
<message><source>Failed to build the result snapshot.</source><translation></translation></message>
<message><source>Insufficient memory to build the result snapshot.</source><translation></translation></message>
<message><source>Failed to commit the solver results.</source><translation></translation></message>
<message><source>Failed to commit the generated grid.</source><translation></translation></message>
<message><source>The generated grid is no longer valid.</source><translation></translation></message>
</context>
<context>
<name>nmParameterField</name>

@ -49,6 +49,8 @@ class NMCALCULATION_EXPORT nmCalculationDllPebiSolverTask : public QThread {
int getSolveTimeMs() const;
/** @brief 获取本次求解的PEBI网格数量。 */
int getPebiCount() const;
/** @brief 返回当前代码已识别的失败原因;成功或主动停止时为空。 */
QString getFailureReason() const;
/** @brief 请求协作式停止DLL 正在执行时会在返回后丢弃结果。 */
void requestCancel();
/** @brief 返回本次任务是否因手工停止而结束。 */
@ -91,6 +93,8 @@ class NMCALCULATION_EXPORT nmCalculationDllPebiSolverTask : public QThread {
bool isCancelRequested() const;
/** @brief 仅为手工求解报告真实执行阶段。 */
void reportStage(const QString& sStage, int nCurrent, int nTotal);
/** @brief 记录首个已识别的失败原因并统一返回 false。 */
bool fail(const QString& sFailureReason);
/** @brief 构造 DLL 输入、执行求解并生成仍然有效的局部结果快照。 */
bool execPebiMode();
@ -134,6 +138,7 @@ class NMCALCULATION_EXPORT nmCalculationDllPebiSolverTask : public QThread {
int m_nSolveTimeMs;
/** @brief 本次求解的PEBI网格数量。 */
int m_nPebiCount;
QString m_sFailureReason; ///< 当前代码已识别的首个失败原因。
QString m_sAutoFitTargetWellCode; ///< 自动拟合目标井 WellCode空值表示保存完整结果。
QVector<QVector<double> > m_autoFitResultPressure; ///< 目标井原始压力结果。
QVector<QVector<double> > m_autoFitResultLogLog; ///< 目标井双对数结果。

@ -137,7 +137,8 @@ class NM_SUB_WND_EXPORT nmSubWndMain : public iSubWndBaseFit {
virtual bool slotSaveAll();
// 求解完成
bool on_calculationFinished(NM_Calculation_Result);
bool on_calculationFinished(NM_Calculation_Result,
const QString& sFailureReason);
// DLL线程只返回成功/失败,这里转换回原来的计算结果处理流程。
void on_solverTaskFinished(bool isSuccessed);
/** @brief 完成回调退出后隐藏求解进度框。 */
@ -254,7 +255,8 @@ class NM_SUB_WND_EXPORT nmSubWndMain : public iSubWndBaseFit {
void scheduleSolverResultCompletion(bool bSucceeded,
int nPebiCount,
int nSolveTimeMs,
bool bInputChanged = false);
bool bInputChanged,
const QString& sFailureReason);
// 半对数曲线数据
bool inithalfLog(QVector<QVector<double >> & vvecLogPreData, QVector<iCurveDesc>& vecDescs,bool isPreLoadData);
// 双对数曲线数据
@ -309,6 +311,7 @@ private:
bool m_bSolverResultCompletionPending; ///< 等待进度框隐藏后处理求解结果。
bool m_bPendingSolverSucceeded; ///< 待处理求解结果是否成功。
bool m_bPendingSolverInputChanged; ///< 输入变化导致本次旧结果被丢弃。
QString m_sPendingSolverFailureReason; ///< 当前代码已识别的待显示失败原因。
int m_nPendingSolverPebiCount; ///< 待显示的网格数量。
int m_nPendingSolverTimeMs; ///< 待显示的求解耗时。
bool m_bSolverStartPending; ///< 进度框已显示,输入正分批捕获或任务等待启动。

@ -651,6 +651,7 @@ nmCalculationDllPebiSolverTask::nmCalculationDllPebiSolverTask(
} catch(const std::bad_alloc&) {
// 构造阶段内存不足时保留旧成果,任务保持无效并由既有完成流程报错。
qWarning() << "Cannot allocate PEBI solver input snapshot.";
fail(tr("Insufficient memory to prepare solver input."));
delete m_pManualCaptureState;
m_pManualCaptureState = nullptr;
delete m_pInputSnapshot;
@ -683,6 +684,7 @@ void nmCalculationDllPebiSolverTask::run()
} catch(const std::bad_alloc&) {
// VTK 部分分配接口没有返回值,统一在任务边界拒绝候选并保留旧快照。
qWarning() << "Cannot allocate PEBI solver result snapshot.";
fail(tr("Insufficient memory to process solver results."));
discardPendingFullResult();
bSucceeded = false;
}
@ -732,7 +734,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep(
if(m_pManualCaptureState == nullptr || m_pInputSnapshot == nullptr ||
m_pDataManager == nullptr || isRunning() ||
QThread::currentThread() != m_pDataManager->thread()) {
return false;
return fail(tr("Solver input is unavailable."));
}
if(isCancelRequested()) {
m_nWasCancelled.fetchAndStoreOrdered(1);
@ -745,7 +747,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep(
nmDataNumericalAnalysisCase* pAnalysisCase =
m_pDataManager->getNumericalAnalysisCase();
if(pGridService == nullptr || pAnalysisCase == nullptr) {
return false;
return fail(tr("Solver input is unavailable."));
}
if(pState->m_ePhase !=
@ -764,7 +766,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep(
if(!pGridService->beginManualInputSnapshot(
m_pDataManager, m_pInputSnapshot->m_oGridInput)) {
return false;
return fail(tr("Failed to capture solver input."));
}
const QVector<nmCalculationWellRef> vecEffectiveWells =
@ -774,7 +776,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep(
if(oWellRef.m_sWellCode.isEmpty() ||
pState->m_setEffectiveWellCodes.contains(
oWellRef.m_sWellCode)) {
return false;
return fail(tr("The well configuration is invalid."));
}
pState->m_setEffectiveWellCodes.insert(oWellRef.m_sWellCode);
pState->m_mapWellModes.insert(
@ -782,7 +784,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep(
static_cast<int>(oWellRef.m_eMode));
}
if(pState->m_setEffectiveWellCodes.isEmpty()) {
return false;
return fail(tr("No valid wells are available for solving."));
}
QSet<QString> setOrderedWellCodes;
@ -829,7 +831,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep(
if(setOrderedWellCodes != pState->m_setEffectiveWellCodes ||
pState->m_vecOrderedWells.size() !=
pState->m_setEffectiveWellCodes.size()) {
return false;
return fail(tr("The well configuration is invalid."));
}
pState->m_ePhase = nmPebiManualCaptureState::CapturePhase_Wells;
@ -856,7 +858,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep(
pWellData,
pState->m_mapWellModes.value(pWellData->getWellCode()),
m_pInputSnapshot->m_oGridInput)) {
return false;
return fail(tr("Failed to capture well data."));
}
if(m_pInputSnapshot->m_oGridInput.m_vecWellInputs.isEmpty() ||
!captureResultWellMetadata(
@ -864,7 +866,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep(
isDisplayResultWell(pAnalysisCase,
pWellData->getWellCode()),
m_pInputSnapshot->m_oGridInput.m_vecWellInputs.last())) {
return false;
return fail(tr("Failed to capture well data."));
}
++pState->m_nNextWellIndex;
}
@ -887,7 +889,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep(
m_pDataManager,
pState->m_setEffectiveWellCodes,
m_pInputSnapshot->m_oGridInput)) {
return false;
return fail(tr("Failed to finalize solver input."));
}
pState->m_ePhase =
nmPebiManualCaptureState::CapturePhase_SolverSettings;
@ -907,7 +909,7 @@ bool nmCalculationDllPebiSolverTask::captureManualInputStep(
m_pDataManager->getPebiIluReuseSteps();
if(!captureResultParameters(m_pDataManager,
*m_pInputSnapshot)) {
return false;
return fail(tr("Failed to capture solver settings."));
}
pState->m_ePhase =
nmPebiManualCaptureState::CapturePhase_GridCache;
@ -953,6 +955,14 @@ void nmCalculationDllPebiSolverTask::reportStage(
}
}
bool nmCalculationDllPebiSolverTask::fail(const QString& sFailureReason)
{
if(!isCancelRequested() && m_sFailureReason.isEmpty()) {
m_sFailureReason = sFailureReason;
}
return false;
}
void nmCalculationDllPebiSolverTask::releaseDataManagerUse()
{
if(m_bManagerUseActive && m_pDataManager != nullptr) {
@ -967,13 +977,13 @@ bool nmCalculationDllPebiSolverTask::captureInputSnapshot(
if(m_pDataManager == nullptr || m_pInputSnapshot == nullptr ||
QThread::currentThread() != m_pDataManager->thread()) {
qWarning() << "PEBI solver input must be captured on the DataManager thread.";
return false;
return fail(tr("Solver input is unavailable."));
}
nmDataNumericalAnalysisCase* pAnalysisCase =
m_pDataManager->getNumericalAnalysisCase();
if(pAnalysisCase == nullptr) {
return false;
return fail(tr("Solver input is unavailable."));
}
// 第一步:冻结几何和求解输入版本。提交阶段会再次核对,期间发生任何编辑
@ -992,7 +1002,7 @@ bool nmCalculationDllPebiSolverTask::captureInputSnapshot(
if(pTargetWell == nullptr || pTargetWell->getWellCode().isEmpty()) {
qWarning() << "Auto-fit target well is unavailable:"
<< sAutoFitTargetWellName;
return false;
return fail(tr("The target well is unavailable."));
}
m_sAutoFitTargetWellCode = pTargetWell->getWellCode();
} else {
@ -1010,14 +1020,14 @@ bool nmCalculationDllPebiSolverTask::captureInputSnapshot(
!m_pInputSnapshot->m_bAutoFitTargetOnly) ||
m_pInputSnapshot->m_oGridInput.m_nGridInputRevision !=
m_nGridInputRevision) {
return false;
return fail(tr("Failed to capture solver input."));
}
const QVector<nmSolverWellRef>& vecWellOrder =
m_pInputSnapshot->m_oGridInput.m_vecSolverWellOrder;
if(m_pInputSnapshot->m_oGridInput.m_vecWellInputs.size() !=
vecWellOrder.size()) {
return false;
return fail(tr("Failed to capture well data."));
}
// 自动拟合候选保持原来的轻量输入;只有最终完整场求解冻结正式结果元数据。
@ -1044,7 +1054,7 @@ bool nmCalculationDllPebiSolverTask::captureInputSnapshot(
isDisplayResultWell(pAnalysisCase,
oWellRef.m_sWellCode),
m_pInputSnapshot->m_oGridInput.m_vecWellInputs[nIndex])) {
return false;
return fail(tr("Failed to capture well data."));
}
}
}
@ -1061,7 +1071,7 @@ bool nmCalculationDllPebiSolverTask::captureInputSnapshot(
m_pDataManager->getPebiIluReuseSteps();
if(!m_pInputSnapshot->m_bAutoFitTargetOnly &&
!captureResultParameters(m_pDataManager, *m_pInputSnapshot)) {
return false;
return fail(tr("Failed to capture solver settings."));
}
// 第四步:主线程仅检查缓存并捕获基础网格的智能指针。生成后的基础网格
@ -1106,8 +1116,10 @@ bool nmCalculationDllPebiSolverTask::captureInputSnapshot(
bool nmCalculationDllPebiSolverTask::prepareManualInput()
{
if(m_pInputSnapshot == nullptr ||
m_pInputSnapshot->m_bAutoFitTargetOnly) {
if(m_pInputSnapshot == nullptr) {
return fail(tr("Solver input snapshot is invalid."));
}
if(m_pInputSnapshot->m_bAutoFitTargetOnly) {
return true;
}
@ -1119,7 +1131,9 @@ bool nmCalculationDllPebiSolverTask::prepareManualInput()
m_pInputSnapshot->m_oGridInput,
&m_nCancelRequested) ||
isCancelRequested()) {
return false;
return isCancelRequested()
? false
: fail(tr("Failed to prepare solver input."));
}
reportStage(tr("Checking grid cache..."), 0, 0);
@ -1149,7 +1163,7 @@ bool nmCalculationDllPebiSolverTask::prepareManualInput()
return false;
}
if(m_pInputSnapshot->m_pBaseGrid->GetNumberOfCells() <= 0) {
return false;
return fail(tr("The prepared result grid is invalid."));
}
} else if(isCancelRequested()) {
return false;
@ -1177,6 +1191,11 @@ int nmCalculationDllPebiSolverTask::getPebiCount() const
return m_nPebiCount;
}
QString nmCalculationDllPebiSolverTask::getFailureReason() const
{
return m_sFailureReason;
}
QVector<QVector<double> > nmCalculationDllPebiSolverTask::getAutoFitResultPressure() const
{
return m_autoFitResultPressure;
@ -1205,7 +1224,9 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
{
if(!m_bInputSnapshotValid || m_pInputSnapshot == nullptr ||
isCancelRequested()) {
return false;
return isCancelRequested()
? false
: fail(tr("Solver input snapshot is invalid."));
}
const QAtomicInt* pCancelRequested =
@ -1229,12 +1250,17 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
const bool bCreateUnstructuredGrid =
!m_pInputSnapshot->m_bAutoFitTargetOnly;
reportStage(tr("Generating grid..."), 0, 0);
if(!nmCalculationPebiGrid::getInstance()->calculateSnapshot(
nmCalculationPebiGrid* pGridService =
nmCalculationPebiGrid::getInstance();
if(pGridService == nullptr ||
!pGridService->calculateSnapshot(
m_pInputSnapshot->m_oGridInput,
oGridResult,
bCreateUnstructuredGrid,
pCancelRequested)) {
return false;
return isCancelRequested()
? false
: fail(tr("Grid generation failed."));
}
if(isCancelRequested()) {
@ -1244,7 +1270,7 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
if(bCreateUnstructuredGrid) {
if(oGridResult.m_pUnstructuredGrid == nullptr ||
oGridResult.m_pUnstructuredGrid->GetNumberOfCells() <= 0) {
return false;
return fail(tr("The generated grid is invalid."));
}
m_pInputSnapshot->m_pBaseGrid =
@ -1262,7 +1288,9 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
if(!oGridResult.m_bSucceeded ||
oGridResult.m_oGridOutput1.PEBI_cell.p.empty() ||
isCancelRequested()) {
return false;
return isCancelRequested()
? false
: fail(tr("The generated grid is invalid."));
}
// 第三步:由场景值快照重建完整模型输入。属性插值可以耗时,但它只读取任务
@ -1283,7 +1311,7 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
.arg(sInterpolationError);
qWarning() << sLogMessage;
zxLogInstance::getInstance()->writeLogF(sLogMessage);
return false;
return fail(tr("Property interpolation failed."));
}
if(isCancelRequested()) {
@ -1301,7 +1329,7 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
if(hModelModule == nullptr) {
qWarning() << "Failed to load HX_NWTM.dll. Error code:"
<< GetLastError();
return false;
return fail(tr("Failed to load HX_NWTM.dll."));
}
typedef void (*HX_NWTM_MODEL_Fun)(
@ -1332,7 +1360,7 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
pfnGetSolveTime == nullptr) {
qWarning() << "Failed to resolve PEBI solver configuration interface.";
FreeLibrary(hModelModule);
return false;
return fail(tr("The solver interface is incomplete."));
}
HX_NWTM_MODEL_OUTPUT oModelOutput;
@ -1356,12 +1384,12 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
.arg(e.what());
logHX_NWTM_MODEL_INPUT_Simplified(oModelInput);
FreeLibrary(hModelModule);
return false;
return fail(tr("An exception occurred while calling the solver."));
} catch(...) {
qWarning() << "SEH Exception Occurred during HX_NWTM_MODEL call";
logHX_NWTM_MODEL_INPUT_Simplified(oModelInput);
FreeLibrary(hModelModule);
return false;
return fail(tr("An exception occurred while calling the solver."));
}
// 后处理只读取本次局部输出,无需继续占用进程级 DLL 锁。
@ -1378,6 +1406,9 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
oModelOutput,
oModelInput.T,
oGridResult.m_oGridOutput1);
if(!bSucceeded && !isCancelRequested() && m_sFailureReason.isEmpty()) {
fail(tr("The solver result data is invalid."));
}
return bSucceeded;
}
@ -1408,7 +1439,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
const HX_NWTM_GRID_OUTPUT1& oGridOutput)
{
if(m_pInputSnapshot == nullptr) {
return false;
return fail(tr("The solver result data is invalid."));
}
const bool autoFitTargetOnly =
@ -1430,7 +1461,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
if(usePseudoPressure && calPseudoPressure == nullptr) {
qWarning() << "Failed to load the gas pseudo-pressure converter.";
return false;
return fail(tr("Failed to load the gas pseudo-pressure converter."));
}
// 井顺序与后处理输入都来自任务启动时的同一份快照。
@ -1444,7 +1475,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
if(vecWellsOrder.isEmpty() ||
vecWellInputs.size() != vecWellsOrder.size() ||
p1.t.empty()) {
return false;
return fail(tr("The solver returned incomplete result data."));
}
for(size_t nTimeIndex = 0; nTimeIndex < p1.t.size(); ++nTimeIndex) {
if((nTimeIndex % 256) == 0 && isCancelRequested()) {
@ -1453,7 +1484,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
if(!isFiniteSolverNumber(p1.t[nTimeIndex])) {
qWarning() << "PEBI returned a non-finite time at index:"
<< static_cast<int>(nTimeIndex);
return false;
return fail(tr("The solver returned invalid time data."));
}
}
for(int nIndex = 0; nIndex < vecWellsOrder.size(); ++nIndex) {
@ -1471,7 +1502,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
vecWellInputs[nIndex].m_sWellCode != oWellRef.m_sWellCode) {
qWarning() << "Incomplete well pressure returned for WellCode:"
<< oWellRef.m_sWellCode;
return false;
return fail(tr("The solver returned incomplete well pressure data."));
}
for(size_t nTimeIndex = 0;
nTimeIndex < p1.pw[nIndex].size();
@ -1483,7 +1514,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
qWarning() << "PEBI returned a non-finite pressure for WellCode:"
<< oWellRef.m_sWellCode
<< "time index:" << static_cast<int>(nTimeIndex);
return false;
return fail(tr("The solver returned invalid well pressure data."));
}
}
}
@ -1573,7 +1604,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
qWarning() << "Failed to convert gas pressure to pseudo-pressure:"
<< p1.pw[wellIdx][i]
<< "well code:" << oWellRef.m_sWellCode;
return false;
return fail(tr("Failed to convert gas pressure to pseudo-pressure."));
}
pt.y = pressureForLog;
@ -1619,7 +1650,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
if(nullptr == preLogFun) {
FreeLibrary(hMod_solver);
std::cout << "preLogFun failed!\n";
return false;
return fail(tr("The pressure curve interface is incomplete."));
}
// 气井传入拟压力序列, 油井和水井仍传入原始压力序列.
@ -1631,7 +1662,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
nTimeNumQ,
logPreResultFromDll)) {
FreeLibrary(hMod_solver);
return false;
return fail(tr("Failed to calculate pressure curves."));
}
if(isCancelRequested()) {
@ -1694,7 +1725,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
FreeLibrary(hMod_solver);
} else {
qWarning() << "Failed to load singlePhaseSolverDll.dll.";
return false;
return fail(tr("Failed to load singlePhaseSolverDll.dll."));
}
}
@ -1730,13 +1761,15 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
&& !m_autoFitResultLogLog[0].isEmpty()
&& m_autoFitResultLogLog[0].size() == m_autoFitResultLogLog[1].size()
&& m_autoFitResultLogLog[0].size() == m_autoFitResultLogLog[2].size();
return pressureValid && logLogValid;
return pressureValid && logLogValid
? true
: fail(tr("The calculated pressure curves are invalid."));
}
// 第四步:完整求解还必须具有与时间轴、网格绘图单元严格对应的场压力。
if(p1.p.size() != p1.t.size() ||
oGridOutput.PEBI_cell.isplot.empty()) {
return false;
return fail(tr("The solver returned incomplete field pressure data."));
}
// 计算有效单元数量
@ -1752,7 +1785,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
}
if(actualPlotCellsCount == 0) {
return false;
return fail(tr("The generated grid is invalid."));
}
for(size_t nTimeIndex = 0; nTimeIndex < p1.p.size(); ++nTimeIndex) {
if(isCancelRequested()) {
@ -1761,7 +1794,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
if(p1.p[nTimeIndex].size() < oGridOutput.PEBI_cell.isplot.size()) {
qWarning() << "Incomplete field pressure returned for time index:"
<< static_cast<int>(nTimeIndex);
return false;
return fail(tr("The solver returned incomplete field pressure data."));
}
for(size_t nCellIndex = 0;
nCellIndex < oGridOutput.PEBI_cell.isplot.size();
@ -1774,7 +1807,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
qWarning() << "PEBI returned a non-finite field pressure at time/cell:"
<< static_cast<int>(nTimeIndex)
<< static_cast<int>(nCellIndex);
return false;
return fail(tr("The solver returned invalid field pressure data."));
}
}
}
@ -1841,14 +1874,14 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
// QMap 使用时间作为唯一键;重复时间会覆盖旧帧,因此必须检查数量一致。
if(m_mapPendingTimeSteps.size() != static_cast<int>(p1.t.size())) {
return false;
return fail(tr("The solver returned invalid time data."));
}
// 第六步:基础网格在任务创建或局部建网阶段已经完成深拷贝。后台结果构造
// 不再读取 DataManager 中可能被网格窗口替换的 VTK 指针。
if(m_pInputSnapshot->m_pBaseGrid == nullptr ||
m_pInputSnapshot->m_pBaseGrid->GetNumberOfCells() <= 0) {
return false;
return fail(tr("The prepared result grid is invalid."));
}
int nExpectedWellResultCount = 0;
@ -1858,7 +1891,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
}
}
if(m_vecPendingWellResults.size() != nExpectedWellResultCount) {
return false;
return fail(tr("The solver returned incomplete well pressure data."));
}
m_dPendingScalarMin = dMinP;
@ -1866,6 +1899,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
m_bPendingFullResultReady = buildPebiResultSnapshotCandidate();
if(!m_bPendingFullResultReady) {
// 候选结构或内存校验失败时立即释放大结果,旧快照保持原状。
fail(tr("Failed to build the result snapshot."));
discardPendingFullResult();
}
return m_bPendingFullResultReady;
@ -2037,6 +2071,7 @@ bool nmCalculationDllPebiSolverTask::buildPebiResultSnapshotCandidate()
return true;
} catch(const std::bad_alloc&) {
qWarning() << "Cannot allocate PEBI result snapshot candidate.";
fail(tr("Insufficient memory to build the result snapshot."));
m_pPendingResultSnapshot.clear();
return false;
}
@ -2056,13 +2091,16 @@ bool nmCalculationDllPebiSolverTask::commitResult(
pDataManager != m_pDataManager ||
QThread::currentThread() != pDataManager->thread()) {
discardPendingFullResult();
return false;
return fail(tr("Failed to commit the solver results."));
}
nmDataNumericalAnalysisCase* pAnalysisCase =
pDataManager->getNumericalAnalysisCase();
if(pAnalysisCase == nullptr ||
pAnalysisCase->getGridInputRevision() != m_nGridInputRevision ||
if(pAnalysisCase == nullptr) {
discardPendingFullResult();
return fail(tr("Failed to commit the solver results."));
}
if(pAnalysisCase->getGridInputRevision() != m_nGridInputRevision ||
pAnalysisCase->getResultInputRevision() != m_nResultInputRevision) {
discardPendingFullResult();
return false;
@ -2071,16 +2109,19 @@ bool nmCalculationDllPebiSolverTask::commitResult(
// 第二步:任务后台生成了新网格时,先在当前主线程按同一输入版本提交。
// 已有网格路径则再次确认其仍然有效。两条路径都不允许旧任务覆盖新编辑。
if(m_pInputSnapshot->m_bGridResultNeedsCommit) {
if(!nmCalculationPebiGrid::getInstance()->commitSnapshotResult(
nmCalculationPebiGrid* pGridService =
nmCalculationPebiGrid::getInstance();
if(pGridService == nullptr ||
!pGridService->commitSnapshotResult(
pDataManager,
m_pInputSnapshot->m_oGridInput,
m_pInputSnapshot->m_oGridResult)) {
discardPendingFullResult();
return false;
return fail(tr("Failed to commit the generated grid."));
}
} else if(!pAnalysisCase->isGridValid()) {
discardPendingFullResult();
return false;
return fail(tr("The generated grid is no longer valid."));
}
// 第三步Manager 在唯一发布点校验 UUID、槽位和版本后替换规范快照。
@ -2090,6 +2131,7 @@ bool nmCalculationDllPebiSolverTask::commitResult(
&sError);
if(!bCommitted) {
qWarning() << "Cannot commit PEBI result snapshot:" << sError;
fail(tr("Failed to commit the solver results."));
}
// 成功和失败都不允许任务继续持有候选可写别名;旧快照只由 Manager 决定。

@ -1764,6 +1764,7 @@ void nmSubWndMain::continueSolverInputCapture()
const bool bCancelled = pTask->wasCancelled();
const bool bInputChanged =
pTask->hasInputChanged(m_pSolverDataManager.data());
const QString sFailureReason = pTask->getFailureReason();
m_pSolverTask = nullptr;
if(pTask == s_pRunningSolverTask) {
s_pRunningSolverTask = nullptr;
@ -1783,7 +1784,11 @@ void nmSubWndMain::continueSolverInputCapture()
m_pSolverDataManager = nullptr;
m_pSolverFitting = nullptr;
} else {
scheduleSolverResultCompletion(false, -1, -1, bInputChanged);
scheduleSolverResultCompletion(false,
-1,
-1,
bInputChanged,
sFailureReason);
}
m_bSolverCancelRequested = false;
return;
@ -2377,13 +2382,18 @@ void nmSubWndMain::geoLayering()
}
}
bool nmSubWndMain::on_calculationFinished(NM_Calculation_Result result)
bool nmSubWndMain::on_calculationFinished(
NM_Calculation_Result result,
const QString& sFailureReason)
{
if(result == NM_Calculation_Result_Success) {
return this->mergeAnaResultToFitting();
} else {
// 如果失败,进度条其实没必要拉满了,直接提示错误
QMessageBox::warning(this, tr("solver error"), tr("solver failed!"));
const QString sMessage = sFailureReason.isEmpty()
? tr("No specific failure reason is available.")
: sFailureReason;
QMessageBox::warning(this, tr("Solver failed"), sMessage);
return false;
}
}
@ -2392,12 +2402,14 @@ void nmSubWndMain::scheduleSolverResultCompletion(
bool bSucceeded,
int nPebiCount,
int nSolveTimeMs,
bool bInputChanged)
bool bInputChanged,
const QString& sFailureReason)
{
s_pPendingSolverWindow = this;
m_bSolverResultCompletionPending = true;
m_bPendingSolverSucceeded = bSucceeded;
m_bPendingSolverInputChanged = bInputChanged;
m_sPendingSolverFailureReason = sFailureReason;
m_nPendingSolverPebiCount = nPebiCount;
m_nPendingSolverTimeMs = nSolveTimeMs;
@ -2421,11 +2433,13 @@ void nmSubWndMain::completePendingSolverResult()
const bool bSucceeded = m_bPendingSolverSucceeded;
const bool bInputChanged = m_bPendingSolverInputChanged;
const QString sFailureReason = m_sPendingSolverFailureReason;
const int nPebiCount = m_nPendingSolverPebiCount;
const int nSolveTimeMs = m_nPendingSolverTimeMs;
m_bSolverResultCompletionPending = false;
m_bPendingSolverSucceeded = false;
m_bPendingSolverInputChanged = false;
m_sPendingSolverFailureReason.clear();
m_nPendingSolverPebiCount = -1;
m_nPendingSolverTimeMs = -1;
@ -2437,9 +2451,11 @@ void nmSubWndMain::completePendingSolverResult()
tr("The input changed while the solver was preparing or running. "
"The outdated result was discarded."));
} else {
bResultWindowReady = on_calculationFinished(bSucceeded
? NM_Calculation_Result_Success
: NM_Calculation_Result_Fail);
bResultWindowReady = on_calculationFinished(
bSucceeded
? NM_Calculation_Result_Success
: NM_Calculation_Result_Fail,
sFailureReason);
}
// mergeAnaResultToFitting() 已使用完启动时捕获的上下文。
@ -2496,6 +2512,7 @@ void nmSubWndMain::on_solverTaskFinished(bool isSuccessed)
int nPebiCount = pTask != nullptr ? pTask->getPebiCount() : -1;
int nSolveTimeMs = pTask != nullptr ? pTask->getSolveTimeMs() : -1;
const bool bCancelled = pTask->wasCancelled();
QString sFailureReason = pTask->getFailureReason();
bool bInputChanged = false;
// 后台线程只生成局部结果快照。回到主线程后先验证所属 DataManager 和
// 输入版本,再整体替换旧成果;输入变化与真正的求解失败分别提示。
@ -2508,6 +2525,9 @@ void nmSubWndMain::on_solverTaskFinished(bool isSuccessed)
pTask->hasInputChanged(m_pSolverDataManager.data());
isSuccessed = pTask->commitResult(m_pSolverDataManager.data());
bInputChanged = !isSuccessed && bInputChanged;
if(!isSuccessed) {
sFailureReason = pTask->getFailureReason();
}
} else if(bCancelled) {
isSuccessed = false;
}
@ -2530,7 +2550,8 @@ void nmSubWndMain::on_solverTaskFinished(bool isSuccessed)
scheduleSolverResultCompletion(isSuccessed,
nPebiCount,
nSolveTimeMs,
bInputChanged);
bInputChanged,
sFailureReason);
}
}

Loading…
Cancel
Save