|
|
#ifndef NMCALCULATIONAUTOFITLM_H
|
|
|
#define NMCALCULATIONAUTOFITLM_H
|
|
|
|
|
|
#include <QObject>
|
|
|
#include <QVector>
|
|
|
#include <QPointF>
|
|
|
#include <QString>
|
|
|
#include <QStringList>
|
|
|
#include <QFile>
|
|
|
#include <limits>
|
|
|
|
|
|
#include "nmCalculation_global.h"
|
|
|
|
|
|
class nmDataWellBase;
|
|
|
|
|
|
// 双对数曲线误差分解。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;
|
|
|
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)
|
|
|
, 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);
|
|
|
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);
|
|
|
|
|
|
void applyParametersToDataManager(const QVector<double>& parameters);
|
|
|
void updateReservoirParameters(const QVector<double>& parameters);
|
|
|
void updateWellParameters(const QVector<double>& parameters);
|
|
|
void updateWellToDataManager(nmDataWellBase* pWell);
|
|
|
|
|
|
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) const;
|
|
|
|
|
|
private:
|
|
|
bool m_isRunning;
|
|
|
bool m_shouldStop;
|
|
|
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 h,5 Ct,
|
|
|
// 6 Cf,7 Swi,8 Dfc,9 fractureHalfLength。
|
|
|
QVector<bool> m_parameterSelected;
|
|
|
QVector<double> m_parameterLower;
|
|
|
QVector<double> m_parameterUpper;
|
|
|
QVector<int> m_enabledParamIndices;
|
|
|
QVector<QVector<double> > m_targetLogLogData;
|
|
|
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
|