You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Include/nmNum/nmData/nmDataWellBase.h

404 lines
17 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#pragma once
#include "nmData_global.h"
#include "nmDefines.h"
#include "nmDataAttribute.h"
#include "nmDataGaugeRecord.h"
#include "ZxDataObjectDbl.h"
#include "nmDataPerforation.h"
#include <QWeakPointer>
//#include "nmDataReservoir.h"
//#include "nmDataAnalyzeManager.h"
class nmDataReservoir;
class nmDataAnalyzeManager;
class nmPebiResultSnapshot;
class NM_DATA_EXPORT nmDataWellBase : public nmDataBase
{
Q_OBJECT
public:
nmDataWellBase();
nmDataWellBase(const nmDataWellBase& other);
~nmDataWellBase();
nmDataWellBase& operator=(const nmDataWellBase& other);
// 创建当前对象的深拷贝
virtual nmDataWellBase* clone() const = 0;
// 实现 nmDataBase 的抽象方法:将当前 C++ 对象序列化为 RapidJSON Value
virtual rapidjson::Value ToJsonValue(rapidjson::Document::AllocatorType& allocator) const override;
// 实现 nmDataBase 的抽象方法:从 RapidJSON Value 反序列化数据到当前 C++ 对象
virtual void FromJsonValue(const rapidjson::Value& jsonValue) override;
// 统一连接 nmDataAttribute 的信号
virtual void connectAttributeSignals();
// 用于获取某个射孔的允许MD范围
virtual void getPerforationAllowedMdRange(nmDataPerforation* pPerfToValidate,
double& dUpperAllowedMd,
double& dLowerAllowedMd) = 0;
public:
// 手动发送信号,通知参数视图进行更新
void notifyParameterChanged();
signals:
// 数据模型发生改变时发出的信号,通知所有监听者刷新视图
void sigWellDataChanged();
// 专门用于通知参数视图更新,通常在模型视图完成交互后发出。
void sigParameterChanged();
public slots:
// 井身长度变化,更新射孔位置
void slotWellLengthChanged();
public:
// 属性的 set 和 get 方法
void setWellName(const QString& name);
QString getWellName() const;
void setWellCode(const QString& code);
QString getWellCode() const;
/** @brief 保存工程井的油井、气井或水井井别;该值不由数值井编辑器修改。 */
void setWellCategory(NM_WELL_CATEGORY eWellCategory);
/** @brief 返回工程井井别,用于选择历史曲线的参考流量相。 */
NM_WELL_CATEGORY getWellCategory() const;
/** @brief 返回井对象的稳定实例标识,与可编辑井编码相互独立。 */
QString getWellInstanceId() const;
/** @brief 项目加载或井型替换时恢复已有实例标识。 */
bool restoreWellInstanceId(const QString& sWellInstanceId);
/** @brief 为新建井生成不带花括号的 UUID。 */
static QString createWellInstanceId();
void setX(const nmDataAttribute& attr);
nmDataAttribute& getX(); // 修改为返回引用
void setY(const nmDataAttribute& attr);
nmDataAttribute& getY(); // 修改为返回引用
void setRadius(const nmDataAttribute& attr);
nmDataAttribute& getRadius(); // 修改为返回引用
void setDrillFloorElevation(const nmDataAttribute& attr);
nmDataAttribute& getDrillFloorElevation(); // 修改为返回引用
void setZw(const nmDataAttribute& attr);
nmDataAttribute& getZw(); // 修改为返回引用
void setWellLength(const nmDataAttribute& attr);
nmDataAttribute& getWellLength(); // 修改为返回引用
void setRateDependentSkin(const nmDataAttribute& attr);
nmDataAttribute& getRateDependentSkin(); // 修改为返回引用
void setdSdQ(const nmDataAttribute& attr);
nmDataAttribute& getdSdQ(); // 修改为返回引用
void setWellboreModel(const nmDataAttribute& attr);
nmDataAttribute& getWellboreModel(); // 修改为返回引用
void setWellboreStorage(const nmDataAttribute& attr);
nmDataAttribute& getWellboreStorage(); // 修改为返回引用
void setBottomholeMD(const nmDataAttribute& attr);
nmDataAttribute& getBottomholeMD(); // 修改为返回引用
// Location---位置
void setInputWellHead(const nmDataAttribute& attr);
nmDataAttribute& getInputWellHead();
void setWellHeadX(const nmDataAttribute& attr);
nmDataAttribute& getWellHeadX();
void setWellHeadY(const nmDataAttribute& attr);
nmDataAttribute& getWellHeadY();
// Wellbore---井储
void setCInitialCFinal(const nmDataAttribute& attr);
nmDataAttribute& getCInitialCFinal();
void setDtChangingStorage(const nmDataAttribute& attr);
nmDataAttribute& getDtChangingStorage();
void setLeakSkin(const nmDataAttribute& attr);
nmDataAttribute& getLeakSkin();
// Wellbore---井储
void setFinalWellboreStorage(const nmDataAttribute& attr);
nmDataAttribute& getFinalWellboreStorage();
// 获取压力曲线点数据
QVector<QPointF> getPressurePoints() const;
// 设置压力曲线点数据
void setPressurePoints(const QVector<QPointF>& points);
// 获取井别对应相的流量曲线点数据,供现有历史曲线逻辑使用
QVector<QPointF> getFlowPoints() const;
// 设置井别对应相的流量曲线点数据
void setFlowPoints(const QVector<QPointF>& points);
/** @brief 返回工程井别对应的历史曲线参考相。 */
NM_PHASE_TYPE getReferenceFlowPhase() const;
/** @brief 获取或设置指定油、气、水相的原始流量点。 */
QVector<QPointF> getFlowPoints(NM_PHASE_TYPE eFlowPhase) const;
void setFlowPoints(NM_PHASE_TYPE eFlowPhase,
const QVector<QPointF>& points);
/** @brief 返回指定相去除可选 (0,0) 占位点后的真实流动段。 */
QVector<QPointF> getFlowSegmentPoints(NM_PHASE_TYPE eFlowPhase) const;
/** @brief 返回指定相的真实流动段数量。 */
int getFlowSegmentCount(NM_PHASE_TYPE eFlowPhase) const;
/** @brief 指定相是否至少包含一个真实流动段。 */
bool hasFlowPhaseData(NM_PHASE_TYPE eFlowPhase) const;
/** @brief 油、气、水中是否至少有一相包含真实流动段。 */
bool hasAnyFlowData() const;
/** @brief 全部框架记录中是否存在至少一个可用的非零产量相。 */
bool hasAvailableFlowRate() const;
/** @brief 返回当前启用相的公共流量制度;优先取井别对应相。 */
QVector<QPointF> getFlowSegmentPoints() const;
/** @brief 返回当前公共流量制度采用的参考相;没有启用相时返回 Unknown。 */
NM_PHASE_TYPE getFlowSchedulePhase() const;
/** @brief 返回当前启用相共用的真实流动段数量。 */
int getFlowSegmentCount() const;
/** @brief 校验当前流动段索引是否位于一基的真实流动段范围内。 */
bool hasValidFlowSectionIndex() const;
/** @brief 设置全部压力记录列表(不改变当前选中 Code。 */
void setPressureRecords(const QVector<nmPressureGaugeRecord>& vecRecords);
/** @brief 设置全部流量记录列表(不改变当前选中 Code。 */
void setFlowRecords(const QVector<nmFlowGaugeRecord>& vecRecords);
/** @brief 按 Gauge Code 选中一条压力记录;传入空字符串表示无选中。 */
void selectPressureGaugeCode(const QString& sGaugeCode);
/** @brief 按 Gauge Code 选中一条流量记录;传入空字符串表示无选中。 */
void selectFlowGaugeCode(const QString& sGaugeCode);
/**
* @brief 切换选中流量记录:把当前 m_nIndexF 写回旧记录的 nIndexF
* 再用新记录的 nIndexF 恢复并按新记录的真实段数校验当前索引。
* @note UI 层切换流量记录下拉时必须调用本方法,而不是直接调用 selectFlowGaugeCode
* 否则流动段索引不会跟随记录切换正确恢复。
*/
void switchSelectedFlowGaugeCode(const QString& sGaugeCode);
/** @brief 返回当前选中的压力记录 Gauge Code未选中时为空。 */
QString getSelectedPressureGaugeCode() const;
/** @brief 返回当前选中的流量记录 Gauge Code未选中时为空。 */
QString getSelectedFlowGaugeCode() const;
/** @brief 返回全部压力记录(包含损坏/空/身份无效记录)。 */
QVector<nmPressureGaugeRecord> getPressureRecords() const;
/** @brief 返回全部流量记录(包含损坏/空/身份无效记录)。 */
QVector<nmFlowGaugeRecord> getFlowRecords() const;
/** @brief 返回指定相是否作为当前流量制度的一部分传给求解器。 */
bool isFlowPhaseUsed(NM_PHASE_TYPE eFlowPhase) const;
/** @brief 设置指定相是否参与当前流量制度;井别不会随此状态改变。 */
void setFlowPhaseUsed(NM_PHASE_TYPE eFlowPhase, bool bUsed);
// 以下显式接口供现有 UI 和快照组装代码使用,语义与上面的分相接口一致。
// 三个开关只控制求解器输入,不修改框架原始记录,也不改变工程井井别。
bool getUseOilRate() const;
bool getUseGasRate() const;
bool getUseWaterRate() const;
void setUseOilRate(bool bUsed);
void setUseGasRate(bool bUsed);
void setUseWaterRate(bool bUsed);
/** @brief 构造与井角色无关的规范化 Gauge 输入。 */
void buildGaugeInputData(nmWellGaugeInputData& oInput) const;
/** @brief 按固定二进制格式计算指定规范化 Gauge 输入的 SHA-1。 */
static QString calculateGaugeInputSha1(
const nmWellGaugeInputData& oInput);
/** @brief 返回当前井规范化 Gauge 输入的 SHA-1。 */
QString calculateGaugeInputSha1() const;
/** @brief 返回记录自身、不受分相开关影响的真实段数。 */
static int getRawFlowRecordSegmentCount(
const nmFlowGaugeRecord& oRecord);
int getIndexF() const;
void setIndexF(const int newIndex);
bool getPlotVisible() const;
void setPlotVisible(const bool newState);
// 图元外观属性 getter/setter
int getDotStyle() const { return m_nDotStyle; }
void setDotStyle(int style) { m_nDotStyle = style; }
int getDotColorR() const { return m_nDotColorR; }
int getDotColorG() const { return m_nDotColorG; }
int getDotColorB() const { return m_nDotColorB; }
void setDotColor(int r, int g, int b) { m_nDotColorR = r; m_nDotColorG = g; m_nDotColorB = b; }
double getDotRadius() const { return m_dDotRadius; }
void setDotRadius(double r) { m_dDotRadius = r; }
bool getDotFilling() const { return m_bDotFilling; }
void setDotFilling(bool b) { m_bDotFilling = b; }
bool getShowSubObjs() const { return m_bShowSubObjs; }
void setShowSubObjs(bool b) { m_bShowSubObjs = b; }
// 历史数据相关方法
QVector<QVector<double>> getHistoryPressure();
void setHistoryPressure(QVector<QVector<double>> pressureData);
QVector<QVector<double>> getHistoryLogLog();
void setHistoryLogLog(QVector<QVector<double>> loglogData);
QVector<QVector<double>> getHistorySemiLog();
void setHistorySemiLog(QVector<QVector<double>> semiLogData);
/** @brief 原子写入三组历史曲线及其对应的 Gauge 输入签名。 */
void setHistoryData(
const QVector<QVector<double> >& vecPressure,
const QVector<QVector<double> >& vecLogLog,
const QVector<QVector<double> >& vecSemiLog,
const QString& sGaugeInputSha1);
/** @brief 返回生成当前三组历史曲线时冻结的 Gauge 输入签名。 */
QString getHistoryGaugeInputSha1() const;
void setWellType(NM_WELL_MODEL newWellType);
NM_WELL_MODEL getWellType() const;
// 计算结果相关方法
/** @brief 返回当前井 UUID 在最后结果快照中的压力曲线;未绑定时返回空。 */
QVector<QVector<double>> getResultPressure();
/** @brief 返回当前井 UUID 在最后结果快照中的双对数曲线;未绑定时返回空。 */
QVector<QVector<double>> getResultLogLog();
/** @brief 返回当前井 UUID 在最后结果快照中的半对数曲线;未绑定时返回空。 */
QVector<QVector<double>> getResultSemiLog();
// 时间变表皮状态的getter和setter
bool isTimeDependentSkin() const;
void setTimeDependentSkin(bool enabled);
// 管理射孔段的方法
void addPerforation(nmDataPerforation* perforation); // 接受指针
void removePerforation(int index); // 根据索引移除
nmDataPerforation* getPerforation(int index); // 获取单个射孔段
nmDataPerforation getPerforationCopy(int index); // 获取单个射孔段副本
void updatePerforation(int index, const nmDataPerforation& newData); // 更新单个射孔段数据
int getPerforationCount(); // 获取射孔段数量
QVector<nmDataPerforation*>& getPerforations(); // 获取所有射孔段(返回指针的引用)
void clearPerforations(); // 清空所有射孔段数据
/**
* @brief 一次性应用井筒范围和完整射孔快照。
* @note 显式编辑时不触发井长变化的自动缩放,保证校验值与最终数据一致。
*/
bool applyWellboreEdit(double dBottomholeMd,
double dWellLength,
const QVector<nmDataPerforation>& vecPerforations);
// 井级别的流量和时间查询方法
double getTotalTimeRange() const;
double getFlowRateAtTime(double time) const;
QVector<double> getAllFlowStepBoundaries() const;
QVector<QPointF> getFlowStepsInTimeRange(double startTime, double endTime) const;
double findFlowStepBoundaryAtTime(double timePoint) const;
double findSmartFlowStepBoundary(double targetTime) const;
double findNearestFlowStepBoundary(double targetTime) const;
bool isTimeInFlowStepFirstHalf(double time) const;
// 射孔段相关的查询方法
QVector<double> getFlowStepBoundariesInSegment(int segmentIndex, int perforationIndex) const;
QVector<double> getAllBoundariesInSegment(int segmentIndex, int perforationIndex) const;
int countFlowStepsInSegment(int segmentIndex, int perforationIndex) const;
bool canFlowSegmentBeSplit(int segmentIndex, int perforationIndex) const;
double findNearestFlowStepBoundaryBeforeSegment(int segmentIndex, int perforationIndex) const;
// 判断是否基础射孔段
bool isBasePerforation();
void resetToDefaults(); // 重置所有参数为构造函数默认值
// 导出双对数历史曲线到 CSV
bool exportHistoryLogLogToCsv(const QString& outDir);
// 导出流量数据到 CSV
bool exportHistoryRateToCsv(const QString& outDir);
// 导出历史压力数据到 CSV
bool exportHistoryPressureToCsv(const QString& outDir);
// 导出求解结果双对数曲线到 CSV
bool exportResultLogLogToCsv(const QString& outDir);
// 导出求解结果压力数据到 CSV
bool exportResultPressureToCsv(const QString& outDir);
protected:
/** @brief 井实例 UUID井型替换时保持不变删除重建时必须变化。 */
QString m_sWellInstanceId;
QString m_wellName; // 井名
QString m_wellCode; // 井编码项目级唯一标识来自ZxDataWell::getCode()
NM_WELL_CATEGORY m_eWellCategory; // 工程井井别:油井、气井或水井
// Location---位置
nmDataAttribute m_inputWellHead; //井口坐标输入
nmDataAttribute m_wellHeadX; //井口坐标X
nmDataAttribute m_wellHeadY; //井口坐标Y
nmDataAttribute m_x; // X
nmDataAttribute m_y; // Y
// Geometry and properties---几何与属性
nmDataAttribute m_drillFloorElevation; // 钻台标高
nmDataAttribute m_radius; // 井径
nmDataAttribute m_zw; // Zw
nmDataAttribute m_wellLength; // 井身长度
nmDataAttribute m_rateDependentSkin; // 速度表皮
nmDataAttribute m_dSdQ; // dS/dQ 表皮关于产量的变化率
// Wellbore---井储
nmDataAttribute m_wellboreModel; // 井储模型
nmDataAttribute m_wellboreStorage; // 井筒储集系数
nmDataAttribute m_finalWellboreStorage; // 最终井储
nmDataAttribute m_cInitialCFinal; // 初始井储/最终井储
nmDataAttribute m_dtChangingStorage; //井储变化时间
nmDataAttribute m_leakSkin; // 漏失表皮
// Bottomhole conditions---井底条件
nmDataAttribute m_bottomholeMD; // 井底测量深度
QVector<nmPressureGaugeRecord> m_vecPressureRecords; // 全部压力测量记录(可能包含损坏/空/身份无效记录)
QVector<nmFlowGaugeRecord> m_vecFlowRecords; // 全部流量测量记录(可能包含损坏/空/身份无效记录)
QString m_sSelectedPressureGaugeCode; // 当前选中的压力记录 Gauge Code为空表示未选中
QString m_sSelectedFlowGaugeCode; // 当前选中的流量记录 Gauge Code为空表示未选中
bool m_bUseOilRate; // 当前流量制度是否传入油相产量
bool m_bUseGasRate; // 当前流量制度是否传入气相产量
bool m_bUseWaterRate; // 当前流量制度是否传入水相产量
int m_nIndexF; // 当前流量段的索引
bool m_bPlotVisible; // 图元是否可见
// 图元外观属性(用于保存/加载,由 Binder 在 syncWellData 和 _pushWellDataToGraphic 中同步)
int m_nDotStyle; // ZxDotType (int)
int m_nDotColorR; // QColor R
int m_nDotColorG; // QColor G
int m_nDotColorB; // QColor B
double m_dDotRadius; // 点半径
bool m_bDotFilling; // 是否填充
bool m_bShowSubObjs; // 是否显示子对象
// 添加时间变表皮状态字段
bool m_bTimeDependentSkin;
// 井类型
NM_WELL_MODEL m_eWellType;
// 历史数据
QVector<QVector<double>> m_vvecHsyPressure; // 历史压力数据
QVector<QVector<double>> m_vvecHsyLogLog; // 历史双对数数据
QVector<QVector<double>> m_vvecHsySemiLog; // 历史半对数数据
QString m_sHistoryGaugeInputSha1; // 三组历史曲线对应的规范化 Gauge 输入签名
/** @brief 最后结果快照的弱引用,不延长历史结果生命周期。 */
QWeakPointer<const nmPebiResultSnapshot> m_pPebiResultSnapshot;
// 射孔段集合
QVector<nmDataPerforation*> m_vecPerforations;
// 记录原始井身长度,用于计算更新井身长度之后射孔段的位置
double m_dLastWellLength;
nmDataReservoir* m_pReservoir;
private:
/** @brief 由数据管理器按井 UUID 统一绑定或解除最后结果快照。 */
void bindPebiResultSnapshot(
const QWeakPointer<const nmPebiResultSnapshot>& pSnapshot);
/** @brief 只有所属数据管理器可以维护井与结果快照之间的弱关联。 */
friend class nmDataAnalyzeManager;
};