22#ifndef HYBRID_NEWTON_HPP
23#define HYBRID_NEWTON_HPP
27#include <opm/simulators/flow/HybridNewtonConfig.hpp>
28#include <opm/input/eclipse/Units/UnitSystem.hpp>
30#include <opm/ml/ml_model.hpp>
57template <
typename TypeTag>
68 enum { numPhases = FluidSystem::numPhases };
70 enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
71 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
72 enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
74 static constexpr bool compositionSwitchEnabled = Indices::compositionSwitchIdx >= 0;
78 : simulator_(simulator)
79 , configsLoaded_(
false)
102 if (!Parameters::Get<Parameters::UseHyNe>())
105 validateFluidSystem();
107 if (!configsLoaded_) {
108 std::string
config_file = Parameters::Get<Parameters::HyNeConfigFile>();
110 for (
const auto&
model_key :
pt.get_child_keys()) {
112 config.validateConfig(compositionSwitchEnabled);
113 configs_.push_back(std::move(
config));
115 configsLoaded_ =
true;
120 for (
const auto&
config : configs_) {
151 void validateFluidSystem()
153 const auto& eclState = simulator_.vanguard().eclState();
154 const auto&
phases = eclState.runspec().phases();
164 "HybridNewton: Unsupported fluid system. Only three-phase black oil is supported.");
190 if (
config.apply_times.size() == 1) {
192 constexpr Scalar tolerance = 1
e-6;
197 if (
config.apply_times.size() == 2) {
243 if (
spec.actual_name ==
"TIMESTEP") {
251 std::size_t offset = 0;
257 if (
spec.actual_name ==
"TIMESTEP") {
259 input(offset++) = value;
261 for (std::size_t i = 0; i <
config.n_cells; ++i) {
262 auto value =
static_cast<Evaluation
>(
265 input(offset + i) = value;
292 if (
spec.actual_name ==
"TIMESTEP") {
293 value = simulator_.timeStepSize();
295 OPM_THROW(std::runtime_error,
"Unknown scalar feature: " +
spec.actual_name);
298 value =
spec.transform.apply(value);
299 return spec.scaler.scale(value);
321 const auto& intQuants = simulator_.model().intensiveQuantities(cell_index, 0);
322 const auto& fs = intQuants.fluidState();
323 const auto&
unitSyst = simulator_.vanguard().schedule().getUnits();
327 if (
spec.actual_name ==
"PRESSURE") {
328 value =
getValue(fs.pressure(oilPhaseIdx));
329 value =
unitSyst.from_si(UnitSystem::measure::pressure, value);
330 }
else if (
spec.actual_name ==
"SWAT") {
331 value =
getValue(fs.saturation(waterPhaseIdx));
332 }
else if (
spec.actual_name ==
"SGAS") {
333 value =
getValue(fs.saturation(gasPhaseIdx));
334 }
else if (
spec.actual_name ==
"SOIL") {
335 value =
getValue(fs.saturation(oilPhaseIdx));
336 }
else if (
spec.actual_name ==
"RS") {
338 value =
unitSyst.from_si(UnitSystem::measure::gas_oil_ratio, value);
339 }
else if (
spec.actual_name ==
"RV") {
341 value =
unitSyst.from_si(UnitSystem::measure::oil_gas_ratio, value);
342 }
else if (
spec.actual_name ==
"PERMX") {
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>
382 ML::NNModel<Evaluation> model;
383 model.loadModel(
config.model_path);
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();
453 if (
spec.actual_name ==
"PRESSURE") {
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") {
463 }
else if (
spec.actual_name ==
"RV") {
466 OPM_THROW(std::runtime_error,
"Unknown delta feature: " + name);
470 if (
spec.actual_name ==
"PRESSURE") {
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") {
479 if constexpr (compositionSwitchEnabled) {
483 }
else if (
spec.actual_name ==
"RV") {
484 if constexpr (compositionSwitchEnabled) {
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);
502 if (!
flags.has_SWAT) {
504 }
else if (!
flags.has_SOIL) {
506 }
else if (!
flags.has_SGAS) {
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));
519 fs.setSaturation(waterPhaseIdx,
sw / sum);
520 fs.setSaturation(oilPhaseIdx,
so / sum);
521 fs.setSaturation(gasPhaseIdx, sg / sum);
524 if (
flags.has_PRESSURE) {
525 std::array<Evaluation, numPhases>
pC;
530 if (!FluidSystem::phaseIsActive(
phaseIdx))
continue;
539 auto& primaryVars = simulator_.model().solution(0)[
cell_idx];
540 primaryVars.assignNaive(fs);
543 simulator_.model().invalidateAndUpdateIntensiveQuantities(0);
547 bool has_SWAT =
false;
548 bool has_SOIL =
false;
549 bool has_SGAS =
false;
550 bool has_PRESSURE =
false;
559 if (
spec.actual_name ==
"SWAT") {
560 flags.has_SWAT =
true;
561 }
else if (
spec.actual_name ==
"SOIL") {
562 flags.has_SOIL =
true;
563 }
else if (
spec.actual_name ==
"SGAS") {
564 flags.has_SGAS =
true;
565 }
else if (
spec.actual_name ==
"PRESSURE") {
566 flags.has_PRESSURE =
true;
574 Simulator& simulator_;
575 std::vector<HybridNewtonConfig> configs_;
Hybrid Newton solver extension for the black-oil model.
Definition HybridNewton.hpp:59
void tryApplyHybridNewton()
Attempt to apply the Hybrid Newton correction at the current timestep.
Definition HybridNewton.hpp:99
Scalar getPerCellFeatureValue(const FeatureSpec &spec, int cell_index)
Retrieve and transform a per-cell feature value.
Definition HybridNewton.hpp:319
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
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
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
ML::Tensor< Evaluation > constructInputTensor(const HybridNewtonConfig &config)
Construct the input feature tensor for the Hybrid Newton model.
Definition HybridNewton.hpp:233
Configuration for a Hybrid Newton ML model.
Definition HybridNewtonConfig.hpp:130
Hierarchical collection of key/value pairs.
Definition PropertyTree.hpp:39
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition blackoilbioeffectsmodules.hh:43
constexpr auto getPropValue()
get the value data member of a property
Definition propertysystem.hh:240
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
Definition HybridNewton.hpp:546
Metadata for a single feature (input or output).
Definition HybridNewtonConfig.hpp:115