diff --git a/Bin/Config/Lang/cn/nmNum_cn.qm b/Bin/Config/Lang/cn/nmNum_cn.qm
index 4c6dfbfc..c234a7d0 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 ad1f6241..4aee9b73 100644
--- a/Bin/Config/Lang/cn/nmNum_cn.ts
+++ b/Bin/Config/Lang/cn/nmNum_cn.ts
@@ -664,6 +664,172 @@ Reason: %1
nmCalculationAutoFitLM
+
+ [Fitting completed]
+ 【拟合完成】
+
+
+ [Fitting ended]
+ 【拟合结束】
+
+
+ [Initial parameters]
+ 【初始参数】
+
+
+ [Stage 1: Height alignment]
+Adjust permeability only; accept by height error.
+ 【第一阶段:高度预调】
+只调整渗透率,按高度误差判断是否接受。
+
+
+ [Stage 2: Joint LM - Shape]
+Adjust selected parameters; accept by shape error.
+ 【第二阶段:联合 LM · 形状】
+调整勾选参数,按形状误差判断是否接受。
+
+
+ [Stage 2: Joint LM - Total error]
+Adjust selected parameters; accept by total error.
+ 【第二阶段:联合 LM · 总误差】
+调整勾选参数,按总误差判断是否接受。
+
+
+ %1 | %2 | %3 | Improvement: %4%
+ %1|%2|%3|改善:%4%
+
+
+ %1 | Solver failed
+No valid error was returned; keep the last accepted result and reduce the step.
+ %1|求解失败
+未返回有效误差,保留上次已接受结果并缩小步长。
+
+
+
+ Objective error did not decrease; keep the last accepted result and reduce the step.
+
+ 目标误差未减小,保留上次已接受结果并缩小步长。
+
+
+ ========== LM fitting started ==========
+ ========== LM 拟合开始 ==========
+
+
+ Target well: %1
+ 目标井:%1
+
+
+ Target error: %1
+ 目标误差:%1
+
+
+ Initial total error: %1
+ 初始总误差:%1
+
+
+ Permeability
+ 渗透率
+
+
+ Skin
+ 表皮系数
+
+
+ Wellbore storage
+ 井筒储集系数
+
+
+ Porosity
+ 孔隙度
+
+
+ Fracture conductivity
+ 裂缝导流能力
+
+
+ Fracture half length
+ 裂缝半长
+
+
+ m^3/MPa
+ m³/MPa
+
+
+ mD.m
+ mD·m
+
+
+ Trial %1 | %2 | Height error: %3 -> %4
+ 试算 %1|%2|高度误差:%3 → %4
+
+
+ Trial %1 | Solver failed; keep the last accepted result and reduce the step.
+ 试算 %1|求解失败,保留上次已接受结果并缩小步长。
+
+
+ Height error did not decrease; keep the last accepted result and reduce the step.
+ 高度误差未减小,保留上次已接受结果并缩小步长。
+
+
+ Pressure and derivative height directions conflict; keep the last accepted result and reduce the step.
+ 压力与导数的高度偏移方向冲突,保留上次已接受结果并缩小步长。
+
+
+ Height alignment ended: %1
+ 高度预调结束:%1
+
+
+ Height alignment skipped: permeability is not selected.
+ 跳过高度预调:未勾选渗透率。
+
+
+ Calculating sensitivity...
+ 正在计算灵敏度……
+
+
+ Sensitivity trial
+ 灵敏度试算
+
+
+ Iteration %1
+ 迭代 %1
+
+
+ Shape error: %1 -> %2
+ 形状误差:%1 → %2
+
+
+ Total error: %1 -> %2
+ 总误差:%1 → %2
+
+
+ Shape phase ended: %1
+ 形状部分结束:%1
+
+
+ Total-error phase ended: %1
+ 总误差部分结束:%1
+
+
+ Iteration %1 | No feasible descent step; keep the last accepted result.
+ 迭代 %1|没有可行的下降步,保留上次已接受结果。
+
+
+ Iteration or evaluation budget reached
+ 达到本阶段迭代次数或试算次数上限
+
+
+ Final total error did not improve; restoring the initial result.
+ 最终结果无效或总误差变大,恢复初始结果。
+
+
+ Initial solution failed; trying the parameter-range midpoint.
+ 初始求解失败,将尝试参数范围中点。
+
+
+ Solver calls: %1
+ 共调用求解器:%1 次
+
Failed to refresh the sampling layer from the current curve.
无法根据当前曲线刷新采样层级。
@@ -4395,6 +4561,10 @@ Supported types: Vertical, Vertical Fractured, and Horizontal Multi-Fractured We
nmWxAutomaticfittingStart
+
+ Total time: %1 min %2 s
+ 总耗时:%1 分 %2 秒
+
Auto Fitting Progress
自动拟合进程
diff --git a/Include/nmNum/nmCalculation/nmCalculationAutoFitLM.h b/Include/nmNum/nmCalculation/nmCalculationAutoFitLM.h
index e88920fd..d7ff03aa 100644
--- a/Include/nmNum/nmCalculation/nmCalculationAutoFitLM.h
+++ b/Include/nmNum/nmCalculation/nmCalculationAutoFitLM.h
@@ -7,6 +7,7 @@
#include
#include
#include
+#include
#include
#include "nmCalculation_global.h"
@@ -112,6 +113,7 @@ public:
bool isRunning() const;
int getCurrentIteration() const;
int getTotalEvaluations() const;
+ int getSolverCallCount() const;
void resetOptimizer();
void setTargetWellName(const QString& wellName);
@@ -126,6 +128,10 @@ signals:
void finalizingStarted();
void logMessageGenerated(const QString& message);
+private slots:
+ // 由求解线程直接通知,仅累加原子计数,不操作界面。
+ void recordSolverCall();
+
private:
bool initializeTemporaryDirectory();
void cleanupTemporaryDirectory();
@@ -172,6 +178,8 @@ private:
const AutoFitObjectiveBreakdownLM* objectiveBreakdown = nullptr);
QVector buildTraceParameterVector(const QVector& selectedParameters) const;
void emitRunSummary(bool success, StopReasonLM finalReason);
+ void emitTrialLog(const QString& title, const AutoFitObjectiveBreakdownLM& before,
+ const AutoFitObjectiveBreakdownLM& after, bool valid, bool accepted, bool shapeStage);
bool validateParameters(const QVector& parameters) const;
bool validateLogLogData(const QVector >& logLogData) const;
@@ -212,6 +220,7 @@ private:
int m_maxIterations;
double m_targetError;
int m_totalEvaluations;
+ QAtomicInt m_solverCallCount;
int m_successfulEvaluations;
volatile int m_evaluationInProgress;
diff --git a/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h b/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h
index 309d7e9b..38bae72d 100644
--- a/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h
+++ b/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h
@@ -157,6 +157,8 @@ class NMCALCULATION_EXPORT nmCalculationDllPebiSolverTask : public QThread {
//void slotTaskUpdateProgress();
signals:
+ /** @brief 即将实际调用数值求解器,供 LM 统计调用次数。 */
+ void solverInvoked();
void sig_calculateDone(bool isSuccessed);
/** @brief 报告当前真实阶段;nTotal<=0 表示 DLL 等不可测阶段。 */
void sigStageChanged(QString sStage, int nCurrent, int nTotal);
diff --git a/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp b/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp
index 2ca16e59..58fadf72 100644
--- a/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp
+++ b/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp
@@ -695,6 +695,7 @@ nmCalculationAutoFitLM::nmCalculationAutoFitLM(QObject* parent)
, m_maxIterations(100)
, m_targetError(0.001)
, m_totalEvaluations(0)
+ , m_solverCallCount(0)
, m_successfulEvaluations(0)
, m_evaluationInProgress(0)
, m_consecutiveFailures(0)
@@ -791,15 +792,15 @@ void nmCalculationAutoFitLM::setTargetLogLogData(const QVector >
void nmCalculationAutoFitLM::stopFitting()
{
if(m_isFinalizing) {
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("The final full-field calculation is already running"));
return;
}
// 用户点击停止时只设置请求标志,让 LM 主循环和求解器等待逻辑自然退出。
if(m_isRunning) {
- emit logMessageGenerated(tr("=== User Stop Request Received ==="));
- emit logMessageGenerated(tr("Gracefully stopping LM automatic fitting..."));
+ DEBUG_OUT(tr("=== User Stop Request Received ==="));
+ DEBUG_OUT(tr("Gracefully stopping LM automatic fitting..."));
m_shouldStop = true;
// 此槽由求解等待循环派发,必须立即返回,外层循环才能转发取消请求。
@@ -807,9 +808,9 @@ void nmCalculationAutoFitLM::stopFitting()
emit logMessageGenerated(tr("Waiting for current solver evaluation to stop..."));
}
- emit logMessageGenerated(tr("LM automatic fitting stop request processed"));
+ DEBUG_OUT(tr("LM automatic fitting stop request processed"));
} else {
- emit logMessageGenerated(tr("Stop request received but optimization is not running"));
+ DEBUG_OUT(tr("Stop request received but optimization is not running"));
}
}
@@ -827,10 +828,22 @@ int nmCalculationAutoFitLM::getCurrentIteration() const
int nmCalculationAutoFitLM::getTotalEvaluations() const
{
- // 返回本轮拟合实际调用真实求解器的总次数,供完成日志展示。
+ // 返回评价次数,用于迭代预算;真实求解器调用次数另行统计。
return m_totalEvaluations;
}
+int nmCalculationAutoFitLM::getSolverCallCount() const
+{
+ // 包含失败调用、重试和最终完整求解,不包含未进入求解器的评价。
+ return m_solverCallCount;
+}
+
+void nmCalculationAutoFitLM::recordSolverCall()
+{
+ // 信号来自求解线程,使用原子累加避免跨线程读写竞争。
+ m_solverCallCount.fetchAndAddOrdered(1);
+}
+
QVector nmCalculationAutoFitLM::getBestSolution() const
{
// 返回紧凑的“启用参数向量”,顺序与 m_enabledParamIndices 一致。
@@ -873,6 +886,7 @@ void nmCalculationAutoFitLM::resetOptimizer()
m_comparisonTimeMax = 0.0;
m_currentIteration = 0;
m_totalEvaluations = 0;
+ m_solverCallCount = 0;
m_successfulEvaluations = 0;
m_lastError.clear();
m_initialValues.clear();
@@ -931,9 +945,9 @@ void nmCalculationAutoFitLM::initializeTraceFile()
writeTraceHeader();
writeTraceMetaFile();
- emit logMessageGenerated(tr("LM fitting trace: %1").arg(m_traceFilePath));
+ DEBUG_OUT(tr("LM fitting trace: %1").arg(m_traceFilePath));
if(!m_traceMetaFilePath.isEmpty()) {
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("LM fitting trace metadata: %1").arg(m_traceMetaFilePath));
}
}
@@ -1172,26 +1186,48 @@ void nmCalculationAutoFitLM::writeTraceRow(
m_traceFile.flush();
}
+// 窗口统一显示普通小数;失败评价不展示惩罚值或非有限数。
+static QString lmLogError(double value)
+{
+ return isFiniteNumber(value) && value < 1.0e9
+ ? QString::number(value, 'f', 6) : QString("--");
+}
+
void nmCalculationAutoFitLM::emitRunSummary(bool success, StopReasonLM finalReason)
{
- // 汇总仅描述 LM 迭代和真实求解器评价。
- emit logMessageGenerated(tr("=== LM Run Summary ==="));
- emit logMessageGenerated(tr("Stop reason: %1").arg(getStopReasonDescription(finalReason)));
- emit logMessageGenerated(
- tr("Result: %1, final error=%2, iterations=%3, evaluations=%4 (successful=%5, failed=%6)")
- .arg(success ? tr("SUCCESS") : tr("FAILED"))
- .arg(m_globalBestFitness, 0, 'e', 4)
- .arg(m_currentIteration + 1)
- .arg(m_totalEvaluations)
- .arg(m_successfulEvaluations)
- .arg(m_totalEvaluations - m_successfulEvaluations));
-
- if(!m_traceFilePath.isEmpty()) {
- emit logMessageGenerated(tr("Artifacts: trace=%1").arg(m_traceFilePath));
- }
- if(!m_traceMetaFilePath.isEmpty()) {
- emit logMessageGenerated(tr("Artifacts: trace_meta=%1").arg(m_traceMetaFilePath));
+ // 最终只汇总总误差,耗时由进程窗口在收到结束信号后追加。
+ emit logMessageGenerated(success ? tr("[Fitting completed]") : tr("[Fitting ended]"));
+ emit logMessageGenerated(tr("Stop reason: %1").arg(success
+ ? getStopReasonDescription(finalReason)
+ : (m_lastError.isEmpty() ? getStopReasonDescription(finalReason) : m_lastError)));
+ emit logMessageGenerated(tr("Total error: %1 -> %2")
+ .arg(lmLogError(m_userInitialFitness)).arg(lmLogError(m_globalBestFitness)));
+ emit logMessageGenerated(tr("Solver calls: %1").arg(getSolverCallCount()));
+}
+
+void nmCalculationAutoFitLM::emitTrialLog(const QString& title,
+ const AutoFitObjectiveBreakdownLM& before, const AutoFitObjectiveBreakdownLM& after,
+ bool valid, bool accepted, bool shapeStage)
+{
+ // 只显示当前阶段目标;改善率相对上次已接受的误差计算,变差时为负值。
+ if(!valid) {
+ emit logMessageGenerated(tr("%1 | Solver failed\nNo valid error was returned; keep the last accepted result and reduce the step.").arg(title));
+ return;
}
+ const QString status = accepted ? tr("accepted") : tr("rejected");
+ const double beforeError = shapeStage ? before.shapeLoss : before.total;
+ const double afterError = shapeStage ? after.shapeLoss : after.total;
+ const QString objective = (shapeStage ? tr("Shape error: %1 -> %2")
+ : tr("Total error: %1 -> %2"))
+ .arg(lmLogError(beforeError)).arg(lmLogError(afterError));
+ // 起点为零时相对改善率无定义,避免除零。
+ const QString improvement = beforeError > 0.0
+ ? QString::number((beforeError - afterError) / beforeError * 100.0, 'f', 2)
+ : QString("--");
+ QString message = tr("%1 | %2 | %3 | Improvement: %4%")
+ .arg(title).arg(status).arg(objective).arg(improvement);
+ if(!accepted) message += tr("\n Objective error did not decrease; keep the last accepted result and reduce the step.");
+ emit logMessageGenerated(message);
}
QVector nmCalculationAutoFitLM::buildTraceParameterVector(const QVector& selectedParameters) const
@@ -1353,9 +1389,9 @@ bool nmCalculationAutoFitLM::startAutoFitting()
return false;
}
- emit logMessageGenerated(tr("Algorithm: LM"));
+ DEBUG_OUT(tr("Algorithm: LM"));
const int enabledParams = getEnabledParameterCount();
- emit logMessageGenerated(tr("Enabled parameters count: %1").arg(enabledParams));
+ DEBUG_OUT(tr("Enabled parameters count: %1").arg(enabledParams));
if(enabledParams == 0) {
m_lastError = tr("No parameters enabled for optimization");
@@ -1382,7 +1418,7 @@ bool nmCalculationAutoFitLM::startAutoFitting()
return false;
}
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("Target data validation passed (%1 data points)")
.arg(m_targetLogLogData[0].size()));
@@ -1403,21 +1439,29 @@ bool nmCalculationAutoFitLM::startAutoFitting()
m_consecutiveFailures = 0;
m_initialValues = savedInitialValues;
initializeTraceFile();
+ // 开头只展示一次初始参数和总误差,不展示形状误差。
+ emit logMessageGenerated(tr("========== LM fitting started =========="));
+ emit logMessageGenerated(tr("Target well: %1").arg(m_targetWellName));
+ emit logMessageGenerated(tr("Target error: %1").arg(lmLogError(m_targetError)));
// 先用真实求解器评价用户当前模型,供最终精英保护使用。
if(!savedInitialValues.isEmpty()) {
m_userInitialSolution = savedInitialValues;
- emit logMessageGenerated(tr("=== Evaluating Initial Solution (Elite Protection) ==="));
+ DEBUG_OUT(tr("=== Evaluating Initial Solution (Elite Protection) ==="));
- QString paramStr = tr("Initial parameters: ");
+ const char* names[] = { QT_TR_NOOP("Permeability"), QT_TR_NOOP("Skin"),
+ QT_TR_NOOP("Wellbore storage"), QT_TR_NOOP("Porosity"), "",
+ QT_TR_NOOP("Fracture conductivity"), QT_TR_NOOP("Fracture half length") };
+ const char* units[] = { "mD", "", "m^3/MPa", "", "", "mD.m", "m" };
+ emit logMessageGenerated(tr("[Initial parameters]"));
for(int i = 0; i < m_userInitialSolution.size(); ++i) {
- paramStr += QString("[%1]=%2 ")
- .arg(i).arg(m_userInitialSolution[i], 0, 'f', 6);
+ const int index = m_enabledParamIndices[i];
+ emit logMessageGenerated(QString("%1: %2 %3").arg(tr(names[index]))
+ .arg(m_userInitialSolution[i], 0, 'g', 10).arg(tr(units[index])));
}
- emit logMessageGenerated(paramStr);
try {
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("Starting initial solution evaluation..."));
QTime initialEvalTimer;
initialEvalTimer.start();
@@ -1434,16 +1478,15 @@ bool nmCalculationAutoFitLM::startAutoFitting()
m_globalBestLogLogData = m_userInitialLogLogData;
m_userInitialObjectiveBreakdown = m_lastObjectiveBreakdown;
m_globalBestObjectiveBreakdown = m_userInitialObjectiveBreakdown;
- emit logMessageGenerated(tr("Initial solution evaluation successful"));
- emit logMessageGenerated(
- tr("Initial Error: %1").arg(m_userInitialFitness, 0, 'e', 4));
+ DEBUG_OUT(tr("Initial solution evaluation successful"));
+ emit logMessageGenerated(tr("Initial total error: %1").arg(lmLogError(m_userInitialFitness)));
emit bestCurveUpdated(m_targetLogLogData,
m_globalBestLogLogData,
0,
m_globalBestFitness);
} else {
m_hasValidUserSolution = false;
- emit logMessageGenerated(tr("Initial solution evaluation failed"));
+ if(!m_shouldStop) emit logMessageGenerated(tr("Initial solution failed; trying the parameter-range midpoint."));
}
writeTraceRow(-1,
@@ -1458,7 +1501,7 @@ bool nmCalculationAutoFitLM::startAutoFitting()
? &m_userInitialObjectiveBreakdown : nullptr);
} catch(...) {
m_hasValidUserSolution = false;
- emit logMessageGenerated(tr("Exception during initial solution evaluation"));
+ if(!m_shouldStop) emit logMessageGenerated(tr("Initial solution failed; trying the parameter-range midpoint."));
}
m_initialValues = savedInitialValues;
@@ -1491,6 +1534,7 @@ bool nmCalculationAutoFitLM::startAutoFitting()
cleanupTemporaryDirectory();
m_isFinalizing = false;
m_isRunning = false;
+ emitRunSummary(false, LM_OPTIMIZATION_FAILED);
emit fittingFinished(false, m_lastError);
return false;
} catch(...) {
@@ -1500,6 +1544,7 @@ bool nmCalculationAutoFitLM::startAutoFitting()
cleanupTemporaryDirectory();
m_isFinalizing = false;
m_isRunning = false;
+ emitRunSummary(false, LM_OPTIMIZATION_FAILED);
emit fittingFinished(false, m_lastError);
return false;
}
@@ -1513,7 +1558,7 @@ bool nmCalculationAutoFitLM::startAutoFitting()
// Stop 只结束优化迭代;从这里开始必须用当前最优参数生成并发布正式快照。
m_isFinalizing = true;
emit finalizingStarted();
- emit logMessageGenerated(tr("Applying optimized parameters to model..."));
+ DEBUG_OUT(tr("Applying optimized parameters to model..."));
applyParametersToDataManager(m_globalBestPosition);
// 裂缝参数会改变网格输入;标记失效后,最终求解任务会基于新快照重建网格。
@@ -1529,28 +1574,28 @@ bool nmCalculationAutoFitLM::startAutoFitting()
dataManager->invalidatePebiGrid();
}
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("Running final full-field calculation with optimized parameters..."));
finalFullSolverExecuted = true;
finalFullSolverSucceeded = runFinalFullSolver();
if(finalFullSolverSucceeded) {
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("Final full-field calculation completed successfully"));
} else {
m_lastError =
tr("Optimized parameters were found, but the final full-field calculation failed");
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("ERROR: Final full-field calculation failed"));
}
saveOptimizationResult();
- emit logMessageGenerated(tr("=== Optimization Results ==="));
- emit logMessageGenerated(
+ DEBUG_OUT(tr("=== Optimization Results ==="));
+ DEBUG_OUT(
tr("Final error: %1").arg(m_globalBestFitness, 0, 'e', 4));
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("Total iterations: %1").arg(m_currentIteration + 1));
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("Total evaluations: %1 (successful: %2)")
.arg(m_totalEvaluations).arg(m_successfulEvaluations));
@@ -1559,24 +1604,24 @@ bool nmCalculationAutoFitLM::startAutoFitting()
finalParams += QString("[%1]=%2 ")
.arg(i).arg(m_globalBestPosition[i], 0, 'f', 6);
}
- emit logMessageGenerated(finalParams);
+ DEBUG_OUT(finalParams);
if(finalFullSolverExecuted && finalFullSolverSucceeded) {
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("Parameters and full-field results applied successfully to data manager"));
} else if(!finalFullSolverExecuted) {
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("Optimized parameters applied to data manager"));
}
} catch(const std::exception& e) {
finalFullSolverSucceeded = false;
m_lastError = tr("Failed to apply final parameters: %1").arg(e.what());
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("ERROR: Failed to apply final parameters: %1").arg(e.what()));
} catch(...) {
finalFullSolverSucceeded = false;
m_lastError = tr("Failed to apply final parameters due to unknown error");
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("ERROR: Unknown error applying final parameters"));
}
}
@@ -1591,45 +1636,45 @@ bool nmCalculationAutoFitLM::startAutoFitting()
message = QString(tr("Target achieved. Best error: %1, Iterations: %2"))
.arg(m_globalBestFitness, 0, 'e', 4)
.arg(m_currentIteration + 1);
- emit logMessageGenerated(tr("=== LM AUTOMATIC FITTING SUCCESSFUL ==="));
+ DEBUG_OUT(tr("=== LM AUTOMATIC FITTING SUCCESSFUL ==="));
} else if(finalReason == LM_TRUE_CONVERGENCE) {
success = true;
message = QString(
tr("Automatic fitting converged to a stable solution. Best error: %1, Iterations: %2"))
.arg(m_globalBestFitness, 0, 'e', 4)
.arg(m_currentIteration + 1);
- emit logMessageGenerated(tr("=== LM AUTOMATIC FITTING CONVERGED ==="));
+ DEBUG_OUT(tr("=== LM AUTOMATIC FITTING CONVERGED ==="));
} else if(finalReason == LM_LOCAL_OPTIMUM) {
success = true;
message = QString(
tr("Automatic fitting reached a local optimum. Best error: %1, Iterations: %2"))
.arg(m_globalBestFitness, 0, 'e', 4)
.arg(m_currentIteration + 1);
- emit logMessageGenerated(tr("=== LM AUTOMATIC FITTING - LOCAL OPTIMUM ==="));
+ DEBUG_OUT(tr("=== LM AUTOMATIC FITTING - LOCAL OPTIMUM ==="));
} else if(finalReason == LM_MAX_ITERATIONS) {
success = true;
message = QString(tr("Total-stage budget reached. Best error: %1, Cumulative iterations: %2"))
.arg(m_globalBestFitness, 0, 'e', 4)
.arg(m_currentIteration + 1);
- emit logMessageGenerated(tr("=== LM AUTOMATIC FITTING - MAX ITERATIONS ==="));
+ DEBUG_OUT(tr("=== LM AUTOMATIC FITTING - MAX ITERATIONS ==="));
} else if(finalReason == LM_USER_STOPPED) {
success = true;
message = QString(tr("Stopped by user. Best error: %1, Iterations: %2"))
.arg(m_globalBestFitness, 0, 'e', 4)
.arg(m_currentIteration + 1);
- emit logMessageGenerated(tr("=== LM AUTOMATIC FITTING STOPPED BY USER ==="));
+ DEBUG_OUT(tr("=== LM AUTOMATIC FITTING STOPPED BY USER ==="));
} else if(finalReason == LM_CONSECUTIVE_FAILURES) {
message = QString(
tr("Automatic fitting failed due to consecutive failures. Best error: %1, Iterations: %2"))
.arg(m_globalBestFitness, 0, 'e', 4)
.arg(m_currentIteration + 1);
- emit logMessageGenerated(tr("=== LM AUTOMATIC FITTING FAILED ==="));
+ DEBUG_OUT(tr("=== LM AUTOMATIC FITTING FAILED ==="));
} else {
message = QString(
tr("Automatic fitting ended unexpectedly. Best error: %1, Iterations: %2"))
.arg(m_globalBestFitness, 0, 'e', 4)
.arg(m_currentIteration + 1);
- emit logMessageGenerated(tr("=== LM AUTOMATIC FITTING - UNKNOWN END ==="));
+ DEBUG_OUT(tr("=== LM AUTOMATIC FITTING - UNKNOWN END ==="));
}
if(!finalFullSolverSucceeded) {
@@ -1918,8 +1963,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
restoreEvaluationState(current);
emit progressUpdated(-1, current.fitness);
- emit logMessageGenerated(tr("=== Starting LM Main Loop ==="));
- emit logMessageGenerated(
+ DEBUG_OUT(tr("=== Starting LM Main Loop ==="));
+ DEBUG_OUT(
tr("LM starting point error: %1; evaluation budget per LM phase: %2")
.arg(current.fitness, 0, 'e', 4)
.arg(phaseEvaluationBudget));
@@ -1931,8 +1976,9 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
int heightStagnation = 0;
double heightScale = 1.0;
double heightSlope = -1.0;
+ int heightTrials = 0;
if(permeabilityColumn >= 0) {
- emit logMessageGenerated(tr("LM stage 1: align curve height using permeability only; no fixed evaluation limit, effective improvement threshold 10%."));
+ emit logMessageGenerated(tr("[Stage 1: Height alignment]\nAdjust permeability only; accept by height error."));
// 不限制试算次数,由高度对齐、改善停滞及可行步长决定何时结束。
while(processPauseAndStop()) {
const double bias = current.breakdown.verticalCommonBias;
@@ -1941,6 +1987,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
if(k <= 0.0 || m_parameterLower[0] <= 0.0 || m_parameterUpper[0] <= m_parameterLower[0]) break;
const double logRange = qLn(m_parameterUpper[0]) - qLn(m_parameterLower[0]);
const double change = qBound(-0.30 * logRange, -bias / heightSlope * heightScale, 0.30 * logRange);
+ const AutoFitObjectiveBreakdownLM previous = current.breakdown;
+ ++heightTrials;
TrustRegionEvaluation candidate;
candidate.parameters = current.parameters;
candidate.parameters[permeabilityColumn] = qBound(m_parameterLower[0], k * qExp(change), m_parameterUpper[0]);
@@ -1970,10 +2018,16 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
heightBaseline = current.breakdown.verticalLoss;
heightStagnation = 0;
} else ++heightStagnation;
- emit logMessageGenerated(tr("Permeability alignment: k=%1, height error=%2, shape error=%3, result=%4")
- .arg(candidate.parameters[permeabilityColumn], 0, 'g', 6)
- .arg(candidate.breakdown.verticalLoss, 0, 'e', 4).arg(candidate.breakdown.shapeLoss, 0, 'e', 4)
- .arg(accepted ? tr("accepted") : tr("rejected")));
+ if(candidate.valid) {
+ emit logMessageGenerated(tr("Trial %1 | %2 | Height error: %3 -> %4")
+ .arg(heightTrials).arg(accepted ? tr("accepted") : tr("rejected"))
+ .arg(lmLogError(previous.verticalLoss)).arg(lmLogError(candidate.breakdown.verticalLoss)));
+ if(!accepted) emit logMessageGenerated(candidate.breakdown.verticalReliable
+ ? tr("Height error did not decrease; keep the last accepted result and reduce the step.")
+ : tr("Pressure and derivative height directions conflict; keep the last accepted result and reduce the step."));
+ } else {
+ emit logMessageGenerated(tr("Trial %1 | Solver failed; keep the last accepted result and reduce the step.").arg(heightTrials));
+ }
}
QString heightReason = tr("no feasible permeability step or step too small");
if(m_shouldStop) heightReason = tr("stopped by user");
@@ -1982,9 +2036,10 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
else if(heightStagnation >= 2) heightReason = tr("2 consecutive steps without effective height improvement");
else if(current.parameters[permeabilityColumn] <= m_parameterLower[0] ||
current.parameters[permeabilityColumn] >= m_parameterUpper[0]) heightReason = tr("permeability reached its bound");
- emit logMessageGenerated(tr("Permeability alignment ended: %1").arg(heightReason));
+ emit logMessageGenerated(tr("Height alignment ended: %1").arg(heightReason));
}
+ if(permeabilityColumn < 0) emit logMessageGenerated(tr("Height alignment skipped: permeability is not selected."));
if(m_shouldStop) return LM_USER_STOPPED;
// 原逐参数第二阶段已移除;同一个联合 LM 先匹配整体形状,再匹配总误差。
@@ -2002,7 +2057,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
restoreEvaluationState(current);
};
double effectiveImprovementBaseline = stageError(current);
- emit logMessageGenerated(tr("LM sampling: %1 points (%2 intervals per log-time decade).")
+ DEBUG_OUT(tr("LM sampling: %1 points (%2 intervals per log-time decade).")
.arg(current.breakdown.residualVector.size() / 2).arg(kAutoFitIntervalsPerDecade));
auto registerEffectiveImprovement = [&](double fitness) -> bool {
@@ -2048,7 +2103,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
return false;
};
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("LM effective improvement threshold: max(%1, %2% of baseline error); "
"%3 consecutive ineffective steps trigger convergence confirmation")
.arg(effectiveAbsoluteImprovement, 0, 'e', 2)
@@ -2212,9 +2267,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
0,
shapeStage ? "shape_accepted_cached_probe" : "total_accepted_cached_probe",
¤t.breakdown);
- emit logMessageGenerated(
- tr("Sensitivity probe accepted: current objective error=%1")
- .arg(stageError(current), 0, 'e', 4));
+ emitTrialLog(tr("Sensitivity trial"), base.breakdown, current.breakdown, true, true, shapeStage);
} else {
restoreEvaluationState(current);
}
@@ -2258,9 +2311,9 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
: QT_TR_NOOP("full sensitivity at total-stage entry");
emit progressUpdated(0, current.fitness);
emit logMessageGenerated(shapeStage
- ? tr("Joint LM shape phase: adjust all selected parameters by full shape error.")
- : tr("Joint LM total phase: adjust all selected parameters by total error."));
- emit logMessageGenerated(tr("LM phase budget: %1 iterations, %2 evaluations.")
+ ? tr("[Stage 2: Joint LM - Shape]\nAdjust selected parameters; accept by shape error.")
+ : tr("[Stage 2: Joint LM - Total error]\nAdjust selected parameters; accept by total error."));
+ DEBUG_OUT(tr("LM phase budget: %1 iterations, %2 evaluations.")
.arg(m_maxIterations).arg(phaseEvaluationBudget));
writeTraceRow(completedIterations, -1, "stage_switch", current.parameters, current.fitness,
true, 0, shapeStage ? "height_to_shape_lm" : "shape_to_total", ¤t.breakdown);
@@ -2276,7 +2329,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
break;
}
if(rebuildRequested) {
- emit logMessageGenerated(tr("Rebuilding sensitivity model: %1").arg(tr(rebuildReason)));
+ emit logMessageGenerated(tr("Calculating sensitivity..."));
writeTraceRow(m_currentIteration, -1, "sensitivity_rebuild", current.parameters,
current.fitness, true, 0, rebuildReason, ¤t.breakdown);
if(!rebuildSensitivity()) {
@@ -2333,6 +2386,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
// 当前阶段没有可行下降步时,收缩半径并进入原有重建/收敛处理。
if(selectedColumns.isEmpty()) {
+ emit logMessageGenerated(tr("Iteration %1 | No feasible descent step; keep the last accepted result.").arg(phaseIterations));
if(trustRadius <= minimumTrustRadius * 1.01 &&
modelRebuiltAtMinimumRadius) {
stopReason = LM_LOCAL_OPTIMUM;
@@ -2379,6 +2433,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
}
if(!candidate.valid) {
+ emitTrialLog(tr("Iteration %1").arg(phaseIterations), current.breakdown, candidate.breakdown,
+ false, false, shapeStage);
// 求解失败的候选不能改变 current。先完整恢复上一个已接受参数和
// 对应误差快照,再缩小信赖域;连续失败达到上限才终止整个拟合。
++consecutiveSolverFailures;
@@ -2493,14 +2549,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
: "rejected_" + selectionName,
&candidate.breakdown);
- QString componentDisplayName = shapeStage ? tr("shape deviation") : tr("total error");
- emit logMessageGenerated(
- tr("Iteration %1: focus=%2, parameters=%3, error=%4, result=%5")
- .arg(iteration + 1)
- .arg(componentDisplayName)
- .arg(selectedColumns.size())
- .arg(stageError(candidate), 0, 'e', 4)
- .arg(accepted ? tr("accepted") : tr("rejected")));
+ emitTrialLog(tr("Iteration %1").arg(phaseIterations), oldBreakdown, candidate.breakdown,
+ true, accepted, shapeStage);
emit progressUpdated(phaseIterations, m_globalBestFitness);
const bool effectiveImprovement = registerEffectiveImprovement(stageError(current));
@@ -2528,9 +2578,11 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
break;
// 形状达标、确认停滞或用完额度后,保留当前参数进入总误差段。
if(shapeStage) {
- emit logMessageGenerated(tr("Shape LM phase ended: %1").arg(getStopReasonDescription(stopReason)));
+ emit logMessageGenerated(tr("Shape phase ended: %1").arg(getStopReasonDescription(stopReason)));
writeTraceRow(m_currentIteration, -1, "lm_phase_end", current.parameters, current.fitness,
true, 0, QString("shape_stop_reason_%1").arg(static_cast(stopReason)), ¤t.breakdown);
+ } else {
+ emit logMessageGenerated(tr("Total-error phase ended: %1").arg(getStopReasonDescription(stopReason)));
}
}
@@ -2538,7 +2590,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
m_currentIteration = completedIterations - 1;
}
restoreEvaluationState(current);
- emit logMessageGenerated(tr("Adaptive fitting counts: %1 shape LM iterations, %2 total LM iterations, %3 total evaluations.")
+ DEBUG_OUT(tr("Adaptive fitting counts: %1 shape LM iterations, %2 total LM iterations, %3 total evaluations.")
.arg(shapeIterations).arg(totalIterations).arg(m_totalEvaluations));
if(m_shouldStop) {
@@ -3001,17 +3053,17 @@ void nmCalculationAutoFitLM::validateAndProtectFinalResult()
// 最终精英保护只阻止无效结果或真正变差的结果。任何真实误差下降都应保留,
// 不能再用固定百分比门槛把已经找到的更优解恢复成初始值。
if(!m_hasValidUserSolution) {
- emit logMessageGenerated(tr("No initial solution for elite protection"));
+ DEBUG_OUT(tr("No initial solution for elite protection"));
return;
}
- emit logMessageGenerated(tr("=== Final Result Validation (Elite Protection) ==="));
+ DEBUG_OUT(tr("=== Final Result Validation (Elite Protection) ==="));
// 使用已有的评估结果
double finalFitness = m_globalBestFitness;
double initialFitness = m_userInitialFitness;
- emit logMessageGenerated(tr("Comparing results: Initial=%1, Final=%2")
+ DEBUG_OUT(tr("Comparing results: Initial=%1, Final=%2")
.arg(initialFitness, 0, 'e', 4).arg(finalFitness, 0, 'e', 4));
bool finalValid = isFiniteNumber(finalFitness) &&
@@ -3024,15 +3076,15 @@ void nmCalculationAutoFitLM::validateAndProtectFinalResult()
double improvement = initialFitness - finalFitness;
double relativeImprovement =
improvement / qMax(1.0e-10, qAbs(initialFitness));
- emit logMessageGenerated(tr("Improvement: %1 (%2%)")
+ DEBUG_OUT(tr("Improvement: %1 (%2%)")
.arg(improvement, 0, 'e', 4)
.arg(relativeImprovement * 100, 0, 'f', 2));
}
if(!finalValid || finalFitness > initialFitness) {
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("Elite protection triggered: final result is invalid or worse than initial"));
- emit logMessageGenerated(tr("Restoring initial solution as final result"));
+ emit logMessageGenerated(tr("Final total error did not improve; restoring the initial result."));
m_globalBestFitness = initialFitness;
m_globalBestPosition = m_userInitialSolution;
@@ -3040,9 +3092,9 @@ void nmCalculationAutoFitLM::validateAndProtectFinalResult()
m_globalBestObjectiveBreakdown = m_userInitialObjectiveBreakdown;
emit bestCurveUpdated(m_targetLogLogData, m_globalBestLogLogData, m_currentIteration + 1, m_globalBestFitness);
- emit logMessageGenerated(tr("Initial solution restored successfully"));
+ DEBUG_OUT(tr("Initial solution restored successfully"));
} else {
- emit logMessageGenerated(
+ DEBUG_OUT(
tr("Final result validated - solution is not worse than initial"));
}
}
@@ -4129,6 +4181,7 @@ QVector> nmCalculationAutoFitLM::runSolverDll()
DEBUG_OUT("Starting DLL solver execution...");
// 异步执行 DLL 任务。循环等待期间持续 processEvents,保证界面不会完全卡死。
+ connect(dllTask, SIGNAL(solverInvoked()), this, SLOT(recordSolverCall()), Qt::DirectConnection);
dllTask->start();
// 等待完成。最大等待 1 小时;用户停止使用任务已有的协作取消接口。
@@ -4296,6 +4349,7 @@ bool nmCalculationAutoFitLM::runFinalFullSolver()
++m_evaluationInProgress;
nmCalculationDllPebiSolverTask dllTask(m_tempDirectory, dataManager);
+ connect(&dllTask, SIGNAL(solverInvoked()), this, SLOT(recordSolverCall()), Qt::DirectConnection);
dllTask.start();
const int maxWait = 3600000;
@@ -4347,7 +4401,7 @@ QString nmCalculationAutoFitLM::getStopReasonDescription(StopReasonLM reason) co
return tr("Local optimum detected");
case LM_MAX_ITERATIONS:
- return tr("Total-stage iteration or evaluation budget reached");
+ return tr("Iteration or evaluation budget reached");
case LM_USER_STOPPED:
return tr("Stopped by user request");
diff --git a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp
index 3220d85b..5feeafb7 100644
--- a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp
+++ b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp
@@ -1382,6 +1382,8 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
}
reportStage(tr("Solving model..."), 0, 0);
+ // 只统计进入数值求解器的调用,网格准备失败和缓存复用不计入。
+ emit solverInvoked();
pfnModel(oModelOutput,
oModelInput,
m_pInputSnapshot->m_oGridInput.m_sLicensePath
diff --git a/Src/nmNum/nmSubWxs/nmWxAutomaticFittingStart.cpp b/Src/nmNum/nmSubWxs/nmWxAutomaticFittingStart.cpp
index 9de73cd7..de0d367c 100644
--- a/Src/nmNum/nmSubWxs/nmWxAutomaticFittingStart.cpp
+++ b/Src/nmNum/nmSubWxs/nmWxAutomaticFittingStart.cpp
@@ -612,6 +612,8 @@ void nmWxAutomaticfittingStart::setAutoFitter(nmCalculationAutoFitLM* autoFitter
m_autoFitterPSO = nullptr;
m_autoFitterLM = autoFitter;
m_algorithmName = "LM";
+ // LM 日志由优化器统一组织,清除通用初始化提示。
+ logTextEdit->clear();
algorithmTypeValue->setText(m_algorithmName);
algorithmTypeValue->setStyleSheet("QLabel { color: blue; font-weight: bold; }");
@@ -629,7 +631,6 @@ void nmWxAutomaticfittingStart::setAutoFitter(nmCalculationAutoFitLM* autoFitter
this, SLOT(onBestCurveUpdated(QVector >,QVector >,int,double)));
stopButton->setEnabled(true);
- addLogMessage(tr("%1 auto fitting started").arg(m_algorithmName));
}
}
@@ -646,7 +647,7 @@ void nmWxAutomaticfittingStart::setFittingParameters(int maxIterations, double t
progressBar->setRange(0, maxIterations);
const QString algorithmName = m_algorithmName;
- addLogMessage(tr("%1 fitting parameters set: MaxIterations=%2, TargetAccuracy=%3, TargetWell=%4")
+ if(!m_autoFitterLM) addLogMessage(tr("%1 fitting parameters set: MaxIterations=%2, TargetAccuracy=%3, TargetWell=%4")
.arg(algorithmName).arg(maxIterations).arg(formatScientific(targetError)).arg(wellName));
}
@@ -657,7 +658,7 @@ void nmWxAutomaticfittingStart::markFittingStarted()
const QString algorithmName = m_algorithmName;
QString timestamp = m_startTime.toString("yyyy-MM-dd hh:mm:ss");
- addLogMessage(tr("=== %1 Fitting Session Started at %2 ===")
+ if(!m_autoFitterLM) addLogMessage(tr("=== %1 Fitting Session Started at %2 ===")
.arg(algorithmName)
.arg(timestamp));
}
@@ -670,7 +671,7 @@ void nmWxAutomaticfittingStart::setSelectedParameters(const QStringList& paramet
updateParameterTable();
const QString algorithmName = m_algorithmName;
- addLogMessage(tr("%1 selected parameters: %2").arg(algorithmName).arg(parameterNames.join(", ")));
+ if(!m_autoFitterLM) addLogMessage(tr("%1 selected parameters: %2").arg(algorithmName).arg(parameterNames.join(", ")));
}
void nmWxAutomaticfittingStart::setTargetLogLogData(const QVector >& targetData)
@@ -710,7 +711,7 @@ void nmWxAutomaticfittingStart::onFittingProgress(int iteration, double fitness)
bestComfortValue->setText(formatScientific(fitness));
bestComfortValue->setStyleSheet("QLabel { color: green; font-weight: bold; }");
- addLogMessage(tr("Better solution found: %1").arg(formatScientific(fitness)));
+ if(!m_autoFitterLM) addLogMessage(tr("Better solution found: %1").arg(formatScientific(fitness)));
// 更新参数表格
updateParameterTable();
@@ -732,7 +733,7 @@ void nmWxAutomaticfittingStart::onFittingFinished(bool success, const QString& m
// 区分正常完成和用户停止
if(message.contains("stopped by user", Qt::CaseInsensitive)) {
- addLogMessage(tr("%1 fitting stopped by user: %2").arg(algorithmName).arg(message));
+ if(!m_autoFitterLM) addLogMessage(tr("%1 fitting stopped by user: %2").arg(algorithmName).arg(message));
// 更新进度条显示停止状态
progressBar->setFormat(tr("Stopped: 100%"));
@@ -741,7 +742,7 @@ void nmWxAutomaticfittingStart::onFittingFinished(bool success, const QString& m
"QProgressBar::chunk { background-color: #FF9800; }" // 橙色表示停止
);
} else if(message.contains("target achieved", Qt::CaseInsensitive)) {
- addLogMessage(tr("%1 fitting completed successfully - target achieved: %2").arg(algorithmName).arg(message));
+ if(!m_autoFitterLM) addLogMessage(tr("%1 fitting completed successfully - target achieved: %2").arg(algorithmName).arg(message));
// 更新进度条显示成功状态
progressBar->setFormat(tr("Target Achieved: 100%"));
@@ -750,7 +751,7 @@ void nmWxAutomaticfittingStart::onFittingFinished(bool success, const QString& m
"QProgressBar::chunk { background-color: #4CAF50; }" // 绿色表示成功
);
} else {
- addLogMessage(tr("%1 fitting completed successfully: %2").arg(algorithmName).arg(message));
+ if(!m_autoFitterLM) addLogMessage(tr("%1 fitting completed successfully: %2").arg(algorithmName).arg(message));
// 更新进度条显示完成状态
progressBar->setFormat(tr("Completed: 100%"));
@@ -761,7 +762,7 @@ void nmWxAutomaticfittingStart::onFittingFinished(bool success, const QString& m
}
} else {
// 真正的失败情况
- addLogMessage(tr("%1 fitting failed: %2").arg(algorithmName).arg(message));
+ if(!m_autoFitterLM) addLogMessage(tr("%1 fitting failed: %2").arg(algorithmName).arg(message));
// 更新进度条显示失败状态
int currentProgress = progressBar->value();
@@ -786,7 +787,7 @@ void nmWxAutomaticfittingStart::onFittingFinished(bool success, const QString& m
// 添加完成时间戳
QDateTime endTime = QDateTime::currentDateTime();
QString timestamp = endTime.toString("yyyy-MM-dd hh:mm:ss");
- addLogMessage(tr("=== %1 Fitting Session Ended at %2 ===")
+ if(!m_autoFitterLM) addLogMessage(tr("=== %1 Fitting Session Ended at %2 ===")
.arg(algorithmName).arg(timestamp));
// 如果有开始时间,则计算总耗时
@@ -800,12 +801,13 @@ void nmWxAutomaticfittingStart::onFittingFinished(bool success, const QString& m
? m_autoFitterLM->getTotalEvaluations()
: (m_autoFitterPSO ? m_autoFitterPSO->getTotalEvaluations() : 0);
- // 同时显示总秒数、分秒和本轮真实求解器调用次数。
- addLogMessage(tr("Total fitting time: %1 s (%2 min %3 s), total solver calls: %4")
- .arg(seconds, 0, 'f', 2)
- .arg(minutes)
- .arg(remainSec, 0, 'f', 2)
- .arg(totalEvaluations));
+ // LM 的调用次数由优化器汇总,这里只在结束时显示一次总耗时。
+ if(m_autoFitterLM) {
+ addLogMessage(tr("Total time: %1 min %2 s").arg(minutes).arg(remainSec, 0, 'f', 1));
+ } else {
+ addLogMessage(tr("Total fitting time: %1 s (%2 min %3 s), total solver calls: %4")
+ .arg(seconds, 0, 'f', 2).arg(minutes).arg(remainSec, 0, 'f', 2).arg(totalEvaluations));
+ }
}
}
@@ -840,7 +842,7 @@ void nmWxAutomaticfittingStart::onStopButtonClicked()
} else if (m_autoFitterLM) {
m_autoFitterLM->stopFitting();
}
- addLogMessage(tr("User requested to stop %1 fitting").arg(algorithmName));
+ if(!m_autoFitterLM) addLogMessage(tr("User requested to stop %1 fitting").arg(algorithmName));
}
}
}