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/Src/nmNum/nmCalculation/nmCalculationAutoFitGA.cpp

2945 lines
88 KiB
C++

#include "nmCalculationAutoFitGA.h"
//#include "nmCalculationExeSolverTask.h"
#include "nmCalculationDllPebiSolverTask.h"
#include "nmDataAnalyzeManager.h"
#include "nmDataWellBase.h"
#include "nmDataVerticalWell.h"
#include "nmDataVerticalFracturedWell.h"
#include "nmDataHorizontalFracturedWell.h"
#include "nmDataReservoir.h"
#include "nmDataAutomaticFitting.h"
#include <QApplication>
#include <QDebug>
#include <QTime>
#include <QDir>
#include <QtCore/qmath.h>
#include <cmath>
#include <algorithm>
#ifdef Q_OS_WIN
#include <windows.h>
#include <float.h>
#define DEBUG_OUT(msg) OutputDebugStringA(QString("[AutoFit] %1\n").arg(msg).toLocal8Bit().data())
#endif
// 常量定义
const double nmCalculationAutoFitGA::MIN_FITNESS_IMPROVEMENT = 1e-8;
const double nmCalculationAutoFitGA::MUTATION_STRENGTH = 0.1;
const int nmCalculationAutoFitGA::CONVERGENCE_CHECK_INTERVAL = 10;
const int nmCalculationAutoFitGA::MAX_STAGNATION_GENERATIONS = 20;
// 无穷大和NaN检查
static inline bool isFiniteNumber(double value)
{
#ifdef Q_OS_WIN
return _finite(value) != 0 && !_isnan(value);
#else
return std::isfinite(value);
#endif
}
// sleep函数
static inline void msleep(int ms)
{
#ifdef Q_OS_WIN
Sleep(ms);
#endif
}
// 构造函数
nmCalculationAutoFitGA::nmCalculationAutoFitGA(QObject* parent)
: QObject(parent)
, m_isRunning(false)
, m_shouldStop(false)
, m_isPaused(false)
, m_currentGeneration(0)
, m_bestFitness(1e10)
, m_worstFitness(-1e10)
, m_averageFitness(1e10)
, m_previousBestFitness(1e10)
, m_populationSize(40)
, m_maxGenerations(100)
, m_targetError(0.001)
, m_crossoverRate(0.8)
, m_mutationRate(0.1)
, m_elitismRate(0.1)
, m_tournamentSize(3)
, m_useUniformCrossover(true)
, m_totalEvaluations(0)
, m_successfulEvaluations(0)
, m_evaluationInProgress(0)
, m_consecutiveFailures(0)
, m_progressTimer(0)
, m_userInitialFitness(1e10)
, m_consecutiveFailedGenerations(0)
, m_maxConsecutiveFailures(3)
, m_hasValidUserSolution(false)
, m_improvementThreshold(0.05)
, m_diversityThreshold(0.05)
, m_convergenceVarianceThreshold(1e-8)
, m_trueConvergenceWindow(15)
, m_localOptimumWindow(8)
, m_nearTargetFactor(2.0)
, m_farTargetFactor(10.0)
, m_targetWellName("")
{
DEBUG_OUT(QString("GA Constructor: this=0x%1").arg((quintptr)this, 0, 16));
// 初始化随机数种子
qsrand(QTime::currentTime().msec());
// 初始化临时目录用于DLL求解器
initializeTemporaryDirectory();
// 初始化最优个体
m_bestIndividual.fitness = 1e10;
m_bestIndividual.isEvaluated = false;
// 创建进度更新定时器
m_progressTimer = new QTimer(this);
connect(m_progressTimer, SIGNAL(timeout()), this, SLOT(updateProgress()));
DEBUG_OUT("AutoFit GA calculator initialized (data-driven mode)");
DEBUG_OUT("GA Constructor completed");
}
// 析构函数
nmCalculationAutoFitGA::~nmCalculationAutoFitGA()
{
DEBUG_OUT(QString("GA Destructor: this=0x%1").arg((quintptr)this, 0, 16));
// 首先停止算法
if(m_isRunning) {
m_shouldStop = true; // 立即设置停止标志
// 等待当前操作完成,增加超时时间
int waitCount = 0;
while(m_isRunning && waitCount < 100) {
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 50);
msleep(50);
waitCount++;
}
// 如果仍在运行则强制停止
if(m_isRunning) {
DEBUG_OUT("Force stopping GA - timeout reached");
m_isRunning = false;
}
}
// 清理临时目录
cleanupTemporaryDirectory();
// 断开所有信号连接,防止回调已销毁的对象
disconnect(this, nullptr, nullptr, nullptr);
DEBUG_OUT("GA Destructor completed");
}
// ==================== 目录处理方法 ====================
void nmCalculationAutoFitGA::initializeTemporaryDirectory()
{
QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss_zzz");
QString processId = QString::number(QCoreApplication::applicationPid());
m_tempDirectory = QApplication::applicationDirPath() +
"/autofit_temp_" + processId + "_" + timestamp;
// 确保目录不存在
int counter = 0;
QString originalPath = m_tempDirectory;
while(QDir(m_tempDirectory).exists() && counter < 100) {
m_tempDirectory = originalPath + "_" + QString::number(counter);
counter++;
}
if(QDir().mkpath(m_tempDirectory)) {
DEBUG_OUT(QString("Initialized temp directory: %1").arg(m_tempDirectory));
} else {
DEBUG_OUT(QString("Warning: Failed to create temp directory: %1").arg(m_tempDirectory));
m_tempDirectory = QApplication::applicationDirPath();
}
}
void nmCalculationAutoFitGA::cleanupTemporaryDirectory()
{
if(QDir(m_tempDirectory).exists()) {
if(removeDirectoryRecursively(m_tempDirectory)) {
DEBUG_OUT("Temp directory cleaned up successfully");
} else {
DEBUG_OUT("Warning: Failed to clean up temp directory completely");
}
}
}
bool nmCalculationAutoFitGA::removeDirectoryRecursively(const QString& path)
{
QDir dir(path);
if(!dir.exists()) {
return true;
}
// 递归删除子目录和文件
QFileInfoList entries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden);
bool allRemoved = true;
for(int i = 0; i < entries.size(); ++i) {
const QFileInfo& entry = entries[i];
if(entry.isDir()) {
if(!removeDirectoryRecursively(entry.absoluteFilePath())) {
allRemoved = false;
}
} else {
QFile file(entry.absoluteFilePath());
// 处理只读文件
if(!file.permissions().testFlag(QFile::WriteUser)) {
file.setPermissions(file.permissions() | QFile::WriteUser);
}
if(!file.remove()) {
DEBUG_OUT(QString("Failed to remove file: %1").arg(entry.absoluteFilePath()));
allRemoved = false;
}
}
}
// 删除目录本身
if(allRemoved) {
return dir.rmdir(path);
}
return false;
}
// ==================== 公共接口方法 ====================
void nmCalculationAutoFitGA::setTargetLogLogData(const QVector<QVector<double>>& targetData)
{
m_targetLogLogData = targetData;
DEBUG_OUT(QString("Target LogLog data set: %1 arrays").arg(targetData.size()));
if(targetData.size() >= 3) {
DEBUG_OUT(QString("LogLog data points: X=%1, Y1=%2, Y2=%3")
.arg(targetData[0].size())
.arg(targetData[1].size())
.arg(targetData[2].size()));
}
}
bool nmCalculationAutoFitGA::startAutoFitting()
{
if(m_isRunning) {
m_lastError = "GA fitting is already running";
return false;
}
DEBUG_OUT("=== GA AUTO FITTING START ===");
// 发送初始化日志
emit logMessageGenerated(tr("=== GA Automatic Fitting Started ==="));
emit logMessageGenerated(tr("Algorithm: Genetic Algorithm"));
try {
// 从数据管理器加载所有配置
if(!loadAllConfigFromDataManager()) {
emit logMessageGenerated(tr("ERROR: Failed to load configuration from data manager"));
return false;
}
int enabledParams = getEnabledParameterCount();
emit logMessageGenerated(tr("Enabled parameters count: %1").arg(enabledParams));
if(enabledParams == 0) {
m_lastError = "No parameters enabled for optimization";
emit logMessageGenerated(tr("ERROR: No parameters enabled for optimization"));
return false;
}
if(m_targetLogLogData.isEmpty() || m_targetLogLogData.size() < 3) {
m_lastError = "Target LogLog data is empty or insufficient";
emit logMessageGenerated(tr("ERROR: Target LogLog data is empty or insufficient"));
return false;
}
// 检查数据一致性
if(m_targetLogLogData[0].size() != m_targetLogLogData[1].size() ||
m_targetLogLogData[0].size() != m_targetLogLogData[2].size()) {
m_lastError = "Target LogLog data arrays have inconsistent sizes";
emit logMessageGenerated(tr("ERROR: Target LogLog data arrays have inconsistent sizes"));
return false;
}
emit logMessageGenerated(tr("Target data validation passed (%1 data points)").arg(m_targetLogLogData[0].size()));
// 使用保存的初始值进行精英保护
QVector<double> savedInitialValues = m_initialValues;
// 重置状态
resetOptimizer();
m_isRunning = true;
m_shouldStop = false;
m_isPaused = false;
m_currentGeneration = 0;
m_consecutiveFailures = 0;
m_consecutiveFailedGenerations = 0;
// 精英保护:评估用户初始解
if(!savedInitialValues.isEmpty()) {
m_userInitialSolution = savedInitialValues;
emit logMessageGenerated(tr("=== Evaluating Initial Solution (Elite Protection) ==="));
// 输出初始参数值
QString paramStr = tr("Initial parameters: ");
for(int i = 0; i < m_userInitialSolution.size(); ++i) {
paramStr += QString("[%1]=%2 ").arg(i).arg(m_userInitialSolution[i], 0, 'f', 6);
}
emit logMessageGenerated(paramStr);
try {
emit logMessageGenerated(tr("Starting initial solution evaluation..."));
DEBUG_OUT(QString("Before evaluateFitness: m_userInitialSolution size = %1").arg(m_userInitialSolution.size()));
if(m_userInitialSolution.isEmpty()) {
emit logMessageGenerated(tr("ERROR: m_userInitialSolution is empty!"));
return false;
}
for(int i = 0; i < m_userInitialSolution.size(); ++i) {
emit logMessageGenerated(tr("Initial param[%1] = %2").arg(i).arg(m_userInitialSolution[i], 0, 'f', 6));
}
m_userInitialFitness = evaluateGenes(m_userInitialSolution);
emit logMessageGenerated(tr("evaluateGenes returned: %1").arg(m_userInitialFitness, 0, 'e', 10));
if(m_userInitialFitness < 1e9) {
emit logMessageGenerated(tr("Taking SUCCESS branch (fitness < 1e9)"));
m_hasValidUserSolution = true;
m_bestFitness = m_userInitialFitness;
m_bestIndividual.genes = m_userInitialSolution;
m_bestIndividual.fitness = m_userInitialFitness;
m_bestIndividual.isEvaluated = true;
emit logMessageGenerated(tr("Initial solution evaluation successful"));
emit logMessageGenerated(tr("Initial fitness (error): %1").arg(m_userInitialFitness, 0, 'e', 4));
emit logMessageGenerated(tr("Elite protection activated - initial solution will be preserved if no significant improvement found"));
} else {
emit logMessageGenerated(tr("Taking FAILURE branch (fitness >= 1e9)"));
m_hasValidUserSolution = false;
emit logMessageGenerated(tr("Initial solution evaluation failed - starting with random initialization"));
}
} catch(...) {
m_hasValidUserSolution = false;
emit logMessageGenerated(tr("Exception during initial solution evaluation"));
}
// 恢复初始值供种群初始化使用
m_initialValues = savedInitialValues;
}
// 初始化种群
initializePopulation();
emit logMessageGenerated(tr("Population initialized: %1 individuals, %2 dimensions").arg(m_populationSize).arg(getEnabledParameterCount()));
// GA主循环
emit logMessageGenerated(tr("=== Starting GA Main Loop ==="));
for(m_currentGeneration = 0; m_currentGeneration < m_maxGenerations && !m_shouldStop; ++m_currentGeneration) {
// 每次迭代都输出标题,或者只在重要迭代输出详细信息
bool shouldOutputDetail = (m_currentGeneration % qMax(1, m_maxGenerations / 10) == 0) ||
(m_currentGeneration < 5) ||
(m_currentGeneration >= m_maxGenerations - 2);
// 每次迭代都输出标题
emit logMessageGenerated(tr("--- Generation %1/%2 ---").arg(m_currentGeneration + 1).arg(m_maxGenerations));
// 只在特定迭代输出详细统计信息
if(shouldOutputDetail) {
emit logMessageGenerated(tr("Current best error: %1").arg(m_bestFitness, 0, 'e', 4));
emit logMessageGenerated(tr("Total evaluations: %1 (successful: %2, failures: %3)")
.arg(m_totalEvaluations).arg(m_successfulEvaluations).arg(m_totalEvaluations - m_successfulEvaluations));
}
// 检查暂停状态
while(m_isPaused && !m_shouldStop) {
QApplication::processEvents();
//msleep(100);
}
if(m_shouldStop) {
emit logMessageGenerated(tr("Optimization stopped by user request"));
break;
}
// 1. 评估种群
evaluatePopulation();
if(m_shouldStop) break;
// 2. 更新统计信息
updatePopulationStatistics();
// 3. 发射进度信号
emit progressUpdated(m_currentGeneration, m_bestFitness);
if(shouldOutputDetail) {
emit logMessageGenerated(tr("Generation %1 completed: best = %2, avg = %3, worst = %4")
.arg(m_currentGeneration + 1).arg(m_bestFitness, 0, 'e', 4)
.arg(m_averageFitness, 0, 'e', 4).arg(m_worstFitness, 0, 'e', 4));
}
// 记录收敛历史
m_convergenceHistory.append(m_bestFitness);
// 更新收敛指标
updateConvergenceMetrics();
// 智能收敛判断
StopReasonGA stopReason = analyzeOptimizationStatus();
if(stopReason == GA_TARGET_ACHIEVED) {
emit logMessageGenerated(tr("=== TARGET ACHIEVED ==="));
emit logMessageGenerated(tr("Target error achieved! Current error: %1 < Target: %2")
.arg(m_bestFitness, 0, 'e', 4).arg(m_targetError, 0, 'e', 4));
emit logMessageGenerated(tr("Optimization completed successfully after %1 generations")
.arg(m_currentGeneration + 1));
break;
}
else if(stopReason == GA_TRUE_CONVERGENCE) {
emit logMessageGenerated(tr("=== TRUE CONVERGENCE DETECTED ==="));
emit logMessageGenerated(tr("Algorithm has converged to a stable solution"));
emit logMessageGenerated(tr("Final error: %1 after %2 generations")
.arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1));
emit logMessageGenerated(tr("Solution quality: %1 (1.0 = target achieved)")
.arg(m_targetError / qMax(1e-10, m_bestFitness), 0, 'f', 3));
break;
}
else if(stopReason == GA_LOCAL_OPTIMUM) {
emit logMessageGenerated(tr("=== LOCAL OPTIMUM DETECTED ==="));
emit logMessageGenerated(tr("Algorithm appears to be trapped in local optimum"));
emit logMessageGenerated(tr("Current error: %1 after %2 generations")
.arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1));
emit logMessageGenerated(tr("Suggestion: Try restarting with different parameters or larger search space"));
break;
}
else if(stopReason == GA_CONSECUTIVE_FAILURES) {
emit logMessageGenerated(tr("=== CONSECUTIVE FAILURES ==="));
emit logMessageGenerated(tr("Too many consecutive failed generations (%1/%2)")
.arg(m_consecutiveFailedGenerations).arg(m_maxConsecutiveFailures));
break;
}
else if(stopReason == GA_CONTINUE_OPTIMIZATION) {
// 继续优化每10次迭代输出一次状态
if(m_currentGeneration > 0 && m_currentGeneration % 10 == 0) {
double diversity = calculatePopulationDiversity();
emit logMessageGenerated(tr(" Optimization status: diversity=%1")
.arg(diversity, 0, 'f', 4));
}
}
// 4. 创建新一代种群
if(m_currentGeneration < m_maxGenerations - 1)
{
QVector<GAIndividual> newPopulation;
newPopulation.reserve(m_populationSize);
// 精英保留
applyElitism(newPopulation);
// 生成新个体直到填满种群
while(newPopulation.size() < m_populationSize && !m_shouldStop) {
// 选择父代
int parent1Index = tournamentSelection();
int parent2Index = tournamentSelection();
// 确保父代不同
while(parent1Index == parent2Index && m_population.size() > 1) {
parent2Index = tournamentSelection();
}
GAIndividual offspring1, offspring2;
// 交叉
if(random01() < m_crossoverRate) {
crossover(m_population[parent1Index], m_population[parent2Index],
offspring1, offspring2);
} else {
offspring1 = m_population[parent1Index];
offspring2 = m_population[parent2Index];
}
// 变异
if(random01() < m_mutationRate) {
mutate(offspring1);
}
if(random01() < m_mutationRate) {
mutate(offspring2);
}
// 边界约束
clampToLimits(offspring1.genes);
clampToLimits(offspring2.genes);
// 添加到新种群
if(newPopulation.size() < m_populationSize) {
newPopulation.append(offspring1);
}
if(newPopulation.size() < m_populationSize) {
newPopulation.append(offspring2);
}
}
// 替换种群
m_population = newPopulation;
// 自适应参数调整
adaptiveParameterUpdate(m_currentGeneration);
}
// 输出迭代结束标记
if(shouldOutputDetail) {
emit logMessageGenerated(tr("Generation %1 completed - Current best: %2")
.arg(m_currentGeneration + 1).arg(m_bestFitness, 0, 'e', 4));
}
// 强制处理事件,保持界面响应
QApplication::processEvents();
// 在世代间稍作停顿,减少系统负载
if(m_currentGeneration % 3 == 2) {
//msleep(200);
}
}
// 最终结果验证和保护
validateAndProtectFinalResult();
} catch(const std::exception& e) {
m_lastError = QString("Critical exception in GA main loop: %1").arg(e.what());
emit logMessageGenerated(tr("CRITICAL ERROR: %1").arg(e.what()));
cleanupTemporaryDirectory();
m_isRunning = false;
if(m_progressTimer) m_progressTimer->stop();
emit fittingFinished(false, m_lastError);
return false;
} catch(...) {
m_lastError = "Unknown critical exception in GA main loop";
emit logMessageGenerated(tr("CRITICAL ERROR: Unknown exception in GA main loop"));
cleanupTemporaryDirectory();
m_isRunning = false;
if(m_progressTimer) m_progressTimer->stop();
emit fittingFinished(false, m_lastError);
return false;
}
m_isRunning = false;
if(m_progressTimer) m_progressTimer->stop();
// 应用最终参数
if(!m_bestIndividual.genes.isEmpty()) {
try {
emit logMessageGenerated(tr("Applying optimized parameters to model..."));
applyParametersToDataManager(m_bestIndividual.genes);
saveOptimizationResult();
// 输出最终优化结果
emit logMessageGenerated(tr("=== Optimization Results ==="));
emit logMessageGenerated(tr("Final error: %1").arg(m_bestFitness, 0, 'e', 4));
emit logMessageGenerated(tr("Total generations: %1").arg(m_currentGeneration + 1));
emit logMessageGenerated(tr("Total evaluations: %1 (successful: %2)")
.arg(m_totalEvaluations).arg(m_successfulEvaluations));
// 输出最优参数值
QString finalParams = tr("Optimized parameters: ");
for(int i = 0; i < m_bestIndividual.genes.size(); ++i) {
finalParams += QString("[%1]=%2 ").arg(i).arg(m_bestIndividual.genes[i], 0, 'f', 6);
}
emit logMessageGenerated(finalParams);
emit logMessageGenerated(tr("Parameters applied successfully to data manager"));
} catch(const std::exception& e) {
emit logMessageGenerated(tr("ERROR: Failed to apply final parameters: %1").arg(e.what()));
m_lastError = QString("Failed to apply final parameters: %1").arg(e.what());
} catch(...) {
emit logMessageGenerated(tr("ERROR: Unknown error applying final parameters"));
m_lastError = "Failed to apply final parameters due to unknown error";
}
}
// 判断系统确定最终结果
bool success;
QString message;
StopReasonGA finalReason = analyzeOptimizationStatus();
if(finalReason == GA_TARGET_ACHIEVED) {
success = true;
//message = QString("GA optimization completed successfully. Target achieved. Best error: %1, Generations: %2")
// .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1);
emit logMessageGenerated(tr("=== GA OPTIMIZATION SUCCESSFUL ==="));
}
else if(finalReason == GA_TRUE_CONVERGENCE) {
success = true;
//message = QString("GA optimization converged to stable solution. Best error: %1, Generations: %2")
// .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1);
emit logMessageGenerated(tr("=== GA OPTIMIZATION CONVERGED ==="));
}
else if(finalReason == GA_LOCAL_OPTIMUM) {
success = true;
//message = QString("GA optimization trapped in local optimum. Best error: %1, Generations: %2")
// .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1);
emit logMessageGenerated(tr("=== GA OPTIMIZATION - LOCAL OPTIMUM ==="));
}
else if(finalReason == GA_MAX_ITERATIONS) {
success = true;
//message = QString("GA optimization completed. Max generations reached. Best error: %1, Generations: %2")
// .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1);
emit logMessageGenerated(tr("=== GA OPTIMIZATION - MAX GENERATIONS ==="));
}
else if(finalReason == GA_USER_STOPPED) {
success = true;
//message = QString("GA optimization stopped by user. Best error: %1, Generations: %2")
// .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1);
emit logMessageGenerated(tr("=== GA OPTIMIZATION STOPPED BY USER ==="));
}
else if(finalReason == GA_CONSECUTIVE_FAILURES) {
success = false;
//message = QString("GA optimization failed due to consecutive failures. Best error: %1, Generations: %2")
// .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1);
emit logMessageGenerated(tr("=== GA OPTIMIZATION FAILED ==="));
}
else {
success = false;
//message = QString("GA optimization ended unexpectedly. Best error: %1, Generations: %2")
// .arg(m_bestFitness, 0, 'e', 4).arg(m_currentGeneration + 1);
emit logMessageGenerated(tr("=== GA OPTIMIZATION - UNKNOWN END ==="));
}
emit logMessageGenerated(tr("Result: %1").arg(success ? "SUCCESS" : "FAILED"));
emit fittingFinished(success, message);
cleanupTemporaryDirectory();
return success;
}
void nmCalculationAutoFitGA::stopFitting()
{
if(m_isRunning) {
DEBUG_OUT("Stop request received, setting stop flag...");
// 添加停止日志
emit logMessageGenerated(tr("=== User Stop Request Received ==="));
emit logMessageGenerated(tr("Gracefully stopping GA optimization..."));
m_shouldStop = true;
if(m_progressTimer) {
m_progressTimer->stop();
}
// 等待当前评估完成,缩短超时时间
int waitCount = 0;
while(m_evaluationInProgress > 0 && waitCount < 30) { // 减少等待时间
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 50);
msleep(50);
waitCount++;
}
// 超时时强制重置
if(m_evaluationInProgress > 0) {
DEBUG_OUT("Force resetting evaluation counter");
emit logMessageGenerated(tr("Force stopping current evaluation..."));
m_evaluationInProgress = 0;
}
// 确保运行标志被清除
m_isRunning = false;
emit logMessageGenerated(tr("GA optimization stop request processed"));
DEBUG_OUT("Stop request processed");
} else {
DEBUG_OUT("Stop request received but GA is not running");
emit logMessageGenerated(tr("Stop request received but optimization is not running"));
}
cleanupTemporaryDirectory();
}
bool nmCalculationAutoFitGA::isRunning() const
{
return m_isRunning;
}
int nmCalculationAutoFitGA::getCurrentGeneration() const
{
return m_currentGeneration;
}
QVector<double> nmCalculationAutoFitGA::getBestSolution() const
{
return m_bestIndividual.genes;
}
double nmCalculationAutoFitGA::getBestFitness() const
{
return m_bestFitness;
}
QString nmCalculationAutoFitGA::getLastError() const
{
return m_lastError;
}
void nmCalculationAutoFitGA::resetOptimizer()
{
m_population.clear();
m_eliteIndividuals.clear();
m_bestIndividual = GAIndividual();
m_bestFitness = 1e10;
m_worstFitness = -1e10;
m_averageFitness = 1e10;
m_previousBestFitness = 1e10;
m_currentGeneration = 0;
m_totalEvaluations = 0;
m_successfulEvaluations = 0;
m_convergenceHistory.clear();
m_lastError.clear();
m_initialValues.clear();
m_userInitialSolution.clear();
m_userInitialFitness = 1e10;
m_hasValidUserSolution = false;
m_diversityHistory.clear();
DEBUG_OUT("GA optimizer reset");
}
void nmCalculationAutoFitGA::setGATargetWellName(const QString& wellName)
{
m_targetWellName = wellName;
}
void nmCalculationAutoFitGA::updateProgress()
{
// 这个槽函数在定时器触发时被调用,可以用来更新界面或执行周期性任务
if(m_isRunning) {
QApplication::processEvents();
}
}
// ==================== 数据加载方法 ====================
bool nmCalculationAutoFitGA::loadAllConfigFromDataManager()
{
try {
loadOptimizationConfig();
loadParameterBounds();
extractUserInitialValues();
return true;
} catch(...) {
m_lastError = "Failed to load configuration from data manager";
return false;
}
}
void nmCalculationAutoFitGA::loadOptimizationConfig()
{
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
nmDataAutomaticFitting fittingData = dataManager->getAutomaticFittingDataCopy();
// 加载基本配置
m_maxGenerations = fittingData.getIterationCount().getValue().toInt();
m_targetError = fittingData.getErrorTolerance().getValue().toDouble();
// 设置GA默认参数
m_populationSize = 40;
m_crossoverRate = 0.8;
m_mutationRate = 0.1;
m_elitismRate = 0.15;
m_tournamentSize = 3;
m_useUniformCrossover = true;
DEBUG_OUT(QString("Loaded GA optimization config: generations=%1, error=%2, population=%3")
.arg(m_maxGenerations).arg(m_targetError).arg(m_populationSize));
}
void nmCalculationAutoFitGA::loadParameterBounds()
{
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
nmDataAutomaticFitting fittingData = dataManager->getAutomaticFittingDataCopy();
// 获取参数选择状态
m_parameterSelected.resize(11);
m_parameterSelected[0] = fittingData.getPermeabilitySelected();
m_parameterSelected[1] = fittingData.getSkinSelected();
m_parameterSelected[2] = fittingData.getWellboreStorageSelected();
m_parameterSelected[3] = fittingData.getPorositySelected();
m_parameterSelected[4] = fittingData.getInitialPressureSelected();
m_parameterSelected[5] = fittingData.getThicknessSelected();
m_parameterSelected[6] = fittingData.getCtSelected();
m_parameterSelected[7] = fittingData.getCfSelected();
m_parameterSelected[8] = fittingData.getSoiSelected();
m_parameterSelected[9] = fittingData.getSwiSelected();
m_parameterSelected[10] = fittingData.getSgiSelected();
// 获取参数边界
m_parameterLower.resize(11);
m_parameterUpper.resize(11);
m_parameterLower[0] = fittingData.getPermeabilityMin().getValue().toDouble();
m_parameterUpper[0] = fittingData.getPermeabilityMax().getValue().toDouble();
m_parameterLower[1] = fittingData.getSkinMin().getValue().toDouble();
m_parameterUpper[1] = fittingData.getSkinMax().getValue().toDouble();
m_parameterLower[2] = fittingData.getWellboreStorageMin().getValue().toDouble();
m_parameterUpper[2] = fittingData.getWellboreStorageMax().getValue().toDouble();
m_parameterLower[3] = fittingData.getPorosityMin().getValue().toDouble();
m_parameterUpper[3] = fittingData.getPorosityMax().getValue().toDouble();
m_parameterLower[4] = fittingData.getInitialPressureMin().getValue().toDouble();
m_parameterUpper[4] = fittingData.getInitialPressureMax().getValue().toDouble();
m_parameterLower[5] = fittingData.getThicknessMin().getValue().toDouble();
m_parameterUpper[5] = fittingData.getThicknessMax().getValue().toDouble();
m_parameterLower[6] = fittingData.getCtMin().getValue().toDouble();
m_parameterUpper[6] = fittingData.getCtMax().getValue().toDouble();
m_parameterLower[7] = fittingData.getCfMin().getValue().toDouble();
m_parameterUpper[7] = fittingData.getCfMax().getValue().toDouble();
m_parameterLower[8] = fittingData.getSoiMin().getValue().toDouble();
m_parameterUpper[8] = fittingData.getSoiMax().getValue().toDouble();
m_parameterLower[9] = fittingData.getSwiMin().getValue().toDouble();
m_parameterUpper[9] = fittingData.getSwiMax().getValue().toDouble();
m_parameterLower[10] = fittingData.getSgiMin().getValue().toDouble();
m_parameterUpper[10] = fittingData.getSgiMax().getValue().toDouble();
// 更新启用参数索引
m_enabledParamIndices.clear();
for(int i = 0; i < m_parameterSelected.size(); ++i) {
if(m_parameterSelected[i]) {
m_enabledParamIndices.append(i);
}
}
DEBUG_OUT(QString("Loaded parameter bounds: %1 enabled parameters")
.arg(m_enabledParamIndices.size()));
}
void nmCalculationAutoFitGA::extractUserInitialValues()
{
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
nmDataReservoir reservoirData = dataManager->getReservoirDataCopy();
//QVector<nmDataWellBase*> wells = dataManager->getWellDataList();
nmDataWellBase* pTargetWell = dataManager->findWellByName(m_targetWellName);
m_initialValues.clear();
// 按照启用参数的顺序提取初始值
for(int i = 0; i < m_enabledParamIndices.size(); ++i) {
int paramIndex = m_enabledParamIndices[i];
double initialValue = 0.0;
switch(paramIndex) {
case 0: // 渗透率
initialValue = reservoirData.getPermeability().getValue().toDouble();
break;
case 1: // 表皮系数
if(pTargetWell) {
initialValue = pTargetWell->getPerforation(0)->getSkin().getValue().toDouble();
}
break;
case 2: // 井筒储集系数
if(pTargetWell) {
initialValue = pTargetWell->getWellboreStorage().getValue().toDouble();
}
break;
case 3: // 孔隙度
initialValue = reservoirData.getPorosity().getValue().toDouble();
break;
case 4: // 初始压力
initialValue = reservoirData.getInitialPressure().getValue().toDouble();
break;
case 5: // 储层厚度
initialValue = reservoirData.getThickness().getValue().toDouble();
break;
case 6: // 综合压缩系数
initialValue = reservoirData.getCt().getValue().toDouble();
break;
case 7: // 岩石压缩系数
initialValue = reservoirData.getCf().getValue().toDouble();
break;
case 8: // 初始含油饱和度
initialValue = reservoirData.getSoi().getValue().toDouble();
break;
case 9: // 初始含水饱和度
initialValue = reservoirData.getSwi().getValue().toDouble();
break;
case 10: // 初始含气饱和度
initialValue = reservoirData.getSgi().getValue().toDouble();
break;
}
m_initialValues.append(initialValue);
}
DEBUG_OUT(QString("Extracted %1 user initial values").arg(m_initialValues.size()));
for(int i = 0; i < m_initialValues.size(); ++i) {
DEBUG_OUT(QString(" Initial[%1] = %2").arg(i).arg(m_initialValues[i], 0, 'e', 3));
}
// 验证初始值
if(!validateInitialValues()) {
DEBUG_OUT("Warning: Some initial values are outside parameter bounds");
}
}
// ==================== 遗传算法核心方法 ====================
void nmCalculationAutoFitGA::initializePopulation()
{
int dimensions = getEnabledParameterCount();
if(dimensions == 0) return;
m_population.clear();
m_population.resize(m_populationSize);
bool hasValidInitials = !m_initialValues.isEmpty() && m_initialValues.size() >= dimensions;
int guidedCount = hasValidInitials ? qMax(2, m_populationSize / 2) : qMax(1, m_populationSize / 3);
DEBUG_OUT(QString("Enhanced population initialization: %1 individuals, %2 guided, %3 random")
.arg(m_populationSize).arg(guidedCount).arg(m_populationSize - guidedCount));
for(int i = 0; i < m_populationSize; ++i) {
GAIndividual& individual = m_population[i];
individual.genes.resize(dimensions);
individual.fitness = 1e10;
individual.isEvaluated = false;
// 基因初始化
for(int j = 0; j < dimensions; ++j) {
int paramIndex = m_enabledParamIndices[j];
double range = m_parameterUpper[paramIndex] - m_parameterLower[paramIndex];
if(i == 0 && hasValidInitials) {
// 第一个个体:使用用户初始值
individual.genes[j] = m_initialValues[j];
} else if(i < guidedCount && hasValidInitials) {
// 引导搜索策略
double searchRadius;
if(i <= guidedCount / 3) {
searchRadius = range * 0.03;
} else if(i <= guidedCount * 2 / 3) {
searchRadius = range * 0.08;
} else {
searchRadius = range * 0.15;
}
double offset = (random01() - 0.5) * searchRadius;
individual.genes[j] = m_initialValues[j] + offset;
} else {
// 随机初始化
individual.genes[j] = m_parameterLower[paramIndex] + random01() * range;
}
}
// 边界约束
clampToLimits(individual.genes);
}
}
double nmCalculationAutoFitGA::evaluateGenes(const QVector<double>& genes)
{
const QString funcName = QString("evaluateGenes[Gen%1]").arg(m_currentGeneration);
static int callCount = 0;
callCount++;
try {
DEBUG_OUT(QString("%1: Call #%2 - Starting evaluation with %3 genes")
.arg(funcName).arg(callCount).arg(genes.size()));
// 打印参数值用于对比
QString paramStr = "Parameters: ";
for(int i = 0; i < genes.size(); ++i) {
paramStr += QString("[%1]=%2 ").arg(i).arg(genes[i], 0, 'f', 6);
}
DEBUG_OUT(QString("%1: %2").arg(funcName).arg(paramStr));
// 1. 参数有效性检查
if(!validateParameters(genes)) {
DEBUG_OUT(QString("%1: Call #%2 - Invalid parameters").arg(funcName).arg(callCount));
return 1e10;
}
// 2. 检查数据管理器状态
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
if(!dataManager) {
DEBUG_OUT(QString("%1: Call #%2 - DataManager is null").arg(funcName).arg(callCount));
return 1e10;
}
// 3. 应用参数到数据管理器
try {
DEBUG_OUT(QString("%1: Call #%2 - Applying parameters to DataManager").arg(funcName).arg(callCount));
applyParametersToDataManager(genes);
DEBUG_OUT(QString("%1: Call #%2 - Parameters applied successfully").arg(funcName).arg(callCount));
} catch(const std::exception& e) {
DEBUG_OUT(QString("%1: Call #%2 - Failed to apply parameters: %3").arg(funcName).arg(callCount).arg(e.what()));
return 1e10;
} catch(...) {
DEBUG_OUT(QString("%1: Call #%2 - Unknown error applying parameters").arg(funcName).arg(callCount));
return 1e10;
}
// 4. 运行求解器
QVector<QVector<double> > solverResult;
const int maxRetries = 2;
bool solverSuccess = false;
for(int retry = 0; retry <= maxRetries; ++retry) {
if(m_shouldStop) return 1e10;
try {
DEBUG_OUT(QString("%1: Call #%2 - Solver attempt %3/%4")
.arg(funcName).arg(callCount).arg(retry + 1).arg(maxRetries + 1));
// 在求解器调用前添加短暂延迟,确保状态稳定
if(retry > 0) {
DEBUG_OUT(QString("%1: Call #%2 - Retry delay before solver attempt")
.arg(funcName).arg(callCount));
msleep(1000); // 增加延迟时间
}
solverResult = runSolver();
if(!solverResult.isEmpty() && validateSolverResult(solverResult)) {
DEBUG_OUT(QString("%1: Call #%2 - Solver successful on attempt %3, result size: %4")
.arg(funcName).arg(callCount).arg(retry + 1).arg(solverResult[0].size()));
solverSuccess = true;
break;
} else {
DEBUG_OUT(QString("%1: Call #%2 - Solver failed on attempt %3 - empty or invalid result")
.arg(funcName).arg(callCount).arg(retry + 1));
if(retry < maxRetries) {
DEBUG_OUT(QString("%1: Call #%2 - Will retry solver").arg(funcName).arg(callCount));
}
}
} catch(const std::exception& e) {
DEBUG_OUT(QString("%1: Call #%2 - Solver exception on attempt %3: %4")
.arg(funcName).arg(callCount).arg(retry + 1).arg(e.what()));
} catch(...) {
DEBUG_OUT(QString("%1: Call #%2 - Unknown solver exception on attempt %3")
.arg(funcName).arg(callCount).arg(retry + 1));
}
}
if(!solverSuccess) {
DEBUG_OUT(QString("%1: Call #%2 - All solver attempts failed").arg(funcName).arg(callCount));
return 1e10;
}
// 5. 获取双对数结果数据
QVector<QVector<double> > resultLogLogData;
try {
nmDataWellBase* pTargetWell = dataManager->findWellByName(m_targetWellName);
if(pTargetWell) {
resultLogLogData = pTargetWell->getResultLogLog();
if(!validateLogLogData(resultLogLogData)) {
DEBUG_OUT(QString("%1: Call #%2 - Invalid result LogLog data").arg(funcName).arg(callCount));
return 1e10;
}
DEBUG_OUT(QString("%1: Call #%2 - LogLog result data obtained, size: %3")
.arg(funcName).arg(callCount).arg(resultLogLogData[0].size()));
} else {
DEBUG_OUT(QString("%1: Call #%2 - No wells found after solver").arg(funcName).arg(callCount));
return 1e10;
}
} catch(const std::exception& e) {
DEBUG_OUT(QString("%1: Call #%2 - Error getting LogLog result: %3").arg(funcName).arg(callCount).arg(e.what()));
return 1e10;
} catch(...) {
DEBUG_OUT(QString("%1: Call #%2 - Unknown error getting LogLog result").arg(funcName).arg(callCount));
return 1e10;
}
// 6. 双对数曲线对齐和误差计算
double error;
try {
error = calculateLogLogCurveError(m_targetLogLogData, resultLogLogData);
if(!isFiniteNumber(error) || error < 0) {
DEBUG_OUT(QString("%1: Call #%2 - Invalid error value: %3").arg(funcName).arg(callCount).arg(error));
return 1e10;
}
DEBUG_OUT(QString("%1: Call #%2 - Evaluation successful, error = %3")
.arg(funcName).arg(callCount).arg(error, 0, 'e', 6));
} catch(const std::exception& e) {
DEBUG_OUT(QString("%1: Call #%2 - LogLog error calculation failed: %3").arg(funcName).arg(callCount).arg(e.what()));
return 1e10;
} catch(...) {
DEBUG_OUT(QString("%1: Call #%2 - Unknown error in LogLog error calculation").arg(funcName).arg(callCount));
return 1e10;
}
return error;
} catch(const std::exception& e) {
DEBUG_OUT(QString("%1: Call #%2 - Top-level exception: %3").arg(funcName).arg(callCount).arg(e.what()));
return 1e10;
} catch(...) {
DEBUG_OUT(QString("%1: Call #%2 - Unknown top-level exception").arg(funcName).arg(callCount));
return 1e10;
}
}
double nmCalculationAutoFitGA::evaluateIndividual(GAIndividual& individual)
{
// 如果已经评估过,直接返回
if(individual.isEvaluated) {
return individual.fitness;
}
// 调用新的评估函数
individual.fitness = evaluateGenes(individual.genes);
individual.isEvaluated = true;
return individual.fitness;
}
void nmCalculationAutoFitGA::evaluatePopulation()
{
int successfulEvaluations = 0;
int totalEvaluations = 0;
int currentGenerationFailed = 0;
for(int i = 0; i < m_population.size() && !m_shouldStop; ++i) {
GAIndividual& individual = m_population[i];
if(!individual.isEvaluated) {
try {
double previousFitness = individual.fitness;
individual.fitness = evaluateGenes(individual.genes);
individual.isEvaluated = true;
totalEvaluations++;
m_totalEvaluations++;
if(individual.fitness < 1e9) {
successfulEvaluations++;
m_successfulEvaluations++;
// 更新全局最优
if(individual.fitness < m_bestFitness) {
m_bestFitness = individual.fitness;
m_bestIndividual = individual;
emit logMessageGenerated(tr(" Individual %1 improved: %2 -> %3")
.arg(i + 1).arg(previousFitness, 0, 'e', 3).arg(individual.fitness, 0, 'e', 3));
}
} else {
currentGenerationFailed++;
emit logMessageGenerated(tr(" Individual %1: evaluation failed").arg(i + 1));
}
// 每评估2个个体处理一次事件
if(i % 2 == 0) {
QApplication::processEvents();
}
} catch(const std::exception& e) {
emit logMessageGenerated(tr(" Individual %1: Exception: %2").arg(i + 1).arg(e.what()));
individual.fitness = 1e10;
individual.isEvaluated = true;
totalEvaluations++;
currentGenerationFailed++;
m_totalEvaluations++;
} catch(...) {
emit logMessageGenerated(tr(" Individual %1: Unknown exception").arg(i + 1));
individual.fitness = 1e10;
individual.isEvaluated = true;
totalEvaluations++;
currentGenerationFailed++;
m_totalEvaluations++;
}
}
}
if(m_shouldStop) return;
double currentSuccessRate = totalEvaluations > 0 ?
(double)successfulEvaluations / totalEvaluations : 0.0;
// 更新连续失败代数计数
if(successfulEvaluations == 0) {
m_consecutiveFailedGenerations++;
emit logMessageGenerated(tr("WARNING: No successful evaluations in generation %1 (consecutive failures: %2)")
.arg(m_currentGeneration + 1).arg(m_consecutiveFailedGenerations));
} else {
m_consecutiveFailedGenerations = 0; // 重置连续失败计数
}
// 输出当前代统计
emit logMessageGenerated(tr("Current generation stats: %1 successful, %2 failed out of %3 individuals (success rate: %4%)")
.arg(successfulEvaluations).arg(currentGenerationFailed)
.arg(totalEvaluations).arg(currentSuccessRate * 100, 0, 'f', 1));
// 检查是否需要停止优化
if(m_consecutiveFailedGenerations >= m_maxConsecutiveFailures) {
m_lastError = QString("Too many consecutive failed generations (%1)").arg(m_consecutiveFailedGenerations);
emit logMessageGenerated(tr("ERROR: Too many consecutive failed generations (%1/%2) - stopping optimization")
.arg(m_consecutiveFailedGenerations).arg(m_maxConsecutiveFailures));
return;
}
// 警告低成功率但不立即停止
if(currentSuccessRate < 0.5 && m_currentGeneration > 3) {
emit logMessageGenerated(tr("WARNING: Low success rate (%1%) in generation %2, but continuing optimization")
.arg(currentSuccessRate * 100, 0, 'f', 1).arg(m_currentGeneration + 1));
}
}
int nmCalculationAutoFitGA::tournamentSelection()
{
int bestIndex = qrand() % m_population.size();
double bestFitness = m_population[bestIndex].fitness;
for(int i = 1; i < m_tournamentSize; ++i) {
int candidateIndex = qrand() % m_population.size();
double candidateFitness = m_population[candidateIndex].fitness;
if(candidateFitness < bestFitness) {
bestIndex = candidateIndex;
bestFitness = candidateFitness;
}
}
return bestIndex;
}
int nmCalculationAutoFitGA::rouletteWheelSelection()
{
// 计算适应度总和(使用倒数,因为我们要最小化)
double totalFitness = 0.0;
double maxFitness = -1e10;
// 找到最大适应度值
for(int i = 0; i < m_population.size(); ++i) {
if(m_population[i].fitness > maxFitness) {
maxFitness = m_population[i].fitness;
}
}
// 计算转换后的适应度总和
for(int i = 0; i < m_population.size(); ++i) {
double transformedFitness = maxFitness - m_population[i].fitness + 1e-6;
totalFitness += transformedFitness;
}
// 轮盘赌选择
double randomValue = random01() * totalFitness;
double cumulativeFitness = 0.0;
for(int i = 0; i < m_population.size(); ++i) {
double transformedFitness = maxFitness - m_population[i].fitness + 1e-6;
cumulativeFitness += transformedFitness;
if(cumulativeFitness >= randomValue) {
return i;
}
}
return m_population.size() - 1; // 备用选择
}
void nmCalculationAutoFitGA::crossover(const GAIndividual& parent1, const GAIndividual& parent2,
GAIndividual& offspring1, GAIndividual& offspring2)
{
if(m_useUniformCrossover) {
uniformCrossover(parent1, parent2, offspring1, offspring2);
} else {
singlePointCrossover(parent1, parent2, offspring1, offspring2);
}
}
void nmCalculationAutoFitGA::singlePointCrossover(const GAIndividual& parent1, const GAIndividual& parent2,
GAIndividual& offspring1, GAIndividual& offspring2)
{
int dimensions = parent1.genes.size();
if(dimensions == 0) return;
// 初始化子代
offspring1.genes.resize(dimensions);
offspring2.genes.resize(dimensions);
offspring1.fitness = 1e10;
offspring2.fitness = 1e10;
offspring1.isEvaluated = false;
offspring2.isEvaluated = false;
// 选择交叉点
int crossoverPoint = qrand() % dimensions;
// 执行交叉
for(int i = 0; i < dimensions; ++i) {
if(i < crossoverPoint) {
offspring1.genes[i] = parent1.genes[i];
offspring2.genes[i] = parent2.genes[i];
} else {
offspring1.genes[i] = parent2.genes[i];
offspring2.genes[i] = parent1.genes[i];
}
}
}
void nmCalculationAutoFitGA::uniformCrossover(const GAIndividual& parent1, const GAIndividual& parent2,
GAIndividual& offspring1, GAIndividual& offspring2)
{
int dimensions = parent1.genes.size();
if(dimensions == 0) return;
// 初始化子代
offspring1.genes.resize(dimensions);
offspring2.genes.resize(dimensions);
offspring1.fitness = 1e10;
offspring2.fitness = 1e10;
offspring1.isEvaluated = false;
offspring2.isEvaluated = false;
// 均匀交叉
for(int i = 0; i < dimensions; ++i) {
if(random01() < 0.5) {
offspring1.genes[i] = parent1.genes[i];
offspring2.genes[i] = parent2.genes[i];
} else {
offspring1.genes[i] = parent2.genes[i];
offspring2.genes[i] = parent1.genes[i];
}
}
}
void nmCalculationAutoFitGA::mutate(GAIndividual& individual)
{
// 使用高斯变异作为主要方式
gaussianMutation(individual);
}
void nmCalculationAutoFitGA::gaussianMutation(GAIndividual& individual)
{
for(int i = 0; i < individual.genes.size(); ++i) {
if(random01() < m_mutationRate) {
int paramIndex = m_enabledParamIndices[i];
double range = m_parameterUpper[paramIndex] - m_parameterLower[paramIndex];
double sigma = range * MUTATION_STRENGTH;
// 高斯变异
double mutation = gaussianRandom(0.0, sigma);
individual.genes[i] += mutation;
// 边界处理
individual.genes[i] = qMax(m_parameterLower[paramIndex],
qMin(m_parameterUpper[paramIndex], individual.genes[i]));
}
}
// 标记为未评估
individual.isEvaluated = false;
}
void nmCalculationAutoFitGA::polynomialMutation(GAIndividual& individual)
{
const double eta = 20.0; // 分布指数
for(int i = 0; i < individual.genes.size(); ++i) {
if(random01() < m_mutationRate) {
int paramIndex = m_enabledParamIndices[i];
double lower = m_parameterLower[paramIndex];
double upper = m_parameterUpper[paramIndex];
double y = individual.genes[i];
double delta1 = (y - lower) / (upper - lower);
double delta2 = (upper - y) / (upper - lower);
double rnd = random01();
double mut_pow = 1.0 / (eta + 1.0);
double deltaq;
if(rnd <= 0.5) {
double xy = 1.0 - delta1;
double val = 2.0 * rnd + (1.0 - 2.0 * rnd) * pow(xy, eta + 1.0);
deltaq = pow(val, mut_pow) - 1.0;
} else {
double xy = 1.0 - delta2;
double val = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * pow(xy, eta + 1.0);
deltaq = 1.0 - pow(val, mut_pow);
}
y += deltaq * (upper - lower);
individual.genes[i] = qMax(lower, qMin(upper, y));
}
}
// 标记为未评估
individual.isEvaluated = false;
}
void nmCalculationAutoFitGA::applyElitism(QVector<GAIndividual>& newPopulation)
{
int eliteCount = static_cast<int>(m_populationSize * m_elitismRate);
if(eliteCount == 0) return;
// 对种群按适应度排序
QVector<GAIndividual> sortedPopulation = m_population;
// 冒泡排序(适应度从小到大)
for(int i = 0; i < sortedPopulation.size() - 1; ++i) {
for(int j = 0; j < sortedPopulation.size() - 1 - i; ++j) {
if(sortedPopulation[j].fitness > sortedPopulation[j + 1].fitness) {
GAIndividual temp = sortedPopulation[j];
sortedPopulation[j] = sortedPopulation[j + 1];
sortedPopulation[j + 1] = temp;
}
}
}
// 复制精英个体到新种群
for(int i = 0; i < eliteCount && i < sortedPopulation.size(); ++i) {
newPopulation.append(sortedPopulation[i]);
}
DEBUG_OUT(QString("Applied elitism: %1 elite individuals preserved").arg(eliteCount));
}
void nmCalculationAutoFitGA::updatePopulationStatistics()
{
if(m_population.isEmpty()) return;
m_previousBestFitness = m_bestFitness;
double sum = 0.0;
double minFitness = 1e10;
double maxFitness = -1e10;
int validCount = 0;
for(int i = 0; i < m_population.size(); ++i) {
const GAIndividual& individual = m_population[i];
if(individual.isEvaluated && individual.fitness < 1e9) {
sum += individual.fitness;
validCount++;
if(individual.fitness < minFitness) {
minFitness = individual.fitness;
}
if(individual.fitness > maxFitness) {
maxFitness = individual.fitness;
}
// 更新全局最优
if(individual.fitness < m_bestFitness) {
// 只有显著改进时才更新
double improvement = (m_bestFitness - individual.fitness);
double relativeImprovement = improvement / qMax(1e-10, qAbs(m_bestFitness));
if(relativeImprovement > m_improvementThreshold) {
m_bestFitness = individual.fitness;
m_bestIndividual = individual;
DEBUG_OUT(QString("Global best updated with %1% improvement: %2")
.arg(relativeImprovement * 100, 0, 'f', 3)
.arg(m_bestFitness, 0, 'e', 4));
}
}
}
}
if(validCount > 0) {
m_averageFitness = sum / validCount;
m_worstFitness = maxFitness;
} else {
m_averageFitness = 1e10;
m_worstFitness = 1e10;
}
// 在没有找到更好解时才检查精英保护
if(m_hasValidUserSolution && m_userInitialFitness < m_bestFitness) {
DEBUG_OUT("Elite protection: No significant improvement found, checking initial solution");
// 检查初始解是否仍然是最优的
double improvement = m_bestFitness - m_userInitialFitness;
double relativeImprovement = improvement / qMax(1e-10, qAbs(m_bestFitness));
if(relativeImprovement > m_improvementThreshold * 0.5) { // 使用更宽松的阈值
DEBUG_OUT("Elite protection: Restoring user initial solution");
m_bestFitness = m_userInitialFitness;
m_bestIndividual.genes = m_userInitialSolution;
m_bestIndividual.fitness = m_userInitialFitness;
m_bestIndividual.isEvaluated = true;
}
}
}
bool nmCalculationAutoFitGA::checkConvergence()
{
if(m_convergenceHistory.size() < CONVERGENCE_CHECK_INTERVAL) {
return false;
}
// 检查最近几次世代的改进
double recentBest = m_convergenceHistory.last();
double oldBest = m_convergenceHistory[m_convergenceHistory.size() - CONVERGENCE_CHECK_INTERVAL];
double improvement = oldBest - recentBest;
// 如果连续多代没有显著改进,认为已收敛
if(improvement < MIN_FITNESS_IMPROVEMENT) {
// 检查是否连续停滞
int stagnationCount = 0;
for(int i = m_convergenceHistory.size() - 1; i >= qMax(0, m_convergenceHistory.size() - MAX_STAGNATION_GENERATIONS); --i) {
if(i > 0) {
double diff = m_convergenceHistory[i - 1] - m_convergenceHistory[i];
if(diff < MIN_FITNESS_IMPROVEMENT) {
stagnationCount++;
} else {
break;
}
}
}
return stagnationCount >= MAX_STAGNATION_GENERATIONS;
}
return false;
}
void nmCalculationAutoFitGA::adaptiveParameterUpdate(int generation)
{
// 自适应调整变异率
double progress = static_cast<double>(generation) / m_maxGenerations;
// 早期探索,后期开发
m_mutationRate = 0.2 * (1.0 - progress) + 0.05 * progress;
// 自适应调整交叉率
if(generation > 0) {
double improvement = m_previousBestFitness - m_bestFitness;
if(improvement < MIN_FITNESS_IMPROVEMENT) {
// 如果改进很小,增加探索性
m_mutationRate = qMin(0.3, m_mutationRate * 1.1);
m_crossoverRate = qMax(0.6, m_crossoverRate * 0.95);
} else {
// 如果有明显改进,增加开发性
m_mutationRate = qMax(0.05, m_mutationRate * 0.9);
m_crossoverRate = qMin(0.9, m_crossoverRate * 1.05);
}
}
}
void nmCalculationAutoFitGA::validateAndProtectFinalResult()
{
if(!m_hasValidUserSolution) {
emit logMessageGenerated(tr("No initial solution for elite protection"));
return;
}
emit logMessageGenerated(tr("=== Final Result Validation (Elite Protection) ==="));
// 使用已有的评估结果
double finalFitness = m_bestFitness;
double initialFitness = m_userInitialFitness;
emit logMessageGenerated(tr("Comparing results: Initial=%1, Final=%2")
.arg(initialFitness, 0, 'e', 4).arg(finalFitness, 0, 'e', 4));
// 计算改进程度
double improvement = initialFitness - finalFitness;
double relativeImprovement = improvement / qMax(1e-10, qAbs(initialFitness));
emit logMessageGenerated(tr("Improvement: %1 (%2%)")
.arg(improvement, 0, 'e', 4).arg(relativeImprovement * 100, 0, 'f', 2));
if(relativeImprovement < m_improvementThreshold) {
emit logMessageGenerated(tr("Elite protection triggered: insufficient improvement"));
emit logMessageGenerated(tr("Threshold: %1%, Actual: %2%")
.arg(m_improvementThreshold * 100, 0, 'f', 2)
.arg(relativeImprovement * 100, 0, 'f', 4));
emit logMessageGenerated(tr("Restoring initial solution as final result"));
m_bestFitness = initialFitness;
m_bestIndividual.genes = m_userInitialSolution;
m_bestIndividual.fitness = initialFitness;
m_bestIndividual.isEvaluated = true;
emit logMessageGenerated(tr("Initial solution restored successfully"));
} else {
emit logMessageGenerated(tr("Final result validated - significant improvement achieved"));
}
}
StopReasonGA nmCalculationAutoFitGA::analyzeOptimizationStatus()
{
// 1. 检查用户停止
if(m_shouldStop) {
return GA_USER_STOPPED;
}
// 2. 检查连续失败
if(m_consecutiveFailedGenerations >= m_maxConsecutiveFailures) {
return GA_CONSECUTIVE_FAILURES;
}
// 3. 检查是否达到目标精度
if(m_bestFitness < m_targetError) {
return GA_TARGET_ACHIEVED;
}
// 4. 检查是否达到最大迭代数
if(m_currentGeneration >= m_maxGenerations - 1) {
return GA_MAX_ITERATIONS;
}
// 5. 需要足够的历史数据才能判断收敛
if(m_convergenceHistory.size() < m_localOptimumWindow) {
return GA_CONTINUE_OPTIMIZATION;
}
// 6. 检查真正的收敛
if(m_convergenceHistory.size() >= m_trueConvergenceWindow && checkTrueConvergence()) {
return GA_TRUE_CONVERGENCE;
}
// 7. 检查局部最优陷阱
if(checkLocalOptimumTrap()) {
return GA_LOCAL_OPTIMUM;
}
return GA_CONTINUE_OPTIMIZATION;
}
bool nmCalculationAutoFitGA::checkTrueConvergence() const
{
if(m_convergenceHistory.size() < m_trueConvergenceWindow) {
return false;
}
// 1. 检查解质量 - 如果已经接近目标,小改进可能是真收敛
bool nearTarget = (m_bestFitness < m_targetError * m_nearTargetFactor);
// 2. 检查适应度稳定性 - 长期小幅波动
double recentVariance = calculateFitnessVariance(10);
double recentMean = 0.0;
int windowSize = qMin(10, m_convergenceHistory.size());
// 计算最近窗口的均值
for(int i = m_convergenceHistory.size() - windowSize; i < m_convergenceHistory.size(); ++i) {
recentMean += m_convergenceHistory[i];
}
recentMean /= windowSize;
double relativeVariance = recentVariance / qMax(1e-10, recentMean * recentMean);
bool stableError = (relativeVariance < m_convergenceVarianceThreshold);
// 3. 检查种群多样性 - 应该收敛到同一区域
double currentDiversity = calculatePopulationDiversity();
bool lowDiversity = (currentDiversity < m_diversityThreshold);
// 4. 检查长期改进趋势
double longTermImprovement = calculateLongTermImprovement(m_trueConvergenceWindow);
bool minimalLongTermImprovement = (longTermImprovement < 1e-4); // 0.01%
// 真收敛的判断条件
bool isConverged = nearTarget ||
(stableError && lowDiversity && minimalLongTermImprovement);
if(isConverged) {
DEBUG_OUT("=== TRUE CONVERGENCE ANALYSIS ===");
DEBUG_OUT(QString("nearTarget=%1 (fitness=%2, target*factor=%3)")
.arg(nearTarget).arg(m_bestFitness, 0, 'e', 4)
.arg(m_targetError * m_nearTargetFactor, 0, 'e', 4));
DEBUG_OUT(QString("stableError=%1 (relativeVariance=%2)")
.arg(stableError).arg(relativeVariance, 0, 'e', 6));
DEBUG_OUT(QString("lowDiversity=%1 (diversity=%2, threshold=%3)")
.arg(lowDiversity).arg(currentDiversity, 0, 'f', 6).arg(m_diversityThreshold));
DEBUG_OUT(QString("longTermImprovement=%1%")
.arg(longTermImprovement * 100, 0, 'f', 4));
}
return isConverged;
}
bool nmCalculationAutoFitGA::checkLocalOptimumTrap() const
{
if(m_convergenceHistory.size() < m_localOptimumWindow) {
return false;
}
// 1. 检查解质量 - 如果距离目标还很远,停滞就可能是局部最优
bool farFromTarget = (m_bestFitness > m_targetError * m_farTargetFactor);
// 2. 检查短期改进 - 近期改进非常小
double shortTermImprovement = calculateLongTermImprovement(m_localOptimumWindow);
bool poorShortTermImprovement = (shortTermImprovement < 1e-5); // 0.001%
// 3. 检查种群多样性 - 可能过早聚集或无效分散
double currentDiversity = calculatePopulationDiversity();
bool problematicDiversity = (currentDiversity < m_diversityThreshold * 0.1) ||
(currentDiversity > m_diversityThreshold * 5.0);
// 4. 检查适应度方差 - 可能卡在平坦区域
double fitnessVariance = calculateFitnessVariance(m_localOptimumWindow);
bool flatFitnessLandscape = (fitnessVariance < m_convergenceVarianceThreshold * 0.1);
// 局部最优的判断条件
bool isLocalOptimum = farFromTarget && poorShortTermImprovement &&
(problematicDiversity || flatFitnessLandscape);
if(isLocalOptimum) {
DEBUG_OUT("=== LOCAL OPTIMUM ANALYSIS ===");
DEBUG_OUT(QString("farFromTarget=%1 (fitness=%2, target*factor=%3)")
.arg(farFromTarget).arg(m_bestFitness, 0, 'e', 4)
.arg(m_targetError * m_farTargetFactor, 0, 'e', 4));
DEBUG_OUT(QString("poorShortTermImprovement=%1 (improvement=%2%)")
.arg(poorShortTermImprovement).arg(shortTermImprovement * 100, 0, 'f', 4));
DEBUG_OUT(QString("problematicDiversity=%1 (diversity=%2)")
.arg(problematicDiversity).arg(currentDiversity, 0, 'f', 6));
DEBUG_OUT(QString("fitnessVariance=%1")
.arg(fitnessVariance, 0, 'e', 6));
}
return isLocalOptimum;
}
double nmCalculationAutoFitGA::calculatePopulationDiversity() const
{
if(m_population.size() < 2) return 0.0;
int dimensions = getEnabledParameterCount();
if(dimensions == 0) return 0.0;
double totalDiversity = 0.0;
for(int dim = 0; dim < dimensions; ++dim) {
// 计算该维度上所有个体的均值
double mean = 0.0;
for(int i = 0; i < m_population.size(); ++i) {
mean += m_population[i].genes[dim];
}
mean /= m_population.size();
// 计算该维度上的方差
double variance = 0.0;
for(int i = 0; i < m_population.size(); ++i) {
double diff = m_population[i].genes[dim] - mean;
variance += diff * diff;
}
variance /= m_population.size();
// 归一化到参数范围
int paramIndex = m_enabledParamIndices[dim];
double range = m_parameterUpper[paramIndex] - m_parameterLower[paramIndex];
double normalizedStd = sqrt(variance) / qMax(1e-10, range);
totalDiversity += normalizedStd;
}
return totalDiversity / dimensions;
}
double nmCalculationAutoFitGA::calculateFitnessVariance(int windowSize) const
{
if(m_convergenceHistory.size() < windowSize) {
return 1e10; // 数据不足,返回大值
}
// 计算最近windowSize次迭代的方差
double mean = 0.0;
int startIdx = m_convergenceHistory.size() - windowSize;
for(int i = startIdx; i < m_convergenceHistory.size(); ++i) {
mean += m_convergenceHistory[i];
}
mean /= windowSize;
double variance = 0.0;
for(int i = startIdx; i < m_convergenceHistory.size(); ++i) {
double diff = m_convergenceHistory[i] - mean;
variance += diff * diff;
}
variance /= windowSize;
return variance;
}
double nmCalculationAutoFitGA::calculateLongTermImprovement(int windowSize) const
{
if(m_convergenceHistory.size() < windowSize) {
return 1.0; // 数据不足,假设有改进
}
double oldFitness = m_convergenceHistory[m_convergenceHistory.size() - windowSize];
double improvement = (oldFitness - m_bestFitness) / qMax(1e-10, qAbs(oldFitness));
return improvement;
}
void nmCalculationAutoFitGA::updateConvergenceMetrics()
{
// 更新多样性历史
m_diversityHistory.append(calculatePopulationDiversity());
// 保持历史长度合理最多保留50个数据点
const int maxHistorySize = 50;
while(m_diversityHistory.size() > maxHistorySize) {
m_diversityHistory.remove(0);
}
}
// ==================== 参数应用方法 ====================
bool nmCalculationAutoFitGA::validateParameters(const QVector<double>& parameters) const
{
if(parameters.size() != getEnabledParameterCount()) {
return false;
}
for(int i = 0; i < parameters.size(); ++i) {
if(!isFiniteNumber(parameters[i])) {
return false;
}
// 检查参数范围
if(i < m_enabledParamIndices.size()) {
int paramIndex = m_enabledParamIndices[i];
if(paramIndex >= 0 && paramIndex < m_parameterLower.size()) {
if(parameters[i] < m_parameterLower[paramIndex] ||
parameters[i] > m_parameterUpper[paramIndex]) {
return false;
}
}
}
}
// 直接拦截会导致求解器数值崩溃的参数值
for(int i = 0; i < parameters.size() && i < m_enabledParamIndices.size(); ++i) {
int paramIndex = m_enabledParamIndices[i];
double value = parameters[i];
switch(paramIndex) {
case 0: // 渗透率:必须大于零
if(value <= 1e-8) {
DEBUG_OUT(QString("Rejecting near-zero permeability: %1").arg(value));
return false;
}
break;
case 2: // 井筒储集系数:必须大于零
if(value <= 1e-10) {
DEBUG_OUT(QString("Rejecting near-zero wellbore storage: %1").arg(value));
return false;
}
break;
case 3: // 孔隙度:必须在合理范围
if(value <= 1e-6 || value >= 0.99) {
DEBUG_OUT(QString("Rejecting unrealistic porosity: %1").arg(value));
return false;
}
break;
case 6: // 综合压缩系数:必须大于零
if(value <= 1e-8) {
DEBUG_OUT(QString("Rejecting near-zero total compressibility: %1").arg(value));
return false;
}
break;
}
}
return true;
}
bool nmCalculationAutoFitGA::validateLogLogData(const QVector<QVector<double>>& logLogData) const
{
// 检查基本结构
if(logLogData.size() < 3) {
DEBUG_OUT("LogLog data has less than 3 arrays");
return false;
}
// 检查数组大小一致性
int size = logLogData[0].size();
if(size == 0) {
DEBUG_OUT("Empty LogLog data");
return false;
}
if(logLogData[1].size() != size || logLogData[2].size() != size) {
DEBUG_OUT(QString("LogLog data size mismatch: X=%1, Y1=%2, Y2=%3")
.arg(logLogData[0].size())
.arg(logLogData[1].size())
.arg(logLogData[2].size()));
return false;
}
// 检查最小数据点数
if(size < 5) {
DEBUG_OUT(QString("Too few LogLog data points: %1").arg(size));
return false;
}
// 数据有效性检查
for(int i = 0; i < size; ++i) {
if(!isFiniteNumber(logLogData[0][i]) ||
!isFiniteNumber(logLogData[1][i]) ||
!isFiniteNumber(logLogData[2][i])) {
DEBUG_OUT(QString("Invalid LogLog data at index %1").arg(i));
return false;
}
}
return true;
}
bool nmCalculationAutoFitGA::validateInitialValues() const
{
if(m_initialValues.size() != m_enabledParamIndices.size()) {
DEBUG_OUT("Initial values count mismatch with enabled parameters");
return false;
}
bool allValid = true;
for(int i = 0; i < m_initialValues.size(); ++i) {
int paramIndex = m_enabledParamIndices[i];
double value = m_initialValues[i];
if(!isFiniteNumber(value)) {
DEBUG_OUT(QString("Initial value[%1] is not finite: %2").arg(i).arg(value));
allValid = false;
continue;
}
if(paramIndex < m_parameterLower.size() && paramIndex < m_parameterUpper.size()) {
double minVal = m_parameterLower[paramIndex];
double maxVal = m_parameterUpper[paramIndex];
if(value < minVal || value > maxVal) {
DEBUG_OUT(QString("Initial value[%1] = %2 is outside bounds [%3, %4]")
.arg(i).arg(value).arg(minVal).arg(maxVal));
allValid = false;
}
}
}
return allValid;
}
void nmCalculationAutoFitGA::applyParametersToDataManager(const QVector<double>& parameters)
{
if(parameters.size() != getEnabledParameterCount()) {
return;
}
updateReservoirParameters(parameters);
updateWellParameters(parameters);
}
void nmCalculationAutoFitGA::updateReservoirParameters(const QVector<double>& parameters)
{
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
nmDataReservoir reservoirData = dataManager->getReservoirDataCopy();
int paramIndex = 0;
for(int i = 0; i < m_parameterSelected.size() && i < 11; ++i) {
if(m_parameterSelected[i] && paramIndex < parameters.size()) {
double value = parameters[paramIndex];
switch(i) {
case 0: // 渗透率
reservoirData.getPermeability().setValue(value);
break;
case 3: // 孔隙度
reservoirData.getPorosity().setValue(value);
break;
case 4: // 初始压力
reservoirData.getInitialPressure().setValue(value);
break;
case 5: // 储层厚度
reservoirData.getThickness().setValue(value);
break;
case 6: // 综合压缩系数
reservoirData.getCt().setValue(value);
break;
case 7: // 岩石压缩系数
reservoirData.getCf().setValue(value);
break;
case 8: // 初始含油饱和度
reservoirData.getSoi().setValue(value);
break;
case 9: // 初始含水饱和度
reservoirData.getSwi().setValue(value);
break;
case 10: // 初始含气饱和度
reservoirData.getSgi().setValue(value);
break;
}
paramIndex++;
}
}
// 更新数据管理器
dataManager->updateReservoirData(reservoirData);
}
void nmCalculationAutoFitGA::updateWellParameters(const QVector<double>& parameters)
{
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
// 获取井列表,更新第一口井的参数
//QVector<nmDataWellBase*> wells = dataManager->getWellDataList();
nmDataWellBase* pWell = dataManager->findWellByName(m_targetWellName);
if(!pWell) return;
//nmDataWellBase* pWell = wells[0]; // 使用第一口井
int paramIndex = 0;
for(int i = 0; i < m_parameterSelected.size() && i < 9; ++i) {
if(m_parameterSelected[i] && paramIndex < parameters.size()) {
double value = parameters[paramIndex];
switch(i) {
case 1: { // 表皮系数
nmDataAttribute skinAttr = pWell->getPerforation(0)->getSkin();
skinAttr.setValue(value);
pWell->setRateDependentSkin(skinAttr);
}
break;
case 2: { // 井筒储集系数
nmDataAttribute wellboreAttr = pWell->getWellboreStorage();
wellboreAttr.setValue(value);
pWell->setWellboreStorage(wellboreAttr);
}
break;
}
paramIndex++;
}
}
// 根据井类型更新到数据管理器
updateWellToDataManager(pWell);
}
void nmCalculationAutoFitGA::updateWellToDataManager(nmDataWellBase* pWell)
{
if(!pWell) return;
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
NM_WELL_MODEL wellType = pWell->getWellType();
switch(wellType) {
case NM_WELL_MODEL::Vertical_Well: {
nmDataVerticalWell* pVerticalWell = dynamic_cast<nmDataVerticalWell*>(pWell);
if(pVerticalWell) {
QVector<nmDataVerticalWell> wells;
wells.append(*pVerticalWell);
dataManager->updateVerticalWells(wells);
}
break;
}
case NM_WELL_MODEL::Vertical_Fractured_Well: {
nmDataVerticalFracturedWell* pVFracturedWell = dynamic_cast<nmDataVerticalFracturedWell*>(pWell);
if(pVFracturedWell) {
QVector<nmDataVerticalFracturedWell> wells;
wells.append(*pVFracturedWell);
dataManager->updateVerticalFracturedWells(wells);
}
break;
}
case NM_WELL_MODEL::Horizontal_Fractured_Well: {
nmDataHorizontalFracturedWell* pHFracturedWell = dynamic_cast<nmDataHorizontalFracturedWell*>(pWell);
if(pHFracturedWell) {
QVector<nmDataHorizontalFracturedWell> wells;
wells.append(*pHFracturedWell);
dataManager->updateHorizontalFracturedWells(wells);
}
break;
}
default:
break;
}
}
void nmCalculationAutoFitGA::clampToLimits(QVector<double>& parameters) const
{
for(int i = 0; i < parameters.size() && i < m_enabledParamIndices.size(); ++i) {
int paramIndex = m_enabledParamIndices[i];
if(paramIndex >= 0 && paramIndex < m_parameterLower.size()) {
parameters[i] = qMax(m_parameterLower[paramIndex],
qMin(m_parameterUpper[paramIndex], parameters[i]));
}
}
}
// ==================== 求解器相关方法 ====================
QVector<QVector<double>> nmCalculationAutoFitGA::runSolver()
{
//return runSolverExe();
return runSolverDll();
}
bool nmCalculationAutoFitGA::validateSolverResult(const QVector<QVector<double>>& result) const
{
// 基本检查
if(result.size() < 2) {
DEBUG_OUT("Solver result has less than 2 arrays");
return false;
}
if(result[0].size() != result[1].size()) {
DEBUG_OUT(QString("Size mismatch: X=%1, Y=%2").arg(result[0].size()).arg(result[1].size()));
return false;
}
if(result[0].size() == 0) {
DEBUG_OUT("Empty solver result");
return false;
}
// 检查最小数据点数
if(result[0].size() < 10) {
DEBUG_OUT(QString("Too few data points: %1").arg(result[0].size()));
return false;
}
// 数据有效性检查
for(int i = 0; i < result[0].size(); ++i) {
if(!isFiniteNumber(result[0][i]) || !isFiniteNumber(result[1][i])) {
DEBUG_OUT(QString("Invalid data at index %1: X=%2, Y=%3")
.arg(i).arg(result[0][i]).arg(result[1][i]));
return false;
}
}
return true;
}
QVector<QVector<double>> nmCalculationAutoFitGA::runSolverDll()
{
DEBUG_OUT("SOLVER DLL START");
if(m_evaluationInProgress > 0) {
DEBUG_OUT("DLL Solver already running, skipping");
return QVector<QVector<double>>();
}
++m_evaluationInProgress;
QVector<QVector<double>> result;
nmCalculationDllPebiSolverTask* dllTask = nullptr;
try {
DEBUG_OUT("Creating DLL solver task");
dllTask = new nmCalculationDllPebiSolverTask(m_tempDirectory);
if(m_shouldStop) {
DEBUG_OUT("Should stop - cleaning up and returning empty result");
delete dllTask;
--m_evaluationInProgress;
return result;
}
DEBUG_OUT("Starting DLL solver execution...");
// 异步执行
dllTask->start();
// 等待完成
int waitTime = 0;
const int maxWait = 30000; // 30秒超时
const int checkInterval = 500;
while(waitTime < maxWait) {
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 100);
if(!dllTask->isRunning()) {
DEBUG_OUT("DLL solver task completed");
break;
}
if(m_shouldStop) {
DEBUG_OUT("DLL solver task terminated by user");
dllTask->terminate();
break;
}
msleep(checkInterval);
waitTime += checkInterval;
}
// 超时处理
if(dllTask->isRunning()) {
DEBUG_OUT("DLL solver task timeout, terminating...");
dllTask->terminate();
dllTask->wait(2000);
delete dllTask;
dllTask = nullptr;
--m_evaluationInProgress;
m_consecutiveFailures++;
return result;
}
// 验证结果数据是否已更新
nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
//QVector<nmDataWellBase*> wells = dataManager->getWellDataList();
nmDataWellBase* pTargetWell = dataManager->findWellByName(m_targetWellName);
if(!pTargetWell) {
DEBUG_OUT("No wells found in data manager after DLL execution");
delete dllTask;
--m_evaluationInProgress;
return result;
}
// 验证结果数据
QVector<QVector<double>> pressureResult = pTargetWell->getResultPressure();
QVector<QVector<double>> logLogResult = pTargetWell->getResultLogLog();
DEBUG_OUT(QString("DLL result verification - Pressure arrays: %1, LogLog arrays: %2")
.arg(pressureResult.size()).arg(logLogResult.size()));
if(pressureResult.size() >= 2) {
DEBUG_OUT(QString("Pressure result - Time points: %1, Pressure points: %2")
.arg(pressureResult[0].size()).arg(pressureResult[1].size()));
if(pressureResult[0].size() > 0) {
DEBUG_OUT(QString("Sample pressure data - Time[0]: %1, Time[last]: %2, P[0]: %3, P[last]: %4")
.arg(pressureResult[0][0])
.arg(pressureResult[0][pressureResult[0].size()-1])
.arg(pressureResult[1][0])
.arg(pressureResult[1][pressureResult[1].size()-1]));
}
}
// 数据有效性检查
if(pressureResult.size() >= 2 && pressureResult[0].size() > 0 && pressureResult[1].size() > 0) {
result = pressureResult;
DEBUG_OUT(QString("Got DLL solver result: %1 points").arg(result[0].size()));
m_consecutiveFailures = 0;
// 检查结果是否与之前不同
static QVector<double> lastPressureResult;
bool isDifferentFromLast = false;
if(lastPressureResult.isEmpty() || lastPressureResult.size() != pressureResult[1].size()) {
isDifferentFromLast = true;
} else {
for(int i = 0; i < qMin(5, pressureResult[1].size()); ++i) {
if(qAbs(lastPressureResult[i] - pressureResult[1][i]) > 1e-12) {
isDifferentFromLast = true;
break;
}
}
}
if(isDifferentFromLast) {
DEBUG_OUT("RESULT VERIFICATION: Got NEW result data from DLL");
lastPressureResult = pressureResult[1];
} else {
DEBUG_OUT("!!! WARNING: Result data appears to be identical to previous run !!!");
}
} else {
DEBUG_OUT("DLL solver result is empty or invalid");
DEBUG_OUT(QString("Pressure result size: %1, Array sizes: %2, %3")
.arg(pressureResult.size())
.arg(pressureResult.size() > 0 ? pressureResult[0].size() : 0)
.arg(pressureResult.size() > 1 ? pressureResult[1].size() : 0));
m_consecutiveFailures++;
}
} catch(const std::bad_alloc& e) {
DEBUG_OUT(QString("Memory allocation failed in DLL solver: %1").arg(e.what()));
m_consecutiveFailures++;
} catch(const std::exception& e) {
DEBUG_OUT(QString("Exception in DLL solver: %1").arg(e.what()));
m_consecutiveFailures++;
} catch(...) {
DEBUG_OUT("Unknown exception in DLL solver");
m_consecutiveFailures++;
}
// 清理DLL任务
if(dllTask) {
if(dllTask->isRunning()) {
dllTask->terminate();
dllTask->wait(3000);
}
DEBUG_OUT("Cleaning up DLL solver task...");
delete dllTask;
dllTask = nullptr;
}
QApplication::processEvents(QEventLoop::AllEvents, 100);
--m_evaluationInProgress;
DEBUG_OUT(QString("SOLVER DLL END - ResultPoints: %1")
.arg(result.isEmpty() ? 0 : result[0].size()));
return result;
}
//QVector<QVector<double>> nmCalculationAutoFitGA::runSolverExe()
//{
// DEBUG_OUT("SOLVER EXE START");
//
// if(m_evaluationInProgress > 0) {
// DEBUG_OUT("EXE Solver already running, skipping");
// return QVector<QVector<double>>();
// }
//
// ++m_evaluationInProgress;
// QVector<QVector<double>> result;
// nmCalculationExeSolverTask* exeTask = nullptr;
//
// try {
// DEBUG_OUT("Creating EXE solver task");
// exeTask = new nmCalculationExeSolverTask(QString());
//
// if(m_shouldStop) {
// DEBUG_OUT("Should stop - cleaning up and returning empty result");
// delete exeTask;
// --m_evaluationInProgress;
// return result;
// }
//
// DEBUG_OUT("Starting EXE solver execution...");
//
// // 启动
// bool executeSuccess = exeTask->execute();
//
// // 检查执行状态
// if(!executeSuccess) {
// DEBUG_OUT(QString("EXE solver execution failed: %1").arg(exeTask->getLastError()));
// DEBUG_OUT(QString("EXE solver exit code: %1").arg(exeTask->getExitCode()));
//
// // 清理并返回空结果
// delete exeTask;
// exeTask = nullptr;
// --m_evaluationInProgress;
// m_consecutiveFailures++;
// return result;
// }
//
// DEBUG_OUT("EXE solver execution completed successfully");
//
// // 验证结果数据是否已更新
// nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance();
// QVector<nmDataWellBase*> wells = dataManager->getWellDataList();
//
// if(wells.isEmpty()) {
// DEBUG_OUT("No wells found in data manager after EXE execution");
// delete exeTask;
// --m_evaluationInProgress;
// return result;
// }
//
// // 验证结果数据的时间戳或唯一性
// QVector<QVector<double>> pressureResult = wells[0]->getResultPressure();
// QVector<QVector<double>> logLogResult = wells[0]->getResultLogLog();
//
// DEBUG_OUT(QString("Raw result verification - Pressure arrays: %1, LogLog arrays: %2")
// .arg(pressureResult.size()).arg(logLogResult.size()));
//
// if(pressureResult.size() >= 2) {
// DEBUG_OUT(QString("Pressure result - Time points: %1, Pressure points: %2")
// .arg(pressureResult[0].size()).arg(pressureResult[1].size()));
//
// if(pressureResult[0].size() > 0) {
// DEBUG_OUT(QString("Sample pressure data - Time[0]: %1, Time[last]: %2, P[0]: %3, P[last]: %4")
// .arg(pressureResult[0][0])
// .arg(pressureResult[0][pressureResult[0].size() - 1])
// .arg(pressureResult[1][0])
// .arg(pressureResult[1][pressureResult[1].size() - 1]));
// }
// }
//
// if(logLogResult.size() >= 3) {
// DEBUG_OUT(QString("LogLog result - X points: %1, Y1 points: %2, Y2 points: %3")
// .arg(logLogResult[0].size()).arg(logLogResult[1].size()).arg(logLogResult[2].size()));
//
// if(logLogResult[0].size() > 0) {
// DEBUG_OUT(QString("Sample LogLog data - X[0]: %1, X[last]: %2, Y1[0]: %3, Y2[0]: %4")
// .arg(logLogResult[0][0])
// .arg(logLogResult[0][logLogResult[0].size() - 1])
// .arg(logLogResult[1][0])
// .arg(logLogResult[2][0]));
// }
// }
//
// // 数据有效性检查
// if(pressureResult.size() >= 2 && pressureResult[0].size() > 0 && pressureResult[1].size() > 0) {
// result = pressureResult;
// DEBUG_OUT(QString("Got EXE solver result: %1 points").arg(result[0].size()));
// m_consecutiveFailures = 0;
//
// // 检查结果是否与之前不同
// static QVector<double> lastPressureResult;
// bool isDifferentFromLast = false;
//
// if(lastPressureResult.isEmpty() || lastPressureResult.size() != pressureResult[1].size()) {
// isDifferentFromLast = true;
// } else {
// for(int i = 0; i < qMin(5, pressureResult[1].size()); ++i) {
// if(qAbs(lastPressureResult[i] - pressureResult[1][i]) > 1e-12) {
// isDifferentFromLast = true;
// break;
// }
// }
// }
//
// if(isDifferentFromLast) {
// DEBUG_OUT("RESULT VERIFICATION: Got NEW result data from EXE");
// lastPressureResult = pressureResult[1];
// } else {
// DEBUG_OUT("!!! WARNING: Result data appears to be identical to previous run !!!");
// }
//
// } else {
// DEBUG_OUT("EXE solver result is empty or invalid");
// DEBUG_OUT(QString("Pressure result size: %1, Array sizes: %2, %3")
// .arg(pressureResult.size())
// .arg(pressureResult.size() > 0 ? pressureResult[0].size() : 0)
// .arg(pressureResult.size() > 1 ? pressureResult[1].size() : 0));
// m_consecutiveFailures++;
// }
//
// } catch(const std::exception& e) {
// DEBUG_OUT(QString("Exception in EXE solver: %1").arg(e.what()));
// m_consecutiveFailures++;
// } catch(...) {
// DEBUG_OUT("Unknown exception in EXE solver");
// m_consecutiveFailures++;
// }
//
// // 清理EXE任务
// if(exeTask) {
// DEBUG_OUT("Cleaning up EXE solver task...");
// delete exeTask;
// exeTask = nullptr;
// }
//
// QApplication::processEvents(QEventLoop::AllEvents, 100);
// --m_evaluationInProgress;
//
// DEBUG_OUT(QString("SOLVER EXE END - ResultPoints: %1")
// .arg(result.isEmpty() ? 0 : result[0].size()));
//
// return result;
//}
// ==================== 数据处理方法 ====================
QVector<QPointF> nmCalculationAutoFitGA::interpolateData(
const QVector<QPointF>& source, const QVector<double>& targetX) const
{
QVector<QPointF> result;
if(source.isEmpty() || targetX.isEmpty()) {
DEBUG_OUT("Warning: Empty data in interpolation");
return result;
}
// 数据清理和验证合并
QVector<QPointF> validSource;
const double MAX_REASONABLE_VALUE = 1e12;
for(int i = 0; i < source.size(); ++i) {
const QPointF& point = source[i];
// 检查数值有效性
if(!isFiniteNumber(point.x()) || !isFiniteNumber(point.y())) {
DEBUG_OUT(QString("Skipping invalid data point at index %1: X=%2, Y=%3")
.arg(i).arg(point.x()).arg(point.y()));
continue;
}
// 检查极大值 - 跳过而不是失败
if(qAbs(point.y()) > MAX_REASONABLE_VALUE) {
DEBUG_OUT(QString("Skipping extremely large Y value at index %1: %2")
.arg(i).arg(point.y()));
continue;
}
// 只保留有效的数据点
validSource.append(point);
}
// 检查清理后的数据是否足够
if(validSource.size() < 3) {
DEBUG_OUT(QString("Insufficient valid data points after cleaning: %1")
.arg(validSource.size()));
return result; // 返回空结果,但不算失败
}
DEBUG_OUT(QString("Data cleaning: %1 -> %2 valid points")
.arg(source.size()).arg(validSource.size()));
// 对清理后的数据进行排序
QVector<QPointF> sortedSource = validSource;
for(int i = 0; i < sortedSource.size() - 1; ++i) {
for(int j = 0; j < sortedSource.size() - 1 - i; ++j) {
if(sortedSource[j].x() > sortedSource[j + 1].x()) {
QPointF temp = sortedSource[j];
sortedSource[j] = sortedSource[j + 1];
sortedSource[j + 1] = temp;
}
}
}
double sourceMinX = sortedSource.first().x();
double sourceMaxX = sortedSource.last().x();
double targetMinX = targetX[0];
double targetMaxX = targetX[0];
for(int i = 1; i < targetX.size(); ++i) {
if(targetX[i] < targetMinX) targetMinX = targetX[i];
if(targetX[i] > targetMaxX) targetMaxX = targetX[i];
}
DEBUG_OUT(QString("Source X range: [%1, %2], Target X range: [%3, %4]")
.arg(sourceMinX).arg(sourceMaxX).arg(targetMinX).arg(targetMaxX));
// 安全插值算法
for(int i = 0; i < targetX.size(); ++i) {
double x = targetX[i];
if(!isFiniteNumber(x)) continue;
double y = 0.0;
// 插值逻辑保持原有逻辑但使用sortedSource
if(x <= sourceMinX) {
if(sortedSource.size() >= 2) {
double dx = sortedSource[1].x() - sortedSource[0].x();
if(qAbs(dx) > 1e-10) {
double slope = (sortedSource[1].y() - sortedSource[0].y()) / dx;
slope = qMax(-1e6, qMin(1e6, slope));
y = sortedSource[0].y() + slope * (x - sortedSource[0].x());
} else {
y = sortedSource[0].y();
}
} else {
y = sortedSource[0].y();
}
} else if(x >= sourceMaxX) {
if(sortedSource.size() >= 2) {
int lastIdx = sortedSource.size() - 1;
double dx = sortedSource[lastIdx].x() - sortedSource[lastIdx - 1].x();
if(qAbs(dx) > 1e-10) {
double slope = (sortedSource[lastIdx].y() - sortedSource[lastIdx - 1].y()) / dx;
slope = qMax(-1e6, qMin(1e6, slope));
y = sortedSource[lastIdx].y() + slope * (x - sortedSource[lastIdx].x());
} else {
y = sortedSource[lastIdx].y();
}
} else {
y = sortedSource.last().y();
}
} else {
// 内插
bool found = false;
for(int j = 0; j < sortedSource.size() - 1; ++j) {
if(x >= sortedSource[j].x() && x <= sortedSource[j + 1].x()) {
double dx = sortedSource[j + 1].x() - sortedSource[j].x();
if(qAbs(dx) > 1e-10) {
double ratio = (x - sortedSource[j].x()) / dx;
y = sortedSource[j].y() + ratio * (sortedSource[j + 1].y() - sortedSource[j].y());
} else {
y = sortedSource[j].y();
}
found = true;
break;
}
}
if(!found) {
// 使用最近点
double minDist = 1e10;
for(int k = 0; k < sortedSource.size(); ++k) {
double dist = qAbs(sortedSource[k].x() - x);
if(dist < minDist) {
minDist = dist;
y = sortedSource[k].y();
}
}
}
}
// 最终数值检查
if(!isFiniteNumber(y)) {
y = sortedSource.size() > 0 ? sortedSource[0].y() : 1.0;
}
y = qMax(-1e12, qMin(1e12, y));
result.append(QPointF(x, y));
}
if(result.isEmpty()) {
DEBUG_OUT("LogLog interpolation failed");
return result;
}
DEBUG_OUT(QString("Interpolation completed: %1 -> %2 points")
.arg(validSource.size()).arg(result.size()));
return result;
}
double nmCalculationAutoFitGA::calculateLogLogCurveError(
const QVector<QVector<double>>& target,
const QVector<QVector<double>>& result) const
{
// 验证数据
if(!validateLogLogData(target) || !validateLogLogData(result)) {
return 1e10;
}
try {
// 数据对齐找到X值的重叠区域
double targetMinX = target[0][0];
double targetMaxX = target[0][0];
for(int i = 1; i < target[0].size(); ++i) {
if(target[0][i] < targetMinX) targetMinX = target[0][i];
if(target[0][i] > targetMaxX) targetMaxX = target[0][i];
}
double resultMinX = result[0][0];
double resultMaxX = result[0][0];
for(int i = 1; i < result[0].size(); ++i) {
if(result[0][i] < resultMinX) resultMinX = result[0][i];
if(result[0][i] > resultMaxX) resultMaxX = result[0][i];
}
double overlapMinX = qMax(targetMinX, resultMinX);
double overlapMaxX = qMin(targetMaxX, resultMaxX);
if(overlapMinX >= overlapMaxX) {
DEBUG_OUT("No overlap between target and result LogLog curves");
return 1e10;
}
// 生成公共X网格进行插值
QVector<double> commonX;
int numPoints = 50;
if(overlapMinX > 0 && overlapMaxX > 0) {
// 对数空间均匀分布
double logMin = qLn(overlapMinX);
double logMax = qLn(overlapMaxX);
for(int i = 0; i < numPoints; ++i) {
double logX = logMin + i * (logMax - logMin) / (numPoints - 1);
double x = qExp(logX);
// 数值保护
if(!isFiniteNumber(x) || x <= 0) {
continue;
}
commonX.append(x);
}
DEBUG_OUT("Using log-uniform grid for better early-time coverage");
}
if(commonX.isEmpty()) {
DEBUG_OUT("Failed to generate common X grid");
return 1e10;
}
// 插值目标曲线
QVector<QPointF> targetCurve1, targetCurve2;
for(int i = 0; i < target[0].size(); ++i) {
// 检查数据有效性
if(isFiniteNumber(target[0][i]) && isFiniteNumber(target[1][i]) &&
isFiniteNumber(target[2][i])) {
targetCurve1.append(QPointF(target[0][i], target[1][i]));
targetCurve2.append(QPointF(target[0][i], target[2][i]));
}
}
if(targetCurve1.isEmpty() || targetCurve2.isEmpty()) {
DEBUG_OUT("Target curves are empty after filtering");
return 1e10;
}
QVector<QPointF> alignedTarget1 = interpolateData(targetCurve1, commonX);
QVector<QPointF> alignedTarget2 = interpolateData(targetCurve2, commonX);
// 插值结果曲线
QVector<QPointF> resultCurve1, resultCurve2;
for(int i = 0; i < result[0].size(); ++i) {
// 检查数据有效性
if(isFiniteNumber(result[0][i]) && isFiniteNumber(result[1][i]) &&
isFiniteNumber(result[2][i])) {
resultCurve1.append(QPointF(result[0][i], result[1][i]));
resultCurve2.append(QPointF(result[0][i], result[2][i]));
}
}
if(resultCurve1.isEmpty() || resultCurve2.isEmpty()) {
DEBUG_OUT("Result curves are empty after filtering");
return 1e10;
}
QVector<QPointF> alignedResult1 = interpolateData(resultCurve1, commonX);
QVector<QPointF> alignedResult2 = interpolateData(resultCurve2, commonX);
// 检查插值结果
if(alignedTarget1.isEmpty() || alignedTarget2.isEmpty() ||
alignedResult1.isEmpty() || alignedResult2.isEmpty()) {
DEBUG_OUT("LogLog interpolation failed");
return 1e10;
}
if(alignedTarget1.size() != alignedResult1.size() ||
alignedTarget2.size() != alignedResult2.size()) {
DEBUG_OUT("LogLog interpolation size mismatch");
return 1e10;
}
// 计算两条曲线的误差
double error1 = calculateCurveError(alignedTarget1, alignedResult1);
double error2 = calculateCurveError(alignedTarget2, alignedResult2);
// 检查个别误差是否有效
if(!isFiniteNumber(error1) || error1 > 1e9) {
DEBUG_OUT(QString("Curve1 error is invalid: %1").arg(error1));
error1 = 1e10;
}
if(!isFiniteNumber(error2) || error2 > 1e9) {
DEBUG_OUT(QString("Curve2 error is invalid: %1").arg(error2));
error2 = 1e10;
}
// 组合误差 - 添加保护
double combinedError;
if(error1 > 1e9 && error2 > 1e9) {
combinedError = 1e10;
} else if(error1 > 1e9) {
combinedError = error2;
} else if(error2 > 1e9) {
combinedError = error1;
} else {
combinedError = 0.5 * error1 + 0.5 * error2;
}
DEBUG_OUT(QString("LogLog errors: Curve1=%1, Curve2=%2, Combined=%3")
.arg(error1, 0, 'e', 4).arg(error2, 0, 'e', 4).arg(combinedError, 0, 'e', 4));
return qMin(1e9, combinedError);
} catch(const std::exception& e) {
DEBUG_OUT(QString("Exception in LogLog error calculation: %1").arg(e.what()));
return 1e10;
} catch(...) {
DEBUG_OUT("Unknown exception in LogLog error calculation");
return 1e10;
}
}
double nmCalculationAutoFitGA::calculateCurveError(
const QVector<QPointF>& curve1, const QVector<QPointF>& curve2) const
{
if(curve1.size() != curve2.size() || curve1.isEmpty()) {
return 1e10;
}
// 预检查:确保没有无穷大值
for(int i = 0; i < curve1.size(); ++i) {
if(!isFiniteNumber(curve1[i].y()) || !isFiniteNumber(curve2[i].y())) {
DEBUG_OUT(QString("Infinite value detected at index %1: Y1=%2, Y2=%3")
.arg(i).arg(curve1[i].y()).arg(curve2[i].y()));
return 1e10;
}
if(qAbs(curve1[i].y()) > 1e12 || qAbs(curve2[i].y()) > 1e12) {
DEBUG_OUT(QString("Extremely large value detected at index %1")
.arg(i));
return 1e10;
}
}
double totalError = 0.0;
double totalWeight = 0.0;
int validPoints = 0;
for(int i = 0; i < curve1.size(); ++i) {
double y1 = curve1[i].y();
double y2 = curve2[i].y();
// 跳过异常值
if(!isFiniteNumber(y1) || !isFiniteNumber(y2)) {
continue;
}
// 自适应权重根据Y值大小调整添加上限
double weightFactor = qMin(100.0, qAbs(y1) * 0.01);
double weight = 1.0 / (1.0 + weightFactor);
// 相对误差和绝对误差的组合
double yMax = qMax(qAbs(y1), qAbs(y2));
yMax = qMax(1e-12, yMax); // 防止除零
double relativeError = qAbs(y1 - y2) / yMax;
double absoluteError = qAbs(y1 - y2);
// 限制误差值
relativeError = qMin(1e6, relativeError);
absoluteError = qMin(1e6, absoluteError);
// 误差组合:相对误差为主,绝对误差为辅
double pointError = 0.7 * relativeError + 0.3 * absoluteError;
if(isFiniteNumber(pointError) && pointError < 1e10) {
totalError += weight * pointError * pointError;
totalWeight += weight;
validPoints++;
}
}
if(totalWeight > 0 && validPoints > 0) {
double result = sqrt(totalError / totalWeight);
// 最终检查
if(!isFiniteNumber(result)) {
DEBUG_OUT("Final error calculation produced infinite result");
return 1e10;
}
return qMin(1e9, result); // 限制最大误差值
} else {
DEBUG_OUT(QString("No valid points for error calculation: validPoints=%1")
.arg(validPoints));
return 1e10;
}
}
// ==================== 工具方法 ====================
double nmCalculationAutoFitGA::random01() const
{
return static_cast<double>(qrand()) / RAND_MAX;
}
double nmCalculationAutoFitGA::gaussianRandom(double mean, double stddev) const
{
static bool hasSpare = false;
static double spare;
if(hasSpare) {
hasSpare = false;
return spare * stddev + mean;
}
hasSpare = true;
double u = qMax(random01(), 1e-12);
double v = random01();
double mag = stddev * sqrt(-2.0 * log(u));
spare = mag * cos(2.0 * 3.14159265359 * v);
return mag * sin(2.0 * 3.14159265359 * v) + mean;
}
int nmCalculationAutoFitGA::getEnabledParameterCount() const
{
int count = 0;
for(int i = 0; i < m_parameterSelected.size(); ++i) {
if(m_parameterSelected[i]) count++;
}
return count;
}
void nmCalculationAutoFitGA::saveOptimizationResult()
{
DEBUG_OUT(QString("GA optimization result: fitness=%1, evaluations=%2/%3")
.arg(m_bestFitness, 0, 'e', 4)
.arg(m_successfulEvaluations)
.arg(m_totalEvaluations));
}