|
|
|
|
@ -1,4 +1,5 @@
|
|
|
|
|
#include "nmCalculationDllPebiSolverTask.h"
|
|
|
|
|
#include "pch.h"
|
|
|
|
|
#include "zxLogInstance.h"
|
|
|
|
|
#include "nmDataAnalyzeManager.h"
|
|
|
|
|
#include "nmDataSensitive.h"
|
|
|
|
|
@ -28,6 +29,7 @@
|
|
|
|
|
#include <QHash>
|
|
|
|
|
#include <QMutexLocker>
|
|
|
|
|
#include <QScopedPointer>
|
|
|
|
|
#include <QElapsedTimer>
|
|
|
|
|
#include <QSet>
|
|
|
|
|
#include <QUuid>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
@ -173,7 +175,7 @@ public:
|
|
|
|
|
if(pCancelRequested == NULL) {
|
|
|
|
|
pMutex->lock();
|
|
|
|
|
} else {
|
|
|
|
|
// 只让手工任务在等待全局 DLL 锁时可停止,互斥范围和锁顺序不变。
|
|
|
|
|
// 手工与敏感性批量任务等待全局 DLL 锁时可停止,互斥范围不变。
|
|
|
|
|
while(!pMutex->tryLock(100)) {
|
|
|
|
|
if(isTaskCancellationRequested(pCancelRequested)) {
|
|
|
|
|
return false;
|
|
|
|
|
@ -651,7 +653,8 @@ nmCalculationDllPebiSolverTask::nmCalculationDllPebiSolverTask(
|
|
|
|
|
m_dPendingScalarMax(0.0),
|
|
|
|
|
m_bPendingFullResultReady(false),
|
|
|
|
|
m_nCancelRequested(0),
|
|
|
|
|
m_nWasCancelled(0)
|
|
|
|
|
m_nWasCancelled(0),
|
|
|
|
|
m_bSensitivityBatchCompleted(false)
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
m_pInputSnapshot = new nmPebiSolverInputSnapshot();
|
|
|
|
|
@ -707,7 +710,8 @@ nmCalculationDllPebiSolverTask::nmCalculationDllPebiSolverTask(
|
|
|
|
|
m_lastRunSucceeded(false), m_nSolveTimeMs(-1), m_nPebiCount(-1),
|
|
|
|
|
m_sAutoFitTargetWellCode(source.m_sAutoFitTargetWellCode),
|
|
|
|
|
m_dPendingScalarMin(0.0), m_dPendingScalarMax(0.0),
|
|
|
|
|
m_bPendingFullResultReady(false), m_nCancelRequested(0), m_nWasCancelled(0)
|
|
|
|
|
m_bPendingFullResultReady(false), m_nCancelRequested(0), m_nWasCancelled(0),
|
|
|
|
|
m_bSensitivityBatchCompleted(false)
|
|
|
|
|
{
|
|
|
|
|
// 采样任务只持有自己的值快照;源任务和分析窗口可独立释放。
|
|
|
|
|
}
|
|
|
|
|
@ -766,8 +770,9 @@ bool nmCalculationDllPebiSolverTask::updateSensitivityRun(
|
|
|
|
|
const nmDataSensitive& sampling, quint64 runIndex, QString* errorMessage)
|
|
|
|
|
{
|
|
|
|
|
if(errorMessage) errorMessage->clear();
|
|
|
|
|
// 更新必须发生在两次求解之间,不能用于原始任务或实时管理器输入。
|
|
|
|
|
if(isRunning() || m_pDataManager != nullptr || !m_pInputSnapshot ||
|
|
|
|
|
// 更新只在两组之间进行;运行中的批量任务仅允许自己的工作线程更新。
|
|
|
|
|
if((isRunning() && (m_pSensitivitySampling.isNull() || QThread::currentThread() != this)) ||
|
|
|
|
|
m_pDataManager != nullptr || !m_pInputSnapshot ||
|
|
|
|
|
!m_pInputSnapshot->m_bAutoFitTargetOnly ||
|
|
|
|
|
m_pInputSnapshot->m_oSensitivityBaseline.m_nTarget < 0) {
|
|
|
|
|
if(errorMessage) *errorMessage = tr("Sensitivity task is unavailable or still running.");
|
|
|
|
|
@ -781,8 +786,11 @@ bool nmCalculationDllPebiSolverTask::updateSensitivityRun(
|
|
|
|
|
m_sFailureReason.clear();
|
|
|
|
|
m_nSolveTimeMs = -1;
|
|
|
|
|
m_nPebiCount = -1;
|
|
|
|
|
// 批量任务的停止标记持续到整次结束,不能在更新下一组时丢失界面的请求。
|
|
|
|
|
if(m_pSensitivitySampling.isNull()) {
|
|
|
|
|
m_nCancelRequested.fetchAndStoreOrdered(0);
|
|
|
|
|
m_nWasCancelled.fetchAndStoreOrdered(0);
|
|
|
|
|
}
|
|
|
|
|
QVector<double> values;
|
|
|
|
|
if(!sampling.usesBaseUnits() || !sampling.getRunValues(runIndex, values)) {
|
|
|
|
|
fail(tr("Invalid sensitivity sampling configuration."));
|
|
|
|
|
@ -862,9 +870,22 @@ bool nmCalculationDllPebiSolverTask::calculateSensitivityBatch(
|
|
|
|
|
QString* errorMessage) const
|
|
|
|
|
{
|
|
|
|
|
results.clear();
|
|
|
|
|
// 同步入口与后台入口共用批量循环,只转移结果容器,不复制整批曲线。
|
|
|
|
|
QScopedPointer<nmCalculationDllPebiSolverTask> task(
|
|
|
|
|
createSensitivityBatch(sampling, errorMessage));
|
|
|
|
|
if(!task) return false;
|
|
|
|
|
task->run();
|
|
|
|
|
results.swap(task->m_vecSensitivityResults);
|
|
|
|
|
if(errorMessage) *errorMessage = task->m_sSensitivityFailureReason;
|
|
|
|
|
return task->m_bSensitivityBatchCompleted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nmCalculationDllPebiSolverTask* nmCalculationDllPebiSolverTask::createSensitivityBatch(
|
|
|
|
|
const nmDataSensitive& sampling, QString* errorMessage) const
|
|
|
|
|
{
|
|
|
|
|
if(errorMessage) errorMessage->clear();
|
|
|
|
|
try {
|
|
|
|
|
// 冻结整次批量的配置,次数、运行顺序和返回参数都使用同一份采样数据。
|
|
|
|
|
// 所有配置与模型复制都在启动线程前完成,后台只读取独立的值输入。
|
|
|
|
|
const nmDataSensitive frozenSampling(sampling);
|
|
|
|
|
bool overflow = false;
|
|
|
|
|
const quint64 count = frozenSampling.calculateModelCount(&overflow);
|
|
|
|
|
@ -873,7 +894,7 @@ bool nmCalculationDllPebiSolverTask::calculateSensitivityBatch(
|
|
|
|
|
(type != nmDataSensitive::CALC_DETERMINISTIC &&
|
|
|
|
|
type != nmDataSensitive::CALC_DETERMINISTIC_MULTIVARIATE)) {
|
|
|
|
|
if(errorMessage) *errorMessage = tr("Invalid sensitivity sampling configuration.");
|
|
|
|
|
return false;
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 只在整次批量开始时复制模型与网格;首组参数由创建接口填入。
|
|
|
|
|
@ -882,47 +903,117 @@ bool nmCalculationDllPebiSolverTask::calculateSensitivityBatch(
|
|
|
|
|
createSensitivityRun(frozenSampling, 0, &creationError));
|
|
|
|
|
if(!task) {
|
|
|
|
|
if(errorMessage) *errorMessage = creationError;
|
|
|
|
|
return false;
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
task->m_pSensitivitySampling = QSharedPointer<const nmDataSensitive>(
|
|
|
|
|
new nmDataSensitive(frozenSampling));
|
|
|
|
|
return task.take();
|
|
|
|
|
} catch(const std::bad_alloc&) {
|
|
|
|
|
if(errorMessage) *errorMessage = tr("Insufficient memory to prepare solver input.");
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::vector<nmCalculationDllPebiSolverTask::SensitivityRunResult>&
|
|
|
|
|
nmCalculationDllPebiSolverTask::getSensitivityResults() const
|
|
|
|
|
{
|
|
|
|
|
// 调用方须先等待线程结束,运行中的结果容器不向界面开放读取。
|
|
|
|
|
return m_vecSensitivityResults;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nmCalculationDllPebiSolverTask::wasSensitivityBatchCompleted() const
|
|
|
|
|
{
|
|
|
|
|
return m_bSensitivityBatchCompleted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nmCalculationDllPebiSolverTask::executeSensitivityBatch()
|
|
|
|
|
{
|
|
|
|
|
m_vecSensitivityResults.clear();
|
|
|
|
|
m_sSensitivityFailureReason.clear();
|
|
|
|
|
const quint64 count = m_pSensitivitySampling->calculateModelCount();
|
|
|
|
|
quint64 failed = 0;
|
|
|
|
|
QElapsedTimer progressTimer;
|
|
|
|
|
progressTimer.start();
|
|
|
|
|
emit sigSensitivityProgress(0, count, 0);
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
|
|
for(quint64 runIndex = 0; runIndex < count; ++runIndex) {
|
|
|
|
|
if(isCancelRequested()) return false;
|
|
|
|
|
SensitivityRunResult result;
|
|
|
|
|
result.m_nRunIndex = runIndex;
|
|
|
|
|
// 单参数法保持其余参数的模型值,多参数法按预览组合顺序逐组取值。
|
|
|
|
|
bool inputReady = frozenSampling.getRunValues(runIndex, result.m_vecParameters);
|
|
|
|
|
bool inputReady = m_pSensitivitySampling->getRunValues(runIndex, result.m_vecParameters);
|
|
|
|
|
if(!inputReady) {
|
|
|
|
|
result.m_sFailureReason = tr("Invalid sensitivity sampling configuration.");
|
|
|
|
|
} else if(runIndex > 0) {
|
|
|
|
|
} else {
|
|
|
|
|
// 本组更新失败仍保留运行编号,下一组继续从冻结基准更新。
|
|
|
|
|
inputReady = task->updateSensitivityRun(frozenSampling, runIndex,
|
|
|
|
|
inputReady = updateSensitivityRun(*m_pSensitivitySampling, runIndex,
|
|
|
|
|
&result.m_sFailureReason);
|
|
|
|
|
}
|
|
|
|
|
if(inputReady) {
|
|
|
|
|
task->run();
|
|
|
|
|
result.m_bSucceeded = task->wasSuccessful();
|
|
|
|
|
calculateSingleRun();
|
|
|
|
|
result.m_bSucceeded = m_lastRunSucceeded;
|
|
|
|
|
if(result.m_bSucceeded) {
|
|
|
|
|
result.m_vecPressure = task->getAutoFitResultPressure();
|
|
|
|
|
result.m_vecLogLog = task->getAutoFitResultLogLog();
|
|
|
|
|
result.m_vecSemiLog = task->getAutoFitResultSemiLog();
|
|
|
|
|
result.m_vecPressure = m_autoFitResultPressure;
|
|
|
|
|
result.m_vecLogLog = m_autoFitResultLogLog;
|
|
|
|
|
result.m_vecSemiLog = m_autoFitResultSemiLog;
|
|
|
|
|
} else {
|
|
|
|
|
result.m_sFailureReason = task->getFailureReason();
|
|
|
|
|
result.m_sFailureReason = m_sFailureReason;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(isCancelRequested()) {
|
|
|
|
|
result.m_bCancelled = true;
|
|
|
|
|
result.m_bSucceeded = false;
|
|
|
|
|
result.m_sFailureReason.clear();
|
|
|
|
|
result.m_vecPressure.clear();
|
|
|
|
|
result.m_vecLogLog.clear();
|
|
|
|
|
result.m_vecSemiLog.clear();
|
|
|
|
|
} else if(!result.m_bSucceeded) {
|
|
|
|
|
++failed;
|
|
|
|
|
}
|
|
|
|
|
// Qt 曲线容器按值保留;下一组清空任务结果不会清掉这里的曲线。
|
|
|
|
|
// 不预先展开全部组合或预分配总次数,也不合并重复的基准组合。
|
|
|
|
|
results.push_back(result);
|
|
|
|
|
m_vecSensitivityResults.push_back(result);
|
|
|
|
|
// 快速失败的多组输入也限频通知,避免排队的进度信号堵塞界面。
|
|
|
|
|
if(progressTimer.elapsed() >= 100 || runIndex + 1 == count || isCancelRequested()) {
|
|
|
|
|
emit sigSensitivityProgress(runIndex + 1, count, failed);
|
|
|
|
|
progressTimer.restart();
|
|
|
|
|
}
|
|
|
|
|
if(isCancelRequested()) return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
} catch(const std::bad_alloc&) {
|
|
|
|
|
if(errorMessage) *errorMessage = tr("Insufficient memory to process solver results.");
|
|
|
|
|
m_sSensitivityFailureReason = tr("Insufficient memory to process solver results.");
|
|
|
|
|
return false;
|
|
|
|
|
} catch(const std::length_error&) {
|
|
|
|
|
if(errorMessage) *errorMessage = tr("Insufficient memory to process solver results.");
|
|
|
|
|
m_sSensitivityFailureReason = tr("Insufficient memory to process solver results.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmCalculationDllPebiSolverTask::run()
|
|
|
|
|
{
|
|
|
|
|
if(!m_pSensitivitySampling.isNull()) {
|
|
|
|
|
// 同一后台线程逐组执行,仅在整次结束后发送完成信号。
|
|
|
|
|
m_bSensitivityBatchCompleted = executeSensitivityBatch();
|
|
|
|
|
m_lastRunSucceeded = m_bSensitivityBatchCompleted;
|
|
|
|
|
for(size_t i = 0; m_lastRunSucceeded && i < m_vecSensitivityResults.size(); ++i)
|
|
|
|
|
m_lastRunSucceeded = m_vecSensitivityResults[i].m_bSucceeded;
|
|
|
|
|
if(isCancelRequested()) {
|
|
|
|
|
m_bSensitivityBatchCompleted = false;
|
|
|
|
|
m_lastRunSucceeded = false;
|
|
|
|
|
m_nWasCancelled.fetchAndStoreOrdered(1);
|
|
|
|
|
}
|
|
|
|
|
discardPendingFullResult();
|
|
|
|
|
} else {
|
|
|
|
|
calculateSingleRun();
|
|
|
|
|
}
|
|
|
|
|
// 完成信号可能触发成果关闭;必须在发信号前结束 DataManager 使用期。
|
|
|
|
|
releaseDataManagerUse();
|
|
|
|
|
emit sig_calculateDone(m_lastRunSucceeded);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmCalculationDllPebiSolverTask::calculateSingleRun()
|
|
|
|
|
{
|
|
|
|
|
m_nSolveTimeMs = -1;
|
|
|
|
|
m_nPebiCount = -1;
|
|
|
|
|
@ -948,9 +1039,6 @@ void nmCalculationDllPebiSolverTask::run()
|
|
|
|
|
bSucceeded = false;
|
|
|
|
|
}
|
|
|
|
|
m_lastRunSucceeded = bSucceeded;
|
|
|
|
|
// 完成信号可能触发成果关闭;必须在发信号前结束 DataManager 使用期。
|
|
|
|
|
releaseDataManagerUse();
|
|
|
|
|
emit sig_calculateDone(m_lastRunSucceeded);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmCalculationDllPebiSolverTask::requestCancel()
|
|
|
|
|
@ -1209,7 +1297,7 @@ void nmCalculationDllPebiSolverTask::reportStage(
|
|
|
|
|
int nTotal)
|
|
|
|
|
{
|
|
|
|
|
if(m_pInputSnapshot != nullptr &&
|
|
|
|
|
!m_pInputSnapshot->m_bAutoFitTargetOnly) {
|
|
|
|
|
(!m_pInputSnapshot->m_bAutoFitTargetOnly || !m_pSensitivitySampling.isNull())) {
|
|
|
|
|
emit sigStageChanged(sStage, nCurrent, nTotal);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1460,7 +1548,7 @@ int nmCalculationDllPebiSolverTask::getPebiCount() const
|
|
|
|
|
|
|
|
|
|
QString nmCalculationDllPebiSolverTask::getFailureReason() const
|
|
|
|
|
{
|
|
|
|
|
return m_sFailureReason;
|
|
|
|
|
return m_pSensitivitySampling.isNull() ? m_sFailureReason : m_sSensitivityFailureReason;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVector<QVector<double> > nmCalculationDllPebiSolverTask::getAutoFitResultPressure() const
|
|
|
|
|
@ -1497,7 +1585,7 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QAtomicInt* pCancelRequested =
|
|
|
|
|
m_pInputSnapshot->m_bAutoFitTargetOnly
|
|
|
|
|
m_pInputSnapshot->m_bAutoFitTargetOnly && m_pSensitivitySampling.isNull()
|
|
|
|
|
? NULL : &m_nCancelRequested;
|
|
|
|
|
|
|
|
|
|
// 第一步:清空本次任务自己的输出。旧成果仍保留在 DataManager 中,只有主线程
|
|
|
|
|
@ -1619,6 +1707,8 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
|
|
|
|
|
pCancelRequested)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// 等待锁结束时再次检查停止请求,避免已经停止的批量组仍进入 DLL。
|
|
|
|
|
if(isCancelRequested()) return false;
|
|
|
|
|
HMODULE hModelModule = LoadLibrary(L"HX_NWTM.dll");
|
|
|
|
|
if(hModelModule == nullptr) {
|
|
|
|
|
qWarning() << "Failed to load HX_NWTM.dll. Error code:"
|
|
|
|
|
|