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

224 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 <QAtomicInt>
#include <limits>
#include "nmCalculation_global.h"
#include <functional>
struct nmSensitivityFitSettings;
// 双对数曲线误差分解。预调整使用纵向偏差,形状阶段使用双曲线斜率残差,
// 总误差部分只使用 total 接受候选;两个 LM 目标均联合调整有效参数。
struct AutoFitObjectiveBreakdownLM {
bool valid;
double total;
double pressureLoss;
double derivativeLoss;
QVector<double> residualVector;
double verticalCommonBias;
double verticalLoss;
bool verticalReliable;
double horizontalPhysicalShift;
double horizontalLoss;
bool horizontalReliable;
bool registrationAmbiguous;
// 与整体误差共用 log-time 采样网格,斜率跨度约为完整对数时域的 10%。
QVector<double> shapeResiduals;
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)
, 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_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();
// 在样本副本上复用拟合算法,评价和停止由敏感性任务负责,不写回当前模型。
bool startSensitivityFitting(const nmSensitivityFitSettings& settings,
const std::function<QVector<QVector<double> >(const QVector<double>&)>& evaluate,
const std::function<bool()>& cancelled, bool verticalWell);
void stopFitting();
QVector<double> getBestSolution() const;
double getBestFitness() const;
AutoFitObjectiveBreakdownLM getLastObjectiveBreakdown() const;
QString getLastError() const;
bool isRunning() const;
int getCurrentIteration() const;
int getTotalEvaluations() const;
int getSolverCallCount() const;
void resetOptimizer();
void setTargetWellName(const QString& wellName);
signals:
// 阶段仅用于界面显示:0 初始求解,1 高度,2 形状,3 总误差。
void fittingStageChanged(int stage);
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);
// 优化迭代结束,开始用当前最优参数生成正式结果。
void finalizingStarted();
void logMessageGenerated(const QString& message);
private slots:
// 由求解线程直接通知,仅累加原子计数,不操作界面。
void recordSolverCall();
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> > runSolverDll();
bool runFinalFullSolver();
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);
void emitTrialLog(const QString& title, const AutoFitObjectiveBreakdownLM& before,
const AutoFitObjectiveBreakdownLM& after, bool valid, bool accepted, bool shapeStage);
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:
const nmSensitivityFitSettings* m_sensitivitySettings;
std::function<QVector<QVector<double> >(const QVector<double>&)> m_sensitivityEvaluate;
std::function<bool()> m_sensitivityCancelled;
bool m_sensitivityVerticalWell;
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;
AutoFitObjectiveBreakdownLM m_lastObjectiveBreakdown;
QVector<QVector<double> > m_userInitialLogLogData;
AutoFitObjectiveBreakdownLM m_userInitialObjectiveBreakdown;
// 参数索引:0 k,1 skin,2 wellboreC,3 phi,4 Dfc,5 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;
QAtomicInt m_solverCallCount;
int m_successfulEvaluations;
volatile int m_evaluationInProgress;
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