feat(nmNum): 增加参数上下限汇总

- 按散点图阈值统计参数上下限。
- 结果面板显示运行次数、阈值和参数范围。
- 保留批次筛选状态,空筛选隐藏范围。
feature/Sensitivity-20261012
lvjunjie 1 week ago
parent a1356f5555
commit 36f54d9b12

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -129,4 +129,22 @@
<ParaItem Name="Result_Cg" Alias="气压缩系数" Unit="1/MPa" Default="0" Max="1e+30" Min="0" Digit="10" Scientific="1" Desc="result gas compressibility" />
</ParaGroup>
<!-- 敏感性结果按阈值筛选后显示,空筛选不创建参数上下限行。 -->
<ParaGroup Name="" Alias="结果参数">
<ParaItem Name="Sensitivity_RunCount" Alias="蒙特卡洛运行次数" Unit="" Default="0" Max="1e+30" Min="0" Digit="0" Desc="Monte Carlo run count" />
<ParaItem Name="Sensitivity_Threshold" Alias="阈值" Unit="MPa" Default="0" Max="1e+30" Min="0" Digit="6" Desc="goodness of fit threshold" />
<ParaItem Name="Sensitivity_Skin_Lower" Alias="表皮系数 - 下限" Unit="" Default="0" Max="1000" Min="-100" Digit="6" Desc="filtered Skin lower bound" />
<ParaItem Name="Sensitivity_Skin_Higher" Alias="表皮系数 - 上限" Unit="" Default="0" Max="1000" Min="-100" Digit="6" Desc="filtered Skin higher bound" />
<ParaItem Name="Sensitivity_C_Lower" Alias="井筒储集系数 - 下限" Unit="m^3/MPa" Default="0" Max="1000" Min="0" Digit="6" Desc="filtered C lower bound" />
<ParaItem Name="Sensitivity_C_Higher" Alias="井筒储集系数 - 上限" Unit="m^3/MPa" Default="0" Max="1000" Min="0" Digit="6" Desc="filtered C higher bound" />
<ParaItem Name="Sensitivity_Pi_Lower" Alias="初始地层压力 - 下限" Unit="MPa" Default="40" Max="500" Min="0.1" Digit="6" Desc="filtered Pi lower bound" />
<ParaItem Name="Sensitivity_Pi_Higher" Alias="初始地层压力 - 上限" Unit="MPa" Default="40" Max="500" Min="0.1" Digit="6" Desc="filtered Pi higher bound" />
<ParaItem Name="Sensitivity_K_Lower" Alias="渗透率 - 下限" Unit="mD" Default="25" Max="10000" Min="0" Digit="6" Desc="filtered K lower bound" />
<ParaItem Name="Sensitivity_K_Higher" Alias="渗透率 - 上限" Unit="mD" Default="25" Max="10000" Min="0" Digit="6" Desc="filtered K higher bound" />
<ParaItem Name="Sensitivity_h_Lower" Alias="储层厚度 - 下限" Unit="m" Default="10" Max="10000" Min="1e-05" Digit="6" Desc="filtered h lower bound" />
<ParaItem Name="Sensitivity_h_Higher" Alias="储层厚度 - 上限" Unit="m" Default="10" Max="10000" Min="1e-05" Digit="6" Desc="filtered h higher bound" />
<ParaItem Name="Sensitivity_phi_Lower" Alias="孔隙度 - 下限" Unit="" Default="0.1" Max="1" Min="1e-05" Digit="6" Desc="filtered phi lower bound" />
<ParaItem Name="Sensitivity_phi_Higher" Alias="孔隙度 - 上限" Unit="" Default="0.1" Max="1" Min="1e-05" Digit="6" Desc="filtered phi higher bound" />
</ParaGroup>
</Root>

