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>
58template <
typename TypeTag>
76 Indices::compositionSwitchIdx != std::numeric_limits<unsigned>::max();
104 if (!Parameters::Get<Parameters::UseHybridNewton>())
110 std::string config_file = Parameters::Get<Parameters::HybridNewtonConfigFile>();
115 configs_.push_back(std::move(config));
122 for (
const auto& config :
configs_) {
124 runHybridNewton(config);
154 const auto& eclState =
simulator_.vanguard().eclState();
155 const auto& phases = eclState.runspec().phases();
157 bool hasWater = phases.active(Phase::WATER);
158 bool hasGas = phases.active(Phase::GAS);
159 bool hasOil = phases.active(Phase::OIL);
160 bool hasSolvent = phases.active(Phase::SOLVENT);
163 if (!(hasWater && hasOil && hasGas && !hasSolvent)) {
164 OPM_THROW(std::runtime_error,
165 "HybridNewton: Unsupported fluid system. Only three-phase black oil is supported.");
193 constexpr Scalar tolerance = 1e-6;
194 bool apply = std::abs(current_time - config.
apply_times[0]) < tolerance;
201 bool apply = (current_time >= start_time) && (current_time <= end_time);
234 ML::Tensor<Evaluation>
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>
381 const int n_features = features.size();
383 ML::NNModel<Evaluation> model;
386 ML::Tensor<Evaluation> output(1, config.
n_cells * n_features);
387 model.apply(input, output);
426 const auto& unitSyst =
simulator_.vanguard().schedule().getUnits();
428 for (std::size_t i = 0; i < config.
n_cells; ++i) {
430 const auto& intQuants =
simulator_.model().intensiveQuantities(cell_idx, 0);
431 auto fs = intQuants.fluidState();
441 for (
const auto& [name, spec] : features) {
443 auto scaled_value = getValue(output(feature_idx * config.
n_cells + i));
446 Scalar raw_value = spec.scaler.unscale(scaled_value);
449 raw_value = spec.transform.applyInverse(raw_value);
452 if (spec.actual_name ==
"PRESSURE") {
453 raw_value = raw_value + unitSyst.from_si(UnitSystem::measure::pressure, getValue(fs.pressure(
oilPhaseIdx)));
454 }
else if (spec.actual_name ==
"SWAT") {
456 }
else if (spec.actual_name ==
"SOIL") {
458 }
else if (spec.actual_name ==
"SGAS") {
460 }
else if (spec.actual_name ==
"RS") {
461 raw_value = raw_value + unitSyst.from_si(UnitSystem::measure::gas_oil_ratio, getValue(fs.Rs()));
462 }
else if (spec.actual_name ==
"RV") {
463 raw_value = raw_value + unitSyst.from_si(UnitSystem::measure::oil_gas_ratio, getValue(fs.Rv()));
465 OPM_THROW(std::runtime_error,
"Unknown delta feature: " + name);
469 if (spec.actual_name ==
"PRESSURE") {
470 po_val = unitSyst.to_si(UnitSystem::measure::pressure, raw_value);
471 }
else if (spec.actual_name ==
"SWAT") {
473 }
else if (spec.actual_name ==
"SOIL") {
475 }
else if (spec.actual_name ==
"SGAS") {
477 }
else if (spec.actual_name ==
"RS") {
479 raw_value = unitSyst.to_si(UnitSystem::measure::gas_oil_ratio, raw_value);
482 }
else if (spec.actual_name ==
"RV") {
484 raw_value = unitSyst.to_si(UnitSystem::measure::oil_gas_ratio, raw_value);
488 OPM_THROW(std::runtime_error,
"Unknown output feature: " + name);
494 int sat_count =
static_cast<int>(flags.
has_SWAT) +
498 if (sat_count >= 2) {
511 sw = max(0.0, min(sw, 1.0));
512 so = max(0.0, min(so, 1.0));
513 sg = max(0.0, min(sg, 1.0));
515 Scalar sum = sw + so + sg;
517 OPM_THROW(std::runtime_error,
"Saturation sum is zero in cell " +
std::to_string(cell_idx));
526 std::array<Evaluation, numPhases> pC;
527 const auto& materialParams =
simulator_.problem().materialLawParams(cell_idx);
528 MaterialLaw::capillaryPressures(pC, materialParams, fs);
530 for (
unsigned phaseIdx = 0; phaseIdx <
numPhases; ++phaseIdx) {
531 if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
533 fs.setPressure(phaseIdx, po_val);
535 fs.setPressure(phaseIdx, po_val - pC[phaseIdx]);
540 auto& primaryVars =
simulator_.model().solution(0)[cell_idx];
541 primaryVars.assignNaive(fs);
544 simulator_.model().invalidateAndUpdateIntensiveQuantities(0);
559 for (
const auto& [name, spec] : features) {
561 if (spec.actual_name ==
"SWAT") {
563 }
else if (spec.actual_name ==
"SOIL") {
565 }
else if (spec.actual_name ==
"SGAS") {
567 }
else if (spec.actual_name ==
"PRESSURE") {
Hybrid Newton solver extension for the black-oil model.
Definition: HybridNewton.hpp:60
bool configsLoaded_
Definition: HybridNewton.hpp:578
GetPropType< TypeTag, Properties::Indices > Indices
Definition: HybridNewton.hpp:66
void tryApplyHybridNewton()
Attempt to apply the Hybrid Newton correction at the current timestep.
Definition: HybridNewton.hpp:101
FeatureFlags flagFeatures(const std::vector< std::pair< std::string, FeatureSpec > > &features)
Definition: HybridNewton.hpp:555
GetPropType< TypeTag, Properties::Evaluation > Evaluation
Definition: HybridNewton.hpp:63
BlackOilHybridNewton(Simulator &simulator)
Definition: HybridNewton.hpp:79
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:577
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:189
static constexpr bool compositionSwitchEnabled
Definition: HybridNewton.hpp:75
GetPropType< TypeTag, Properties::MaterialLaw > MaterialLaw
Definition: HybridNewton.hpp:65
@ gasPhaseIdx
Definition: HybridNewton.hpp:71
@ numPhases
Definition: HybridNewton.hpp:69
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition: HybridNewton.hpp:67
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:62
GetPropType< TypeTag, Properties::FluidSystem > FluidSystem
Definition: HybridNewton.hpp:64
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:419
void validateFluidSystem()
Definition: HybridNewton.hpp:152
@ waterPhaseIdx
Definition: HybridNewton.hpp:73
ML::Tensor< Evaluation > constructInputTensor(const HybridNewtonConfig &config)
Construct the input feature tensor for the Hybrid Newton model.
Definition: HybridNewton.hpp:235
Simulator & simulator_
Definition: HybridNewton.hpp:576
@ oilPhaseIdx
Definition: HybridNewton.hpp:72
Configuration for a Hybrid Newton ML model.
Definition: HybridNewtonConfig.hpp:136
std::vector< double > apply_times
Definition: HybridNewtonConfig.hpp:142
std::vector< std::pair< std::string, FeatureSpec > > input_features
Definition: HybridNewtonConfig.hpp:143
std::vector< std::pair< std::string, FeatureSpec > > output_features
Definition: HybridNewtonConfig.hpp:144
void validateConfig(bool compositionSwitchEnabled) const
Validate feature compatibility with simulator settings.
std::size_t n_cells
Definition: HybridNewtonConfig.hpp:141
std::vector< int > cell_indices
Definition: HybridNewtonConfig.hpp:140
std::string model_path
Definition: HybridNewtonConfig.hpp:138
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:45
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:548
bool has_SOIL
Definition: HybridNewton.hpp:550
bool has_SWAT
Definition: HybridNewton.hpp:549
bool has_SGAS
Definition: HybridNewton.hpp:551
bool has_PRESSURE
Definition: HybridNewton.hpp:552
Metadata for a single feature (input or output).
Definition: HybridNewtonConfig.hpp:120
Transform transform
Definition: HybridNewtonConfig.hpp:121
std::string actual_name
Definition: HybridNewtonConfig.hpp:124
Scaler scaler
Definition: HybridNewtonConfig.hpp:122
double scale(double raw_value) const
Definition: HybridNewtonConfig.hpp:46