Hide code cell content
###############################################################################
# The Institute for the Design of Advanced Energy Systems Integrated Platform
# Framework (IDAES IP) was produced under the DOE Institute for the
# Design of Advanced Energy Systems (IDAES).
#
# Copyright (c) 2018-2023 by the software owners: The Regents of the
# University of California, through Lawrence Berkeley National Laboratory,
# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon
# University, West Virginia University Research Corporation, et al.
# All rights reserved.  Please see the files COPYRIGHT.md and LICENSE.md
# for full copyright and license information.
###############################################################################

Autothermal Reformer Flowsheet Optimization with OMLT (TensorFlow Keras) Surrogate Object#

Maintainer: Brandon Paul
Author: Brandon Paul
Updated: 2023-06-01

1. Introduction#

This example demonstrates autothermal reformer optimization leveraging the OMLT package utilizing TensorFlow Keras neural networks. In this notebook, sampled simulation data will be used to train and validate a surrogate model. IDAES surrogate plotting tools will be utilized to visualize the surrogates on training and validation data. Once validated, integration of the surrogate into an IDAES flowsheet will be demonstrated.

2. Problem Statement#

Within the context of a larger NGFC system, the autothermal reformer generates syngas from air, steam and natural gas for use in a solid-oxide fuel cell (SOFC).

2.1. Main Inputs:#

  • Bypass fraction (dimensionless) - split fraction of natural gas to bypass AR unit and feed directly to the power island

  • NG-Steam Ratio (dimensionless) - proportion of natural relative to steam fed into AR unit operation

2.2. Main Outputs:#

  • Steam flowrate (kg/s) - inlet steam fed to AR unit

  • Reformer duty (kW) - required energy input to AR unit

  • Composition (dimensionless) - outlet mole fractions of components (Ar, C2H6, C3H8, C4H10, CH4, CO, CO2, H2, H2O, N2, O2)

from IPython.display import Image
from pathlib import Path


def datafile_path(name):
    return Path("..") / name


Image(datafile_path("AR_PFD.png"))
../../../_images/1a3b4ae911ad91d018a0eda19303684d24f174506309b4831ccbdaefc6dc984b.png

3. Training and Validating Surrogates#

First, let’s import the required Python, Pyomo and IDAES modules:

# Import statements
import os
import numpy as np
import pandas as pd
import random as rn
import tensorflow as tf

# Import Pyomo libraries
from pyomo.environ import (
    ConcreteModel,
    SolverFactory,
    value,
    Var,
    Constraint,
    Set,
    Objective,
    maximize,
)
from pyomo.common.timing import TicTocTimer

# Import IDAES libraries
from idaes.core.surrogate.sampling.data_utils import split_training_validation
from idaes.core.surrogate.sampling.scaling import OffsetScaler
from idaes.core.surrogate.keras_surrogate import (
    KerasSurrogate,
    save_keras_json_hd5,
    load_keras_json_hd5,
)
from idaes.core.surrogate.plotting.sm_plotter import (
    surrogate_scatter2D,
    surrogate_parity,
    surrogate_residual,
)
from idaes.core.surrogate.surrogate_block import SurrogateBlock
from idaes.core import FlowsheetBlock

# fix environment variables to ensure consist neural network training
os.environ["PYTHONHASHSEED"] = "0"
os.environ["CUDA_VISIBLE_DEVICES"] = ""
np.random.seed(46)
rn.seed(1342)
tf.random.set_seed(62)
2024-05-28 17:19:11.494640: I tensorflow/tsl/cuda/cudart_stub.cc:28] Could not find cuda drivers on your machine, GPU will not be used.
2024-05-28 17:19:11.544393: I tensorflow/tsl/cuda/cudart_stub.cc:28] Could not find cuda drivers on your machine, GPU will not be used.
2024-05-28 17:19:11.545296: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.
To enable the following instructions: AVX2 AVX512F FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.
2024-05-28 17:19:12.447655: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT
WARNING: DEPRECATED: Declaring class 'OmltBlockData' derived from
'_BlockData'. The class '_BlockData' has been renamed to 'BlockData'.
(deprecated in 6.7.2) (called from
/home/docs/checkouts/readthedocs.org/user_builds/idaes-
examples/envs/latest/lib/python3.8/site-packages/omlt/block.py:33)

3.1 Importing Training and Validation Datasets#

In this section, we read the dataset from the CSV file located in this directory. 2800 data points were simulated from a rigorous IDAES NGFC flowsheet using a grid sampling method. For simplicity and to reduce training runtime, this example randomly selects 100 data points to use for training/validation. The data is separated using an 80/20 split into training and validation data using the IDAES split_training_validation() method.

# Import Auto-reformer training data
np.set_printoptions(precision=6, suppress=True)

csv_data = pd.read_csv(datafile_path("reformer-data.csv"))  # 2800 data points
data = csv_data.sample(n=100)  # randomly sample points for training/validation

input_data = data.iloc[:, :2]
output_data = data.iloc[:, 2:]

# Define labels, and split training and validation data
input_labels = input_data.columns
output_labels = output_data.columns

n_data = data[input_labels[0]].size
data_training, data_validation = split_training_validation(
    data, 0.8, seed=n_data
)  # seed=100

3.2 Training Surrogates with TensorFlow Keras#

TensorFlow Keras provides an interface to pass regression settings, build neural networks and train surrogate models. Keras enables the usage of two API formats: Sequential and Functional. While the Functional API offers more versatility, including multiple input and output layers in a single neural network, the Sequential API is more stable and user-friendly. Further, the Sequential API integrates cleanly with existing IDAES surrogate tools and will be utilized in this example.

In the code below, we build the neural network structure based on our training data structure and desired regression settings. Offline, neural network models were trained for the list of settings below, and the options bolded and italicized were determined to have the minimum mean squared error for the dataset:

  • Activation function: relu, sigmoid, tanh

  • Optimizer: Adam, RMSprop, SGD

  • Number of hidden layers: 1, 2, 4

  • Number of neurons per layer: 10, 20, 40

Typically, Sequential Keras models are built vertically; the dataset is scaled and normalized. The network is defined for the input layer, hidden layers, and output layer for the passed activation functions and network/layer sizes. Then, the model is compiled using the passed optimizer and trained using a desired number of epochs. Keras internally validates while training and updates each epoch’s model weight (coefficient) values.

Finally, after training the model, we save the results and model expressions to a folder that contains a serialized JSON file. Serializing the model in this fashion enables importing a previously trained set of surrogate models into external flowsheets. This feature will be used later.

# capture long output (not required to use surrogate API)
from io import StringIO
import sys

stream = StringIO()
oldstdout = sys.stdout
sys.stdout = stream

# selected settings for regression (best fit from options above)
activation, optimizer, n_hidden_layers, n_nodes_per_layer = "tanh", "Adam", 2, 40
loss, metrics = "mse", ["mae", "mse"]

