#ifndef NMCALCULATIONDLLPEBISOLVERTASK_H #define NMCALCULATIONDLLPEBISOLVERTASK_H #include #include #include #include #include #include #include #include #include #include #include "nmCalculationDefine.h" #include "nmCalculation_global.h" #include "pch.h" class nmDataAnalyzeManager; class nmPebiResultSnapshot; class vtkDoubleArray; struct nmPebiSolverInputSnapshot; struct nmPebiManualCaptureState; // 主窗口现在直接创建DLL求解线程任务,因此类需要导出,供nmSubWnd模块跨DLL使用。 class NMCALCULATION_EXPORT nmCalculationDllPebiSolverTask : public QThread { Q_OBJECT public: /** * @brief 创建绑定到指定分析窗口的 PEBI 求解任务。 * @param sPostprocessingDir 后处理文件输出目录。 * @param pDataManager 任务所属数据管理器,不转移所有权。 * @param sAutoFitTargetWellName 自动拟合目标井名;空值表示完整成果计算。 * @param parent Qt 父对象。 * @param bDeferManualSnapshot 手工求解是否由界面事件循环分批捕获输入。 */ nmCalculationDllPebiSolverTask(QString sPostprocessingDir, nmDataAnalyzeManager* pDataManager = nullptr, const QString& sAutoFitTargetWellName = QString(), QObject *parent = nullptr, bool bDeferManualSnapshot = false); ~nmCalculationDllPebiSolverTask(); /** @brief QThread 入口,记录本次 execute() 的成功状态并发送完成信号。 */ void run(); // PSO 等待线程结束后通过该接口判断本次结果是否可以继续参与误差计算. // 返回 false 时调用方会丢弃本次结果, 防止复用上一粒子留下的旧曲线. bool wasSuccessful() const; /** @brief 获取本次DLL内部求解耗时,单位为毫秒。 */ int getSolveTimeMs() const; /** @brief 获取本次求解的PEBI网格数量。 */ int getPebiCount() const; /** @brief 返回当前代码已识别的失败原因;成功或主动停止时为空。 */ QString getFailureReason() const; /** @brief 请求协作式停止;DLL 正在执行时会在返回后丢弃结果。 */ void requestCancel(); /** @brief 返回本次任务是否因手工停止而结束。 */ bool wasCancelled() const; /** @brief 返回任务启动后网格或求解输入是否已经变化。 */ bool hasInputChanged(nmDataAnalyzeManager* pDataManager) const; /** * @brief 在 DataManager 所属线程分批捕获手工求解输入。 * @param nMaxWellCount 本次最多捕获的真实井数量。 * @param bFinished 全部值快照完成时置为 true,随后才允许 start()。 */ bool captureManualInputStep(int nMaxWellCount, bool& bFinished); /** * @brief 在主线程一次性提交已经完整校验的求解结果。 * @param pDataManager 启动任务时绑定的数据管理器,必须仍然存活且版本一致。 * @return 全部结果提交成功返回 true;自动拟合任务和过期任务返回 false。 */ bool commitResult(nmDataAnalyzeManager* pDataManager); /** @brief 返回自动拟合目标井的原始压力结果副本。 */ QVector > getAutoFitResultPressure() const; /** @brief 返回自动拟合目标井的双对数结果副本。 */ QVector > getAutoFitResultLogLog() const; /** @brief 返回自动拟合目标井的半对数结果副本。 */ QVector > getAutoFitResultSemiLog() const; private: /** @brief 执行当前唯一的 PEBI 求解模式。 */ bool execute(); /** @brief 成对释放构造时登记的 DataManager 后台使用权。 */ void releaseDataManagerUse(); /** @brief 丢弃正式结果候选及任务侧全部 VTK 可写别名,不影响旧快照。 */ void discardPendingFullResult(); /** @brief 同步路径在任务创建线程一次性捕获全部求解输入。 */ bool captureInputSnapshot(const QString& sAutoFitTargetWellName); /** @brief 手工求解在线程内完成场景、缓存和 VTK 基础网格准备。 */ bool prepareManualInput(); /** @brief 无锁读取原子停止标记。 */ bool isCancelRequested() const; /** @brief 仅为手工求解报告真实执行阶段。 */ void reportStage(const QString& sStage, int nCurrent, int nTotal); /** @brief 记录首个已识别的失败原因并统一返回 false。 */ bool fail(const QString& sFailureReason); /** @brief 构造 DLL 输入、执行求解并生成仍然有效的局部结果快照。 */ bool execPebiMode(); /** @brief 按求解器井顺序组装压力、曲线和场结果快照,不修改 DataManager。 */ bool buildPebiModeResult(HX_NWTM_MODEL_OUTPUT& p1, int nModelType, const HX_NWTM_GRID_OUTPUT1& oGridOutput); /** @brief 用任务局部输出构造并封闭完整结果候选,不访问实时数据对象。 */ bool buildPebiResultSnapshotCandidate(); /** @brief 输出精简版 DLL 输入日志,用于定位求解异常。 */ void logHX_NWTM_MODEL_INPUT_Simplified(const HX_NWTM_MODEL_INPUT& p0); /** @brief 将完整 DLL 输入保存到文本文件,成功时返回 true。 */ bool saveHX_NWTM_MODEL_INPUT_ToTxt(const HX_NWTM_MODEL_INPUT& p0, const QString& filePath); private: /** @brief 一口真实井在本次求解中完整生成的待提交结果。 */ struct nmPebiWellResultSnapshot { QString m_sWellCode; ///< 稳定井编码。 QVector > m_vecPressure; ///< 时间和井底压力。 QVector > m_vecLogLog; ///< 时间、压差及导数。 QVector > m_vecSemiLog; ///< 时间和半对数压力。 }; QString m_sPostprocessingDir; ///< 本次求解使用的后处理输出目录。 /** @brief 创建任务时捕获所属数据中心,工作线程不得读取全局当前窗口。 */ nmDataAnalyzeManager* m_pDataManager; /** @brief 任务独占的完整值快照;析构时释放,后台禁止访问 DataManager。 */ nmPebiSolverInputSnapshot* m_pInputSnapshot; /** @brief 仅在界面线程分批捕获期间持有井对象,线程启动前必须释放。 */ nmPebiManualCaptureState* m_pManualCaptureState; bool m_bManagerUseActive; ///< 是否仍持有 DataManager 后台使用权。 bool m_bInputSnapshotValid; ///< 构造阶段是否已完成全部输入校验。 /** @brief 创建任务时捕获网格输入版本,防止回填过期网格上的结果。 */ quint64 m_nGridInputRevision; /** @brief 创建任务时捕获求解输入版本,防止角色或参数变化后回填旧结果。 */ quint64 m_nResultInputRevision; bool m_lastRunSucceeded; ///< run() 保存的执行状态,供等待线程安全读取。 /** @brief 本次DLL内部求解耗时,单位为毫秒。 */ int m_nSolveTimeMs; /** @brief 本次求解的PEBI网格数量。 */ int m_nPebiCount; QString m_sFailureReason; ///< 当前代码已识别的首个失败原因。 QString m_sAutoFitTargetWellCode; ///< 自动拟合目标井 WellCode;空值表示保存完整结果。 QVector > m_autoFitResultPressure; ///< 目标井原始压力结果。 QVector > m_autoFitResultLogLog; ///< 目标井双对数结果。 QVector > m_autoFitResultSemiLog; ///< 目标井半对数结果。 QVector m_vecPendingWellResults; ///< 完整求解的井结果快照。 QMap > m_mapPendingTimeSteps; ///< 场压力时间步快照。 /** @brief 工作线程已经完整校验、等待主线程发布的可写候选引用。 */ QSharedPointer m_pPendingResultSnapshot; double m_dPendingScalarMin; ///< 全部场压力的最小值。 double m_dPendingScalarMax; ///< 全部场压力的最大值。 bool m_bPendingFullResultReady; ///< 是否已有可由主线程一次提交的完整结果。 QAtomicInt m_nCancelRequested; ///< 跨线程协作式停止标记,1 表示请求停止。 QAtomicInt m_nWasCancelled; ///< run() 已按停止请求丢弃本次局部结果。 private slots: //void slotTaskUpdateProgress(); signals: void sig_calculateDone(bool isSuccessed); /** @brief 报告当前真实阶段;nTotal<=0 表示 DLL 等不可测阶段。 */ void sigStageChanged(QString sStage, int nCurrent, int nTotal); //void sigTaskProgressUpdated(int progress); //void sigResSolverProgressUpdated(int progress); }; #endif // NMCALCULATIONDLLPEBISOLVERTASK_H