You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Include/nmNum/nmCalculation/nmCalculationAutoFitLM.h

233 lines
7.6 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#ifndef NMCALCULATIONAUTOFITLM_H
#define NMCALCULATIONAUTOFITLM_H
#include <QObject>
#include <QVector>
#include <QPointF>
#include <QString>
#include <QStringList>
#include <QFile>
#include <limits>
#include "nmCalculation_global.h"
// 固定对数时间窗口的误差诊断。时间边界为不含重叠区的基础边界;
// rmsError 是局部加权均方根,energy 是对整体残差能量的贡献。
struct AutoFitTimeWindowLM {
double timeMin;
double timeMax;
double weightSum;
double rmsError;
double energy;
AutoFitTimeWindowLM()
: timeMin(0.0), timeMax(0.0), weightSum(0.0), rmsError(0.0), energy(0.0)
{}
};
// 双对数曲线误差分解。预调整使用纵向偏差,形状阶段使用双曲线斜率残差,
// 整体阶段只使用 total 接受候选;时间窗口和残差用于 Fisher 选参。
struct AutoFitObjectiveBreakdownLM {
bool valid;
double total;
double pressureLoss;
double derivativeLoss;
QVector<double> residualVector;
QVector<AutoFitTimeWindowLM> timeWindows;
double verticalCommonBias;
double verticalLoss;
bool verticalReliable;
double horizontalPhysicalShift;
double horizontalLoss;
bool horizontalReliable;
bool registrationAmbiguous;
// 与整体误差共用 log-time 采样网格,斜率跨度约为完整对数时域的 10%。
QVector<double> shapeResiduals;
// 前期数值和形状残差沿用同一网格与斜率跨度,均含第一窗口权重。
// earlyParallelResiduals/Loss 沿用历史字段名,现为压力、导数分别匹配目标的形状误差。
// earlyParallelBias 仍记录相对斜率偏差,仅供诊断。
QVector<double> earlyValueResiduals;
QVector<double> earlyParallelResiduals;
double earlyValueLoss;
double earlyParallelLoss;
double earlyParallelBias;
double pressureVerticalBias;
double derivativeVerticalBias;
double shapeLoss;
double lateDerivativeSlopeBias;
double lateDerivativeTrendLoss;
bool lateDerivativeTrendReliable;
AutoFitObjectiveBreakdownLM()
: valid(false)
, total(1.0e10)
, pressureLoss(std::numeric_limits<double>::quiet_NaN())
, derivativeLoss(std::numeric_limits<double>::quiet_NaN())
, verticalCommonBias(std::numeric_limits<double>::quiet_NaN())
, verticalLoss(std::numeric_limits<double>::quiet_NaN())
, verticalReliable(false)
, horizontalPhysicalShift(std::numeric_limits<double>::quiet_NaN())
, horizontalLoss(std::numeric_limits<double>::quiet_NaN())
, horizontalReliable(false)
, registrationAmbiguous(false)
, earlyValueLoss(std::numeric_limits<double>::quiet_NaN())
, earlyParallelLoss(std::numeric_limits<double>::quiet_NaN())
, earlyParallelBias(std::numeric_limits<double>::quiet_NaN())
, pressureVerticalBias(0.0)
, derivativeVerticalBias(0.0)
, shapeLoss(std::numeric_limits<double>::quiet_NaN())
, lateDerivativeSlopeBias(std::numeric_limits<double>::quiet_NaN())
, lateDerivativeTrendLoss(std::numeric_limits<double>::quiet_NaN())
, lateDerivativeTrendReliable(false)
{}
};
// 有限差分 + LM/信赖域拟合的停止原因。
enum StopReasonLM {
LM_CONTINUE_OPTIMIZATION = 0,
LM_TARGET_ACHIEVED = 1,
LM_TRUE_CONVERGENCE = 2,
LM_LOCAL_OPTIMUM = 3,
LM_MAX_ITERATIONS = 4,
LM_USER_STOPPED = 5,
LM_CONSECUTIVE_FAILURES = 6,
LM_OPTIMIZATION_FAILED = 7
};
class NMCALCULATION_EXPORT nmCalculationAutoFitLM : public QObject
{
Q_OBJECT
public:
explicit nmCalculationAutoFitLM(QObject* parent = 0);
~nmCalculationAutoFitLM();
void setTargetLogLogData(const QVector<QVector<double> >& targetData);
bool startAutoFitting();
void stopFitting();
QVector<double> getBestSolution() const;
double getBestFitness() const;
AutoFitObjectiveBreakdownLM getLastObjectiveBreakdown() const;
QString getLastError() const;
bool isRunning() const;
int getCurrentIteration() const;
int getTotalEvaluations() const;
void resetOptimizer();
void setTargetWellName(const QString& wellName);
signals:
void progressUpdated(int iteration, double bestFitness);
void fittingFinished(bool success, const QString& message);
void bestCurveUpdated(QVector<QVector<double> > targetData,
QVector<QVector<double> > bestData,
int iteration,
double fitness);
/** @brief 优化迭代结束,开始用当前最优参数生成正式结果。 */
void finalizingStarted();
void logMessageGenerated(const QString& message);
private:
bool initializeTemporaryDirectory();
void cleanupTemporaryDirectory();
bool loadAllConfigFromDataManager();
void loadOptimizationConfig();
void loadParameterBounds();
void extractUserInitialValues();
// 有限差分 + LM/信赖域核心算法。
StopReasonLM runTrustRegionFitting();
bool evaluateTrustRegionPoint(const QVector<double>& parameters,
double* fitness,
AutoFitObjectiveBreakdownLM* breakdown,
QVector<QVector<double> >* curve,
int* elapsedMs);
double evaluateFitness(const QVector<double>& parameters, bool retrySolver = true);
void applyParametersToDataManager(const QVector<double>& parameters);
void updateReservoirParameters(const QVector<double>& parameters);
void updateWellParameters(const QVector<double>& parameters);
QVector<QVector<double> > runSolver();
QVector<QVector<double> > runSolverDll();
bool runFinalFullSolver();
void saveOptimizationResult();
void validateAndProtectFinalResult();
QString getStopReasonDescription(StopReasonLM reason) const;
int getEnabledParameterCount() const;
// LM 运行轨迹。
void initializeTraceFile();
void closeTraceFile();
void writeTraceHeader();
void writeTraceMetaFile();
void writeTraceRow(int iteration,
int parameterIndex,
const QString& phase,
const QVector<double>& parameters,
double solverObjective,
bool solverSuccess,
int elapsedMs,
const QString& decision,
const AutoFitObjectiveBreakdownLM* objectiveBreakdown = nullptr);
QVector<double> buildTraceParameterVector(const QVector<double>& selectedParameters) const;
void emitRunSummary(bool success, StopReasonLM finalReason);
bool validateParameters(const QVector<double>& parameters) const;
bool validateLogLogData(const QVector<QVector<double> >& logLogData) const;
bool validateInitialValues() const;
bool validateSolverResult(const QVector<QVector<double> >& result) const;
double calculateLogLogCurveError(const QVector<QVector<double> >& target,
const QVector<QVector<double> >& result);
private:
bool m_isRunning;
bool m_shouldStop;
bool m_isFinalizing;
int m_currentIteration;
QString m_lastError;
QVector<double> m_initialValues;
QVector<double> m_globalBestPosition;
double m_globalBestFitness;
AutoFitObjectiveBreakdownLM m_globalBestObjectiveBreakdown;
QVector<QVector<double> > m_lastEvaluatedLogLogData;
QVector<QVector<double> > m_globalBestLogLogData;
mutable AutoFitObjectiveBreakdownLM m_lastObjectiveBreakdown;
QVector<QVector<double> > m_userInitialLogLogData;
AutoFitObjectiveBreakdownLM m_userInitialObjectiveBreakdown;
// 参数索引:0 k,1 skin,2 wellboreC,3 phi,4 Swi,
// 5 Dfc,6 fractureHalfLength。
QVector<bool> m_parameterSelected;
QVector<double> m_parameterLower;
QVector<double> m_parameterUpper;
QVector<int> m_enabledParamIndices;
QVector<QVector<double> > m_targetLogLogData;
// 首次有效评价后固定,后续候选必须覆盖同一时间区间。
double m_comparisonTimeMin;
double m_comparisonTimeMax;
QString m_targetWellName;
int m_maxIterations;
double m_targetError;
int m_totalEvaluations;
int m_successfulEvaluations;
volatile int m_evaluationInProgress;
int m_consecutiveFailures;
int m_maxConsecutiveFailures;
QVector<double> m_userInitialSolution;
double m_userInitialFitness;
bool m_hasValidUserSolution;
QString m_tempDirectory;
QString m_traceRunId;
QString m_traceFilePath;
QString m_traceMetaFilePath;
QFile m_traceFile;
};
#endif // NMCALCULATIONAUTOFITLM_H