diff --git a/Include/nmNum/nmData/nmDataAutomaticFitting.h b/Include/nmNum/nmData/nmDataAutomaticFitting.h index e2d296bf..e1b1f742 100644 --- a/Include/nmNum/nmData/nmDataAutomaticFitting.h +++ b/Include/nmNum/nmData/nmDataAutomaticFitting.h @@ -6,6 +6,20 @@ #include "nmDataAttribute.h" #include +// 一项拟合未知量,参数类型仍沿用原来的六种;储层参数的井编码为空。 +struct NM_DATA_EXPORT nmFitParameter +{ + nmFitParameter() : type(0), selected(false), initial(0.0), lower(0.0), upper(0.0) {} + QString wellCode, wellName; + int type; // 0 k,1 Skin,2 C,3 phi,4 Dfc,5 裂缝半长。 + bool selected; + double initial, lower, upper; + QString name() const; + QString code() const; + QString unit() const; + QString samplingKey() const; +}; + class NM_DATA_EXPORT nmDataAutomaticFitting : public nmDataBase { Q_OBJECT @@ -20,6 +34,11 @@ public: // 实现 nmDataBase 的抽象方法:从 RapidJSON Value 反序列化数据到当前 C++ 对象 virtual void FromJsonValue(const rapidjson::Value& jsonValue) override; + // 多井参数按表格顺序保存,旧项目无此列表时沿用原单井配置。 + QVector& getModelParameters(); + const QVector& getModelParameters() const; + bool hasSelectedParameters() const; + // Getter and Setter for permeabilityMax nmDataAttribute& getPermeabilityMax(); void setPermeabilityMax(const nmDataAttribute& permeabilityMax); @@ -97,6 +116,7 @@ public: void setFractureHalfLengthSelected(bool selected); private: + QVector m_modelParameters; // 参数最大值 nmDataAttribute m_permeabilityMax; nmDataAttribute m_skinMax; diff --git a/Include/nmNum/nmData/nmDataSensitive.h b/Include/nmNum/nmData/nmDataSensitive.h index e8cc11ef..d28dde6b 100644 --- a/Include/nmNum/nmData/nmDataSensitive.h +++ b/Include/nmNum/nmData/nmDataSensitive.h @@ -32,6 +32,10 @@ public: QString m_varGroup; // 变量名称 QString m_varName; + // 井参数使用稳定井编码区分;空编码表示共用储层参数或旧版主井参数。 + QString m_wellCode; + QString displayName() const; + QString parameterKey() const; // 是否勾选 bool m_enabled; // Mode 枚举 diff --git a/Src/nmNum/nmData/nmDataAutomaticFitting.cpp b/Src/nmNum/nmData/nmDataAutomaticFitting.cpp index 2ad649a6..680a92a7 100644 --- a/Src/nmNum/nmData/nmDataAutomaticFitting.cpp +++ b/Src/nmNum/nmData/nmDataAutomaticFitting.cpp @@ -1,4 +1,6 @@ #include "nmDataAutomaticFitting.h" +#include +#include nmDataAutomaticFitting::nmDataAutomaticFitting() { @@ -44,7 +46,8 @@ nmDataAutomaticFitting::nmDataAutomaticFitting(const nmDataAutomaticFitting& oth nmDataAutomaticFitting& nmDataAutomaticFitting::operator=(const nmDataAutomaticFitting& other) { if (this != &other) { - // 复制参数选择标志 + // 复制多井参数及原单井配置 + m_modelParameters = other.m_modelParameters; m_permeabilitySelected = other.m_permeabilitySelected; m_skinSelected = other.m_skinSelected; m_wellboreStorageSelected = other.m_wellboreStorageSelected; @@ -111,11 +114,51 @@ rapidjson::Value nmDataAutomaticFitting::ToJsonValue(rapidjson::Document::Alloca fittingObject.AddMember("AlgorithmName", rapidjson::Value(m_algorithmName.toStdString().c_str(), allocator).Move(), allocator); fittingObject.AddMember("SurrogateScreeningEnabled", m_surrogateScreeningEnabled, allocator); + // 多井配置仍存放在原自动拟合节点中,敏感性配置复用同一序列化。 + rapidjson::Value parameters(rapidjson::kArrayType); + for(int i = 0; i < m_modelParameters.size(); ++i) { + const nmFitParameter& p = m_modelParameters[i]; + rapidjson::Value item(rapidjson::kObjectType); + item.AddMember("WellCode", rapidjson::Value(p.wellCode.toUtf8().constData(), allocator).Move(), allocator); + item.AddMember("WellName", rapidjson::Value(p.wellName.toUtf8().constData(), allocator).Move(), allocator); + item.AddMember("Type", p.type, allocator); + item.AddMember("Selected", p.selected, allocator); + item.AddMember("Initial", p.initial, allocator); + item.AddMember("Lower", p.lower, allocator); + item.AddMember("Upper", p.upper, allocator); + parameters.PushBack(item, allocator); + } + fittingObject.AddMember("ModelParameters", parameters, allocator); + return fittingObject; } void nmDataAutomaticFitting::FromJsonValue(const rapidjson::Value& jsonValue) { + // 缺失列表表示旧版单井设置;非法项不进入优化向量。 + m_modelParameters.clear(); + if(jsonValue.HasMember("ModelParameters") && jsonValue["ModelParameters"].IsArray()) { + const rapidjson::Value& items = jsonValue["ModelParameters"]; + for(rapidjson::SizeType i = 0; i < items.Size(); ++i) { + const rapidjson::Value& item = items[i]; + if(!item.IsObject() || !item.HasMember("Type") || !item["Type"].IsInt() || + item["Type"].GetInt() < 0 || item["Type"].GetInt() > 5 || + !item.HasMember("Initial") || !item["Initial"].IsNumber() || + !item.HasMember("Lower") || !item["Lower"].IsNumber() || + !item.HasMember("Upper") || !item["Upper"].IsNumber()) continue; + nmFitParameter p; + p.type = item["Type"].GetInt(); + if(item.HasMember("WellCode") && item["WellCode"].IsString()) p.wellCode = QString::fromUtf8(item["WellCode"].GetString()); + if(item.HasMember("WellName") && item["WellName"].IsString()) p.wellName = QString::fromUtf8(item["WellName"].GetString()); + p.initial = item["Initial"].GetDouble(); + p.lower = item["Lower"].GetDouble(); + p.upper = item["Upper"].GetDouble(); + if(!qIsFinite(p.initial) || !qIsFinite(p.lower) || !qIsFinite(p.upper) || p.lower > p.upper) continue; + p.selected = item.HasMember("Selected") && item["Selected"].IsBool() && item["Selected"].GetBool(); + m_modelParameters.append(p); + } + } + // 反序列化参数选择标志 if (jsonValue.HasMember("PermeabilitySelected") && jsonValue["PermeabilitySelected"].IsBool()) { m_permeabilitySelected = jsonValue["PermeabilitySelected"].GetBool(); @@ -268,3 +311,56 @@ void nmDataAutomaticFitting::setAlgorithmName(const QString& algorithmName) { m_ bool nmDataAutomaticFitting::getSurrogateScreeningEnabled() const { return m_surrogateScreeningEnabled; } void nmDataAutomaticFitting::setSurrogateScreeningEnabled(bool enabled) { m_surrogateScreeningEnabled = enabled; } + +QString nmFitParameter::name() const +{ + // 井参数携带井名,共用参数保持原名称和翻译。 + const char* names[] = {"Permeability", "Skin", "Wellbore storage", "Porosity", "Fracture conductivity", "Fracture half length"}; + const QString label = QCoreApplication::translate("nmWxAutomaticFitting", names[type]); + return wellCode.isEmpty() ? label : wellName + " / " + label; +} + +QString nmFitParameter::code() const +{ + // 结果面板继续使用已有 XML 参数编码。 + const char* codes[] = {"K", "Skin", "C", "phi", "Dfc", "FractureHalfLength"}; + return codes[type]; +} + +QString nmFitParameter::unit() const +{ + // 与既有六参数的基准单位一致。 + const char* units[] = {"mD", "", "m^3/MPa", "", "mD.m", "m"}; + return units[type]; +} + +QString nmFitParameter::samplingKey() const +{ + // 同井同参数才与敏感性采样互斥。 + const QString names[] = {"k", "Skin", "C", QString(QChar(0x03c6)), "Dfc", "FractureHalfLength"}; + return wellCode.isEmpty() ? names[type] : wellCode + "/" + names[type]; +} + +QVector& nmDataAutomaticFitting::getModelParameters() +{ + // 窗口在自己的配置副本上编辑。 + return m_modelParameters; +} + +const QVector& nmDataAutomaticFitting::getModelParameters() const +{ + // 后台计算只读取启动前冻结的设置。 + return m_modelParameters; +} + +bool nmDataAutomaticFitting::hasSelectedParameters() const +{ + // 新配置检查完整多井列表,旧配置兼容原六个勾选标志。 + if(!m_modelParameters.isEmpty()) { + for(int i = 0; i < m_modelParameters.size(); ++i) + if(m_modelParameters[i].selected) return true; + return false; + } + return m_permeabilitySelected || m_skinSelected || m_wellboreStorageSelected || + m_porositySelected || m_fractureConductivitySelected || m_fractureHalfLengthSelected; +} diff --git a/Src/nmNum/nmData/nmDataSensitive.cpp b/Src/nmNum/nmData/nmDataSensitive.cpp index dab62f08..3d6acbb1 100644 --- a/Src/nmNum/nmData/nmDataSensitive.cpp +++ b/Src/nmNum/nmData/nmDataSensitive.cpp @@ -277,6 +277,7 @@ rapidjson::Value nmDataSensitive::VariableSampling::ToJsonValue( rapidjson::Document::AllocatorType& allocator) const { rapidjson::Value obj(rapidjson::kObjectType); + obj.AddMember("WellCode", rapidjson::Value(m_wellCode.toUtf8().constData(), allocator).Move(), allocator); // 字符串字段 obj.AddMember("VarGroup", @@ -320,6 +321,8 @@ void nmDataSensitive::VariableSampling::FromJsonValue(const rapidjson::Value& js { // 旧文件未保存分布时保留默认状态,由分析窗口按模型值初始化。 *this = VariableSampling(); + m_wellCode = jsonValue.HasMember("WellCode") && jsonValue["WellCode"].IsString() + ? QString::fromUtf8(jsonValue["WellCode"].GetString()) : QString(); if(jsonValue.HasMember("Distribution") && jsonValue["Distribution"].IsInt()) { const int distribution = jsonValue["Distribution"].GetInt(); if(distribution >= NORMAL && distribution <= TRIANGULAR) @@ -385,6 +388,18 @@ void nmDataSensitive::VariableSampling::setVarGroup(const QString& group) } // varName +QString nmDataSensitive::VariableSampling::displayName() const +{ + // 预览与曲线标注同时显示井名,避免不同井的同名参数混淆。 + return m_wellCode.isEmpty() ? m_varName : m_varGroup + " / " + m_varName; +} + +QString nmDataSensitive::VariableSampling::parameterKey() const +{ + // 参数互斥按所属井判断,共用储层参数仍只使用参数名。 + return m_wellCode.isEmpty() ? m_varName : m_wellCode + "/" + m_varName; +} + QString nmDataSensitive::VariableSampling::getVarName() const { return m_varName;