@ -130,4 +130,22 @@
<ParaItem Name="Result_Cg" Alias="Gas Compressibility" Unit="1/MPa" Default="0" Max="1e+30" Min="0" Digit="10" Scientific="1" Desc="result gas compressibility" />
</ParaGroup>
<!-- 敏感性结果按阈值筛选后显示,空筛选不创建参数上下限行。 -->
<ParaGroup Name="" Alias="Result Parameters">
<ParaItem Name="Sensitivity_RunCount" Alias="Number of Monte Carlo runs" Unit="" Default="0" Max="1e+30" Min="0" Digit="0" Desc="Monte Carlo run count" />
<ParaItem Name="Sensitivity_Threshold" Alias="Threshold" Unit="MPa" Default="0" Max="1e+30" Min="0" Digit="6" Desc="goodness of fit threshold" />
<ParaItem Name="Sensitivity_Skin_Lower" Alias="Skin - Lower" Unit="" Default="0" Max="1000" Min="-100" Digit="6" Desc="filtered Skin lower bound" />
<ParaItem Name="Sensitivity_Skin_Higher" Alias="Skin - Higher" Unit="" Default="0" Max="1000" Min="-100" Digit="6" Desc="filtered Skin higher bound" />
<ParaItem Name="Sensitivity_C_Lower" Alias="C - Lower" Unit="m^3/MPa" Default="0" Max="1000" Min="0" Digit="6" Desc="filtered C lower bound" />
<ParaItem Name="Sensitivity_C_Higher" Alias="C - Higher" Unit="m^3/MPa" Default="0" Max="1000" Min="0" Digit="6" Desc="filtered C higher bound" />
<ParaItem Name="Sensitivity_Pi_Lower" Alias="Pi - Lower" Unit="MPa" Default="40" Max="500" Min="0.1" Digit="6" Desc="filtered Pi lower bound" />
<ParaItem Name="Sensitivity_Pi_Higher" Alias="Pi - Higher" Unit="MPa" Default="40" Max="500" Min="0.1" Digit="6" Desc="filtered Pi higher bound" />
<ParaItem Name="Sensitivity_K_Lower" Alias="k - Lower" Unit="mD" Default="25" Max="10000" Min="0" Digit="6" Desc="filtered K lower bound" />
<ParaItem Name="Sensitivity_K_Higher" Alias="k - Higher" Unit="mD" Default="25" Max="10000" Min="0" Digit="6" Desc="filtered K higher bound" />
<ParaItem Name="Sensitivity_h_Lower" Alias="h - Lower" Unit="m" Default="10" Max="10000" Min="1e-05" Digit="6" Desc="filtered h lower bound" />
<ParaItem Name="Sensitivity_h_Higher" Alias="h - Higher" Unit="m" Default="10" Max="10000" Min="1e-05" Digit="6" Desc="filtered h higher bound" />
<ParaItem Name="Sensitivity_phi_Lower" Alias="φ - Lower" Unit="" Default="0.1" Max="1" Min="1e-05" Digit="6" Desc="filtered phi lower bound" />
<ParaItem Name="Sensitivity_phi_Higher" Alias="φ - Higher" Unit="" Default="0.1" Max="1" Min="1e-05" Digit="6" Desc="filtered phi higher bound" />
</ParaGroup>
</Root>

