feat(nmNum): 完善敏感性分析参数选择与采样配置

- 绑定六个参数的真实模型值,统一单位转换、配置保存与物理范围校验。
- 完善自动和手动采样,实现两种确定性方法的次数统计与分页组合预览。
- 调整 Skin 和压力默认范围,统一有效数字显示并保留原始采样精度。
feature/Sensitivity-20261012
lvjunjie 2 weeks ago
parent 879b495662
commit e18988426e

@ -87,6 +87,8 @@ public:
// values // values
QVector<double>& getValues(); QVector<double>& getValues();
void setValues(const QVector<double>& vals); void setValues(const QVector<double>& vals);
// 自动采样始终保留原始精度;手动模式直接返回用户指定值。
QVector<double> samplingValues() const;
}; };
public: public:
@ -104,8 +106,13 @@ public:
void setCalculationType(CalculationType type); void setCalculationType(CalculationType type);
// === 总模型数 === // === 总模型数 ===
int getTotalModelCount() const; quint64 getTotalModelCount() const;
void setTotalModelCount(int count); void setTotalModelCount(quint64 count);
quint64 calculateModelCount(bool* overflow = nullptr) const;
// 返回与变量列表对应的基准单位值,未改变的参数保持模型值。
bool getRunValues(quint64 runIndex, QVector<double>& values) const;
bool usesBaseUnits() const;
void setUsesBaseUnits(bool enabled);
// === 变量列表 === // === 变量列表 ===
QList<VariableSampling>& getVariables(); QList<VariableSampling>& getVariables();
@ -116,7 +123,8 @@ public:
private: private:
CalculationType m_calcType; CalculationType m_calcType;
int m_totalModelCount; quint64 m_totalModelCount;
bool m_usesBaseUnits;
QList<VariableSampling> m_variables; QList<VariableSampling> m_variables;
}; };

@ -13,7 +13,8 @@ class QPushButton;
class QStackedWidget; class QStackedWidget;
class QCheckBox; class QCheckBox;
class QSpinBox; class QSpinBox;
class QDoubleSpinBox; class QLineEdit;
class nmDataAnalyzeManager;
class QTableWidget; class QTableWidget;
class QLabel; class QLabel;
class QIcon; class QIcon;
@ -23,7 +24,7 @@ class NM_SUB_WXS_EXPORT nmWxSensitive : public iDlgBase
Q_OBJECT Q_OBJECT
public: public:
explicit nmWxSensitive(QWidget *parent = 0); explicit nmWxSensitive(QWidget *parent = 0, nmDataAnalyzeManager* manager = nullptr);
~nmWxSensitive(); ~nmWxSensitive();
private slots: private slots:
@ -32,7 +33,13 @@ public:
void onCalculationTypeChanged(int index); void onCalculationTypeChanged(int index);
void onTreeItemClicked(QTreeWidgetItem *item, int column); void onTreeItemClicked(QTreeWidgetItem *item, int column);
void onVariableParamChanged(); void onVariableParamChanged();
void onSamplingEditingFinished();
void onTableCellClicked(int row, int column); void onTableCellClicked(int row, int column);
void onTreeItemChanged(QTreeWidgetItem *item, int column);
void onPreviewClicked();
void onPreviewPrevious();
void onPreviewNext();
void onPreviewJump();
private: private:
void setupUI(); void setupUI();
@ -44,7 +51,10 @@ private:
QIcon createTriangleIcon(); // 创建三角箭头图标 QIcon createTriangleIcon(); // 创建三角箭头图标
void loadDataToUI(); // 从数据加载到界面 void loadDataToUI(); // 从数据加载到界面
void saveDataFromUI(); // 从界面保存到数据 bool saveDataFromUI(); // 校验并从界面保存到数据
void refreshModelValues();
void updateModelCount();
void refreshPreviewPage();
int findVariableIndex(const QString& varName); // 查找变量索引 int findVariableIndex(const QString& varName); // 查找变量索引
// UI 控件 // UI 控件
@ -54,19 +64,26 @@ private:
QLabel *modelCountLabel; QLabel *modelCountLabel;
QPushButton *generateButton; QPushButton *generateButton;
QPushButton *cancelButton; QPushButton *cancelButton;
QPushButton *previewButton;
// 各个变量页面的控件列表 // 各个变量页面的控件列表
QList<QComboBox*> m_modeCombos; QList<QComboBox*> m_modeCombos;
QList<QCheckBox*> m_logChecks; QList<QCheckBox*> m_logChecks;
QList<QSpinBox*> m_numSpins; QList<QSpinBox*> m_numSpins;
QList<QDoubleSpinBox*> m_modelSpins; QList<QLineEdit*> m_modelSpins;
QList<QDoubleSpinBox*> m_minSpins; QList<QLineEdit*> m_minSpins;
QList<QDoubleSpinBox*> m_maxSpins; QList<QLineEdit*> m_maxSpins;
QList<QTableWidget*> m_valueTables; QList<QTableWidget*> m_valueTables;
QList<QLabel*> m_unitLabels; QList<QLabel*> m_unitLabels;
// 跟踪当前选中的值索引 // 跟踪当前选中的值索引
int m_selectedValueIndex; int m_selectedValueIndex;
bool m_loading;
nmDataAnalyzeManager* m_pDataManager;
QTableWidget* m_previewTable;
QLineEdit* m_previewPageEdit;
QLabel* m_previewPageLabel;
quint64 m_previewPage;
// 敏感分析数据 // 敏感分析数据
nmDataSensitive m_sensitiveData; nmDataSensitive m_sensitiveData;

