diff --git a/Bin/Config/Lang/cn/nmNum_cn.qm b/Bin/Config/Lang/cn/nmNum_cn.qm
index 13ec7e77..5fba4952 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 28acd643..104dcbea 100644
--- a/Bin/Config/Lang/cn/nmNum_cn.ts
+++ b/Bin/Config/Lang/cn/nmNum_cn.ts
@@ -1257,8 +1257,8 @@ Reason: %1
井储试调:相对斜率匹配误差=%1,井储=%2 → %3
- Wellbore recheck: early error=%1, total limit=%2, shape limit=%3.
- 井储表皮回检:前期相对斜率匹配误差=%1,整体误差上限=%2,形状误差上限=%3。
+ Wellbore recheck: early shape error=%1, shape limit=%2.
+ 井储表皮回检:前期形状误差=%1,整体形状误差上限=%2。
early relative-slope error restored within tolerance
@@ -1273,8 +1273,8 @@ Reason: %1
井储表皮回检在灵敏度评价期间完成
- total target reached during shape fitting
- 形状调整期间已达到总误差目标
+ Sensitivity probe accepted: shape error=%1
+ 接受灵敏度探针:形状误差=%1
fresh sensitivity at joint shape entry
diff --git a/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp b/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp
index 1aeccba9..378e7276 100644
--- a/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp
+++ b/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp
@@ -1212,9 +1212,9 @@ void nmCalculationAutoFitLM::writeTraceMetaFile()
QTextStream out(&metaFile);
out << "{\n";
- out << " \"schema_version\": 29,\n";
+ out << " \"schema_version\": 30,\n";
out << " \"strategy\": \"permeability_height_then_shape_then_joint_lm\",\n";
- out << " \"height_acceptance\": \"reliable_vertical_loss_decrease; no_shape_loss_constraint\",\n";
+ out << " \"height_acceptance\": \"reliable_vertical_loss_decrease; no_shape_or_total_loss_constraint\",\n";
out << " \"shape_priority\": \"storage_then_skin_then_shape_without_wellbore_then_optional_wellbore_recheck\",\n";
out << " \"shape_metric\": \"pressure_and_derivative_log_slopes_81_points_lag_8\",\n";
out << " \"early_parallel_metric\": \"pressure_and_derivative_log_slopes_first_window_81_points_lag_8\",\n";
@@ -1225,7 +1225,7 @@ void nmCalculationAutoFitLM::writeTraceMetaFile()
out << " \"early_initial_expansion_policy\": \"before_first_accepted_shape_improvement; if_shape_worsens_double_coordinate_step_from_unchanged_base_up_to_parameter_bound; retain_base_on_failure\",\n";
out << " \"early_wellbore_acceptance\": \"locked_gap_direction_and_early_shape_decrease\",\n";
out << " \"early_wellbore_total_constraint\": false,\n";
- out << " \"shape_stage_total_tolerance\": \"max(0.02, 25% of stage entry total)\",\n";
+ out << " \"shape_stage_total_constraint\": false,\n";
out << " \"shape_wellbore_parameters_frozen\": true,\n";
out << " \"shape_sensitivity_refresh\": \"full Jacobian at joint shape entry and stagnation confirmation\",\n";
out << " \"shape_expansion_policy\": \"one expansion per reliable shape direction, up to 2x when actual rho exceeds 0.75; retain ordinary step on failure\",\n";
@@ -1234,7 +1234,7 @@ void nmCalculationAutoFitLM::writeTraceMetaFile()
out << " \"shape_round_improvement_threshold\": \"max(0.0001, 1% of round entry shape loss)\",\n";
out << " \"iteration_count_scope\": \"max_iterations applies to total-stage LM; trace iteration remains cumulative\",\n";
out << " \"wellbore_recheck_trigger\": \"early loss exceeds initial early-stage exit by max(0.0001, 10%)\",\n";
- out << " \"wellbore_recheck_acceptance\": \"early decrease with fixed entry total and shape limits, each max(0.0001, 5%)\",\n";
+ out << " \"wellbore_recheck_acceptance\": \"early decrease with fixed entry shape limit max(0.0001, 5%); no_total_loss_constraint\",\n";
out << " \"wellbore_recheck_budget\": \"once when early shape degrades; each wellbore parameter stops after 2 ineffective steps, independent of total-stage budget\",\n";
out << " \"total_stage_shape_constraint\": false,\n";
out << " \"total_parameter_selection\": \"all_valid_free_columns\",\n";
@@ -2154,7 +2154,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
int heightStagnation = 0;
double heightScale = 1.0;
double heightSlope = -1.0;
- if(permeabilityColumn >= 0 && current.fitness >= m_targetError) {
+ if(permeabilityColumn >= 0) {
emit logMessageGenerated(tr("LM stage 1: align curve height using permeability only (up to %1 evaluations).")
.arg(heightBudget));
for(int trial = 0; trial < heightBudget && processPauseAndStop(); ++trial) {
@@ -2211,9 +2211,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
if(m_shouldStop) return LM_USER_STOPPED;
// 第二阶段不按迭代比例截断;普通形状按完整搜索轮次判断是否仍有显著改善。
- // 井储、表皮保持冻结,总误差上限仍固定于普通形状阶段入口。
- bool shapeStage = current.fitness >= m_targetError;
- double shapeValueLimit = current.fitness + qMax(0.02, 0.25 * current.fitness);
+ // 普通形状调整冻结井储、表皮,只按形状验收;总误差达标只在第三阶段判断。
+ bool shapeStage = true;
bool jointShapeStarted = false;
double shapeRoundBaseline = current.breakdown.shapeLoss;
int shapeRoundNumber = 0;
@@ -2230,7 +2229,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
bool wellboreRecheck = false;
bool wellboreRecheckDone = false;
double earlyWellboreBaseline = current.breakdown.earlyParallelLoss;
- double recheckTotalLimit = 0.0;
double recheckShapeLimit = 0.0;
// 先井储、再表皮;回检沿用相同顺序和前期指标,不回到形状阶段反复循环。
bool earlyShapeStage = shapeStage && wellboreParameterCount > 0;
@@ -2270,11 +2268,10 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
const int column = m_enabledParamIndices.indexOf(earlyShapeParameter);
return earlyGapDirection * (point.coordinates[column] - base.coordinates[column]) > 0.0 &&
point.breakdown.earlyParallelLoss < base.breakdown.earlyParallelLoss &&
- (!wellboreRecheck || (point.fitness <= recheckTotalLimit &&
- point.breakdown.shapeLoss <= recheckShapeLimit));
+ (!wellboreRecheck || point.breakdown.shapeLoss <= recheckShapeLimit);
}
return shapeStage
- ? point.breakdown.shapeLoss < base.breakdown.shapeLoss && point.fitness <= shapeValueLimit
+ ? point.breakdown.shapeLoss < base.breakdown.shapeLoss
// 预调整结束后恢复原 LM:有效候选只按整体误差下降接受。
: point.fitness < base.fitness;
};
@@ -2408,7 +2405,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
initialEarlyGapBias = trustRegionEarlyGapBias(current.breakdown);
earlyGapDirection = trustRegionEarlyGapDirection(initialEarlyGapBias);
earlyShapeHasImproved = false;
- recheckTotalLimit = current.fitness + qMax(1.0e-4, 0.05 * current.fitness);
+ // 回检只约束形状:允许总误差上升,但保护其他参数已调好的整体形状。
recheckShapeLimit = current.breakdown.shapeLoss + qMax(1.0e-4, 0.05 * current.breakdown.shapeLoss);
effectiveImprovementBaseline = current.breakdown.earlyParallelLoss;
// 其他参数已改变,回检入口重测形状灵敏度,方向由本轮初始间距重新确定。
@@ -2416,9 +2413,9 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
reuseSensitivityForNextStage();
rebuildRequested = true;
rebuildReason = QT_TR_NOOP("new sensitivity for wellbore recheck");
- emit logMessageGenerated(tr("Wellbore recheck: early error=%1, total limit=%2, shape limit=%3.")
+ emit logMessageGenerated(tr("Wellbore recheck: early shape error=%1, shape limit=%2.")
.arg(current.breakdown.earlyParallelLoss, 0, 'g', 6)
- .arg(recheckTotalLimit, 0, 'g', 6).arg(recheckShapeLimit, 0, 'g', 6));
+ .arg(recheckShapeLimit, 0, 'g', 6));
writeTraceRow(m_currentIteration, -1, "stage_switch", current.parameters, current.fitness,
true, 0, "shape_to_wellbore_recheck", ¤t.breakdown);
announceEarlyGapDirection();
@@ -2451,8 +2448,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
return;
}
effectiveImprovementBaseline = current.breakdown.shapeLoss;
- // 井储、表皮可使总误差上升;联合形状阶段从当前工作点建立固定上限。
- shapeValueLimit = current.fitness + qMax(0.02, 0.25 * current.fitness);
reuseSensitivityForNextStage();
emit logMessageGenerated(tr("Shape fitting continues with storage and skin fixed; a conditional wellbore recheck follows."));
writeTraceRow(m_currentIteration, -1, "stage_switch", current.parameters, current.fitness,
@@ -2733,8 +2728,9 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
¤t.breakdown);
emit logMessageGenerated(
(earlyShapeStage ? tr("Sensitivity probe accepted: early shape error=%1")
- : tr("Sensitivity probe accepted: total error=%1"))
- .arg(earlyShapeStage ? current.breakdown.earlyParallelLoss : current.fitness, 0, 'e', 4));
+ : (shapeStage ? tr("Sensitivity probe accepted: shape error=%1")
+ : tr("Sensitivity probe accepted: total error=%1")))
+ .arg(stageError(current), 0, 'e', 4));
} else {
restoreEvaluationState(current);
}
@@ -2819,11 +2815,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
: LM_LOCAL_OPTIMUM;
break;
}
- if(shapeStage && !earlyShapeStage && current.fitness < m_targetError) {
- finishShapeStage(tr("total target reached during shape fitting"));
- --iteration;
- continue;
- }
if(!shapeStage && current.fitness < m_targetError) {
promoteSampling(true);
stopReason = LM_TARGET_ACHIEVED;
@@ -2956,37 +2947,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
: buildTrustRegionFisherStep(stepInformation, columns, current.coordinates,
damping, trustRadius, minimumCoordinateStep, &step, &reduction);
if(!stepBuilt) continue;
- // 仅联合形状阶段预测总误差上限;井储、表皮步长不受总误差裁剪。
- if(shapeStage && !earlyShapeStage) {
- auto predictedGuard = [&](double scale) -> double {
- double energy = 0.0;
- for(int row = 0; row < current.breakdown.residualVector.size(); ++row) {
- double value = current.breakdown.residualVector[row];
- for(int column = 0; column < dimensions; ++column)
- value += scale * jacobian[row][column] * step[column];
- energy += value * value;
- }
- return qSqrt(energy);
- };
- const double currentGuard = predictedGuard(0.0);
- const double predictedLimit = currentGuard + 0.9 * qMax(0.0, shapeValueLimit - currentGuard);
- if(predictedGuard(1.0) > predictedLimit) {
- double low = 0.0, high = 1.0;
- for(int search = 0; search < 32; ++search) {
- const double middle = 0.5 * (low + high);
- if(predictedGuard(middle) <= predictedLimit) low = middle;
- else high = middle;
- }
- const double stepScale = low;
- for(int column = 0; column < dimensions; ++column) step[column] *= stepScale;
- if(qSqrt(trustRegionSquaredNorm(step)) < minimumCoordinateStep) continue;
- reduction = -trustRegionDotProduct(stepInformation.gradient, step);
- for(int a = 0; a < dimensions; ++a)
- for(int b = 0; b < dimensions; ++b)
- reduction -= 0.5 * step[a] * stepInformation.matrix[a][b] * step[b];
- if(!isFiniteNumber(reduction) || reduction <= 1.0e-14) continue;
- }
- }
const double tolerance = 1.0e-12 * qMax(predictedReduction, reduction);
if(selectedColumns.isEmpty() || reduction > predictedReduction + tolerance ||
(qAbs(reduction - predictedReduction) <= tolerance &&
@@ -3141,7 +3101,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
}
// 普通形状步真实表现可靠时,沿同一联合方向最多扩步试算一次,不区分参数类型。
- // 扩步仍须通过固定总误差上限且优于原步,否则保留原候选。
+ // 扩步只按整体形状验收,优于原步才替换,否则保留原候选。
if(shapeStage && !earlyShapeStage && acceptable(candidate, current) && processPauseAndStop()) {
const double ordinaryEnergy = 0.5 * trustRegionSquaredNorm(objectiveResidual);
const double ordinaryReduction = ordinaryEnergy - 0.5 * trustRegionSquaredNorm(candidate.breakdown.shapeResiduals);
@@ -3286,7 +3246,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
.arg(iteration + 1)
.arg(componentDisplayName)
.arg(selectedColumns.size())
- .arg(earlyShapeStage ? candidate.breakdown.earlyParallelLoss : candidate.fitness, 0, 'e', 4)
+ .arg(stageError(candidate), 0, 'e', 4)
.arg(accepted ? tr("accepted") : tr("rejected")));
emit progressUpdated(shapeStage ? -1 : totalIterations, m_globalBestFitness);
@@ -3306,9 +3266,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
if(stopReason == LM_LOCAL_OPTIMUM || samplingRefreshFailed) break;
}
- if(shapeStage && !earlyShapeStage && current.fitness < m_targetError) {
- finishShapeStage(tr("total target reached during shape fitting"));
- }
if(!shapeStage && current.fitness < m_targetError) {
promoteSampling(true);
stopReason = LM_TARGET_ACHIEVED;
@@ -3337,7 +3294,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
return LM_USER_STOPPED;
}
if(samplingRefreshFailed) return LM_OPTIMIZATION_FAILED;
- if(current.fitness < m_targetError) {
+ if(!shapeStage && current.fitness < m_targetError) {
promoteSampling(true);
return samplingRefreshFailed ? LM_OPTIMIZATION_FAILED : LM_TARGET_ACHIEVED;
}