|
|
|
@ -495,6 +495,8 @@ static QStringList traceParameterNames()
|
|
|
|
|
|
|
|
|
|
|
|
nmCalculationAutoFitLM::nmCalculationAutoFitLM(QObject* parent)
|
|
|
|
nmCalculationAutoFitLM::nmCalculationAutoFitLM(QObject* parent)
|
|
|
|
: QObject(parent)
|
|
|
|
: QObject(parent)
|
|
|
|
|
|
|
|
, m_sensitivitySettings(nullptr)
|
|
|
|
|
|
|
|
, m_sensitivityVerticalWell(false)
|
|
|
|
, m_isRunning(false)
|
|
|
|
, m_isRunning(false)
|
|
|
|
, m_shouldStop(false)
|
|
|
|
, m_shouldStop(false)
|
|
|
|
, m_isFinalizing(false)
|
|
|
|
, m_isFinalizing(false)
|
|
|
|
@ -1079,8 +1081,10 @@ bool nmCalculationAutoFitLM::loadAllConfigFromDataManager()
|
|
|
|
void nmCalculationAutoFitLM::loadOptimizationConfig()
|
|
|
|
void nmCalculationAutoFitLM::loadOptimizationConfig()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// LM 只读取迭代次数和目标误差,其他数值控制保留在现有算法实现中。
|
|
|
|
// LM 只读取迭代次数和目标误差,其他数值控制保留在现有算法实现中。
|
|
|
|
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
// 敏感性运行只读取确认过的设置,普通拟合保留原来的配置来源。
|
|
|
|
nmDataAutomaticFitting fittingData = dataManager->getAutomaticFittingDataCopy();
|
|
|
|
nmDataAutomaticFitting fittingData = m_sensitivitySettings
|
|
|
|
|
|
|
|
? m_sensitivitySettings->parameters
|
|
|
|
|
|
|
|
: nmDataAnalyzeManager::getCurrentInstance()->getAutomaticFittingDataCopy();
|
|
|
|
|
|
|
|
|
|
|
|
m_maxIterations = fittingData.getIterationCount().getValue().toInt();
|
|
|
|
m_maxIterations = fittingData.getIterationCount().getValue().toInt();
|
|
|
|
m_targetError = fittingData.getErrorTolerance().getValue().toDouble();
|
|
|
|
m_targetError = fittingData.getErrorTolerance().getValue().toDouble();
|
|
|
|
@ -1096,8 +1100,10 @@ void nmCalculationAutoFitLM::loadParameterBounds()
|
|
|
|
// - m_parameterSelected[6]:完整参数体系中每个参数是否参与拟合;
|
|
|
|
// - m_parameterSelected[6]:完整参数体系中每个参数是否参与拟合;
|
|
|
|
// - m_parameterLower/Upper[6]:完整参数体系的搜索上下界;
|
|
|
|
// - m_parameterLower/Upper[6]:完整参数体系的搜索上下界;
|
|
|
|
// - m_enabledParamIndices:将勾选参数向量映射回完整参数索引。
|
|
|
|
// - m_enabledParamIndices:将勾选参数向量映射回完整参数索引。
|
|
|
|
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
// 敏感性运行只读取确认过的设置,普通拟合保留原来的配置来源。
|
|
|
|
nmDataAutomaticFitting fittingData = dataManager->getAutomaticFittingDataCopy();
|
|
|
|
nmDataAutomaticFitting fittingData = m_sensitivitySettings
|
|
|
|
|
|
|
|
? m_sensitivitySettings->parameters
|
|
|
|
|
|
|
|
: nmDataAnalyzeManager::getCurrentInstance()->getAutomaticFittingDataCopy();
|
|
|
|
|
|
|
|
|
|
|
|
m_parameterSelected.resize(6);
|
|
|
|
m_parameterSelected.resize(6);
|
|
|
|
m_parameterSelected[0] = fittingData.getPermeabilitySelected();
|
|
|
|
m_parameterSelected[0] = fittingData.getPermeabilitySelected();
|
|
|
|
@ -1141,6 +1147,24 @@ void nmCalculationAutoFitLM::loadParameterBounds()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 自动拟合核心方法 ====================
|
|
|
|
// ==================== 自动拟合核心方法 ====================
|
|
|
|
|
|
|
|
bool nmCalculationAutoFitLM::startSensitivityFitting(
|
|
|
|
|
|
|
|
const nmSensitivityFitSettings& settings,
|
|
|
|
|
|
|
|
const std::function<QVector<QVector<double> >(const QVector<double>&)>& evaluate,
|
|
|
|
|
|
|
|
const std::function<bool()>& cancelled, bool verticalWell)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 同步复用原算法;返回前释放回调,避免持有任务局部对象。
|
|
|
|
|
|
|
|
m_sensitivitySettings = &settings;
|
|
|
|
|
|
|
|
m_sensitivityEvaluate = evaluate;
|
|
|
|
|
|
|
|
m_sensitivityCancelled = cancelled;
|
|
|
|
|
|
|
|
m_sensitivityVerticalWell = verticalWell;
|
|
|
|
|
|
|
|
m_targetWellName = settings.targetWell;
|
|
|
|
|
|
|
|
const bool succeeded = startAutoFitting();
|
|
|
|
|
|
|
|
m_sensitivitySettings = nullptr;
|
|
|
|
|
|
|
|
m_sensitivityEvaluate = std::function<QVector<QVector<double> >(const QVector<double>&)>();
|
|
|
|
|
|
|
|
m_sensitivityCancelled = std::function<bool()>();
|
|
|
|
|
|
|
|
return succeeded;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmCalculationAutoFitLM::startAutoFitting()
|
|
|
|
bool nmCalculationAutoFitLM::startAutoFitting()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// 总入口只负责准备数据、调用有限差分 + LM/信赖域,并写回最终结果。
|
|
|
|
// 总入口只负责准备数据、调用有限差分 + LM/信赖域,并写回最终结果。
|
|
|
|
@ -1195,7 +1219,7 @@ bool nmCalculationAutoFitLM::startAutoFitting()
|
|
|
|
resetOptimizer();
|
|
|
|
resetOptimizer();
|
|
|
|
// 输入校验通过后,为本次拟合创建新的临时计算目录。
|
|
|
|
// 输入校验通过后,为本次拟合创建新的临时计算目录。
|
|
|
|
cleanupTemporaryDirectory();
|
|
|
|
cleanupTemporaryDirectory();
|
|
|
|
if(!initializeTemporaryDirectory()) {
|
|
|
|
if(!m_sensitivitySettings && !initializeTemporaryDirectory()) {
|
|
|
|
m_lastError = tr("Cannot create the automatic fitting temporary directory");
|
|
|
|
m_lastError = tr("Cannot create the automatic fitting temporary directory");
|
|
|
|
emit logMessageGenerated(tr("ERROR: %1").arg(m_lastError));
|
|
|
|
emit logMessageGenerated(tr("ERROR: %1").arg(m_lastError));
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
@ -1205,7 +1229,7 @@ bool nmCalculationAutoFitLM::startAutoFitting()
|
|
|
|
m_isFinalizing = false;
|
|
|
|
m_isFinalizing = false;
|
|
|
|
m_currentIteration = -1;
|
|
|
|
m_currentIteration = -1;
|
|
|
|
m_initialValues = savedInitialValues;
|
|
|
|
m_initialValues = savedInitialValues;
|
|
|
|
initializeTraceFile();
|
|
|
|
if(!m_sensitivitySettings) initializeTraceFile();
|
|
|
|
// 开头只展示一次初始参数和总误差,不展示形状误差。
|
|
|
|
// 开头只展示一次初始参数和总误差,不展示形状误差。
|
|
|
|
emit logMessageGenerated(tr("========== LM fitting started =========="));
|
|
|
|
emit logMessageGenerated(tr("========== LM fitting started =========="));
|
|
|
|
emit logMessageGenerated(tr("Target well: %1").arg(m_targetWellName));
|
|
|
|
emit logMessageGenerated(tr("Target well: %1").arg(m_targetWellName));
|
|
|
|
@ -1317,7 +1341,14 @@ bool nmCalculationAutoFitLM::startAutoFitting()
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 只有最终完整求解实际执行并提交快照后才能置为成功。
|
|
|
|
// 敏感性任务自己用最优参数收尾,不能进入普通拟合的模型回写流程。
|
|
|
|
|
|
|
|
if(m_sensitivitySettings) {
|
|
|
|
|
|
|
|
m_isRunning = false;
|
|
|
|
|
|
|
|
return !m_shouldStop && !m_sensitivityCancelled() &&
|
|
|
|
|
|
|
|
!m_globalBestPosition.isEmpty() && m_globalBestFitness < 1.0e9;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 普通拟合只有完整求解并提交快照后才算成功。
|
|
|
|
bool finalFullSolverSucceeded = false;
|
|
|
|
bool finalFullSolverSucceeded = false;
|
|
|
|
bool finalFullSolverExecuted = false;
|
|
|
|
bool finalFullSolverExecuted = false;
|
|
|
|
|
|
|
|
|
|
|
|
@ -1454,6 +1485,17 @@ bool nmCalculationAutoFitLM::startAutoFitting()
|
|
|
|
|
|
|
|
|
|
|
|
void nmCalculationAutoFitLM::extractUserInitialValues()
|
|
|
|
void nmCalculationAutoFitLM::extractUserInitialValues()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
// 按勾选顺序提取快照初值,并沿用窗口确认的上下限。
|
|
|
|
|
|
|
|
if(m_sensitivitySettings) {
|
|
|
|
|
|
|
|
m_initialValues.clear();
|
|
|
|
|
|
|
|
for(int i = 0; i < m_enabledParamIndices.size(); ++i) {
|
|
|
|
|
|
|
|
const int index = m_enabledParamIndices[i];
|
|
|
|
|
|
|
|
m_initialValues.append(qBound(m_parameterLower[index],
|
|
|
|
|
|
|
|
m_sensitivitySettings->initialValues[index], m_parameterUpper[index]));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从当前项目模型读取用户已有初始参数。
|
|
|
|
// 从当前项目模型读取用户已有初始参数。
|
|
|
|
// 只提取用户勾选的参数,并按 m_enabledParamIndices 的顺序写入 m_initialValues。
|
|
|
|
// 只提取用户勾选的参数,并按 m_enabledParamIndices 的顺序写入 m_initialValues。
|
|
|
|
// 这些值用于初始解真实评价、LM 起点和最终精英保护。
|
|
|
|
// 这些值用于初始解真实评价、LM 起点和最终精英保护。
|
|
|
|
@ -1574,9 +1616,10 @@ bool nmCalculationAutoFitLM::evaluateTrustRegionPoint(
|
|
|
|
StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
|
|
|
|
StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// 本次拟合开始时按目标井的实际井型确定流程,普通直井跳过形状调整。
|
|
|
|
// 本次拟合开始时按目标井的实际井型确定流程,普通直井跳过形状调整。
|
|
|
|
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
nmDataAnalyzeManager* dataManager = m_sensitivitySettings ? nullptr : nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
nmDataWellBase* targetWell = dataManager ? dataManager->findWellByName(m_targetWellName) : nullptr;
|
|
|
|
nmDataWellBase* targetWell = dataManager ? dataManager->findWellByName(m_targetWellName) : nullptr;
|
|
|
|
const bool skipShapeStage = targetWell && targetWell->getWellType() == NM_WELL_MODEL::Vertical_Well;
|
|
|
|
const bool skipShapeStage = m_sensitivitySettings ? m_sensitivityVerticalWell
|
|
|
|
|
|
|
|
: targetWell && targetWell->getWellType() == NM_WELL_MODEL::Vertical_Well;
|
|
|
|
const int dimensions = getEnabledParameterCount();
|
|
|
|
const int dimensions = getEnabledParameterCount();
|
|
|
|
if(dimensions <= 0 || m_enabledParamIndices.size() != dimensions) {
|
|
|
|
if(dimensions <= 0 || m_enabledParamIndices.size() != dimensions) {
|
|
|
|
m_lastError = tr("No valid parameters are available for trust-region fitting");
|
|
|
|
m_lastError = tr("No valid parameters are available for trust-region fitting");
|
|
|
|
@ -1654,7 +1697,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
|
|
|
|
auto restoreEvaluationState = [&](const TrustRegionEvaluation& evaluation) {
|
|
|
|
auto restoreEvaluationState = [&](const TrustRegionEvaluation& evaluation) {
|
|
|
|
// evaluateFitness() 会把试算参数写入 DataManager。无论候选是否接受,
|
|
|
|
// evaluateFitness() 会把试算参数写入 DataManager。无论候选是否接受,
|
|
|
|
// 下一次计算前都恢复到唯一的已接受工作点,防止失败试算污染后续求解。
|
|
|
|
// 下一次计算前都恢复到唯一的已接受工作点,防止失败试算污染后续求解。
|
|
|
|
applyParametersToDataManager(evaluation.parameters);
|
|
|
|
if(!m_sensitivitySettings) applyParametersToDataManager(evaluation.parameters);
|
|
|
|
m_lastObjectiveBreakdown = evaluation.breakdown;
|
|
|
|
m_lastObjectiveBreakdown = evaluation.breakdown;
|
|
|
|
m_lastEvaluatedLogLogData = evaluation.curve;
|
|
|
|
m_lastEvaluatedLogLogData = evaluation.curve;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
@ -1673,6 +1716,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
auto processPauseAndStop = [&]() -> bool {
|
|
|
|
auto processPauseAndStop = [&]() -> bool {
|
|
|
|
|
|
|
|
if(m_sensitivitySettings) m_shouldStop = m_sensitivityCancelled();
|
|
|
|
QApplication::processEvents();
|
|
|
|
QApplication::processEvents();
|
|
|
|
return !m_shouldStop;
|
|
|
|
return !m_shouldStop;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
@ -2371,6 +2415,18 @@ double nmCalculationAutoFitLM::evaluateFitness(const QVector<double>& parameters
|
|
|
|
m_lastEvaluatedLogLogData.clear();
|
|
|
|
m_lastEvaluatedLogLogData.clear();
|
|
|
|
m_lastObjectiveBreakdown = AutoFitObjectiveBreakdownLM();
|
|
|
|
m_lastObjectiveBreakdown = AutoFitObjectiveBreakdownLM();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 候选求解在冻结输入副本上执行,误差口径仍使用本算法现有实现。
|
|
|
|
|
|
|
|
if(m_sensitivitySettings) {
|
|
|
|
|
|
|
|
m_shouldStop = m_sensitivityCancelled();
|
|
|
|
|
|
|
|
if(m_shouldStop || !validateParameters(parameters)) return 1.0e10;
|
|
|
|
|
|
|
|
const QVector<QVector<double> > curve = m_sensitivityEvaluate(parameters);
|
|
|
|
|
|
|
|
m_shouldStop = m_sensitivityCancelled();
|
|
|
|
|
|
|
|
if(m_shouldStop || !validateLogLogData(curve)) return 1.0e10;
|
|
|
|
|
|
|
|
const double fitness = calculateLogLogCurveError(m_targetLogLogData, curve);
|
|
|
|
|
|
|
|
if(fitness < 1.0e9) m_lastEvaluatedLogLogData = curve;
|
|
|
|
|
|
|
|
return fitness;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
DEBUG_OUT(QString("%1: Call #%2 - Starting evaluation with %3 parameters")
|
|
|
|
DEBUG_OUT(QString("%1: Call #%2 - Starting evaluation with %3 parameters")
|
|
|
|
.arg(funcName).arg(callCount).arg(parameters.size()));
|
|
|
|
.arg(funcName).arg(callCount).arg(parameters.size()));
|
|
|
|
|