@ -118,7 +118,7 @@ public:
struct NM_DATA_EXPORT BatchResult
{
BatchResult() : m_calcType(CALC_DETERMINISTIC), m_bCompleted(false), m_bStopped(false) {}
BatchResult() : m_calcType(CALC_DETERMINISTIC), m_dFilterThreshold(-1.0), m_bCompleted(false), m_bStopped(false) {}
CalculationType m_calcType;
QList<VariableSampling> m_variables; // 求解时冻结的配置,独立于之后的参数编辑。
QString m_sWellCode;
@ -130,6 +130,9 @@ public:
QVector<QVector<double> > m_vecHistoryLogLog;
QVector<QVector<double> > m_vecBaseLogLog; // 批次启动时原模型已有的数值解。
std::vector<RunResult> m_runs;
// 散点筛选阈值只随当前批次保存在内存中,负值表示尚未筛选。
double m_dFilterThreshold;
bool filteredParameterBounds(int index, double& minimum, double& maximum) const;
bool m_bCompleted;
bool m_bStopped;
QString m_sFailureReason;

@ -168,6 +168,7 @@ class NM_SUB_WND_EXPORT nmSubWndMain : public iSubWndBaseFit {
void onSensitivityTaskDestroyed();
/** @brief 在框架已有的敏感性子窗口叠加显示本分析的双对数结果。 */
void onShowSensitiveResults();
void onSensitiveFilterChanged();
void onSensitiveShowClicked();
/** @brief 刷新主界面的误差直方图,修改分箱数时复用当前批次结果。 */
void updateSensitiveHistogramPlot();

@ -36,6 +36,8 @@ public:
/// @brief 重建结果参数面板,只读显示求解器使用的井、储层和PVT参数
void rebuildResultParas();
/// @brief 只更新敏感性上下限数值,保留已有分组的折叠状态。
void refreshSensitivityResults();
/// @brief 设置数据管理器引用(用于面板重建时获取井和几何对象列表)
void setDataManager(nmDataAnalyzeManager* mgr) { m_pDataManager = mgr; }

@ -48,6 +48,8 @@ class NM_SUB_WXS_EXPORT nmWxSensitivityScatter : public iDlgBase
public:
nmWxSensitivityScatter(const QSharedPointer<nmDataSensitive::BatchResult>& results,
double baseError, QWidget* parent = nullptr);
signals:
void filterChanged();
protected:
bool eventFilter(QObject* object, QEvent* event) override;
private slots:

@ -5,6 +5,24 @@
#include <QDateTime>
#include <QtCore/qnumeric.h>
bool nmDataSensitive::BatchResult::filteredParameterBounds(int index, double& minimum, double& maximum) const
{
// 所有参数共用同一批误差严格小于阈值的样本,不受曲线可见性影响。
bool found = false;
for(size_t i = 0; i < m_runs.size(); ++i) {
const RunResult& run = m_runs[i];
if(!run.m_bSucceeded || run.m_bCancelled || !qIsFinite(run.m_dPressureRmse) ||
run.m_dPressureRmse < 0.0 || !(run.m_dPressureRmse < m_dFilterThreshold) ||
index < 0 || index >= run.m_vecParameters.size()) continue;
const double value = run.m_vecParameters[index];
if(!qIsFinite(value)) continue;
minimum = found ? qMin(minimum, value) : value;
maximum = found ? qMax(maximum, value) : value;
found = true;
}
return found;
}
namespace
{
double normalCdf(double z)

@ -1907,6 +1907,8 @@ void nmSubWndMain::onShowSensitiveResults()
nmDataAnalyzeManager* manager = m_pResultRefreshDataManager.data();
iSubWndFitting* fitting = m_pResultRefreshFitting.data();
if(!manager || !fitting || !manager->getSensitiveData()) return;
// 新批次或清空结果时同步移除上一批的上下限分组。
onSensitiveFilterChanged();
updateSensitiveHistoryPlot();
updateSensitiveHistogramPlot();
QSharedPointer<nmDataSensitive::BatchResult> result = manager->getSensitiveData()->getResults();
@ -2351,6 +2353,16 @@ void nmSubWndMain::onSensitiveHistogramBinsChanged(int bins)
updateSensitiveHistogramPlot();
}
void nmSubWndMain::onSensitiveFilterChanged()
{
// 只刷新所属分析的结果参数页,不触发会关闭散点窗的批次更新信号。
iSubWndFitting* fitting = m_pResultRefreshFitting.data();
if(!fitting) return;
QWidget* page = fitting->getFitSubRstWxOf(FSRT_NmRst, false);
nmWxParaPropertyPebi* parameters = page ? page->findChild<nmWxParaPropertyPebi*>() : nullptr;
if(parameters) parameters->refreshSensitivityResults();
}
void nmSubWndMain::onSensitiveScatter()
{
// 与 Show 一样打开独立弹窗,重复点击时激活已有窗口。
@ -2373,6 +2385,9 @@ void nmSubWndMain::onSensitiveScatter()
break;
}
dialog = new nmWxSensitivityScatter(batch, baseError, window->widget());
connect(dialog, SIGNAL(filterChanged()), this, SLOT(onSensitiveFilterChanged()));
// 构造时已应用初始阈值,连接完成后补一次结果面板同步。
onSensitiveFilterChanged();
// 新结果或新模型生成后关闭弹窗,避免保留旧批次的点和阈值。
connect(manager, SIGNAL(sigSensitiveResultsChanged()), dialog, SLOT(reject()));
}

@ -20,6 +20,7 @@
#include "nmDataReservoir.h"
#include "nmDataPvtParaForPebi.h"
#include "nmPebiResultSnapshot.h"
#include "nmDataSensitive.h"
#include "nmAttrRegistry.h"
#include <QCoreApplication>
@ -128,6 +129,33 @@ void appendPvtVectorPara(QStringList& paras,
}
}
void appendSensitivityParas(nmDataAnalyzeManager* manager, QStringList& paras,
QMap<QString, QVariant>& values, QMap<QString, QString>& groups)
{
// 与模型结果共用对象分组,排序在 PVT 之后;XML 提供内部“结果参数”层。
if(!manager->getSensitiveData()) return;
const QSharedPointer<nmDataSensitive::BatchResult> batch = manager->getSensitiveData()->getResults();
if(batch.isNull() || batch->m_calcType != nmDataSensitive::CALC_MONTE_CARLO ||
batch->m_dFilterThreshold < 0.0) return;
const QStringList names = QStringList() << "Skin" << "C" << "Pi" << "k" << "h" << QString(QChar(0x03c6));
const QStringList resultNames = QStringList() << "Skin" << "C" << "Pi" << "K" << "h" << "phi";
const QString groupCode = "RESULT_04_SENSITIVITY";
groups[groupCode] = QCoreApplication::translate("nmWxParaPropertyPebi", "Sensitivity results");
appendResultPara(paras, values, groupCode, "Sensitivity_RunCount", double(batch->m_runs.size()));
appendResultPara(paras, values, groupCode, "Sensitivity_Threshold", batch->m_dFilterThreshold);
for(int i = 0; i < batch->m_variables.size(); ++i) {
const nmDataSensitive::VariableSampling& variable = batch->m_variables[i];
const int index = names.indexOf(variable.m_varName);
if(!variable.m_enabled || index < 0) continue;
double minimum = 0.0, maximum = 0.0;
if(!batch->filteredParameterBounds(i, minimum, maximum)) continue;
const QString lower = "Sensitivity_" + resultNames[index] + "_Lower";
const QString higher = "Sensitivity_" + resultNames[index] + "_Higher";
appendResultPara(paras, values, groupCode, lower, minimum);
appendResultPara(paras, values, groupCode, higher, maximum);
}
}
QString resultModelTitlePrefix()
{
// 沿用旧结果面板已有的翻译,并统一为“模型-xxx”的标题格式。
@ -648,6 +676,8 @@ void nmWxParaPropertyPebi::rebuildResultParas()
mapObjectNames[pvtGroupCode] = resultModelTitlePrefix() + "PVT";
}
appendSensitivityParas(m_pDataManager, listParas, mapValues, mapObjectNames);
// 与左侧面板一致:先按 XML 构建控件并回填实际值,再统一设为只读。
refreshUIs(listParas, false, mapObjectNames);
restoreOldParas(mapValues);
@ -658,6 +688,25 @@ void nmWxParaPropertyPebi::rebuildResultParas()
}
}
void nmWxParaPropertyPebi::refreshSensitivityResults()
{
if(!m_pDataManager || !m_pGridItemUtils) return;
QStringList paras;
QMap<QString, QVariant> values;
QMap<QString, QString> groups;
appendSensitivityParas(m_pDataManager, paras, values, groups);
QStringList previous;
foreach(const QString& para, m_listParas) {
if(para.startsWith("RESULT_04_SENSITIVITY_")) previous.append(para);
}
// 首次筛选、空筛选或批次清空导致参数行变化时重建,其余只原位填值。
if(previous != paras) rebuildResultParas();
else {
restoreOldParas(values);
m_pGridItemUtils->update();
}
}
bool nmWxParaPropertyPebi::getParaValue(QString sPara, QVariant& o)
{
if (nullptr != m_pGridItemUtils)

@ -501,7 +501,7 @@ nmWxSensitivityScatter::nmWxSensitivityScatter(
for(size_t i = 0; i < results->m_runs.size(); ++i)
if(hasSensitivityError(results->m_runs[i])) m_defaultThreshold = qMax(m_defaultThreshold, results->m_runs[i].m_dPressureRmse);
if(qIsFinite(baseError) && baseError >= 0.0) m_defaultThreshold = baseError;
m_threshold = m_defaultThreshold;
m_threshold = results->m_dFilterThreshold >= 0.0 ? results->m_dFilterThreshold : m_defaultThreshold;
layout->addLayout(options);
m_plot = new iGuiPlot(true, this);
m_plot->initUI(tr("Sensitivity scatter plot"));
@ -612,6 +612,10 @@ void nmWxSensitivityScatter::updateThreshold()
{
// 阈值以下的点填黑,并同步图例中的阈值显示。
if(m_parameter->currentIndex() < 0) return;
if(m_results->m_dFilterThreshold != m_threshold) {
m_results->m_dFilterThreshold = m_threshold;
emit filterChanged();
}
updateLegend();
QVector<QPointF> accepted;
for(int i = 0; i < m_points.size(); ++i) if(m_points[i].y() < m_threshold) {

Loading…
Cancel
Save