diff --git a/Bin/Config/Lang/cn/nmNum_cn.qm b/Bin/Config/Lang/cn/nmNum_cn.qm
index b3e2db2..00d929e 100644
Binary files a/Bin/Config/Lang/cn/nmNum_cn.qm and b/Bin/Config/Lang/cn/nmNum_cn.qm differ
diff --git a/Bin/Config/Lang/cn/nmNum_cn.ts b/Bin/Config/Lang/cn/nmNum_cn.ts
index aeffc34..c5ae027 100644
--- a/Bin/Config/Lang/cn/nmNum_cn.ts
+++ b/Bin/Config/Lang/cn/nmNum_cn.ts
@@ -2846,10 +2846,8 @@ Reason: %1
The solver currently supports oil, gas, and water single-phase models and the oil-water two-phase model only.
当前求解器仅支持油、气、水单相模型和油水两相模型。
-
- solver failed!
- 求解失败!
-
+ Solver failed求解失败
+ No specific failure reason is available.未获取到具体失败原因。
Progress:
求解进度:
@@ -5230,6 +5228,10 @@ Please check your input coordinates.
Segment %1第 %1 段
No eligible wells没有可配置的其他井
Select at least one production record first.请先选择至少一个产量相。
+
+ Help
+ 帮助
+
OK
确定
@@ -7145,6 +7147,43 @@ Average pressure in contour: %2 MPa
Capturing solver settings...
正在捕获求解设置...
+ Insufficient memory to prepare solver input.准备求解输入时内存不足。
+ Insufficient memory to process solver results.处理求解结果时内存不足。
+ Solver input is unavailable.当前求解输入不可用。
+ Failed to capture solver input.无法获取求解输入。
+ The well configuration is invalid.井配置无效。
+ No valid wells are available for solving.没有可用于求解的有效井。
+ Failed to capture well data.无法获取井数据。
+ Failed to finalize solver input.无法完成求解输入准备。
+ Failed to capture solver settings.无法获取求解设置。
+ The target well is unavailable.目标井不可用。
+ Solver input snapshot is invalid.求解输入快照无效。
+ Failed to prepare solver input.求解输入准备失败。
+ The prepared result grid is invalid.准备的结果网格无效。
+ Grid generation failed.网格生成失败。
+ The generated grid is invalid.生成的网格数据无效。
+ Property interpolation failed.属性插值失败。
+ Failed to load HX_NWTM.dll.无法加载 HX_NWTM.dll。
+ The solver interface is incomplete.求解器接口不完整。
+ An exception occurred while calling the solver.调用求解器时发生异常。
+ The solver result data is invalid.求解器结果数据无效。
+ Failed to load the gas pseudo-pressure converter.无法加载气体拟压力转换器。
+ The solver returned incomplete result data.求解器返回的结果数据不完整。
+ The solver returned invalid time data.求解器返回的时间数据无效。
+ The solver returned incomplete well pressure data.求解器返回的井压力数据不完整。
+ The solver returned invalid well pressure data.求解器返回的井压力数据无效。
+ Failed to convert gas pressure to pseudo-pressure.气体压力转换为拟压力失败。
+ The pressure curve interface is incomplete.压力曲线接口不完整。
+ Failed to calculate pressure curves.压力曲线计算失败。
+ Failed to load singlePhaseSolverDll.dll.无法加载 singlePhaseSolverDll.dll。
+ The calculated pressure curves are invalid.计算得到的压力曲线无效。
+ The solver returned incomplete field pressure data.求解器返回的场压力数据不完整。
+ The solver returned invalid field pressure data.求解器返回的场压力数据无效。
+ Failed to build the result snapshot.求解结果快照构建失败。
+ Insufficient memory to build the result snapshot.构建求解结果快照时内存不足。
+ Failed to commit the solver results.求解结果提交失败。
+ Failed to commit the generated grid.生成的网格提交失败。
+ The generated grid is no longer valid.生成的网格已失效。
nmParameterField
diff --git a/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h b/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h
index 73ebc70..309d7e9 100644
--- a/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h
+++ b/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h
@@ -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 > m_autoFitResultPressure; ///< 目标井原始压力结果。
QVector > m_autoFitResultLogLog; ///< 目标井双对数结果。
diff --git a/Include/nmNum/nmSubWnd/nmSubWndMain.h b/Include/nmNum/nmSubWnd/nmSubWndMain.h
index 305868b..ce26e00 100644
--- a/Include/nmNum/nmSubWnd/nmSubWndMain.h
+++ b/Include/nmNum/nmSubWnd/nmSubWndMain.h
@@ -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> & vvecLogPreData, QVector& 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; ///< 进度框已显示,输入正分批捕获或任务等待启动。
diff --git a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp
index bbcfa11..4b27c7c 100644
--- a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp
+++ b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp
@@ -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 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(oWellRef.m_eMode));
}
if(pState->m_setEffectiveWellCodes.isEmpty()) {
- return false;
+ return fail(tr("No valid wells are available for solving."));
}
QSet 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& 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 > 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(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(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(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(nTimeIndex)
<< static_cast(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(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 决定。
diff --git a/Src/nmNum/nmSubWnd/nmSubWndMain.cpp b/Src/nmNum/nmSubWnd/nmSubWndMain.cpp
index 3603ee5..b81b67c 100644
--- a/Src/nmNum/nmSubWnd/nmSubWndMain.cpp
+++ b/Src/nmNum/nmSubWnd/nmSubWndMain.cpp
@@ -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);
}
}