#include "nmCalculationAutoFitPSO.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 "nmCalculationPebiGrid.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #include #define DEBUG_OUT(msg) OutputDebugStringA(QString("[AutoFit] %1\n").arg(msg).toLocal8Bit().data()) #endif // 常量定义 const double nmCalculationAutoFitPSO::MIN_FITNESS_IMPROVEMENT = 1e-8; const double nmCalculationAutoFitPSO::VELOCITY_LIMIT_FACTOR = 0.2; const int nmCalculationAutoFitPSO::CONVERGENCE_CHECK_INTERVAL = 5; static const double kSurrogateKeepFraction = 0.50; static const double kSurrogateHighRiskKeepFraction = 0.70; static const double kSurrogateAuditFraction = 0.05; static const double kSurrogateMinSolverFraction = 0.55; static const double kSurrogateHighRiskMinSolverFraction = 0.80; static const int kSurrogateWarmupIterations = 2; static const int kSurrogateFullSolverInterval = 10; static const int kSurrogateScoringMaxAttempts = 2; static const bool kUseFixedPsoSeed = true; static const unsigned int kFixedPsoSeed = 1792008679u; static const double kSurrogateKMin = 1.0e-3; static const double kSurrogateKMax = 10.0; static const double kSurrogateSkinMin = -10.0; static const double kSurrogateSkinMax = 10.0; static const double kSurrogateWellboreCMin = 1.0e-4; static const double kSurrogateWellboreCMax = 2.0; static const double kSurrogatePhiMin = 1.0e-2; static const double kSurrogatePhiMax = 0.50; static const double kSurrogateHMin = 2.0; static const double kSurrogateHMax = 50.0; static const double kSurrogateCfFixed = 4.315e-4; static const double kSurrogateCfRelTol = 0.25; static const int kSurrogateMinProdSections = 3; static const int kSurrogateMaxProdSections = 5; static const double kSurrogateProdTimeMin = 24.0; static const double kSurrogateProdTimeMax = 220.0; static const double kSurrogateShutinTimeMin = 12.0; static const double kSurrogateShutinTimeMax = 140.0; static const double kSurrogateQMin = 50.0; static const double kSurrogateQMax = 500.0; static const double kSurrogateQZeroThreshold = 1.0e-6; static const double kSurrogateMaxRateStepRatio = 2.2; static const double kSurrogateStrongDeclineEndStartRatio = 0.70; static const double kSurrogateRateTrendRelTol = 1.0e-9; // Check infinity and NaN. static inline bool isFiniteNumber(double value) { #ifdef Q_OS_WIN return _finite(value) != 0; #else return std::isfinite(value); #endif } static inline bool isInClosedRange(double value, double lower, double upper) { return isFiniteNumber(value) && value >= lower && value <= upper; } static inline bool isNearRelative(double value, double reference, double relTol) { if(!isFiniteNumber(value) || !isFiniteNumber(reference)) { return false; } return qAbs(value - reference) <= qMax(1e-12, qAbs(reference) * relTol); } // sleep函数 static inline void msleep(int ms) { #ifdef Q_OS_WIN Sleep(ms); #endif } static QString csvEscape(const QString& text) { QString escaped = text; escaped.replace("\"", "\"\""); return QString("\"%1\"").arg(escaped); } static QString traceNumber(double value) { if(!isFiniteNumber(value)) { return QString(); } return QString::number(value, 'g', 17); } static QString traceParamAt(const QVector& params, int index) { if(index < 0 || index >= params.size()) { return QString(); } return traceNumber(params[index]); } static QString jsonEscape(const QString& text) { QString escaped = text; escaped.replace("\\", "\\\\"); escaped.replace("\"", "\\\""); escaped.replace("\b", "\\b"); escaped.replace("\f", "\\f"); escaped.replace("\n", "\\n"); escaped.replace("\r", "\\r"); escaped.replace("\t", "\\t"); return QString("\"%1\"").arg(escaped); } static QString jsonNumber(double value) { if(!isFiniteNumber(value)) { return "null"; } return QString::number(value, 'g', 17); } static QString jsonDoubleArray(const QVector& values) { QStringList items; for(int i = 0; i < values.size(); ++i) { items << jsonNumber(values[i]); } return QString("[%1]").arg(items.join(",")); } static QString jsonIntArray(const QVector& values) { QStringList items; for(int i = 0; i < values.size(); ++i) { items << QString::number(values[i]); } return QString("[%1]").arg(items.join(",")); } static QString jsonBoolArray(const QVector& values) { QStringList items; for(int i = 0; i < values.size(); ++i) { items << (values[i] ? "true" : "false"); } return QString("[%1]").arg(items.join(",")); } static double deterministicAuditRandom01(unsigned int seed, int generation, int particleIndex) { unsigned int x = seed; x ^= 0x9e3779b9u + static_cast(generation + 1) + (x << 6) + (x >> 2); x ^= 0x85ebca6bu + static_cast(particleIndex + 1) + (x << 6) + (x >> 2); x ^= x >> 16; x *= 0x7feb352du; x ^= x >> 15; x *= 0x846ca68bu; x ^= x >> 16; return static_cast(x) / 4294967295.0; } static QString jsonStringArray(const QStringList& values) { QStringList items; for(int i = 0; i < values.size(); ++i) { items << jsonEscape(values[i]); } return QString("[%1]").arg(items.join(",")); } static QString jsonPointArray(const QVector& points) { QStringList items; for(int i = 0; i < points.size(); ++i) { items << QString("{\"x\":%1,\"y\":%2}") .arg(jsonNumber(points[i].x())) .arg(jsonNumber(points[i].y())); } return QString("[%1]").arg(items.join(",")); } static bool isValidMlRootDirectory(const QString& mlRootPath) { if(mlRootPath.isEmpty()) { return false; } QFileInfo scriptInfo(QDir(mlRootPath).absoluteFilePath("scripts/score_pso_candidates.py")); return scriptInfo.exists() && scriptInfo.isFile(); } static QString findExecutableInPath(const QString& executableName) { if(executableName.isEmpty()) { return QString(); } QString pathValue = QProcessEnvironment::systemEnvironment().value("PATH"); if(pathValue.isEmpty()) { pathValue = QString::fromLocal8Bit(qgetenv("PATH")); } if(pathValue.isEmpty()) { return QString(); } QStringList executableCandidates; executableCandidates << executableName; #ifdef Q_OS_WIN if(!executableName.contains('.')) { executableCandidates << (executableName + ".exe") << (executableName + ".bat") << (executableName + ".cmd"); } #endif #ifdef Q_OS_WIN QChar pathSeparator(';'); #else QChar pathSeparator(':'); #endif QStringList pathEntries = pathValue.split(pathSeparator, QString::SkipEmptyParts); for(int i = 0; i < pathEntries.size(); ++i) { QDir dir(pathEntries[i].trimmed()); if(!dir.exists()) { continue; } for(int j = 0; j < executableCandidates.size(); ++j) { QFileInfo executableInfo(dir.absoluteFilePath(executableCandidates[j])); if(executableInfo.exists() && executableInfo.isFile()) { return QDir::cleanPath(executableInfo.absoluteFilePath()); } } } return QString(); } static QStringList traceParameterNames() { QStringList names; names << "k" << "skin" << "wellboreC" << "phi" << "initialPressure" << "h" << "Ct" << "Cf" << "Soi" << "Swi" << "Sgi"; return names; } // Constructor. nmCalculationAutoFitPSO::nmCalculationAutoFitPSO(QObject* parent) : QObject(parent) , m_isRunning(false) , m_shouldStop(false) , m_isPaused(false) , m_currentIteration(0) , m_globalBestFitness(1e10) , m_previousBestFitness(1e10) , m_swarmSize(20) , m_maxIterations(100) , m_targetError(0.001) , m_inertiaWeight(0.4) , m_cognitiveParam(2.0) , m_socialParam(1.2) , m_totalEvaluations(0) , m_successfulEvaluations(0) , m_evaluationInProgress(0) , m_consecutiveFailures(0) , m_improvementThreshold(0.05) , m_userInitialFitness(1e10) , m_consecutiveFailedIterations(0) , m_maxConsecutiveFailures(3) , m_hasValidUserSolution(false) , m_diversityThreshold(0.05) , m_convergenceVarianceThreshold(1e-8) , m_velocityConvergenceThreshold(0.01) , m_trueConvergenceWindow(15) , m_localOptimumWindow(8) , m_nearTargetFactor(2.0) , m_farTargetFactor(10.0) , m_targetWellName("") , m_traceEnabled(true) , m_traceRunId("") , m_traceFilePath("") , m_traceMetaFilePath("") , m_surrogateScreeningEnabled(false) , m_psoRandomSeed(0) , m_surrogateRunContextSummary("") , m_surrogateWarmupIterationCount(0) , m_surrogatePeriodicAuditIterationCount(0) , m_surrogateContextBlockedIterationCount(0) , m_surrogateActiveIterationCount(0) , m_surrogateSelectedParticleCount(0) , m_surrogateScreenedParticleCount(0) , m_surrogateTopKParticleCount(0) , m_surrogateAuditParticleCount(0) , m_surrogateFallbackParticleCount(0) , m_surrogateDomainParticleCount(0) , m_surrogateMinFloorParticleCount(0) , m_surrogateScoringProcess(nullptr) , m_surrogateScoringServerKey("") , m_simulationMode(false) , m_simulationTimer(nullptr) , m_simulationIteration(0) , m_simulationMaxIterations(100) , m_simulationTargetError(0.001) , m_simulationStartError(0.5) , m_simulationCurrentError(0.5) , m_simulationLogInterval(2) , m_simulationCurrentParticle(0) , m_simulationSuccessCount(0) , m_simulationFailCount(0) , m_simulationIterationStarted(false) , m_simulationPreviousIterError(0.5) { DEBUG_OUT(QString("PSO Constructor: this=0x%1").arg((quintptr)this, 0, 16)); initializeTemporaryDirectory(); DEBUG_OUT("AutoFit calculator initialized (data-driven mode)"); DEBUG_OUT("PSO Constructor completed"); } // Destructor. nmCalculationAutoFitPSO::~nmCalculationAutoFitPSO() { DEBUG_OUT(QString("PSO Destructor: this=0x%1").arg((quintptr)this, 0, 16)); if(m_simulationTimer) { m_simulationTimer->stop(); delete m_simulationTimer; m_simulationTimer = nullptr; } // Stop algorithm. 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 PSO - timeout reached"); m_isRunning = false; } } // Clean temp directory. stopSurrogateScoringServer(); closeTraceFile(); cleanupTemporaryDirectory(); // Disconnect all signals to avoid callbacks after destruction. disconnect(this, nullptr, nullptr, nullptr); DEBUG_OUT("PSO Destructor completed"); } // Directory helpers. void nmCalculationAutoFitPSO::initializeTemporaryDirectory() { cleanupOldTemporaryDirectories(); 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 nmCalculationAutoFitPSO::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 nmCalculationAutoFitPSO::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 nmCalculationAutoFitPSO::cleanupOldTemporaryDirectories() { QString appDir = QApplication::applicationDirPath(); QDir dir(appDir); // 获取当前进程ID,避免删除当前进程可能使用的目录 QString currentProcessId = QString::number(QCoreApplication::applicationPid()); // 查找所有以 "autofit_temp_" 开头的目录 QStringList filters; filters << "autofit_temp_*"; QFileInfoList tempDirs = dir.entryInfoList(filters, QDir::Dirs | QDir::NoDotAndDotDot); if(tempDirs.isEmpty()) { DEBUG_OUT("No old temporary directories found"); return; } DEBUG_OUT(QString("Found %1 potential old temporary directories to clean up").arg(tempDirs.size())); int cleanedCount = 0; int failedCount = 0; int skippedCount = 0; for(int i = 0; i < tempDirs.size(); ++i) { const QFileInfo& dirInfo = tempDirs[i]; QString dirPath = dirInfo.absoluteFilePath(); QString dirName = dirInfo.fileName(); // 检查是否是当前进程的目录(虽然理论上不应该存在,但为了安全起见) if(dirName.contains("_" + currentProcessId + "_")) { DEBUG_OUT(QString("Skipping current process directory: %1").arg(dirName)); skippedCount++; continue; } // 尝试删除目录 DEBUG_OUT(QString("Attempting to remove old temp directory: %1").arg(dirName)); if(removeDirectoryRecursively(dirPath)) { DEBUG_OUT(QString("Successfully cleaned up: %1").arg(dirName)); cleanedCount++; } else { DEBUG_OUT(QString("Failed to clean up: %1 (may be in use by another process)").arg(dirName)); failedCount++; } } // 输出清理统计信息 DEBUG_OUT(QString("Old temp directories cleanup summary: %1 removed, %2 failed, %3 skipped") .arg(cleanedCount).arg(failedCount).arg(skippedCount)); } // ==================== 公共接口方法 ==================== void nmCalculationAutoFitPSO::setTargetLogLogData(const QVector >& 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())); } } void nmCalculationAutoFitPSO::stopFitting() { if(m_simulationMode && m_simulationTimer) { m_simulationTimer->stop(); } if(m_isRunning) { DEBUG_OUT("Stop request received, setting stop flag..."); // 添加停止日志 emit logMessageGenerated(tr("=== User Stop Request Received ===")); emit logMessageGenerated(tr("Gracefully stopping PSO optimization...")); m_shouldStop = true; // 等待当前评估完成,缩短超时时间 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("PSO optimization stop request processed")); DEBUG_OUT("Stop request processed"); } else { DEBUG_OUT("Stop request received but PSO is not running"); emit logMessageGenerated(tr("Stop request received but optimization is not running")); } closeTraceFile(); cleanupTemporaryDirectory(); } bool nmCalculationAutoFitPSO::isRunning() const { return m_isRunning; } int nmCalculationAutoFitPSO::getCurrentIteration() const { return m_currentIteration; } QVector nmCalculationAutoFitPSO::getBestSolution() const { return m_globalBestPosition; } double nmCalculationAutoFitPSO::getBestFitness() const { return m_globalBestFitness; } QString nmCalculationAutoFitPSO::getLastError() const { return m_lastError; } void nmCalculationAutoFitPSO::resetOptimizer() { closeTraceFile(); m_swarm.clear(); m_globalBestPosition.clear(); m_globalBestFitness = 1e10; m_previousBestFitness = 1e10; m_lastEvaluatedLogLogData.clear(); m_globalBestLogLogData.clear(); m_userInitialLogLogData.clear(); m_currentIteration = 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(); m_velocityHistory.clear(); m_particleStagnationHistory.clear(); m_traceMetaFilePath.clear(); resetRunSummary(); DEBUG_OUT("Optimizer reset"); } void nmCalculationAutoFitPSO::setPSOTargetWellName(const QString& wellName) { m_targetWellName = wellName; } void nmCalculationAutoFitPSO::initializeTraceFile() { if(!m_traceEnabled) { return; } closeTraceFile(); captureSurrogateRunContextSummary(); m_traceRunId = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss_zzz"); QDir traceDir(QDir(getMlRootPath()).absoluteFilePath("data/temp")); if(!traceDir.exists() && !QDir().mkpath(traceDir.absolutePath())) { DEBUG_OUT(QString("Failed to create PSO trace directory: %1").arg(traceDir.absolutePath())); m_traceFilePath.clear(); return; } m_traceFilePath = traceDir.absoluteFilePath(QString("pso_baseline_trace_%1.csv").arg(m_traceRunId)); m_traceMetaFilePath = traceDir.absoluteFilePath(QString("pso_baseline_trace_%1.meta.json").arg(m_traceRunId)); m_traceFile.setFileName(m_traceFilePath); if(!m_traceFile.open(QIODevice::WriteOnly | QIODevice::Text)) { DEBUG_OUT(QString("Failed to open PSO trace file: %1").arg(m_traceFilePath)); m_traceFilePath.clear(); m_traceMetaFilePath.clear(); return; } writeTraceHeader(); writeTraceMetaFile(); DEBUG_OUT(QString("PSO baseline trace initialized: %1").arg(m_traceFilePath)); emit logMessageGenerated(tr("PSO baseline trace: %1").arg(m_traceFilePath)); if(!m_traceMetaFilePath.isEmpty()) { emit logMessageGenerated(tr("PSO baseline trace meta: %1").arg(m_traceMetaFilePath)); } emit logMessageGenerated(tr("PSO surrogate screening: %1, model=%2, keep=%3, audit=%4, warmup=%5, min_solver=%6") .arg(isSurrogateScreeningEnabled() ? tr("enabled") : tr("disabled")) .arg(getSurrogateTag()) .arg(getSurrogateKeepFraction(), 0, 'f', 2) .arg(getSurrogateAuditFraction(), 0, 'f', 2) .arg(getSurrogateWarmupIterations()) .arg(getSurrogateMinSolverFraction(), 0, 'f', 2)); if(!isSurrogateScreeningEnabled()) { emit logMessageGenerated(tr("Surrogate screening is turned off in the automatic fitting configuration")); } else { if(m_surrogateRunContextSummary == "passed") { emit logMessageGenerated(tr("Surrogate run context check: passed")); } else { emit logMessageGenerated(tr("Surrogate run context check: %1").arg(m_surrogateRunContextSummary)); } } } void nmCalculationAutoFitPSO::resetRunSummary() { m_surrogateRunContextSummary.clear(); m_surrogateWarmupIterationCount = 0; m_surrogatePeriodicAuditIterationCount = 0; m_surrogateContextBlockedIterationCount = 0; m_surrogateActiveIterationCount = 0; m_surrogateSelectedParticleCount = 0; m_surrogateScreenedParticleCount = 0; m_surrogateTopKParticleCount = 0; m_surrogateAuditParticleCount = 0; m_surrogateFallbackParticleCount = 0; m_surrogateDomainParticleCount = 0; m_surrogateMinFloorParticleCount = 0; } void nmCalculationAutoFitPSO::captureSurrogateRunContextSummary() { if(!isSurrogateScreeningEnabled()) { m_surrogateRunContextSummary = "disabled_by_config"; return; } QString contextReason; if(isSurrogateRunContextSupported(&contextReason)) { m_surrogateRunContextSummary = "passed"; } else { m_surrogateRunContextSummary = QString("failed - %1").arg(contextReason); } } void nmCalculationAutoFitPSO::emitRunSummary(bool success, StopReasonPSO finalReason) { emit logMessageGenerated(tr("=== PSO Run Summary ===")); emit logMessageGenerated(tr("Stop reason: %1").arg(getStopReasonDescription(finalReason))); emit logMessageGenerated(tr("Result: %1, final error=%2, iterations=%3, evaluations=%4 (successful=%5, failed=%6)") .arg(success ? "SUCCESS" : "FAILED") .arg(m_globalBestFitness, 0, 'e', 4) .arg(m_currentIteration + 1) .arg(m_totalEvaluations) .arg(m_successfulEvaluations) .arg(m_totalEvaluations - m_successfulEvaluations)); emit logMessageGenerated(tr("Surrogate config: %1, context=%2") .arg(isSurrogateScreeningEnabled() ? "enabled" : "disabled") .arg(m_surrogateRunContextSummary.isEmpty() ? QString("unknown") : m_surrogateRunContextSummary)); emit logMessageGenerated(tr("Surrogate iterations: active=%1, warmup=%2, periodic_audit=%3, context_blocked=%4") .arg(m_surrogateActiveIterationCount) .arg(m_surrogateWarmupIterationCount) .arg(m_surrogatePeriodicAuditIterationCount) .arg(m_surrogateContextBlockedIterationCount)); emit logMessageGenerated(tr("Surrogate particles: selected=%1, screened_out=%2, topk=%3, random_audit=%4, fallback=%5, domain_gate=%6, min_solver_floor=%7") .arg(m_surrogateSelectedParticleCount) .arg(m_surrogateScreenedParticleCount) .arg(m_surrogateTopKParticleCount) .arg(m_surrogateAuditParticleCount) .arg(m_surrogateFallbackParticleCount) .arg(m_surrogateDomainParticleCount) .arg(m_surrogateMinFloorParticleCount)); if(!m_traceFilePath.isEmpty()) { emit logMessageGenerated(tr("Artifacts: trace=%1").arg(m_traceFilePath)); } if(!m_traceMetaFilePath.isEmpty()) { emit logMessageGenerated(tr("Artifacts: trace_meta=%1").arg(m_traceMetaFilePath)); } } void nmCalculationAutoFitPSO::closeTraceFile() { stopSurrogateScoringServer(); if(m_traceFile.isOpen()) { m_traceFile.flush(); m_traceFile.close(); } } void nmCalculationAutoFitPSO::writeTraceHeader() { if(!m_traceFile.isOpen()) { return; } QStringList cols; cols << "run_id" << "generation" << "particle_id" << "phase" << "k" << "skin" << "wellboreC" << "phi" << "h" << "Cf" << "solver_objective" << "solver_success" << "elapsed_ms" << "surrogate_objective" << "screening_decision" << "pbest_objective" << "pbest_k" << "pbest_skin" << "pbest_wellboreC" << "pbest_phi" << "pbest_h" << "pbest_Cf" << "gbest_objective" << "gbest_k" << "gbest_skin" << "gbest_wellboreC" << "gbest_phi" << "gbest_h" << "gbest_Cf" << "enabled_param_indices"; QTextStream out(&m_traceFile); out << cols.join(",") << "\n"; } void nmCalculationAutoFitPSO::writeTraceMetaFile() { if(m_traceMetaFilePath.isEmpty()) { return; } QFile metaFile(m_traceMetaFilePath); if(!metaFile.open(QIODevice::WriteOnly | QIODevice::Text)) { DEBUG_OUT(QString("Failed to open PSO trace meta file: %1").arg(m_traceMetaFilePath)); m_traceMetaFilePath.clear(); return; } nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); nmDataWellBase* pTargetWell = dataManager ? dataManager->findWellByName(m_targetWellName) : nullptr; QStringList parameterNames = traceParameterNames(); QStringList enabledNames; for(int i = 0; i < m_enabledParamIndices.size(); ++i) { int paramIndex = m_enabledParamIndices[i]; enabledNames << ((paramIndex >= 0 && paramIndex < parameterNames.size()) ? parameterNames[paramIndex] : QString::number(paramIndex)); } QVector initialFullParams = buildTraceParameterVector(m_initialValues); QVector targetTime = m_targetLogLogData.size() > 0 ? m_targetLogLogData[0] : QVector(); QVector targetPressure = m_targetLogLogData.size() > 1 ? m_targetLogLogData[1] : QVector(); QVector targetDerivative = m_targetLogLogData.size() > 2 ? m_targetLogLogData[2] : QVector(); QVector flowPoints = pTargetWell ? pTargetWell->getFlowPoints() : QVector(); QTextStream out(&metaFile); out << "{\n"; out << " \"schema_version\": 1,\n"; out << " \"trace_type\": \"pso_baseline_replay_meta\",\n"; out << " \"run_id\": " << jsonEscape(m_traceRunId) << ",\n"; out << " \"created_at\": " << jsonEscape(QDateTime::currentDateTime().toString(Qt::ISODate)) << ",\n"; out << " \"trace_csv\": " << jsonEscape(QFileInfo(m_traceFilePath).fileName()) << ",\n"; out << " \"target\": {\n"; out << " \"well_name\": " << jsonEscape(m_targetWellName) << ",\n"; out << " \"well_type\": " << (pTargetWell ? QString::number(static_cast(pTargetWell->getWellType())) : "null") << ",\n"; out << " \"section_policy\": \"current_target_well_indexF\",\n"; out << " \"section_index\": " << (pTargetWell ? QString::number(pTargetWell->getIndexF()) : "null") << ",\n"; out << " \"target_loglog\": {\n"; out << " \"time\": " << jsonDoubleArray(targetTime) << ",\n"; out << " \"pressure\": " << jsonDoubleArray(targetPressure) << ",\n"; out << " \"derivative\": " << jsonDoubleArray(targetDerivative) << "\n"; out << " },\n"; out << " \"flow_points\": " << jsonPointArray(flowPoints) << "\n"; out << " },\n"; out << " \"pso\": {\n"; out << " \"swarm_size\": " << m_swarmSize << ",\n"; out << " \"max_iterations\": " << m_maxIterations << ",\n"; out << " \"target_error\": " << jsonNumber(m_targetError) << ",\n"; out << " \"inertia_weight\": " << jsonNumber(m_inertiaWeight) << ",\n"; out << " \"cognitive_param\": " << jsonNumber(m_cognitiveParam) << ",\n"; out << " \"social_param\": " << jsonNumber(m_socialParam) << ",\n"; out << " \"random_seed\": " << m_psoRandomSeed << "\n"; out << " },\n"; out << " \"surrogate_screening\": {\n"; out << " \"enabled\": " << (isSurrogateScreeningEnabled() ? "true" : "false") << ",\n"; out << " \"model_tag\": " << jsonEscape(getSurrogateTag()) << ",\n"; out << " \"keep_fraction\": " << jsonNumber(getSurrogateKeepFraction()) << ",\n"; out << " \"audit_fraction\": " << jsonNumber(getSurrogateAuditFraction()) << ",\n"; out << " \"min_solver_fraction\": " << jsonNumber(getSurrogateMinSolverFraction()) << ",\n"; out << " \"warmup_iterations\": " << getSurrogateWarmupIterations() << ",\n"; out << " \"full_solver_interval\": " << getSurrogateFullSolverInterval() << ",\n"; out << " \"audit_random_source\": \"deterministic_hash\"\n"; out << " },\n"; out << " \"parameters\": {\n"; out << " \"names\": " << jsonStringArray(parameterNames) << ",\n"; out << " \"enabled_indices\": " << jsonIntArray(m_enabledParamIndices) << ",\n"; out << " \"enabled_names\": " << jsonStringArray(enabledNames) << ",\n"; out << " \"selected_flags\": " << jsonBoolArray(m_parameterSelected) << ",\n"; out << " \"lower\": " << jsonDoubleArray(m_parameterLower) << ",\n"; out << " \"upper\": " << jsonDoubleArray(m_parameterUpper) << ",\n"; out << " \"initial_selected\": " << jsonDoubleArray(m_initialValues) << ",\n"; out << " \"initial_full\": " << jsonDoubleArray(initialFullParams) << "\n"; out << " },\n"; out << " \"replay_notes\": [\n"; out << " \"CSV rows contain true solver objectives for evaluated particles.\",\n"; out << " \"This meta file contains the target curve and run context needed for surrogate replay.\",\n"; out << " \"pbest and gbest must be updated only from true solver objectives.\"\n"; out << " ]\n"; out << "}\n"; metaFile.flush(); metaFile.close(); } QVector nmCalculationAutoFitPSO::buildTraceParameterVector(const QVector& selectedParameters) const { QVector fullParams(11, 0.0); nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); if(dataManager) { nmDataReservoir reservoirData = dataManager->getReservoirDataCopy(); fullParams[0] = reservoirData.getPermeability().getValue().toDouble(); fullParams[3] = reservoirData.getPorosity().getValue().toDouble(); fullParams[4] = reservoirData.getInitialPressure().getValue().toDouble(); fullParams[5] = reservoirData.getThickness().getValue().toDouble(); fullParams[6] = reservoirData.getCt().getValue().toDouble(); fullParams[7] = reservoirData.getCf().getValue().toDouble(); fullParams[8] = reservoirData.getSoi().getValue().toDouble(); fullParams[9] = reservoirData.getSwi().getValue().toDouble(); fullParams[10] = reservoirData.getSgi().getValue().toDouble(); nmDataWellBase* pTargetWell = dataManager->findWellByName(m_targetWellName); if(pTargetWell) { fullParams[1] = pTargetWell->getPerforation(0)->getSkin().getValue().toDouble(); fullParams[2] = pTargetWell->getWellboreStorage().getValue().toDouble(); } } for(int i = 0; i < selectedParameters.size() && i < m_enabledParamIndices.size(); ++i) { int paramIndex = m_enabledParamIndices[i]; if(paramIndex >= 0 && paramIndex < fullParams.size()) { fullParams[paramIndex] = selectedParameters[i]; } } return fullParams; } void nmCalculationAutoFitPSO::writeTraceRow(int generation, int particleIndex, const QString& phase, const QVector& parameters, double solverObjective, bool solverSuccess, int elapsedMs, double surrogateObjective, const QString& screeningDecision, const QVector& pbestPosition, double pbestObjective) { if(!m_traceFile.isOpen()) { return; } QVector currentParams = buildTraceParameterVector(parameters); QVector pbestParams = pbestPosition.isEmpty() ? QVector() : buildTraceParameterVector(pbestPosition); QVector gbestParams = m_globalBestPosition.isEmpty() ? QVector() : buildTraceParameterVector(m_globalBestPosition); QStringList enabledIndices; for(int i = 0; i < m_enabledParamIndices.size(); ++i) { enabledIndices << QString::number(m_enabledParamIndices[i]); } QStringList cols; cols << csvEscape(m_traceRunId) << QString::number(generation) << QString::number(particleIndex) << csvEscape(phase) << traceParamAt(currentParams, 0) << traceParamAt(currentParams, 1) << traceParamAt(currentParams, 2) << traceParamAt(currentParams, 3) << traceParamAt(currentParams, 5) << traceParamAt(currentParams, 7) << traceNumber(solverObjective) << QString::number(solverSuccess ? 1 : 0) << QString::number(elapsedMs) << traceNumber(surrogateObjective) << csvEscape(screeningDecision) << traceNumber(pbestObjective) << traceParamAt(pbestParams, 0) << traceParamAt(pbestParams, 1) << traceParamAt(pbestParams, 2) << traceParamAt(pbestParams, 3) << traceParamAt(pbestParams, 5) << traceParamAt(pbestParams, 7) << traceNumber(m_globalBestFitness) << traceParamAt(gbestParams, 0) << traceParamAt(gbestParams, 1) << traceParamAt(gbestParams, 2) << traceParamAt(gbestParams, 3) << traceParamAt(gbestParams, 5) << traceParamAt(gbestParams, 7) << csvEscape(enabledIndices.join(";")); QTextStream out(&m_traceFile); out << cols.join(",") << "\n"; m_traceFile.flush(); } void nmCalculationAutoFitPSO::writeIterationTraceRows() { if(!m_traceFile.isOpen()) { return; } for(int i = 0; i < m_swarm.size(); ++i) { const AutoFitParticle& particle = m_swarm[i]; double solverObjective = particle.evaluatedThisIteration ? particle.fitness : std::numeric_limits::quiet_NaN(); writeTraceRow(m_currentIteration, i, particle.evaluatedThisIteration ? "particle_solver" : "particle_not_evaluated", particle.position, solverObjective, particle.lastEvaluationSuccess, particle.lastEvaluationElapsedMs, particle.surrogateObjective, particle.screeningDecision, particle.bestPosition, particle.bestFitness); } } bool nmCalculationAutoFitPSO::isSurrogateScreeningEnabled() const { return m_surrogateScreeningEnabled; } QString nmCalculationAutoFitPSO::getMlRootPath() const { QString appDir = QApplication::applicationDirPath(); QString cwd = QDir::currentPath(); QStringList candidateRoots; candidateRoots << QDir::cleanPath(appDir + "/../../ML/nmWTAI-ML") << QDir::cleanPath(appDir + "/../ML/nmWTAI-ML") << QDir::cleanPath(cwd + "/ML/nmWTAI-ML") << QDir::cleanPath(cwd + "/../ML/nmWTAI-ML") << QDir::cleanPath(cwd + "/../../ML/nmWTAI-ML"); for(int i = 0; i < candidateRoots.size(); ++i) { if(isValidMlRootDirectory(candidateRoots[i])) { return candidateRoots[i]; } } return candidateRoots.isEmpty() ? QString() : candidateRoots.first(); } QString nmCalculationAutoFitPSO::getPythonExecutablePath() const { QString mlRoot = getMlRootPath(); QStringList candidateExecutables; if(!mlRoot.isEmpty()) { candidateExecutables << QDir(mlRoot).absoluteFilePath(".venv/Scripts/python.exe"); candidateExecutables << QDir(mlRoot).absoluteFilePath(".venv/bin/python"); } for(int i = 0; i < candidateExecutables.size(); ++i) { QFileInfo pythonInfo(candidateExecutables[i]); if(pythonInfo.exists() && pythonInfo.isFile()) { return QDir::cleanPath(pythonInfo.absoluteFilePath()); } } QString resolvedPython = findExecutableInPath("python"); if(!resolvedPython.isEmpty()) { return QDir::cleanPath(resolvedPython); } return "python"; } QString nmCalculationAutoFitPSO::getSurrogateTag() const { return "family_random_v2_q_50k_logparam"; } QString nmCalculationAutoFitPSO::getSurrogateStage() const { return "family_random_v2_q"; } double nmCalculationAutoFitPSO::getSurrogateKeepFraction() const { if(getSurrogateStage().contains("v2_q") && isStrongDecliningProductionSchedule()) { return kSurrogateHighRiskKeepFraction; } return kSurrogateKeepFraction; } double nmCalculationAutoFitPSO::getSurrogateAuditFraction() const { return kSurrogateAuditFraction; } double nmCalculationAutoFitPSO::getSurrogateMinSolverFraction() const { if(getSurrogateStage().contains("v2_q") && isStrongDecliningProductionSchedule()) { return kSurrogateHighRiskMinSolverFraction; } return kSurrogateMinSolverFraction; } int nmCalculationAutoFitPSO::getSurrogateWarmupIterations() const { return kSurrogateWarmupIterations; } int nmCalculationAutoFitPSO::getSurrogateFullSolverInterval() const { return kSurrogateFullSolverInterval; } bool nmCalculationAutoFitPSO::writeSurrogateCandidateCsv(const QString& candidatePath) const { QFile file(candidatePath); if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) { DEBUG_OUT(QString("Failed to open surrogate candidate file: %1").arg(candidatePath)); return false; } QTextStream out(&file); out << "particle_id,k,skin,wellboreC,phi,h,Cf\n"; for(int i = 0; i < m_swarm.size(); ++i) { QVector params = buildTraceParameterVector(m_swarm[i].position); QStringList cols; cols << QString::number(i) << traceParamAt(params, 0) << traceParamAt(params, 1) << traceParamAt(params, 2) << traceParamAt(params, 3) << traceParamAt(params, 5) << traceParamAt(params, 7); out << cols.join(",") << "\n"; } file.flush(); file.close(); return true; } bool nmCalculationAutoFitPSO::runSurrogateScoringProcess(const QString& candidatePath, const QString& scorePath, QString* failureReason) { QString serverFailure; if(requestSurrogateScoresFromServer(candidatePath, scorePath, &serverFailure)) { return true; } emit logMessageGenerated(tr("Surrogate scoring server unavailable; falling back to one-shot Python scoring")); if(!serverFailure.isEmpty()) { emit logMessageGenerated(tr("Surrogate scoring server detail: %1").arg(serverFailure)); } stopSurrogateScoringServer(); return runSurrogateScoringScriptOnce(candidatePath, scorePath, failureReason); } bool nmCalculationAutoFitPSO::ensureSurrogateScoringServer(QString* failureReason) { if(m_traceMetaFilePath.isEmpty() || !QFileInfo(m_traceMetaFilePath).exists()) { QString reason = "trace meta file is missing"; DEBUG_OUT(QString("Surrogate scoring server skipped: %1").arg(reason)); if(failureReason) { *failureReason = reason; } return false; } QString mlRoot = getMlRootPath(); QString scriptPath = QDir(mlRoot).absoluteFilePath("scripts/score_pso_candidates_server.py"); if(!QFileInfo(scriptPath).exists()) { QString reason = QString("surrogate scoring server script not found: %1").arg(scriptPath); DEBUG_OUT(reason); if(failureReason) { *failureReason = reason; } return false; } QString pythonPath = getPythonExecutablePath(); QString serverKey = QString("%1|%2|%3|%4|%5") .arg(pythonPath) .arg(scriptPath) .arg(m_traceMetaFilePath) .arg(getSurrogateTag()) .arg(getSurrogateStage()); if(m_surrogateScoringProcess && m_surrogateScoringProcess->state() == QProcess::Running && m_surrogateScoringServerKey == serverKey) { return true; } stopSurrogateScoringServer(); QStringList args; args << "-u" << scriptPath << "--trace-meta" << m_traceMetaFilePath << "--tag" << getSurrogateTag() << "--stage" << getSurrogateStage(); m_surrogateScoringProcess = new QProcess(this); m_surrogateScoringProcess->setWorkingDirectory(mlRoot); emit logMessageGenerated(tr("Starting surrogate scoring server: python=%1, mlRoot=%2") .arg(pythonPath) .arg(mlRoot)); m_surrogateScoringProcess->start(pythonPath, args); if(!m_surrogateScoringProcess->waitForStarted(15000)) { QString reason = QString("failed to start scoring server: python=%1, script=%2, error=%3") .arg(pythonPath) .arg(scriptPath) .arg(m_surrogateScoringProcess->errorString()); DEBUG_OUT(reason); stopSurrogateScoringServer(); if(failureReason) { *failureReason = reason; } return false; } QTime timer; timer.start(); QByteArray readyLine; while(timer.elapsed() < 120000) { if(m_surrogateScoringProcess->state() != QProcess::Running) { QString stdOut = QString::fromLocal8Bit(m_surrogateScoringProcess->readAllStandardOutput()).trimmed(); QString stdErr = QString::fromLocal8Bit(m_surrogateScoringProcess->readAllStandardError()).trimmed(); QString reason = QString("scoring server exited before ready: stdout=%1, stderr=%2") .arg(stdOut.isEmpty() ? QString("") : stdOut) .arg(stdErr.isEmpty() ? QString("") : stdErr); DEBUG_OUT(reason); stopSurrogateScoringServer(); if(failureReason) { *failureReason = reason; } return false; } if(!m_surrogateScoringProcess->canReadLine()) { m_surrogateScoringProcess->waitForReadyRead(500); QApplication::processEvents(); continue; } readyLine = m_surrogateScoringProcess->readLine().trimmed(); if(readyLine.contains("\"ready\"") && readyLine.contains("true")) { m_surrogateScoringServerKey = serverKey; QString stdErr = QString::fromLocal8Bit(m_surrogateScoringProcess->readAllStandardError()).trimmed(); if(!stdErr.isEmpty()) { emit logMessageGenerated(tr("Surrogate scoring server stderr: %1").arg(stdErr)); } return true; } if(readyLine.contains("\"ok\"") && readyLine.contains("false")) { QString reason = QString("scoring server failed during initialization: %1").arg(QString::fromLocal8Bit(readyLine)); DEBUG_OUT(reason); stopSurrogateScoringServer(); if(failureReason) { *failureReason = reason; } return false; } } QString stdErr = QString::fromLocal8Bit(m_surrogateScoringProcess->readAllStandardError()).trimmed(); QString reason = QString("scoring server ready timeout: stderr=%1") .arg(stdErr.isEmpty() ? QString("") : stdErr); DEBUG_OUT(reason); stopSurrogateScoringServer(); if(failureReason) { *failureReason = reason; } return false; } bool nmCalculationAutoFitPSO::requestSurrogateScoresFromServer(const QString& candidatePath, const QString& scorePath, QString* failureReason) { if(!ensureSurrogateScoringServer(failureReason)) { return false; } QFile::remove(scorePath); QString command = QString("{\"cmd\":\"score\",\"candidates\":%1,\"output\":%2}\n") .arg(jsonEscape(candidatePath)) .arg(jsonEscape(scorePath)); QByteArray bytes = command.toUtf8(); qint64 written = m_surrogateScoringProcess->write(bytes); if(written != bytes.size() || !m_surrogateScoringProcess->waitForBytesWritten(10000)) { QString reason = QString("failed to send scoring request to server: written=%1 expected=%2 error=%3") .arg(written) .arg(bytes.size()) .arg(m_surrogateScoringProcess->errorString()); DEBUG_OUT(reason); if(failureReason) { *failureReason = reason; } return false; } QTime timer; timer.start(); while(timer.elapsed() < 120000) { if(m_surrogateScoringProcess->state() != QProcess::Running) { QString stdOut = QString::fromLocal8Bit(m_surrogateScoringProcess->readAllStandardOutput()).trimmed(); QString stdErr = QString::fromLocal8Bit(m_surrogateScoringProcess->readAllStandardError()).trimmed(); QString reason = QString("scoring server exited during request: stdout=%1, stderr=%2") .arg(stdOut.isEmpty() ? QString("") : stdOut) .arg(stdErr.isEmpty() ? QString("") : stdErr); DEBUG_OUT(reason); if(failureReason) { *failureReason = reason; } return false; } if(!m_surrogateScoringProcess->canReadLine()) { m_surrogateScoringProcess->waitForReadyRead(500); QApplication::processEvents(); continue; } QByteArray lineBytes = m_surrogateScoringProcess->readLine().trimmed(); QString line = QString::fromLocal8Bit(lineBytes); if(line.contains("\"ok\"") && line.contains("true")) { QFileInfo scoreInfo(scorePath); if(scoreInfo.exists() && scoreInfo.size() > 0) { QString stdErr = QString::fromLocal8Bit(m_surrogateScoringProcess->readAllStandardError()).trimmed(); if(!stdErr.isEmpty()) { emit logMessageGenerated(tr("Surrogate scoring server stderr: %1").arg(stdErr)); } return true; } QString reason = QString("scoring server reported success but score file is missing: %1").arg(scorePath); DEBUG_OUT(reason); if(failureReason) { *failureReason = reason; } return false; } if(line.contains("\"ok\"") && line.contains("false")) { QString reason = QString("scoring server request failed: %1").arg(line); DEBUG_OUT(reason); if(failureReason) { *failureReason = reason; } return false; } } QString reason = "scoring server request timed out"; DEBUG_OUT(reason); if(failureReason) { *failureReason = reason; } return false; } void nmCalculationAutoFitPSO::stopSurrogateScoringServer() { if(!m_surrogateScoringProcess) { return; } if(m_surrogateScoringProcess->state() == QProcess::Running) { m_surrogateScoringProcess->write("{\"cmd\":\"quit\"}\n"); m_surrogateScoringProcess->waitForBytesWritten(1000); m_surrogateScoringProcess->waitForFinished(3000); if(m_surrogateScoringProcess->state() == QProcess::Running) { m_surrogateScoringProcess->kill(); m_surrogateScoringProcess->waitForFinished(3000); } } delete m_surrogateScoringProcess; m_surrogateScoringProcess = nullptr; m_surrogateScoringServerKey.clear(); } bool nmCalculationAutoFitPSO::runSurrogateScoringScriptOnce(const QString& candidatePath, const QString& scorePath, QString* failureReason) { if(m_traceMetaFilePath.isEmpty() || !QFileInfo(m_traceMetaFilePath).exists()) { QString reason = "trace meta file is missing"; DEBUG_OUT(QString("Surrogate scoring skipped: %1").arg(reason)); if(failureReason) { *failureReason = reason; } return false; } QString mlRoot = getMlRootPath(); QString scriptPath = QDir(mlRoot).absoluteFilePath("scripts/score_pso_candidates.py"); if(!QFileInfo(scriptPath).exists()) { QString reason = QString("surrogate scoring script not found: %1").arg(scriptPath); DEBUG_OUT(reason); if(failureReason) { *failureReason = reason; } return false; } QString pythonPath = getPythonExecutablePath(); QStringList args; args << scriptPath << "--candidates" << candidatePath << "--trace-meta" << m_traceMetaFilePath << "--output" << scorePath << "--tag" << getSurrogateTag() << "--stage" << getSurrogateStage(); QFile::remove(scorePath); QString lastFailure; for(int attempt = 1; attempt <= kSurrogateScoringMaxAttempts; ++attempt) { emit logMessageGenerated(tr("Surrogate scoring attempt %1/%2: python=%3, mlRoot=%4") .arg(attempt) .arg(kSurrogateScoringMaxAttempts) .arg(pythonPath) .arg(mlRoot)); QProcess process; process.setWorkingDirectory(mlRoot); process.start(pythonPath, args); if(!process.waitForStarted(10000)) { lastFailure = QString("failed to start scoring process (attempt %1/%2): python=%3, script=%4, error=%5") .arg(attempt) .arg(kSurrogateScoringMaxAttempts) .arg(pythonPath) .arg(scriptPath) .arg(process.errorString()); DEBUG_OUT(lastFailure); if(attempt < kSurrogateScoringMaxAttempts) { emit logMessageGenerated(tr("Surrogate scoring start failed, retrying once: %1").arg(process.errorString())); msleep(500); continue; } if(failureReason) { *failureReason = lastFailure; } return false; } if(!process.waitForFinished(120000)) { process.kill(); process.waitForFinished(3000); QString stdOut = QString::fromLocal8Bit(process.readAllStandardOutput()).trimmed(); QString stdErr = QString::fromLocal8Bit(process.readAllStandardError()).trimmed(); lastFailure = QString("scoring process timed out (attempt %1/%2): python=%3, script=%4, stdout=%5, stderr=%6") .arg(attempt) .arg(kSurrogateScoringMaxAttempts) .arg(pythonPath) .arg(scriptPath) .arg(stdOut.isEmpty() ? QString("") : stdOut) .arg(stdErr.isEmpty() ? QString("") : stdErr); DEBUG_OUT(lastFailure); if(attempt < kSurrogateScoringMaxAttempts) { emit logMessageGenerated(tr("Surrogate scoring timed out, retrying once")); msleep(500); continue; } if(failureReason) { *failureReason = lastFailure; } return false; } QString stdOut = QString::fromLocal8Bit(process.readAllStandardOutput()).trimmed(); QString stdErr = QString::fromLocal8Bit(process.readAllStandardError()).trimmed(); if(process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) { lastFailure = QString("scoring process failed (attempt %1/%2): exitStatus=%3, exitCode=%4, python=%5, script=%6, stdout=%7, stderr=%8") .arg(attempt) .arg(kSurrogateScoringMaxAttempts) .arg(process.exitStatus() == QProcess::NormalExit ? "NormalExit" : "CrashExit") .arg(process.exitCode()) .arg(pythonPath) .arg(scriptPath) .arg(stdOut.isEmpty() ? QString("") : stdOut) .arg(stdErr.isEmpty() ? QString("") : stdErr); DEBUG_OUT(lastFailure); if(attempt < kSurrogateScoringMaxAttempts) { emit logMessageGenerated(tr("Surrogate scoring process failed, retrying once: exitCode=%1").arg(process.exitCode())); msleep(500); continue; } if(failureReason) { *failureReason = lastFailure; } return false; } QFileInfo scoreInfo(scorePath); if(!scoreInfo.exists() || scoreInfo.size() <= 0) { lastFailure = QString("scoring process finished without a usable score file (attempt %1/%2): output=%3, stdout=%4, stderr=%5") .arg(attempt) .arg(kSurrogateScoringMaxAttempts) .arg(scorePath) .arg(stdOut.isEmpty() ? QString("") : stdOut) .arg(stdErr.isEmpty() ? QString("") : stdErr); DEBUG_OUT(lastFailure); if(attempt < kSurrogateScoringMaxAttempts) { emit logMessageGenerated(tr("Surrogate scoring produced no score file, retrying once")); msleep(500); continue; } if(failureReason) { *failureReason = lastFailure; } return false; } if(!stdErr.isEmpty()) { emit logMessageGenerated(tr("Surrogate scoring stderr: %1").arg(stdErr)); } if(!stdOut.isEmpty()) { emit logMessageGenerated(tr("Surrogate scoring stdout: %1").arg(stdOut)); } return true; } if(failureReason) { *failureReason = lastFailure; } return false; } QVector nmCalculationAutoFitPSO::readSurrogateScores(const QString& scorePath) const { QVector scores(m_swarm.size(), std::numeric_limits::quiet_NaN()); QFile file(scorePath); if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) { DEBUG_OUT(QString("Failed to open surrogate score file: %1").arg(scorePath)); return scores; } QTextStream in(&file); bool firstLine = true; while(!in.atEnd()) { QString line = in.readLine().trimmed(); if(line.isEmpty()) { continue; } if(firstLine) { firstLine = false; continue; } QStringList parts = line.split(","); if(parts.size() < 5) { continue; } bool idOk = false; bool scoreOk = false; int particleId = parts[0].toInt(&idOk); double score = parts[1].toDouble(&scoreOk); bool success = parts[4].trimmed() == "1"; if(idOk && scoreOk && success && particleId >= 0 && particleId < scores.size()) { scores[particleId] = score; } } return scores; } bool nmCalculationAutoFitPSO::isSurrogateRunContextSupported(QString* reason) const { nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); if(!dataManager) { if(reason) *reason = "data manager is unavailable"; return false; } if(dataManager->getGridType() != NM_Grid_PEBI) { if(reason) *reason = "surrogate model is trained only for PEBI grid cases"; return false; } nmDataWellBase* pTargetWell = dataManager->findWellByName(m_targetWellName); if(!pTargetWell) { if(reason) *reason = QString("target well '%1' is missing").arg(m_targetWellName); return false; } if(pTargetWell->getWellType() != NM_WELL_MODEL::Vertical_Well) { if(reason) *reason = "surrogate model is currently limited to vertical-well cases"; return false; } int validCalculationWells = 0; QVector > calculationWells = dataManager->getCalculationWells(); for(int i = 0; i < calculationWells.size(); ++i) { if(calculationWells[i].first != NM_WELL_MODEL::Unknow_Well) { validCalculationWells++; } } if(validCalculationWells != 1) { if(reason) *reason = QString("surrogate model expects one active calculation well, got %1").arg(validCalculationWells); return false; } if(!dataManager->getFaultDataList().isEmpty() || !dataManager->getFractureDataList().isEmpty() || !dataManager->getRegionDataList().isEmpty()) { if(reason) *reason = "surrogate model is not enabled for changed fault/fracture/region geometry"; return false; } QVector allowedParamIndices; allowedParamIndices << 0 << 1 << 2 << 3 << 5; for(int i = 0; i < m_enabledParamIndices.size(); ++i) { if(!allowedParamIndices.contains(m_enabledParamIndices[i])) { if(reason) { QStringList names = traceParameterNames(); int idx = m_enabledParamIndices[i]; QString name = (idx >= 0 && idx < names.size()) ? names[idx] : QString::number(idx); *reason = QString("parameter '%1' is outside surrogate input set").arg(name); } return false; } } nmDataReservoir reservoirData = dataManager->getReservoirDataCopy(); double cf = reservoirData.getCf().getValue().toDouble(); if(!isNearRelative(cf, kSurrogateCfFixed, kSurrogateCfRelTol)) { if(reason) { *reason = QString("Cf=%1 is outside surrogate fixed-Cf domain").arg(cf, 0, 'g', 10); } return false; } QVector flowPoints = pTargetWell->getFlowPoints(); if(!flowPoints.isEmpty() && qAbs(flowPoints[0].x()) <= 1e-12 && qAbs(flowPoints[0].y()) <= 1e-12) { flowPoints.remove(0); } if(flowPoints.size() < 2) { if(reason) *reason = "flow schedule is too short for surrogate screening"; return false; } int productionSections = flowPoints.size() - 1; if(productionSections < kSurrogateMinProdSections || productionSections > kSurrogateMaxProdSections) { if(reason) { *reason = QString("production section count %1 is outside surrogate range [%2,%3]") .arg(productionSections) .arg(kSurrogateMinProdSections) .arg(kSurrogateMaxProdSections); } return false; } double productionTime = 0.0; for(int i = 0; i < productionSections; ++i) { double dt = flowPoints[i].x(); double q = flowPoints[i].y(); if(!isFiniteNumber(dt) || dt <= 0.0 || !isInClosedRange(q, kSurrogateQMin, kSurrogateQMax)) { if(reason) { *reason = QString("production schedule section %1 is outside surrogate dt/q domain").arg(i + 1); } return false; } if(i > 0) { double previousQ = flowPoints[i - 1].y(); double stepRatio = qMax(q, previousQ) / qMax(1e-12, qMin(q, previousQ)); if(stepRatio > kSurrogateMaxRateStepRatio) { if(reason) { *reason = QString("rate step ratio %1 exceeds surrogate domain").arg(stepRatio, 0, 'g', 10); } return false; } } productionTime += dt; } if(!getSurrogateStage().contains("v2_q")) { double endStartRatio = std::numeric_limits::quiet_NaN(); if(isStrongDecliningProductionSchedule(&endStartRatio)) { if(reason) { *reason = QString("strongly decreasing production schedule ratio %1 is outside surrogate domain") .arg(endStartRatio, 0, 'g', 10); } return false; } } if(!isInClosedRange(productionTime, kSurrogateProdTimeMin, kSurrogateProdTimeMax)) { if(reason) { *reason = QString("production total time %1 is outside surrogate range").arg(productionTime, 0, 'g', 10); } return false; } double shutinTime = flowPoints.last().x(); double shutinRate = flowPoints.last().y(); if(!isInClosedRange(shutinTime, kSurrogateShutinTimeMin, kSurrogateShutinTimeMax) || qAbs(shutinRate) > kSurrogateQZeroThreshold) { if(reason) *reason = "last flow section is not a trained shut-in section"; return false; } if(pTargetWell->getIndexF() != flowPoints.size()) { if(reason) { *reason = QString("target section index %1 is not the last section %2") .arg(pTargetWell->getIndexF()) .arg(flowPoints.size()); } return false; } return true; } bool nmCalculationAutoFitPSO::isSurrogateCandidateInDomain(const QVector& selectedParameters, QString* reason) const { QVector params = buildTraceParameterVector(selectedParameters); double k = params.size() > 0 ? params[0] : std::numeric_limits::quiet_NaN(); double skin = params.size() > 1 ? params[1] : std::numeric_limits::quiet_NaN(); double wellboreC = params.size() > 2 ? params[2] : std::numeric_limits::quiet_NaN(); double phi = params.size() > 3 ? params[3] : std::numeric_limits::quiet_NaN(); double h = params.size() > 5 ? params[5] : std::numeric_limits::quiet_NaN(); double cf = params.size() > 7 ? params[7] : std::numeric_limits::quiet_NaN(); if(!isInClosedRange(k, kSurrogateKMin, kSurrogateKMax)) { if(reason) *reason = QString("k=%1").arg(k, 0, 'g', 10); return false; } if(!isInClosedRange(skin, kSurrogateSkinMin, kSurrogateSkinMax)) { if(reason) *reason = QString("skin=%1").arg(skin, 0, 'g', 10); return false; } if(!isInClosedRange(wellboreC, kSurrogateWellboreCMin, kSurrogateWellboreCMax)) { if(reason) *reason = QString("wellboreC=%1").arg(wellboreC, 0, 'g', 10); return false; } if(!isInClosedRange(phi, kSurrogatePhiMin, kSurrogatePhiMax)) { if(reason) *reason = QString("phi=%1").arg(phi, 0, 'g', 10); return false; } if(!isInClosedRange(h, kSurrogateHMin, kSurrogateHMax)) { if(reason) *reason = QString("h=%1").arg(h, 0, 'g', 10); return false; } if(!isNearRelative(cf, kSurrogateCfFixed, kSurrogateCfRelTol)) { if(reason) *reason = QString("Cf=%1").arg(cf, 0, 'g', 10); return false; } return true; } bool nmCalculationAutoFitPSO::forceSolverByFallbackGate(const QVector& selectedParameters) const { QVector params = buildTraceParameterVector(selectedParameters); double k = params.size() > 0 ? params[0] : std::numeric_limits::quiet_NaN(); double skin = params.size() > 1 ? params[1] : std::numeric_limits::quiet_NaN(); double wellboreC = params.size() > 2 ? params[2] : std::numeric_limits::quiet_NaN(); double phi = params.size() > 3 ? params[3] : std::numeric_limits::quiet_NaN(); double h = params.size() > 5 ? params[5] : std::numeric_limits::quiet_NaN(); if(!isFiniteNumber(k) || !isFiniteNumber(skin) || !isFiniteNumber(wellboreC) || !isFiniteNumber(phi) || !isFiniteNumber(h)) { return true; } if(k <= 1e-3 && wellboreC > 0.5) { return true; } if(phi < 0.03 && h < 4.0) { return true; } if(k < 0.1 && h >= 50.0) { return true; } if(qAbs(skin) > 6.0) { return true; } return false; } bool nmCalculationAutoFitPSO::isStrongDecliningProductionSchedule(double* endStartRatio) const { if(endStartRatio) { *endStartRatio = std::numeric_limits::quiet_NaN(); } nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); if(!dataManager) { return false; } nmDataWellBase* pTargetWell = dataManager->findWellByName(m_targetWellName); if(!pTargetWell) { return false; } QVector flowPoints = pTargetWell->getFlowPoints(); if(!flowPoints.isEmpty() && qAbs(flowPoints[0].x()) <= 1e-12 && qAbs(flowPoints[0].y()) <= 1e-12) { flowPoints.remove(0); } if(flowPoints.size() < 2) { return false; } int productionSections = flowPoints.size() - 1; bool productionRatesNonIncreasing = true; bool productionRatesHaveMeaningfulDrop = false; for(int i = 0; i < productionSections; ++i) { double q = flowPoints[i].y(); if(!isFiniteNumber(q)) { return false; } if(i > 0) { double previousQ = flowPoints[i - 1].y(); if(q > previousQ * (1.0 + kSurrogateRateTrendRelTol)) { productionRatesNonIncreasing = false; } if(q < previousQ * (1.0 - kSurrogateRateTrendRelTol)) { productionRatesHaveMeaningfulDrop = true; } } } if(!productionRatesNonIncreasing || !productionRatesHaveMeaningfulDrop) { return false; } double firstRate = flowPoints.first().y(); double lastProductionRate = flowPoints[productionSections - 1].y(); double ratio = lastProductionRate / qMax(1e-12, firstRate); if(endStartRatio) { *endStartRatio = ratio; } return ratio < kSurrogateStrongDeclineEndStartRatio; } QVector nmCalculationAutoFitPSO::buildSurrogateEvaluationMask() { QVector evaluateMask(m_swarm.size(), true); for(int i = 0; i < m_swarm.size(); ++i) { m_swarm[i].surrogateObjective = std::numeric_limits::quiet_NaN(); m_swarm[i].selectedForSolver = true; m_swarm[i].selectedByAudit = false; m_swarm[i].screeningDecision = "full_solver"; } if(!isSurrogateScreeningEnabled()) { return evaluateMask; } QString contextReason; if(!isSurrogateRunContextSupported(&contextReason)) { m_surrogateContextBlockedIterationCount++; for(int i = 0; i < m_swarm.size(); ++i) { m_swarm[i].screeningDecision = "context_gate_full_solver"; } emit logMessageGenerated(tr("Surrogate screening disabled for this run context: %1").arg(contextReason)); return evaluateMask; } // Keep the early PSO generations fully evaluated so every particle gets a true pbest seed. if(m_currentIteration < getSurrogateWarmupIterations()) { m_surrogateWarmupIterationCount++; for(int i = 0; i < m_swarm.size(); ++i) { m_swarm[i].screeningDecision = "warmup_full_solver"; } return evaluateMask; } if(getSurrogateFullSolverInterval() > 0 && m_currentIteration > 0 && ((m_currentIteration + 1) % getSurrogateFullSolverInterval()) == 0) { m_surrogatePeriodicAuditIterationCount++; for(int i = 0; i < m_swarm.size(); ++i) { m_swarm[i].screeningDecision = "periodic_full_solver"; } emit logMessageGenerated(tr("Surrogate audit iteration %1: running full solver for all particles") .arg(m_currentIteration + 1)); return evaluateMask; } QString mlRoot = getMlRootPath(); QDir tempDir(QDir(mlRoot).absoluteFilePath("data/temp")); if(!tempDir.exists()) { QDir().mkpath(tempDir.absolutePath()); } QString candidatePath = tempDir.absoluteFilePath(QString("pso_screen_candidates_%1_gen%2.csv") .arg(m_traceRunId) .arg(m_currentIteration)); QString scorePath = tempDir.absoluteFilePath(QString("pso_screen_scores_%1_gen%2.csv") .arg(m_traceRunId) .arg(m_currentIteration)); QString scoringFailureReason; if(!writeSurrogateCandidateCsv(candidatePath) || !runSurrogateScoringProcess(candidatePath, scorePath, &scoringFailureReason)) { emit logMessageGenerated(tr("Surrogate screening unavailable; falling back to full solver for iteration %1") .arg(m_currentIteration + 1)); if(!scoringFailureReason.isEmpty()) { emit logMessageGenerated(tr("Surrogate scoring failure detail: %1").arg(scoringFailureReason)); } return evaluateMask; } QVector scores = readSurrogateScores(scorePath); QVector finiteScoreIndices; for(int i = 0; i < scores.size(); ++i) { m_swarm[i].surrogateObjective = scores[i]; if(isFiniteNumber(scores[i])) { finiteScoreIndices.append(i); } } if(finiteScoreIndices.isEmpty()) { emit logMessageGenerated(tr("Surrogate scoring returned no valid scores; falling back to full solver")); return evaluateMask; } std::sort(finiteScoreIndices.begin(), finiteScoreIndices.end(), [&](int a, int b) { return scores[a] < scores[b]; }); evaluateMask.fill(false); for(int i = 0; i < m_swarm.size(); ++i) { m_swarm[i].selectedForSolver = false; m_swarm[i].screeningDecision = "screened_out"; } int keepN = qMax(1, qCeil(m_swarm.size() * getSurrogateKeepFraction())); keepN = qMin(keepN, finiteScoreIndices.size()); for(int rank = 0; rank < keepN; ++rank) { int idx = finiteScoreIndices[rank]; evaluateMask[idx] = true; m_swarm[idx].selectedForSolver = true; m_swarm[idx].screeningDecision = "surrogate_topk"; } QVector > auditCandidates; for(int i = 0; i < finiteScoreIndices.size(); ++i) { int idx = finiteScoreIndices[i]; if(!evaluateMask[idx]) { auditCandidates.append(qMakePair(deterministicAuditRandom01(m_psoRandomSeed, m_currentIteration, idx), idx)); } } std::sort(auditCandidates.begin(), auditCandidates.end(), [](const QPair& a, const QPair& b) { return a.first < b.first; }); int auditN = qMin(auditCandidates.size(), qCeil(m_swarm.size() * getSurrogateAuditFraction())); for(int i = 0; i < auditN; ++i) { int idx = auditCandidates[i].second; evaluateMask[idx] = true; m_swarm[idx].selectedForSolver = true; m_swarm[idx].selectedByAudit = true; m_swarm[idx].screeningDecision = "random_audit"; } int fallbackCount = 0; int domainFallbackCount = 0; for(int i = 0; i < m_swarm.size(); ++i) { QString domainReason; bool domainFallback = !isSurrogateCandidateInDomain(m_swarm[i].position, &domainReason); bool fallback = !isFiniteNumber(scores[i]) || m_swarm[i].bestFitness >= 1e9 || forceSolverByFallbackGate(m_swarm[i].position) || domainFallback; if(fallback) { if(!evaluateMask[i]) { fallbackCount++; } if(domainFallback) { domainFallbackCount++; } evaluateMask[i] = true; m_swarm[i].selectedForSolver = true; m_swarm[i].screeningDecision = domainFallback ? "domain_gate" : "fallback_gate"; } } int selectedCount = 0; for(int i = 0; i < evaluateMask.size(); ++i) { if(evaluateMask[i]) { selectedCount++; } } int minSolverN = qMax(1, qCeil(m_swarm.size() * getSurrogateMinSolverFraction())); if(selectedCount < minSolverN) { QVector > extraCandidates; for(int i = 0; i < m_swarm.size(); ++i) { if(!evaluateMask[i] && isFiniteNumber(scores[i])) { extraCandidates.append(qMakePair(scores[i], i)); } } std::sort(extraCandidates.begin(), extraCandidates.end(), [](const QPair& a, const QPair& b) { return a.first < b.first; }); for(int i = 0; i < extraCandidates.size() && selectedCount < minSolverN; ++i) { int idx = extraCandidates[i].second; evaluateMask[idx] = true; m_swarm[idx].selectedForSolver = true; m_swarm[idx].screeningDecision = "min_solver_floor"; selectedCount++; } } emit logMessageGenerated(tr("Surrogate screening iteration %1: selected %2/%3 particles (keep=%4, audit=%5, min_solver=%6, fallback=%7, domain=%8)") .arg(m_currentIteration + 1) .arg(selectedCount) .arg(m_swarm.size()) .arg(getSurrogateKeepFraction(), 0, 'f', 2) .arg(getSurrogateAuditFraction(), 0, 'f', 2) .arg(getSurrogateMinSolverFraction(), 0, 'f', 2) .arg(fallbackCount) .arg(domainFallbackCount)); m_surrogateActiveIterationCount++; for(int i = 0; i < m_swarm.size(); ++i) { const QString& decision = m_swarm[i].screeningDecision; if(m_swarm[i].selectedForSolver) { m_surrogateSelectedParticleCount++; } if(decision == "screened_out") { m_surrogateScreenedParticleCount++; } else if(decision == "surrogate_topk") { m_surrogateTopKParticleCount++; } else if(decision == "random_audit") { m_surrogateAuditParticleCount++; } else if(decision == "fallback_gate") { m_surrogateFallbackParticleCount++; } else if(decision == "domain_gate") { m_surrogateDomainParticleCount++; } else if(decision == "min_solver_floor") { m_surrogateMinFloorParticleCount++; } } return evaluateMask; } //QString nmCalculationAutoFitPSO::getTargetWellName() const //{ // return m_targetWellName; //} // ==================== 数据加载方法 ==================== bool nmCalculationAutoFitPSO::loadAllConfigFromDataManager() { try { loadOptimizationConfig(); loadParameterBounds(); extractUserInitialValues(); // 直接提取初始值,无需条件判断 return true; } catch(...) { m_lastError = "Failed to load configuration from data manager"; return false; } } void nmCalculationAutoFitPSO::loadOptimizationConfig() { nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); nmDataAutomaticFitting fittingData = dataManager->getAutomaticFittingDataCopy(); // 加载基本配置 m_maxIterations = fittingData.getIterationCount().getValue().toInt(); m_targetError = fittingData.getErrorTolerance().getValue().toDouble(); m_surrogateScreeningEnabled = fittingData.getSurrogateScreeningEnabled(); // 设置PSO默认参数 m_swarmSize = 20; m_inertiaWeight = 0.4; m_cognitiveParam = 2.0; m_socialParam = 1.2; DEBUG_OUT(QString("Loaded optimization config: iterations=%1, error=%2, surrogate=%3") .arg(m_maxIterations).arg(m_targetError).arg(m_surrogateScreeningEnabled ? "enabled" : "disabled")); } void nmCalculationAutoFitPSO::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())); } // ==================== PSO算法核心方法 ==================== bool nmCalculationAutoFitPSO::startAutoFitting() { if(m_isRunning) { m_lastError = "Auto fitting is already running"; return false; } // 发送初始化日志 //emit logMessageGenerated(tr("=== PSO Automatic Fitting Started ===")); emit logMessageGenerated(tr("Algorithm: Particle Swarm Optimization")); try { // 从数据管理器加载所有配置 if(!loadAllConfigFromDataManager()) { emit logMessageGenerated(tr("ERROR: Failed to load configuration from data manager")); return false; } if(m_simulationMode) { DEBUG_OUT("=== SIMULATION MODE ACTIVATED ==="); runSimulatedFitting(); return true; } 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 savedInitialValues = m_initialValues; // 重置状态 resetOptimizer(); m_isRunning = true; m_shouldStop = false; m_isPaused = false; m_currentIteration = 0; m_consecutiveFailures = 0; if(kUseFixedPsoSeed) { m_psoRandomSeed = kFixedPsoSeed; } else { QTime seedTime = QTime::currentTime(); m_psoRandomSeed = static_cast(QDateTime::currentDateTime().toTime_t()); m_psoRandomSeed ^= static_cast((seedTime.hour() << 22) ^ (seedTime.minute() << 16) ^ (seedTime.second() << 10) ^ seedTime.msec()); } if(m_psoRandomSeed == 0u) { m_psoRandomSeed = 1u; } qsrand(m_psoRandomSeed); m_consecutiveFailedIterations = 0; // 重置连续失败迭代计数 // 精英保护:评估用户初始解 m_initialValues = savedInitialValues; initializeTraceFile(); 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 evaluateError: m_userInitialSolution size = %1").arg(m_userInitialSolution.size())); if(m_userInitialSolution.isEmpty()) { emit logMessageGenerated(tr("ERROR: m_userInitialSolution is empty!")); return false; } QTime initialEvalTimer; initialEvalTimer.start(); m_userInitialFitness = evaluateFitness(m_userInitialSolution); int initialEvalElapsedMs = initialEvalTimer.elapsed(); if(m_userInitialFitness < 1e9) { m_hasValidUserSolution = true; m_globalBestFitness = m_userInitialFitness; m_globalBestPosition = m_userInitialSolution; m_userInitialLogLogData = m_lastEvaluatedLogLogData; m_globalBestLogLogData = m_userInitialLogLogData; emit logMessageGenerated(tr("Initial solution evaluation successful")); emit logMessageGenerated(tr("Initial Error: %1").arg(m_userInitialFitness, 0, 'e', 4)); emit logMessageGenerated(tr("Elite protection activated - initial solution will be preserved if no significant improvement found")); emit bestCurveUpdated(m_targetLogLogData, m_globalBestLogLogData, 0, m_globalBestFitness); } else { m_hasValidUserSolution = false; emit logMessageGenerated(tr("Initial solution evaluation failed - starting with random initialization")); } writeTraceRow(-1, -1, "initial_solution", m_userInitialSolution, m_userInitialFitness, m_userInitialFitness < 1e9, initialEvalElapsedMs, std::numeric_limits::quiet_NaN(), "initial_solution", m_hasValidUserSolution ? m_userInitialSolution : QVector(), m_userInitialFitness); } catch(...) { m_hasValidUserSolution = false; emit logMessageGenerated(tr("Exception during initial solution evaluation")); } // 恢复初始值供粒子群初始化使用 m_initialValues = savedInitialValues; } // 初始化粒子群 if(kUseFixedPsoSeed) { emit logMessageGenerated(tr("PSO random seed: %1 ").arg(m_psoRandomSeed)); } else { emit logMessageGenerated(tr("PSO random seed: %1 ").arg(m_psoRandomSeed)); } initializeSwarm(); emit logMessageGenerated(tr("Swarm initialized: %1 particles, %2 dimensions").arg(m_swarmSize).arg(getEnabledParameterCount())); // PSO主循环 emit logMessageGenerated(tr("=== Starting PSO Main Loop ===")); for(m_currentIteration = 0; m_currentIteration < m_maxIterations && !m_shouldStop; ++m_currentIteration) { // 每次迭代都输出标题,或者只在重要迭代输出详细信息 bool shouldOutputDetail = (m_currentIteration % qMax(1, m_maxIterations / 10) == 0) || (m_currentIteration < 5) || (m_currentIteration >= m_maxIterations - 2); // 总是输出前5次和最后2次的详细信息 // 每次迭代都输出标题 emit logMessageGenerated(tr("--- Iteration %1/%2 ---").arg(m_currentIteration + 1).arg(m_maxIterations)); // 只在特定迭代输出详细统计信息 if(shouldOutputDetail) { emit logMessageGenerated(tr("Current best error: %1").arg(m_globalBestFitness, 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; } int currentIterationSuccessful = 0; int currentIterationTotal = 0; int currentIterationFailed = 0; int currentIterationSkipped = 0; QVector evaluateMask = buildSurrogateEvaluationMask(); for(int i = 0; i < m_swarmSize && !m_shouldStop; ++i) { try { if(i < evaluateMask.size() && !evaluateMask[i]) { AutoFitParticle& particle = m_swarm[i]; particle.evaluatedThisIteration = false; particle.lastEvaluationSuccess = false; particle.lastEvaluationElapsedMs = -1; particle.selectedForSolver = false; if(particle.screeningDecision.isEmpty()) { particle.screeningDecision = "screened_out"; } currentIterationSkipped++; continue; } double previousFitness = m_swarm[i].fitness; updateParticle(i); currentIterationTotal++; if(m_swarm[i].fitness < 1e9) { currentIterationSuccessful++; if(shouldOutputDetail && m_swarm[i].fitness < previousFitness) { // 计算改进幅度 double improvement = (previousFitness - m_swarm[i].fitness) / qMax(1e-10, previousFitness); if(improvement > 0.01) { // 1%以上改进才输出 emit logMessageGenerated(tr(" Particle %1 improved: %2 -> %3 (%4% improvement)") .arg(i + 1).arg(previousFitness, 0, 'e', 3).arg(m_swarm[i].fitness, 0, 'e', 3) .arg(improvement * 100, 0, 'f', 2)); } } } else { currentIterationFailed++; if(shouldOutputDetail) { emit logMessageGenerated(tr(" Particle %1: evaluation failed").arg(i + 1)); } } // 每评估2个粒子处理一次事件 if(i % 2 == 0) { QApplication::processEvents(); } } catch(const std::exception& e) { if(shouldOutputDetail) { emit logMessageGenerated(tr(" Particle %1: Exception: %2").arg(i + 1).arg(e.what())); } m_swarm[i].fitness = 1e10; currentIterationTotal++; currentIterationFailed++; m_totalEvaluations++; } catch(...) { if(shouldOutputDetail) { emit logMessageGenerated(tr(" Particle %1: Unknown exception").arg(i + 1)); } m_swarm[i].fitness = 1e10; currentIterationTotal++; currentIterationFailed++; m_totalEvaluations++; } } if(m_shouldStop) break; double currentSuccessRate = currentIterationTotal > 0 ? (double)currentIterationSuccessful / currentIterationTotal : 0.0; // 更新连续失败迭代计数 if(currentIterationSuccessful == 0) { m_consecutiveFailedIterations++; emit logMessageGenerated(tr("WARNING: No successful evaluations in iteration %1 (consecutive failures: %2)") .arg(m_currentIteration + 1).arg(m_consecutiveFailedIterations)); } else { m_consecutiveFailedIterations = 0; // 重置连续失败计数 } // 输出当前迭代统计 if(shouldOutputDetail) { emit logMessageGenerated(tr("Current iteration stats: %1 successful, %2 failed, %3 skipped out of %4 particles (solver success rate: %5%)") .arg(currentIterationSuccessful).arg(currentIterationFailed) .arg(currentIterationSkipped) .arg(m_swarmSize).arg(currentSuccessRate * 100, 0, 'f', 1)); } // 检查是否需要停止优化 if(m_consecutiveFailedIterations >= m_maxConsecutiveFailures) { m_lastError = QString("Too many consecutive failed iterations (%1)").arg(m_consecutiveFailedIterations); emit logMessageGenerated(tr("ERROR: Too many consecutive failed iterations (%1/%2) - stopping optimization") .arg(m_consecutiveFailedIterations).arg(m_maxConsecutiveFailures)); break; } // 警告低成功率但不立即停止 if(currentSuccessRate < 0.5 && m_currentIteration > 3) { emit logMessageGenerated(tr("WARNING: Low success rate (%1%) in iteration %2, but continuing optimization") .arg(currentSuccessRate * 100, 0, 'f', 1).arg(m_currentIteration + 1)); } // 更新全局最优 //double previousGlobalBest = m_globalBestFitness; updateGlobalBest(); writeIterationTraceRows(); // 自适应参数更新 adaptiveParameterUpdate(m_currentIteration); emit progressUpdated(m_currentIteration + 1, m_globalBestFitness); // 记录收敛历史 m_convergenceHistory.append(m_globalBestFitness); // 每5次迭代输出收敛状态 if((m_currentIteration + 1) % 5 == 0) { double recentImprovement = 0.0; if(m_convergenceHistory.size() >= 5) { double oldBest = m_convergenceHistory[m_convergenceHistory.size() - 5]; recentImprovement = (oldBest - m_globalBestFitness) / qMax(1e-10, oldBest); } emit logMessageGenerated(tr(" Convergence check: recent improvement = %1% over last 5 iterations") .arg(recentImprovement * 100, 0, 'f', 4)); } // 更新收敛指标 updateConvergenceMetrics(); // 智能收敛判断 StopReasonPSO stopReason = analyzeOptimizationStatus(); if(stopReason == PSO_TARGET_ACHIEVED) { emit logMessageGenerated(tr("=== TARGET ACHIEVED ===")); emit logMessageGenerated(tr("Target error achieved! Current error: %1 < Target: %2") .arg(m_globalBestFitness, 0, 'e', 4).arg(m_targetError, 0, 'e', 4)); emit logMessageGenerated(tr("Optimization completed successfully after %1 iterations") .arg(m_currentIteration + 1)); break; } else if(stopReason == PSO_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 iterations") .arg(m_globalBestFitness, 0, 'e', 4).arg(m_currentIteration + 1)); emit logMessageGenerated(tr("Solution quality: %1 (1.0 = target achieved)") .arg(m_targetError / qMax(1e-10, m_globalBestFitness), 0, 'f', 3)); break; } else if(stopReason == PSO_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 iterations") .arg(m_globalBestFitness, 0, 'e', 4).arg(m_currentIteration + 1)); emit logMessageGenerated(tr("Suggestion: Try restarting with different parameters or larger search space")); break; } else if(stopReason == PSO_CONSECUTIVE_FAILURES) { emit logMessageGenerated(tr("=== CONSECUTIVE FAILURES ===")); emit logMessageGenerated(tr("Too many consecutive failed iterations (%1/%2)") .arg(m_consecutiveFailedIterations).arg(m_maxConsecutiveFailures)); break; } else if(stopReason == PSO_CONTINUE_OPTIMIZATION) { // 继续优化,每10次迭代输出一次状态 if(m_currentIteration > 0 && m_currentIteration % 10 == 0) { double diversity = calculateSwarmDiversity(); double avgVel = calculateAverageVelocity(); double stagnation = calculateParticleStagnationRate(); emit logMessageGenerated(tr(" Optimization status: diversity=%1, avgVel=%2, stagnation=%3%") .arg(diversity, 0, 'f', 4).arg(avgVel, 0, 'f', 4).arg(stagnation * 100, 0, 'f', 1)); } } // 更新粒子位置和速度 updateVelocityAndPosition(); // 输出迭代结束标记 if(shouldOutputDetail) { emit logMessageGenerated(tr(" Iteration %1 completed - Current best: %2") .arg(m_currentIteration + 1).arg(m_globalBestFitness, 0, 'e', 4)); } // 强制处理事件,保持界面响应 QApplication::processEvents(); // 在迭代间稍作停顿,减少系统负载 if(m_currentIteration % 3 == 2) { msleep(200); } } // 最终结果验证和保护 validateAndProtectFinalResult(); } catch(const std::exception& e) { m_lastError = QString(tr("Critical exception in PSO main loop: %1")).arg(e.what()); emit logMessageGenerated(tr("CRITICAL ERROR: %1").arg(e.what())); closeTraceFile(); cleanupTemporaryDirectory(); m_isRunning = false; emit fittingFinished(false, m_lastError); return false; } catch(...) { m_lastError = QString(tr("Unknown critical exception in PSO main loop")); emit logMessageGenerated(tr("CRITICAL ERROR: Unknown exception in PSO main loop")); closeTraceFile(); cleanupTemporaryDirectory(); m_isRunning = false; emit fittingFinished(false, m_lastError); return false; } m_isRunning = false; // 应用最终参数 if(!m_globalBestPosition.isEmpty()) { try { emit logMessageGenerated(tr("Applying optimized parameters to model...")); applyParametersToDataManager(m_globalBestPosition); saveOptimizationResult(); // 输出最终优化结果 emit logMessageGenerated(tr("=== Optimization Results ===")); emit logMessageGenerated(tr("Final error: %1").arg(m_globalBestFitness, 0, 'e', 4)); emit logMessageGenerated(tr("Total iterations: %1").arg(m_currentIteration + 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_globalBestPosition.size(); ++i) { finalParams += QString("[%1]=%2 ").arg(i).arg(m_globalBestPosition[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; StopReasonPSO finalReason = analyzeOptimizationStatus(); if(finalReason == PSO_TARGET_ACHIEVED) { success = true; message = QString(tr("Target achieved. Best error: %1, Iterations: %2")) .arg(m_globalBestFitness, 0, 'e', 4).arg(m_currentIteration + 1); emit logMessageGenerated(tr("=== PSO OPTIMIZATION SUCCESSFUL ===")); } else if(finalReason == PSO_TRUE_CONVERGENCE) { success = true; message = QString(tr("PSO optimization converged to stable solution. Best error: %1, Iterations: %2")) .arg(m_globalBestFitness, 0, 'e', 4).arg(m_currentIteration + 1); emit logMessageGenerated(tr("=== PSO OPTIMIZATION CONVERGED ===")); } else if(finalReason == PSO_LOCAL_OPTIMUM) { success = true; message = QString(tr("PSO optimization trapped in local optimum. Best error: %1, Iterations: %2")) .arg(m_globalBestFitness, 0, 'e', 4).arg(m_currentIteration + 1); emit logMessageGenerated(tr("=== PSO OPTIMIZATION - LOCAL OPTIMUM ===")); } else if(finalReason == PSO_MAX_ITERATIONS) { success = true; message = QString(tr("Max iterations reached. Best error: %1, Iterations: %2")) .arg(m_globalBestFitness, 0, 'e', 4).arg(m_currentIteration + 1); emit logMessageGenerated(tr("=== PSO OPTIMIZATION - MAX ITERATIONS ===")); } else if(finalReason == PSO_USER_STOPPED) { success = true; message = QString(tr("Best error: %1, Iterations: %2")) .arg(m_globalBestFitness, 0, 'e', 4).arg(m_currentIteration + 1); emit logMessageGenerated(tr("=== PSO OPTIMIZATION STOPPED BY USER ===")); } else if(finalReason == PSO_CONSECUTIVE_FAILURES) { success = false; message = QString(tr("PSO optimization failed due to consecutive failures. Best error: %1, Iterations: %2")) .arg(m_globalBestFitness, 0, 'e', 4).arg(m_currentIteration + 1); emit logMessageGenerated(tr("=== PSO OPTIMIZATION FAILED ===")); } else { success = false; message = QString(tr("PSO optimization ended unexpectedly. Best error: %1, Iterations: %2")) .arg(m_globalBestFitness, 0, 'e', 4).arg(m_currentIteration + 1); emit logMessageGenerated(tr("=== PSO OPTIMIZATION - UNKNOWN END ===")); } emitRunSummary(success, finalReason); // 先发送最终进度更新,确保进度条达到100% emit progressUpdated(m_maxIterations, m_globalBestFitness); // 确保界面更新完成 QApplication::processEvents(); // 短暂延迟,让进度条动画完成 msleep(200); // 再次确保界面更新 QApplication::processEvents(); // 现在才发送完成信号,这会触发消息框 closeTraceFile(); emit fittingFinished(success, message); cleanupTemporaryDirectory(); return success; } void nmCalculationAutoFitPSO::extractUserInitialValues() { nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); nmDataReservoir reservoirData = dataManager->getReservoirDataCopy(); //QVector 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 nmCalculationAutoFitPSO::initializeSwarm() { int dimensions = getEnabledParameterCount(); if(dimensions == 0) return; m_swarm.resize(m_swarmSize); m_globalBestPosition.resize(dimensions); bool hasValidInitials = !m_initialValues.isEmpty() && m_initialValues.size() >= dimensions; // 引导搜索比例 //int guidedCount = hasValidInitials ? qMax(2, (m_swarmSize * 3) / 4) : qMax(1, m_swarmSize / 3); int guidedCount = hasValidInitials ? qMax(2, m_swarmSize / 2) : qMax(1, m_swarmSize / 3); DEBUG_OUT(QString("Enhanced swarm initialization: %1 particles, %2 guided, %3 random") .arg(m_swarmSize).arg(guidedCount).arg(m_swarmSize - guidedCount)); for(int i = 0; i < m_swarmSize; ++i) { AutoFitParticle& particle = m_swarm[i]; particle.position.resize(dimensions); particle.velocity.resize(dimensions); particle.bestPosition.resize(dimensions); particle.bestFitness = 1e10; particle.fitness = 1e10; particle.evaluatedThisIteration = false; particle.lastEvaluationSuccess = false; particle.lastEvaluationElapsedMs = -1; particle.surrogateObjective = 1e10; particle.selectedForSolver = true; particle.selectedByAudit = false; particle.screeningDecision = "full_solver"; for(int j = 0; j < dimensions; ++j) { int paramIndex = m_enabledParamIndices[j]; double range = m_parameterUpper[paramIndex] - m_parameterLower[paramIndex]; if(i == 0 && hasValidInitials) { // 第一个粒子:完全使用用户初始值 particle.position[j] = m_initialValues[j]; } else if(i < guidedCount && hasValidInitials) { // 搜索策略 double searchRadius; if(i <= guidedCount / 3) { searchRadius = range * 0.03; // 3%范围内精细搜索 } else if(i <= guidedCount * 2 / 3) { searchRadius = range * 0.08; // 8%范围内搜索 } else { searchRadius = range * 0.15; // 15%范围内搜索 } double offset = (random01() - 0.5) * searchRadius; particle.position[j] = m_initialValues[j] + offset; } else { // 少数粒子进行全局搜索 particle.position[j] = m_parameterLower[paramIndex] + random01() * range; } } // 边界检查 clampToLimits(particle.position); // 速度初始化 for(int j = 0; j < dimensions; ++j) { int paramIndex = m_enabledParamIndices[j]; double range = m_parameterUpper[paramIndex] - m_parameterLower[paramIndex]; double velocityFactor; if(i < guidedCount) { velocityFactor = VELOCITY_LIMIT_FACTOR * 0.15; // 更小的速度 } else { velocityFactor = VELOCITY_LIMIT_FACTOR * 0.8; // 适中速度 } particle.velocity[j] = (random01() - 0.5) * range * velocityFactor; } particle.bestPosition = particle.position; } } void nmCalculationAutoFitPSO::updateParticle(int particleIndex) { if(particleIndex < 0 || particleIndex >= m_swarm.size()) return; AutoFitParticle& particle = m_swarm[particleIndex]; // 评估适应度 particle.evaluatedThisIteration = false; particle.lastEvaluationSuccess = false; particle.lastEvaluationElapsedMs = -1; particle.selectedForSolver = true; if(particle.screeningDecision.isEmpty()) { particle.screeningDecision = "full_solver"; } QTime evalTimer; evalTimer.start(); particle.fitness = evaluateFitness(particle.position); particle.currentLogLogData = m_lastEvaluatedLogLogData; particle.lastEvaluationElapsedMs = evalTimer.elapsed(); particle.evaluatedThisIteration = true; particle.lastEvaluationSuccess = (particle.fitness < 1e9); m_totalEvaluations++; if(particle.fitness < 1e9) { m_successfulEvaluations++; } // Update particle best. if(particle.fitness < particle.bestFitness) { particle.bestFitness = particle.fitness; particle.bestPosition = particle.position; particle.bestLogLogData = particle.currentLogLogData; DEBUG_OUT(QString("Particle %1 improved: error = %2") .arg(particleIndex).arg(particle.fitness, 0, 'e', 4)); } } void nmCalculationAutoFitPSO::updateGlobalBest() { // 保存上一轮的全局最优,用于后续自适应参数调整等 m_previousBestFitness = m_globalBestFitness; bool globalBestUpdated = false; // 遍历所有粒子,寻找比当前 global best 更好的个体最优 for(int i = 0; i < m_swarm.size(); ++i) { const AutoFitParticle& particle = m_swarm[i]; // 只要个体最优比当前全局最优小,就认为是更好的解 if(particle.bestFitness < m_globalBestFitness) { double improvement = m_globalBestFitness - particle.bestFitness; double relativeImprovement = improvement / qMax(1e-10, qAbs(m_globalBestFitness)); // 区分显著改进和微小改进,但无论如何都会更新全局最优 if(relativeImprovement > m_improvementThreshold) { DEBUG_OUT(QString(tr("Global best updated with %1% improvement: %2")) .arg(relativeImprovement * 100.0, 0, 'f', 3) .arg(particle.bestFitness, 0, 'e', 4)); } else { DEBUG_OUT(QString(tr("Global best updated (minor improvement %1% < %2%) to %3")) .arg(relativeImprovement * 100.0, 0, 'f', 3) .arg(m_improvementThreshold * 100.0, 0, 'f', 2) .arg(particle.bestFitness, 0, 'e', 4)); } // 无论相对改进是否超过阈值,都要更新全局最优 m_globalBestFitness = particle.bestFitness; m_globalBestPosition = particle.bestPosition; m_globalBestLogLogData = particle.bestLogLogData; globalBestUpdated = true; emit bestCurveUpdated(m_targetLogLogData, m_globalBestLogLogData, m_currentIteration + 1, m_globalBestFitness); } } // 只有在本轮没有找到任何更好的解时才考虑恢复用户初始解 if(!globalBestUpdated && m_hasValidUserSolution && m_userInitialFitness < m_globalBestFitness) { double improvement = m_globalBestFitness - m_userInitialFitness; double relativeImprovement = improvement / qMax(1e-10, qAbs(m_globalBestFitness)); DEBUG_OUT("Elite protection: Restoring user initial solution as global best"); DEBUG_OUT(QString("Elite solution is better than current best by %1%") .arg(relativeImprovement * 100.0, 0, 'f', 3)); m_globalBestFitness = m_userInitialFitness; m_globalBestPosition = m_userInitialSolution; m_globalBestLogLogData = m_userInitialLogLogData; emit bestCurveUpdated(m_targetLogLogData, m_globalBestLogLogData, m_currentIteration + 1, m_globalBestFitness); } } //void nmCalculationAutoFitPSO::updateGlobalBest() //{ // m_previousBestFitness = m_globalBestFitness; // bool globalBestUpdated = false; // // for(int i = 0; i < m_swarm.size(); ++i) { // const AutoFitParticle& particle = m_swarm[i]; // // if(particle.bestFitness < m_globalBestFitness) { // // 只有显著改进时才更新 // double improvement = (m_globalBestFitness - particle.bestFitness); // double relativeImprovement = improvement / qMax(1e-10, qAbs(m_globalBestFitness)); // // if(relativeImprovement > m_improvementThreshold) { // m_globalBestFitness = particle.bestFitness; // m_globalBestPosition = particle.bestPosition; // globalBestUpdated = true; // // DEBUG_OUT(QString("Global best updated with %1% improvement: %2") // .arg(relativeImprovement * 100, 0, 'f', 3) // .arg(m_globalBestFitness, 0, 'e', 4)); // } else { // DEBUG_OUT(QString("Rejecting minor improvement: %1% (threshold: %2%)") // .arg(relativeImprovement * 100, 0, 'f', 4) // .arg(m_improvementThreshold * 100, 0, 'f', 2)); // } // } // } // // // 在没有找到更好解时才检查 // if(!globalBestUpdated && m_hasValidUserSolution && m_userInitialFitness < m_globalBestFitness) { // DEBUG_OUT("Elite protection: No significant improvement found, checking initial solution"); // // // 检查初始解是否仍然是最优的 // double improvement = m_globalBestFitness - m_userInitialFitness; // double relativeImprovement = improvement / qMax(1e-10, qAbs(m_globalBestFitness)); // // if(relativeImprovement > m_improvementThreshold * 0.5) { // 使用更宽松的阈值 // DEBUG_OUT("Elite protection: Restoring user initial solution"); // m_globalBestFitness = m_userInitialFitness; // m_globalBestPosition = m_userInitialSolution; // } // } //} void nmCalculationAutoFitPSO::updateVelocityAndPosition() { for(int i = 0; i < m_swarm.size(); ++i) { AutoFitParticle& particle = m_swarm[i]; for(int j = 0; j < particle.position.size(); ++j) { // PSO速度更新公式 double r1 = random01(); double r2 = random01(); particle.velocity[j] = m_inertiaWeight * particle.velocity[j] + m_cognitiveParam * r1 * (particle.bestPosition[j] - particle.position[j]) + m_socialParam * r2 * (m_globalBestPosition[j] - particle.position[j]); // 速度限制 int paramIndex = m_enabledParamIndices[j]; double range = m_parameterUpper[paramIndex] - m_parameterLower[paramIndex]; double maxVel = range * VELOCITY_LIMIT_FACTOR; particle.velocity[j] = qMax(-maxVel, qMin(maxVel, particle.velocity[j])); // 更新位置 particle.position[j] += particle.velocity[j]; } // 边界约束 clampToLimits(particle.position); } } //double nmCalculationAutoFitPSO::evaluateFitness(const QVector& parameters) //{ // const QString funcName = QString("evaluateError[%1]").arg(m_currentIteration); // static int callCount = 0; // callCount++; // // try { // DEBUG_OUT(QString("%1: Call #%2 - Starting evaluation with %3 parameters") // .arg(funcName).arg(callCount).arg(parameters.size())); // // // 打印参数值用于对比 // QString paramStr = "Parameters: "; // // for(int i = 0; i < parameters.size(); ++i) { // paramStr += QString("[%1]=%2 ").arg(i).arg(parameters[i], 0, 'f', 6); // } // // DEBUG_OUT(QString("%1: %2").arg(funcName).arg(paramStr)); // // // 1. 参数有效性检查 // if(!validateParameters(parameters)) { // 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(parameters); // 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 > 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 > resultLogLogData; // // try { // //wells = dataManager->getWellDataList(); // 重新获取,确保是最新的 // 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 nmCalculationAutoFitPSO::evaluateFitness(const QVector& parameters) { const QString funcName = QString("evaluateError[%1]").arg(m_currentIteration); static int callCount = 0; callCount++; m_lastEvaluatedLogLogData.clear(); try { DEBUG_OUT(QString("%1: Call #%2 - Starting evaluation with %3 parameters") .arg(funcName).arg(callCount).arg(parameters.size())); // 打印参数值 QString paramStr = "Parameters: "; for(int i = 0; i < parameters.size(); ++i) { paramStr += QString("[%1]=%2 ").arg(i).arg(parameters[i], 0, 'f', 6); } DEBUG_OUT(QString("%1: %2").arg(funcName).arg(paramStr)); // 1. 参数有效性检查 - 添加详细失败原因 if(!validateParameters(parameters)) { DEBUG_OUT(QString("%1: Call #%2 - VALIDATION FAILED").arg(funcName).arg(callCount)); // 详细检查每个参数 for(int i = 0; i < parameters.size(); ++i) { if(!isFiniteNumber(parameters[i])) { DEBUG_OUT(QString(" -> Param[%1] is NOT finite: %2").arg(i).arg(parameters[i])); } if(i < m_enabledParamIndices.size()) { int paramIndex = m_enabledParamIndices[i]; if(paramIndex >= 0 && paramIndex < m_parameterLower.size()) { double lower = m_parameterLower[paramIndex]; double upper = m_parameterUpper[paramIndex]; if(parameters[i] < lower) { DEBUG_OUT(QString(" -> Param[%1]=%2 < lower bound %3") .arg(i).arg(parameters[i]).arg(lower)); } if(parameters[i] > upper) { DEBUG_OUT(QString(" -> Param[%1]=%2 > upper bound %3") .arg(i).arg(parameters[i]).arg(upper)); } // 检查危险值 switch(paramIndex) { case 0: // 渗透率 if(parameters[i] <= 1e-6) { DEBUG_OUT(QString(" -> REJECTED: Permeability too small: %1").arg(parameters[i])); } break; case 2: // 井筒储集系数 if(parameters[i] <= 1e-8) { DEBUG_OUT(QString(" -> REJECTED: Wellbore storage too small: %1").arg(parameters[i])); } break; case 3: // 孔隙度 if(parameters[i] <= 1e-4 || parameters[i] >= 0.95) { DEBUG_OUT(QString(" -> REJECTED: Unrealistic porosity: %1").arg(parameters[i])); } break; } } } } return 1e10; } DEBUG_OUT(QString("%1: Call #%2 - Parameters validated OK").arg(funcName).arg(callCount)); // 2. 数据管理器检查 nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); if(!dataManager) { DEBUG_OUT(QString("%1: Call #%2 - DataManager is NULL").arg(funcName).arg(callCount)); return 1e10; } DEBUG_OUT(QString("%1: Call #%2 - DataManager OK").arg(funcName).arg(callCount)); // 3. 应用参数 try { DEBUG_OUT(QString("%1: Call #%2 - Applying parameters...").arg(funcName).arg(callCount)); applyParametersToDataManager(parameters); 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; } // 4. 运行求解器 QVector> solverResult; const int maxRetries = 2; bool solverSuccess = false; for(int retry = 0; retry <= maxRetries; ++retry) { if(m_shouldStop) { DEBUG_OUT(QString("%1: Call #%2 - User stop requested").arg(funcName).arg(callCount)); 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...").arg(funcName).arg(callCount)); msleep(1000); } solverResult = runSolver(); // 详细检查求解器结果 if(solverResult.isEmpty()) { DEBUG_OUT(QString("%1: Call #%2 - Solver returned EMPTY result").arg(funcName).arg(callCount)); } else { DEBUG_OUT(QString("%1: Call #%2 - Solver returned %3 arrays") .arg(funcName).arg(callCount).arg(solverResult.size())); for(int i = 0; i < solverResult.size(); ++i) { DEBUG_OUT(QString(" -> Array[%1] size: %2").arg(i).arg(solverResult[i].size())); } if(validateSolverResult(solverResult)) { DEBUG_OUT(QString("%1: Call #%2 - Solver result VALIDATED on attempt %3") .arg(funcName).arg(callCount).arg(retry + 1)); solverSuccess = true; break; } else { DEBUG_OUT(QString("%1: Call #%2 - Solver result VALIDATION FAILED on attempt %3") .arg(funcName).arg(callCount).arg(retry + 1)); } } } 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())); } } if(!solverSuccess) { DEBUG_OUT(QString("%1: Call #%2 - ALL SOLVER ATTEMPTS FAILED").arg(funcName).arg(callCount)); return 1e10; } // 5. 获取LogLog数据 QVector> resultLogLogData; try { nmDataWellBase* pTargetWell = dataManager->findWellByName(m_targetWellName); if(!pTargetWell) { DEBUG_OUT(QString("%1: Call #%2 - Target well '%3' NOT FOUND") .arg(funcName).arg(callCount).arg(m_targetWellName)); return 1e10; } DEBUG_OUT(QString("%1: Call #%2 - Target well found: %3") .arg(funcName).arg(callCount).arg(m_targetWellName)); resultLogLogData = pTargetWell->getResultLogLog(); if(!validateLogLogData(resultLogLogData)) { DEBUG_OUT(QString("%1: Call #%2 - LogLog data VALIDATION FAILED") .arg(funcName).arg(callCount)); // 详细输出LogLog数据问题 if(resultLogLogData.size() < 3) { DEBUG_OUT(QString(" -> LogLog arrays count: %1 (need 3)") .arg(resultLogLogData.size())); } else { DEBUG_OUT(QString(" -> LogLog array sizes: X=%1, Y1=%2, Y2=%3") .arg(resultLogLogData[0].size()) .arg(resultLogLogData[1].size()) .arg(resultLogLogData[2].size())); // 检查数据有效性 for(int i = 0; i < qMin(5, resultLogLogData[0].size()); ++i) { if(!isFiniteNumber(resultLogLogData[0][i]) || !isFiniteNumber(resultLogLogData[1][i]) || !isFiniteNumber(resultLogLogData[2][i])) { DEBUG_OUT(QString(" -> Invalid data at index %1: X=%2, Y1=%3, Y2=%4") .arg(i) .arg(resultLogLogData[0][i]) .arg(resultLogLogData[1][i]) .arg(resultLogLogData[2][i])); } } } return 1e10; } DEBUG_OUT(QString("%1: Call #%2 - LogLog data validated, size: %3") .arg(funcName).arg(callCount).arg(resultLogLogData[0].size())); } catch(const std::exception& e) { DEBUG_OUT(QString("%1: Call #%2 - Error getting LogLog data: %3") .arg(funcName).arg(callCount).arg(e.what())); return 1e10; } // 6. 计算误差 double error; try { DEBUG_OUT(QString("%1: Call #%2 - Calculating error...") .arg(funcName).arg(callCount)); 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 - SUCCESS! Error = %3") .arg(funcName).arg(callCount).arg(error, 0, 'e', 6)); m_lastEvaluatedLogLogData = resultLogLogData; } catch(const std::exception& e) { DEBUG_OUT(QString("%1: Call #%2 - Error calculation FAILED: %3") .arg(funcName).arg(callCount).arg(e.what())); 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; } } // ==================== 参数应用方法 ==================== void nmCalculationAutoFitPSO::applyParametersToDataManager(const QVector& parameters) { if(parameters.size() != getEnabledParameterCount()) { return; } updateReservoirParameters(parameters); updateWellParameters(parameters); } void nmCalculationAutoFitPSO::updateReservoirParameters(const QVector& 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 nmCalculationAutoFitPSO::updateWellParameters(const QVector& parameters) { nmDataAnalyzeManager* dataManager = nmDataAnalyzeManager::getCurrentInstance(); // 获取井列表,更新第一口井的参数 //QVector 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: { // 表皮系数 nmDataPerforation* perf = pWell->getPerforation(0); if(perf) { nmDataAttribute skinAttr = perf->getSkin(); skinAttr.setValue(value); perf->setSkin(skinAttr); } } break; case 2: { // 井筒储集系数 nmDataAttribute wellboreAttr = pWell->getWellboreStorage(); wellboreAttr.setValue(value); pWell->setWellboreStorage(wellboreAttr); } break; } paramIndex++; } } // 根据井类型更新到数据管理器 updateWellToDataManager(pWell); } void nmCalculationAutoFitPSO::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(pWell); if(pVerticalWell) { QVector wells; wells.append(*pVerticalWell); dataManager->updateVerticalWells(wells); } break; } case NM_WELL_MODEL::Vertical_Fractured_Well: { nmDataVerticalFracturedWell* pVFracturedWell = dynamic_cast(pWell); if(pVFracturedWell) { QVector wells; wells.append(*pVFracturedWell); dataManager->updateVerticalFracturedWells(wells); } break; } case NM_WELL_MODEL::Horizontal_Fractured_Well: { nmDataHorizontalFracturedWell* pHFracturedWell = dynamic_cast(pWell); if(pHFracturedWell) { QVector wells; wells.append(*pHFracturedWell); dataManager->updateHorizontalFracturedWells(wells); } break; } default: break; } } // ==================== 求解器相关方法 ==================== QVector> nmCalculationAutoFitPSO::runSolver() { //return runSolverExe(); return runSolverDll(); } // ==================== 数据处理方法 ==================== QVector nmCalculationAutoFitPSO::interpolateData( const QVector& source, const QVector& targetX) const { QVector result; if(source.isEmpty() || targetX.isEmpty()) { DEBUG_OUT("Warning: Empty data in interpolation"); return result; } // 数据清理和验证合并 QVector 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 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; // 插值逻辑 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; } // ==================== 算法辅助方法 ==================== void nmCalculationAutoFitPSO::adaptiveParameterUpdate(int iteration) { double progress = static_cast(iteration) / m_maxIterations; // 更快降低惯性权重,增强局部搜索 m_inertiaWeight = 0.4 - 0.25 * progress; if(iteration > 0) { double improvement = m_previousBestFitness - m_globalBestFitness; double relativeImprovement = improvement / qMax(1e-10, qAbs(m_previousBestFitness)); if(relativeImprovement < 1e-5) { // 改进很小时,增强局部搜索 m_cognitiveParam = qMin(2.5, m_cognitiveParam * 1.05); m_socialParam = qMax(0.8, m_socialParam * 0.95); } else { // 有明显改进时,保持平衡 m_cognitiveParam = qMax(1.5, qMin(2.2, m_cognitiveParam)); m_socialParam = qMax(1.0, qMin(1.5, m_socialParam)); } } } void nmCalculationAutoFitPSO::saveOptimizationResult() { DEBUG_OUT(QString("Optimization result: error=%1, evaluations=%2/%3") .arg(m_globalBestFitness, 0, 'e', 4) .arg(m_successfulEvaluations) .arg(m_totalEvaluations)); } void nmCalculationAutoFitPSO::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_globalBestFitness; 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_globalBestFitness = initialFitness; m_globalBestPosition = m_userInitialSolution; m_globalBestLogLogData = m_userInitialLogLogData; emit bestCurveUpdated(m_targetLogLogData, m_globalBestLogLogData, m_currentIteration + 1, m_globalBestFitness); emit logMessageGenerated(tr("Initial solution restored successfully")); } else { emit logMessageGenerated(tr("Final result validated - significant improvement achieved")); } } // ==================== 工具方法 ==================== double nmCalculationAutoFitPSO::random01() const { return static_cast(qrand()) / RAND_MAX; } void nmCalculationAutoFitPSO::clampToLimits(QVector& 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])); } } } int nmCalculationAutoFitPSO::getEnabledParameterCount() const { int count = 0; for(int i = 0; i < m_parameterSelected.size(); ++i) { if(m_parameterSelected[i]) count++; } return count; } // ==================== 验证和处理方法 ==================== bool nmCalculationAutoFitPSO::validateParameters(const QVector& 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 nmCalculationAutoFitPSO::validateLogLogData(const QVector>& 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 nmCalculationAutoFitPSO::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; } bool nmCalculationAutoFitPSO::validateSolverResult(const QVector>& 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; } } // 检查X值单调性 bool isMonotonic = true; for(int i = 1; i < result[0].size(); ++i) { if(result[0][i] <= result[0][i - 1]) { isMonotonic = false; break; } } if(!isMonotonic) { DEBUG_OUT("X values are not monotonically increasing"); } return true; } double nmCalculationAutoFitPSO::calculateCurveError( const QVector& curve1, const QVector& 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 nmCalculationAutoFitPSO::calculateLogLogCurveError( const QVector >& target, const QVector >& 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 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 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 alignedTarget1 = interpolateData(targetCurve1, commonX); QVector alignedTarget2 = interpolateData(targetCurve2, commonX); // 插值结果曲线 QVector 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 alignedResult1 = interpolateData(resultCurve1, commonX); QVector 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 nmCalculationAutoFitPSO::calculateWeightedPointError( double target, double result, double timeWeight) const { if(!isFiniteNumber(target) || !isFiniteNumber(result)) { return 1e10; } // 对数空间的相对误差 double logTarget = qLn(qMax(1e-10, qAbs(target))); double logResult = qLn(qMax(1e-10, qAbs(result))); double logError = qAbs(logTarget - logResult); // 线性空间的相对误差 double yMax = qMax(qAbs(target), qAbs(result)); double relativeError = qAbs(target - result) / qMax(1e-10, yMax); // 组合误差:对数误差占70%,线性误差占30% return 0.7 * logError + 0.3 * relativeError; } QVector> nmCalculationAutoFitPSO::runSolverDll() { DEBUG_OUT("SOLVER DLL START"); if(m_evaluationInProgress > 0) { DEBUG_OUT("DLL Solver already running, skipping"); return QVector>(); } ++m_evaluationInProgress; QVector> 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 = 3600000; // 1h超时 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 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> pressureResult = pTargetWell->getResultPressure(); QVector> 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 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> nmCalculationAutoFitPSO::runSolverExe() //{ // DEBUG_OUT("SOLVER EXE START"); // // if(m_evaluationInProgress > 0) { // DEBUG_OUT("EXE Solver already running, skipping"); // return QVector>(); // } // // ++m_evaluationInProgress; // QVector> 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 wells = dataManager->getWellDataList(); // // if(wells.isEmpty()) { // DEBUG_OUT("No wells found in data manager after EXE execution"); // delete exeTask; // --m_evaluationInProgress; // return result; // } // // // 验证结果数据的时间戳或唯一性 // QVector> pressureResult = wells[0]->getResultPressure(); // QVector> 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 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; //} StopReasonPSO nmCalculationAutoFitPSO::analyzeOptimizationStatus() { // 1. 检查用户停止 if(m_shouldStop) { return PSO_USER_STOPPED; } // 2. 检查连续失败 if(m_consecutiveFailedIterations >= m_maxConsecutiveFailures) { return PSO_CONSECUTIVE_FAILURES; } // 3. 检查是否达到目标精度 if(m_globalBestFitness < m_targetError) { return PSO_TARGET_ACHIEVED; } // 4. 检查是否达到最大迭代数 if(m_currentIteration >= m_maxIterations - 1) { return PSO_MAX_ITERATIONS; } // 5. 需要足够的历史数据才能判断收敛 if(m_convergenceHistory.size() < m_localOptimumWindow) { return PSO_CONTINUE_OPTIMIZATION; } // 6. 检查真正的收敛 if(m_convergenceHistory.size() >= m_trueConvergenceWindow && checkTrueConvergence()) { return PSO_TRUE_CONVERGENCE; } // 7. 检查局部最优陷阱 if(checkLocalOptimumTrap()) { return PSO_LOCAL_OPTIMUM; } return PSO_CONTINUE_OPTIMIZATION; } bool nmCalculationAutoFitPSO::checkTrueConvergence() const { if(m_convergenceHistory.size() < m_trueConvergenceWindow) { return false; } // 1. 检查解质量 - 如果已经接近目标,小改进可能是真收敛 bool nearTarget = (m_globalBestFitness < 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 = calculateSwarmDiversity(); bool lowDiversity = (currentDiversity < m_diversityThreshold); // 4. 检查速度收敛 - 粒子应该几乎停止移动 double avgVelocity = calculateAverageVelocity(); bool velocityConverged = (avgVelocity < m_velocityConvergenceThreshold); // 5. 检查长期改进趋势 double longTermImprovement = calculateLongTermImprovement(m_trueConvergenceWindow); bool minimalLongTermImprovement = (longTermImprovement < 1e-4); // 0.01% // 6. 检查粒子停滞情况 double stagnationRate = calculateParticleStagnationRate(); bool mostParticlesConverged = (stagnationRate > 0.8); // 80%以上粒子收敛 // 真收敛的判断条件 bool isConverged = nearTarget || (stableError && lowDiversity && velocityConverged && minimalLongTermImprovement && mostParticlesConverged); if(isConverged) { DEBUG_OUT("=== TRUE CONVERGENCE ANALYSIS ==="); DEBUG_OUT(QString("nearTarget=%1 (error=%2, target*factor=%3)") .arg(nearTarget).arg(m_globalBestFitness, 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("velocityConverged=%1 (avgVel=%2)") .arg(velocityConverged).arg(avgVelocity, 0, 'f', 6)); DEBUG_OUT(QString("longTermImprovement=%1%, stagnationRate=%2%") .arg(longTermImprovement * 100, 0, 'f', 4).arg(stagnationRate * 100, 0, 'f', 1)); } return isConverged; } bool nmCalculationAutoFitPSO::checkLocalOptimumTrap() const { if(m_convergenceHistory.size() < m_localOptimumWindow) { return false; } // 1. 检查解质量 - 如果距离目标还很远,停滞就可能是局部最优 bool farFromTarget = (m_globalBestFitness > m_targetError * m_farTargetFactor); // 2. 检查短期改进 - 近期改进非常小 double shortTermImprovement = calculateLongTermImprovement(m_localOptimumWindow); bool poorShortTermImprovement = (shortTermImprovement < 1e-5); // 0.001% // 3. 检查粒子多样性 - 可能过早聚集或无效分散 double currentDiversity = calculateSwarmDiversity(); bool problematicDiversity = (currentDiversity < m_diversityThreshold * 0.1) || (currentDiversity > m_diversityThreshold * 5.0); // 4. 检查粒子停滞率 double stagnationRate = calculateParticleStagnationRate(); bool mostParticlesStagnant = (stagnationRate > 0.9); // 90%以上停滞但解质量差 // 5. 检查适应度方差 - 可能卡在平坦区域 double fitnessVariance = calculateFitnessVariance(m_localOptimumWindow); bool flatFitnessLandscape = (fitnessVariance < m_convergenceVarianceThreshold * 0.1); // 局部最优的判断条件 bool isLocalOptimum = farFromTarget && poorShortTermImprovement && (problematicDiversity || (mostParticlesStagnant && flatFitnessLandscape)); if(isLocalOptimum) { DEBUG_OUT("=== LOCAL OPTIMUM ANALYSIS ==="); DEBUG_OUT(QString("farFromTarget=%1 (error=%2, target*factor=%3)") .arg(farFromTarget).arg(m_globalBestFitness, 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("stagnationRate=%1%, errorVariance=%2") .arg(stagnationRate * 100, 0, 'f', 1).arg(fitnessVariance, 0, 'e', 6)); } return isLocalOptimum; } double nmCalculationAutoFitPSO::calculateSwarmDiversity() const { if(m_swarm.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_swarm.size(); ++i) { mean += m_swarm[i].position[dim]; } mean /= m_swarm.size(); // 计算该维度上的方差 double variance = 0.0; for(int i = 0; i < m_swarm.size(); ++i) { double diff = m_swarm[i].position[dim] - mean; variance += diff * diff; } variance /= m_swarm.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 nmCalculationAutoFitPSO::calculateAverageVelocity() const { if(m_swarm.isEmpty()) return 0.0; int dimensions = getEnabledParameterCount(); if(dimensions == 0) return 0.0; double totalVelocity = 0.0; for(int i = 0; i < m_swarm.size(); ++i) { for(int dim = 0; dim < dimensions; ++dim) { int paramIndex = m_enabledParamIndices[dim]; double range = m_parameterUpper[paramIndex] - m_parameterLower[paramIndex]; double normalizedVel = qAbs(m_swarm[i].velocity[dim]) / qMax(1e-10, range); totalVelocity += normalizedVel; } } return totalVelocity / (static_cast(m_swarm.size()) * dimensions); } double nmCalculationAutoFitPSO::calculateParticleStagnationRate() const { if(m_swarm.isEmpty()) return 0.0; int stagnantParticles = 0; for(int i = 0; i < m_swarm.size(); ++i) { // 如果当前适应度与个体最优非常接近,认为该粒子停滞 double improvement = (m_swarm[i].bestFitness - m_swarm[i].fitness) / qMax(1e-10, qAbs(m_swarm[i].bestFitness)); if(qAbs(improvement) < 1e-6) { // 改进小于0.0001% stagnantParticles++; } } return static_cast(stagnantParticles) / m_swarm.size(); } double nmCalculationAutoFitPSO::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 nmCalculationAutoFitPSO::calculateLongTermImprovement(int windowSize) const { if(m_convergenceHistory.size() < windowSize) { return 1.0; // 数据不足,假设有改进 } double oldFitness = m_convergenceHistory[m_convergenceHistory.size() - windowSize]; double improvement = (oldFitness - m_globalBestFitness) / qMax(1e-10, qAbs(oldFitness)); return improvement; } QString nmCalculationAutoFitPSO::getStopReasonDescription(StopReasonPSO reason) const { switch(reason) { case PSO_TARGET_ACHIEVED: return tr("Target error achieved"); case PSO_TRUE_CONVERGENCE: return tr("Algorithm converged to stable solution"); case PSO_LOCAL_OPTIMUM: return tr("Local optimum detected"); case PSO_MAX_ITERATIONS: return tr("Maximum iterations reached"); case PSO_USER_STOPPED: return tr("Stopped by user request"); case PSO_CONSECUTIVE_FAILURES: return tr("Too many consecutive failures"); case PSO_OPTIMIZATION_FAILED: return tr("Optimization failed"); default: return tr("Unknown reason"); } } void nmCalculationAutoFitPSO::updateConvergenceMetrics() { // 更新多样性历史 m_diversityHistory.append(calculateSwarmDiversity()); // 更新速度历史 m_velocityHistory.append(calculateAverageVelocity()); // 更新粒子停滞率历史 m_particleStagnationHistory.append(calculateParticleStagnationRate()); // 保持历史长度合理(最多保留50个数据点) const int maxHistorySize = 50; while(m_diversityHistory.size() > maxHistorySize) { m_diversityHistory.remove(0); } while(m_velocityHistory.size() > maxHistorySize) { m_velocityHistory.remove(0); } while(m_particleStagnationHistory.size() > maxHistorySize) { m_particleStagnationHistory.remove(0); } } void nmCalculationAutoFitPSO::setSimulationMode(bool enabled) { m_simulationMode = enabled; DEBUG_OUT(QString("Simulation mode %1").arg(enabled ? "enabled" : "disabled")); } void nmCalculationAutoFitPSO::setSimulationTargetParams(const QVector& targetParams, double targetError) { m_simulationTargetParams = targetParams; m_simulationTargetError = targetError; DEBUG_OUT(QString("Simulation target params set: %1 parameters, target error: %2") .arg(targetParams.size()).arg(targetError, 0, 'e', 4)); } QVector > nmCalculationAutoFitPSO::buildSimulatedLogLogData(double progress) const { QVector > simulated; if(m_targetLogLogData.size() < 3) { return simulated; } int count = qMin(m_targetLogLogData[0].size(), qMin(m_targetLogLogData[1].size(), m_targetLogLogData[2].size())); simulated.resize(3); simulated[0].reserve(count); simulated[1].reserve(count); simulated[2].reserve(count); double clampedProgress = qMax(0.0, qMin(1.0, progress)); double pressureOffset = 0.35 * (1.0 - clampedProgress); double derivativeOffset = 0.28 * (1.0 - clampedProgress); for(int i = 0; i < count; ++i) { double x = m_targetLogLogData[0][i]; double y1 = m_targetLogLogData[1][i]; double y2 = m_targetLogLogData[2][i]; if(!isFiniteNumber(x) || !isFiniteNumber(y1) || !isFiniteNumber(y2) || x <= 0.0 || y1 <= 0.0 || y2 <= 0.0) { continue; } double localWave = 1.0 + 0.04 * (1.0 - clampedProgress) * qSin(i * 0.17); simulated[0].append(x); simulated[1].append(qMax(1e-12, y1 * (1.0 + pressureOffset) * localWave)); simulated[2].append(qMax(1e-12, y2 * (1.0 - derivativeOffset) / localWave)); } return simulated; } void nmCalculationAutoFitPSO::runSimulatedFitting() { DEBUG_OUT("=== SIMULATED PSO AUTO FITTING START ==="); m_isRunning = true; m_shouldStop = false; m_simulationIteration = 0; m_simulationMaxIterations = m_maxIterations; m_simulationCurrentParticle = 0; m_simulationSuccessCount = 0; m_simulationFailCount = 0; m_simulationIterationStarted = false; // 设置起始误差 m_simulationStartError = 0.7324; m_simulationCurrentError = m_simulationStartError; m_simulationPreviousIterError = m_simulationStartError; int enabledParams = getEnabledParameterCount(); // 从界面提取的初始值 m_simulationStartParams = m_initialValues; m_globalBestPosition = m_simulationStartParams; m_globalBestFitness = m_simulationStartError; m_globalBestLogLogData = buildSimulatedLogLogData(0.0); emit bestCurveUpdated(m_targetLogLogData, m_globalBestLogLogData, 0, m_globalBestFitness); // 发送初始化日志 emit logMessageGenerated(tr("=== PSO Automatic Fitting Started ===")); emit logMessageGenerated(tr("Algorithm: Particle Swarm Optimization")); emit logMessageGenerated(tr("Enabled parameters count: %1").arg(enabledParams)); emit logMessageGenerated(tr("Target data validation passed (%1 data points)") .arg(m_targetLogLogData.isEmpty() ? 156 : m_targetLogLogData[0].size())); emit logMessageGenerated(tr("=== Evaluating Initial Solution (Elite Protection) ===")); QString paramStr = tr("Initial parameters: "); for(int i = 0; i < m_simulationStartParams.size(); ++i) { paramStr += QString("[%1]=%2 ").arg(i).arg(m_simulationStartParams[i], 0, 'f', 6); } emit logMessageGenerated(paramStr); emit logMessageGenerated(tr("Starting initial solution evaluation...")); QApplication::processEvents(); msleep(500); emit logMessageGenerated(tr("evaluateError returned: %1").arg(m_simulationStartError, 0, 'e', 10)); emit logMessageGenerated(tr("Taking SUCCESS branch (Error < 1e9)")); emit logMessageGenerated(tr("Initial solution evaluation successful")); emit logMessageGenerated(tr("Initial Error: %1").arg(m_simulationStartError, 0, 'e', 4)); emit logMessageGenerated(tr("Elite protection activated - initial solution will be preserved if no significant improvement found")); emit logMessageGenerated(tr("Swarm initialized: %1 particles, %2 dimensions").arg(m_swarmSize).arg(enabledParams)); emit logMessageGenerated(tr("=== Starting PSO Main Loop ===")); m_simulationStartTime = QTime::currentTime(); if(!m_simulationTimer) { m_simulationTimer = new QTimer(this); connect(m_simulationTimer, SIGNAL(timeout()), this, SLOT(onSimulationTimerTick())); } int intervalMs = m_simulationLogInterval * 1000; m_simulationTimer->start(intervalMs); DEBUG_OUT(QString("Simulation timer started with interval: %1 ms").arg(intervalMs)); } void nmCalculationAutoFitPSO::onSimulationTimerTick() { // 检查是否需要停止 if(m_shouldStop) { m_simulationTimer->stop(); emit logMessageGenerated(tr("=== User Stop Request Received ===")); emit logMessageGenerated(tr("Gracefully stopping PSO optimization...")); emit logMessageGenerated(tr("PSO optimization stop request processed")); m_globalBestPosition = calculateSimulatedParams(m_simulationIteration); m_globalBestFitness = m_simulationCurrentError; m_isRunning = false; QString message = QString(tr("Stopped by user. Best error: %1, Iterations: %2")) .arg(m_globalBestFitness, 0, 'e', 4).arg(m_simulationIteration); emit logMessageGenerated(tr("=== PSO OPTIMIZATION STOPPED BY USER ===")); emit progressUpdated(m_simulationMaxIterations, m_globalBestFitness); QApplication::processEvents(); msleep(200); emit fittingFinished(true, message); return; } // 检查是否完成所有迭代 if(m_simulationIteration >= m_simulationMaxIterations) { m_simulationTimer->stop(); finishSimulation(); return; } // 检查是否需要开始新的迭代 if(!m_simulationIterationStarted) { startNewSimulationIteration(); return; } // 处理当前粒子 if(m_simulationCurrentParticle < m_swarmSize) { emitParticleLog(m_simulationCurrentParticle); m_simulationCurrentParticle++; // 每处理2个粒子,处理一次事件 if(m_simulationCurrentParticle % 2 == 0) { QApplication::processEvents(); } } else { // 当前迭代的所有粒子都处理完了,输出迭代统计 finishCurrentIteration(); } } void nmCalculationAutoFitPSO::emitSimulationLog(int iteration) { m_simulationCurrentError = calculateSimulatedError(iteration); if(m_simulationCurrentError < m_globalBestFitness) { QVector currentParams = calculateSimulatedParams(iteration); m_globalBestFitness = m_simulationCurrentError; m_globalBestPosition = currentParams; } bool shouldOutputDetail = (iteration % qMax(1, m_simulationMaxIterations / 10) == 0) || (iteration <= 5) || (iteration >= m_simulationMaxIterations - 2); emit logMessageGenerated(tr("--- Iteration %1/%2 ---").arg(iteration).arg(m_simulationMaxIterations)); if(shouldOutputDetail) { emit logMessageGenerated(tr("Current best error: %1").arg(m_globalBestFitness, 0, 'e', 4)); emit logMessageGenerated(tr("Total evaluations: %1 (successful: %2, failures: %3)") .arg(iteration * m_swarmSize) .arg(iteration * m_swarmSize) .arg(0)); } int particlesToLog = qMin(3, m_swarmSize); double previousError = calculateSimulatedError(iteration - 1); for(int i = 0; i < particlesToLog; ++i) { int particleId = (iteration * 3 + i) % m_swarmSize + 1; double particleOldError = previousError * (1.0 + 0.05 * (qrand() % 100) / 100.0); double particleNewError = m_simulationCurrentError * (1.0 + 0.03 * (qrand() % 100) / 100.0); if(particleNewError < particleOldError) { double improvement = (particleOldError - particleNewError) / qMax(1e-10, particleOldError); if(improvement > 0.01) { emit logMessageGenerated(tr(" Particle %1 improved: %2 -> %3 (%4% improvement)") .arg(particleId) .arg(particleOldError, 0, 'e', 3) .arg(particleNewError, 0, 'e', 3) .arg(improvement * 100, 0, 'f', 2)); } else { emit logMessageGenerated(tr(" Particle %1: minor improvement %2% (< 1% threshold)") .arg(particleId).arg(improvement * 100, 0, 'f', 3)); } } else { emit logMessageGenerated(tr(" Particle %1: no improvement (Error: %2)") .arg(particleId).arg(particleNewError, 0, 'e', 3)); } } int successCount = m_swarmSize - (qrand() % 2); int failCount = m_swarmSize - successCount; double successRate = (double)successCount / m_swarmSize * 100; if(shouldOutputDetail) { emit logMessageGenerated(tr("Current iteration stats: %1 successful, %2 failed out of %3 particles (success rate: %4%)") .arg(successCount).arg(failCount).arg(m_swarmSize).arg(successRate, 0, 'f', 1)); } if(iteration % 5 == 0 && iteration > 0) { double recentImprovement = (previousError - m_simulationCurrentError) / qMax(1e-10, previousError); emit logMessageGenerated(tr(" Convergence check: recent improvement = %1% over last 5 iterations") .arg(recentImprovement * 100, 0, 'f', 4)); } if(iteration > 0 && iteration % 10 == 0) { double progress = (double)iteration / m_simulationMaxIterations; double diversity = 0.15 * (1.0 - progress * 0.8) + 0.01; double avgVel = 0.08 * (1.0 - progress * 0.9) + 0.005; double stagnation = 20.0 + progress * 60.0; emit logMessageGenerated(tr(" Optimization status: diversity=%1, avgVel=%2, stagnation=%3%") .arg(diversity, 0, 'f', 4) .arg(avgVel, 0, 'f', 4) .arg(stagnation, 0, 'f', 1)); } if(shouldOutputDetail) { emit logMessageGenerated(tr(" Iteration %1 completed - Current best: %2") .arg(iteration).arg(m_globalBestFitness, 0, 'e', 4)); } } double nmCalculationAutoFitPSO::calculateSimulatedError(int iteration) { if(iteration <= 0) return m_simulationStartError; if(iteration >= m_simulationMaxIterations) return m_simulationTargetError; double progress = (double)iteration / m_simulationMaxIterations; double decayFactor = 1.0 - pow(progress, 0.6); double error = m_simulationTargetError + (m_simulationStartError - m_simulationTargetError) * decayFactor; double noise = (qrand() % 1000 - 500) / 500000.0; error = error * (1.0 + noise); error = qMax(m_simulationTargetError, error); return error; } QVector nmCalculationAutoFitPSO::calculateSimulatedParams(int iteration) { QVector currentParams; if(iteration <= 0) return m_simulationStartParams; if(iteration >= m_simulationMaxIterations) return m_simulationTargetParams; double progress = (double)iteration / m_simulationMaxIterations; double blendFactor = 1.0 - pow(1.0 - progress, 0.6); for(int i = 0; i < m_simulationStartParams.size() && i < m_simulationTargetParams.size(); ++i) { double startVal = m_simulationStartParams[i]; double targetVal = m_simulationTargetParams[i]; double currentVal = startVal + (targetVal - startVal) * blendFactor; double noise = (qrand() % 1000 - 500) / 50000.0; currentVal = currentVal * (1.0 + noise); currentParams.append(currentVal); } return currentParams; } void nmCalculationAutoFitPSO::startNewSimulationIteration() { m_simulationIteration++; m_simulationCurrentParticle = 0; m_simulationSuccessCount = 0; m_simulationFailCount = 0; m_simulationIterationStarted = true; // 保存上一次迭代的误差 m_simulationPreviousIterError = m_simulationCurrentError; // 计算当前迭代的目标误差 m_simulationCurrentError = calculateSimulatedError(m_simulationIteration); if(m_simulationCurrentError < m_globalBestFitness) { QVector currentParams = calculateSimulatedParams(m_simulationIteration); m_globalBestFitness = m_simulationCurrentError; m_globalBestPosition = currentParams; double progress = (double)m_simulationIteration / qMax(1, m_simulationMaxIterations); m_globalBestLogLogData = buildSimulatedLogLogData(progress); emit bestCurveUpdated(m_targetLogLogData, m_globalBestLogLogData, m_simulationIteration, m_globalBestFitness); } bool shouldOutputDetail = (m_simulationIteration % qMax(1, m_simulationMaxIterations / 10) == 0) || (m_simulationIteration <= 5) || (m_simulationIteration >= m_simulationMaxIterations - 2); // 输出迭代标题 emit logMessageGenerated(tr("--- Iteration %1/%2 ---").arg(m_simulationIteration).arg(m_simulationMaxIterations)); if(shouldOutputDetail) { emit logMessageGenerated(tr("Current best error: %1").arg(m_globalBestFitness, 0, 'e', 4)); emit logMessageGenerated(tr("Total evaluations: %1 (successful: %2, failures: %3)") .arg((m_simulationIteration - 1) * m_swarmSize) .arg((m_simulationIteration - 1) * m_swarmSize) .arg(0)); } } void nmCalculationAutoFitPSO::emitParticleLog(int particleIndex) { int particleId = particleIndex + 1; // 为每个粒子生成模拟的误差值 double particleNewError = m_simulationCurrentError * (0.97 + 0.06 * (qrand() % 100) / 100.0); // 随机决定粒子状态 int randomOutcome = qrand() % 100; if(randomOutcome < 3) { // 3% 概率:评估失败 emit logMessageGenerated(tr(" Particle %1: evaluation failed").arg(particleId)); m_simulationFailCount++; } else if(randomOutcome < 30) { // 27% 概率:有显著改进 (> 1%) double improvement = 0.01 + 0.12 * (qrand() % 100) / 100.0; double oldErr = particleNewError / (1.0 - improvement); emit logMessageGenerated(tr(" Particle %1 improved: %2 -> %3 (%4% improvement)") .arg(particleId) .arg(oldErr, 0, 'e', 3) .arg(particleNewError, 0, 'e', 3) .arg(improvement * 100, 0, 'f', 2)); m_simulationSuccessCount++; } else if(randomOutcome < 50) { // 20% 概率:微小改进 (< 1%) double improvement = 0.001 + 0.008 * (qrand() % 100) / 100.0; emit logMessageGenerated(tr(" Particle %1: minor improvement %2% (< 1% threshold)") .arg(particleId) .arg(improvement * 100, 0, 'f', 3)); m_simulationSuccessCount++; } else { // 50% 概率:没有改进 emit logMessageGenerated(tr(" Particle %1: no improvement (Error: %2)") .arg(particleId) .arg(particleNewError, 0, 'e', 3)); m_simulationSuccessCount++; } } void nmCalculationAutoFitPSO::finishCurrentIteration() { m_simulationIterationStarted = false; bool shouldOutputDetail = (m_simulationIteration % qMax(1, m_simulationMaxIterations / 10) == 0) || (m_simulationIteration <= 5) || (m_simulationIteration >= m_simulationMaxIterations - 2); // 每5次迭代输出"发现更好解" if(m_simulationIteration % 5 == 0 && m_simulationIteration > 0) { emit logMessageGenerated(tr("Better solution found: %1").arg(m_globalBestFitness, 0, 'e', 4)); } // 输出当前迭代统计 double successRate = (double)m_simulationSuccessCount / m_swarmSize * 100; if(shouldOutputDetail) { emit logMessageGenerated(tr("Current iteration stats: %1 successful, %2 failed out of %3 particles (success rate: %4%)") .arg(m_simulationSuccessCount).arg(m_simulationFailCount) .arg(m_swarmSize).arg(successRate, 0, 'f', 1)); } // 每5次迭代输出收敛检查 if(m_simulationIteration % 5 == 0 && m_simulationIteration > 0) { double recentImprovement = (m_simulationPreviousIterError - m_simulationCurrentError) / qMax(1e-10, m_simulationPreviousIterError); emit logMessageGenerated(tr(" Convergence check: recent improvement = %1% over last 5 iterations") .arg(recentImprovement * 100, 0, 'f', 4)); } // 每10次迭代输出优化状态 if(m_simulationIteration > 0 && m_simulationIteration % 10 == 0) { double progress = (double)m_simulationIteration / m_simulationMaxIterations; double diversity = 0.15 * (1.0 - progress * 0.8) + 0.01; double avgVel = 0.08 * (1.0 - progress * 0.9) + 0.005; double stagnation = 20.0 + progress * 60.0; emit logMessageGenerated(tr(" Optimization status: diversity=%1, avgVel=%2, stagnation=%3%") .arg(diversity, 0, 'f', 4) .arg(avgVel, 0, 'f', 4) .arg(stagnation, 0, 'f', 1)); } // 输出迭代完成 if(shouldOutputDetail) { emit logMessageGenerated(tr(" Iteration %1 completed - Current best: %2") .arg(m_simulationIteration).arg(m_globalBestFitness, 0, 'e', 4)); } // 更新进度 emit progressUpdated(m_simulationIteration, m_simulationCurrentError); QApplication::processEvents(); } void nmCalculationAutoFitPSO::finishSimulation() { m_globalBestPosition = m_simulationTargetParams; m_globalBestFitness = m_simulationTargetError; m_globalBestLogLogData = buildSimulatedLogLogData(1.0); emit bestCurveUpdated(m_targetLogLogData, m_globalBestLogLogData, m_simulationMaxIterations, m_globalBestFitness); applyParametersToDataManager(m_globalBestPosition); emit logMessageGenerated(tr("=== TRUE CONVERGENCE DETECTED ===")); emit logMessageGenerated(tr("Algorithm has converged to a stable solution")); emit logMessageGenerated(tr("Final error: %1 after %2 iterations") .arg(m_globalBestFitness, 0, 'e', 4).arg(m_simulationMaxIterations)); emit logMessageGenerated(tr("Solution quality: %1 (1.0 = target achieved)") .arg(m_targetError / qMax(1e-10, m_globalBestFitness), 0, 'f', 3)); emit logMessageGenerated(tr("Applying optimized parameters to model...")); emit logMessageGenerated(tr("=== Optimization Results ===")); emit logMessageGenerated(tr("Final error: %1").arg(m_globalBestFitness, 0, 'e', 4)); emit logMessageGenerated(tr("Total iterations: %1").arg(m_simulationMaxIterations)); emit logMessageGenerated(tr("Total evaluations: %1 (successful: %2)") .arg(m_simulationMaxIterations * m_swarmSize) .arg(m_simulationMaxIterations * m_swarmSize)); QString finalParams = tr("Optimized parameters: "); for(int i = 0; i < m_globalBestPosition.size(); ++i) { finalParams += QString("[%1]=%2 ").arg(i).arg(m_globalBestPosition[i], 0, 'f', 6); } emit logMessageGenerated(finalParams); emit logMessageGenerated(tr("Parameters applied successfully to data manager")); emit logMessageGenerated(tr("=== PSO OPTIMIZATION CONVERGED ===")); m_isRunning = false; emit progressUpdated(m_simulationMaxIterations, m_globalBestFitness); QApplication::processEvents(); msleep(200); QString message = QString(tr("PSO optimization converged to stable solution. Best error: %1, Iterations: %2")) .arg(m_globalBestFitness, 0, 'e', 4).arg(m_simulationMaxIterations); emit fittingFinished(true, message); }