# Create data objects for training using scalar normalization
n_inputs = len(input_labels)
n_outputs = len(output_labels)
x = input_data
y = output_data

input_scaler = None
output_scaler = None
input_scaler = OffsetScaler.create_normalizing_scaler(x)
output_scaler = OffsetScaler.create_normalizing_scaler(y)
x = input_scaler.scale(x)
y = output_scaler.scale(y)
x = x.to_numpy()
y = y.to_numpy()

# Create Keras Sequential object and build neural network
model = tf.keras.Sequential()
model.add(
    tf.keras.layers.Dense(
        units=n_nodes_per_layer, input_dim=n_inputs, activation=activation
    )
)
for i in range(1, n_hidden_layers):
    model.add(tf.keras.layers.Dense(units=n_nodes_per_layer, activation=activation))
model.add(tf.keras.layers.Dense(units=n_outputs))

# Train surrogate (calls optimizer on neural network and solves for weights)
model.compile(loss=loss, optimizer=optimizer, metrics=metrics)
mcp_save = tf.keras.callbacks.ModelCheckpoint(
    ".mdl_wts.hdf5", save_best_only=True, monitor="val_loss", mode="min"
)
history = model.fit(
    x=x, y=y, validation_split=0.2, verbose=1, epochs=1000, callbacks=[mcp_save]
)

# save model to JSON and create callable surrogate object
xmin, xmax = [0.1, 0.8], [0.8, 1.2]
input_bounds = {input_labels[i]: (xmin[i], xmax[i]) for i in range(len(input_labels))}

keras_surrogate = KerasSurrogate(
    model,
    input_labels=list(input_labels),
    output_labels=list(output_labels),
    input_bounds=input_bounds,
    input_scaler=input_scaler,
    output_scaler=output_scaler,
)
keras_surrogate.save_to_folder("keras_surrogate")

# revert back to normal output capture
sys.stdout = oldstdout

# display first 50 lines and last 50 lines of output
celloutput = stream.getvalue().split("\n")
for line in celloutput[:50]:
    print(line)
print(".")
print(".")
print(".")
for line in celloutput[-50:]:
    print(line)
