@ -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 < double > & residual )
@ -695,50 +688,6 @@ static bool buildBestSingleParameterStep(const TrustRegionFisher& information,
return ! selected - > isEmpty ( ) ;
}
// 前期每次只调一个参数:间距锁定符号,形状 LM 提供幅度和后续验收依据。
static bool buildEarlyGapGuidedStep ( const TrustRegionFisher & shapeInformation ,
const QVector < int > & selected , const QVector < double > & coordinates , double direction ,
double damping , double trustRadius , double minimumStep ,
QVector < double > * 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 < double > & coordinates , const QVector < double > & originalStep ,
double maximumRadius , QVector < double > * 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_entr y\" , \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_onl y\" , \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 ) ,
& current . 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 = = earlySha peP arameter;
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 " , & current . 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 " , & current . 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 < double > 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 " ,
& current . 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 < TrustRegionFisher > information = buildTrustRegionFisher (
objectiveJacobian , objectiveResidual , jacobianColumnValid , objectiveCoordinates ) ;
const TrustRegionFisher & global = information [ kAutoFitTimeWindowCount ] ;
// 前期残差已含第一窗口权重,使用全局和,不能再次乘局部窗口权重。
const TrustRegionFisher & stepInformation = global ;
const TrustRegionFisher & global = information [ kAutoFitTimeWindowCount ] ;
QVector < bool > 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 < int > availableColumns ;
@ -2848,12 +2727,13 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
" largest_predicted_reduction_unvisited " , & current . 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 < double > 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 ;
}