22#ifndef HYBRID_NEWTON_HPP
23#define HYBRID_NEWTON_HPP
28#include <opm/input/eclipse/Units/UnitSystem.hpp>
30#include <opm/ml/ml_model.hpp>
57template <
typename TypeTag>
102 if (!Parameters::Get<Parameters::UseHyNe>())
108 std::string config_file = Parameters::Get<Parameters::HyNeConfigFile>();
113 configs_.push_back(std::move(config));
120 for (
const auto& config :
configs_) {
122 runHybridNewton(config);
153 const auto& eclState =
simulator_.vanguard().eclState();
154 const auto& phases = eclState.runspec().phases();
156 bool hasWater = phases.active(Phase::WATER);
157 bool hasGas = phases.active(Phase::GAS);
158 bool hasOil = phases.active(Phase::OIL);
159 bool hasSolvent = phases.active(Phase::SOLVENT);
162 if (!(hasWater && hasOil && hasGas && !hasSolvent)) {
163 OPM_THROW(std::runtime_error,
164 "HybridNewton: Unsupported fluid system. Only three-phase black oil is supported.");
192 constexpr Scalar tolerance = 1e-6;
193 bool apply = std::abs(current_time - config.
apply_times[0]) < tolerance;
200 bool apply = (current_time >= start_time) && (current_time <= end_time);
240 std::size_t input_tensor_length = 0;
241 for (
const auto& feature : features) {
244 input_tensor_length += 1;
246 input_tensor_length += config.
n_cells;
250 ML::Tensor<Evaluation> input(input_tensor_length);
251 std::size_t offset = 0;
254 for (
const auto& feature: features) {
259 input(offset++) = value;
261 for (std::size_t i = 0; i < config.
n_cells; ++i) {
265 input(offset + i) = value;
295 OPM_THROW(std::runtime_error,
"Unknown scalar feature: " + spec.
actual_name);
321 const auto& intQuants =
simulator_.model().intensiveQuantities(cell_index, 0);
322 const auto& fs = intQuants.fluidState();
323 const auto& unitSyst =
simulator_.vanguard().schedule().getUnits();
329 value = unitSyst.from_si(UnitSystem::measure::pressure, value);
337 value = getValue(fs.Rs());
338 value = unitSyst.from_si(UnitSystem::measure::gas_oil_ratio, value);
340 value = getValue(fs.Rv());
341 value = unitSyst.from_si(UnitSystem::measure::oil_gas_ratio, value);
343 const auto& eclState =
simulator_.vanguard().eclState();
344 const auto& fp = eclState.fieldProps();
345 auto permX = fp.get_double(
"PERMX");
346 value = permX[cell_index];
347 value = unitSyst.from_si(UnitSystem::measure::permeability, value);
349 OPM_THROW(std::runtime_error,
"Unknown per-cell feature: " + spec.
actual_name);
376 ML::Tensor<Evaluation>
380 const int n_features = features.size();
382 ML::NNModel<Evaluation> model;
385 ML::Tensor<Evaluation> output(1, config.
n_cells * n_features);
386 model.apply(input, output);
419 ML::Tensor<Evaluation>& output,
427 const auto& unitSyst =
simulator_.vanguard().schedule().getUnits();
429 for (std::size_t i = 0; i < config.
n_cells; ++i) {
431 const auto& intQuants =
simulator_.model().intensiveQuantities(cell_idx, 0);
432 auto fs = intQuants.fluidState();
442 for (
const auto& [name, spec] : features) {
444 auto scaled_value = getValue(output(feature_idx * config.
n_cells + i));
447 Scalar raw_value = spec.scaler.unscale(scaled_value);
450 raw_value = spec.transform.applyInverse(raw_value);
453 if (spec.actual_name ==
"PRESSURE") {
454 raw_value = raw_value + unitSyst.from_si(UnitSystem::measure::pressure, getValue(fs.pressure(
oilPhaseIdx)));
455 }
else if (spec.actual_name ==
"SWAT") {
457 }
else if (spec.actual_name ==
"SOIL") {
459 }
else if (spec.actual_name ==
"SGAS") {
461 }
else if (spec.actual_name ==
"RS") {
462 raw_value = raw_value + unitSyst.from_si(UnitSystem::measure::gas_oil_ratio, getValue(fs.Rs()));
463 }
else if (spec.actual_name ==
"RV") {
464 raw_value = raw_value + unitSyst.from_si(UnitSystem::measure::oil_gas_ratio, getValue(fs.Rv()));
466 OPM_THROW(std::runtime_error,
"Unknown delta feature: " + name);
470 if (spec.actual_name ==
"PRESSURE") {
471 po_val = unitSyst.to_si(UnitSystem::measure::pressure, raw_value);
472 }
else if (spec.actual_name ==
"SWAT") {
474 }
else if (spec.actual_name ==
"SOIL") {
476 }
else if (spec.actual_name ==
"SGAS") {
478 }
else if (spec.actual_name ==
"RS") {
480 raw_value = unitSyst.to_si(UnitSystem::measure::gas_oil_ratio, raw_value);
483 }
else if (spec.actual_name ==
"RV") {
485 raw_value = unitSyst.to_si(UnitSystem::measure::oil_gas_ratio, raw_value);
489 OPM_THROW(std::runtime_error,
"Unknown output feature: " + name);
495 int sat_count =
static_cast<int>(flags.
has_SWAT) +
static_cast<int>(flags.
has_SOIL) +
static_cast<int>(flags.
has_SGAS);
497 if (sat_count >= 2) {
510 sw = max(0.0, min(sw, 1.0));
511 so = max(0.0, min(so, 1.0));
512 sg = max(0.0, min(sg, 1.0));
514 Scalar sum = sw + so + sg;
516 OPM_THROW(std::runtime_error,
"Saturation sum is zero in cell " +
std::to_string(cell_idx));
525 std::array<Evaluation, numPhases> pC;
526 const auto& materialParams =
simulator_.problem().materialLawParams(cell_idx);
527 MaterialLaw::capillaryPressures(pC, materialParams, fs);
529 for (
unsigned phaseIdx = 0; phaseIdx <
numPhases; ++phaseIdx) {
530 if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
532 fs.setPressure(phaseIdx, po_val);
534 fs.setPressure(phaseIdx, po_val - pC[phaseIdx]);
539 auto& primaryVars =
simulator_.model().solution(0)[cell_idx];
540 primaryVars.assignNaive(fs);
543 simulator_.model().invalidateAndUpdateIntensiveQuantities(0);
557 for (
const auto& [name, spec] : features) {
559 if (spec.actual_name ==
"SWAT") {
561 }
else if (spec.actual_name ==
"SOIL") {
563 }
else if (spec.actual_name ==
"SGAS") {
565 }
else if (spec.actual_name ==
"PRESSURE") {
Hybrid Newton solver extension for the black-oil model.
Definition: HybridNewton.hpp:59
bool configsLoaded_
Definition: HybridNewton.hpp:576
GetPropType< TypeTag, Properties::Indices > Indices
Definition: HybridNewton.hpp:65
@ gasPhaseIdx
Definition: HybridNewton.hpp:70
void tryApplyHybridNewton()
Attempt to apply the Hybrid Newton correction at the current timestep.
Definition: HybridNewton.hpp:99
FeatureFlags flagFeatures(const std::vector< std::pair< std::string, FeatureSpec > > &features)
Definition: HybridNewton.hpp:553
@ numPhases
Definition: HybridNewton.hpp:68
GetPropType< TypeTag, Properties::Evaluation > Evaluation
Definition: HybridNewton.hpp:62
BlackOilHybridNewton(Simulator &simulator)
Definition: HybridNewton.hpp:77
Scalar getPerCellFeatureValue(const FeatureSpec &spec, int cell_index)
Retrieve and transform a per-cell feature value.
Definition: HybridNewton.hpp:319
std::vector< HybridNewtonConfig > configs_
Definition: HybridNewton.hpp:575
bool shouldApplyHybridNewton(Scalar current_time, const HybridNewtonConfig &config) const
Check whether the Hybrid Newton method should be applied at the given time.
Definition: HybridNewton.hpp:188
static constexpr bool compositionSwitchEnabled
Definition: HybridNewton.hpp:74
GetPropType< TypeTag, Properties::MaterialLaw > MaterialLaw
Definition: HybridNewton.hpp:64
@ waterPhaseIdx
Definition: HybridNewton.hpp:72
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition: HybridNewton.hpp:66
ML::Tensor< Evaluation > constructOutputTensor(const ML::Tensor< Evaluation > &input, const HybridNewtonConfig &config)
Run the Hybrid Newton model to produce output predictions.
Definition: HybridNewton.hpp:377
GetPropType< TypeTag, Properties::Simulator > Simulator
Definition: HybridNewton.hpp:61
GetPropType< TypeTag, Properties::FluidSystem > FluidSystem
Definition: HybridNewton.hpp:63
Scalar getScalarFeatureValue(const FeatureSpec &spec)
Retrieve and transform a scalar feature (global across the domain).
Definition: HybridNewton.hpp:288
void updateInitialGuess(ML::Tensor< Evaluation > &output, const HybridNewtonConfig &config)
Update the nonlinear solver's initial guess using ML predictions.
Definition: HybridNewton.hpp:418
void validateFluidSystem()
Definition: HybridNewton.hpp:151
@ oilPhaseIdx
Definition: HybridNewton.hpp:71
ML::Tensor< Evaluation > constructInputTensor(const HybridNewtonConfig &config)
Construct the input feature tensor for the Hybrid Newton model.
Definition: HybridNewton.hpp:233
Simulator & simulator_
Definition: HybridNewton.hpp:574
Configuration for a Hybrid Newton ML model.
Definition: HybridNewtonConfig.hpp:130
std::vector< double > apply_times
Definition: HybridNewtonConfig.hpp:136
std::vector< std::pair< std::string, FeatureSpec > > input_features
Definition: HybridNewtonConfig.hpp:137
std::vector< std::pair< std::string, FeatureSpec > > output_features
Definition: HybridNewtonConfig.hpp:138
void validateConfig(bool compositionSwitchEnabled) const
Validate feature compatibility with simulator settings.
Definition: HybridNewtonConfig.hpp:195
std::size_t n_cells
Definition: HybridNewtonConfig.hpp:135
std::vector< int > cell_indices
Definition: HybridNewtonConfig.hpp:134
std::string model_path
Definition: HybridNewtonConfig.hpp:132
Hierarchical collection of key/value pairs.
Definition: PropertyTree.hpp:39
std::vector< std::string > get_child_keys() const
PropertyTree get_child(const std::string &key) const
Definition: blackoilbioeffectsmodules.hh:43
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:233
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t)
Definition: HybridNewton.hpp:546
bool has_SOIL
Definition: HybridNewton.hpp:548
bool has_SWAT
Definition: HybridNewton.hpp:547
bool has_SGAS
Definition: HybridNewton.hpp:549
bool has_PRESSURE
Definition: HybridNewton.hpp:550
Metadata for a single feature (input or output).
Definition: HybridNewtonConfig.hpp:115
Transform transform
Definition: HybridNewtonConfig.hpp:116
std::string actual_name
Definition: HybridNewtonConfig.hpp:119
Scaler scaler
Definition: HybridNewtonConfig.hpp:117
double scale(double raw_value) const
Definition: HybridNewtonConfig.hpp:48