#ifndef NMDATANUMERICALANALYSISCASE_H #define NMDATANUMERICALANALYSISCASE_H #include "nmData_global.h" #include "nmDefines.h" #include #include #include /** * @brief 井在当前数值分析方案中的计算角色。 * * PEBI 求解器本身不区分“测试井”和“干扰井”,但构造产量输入和 * 后处理曲线时必须明确井是否提供源汇项。因此这里把角色定义在 * 数值分析方案中,而不是写入井的永久属性。 */ enum NM_CASE_WELL_MODE { NM_CaseWell_RateControlled = 1, ///< 有生产或注入制度,参与改变压力场。 NM_CaseWell_Observation = 2 ///< 无产量制度,只接收并保存井底压力。 }; /** * @brief 当前分析方案中的一口真实井。 */ struct NM_DATA_EXPORT nmCalculationWellRef { /** @brief 构造空井引用,默认角色为无源汇项观察井。 */ nmCalculationWellRef(); /** @brief 使用稳定井编码和本次分析角色构造井引用。 */ nmCalculationWellRef(const QString& sWellCode, NM_CASE_WELL_MODE eMode); QString m_sWellCode; ///< 项目内唯一井编码,所有持久化关联均使用该字段。 NM_CASE_WELL_MODE m_eMode; ///< 当前方案中的计算角色。 }; /** * @brief 求解器数组中的条目类型。 * * 手工裂缝在旧流程中使用“未知井 + 空井名”占位。显式区分条目类型后, * 可以继续保持 DLL 数组下标对齐,同时不再伪装成一口井。 */ enum NM_SOLVER_ENTRY_KIND { NM_SolverEntry_Well = 1, ///< 真实井,占用一组 Rate/CS/pw 数组槽位。 NM_SolverEntry_ManualFracture = 2 ///< Map 手工裂缝,仅用于保持 DLL 下标对齐。 }; /** * @brief PEBI 网格输出确定的求解器井顺序。 */ struct NM_DATA_EXPORT nmSolverWellRef { /** @brief 构造尚未分配求解器下标的真实井条目。 */ nmSolverWellRef(); /** @brief 构造网格输出中的求解器槽位描述。 */ nmSolverWellRef(int nSolverIndex, NM_WELL_MODEL eWellType, const QString& sWellCode, NM_SOLVER_ENTRY_KIND eEntryKind = NM_SolverEntry_Well); int m_nSolverIndex; ///< 对应 Rate[i] 和 pw[i] 的固定下标。 NM_WELL_MODEL m_eWellType; ///< 真实井的几何模型类型。 QString m_sWellCode; ///< 真实井编码;手工裂缝条目为空。 NM_SOLVER_ENTRY_KIND m_eEntryKind; ///< 真实井或手工裂缝占位。 }; /** * @brief 一次数值分析从选井到结果展示所需的独立状态。 * * 该类不拥有井对象,也不保存井名称。Map 负责“项目中有什么”,本类保存 * 主井和手工包含的有产量井;数据管理层再自动加入 Map 中的无产量观察井。 */ class NM_DATA_EXPORT nmDataNumericalAnalysisCase { public: /** @brief 建立空分析方案,并初始化网格与结果版本号。 */ nmDataNumericalAnalysisCase(); /** @brief 返回主分析井的项目唯一 WellCode。 */ QString getPrimaryWellCode() const; /** @brief 设置主分析井;同时移除包含列表中的同井项并使网格失效。 */ void setPrimaryWellCode(const QString& sWellCode); /** @brief 返回主分析井在本次方案中的主动井或观察井角色。 */ NM_CASE_WELL_MODE getPrimaryWellMode() const; /** @brief 设置主井角色;角色只影响源汇输入,因此仅使结果失效。 */ void setPrimaryWellMode(NM_CASE_WELL_MODE eMode); /** @brief 返回是否启用手工选择的其他有产量井。 */ bool getIncludeOtherWells() const; /** @brief 启停其他有产量井;Map 无产量井不受该开关影响。 */ void setIncludeOtherWells(bool bInclude); /** @brief 返回当前方案的 PEBI 网格疏密控制值。 */ double getPebiGridControl() const; /** @brief 设置正数网格控制值;实际变化时使网格和结果失效。 */ void setPebiGridControl(double dGridControl); /** @brief 返回已保存的其他有产量井选择,关闭总开关时选择仍保留。 */ QVector getIncludedWells() const; /** @brief 保存其他有产量井,并按 WellCode 去空、去主井和去重。 */ void setIncludedWells(const QVector& vecWells); /** @brief 判断 WellCode 是否存在于已保存的包含井列表。 */ bool isIncludedWell(const QString& sWellCode) const; /** @brief 查询主井或显式包含井的方案角色,未配置井返回观察井角色。 */ NM_CASE_WELL_MODE getWellMode(const QString& sWellCode) const; /** @brief 返回方案显式选择的井;Map 观察井由数据管理层自动补充。 */ QVector getEffectiveWells() const; /** @brief 返回界面当前查看结果的井编码。 */ QString getCurrentResultWellCode() const; /** @brief 切换结果查看井;不改变主井、网格或已计算结果。 */ void setCurrentResultWellCode(const QString& sWellCode); /** @brief 返回网格生成后确定的 DLL 井槽位顺序。 */ QVector getSolverWellOrder() const; /** @brief 清空求解器顺序,并将已建网格和结果标记为无效。 */ void clearSolverWellOrder(); /** @brief 在末尾追加槽位,并自动写入连续求解器下标。 */ void appendSolverWell(const nmSolverWellRef& oWellRef); /** @brief 在指定下标插入槽位,并重新编号后续全部条目。 */ void insertSolverWell(int nIndex, const nmSolverWellRef& oWellRef); /** @brief 删除指定槽位并重新编号;下标非法时返回 false。 */ bool removeSolverWell(int nIndex); /** @brief 整体替换求解器顺序,并按容器顺序重新编号。 */ void setSolverWellOrder(const QVector& vecOrder); /** @brief 返回最后一次成功求解所使用的 DLL 井槽位顺序。 */ QVector getResultSolverWellOrder() const; /** @brief 返回最后一次成功求解时冻结的结果下拉框井编码。 */ QStringList getResultSelectableWellCodes() const; /** @brief 从成果文件恢复结果存在状态、当前性和独立井顺序。 */ void restoreResultState(const QVector& vecOrder, bool bAvailable, bool bCurrent); /** @brief 从成果文件同时恢复冻结的结果下拉框井编码。 */ void restoreResultState(const QVector& vecOrder, const QStringList& listSelectableWellCodes, bool bAvailable, bool bCurrent); /** @brief 选井或几何输入改变后,使当前网格和结果失效。 */ void invalidateGrid(); /** @brief 产量、PVT 等只影响求解的输入改变后,仅使结果失效。 */ void invalidateResults(); /** @brief 网格成功生成后记录当前输入版本。 */ void markGridBuilt(); /** @brief 仅当网格生成期间几何输入未变化时提交网格。 */ bool markGridBuiltIfCurrent(quint64 nGridInputRevision); /** @brief 丢弃旧结果,但不改变输入版本号。 */ void discardResults(); /** @brief 求解成功并完成结果映射后记录结果有效。 */ void markResultsAvailable(); /** @brief 仅当任务启动后的网格和求解输入均未变化时提交结果。 */ bool markResultsAvailableIfCurrent(quint64 nGridInputRevision, quint64 nResultInputRevision); /** @brief 当前网格版本与几何输入一致且井顺序非空时返回 true。 */ bool isGridValid() const; /** @brief 内存中存在一套可保存和查看的完整求解结果时返回 true。 */ bool hasResults() const; /** @brief 已有结果仍对应当前输入时返回 true。 */ bool areResultsCurrent() const; /** @brief 当前结果已提交且所依赖网格仍有效时返回 true。 */ bool areResultsValid() const; /** @brief 返回最新几何/选井输入版本,供后台任务启动时捕获。 */ quint64 getGridInputRevision() const; /** @brief 返回当前缓存网格对应的输入版本,0 表示没有有效网格。 */ quint64 getBuiltGridRevision() const; /** @brief 返回最新产量/PVT等求解输入版本,供后台任务启动时捕获。 */ quint64 getResultInputRevision() const; /** * @brief 从 v3 成果恢复三个输入版本号。 * @note 当前网格版本只能为 0 或等于网格输入版本。 */ bool restoreInputRevisions(quint64 nGridInputRevision, quint64 nBuiltGridRevision, quint64 nResultInputRevision); /** @brief 清空方案状态,用于重新加载项目。 */ void clear(); private: /** @brief 规范化有产量包含井,移除空编码、主井和重复项。 */ void normalizeIncludedWells(); /** @brief 保证当前结果井属于最后结果顺序,否则回退到第一口真实井。 */ void normalizeCurrentResultWellCode(); /** @brief 按本次主井和已启用主动井冻结结果下拉框井编码。 */ void freezeResultSelectableWellCodes(); private: QString m_sPrimaryWellCode; ///< 主分析井的项目唯一 WellCode。 NM_CASE_WELL_MODE m_ePrimaryWellMode; ///< 主井在本次方案中的源汇角色。 bool m_bIncludeOtherWells; ///< 是否启用手工选择的有产量干扰井。 double m_dPebiGridControl; ///< 当前方案使用的 PEBI 网格疏密参数。 QVector m_vecIncludedWells; ///< 已选择的其他有产量井,不含自动观察井。 QString m_sCurrentResultWellCode; ///< 当前结果查看井,仅属于展示状态。 QVector m_vecSolverWellOrder; ///< 网格确定的 DLL 数组下标映射。 QVector m_vecResultSolverWellOrder; ///< 最后结果使用的独立槽位映射。 QStringList m_listResultSelectableWellCodes; ///< 最后结果允许在下拉框中显示的井编码。 quint64 m_nGridInputRevision; ///< 几何、选井等网格输入的最新版本。 quint64 m_nBuiltGridRevision; ///< 当前缓存网格对应版本,0 表示无有效网格。 quint64 m_nResultInputRevision; ///< 产量、角色、PVT 等求解输入版本。 bool m_bResultsAvailable; ///< 是否存在一套可保存和查看的结果载荷。 bool m_bResultsValid; ///< 已有结果是否仍对应当前输入和网格。 }; #endif // NMDATANUMERICALANALYSISCASE_H