#include "nmReservoirPropertiesSession.h" #include "nmAttrRegistry.h" #include "nmDataAttribute.h" #include "rapidjson/document.h" namespace { /** @brief 比较两个QVariant数值,保留字符串和整数的精确语义。 */ bool sameValue(const QVariant& oLeft, const QVariant& oRight) { return oLeft == oRight; } template bool sameDataObject(const T& oLeft, const T& oRight) { rapidjson::Document oLeftDocument; rapidjson::Document oRightDocument; rapidjson::Value oLeftValue = oLeft.ToJsonValue( oLeftDocument.GetAllocator()); rapidjson::Value oRightValue = oRight.ToJsonValue( oRightDocument.GetAllocator()); return oLeftValue == oRightValue; } template bool sameDataVector(const QVector& vecLeft, const QVector& vecRight) { if(vecLeft.size() != vecRight.size()) { return false; } for(int nIndex = 0; nIndex < vecLeft.size(); ++nIndex) { if(!sameDataObject(vecLeft[nIndex], vecRight[nIndex])) { return false; } } return true; } /** @brief 比较两口井的平面位置。 */ bool sameWellPosition(nmDataWellBase& oLeft, nmDataWellBase& oRight) { return sameValue(oLeft.getX().getValue(), oRight.getX().getValue()) && sameValue(oLeft.getY().getValue(), oRight.getY().getValue()); } } nmReservoirPropertiesSession::nmReservoirPropertiesSession( nmIReservoirPropertiesDataSource* pDataSource) : m_pDataSource(pDataSource), m_pAttrRegistry(new nmAttrRegistry), m_bInitialized(false) { } nmReservoirPropertiesSession::~nmReservoirPropertiesSession() { delete m_pAttrRegistry; m_pAttrRegistry = nullptr; m_pDataSource = nullptr; } bool nmReservoirPropertiesSession::initialize(QString& sError) { // 第一步:读取一次真实数据,作为取消和变更检测的基线。 if (m_pDataSource == nullptr || !m_pDataSource->loadSnapshot(m_oOriginalSnapshot, sError)) { m_bInitialized = false; return false; } // 第二步:复制出独立工作副本,后续界面修改只写入此对象。 m_oWorkingSnapshot = m_oOriginalSnapshot; nmReservoirParameterCatalog::registerSnapshot(m_pAttrRegistry, m_oWorkingSnapshot); m_bInitialized = true; sError.clear(); return true; } QList nmReservoirPropertiesSession::objectInfos( nmReservoirPropertiesCategory eCategory) { if (!m_bInitialized) { return QList(); } return nmReservoirParameterCatalog::createObjectInfos(eCategory, m_oWorkingSnapshot); } QVariant nmReservoirPropertiesSession::value(const QString& sParameterId) const { if (!m_bInitialized || m_pAttrRegistry == nullptr) { return QVariant(); } QStringList listIds; listIds << sParameterId; return m_pAttrRegistry->collect(listIds).value(sParameterId, QVariant()); } bool nmReservoirPropertiesSession::setValue(const QString& sParameterId, const QVariant& oValue) { if (!m_bInitialized || m_pAttrRegistry == nullptr || !m_pAttrRegistry->registeredNames().contains(sParameterId)) { return false; } if (sameValue(value(sParameterId), oValue)) { return true; } m_pAttrRegistry->setValue(sParameterId, oValue); return true; } void nmReservoirPropertiesSession::setValues( const QMap& mapValues) { QMap::const_iterator oIterator = mapValues.constBegin(); for (; oIterator != mapValues.constEnd(); ++oIterator) { setValue(oIterator.key(), oIterator.value()); } } QString nmReservoirPropertiesSession::enumCode(const QString& sParameterId) const { if (!m_bInitialized) { return QString(); } return nmReservoirParameterCatalog::enumCode(m_oWorkingSnapshot, sParameterId); } bool nmReservoirPropertiesSession::setEnumCode(const QString& sParameterId, const QString& sCode) { if (!m_bInitialized) { return false; } if (enumCode(sParameterId) == sCode) { return true; } if (!nmReservoirParameterCatalog::setEnumCode(m_oWorkingSnapshot, sParameterId, sCode)) { return false; } return true; } bool nmReservoirPropertiesSession::commit(QString& sError) { if (!m_bInitialized || m_pDataSource == nullptr) { sError = QObject::tr("The reservoir properties editing session is unavailable."); return false; } // 第一步:几何变化优先级最高;其他正式输入只推进结果版本。 NM_PEBI_INPUT_CHANGE eInputChange = NM_PEBI_INPUT_UNCHANGED; if (isGeometryChanged()) { eInputChange = NM_PEBI_GRID_INPUT_CHANGED; } else if (isInputChanged()) { eInputChange = NM_PEBI_RESULT_INPUT_CHANGED; } // 第二步:将完整工作副本一次性交给数据源;失败时继续保留当前编辑内容。 if (!m_pDataSource->commitSnapshot(m_oWorkingSnapshot, eInputChange, sError)) { return false; } // 第三步:提交成功后更新基线,防止同一会话重复识别旧变更。 m_oOriginalSnapshot = m_oWorkingSnapshot; sError.clear(); return true; } const nmReservoirPropertiesSnapshot& nmReservoirPropertiesSession::workingSnapshot() const { return m_oWorkingSnapshot; } bool nmReservoirPropertiesSession::isInputChanged() const { // 完整结构化比较覆盖数值、枚举和批量导入,不依赖具体界面入口。 return m_oOriginalSnapshot.m_nSolverModelType != m_oWorkingSnapshot.m_nSolverModelType || !sameDataObject(m_oOriginalSnapshot.m_oReservoir, m_oWorkingSnapshot.m_oReservoir) || !sameDataVector(m_oOriginalSnapshot.m_vecVerticalWells, m_oWorkingSnapshot.m_vecVerticalWells) || !sameDataVector(m_oOriginalSnapshot.m_vecVerticalFracturedWells, m_oWorkingSnapshot.m_vecVerticalFracturedWells) || !sameDataVector(m_oOriginalSnapshot.m_vecHorizontalFracturedWells, m_oWorkingSnapshot.m_vecHorizontalFracturedWells) || !sameDataVector(m_oOriginalSnapshot.m_vecRegionMarks, m_oWorkingSnapshot.m_vecRegionMarks) || !sameDataVector(m_oOriginalSnapshot.m_vecFaults, m_oWorkingSnapshot.m_vecFaults) || !sameDataVector(m_oOriginalSnapshot.m_vecFractures, m_oWorkingSnapshot.m_vecFractures) || !sameDataVector(m_oOriginalSnapshot.m_vecRegions, m_oWorkingSnapshot.m_vecRegions); } bool nmReservoirPropertiesSession::isGeometryChanged() const { // 第一步:对象数量变化视为几何变化,虽然当前对话框本身不提供增删操作。 if (m_oOriginalSnapshot.m_vecVerticalWells.size() != m_oWorkingSnapshot.m_vecVerticalWells.size() || m_oOriginalSnapshot.m_vecVerticalFracturedWells.size() != m_oWorkingSnapshot.m_vecVerticalFracturedWells.size() || m_oOriginalSnapshot.m_vecHorizontalFracturedWells.size() != m_oWorkingSnapshot.m_vecHorizontalFracturedWells.size()) { return true; } // 第二步:比较三类井的位置和井径。 for (int nIndex = 0; nIndex < m_oWorkingSnapshot.m_vecVerticalWells.size(); ++nIndex) { nmDataVerticalWell& oOriginal = const_cast(m_oOriginalSnapshot.m_vecVerticalWells[nIndex]); nmDataVerticalWell& oWorking = const_cast(m_oWorkingSnapshot.m_vecVerticalWells[nIndex]); if (!sameWellPosition(oOriginal, oWorking) || !sameValue(oOriginal.getRadius().getValue(), oWorking.getRadius().getValue())) { return true; } } for (int nIndex = 0; nIndex < m_oWorkingSnapshot.m_vecVerticalFracturedWells.size(); ++nIndex) { nmDataVerticalFracturedWell& oOriginal = const_cast( m_oOriginalSnapshot.m_vecVerticalFracturedWells[nIndex]); nmDataVerticalFracturedWell& oWorking = const_cast( m_oWorkingSnapshot.m_vecVerticalFracturedWells[nIndex]); if (!sameWellPosition(oOriginal, oWorking) || !sameValue(oOriginal.getFractureHalfLength().getValue(), oWorking.getFractureHalfLength().getValue()) || !sameValue(oOriginal.getFractureAngle().getValue(), oWorking.getFractureAngle().getValue()) || !sameValue(oOriginal.getWidth().getValue(), oWorking.getWidth().getValue()) || !sameValue(oOriginal.getDfc().getValue(), oWorking.getDfc().getValue())) { return true; } } for (int nIndex = 0; nIndex < m_oWorkingSnapshot.m_vecHorizontalFracturedWells.size(); ++nIndex) { nmDataHorizontalFracturedWell& oOriginal = const_cast( m_oOriginalSnapshot.m_vecHorizontalFracturedWells[nIndex]); nmDataHorizontalFracturedWell& oWorking = const_cast( m_oWorkingSnapshot.m_vecHorizontalFracturedWells[nIndex]); if (!sameWellPosition(oOriginal, oWorking) || !sameValue(oOriginal.getWellLength().getValue(), oWorking.getWellLength().getValue()) || !sameValue(oOriginal.getDrainAngle().getValue(), oWorking.getDrainAngle().getValue()) || !sameValue(oOriginal.getNumberOfFractures().getValue(), oWorking.getNumberOfFractures().getValue()) || !sameValue(oOriginal.getFractureHalfLength().getValue(), oWorking.getFractureHalfLength().getValue()) || !sameValue(oOriginal.getFractureAngle().getValue(), oWorking.getFractureAngle().getValue()) || !sameValue(oOriginal.getWidth().getValue(), oWorking.getWidth().getValue()) || !sameValue(oOriginal.getDfc().getValue(), oWorking.getDfc().getValue())) { return true; } } // 第三步:断层和裂缝端点也直接参与网格,因此比较完整点坐标。 if (m_oOriginalSnapshot.m_vecFaults.size() != m_oWorkingSnapshot.m_vecFaults.size() || m_oOriginalSnapshot.m_vecFractures.size() != m_oWorkingSnapshot.m_vecFractures.size()) { return true; } for (int nIndex = 0; nIndex < m_oWorkingSnapshot.m_vecFaults.size(); ++nIndex) { if (m_oOriginalSnapshot.m_vecFaults[nIndex].getFaultPoints() != m_oWorkingSnapshot.m_vecFaults[nIndex].getFaultPoints()) { return true; } } for (int nIndex = 0; nIndex < m_oWorkingSnapshot.m_vecFractures.size(); ++nIndex) { if (m_oOriginalSnapshot.m_vecFractures[nIndex].getFracturePoints() != m_oWorkingSnapshot.m_vecFractures[nIndex].getFracturePoints()) { return true; } } return false; }