#include "nmDataWellBase.h" #include "nmDataReservoir.h" #include "nmDataAnalyzeManager.h" #include #include #include #include #include nmDataWellBase::nmDataWellBase() : m_nIndexF(0) , m_bPlotVisible(true) , m_bTimeDependentSkin(false) , m_eWellType(Vertical_Well) , m_dLastWellLength(0.0) , m_pReservoir(nullptr) { m_pReservoir = nmDataAnalyzeManager::getCurrentInstance()->getReservoirData(); m_wellName = ""; m_x = nmDataAttribute("X", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), QStringList() << "m" << "cm" << "mm" << "in" << "0.1 in" << "ft" << "mile" << "km"); m_y = nmDataAttribute("Y", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), QStringList() << "m" << "cm" << "mm" << "in" << "0.1 in" << "ft" << "mile" << "km"); m_radius = nmDataAttribute("Radius", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), QStringList() << "m" << "cm" << "mm" << "in" << "0.1 in" << "ft" << "mile" << "km"); m_drillFloorElevation = nmDataAttribute("Drill floor elevation", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), QStringList() << "m" << "cm" << "mm" << "in" << "0.1 in" << "ft" << "mile" << "km"); m_zw = nmDataAttribute("Zw", 22.5, "m", UNIT_TYPE_LENGTH, QStringList(), QStringList() << "m" << "cm" << "mm" << "in" << "0.1 in" << "ft" << "mile" << "km"); m_wellLength = nmDataAttribute("Well length", m_pReservoir->getThickness().getValue(), "m", UNIT_TYPE_LENGTH, QStringList(), QStringList() << "m" << "cm" << "mm" << "in" << "0.1 in" << "ft" << "mile" << "km"); m_rateDependentSkin = nmDataAttribute("Rate dependent skin", false, ""); m_dSdQ = nmDataAttribute("dS/dQ", 0.0, "1/B/D", UNIT_TYPE_FLOW_RATE_RECIPROCAL, QStringList(), QStringList() << "1/B/D" << "1/MMm^3/D" << "1/Mcf/D" << "1/Mm^3/D" << "1/Mm^3/hr" << "1/U.K. gal/hr" << "1/U.K. gal/min" << "1/U.S. gal/hr" << "1/U.S. gal/min" << "1/cf/D" << "1/cf/s" << "1/cm^3/sec" << "1/l/min" << "1/m^3/D" << "1/m^3/hr" << "1/m^3/min" << "1/m^3/sec"); m_wellboreModel = nmDataAttribute("Wellbore model", "Constant", "", UNIT_TYPE_DIMENSIONLESS, QStringList() << "None" << "Constant" << "Changing hegeman" << "Changing fair" << "Changing spivey packer" << "Changing spivey fissures", QStringList()); m_wellboreStorage = nmDataAttribute("Wellbore storage", 0.01, "m^3/MPa", UNIT_TYPE_COMPRESSIBILITY, QStringList(), QStringList() << "bbl/psi" << "m^3/bar" << "m^3/kPa" << "m^3/Pa" << "m^3.cm^2/kg" << "m^2" << "m^3/MPa"); m_bottomholeMD = nmDataAttribute("Bottomhole MD", 6000.0, "m", UNIT_TYPE_LENGTH, QStringList(), QStringList() << "m" << "cm" << "mm" << "in" << "0.1 in" << "ft" << "mile" << "km"); // 初始化新添加的成员 m_inputWellHead = nmDataAttribute("Input well head", "", ""); m_wellHeadX = nmDataAttribute("Well head X", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), QStringList() << "m" << "cm" << "mm" << "in" << "0.1 in" << "ft" << "mile" << "km"); m_wellHeadY = nmDataAttribute("Well head Y", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), QStringList() << "m" << "cm" << "mm" << "in" << "0.1 in" << "ft" << "mile" << "km"); m_finalWellboreStorage = nmDataAttribute("Final wellbore storage", 0.01, "bbl/psi", UNIT_TYPE_COMPRESSIBILITY, QStringList(), QStringList() << "bbl/psi" << "m^3/bar" << "m^3/kPa" << "m^3/Pa" << "m^3.cm^2/kg" << "m^2" << "m^3/MPa"); m_cInitialCFinal = nmDataAttribute("C[initial]/C[final]", 10.0, ""); m_dtChangingStorage = nmDataAttribute("Dt changing storage", 1.0, "hr", UNIT_TYPE_TIME, QStringList(), QStringList() << "ms" << "sec" << "min" << "hr" << "day" << "Week" << "Month" << "Year"); m_leakSkin = nmDataAttribute("Leak Skin", 0.0, ""); // 图元可见性,默认为true m_bPlotVisible = true; m_bTimeDependentSkin = false; // 添加一段射孔,默认与井身长度相同 (现在创建对象并添加指针) nmDataPerforation* defaultPerforation = new nmDataPerforation(); defaultPerforation->getMdStart().setValue(m_bottomholeMD.getValue().toDouble()); defaultPerforation->getMdEnd().setValue(m_bottomholeMD.getValue().toDouble() + m_wellLength.getValue().toDouble()); m_vecPerforations.append(defaultPerforation); // 添加指针 // 默认与当前井身长度一致 m_dLastWellLength = m_wellLength.getValue().toDouble(); this->connectAttributeSignals(); } void nmDataWellBase::resetToDefaults() { m_wellboreStorage.setValue(0.01); // 重置第一段射孔的皮损系数 if(getPerforationCount() > 0) { nmDataPerforation* firstPerforation = getPerforation(0); if(firstPerforation) { firstPerforation->getSkin().setValue(0.0); // 皮损系数 } } } nmDataWellBase::nmDataWellBase(const nmDataWellBase& other) { *this = other; // 使用赋值运算符实现 } nmDataWellBase::~nmDataWellBase() { // 释放所有射孔段对象 qDeleteAll(m_vecPerforations); m_vecPerforations.clear(); } nmDataWellBase& nmDataWellBase::operator=(const nmDataWellBase& other) { if(this != &other) { m_wellName = other.m_wellName; m_x = other.m_x; m_y = other.m_y; m_radius = other.m_radius; m_drillFloorElevation = other.m_drillFloorElevation; m_zw = other.m_zw; m_wellLength = other.m_wellLength; m_rateDependentSkin = other.m_rateDependentSkin; m_dSdQ = other.m_dSdQ; m_wellboreModel = other.m_wellboreModel; m_wellboreStorage = other.m_wellboreStorage; m_bottomholeMD = other.m_bottomholeMD; m_vecPtsP = other.m_vecPtsP; m_vecPtsF = other.m_vecPtsF; m_nIndexF = other.m_nIndexF; m_finalWellboreStorage = other.m_finalWellboreStorage; m_inputWellHead = other.m_inputWellHead; m_wellHeadX = other.m_wellHeadX; m_wellHeadY = other.m_wellHeadY; m_cInitialCFinal = other.m_cInitialCFinal; m_dtChangingStorage = other.m_dtChangingStorage; m_leakSkin = other.m_leakSkin; m_bPlotVisible = other.m_bPlotVisible; m_bTimeDependentSkin = other.m_bTimeDependentSkin; m_eWellType = other.m_eWellType; // 先释放当前的射孔段对象 qDeleteAll(m_vecPerforations); m_vecPerforations.clear(); // 深拷贝新的射孔段对象 foreach(nmDataPerforation* perf, other.m_vecPerforations) { if(perf) { m_vecPerforations.append(new nmDataPerforation(*perf)); } } // 复制历史数据 m_vvecHsyPressure = other.m_vvecHsyPressure; m_vvecHsyLogLog = other.m_vvecHsyLogLog; m_vvecHsySemiLog = other.m_vvecHsySemiLog; // 复制计算结果数据 m_vvecRstPressure = other.m_vvecRstPressure; m_vvecRstLogLog = other.m_vvecRstLogLog; m_vvecRstSemiLog = other.m_vvecRstSemiLog; // 默认与当前井身长度一致 m_dLastWellLength = m_wellLength.getValue().toDouble(); } return *this; } // 序列化 nmDataWellBase 为 RapidJSON Value rapidjson::Value nmDataWellBase::ToJsonValue(rapidjson::Document::AllocatorType& allocator) const { // 创建一个 RapidJSON 对象类型的值 rapidjson::Value wellObject(rapidjson::kObjectType); // 序列化名称 wellObject.AddMember("WellName", rapidjson::Value(m_wellName.toStdString().c_str(), allocator).Move(), allocator); // 序列化井类型 wellObject.AddMember("WellType", rapidjson::Value(static_cast(m_eWellType)), allocator); // 序列化 nmDataAttribute 类型的成员 // 调用 nmDataAttribute 自身的 ToJsonValue 方法进行递归序列化 wellObject.AddMember("X", m_x.ToJsonValue(allocator), allocator); wellObject.AddMember("Y", m_y.ToJsonValue(allocator), allocator); wellObject.AddMember("Radius", m_radius.ToJsonValue(allocator), allocator); wellObject.AddMember("DrillFloorElevation", m_drillFloorElevation.ToJsonValue(allocator), allocator); wellObject.AddMember("Zw", m_zw.ToJsonValue(allocator), allocator); wellObject.AddMember("WellLength", m_wellLength.ToJsonValue(allocator), allocator); wellObject.AddMember("RateDependentSkin", m_rateDependentSkin.ToJsonValue(allocator), allocator); wellObject.AddMember("dSdQ", m_dSdQ.ToJsonValue(allocator), allocator); wellObject.AddMember("WellboreModel", m_wellboreModel.ToJsonValue(allocator), allocator); wellObject.AddMember("WellboreStorage", m_wellboreStorage.ToJsonValue(allocator), allocator); wellObject.AddMember("BottomholeMD", m_bottomholeMD.ToJsonValue(allocator), allocator); wellObject.AddMember("InputWellHead", m_inputWellHead.ToJsonValue(allocator), allocator); wellObject.AddMember("WellHeadX", m_wellHeadX.ToJsonValue(allocator), allocator); wellObject.AddMember("WellHeadY", m_wellHeadY.ToJsonValue(allocator), allocator); wellObject.AddMember("FinalWellboreStorage", m_finalWellboreStorage.ToJsonValue(allocator), allocator); wellObject.AddMember("CInitialCFinal", m_cInitialCFinal.ToJsonValue(allocator), allocator); wellObject.AddMember("DtChangingStorage", m_dtChangingStorage.ToJsonValue(allocator), allocator); wellObject.AddMember("LeakSkin", m_leakSkin.ToJsonValue(allocator), allocator); // 序列化时间变表皮状态 wellObject.AddMember("TimeDependentSkin", m_bTimeDependentSkin, allocator); // 序列化图元可见性 (m_bPlotVisible) wellObject.AddMember("PlotVisible", m_bPlotVisible, allocator); // 序列化井的流动段索引 (m_nIndexF) wellObject.AddMember("IndexFlow", m_nIndexF, allocator); // 序列化射孔段集合 (现在处理指针) rapidjson::Value perforationsArray(rapidjson::kArrayType); foreach(const nmDataPerforation* perfPtr, m_vecPerforations) { if(perfPtr) { // 检查指针是否有效 perforationsArray.PushBack(perfPtr->ToJsonValue(allocator), allocator); } } wellObject.AddMember("Perforations", perforationsArray, allocator); return wellObject; // 返回序列化后的 RapidJSON Value } // 从 RapidJSON Value 反序列化数据到 nmDataWellBase void nmDataWellBase::FromJsonValue(const rapidjson::Value& jsonValue) { // 反序列化名称 if(jsonValue.HasMember("WellName") && jsonValue["WellName"].IsString()) { m_wellName = QString::fromUtf8(jsonValue["WellName"].GetString()); } // 反序列化井类型 (m_eWellType) if(jsonValue.HasMember("WellType") && jsonValue["WellType"].IsInt()) { m_eWellType = static_cast(jsonValue["WellType"].GetInt()); } // 反序列化 nmDataAttribute 类型的成员 // 调用 nmDataAttribute 自身的 FromJsonValue 方法进行递归反序列化 if(jsonValue.HasMember("X") && jsonValue["X"].IsObject()) { m_x.FromJsonValue(jsonValue["X"]); } if(jsonValue.HasMember("Y") && jsonValue["Y"].IsObject()) { m_y.FromJsonValue(jsonValue["Y"]); } if(jsonValue.HasMember("Radius") && jsonValue["Radius"].IsObject()) { m_radius.FromJsonValue(jsonValue["Radius"]); } if(jsonValue.HasMember("DrillFloorElevation") && jsonValue["DrillFloorElevation"].IsObject()) { m_drillFloorElevation.FromJsonValue(jsonValue["DrillFloorElevation"]); } if(jsonValue.HasMember("Zw") && jsonValue["Zw"].IsObject()) { m_zw.FromJsonValue(jsonValue["Zw"]); } if(jsonValue.HasMember("WellLength") && jsonValue["WellLength"].IsObject()) { m_wellLength.FromJsonValue(jsonValue["WellLength"]); } if(jsonValue.HasMember("RateDependentSkin") && jsonValue["RateDependentSkin"].IsObject()) { m_rateDependentSkin.FromJsonValue(jsonValue["RateDependentSkin"]); } if(jsonValue.HasMember("dSdQ") && jsonValue["dSdQ"].IsObject()) { m_dSdQ.FromJsonValue(jsonValue["dSdQ"]); } if(jsonValue.HasMember("WellboreModel") && jsonValue["WellboreModel"].IsObject()) { m_wellboreModel.FromJsonValue(jsonValue["WellboreModel"]); } if(jsonValue.HasMember("WellboreStorage") && jsonValue["WellboreStorage"].IsObject()) { m_wellboreStorage.FromJsonValue(jsonValue["WellboreStorage"]); } if(jsonValue.HasMember("BottomholeMD") && jsonValue["BottomholeMD"].IsObject()) { m_bottomholeMD.FromJsonValue(jsonValue["BottomholeMD"]); } if(jsonValue.HasMember("InputWellHead") && jsonValue["InputWellHead"].IsObject()) { m_inputWellHead.FromJsonValue(jsonValue["InputWellHead"]); } if(jsonValue.HasMember("WellHeadX") && jsonValue["WellHeadX"].IsObject()) { m_wellHeadX.FromJsonValue(jsonValue["WellHeadX"]); } if(jsonValue.HasMember("WellHeadY") && jsonValue["WellHeadY"].IsObject()) { m_wellHeadY.FromJsonValue(jsonValue["WellHeadY"]); } if(jsonValue.HasMember("FinalWellboreStorage") && jsonValue["FinalWellboreStorage"].IsObject()) { m_finalWellboreStorage.FromJsonValue(jsonValue["FinalWellboreStorage"]); } if(jsonValue.HasMember("CInitialCFinal") && jsonValue["CInitialCFinal"].IsObject()) { m_cInitialCFinal.FromJsonValue(jsonValue["CInitialCFinal"]); } if(jsonValue.HasMember("DtChangingStorage") && jsonValue["DtChangingStorage"].IsObject()) { m_dtChangingStorage.FromJsonValue(jsonValue["DtChangingStorage"]); } if(jsonValue.HasMember("LeakSkin") && jsonValue["LeakSkin"].IsObject()) { m_leakSkin.FromJsonValue(jsonValue["LeakSkin"]); } // 反序列化时间变表皮状态 if(jsonValue.HasMember("TimeDependentSkin") && jsonValue["TimeDependentSkin"].IsBool()) { m_bTimeDependentSkin = jsonValue["TimeDependentSkin"].GetBool(); } // 反序列化图元可见性 (m_bPlotVisible) if(jsonValue.HasMember("PlotVisible") && jsonValue["PlotVisible"].IsBool()) { m_bPlotVisible = jsonValue["PlotVisible"].GetBool(); } // 反序列化井的流动段索引 (m_nIndexF) if(jsonValue.HasMember("IndexFlow") && jsonValue["IndexFlow"].IsInt()) { m_nIndexF = jsonValue["IndexFlow"].GetInt(); } // 反序列化射孔段集合 (现在处理指针) if(jsonValue.HasMember("Perforations") && jsonValue["Perforations"].IsArray()) { // 清空并释放现有射孔段对象 qDeleteAll(m_vecPerforations); m_vecPerforations.clear(); const rapidjson::Value& perforationsArray = jsonValue["Perforations"]; for(rapidjson::SizeType i = 0; i < perforationsArray.Size(); ++i) { if(perforationsArray[i].IsObject()) { nmDataPerforation* newPerforation = new nmDataPerforation(); // 创建新对象 newPerforation->FromJsonValue(perforationsArray[i]); m_vecPerforations.append(newPerforation); // 添加指针 } } } // 默认与当前井身长度一致 m_dLastWellLength = m_wellLength.getValue().toDouble(); } void nmDataWellBase::connectAttributeSignals() { // 通用属性 connect(&m_inputWellHead, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_wellHeadX, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_wellHeadY, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_x, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_y, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_drillFloorElevation, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_radius, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_zw, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_wellLength, SIGNAL(sigValueChanged()), this, SLOT(slotWellLengthChanged())); connect(&m_rateDependentSkin, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_dSdQ, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_wellboreModel, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_wellboreStorage, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_finalWellboreStorage, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_cInitialCFinal, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_dtChangingStorage, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_leakSkin, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); connect(&m_bottomholeMD, SIGNAL(sigValueChanged()), this, SIGNAL(sigWellDataChanged())); } void nmDataWellBase::notifyParameterChanged() { emit sigParameterChanged(); } void nmDataWellBase::slotWellLengthChanged() { double oldLength = m_dLastWellLength; double newLength = m_wellLength.getValue().toDouble(); // 避免除以零和不必要的计算 if (qFuzzyIsNull(oldLength) || oldLength <= 0 || qFuzzyCompare(oldLength, newLength)) { return; } // 获取井口深度 double wellHeadMd = this->getBottomholeMD().getValue().toDouble(); // 对于多段压裂水平井类型,井口MD是第一段射孔的起点 if (m_eWellType == Horizontal_Fractured_Well) { wellHeadMd = getPerforations()[0]->getMdStart().getValue().toDouble(); } // 遍历所有射孔段,并按比例更新其MD数据 foreach(nmDataPerforation* pPerfData, m_vecPerforations) { if(pPerfData) { double originalPerforationMdStart = pPerfData->getMdStart().getValue().toDouble(); double originalPerforationMdEnd = pPerfData->getMdEnd().getValue().toDouble(); // 计算射孔在旧井筒上的相对位置 double relativePerforationStart = (originalPerforationMdStart - wellHeadMd) / oldLength; double relativePerforationEnd = (originalPerforationMdEnd - wellHeadMd) / oldLength; // 根据新的井筒长度计算新的绝对MD值 double newPerforationMdStart = wellHeadMd + (relativePerforationStart * newLength); double newPerforationMdEnd = wellHeadMd + (relativePerforationEnd * newLength); pPerfData->getMdStart().setValue(newPerforationMdStart); pPerfData->getMdEnd().setValue(newPerforationMdEnd); } } // 更新历史井身 m_dLastWellLength = newLength; emit sigWellDataChanged(); } // Getters and Setters void nmDataWellBase::setWellName(const QString& name) { m_wellName = name; } QString nmDataWellBase::getWellName() const { return m_wellName; } void nmDataWellBase::setX(const nmDataAttribute& attr) { m_x = attr; emit sigWellDataChanged(); } nmDataAttribute& nmDataWellBase::getX() { return m_x; } void nmDataWellBase::setY(const nmDataAttribute& attr) { m_y = attr; emit sigWellDataChanged(); } nmDataAttribute& nmDataWellBase::getY() { return m_y; } void nmDataWellBase::setRadius(const nmDataAttribute& attr) { m_radius = attr; } nmDataAttribute& nmDataWellBase::getRadius() { return m_radius; } void nmDataWellBase::setDrillFloorElevation(const nmDataAttribute& attr) { m_drillFloorElevation = attr; } nmDataAttribute& nmDataWellBase::getDrillFloorElevation() { return m_drillFloorElevation; } void nmDataWellBase::setZw(const nmDataAttribute& attr) { m_zw = attr; } nmDataAttribute& nmDataWellBase::getZw() { return m_zw; } void nmDataWellBase::setWellLength(const nmDataAttribute& attr) { m_wellLength = attr; emit sigWellDataChanged(); } nmDataAttribute& nmDataWellBase::getWellLength() { return m_wellLength; } void nmDataWellBase::setRateDependentSkin(const nmDataAttribute& attr) { m_rateDependentSkin = attr; } nmDataAttribute& nmDataWellBase::getRateDependentSkin() { return m_rateDependentSkin; } void nmDataWellBase::setdSdQ(const nmDataAttribute& attr) { m_dSdQ = attr; } nmDataAttribute& nmDataWellBase::getdSdQ() { return m_dSdQ; } void nmDataWellBase::setWellboreModel(const nmDataAttribute& attr) { m_wellboreModel = attr; } nmDataAttribute& nmDataWellBase::getWellboreModel() { return m_wellboreModel; } void nmDataWellBase::setWellboreStorage(const nmDataAttribute& attr) { m_wellboreStorage = attr; } nmDataAttribute& nmDataWellBase::getWellboreStorage() { return m_wellboreStorage; } void nmDataWellBase::setBottomholeMD(const nmDataAttribute& attr) { m_bottomholeMD = attr; emit sigWellDataChanged(); } nmDataAttribute& nmDataWellBase::getBottomholeMD() { return m_bottomholeMD; } bool nmDataWellBase::isTimeDependentSkin() const { return m_bTimeDependentSkin; } void nmDataWellBase::setTimeDependentSkin(bool enabled) { m_bTimeDependentSkin = enabled; } // 获取压力曲线点数据 QVector nmDataWellBase::getPressurePoints() const { return m_vecPtsP; } // 设置压力曲线点数据 void nmDataWellBase::setPressurePoints(const QVector& points) { m_vecPtsP = points; } // 获取流量曲线点数据 QVector nmDataWellBase::getFlowPoints() const { return m_vecPtsF; } // 设置流量曲线点数据 void nmDataWellBase::setFlowPoints(const QVector& points) { m_vecPtsF = points; } int nmDataWellBase::getIndexF() const { return m_nIndexF; } void nmDataWellBase::setIndexF(const int newIndex) { m_nIndexF = newIndex; } // Location---位置 void nmDataWellBase::setInputWellHead(const nmDataAttribute& attr) { m_inputWellHead = attr; } nmDataAttribute& nmDataWellBase::getInputWellHead() { return m_inputWellHead; } void nmDataWellBase::setWellHeadX(const nmDataAttribute& attr) { m_wellHeadX = attr; } nmDataAttribute& nmDataWellBase::getWellHeadX() { return m_wellHeadX; } void nmDataWellBase::setWellHeadY(const nmDataAttribute& attr) { m_wellHeadY = attr; } nmDataAttribute& nmDataWellBase::getWellHeadY() { return m_wellHeadY; } // Wellbore---井储 void nmDataWellBase::setCInitialCFinal(const nmDataAttribute& attr) { m_cInitialCFinal = attr; } nmDataAttribute& nmDataWellBase::getCInitialCFinal() { return m_cInitialCFinal; } void nmDataWellBase::setDtChangingStorage(const nmDataAttribute& attr) { m_dtChangingStorage = attr; } nmDataAttribute& nmDataWellBase::getDtChangingStorage() { return m_dtChangingStorage; } void nmDataWellBase::setLeakSkin(const nmDataAttribute& attr) { m_leakSkin = attr; } nmDataAttribute& nmDataWellBase::getLeakSkin() { return m_leakSkin; } void nmDataWellBase::setFinalWellboreStorage(const nmDataAttribute& attr) { m_finalWellboreStorage = attr; } nmDataAttribute& nmDataWellBase::getFinalWellboreStorage() { return m_finalWellboreStorage; } bool nmDataWellBase::getPlotVisible() const { return m_bPlotVisible; } void nmDataWellBase::setPlotVisible(const bool newState) { m_bPlotVisible = newState; } void nmDataWellBase::setWellType(NM_WELL_MODEL newWellType) { m_eWellType = newWellType; } NM_WELL_MODEL nmDataWellBase::getWellType() const { return m_eWellType; } // 历史数据相关方法 QVector> nmDataWellBase::getHistoryPressure() { return m_vvecHsyPressure; } void nmDataWellBase::setHistoryPressure(QVector> pressureData) { m_vvecHsyPressure = pressureData; } QVector> nmDataWellBase::getHistoryLogLog() { return m_vvecHsyLogLog; } void nmDataWellBase::setHistoryLogLog(QVector> loglogData) { m_vvecHsyLogLog = loglogData; } QVector> nmDataWellBase::getHistorySemiLog() { return m_vvecHsySemiLog; } void nmDataWellBase::setHistorySemiLog(QVector> semiLogData) { m_vvecHsySemiLog = semiLogData; } // 计算结果相关方法 QVector> nmDataWellBase::getResultPressure() { return m_vvecRstPressure; } void nmDataWellBase::setResultPressure(QVector> pressureData) { m_vvecRstPressure = pressureData; } QVector> nmDataWellBase::getResultLogLog() { return m_vvecRstLogLog; } void nmDataWellBase::setResultLogLog(QVector> loglogData) { m_vvecRstLogLog = loglogData; } QVector> nmDataWellBase::getResultSemiLog() { return m_vvecRstSemiLog; } void nmDataWellBase::setResultSemiLog(QVector> semiLogData) { m_vvecRstSemiLog = semiLogData; } // 射孔管理相关方法 void nmDataWellBase::addPerforation(nmDataPerforation* perforation) { if(perforation) { // 确保传入的指针非空 m_vecPerforations.append(perforation); emit sigWellDataChanged(); } } void nmDataWellBase::removePerforation(int index) { if(index >= 0 && index < m_vecPerforations.size()) { delete m_vecPerforations.at(index); // 释放内存 m_vecPerforations.remove(index); // 从 QVector 中移除指针 emit sigWellDataChanged(); } } nmDataPerforation* nmDataWellBase::getPerforation(int index) { if(index >= 0 && index < m_vecPerforations.size()) { return m_vecPerforations.at(index); } return nullptr; } nmDataPerforation nmDataWellBase::getPerforationCopy(int index) { if (index >= 0 && index < m_vecPerforations.size() && m_vecPerforations[index] != nullptr) { return *m_vecPerforations[index]; // 调用拷贝构造函数 } return nmDataPerforation(); // 返回默认构造对象 } void nmDataWellBase::updatePerforation(int index, const nmDataPerforation& newData) { if (index >= 0 && index < m_vecPerforations.size() && m_vecPerforations[index] != nullptr) { *m_vecPerforations[index] = newData; // 调用赋值运算符 emit sigWellDataChanged(); // 发出数据变化信号 } } int nmDataWellBase::getPerforationCount() { return m_vecPerforations.size(); } QVector& nmDataWellBase::getPerforations() { return m_vecPerforations; } void nmDataWellBase::clearPerforations() { foreach (nmDataPerforation* perf , m_vecPerforations) { delete perf; } m_vecPerforations.clear(); } bool nmDataWellBase::isBasePerforation() { if(m_vecPerforations.size() > 1 || m_vecPerforations.size() <= 0 ) { return false; } // 检查第一个射孔段数据是不是基础射孔 nmDataPerforation* pPerf = m_vecPerforations[0]; if (pPerf == nullptr) return false; // 名称检查 if (pPerf->getName().getValue().toString() != "Perforation#1") return false; // 长度检查 double bottomholeMd = this->getBottomholeMD().getValue().toDouble(); double mdStart = pPerf->getMdStart().getValue().toDouble(); double mdEnd = pPerf->getMdEnd().getValue().toDouble(); double expectedMdEnd = bottomholeMd + this->getWellLength().getValue().toDouble(); if (qAbs(mdStart - bottomholeMd) > 1e-9) return false; if (qAbs(mdEnd - expectedMdEnd) > 1e-9) return false; // 表皮系数检查 if(qAbs(pPerf->getSkin().getValue().toDouble()) > 1e-9) return false; return true; } // 井级别的流量和时间查询方法 double nmDataWellBase::getTotalTimeRange() const { QVector allFlowPoints = getFlowPoints(); double totalTime = 0.0; for (int i = 0; i < allFlowPoints.size(); ++i) { totalTime += allFlowPoints[i].x(); } return totalTime; } double nmDataWellBase::getFlowRateAtTime(double time) const { QVector allFlowPoints = getFlowPoints(); double currentTime = 0.0; // 遍历所有流量点,找到包含指定时间的阶梯段 for (int i = 0; i < allFlowPoints.size(); ++i) { const QPointF& point = allFlowPoints.at(i); double stepStartTime = currentTime; double stepEndTime = currentTime + point.x(); // 如果时间在这个阶梯段内 if (time >= stepStartTime && time < stepEndTime) { return point.y(); // 返回该阶梯段的流量值 } currentTime = stepEndTime; // 如果时间超出了所有阶梯段,返回最后一个阶梯段的流量值 if (time >= stepEndTime && i == allFlowPoints.size() - 1) { return point.y(); } } // 如果没有找到合适的阶梯段(可能是时间为0或负数),返回第一个阶梯段的流量值 if (!allFlowPoints.isEmpty()) { return allFlowPoints.first().y(); } return 100.0; // 默认值 } QVector nmDataWellBase::getAllFlowStepBoundaries() const { QVector allBoundaries; QVector allFlowPoints = getFlowPoints(); double currentTime = 0.0; // 添加起始时间 allBoundaries.append(currentTime); // 遍历所有流量点,收集所有阶梯边界时间 for (int i = 0; i < allFlowPoints.size(); ++i) { const QPointF& point = allFlowPoints.at(i); currentTime += point.x(); allBoundaries.append(currentTime); } return allBoundaries; } QVector nmDataWellBase::getFlowStepsInTimeRange(double startTime, double endTime) const { QVector stepsInRange; QVector allFlowPoints = getFlowPoints(); double currentTime = 0.0; for (int i = 0; i < allFlowPoints.size(); ++i) { const QPointF& point = allFlowPoints.at(i); double stepStartTime = currentTime; double stepEndTime = currentTime + point.x(); // 检查这个阶梯段是否与指定时间范围有重叠 if (stepEndTime > startTime && stepStartTime < endTime) { // 计算在范围内的部分 double overlapStart = qMax(stepStartTime, startTime); double overlapEnd = qMin(stepEndTime, endTime); if (overlapEnd > overlapStart) { stepsInRange.append(QPointF(overlapEnd - overlapStart, point.y())); } } currentTime = stepEndTime; if (currentTime >= endTime) { break; // 超出范围,停止 } } return stepsInRange; } double nmDataWellBase::findFlowStepBoundaryAtTime(double timePoint) const { QVector allFlowPoints = getFlowPoints(); double currentTime = 0.0; // 遍历所有流量点,找到包含timePoint的阶梯段 for (int i = 0; i < allFlowPoints.count(); ++i) { const QPointF& point = allFlowPoints.at(i); double stepStartTime = currentTime; double stepEndTime = currentTime + point.x(); // 如果timePoint在这个阶梯段内 if (timePoint >= stepStartTime && timePoint < stepEndTime) { return stepEndTime; // 返回该阶梯段的结束时间作为分割边界 } currentTime = stepEndTime; } return -1.0; // 没有找到合适的阶梯边界 } double nmDataWellBase::findSmartFlowStepBoundary(double targetTime) const { QVector allFlowPoints = getFlowPoints(); double currentTime = 0.0; // 遍历所有流量点,找到包含targetTime的阶梯段 for (int i = 0; i < allFlowPoints.count(); ++i) { const QPointF& point = allFlowPoints.at(i); double stepStartTime = currentTime; double stepEndTime = currentTime + point.x(); // 如果targetTime在这个阶梯段内 if (targetTime >= stepStartTime && targetTime <= stepEndTime) { double stepMidTime = (stepStartTime + stepEndTime) / 2.0; // 根据在阶梯段的前半部分还是后半部分决定吸附位置 if (targetTime <= stepMidTime) { // 在前半部分,吸附到阶梯段开始 return stepStartTime; } else { // 在后半部分,吸附到阶梯段结束 return stepEndTime; } } currentTime = stepEndTime; } // 如果没有找到对应的阶梯段,使用已有的findNearestFlowStepBoundary函数 return findNearestFlowStepBoundary(targetTime); } double nmDataWellBase::findNearestFlowStepBoundary(double targetTime) const { QVector boundaries = getAllFlowStepBoundaries(); if (boundaries.isEmpty()) { return targetTime; // 如果没有边界,返回原时间 } double nearestBoundary = boundaries[0]; double minDistance = qAbs(targetTime - boundaries[0]); for (int i = 1; i < boundaries.size(); ++i) { double distance = qAbs(targetTime - boundaries[i]); if (distance < minDistance) { minDistance = distance; nearestBoundary = boundaries[i]; } } return nearestBoundary; } bool nmDataWellBase::isTimeInFlowStepFirstHalf(double time) const { QVector allFlowPoints = getFlowPoints(); double currentTime = 0.0; // 遍历所有流量点,找到包含time的阶梯段 for (int i = 0; i < allFlowPoints.count(); ++i) { const QPointF& point = allFlowPoints.at(i); double stepStartTime = currentTime; double stepEndTime = currentTime + point.x(); // 如果time在这个阶梯段内 if (time >= stepStartTime && time <= stepEndTime) { double stepMidTime = (stepStartTime + stepEndTime) / 2.0; return time <= stepMidTime; } currentTime = stepEndTime; } return false; } // 射孔段相关的查询方法 QVector nmDataWellBase::getFlowStepBoundariesInSegment(int segmentIndex, int perforationIndex) const { QVector boundaries; if (perforationIndex < 0 || perforationIndex >= m_vecPerforations.size()) { return boundaries; } nmDataPerforation* perforation = m_vecPerforations[perforationIndex]; if (!perforation) { return boundaries; } const QVector& segments = perforation->getFlowSegments(); if (segmentIndex < 0 || segmentIndex >= segments.size()) { return boundaries; } const FlowSegmentData& segment = segments[segmentIndex]; double segmentStartTime = segment.segmentStart.getValue().toDouble(); double segmentEndTime = segment.segmentEnd.getValue().toDouble(); QVector allFlowPoints = getFlowPoints(); double currentTime = 0.0; // 遍历所有流量点,找到在该段范围内的所有阶梯边界 for (int i = 0; i < allFlowPoints.size(); ++i) { const QPointF& point = allFlowPoints.at(i); double stepEndTime = currentTime + point.x(); // 如果这个阶梯段与目标段有重叠 if (stepEndTime > segmentStartTime && currentTime < segmentEndTime) { // 添加在段范围内的边界点 if (stepEndTime <= segmentEndTime) { boundaries.append(stepEndTime); } } currentTime = stepEndTime; // 如果已经超出段的结束时间,停止遍历 if (currentTime >= segmentEndTime) { break; } } // 确保最后一个边界不超过段的结束时间 if (!boundaries.isEmpty() && boundaries.last() > segmentEndTime) { boundaries[boundaries.size() - 1] = segmentEndTime; } // 如果没有找到任何边界,添加段的结束时间 if (boundaries.isEmpty()) { boundaries.append(segmentEndTime); } return boundaries; } QVector nmDataWellBase::getAllBoundariesInSegment(int segmentIndex, int perforationIndex) const { QVector allBoundaries; if (perforationIndex < 0 || perforationIndex >= m_vecPerforations.size()) { return allBoundaries; } nmDataPerforation* perforation = m_vecPerforations[perforationIndex]; if (!perforation) { return allBoundaries; } const QVector& segments = perforation->getFlowSegments(); if (segmentIndex < 0 || segmentIndex >= segments.size()) { return allBoundaries; } const FlowSegmentData& segment = segments[segmentIndex]; double segmentStartTime = segment.segmentStart.getValue().toDouble(); double segmentEndTime = segment.segmentEnd.getValue().toDouble(); // 获取流量阶梯边界 QVector flowBoundaries = getFlowStepBoundariesInSegment(segmentIndex, perforationIndex); // 添加所有边界 allBoundaries.append(segmentStartTime); for (int i = 0; i < flowBoundaries.size(); ++i) { double boundary = flowBoundaries[i]; if (boundary > segmentStartTime && boundary <= segmentEndTime) { allBoundaries.append(boundary); } } // 排序并去重 qSort(allBoundaries); for (int i = allBoundaries.size() - 1; i > 0; --i) { if (qAbs(allBoundaries[i] - allBoundaries[i - 1]) < 1e-6) { allBoundaries.remove(i); } } return allBoundaries; } int nmDataWellBase::countFlowStepsInSegment(int segmentIndex, int perforationIndex) const { if (perforationIndex < 0 || perforationIndex >= m_vecPerforations.size()) { return 0; } nmDataPerforation* perforation = m_vecPerforations[perforationIndex]; if (!perforation) { return 0; } const QVector& segments = perforation->getFlowSegments(); if (segmentIndex < 0 || segmentIndex >= segments.size()) { return 0; } const FlowSegmentData& segment = segments[segmentIndex]; double startTime = segment.segmentStart.getValue().toDouble(); double endTime = segment.segmentEnd.getValue().toDouble(); QVector stepsInRange = getFlowStepsInTimeRange(startTime, endTime); return stepsInRange.size(); } bool nmDataWellBase::canFlowSegmentBeSplit(int segmentIndex, int perforationIndex) const { return countFlowStepsInSegment(segmentIndex, perforationIndex) > 1; } double nmDataWellBase::findNearestFlowStepBoundaryBeforeSegment(int segmentIndex, int perforationIndex) const { if (perforationIndex < 0 || perforationIndex >= m_vecPerforations.size()) { return -1.0; } nmDataPerforation* perforation = m_vecPerforations[perforationIndex]; if (!perforation) { return -1.0; } const QVector& segments = perforation->getFlowSegments(); if (segmentIndex <= 0 || segmentIndex >= segments.size()) { return -1.0; // 第一个段或无效索引,无法插入 } // 获取当前段的开始时间 double currentSegmentStartTime = segments[segmentIndex].segmentStart.getValue().toDouble(); // 获取前一个段的开始和结束时间 double prevSegmentStartTime = segments[segmentIndex - 1].segmentStart.getValue().toDouble(); double prevSegmentEndTime = segments[segmentIndex - 1].segmentEnd.getValue().toDouble(); // 在前一个段内查找所有流量阶梯边界 QVector boundaries = getFlowStepBoundariesInSegment(segmentIndex - 1, perforationIndex); if (boundaries.isEmpty()) { return -1.0; } // 找到距离当前段开始时间最近的边界(但要小于当前段的开始时间,且不等于前一个段的结束时间) double nearestBoundary = -1.0; double minDistance = 1e10; for (int i = 0; i < boundaries.size(); ++i) { double boundary = boundaries[i]; // 边界必须在前一个段内部,且小于当前段的开始时间,且不等于前一个段的结束时间 if (boundary > prevSegmentStartTime && boundary < currentSegmentStartTime && qAbs(boundary - prevSegmentEndTime) > 1e-6) { // 不等于前一个段的结束时间 double distance = currentSegmentStartTime - boundary; if (distance < minDistance) { minDistance = distance; nearestBoundary = boundary; } } } return nearestBoundary; } bool nmDataWellBase::exportHistoryLogLogToCsv(const QString& outDir) { // 1) 取历史数据:期望 hist[0]=t, hist[1]=p, hist[2]=deriv QVector > hist = this->getHistoryLogLog(); if(hist.size() < 2) { return false; } const QVector& t = hist[0]; const QVector& p = hist[1]; QVector deriv; bool hasDeriv = false; if(hist.size() >= 3) { deriv = hist[2]; hasDeriv = true; } // 2) 长度检查 int n = t.size(); if(n <= 0) return false; if(p.size() != n) return false; if(hasDeriv && deriv.size() != n) { // 导数长度不一致就当没有导数 hasDeriv = false; } // 3) 输出文件名 QString wellName = this->getWellName(); // 你已有方法 if(wellName.isEmpty()) wellName = "UnknownWell"; // 文件直接放 temp 目录,不创建子目录 QString filePath = QDir(outDir).filePath(wellName + "_loglog.csv"); QFile file(filePath); if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return false; } QTextStream out(&file); // 4) 写表头 if(hasDeriv) { out << "t,p,deriv\n"; } else { out << "t,p\n"; } // 5) 正确写入:按索引 i 写 t[i], p[i], deriv[i] for(int i = 0; i < n; ++i) { // 过滤非法数据 double ti = t[i]; double pi = p[i]; if(ti <= 0) continue; if(pi <= 0) continue; out << QString::number(ti, 'g', 12) << ","; out << QString::number(pi, 'g', 12); if(hasDeriv) { double di = deriv[i]; if(di <= 0) di = 1e-12; // 你后续 log10 时需要正数 out << "," << QString::number(di, 'g', 12); } out << "\n"; } file.close(); return true; } bool nmDataWellBase::exportHistoryRateToCsv(const QString& outDir) { // 1) 获取流量点 (t, q) QVector vecTimeQ = this->getFlowPoints(); if(vecTimeQ.size() < 2) { return false; } // 2) 移除第一个点 (0,0) if(!vecTimeQ.isEmpty() && vecTimeQ[0].x() == 0.0 && vecTimeQ[0].y() == 0.0) { vecTimeQ.remove(0); } if(vecTimeQ.size() < 2) { return false; } // 3) sectionIndex(流动段索引) int sectionIndex = this->getIndexF(); // 4) 输出文件名 QString wellName = this->getWellName(); if(wellName.isEmpty()) wellName = "UnknownWell"; QString filePath = QDir(outDir).filePath(wellName + "_rate.csv"); QFile file(filePath); if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return false; } QTextStream out(&file); // 5) 写表头 out << "t,qo,sectionIndex\n"; // 6) 写入每个点 for(int i = 0; i < vecTimeQ.size(); ++i) { double ti = vecTimeQ[i].x(); double qi = vecTimeQ[i].y(); if(ti <= 0) continue; if(qi < 0) qi = 0; // 流量允许关井 out << QString::number(ti, 'g', 12) << ","; out << QString::number(qi, 'g', 12) << ","; out << sectionIndex << "\n"; } file.close(); return true; } bool nmDataWellBase::exportHistoryPressureToCsv(const QString& outDir) { // 1) 取历史压力数据:期望 hist[0]=t, hist[1]=p QVector > hist = this->getHistoryPressure(); if(hist.size() < 2) { return false; } const QVector& t = hist[0]; const QVector& p = hist[1]; // 2) 长度检查 int n = t.size(); if(n <= 0) return false; if(p.size() != n) return false; // 3) 输出文件名 QString wellName = this->getWellName(); if(wellName.isEmpty()) wellName = "UnknownWell"; // 文件直接放 temp 目录,不创建子目录 QString filePath = QDir(outDir).filePath(wellName + "_pressure.csv"); QFile file(filePath); if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return false; } QTextStream out(&file); out.setRealNumberPrecision(12); // 设置精度 // 4) 写表头 out << "t,p\n"; // 5) 写入数据 for(int i = 0; i < n; ++i) { double ti = t[i]; double pi = p[i]; // 过滤非法数据 if(ti <= 0) continue; if(pi <= 0) continue; // 假设压力为正 out << ti << "," << pi << "\n"; } file.close(); return true; } bool nmDataWellBase::exportResultLogLogToCsv(const QString& outDir) { QVector > result = this->getResultLogLog(); if(result.size() < 2) { return false; } const QVector& t = result[0]; const QVector& p = result[1]; QVector deriv; bool hasDeriv = false; if(result.size() >= 3) { deriv = result[2]; hasDeriv = true; } int n = t.size(); if(n <= 0) return false; if(p.size() != n) return false; if(hasDeriv && deriv.size() != n) { hasDeriv = false; } QString wellName = this->getWellName(); if(wellName.isEmpty()) wellName = "UnknownWell"; QString filePath = QDir(outDir).filePath(wellName + "_result_loglog.csv"); QFile file(filePath); if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return false; } QTextStream out(&file); if(hasDeriv) { out << "t,p,deriv\n"; } else { out << "t,p\n"; } for(int i = 0; i < n; ++i) { double ti = t[i]; double pi = p[i]; if(ti <= 0) continue; if(pi <= 0) continue; out << QString::number(ti, 'g', 12) << ","; out << QString::number(pi, 'g', 12); if(hasDeriv) { double di = deriv[i]; if(di <= 0) di = 1e-12; out << "," << QString::number(di, 'g', 12); } out << "\n"; } file.close(); return true; } bool nmDataWellBase::exportResultPressureToCsv(const QString& outDir) { QVector > result = this->getResultPressure(); if(result.size() < 2) { return false; } const QVector& t = result[0]; const QVector& p = result[1]; int n = t.size(); if(n <= 0) return false; if(p.size() != n) return false; QString wellName = this->getWellName(); if(wellName.isEmpty()) wellName = "UnknownWell"; QString filePath = QDir(outDir).filePath(wellName + "_result_pressure.csv"); QFile file(filePath); if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return false; } QTextStream out(&file); out.setRealNumberPrecision(12); out << "t,p\n"; for(int i = 0; i < n; ++i) { double ti = t[i]; double pi = p[i]; if(ti <= 0) continue; if(pi <= 0) continue; out << ti << "," << pi << "\n"; } file.close(); return true; }