@ -1,4 +1,6 @@
#include "nmDataSensitive.h" #include "nmDataSensitive.h"
#include <cmath>
#include <limits>
nmDataSensitive::VariableSampling::VariableSampling() nmDataSensitive::VariableSampling::VariableSampling()
: m_varGroup("") : m_varGroup("")
@ -204,10 +206,33 @@ void nmDataSensitive::VariableSampling::setValues(const QVector<double>& vals)
m_values = vals; m_values = vals;
} }
QVector<double> nmDataSensitive::VariableSampling::samplingValues() const
{
// 表格显示精度不参与采样,包含零或负数的对数范围按线性处理。
if (m_mode == MODE_MANUAL) return m_values;
QVector<double> values;
if (m_number <= 0) return values;
const double minimum = m_minValue.getValue().toDouble();
const double maximum = m_maxValue.getValue().toDouble();
const bool logarithmic = m_log && minimum > 0.0 && maximum > 0.0;
for (int i = 0; i < m_number; ++i) {
const double t = m_number == 1 ? 0.0 : double(i) / (m_number - 1);
double value = logarithmic
? std::exp((1.0 - t) * std::log(minimum) + t * std::log(maximum))
: (1.0 - t) * minimum + t * maximum;
if (m_number == 1) value = m_modelValue.getValue().toDouble();
else if (i == 0) value = minimum;
else if (i == m_number - 1) value = maximum;
values.append(value);
}
return values;
}
nmDataSensitive::nmDataSensitive() nmDataSensitive::nmDataSensitive()
: m_calcType(CALC_DETERMINISTIC) : m_calcType(CALC_DETERMINISTIC)
, m_totalModelCount(0) , m_totalModelCount(0)
, m_usesBaseUnits(false)
, m_variables() , m_variables()
{ {
} }
@ -224,6 +249,7 @@ nmDataSensitive& nmDataSensitive::operator=(const nmDataSensitive& other)
if (this != &other) { if (this != &other) {
m_calcType = other.m_calcType; m_calcType = other.m_calcType;
m_totalModelCount = other.m_totalModelCount; m_totalModelCount = other.m_totalModelCount;
m_usesBaseUnits = other.m_usesBaseUnits;
m_variables = other.m_variables; m_variables = other.m_variables;
} }
return *this; return *this;
@ -238,6 +264,8 @@ rapidjson::Value nmDataSensitive::ToJsonValue(
rapidjson::Document::AllocatorType& allocator) const rapidjson::Document::AllocatorType& allocator) const
{ {
rapidjson::Value root(rapidjson::kObjectType); rapidjson::Value root(rapidjson::kObjectType);
// 旧配置中的采样值是显示单位,新配置统一保存业务基准单位。
root.AddMember("UsesBaseUnits", m_usesBaseUnits, allocator);
// 顶部 Calculation type // 顶部 Calculation type
root.AddMember("CalculationType", root.AddMember("CalculationType",
@ -262,6 +290,8 @@ rapidjson::Value nmDataSensitive::ToJsonValue(
// 从 RapidJSON Value 反序列化数据到 nmDataSensitive // 从 RapidJSON Value 反序列化数据到 nmDataSensitive
void nmDataSensitive::FromJsonValue(const rapidjson::Value& jsonValue) void nmDataSensitive::FromJsonValue(const rapidjson::Value& jsonValue)
{ {
m_usesBaseUnits = jsonValue.HasMember("UsesBaseUnits") &&
jsonValue["UsesBaseUnits"].IsBool() && jsonValue["UsesBaseUnits"].GetBool();
if (jsonValue.HasMember("CalculationType") && jsonValue["CalculationType"].IsInt()) { if (jsonValue.HasMember("CalculationType") && jsonValue["CalculationType"].IsInt()) {
int t = jsonValue["CalculationType"].GetInt(); int t = jsonValue["CalculationType"].GetInt();
if (t == CALC_DETERMINISTIC_MULTIVARIATE) if (t == CALC_DETERMINISTIC_MULTIVARIATE)
@ -270,8 +300,8 @@ void nmDataSensitive::FromJsonValue(const rapidjson::Value& jsonValue)
m_calcType = CALC_DETERMINISTIC; m_calcType = CALC_DETERMINISTIC;
} }
if (jsonValue.HasMember("TotalModelCount") && jsonValue["TotalModelCount"].IsInt()) { if (jsonValue.HasMember("TotalModelCount") && jsonValue["TotalModelCount"].IsUint64()) {
m_totalModelCount = jsonValue["TotalModelCount"].GetInt(); m_totalModelCount = jsonValue["TotalModelCount"].GetUint64();
} }
m_variables.clear(); m_variables.clear();
@ -300,16 +330,87 @@ void nmDataSensitive::setCalculationType(CalculationType type)
} }
// === 总模型数 === // === 总模型数 ===
int nmDataSensitive::getTotalModelCount() const quint64 nmDataSensitive::getTotalModelCount() const
{ {
return m_totalModelCount; return m_totalModelCount;
} }
void nmDataSensitive::setTotalModelCount(int count) void nmDataSensitive::setTotalModelCount(quint64 count)
{ {
m_totalModelCount = count; m_totalModelCount = count;
} }
quint64 nmDataSensitive::calculateModelCount(bool* overflow) const
{
// 未选择变量时为零;两种确定性方法分别累计和、积。
if (overflow) *overflow = false;
quint64 count = 0;
bool selected = false;
for (int i = 0; i < m_variables.size(); ++i) {
const VariableSampling& variable = m_variables[i];
if (!variable.m_enabled) continue;
const quint64 number = variable.m_number > 0 ? variable.m_number : 0;
if (!number) return 0;
const quint64 limit = (std::numeric_limits<quint64>::max)();
if (m_calcType == CALC_DETERMINISTIC) {
if (count > limit - number) { if (overflow) *overflow = true; return 0; }
count += number;
} else {
if (!selected) count = 1;
if (count > limit / number) { if (overflow) *overflow = true; return 0; }
count *= number;
}
selected = true;
}
return count;
}
bool nmDataSensitive::getRunValues(quint64 runIndex, QVector<double>& values) const
{
// 按编号解码组合,不预先展开笛卡尔积,也不删除重复的基准组合。
bool overflow = false;
const quint64 count = calculateModelCount(&overflow);
if (overflow || runIndex >= count) return false;
values.clear();
for (int i = 0; i < m_variables.size(); ++i)
values.append(m_variables[i].m_modelValue.getValue().toDouble());
if (m_calcType == CALC_DETERMINISTIC) {
for (int i = 0; i < m_variables.size(); ++i) {
const VariableSampling& variable = m_variables[i];
if (!variable.m_enabled) continue;
const QVector<double> samples = variable.samplingValues();
if (samples.size() != variable.m_number) return false;
if (runIndex < quint64(samples.size())) {
values[i] = samples[int(runIndex)];
return true;
}
runIndex -= samples.size();
}
} else {
for (int i = m_variables.size() - 1; i >= 0; --i) {
const VariableSampling& variable = m_variables[i];
if (!variable.m_enabled) continue;
const QVector<double> samples = variable.samplingValues();
if (samples.isEmpty() || samples.size() != variable.m_number) return false;
values[i] = samples[int(runIndex % samples.size())];
runIndex /= samples.size();
}
return true;
}
return false;
}
bool nmDataSensitive::usesBaseUnits() const
{
return m_usesBaseUnits;
}
void nmDataSensitive::setUsesBaseUnits(bool enabled)
{
// 单位标记随配置保存,避免再次打开时重复转换。
m_usesBaseUnits = enabled;
}
// === 变量列表 === // === 变量列表 ===
QList<nmDataSensitive::VariableSampling>& nmDataSensitive::getVariables() QList<nmDataSensitive::VariableSampling>& nmDataSensitive::getVariables()
{ {

@ -1444,7 +1444,7 @@ void nmWxNumericalDesign::onForecastClicked()
void nmWxNumericalDesign::onSensitiveClicked() void nmWxNumericalDesign::onSensitiveClicked()
{ {
nmWxSensitive* dlg = new nmWxSensitive(); nmWxSensitive* dlg = new nmWxSensitive(this, m_pDataManager);
dlg->show(); dlg->show();
} }

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save