diff --git a/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h b/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h index 9b6ba809..25de48bb 100644 --- a/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h +++ b/Include/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.h @@ -103,6 +103,31 @@ class NMCALCULATION_EXPORT nmCalculationDllPebiSolverTask : public QThread { bool updateSensitivityRun(const nmDataSensitive& sampling, quint64 runIndex, QString* errorMessage = nullptr); + /** @brief 一组采样的临时返回值,参数顺序与采样配置的变量列表一致。 */ + struct SensitivityRunResult + { + SensitivityRunResult() : m_nRunIndex(0), m_bSucceeded(false) {} + quint64 m_nRunIndex; ///< 与预览一致的零基运行编号。 + QVector m_vecParameters; ///< 本组参数的业务基准单位值。 + QVector > m_vecPressure; + QVector > m_vecLogLog; + QVector > m_vecSemiLog; + bool m_bSucceeded; + QString m_sFailureReason; + }; + + /** + * @brief 从源快照创建一份副本,按两种确定性方法的预览顺序串行求解全部组合。 + * @param results 本次批量返回值;进入时清空,每组结果在更新下一组前独立保留。 + * @return 全部组合遍历完成返回 true,单组成功与否读取对应 m_bSucceeded。 + * 配置、基础网格或内存不足时返回 false;已完成的结果仍保留。 + * @note 源任务要求与 createSensitivityRun() 相同。此接口同步执行,调用方 + * 负责安排执行线程和在 DataManager 所属线程提前捕获源输入。 + */ + bool calculateSensitivityBatch(const nmDataSensitive& sampling, + std::vector& results, + QString* errorMessage = nullptr) const; + private: /** @brief 仅复制目标井求解的值快照,不登记或访问实时管理器。 */ nmCalculationDllPebiSolverTask(const nmCalculationDllPebiSolverTask& source, diff --git a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp index 372c4cb1..6af0b7d1 100644 --- a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp +++ b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp @@ -857,6 +857,71 @@ bool nmCalculationDllPebiSolverTask::updateSensitivityRun( return true; } +bool nmCalculationDllPebiSolverTask::calculateSensitivityBatch( + const nmDataSensitive& sampling, std::vector& results, + QString* errorMessage) const +{ + results.clear(); + if(errorMessage) errorMessage->clear(); + try { + // 冻结整次批量的配置,次数、运行顺序和返回参数都使用同一份采样数据。 + const nmDataSensitive frozenSampling(sampling); + bool overflow = false; + const quint64 count = frozenSampling.calculateModelCount(&overflow); + const nmDataSensitive::CalculationType type = frozenSampling.getCalculationType(); + if(overflow || count == 0 || !frozenSampling.usesBaseUnits() || + (type != nmDataSensitive::CALC_DETERMINISTIC && + type != nmDataSensitive::CALC_DETERMINISTIC_MULTIVARIATE)) { + if(errorMessage) *errorMessage = tr("Invalid sensitivity sampling configuration."); + return false; + } + + // 只在整次批量开始时复制模型与网格;首组参数由创建接口填入。 + QString creationError; + QScopedPointer task( + createSensitivityRun(frozenSampling, 0, &creationError)); + if(!task) { + if(errorMessage) *errorMessage = creationError; + return false; + } + + for(quint64 runIndex = 0; runIndex < count; ++runIndex) { + SensitivityRunResult result; + result.m_nRunIndex = runIndex; + // 单参数法保持其余参数的模型值,多参数法按预览组合顺序逐组取值。 + bool inputReady = frozenSampling.getRunValues(runIndex, result.m_vecParameters); + if(!inputReady) { + result.m_sFailureReason = tr("Invalid sensitivity sampling configuration."); + } else if(runIndex > 0) { + // 本组更新失败仍保留运行编号,下一组继续从冻结基准更新。 + inputReady = task->updateSensitivityRun(frozenSampling, runIndex, + &result.m_sFailureReason); + } + if(inputReady) { + task->run(); + result.m_bSucceeded = task->wasSuccessful(); + if(result.m_bSucceeded) { + result.m_vecPressure = task->getAutoFitResultPressure(); + result.m_vecLogLog = task->getAutoFitResultLogLog(); + result.m_vecSemiLog = task->getAutoFitResultSemiLog(); + } else { + result.m_sFailureReason = task->getFailureReason(); + } + } + // Qt 曲线容器按值保留;下一组清空任务结果不会清掉这里的曲线。 + // 不预先展开全部组合或预分配总次数,也不合并重复的基准组合。 + results.push_back(result); + } + return true; + } catch(const std::bad_alloc&) { + if(errorMessage) *errorMessage = tr("Insufficient memory to process solver results."); + return false; + } catch(const std::length_error&) { + if(errorMessage) *errorMessage = tr("Insufficient memory to process solver results."); + return false; + } +} + void nmCalculationDllPebiSolverTask::run() { m_nSolveTimeMs = -1;