mirror of
https://github.com/OPM/opm-simulators.git
synced 2026-10-24 22:57:42 -05:00
Hybrid Newton small fixes + first test commit
This commit is contained in:
1 parent
859d9de092
commit
6dfcb6f856
5 files changed
+141
-12
No files matched your search
@@ -158,7 +158,7 @@ protected:
|
||||
using IntensiveQuantities = GetPropType<TypeTag, Properties::IntensiveQuantities>;
|
||||
using WellModel = GetPropType<TypeTag, Properties::WellModel>;
|
||||
using AquiferModel = GetPropType<TypeTag, Properties::AquiferModel>;
|
||||
|
||||
|
||||
using Toolbox = MathToolbox<Evaluation>;
|
||||
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
|
||||
|
||||
@@ -1672,7 +1672,7 @@ protected:
|
||||
GlobalEqVector drift_;
|
||||
|
||||
WellModel wellModel_;
|
||||
AquiferModel aquiferModel_;
|
||||
AquiferModel aquiferModel_;
|
||||
|
||||
PffGridVector<GridView, Stencil, PffDofData_, DofMapper> pffDofData_;
|
||||
TracerModel tracerModel_;
|
||||
|
||||
@@ -81,6 +81,7 @@ public:
|
||||
: simulator_(simulator)
|
||||
, configsLoaded_(false)
|
||||
{}
|
||||
|
||||
void tryApplyHybridNewton()
|
||||
{
|
||||
// Check if flag activated
|
||||
@@ -128,7 +129,7 @@ private:
|
||||
{
|
||||
// Load cell indices from file at runtime
|
||||
std::vector<int> cell_indices = loadCellIndicesFromFile(config.cell_indices_file);
|
||||
const size_t n_cells = cell_indices.size();
|
||||
const std::size_t n_cells = cell_indices.size();
|
||||
|
||||
// Pass cells to each stage
|
||||
auto input = constructInputTensor(config, cell_indices, n_cells);
|
||||
@@ -136,8 +137,6 @@ private:
|
||||
updateInitialGuess(output, config, cell_indices, n_cells);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void validateFluidSystem()
|
||||
@@ -319,7 +318,7 @@ protected:
|
||||
* correspond to cells and columns correspond to input features.
|
||||
*/
|
||||
Opm::ML::Tensor<Evaluation>
|
||||
constructInputTensor(const HybridNewtonConfig& config, const std::vector<int>& cell_indices, size_t n_cells)
|
||||
constructInputTensor(const HybridNewtonConfig& config, const std::vector<int>& cell_indices, std::size_t n_cells)
|
||||
{
|
||||
const auto& features = config.input_features;
|
||||
|
||||
@@ -336,11 +335,11 @@ protected:
|
||||
|
||||
const auto& unitSyst = simulator_.vanguard().schedule().getUnits();
|
||||
// Calculate total input size (feature-major)
|
||||
size_t input_size = num_per_cell_features * n_cells + num_scalar_features;
|
||||
std::size_t input_size = num_per_cell_features * n_cells + num_scalar_features;
|
||||
Opm::ML::Tensor<Evaluation> input(input_size);
|
||||
|
||||
// Track offset for each feature in flat tensor
|
||||
size_t offset = 0;
|
||||
std::size_t offset = 0;
|
||||
|
||||
for (const auto& [name, spec] : features) {
|
||||
if (name == "TIMESTEP") {
|
||||
@@ -353,7 +352,7 @@ protected:
|
||||
offset += 1; // advance offset by 1 for scalar
|
||||
} else {
|
||||
// Per-cell feature: assign values for each cell
|
||||
for (size_t cell_idx = 0; cell_idx < n_cells; ++cell_idx) {
|
||||
for (std::size_t cell_idx = 0; cell_idx < n_cells; ++cell_idx) {
|
||||
const auto& intQuants = simulator_.model().intensiveQuantities(cell_indices[cell_idx], 0);
|
||||
const auto& fs = intQuants.fluidState();
|
||||
|
||||
@@ -415,7 +414,7 @@ protected:
|
||||
* output tensor does not match the expected feature layout.
|
||||
*/
|
||||
Opm::ML::Tensor<Evaluation>
|
||||
constructOutputTensor(const Opm::ML::Tensor<Evaluation>& input, const HybridNewtonConfig& config, size_t n_cells)
|
||||
constructOutputTensor(const Opm::ML::Tensor<Evaluation>& input, const HybridNewtonConfig& config, std::size_t n_cells)
|
||||
{
|
||||
const auto& features = config.output_features;
|
||||
const int n_features = features.size();
|
||||
@@ -450,7 +449,7 @@ protected:
|
||||
* \throws std::runtime_error if an expected output feature is missing
|
||||
* or if state update fails for any cell.
|
||||
*/
|
||||
void updateInitialGuess(Opm::ML::Tensor<Evaluation>& output, const HybridNewtonConfig& config, const std::vector<int>& cell_indices, size_t n_cells)
|
||||
void updateInitialGuess(Opm::ML::Tensor<Evaluation>& output, const HybridNewtonConfig& config, const std::vector<int>& cell_indices, std::size_t n_cells)
|
||||
{
|
||||
const auto& features = config.output_features;
|
||||
|
||||
@@ -471,7 +470,7 @@ protected:
|
||||
|
||||
const auto& unitSyst = simulator_.vanguard().schedule().getUnits();
|
||||
|
||||
for (size_t i = 0; i < n_cells; ++i) {
|
||||
for (std::size_t i = 0; i < n_cells; ++i) {
|
||||
const int cell_idx = cell_indices[i];
|
||||
const auto& intQuants = simulator_.model().intensiveQuantities(cell_idx, /*timeIdx*/0);
|
||||
auto fs = intQuants.fluidState();
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
|
||||
|
||||
|
||||
requirements (same as opm-common/python/opm/ml/ml_tools/requirements.txt)
|
||||
|
||||
# Python v.3.9.0 and above
|
||||
python>=3.9.0<=3.12.0
|
||||
|
||||
# Numpy 1.23.0 and above
|
||||
numpy>=1.23.0
|
||||
|
||||
# TensorFlow v.2.1 and above include both CPU and GPU versions.
|
||||
tensorflow>=2.1.0
|
||||
|
||||
# Keras v.2.12.0 and above
|
||||
keras>=2.12.0
|
||||
@@ -0,0 +1,2 @@
|
||||
from opm.io.ecl_state import EclipseState
|
||||
from opm.simulators import BlackOilSimulator
|
||||
@@ -0,0 +1,111 @@
|
||||
import os, json
|
||||
|
||||
def write_config(models, model_dir, multi_mode=False, case_label=None):
|
||||
"""
|
||||
Write one or multiple model configs to JSON.
|
||||
|
||||
models: list of dicts, each dict must contain:
|
||||
- input_features
|
||||
- output_features
|
||||
- model_path
|
||||
- active_cells
|
||||
- apply_time
|
||||
- feature_engineering_input (optional)
|
||||
- scaling_input (optional)
|
||||
- feature_engineering_output (optional)
|
||||
- scaling_output (optional)
|
||||
- input_scaling_params (optional)
|
||||
- output_scaling_params (optional)
|
||||
|
||||
multi_mode: if True, write all configs into a single JSON.
|
||||
case_label: used as filename for multi-mode JSON (required if multi_mode=True).
|
||||
"""
|
||||
|
||||
if multi_mode and not case_label:
|
||||
raise ValueError("case_label must be provided for multi_mode=True")
|
||||
|
||||
os.makedirs(model_dir, exist_ok=True)
|
||||
all_configs = []
|
||||
|
||||
for m in models:
|
||||
# Normalize input/output features
|
||||
input_features = m["input_features"]
|
||||
output_features = m["output_features"]
|
||||
if isinstance(input_features, str):
|
||||
input_features = [input_features]
|
||||
if isinstance(output_features, str):
|
||||
output_features = [output_features]
|
||||
|
||||
n_input = len(input_features)
|
||||
n_output = len(output_features)
|
||||
|
||||
# Optional fields (safe defaults)
|
||||
fe_input = m.get("feature_engineering_input") or [None]*n_input
|
||||
fe_output = m.get("feature_engineering_output") or [None]*n_output
|
||||
scaling_input = m.get("scaling_input") or [None]*n_input
|
||||
scaling_output = m.get("scaling_output") or [None]*n_output
|
||||
input_scaling_params = m.get("input_scaling_params") or [None]*n_input
|
||||
output_scaling_params = m.get("output_scaling_params") or [None]*n_output
|
||||
|
||||
# Build input block
|
||||
input_block = {}
|
||||
for i, fname in enumerate(input_features):
|
||||
feat_eng = fe_input[i] if i < len(fe_input) else None
|
||||
scale = scaling_input[i] if i < len(scaling_input) else None
|
||||
feature_dict = {
|
||||
"feature_engineering": feat_eng.lower() if feat_eng and feat_eng.lower() != "none" else None,
|
||||
"scaling": scale.lower() if scale and scale.lower() != "none" else None,
|
||||
}
|
||||
feature_dict = {k: v for k, v in feature_dict.items() if v is not None}
|
||||
if i < len(input_scaling_params) and input_scaling_params[i] is not None:
|
||||
feature_dict["scaling_params"] = input_scaling_params[i]
|
||||
input_block[fname] = feature_dict
|
||||
|
||||
# Build output block
|
||||
output_block = {}
|
||||
for i, fname in enumerate(output_features):
|
||||
feat_eng = fe_output[i] if i < len(fe_output) else None
|
||||
scale = scaling_output[i] if i < len(scaling_output) else None
|
||||
feature_dict = {
|
||||
"feature_engineering": feat_eng.lower() if feat_eng and feat_eng.lower() != "none" else None,
|
||||
"scaling": scale.lower() if scale and scale.lower() != "none" else None,
|
||||
}
|
||||
feature_dict = {k: v for k, v in feature_dict.items() if v is not None}
|
||||
if i < len(output_scaling_params) and output_scaling_params[i] is not None:
|
||||
feature_dict["scaling_params"] = output_scaling_params[i]
|
||||
output_block[fname] = feature_dict
|
||||
|
||||
# Save active cells
|
||||
model_base = os.path.splitext(os.path.basename(m["model_path"]))[0]
|
||||
cells_file = os.path.join(model_dir, model_base + "_active_cells.txt")
|
||||
with open(cells_file, "w") as f:
|
||||
for cell in m["active_cells"]:
|
||||
f.write(f"{cell}\n")
|
||||
|
||||
# Build config dict
|
||||
cfg = {
|
||||
"model_path": m["model_path"],
|
||||
"cell_indices_file": cells_file,
|
||||
"apply_times": [m["apply_time"]],
|
||||
"features": {
|
||||
"inputs": input_block,
|
||||
"outputs": output_block
|
||||
}
|
||||
}
|
||||
all_configs.append(cfg)
|
||||
|
||||
# Determine JSON filename
|
||||
if multi_mode:
|
||||
if not case_label:
|
||||
raise ValueError("case_label is required for multi_mode")
|
||||
json_name = case_label + ".json"
|
||||
else:
|
||||
json_name = os.path.splitext(os.path.basename(models[0]["model_path"]))[0] + ".json"
|
||||
|
||||
json_path = os.path.join(model_dir, json_name)
|
||||
|
||||
# Always write a list of configs
|
||||
with open(json_path, "w") as f:
|
||||
json.dump(all_configs, f, indent=2)
|
||||
|
||||
return json_path
|
||||
Reference in new issue
Block a user