From a8053b23a0261073b5cbaf19978dacb86a28ddd3 Mon Sep 17 00:00:00 2001 From: lvjunjie Date: Tue, 29 Sep 2026 16:03:51 +0800 Subject: [PATCH] =?UTF-8?q?refactor(nmNum):=20=E5=B0=86=E4=BA=95=E5=82=A8?= =?UTF-8?q?=E5=92=8C=E8=A1=A8=E7=9A=AE=E8=B0=83=E6=95=B4=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E4=B8=BA=E5=8D=95=E5=8F=82=E6=95=B0=20LM=20=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 按第一时间窗口形状误差的预计下降量选择参数、方向和初始步长 - 改善后步长翻倍,拒绝后减半,连续拒绝三次后切换参数 - 移除间距定向及初始形状变差时的扩步试探逻辑 - 同步拟合策略记录和中文日志资源 --- Bin/Config/Lang/cn/nmNum_cn.qm | Bin 147327 -> 147143 bytes Bin/Config/Lang/cn/nmNum_cn.ts | 12 +- .../nmCalculation/nmCalculationAutoFitLM.cpp | 305 ++++-------------- 3 files changed, 73 insertions(+), 244 deletions(-) diff --git a/Bin/Config/Lang/cn/nmNum_cn.qm b/Bin/Config/Lang/cn/nmNum_cn.qm index 3cf81428bf4af72037805cfb519fd4178f06df91..c3daf82477005f5eef97c00e171e3cc69670b6ee 100644 GIT binary patch delta 13907 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 R_)H3(yEH6iX&C#M{y$*vyN&<= delta 14161 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 Qd$1XniH9u{*^zVq3x{$HWB>pF diff --git a/Bin/Config/Lang/cn/nmNum_cn.ts b/Bin/Config/Lang/cn/nmNum_cn.ts index 6759fa7a..37b1bbbf 100644 --- a/Bin/Config/Lang/cn/nmNum_cn.ts +++ b/Bin/Config/Lang/cn/nmNum_cn.ts @@ -1217,16 +1217,12 @@ Reason: %1 没有其他勾选参数需要调整形状 - Early adjustment: adjust wellbore storage, then skin, to match the early pressure-derivative slope difference of the target. - 前期预调整:先调整井储,再调整表皮,使模拟压力与导数的前期斜率差接近目标曲线。 + Early adjustment: select storage or skin by predicted first-window shape reduction; halve the step after rejection and switch after 3 consecutive rejections. + 前期预调整:按第一时间窗口形状误差的预计下降量选择井储或表皮;拒绝后步长减半,连续拒绝三次换参数。 - Early adjustment: adjust skin to match the early pressure-derivative slope difference of the target. - 前期预调整:调整表皮,使模拟压力与导数的前期斜率差接近目标曲线。 - - - Wellbore storage adjustment ended: %1; now adjusting skin. - 井储调整结束:%1;开始单独调整表皮。 + all wellbore parameters visited once + 已勾选的井储、表皮参数均已完成一轮调整 Early wellbore adjustment ended: %1 diff --git a/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp b/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp index e3f6579b..4b0257c8 100644 --- a/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp +++ b/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp @@ -381,13 +381,6 @@ static double trustRegionEarlyGapBias(const AutoFitObjectiveBreakdownLM& objecti return bias / qLn(10.0); } -// 按用户指定的形态规则定向:初始模拟间距大则增大井储/表皮,小则减小。 -static double trustRegionEarlyGapDirection(double initialGapBias) -{ - if(!isFiniteNumber(initialGapBias) || qAbs(initialGapBias) <= 1.0e-12) return 0.0; - return initialGapBias > 0.0 ? 1.0 : -1.0; -} - // 第一窗口的形状能量与局部 Fisher 使用相同的中心时间和重叠权重, // 压力、导数同时参与;不重新插值或调用求解器。 static double trustRegionEarlyShapeEnergy(const QVector& residual) @@ -695,50 +688,6 @@ static bool buildBestSingleParameterStep(const TrustRegionFisher& information, return !selected->isEmpty(); } -// 前期每次只调一个参数:间距锁定符号,形状 LM 提供幅度和后续验收依据。 -static bool buildEarlyGapGuidedStep(const TrustRegionFisher& shapeInformation, - const QVector& selected, const QVector& coordinates, double direction, - double damping, double trustRadius, double minimumStep, - QVector* step, double* predictedReduction) -{ - if(selected.size() != 1 || direction == 0.0) return false; - const int column = selected[0]; - TrustRegionFisher guided = shapeInformation; - guided.gradient[column] = -direction * qAbs(shapeInformation.gradient[column]); - if(!buildTrustRegionFisherStep(guided, selected, coordinates, damping, - trustRadius, minimumStep, step, predictedReduction)) return false; - // 改方向后的预测必须用原形状模型重算,不能把上坡伪装成预测下降。 - const double delta = (*step)[column]; - *predictedReduction = -shapeInformation.gradient[column] * delta - - 0.5 * shapeInformation.matrix[column][column] * delta * delta; - return isFiniteNumber(*predictedReduction); -} - -// 放大当前方向,仍受传入的最大半径和参数边界限制。 -// 前期初始探路可跨过预测上坡区,最终仍按真实形状验收。 -static bool buildExpandedTrustRegionStep(const TrustRegionFisher& information, - const QVector& coordinates, const QVector& originalStep, - double maximumRadius, QVector* expandedStep, double* prediction, - bool requirePredictedDescent = true) -{ - const double norm = qSqrt(trustRegionSquaredNorm(originalStep)); - if(norm <= 1.0e-12) return false; - const double scale = qMin(2.0, maximumRadius / norm); - if(scale <= 1.01) return false; - expandedStep->resize(originalStep.size()); - double difference = 0.0; - for(int i = 0; i < originalStep.size(); ++i) { - (*expandedStep)[i] = qBound(0.0, coordinates[i] + scale * originalStep[i], 1.0) - coordinates[i]; - difference += qAbs((*expandedStep)[i] - originalStep[i]); - } - if(difference <= 1.0e-10) return false; - *prediction = -trustRegionDotProduct(information.gradient, *expandedStep); - for(int i = 0; i < expandedStep->size(); ++i) - for(int j = 0; j < expandedStep->size(); ++j) - *prediction -= 0.5 * (*expandedStep)[i] * information.matrix[i][j] * (*expandedStep)[j]; - return isFiniteNumber(*prediction) && (!requirePredictedDescent || *prediction > 1.0e-14); -} - // 每次得到有效真实候选后,使用满足最新割线条件的秩一修正更新完整残差 // Jacobian。这样模型吸收了刚得到的真实变化,又不必立即逐参数重新试算。 static void updateTrustRegionJacobian( @@ -1147,31 +1096,31 @@ void nmCalculationAutoFitLM::writeTraceMetaFile() QTextStream out(&metaFile); out << "{\n"; - out << " \"schema_version\": 39,\n"; + out << " \"schema_version\": 47,\n"; out << " \"strategy\": \"permeability_height_then_shape_then_joint_lm\",\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_priority\": \"wellbore_parameter_sweep_then_non_wellbore_sweep_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"; out << " \"early_gap_metric\": \"weighted_rms_log10_pressure_derivative_ratio_error_first_window_81_points\",\n"; out << " \"early_gap_bias_metric\": \"weighted_mean_signed_log10_gap_simulation_minus_target_first_window\",\n"; - out << " \"early_direction_policy\": \"initial_gap_bias_positive_increase_negative_decrease; direction_shared_and_locked_for_storage_and_skin; recompute_only_at_wellbore_recheck_entry\",\n"; - out << " \"early_initial_step_policy\": \"after_gap_direction_selection; storage_ratio_cap_1.05; skin_local_scale_fraction_0.02; no_cached_probe_acceptance_before_first_shape_improvement\",\n"; - 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_direction_policy\": \"first_window_shape_LM_selects_unvisited_wellbore_parameter_and_initial_direction; direction_locked_until_parameter_finished; gap_diagnostics_only\",\n"; + out << " \"early_initial_step_policy\": \"same_as_later_shape_sweep; initial_LM_coordinate_radius_0.24; no_cached_probe_acceptance\",\n"; + out << " \"early_expansion_policy\": \"accepted_double_from_new_point; rejected_halve_from_unchanged_point; coordinate_step_cap_0.60; switch_after_3_consecutive_rejections\",\n"; + out << " \"early_wellbore_acceptance\": \"first_window_shape_decrease; no_gap_direction_constraint; wellbore_recheck_retains_full_shape_guard\",\n"; out << " \"early_wellbore_total_constraint\": false,\n"; out << " \"shape_stage_total_constraint\": false,\n"; out << " \"shape_wellbore_parameters_frozen\": true,\n"; - out << " \"shape_sensitivity_refresh\": \"non_wellbore_columns_once_at_sweep_entry; secant updates during sweep; full Jacobian rebuilt at total-stage entry\",\n"; + out << " \"shape_sensitivity_refresh\": \"active_group_columns_once_at_each_sweep_entry; secant updates during sweep; full Jacobian rebuilt at total-stage entry\",\n"; out << " \"shape_expansion_policy\": \"lock parameter and direction; after each strict shape decrease double next coordinate step from accepted point; otherwise retain point and halve step\",\n"; out << " \"shape_radius_policy\": \"initial LM step capped at 0.24; subsequent coordinate steps capped at 0.60; no prediction-ratio gate\",\n"; - out << " \"shape_global_parameter_selection\": \"largest predicted reduction among unvisited non-wellbore parameters; finish current parameter before selecting next; each parameter visited once\",\n"; - out << " \"stage2_budget\": \"one parameter sweep; each parameter stops after 3 consecutive non-improving trials, a bound, or minimum step; existing solver failure limit retained\",\n"; + out << " \"shape_global_parameter_selection\": \"largest predicted reduction among unvisited parameters_in_current_group; finish current parameter before selecting next; each parameter visited once_per_sweep\",\n"; + out << " \"stage2_budget\": \"one sweep_per_parameter_group; switch_after_3_consecutive_rejections; bounds, minimum step and solver failure limit retained\",\n"; out << " \"shape_step_improvement_threshold\": \"any strict shape loss decrease; no cumulative improvement threshold\",\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 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 << " \"wellbore_recheck_budget\": \"once_when_early_shape_degrades; single_parameter_sweep_with_3_consecutive_rejections; stop_when_baseline_restored; independent_of_total_stage_budget\",\n"; out << " \"total_stage_shape_constraint\": false,\n"; out << " \"total_parameter_selection\": \"all_valid_free_columns\",\n"; out << " \"skin_difference_policy\": \"local_scale_in_all_stages\",\n"; @@ -1949,7 +1898,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() const double minimumCoordinateStep = 1.0e-5; const double minimumTrustRadius = 2.0e-3; const double maximumTrustRadius = 0.30; - // 第二阶段整体形状允许更大步幅;第三阶段继续使用原来的半径和预测验收规则。 + // 第二阶段两组逐参数调整共用较大步幅;第三阶段继续使用原来的半径和预测验收规则。 const double initialShapeTrustRadius = 0.24; const double maximumShapeTrustRadius = 0.60; // 误差下降至少达到绝对 1e-5 且相对当前有效基准 0.2% 才算有效改善。 @@ -2147,7 +2096,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() if(m_shouldStop) return LM_USER_STOPPED; - // 第二阶段先测灵敏度,再逐个调完非井筒参数;每个参数只访问一次。 + // 第二阶段先调井筒参数、再调其他参数;各组共用单参数扫描,每个参数只访问一次。 // 普通形状调整冻结井储、表皮,只按形状验收;总误差达标只在第三阶段判断。 bool shapeStage = true; bool singleShapeStarted = false; @@ -2169,31 +2118,14 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() bool wellboreRecheckDone = false; double earlyWellboreBaseline = current.breakdown.earlyParallelLoss; double recheckShapeLimit = 0.0; - // 先井储、再表皮;回检沿用相同顺序和前期指标,不回到形状阶段反复循环。 + // 井储、表皮在组内按预测下降量选序;回检沿用第一窗口指标和相同扫描规则。 bool earlyShapeStage = shapeStage && wellboreParameterCount > 0; - int earlyShapeParameter = storageColumn >= 0 ? 2 : 1; - double initialEarlyGapBias = trustRegionEarlyGapBias(current.breakdown); - double earlyGapDirection = trustRegionEarlyGapDirection(initialEarlyGapBias); - bool earlyShapeHasImproved = false; - auto announceEarlyGapDirection = [&]() { - // 两个参数共用本轮入口的方向;日志保留初始偏差,避免误读为探针响应方向。 - const QString directionName = earlyGapDirection > 0.0 ? "increase" : - (earlyGapDirection < 0.0 ? "decrease" : "matched"); - writeTraceRow(m_currentIteration, m_enabledParamIndices.indexOf(earlyShapeParameter), - "early_gap_direction", current.parameters, current.fitness, true, 0, - QString("%1_initial_gap_bias_%2").arg(directionName).arg(initialEarlyGapBias, 0, 'g', 12), - ¤t.breakdown); - emit logMessageGenerated(tr("Early gap guidance: %1, initial signed gap=%2, direction=%3; fixed for storage and skin.") - .arg(earlyShapeParameter == 2 ? tr("wellbore storage") : tr("skin")) - .arg(initialEarlyGapBias, 0, 'g', 6) - .arg(earlyGapDirection > 0.0 ? tr("increase") : - (earlyGapDirection < 0.0 ? tr("decrease") : tr("matched")))); - }; + trustRadius = initialShapeTrustRadius; auto parameterAllowedInStage = [&](int column) -> bool { const int parameterIndex = m_enabledParamIndices[column]; - // 候选和缓存灵敏度探针共用此限制,防止探针绕过形状阶段的冻结。 + // 各子阶段只开放对应参数组,实际候选始终只改变选中的一列。 if(!shapeStage) return true; - if(earlyShapeStage) return parameterIndex == earlyShapeParameter; + if(earlyShapeStage) return parameterIndex == 1 || parameterIndex == 2; return parameterIndex != 1 && parameterIndex != 2; }; auto stageError = [&](const TrustRegionEvaluation& point) -> double { @@ -2203,10 +2135,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() auto acceptable = [&](const TrustRegionEvaluation& point, const TrustRegionEvaluation& base) -> bool { if(!point.valid) return false; if(earlyShapeStage) { - // 缓存探针也只能沿间距确定的方向接受;停止仍看原来的前期形状改善。 - const int column = m_enabledParamIndices.indexOf(earlyShapeParameter); - return earlyGapDirection * (point.coordinates[column] - base.coordinates[column]) > 0.0 && - point.breakdown.earlyParallelLoss < base.breakdown.earlyParallelLoss && + // 第一窗口形状决定是否改善;补调保留原有的整体形状保护。 + return point.breakdown.earlyParallelLoss < base.breakdown.earlyParallelLoss && (!wellboreRecheck || point.breakdown.shapeLoss <= recheckShapeLimit); } return shapeStage @@ -2215,8 +2145,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() : point.fitness < base.fitness; }; auto acceptPoint = [&](const TrustRegionEvaluation& point) { - // 缓存探针和正式候选共用此标记;首次接受形状改善后,不再启用初始扩步探路。 - if(earlyShapeStage) earlyShapeHasImproved = true; + // 只发布通过当前阶段目标验收的真实候选。 current = point; publishAcceptedPoint(current); restoreEvaluationState(current); @@ -2225,14 +2154,10 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() ? tr("LM stage 2: adjust each shape parameter once; double the step after improvement, halve it after rejection, and switch after 3 consecutive rejections.") : tr("LM stage 3: original LM fitting; accept by total error only.")); if(earlyShapeStage) { - emit logMessageGenerated(earlyShapeParameter == 2 - ? tr("Early adjustment: storage then skin; pressure-derivative gap selects direction, early shape error controls acceptance and stopping.") - : tr("Early adjustment: skin; pressure-derivative gap selects direction, early shape error controls acceptance and stopping.")); - announceEarlyGapDirection(); + emit logMessageGenerated(tr("Early adjustment: select storage or skin by predicted first-window shape reduction; halve the step after rejection and switch after 3 consecutive rejections.")); } - // 有效改善始终相对“上一次有效改善后的误差”累计判断,避免一连串微小 - // 下降每次都清零计数;累计达到门槛后才开始新的有效改善基准。 + // 第三阶段有效改善相对上一次有效基准累计判断;第二阶段按逐参数拒绝次数结束。 double effectiveImprovementBaseline = stageError(current); int fullDataRejections = 0; bool samplingRefreshFailed = false; @@ -2296,7 +2221,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() consecutiveSolverFailures = 0; stagnationConfirmationRequested = false; globalFallbackAttempted = false; - trustRadius = shapeStage && !earlyShapeStage ? initialShapeTrustRadius : 0.12; + trustRadius = shapeStage ? initialShapeTrustRadius : 0.12; damping = 0.01; }; auto enterTotalStage = [&](const QString& reason) { @@ -2306,6 +2231,9 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() shapeStage = false; earlyShapeStage = false; wellboreRecheck = false; + activeShapeColumn = -1; + shapeCoordinateStep = 0.0; + consecutiveShapeRejections = 0; effectiveImprovementBaseline = current.fitness; reuseSensitivityForNextStage(); // 第二阶段只测各子阶段需要的列;所有出口都在当前点重建完整 J,不能把缺列模型带入整体 LM。 @@ -2338,14 +2266,16 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() } wellboreRecheck = true; earlyShapeStage = true; - earlyShapeParameter = storageColumn >= 0 ? 2 : 1; - initialEarlyGapBias = trustRegionEarlyGapBias(current.breakdown); - earlyGapDirection = trustRegionEarlyGapDirection(initialEarlyGapBias); - earlyShapeHasImproved = false; // 回检只约束形状:允许总误差上升,但保护其他参数已调好的整体形状。 recheckShapeLimit = current.breakdown.shapeLoss + qMax(1.0e-4, 0.05 * current.breakdown.shapeLoss); + // 回检重新开放井储和表皮,清除上一组留下的活动步长及完成标记。 + if(storageColumn >= 0) shapeParameterFinished[storageColumn] = false; + if(skinColumn >= 0) shapeParameterFinished[skinColumn] = false; + activeShapeColumn = -1; + shapeCoordinateStep = 0.0; + consecutiveShapeRejections = 0; effectiveImprovementBaseline = current.breakdown.earlyParallelLoss; - // 其他参数已改变,回检入口重测形状灵敏度,方向由本轮初始间距重新确定。 + // 其他参数已改变,回检入口重测第一窗口形状灵敏度,由 LM 重新确定方向和步幅。 jacobian.clear(); reuseSensitivityForNextStage(); rebuildRequested = true; @@ -2355,24 +2285,14 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() .arg(recheckShapeLimit, 0, 'g', 6)); writeTraceRow(m_currentIteration, -1, "stage_switch", current.parameters, current.fitness, true, 0, "shape_to_wellbore_recheck", ¤t.breakdown); - announceEarlyGapDirection(); }; auto finishEarlyShapeStage = [&](const QString& reason) { - if(earlyShapeParameter == 2 && skinColumn >= 0) { - earlyShapeParameter = 1; - earlyShapeHasImproved = false; - effectiveImprovementBaseline = current.breakdown.earlyParallelLoss; - reuseSensitivityForNextStage(); - // 井储已变,重测表皮的形状灵敏度和步幅,方向仍保持本轮入口的判断。 - rebuildRequested = true; - rebuildReason = QT_TR_NOOP("refresh shape sensitivity at skin adjustment entry"); - emit logMessageGenerated(tr("Wellbore storage adjustment ended: %1; now adjusting skin.").arg(reason)); - writeTraceRow(m_currentIteration, -1, "stage_switch", current.parameters, current.fitness, - true, 0, wellboreRecheck ? "recheck_storage_to_skin" : "storage_to_skin", ¤t.breakdown); - announceEarlyGapDirection(); - return; - } + if(m_shouldStop) return; + // 井筒参数整组完成后才切换目标,不能把旧组的活动参数或步长带入下一组。 + activeShapeColumn = -1; + shapeCoordinateStep = 0.0; + consecutiveShapeRejections = 0; if(wellboreRecheck) { enterTotalStage(reason); return; @@ -2404,11 +2324,12 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() for(int column = 0; column < dimensions; ++column) { if(parameterAllowedInStage(column) && !shapeParameterFinished[column]) return; } - finishShapeStage(tr("all shape parameters visited once")); + if(earlyShapeStage) finishEarlyShapeStage(tr("all wellbore parameters visited once")); + else finishShapeStage(tr("all shape parameters visited once")); }; auto completeShapeSearchStep = [&](bool accepted) { - if(!shapeStage || earlyShapeStage || m_shouldStop) return; - // 只按本次真实下降控制实际步长;不再使用累计 10% 门槛提前结束整轮。 + if(!shapeStage || m_shouldStop) return; + // 两组参数共用扩缩步规则:改善后放大,拒绝后从已接受点缩步重试。 ++shapeStepCount; consecutiveShapeRejections = accepted ? 0 : consecutiveShapeRejections + 1; shapeCoordinateStep = qBound(-maximumShapeTrustRadius, @@ -2425,11 +2346,10 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() }; auto registerEffectiveImprovement = [&](double fitness) -> bool { - if(shapeStage && !earlyShapeStage) return false; + if(shapeStage) return false; const double requiredImprovement = qMax( - shapeStage ? 1.0e-4 : effectiveAbsoluteImprovement, - qAbs(effectiveImprovementBaseline) * - (shapeStage ? 0.01 : effectiveRelativeImprovement)); + effectiveAbsoluteImprovement, + qAbs(effectiveImprovementBaseline) * effectiveRelativeImprovement); const double improvement = effectiveImprovementBaseline - fitness; if(improvement < requiredImprovement) { return false; @@ -2443,20 +2363,13 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() return true; }; - // 普通形状的失败试算缩步并累计当前参数的拒绝次数; - // 前期井储、表皮与整体 LM 沿用各自的无效次数处理。 + // 第二阶段求解失败也进入当前参数的拒绝处理,第三阶段保留原 LM 停滞确认。 auto recordIneffectiveStep = [&]() -> bool { - if(shapeStage && !earlyShapeStage) { + if(shapeStage) { completeShapeSearchStep(false); return false; } ++consecutiveIneffectiveSteps; - if(earlyShapeStage) { - // 一次拒绝只缩步,再给当前参数一次真实尝试;连续无改善才交给下一段。 - if(consecutiveIneffectiveSteps >= 2) - finishEarlyShapeStage(tr("2 consecutive steps without effective early improvement")); - return false; - } if(!globalFallbackAttempted) { return false; } @@ -2525,9 +2438,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() processPauseAndStop(); ++column) { const int parameterIndex = m_enabledParamIndices[column]; - if(earlyShapeStage && parameterIndex != 1 && parameterIndex != 2) continue; - // 普通形状阶段跳过冻结的井储、表皮,避免无用正演;回检和整体阶段会重新差分。 - if(shapeStage && !earlyShapeStage && !parameterAllowedInStage(column)) continue; + // 每组入口只测该组开放的参数;回检和整体阶段会重新差分。 + if(shapeStage && !parameterAllowedInStage(column)) continue; const double lower = m_parameterLower[parameterIndex]; const double upper = m_parameterUpper[parameterIndex]; if(upper <= lower) continue; @@ -2615,11 +2527,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() jacobianColumnValid[column] = true; columnBuilt = true; - // 后半段形状探针仅用于灵敏度,正式调整必须经过单参数 LM 预测选优。 - // 前期同时测井储和表皮,但缓存探针不能绕过当前子阶段的选参限制。 - // 前期首次正式调整必须从小步开始,测形状灵敏度的大探针不能提前成为工作点。 - if((!shapeStage || earlyShapeStage) && - (!earlyShapeStage || earlyShapeHasImproved) && + // 第二阶段探针只用于灵敏度;只有第三阶段保留直接接受缓存探针的规则。 + if(!shapeStage && parameterAllowedInStage(column) && acceptable(probe, base) && (!bestProbe.valid || stageError(probe) < stageError(bestProbe))) { bestProbe = probe; @@ -2640,12 +2549,12 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() } } // 冻结列成功不能掩盖所有可调形状列的求解失败;有效零梯度交给逐参数选步处理。 - if(validColumnCount == 0 || (shapeStage && !earlyShapeStage && !hasActiveSensitivity) || m_shouldStop) { + if(validColumnCount == 0 || (shapeStage && !hasActiveSensitivity) || m_shouldStop) { restoreEvaluationState(base); return false; } - // 前期井储/表皮和整体阶段仍可接受更优缓存探针;后半段形状只由 LM 选步。 + // 只有整体阶段可接受更优缓存探针,第二阶段两组参数都由单参数 LM 选步。 // 所有列先基于同一个 base 建完,再用已知割线平移 Jacobian,避免边算边移动基点。 if(bestProbe.valid && bestProbeColumn >= 0) { QVector acceptedStep(dimensions, 0.0); @@ -2663,14 +2572,10 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() current.fitness, true, 0, - wellboreRecheck ? "wellbore_recheck_accepted_cached_probe" : - (earlyShapeStage ? "early_shape_accepted_cached_probe" : - (shapeStage ? "shape_accepted_cached_probe" : "total_accepted_cached_probe")), + "total_accepted_cached_probe", ¤t.breakdown); emit logMessageGenerated( - (earlyShapeStage ? tr("Sensitivity probe accepted: early shape error=%1") - : (shapeStage ? tr("Sensitivity probe accepted: shape error=%1") - : tr("Sensitivity probe accepted: total error=%1"))) + tr("Sensitivity probe accepted: total error=%1") .arg(stageError(current), 0, 'e', 4)); } else { restoreEvaluationState(current); @@ -2764,12 +2669,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() stopReason = LM_MAX_ITERATIONS; break; } - if(wellboreRecheck && current.breakdown.earlyParallelLoss <= - earlyWellboreBaseline + qMax(1.0e-4, 0.10 * earlyWellboreBaseline)) { - enterTotalStage(tr("wellbore recheck completed during sensitivity evaluation")); - --iteration; - continue; - } // 差分探针不等于 LM 候选;重建后继续按当前阶段求步并真实评价,再确认停滞。 registerEffectiveImprovement(stageError(current)); } @@ -2792,9 +2691,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() } const QVector information = buildTrustRegionFisher( objectiveJacobian, objectiveResidual, jacobianColumnValid, objectiveCoordinates); - const TrustRegionFisher& global = information[kAutoFitTimeWindowCount]; // 前期残差已含第一窗口权重,使用全局和,不能再次乘局部窗口权重。 - const TrustRegionFisher& stepInformation = global; + const TrustRegionFisher& global = information[kAutoFitTimeWindowCount]; QVector stageColumnValid = jacobianColumnValid; for(int column = 0; column < dimensions; ++column) { if(!parameterAllowedInStage(column)) stageColumnValid[column] = false; @@ -2804,32 +2702,13 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() double predictedReduction = 0.0; const int selectedWindow = earlyShapeStage ? 0 : -1; - // 前期只开放当前井储或表皮;后半段形状从有效自由列中选一个,整体 LM 仍联合求解。 + // 第二阶段从当前组有效自由列中选一个,整体 LM 仍联合求解。 // 保留弱敏感、相关及边界列供预测比较;窗口只保留作误差诊断。 for(int column = 0; column < dimensions; ++column) { - if(stageColumnValid[column] && (earlyShapeStage || global.matrix[column][column] > 0.0)) + if(stageColumnValid[column] && global.matrix[column][column] > 0.0) selectedColumns.append(column); } - if(earlyShapeStage) { - double earlyStepRadius = trustRadius; - if(!earlyShapeHasImproved && selectedColumns.size() == 1) { - // 首次调整沿用小步起调,形状变差时由后面的同向扩步循环处理。 - const int column = selectedColumns[0]; - const int parameterIndex = m_enabledParamIndices[column]; - const double lower = m_parameterLower[parameterIndex]; - const double upper = m_parameterUpper[parameterIndex]; - const double smallStep = useTrustRegionLogScale(parameterIndex, lower, upper) - ? qLn(1.05) / (qLn(upper) - qLn(lower)) - : (parameterIndex == 1 ? 0.02 * qMax(0.1, qAbs(current.parameters[column])) - : 0.05 * qMax(1.0e-8, qAbs(current.parameters[column]))) / (upper - lower); - earlyStepRadius = qMin(trustRadius, smallStep); - } - if(selectedColumns.isEmpty() || !buildEarlyGapGuidedStep( - stepInformation, selectedColumns, current.coordinates, earlyGapDirection, - damping, earlyStepRadius, minimumCoordinateStep, &coordinateStep, &predictedReduction)) { - selectedColumns.clear(); - } - } else if(shapeStage) { + if(shapeStage) { // 首步由灵敏度选出尚未调过的参数;后续锁定方向,直接使用扩缩后的步长。 if(activeShapeColumn < 0) { QVector availableColumns; @@ -2848,12 +2727,13 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() "largest_predicted_reduction_unvisited", ¤t.breakdown); } else { // 剩余参数均无可行预测下降步时逐项记录,不能重复选择已完成参数。 + const bool finishingEarlyShape = earlyShapeStage; for(int column = 0; column < dimensions; ++column) { if(!parameterAllowedInStage(column) || shapeParameterFinished[column]) continue; activeShapeColumn = column; finishShapeParameter(jacobianColumnValid[column] ? "no_feasible_descent_step" : "invalid_sensitivity"); - if(!shapeStage || earlyShapeStage) break; + if(!shapeStage || earlyShapeStage != finishingEarlyShape) break; } --iteration; continue; @@ -2887,12 +2767,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() // 当前阶段没有可行下降步时,收缩半径并进入原有重建/收敛处理。 if(selectedColumns.isEmpty()) { - if(earlyShapeStage) { - finishEarlyShapeStage(tr("no feasible early adjustment direction or parameter at bound")); - // 尚未求解候选,原迭代留给其余参数,不额外占用迭代或求解预算。 - --iteration; - continue; - } if(trustRadius <= minimumTrustRadius * 1.01 && modelRebuiltAtMinimumRadius) { if(promoteSampling(false)) continue; @@ -2922,14 +2796,14 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() selectedParameterIndices << QString::number(m_enabledParamIndices[selectedColumns[i]]); } QString selectionName = (wellboreRecheck ? QString("recheck_") : QString()) + QString(earlyShapeStage - ? (earlyShapeParameter == 2 ? "storage_parallel_" : "skin_parallel_") : (shapeStage ? "shape_" : "total_")) + (selectedWindow >= 0 + ? (m_enabledParamIndices[selectedColumns[0]] == 2 ? "storage_parallel_" : "skin_parallel_") : (shapeStage ? "shape_" : "total_")) + (selectedWindow >= 0 ? QString("window_%1").arg(selectedWindow + 1) : QString("global")) + "_params_" + selectedParameterIndices.join("_"); TrustRegionEvaluation candidate; candidate.coordinates = candidateCoordinates; candidate.parameters = parametersFromCoordinates(candidate.coordinates); - if(earlyShapeStage && earlyShapeParameter == 2) { + if(earlyShapeStage && m_enabledParamIndices[selectedColumns[0]] == 2) { emit logMessageGenerated(tr("Wellbore storage trial: early shape error=%1, C=%2 -> %3") .arg(current.breakdown.earlyParallelLoss, 0, 'g', 5) .arg(current.parameters[storageColumn], 0, 'g', 6) @@ -2942,43 +2816,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() &candidate.curve, &candidate.elapsedMs); - // 初始形状变差时先沿锁定方向跨大步探路,不立即缩步或累计无效次数。 - // 始终以未移动的 current 为基点;每次翻倍并裁到边界,差解不发布、不接受。 - bool earlyInitialExpanded = false; - bool earlyInitialExpansionAtBound = false; - while(earlyShapeStage && !earlyShapeHasImproved && candidate.valid && - candidate.breakdown.earlyParallelLoss > current.breakdown.earlyParallelLoss && - processPauseAndStop()) { - QVector expandedStep; - double expandedPrediction = 0.0; - if(!buildExpandedTrustRegionStep(stepInformation, current.coordinates, coordinateStep, - 1.0, &expandedStep, &expandedPrediction, false)) { - earlyInitialExpansionAtBound = true; - break; - } - writeTraceRow(m_currentIteration, selectedColumns[0], "early_initial_expansion", - candidate.parameters, candidate.fitness, true, candidate.elapsedMs, - "shape_worse_expand_same_direction", &candidate.breakdown); - restoreEvaluationState(current); - TrustRegionEvaluation expanded; - expanded.coordinates = current.coordinates; - for(int column = 0; column < dimensions; ++column) - expanded.coordinates[column] += expandedStep[column]; - expanded.parameters = parametersFromCoordinates(expanded.coordinates); - const int column = selectedColumns[0]; - emit logMessageGenerated(tr("Early shape initially worsened: %1, trial=%2 -> %3; expanding in the same direction.") - .arg(earlyShapeParameter == 2 ? tr("wellbore storage") : tr("skin")) - .arg(candidate.parameters[column], 0, 'g', 6) - .arg(expanded.parameters[column], 0, 'g', 6)); - expanded.valid = evaluateTrustRegionPoint(expanded.parameters, &expanded.fitness, - &expanded.breakdown, &expanded.curve, &expanded.elapsedMs); - candidate = expanded; - coordinateStep = expandedStep; - predictedReduction = expandedPrediction; - stepNorm = qSqrt(trustRegionSquaredNorm(coordinateStep)); - earlyInitialExpanded = true; - } - if(earlyInitialExpanded) selectionName += "_initial_expanded"; if(m_shouldStop) { restoreEvaluationState(current); stopReason = LM_USER_STOPPED; @@ -3003,7 +2840,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() "solver_invalid_" + selectionName, nullptr); restoreEvaluationState(current); - if(consecutiveSolverFailures >= 2 && (!shapeStage || earlyShapeStage)) { + if(consecutiveSolverFailures >= 2 && !shapeStage) { rebuildRequested = true; rebuildReason = QT_TR_NOOP("2 consecutive solver failures"); } @@ -3048,7 +2885,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() const bool poorPrediction = predictedReduction > predictionFloor && (!isFiniteNumber(reductionRatio) || reductionRatio < 0.25); consecutivePoorPredictions = poorPrediction ? consecutivePoorPredictions + 1 : 0; - if(consecutivePoorPredictions >= 2 && (!shapeStage || earlyShapeStage)) { + if(consecutivePoorPredictions >= 2 && !shapeStage) { rebuildRequested = true; rebuildReason = QT_TR_NOOP("2 consecutive steps with actual improvement below 25% of prediction"); } @@ -3060,7 +2897,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() fullDataRejections = 0; } QString componentName = earlyShapeStage - ? (earlyShapeParameter == 2 ? "storage_parallel" : "skin_parallel") : (shapeStage ? "shape" : "total"); + ? (m_enabledParamIndices[selectedColumns[0]] == 2 ? "storage_parallel" : "skin_parallel") : (shapeStage ? "shape" : "total"); if(accepted) { // 当前阶段接受候选后同步发布参数、曲线和诊断。 @@ -3069,8 +2906,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() ++acceptedSinceRebuild; consecutiveRejectedSteps = 0; - // 井筒调整及第三阶段保留原 LM 控制;逐参数粗调在步末直接扩缩实际步长。 - if(!shapeStage || earlyShapeStage) { + // 第三阶段保留原 LM 控制;第二阶段两组都在步末直接扩缩实际步长。 + if(!shapeStage) { if(reductionRatio > 0.75) { damping = qMax(1.0e-8, damping * 0.5); if(stepNorm >= trustRadius * 0.8) { @@ -3086,7 +2923,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() } } - if(acceptedSinceRebuild >= 10 && !rebuildRequested && (!shapeStage || earlyShapeStage)) { + if(acceptedSinceRebuild >= 10 && !rebuildRequested && !shapeStage) { rebuildRequested = true; rebuildReason = QT_TR_NOOP("10 accepted steps since last rebuild"); } @@ -3138,11 +2975,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting() emit progressUpdated(shapeStage ? -1 : totalIterations, m_globalBestFitness); // 先记录当前试调结果,再发布阶段切换,避免日志显示为未试调就结束。 - if(earlyInitialExpansionAtBound && !accepted) { - finishEarlyShapeStage(tr("initial same-direction expansion reached the parameter bound without early shape improvement")); - continue; - } - if(shapeStage && !earlyShapeStage) { + if(shapeStage) { completeShapeSearchStep(accepted); continue; }