/home/docs/checkouts/readthedocs.org/user_builds/idaes-examples/envs/latest/lib/python3.8/site-packages/keras/src/engine/training.py:3000: UserWarning: You are saving your model as an HDF5 file via `model.save()`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')`.
  saving_api.save_model(
INFO:tensorflow:Assets written to: keras_surrogate/assets
INFO:tensorflow:Assets written to: keras_surrogate/assets
Epoch 1/1000

1/3 [=========>....................] - ETA: 1s - loss: 0.3816 - mae: 0.5276 - mse: 0.3816
3/3 [==============================] - 1s 92ms/step - loss: 0.3703 - mae: 0.5194 - mse: 0.3703 - val_loss: 0.3230 - val_mae: 0.4945 - val_mse: 0.3230
Epoch 2/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.3274 - mae: 0.4777 - mse: 0.3274
3/3 [==============================] - 0s 17ms/step - loss: 0.3078 - mae: 0.4684 - mse: 0.3078 - val_loss: 0.2686 - val_mae: 0.4450 - val_mse: 0.2686
Epoch 3/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.2678 - mae: 0.4329 - mse: 0.2678
3/3 [==============================] - 0s 17ms/step - loss: 0.2556 - mae: 0.4217 - mse: 0.2556 - val_loss: 0.2235 - val_mae: 0.3991 - val_mse: 0.2235
Epoch 4/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.2350 - mae: 0.4022 - mse: 0.2350
3/3 [==============================] - 0s 16ms/step - loss: 0.2136 - mae: 0.3798 - mse: 0.2136 - val_loss: 0.1862 - val_mae: 0.3568 - val_mse: 0.1862
Epoch 5/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.1953 - mae: 0.3559 - mse: 0.1953
3/3 [==============================] - 0s 17ms/step - loss: 0.1792 - mae: 0.3424 - mse: 0.1792 - val_loss: 0.1557 - val_mae: 0.3193 - val_mse: 0.1557
Epoch 6/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.1581 - mae: 0.3172 - mse: 0.1581
3/3 [==============================] - 0s 16ms/step - loss: 0.1512 - mae: 0.3100 - mse: 0.1512 - val_loss: 0.1303 - val_mae: 0.2857 - val_mse: 0.1303
Epoch 7/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.1335 - mae: 0.2904 - mse: 0.1335
3/3 [==============================] - 0s 17ms/step - loss: 0.1286 - mae: 0.2829 - mse: 0.1286 - val_loss: 0.1099 - val_mae: 0.2583 - val_mse: 0.1099
Epoch 8/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.1202 - mae: 0.2749 - mse: 0.1202
3/3 [==============================] - 0s 16ms/step - loss: 0.1108 - mae: 0.2615 - mse: 0.1108 - val_loss: 0.0935 - val_mae: 0.2381 - val_mse: 0.0935
Epoch 9/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.1021 - mae: 0.2497 - mse: 0.1021
3/3 [==============================] - 0s 17ms/step - loss: 0.0969 - mae: 0.2445 - mse: 0.0969 - val_loss: 0.0810 - val_mae: 0.2227 - val_mse: 0.0810
Epoch 10/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0953 - mae: 0.2431 - mse: 0.0953
3/3 [==============================] - 0s 17ms/step - loss: 0.0870 - mae: 0.2324 - mse: 0.0870 - val_loss: 0.0717 - val_mae: 0.2123 - val_mse: 0.0717
Epoch 11/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0818 - mae: 0.2266 - mse: 0.0818
3/3 [==============================] - 0s 16ms/step - loss: 0.0795 - mae: 0.2228 - mse: 0.0795 - val_loss: 0.0650 - val_mae: 0.2041 - val_mse: 0.0650
Epoch 12/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0744 - mae: 0.2109 - mse: 0.0744
3/3 [==============================] - 0s 16ms/step - loss: 0.0745 - mae: 0.2165 - mse: 0.0745 - val_loss: 0.0599 - val_mae: 0.1972 - val_mse: 0.0599
Epoch 13/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0674 - mae: 0.2048 - mse: 0.0674
3/3 [==============================] - 0s 17ms/step - loss: 0.0703 - mae: 0.2108 - mse: 0.0703 - val_loss: 0.0565 - val_mae: 0.1925 - val_mse: 0.0565
Epoch 14/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0756 - mae: 0.2171 - mse: 0.0756
3/3 [==============================] - 0s 17ms/step - loss: 0.0670 - mae: 0.2056 - mse: 0.0670 - val_loss: 0.0534 - val_mae: 0.1879 - val_mse: 0.0534
Epoch 15/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0709 - mae: 0.2180 - mse: 0.0709
3/3 [==============================] - 0s 17ms/step - loss: 0.0640 - mae: 0.2005 - mse: 0.0640 - val_loss: 0.0506 - val_mae: 0.1828 - val_mse: 0.0506
Epoch 16/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0443 - mae: 0.1687 - mse: 0.0443
3/3 [==============================] - 0s 17ms/step - loss: 0.0611 - mae: 0.1949 - mse: 0.0611 - val_loss: 0.0477 - val_mae: 0.1767 - val_mse: 0.0477
Epoch 17/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0589 - mae: 0.1894 - mse: 0.0589
3/3 [==============================] - 0s 18ms/step - loss: 0.0582 - mae: 0.1889 - mse: 0.0582 - val_loss: 0.0454 - val_mae: 0.1711 - val_mse: 0.0454
Epoch 18/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0636 - mae: 0.1930 - mse: 0.0636
3/3 [==============================] - 0s 17ms/step - loss: 0.0557 - mae: 0.1833 - mse: 0.0557 - val_loss: 0.0436 - val_mae: 0.1659 - val_mse: 0.0436
Epoch 19/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0483 - mae: 0.1658 - mse: 0.0483
3/3 [==============================] - 0s 17ms/step - loss: 0.0533 - mae: 0.1778 - mse: 0.0533 - val_loss: 0.0418 - val_mae: 0.1601 - val_mse: 0.0418
Epoch 20/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0401 - mae: 0.1556 - mse: 0.0401
3/3 [==============================] - 0s 17ms/step - loss: 0.0514 - mae: 0.1727 - mse: 0.0514 - val_loss: 0.0403 - val_mae: 0.1546 - val_mse: 0.0403
Epoch 21/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0536 - mae: 0.1683 - mse: 0.0536
3/3 [==============================] - 0s 17ms/step - loss: 0.0496 - mae: 0.1681 - mse: 0.0496 - val_loss: 0.0385 - val_mae: 0.1487 - val_mse: 0.0385
Epoch 22/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0435 - mae: 0.1560 - mse: 0.0435
3/3 [==============================] - 0s 17ms/step - loss: 0.0479 - mae: 0.1630 - mse: 0.0479 - val_loss: 0.0370 - val_mae: 0.1437 - val_mse: 0.0370
Epoch 23/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0517 - mae: 0.1663 - mse: 0.0517
3/3 [==============================] - 0s 17ms/step - loss: 0.0464 - mae: 0.1589 - mse: 0.0464 - val_loss: 0.0359 - val_mae: 0.1404 - val_mse: 0.0359
Epoch 24/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0471 - mae: 0.1616 - mse: 0.0471
3/3 [==============================] - 0s 17ms/step - loss: 0.0449 - mae: 0.1550 - mse: 0.0449 - val_loss: 0.0347 - val_mae: 0.1372 - val_mse: 0.0347
Epoch 25/1000

1/3 [=========>....................] - ETA: 0s - loss: 0.0414 - mae: 0.1462 - mse: 0.0414
3/3 [==============================] - 0s 17ms/step - loss: 0.0433 - mae: 0.1511 - mse: 0.0433 - val_loss: 0.0335 - val_mae: 0.1347 - val_mse: 0.0335
.
.
.

1/3 [=========>....................] - ETA: 0s - loss: 1.1661e-04 - mae: 0.0080 - mse: 1.1661e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.3688e-04 - mae: 0.0084 - mse: 1.3688e-04 - val_loss: 9.2093e-05 - val_mae: 0.0068 - val_mse: 9.2093e-05
Epoch 977/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.3928e-04 - mae: 0.0085 - mse: 1.3928e-04
3/3 [==============================] - 0s 17ms/step - loss: 1.3427e-04 - mae: 0.0085 - mse: 1.3427e-04 - val_loss: 8.4304e-05 - val_mae: 0.0067 - val_mse: 8.4304e-05
Epoch 978/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.0357e-04 - mae: 0.0081 - mse: 1.0357e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.3646e-04 - mae: 0.0087 - mse: 1.3646e-04 - val_loss: 9.1711e-05 - val_mae: 0.0071 - val_mse: 9.1711e-05
Epoch 979/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.3586e-04 - mae: 0.0084 - mse: 1.3586e-04
3/3 [==============================] - 0s 16ms/step - loss: 1.3732e-04 - mae: 0.0087 - mse: 1.3732e-04 - val_loss: 8.2200e-05 - val_mae: 0.0067 - val_mse: 8.2200e-05
Epoch 980/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.7129e-04 - mae: 0.0094 - mse: 1.7129e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.2526e-04 - mae: 0.0082 - mse: 1.2526e-04 - val_loss: 1.0392e-04 - val_mae: 0.0074 - val_mse: 1.0392e-04
Epoch 981/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.1030e-04 - mae: 0.0075 - mse: 1.1030e-04
3/3 [==============================] - 0s 16ms/step - loss: 1.3412e-04 - mae: 0.0082 - mse: 1.3412e-04 - val_loss: 8.1917e-05 - val_mae: 0.0065 - val_mse: 8.1917e-05
Epoch 982/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.2036e-04 - mae: 0.0083 - mse: 1.2036e-04
3/3 [==============================] - 0s 16ms/step - loss: 1.3123e-04 - mae: 0.0085 - mse: 1.3123e-04 - val_loss: 8.0986e-05 - val_mae: 0.0067 - val_mse: 8.0986e-05
Epoch 983/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.5498e-04 - mae: 0.0090 - mse: 1.5498e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.2668e-04 - mae: 0.0084 - mse: 1.2668e-04 - val_loss: 8.8135e-05 - val_mae: 0.0069 - val_mse: 8.8135e-05
Epoch 984/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.5492e-04 - mae: 0.0090 - mse: 1.5492e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.2770e-04 - mae: 0.0082 - mse: 1.2770e-04 - val_loss: 8.4017e-05 - val_mae: 0.0066 - val_mse: 8.4017e-05
Epoch 985/1000

1/3 [=========>....................] - ETA: 0s - loss: 9.4718e-05 - mae: 0.0074 - mse: 9.4718e-05
3/3 [==============================] - 0s 17ms/step - loss: 1.2767e-04 - mae: 0.0081 - mse: 1.2767e-04 - val_loss: 7.7591e-05 - val_mae: 0.0064 - val_mse: 7.7591e-05
Epoch 986/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.0524e-04 - mae: 0.0075 - mse: 1.0524e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.2811e-04 - mae: 0.0085 - mse: 1.2811e-04 - val_loss: 7.8276e-05 - val_mae: 0.0066 - val_mse: 7.8276e-05
Epoch 987/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.2713e-04 - mae: 0.0084 - mse: 1.2713e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.2328e-04 - mae: 0.0082 - mse: 1.2328e-04 - val_loss: 9.2079e-05 - val_mae: 0.0071 - val_mse: 9.2079e-05
Epoch 988/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.3256e-04 - mae: 0.0082 - mse: 1.3256e-04
3/3 [==============================] - 0s 17ms/step - loss: 1.2592e-04 - mae: 0.0081 - mse: 1.2592e-04 - val_loss: 7.5439e-05 - val_mae: 0.0064 - val_mse: 7.5439e-05
Epoch 989/1000

1/3 [=========>....................] - ETA: 0s - loss: 8.0360e-05 - mae: 0.0070 - mse: 8.0360e-05
3/3 [==============================] - 0s 11ms/step - loss: 1.2697e-04 - mae: 0.0086 - mse: 1.2697e-04 - val_loss: 8.1591e-05 - val_mae: 0.0068 - val_mse: 8.1591e-05
Epoch 990/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.1743e-04 - mae: 0.0082 - mse: 1.1743e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.2365e-04 - mae: 0.0082 - mse: 1.2365e-04 - val_loss: 8.8449e-05 - val_mae: 0.0067 - val_mse: 8.8449e-05
Epoch 991/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.0918e-04 - mae: 0.0075 - mse: 1.0918e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.2486e-04 - mae: 0.0079 - mse: 1.2486e-04 - val_loss: 8.3745e-05 - val_mae: 0.0065 - val_mse: 8.3745e-05
Epoch 992/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.0088e-04 - mae: 0.0076 - mse: 1.0088e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.2131e-04 - mae: 0.0082 - mse: 1.2131e-04 - val_loss: 7.8311e-05 - val_mae: 0.0066 - val_mse: 7.8311e-05
Epoch 993/1000

1/3 [=========>....................] - ETA: 0s - loss: 9.0210e-05 - mae: 0.0075 - mse: 9.0210e-05
3/3 [==============================] - 0s 11ms/step - loss: 1.2277e-04 - mae: 0.0083 - mse: 1.2277e-04 - val_loss: 7.5934e-05 - val_mae: 0.0064 - val_mse: 7.5934e-05
Epoch 994/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.2529e-04 - mae: 0.0084 - mse: 1.2529e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.1942e-04 - mae: 0.0082 - mse: 1.1942e-04 - val_loss: 7.9994e-05 - val_mae: 0.0067 - val_mse: 7.9994e-05
Epoch 995/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.4463e-04 - mae: 0.0086 - mse: 1.4463e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.1739e-04 - mae: 0.0079 - mse: 1.1739e-04 - val_loss: 8.5977e-05 - val_mae: 0.0066 - val_mse: 8.5977e-05
Epoch 996/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.2477e-04 - mae: 0.0077 - mse: 1.2477e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.1918e-04 - mae: 0.0078 - mse: 1.1918e-04 - val_loss: 7.7405e-05 - val_mae: 0.0062 - val_mse: 7.7405e-05
Epoch 997/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.3463e-04 - mae: 0.0084 - mse: 1.3463e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.1708e-04 - mae: 0.0080 - mse: 1.1708e-04 - val_loss: 7.7886e-05 - val_mae: 0.0064 - val_mse: 7.7886e-05
Epoch 998/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.0271e-04 - mae: 0.0075 - mse: 1.0271e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.1993e-04 - mae: 0.0079 - mse: 1.1993e-04 - val_loss: 7.7599e-05 - val_mae: 0.0065 - val_mse: 7.7599e-05
Epoch 999/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.3346e-04 - mae: 0.0085 - mse: 1.3346e-04
3/3 [==============================] - 0s 16ms/step - loss: 1.1611e-04 - mae: 0.0081 - mse: 1.1611e-04 - val_loss: 7.2371e-05 - val_mae: 0.0064 - val_mse: 7.2371e-05
Epoch 1000/1000

1/3 [=========>....................] - ETA: 0s - loss: 1.4569e-04 - mae: 0.0092 - mse: 1.4569e-04
3/3 [==============================] - 0s 11ms/step - loss: 1.1746e-04 - mae: 0.0083 - mse: 1.1746e-04 - val_loss: 8.1321e-05 - val_mae: 0.0068 - val_mse: 8.1321e-05

3.3 Visualizing surrogates#

Now that the surrogate models have been trained, the models can be visualized through scatter, parity, and residual plots to confirm their validity in the chosen domain. The training data will be visualized first to confirm the surrogates fit the data. Then the validation data will be visualized to confirm the surrogates accurately predict new output values.

# visualize with IDAES surrogate plotting tools
surrogate_scatter2D(
    keras_surrogate, data_training, filename="keras_train_scatter2D.pdf"
)
surrogate_parity(keras_surrogate, data_training, filename="keras_train_parity.pdf")
surrogate_residual(keras_surrogate, data_training, filename="keras_train_residual.pdf")
1/3 [=========>....................] - ETA: 0s

3/3 [==============================] - 0s 2ms/step
../../../_images/3dbc61c88db15f5d261612b8a3d141b60dcdac612bd42d13659199e8f1792161.png ../../../_images/8cd42571a29e7b54378333c2f1489ae2c399f89b3275fb2cd09b797d9d63f400.png ../../../_images/6cfa0706064e079e22c55615c8acc0e667eedd653884cb8fcde10a82c0a174cb.png ../../../_images/1e1129cc65ac29bb706fca886ce8f420d6b7f88a451f62192006e93b0e207d61.png ../../../_images/24dd8ae0ff3b8bc2de1af8f9c4b4650920928e842afeed161dabb1c47e3046bc.png ../../../_images/aa42ea8ff3a53033650a0a4bbb948755ac004ec6849a42bdbf64b827619f5873.png ../../../_images/2367c0044a3c83a072df0294d9fcb729efad89799f0970ba05ba9655466ae799.png ../../../_images/fd9fd3d1ddf69f5ad45bf0c40e8cac85ffdc464ef92d71a82f341a9422fe6344.png ../../../_images/4416edcf2e61cdf5fb47c90d7e854b40c6ecdf0b71bd4a2ea988b54f175840b0.png ../../../_images/225cc6592553f9ce6c007ccb0028d6e9de7e6eb3c72996b1d146672ca100f5c5.png ../../../_images/6ad8d18fa70da3fdf09f90311741d36dd42c29c6eafeb4bf3f71342a602697f6.png ../../../_images/f4a9877fed8491abb5a1a669e251ce1d69de3b08a7507957a92f2056649cea61.png ../../../_images/405534b021335cd8391d19e1bd29aaf1f4dc9915b04fe33d72bba60dded4125f.png ../../../_images/faf9fd1aef7256c800ef5211b34c31b86c6b3a761a4c1e61409e4c3270978880.png ../../../_images/ff8875c30107183be825a0025f08cd51b31effb996eb619c1129a5766f1349bd.png ../../../_images/ff75f6ac9b0c3f94eda6cee30869abf6b454f8c009cd402854fb827a4aba9737.png ../../../_images/438d333e2d7fb445fef966ba60ceeb5452220ba9e26b77bec37389132ee95b52.png ../../../_images/cbf97495d5a27128ea4cb368b446d59cf6b2875e2aa18fbb14ca3f44df611411.png ../../../_images/0a3512c3ef16e64998fa6f9f7f0e20caf3fb884e90313f9b0f9d607e93b78983.png ../../../_images/d9edd0b0926e59b104ace36ac60fb34b2842063a731edcb444f970730938e3ac.png ../../../_images/80b295488da8cec4e7a495899dfbee7db6611b6abb86049326794aa2e3ba97b4.png ../../../_images/887f28609f824a3e572f3103ab50f4b0b075bd9b6d6ab21d340558d88e917167.png ../../../_images/33a5a38ec38879102b66366e51d60caf39f14e4bf7fbc064212dac3c9183aca4.png ../../../_images/d4d7d68bed84f1237b42745472b4be75468f4bcf6c5aca058ca0b6f7b0391cdb.png ../../../_images/a65f9afc60ca0c0d39f59c56e0f032c8924097eed5c6445eb5fcf4d329da3818.png ../../../_images/15cae95a4a2cd9bc9853c8c0ebab99ccc50e06fec854f7eb4424a5e7df598bc4.png
1/3 [=========>....................] - ETA: 0s

3/3 [==============================] - 0s 2ms/step
../../../_images/977ec87f3af0169ab2c44452570d511a8d2cba3503fd62239080a33439f0d3b2.png ../../../_images/9d4328ba1bbe7c3d09f7177cb80843ad3db99a379fa04e0e9c3214a247d94e13.png ../../../_images/1ca4676895de6b72e2ebe4f5b1905b3bf572df4e99c4d0c7cef85274652d052e.png ../../../_images/2298465580e7709c55226c66df6d673d57957113882adf171b521f8eb3c9dde2.png ../../../_images/f05a1e44af6d7ee96650f537710504a42e8404c3a15d26f8795380f4a7a8e988.png ../../../_images/6a0d0669f760f3a9a4a427fb3f817ca936d0ca46453c7cf2ec319b82199e44c1.png ../../../_images/63f0e123ec8fa7f5a135a46b7b12771ed1731c2b13553cb836b2b05e9ef784f3.png ../../../_images/f5cc1590ff19180bf14a86e1a14c5a8c735798cefb2397f89fa7de16d940c450.png ../../../_images/61c17f93285d57410d2224ef459c4fb686f3b5c8de39d4a5f92a1b6a0e87cd56.png ../../../_images/01bb311d82ccb82ab6a4b35ad872f9517742ad98455554c2ea12049383aeed08.png ../../../_images/af04e4cbda4b04a5d33dd0c6faeb9096efa3ef42b2fb7d399924f6168210d961.png ../../../_images/be9e8f09376bee212e3cb7746ecdd116cfaf305df7e1aae96602378dce012679.png ../../../_images/a8064c399c968fe71a94212c58a128d735402d37c18e9d5af4c457e63e06b81b.png
1/3 [=========>....................] - ETA: 0s

3/3 [==============================] - 0s 2ms/step
../../../_images/844c7b752215557ef95ecf70db3c20b7c65cedcdee3a970f547f879663e09b8e.png ../../../_images/d827306357d5b34485a0529bcfee7dca9bc23c2694234fd7e286d73635c80cb0.png ../../../_images/7a42e4f63e6452b5137a526f78292ac77fef3da2a5c45831613c0ab10c718d5c.png ../../../_images/6e397ea14a90cc26e895bd4acc3882c4031dcc36c648eebd5bd983225ed6f06d.png ../../../_images/ef33bb7c853e4676d0ed1148ece29d00f8d7ba7197094de3c8dd170eacc4c9e3.png ../../../_images/6d1b714c2bd7006d7ac3657c8e959abc917125ee8eceea10048e7cbfa93c41f7.png ../../../_images/e7aa691bf0caae3082ad7d05a1a139b54944cb6b7e129d28eaa3f61b201bbb4c.png ../../../_images/68590377006bcd11ef0777adcead4d19fef107e8426a400b6de7d0debeb4801b.png ../../../_images/04d8c7c18710bd77eb7a2b4480b51e2cadccc47972b05c56fe8354ebcfea96df.png ../../../_images/60da6c2a50e7f9c3f79e4bc9e47564376cf4b42bf0170ed9794877efd2d94b61.png ../../../_images/b3274c0972801dba7b3588f7cf058f71251d45830460e28500faa522488e6326.png ../../../_images/a6f897f94949709679ff32c9c901fab135eeca9e0f6990463c5ffa8917c160eb.png ../../../_images/819e0325cb283f72957954f6715c8e101bce5e1ecea6cd1c8a74cb601a38627c.png ../../../_images/2260bf65d34f0a7e6877e19f74caa07236f0e23bba2f6d8763824374ad8a7479.png ../../../_images/ae748b46d4402ce4e098a3fc0cc7f092a23a5d5b3fb7a2b8935b7d75c4bab704.png ../../../_images/80d4a88f5e748595c2ec09629ecb77ab2563d5a0d2fb7362fd52d17f82206109.png ../../../_images/999bf36608864b81f9ff99d9bbf0780ce6f5cedf72113cb906a2f69838999c5b.png ../../../_images/9889a3d9991475e0ce9d6656bf788d90d9b9280abd2b9f69d4a76dca9821803f.png ../../../_images/c6a09fc9bffff2f33668da6607ad1843ca2f321798a5f10a333459620c9fbe1f.png ../../../_images/4ccbe3d268daba1c69820488f810c89edc84096b97b323ed422f72198ad5cde4.png ../../../_images/ad81fa881673b223ede4954cb20ae0e08dadc357043eb6f8743a839f2c7fba50.png ../../../_images/f3c3c022353bb91fa2f1f3c28f9fabf288142bb9651dbe7bd02aa94c250aa209.png ../../../_images/67b95cad3e37b9eb614287aadb96f498f8f5c6ca6653695f13d0dbab650781c1.png ../../../_images/19e6378a559eff91d762a65086b300a1ccd69be0a848eb00f27bc25bfe64e69d.png ../../../_images/0807c1ad81bb26b7a36a3d07256e0ca4476338d3cab936ee320e612c74c4eed6.png ../../../_images/8fd4556c66578e30a008c62fd29c7e0ce5719e58c6ea00c1d8aee6b60becb170.png
[<Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>]

3.4 Model Validation#

# visualize with IDAES surrogate plotting tools
surrogate_scatter2D(
    keras_surrogate, data_validation, filename="keras_val_scatter2D.pdf"
)
surrogate_parity(keras_surrogate, data_validation, filename="keras_val_parity.pdf")
surrogate_residual(keras_surrogate, data_validation, filename="keras_val_residual.pdf")
1/1 [==============================] - ETA: 0s

1/1 [==============================] - 0s 15ms/step
../../../_images/de3c1a681813df84393b3bb45b789e7040e337b5159f5d068372e8d02b0ea2c4.png ../../../_images/d8cc71d52ad865ee6b50d415f86c4c107e2e0b14a525615d2695855203668d87.png ../../../_images/a9555fc59e7b025d9a2cefe0885cb9f0ef180c7bc3979873f2a63d19bd2367ce.png ../../../_images/ad64eb073815e3f0cc323f33c3752c872c40ee08c1a49b6a45e313b8c1cbea4c.png ../../../_images/43fb6a185ebf47db21e866a141c42154dcd3b655971345959f5658300f5257b2.png ../../../_images/1c192fc54d51e53640e58ab1895fd94eab6026bdfb502e0005316ed0c3a2de00.png ../../../_images/92c5609248fd39c039ea1580f9cc64cfebecd01c3d49a01421a7368e81024cae.png ../../../_images/c707281ff13e3a42802fb838647b973ba48b2de6e11f8d0fb6fcd84b9e8ac6c8.png ../../../_images/0a9ca4f16dffe45909e47003b3b8a9574551b97731510857d73a52ad4dbb0631.png ../../../_images/167076f023ed8725a5d2f7ef284775555eed78b18a81b988608537d2f1cf7354.png ../../../_images/808f3fca8bb699d348ba5871e7bf47de2b7dabaf960b6b4c486656751ac1837c.png ../../../_images/77ebb8d1913d03ad81a0ee461668342a79abc540a71bce08ea7cb1f2d086664b.png ../../../_images/5ef9b0556cb458744f98ef2fa9eef531323f35384457874aa79a50f2df0f1656.png ../../../_images/cd68d9561a00cc8837fd02670f5e4168165809be79fb16017514564be1ebf398.png ../../../_images/d3d083b98d1161e35e2527397b6b1aed8ee7d6578ab4075b606fc81488aa598b.png ../../../_images/c2a9d55f5b0b0da94e2ed07e75b4195d3425e4c69202d27cf5c52ecc7a44f4ac.png ../../../_images/8e189a3091ee2b1463f2713b73fd4a5e2af9d8ed78b41ad8529b3902b8c45df3.png ../../../_images/b00149f70183bef731b440c8ccbd7db88f26617a51a5627b6de7ea7fc6e1a648.png ../../../_images/fb5c4e81220e947cf015c061fbd90d0e4841599f2a0d5094a2d2ad7cb1641984.png ../../../_images/0a6fc5bc4c5b224a4c6b63df18f20bd090e3e7bae92a9cfdd0d58c35fd78ae5f.png ../../../_images/83d023be1e6a27b2597458faa43353b848ebb662ebd95ddafa6c073f4bcf6710.png ../../../_images/7c1b16c5cb0cd4537e334d3bcec2b05eeb5bc30a258b8a6edd79feb6fd2898d6.png ../../../_images/7c71a8e0f13ae88d7f736f4c6925f856886e560fe1c918d161a7edf240d40974.png ../../../_images/fb590127469f0503f3795ea0f4972aadb9420910415b05c74f9e34b98b3a2906.png ../../../_images/01bc11726df1af4d27ad01ce1b7d2301f1930cda7ccdf26916bc5b0198a5f54b.png ../../../_images/7524576b75baad56189c7c13385e110437f66971292d2405c443c04dbfe0838d.png
1/1 [==============================] - ETA: 0s

1/1 [==============================] - 0s 14ms/step
../../../_images/39cef7172ba0ff698b1c2667da3d08afd9a5ea0f16a368fc4377c1216bb5f545.png ../../../_images/5ec63a38cc0e322d7a836b30b380847f9eabc8c2cf58bd73ce078969c81d03bc.png ../../../_images/b5f7c5af17cfc6732f7c001a7db950744622f46469503a7599b10c420455e1ff.png ../../../_images/55ebaaa1535d4464a6948003c7ba8fd1166fc49dc14cf2e7130e6f57fcb91f92.png ../../../_images/70c30bb318458708cf90a3d7008fcac8888941bf550b8d217b8f3eb3337290ff.png ../../../_images/0e9a7d81ad388eb99004d9ea08639313244207de4aad24a75e49479c55fd8842.png ../../../_images/4c96f2ba8ce9dc13d2f91c7ed4e238102e2c905a841d27e59623c7b61bc45d0b.png ../../../_images/ae28bbc1b73f60d1cdb56d8e429f56aad562e7a81b5f65d36b80f9ae60e469b8.png ../../../_images/d70e7a8a3c6f28bc5f770f9062ee301ae480ba2fda2e0467d0e30fa0bdeb45af.png ../../../_images/85a4ff879f8d794f54f4504041e72713b3b2804eac7d647fc9ec94e3472cfe05.png ../../../_images/d52082c6f984a04a853492795a8e11147f35e9423b4c0b61e97967a22c71639d.png ../../../_images/160c5da9ca5be2928e1dc152ab5152f7d3075dde6625d50c8432af0c86755827.png ../../../_images/e61707f798f61872e70cf21e4ddc3dee22b84ec855b3bd84855951e33363f568.png
1/1 [==============================] - ETA: 0s

1/1 [==============================] - 0s 15ms/step
../../../_images/99c2c65e04b3394a4e97da20c48f8e4a5a4641582c07029e692329bd12d70c9a.png ../../../_images/9ef364d8c405e8db923d523b5ec399ac5741ce0c446b50517d2a1fbcafc39871.png ../../../_images/dfaea05859e5d6e1afb27d7c97923aacc5d47e1d95b3b8768cb8441f45d410d6.png ../../../_images/7f76cf6ea32cced87bb0b9e579057c431c5a8e3fdcd1cfc7af7ab8804ddb6243.png ../../../_images/f08b7193443e73b6b5876efa2eb100367277373672b4711709ebee4f32022f38.png ../../../_images/3f545591e4b4ed2525bd4405fb3aec423864162ffc1ee5ab2e20912d772e2883.png ../../../_images/6e97a60a230076ad1c423306337cff2e43df78ac4918475d478c7c5ceb04d581.png ../../../_images/9f63d29001e2eeca2642d9083ec0ad0c9162ed3938ee5d61fc06fdc8b9474155.png ../../../_images/fbb3485879d9af2716e7a8fda1d2738cb65b39b347ea0a5055a1712804244086.png ../../../_images/4e1753eca37be69194e30554e8da6dbbdc9157fb8e0c729826281d103ccaa85e.png ../../../_images/d151752755878968d671a3f109755f904d0cc87f80dfc4cd5570ad56822de03a.png ../../../_images/5089811b778f1a2f6126dfaa426900fd59709c342309ca2e9e754719a8a904fa.png ../../../_images/8037d6e21e9609dd8a91d756ac401668cfd2e4387b227a2004b88c59638a08e7.png ../../../_images/0c9289874b10f944e28c423ea3aac00875281151169ca7c830f0671e9a4e5ec1.png ../../../_images/c5dd0a9865287ce3a963e5b09dbe05d1e8841bbefd1f2efecbe898102e2a4ee1.png ../../../_images/8feaa3c174ea57fa8dfa58faf8e2f4189184575609b68a393f803a4288877198.png ../../../_images/298e87e3f4500c7ff3d75fcf9f03dcef717dc4956f6581e13387639a6b4c053a.png ../../../_images/70a7fa4b168841e2c5f9b9b8712f503c22982d65ffb9a8d65617f3bd4a61a5a1.png ../../../_images/e2f40e183a672340e4c1268391345103d3ae44ff142856fddaf67d3c7be5cf95.png ../../../_images/05c0b7666e20c87c21774c9a4f3446c6a71c526473cac68d489f2b860437b85a.png ../../../_images/9ce7c03f95ecab967ecdae05de3500e0d40ba5256ef1918c24e007b239abcbd6.png ../../../_images/8fe19f35d55ee3d43151931dcf312bdc60995e85bc45a34b4aa616f2bfb2b0b4.png ../../../_images/1fbfcb6a17593c07c8f1cbb38148c83760935bb3f0aa64c531029763a4c06a0d.png ../../../_images/d32f74ea924b8b6c4c729ff639a86ebf82291dc8122fc7f20055c6e170eba544.png ../../../_images/fb1f289dce278b68916ccd9b2f494472960df8b721fc59b0fa2211fd1d8d198e.png ../../../_images/3e01a9213877bc0283292f740b92507eb8fab56b2c03bc456d725f661df4a7a5.png
[<Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>,
 <Figure size 640x480 with 1 Axes>]

4. IDAES Flowsheet Integration#

4.1 Build and Run IDAES Flowsheet#

Next, we will build an IDAES flowsheet and import the surrogate model object. A single Keras neural network model accounts for all input and output variables, and the JSON model serialized earlier may be imported into a single SurrogateBlock() component.

# create the IDAES model and flowsheet
m = ConcreteModel()
m.fs = FlowsheetBlock(dynamic=False)

# create flowsheet input variables
m.fs.bypass_frac = Var(
    initialize=0.80, bounds=[0.1, 0.8], doc="natural gas bypass fraction"
)
m.fs.ng_steam_ratio = Var(
    initialize=0.80, bounds=[0.8, 1.2], doc="natural gas to steam ratio"
)

# create flowsheet output variables
m.fs.steam_flowrate = Var(initialize=0.2, doc="steam flowrate")
m.fs.reformer_duty = Var(initialize=10000, doc="reformer heat duty")
m.fs.AR = Var(initialize=0, doc="AR fraction")
m.fs.C2H6 = Var(initialize=0, doc="C2H6 fraction")
m.fs.C3H8 = Var(initialize=0, doc="C3H8 fraction")
m.fs.C4H10 = Var(initialize=0, doc="C4H10 fraction")
m.fs.CH4 = Var(initialize=0, doc="CH4 fraction")
m.fs.CO = Var(initialize=0, doc="CO fraction")
m.fs.CO2 = Var(initialize=0, doc="CO2 fraction")
m.fs.H2 = Var(initialize=0, doc="H2 fraction")
m.fs.H2O = Var(initialize=0, doc="H2O fraction")
m.fs.N2 = Var(initialize=0, doc="N2 fraction")
m.fs.O2 = Var(initialize=0, doc="O2 fraction")

# create input and output variable object lists for flowsheet
inputs = [m.fs.bypass_frac, m.fs.ng_steam_ratio]
outputs = [
    m.fs.steam_flowrate,
    m.fs.reformer_duty,
    m.fs.AR,
    m.fs.C2H6,
    m.fs.C4H10,
    m.fs.C3H8,
    m.fs.CH4,
    m.fs.CO,
    m.fs.CO2,
    m.fs.H2,
    m.fs.H2O,
    m.fs.N2,
    m.fs.O2,
]

# create the Pyomo/IDAES block that corresponds to the surrogate
# Keras
keras_surrogate = KerasSurrogate.load_from_folder("keras_surrogate")
m.fs.surrogate = SurrogateBlock()
m.fs.surrogate.build_model(
    keras_surrogate,
    formulation=KerasSurrogate.Formulation.FULL_SPACE,
    input_vars=inputs,
    output_vars=outputs,
)

# fix input values and solve flowsheet
m.fs.bypass_frac.fix(0.5)
m.fs.ng_steam_ratio.fix(1)

solver = SolverFactory("ipopt")
results = solver.solve(m, tee=True)
WARNING:pyomo.solvers:Could not locate the 'ipopt' executable, which is required for solver ipopt
---------------------------------------------------------------------------
ApplicationError                          Traceback (most recent call last)
Cell In[8], line 62
     59 m.fs.ng_steam_ratio.fix(1)
     61 solver = SolverFactory("ipopt")
---> 62 results = solver.solve(m, tee=True)

File ~/checkouts/readthedocs.org/user_builds/idaes-examples/envs/latest/lib/python3.8/site-packages/pyomo/opt/base/solvers.py:534, in OptSolver.solve(self, *args, **kwds)
    531 def solve(self, *args, **kwds):
    532     """Solve the problem"""
--> 534     self.available(exception_flag=True)
    535     #
    536     # If the inputs are models, then validate that they have been
    537     # constructed! Collect suffix names to try and import from solution.
    538     #
    539     from pyomo.core.base.block import BlockData

File ~/checkouts/readthedocs.org/user_builds/idaes-examples/envs/latest/lib/python3.8/site-packages/pyomo/opt/solver/shellcmd.py:140, in SystemCallSolver.available(self, exception_flag)
    138     if exception_flag:
    139         msg = "No executable found for solver '%s'"
--> 140         raise ApplicationError(msg % self.name)
    141     return False
    142 return True

ApplicationError: No executable found for solver 'ipopt'

Let’s print some model results:

print("Steam flowrate = ", value(m.fs.steam_flowrate))
print("Reformer duty = ", value(m.fs.reformer_duty))
print("Mole Fraction Ar = ", value(m.fs.AR))
print("Mole Fraction C2H6 = ", value(m.fs.C2H6))
print("Mole Fraction C3H8 = ", value(m.fs.C3H8))
print("Mole Fraction C4H10 = ", value(m.fs.C4H10))
print("Mole Fraction CH4 = ", value(m.fs.CH4))
print("Mole Fraction CO = ", value(m.fs.CO))
print("Mole Fraction CO2 = ", value(m.fs.CO2))
print("Mole Fraction H2 = ", value(m.fs.H2))
print("Mole Fraction H2O = ", value(m.fs.H2O))
print("Mole Fraction N2 = ", value(m.fs.N2))
print("Mole Fraction O2 = ", value(m.fs.O2))
Steam flowrate =  0.6077815115578293
Reformer duty =  20894.99849692314
Mole Fraction Ar =  0.003685928708625731
Mole Fraction C2H6 =  0.004174498761104526
Mole Fraction C3H8 =  0.0005304604040521441
Mole Fraction C4H10 =  0.0009065647744530309
Mole Fraction CH4 =  0.12893526499890756
Mole Fraction CO =  0.0973757815625882
Mole Fraction CO2 =  0.04594305744149133
Mole Fraction H2 =  0.2947117425194844
Mole Fraction H2O =  0.12005265455241615
Mole Fraction N2 =  0.3067577132635225
Mole Fraction O2 =  2.4775618019229293e-20

4.2 Optimizing the Autothermal Reformer#

Extending this example, we will unfix the input variables and optimize hydrogen production. We will restrict nitrogen below 34 mol% of the product stream and leave all other variables unfixed.

Above, variable values are called in reference to actual objects names; however, as shown below this may be done much more compactly by calling the list objects we created earlier.

# unfix input values and add the objective/constraint to the model
m.fs.bypass_frac.unfix()
m.fs.ng_steam_ratio.unfix()
m.fs.obj = Objective(expr=m.fs.H2, sense=maximize)
m.fs.con = Constraint(expr=m.fs.N2 <= 0.34)

# solve the model
tmr = TicTocTimer()
status = solver.solve(m, tee=True)
solve_time = tmr.toc("solve")

# print and check results
assert abs(value(m.fs.H2) - 0.33) <= 0.01
assert value(m.fs.N2 <= 0.4 + 1e-8)
print("Model status: ", status)
print("Solve time: ", solve_time)
for var in inputs:
    print(var.name, ": ", value(var))
for var in outputs:
    print(var.name, ": ", value(var))
Ipopt 3.13.2: 

******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
 Ipopt is released as open source code under the Eclipse Public License (EPL).
         For more information visit http://projects.coin-or.org/Ipopt

This version of Ipopt was compiled from source code available at
    https://github.com/IDAES/Ipopt as part of the Institute for the Design of
    Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE
    Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.

This version of Ipopt was compiled using HSL, a collection of Fortran codes
    for large-scale scientific computation.  All technical papers, sales and
    publicity material resulting from use of the HSL codes within IPOPT must
    contain the following acknowledgement:
        HSL, a collection of Fortran codes for large-scale scientific
        computation. See http://www.hsl.rl.ac.uk.
******************************************************************************

This is Ipopt version 3.13.2, running with linear solver ma27.

Number of nonzeros in equality constraint Jacobian...:     2569
Number of nonzeros in inequality constraint Jacobian.:        1
Number of nonzeros in Lagrangian Hessian.............:       80

Total number of variables............................:      233
                     variables with only lower bounds:        0
                variables with lower and upper bounds:      194
                     variables with only upper bounds:        0
Total number of equality constraints.................:      231
Total number of inequality constraints...............:        1
        inequality constraints with only lower bounds:        0
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:        1

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0 -2.9471174e-01 1.82e-12 7.70e-04  -1.0 0.00e+00    -  0.00e+00 0.00e+00   0
   1 -2.9581536e-01 1.20e-04 8.37e-03  -1.0 1.91e+02    -  1.00e+00 1.00e+00f  1
   2 -2.9633393e-01 3.93e-05 4.70e-03  -2.5 1.27e+02    -  1.00e+00 1.00e+00h  1
   3 -3.0889147e-01 1.93e-02 1.12e-02  -3.8 3.11e+03    -  8.54e-01 1.00e+00f  1
   4 -3.2218328e-01 2.63e-02 7.48e-03  -3.8 6.21e+03    -  1.00e+00 7.13e-01h  1
   5 -3.2632547e-01 1.41e-02 4.84e-02  -3.8 3.83e+03    -  1.00e+00 5.68e-01h  1
   6 -3.2962499e-01 1.80e-02 1.29e-01  -3.8 4.15e+03    -  7.03e-01 1.00e+00h  1
   7 -3.2891795e-01 1.64e-03 1.88e-04  -3.8 9.52e+02    -  1.00e+00 1.00e+00h  1
   8 -3.2891270e-01 2.73e-06 1.19e-06  -3.8 4.83e+01    -  1.00e+00 1.00e+00h  1
   9 -3.3134549e-01 4.77e-03 1.44e-02  -5.7 3.35e+03    -  7.85e-01 7.19e-01h  1
iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
  10 -3.3265276e-01 3.97e-03 1.14e-02  -5.7 2.96e+03    -  9.82e-01 5.04e-01h  1
  11 -3.3253961e-01 1.13e-05 1.91e-02  -5.7 8.04e+01    -  9.43e-01 1.00e+00h  1
  12 -3.3255403e-01 2.51e-07 2.88e-07  -5.7 1.84e+01    -  1.00e+00 1.00e+00h  1
  13 -3.3256308e-01 2.83e-08 5.83e-04  -8.6 6.96e+00    -  1.00e+00 9.64e-01h  1
  14 -3.3256321e-01 7.97e-11 9.37e-03  -8.6 1.78e-01    -  5.45e-01 1.00e+00f  1
  15 -3.3256321e-01 3.64e-12 2.50e-14  -8.6 1.77e-04    -  1.00e+00 1.00e+00h  1

Number of Iterations....: 15

                                   (scaled)                 (unscaled)
Objective...............:  -3.3256321112789822e-01   -3.3256321112789822e-01
Dual infeasibility......:   2.5035529205297280e-14    2.5035529205297280e-14
Constraint violation....:   1.2123371804825303e-14    3.6379788070917130e-12
Complementarity.........:   2.5392404073929864e-09    2.5392404073929864e-09
Overall NLP error.......:   2.5392404073929864e-09    2.5392404073929864e-09


Number of objective function evaluations             = 16
Number of objective gradient evaluations             = 16
Number of equality constraint evaluations            = 16
Number of inequality constraint evaluations          = 16
Number of equality constraint Jacobian evaluations   = 16
Number of inequality constraint Jacobian evaluations = 16
Number of Lagrangian Hessian evaluations             = 15
Total CPU secs in IPOPT (w/o function evaluations)   =      0.012
Total CPU secs in NLP function evaluations           =      0.000

EXIT: Optimal Solution Found.

[+   0.06] solve
Model status:  
Problem: 
- Lower bound: -inf
  Upper bound: inf
  Number of objectives: 1
  Number of constraints: 232
  Number of variables: 233
  Sense: unknown
Solver: 
- Status: ok
  Message: Ipopt 3.13.2\x3a Optimal Solution Found
  Termination condition: optimal
  Id: 0
  Error rc: 0
  Time: 0.05810403823852539
Solution: 
- number of solutions: 0
  number of solutions displayed: 0

Solve time:  0.06416339997667819
fs.bypass_frac :  0.10000021929992625
fs.ng_steam_ratio :  1.1046796492824769
fs.steam_flowrate :  1.1959739002454326
fs.reformer_duty :  38028.68461541513
fs.AR :  0.004110458211653681
fs.C2H6 :  0.00044761800884280994
fs.C4H10 :  0.00011014452363028629
fs.C3H8 :  7.244928916496591e-05
fs.CH4 :  0.017681638298364968
fs.CO :  0.10597963482121954
fs.CO2 :  0.053167024686581285
fs.H2 :  0.3325632111278982
fs.H2O :  0.14710267683917747
fs.N2 :  0.3400000024525687
fs.O2 :  3.321321379533168e-20