|
|
|
|
@ -206,7 +206,7 @@ QString sensitivityRunParameters(const nmDataSensitive::BatchResult& results, co
|
|
|
|
|
double value = run.m_vecParameters[i];
|
|
|
|
|
const QString unit = variable.m_modelValue.getUnit();
|
|
|
|
|
convertSamplingValue(variable.m_varName, value, samplingBaseUnit(variable.m_varName), unit, value);
|
|
|
|
|
descriptions << variable.m_varName + " = " + formatSamplingValue(value, 3)
|
|
|
|
|
descriptions << variable.displayName() + " = " + formatSamplingValue(value, 3)
|
|
|
|
|
+ (unit.isEmpty() ? QString() : " " + unit);
|
|
|
|
|
}
|
|
|
|
|
return descriptions.join(" + ");
|
|
|
|
|
@ -634,7 +634,7 @@ nmWxSensitivityScatter::nmWxSensitivityScatter(
|
|
|
|
|
options->addWidget(new QLabel(tr("X Axis:"), this));
|
|
|
|
|
m_parameter = new QComboBox(this);
|
|
|
|
|
for(int i = 0; i < results->m_variables.size(); ++i)
|
|
|
|
|
if(results->m_variables[i].m_enabled) m_parameter->addItem(results->m_variables[i].m_varName, i);
|
|
|
|
|
if(results->m_variables[i].m_enabled) m_parameter->addItem(results->m_variables[i].displayName(), i);
|
|
|
|
|
options->addWidget(m_parameter, 1);
|
|
|
|
|
options->addSpacing(20);
|
|
|
|
|
options->addWidget(new QLabel(tr("Y Axis:"), this));
|
|
|
|
|
@ -692,7 +692,7 @@ void nmWxSensitivityScatter::updateParameter()
|
|
|
|
|
const int index = m_parameter->itemData(m_parameter->currentIndex()).toInt();
|
|
|
|
|
const nmDataSensitive::VariableSampling& variable = m_results->m_variables[index];
|
|
|
|
|
const QString unit = variable.m_modelValue.getUnit();
|
|
|
|
|
m_plot->setAxisX(variable.m_varName, unit);
|
|
|
|
|
m_plot->setAxisX(variable.displayName(), unit);
|
|
|
|
|
double modelValue = variable.m_modelValue.getValue().toDouble();
|
|
|
|
|
const bool hasModel = convertSamplingValue(variable.m_varName, modelValue,
|
|
|
|
|
samplingBaseUnit(variable.m_varName), unit, modelValue) && qIsFinite(modelY) && (!errorAxis || modelY >= 0.0);
|
|
|
|
|
@ -1254,7 +1254,7 @@ private:
|
|
|
|
|
nmDataSensitive::VariableSampling& variable = m_data.getVariable(index);
|
|
|
|
|
const QString unit = variable.getModelValue().getUnit();
|
|
|
|
|
convertSamplingValue(variable.getVarName(), value, samplingBaseUnit(variable.getVarName()), unit, value);
|
|
|
|
|
return variable.getVarName() + " = " + formatSamplingValue(value, 3)
|
|
|
|
|
return variable.displayName() + " = " + formatSamplingValue(value, 3)
|
|
|
|
|
+ (unit.isEmpty() ? QString() : " " + unit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1391,12 +1391,26 @@ void nmWxSensitive::closeEvent(QCloseEvent* event)
|
|
|
|
|
void nmWxSensitive::refreshModelValues()
|
|
|
|
|
{
|
|
|
|
|
// 每次打开或模型更新时读取当前参数,沿用已有单位和物理范围限制。
|
|
|
|
|
nmDataWellBase* well = m_pDataManager
|
|
|
|
|
? m_pDataManager->findWellByCode(m_pDataManager->getPrimaryWellCode()) : nullptr;
|
|
|
|
|
nmDataReservoir* reservoir = m_pDataManager ? m_pDataManager->getReservoirData() : nullptr;
|
|
|
|
|
const QVector<nmCalculationWellRef> wells = m_pDataManager
|
|
|
|
|
? m_pDataManager->getEffectiveCalculationWells() : QVector<nmCalculationWellRef>();
|
|
|
|
|
// 旧版主井配置补上井编码;已不参与模型的井不再生成样本。
|
|
|
|
|
for(int i = 0; i < m_sensitiveData.getVariableCount(); ++i) {
|
|
|
|
|
nmDataSensitive::VariableSampling& variable = m_sensitiveData.getVariable(i);
|
|
|
|
|
if(variable.m_varName == "Skin" || variable.m_varName == "C") {
|
|
|
|
|
if(variable.m_wellCode.isEmpty() && m_pDataManager)
|
|
|
|
|
variable.m_wellCode = m_pDataManager->getPrimaryWellCode();
|
|
|
|
|
if(!m_pDataManager || !m_pDataManager->isWellSelectedForCalculation(variable.m_wellCode))
|
|
|
|
|
variable.m_enabled = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bool modelChanged = false;
|
|
|
|
|
const QStringList names = QStringList() << "Skin" << "C" << "Pi" << "k" << "h" << QString(QChar(0x03c6));
|
|
|
|
|
for (int n = 0; n < names.size(); ++n) {
|
|
|
|
|
for (int entry = 0; entry < wells.size() * 2 + 4; ++entry) {
|
|
|
|
|
const bool wellParameter = entry < wells.size() * 2;
|
|
|
|
|
const int n = wellParameter ? entry % 2 : entry - wells.size() * 2 + 2;
|
|
|
|
|
const QString wellCode = wellParameter ? wells[entry / 2].m_sWellCode : QString();
|
|
|
|
|
nmDataWellBase* well = wellParameter ? m_pDataManager->findWellByCode(wellCode) : nullptr;
|
|
|
|
|
nmDataAttribute* attribute = nullptr;
|
|
|
|
|
const QString name = names[n];
|
|
|
|
|
if (well && name == "Skin" && well->getPerforationCount() > 0)
|
|
|
|
|
@ -1409,17 +1423,19 @@ void nmWxSensitive::refreshModelValues()
|
|
|
|
|
|
|
|
|
|
int index = -1;
|
|
|
|
|
for (int i = 0; i < m_sensitiveData.getVariableCount(); ++i)
|
|
|
|
|
if (m_sensitiveData.getVariable(i).getVarName() == name) { index = i; break; }
|
|
|
|
|
if (m_sensitiveData.getVariable(i).getVarName() == name &&
|
|
|
|
|
m_sensitiveData.getVariable(i).m_wellCode == wellCode) { index = i; break; }
|
|
|
|
|
const bool fresh = index < 0;
|
|
|
|
|
if (fresh) {
|
|
|
|
|
nmDataSensitive::VariableSampling variable;
|
|
|
|
|
variable.setVarName(name);
|
|
|
|
|
variable.setVarGroup(n < 2 ? "Tested Well" : "Reservoir");
|
|
|
|
|
variable.m_wellCode = wellCode;
|
|
|
|
|
variable.setNumber(5);
|
|
|
|
|
m_sensitiveData.getVariables().append(variable);
|
|
|
|
|
index = m_sensitiveData.getVariableCount() - 1;
|
|
|
|
|
}
|
|
|
|
|
nmDataSensitive::VariableSampling& variable = m_sensitiveData.getVariable(index);
|
|
|
|
|
variable.setVarGroup(well ? well->getWellName() : "Reservoir");
|
|
|
|
|
double physicalMin = 0.0, physicalMax = 0.0;
|
|
|
|
|
if (!attribute || !samplingPhysicalRange(name, physicalMin, physicalMax)) {
|
|
|
|
|
variable.setEnabled(false);
|
|
|
|
|
@ -1528,7 +1544,7 @@ void nmWxSensitive::loadDataToUI(bool refreshRangesOnly)
|
|
|
|
|
for (int i = 0; i < m_sensitiveData.getVariableCount(); ++i) {
|
|
|
|
|
nmDataSensitive::VariableSampling& variable = m_sensitiveData.getVariable(i);
|
|
|
|
|
const QString name = variable.getVarName();
|
|
|
|
|
const int idx = findVariableIndex(name);
|
|
|
|
|
const int idx = findVariableIndex(variable);
|
|
|
|
|
if (idx < 0) continue;
|
|
|
|
|
const bool available = isSupportedSamplingVariable(name) &&
|
|
|
|
|
variable.getModelValue().getValue().isValid();
|
|
|
|
|
@ -1536,7 +1552,7 @@ void nmWxSensitive::loadDataToUI(bool refreshRangesOnly)
|
|
|
|
|
QTreeWidgetItem* parent = variablesTree->topLevelItem(group);
|
|
|
|
|
for (int child = 0; child < parent->childCount(); ++child) {
|
|
|
|
|
QTreeWidgetItem* item = parent->child(child);
|
|
|
|
|
if (item->text(0) != name) continue;
|
|
|
|
|
if (item->text(0) != name || item->data(0, Qt::UserRole + 1).toString() != variable.m_wellCode) continue;
|
|
|
|
|
item->setDisabled(!available);
|
|
|
|
|
if (!refreshRangesOnly)
|
|
|
|
|
item->setCheckState(0, available && variable.getEnabled() ? Qt::Checked : Qt::Unchecked);
|
|
|
|
|
@ -1594,15 +1610,19 @@ void nmWxSensitive::loadDataToUI(bool refreshRangesOnly)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nmWxSensitive::findVariableIndex(const QString& varName)
|
|
|
|
|
int nmWxSensitive::findVariableIndex(const nmDataSensitive::VariableSampling& variable)
|
|
|
|
|
{
|
|
|
|
|
// 根据创建顺序查找变量索引
|
|
|
|
|
QStringList allVars;
|
|
|
|
|
allVars << "Zw" << "Hw" << "Lw" << "Skin" << "C" // Tested Well
|
|
|
|
|
<< "Pi" << "k" << "h" << QString(QChar(0x03c6)) << "ntg" << "kz/kr" // Reservoir
|
|
|
|
|
<< "Total compressibility"; // Pvt
|
|
|
|
|
|
|
|
|
|
return allVars.indexOf(varName);
|
|
|
|
|
// 页面由树节点创建,通过井编码与参数名定位,不依赖固定页面次序。
|
|
|
|
|
for(int group = 0; group < variablesTree->topLevelItemCount(); ++group) {
|
|
|
|
|
QTreeWidgetItem* parent = variablesTree->topLevelItem(group);
|
|
|
|
|
for(int child = 0; child < parent->childCount(); ++child) {
|
|
|
|
|
QTreeWidgetItem* item = parent->child(child);
|
|
|
|
|
if(item->text(0) == variable.m_varName &&
|
|
|
|
|
item->data(0, Qt::UserRole + 1).toString() == variable.m_wellCode)
|
|
|
|
|
return item->data(0, Qt::UserRole).toInt() - 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxSensitive::updateModelCount()
|
|
|
|
|
@ -1618,9 +1638,10 @@ void nmWxSensitive::updateModelCount()
|
|
|
|
|
QTreeWidgetItem* item = parent->child(child);
|
|
|
|
|
for (int i = 0; i < m_sensitiveData.getVariableCount(); ++i) {
|
|
|
|
|
nmDataSensitive::VariableSampling& variable = m_sensitiveData.getVariable(i);
|
|
|
|
|
if (variable.getVarName() != item->text(0)) continue;
|
|
|
|
|
if (variable.getVarName() != item->text(0) ||
|
|
|
|
|
variable.m_wellCode != item->data(0, Qt::UserRole + 1).toString()) continue;
|
|
|
|
|
variable.setEnabled(!item->isDisabled() && item->checkState(0) == Qt::Checked);
|
|
|
|
|
const int idx = findVariableIndex(variable.getVarName());
|
|
|
|
|
const int idx = findVariableIndex(variable);
|
|
|
|
|
if (idx >= 0) variable.setNumber(m_numSpins[idx]->value());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1637,10 +1658,21 @@ void nmWxSensitive::updateModelCount()
|
|
|
|
|
// 第四种确认设置且至少选择一个拟合参数后才开放生成,空选择直接禁用。
|
|
|
|
|
bool hasFittingParameters = false;
|
|
|
|
|
if(!m_sensitiveData.getImproveSettings().isNull()) {
|
|
|
|
|
const nmDataAutomaticFitting& fitting = m_sensitiveData.getImproveSettings()->parameters;
|
|
|
|
|
hasFittingParameters = fitting.getPermeabilitySelected() || fitting.getSkinSelected() ||
|
|
|
|
|
fitting.getWellboreStorageSelected() || fitting.getPorositySelected() ||
|
|
|
|
|
fitting.getFractureConductivitySelected() || fitting.getFractureHalfLengthSelected();
|
|
|
|
|
nmSensitivityFitSettings settings = *m_sensitiveData.getImproveSettings();
|
|
|
|
|
QVector<nmFitParameter>& parameters = settings.parameters.getModelParameters();
|
|
|
|
|
// 新勾选的采样只取消同井同参数的拟合,其他井的同名参数仍可参与。
|
|
|
|
|
for(int i = 0; i < parameters.size(); ++i) {
|
|
|
|
|
if(!parameters[i].wellCode.isEmpty() &&
|
|
|
|
|
!m_pDataManager->isWellSelectedForCalculation(parameters[i].wellCode))
|
|
|
|
|
parameters[i].selected = false;
|
|
|
|
|
for(int v = 0; v < m_sensitiveData.getVariableCount(); ++v) {
|
|
|
|
|
const nmDataSensitive::VariableSampling& variable = m_sensitiveData.getVariable(v);
|
|
|
|
|
if(variable.m_enabled && variable.parameterKey() == parameters[i].samplingKey())
|
|
|
|
|
parameters[i].selected = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
hasFittingParameters = settings.confirmed && settings.parameters.hasSelectedParameters();
|
|
|
|
|
m_sensitiveData.setImproveSettings(QSharedPointer<const nmSensitivityFitSettings>(new nmSensitivityFitSettings(settings)));
|
|
|
|
|
}
|
|
|
|
|
generateButton->setEnabled(m_pDataManager && !overflow && count > 0 && !m_calculationRunning &&
|
|
|
|
|
(calculationTypeCombo->currentIndex() != 3 || hasFittingParameters));
|
|
|
|
|
@ -1655,7 +1687,7 @@ bool nmWxSensitive::saveDataFromUI()
|
|
|
|
|
for (int i = 0; i < candidate.getVariableCount(); ++i) {
|
|
|
|
|
nmDataSensitive::VariableSampling& variable = candidate.getVariable(i);
|
|
|
|
|
const QString name = variable.getVarName();
|
|
|
|
|
const int idx = findVariableIndex(name);
|
|
|
|
|
const int idx = findVariableIndex(variable);
|
|
|
|
|
if (idx < 0 || !isSupportedSamplingVariable(name)) continue;
|
|
|
|
|
const QString unit = m_unitLabels[idx]->text();
|
|
|
|
|
const QString baseUnit = samplingBaseUnit(name);
|
|
|
|
|
@ -1898,22 +1930,25 @@ void nmWxSensitive::populateTreeWidget()
|
|
|
|
|
{
|
|
|
|
|
variablesTree->clear();
|
|
|
|
|
|
|
|
|
|
// ===== Tested Well =====
|
|
|
|
|
// 只列出实际参与模型的井,每口井复用现有的参数及采样页。
|
|
|
|
|
const QVector<nmCalculationWellRef> wells = m_pDataManager
|
|
|
|
|
? m_pDataManager->getEffectiveCalculationWells() : QVector<nmCalculationWellRef>();
|
|
|
|
|
int i;
|
|
|
|
|
for(int w = 0; w < wells.size(); ++w) {
|
|
|
|
|
nmDataWellBase* well = m_pDataManager->findWellByCode(wells[w].m_sWellCode);
|
|
|
|
|
if(!well) continue;
|
|
|
|
|
QTreeWidgetItem* testedWellItem = new QTreeWidgetItem(variablesTree);
|
|
|
|
|
testedWellItem->setText(0, tr("Tested Well"));
|
|
|
|
|
testedWellItem->setText(0, wells.size() == 1 ? tr("Tested Well") : well->getWellName());
|
|
|
|
|
testedWellItem->setCheckState(0, Qt::Unchecked);
|
|
|
|
|
testedWellItem->setFlags(testedWellItem->flags() | Qt::ItemIsUserCheckable);
|
|
|
|
|
|
|
|
|
|
QStringList testedWellChildren;
|
|
|
|
|
testedWellChildren << "Zw" << "Hw" << "Lw" << "Skin" << "C";
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < testedWellChildren.size(); ++i) {
|
|
|
|
|
QTreeWidgetItem *childItem = new QTreeWidgetItem(testedWellItem);
|
|
|
|
|
childItem->setText(0, testedWellChildren.at(i));
|
|
|
|
|
childItem->setCheckState(0, Qt::Unchecked);
|
|
|
|
|
childItem->setFlags(childItem->flags() | Qt::ItemIsUserCheckable);
|
|
|
|
|
childItem->setDisabled(!isSupportedSamplingVariable(testedWellChildren.at(i)));
|
|
|
|
|
QStringList children;
|
|
|
|
|
children << "Zw" << "Hw" << "Lw" << "Skin" << "C";
|
|
|
|
|
for(i = 0; i < children.size(); ++i) {
|
|
|
|
|
QTreeWidgetItem* child = new QTreeWidgetItem(testedWellItem);
|
|
|
|
|
child->setText(0, children[i]);
|
|
|
|
|
child->setData(0, Qt::UserRole + 1, well->getWellCode());
|
|
|
|
|
child->setCheckState(0, Qt::Unchecked);
|
|
|
|
|
child->setDisabled(!isSupportedSamplingVariable(children[i]));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ===== Reservoir =====
|
|
|
|
|
@ -2296,7 +2331,7 @@ void nmWxSensitive::updateValuesForPage(int idx)
|
|
|
|
|
table->setRowCount(number);
|
|
|
|
|
nmDataSensitive::VariableSampling variable;
|
|
|
|
|
for (int i = 0; i < m_sensitiveData.getVariableCount(); ++i) {
|
|
|
|
|
if (findVariableIndex(m_sensitiveData.getVariable(i).getVarName()) == idx) {
|
|
|
|
|
if (findVariableIndex(m_sensitiveData.getVariable(i)) == idx) {
|
|
|
|
|
variable = m_sensitiveData.getVariable(i);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@ -2375,7 +2410,7 @@ void nmWxSensitive::updateDistributionPage(int idx)
|
|
|
|
|
}
|
|
|
|
|
for(int i = 0; i < m_sensitiveData.getVariableCount(); ++i) {
|
|
|
|
|
nmDataSensitive::VariableSampling variable = m_sensitiveData.getVariable(i);
|
|
|
|
|
if(findVariableIndex(variable.m_varName) != idx) continue;
|
|
|
|
|
if(findVariableIndex(variable) != idx) continue;
|
|
|
|
|
const bool valid = readDistributionPage(idx, variable);
|
|
|
|
|
m_distributionPlots[idx]->setVariable(variable, valid);
|
|
|
|
|
break;
|
|
|
|
|
@ -2393,8 +2428,9 @@ void nmWxSensitive::onSamplingEditingFinished()
|
|
|
|
|
for (int idx = 0; idx < m_minSpins.size(); ++idx) {
|
|
|
|
|
if (edit != m_minSpins[idx] && edit != m_maxSpins[idx]) continue;
|
|
|
|
|
for (int i = 0; i < m_sensitiveData.getVariableCount(); ++i) {
|
|
|
|
|
const QString name = m_sensitiveData.getVariable(i).getVarName();
|
|
|
|
|
if (findVariableIndex(name) != idx) continue;
|
|
|
|
|
const nmDataSensitive::VariableSampling& variable = m_sensitiveData.getVariable(i);
|
|
|
|
|
const QString name = variable.getVarName();
|
|
|
|
|
if (findVariableIndex(variable) != idx) continue;
|
|
|
|
|
double lower = 0.0, upper = 0.0;
|
|
|
|
|
const QString unit = m_unitLabels[idx]->text();
|
|
|
|
|
const QString baseUnit = samplingBaseUnit(name);
|
|
|
|
|
@ -2634,7 +2670,7 @@ void nmWxSensitive::onImproveSettingsClicked()
|
|
|
|
|
updateModelCount();
|
|
|
|
|
QStringList sampledParameters;
|
|
|
|
|
foreach(const nmDataSensitive::VariableSampling& variable, m_sensitiveData.getVariables())
|
|
|
|
|
if(variable.m_enabled) sampledParameters.append(variable.m_varName);
|
|
|
|
|
if(variable.m_enabled) sampledParameters.append(variable.parameterKey());
|
|
|
|
|
nmWxAutomaticFitting dialog(this, &settings, sampledParameters);
|
|
|
|
|
if(dialog.exec() == QDialog::Accepted) {
|
|
|
|
|
m_sensitiveData.setImproveSettings(QSharedPointer<const nmSensitivityFitSettings>(new nmSensitivityFitSettings(settings)));
|
|
|
|
|
|